Copy page
View as Markdown View this page as plain text

Agents

An agent is the top-level conversation orchestrator in Standard Agents. Agents define:

  • conversation type (ai_human or dual_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

PropertyTypeDescription
namestringUnique agent identifier
sideASideConfigSide A configuration

1.2 Optional

PropertyTypeDefaultDescription
type'ai_human' | 'dual_ai''ai_human'Conversation mode
sideBSideConfig-Required for dual_ai
maxSessionTurnsnumber-Session turn safety cap
titlestring-Human-readable label (legacy)
descriptionstring-Agent summary
iconstring-Display icon
exposeAsToolbooleanfalseExpose callable entrypoint
toolDescriptionstring-Callable description
envRecord<string, string>-Agent-level default variable values
hooksstring[]-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 as user.
  • maxSessionTurns should be set for bounded execution.
  • dual_ai agents can be used as autonomous subagents (§7).

3. SideConfig

PropertyTypeDefaultDescription
promptstringRequiredPrompt name for this side
labelstring-UI/log label
stopOnResponsebooleantrueStop side turn on text response without tool calls
stopToolstring-Stop side turn when this tool is called
stopToolResponsePropertystring-Extracted property for stop tool outcomes
maxStepsnumber-Per-side step safety limit
sessionStopSessionToolBinding-End session successfully
sessionFailSessionToolBinding-End session with failure
sessionStatusSessionToolBinding-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 action
  • messageProperty: which arg field becomes lifecycle message text
  • attachmentsProperty: 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:

  1. session-level terminal bindings (sessionStop / sessionFail)
  2. side-level stop bindings (stopTool)
  3. response stop (stopOnResponse)
  4. safety limits (maxSteps, maxSessionTurns)

6. Tool Exposure

When exposeAsTool: true, how the callable behaves depends on agent type:

Agent typeCallable semantics
ai_humanHandoff: the tool-call transfers control to the target agent on the same thread, preserving history.
dual_aiSubagent: 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_ai agent.
  • 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

BlockingNon-blocking
Non-resumableParent waits; child ends after resultParent continues; child returns result later
ResumableParent waits per invocation; child persistsParent 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-instance nameEnv / descriptionEnv hints and scopedEnv transfer.
  • optional — environment flag gating whether this branch is enabled.
  • resumable — persistent child instances addressable via lifecycle tools.
  • resumable.parentCommunicationimplicit (default) auto-queues completion/failure to the parent; explicit leaves escalation to tools/hooks.
  • parentCommunication (top level) — the same modes for non-resumable subagents; explicit suppresses the auto-queued completion so a background child’s finish does not wake the parent. resumable.parentCommunication takes precedence when both are set. See §7.11.
  • hidden — keep the relationship declared (runtime code can still spawn the child via invokeTool/queueTool) while excluding the tool from every LLM request, so the model can never call it. For infrastructure children like background context compaction.

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 nameEnv and descriptionEnv as model-visible hints when deriving initial child arguments via a bootstrap pass.
  • runtimes MUST treat scopedEnv as runtime-only transfer data.
  • runtimes MUST NOT expose scopedEnv values to the model unless the same env is explicitly declared as nameEnv or descriptionEnv.

7.7 Resumable Lifecycle Tools

For resumable instances, runtimes expose built-in lifecycle tools:

  • subagent_create
  • subagent_message

subagent_create MUST require a non-empty name argument for the spawned child instance.

subagent_create SHOULD also accept an arguments object shaped by the prompt schema of the child side that receives parent messages (resumable.receives_messages). Runtimes MUST persist those initial arguments for the lifetime of the child thread and make them available to both child sides through ThreadState.arguments and prompt variable interpolation, including future resumptions.

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 Persistent Invocation Arguments

The receiving agent — through the requiredSchema of its side_a prompt — solely dictates the invocation arguments a subagent accepts. Required schema fields are mandatory; optional fields are merely suggested. The invoking parent supplies them when calling the subagent tool, or via a structured arguments object on subagent_create.

Unlike a plain tool call, these arguments are not ephemeral:

  • runtimes MUST persist the validated arguments for the life of the child thread.
  • runtimes MUST hydrate them into prompt interpolation for both side_a and side_b on every activation — the initial invocation and every later resume — so a system prompt can reference spawn-time context (for example a stylist subagent that needs the user’s gender, sizes, and style preferences) for as long as the thread lives.
  • if required arguments are missing, runtimes MUST reject creation with a structured subagent_arguments_required error rather than spawning the child.

This lets the receiving side declare what it needs once and rely on those values throughout the conversation, instead of only seeing them in the first message.

7.9 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:

  • GET returns required/missing variable names.
  • POST stores the provided values and immediately boots the deferred subagent using the original creation payload.

7.10 Session Lifecycle Bindings on Child Sides

Child completion, failure, and status are defined on each side’s SideConfig:

  • sessionStop
  • sessionFail
  • sessionStatus

Each supports the string and object forms from §4. Mapped properties are the canonical payload for child → parent communication.

7.11 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.13).

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 the effective parentCommunication mode is explicit, runtimes MUST NOT auto-queue completion/failure to the parent. Tools or hooks escalate explicitly:

  • state.notifyParent(content)
  • state.setStatus(status)
  • state.stopSession({ result, notifyParent, status })

The effective mode is resolved as resumable.parentCommunication when set, otherwise the top-level SubagentToolConfig.parentCommunication, defaulting to implicit. The top-level form is how a non-resumable background subagent opts out: because the auto-queued completion message is what triggers a parent turn, explicit means the child’s completion does not wake the parent at all. Such children deliver results through another channel — for example, writing to the parent’s thread key-value store — which the parent picks up on its next natural turn (e.g. via a filter_messages hook).

See Threads for the host-side surface.

7.12 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;
  initialArguments?: Record<string, unknown>;
  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.13 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.14 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 to terminated when 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',
    },
  },
});