Skip to content

Chat and streaming

Earlier technical reference

This page is retained from earlier documentation and has not been fully revalidated for the public 2026.10.19 release. Its revision-specific links and examples may describe older or development behavior. Start with the current public-release user guide; do not use this page alone to select installation commands, image tags, or security settings.

POST /api/chat submits one user-visible turn. Select an existing agent; its configured model and tools determine what the turn can do. A request can incur provider charges and execute granted tools.

Request body

Field Behavior
agentId Registered agent; explicit selection is recommended
sessionId Session name, default default
message Nonblank string; an image attachment permits an image-only request
runId Optional caller-supplied run identifier; absence generates one, not a general idempotency key
attachments Array of {name, type, size, encoding, content} records
modelConnectionId, model Optional exact enabled connection/model overrides
reasoningEffort, temperature Per-turn generation preferences, subject to model support
continuityScope Explicit continuity namespace; workingProject is a compatibility alias
noCallModel Literal true selects no-model behavior; not an authorization or sandbox control

Normal chat does not accept a workspace-selection/execution-target protocol. A continuity namespace or prose path does not change the tool cwd or execution target. Requests sharing an agent/session are serialized by the HTTP adapter.

Attachment and request budgets

The browser defaults to 8 MiB per file, 16 MiB per attachment batch, and 8 files. These are pre-read browser resource budgets, not server admission policy. Deployments can override positive integer values through window.__BURROW_CLIENT_BUDGETS__ before loading the UI bundle.

The server separately truncates non-image attachment content to 200,000 characters and rejects image content above 30,000,000 characters with 413. Its JSON request reader defaults to 96 MiB total body bytes and 30 seconds for body receipt; BURROW_REQUEST_MAX_BYTES and BURROW_REQUEST_TIMEOUT_MS configure those ceilings. JSON traversal is also bounded. None of these limits proves native PDF/Office parsing from a filename or guarantees that all attachment text reaches the model.

NDJSON protocol

Send Accept: application/x-ndjson to receive newline-delimited JSON over the POST response. The response uses HTTP 200 and application/x-ndjson; charset=utf-8, with no-cache, no-transform and x-accel-buffering: no. It is not Server-Sent Events.

Each event has type, runId, sessionId, ts and data. Buffer partial network chunks until a complete line is available, parse each JSON line independently and ignore unknown event types safely.

Event Meaning
run.started Accepted runtime turn and run identifier
route.decided Route/session-kind observation
model.started, model.completed Model request/response metadata
assistant.delta Provisional answer text; data.delta, totalChars, modelCall
assistant.thought Separate provisional thought stream; never merge it into the final answer
tool.started, tool.completed Tool activity/status and selected presentation fields
verification.completed Verification observation
runtime.notice Runtime loop warning/block notice
run.completed Terminal data.response; inspect its application outcome
run.failed, run.cancelled, run.superseded Other terminal outcomes with data.response

The terminal response and persisted transcript are authoritative, not accumulated deltas. A handled unsuccessful result can arrive in run.completed, and an HTTP 200 stream can end with failure. Slash-command turns can produce only a terminal event. Early validation failures can be ordinary JSON errors before streaming starts.

Tool progress is operational evidence, not a content-free telemetry guarantee: projected fields can include command, cwd, paths, query, reason and error. Keep streams private.

sequenceDiagram
    participant C as Client
    participant H as HTTP adapter
    participant R as Runtime
    participant P as PostgreSQL transcript
    C->>H: POST /api/chat (Accept NDJSON)
    H-->>C: run.started
    H->>R: Serialized agent/session turn
    R-->>C: Text, thought and activity events
    R->>P: Durable conversation evidence
    H-->>C: Terminal event with response
    C->>H: Read session to reconcile

Disconnect and cancellation

Closing the browser or aborting the client fetch marks the turn detached; it does not automatically cancel execution. Send POST /api/chat/{runId}/cancel with the owning agentId and optional reason for explicit cancellation. Cancellation is a request to stop active work, not rollback of tools already executed.

After a disconnect, query GET /api/chat/runs/active with agentId/sessionId, then reload session history. Active-run state is in memory and is not a durable streaming replay cursor. There is no automatic resumption of the same event stream. Avoid blindly reposting a turn, which can run it twice.

Steering an active turn

POST /api/chat/{runId}/steer submits new user input to a run. Supply its owning agentId, exact sessionId, a nonblank idempotencyKey, and message (or supported image attachment input). GET /api/chat/{runId}/steering?agentId=...&sessionId=... reads the durable submissions and their status. Both routes use the normal API authentication boundary.

Status Meaning
pending Stored, waiting for a runtime boundary
delivered Handed into the model continuation and recorded for prompt replay
follow_up Run stopped accepting input before delivery; not automatically sent as a new turn

A successful POST confirms storage, not delivery or completion of the requested work. Poll steering status and inspect the resulting transcript. Inputs are delivered at runtime boundaries; steering does not undo a tool already executed. Reuse an idempotency key only for an identical retry: changed payloads return 409 steering_idempotency_conflict. A reset generation mismatch returns 409 chat_run_session_reset; an unknown run returns 404 chat_run_not_found. Stopping the run or recovering after the server no longer has it active can leave input marked follow_up; review it before explicitly sending a new turn to avoid duplicated work.

Endpoint inventory

Methods are significant. Braced segments are placeholders; URL-encode identifiers. See the contract and conventions for artifact limitations.

Method Path Purpose
POST /api/chat Run one chat turn
GET /api/chat/runs/active List active chat runs
POST /api/chat/{runId}/cancel Cancel a chat run
POST /api/chat/{runId}/steer Submit idempotent steering input
GET /api/chat/{runId}/steering Read durable steering input/status