From a77d2c142c3eefcc255b36ae0b92849259abbaf1 Mon Sep 17 00:00:00 2001 From: Colin Date: Thu, 7 May 2026 21:00:20 -0400 Subject: [PATCH] fix: address realtime voice review feedback --- src/gateway/server-methods/talk-shared.ts | 37 +++++++++++++++++-- src/gateway/server-methods/talk.test.ts | 6 ++- ui/src/ui/chat/realtime-talk-gateway-relay.ts | 2 +- ui/src/ui/realtime-talk-gateway-relay.test.ts | 3 +- 4 files changed, 41 insertions(+), 7 deletions(-) diff --git a/src/gateway/server-methods/talk-shared.ts b/src/gateway/server-methods/talk-shared.ts index 0f4c7b709e7c..91f0f0466c54 100644 --- a/src/gateway/server-methods/talk-shared.ts +++ b/src/gateway/server-methods/talk-shared.ts @@ -243,10 +243,11 @@ export function buildRealtimeVoiceLaunchOptions(params: { requested: RealtimeVoiceLaunchOptionInput; defaults: RealtimeVoiceLaunchOptions; }): RealtimeVoiceLaunchOptions { - return withRealtimeBrowserOverrides( - params.defaults, - params.requested, - ) as RealtimeVoiceLaunchOptions; + const options = pickRealtimeVoiceLaunchOptions(params.defaults); + return { + ...options, + ...pickRealtimeVoiceLaunchOptions(params.requested), + }; } export function withRealtimeBrowserOverrides( @@ -278,6 +279,34 @@ export function withRealtimeBrowserOverrides( return Object.keys(overrides).length > 0 ? { ...providerConfig, ...overrides } : providerConfig; } +function pickRealtimeVoiceLaunchOptions( + params: RealtimeVoiceLaunchOptionInput, +): RealtimeVoiceLaunchOptions { + const options: RealtimeVoiceLaunchOptions = {}; + const model = normalizeOptionalString(params.model); + const voice = normalizeOptionalString(params.voice); + const reasoningEffort = normalizeOptionalString(params.reasoningEffort); + if (model) { + options.model = model; + } + if (voice) { + options.voice = voice; + } + if (typeof params.vadThreshold === "number" && Number.isFinite(params.vadThreshold)) { + options.vadThreshold = params.vadThreshold; + } + if (typeof params.silenceDurationMs === "number" && Number.isFinite(params.silenceDurationMs)) { + options.silenceDurationMs = params.silenceDurationMs; + } + if (typeof params.prefixPaddingMs === "number" && Number.isFinite(params.prefixPaddingMs)) { + options.prefixPaddingMs = params.prefixPaddingMs; + } + if (reasoningEffort) { + options.reasoningEffort = reasoningEffort; + } + return options; +} + export function isUnsupportedBrowserWebRtcSession(session: RealtimeVoiceBrowserSession): boolean { const provider = normalizeLowercaseStringOrEmpty(session.provider); const transport = (session as { transport?: string }).transport ?? "webrtc"; diff --git a/src/gateway/server-methods/talk.test.ts b/src/gateway/server-methods/talk.test.ts index d5d28caa0a4e..29de4ebe4d20 100644 --- a/src/gateway/server-methods/talk.test.ts +++ b/src/gateway/server-methods/talk.test.ts @@ -1199,7 +1199,7 @@ describe("talk.client.create handler", () => { }); it("uses talk.realtime provider, model, voice, and instructions without reading speech provider config", async () => { - const createBrowserSession = vi.fn(async () => ({ + const createBrowserSession = vi.fn(async (_input: unknown) => ({ provider: "openai", transport: "webrtc" as const, clientSecret: "secret", @@ -1264,6 +1264,10 @@ describe("talk.client.create handler", () => { reasoningEffort: "low", }), ); + const createInput = createBrowserSession.mock.calls[0]?.[0] as Record; + expect(createInput).not.toHaveProperty("provider"); + expect(createInput).not.toHaveProperty("providers"); + expect(createInput).not.toHaveProperty("transport"); expect(respond).toHaveBeenCalledWith( true, expect.objectContaining({ provider: "openai", transport: "webrtc" }), diff --git a/ui/src/ui/chat/realtime-talk-gateway-relay.ts b/ui/src/ui/chat/realtime-talk-gateway-relay.ts index 00f8b252a6ca..55076685877d 100644 --- a/ui/src/ui/chat/realtime-talk-gateway-relay.ts +++ b/ui/src/ui/chat/realtime-talk-gateway-relay.ts @@ -142,7 +142,7 @@ export class GatewayRelayRealtimeTalkTransport implements RealtimeTalkTransport "error", error instanceof Error ? error.message : String(error), ); - this.stopLocal(); + this.stop(); } }); }; diff --git a/ui/src/ui/realtime-talk-gateway-relay.test.ts b/ui/src/ui/realtime-talk-gateway-relay.test.ts index f434c60f4378..1c346115cc89 100644 --- a/ui/src/ui/realtime-talk-gateway-relay.test.ts +++ b/ui/src/ui/realtime-talk-gateway-relay.test.ts @@ -247,7 +247,8 @@ describe("GatewayRelayRealtimeTalkTransport", () => { .mocked(client.request) .mock.calls.filter(([method]) => method === "talk.session.close"); expect(appendCalls).toHaveLength(1); - expect(closeCalls).toHaveLength(0); + expect(closeCalls).toHaveLength(1); + expect(closeCalls[0]?.[1]).toEqual({ sessionId: "relay-1" }); }); it("treats relay close events as local shutdown", async () => {