> ## Documentation Index
> Fetch the complete documentation index at: https://docs.zeroruntime.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent & Session

> TypeScript API reference for Agent & Session.

## Agent

What the agent is, what it can do, and how it behaves on a call.

Subclass it to give the agent behaviour: fields holding `function_tool`
callables are registered automatically, and the `on_*` hooks below are called
by the session as the call progresses. An instance is inert until `serve`
registers it and a session is started against it.

The pipeline is the other half. This class carries the prompt, the tools and
the call-shaped options; `Pipeline` carries the providers that hear and speak.

### Options

```ts theme={null}
Agent(options: AgentOptions)
```

<ParamField path="agent_id" type="string" required>
  Required. The name `serve` registers under and the runtime routes sessions
  to.
</ParamField>

<ParamField path="agents" type="Agent[]">
  Other agents this one hands off to, kept on `alternates`. Nothing registers
  them for you: `serve` registers one `agent_id` per call, and
  `Session.add_handoff` names the target by that id.
</ParamField>

<ParamField path="call_summary" type="CallSummary | null">
  Summarise the conversation at teardown and POST it somewhere.
</ParamField>

<ParamField path="farewell" type="string | null">
  Spoken on the way out, when the agent ends the call itself.
</ParamField>

<ParamField path="greeting" type="string | null">
  Spoken as soon as the agent joins, before the caller says anything.
</ParamField>

<ParamField path="inherit_context" type="boolean">
  Carry the chat history over when another agent hands off to this one. Off
  means it starts the conversation fresh.
</ParamField>

<ParamField path="instructions" type="string" required>
  The system prompt. Persona, task, and the rules the model is expected to
  hold to.
</ParamField>

<ParamField path="max_session_duration_seconds" type="number | null">
  Hard ceiling on the call. The runtime ends the session when it is reached.
</ParamField>

<ParamField path="mcp_servers" type="MCPServer[]">
  `MCPServerStdio` and `MCPServerHTTP` whose tools join the agent's own.
  Connected on the first call to `initialize_mcp`, not here.
</ParamField>

<ParamField path="name" type="string | null">
  Display name. Defaults to `agent_id`.
</ParamField>

<ParamField path="pipeline" type="Pipeline | null">
  The `Pipeline` this agent runs on.
</ParamField>

<ParamField path="tool_timeout_seconds" type="number | null">
  How long the runtime waits for one of this agent's tools to return before
  handing the model a timeout. `null` keeps the runtime's own default of 30
  seconds.

  Raise it only for an agent whose tools genuinely run long. The case it
  exists for is a tool that awaits `Session.warm_transfer` -- that runs for
  `supervisor_join_timeout + briefing_timeout`, minutes rather than seconds,
  and the default would kill the round trip while the transfer carried on
  underneath. The cost is symmetric: a tool that hangs holds the turn for
  exactly this long.
</ParamField>

<ParamField path="tools" type="FunctionTool<any, any>[]">
  Tools defined elsewhere. Tools declared as fields on the agent are found on
  their own, so this is for the ones that are not.
</ParamField>

<ParamField path="wake_up" type="number">
  Seconds of caller silence before the agent nudges. 0 disables it; negative is rejected.
</ParamField>

<ParamField path="wake_up_message" type="string">
  What the nudge says.
</ParamField>

### agent\_id

```ts theme={null}
agent_id(): void
```

### instructions

```ts theme={null}
instructions(): void
```

### session

```ts theme={null}
session(): void
```

### tools

```ts theme={null}
tools(): void
```

### add\_server

```ts theme={null}
add_server(mcp_server: MCPServer): Promise<void>
```

Connect one MCP server and append what it publishes to `tools`.

Ignores anything that is not an `MCPServerStdio` or `MCPServerHTTP`.

<ParamField path="mcp_server" type="MCPServer" required>
  The server to connect.
</ParamField>

<ResponseField name="returns" type="Promise<void>" />

### cleanup

```ts theme={null}
cleanup(): Promise<void>
```

Close the MCP connections and drop the tools they contributed.

Called for you at teardown. Safe to call twice, and safe with no MCP
servers configured.

<ResponseField name="returns" type="Promise<void>" />

### emit

```ts theme={null}
emit(event: 'agent_started', args: unknown[]): void
```

Call every handler subscribed to `event`.

Returns as soon as the handlers have been started, not when they finish,
and never throws: an exception inside a handler is logged against the event
name. Ignored once the emitter has been closed.

<ParamField path="event" type="'agent_started'" required>
  The event name.
</ParamField>

<ParamField path="args" type="unknown[]" required>
  Passed through to each handler.
</ParamField>

### hangup

```ts theme={null}
hangup(reason: string, farewell: string): Promise<void>
```

End the call from the agent's side. A no-op with no live session.

<ParamField path="reason" type="string" default="'agent ended the call'">
  Recorded against the session.
</ParamField>

<ParamField path="farewell" type="string" default="''">
  Spoken before hanging up. Empty uses the agent's own `farewell`.
</ParamField>

<ResponseField name="returns" type="Promise<void>" />

### initialize\_mcp

```ts theme={null}
initialize_mcp(): Promise<void>
```

Connect every configured MCP server and adopt its tools.

Runs once; later calls return immediately. `serve` calls it while building
the agent, so a server that is down fails the build rather than the first
tool call.

<ResponseField name="returns" type="Promise<void>" />

### off

```ts theme={null}
off(event: 'agent_started', callback: EventHandler): void
```

Unsubscribe one handler.

Matched by identity, so it has to be the same object that was registered --
a fresh arrow function will not match. Removing something that was never
subscribed does nothing.

<ParamField path="event" type="'agent_started'" required />

<ParamField path="callback" type="EventHandler" required />

### on

```ts theme={null}
on(event: 'agent_started', callback: EventHandler): EventHandler
```

Subscribe to an event.

Handlers fire in the order they were registered, and registering the same
one twice calls it twice.

<ParamField path="event" type="'agent_started'" required>
  The event name.
</ParamField>

<ParamField path="callback" type="EventHandler" required>
  The handler.
</ParamField>

<ResponseField name="returns" type="EventHandler" />

### on\_enter

```ts theme={null}
on_enter(): Promise<void>
```

Called once the agent has joined and the session is live.

Override it to open the conversation, prime the context, or set up standing
configuration such as `Session.set_thinking_audio`.

<ResponseField name="returns" type="Promise<void>" />

### on\_exit

```ts theme={null}
on_exit(): Promise<void>
```

Called as the call is ending, before teardown finishes.

<ResponseField name="returns" type="Promise<void>" />

### on\_participant\_joined

```ts theme={null}
on_participant_joined(participant: Participant): Promise<void>
```

Called when somebody joins the room the agent is in.

<ParamField path="participant" type="Participant" required />

<ResponseField name="returns" type="Promise<void>" />

### on\_participant\_left

```ts theme={null}
on_participant_left(participant: Participant): Promise<void>
```

Called when somebody leaves. The agent is not one of them.

<ParamField path="participant" type="Participant" required />

<ResponseField name="returns" type="Promise<void>" />

### register\_tools

```ts theme={null}
register_tools(): void
```

Collect the `function_tool` callables declared on this agent.

Called for you the first time `tools` is read. Call it again after adding
one at runtime; it never registers the same tool twice.

### toString

```ts theme={null}
toString(): string
```

Returns a string representation of an object.

<ResponseField name="returns" type="string" />

### update\_tools

```ts theme={null}
update_tools(tools: FunctionTool<any, any>[]): void
```

Replace the tool list outright.

This drops the tools that were found on the agent and anything MCP added,
so pass the full set you want.

<ParamField path="tools" type="FunctionTool<any, any>[]" required />

***

## AgentContext

What the runtime knows about a job, handed to the agent factory.

`serve` passes one to your factory if it takes an argument, so the agent can
be built around the call it is about to take -- a caller's number out of
`metadata`, a different prompt per room.

### Options

```ts theme={null}
AgentContext(options: AgentContextOptions)
```

<ParamField path="agent_id" type="string">
  Which registration the job was routed to.
</ParamField>

<ParamField path="job_id" type="string">
  The runtime's id for this dispatch.
</ParamField>

<ParamField path="metadata" type="Record<string, any>">
  Whatever the dispatcher attached -- the caller's number, a tenant id,
  anything the job was started with.
</ParamField>

<ParamField path="room_id" type="string">
  The room the agent is joining.
</ParamField>

<ParamField path="room_options" type="Room">
  The `Room` the runtime resolved for this job.
</ParamField>

<ParamField path="token" type="string">
  The auth token for this job.
</ParamField>

### toString

```ts theme={null}
toString(): string
```

<ResponseField name="returns" type="string" />

***

## CallSummary

Summarise the conversation when it ends, and POST the result.

### Options

```ts theme={null}
CallSummary(options: CallSummaryOptions)
```

<ParamField path="enabled" type="boolean">
  Set false to carry the configuration without summarising.
</ParamField>

<ParamField path="endpoint" type="string | null">
  Where the summary is POSTed. Without one it is generated and logged but
  sent nowhere.
</ParamField>

<ParamField path="headers" type="Record<string, string>">
  Sent with the POST -- an auth header, usually.
</ParamField>

<ParamField path="instruction" type="string | null">
  Replaces the built-in summarising prompt.
</ParamField>

<ParamField path="llm" type="ProviderSpec | null">
  A second model for the summary alone. `null` reuses the session's. Worth
  pointing at something cheap: it runs once, over the whole transcript, while
  the process is already shutting down.
</ParamField>

<ParamField path="timeout_s" type="number">
  Seconds the summariser gets. 0 takes the runtime's default. Summarising is
  an LLM round trip over the whole conversation, so it is a different order
  of work from the rest of teardown. The ceiling is the runtime's SIGTERM
  grace, since this runs while the agent is shutting down -- asking for more
  than that gets the process killed mid-request rather than granting the time.
</ParamField>

***

## serve

```ts theme={null}
serve(agent: AgentFactory, options: ServeOptions): Promise<void>
```

Register `agent` and serve every call dispatched to it.

Every option left here describes *this worker* -- how many calls it takes,
what it logs, where it answers probes. Nothing here describes the session:
that is Room's job, and the twelve options which used to say it a second time
are gone, because two spellings of `recording` that could disagree is a
question with no right answer.

The returned promise settles when the worker is interrupted or shut down. The
agent is registered with the runtime's registry, and every call dispatched to
that id builds a fresh agent from the factory -- one instance per call, never
one shared across them.

<ParamField path="agent" type="AgentFactory" required>
  A callable returning an `Agent`. Your subclass is usually the
  callable. An instance is rejected: concurrent calls would share one
  conversation.
</ParamField>

<ParamField path="options" type="ServeOptions" default="{}" />

<ResponseField name="returns" type="Promise<void>" />

***

## invoke

```ts theme={null}
invoke(agent_id: string, options: InvokeOptions): Promise<Record<string, string>>
```

Start a session against an agent this process is already serving.

Resolves once the runtime has accepted the session, which is the point at
which the room is joinable.

An ordinary async function: `await` it from `on_ready`, or from anywhere
else once `serve()` is running.

The agent has to be registered in *this* process. There is no dispatch RPC to
route a start to another one: the pipeline, credentials and tool schemas all
live where `serve` was called.

<ParamField path="agent_id" type="string" required>
  The id passed to `serve`.
</ParamField>

<ParamField path="options" type="InvokeOptions" default="{}" />

<ResponseField name="returns" type="Promise<Record<string, string>>" />

***

## Session

One live call, and everything you can do to it while it runs.

You are handed one rather than constructing one: `invoke` returns it, and
inside a `function_tool` or an `on_*` hook it is the session the agent is
bound to. Every method here is a message to the agent process, so they are
all awaited and none of them block the call.

The object stays usable after the call ends -- `ended` goes true and the send
methods become no-ops -- so a hook can read `ended_reason` without guarding
first.

### Constructor

```ts theme={null}
Session(stream: any, accepted: ProtoMessage, outbound: Outbound, options: object)
```

<ParamField path="stream" type="any" required />

<ParamField path="accepted" type="ProtoMessage" required />

<ParamField path="outbound" type="Outbound" required />

<ParamField path="options" type="object" default="{}" />

### agent

```ts theme={null}
agent(): void
```

### ended

```ts theme={null}
ended(): void
```

### playground\_url

```ts theme={null}
playground_url(): void
```

### \[asyncDispose]

```ts theme={null}
[asyncDispose](): Promise<void>
```

<ResponseField name="returns" type="Promise<void>" />

### aclose

```ts theme={null}
aclose(): Promise<void>
```

Release everything this call holds. Idempotent, and safe after any ending.

Every way a call can finish routes here. Closing the transport is the part
that cannot be skipped: the outbound queue feeds a writer this SDK holds,
and a live writer keeps the stream -- and the process -- alive.

<ResponseField name="returns" type="Promise<void>" />

### add\_handoff

```ts theme={null}
add_handoff(to_agent: string, __namedParameters: object): Promise<void>
```

Hand the conversation to another agent, by id.

The target has to be registered -- `serve` registers one `agent_id` per
call -- and whether it inherits the history is that agent's
`inherit_context`.

<ParamField path="to_agent" type="string" required>
  The `agent_id` taking over.
</ParamField>

<ParamField path="__namedParameters" type="object" default="{}" />

<ResponseField name="returns" type="Promise<void>" />

### add\_message

```ts theme={null}
add_message(role: string, content: string, __namedParameters: object): Promise<void>
```

Write a message into the conversation without speaking it.

Useful for handing the model something it should know -- a CRM lookup, a
verification result -- without a turn being spent saying it out loud.

<ParamField path="role" type="string" required>
  `system`, `developer`, `user` or `assistant`. A `ChatRole` works too.
</ParamField>

<ParamField path="content" type="string" required>
  The message body.
</ParamField>

<ParamField path="__namedParameters" type="object" default="{}" />

<ResponseField name="returns" type="Promise<void>" />

### change\_component

```ts theme={null}
change_component(options: ChangeComponentOptions): Promise<string>
```

Swap the named components and leave the rest of the call alone.

<ParamField path="options" type="ChangeComponentOptions" default="{}" />

<ResponseField name="returns" type="Promise<string>" />

### change\_pipeline

```ts theme={null}
change_pipeline(pipeline: Pipeline, __namedParameters: object): Promise<string>
```

Replace the whole pipeline mid-call.

Everything not named is rebuilt from the pipeline you pass, so state a
complete one. To change a provider or two and leave the rest alone, use
`change_component`.

<ParamField path="pipeline" type="Pipeline" required>
  The `Pipeline` to switch to.
</ParamField>

<ParamField path="__namedParameters" type="object" default="{}" />

<ResponseField name="returns" type="Promise<string>" />

### destroy

```ts theme={null}
destroy(reason: string): Promise<void>
```

Tear the session down at the runtime, without a goodbye.

The blunt one: no farewell, no teardown hooks worth waiting for. `end` is
the polite version.

<ParamField path="reason" type="string" default="'client requested destroy'" />

<ResponseField name="returns" type="Promise<void>" />

### detach

```ts theme={null}
detach(): Promise<void>
```

Stop watching this session without ending the call.

The agent keeps running runtime-side; this process just stops listening.
For a call that should actually stop, use `end` or `destroy`.

<ResponseField name="returns" type="Promise<void>" />

### emit

```ts theme={null}
emit(event: string, args: unknown[]): void
```

Call every handler subscribed to `event`.

Returns as soon as the handlers have been started, not when they finish,
and never throws: an exception inside a handler is logged against the event
name. Ignored once the emitter has been closed.

<ParamField path="event" type="string" required>
  The event name.
</ParamField>

<ParamField path="args" type="unknown[]" required>
  Passed through to each handler.
</ParamField>

### end

```ts theme={null}
end(reason: string, farewell: string): Promise<void>
```

Ask the runtime to end the call. A no-op once it has ended.

<ParamField path="reason" type="string" default="'client ended the session'">
  Recorded against the session.
</ParamField>

<ParamField path="farewell" type="string" default="''">
  Spoken before hanging up.
</ParamField>

<ResponseField name="returns" type="Promise<void>" />

### events

```ts theme={null}
events(): AsyncGenerator<Event>
```

Iterate everything the runtime reports, until the call ends.

Keeps yielding briefly past the `ended` event so the last transcripts and
metrics are not cut off mid-teardown.

<ResponseField name="returns" type="AsyncGenerator<Event>" />

### get\_context\_history

```ts theme={null}
get_context_history(__namedParameters: object): Promise<any[]>
```

Fetch the conversation as the agent process holds it.

<ParamField path="__namedParameters" type="object" default="{}" />

<ResponseField name="returns" type="Promise<any[]>" />

### get\_metrics

```ts theme={null}
get_metrics(__namedParameters: object): Promise<any[]>
```

Fetch the per-turn latency metrics collected so far.

<ParamField path="__namedParameters" type="object" default="{}" />

<ResponseField name="returns" type="Promise<any[]>" />

### get\_participants

```ts theme={null}
get_participants(__namedParameters: object): Promise<any[]>
```

Who is in the room right now, as `Participant` records.

<ParamField path="__namedParameters" type="object" default="{}" />

<ResponseField name="returns" type="Promise<any[]>" />

### interrupt

```ts theme={null}
interrupt(__namedParameters: object): Promise<void>
```

Stop the agent talking.

<ParamField path="__namedParameters" type="object" default="{}" />

<ResponseField name="returns" type="Promise<void>" />

### log\_playground

```ts theme={null}
log_playground(): void
```

Announce the join URL on stdout, at most once per session.

Both the direct-start path and the registry worker path call this, and
`invoke` adds a third; the guard is what keeps one session to one URL. It
prints rather than logs because the URL is the one line the operator is
waiting to copy, and a log record buries it behind level and module columns
that are noise for a value you paste into a browser.

### off

```ts theme={null}
off(event: string, callback: EventHandler): void
```

Unsubscribe one handler.

Matched by identity, so it has to be the same object that was registered --
a fresh arrow function will not match. Removing something that was never
subscribed does nothing.

<ParamField path="event" type="string" required />

<ParamField path="callback" type="EventHandler" required />

### on

```ts theme={null}
on(event: string, callback: EventHandler): EventHandler
```

Subscribe to an event.

Handlers fire in the order they were registered, and registering the same
one twice calls it twice.

<ParamField path="event" type="string" required>
  The event name.
</ParamField>

<ParamField path="callback" type="EventHandler" required>
  The handler.
</ParamField>

<ResponseField name="returns" type="EventHandler" />

### play\_background\_audio

```ts theme={null}
play_background_audio(file: string | object | null, __namedParameters: object): Promise<void>
```

Start a sound bed under the call.

Needs the room's mixing track, `Room(&#123; background_audio: true &#125;)`.

<ParamField path="file" type="string | object | null" default="null">
  A path, or a `BackgroundAudio` carrying one along with its
  volume and looping. A disabled `BackgroundAudio` plays nothing.
</ParamField>

<ParamField path="__namedParameters" type="object" default="{}" />

<ResponseField name="returns" type="Promise<void>" />

### process\_text

```ts theme={null}
process_text(text: string): Promise<void>
```

Feed text to the agent as though the caller had said it.

The full turn runs: the model answers and the answer is spoken.

<ParamField path="text" type="string" required />

<ResponseField name="returns" type="Promise<void>" />

### publish\_to\_pubsub

```ts theme={null}
publish_to_pubsub(pubsub_config: PubSubPublishConfig): Promise<void>
```

Publish one pubsub frame into the room.

<ParamField path="pubsub_config" type="PubSubPublishConfig" required>
  The topic, body and options to publish with.
</ParamField>

<ResponseField name="returns" type="Promise<void>" />

### reply

```ts theme={null}
reply(instructions: string, options: ReplyOptions): Promise<UtteranceHandle>
```

Ask the model for a line, generated against `instructions`.

Unlike `say`, this is a generation: the model sees the conversation so far
plus these instructions, and what it produces is spoken.

<ParamField path="instructions" type="string" required>
  What to tell the model for this turn alone.
</ParamField>

<ParamField path="options" type="ReplyOptions" default="{}" />

<ResponseField name="returns" type="Promise<UtteranceHandle>" />

### say

```ts theme={null}
say(text: string, options: SayOptions): Promise<UtteranceHandle>
```

Speak an exact line. No model involved.

<ParamField path="text" type="string" required>
  What to say.
</ParamField>

<ParamField path="options" type="SayOptions" default="{}" />

<ResponseField name="returns" type="Promise<UtteranceHandle>" />

### set\_thinking\_audio

```ts theme={null}
set_thinking_audio(file: string | null, __namedParameters: object): Promise<void>
```

Play a sound while the agent is generating its reply.

Standing configuration rather than a one-shot: once set, the session starts
it at the top of every generation and stops it when the answer begins, for
as long as the session lasts. Set it from `on_enter`.

`file` omitted takes the runtime's own thinking sound. Any file libav can
decode works -- wav, mp3, ogg, flac, m4a.

Needs the room's mixing track, `Room(&#123; background_audio: true &#125;)`, like
all audio that is not speech.

<ParamField path="file" type="string | null" default="null" />

<ParamField path="__namedParameters" type="object" default="{}" />

<ResponseField name="returns" type="Promise<void>" />

### stop

```ts theme={null}
stop(reason: string): Promise<void>
```

End the call and release it. What `await using` calls.

<ParamField path="reason" type="string" default="'client requested stop'" />

<ResponseField name="returns" type="Promise<void>" />

### stop\_background\_audio

```ts theme={null}
stop_background_audio(): Promise<void>
```

Stop the sound bed. Leaves the thinking sound alone.

<ResponseField name="returns" type="Promise<void>" />

### subscribe\_to\_pubsub

```ts theme={null}
subscribe_to_pubsub(pubsub_config: PubSubSubscribeConfig): Promise<void>
```

Listen on one pubsub topic for the rest of the call.

<ParamField path="pubsub_config" type="PubSubSubscribeConfig" required>
  The topic and its handler.
</ParamField>

<ResponseField name="returns" type="Promise<void>" />

### toString

```ts theme={null}
toString(): string
```

Returns a string representation of an object.

<ResponseField name="returns" type="string" />

### transfer\_call

```ts theme={null}
transfer_call(transfer_to: string, __namedParameters: object): Promise<Record<string, any>>
```

Cold-transfer the call and leave.

The caller is handed to `transfer_to` with no introduction and the agent
drops out.

<ParamField path="transfer_to" type="string" required>
  Where to send them -- a SIP URI or a phone number.
</ParamField>

<ParamField path="__namedParameters" type="object" default="{}" />

<ResponseField name="returns" type="Promise<Record<string, any>>" />

### wait

```ts theme={null}
wait(__namedParameters: object): Promise<void>
```

Consume `events` until the call ends, logging as it goes.

The usual last line of a script that started a session and has nothing else
to do.

<ParamField path="__namedParameters" type="object" default="{}" />

<ResponseField name="returns" type="Promise<void>" />

***

## current\_session

```ts theme={null}
current_session(): Session
```

The session whose callback is currently running.

Valid anywhere the SDK invokes your code on a session's behalf: a
`function_tool`, a lifecycle hook, a pipeline hook. Useful for code that runs
on the call without holding a reference to it -- a module-level
`pipeline.on` handler, say. Anything defined on the agent should reach the
call through `this.session` instead, and a pubsub handler subscribed with
`Session.subscribe_to_pubsub` already has the session in hand.

<ResponseField name="returns" type="Session" />

***

## Participant

### Constructor

```ts theme={null}
Participant(options: object)
```

<ParamField path="options" type="object" required />

***

## PubSubSubscribeConfig

One topic to listen on, and what to call for each frame.

Passed to `Session.subscribe_to_pubsub` and `Room.subscribe_to_pubsub`.

### Options

```ts theme={null}
PubSubSubscribeConfig(options: PubSubSubscribeConfigOptions)
```

<ParamField path="cb" type="PubSubHandler | null">
  Called once per frame with the raw frame as an object -- the whole thing as
  the transport delivered it, since pubsub promises no schema beyond
  `message`. Sync or async; a promise is awaited.

  A handler that declares a second parameter is additionally told whether the
  frame is backlog:

  ```ts theme={null}
  function cb(frame, backlog) &#123;
    if (backlog) return;          // already in the topic before we joined
  &#125;
  ```

  Subscribing replays whatever the topic already held, so a one-argument
  handler sees that history as ordinary traffic -- which is the transport's
  own shape, and worth knowing about before replying to it.
</ParamField>

<ParamField path="topic" type="string" required>
  The topic to subscribe to.
</ParamField>

***

## PubSubPublishConfig

One frame to publish into the room.

Passed to `Session.publish_to_pubsub` and `Room.publish_to_pubsub`.

### Options

```ts theme={null}
PubSubPublishConfig(options: PubSubPublishConfigOptions)
```

<ParamField path="message" type="string">
  The text body.
</ParamField>

<ParamField path="options" type="Record<string, any>">
  Transport options. Only `sendOnly` -- a list of participant ids to deliver
  to -- is carried; anything else is dropped, because the wire has nowhere to
  put it. Omitted, everyone subscribed to the topic gets the frame.
</ParamField>

<ParamField path="payload" type="Record<string, any> | null">
  Structured data alongside it, JSON-encoded on the way out.
</ParamField>

<ParamField path="topic" type="string" required>
  The topic to publish on.
</ParamField>

***

## UtteranceHandle

One thing the agent is saying, and how it went.

Returned by `Session.say` and `Session.reply`. Call `wait()` to block until
the line finishes -- it resolves whether the line played out or was cut off,
so check `interrupted` rather than assuming it was heard.

```ts theme={null}
const handle = await session.say('One moment while I look that up.');
await handle.wait();
if (handle.interrupted) &#123;
  // ...
&#125;
```

The wait is a method rather than the handle itself being awaitable: a
thenable would be unwrapped by `await session.say(...)`, so that line would
not return until the audio had finished playing. As it is, `say()` hands the
handle back the moment the request is on its way.

Waiting is optional. Ignore the handle and the line still plays.

### Constructor

```ts theme={null}
UtteranceHandle(utterance_id: string)
```

<ParamField path="utterance_id" type="string" required />

### interrupted

```ts theme={null}
interrupted(): void
```

### state

```ts theme={null}
state(): void
```

### done

```ts theme={null}
done(): boolean
```

Whether the utterance has settled, either way. Never blocks.

<ResponseField name="returns" type="boolean" />

### toString

```ts theme={null}
toString(): string
```

<ResponseField name="returns" type="string" />

### wait

```ts theme={null}
wait(): Promise<UtteranceHandle>
```

Resolve once the line has settled, either way. Resolves to this handle.

<ResponseField name="returns" type="Promise<UtteranceHandle>" />

***

## Room

Which room the agent joins. `room_id: null` asks for a new one.

### Options

```ts theme={null}
Room(options: RoomOptions)
```

<ParamField path="agent_name" type="string | null">
  The 0.1.2 spelling of `name`. Folded into it when set.
</ParamField>

<ParamField path="agent_participant_id" type="string | null">
  Publish the agent under a fixed participant id. `null` lets the room mint
  one, which is what a single-agent session wants.
</ParamField>

<ParamField path="audio_codec" type="string | null">
  Codec the room negotiates -- `"opus"` (the default when `null`), `"pcmu"`,
  `"pcma"`, `"g722"`. This is what tells a meeting from a phone call: opus is
  48 kHz, pcmu/pcma are 8 kHz and g722 is 16 kHz, and that rate reaches the
  VAD and STT. Leave it `null` for meetings; set `"pcmu"` or `"pcma"` for SIP
  so the pipeline sizes itself to the narrowband audio instead of resampling
  it up to 48 kHz and back down again.
</ParamField>

<ParamField path="auth_token" type="string | null">
  VideoSDK token for the room. Falls back to the environment. It travels in
  `StartSession.credentials`, never in `params_json`.
</ParamField>

<ParamField path="auto_end_session" type="boolean | null">
  End the session when the last participant leaves. `null` leaves the
  runtime's default (TRUE) in place.
</ParamField>

<ParamField path="background_audio" type="boolean">
  Open the room's mixing audio track. Nothing plays by itself -- this is the
  track, not the sound. Start audio on it with
  `session.play_background_audio(&#123; file, volume, looping &#125;)` and stop it with
  `session.stop_background_audio()`.

  Required before either call: without the track the SDK refuses, and the
  failure is a silent one from the caller's side.
</ParamField>

<ParamField path="idle_timeout_seconds" type="number | null">
  Seconds of silence before the session is considered idle.
</ParamField>

<ParamField path="join_meeting" type="boolean | null">
  Whether the agent joins the meeting. `null` leaves the runtime's default
  (TRUE) in place.
</ParamField>

<ParamField path="name" type="string">
  Display name the agent publishes under.
</ParamField>

<ParamField path="no_participant_timeout_seconds" type="number | null">
  Seconds with nobody attached before the session is reclaimed. Carried in
  `SessionLimits.inactivity_timeout_seconds`, same as above.
</ParamField>

<ParamField path="observability" type="Observability | null">
  Where this session's telemetry goes. `null` takes the runtime's defaults.
</ParamField>

<ParamField path="playground" type="boolean">
  Ask the runtime for a playground URL for this session.
</ParamField>

<ParamField path="recording" type="boolean">
  Record the session. Off unless asked for -- recording a call is a decision
  about the person on the other end, so the default has to be the safe one
  and the same runtime serves recorded and unrecorded sessions side by side.
  Audio is always captured when this is on; the two below add tracks to it.
</ParamField>

<ParamField path="recording_screen_share" type="boolean">
  Also record the screen share. Needs `recording` and `vision` -- there is no
  screen-share track on a session that is not receiving video.
</ParamField>

<ParamField path="recording_video" type="boolean">
  Also record camera video. Needs `recording`.
</ParamField>

<ParamField path="room_id" type="string | null">
  Existing room to join. A new room is created when `null`.
</ParamField>

<ParamField path="session_timeout_seconds" type="number | null">
  Hard cap on session length, in seconds. Carried in
  `SessionLimits.max_session_duration_seconds` rather than in `RoomSpec`, so
  it is read by the transport and not by `to_proto`. `null` inherits the
  runtime's own ceiling.
</ParamField>

<ParamField path="signaling_base_url" type="string | null">
  Override the signaling base URL.
</ParamField>

<ParamField path="vision" type="boolean">
  Deliver camera frames to the agent process.
</ParamField>

<ParamField path="wait_for_participant" type="boolean | null">
  Whether the agent waits for someone to join before speaking. `null` leaves
  the runtime's default (TRUE) in place.
</ParamField>

### explicitly\_set

```ts theme={null}
explicitly_set(): void
```

***

## Sip

The telephony leg of a session -- who is being called, and from what.

### Options

```ts theme={null}
Sip(options: SipOptions)
```

<ParamField path="call_from" type="string | null">
  Caller id presented on the call.
</ParamField>

<ParamField path="call_id" type="string | null">
  Identifier correlating the call.
</ParamField>

<ParamField path="call_to" type="string | null">
  Destination number/address for an outbound call.
</ParamField>

<ParamField path="call_type" type="string | null">
  Call direction/type.
</ParamField>

<ParamField path="extra" type="Record<string, string>">
  Additional key/values merged into the metadata map.
</ParamField>

<ParamField path="webhook_url" type="string | null">
  URL to receive call-event callbacks.
</ParamField>

### to\_metadata

```ts theme={null}
to_metadata(): Record<string, string>
```

This leg as the metadata dict the room is created with.

<ResponseField name="returns" type="Record<string, string>" />

***

## UNSET

```ts theme={null}
const UNSET: any
```

Annotated `any` so `recording: any = UNSET` type-checks while the honest
default stays visible in the signature a reader sees.

***

## ZeroRuntimeChannel

A connection to one runtime, and the sessions started over it.

`serve` and `invoke` own one for you. Hold one directly to start sessions
from async code, to reach a runtime other than the configured one, or to ask
a runtime what capacity it has.

Connect explicitly with `await channel.connect()`; every method connects on
first use anyway.

TLS is decided by the target unless `secure` says otherwise: local hosts are
plaintext, port 443 is TLS. `ZERORUNTIME_INSECURE=1` forces plaintext.

### Options

```ts theme={null}
ZeroRuntimeChannel(options: ZeroRuntimeChannelOptions)
```

<ParamField path="auth_token" type="string | null" />

<ParamField path="options" type="Record<string, any> | null" />

<ParamField path="secure" type="boolean | null" />

### auth\_token

```ts theme={null}
auth_token(): void
```

### connected

```ts theme={null}
connected(): void
```

### stub

```ts theme={null}
stub(): void
```

### aclose

```ts theme={null}
aclose(): Promise<void>
```

Close the connection. Sessions started over it stop being watched.

<ResponseField name="returns" type="Promise<void>" />

### attach

```ts theme={null}
attach(session_id: string, __namedParameters: object): Promise<Session>
```

Attach to a session that is already running.

<ParamField path="session_id" type="string" required>
  The session to attach to.
</ParamField>

<ParamField path="__namedParameters" type="object" default="{}" />

<ResponseField name="returns" type="Promise<Session>" />

### connect

```ts theme={null}
connect(__namedParameters: object): Promise<ZeroRuntimeChannel>
```

Open the connection. Returns immediately if it is already open.

<ParamField path="__namedParameters" type="object" default="{}" />

<ResponseField name="returns" type="Promise<ZeroRuntimeChannel>" />

### destroy

```ts theme={null}
destroy(session_id: string, reason: string): Promise<ProtoMessage>
```

Tear a session down at the runtime, by id.

<ParamField path="session_id" type="string" required>
  The session to destroy.
</ParamField>

<ParamField path="reason" type="string" default="'client requested destroy'">
  Recorded against it.
</ParamField>

<ResponseField name="returns" type="Promise<ProtoMessage>" />

### session\_info

```ts theme={null}
session_info(session_id: string): Promise<ProtoMessage>
```

Look up one session's state, pid, room and uptime.

Works for any session on this runtime, including ones this process did not
start.

<ParamField path="session_id" type="string" required />

<ResponseField name="returns" type="Promise<ProtoMessage>" />

### start

```ts theme={null}
start(options: StartOptions): Promise<Session>
```

Start a session and return it, ready to run.

The async counterpart to `invoke`, and what to reach for inside async code,
where `invoke` cannot be called.

<ParamField path="options" type="StartOptions" default="{}" />

<ResponseField name="returns" type="Promise<Session>" />

### status

```ts theme={null}
status(): Promise<ZeroRuntimeStatus>
```

Ask the runtime what capacity it has.

<ResponseField name="returns" type="Promise<ZeroRuntimeStatus>" />

### use\_tls

```ts theme={null}
use_tls(): boolean
```

Whether this channel will speak TLS.

`secure` wins if it was set, then `ZERORUNTIME_INSECURE`, then the target
itself: a local host is plaintext and port 443 is TLS.

<ResponseField name="returns" type="boolean" />
