Browser Agent
Create Agents and Runs, recover requests, and read task results with the Python SDK 0.7.0.
Browser Agent executes a browser task from a natural-language instruction. A Run is one execution; a saved Agent holds a reusable instruction and optional output schema. Use client.browser_agent with SDK 0.7.0.
Setup
pip install lexmount==0.7.0
export LEXMOUNT_API_KEY='<your-api-key>'
export LEXMOUNT_PROJECT_ID='<your-project-id>'
# Optional: SDK 0.7.0 defaults to this global COM origin.
export LEXMOUNT_BASE_URL=https://api.lexmount.comUse an API Key and Project ID from the same project, with Browser Agent enabled in the selected environment. Set the HTTPS origin, without /v1/browser-agent; the SDK adds that path. Set https://api.lexmount.cn explicitly for CN. Playwright is not required for these Agent API calls.
Run a task
Choose and persist a new RUN_IDEMPOTENCY_KEY for one logical task before running this example. Reuse it with the identical request when recovering that task; use a new key for an intentionally new task.
export RUN_IDEMPOTENCY_KEY='<persistent-unique-key-for-this-task>'Save as agent.py and run python agent.py:
import os
from lexmount import APIError, Lexmount, RunWaitTimeout
key = os.environ["RUN_IDEMPOTENCY_KEY"]
try:
with Lexmount() as client:
receipt = client.browser_agent.runs.create(
query="Read the page title and summarize the page.",
start_url="https://example.com/",
idempotency_key=key,
)
print("Accepted:", receipt.id) # Save this Run ID before waiting.
run = client.browser_agent.runs.wait(receipt.id, timeout=300)
print(run.id, run.status, run.output)
if run.status != "succeeded":
print(run.stop_reason, run.error)
raise SystemExit(1)
except RunWaitTimeout as error:
print("Resume with runs.get/wait:", error.run_id)
raise SystemExit(1)
except APIError as error:
print(error.status_code, error.code, error.request_id)
raise SystemExit(1)A create response is a queued receipt, not a completed result. Save receipt.id and use runs.get(id) or runs.wait(id) to recover after a process restart. Closing the SDK client does not cancel an active Run.
Reuse a saved Agent
Set two additional persistent keys, AGENT_IDEMPOTENCY_KEY for the Agent creation and SAVED_RUN_IDEMPOTENCY_KEY for this Run. Save the returned Agent ID and use it for later Runs; creating the Agent is a one-time setup step.
import os
from lexmount import Lexmount
with Lexmount() as client:
agent = client.browser_agent.agents.create(
name="Page summary",
instruction="Summarize the page in {{language}}.",
start_url="https://example.com/",
output_schema={
"type": "object",
"properties": {"summary": {"type": "string"}},
"required": ["summary"],
"additionalProperties": False,
},
idempotency_key=os.environ["AGENT_IDEMPOTENCY_KEY"],
)
receipt = client.browser_agent.runs.create(
agent_id=agent.id,
variables={"language": "English"},
metadata={"source": "docs"},
idempotency_key=os.environ["SAVED_RUN_IDEMPOTENCY_KEY"],
)
print("Agent:", agent.id, "Run:", receipt.id)
# Recover this Run later with runs.get(receipt.id) or runs.wait(receipt.id).Supply exactly the instruction's template variables. The accepted Run freezes the Agent revision, expanded instruction and schema; later Agent edits do not change that Run. metadata is returned to your application and is not sent to the model. A successful schema-based output is an object; free-form output is text.
Manage resources
All methods below are on client.browser_agent. For AsyncLexmount, await each call.
| Operation | Call |
|---|---|
| Read / list Agents | agents.get(id) / agents.list() |
| Edit an Agent | agents.update(id, revision=current.revision, name="Updated name") |
| Delete an Agent | agents.delete(id) |
| Read / list Runs | runs.get(id) / runs.list() |
| Request cancellation | runs.cancel(id) |
| Wait for terminal state | runs.wait(id) |
Read the current Agent first and pass its revision when updating. A revision conflict requires reading it again; updates are not automatically retried. Cancellation can race with completion: inspect the returned state and keep reading until terminal if it is still cancelling.
Recovery and errors
- The SDK generates an idempotency key if omitted. For recovery across process restarts, supply your own:
idempotency_keyas a keyword argument. Persist the key and request body before sending; use 1–128 visible ASCII characters without spaces. Same key/body replays the original receipt for at least seven days; a different body conflicts. Beyond that window, reconcile through history before creating anything again. succeeded,failed,timed_out, andcancelledare terminal Run results. HTTP success alone does not mean the task succeeded; inspectstatus,stop_reason,error, andoutput.RunWaitTimeoutonly stops local polling. Resume with the known Run ID, or explicitly request cancellation.timeout,poll_interval, andrequest_timeoutuse seconds.APIErrorincludesstatus_code,code, andrequest_id. Keep the request ID for support. Passwith_response=Trueto get success response metadata.- Keep the API Key used to create a Run valid until execution and cleanup finish. Revoking it can fail an active Run with
credential_unavailable; changing the client's key does not replace the original Run's execution credential. usage.creditscan beNonewhile metering is pending; it does not mean zero cost. Task execution may have external side effects, so an unknown result must not be blindly resubmitted.
Async client
Use AsyncLexmount for the same resources. This example reads an existing Run; set RUN_ID to its saved ID.
import asyncio
import os
from lexmount import AsyncLexmount
async def main():
async with AsyncLexmount() as client:
run = await client.browser_agent.runs.get(os.environ["RUN_ID"])
print(run.id, run.status, run.output)
asyncio.run(main())Runnable examples cover basic execution, saved Agents and recovery.
