Skip to content

Cloud Agent Runs and Events

Use the environment variables from the quickstart. A run is one task on an agent. Its ID stays stable while the agent works, including when you steer an active run with a follow-up.

Terminal window
RUN=$(curl --fail-with-body --silent --show-error \
-H "Authorization: Bearer $RUNTA_TOKEN" \
-H "Content-Type: application/json" \
--data '{"prompt":"Inspect the workspace and summarize the project."}' \
"$RUNTA_API_URL/v2/agents/$AGENT_ID/runs") || exit 1
export RUN_ID=$(printf '%s' "$RUN" | jq -er '.id')

The response is 202 Accepted, not a completed result. prompt is required and its trimmed UTF-8 representation is limited to 65,536 bytes. It may be empty only when images are supplied. Only one run can be active per harness; a concurrent submission returns a conflict. Wait for completion or use a follow-up.

Creation also accepts optional resume_session_id and parent_run_id for continuation metadata. Prefer the resume or follow-up endpoints below when continuing a known run: they obtain the session and parent from that run.

Read a local image and send raw base64, without a data-URL prefix:

Terminal window
base64 < screenshot.png | tr -d '\n' |
jq -Rs '{
prompt: "Describe this screenshot.",
images: [{type: "image", data: ., mime_type: "image/png"}]
}' |
curl --fail-with-body --silent --show-error \
-H "Authorization: Bearer $RUNTA_TOKEN" \
-H "Content-Type: application/json" \
--data-binary @- "$RUNTA_API_URL/v2/agents/$AGENT_ID/runs"

Use type: "image" and one of image/png, image/jpeg, image/gif, or image/webp. There is a maximum of eight images per request. The chosen model must support image input. Follow-ups accept the same image array. Request size limits still apply to the base64-encoded JSON; see Limits.

Terminal window
curl --fail-with-body --silent --show-error \
-H "Authorization: Bearer $RUNTA_TOKEN" \
"$RUNTA_API_URL/v2/agents/$AGENT_ID/runs?limit=100" | jq .
curl --fail-with-body --silent --show-error \
-H "Authorization: Bearer $RUNTA_TOKEN" \
"$RUNTA_API_URL/v2/agents/$AGENT_ID/runs/$RUN_ID" | jq .

Listing returns a JSON array, newest first, filtered to this harness. The public contract permits limit from 1 to 500, defaulting to 100. There is no run-list pagination cursor.

Run field Meaning
id, agent_id Run and agent identifiers.
status queued, running, cancelling, finished, failed, or cancelled.
prompt Original prompt, nullable. Active follow-ups do not replace this stored original.
result Assistant reply when available, nullable. Fetch this after completion for the final answer.
error Failure description, nullable.
parent_run_id Prior run for a continuation, or null.
dsh_session_id Pi session ID, or null before a session is established.
created_at, updated_at Timestamp strings, nullable.

finished, failed, and cancelled are terminal states. Cancellation and failure can still leave partial output or changed files. A run’s state is independent of the runtime state returned by the agent endpoint.

Use a follow-up for conversation-style interaction:

Terminal window
curl --fail-with-body --silent --show-error \
-H "Authorization: Bearer $RUNTA_TOKEN" \
-H "Content-Type: application/json" \
--data '{"prompt":"Focus on the authentication module."}' \
"$RUNTA_API_URL/v2/agents/$AGENT_ID/runs/$RUN_ID/follow-ups" | jq .
  • Active run: interrupts the current Pi turn, then submits the new prompt in the same conversation and returns the same run ID.
  • Terminal run: creates a new run using the previous session ID and sets parent_run_id to the previous run.
  • Synthetic bootstrap reply without a session: creates a fresh run.

Always take the next run ID from the response, since terminal-state races can change which behavior applies.

To explicitly create a continuation after a prior run:

Terminal window
curl --fail-with-body --silent --show-error \
-H "Authorization: Bearer $RUNTA_TOKEN" \
-H "Content-Type: application/json" \
--data '{"prompt":"Continue with the next step."}' \
"$RUNTA_API_URL/v2/agents/$AGENT_ID/runs/$RUN_ID/resume" | jq .

Resume returns 202 with a new run. The prior run must have a session. The server sets resume_session_id and parent_run_id from it, overriding those fields in the submitted body.

The current supervisor keeps one Pi process and conversation per harness. Resume records continuation metadata and submits to that harness’s current conversation; it does not switch to or rewind an arbitrary historical session. Do not rely on it to restore a specific conversation after a supervisor restart.

Terminal window
curl --fail-with-body --silent --show-error -X DELETE \
-H "Authorization: Bearer $RUNTA_TOKEN" \
"$RUNTA_API_URL/v2/agents/$AGENT_ID/runs/$RUN_ID" | jq .

This returns 200 with run state. Cancelling a terminal run returns its existing state. Cancellation aborts the active turn; it does not remove history, delete the runtime, or undo workspace changes. Poll until terminal if the returned status is still cancelling.

Terminal window
curl --fail-with-body --silent --show-error --no-buffer \
-H "Authorization: Bearer $RUNTA_TOKEN" \
-H "Accept: text/event-stream" \
"$RUNTA_API_URL/v2/agents/$AGENT_ID/runs/$RUN_ID/events?after=-1"

The response is a Server-Sent Events stream:

SSE event ID Data
run.status status:<state> Runtime-side run snapshot when the status changes.
pi.event Decimal sequence number Dynamic Pi event, including seq, type, and emitted_at_unix_ms.
error None JSON object with message; indicates a stream failure.

Keep-alive comments are sent about every 15 seconds. A terminal status drains the remaining events and closes the stream. Handle both in-band error events and transport failures. Fetch the run afterward to distinguish success, failure, and cancellation.

The run.status data is the guest’s stored run object, not the public CloudAgentRun response. In particular it uses session_id; normal run GET responses expose that as dsh_session_id.

Current event types include message_start, message_update, message_end, tool_execution_start, tool_execution_update, tool_execution_end, and agent_settled. Preserve unknown event fields and ignore unknown types safely. The OpenAPI event schema is deliberately open.

Text deltas occur in assistantMessageEvent.type === "text_delta"; append assistantMessageEvent.delta. Start a new assistant message for an assistant message_start. Tool execution and replacement turns can produce multiple assistant messages in one run, so concatenating every text delta into one final answer is incorrect. Use the completed run’s result for that answer.

Persist the largest successfully processed pi.event sequence number, scoped to the run ID. Reconnect with ?after=<sequence>; events with seq > after are returned. The default after=-1 replays from the beginning.

Do not use status:running as a cursor. run.status events can be repeated on reconnection and have no numeric cursor. The handler reads the after query parameter, not the browser’s Last-Event-ID header. De-duplicate pi.event records by run ID and sequence if processing can be retried.

Native browser EventSource cannot set a Bearer authorization header. Use an authenticated fetch-stream client or your backend’s proxy for SSE, and keep the Runta API key on your backend.

Obtain the session ID from the run and pass it as session_id:

Terminal window
SESSION_ID=$(curl --fail-with-body --silent --show-error \
-H "Authorization: Bearer $RUNTA_TOKEN" \
"$RUNTA_API_URL/v2/agents/$AGENT_ID/runs/$RUN_ID" |
jq -er '.dsh_session_id') || exit 1
curl --fail-with-body --silent --show-error --get \
-H "Authorization: Bearer $RUNTA_TOKEN" \
--data-urlencode "session_id=$SESSION_ID" \
--data-urlencode "after=-1" \
"$RUNTA_API_URL/v2/agents/$AGENT_ID/events" | jq .

The JSON response contains agent_id, session_id, and events. It is a snapshot, not a live stream. after has the same exclusive sequence semantics and must be at least -1.

The current helper reads the event log of one matching run for that session; it does not concatenate all runs in a shared conversation. Sequence numbers restart for each run. For complete history, list runs and replay each run’s SSE endpoint with its own cursor.