/** * Wire contract between a browser client and our realtime WS relay. * * This vocabulary is intentionally our own, not a passthrough of any specific * provider's event schema (e.g. OpenAI Realtime's `input_audio_buffer.append`, * `response.create`, etc). Provider adapters under `$lib/server/core/providers` * translate to/from this shape, which is what keeps the client and the * session orchestrator provider-agnostic. */ export const REALTIME_WS_PATH = '/api/realtime/ws'; /** * Client-controllable subset of session config. Deliberately small: things * like `instructions`, `tools`, and `model` are server-owned (see * `$lib/server/core/session`) since this relay is shared infrastructure that * other people's browsers connect to. */ export interface SessionStartConfig { voice?: string; } export type ClientEvent = | { type: 'session.start'; config?: SessionStartConfig } | { type: 'input_audio.chunk'; audio: string } // base64-encoded PCM16 | { type: 'input_audio.commit' } | { type: 'input_text.send'; text: string } | { type: 'response.cancel' } | { type: 'tool.result'; callId: string; output: string } // Resumes the model after all outstanding tool calls in a turn are // resolved. Sent only by RealtimeSession itself (see session.ts) — never // by the browser directly, since a turn can contain multiple parallel // tool calls and only the last one resolving should trigger this. | { type: 'response.trigger' } | { type: 'session.end' }; export type RealtimeErrorCode = | 'auth_expired' | 'invalid_client_event' | 'upstream_unavailable' | 'upstream_error' | 'internal_error'; export type ServerEvent = | { type: 'session.ready'; sessionId: string } | { type: 'output_audio.chunk'; audio: string } // base64-encoded PCM16 | { type: 'output_audio.done' } | { type: 'transcript.delta'; role: 'user' | 'assistant'; text: string } | { type: 'transcript.done'; role: 'user' | 'assistant' } | { type: 'response.done' } | { type: 'tool.call'; callId: string; name: string; arguments: string } | { type: 'error'; code: RealtimeErrorCode; message: string } | { type: 'session.closed'; reason: string };