Run an agent and stream its events
Send an AG-UI RunAgentInput body to a run route and read the AG-UI events it streams back.
Endpoints
All paths start with /api/v1/agents-v2 and need X-Space-Slug.
| Method | URL | Does | Auth |
|---|---|---|---|
POST | /agents/{agent_id}/run-stream/ | Run that agent; the response is the event stream | Key or bearer |
POST | /agents/run-stream/ | Run the workspace's default agent | Key or bearer |
POST | /agents/run-stream/?default=false | Run the inline config in forwardedProps.runtimeConfig, with no agent row | Key or bearer |
POST | /runs/ | Start a background run of ?agent_id= (omitted: the default agent); returns {run_id, thread_id, chat_id, agent_id} | Key or bearer |
GET | /runs/{run_id}/events/?last_id= | Stream a background run's events from after last_id (default 0, the start) | Key or bearer |
POST | /runs/{run_id}/cancel/ | Cancel a background run; 204 | Key or bearer |
GET | /runs/{run_id}/history/ | The events so far: {events, last_event_id, status} | Key or bearer |
GET | /runs/by-thread/{thread_id}/ | The thread's latest background run: {run_id, status} | Key or bearer |
GET | /runs/by-thread/{thread_id}/history/ | {run_id, events, last_event_id, status} for that run | Key or bearer |
POST | /files/upload/ | Upload an attachment | Key or bearer |
GET | /agents/{agent_id}/sandbox/files/presigned-url/ | Download link for a generated file | Key or bearer |
POST | /agents/{agent_id}/sandbox/skills/resync/ | Copy the agent's current skills into its sandbox; 204 | Key or bearer |
GET | /agents/default/ | The workspace's default agent, the one /agents/run-stream/ runs | Key or bearer |
GET · DELETE | /agents/{agent_id}/sandbox/files/?thread_id= · …&path= | List a chat's sandbox files · delete one | Bearer only |
DELETE | /agents/{agent_id}/sandbox/files/clean/ | Empty /home/user/ in the caller's sandbox for this agent | Bearer only |
- The
/runs/routes need background runs enabled on the server; otherwise they return404 Background agent runs are disabled. - Background run events are kept for a limited time after the run ends.
Chat history
| Route | History |
|---|---|
/agents/{agent_id}/run-stream/, /runs/ | Saved to a chat; ?save_history=false skips it |
/agents/run-stream/ | Always saved |
/agents/run-stream/?default=false | Never saved |
- Saved history is a chat; the chat routes are bearer only (Read and share chats). With an API key, read a background run's events through
/runs/{run_id}/history/, or an agent's chats through Lab with thelabscope. - To continue a conversation, reuse its
threadId. With saved history the server replays the stored conversation and uses only the last user message frommessages. - With
?save_history=falseor an inline config nothing is stored: send the whole conversation inmessageson every run.
Request fields
Every top-level key is required: threadId, runId, state, messages, tools, context and forwardedProps.
| Field | Rule |
|---|---|
forwardedProps.mode | "act" (default) or "plan" |
forwardedProps.files | Attachments, [{"id": "<upload id>"}] |
forwardedProps.chatSource, chatSourceRef | Set the saved chat's source and source_ref. Default: none. Used only with a workspace key, on the run that creates the chat through run-stream; "app" hides the chat from the web app's chat list |
forwardedProps.runtimeConfig | Per-run overrides, below |
runtimeConfig field | Effect on the agent's configuration |
|---|---|
system_prompt | Replaces the prompt |
model_config_id or model_slug | Replaces the model |
tool_names | Replaces the tool list |
skill_slugs, skill_set_slugs | Add skills |
connection_ids, mcp_connection_ids | Add connections; never remove the agent's own |
file_scope | Replaces the Files scope |
Stream a run
-
Pick a
threadId, or reuse one to continue a conversation. -
Send the body with
Accept: text/event-stream:curl -N -X POST "$CENTRAL_HUB_URL/api/v1/agents-v2/agents/42/run-stream/" \ -H "X-API-Key: $ALO_API_KEY" \ -H "X-Space-Slug: $WORKSPACE_SLUG" \ -H "Accept: text/event-stream" \ -H "Content-Type: application/json" \ -d '{ "threadId": "contract-demo-1", "runId": "run-1", "state": null, "messages": [{"id": "m1", "role": "user", "content": "Summarize the renewal terms."}], "tools": [], "context": [], "forwardedProps": {} }' -
Read events until
RUN_FINISHEDorRUN_ERROR; either one ends the run.
Run in the background
-
Start the run with the same body; the response holds its
run_id(chat_idisnullwhen history is not saved):curl -X POST "$CENTRAL_HUB_URL/api/v1/agents-v2/runs/?agent_id=42" \ -H "X-API-Key: $ALO_API_KEY" \ -H "X-Space-Slug: $WORKSPACE_SLUG" \ -H "Content-Type: application/json" \ -d '{"threadId": "contract-demo-2", "runId": "run-1", "state": null, "messages": [{"id": "m1", "role": "user", "content": "Summarize the renewal terms."}], "tools": [], "context": [], "forwardedProps": {}}' -
Stream its events from
GET /api/v1/agents-v2/runs/{run_id}/events/?last_id=0. Each chunk starts with anid:line; after a disconnect, reconnect withlast_idset to the lastidyou received. The stream closes with a: donecomment. -
To stop the run, send
POST /api/v1/agents-v2/runs/{run_id}/cancel/.
Override settings for one run
-
Put the overrides in
forwardedProps.runtimeConfig; connections you list are added to the agent's own:curl -N -X POST "$CENTRAL_HUB_URL/api/v1/agents-v2/agents/42/run-stream/" \ -H "X-API-Key: $ALO_API_KEY" \ -H "X-Space-Slug: $WORKSPACE_SLUG" \ -H "Accept: text/event-stream" \ -H "Content-Type: application/json" \ -d '{ "threadId": "contract-demo-1", "runId": "run-2", "state": null, "messages": [{"id": "m2", "role": "user", "content": "Compare it with last year."}], "tools": [], "context": [], "forwardedProps": { "mode": "act", "runtimeConfig": { "connection_ids": [17], "mcp_connection_ids": [7], "model_config_id": 12 } } }'
Attach files
-
Upload the file; the response is
201with{id, name, mime_type, size, gc_url, file_metadata, presigned_url}:curl -X POST "$CENTRAL_HUB_URL/api/v1/agents-v2/files/upload/" \ -H "X-API-Key: $ALO_API_KEY" \ -H "X-Space-Slug: $WORKSPACE_SLUG" \ -F "file=@contract.pdf;type=application/pdf" -
Add
{"id": "<id>"}toforwardedProps.files. The file is copied into the agent's sandbox at/home/user/uploads/<id>-<name>and the agent is told its path. Only your own uploads are resolved. -
Optional: to let the model read the file directly, add a content part to the last user message; use
"type": "image"for images. Files the model cannot take directly are left to the sandbox copy.{"type": "document", "source": {"type": "url", "id": "<id>", "name": "contract.pdf", "mimeType": "application/pdf", "value": "<presigned_url>"}}
Download a generated file
-
Take
pathandfileIdfrom the run'sFILE_GENERATEDevent,{type, toolCallId, path, name, mimeType, size}plusfileIdonce the file is stored. -
Request a link with the run's
agent_idandthread_id:curl "$CENTRAL_HUB_URL/api/v1/agents-v2/agents/42/sandbox/files/presigned-url/?path=/home/user/report.xlsx&thread_id=contract-demo-1&file_id=<fileId>&expires_in_seconds=600" \ -H "X-API-Key: $ALO_API_KEY" \ -H "X-Space-Slug: $WORKSPACE_SLUG" -
Download from
urlin the response,{url, expires_in_seconds}.
| Parameter | Rule |
|---|---|
path | Required; must start with /home/user/ |
thread_id | Required |
file_id | Optional, recommended: one path can hold several versions of a file, and without it the newest is returned |
expires_in_seconds | 30–3600, default 600 |
Troubleshooting
| Response | Cause | Fix |
|---|---|---|
409 {"detail": {"code": "SANDBOX_BUSY", "message": "This chat is still working on an earlier message.", "run_id": "<run id>"}} | Another run still holds this chat's sandbox | Wait for that run to end, or cancel it if it is a background run |
429 | Too many runs; the run routes share one limit per caller | See Rate limits |
402 SUBSCRIPTION_INACTIVE | A signed-in user's subscription is not active | Renew the subscription |
RUN_ERROR with errorSurface.layer quota | The caller is over a credit quota; the event also carries code, quota_type, metric, limit and used | Wait for the quota period to reset, or upgrade the plan |
RUN_ERROR agent request failed (status=422): … | A required top-level key is missing from the body | Send every key listed in Request fields |
PER_USER_AUTH_REQUIRED event, {"connections": [{"connectionId", "connectorKey", "name"}]} | The caller has not authorized a per-user OAuth connection | The run continues without it; the user connects it in the web app, then runs again |
403 You do not have access to this run | The run belongs to another user or workspace | Use the credential that started it |
404 Background agent runs are disabled. | The server has background runs off | Use a run-stream route |
400 Only /home/user files can be downloaded | path is outside /home/user/ | Use the path from FILE_GENERATED |
404 This file is no longer available | The generated file was not kept | Run the agent again |