Skip to content

Per-run controls ​

Every agent run starts with generate(options) or stream(options). Constructor options define stable behavior; run options control one execution.

1. Configure one generated response ​

ts
const result = await supportAgent.generate({
    prompt: input.message,
    maxTurns: 3,
    toolConcurrency: 2,
    controls: { reasoningEffort: 'high' },
    retries: {
        maxAttempts: 3,
        initialDelayMs: 100,
        maxDelayMs: 1000,
    },
    trace: {
        name: 'support-turn',
        userId: user.id,
        metadata: { ticketId: input.ticketId },
    }
})

Supported run options are:

  • maxTurns for this run's loop limit;
  • retries to inherit, replace, or disable (false) the constructor retry policy;
  • controls to override constructor defaults such as reasoningEffort;
  • abortSignal to cancel the run;
  • toolConcurrency for parallel local tool execution;
  • lifecycle for callbacks added to the agent lifecycle;
  • guardrails for additional run policies;
  • middlewares for request-specific model and tool transformation; and
  • trace for observer correlation and behavior.

Tool concurrency must be a positive safe integer. The runtime reduces it to one when approval-capable tools require serial execution.

2. Read the outcome union ​

generate() returns a discriminated response, interaction, or blocked outcome:

ts
if (result.type === 'response') {
  console.log(result.output)
  console.log(result.runId)
  console.log(result.usage.totalTokens)
  console.log(result.messages)
  console.log(result.trace)
} else if (result.type === 'blocked') {
  console.log(result.stage, result.reason)
} else {
  console.log(result.interaction.type)
  console.log(result.interaction.toolName)
  console.log(result.continuation)
}

A response may also contain context usage, guardrail decisions, normalized sources, provider-executed tool metadata, and memory-compaction details.

3. Continue an approval ​

Keep the continuation server-side and start a linked phase with a matching response:

ts
let result = await supportAgent.generate({
    prompt: input.message
})

while (result.type === 'interaction') {
  if (result.interaction.type !== 'tool-approval') {
    throw new Error(`Unexpected interaction: ${result.interaction.type}`)
  }
  const approved = await requestHumanDecision(result.interaction)

  result = await supportAgent.resume(
    result.continuation,
    {
      type: 'tool-approval',
      approved,
      reason: approved ? 'Approved by operator' : 'Rejected by operator',
    },
  )
}

if (result.type === 'response') console.log(result.output)

An interaction is an expected outcome, not an exception or an incomplete result. The application must claim it once, expire stale responses, and preserve the continuation on a trusted server.

4. Stream one run ​

ts
const stream = supportAgent.stream({
    prompt: input.message,
    maxTurns: 3,
    toolConcurrency: 2,
    trace: { name: 'support-stream' }
})

for await (const event of stream) {
  if (event.type === 'text_delta') {
    process.stdout.write(event.delta)
  }

  if (event.type === 'tool_result') {
    console.log(event.toolName, event.result)
  }

  if (event.type === 'response' || event.type === 'interaction' || event.type === 'blocked') {
    console.log(event.text, event.usage)
  }
}

Consumers that do not need partial tool arguments can ignore tool_call_delta and handle the complete tool_call event.

Use server transport to convert safe, selected events into an HTTP stream. Do not send raw reasoning, tool arguments, tool results, or provider metadata to browsers without an explicit data policy.

5. Run inside a memory session ​

When memory is configured, use the same run options on the session:

ts
const sessionAgent = new Agent({
    id: 'support-session',
    model,
    instructions: 'Use conversation history when answering follow-up questions.',
    memory: { store: memoryStore },
});
const session = { sessionId: conversationId, userId: user.id, metadata: { tenantId: user.tenantId } };
const result = await sessionAgent.generate({
    prompt: input.message,
    maxTurns: 3,
    trace: { name: 'support-session-turn' },
    session: session
});

The session value must be a scope object like the one above (sessionId plus optional userId and metadata); anything else throws. A session run takes its input through prompt — a string or one user message — because it loads its history from the store, so a Message[] transcript cannot be combined with a persisted session.

Continue with Runtime lifecycle.

Built for Anvia.