




















@@ -29,6 +29,8 @@ import {
2929convertGoogleMeetTtsAudioForBridge,
3030extendGoogleMeetOutputEchoSuppression,
3131isGoogleMeetLikelyAssistantEchoTranscript,
32+resolveGoogleMeetRealtimeProvider,
33+resolveGoogleMeetRealtimeTranscriptionProvider,
3234startCommandAgentAudioBridge,
3335startCommandRealtimeAudioBridge,
3436} from "./src/realtime.js";
@@ -385,6 +387,7 @@ describe("google-meet plugin", () => {
385387realtime: {
386388strategy: "agent",
387389provider: "openai",
390+transcriptionProvider: "openai",
388391introMessage: "Say exactly: I'm here and listening.",
389392toolPolicy: "safe-read-only",
390393},
@@ -395,6 +398,87 @@ describe("google-meet plugin", () => {
395398expect(resolveGoogleMeetConfig({}).realtime.instructions).toContain("openclaw_agent_consult");
396399});
397400401+it("resolves separate realtime providers for agent transcription and bidi voice", () => {
402+expect(
403+resolveGoogleMeetConfig({
404+realtime: {
405+provider: "openai",
406+transcriptionProvider: "openai",
407+voiceProvider: "google",
408+model: "gemini-2.5-flash-native-audio-preview-12-2025",
409+},
410+}).realtime,
411+).toMatchObject({
412+provider: "openai",
413+transcriptionProvider: "openai",
414+voiceProvider: "google",
415+model: "gemini-2.5-flash-native-audio-preview-12-2025",
416+});
417+});
418+419+it("uses voiceProvider for bidi and transcriptionProvider for agent mode resolution", () => {
420+const voiceProviders: RealtimeVoiceProviderPlugin[] = [
421+{
422+id: "openai",
423+label: "OpenAI",
424+autoSelectOrder: 1,
425+isConfigured: () => true,
426+createBridge: () => {
427+throw new Error("unused");
428+},
429+},
430+{
431+id: "google",
432+label: "Google",
433+autoSelectOrder: 2,
434+resolveConfig: ({ rawConfig }) => rawConfig,
435+isConfigured: () => true,
436+createBridge: () => {
437+throw new Error("unused");
438+},
439+},
440+];
441+const transcriptionProviders: RealtimeTranscriptionProviderPlugin[] = [
442+{
443+id: "openai",
444+label: "OpenAI",
445+autoSelectOrder: 1,
446+isConfigured: () => true,
447+createSession: () => {
448+throw new Error("unused");
449+},
450+},
451+];
452+const config = resolveGoogleMeetConfig({
453+realtime: {
454+provider: "openai",
455+transcriptionProvider: "openai",
456+voiceProvider: "google",
457+model: "gemini-2.5-flash-native-audio-preview-12-2025",
458+},
459+});
460+461+expect(
462+resolveGoogleMeetRealtimeProvider({
463+ config,
464+fullConfig: {} as never,
465+providers: voiceProviders,
466+}),
467+).toMatchObject({
468+provider: { id: "google" },
469+providerConfig: { model: "gemini-2.5-flash-native-audio-preview-12-2025" },
470+});
471+expect(
472+resolveGoogleMeetRealtimeTranscriptionProvider({
473+ config,
474+fullConfig: {} as never,
475+providers: transcriptionProviders,
476+}),
477+).toMatchObject({
478+provider: { id: "openai" },
479+});
480+});
481+398482it("declares barge-in config metadata in the plugin entry and manifest", () => {
399483const manifest = JSON.parse(
400484readFileSync(new URL("./openclaw.plugin.json", import.meta.url), "utf8"),
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。