Docs

Python SDK

The whole API from Python, for plain code and for asyncio. It waits for a machine to be running, sends a request again where that is safe, and raises every refusal as an error with the API's code.

For your agent

agental.io/docs/python.md
shell
pip install agental-sdk
  • Installed as agental-sdk, imported as agental: from agental import Agental.
  • Python 3.10 or later, with httpx and nothing else.
  • Typed: it carries py.typed.
  • Names are the API's in snake case, such as exit_code and idempotency_key. One that is a Python keyword ends in _: a message's sender is from_.

Make a client

Make an API key in the console, under API keys, and put it in AGENTAL_API_KEY. A client made with nothing reads it from there.

python
from agental import Agental

agental = Agental()  # reads AGENTAL_API_KEY

sandbox = agental.sandboxes.create(size="small")
result = sandbox.exec("uname -a")
print(result.exit_code, result.stdout)

sandbox.files.write("app/main.py", "print('hello')\n")
print(sandbox.exec(["python3", "/opt/agental/app/main.py"]).stdout)

sandbox.stop()  # the disk is kept
  • create answers when the machine is running. A sandbox you have already is agental.sandboxes.get(id), and agental.sandboxes.list() gives all of them.
  • A command given as a string is a line of shell, run by sh -c. Given as a list, its arguments are passed exactly, with no shell.
  • A command gets 60 seconds unless you pass timeout, in seconds, up to 90, since a proxy in front of the API stops waiting after 100 seconds. One that runs out is killed and exits 124. Longer work goes to sandbox.commands.start, which takes up to 600 and answers at once.
  • File paths are relative to the work folder, /opt/agental. files.read gives text, and files.read_bytes bytes.
  • A time can be a datetime, which must say its time zone, or a string in ISO 8601.

Output as it arrives

python
for event in sandbox.exec_stream("npm test"):
    if event.type == "exit":
        print("exited", event.exit_code)
    else:
        print(event.data, end="")

For a command that takes more than a minute, sandbox.commands.run runs it without holding a request open, and commands.start starts it to be looked at later. See Running commands.

With asyncio

AsyncAgental is the same client, awaited.

python
import asyncio

from agental import AsyncAgental


async def main() -> None:
    async with AsyncAgental() as agental:
        sandbox = await agental.sandboxes.create()
        print((await sandbox.exec("uname -a")).stdout)
        await sandbox.stop()


asyncio.run(main())

async with closes the client's connections at the end; without it, call await agental.aclose(). Agental does the same with with, or agental.close(). exec_stream is iterated with async for.

Where the key comes from

  • api_key, when you pass one.
  • Otherwise AGENTAL_API_KEY.
  • Otherwise the key the agental command keeps on this computer, in ~/.config/agental/credentials.json, for the API it signed in to and no other.

The API is base_url, otherwise AGENTAL_API_URL, otherwise the API the command signed in to, otherwise https://agental.io.

Options

OptionWhat it does
api_keyThe API key. Left out, as above.
base_urlWhere the API answers. Left out, as above.
max_retriesHow many times a request that is safe to send again is sent again. 3 unless you say.
retry_delayThe shortest wait before it is sent again, in seconds. 1.0 unless you say.
poll_intervalHow often something waited for, such as a machine starting, is looked at, in seconds. 2.0 unless you say.
http_clientAn httpx.Client to send requests with, or an httpx.AsyncClient for AsyncAgental. Left out, one of its own.

What is in it

Each guide shows its calls in Python. Where to find them:

CallsGuide
agental.sandboxes.create, get, list; sandbox.stop, start, update, deleteSandbox lifecycle
sandbox.exec, exec_stream, commands.run, commands.startRunning commands
sandbox.files.read, read_bytes, writeFiles
sandbox.browserBrowser
sandbox.desktopDesktop
sandbox.snapshot, restore; agental.snapshotsSnapshots
sandbox.forkForking
agental.templates, sandbox.secretsTemplates and secrets
template.set_network, sandbox.set_networkOutbound rules
sandbox.expose, routesPublic URLs
sandbox.email, agental.emailEmail
agental.create_webhook, list_webhooks; verify_webhook, imported on its ownWebhooks
sandbox.metrics, agental.metrics, running_over_timeMetrics
agental.usage, sandbox.usageUsage
agental.set_telemetry, test_telemetryOpenTelemetry
agental.billing, prices, checkout, burst, set_burst_budgetBilling
agental.api_keysAPI keys
agental.export_accountYour account and data

What it does for you

  • A create or a fork is sent with an Idempotency-Key. If its answer is lost, or the machine is not confirmed yet, the same request is sent again with the same key, which gives the same sandbox back and never a second one. Pass idempotency_key yourself to be able to ask again after your process has died.
  • Reads, file writes, starts and stops are sent again when a proxy answers in the API's place, when the connection drops, and when the sandbox was moved to another server during the request.
  • A command is never sent twice. One that was cut off may have done part of its work, so whether to run it again is yours to decide.
  • A delete carries the confirm header the API asks for.

Errors

python
from agental import ApiError

try:
    sandbox.exec("make")
except ApiError as error:
    if error.code == "sandbox_not_running":
        sandbox.start()
    else:
        raise
ErrorWhat it means
ApiErrorThe API's own refusal, with status, code and message. Decide from code: Errors lists them.
ProxyErrorA 502, a 504 or any answer with no code in it: something in front of the API answered, and the request may still be running.
AgentalConnectionErrorThe API was not reached.
AgentalTimeoutErrorA wait ran out, such as for a machine to start.

All of them are AgentalError. A command that exits non-zero is not an error: read exit_code.

NextBuilding with the OpenAI Agents SDK? agental-openai-agents runs its agents in an agental sandbox. The TypeScript SDK is the same API in TypeScript.

The full machine-readable reference is OpenAPI 3.1. Every page as Markdown, for an agent: llms.txt. Questions: [email protected]