Agents

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.

MethodURLDoesAuth
POST/agents/{agent_id}/run-stream/Run that agent; the response is the event streamKey or bearer
POST/agents/run-stream/Run the workspace's default agentKey or bearer
POST/agents/run-stream/?default=falseRun the inline config in forwardedProps.runtimeConfig, with no agent rowKey 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; 204Key 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 runKey or bearer
POST/files/upload/Upload an attachmentKey or bearer
GET/agents/{agent_id}/sandbox/files/presigned-url/Download link for a generated fileKey or bearer
POST/agents/{agent_id}/sandbox/skills/resync/Copy the agent's current skills into its sandbox; 204Key or bearer
GET/agents/default/The workspace's default agent, the one /agents/run-stream/ runsKey or bearer
GET · DELETE/agents/{agent_id}/sandbox/files/?thread_id= · …&path=List a chat's sandbox files · delete oneBearer only
DELETE/agents/{agent_id}/sandbox/files/clean/Empty /home/user/ in the caller's sandbox for this agentBearer only
  • The /runs/ routes need background runs enabled on the server; otherwise they return 404 Background agent runs are disabled.
  • Background run events are kept for a limited time after the run ends.

Chat history

RouteHistory
/agents/{agent_id}/run-stream/, /runs/Saved to a chat; ?save_history=false skips it
/agents/run-stream/Always saved
/agents/run-stream/?default=falseNever 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 the lab scope.
  • To continue a conversation, reuse its threadId. With saved history the server replays the stored conversation and uses only the last user message from messages.
  • With ?save_history=false or an inline config nothing is stored: send the whole conversation in messages on every run.

Request fields

Every top-level key is required: threadId, runId, state, messages, tools, context and forwardedProps.

FieldRule
forwardedProps.mode"act" (default) or "plan"
forwardedProps.filesAttachments, [{"id": "<upload id>"}]
forwardedProps.chatSource, chatSourceRefSet 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.runtimeConfigPer-run overrides, below
runtimeConfig fieldEffect on the agent's configuration
system_promptReplaces the prompt
model_config_id or model_slugReplaces the model
tool_namesReplaces the tool list
skill_slugs, skill_set_slugsAdd skills
connection_ids, mcp_connection_idsAdd connections; never remove the agent's own
file_scopeReplaces the Files scope

Stream a run

  1. Pick a threadId, or reuse one to continue a conversation.

  2. 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": {}
      }'
  3. Read events until RUN_FINISHED or RUN_ERROR; either one ends the run.

Run in the background

  1. Start the run with the same body; the response holds its run_id (chat_id is null when 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": {}}'
  2. Stream its events from GET /api/v1/agents-v2/runs/{run_id}/events/?last_id=0. Each chunk starts with an id: line; after a disconnect, reconnect with last_id set to the last id you received. The stream closes with a : done comment.

  3. To stop the run, send POST /api/v1/agents-v2/runs/{run_id}/cancel/.

Override settings for one run

  1. 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

  1. Upload the file; the response is 201 with {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"
  2. Add {"id": "<id>"} to forwardedProps.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.

  3. 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

  1. Take path and fileId from the run's FILE_GENERATED event, {type, toolCallId, path, name, mimeType, size} plus fileId once the file is stored.

  2. Request a link with the run's agent_id and thread_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"
  3. Download from url in the response, {url, expires_in_seconds}.

ParameterRule
pathRequired; must start with /home/user/
thread_idRequired
file_idOptional, recommended: one path can hold several versions of a file, and without it the newest is returned
expires_in_seconds30–3600, default 600

Troubleshooting

ResponseCauseFix
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 sandboxWait for that run to end, or cancel it if it is a background run
429Too many runs; the run routes share one limit per callerSee Rate limits
402 SUBSCRIPTION_INACTIVEA signed-in user's subscription is not activeRenew the subscription
RUN_ERROR with errorSurface.layer quotaThe caller is over a credit quota; the event also carries code, quota_type, metric, limit and usedWait 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 bodySend every key listed in Request fields
PER_USER_AUTH_REQUIRED event, {"connections": [{"connectionId", "connectorKey", "name"}]}The caller has not authorized a per-user OAuth connectionThe run continues without it; the user connects it in the web app, then runs again
403 You do not have access to this runThe run belongs to another user or workspaceUse the credential that started it
404 Background agent runs are disabled.The server has background runs offUse a run-stream route
400 Only /home/user files can be downloadedpath is outside /home/user/Use the path from FILE_GENERATED
404 This file is no longer availableThe generated file was not keptRun the agent again

On this page