Runs and Delegation
Durable background work with bounded subagent calls.
Run lifecycle
queued → running → completed | failed | cancelled | expired
↘ requires_action (approval-gated tools)
Failure diagnostics
A failed run always carries a structured envelope — never a bare message.
Through the project proxy routes, failures normalize to { error, code, message, requestId, timestamp, upstream_status }, so a runtime failure is
distinguishable from a proxy failure without parsing text. Pair any report
with its requestId.
Usage and cost attribution follows the inference path: turns executed through
the Holeacquisition LLC gateway record per-request usage and costUsd (see Chat), and
memory operations report their own costUsd. Turns your own runtime executes
directly against providers are metered by that runtime — route them through
the gateway (or tag them with your run id in your own logs) if you need
per-run cost joined to ours.
Safety boundary
Prompt-injection scanning, content filtering, and the safety verdict apply
to model calls routed through the Holeacquisition LLC gateway — including the memory
write path, which drops override-language facts before they persist. A
self-hosted runtime calling providers directly bypasses all of it: route
agent inference through the gateway (or a project key with scanning enabled)
to inherit input guards, output scanning, and per-response classification.
Scanning is per-project opt-in — check it is enabled before pen-testing it.
POST /v1/agents/:id/runs is idempotent (Idempotency-Key scoped to your project; same key + different body is 409). Suspended tenants accept no new runs. Poll GET /v1/runs/:id, page through the durable JSON event log at GET .../events?after=, and cancel with POST .../cancel — cancellation wins executor races via conditional claims and cascades to active child runs.
Three modes: sync waits and returns the finished run, background enqueues and returns 202 immediately, and streaming executes inline while emitting server-sent events (run.queued, run.started, text.delta word-by-word, tool_call.completed, then run.completed or run.failed, then [DONE]). Billing, metering, and the terminal row are identical across modes. A disconnect never cancels the run — keep polling GET /v1/runs/:id.
Run input accepts JSON up to 64 KiB. The complete JSON is sent to the model as one user message; a messages array inside it is data, not a native multi-role conversation. Use session turns when you need role-aware conversation. Oversized input is rejected with 413 input_too_large, never silently truncated.
For structured output, put response_format beside input in the create request. A requested json_schema is checked after generation; invalid JSON or output that violates the supported schema subset fails the run rather than completing it. The validator supports type, properties, required, additionalProperties, items, and enum. Unsupported assertion keywords are rejected at creation rather than ignored. Callers should still validate critical actions in their own application.
The completed Run.output is an envelope, not the generated value itself: Run.output.output holds the model text, or the parsed JSON value when json_schema was requested. The envelope also includes model, provider, camel-case token usage, USD cost (providerCostUsd and cencoriChargeUsd), versions, citations, and the policy snapshot. Historical runs may lack cost. Every new run records the exact agent/skill/subagent versions, knowledge citations, and policy snapshot used.
Delegation
POST /v1/runs/:id/delegate with { agent_version_id, input, installation_id? } runs one bounded task on an explicitly allowlisted subagent version. The child is isolated: same project/tenant/user, the child's own version config, no parent conversation beyond the task input, no inherited installation or session (bind one explicitly and it is triple-validated). Knowledge loads only from the child's own bindings.
Gates, in order: parent active, tenant active, manifest depth, plan depth, edge allowlist, edge call/timeout/spend budgets, published child, cycle check. subagent.called/completed/failed events correlate parent and child with full cost attribution to the child installation.
Testing versions
POST /v1/agents/:id/versions/:version/test runs a sandboxed single model call — no run row, no webhooks, no bindings, no credentials, capped tokens — and records passing evidence. Publishing requires it: both publish paths reject untested versions.