protocol
@alexkroman1/aai/protocol — the WebSocket wire contract both ends of a session derive.
A FACADE. The subpath resolves here rather than at protocol.ts, which buys two
things the direct form could not. That module can be SPLIT as it grows without
moving the published entry point — the path an implementation file happens to
have is not a thing to promise anyone — and a name it gains next reaches the
public surface only when a line is added below, rather than the moment it is
written.
Named re-exports rather than export * for the second half of that: the
wildcard form re-exports whatever arrives, and needs a noReExportAll
suppression the escape-hatch ratchet only lets move down.
Functions
Section titled “Functions”buildClientConfig()
Section titled “buildClientConfig()”buildClientConfig(
source):object
Build the GET /client-config response body from an agent-shaped config.
Every server that serves the endpoint (a self-hosted createRuntimeServer, the
platform’s per-slug handler, the CLI dev server) goes through this, so a
surface rule can’t drift between them.
Parameters
Section titled “Parameters”source
Section titled “source”greeting?
Section titled “greeting?”string
string
"voice" | "static"
sessionUrl?
Section titled “sessionUrl?”string
Returns
Section titled “Returns”object
greeting?
Section titled “greeting?”
optionalgreeting?:string
optionalname?:string
page:
"voice"|"static"
sessionUrl?
Section titled “sessionUrl?”
optionalsessionUrl?:string
buildReadyConfig()
Section titled “buildReadyConfig()”buildReadyConfig(
s2sConfig):object
Build the protocol-level session config (the config frame’s audio fields)
from the session’s input/output sample rates — used by every session mode,
pipeline and S2S alike.
Parameters
Section titled “Parameters”s2sConfig
Section titled “s2sConfig”inputSampleRate
Section titled “inputSampleRate”number
outputSampleRate
Section titled “outputSampleRate”number
Returns
Section titled “Returns”object
audioFormat
Section titled “audioFormat”audioFormat:
"pcm16"
sampleRate
Section titled “sampleRate”sampleRate:
number
ttsSampleRate
Section titled “ttsSampleRate”ttsSampleRate:
number
lenientParse()
Section titled “lenientParse()”lenientParse<
T>(schema,json,knownTypes?): {data:T;ok:true; } | {error:string;malformed:boolean;ok:false; }
Two-phase message parse: tries the strict schema first, then falls back to the envelope to distinguish unknown-but-valid types (safe to ignore during rolling upgrades) from genuinely malformed messages.
Return value when ok: false:
malformed: true— message doesn’t have a{ type: string }shape (likely corrupt data), OR itstypeis one ofknownTypesbut it still failed strict validation (e.g. atool_resultmissingtoolCallId); both should warnmalformed: false— has a validtypefield whose value is unrecognised; safe to ignore (e.g. new message type from a newer server version)
Passing knownTypes is what separates “unknown newer-version type” from
“known type that failed validation” — without it, an invalid known message
is silently swallowed as if it were a forward-compat unknown type. When
parsing client→server messages, pass SESSION_COMMAND_TYPES as
knownTypes.
Type Parameters
Section titled “Type Parameters”T
Parameters
Section titled “Parameters”schema
Section titled “schema”ZodType<T>
unknown
knownTypes?
Section titled “knownTypes?”ReadonlySet<string>
Returns
Section titled “Returns”{ data: T; ok: true; } | { error: string; malformed: boolean; ok: false; }
Interfaces
Section titled “Interfaces”ClientSink
Section titled “ClientSink”Typed interface for pushing session events to a connected client.
Events send JSON text frames; audio chunks (playAudioChunk) send raw PCM16
binary frames. There is no playAudioDone — the turn’s audio.completed is
an ordinary event now, and the sink orders it behind held audio by type. That
is what let it join the retained stream: a method on the sink was a frame no
event log could see.
Methods
Section titled “Methods”close()?
Section titled “close()?”
optionalclose(reason?):void
Close the underlying connection (best-effort, idempotent). Used when the server retires a session out from under a connected client — a resume takeover, or a sandbox teardown — so the client gets a real close to react to instead of a socket that silently stops answering.
Parameters
Section titled “Parameters”reason?
Section titled “reason?”string
Returns
Section titled “Returns”void
event()
Section titled “event()”event(
event):void
Push a session event (JSON text frame) to the client.
Takes an ALREADY-STAMPED SessionEvent: the envelope is minted once, by the session’s emitter, which is also what appends the event to the retained stream. A sink that stamped its own would mint a second id for an event the stream had already recorded under another.
Parameters
Section titled “Parameters”Returns
Section titled “Returns”void
playAudioChunk()
Section titled “playAudioChunk()”playAudioChunk(
chunk):void
Send a single PCM16 audio chunk (raw binary frame) to the client.
Parameters
Section titled “Parameters”Uint8Array
Returns
Section titled “Returns”void
Properties
Section titled “Properties”
readonlyopen:boolean
True when the underlying connection is open and will accept calls.
Type Aliases
Section titled “Type Aliases”HostConfig
Section titled “HostConfig”HostConfig =
z.infer<typeofHostConfigSchema>
Host-provided agent configuration for a host-mode connection.
ReadyConfig
Section titled “ReadyConfig”ReadyConfig =
z.infer<typeofReadyConfigSchema>
Protocol-level session config returned to the client on connect.
RestoredToolCall
Section titled “RestoredToolCall”RestoredToolCall =
z.infer<typeofRestoredToolCallSchema>
One tool call as a resume reports it.
Public for the reason its schema is: it rides the wire inside
history.restored, so a custom client reads exactly this shape. It was tagged
@internal while the schema it is inferred from was not, which went unseen
until /protocol joined the contract system.
SessionCommand
Section titled “SessionCommand”SessionCommand =
z.infer<typeofSessionCommandSchema>
Client→server text messages (binary frames carry raw PCM16 audio).
Note there is no history command any more. A reconnecting client used to
push its own messages back because the server kept no record; the server is
authoritative now and a resume reads the retained event stream by index. See
“One durable session event stream” in the SDK guide.
SessionErrorCode
Section titled “SessionErrorCode”SessionErrorCode =
z.infer<typeofSessionErrorCodeSchema>
Error codes for categorizing session errors on the wire.
Remarks
Section titled “Remarks”The field a client renders its error banner from (error.reported.code, and
SessionError.code in @alexkroman1/aai-ui). Eight values, by where the
failure came from:
stt— speech-to-text: the provider refused the connection, or its stream failed mid-utterance.llm— the model call for a reply failed. In pipeline mode the caller also hearserrorPhrase, so the turn is handed back rather than going silent.tts— synthesis failed, which is the one the caller cannot hear.tool— a tool threw and the failure could not be given to the model.protocol— a frame that does not parse, or one sent in a state that has no answer for it.connection— the session’s own link, or a provider’s, went away.audio— the audio path: a rate the transport cannot honour, a decode.internal— anything the runtime could not classify.
Severity is fatal, not the code, and the two are independent: any of
these can arrive on a session that continues. fatal: false means surface
the message and keep the session interactive. It is REQUIRED: a fatal frame
is not a banner — aai-ui answers one by releasing the microphone and ending
the call — so every emitter states which it means rather than inheriting a
default that takes the whole session down.
SessionEventMeta
Section titled “SessionEventMeta”SessionEventMeta =
z.infer<typeofSessionEventMetaSchema>
The envelope every session event carries.
Variables
Section titled “Variables”CLIENT_CONFIG_METHODS
Section titled “CLIENT_CONFIG_METHODS”
constCLIENT_CONFIG_METHODS: readonlystring[]
The only method the endpoint answers — read by the host’s route dispatch, so this is the value and not a description of it.
Beside the path for the same reason the path is exported at all: the platform
proxies this route, and aai-server’s GUEST_ROUTE_EXPOSURE has to name the
verbs the guest answers. A hardcoded "GET" on that side would be a second
source of truth for a one-word fact, which is the shape that rots — see
WORKFLOW_API_METHODS on @alexkroman1/aai-runtime for the same rule on the
workflow route, where it has already cost two incidents.
CLIENT_CONFIG_PATH
Section titled “CLIENT_CONFIG_PATH”
constCLIENT_CONFIG_PATH:"client-config"="client-config"
Relative path of the client-config endpoint under an agent’s base URL.
EVENT_ID_PREFIX
Section titled “EVENT_ID_PREFIX”
constEVENT_ID_PREFIX:"evt_"="evt_"
The prefix every session-event id carries, so an id names its own kind.
evt_ then a ULID — see SessionEventMeta and its id field for what
the id is and is not good for. The link names the TYPE rather than the field
because the type is z.inferred, so TypeDoc documents it as an anonymous
object and has no anchor to point a member link at.
HostConfigMessageSchema
Section titled “HostConfigMessageSchema”
constHostConfigMessageSchema:z.ZodObject<{audioFormat:z.ZodOptional<z.ZodEnum<{pcm16:"pcm16"; }>>;host:z.ZodObject<{audioLeadMs:z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber,z.ZodNull]>>;credentials:z.ZodOptional<z.ZodRecord<z.ZodString,z.ZodString>>;greeting:z.ZodOptional<z.ZodString>;sttPrompt:z.ZodOptional<z.ZodString>;systemPrompt:z.ZodString;tools:z.ZodArray<z.ZodObject<{description:z.ZodString;messages:z.ZodOptional<z.ZodObject<{complete:z.ZodOptional<…>;delayed:z.ZodOptional<…>;failed:z.ZodOptional<…>;start:z.ZodOptional<…>; },z.core.$strip>>;name:z.ZodString;parameters:z.ZodRecord<z.ZodString,z.ZodUnknown>;type:z.ZodLiteral<"function">; },z.core.$strip>>; },z.core.$strip>;sampleRate:z.ZodOptional<z.ZodNumber>;ttsSampleRate:z.ZodOptional<z.ZodNumber>;type:z.ZodLiteral<"config">; },z.core.$strip>
The host-mode handshake frame: the first inbound message on a host-mode WebSocket connection, carrying the HostConfigSchema payload.
A host-mode client sends a single config frame that also carries the
audio negotiation fields (audioFormat/sampleRate/ttsSampleRate)
alongside host; they are captured here (optional) so the host-mode
handshake can honor the client’s requested sample rates instead of
discarding them.
HostConfigSchema
Section titled “HostConfigSchema”
constHostConfigSchema:z.ZodObject<{audioLeadMs:z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber,z.ZodNull]>>;credentials:z.ZodOptional<z.ZodRecord<z.ZodString,z.ZodString>>;greeting:z.ZodOptional<z.ZodString>;sttPrompt:z.ZodOptional<z.ZodString>;systemPrompt:z.ZodString;tools:z.ZodArray<z.ZodObject<{description:z.ZodString;messages:z.ZodOptional<z.ZodObject<{complete:z.ZodOptional<z.ZodArray<z.ZodObject<…, …>>>;delayed:z.ZodOptional<z.ZodArray<z.ZodObject<…, …>>>;failed:z.ZodOptional<z.ZodArray<z.ZodObject<…, …>>>;start:z.ZodOptional<z.ZodArray<z.ZodObject<…, …>>>; },z.core.$strip>>;name:z.ZodString;parameters:z.ZodRecord<z.ZodString,z.ZodUnknown>;type:z.ZodLiteral<"function">; },z.core.$strip>>; },z.core.$strip>
Host-provided agent configuration for a host-mode connection: the caller (e.g. an external evaluation harness) supplies the system prompt, optional greeting, and tool schemas for a single session instead of using a deployed agent.
Validated standalone rather than as a SessionCommandSchema member — the
host-mode handshake consumes this message before wireSessionSocket
attaches, so it must never reach dispatchMessage/SessionCommandSchema.
ReadyConfigSchema
Section titled “ReadyConfigSchema”
constReadyConfigSchema:z.ZodObject<{audioFormat:z.ZodEnum<{pcm16:"pcm16"; }>;sampleRate:z.ZodNumber;ttsSampleRate:z.ZodNumber; },z.core.$strip>
Zod schema for ReadyConfig.
RestoredToolCallSchema
Section titled “RestoredToolCallSchema”
constRestoredToolCallSchema:z.ZodObject<{afterMessageIndex:z.ZodNumber;args:z.ZodRecord<z.ZodString,z.ZodUnknown>;callId:z.ZodString;name:z.ZodString;result:z.ZodOptional<z.ZodString>;status:z.ZodEnum<{done:"done";pending:"pending"; }>; },z.core.$strip>
One tool call as a RESUME reports it — see history.restored.
Its own schema because the host builds these (historyFromEvents) and the
client reads them, so the shape wants one name on both sides. It is deliberately
NOT tool.called plus tool.completed: those are two live events, and what a
restore sends is their settled JOIN.
SESSION_COMMAND_TYPES
Section titled “SESSION_COMMAND_TYPES”
constSESSION_COMMAND_TYPES:ReadonlySet<string>
The set of recognised client→server command type values — pass to
lenientParse so a known-but-invalid message warns instead of being
silently dropped as an unknown forward-compat type.
SESSION_EVENT_TYPES
Section titled “SESSION_EVENT_TYPES”
constSESSION_EVENT_TYPES:ReadonlySet<string>
Every event name, as a set — for lenientParse’s known-types argument.
SessionCommandSchema
Section titled “SessionCommandSchema”
constSessionCommandSchema:z.ZodDiscriminatedUnion<[z.ZodObject<{type:z.ZodLiteral<"audio_ready">; },z.core.$strip>,z.ZodObject<{type:z.ZodLiteral<"cancel">; },z.core.$strip>,z.ZodObject<{type:z.ZodLiteral<"reset">; },z.core.$strip>,z.ZodObject<{type:z.ZodLiteral<"user_turn_start">; },z.core.$strip>,z.ZodObject<{type:z.ZodLiteral<"user_turn_commit">; },z.core.$strip>,z.ZodObject<{type:z.ZodLiteral<"user_turn_clear">; },z.core.$strip>,z.ZodObject<{bufferedMs:z.ZodNumber;type:z.ZodLiteral<"playback_progress">; },z.core.$strip>,z.ZodObject<{error:z.ZodOptional<z.ZodString>;result:z.ZodPipe<z.ZodString,z.ZodTransform<string,string>>;toolCallId:z.ZodString;type:z.ZodLiteral<"tool_result">; },z.core.$strip>],"type">
Zod schema for SessionCommand.
SessionErrorCodeSchema
Section titled “SessionErrorCodeSchema”
constSessionErrorCodeSchema:z.ZodEnum<{audio:"audio";connection:"connection";internal:"internal";llm:"llm";protocol:"protocol";stt:"stt";tool:"tool";tts:"tts"; }>
Zod schema for session error codes.
SessionEventMetaSchema
Section titled “SessionEventMetaSchema”
constSessionEventMetaSchema:z.ZodObject<{at:z.ZodNumber;id:z.ZodString; },z.core.$strip>
Zod schema for SessionEventMeta.
References
Section titled “References”ClientConfigResponse
Section titled “ClientConfigResponse”Re-exports ClientConfigResponse
ClientConfigResponseSchema
Section titled “ClientConfigResponseSchema”Re-exports ClientConfigResponseSchema