From 742e84e40f478cb4d01842dd70992f471cc1be28 Mon Sep 17 00:00:00 2001 From: Johannes Kresner Date: Wed, 8 Apr 2026 22:05:13 +0200 Subject: [PATCH] feat(vela): retire mocked.turn.trigger from shared contract --- apps/vela-gateway/src/index.js | 8 ++++++++ apps/vela-gateway/test/websocket-session.test.js | 9 +++++++++ apps/vela-protocol/src/index.cjs | 1 - apps/vela-protocol/src/index.d.ts | 1 - apps/vela-protocol/src/index.js | 1 - docs/backlog.md | 1 + docs/protocol.md | 7 +++++-- 7 files changed, 23 insertions(+), 5 deletions(-) diff --git a/apps/vela-gateway/src/index.js b/apps/vela-gateway/src/index.js index c162365..658bba0 100644 --- a/apps/vela-gateway/src/index.js +++ b/apps/vela-gateway/src/index.js @@ -206,6 +206,14 @@ function validateClientMessage(message) { return 'message must match the shared envelope shape'; } + if (message.type === 'mocked.turn.trigger') { + if (!message.payload || typeof message.payload !== 'object' || Array.isArray(message.payload)) { + return 'message payload must be an object'; + } + + return null; + } + if (!isClientEventType(message.type)) { return `unsupported client event type: ${message.type}`; } diff --git a/apps/vela-gateway/test/websocket-session.test.js b/apps/vela-gateway/test/websocket-session.test.js index c078f35..856a694 100644 --- a/apps/vela-gateway/test/websocket-session.test.js +++ b/apps/vela-gateway/test/websocket-session.test.js @@ -256,6 +256,15 @@ test('http routes stay available and preserve the root response contract', async } }); +test('shared protocol only exposes currently supported client event types', () => { + assert.deepEqual(CLIENT_EVENT_TYPES, [ + 'session.start', + 'input_audio.append', + 'input_audio.commit', + 'response.cancel' + ]); +}); + test('websocket connect creates and cleans up an ephemeral session', async () => { const server = await startServer(); diff --git a/apps/vela-protocol/src/index.cjs b/apps/vela-protocol/src/index.cjs index 1544358..3391470 100644 --- a/apps/vela-protocol/src/index.cjs +++ b/apps/vela-protocol/src/index.cjs @@ -4,7 +4,6 @@ const SESSION_STATES = Object.freeze(['idle', 'listening', 'thinking', 'speaking const CLIENT_EVENT_TYPES = Object.freeze([ 'session.start', - 'mocked.turn.trigger', 'input_audio.append', 'input_audio.commit', 'response.cancel' diff --git a/apps/vela-protocol/src/index.d.ts b/apps/vela-protocol/src/index.d.ts index e0ec333..bfdcfdc 100644 --- a/apps/vela-protocol/src/index.d.ts +++ b/apps/vela-protocol/src/index.d.ts @@ -7,7 +7,6 @@ export type MessageEnvelope = { export type ClientEventPayloads = { 'session.start': Record; - 'mocked.turn.trigger': Record; 'input_audio.append': { chunk: string; }; diff --git a/apps/vela-protocol/src/index.js b/apps/vela-protocol/src/index.js index 69263f9..b41f78e 100644 --- a/apps/vela-protocol/src/index.js +++ b/apps/vela-protocol/src/index.js @@ -4,7 +4,6 @@ export const SESSION_STATES = Object.freeze(['idle', 'listening', 'thinking', 's export const CLIENT_EVENT_TYPES = Object.freeze([ 'session.start', - 'mocked.turn.trigger', 'input_audio.append', 'input_audio.commit', 'response.cancel' diff --git a/docs/backlog.md b/docs/backlog.md index 2f11a67..54c9399 100644 --- a/docs/backlog.md +++ b/docs/backlog.md @@ -184,6 +184,7 @@ Polish the system after the core voice loop is reliable. - `apps/vela-ui` now boots as a minimal SvelteKit app with a starter page - `apps/vela-ui` now includes a minimal voice-session shell that can connect to the gateway `/ws` endpoint and display developer-visible session status - `apps/vela-ui` now exposes a visible push-to-talk mic control shell that sends placeholder `input_audio.append` / `input_audio.commit` events without requesting browser mic permission or capturing real audio +- placeholder push-to-talk via `input_audio.append` + `input_audio.commit` is now the only supported mocked turn entry path in the shared client protocol contract - `apps/vela-ui` now includes browser-level coverage for the placeholder push-to-talk mocked transcript/response slice, including connect, disconnect, and cancel behavior - `apps/vela-gateway` now boots as a minimal Fastify app with `/` and `/health` endpoints - `apps/vela-gateway` now exposes a minimal `/ws` WebSocket session skeleton with ephemeral in-memory sessions and defensive message handling diff --git a/docs/protocol.md b/docs/protocol.md index bced8ab..f6ce575 100644 --- a/docs/protocol.md +++ b/docs/protocol.md @@ -41,7 +41,6 @@ This increment intentionally keeps the envelope minimal: ```ts type ClientEvent = | { type: "session.start"; payload: {} } - | { type: "mocked.turn.trigger"; payload: {} } | { type: "input_audio.append"; payload: { chunk: string } } | { type: "input_audio.commit"; payload: {} } | { type: "response.cancel"; payload: {} }; @@ -50,11 +49,15 @@ type ClientEvent = #### Client event intent - `session.start` initializes a voice session without locking in transport or auth details yet -- `mocked.turn.trigger` is a retired legacy event name that the gateway now rejects with a deterministic recoverable error - `input_audio.append` carries a chunk of captured input audio as an encoded string - `input_audio.commit` marks the current buffered user turn as ready for downstream processing - `response.cancel` interrupts the active listen/think/speak flow +Legacy compatibility note: + +- `mocked.turn.trigger` is no longer part of the active shared client contract +- the gateway still handles raw incoming `mocked.turn.trigger` envelopes explicitly and rejects them with a deterministic recoverable error for backward compatibility + ### Current skeleton behavior - on connect, the gateway creates an ephemeral in-memory session and emits `session.ready` plus `session.state`