Agents APIReference

Python SDK

latentcode_sandbox_agents 0.1.1: the same client as the TypeScript one, in sync and asyncio variants. Python 3.10+, one dependency (httpx).

Install

$pip install https://latentstack.dev/dl/latentcode_sandbox_agents-0.1.1-py3-none-any.whl

Works with uv pip install and poetry add too. In requirements.txt, list the URL on its own line. To pin a copy, download the wheel and install the file.

Create a client

Python
import os
from latentcode_sandbox_agents import LatentStack

client = LatentStack(api_key=os.environ["LS_API_KEY"])
sessions = client.agents.sessions

# ... and when you're done (or use "with LatentStack(...) as client:")
client.close()
LatentStack(api_key: str, *, base_url: str | None = None, transport: httpx.BaseTransport | None = None, timeout: float | httpx.Timeout | None = 60.0)
Argument
api_keyRequired. Your ls-… key.
base_urlYour LatentStack URL, if it isn't https://latentstack.dev.
transportYour own httpx transport, for proxies or tests.
timeoutPer-request timeout in seconds. The event stream is not bounded by it.

asyncio

AsyncLatentStack takes the same arguments. Its methods are coroutines, and events() is an async iterator. Close the stream explicitly if you break out of it early:

Stream a session with asyncio
import asyncio
import os
from contextlib import aclosing

from latentcode_sandbox_agents import AsyncLatentStack


async def main() -> None:
    async with AsyncLatentStack(api_key=os.environ["LS_API_KEY"]) as client:
        sessions = client.agents.sessions
        session = await sessions.create(
            agent={"model": "bedrock/us.anthropic.claude-sonnet-5", "instructions": "Answer briefly."},
            input="Name three uses of a lighthouse.",
        )
        try:
            # aclosing() closes the stream when you break out early.
            async with aclosing(sessions.events(session["id"])) as events:
                async for event in events:
                    if event["type"] == "text.ended":
                        print(event["data"]["text"])
                    if event["type"] in ("run.completed", "run.failed"):
                        break
        finally:
            await sessions.delete(session["id"])


asyncio.run(main())

client.agents.sessions

Responses are plain dicts with the same fields as the TypeScript types. The package's TypedDicts (Session, StreamFrame, Event, …) give your editor the keys. All options are keyword-only.

Lifecycle

create(*, agent, environment=None, input=None, metadata=None, idempotency_key=None) -> Session
Starts a session. See Configuring agents for the settings. idempotency_key makes the call safe to retry.
get(session_id) -> Session
Reads a session.
list(*, limit=None, after=None) -> SessionList
Newest first. Pass next_after as after for the next page.
delete(session_id) -> Session
Stops the session for good.
pause(session_id) -> Session
Saves its state and releases the sandbox.
resume(session_id) -> Session
Continues a paused session in a new sandbox.

Input

message(session_id, text, *, delivery=None) -> InputAccepted
delivery: "steer" (default) or "queue".
approve(session_id, request_id, reply, message=None) -> InputAccepted
reply: "once", "always" or "reject".
cancel(session_id) -> InputAccepted
Interrupts the current run.
send(session_id, input) -> InputAccepted
Any input as a dict.

Following

events(session_id, *, after=None, stop=None, retry_delay=None) -> Iterator[StreamFrame]
Live frames, reconnecting with the last seq when the connection drops. Ends when the session is stopped or failed, or when stop is set.
Argument
afterStart after this seq. Default: from the beginning.
stopA threading.Event (asyncio.Event for the async client). It may take a few seconds to stop.
retry_delayFixed seconds between reconnects. Default: 1, 2, 3 … per failed attempt; gives up after 5.
wait(session_id, *, until=None, timeout=600.0, poll=2.0) -> Session
Polls until the status is in until (default SETTLED). Raises LatentStackError(type="timeout") after timeout seconds. Right after create() a session is briefly idle before its first message starts, so follow events() to know a task is done.

Artifacts

artifacts(session_id) -> ArtifactList
One record per repository.
artifact(session_id, name="patch", *, repo=None) -> str
The unified diff. repo is required with several repositories.

Errors

Python
from latentcode_sandbox_agents import LatentStackError

try:
    sessions.get("ags_missing")
except LatentStackError as e:
    print(e.status, e.type, e.message)   # 404 not_found No session 'ags_missing'.

status is 0 when no response arrived (network_error). See Errors for all types.

Exports

ExportWhat
LatentStack · AsyncLatentStackThe clients.
Sessions · AsyncSessions · Agents · AsyncAgentsThe classes behind client.agents.sessions.
LatentStackErrorThe error: status, type, message.
SETTLED · DEFAULT_BASE_URL · __version__Constants.
TypedDictsSession, SessionList, SessionStatus, SessionStatusName, Agent, Rule, Effect, Environment, EnvironmentNone, EnvironmentRepos, RepoSpec, Event, StreamFrame, ApprovalRequested, PendingApproval, SessionInput, MessageInput, ApprovalInput, CancelInput, ApprovalReply, Delivery, InputAccepted, Artifact, ArtifactList, FileChange, InstanceContext, ApiError
Same behaviour, both languages
The Python client behaves exactly like the TypeScript one: the same methods, errors and reconnecting event stream. Only the naming follows each language.

Upgrading

  • Each new version has its own install URL; see Install above. Reinstall from the new URL.
  • latentcode_sandbox_agents.__version__ tells you what you have.