


























@@ -87,6 +87,19 @@ type SentRealtimeEvent = {
8787turn_detection?: {
8888create_response?: boolean;
8989};
90+output_modalities?: string[];
91+audio?: {
92+input?: {
93+format?: Record<string, unknown>;
94+turn_detection?: {
95+create_response?: boolean;
96+interrupt_response?: boolean;
97+};
98+};
99+output?: {
100+format?: Record<string, unknown>;
101+};
102+};
90103};
91104};
92105@@ -117,6 +130,7 @@ describe("buildOpenAIRealtimeVoiceProvider", () => {
117130it("declares realtime Talk capabilities for catalog selection", () => {
118131const provider = buildOpenAIRealtimeVoiceProvider();
119132133+expect(provider.defaultModel).toBe("gpt-realtime-2");
120134expect(provider.capabilities).toEqual({
121135transports: ["webrtc", "gateway-relay"],
122136inputAudioFormats: [
@@ -152,6 +166,35 @@ describe("buildOpenAIRealtimeVoiceProvider", () => {
152166version: "2026.3.22",
153167"User-Agent": "openclaw/2026.3.22",
154168});
169+expect(options?.headers).not.toHaveProperty("OpenAI-Beta");
170+});
171+172+it("keeps Azure deployment realtime bridge requests on the deployment-compatible session shape", () => {
173+const provider = buildOpenAIRealtimeVoiceProvider();
174+const bridge = provider.createBridge({
175+providerConfig: {
176+apiKey: "sk-test", // pragma: allowlist secret
177+azureEndpoint: "https://example.openai.azure.com",
178+azureDeployment: "realtime-prod",
179+},
180+onAudio: vi.fn(),
181+onClearAudio: vi.fn(),
182+});
183+184+void bridge.connect();
185+const socket = FakeWebSocket.instances[0];
186+if (!socket) {
187+throw new Error("expected bridge to create a websocket");
188+}
189+socket.readyState = FakeWebSocket.OPEN;
190+socket.emit("open");
191+bridge.close();
192+193+expect(parseSent(socket)[0]?.session).toMatchObject({
194+modalities: ["text", "audio"],
195+input_audio_format: "g711_ulaw",
196+output_audio_format: "g711_ulaw",
197+});
155198});
156199157200it("returns browser-safe OpenClaw attribution headers for native WebRTC offers", async () => {
@@ -193,6 +236,7 @@ describe("buildOpenAIRealtimeVoiceProvider", () => {
193236| undefined;
194237const body = JSON.parse(request?.init?.body ?? "{}") as {
195238session?: {
239+model?: string;
196240audio?: {
197241input?: {
198242turn_detection?: Record<string, unknown>;
@@ -201,6 +245,7 @@ describe("buildOpenAIRealtimeVoiceProvider", () => {
201245};
202246};
203247};
248+expect(body.session?.model).toBe("gpt-realtime-2");
204249expect(body.session?.audio?.input).toEqual({
205250turn_detection: {
206251type: "server_vad",
@@ -214,6 +259,7 @@ describe("buildOpenAIRealtimeVoiceProvider", () => {
214259transport: "webrtc",
215260clientSecret: "client-secret-123",
216261offerUrl: "https://api.openai.com/v1/realtime/calls",
262+model: "gpt-realtime-2",
217263});
218264// originator, version, and User-Agent are server-side attribution headers; they
219265// must not be forwarded to the browser so that the browser's direct SDP POST to
@@ -320,7 +366,7 @@ describe("buildOpenAIRealtimeVoiceProvider", () => {
320366rawConfig: {
321367providers: {
322368openai: {
323-model: "gpt-realtime-1.5",
369+model: "gpt-realtime-2",
324370voice: "verse",
325371temperature: 0.6,
326372silenceDurationMs: 850,
@@ -331,7 +377,7 @@ describe("buildOpenAIRealtimeVoiceProvider", () => {
331377});
332378333379expect(resolved).toEqual({
334-model: "gpt-realtime-1.5",
380+model: "gpt-realtime-2",
335381voice: "verse",
336382temperature: 0.6,
337383silenceDurationMs: 850,
@@ -370,9 +416,20 @@ describe("buildOpenAIRealtimeVoiceProvider", () => {
370416expect(onReady).not.toHaveBeenCalled();
371417expect(parseSent(socket).map((event) => event.type)).toEqual(["session.update"]);
372418expect(parseSent(socket)[0]?.session).toMatchObject({
373-input_audio_format: "g711_ulaw",
374-output_audio_format: "g711_ulaw",
419+type: "realtime",
420+model: "gpt-realtime-2",
421+output_modalities: ["audio"],
422+audio: {
423+input: {
424+format: { type: "audio/pcmu" },
425+transcription: { model: "whisper-1" },
426+},
427+output: {
428+format: { type: "audio/pcmu" },
429+},
430+},
375431});
432+expect(parseSent(socket)[0]?.session).not.toHaveProperty("temperature");
376433expect(bridge.isConnected()).toBe(false);
377434378435socket.emit("message", Buffer.from(JSON.stringify({ type: "session.updated" })));
@@ -457,9 +514,14 @@ describe("buildOpenAIRealtimeVoiceProvider", () => {
457514await connecting;
458515459516expect(parseSent(socket)[0]?.session).toMatchObject({
460-turn_detection: expect.objectContaining({
461-create_response: false,
462-}),
517+audio: {
518+input: {
519+turn_detection: expect.objectContaining({
520+create_response: false,
521+interrupt_response: false,
522+}),
523+},
524+},
463525});
464526});
465527@@ -532,8 +594,14 @@ describe("buildOpenAIRealtimeVoiceProvider", () => {
532594await connecting;
533595534596expect(parseSent(socket)[0]?.session).toMatchObject({
535-input_audio_format: "pcm16",
536-output_audio_format: "pcm16",
597+audio: {
598+input: {
599+format: { type: "audio/pcm", rate: 24000 },
600+},
601+output: {
602+format: { type: "audio/pcm", rate: 24000 },
603+},
604+},
537605});
538606});
539607此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。