@spekoai/client handles encoding and decoding internally; this page documents the wire format so server / agent implementations can interoperate.
Encoding
- UTF-8 JSON, one message per
publishDatacall. - Reliable ordering (
reliable: true). - No framing beyond JSON — each
DataReceivedevent is one complete packet.
Outbound (browser → agent)
overrides
Sent once, immediately after the mic publishes, if the browser passed an overrides option.
user_message
Sent by conversation.sendUserMessage(text). Use when the user types rather than speaks.
contextual_update
Sent by conversation.sendContextualUpdate(text). Out-of-band context that shouldn’t be treated as a turn.
Inbound (agent → browser)
transcript
STT output for either speaker.
isFinal defaults to true when omitted.
agent_message
An assistant message emitted by the agent — typically streamed token-by-token as isFinal: false and closed with isFinal: true.
user_message_echo
Echo of a typed user_message so the UI can render it in the same transcript stream. isFinal is always implicitly true.
Forwarding to onMessage
The SDK converts each inbound packet into a ConversationMessage:
onError with SpekoClientError('…', 'INVALID_MESSAGE') instead.
Extending the protocol
If you need a new packet type, add it on both sides:- Agent worker publishes a new
typevalue. - Extend
InboundPacketin@spekoai/clientand handle it inpacketToMessage(or ship a wrapper that subscribes toroom.on('dataReceived')directly).
WebRTCConnection.publish(packet) accepts any OutboundPacket, which you can widen in a fork.