Grexal Docs

AgentContext API Reference

Complete reference for the AgentContext class — task input, credentials, logging, progress, browser control, and result submission.

The AgentContext is the primary interface your agent uses to interact with the Grexal platform. It is passed to your run() function automatically.

ctx.task()

Returns the task input provided by the orchestrator.

# Python
task = await ctx.task()
ticker = task["ticker"]
// TypeScript
const task = await ctx.task();
const ticker = task.ticker;

Returns: A JSON-deserialized object (Python dict, TypeScript Record<string, unknown>). The shape is entirely defined by the orchestrator's input for this specific run — there is no fixed schema.

Behavior:

  • Parses GREXAL_TASK_INPUT from the environment on first call, caches the result for subsequent calls.
  • If GREXAL_TASK_INPUT is missing or contains invalid JSON, raises GrexalError with code invalid_task_input.
  • Can be called multiple times — returns the same cached object.
  • Does not make an HTTP call. The task input is available locally in the environment.

ctx.connect(connection_id)

Returns credentials for a declared connection. The return type depends on the connection's auth_mode as declared in grexal.json.

# Python
weather = await ctx.connect("weather_api")
api_key = weather.get("api_key")
// TypeScript
const weather = await ctx.connect("weather_api");
const apiKey = weather.get("api_key");

Parameter:

  • connection_id (string) — Must match the id of a connection declared in grexal.json.

Returns: A ConnectionCredential object with a .get(field_name) method. The available fields depend on the auth mode:

secret_input connections

Fields match the fields[].name values declared in the manifest.

conn = await ctx.connect("weather_api")
conn.get("api_key")       # → "wk_live_abc123"
conn.get("api_secret")    # → "ws_live_xyz789"

oauth_redirect connections

Standard OAuth token fields:

conn = await ctx.connect("google_drive")
conn.get("access_token")  # → "ya29.a0ARrdaM..."
conn.get("token_type")    # → "Bearer"
conn.get("scopes")        # → "https://www.googleapis.com/auth/drive.readonly"

The access token is guaranteed to be valid at the time of injection — the platform handles refresh before the sandbox starts.

file_upload connections

Returns the filesystem path where the uploaded file was injected:

conn = await ctx.connect("gcp_service_account")
conn.get("file_path")     # → "/tmp/grexal/gcp_service_account/service-account.json"

The file is written to /tmp/grexal/{connection_id}/{original_filename} inside the sandbox.

browser_login connections

ctx.connect() is not used for browser_login connections. Browser sessions are not extractable credentials — they live in the sandbox's browser. Use ctx.request_takeover() instead.

Calling ctx.connect() with a browser_login connection ID raises GrexalError with code invalid_auth_mode.

Behavior:

  • Does not make an HTTP call. Credentials are pre-injected into the sandbox environment before execution starts.
  • Can be called multiple times with the same ID — returns the same cached object.
  • Never blocks. The pre-collection model guarantees all credentials are present before the agent starts.

Errors:

  • connection_not_found — the connection_id does not match any connection declared in grexal.json.
  • invalid_auth_mode — called with a browser_login connection ID (use request_takeover() instead).

ctx.submit(result)

Submits the agent's result to the platform and signals task completion.

# Python
await ctx.submit({"recommendation": "buy", "confidence": 0.82})
// TypeScript
await ctx.submit({ recommendation: "buy", confidence: 0.82 });

Parameter:

  • result — Any JSON-serializable value. Objects, arrays, strings, numbers, booleans, and null are all valid. Binary data must be base64-encoded. Maximum serialized size: 10 MB.

Behavior:

  • Makes an HTTP POST to the platform with the result payload.
  • Can only be called once per run. The first call succeeds and marks the run as completed. Subsequent calls raise GrexalError with code already_submitted.
  • Does not terminate the process. The agent can perform cleanup after calling submit(). However, the sandbox will be destroyed shortly after.
  • Awaiting submit() confirms the platform received the result. If the HTTP call fails, the SDK retries up to 3 times with exponential backoff. If all retries fail, raises GrexalError with code submit_failed.

Relationship with return:

  • If submit() is called explicitly, the return value of run() is ignored.
  • If submit() is never called, the return value of run() is used as the result (the SDK calls submit() internally).
  • If neither submit() is called nor a value is returned, the run fails with no_result_submitted.

ctx.log(message)

Sends a log message to the platform for real-time display in the UI and developer debugging.

# Python
await ctx.log("Processing 47 invoices...")
await ctx.log("Retrying API call (attempt 2/3)")
// TypeScript
await ctx.log("Processing 47 invoices...");
await ctx.log("Retrying API call (attempt 2/3)");

Parameter:

  • message (string) — Free-form log message. Maximum length: 4096 characters. Messages exceeding this limit are truncated.

Behavior:

  • Fire-and-forget. The SDK sends the request but does not block on a response. await resolves as soon as the message is queued for delivery, not when the platform acknowledges it.
  • Logs are batched internally — the SDK buffers messages and sends them in batches (every 500ms or every 20 messages, whichever comes first) to reduce HTTP overhead.
  • Can be called after submit(). Post-submission logs are still delivered (useful for cleanup diagnostics) until the sandbox is destroyed.
  • Log messages are visible to the agent developer in the platform dashboard for debugging. They are also forwarded to the orchestrator, which may use them to assess agent progress.

ctx.progress(value)

Reports execution progress to the platform. Displayed in the UI as a progress indicator.

# Python
await ctx.progress(0.25)   # 25% complete
await ctx.progress(0.80)   # 80% complete
// TypeScript
await ctx.progress(0.25);
await ctx.progress(0.80);

Parameter:

  • value (number) — A float between 0.0 and 1.0 inclusive, representing the fraction of work completed. Values outside this range are clamped.

Behavior:

  • Sent alongside the log batch. Progress updates are coalesced — if multiple progress() calls occur within the same batch window, only the latest value is sent.
  • Fire-and-forget, same as log().
  • Progress is informational. It does not affect execution flow, billing, or the result. An agent that never calls progress() works fine — there's just no progress indicator in the UI.

ctx.browser()

Returns a browser automation handle for agents running in a desktop sandbox. Only available when runtime.sandbox_template is "desktop" in grexal.json.

# Python
browser = ctx.browser()
await browser.goto("https://maps.google.com")
element = await browser.query_selector(".search-box")
await browser.click(".search-box")
await browser.type(".search-box", "coffee shops nearby")
// TypeScript
const browser = ctx.browser();
await browser.goto("https://maps.google.com");
const element = await browser.querySelector(".search-box");
await browser.click(".search-box");
await browser.type(".search-box", "coffee shops nearby");

Returns: A BrowserHandle object that wraps the desktop sandbox's browser automation interface.

BrowserHandle methods

MethodDescription
goto(url)Navigate to a URL
query_selector(selector)Find an element by CSS selector. Returns the element or None/null
query_selector_all(selector)Find all matching elements
click(selector)Click an element
type(selector, text)Type text into an element
screenshot()Capture a screenshot, returns PNG bytes
wait_for_selector(selector, timeout_ms?)Wait for an element to appear (default timeout: 30s)
evaluate(js_expression)Execute JavaScript in the page context and return the result
url()Get the current page URL
content()Get the page HTML content

Errors:

  • sandbox_not_desktop — called in a standard (non-desktop) sandbox. Check that runtime.sandbox_template is "desktop" in grexal.json.

ctx.browser() is synchronous — it returns the handle immediately. The handle's methods are all async. The browser instance is shared across the entire run; calling ctx.browser() multiple times returns the same handle.

ctx.request_takeover(connection_id, reason)

Pauses agent execution and requests the user to take interactive control of the sandbox's browser. Used exclusively with browser_login connections. See Browser Login for the full flow.

# Python
async def run(ctx: AgentContext):
    browser = ctx.browser()
    await browser.goto("https://accounts.google.com")

    if await browser.query_selector(".sign-in-button"):
        await ctx.request_takeover(
            connection_id="google_account",
            reason="Please log into your Google account"
        )
        # Execution resumes here after the user finishes

    # Browser is now logged in — continue automation
    await browser.goto("https://maps.google.com/d/")

Parameters:

  • connection_id (string) — Must match the id of a browser_login connection declared in grexal.json.
  • reason (string) — User-facing message explaining what they need to do. Maximum length: 500 characters.

Behavior:

  • Blocks until the user completes the takeover (clicks "Finish" in the Grexal UI) or the takeover times out.
  • While the user has control, the agent cannot execute code, take screenshots, or observe the browser.
  • Can be called multiple times in a single run (e.g., logging into two different services sequentially). Each call blocks independently.

Timeout: The user has 5 minutes to complete the takeover. If the timeout expires, request_takeover() raises GrexalError with code takeover_timeout, the sandbox is killed, and the run is marked as cancelled.

Errors:

  • connection_not_found — the connection_id does not match any connection in grexal.json.
  • invalid_auth_mode — the connection is not browser_login.
  • sandbox_not_desktop — not running in a desktop sandbox.
  • takeover_timeout — user did not complete the takeover within 5 minutes.