naive.forUser(childProjectId).agents — 22 methods over 20 routes.
Agents are per-child-project, and
create requires one. A child project owns
the vault entries, connections and Account Kit that decide what the agent may
touch, so naive.agents.create() on the unscoped client answers invalid_input
telling you to scope it. Every other method works on either scope.Lifecycle
update({ paused: true }) is a hold on execution. It rides the config push,
so the runtime honours it: no wake is armed and no schedule fires. Work you send
a paused agent is still accepted and still queued — it waits for
update({ paused: false }), which arms again and runs it. It does not abort a
slice already running; cancelTask() does that, cooperatively.There is no
jobs array on create. Create writes Postgres in one
transaction and touches nothing in the runtime — the durable object is made
lazily on first wake — so a create that fails halfway cannot leave an orphaned
agent behind a rolled-back row. Send the work immediately after; it is one
sendJob and it retries on its own.Sending work
A per-task
window takes all three values. An earlier release accepted a
per-task "standard", stored it and echoed it back as "asap" — the runtime
narrowed the inbound window with a two-way test written when there were two
windows. It now narrows against the platform’s window table, and
ci/agents-window-parity.test.ts fails if any surface goes back to spelling that
set by hand.Omitting window on a task inherits the agent’s completion_window — it
does not fall back to "asap". The client sends no field, the API forwards
undefined, and the runtime resolves it, so exactly one component holds that
default. An earlier release did read an omitted window as "asap"; if you are
working from notes written against that, it changed. Send the field only when a
particular task needs a tier other than its agent’s.A non-default window is served on a model that declares one, and REFUSED on
the rest. On any other model the field is accepted here and at the API, and the
turn is then refused with window_unavailable — refused rather than downgraded,
because a window silently served as "asap" reports a discount nobody bought.
The gate runs before a provider is chosen, so a refused turn spends nothing.A task’s window is not the agent’s knob. On a task it selects the tier the
call is priced at, and nothing else. The run’s tool fan-out, sub-agent width and
batch hint come from the agent’s completion_window, because the run manifest
declares one strategy before its first turn.🔴 A schedule entry’s window is accepted, stored, echoed on get, and then
dropped. Every schedule-fired task is created "asap" — which overrides the
schedule’s own window and the agent’s completion_window, so a "flex"
agent’s cron work meters at the dearest tier. The error direction is
over-charge, and no client-side setting fixes it today.The board
source is PLATFORM-SET: no request body can write it, and an unknown value
is refused rather than answered with an empty page. It says why the agent woke
— webhook for an inbound delivery, schedule for a cron fire, self for a
row the agent wrote itself, api for a task you sent. The trigger router states
it on a header the gateway sets, which is why a source in your own request
body is ignored and your tasks read api.Runtimes before 2026-08-19 wrote api into this column for every task, so
{ source: "webhook" } came back {items: []} on them — a working filter’s
answer, which is why it went unnoticed for so long. Tasks those builds created
still read api; find them by metadata.event_type /
metadata.trigger_subscription_id, which the router has always written.The event log
One log, two representations, one reader.AgentEventKind union the SDK publishes is declared, task_started,
task_finished, turn_started, text_delta, tools_offered, tool_call,
tool_result, usage, budget, subagent_started, subagent_finished,
delivered, error.
Deliverables
download_url and upload_url are null when the deployment has no storage
sink — a deployment state, not an error. A minted download_url is
unauthenticated once issued and lives an hour; never cache it, call again.
Limits: 20 deliverables per task, 25 MB each.
Spend
{ period, period_start, cap_micro_usd, max_task_micro_usd, hard, spent_credits, by, groups }. Every paid component appears including the zeros.
Money is decimal strings — the client does no arithmetic on it anywhere.
Inbound webhooks
Signing a delivery
Sign with the helper rather than rebuilding the string — the timestamp is part of the signed content, not a header beside it:
Two separate headers, and the signature is bare hex — a leading
sha256= or
v1, is tolerated and nothing else is. A single Stripe-style combined header
(t=…,v1=…) does not verify. The signed content is the timestamp, a literal
., then the exact request bytes; the window is five minutes.
Errors
Every refusal is aNaiveError with a stable code (see
SDK errors). The agents-specific codes are invalid_model,
agent_not_configured, task_not_replyable, budget_exhausted and
agent_runtime_unavailable; the rest are the platform’s usual set.
window_unavailable is the one refusal a window user has to handle: a
"standard" or "flex" window on a model that does not declare one is refused
with it rather than downgraded. It arrives at the first model call, not at
create and not at sendJob, so it surfaces on the task as a failure rather
than as a rejected request — and nothing is spent, because the gate runs before
a provider is chosen.Refusing rather than downgrading is the feature. Serving the call as "asap"
under the requested name would report a discount nobody bought, and no field
downstream would disagree — which is what happened before the gate existed.
Either pin the agent to a model that declares the window, or leave it at
"asap".window_cannot_stream is in the published union and is never sent — every
window streams. primitive_disabled_by_kit is likewise not a wire code: the kit
gate answers forbidden with details.reason.The 22 methods
Plus
signAgentWebhook(), a pure helper that calls nothing.
See the Agents overview, concepts and
CLI reference.