Core concepts
The vocabulary the rest of the docs assume.
Three roles
- Engine: runs the agent loop. Calls LLMs, dispatches tools, persists
every step, streams events. The
subsbinary, or the cloud. - Worker: your code. An HTTP endpoint that receives a decision request
and returns a decision. Hosts one or more agents, told apart by
agent_id. - Client: anything that sends messages and streams events back. A browser, a backend, the CLI.
Sessions and turns
A session is one conversation: its messages, tool calls, state, and config, persisted by the engine. A turn starts when a client submits input and ends when the agent is done responding.
The decision loop
Whenever the engine needs to know what happens next, it POSTs a decision request to your worker:
{
"session_id": "…",
"agent_id": "my-agent",
"trigger": { "type": "tool.execute", "name": "get_current_time", … },
"proposed": { … }, // the engine's default continuation; empty when it has none
"state": { … }, // your agent state
"agent": { … }, // the current agent config
"calls": [ … ] // in-flight tool/LLM calls
}Your worker returns a decision:
{
"messages": [ … ], // messages to record
"actions": [ … ], // what to do next
"state": { … }, // omit to keep current state
"agent": { … } // omit to keep current config
}The engine only acts on decisions your worker returns.
Triggers
The trigger says why the engine is asking.
| Trigger | Meaning |
|---|---|
session.start | A new session. Usually answered with the agent config. |
client.messages | The client sent or edited messages. |
client.action | The client invoked a named action you define. |
tool.execute | The model called one of your tools. Run it. |
tool.finished | A tool call settled. |
llm.execute | Your worker makes this LLM call (per agent config). |
llm.finished | An LLM call settled. |
sub_agent.finished | A child session completed. |
interrupt.resumed | A paused branch was resumed. |
Proposals
For most triggers, proposed carries the decision an ordinary agent loop
would make next: record the reply, dispatch the tool calls, finish the
turn. Return it as-is to accept. proposed is empty when only your worker
knows what to do, like running one of your own tools.
A worker that returns proposed unchanged is a complete agent.
Actions
A decision's actions say what the engine should do.
| Action | Meaning |
|---|---|
llm.call | Run an LLM call. |
tool.call | Dispatch a tool call. |
tool.result / tool.error | Settle a tool call. |
llm.result / llm.error | Settle a worker-executed LLM call. |
sub_agent.spawn | Start a child session. |
message.send | Write a message into a session. |
interrupt | Pause the active branch until someone resumes it. |
done | End the turn. |
Agent config
The config declares what the agent is: model, system, tools,
sub_agents, and where LLM calls run. It's usually written once at
session.start, but a decision can rewrite it mid-conversation: swap the
model, add a tool, change the system prompt.
Where things run
| Call | Default | Alternative |
|---|---|---|
| Tools | Your worker | The browser (client-side tools) |
| LLM calls | The engine | Your worker (LLMs) |
Durability
Every trigger, decision, and call is persisted before it's acted on. If the engine or your worker dies, the run resumes from the last recorded step. See Durability.
Next
- Tool calls: declaring and running tools.
- Protocol: the full wire reference.