Sessions

Start a session and get a handle that polls, messages, and stops it. The handle is sugar over the generated session methods.

A session is one run of an agent. Starting it returns immediately: the agent works in a cloud sandbox while your code decides whether to wait, watch, or walk away.

Start and wait

sessions.run() starts a session and returns a SessionHandle over it. wait() polls until the session settles:

import os

from ellipsis import Ellipsis

client = Ellipsis(api_key=os.environ["ELLIPSIS_API_TOKEN"])

handle = client.sessions.run(
    prompt="Fix the flaky test in ci/",
    repository="acme/api",
)
session = handle.wait(timeout=900)
print(session.status)

run() takes exactly the arguments sessions.start() takes, and handle.session holds the newest snapshot the handle has seen. handle.id is the session id, which is what you store if you want to pick the session back up later.

What "settled" means

wait() returns when the session reaches a terminal status, completed, error, cancelled, or stopped, or when a keyed conversation parks with session_state of idle or closed. Parking matters: a durable conversation finishes each turn with a terminal per-execution status while the conversation itself is still alive, so waiting only on status would return early on the first turn and never on the last.

wait() polls every 3 seconds by default. Pass poll_interval to change that, and timeout in seconds to bound the wait; exceeding it raises TimeoutError, which leaves the session running.

Message a running session

send() posts into the session's inbox. The message is delivered at the next turn boundary, and it wakes a parked session:

handle.send("Also update the changelog")

Pass idempotency_key to make a retried send safe:

handle.send("Also update the changelog", idempotency_key="changelog-ask-1")

Stop, refresh, and read records

handle.refresh()                 # re-fetch the session snapshot
page = handle.records(limit=50)  # the session's record log
handle.stop()                    # stop the agent now

stop() ends the run; the session's history stays readable afterward.

Pick up an existing session

sessions.handle() builds a handle over a session you already have the id of, which is how a second process resumes watching:

handle = client.sessions.handle("session_7Hq2mX4p")
print(handle.session.status)

Without the handle

run() and handle() are the only two methods on this namespace that are not generated from the spec. Everything else is a direct call, and the handle is optional:

response = client.sessions.start(prompt="Fix the flaky test in ci/")
session_id = response.session.id

The full list of session operations, with each one's parameters and response, is in the API reference.

Async

The async client mirrors this surface with await, and its handle adds stream() for live frames:

import os

from ellipsis import AsyncEllipsis

async with AsyncEllipsis(api_key=os.environ["ELLIPSIS_API_TOKEN"]) as client:
    handle = await client.sessions.run(prompt="Fix the flaky test in ci/")
    await handle.stream(on_frame=print)

See Streaming.