Agents
An agent is the top-level conversation orchestrator in Standard Agents. Agents define:
- conversation type (
ai_humanordual_ai) - side prompts and stop behavior
- session lifecycle tool bindings
- optional tool exposure for handoff or subagent usage
A subagent is not a separate concept — it is a dual_ai agent invoked by a parent thread as a tool (see §7 Subagents).
1. AgentDefinition
1.1 Required
| Property | Type | Description |
|---|---|---|
name | string | Unique agent identifier |
sideA | SideConfig | Side A configuration |
1.2 Optional
| Property | Type | Default | Description |
|---|---|---|---|
type | 'ai_human' | 'dual_ai' | 'ai_human' | Conversation mode |
sideB | SideConfig | - | Required for dual_ai |
maxSessionTurns | number | - | Session turn safety cap |
title | string | - | Human-readable label (legacy) |
description | string | - | Agent summary |
icon | string | - | Display icon |
exposeAsTool | boolean | false | Expose callable entrypoint |
toolDescription | string | - | Callable description |
env | Record<string, string> | - | Agent-level default variable values |
hooks | string[] | - | Fallback hook IDs |
AgentDefinition also accepts optional packaging metadata — packageName, version, author, license — consumed only when the agent is packed for distribution. See Packaging.
2. Agent Types
2.1 ai_human
- Side A is AI.
- Side B is human (no Side B config required).
- Typical usage: user-facing assistants.
2.2 dual_ai
- Both sides are AI.
- Each side sees itself as
assistant, other side asuser. maxSessionTurnsshould be set for bounded execution.dual_aiagents can be used as autonomous subagents (§7).
3. SideConfig
| Property | Type | Default | Description |
|---|---|---|---|
prompt | string | Required | Prompt name for this side |
label | string | - | UI/log label |
stopOnResponse | boolean | true | Stop side turn on text response without tool calls |
stopTool | string | - | Stop side turn when this tool is called |
stopToolResponseProperty | string | - | Extracted property for stop tool outcomes |
maxSteps | number | - | Per-side step safety limit |
sessionStop | SessionToolBinding | - | End session successfully |
sessionFail | SessionToolBinding | - | End session with failure |
sessionStatus | SessionToolBinding | - | Publish status updates |
4. SessionToolBinding
Session lifecycle bindings can be string or object form:
type SessionToolBinding =
| string
| {
name: string;
messageProperty?: string;
attachmentsProperty?: string;
};
name: tool that controls lifecycle actionmessageProperty: which arg field becomes lifecycle message textattachmentsProperty: which arg field contains attachment path(s)
For subagents, mapped stop/fail payloads are the canonical child → parent result/failure payload.
5. Stop Semantics
Runtime stop evaluation order:
- session-level terminal bindings (
sessionStop/sessionFail) - side-level stop bindings (
stopTool) - response stop (
stopOnResponse) - safety limits (
maxSteps,maxSessionTurns)
6. Tool Exposure
When exposeAsTool: true, how the callable behaves depends on agent type:
| Agent type | Callable semantics |
|---|---|
ai_human | Handoff: the tool-call transfers control to the target agent on the same thread, preserving history. |
dual_ai | Subagent: the tool-call spawns a new child thread governed by §7 Subagents. |
7. Subagents
Subagents are autonomous dual_ai child agents spawned from a parent thread. They are the composition primitive for multi-agent workflows.
7.1 What a Subagent Is
- Always a
dual_aiagent. - Invoked from a parent prompt’s tool list.
- Executed in its own isolated thread (messages, filesystem, queue, lifecycle).
- Linked to its parent via thread hierarchy and child registry state.
This lets orchestrators delegate bounded work to specialized children without merging storage or execution state.
7.2 Why Compose
- Parent orchestrates planning, sequencing, and aggregation.
- Child performs focused work with its own prompts/tools.
- Child can run synchronously (blocking) or asynchronously (non-blocking).
- Child can be disposable (non-resumable) or persistent (resumable).
A common pattern: side_a produces, side_b reviews/validates before completion.
7.3 Invocation Modes
| Blocking | Non-blocking | |
|---|---|---|
| Non-resumable | Parent waits; child ends after result | Parent continues; child returns result later |
| Resumable | Parent waits per invocation; child persists | Parent can message anytime; child persists |
7.4 Configuration
Subagents are configured in definePrompt({ tools: [...] }) via SubagentToolConfig. The type and per-field semantics are documented in Tools §5.
The key knobs:
blocking— parent waits for child result.immediate— execute as soon as the prompt becomes active, before the first model step. Object form allows per-instancenameEnv/descriptionEnvhints andscopedEnvtransfer.optional— environment flag gating whether this branch is enabled.resumable— persistent child instances addressable via lifecycle tools.resumable.parentCommunication—implicit(default) auto-queues completion/failure to the parent;explicitleaves escalation to tools/hooks.
7.5 Optional Branches
When optional is set, the branch is enabled only when the named environment variable resolves to one of true, 1, or yes (case-insensitive). Disabled branches are not available for creation or runtime invocation.
7.6 Immediate Execution
When immediate is enabled, runtimes execute the subagent tool immediately when its prompt becomes active:
- thread creation bootstrap
- handoff to a new active prompt
Immediate execution is recursive: if an immediate subagent boots and its active prompt has immediate tools, those execute as soon as the child thread activates.
In the object form:
- runtimes MAY use
nameEnvanddescriptionEnvas model-visible hints when deriving initial child arguments via a bootstrap pass. - runtimes MUST treat
scopedEnvas runtime-only transfer data. - runtimes MUST NOT expose
scopedEnvvalues to the model unless the same env is explicitly declared asnameEnvordescriptionEnv.
7.7 Resumable Lifecycle Tools
For resumable instances, runtimes expose built-in lifecycle tools:
subagent_createsubagent_message
subagent_create MUST require a non-empty name argument for the spawned child instance.
Non-resumable subagents behave like direct tool calls (no persistent addressing).
When maxInstances is reached, new creation attempts SHOULD return a tool error explaining the cap and suggesting messaging an existing instance.
7.8 Scoped Variable Bootstrap
If subagent_create is called but required scoped variables for that child graph are missing, runtimes SHOULD return a structured error (e.g. subagent_env_required) and expose a temporary bootstrap endpoint:
GET /threads/{parent_thread_id}/variables/{request_id}POST /threads/{parent_thread_id}/variables/{request_id}
Expected behavior:
GETreturns required/missing variable names.POSTstores the provided values and immediately boots the deferred subagent using the original creation payload.
7.9 Session Lifecycle Bindings on Child Sides
Child completion, failure, and status are defined on each side’s SideConfig:
sessionStopsessionFailsessionStatus
Each supports the string and object forms from §4. Mapped properties are the canonical payload for child → parent communication.
7.10 Parent ↔ Child Communication
Parent → Child
Parent communication occurs via:
- initial invocation mapping (
initUserMessageProperty,initAttachmentsProperty) - resumable messaging (
subagent_message)
Attachment paths MUST be copied from the parent filesystem to the child filesystem before queuing (§7.12).
Child → Parent: Completion
When the child finishes via sessionStop and parentCommunication is implicit, the parent receives a queued silent message:
Subagent (reference: {uuid}) has returned the following result:
{result}
Returned attachments (if any) are copied child → parent and included as parent-local paths.
Child → Parent: Failure
When sessionFail is called and parentCommunication is implicit, the parent receives:
Subagent (reference: {uuid}) has reported a failure:
{failure details}
Returned attachments are copied child → parent.
Child → Parent: Status
sessionStatus updates the parent’s child registry status text without ending child execution.
Child → Parent: Explicit Escalation
When resumable.parentCommunication is explicit, runtimes MUST NOT auto-queue completion/failure to the parent. Tools or hooks escalate explicitly:
state.notifyParent(content)state.setStatus(status)
See Threads for the host-side surface.
7.11 Child Registry
Resumable instances are tracked in ThreadState.children:
interface SubagentRegistryEntry {
reference: string;
name: string;
title?: string;
description: string;
resumable?: boolean;
blocking?: boolean;
threadName?: string;
spawnGroupId?: string;
createdAt?: number;
status: string;
parentCommunication?: 'implicit' | 'explicit';
}
When children exist, parent context SHOULD include a registry system message so the orchestrator can reason about active instances.
7.12 Attachment Copying
Subagent communication that crosses thread boundaries MUST copy filesystem references:
- parent → child for initial and resumable messaging attachments
- child → parent for completion and failure payload attachments
The destination thread MUST receive destination-local attachment paths.
7.13 Queue and Termination
These are properties of the underlying thread, not of subagents specifically. See Threads for the full queue and termination semantics:
- queued messages are durable and ordered; injected before the next model step when executing, otherwise forcing the next turn.
terminate()is a soft shutdown that aborts in-flight execution, rejects new execution/queued-message entry, and updates parent registry status toterminatedwhen applicable.
8. Example
defineAgent({
name: 'asset_subagent',
type: 'dual_ai',
maxSessionTurns: 40,
exposeAsTool: true,
toolDescription: 'Generate and QA top-down game assets.',
sideA: {
label: 'Worker',
prompt: 'asset_worker',
stopOnResponse: true,
sessionFail: {
name: 'fail_asset',
messageProperty: 'reason',
attachmentsProperty: 'attachments',
},
},
sideB: {
label: 'Reviewer',
prompt: 'asset_reviewer',
stopOnResponse: false,
sessionStop: {
name: 'approve_asset',
messageProperty: 'summary',
attachmentsProperty: 'attachments',
},
sessionStatus: {
name: 'update_asset_status',
messageProperty: 'status',
},
},
});