mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 06:50:43 +00:00
fix(google-meet): avoid duplicate test speech
This commit is contained in:
@@ -24,7 +24,7 @@ import {
|
||||
import { handleGoogleMeetNodeHostCommand } from "./src/node-host.js";
|
||||
import { startNodeRealtimeAudioBridge } from "./src/realtime-node.js";
|
||||
import { startCommandRealtimeAudioBridge } from "./src/realtime.js";
|
||||
import { normalizeMeetUrl } from "./src/runtime.js";
|
||||
import { GoogleMeetRuntime, normalizeMeetUrl } from "./src/runtime.js";
|
||||
import {
|
||||
invokeGoogleMeetGatewayMethodForTest,
|
||||
noopLogger,
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
} from "./src/test-support/plugin-harness.js";
|
||||
import { __testing as chromeTransportTesting } from "./src/transports/chrome.js";
|
||||
import { buildMeetDtmfSequence, normalizeDialInNumber } from "./src/transports/twilio.js";
|
||||
import type { GoogleMeetSession } from "./src/transports/types.js";
|
||||
|
||||
const voiceCallMocks = vi.hoisted(() => ({
|
||||
joinMeetViaVoiceCallGateway: vi.fn(async () => ({ callId: "call-1", dtmfSent: true })),
|
||||
@@ -1837,6 +1838,39 @@ describe("google-meet plugin", () => {
|
||||
expect(result.details).toMatchObject({ createdSession: true });
|
||||
});
|
||||
|
||||
it("does not start a second realtime response for test speech", async () => {
|
||||
const runtime = new GoogleMeetRuntime({
|
||||
config: resolveGoogleMeetConfig({}),
|
||||
fullConfig: {} as never,
|
||||
runtime: {} as never,
|
||||
logger: noopLogger,
|
||||
});
|
||||
const session: GoogleMeetSession = {
|
||||
id: "meet_1",
|
||||
url: "https://meet.google.com/abc-defg-hij",
|
||||
transport: "chrome",
|
||||
mode: "realtime",
|
||||
state: "active",
|
||||
createdAt: "2026-04-27T00:00:00.000Z",
|
||||
updatedAt: "2026-04-27T00:00:00.000Z",
|
||||
participantIdentity: "signed-in Google Chrome profile",
|
||||
realtime: { enabled: true, provider: "openai", toolPolicy: "safe-read-only" },
|
||||
chrome: { audioBackend: "blackhole-2ch", launched: true },
|
||||
notes: [],
|
||||
};
|
||||
const join = vi.spyOn(runtime, "join").mockResolvedValue({ session, spoken: true });
|
||||
const speak = vi.spyOn(runtime, "speak");
|
||||
|
||||
const result = await runtime.testSpeech({
|
||||
url: "https://meet.google.com/abc-defg-hij",
|
||||
message: "Say exactly: hello.",
|
||||
});
|
||||
|
||||
expect(join).toHaveBeenCalledWith(expect.objectContaining({ message: "Say exactly: hello." }));
|
||||
expect(speak).not.toHaveBeenCalled();
|
||||
expect(result.spoken).toBe(true);
|
||||
});
|
||||
|
||||
it("reports manual action when the browser profile needs Google login", async () => {
|
||||
const { tools } = setup(
|
||||
{
|
||||
|
||||
@@ -212,16 +212,18 @@ export class GoogleMeetRuntime {
|
||||
session.transport === transport &&
|
||||
session.mode === mode,
|
||||
);
|
||||
const speechInstructions = request.message ?? this.params.config.realtime.introMessage;
|
||||
if (reusable) {
|
||||
reusable.notes = [
|
||||
...reusable.notes.filter((note) => note !== "Reused existing active Meet session."),
|
||||
"Reused existing active Meet session.",
|
||||
];
|
||||
reusable.updatedAt = nowIso();
|
||||
if (request.message || this.params.config.realtime.introMessage) {
|
||||
this.speak(reusable.id, request.message);
|
||||
}
|
||||
return { session: reusable };
|
||||
const spoken =
|
||||
mode === "realtime" && speechInstructions
|
||||
? this.speak(reusable.id, speechInstructions).spoken
|
||||
: false;
|
||||
return { session: reusable, spoken };
|
||||
}
|
||||
const createdAt = nowIso();
|
||||
|
||||
@@ -347,10 +349,11 @@ export class GoogleMeetRuntime {
|
||||
}
|
||||
|
||||
this.#sessions.set(session.id, session);
|
||||
if (mode === "realtime" && this.params.config.realtime.introMessage) {
|
||||
this.speak(session.id, request.message);
|
||||
}
|
||||
return { session };
|
||||
const spoken =
|
||||
mode === "realtime" && speechInstructions
|
||||
? this.speak(session.id, speechInstructions).spoken
|
||||
: false;
|
||||
return { session, spoken };
|
||||
}
|
||||
|
||||
async leave(sessionId: string): Promise<{ found: boolean; session?: GoogleMeetSession }> {
|
||||
@@ -398,11 +401,10 @@ export class GoogleMeetRuntime {
|
||||
session: GoogleMeetSession;
|
||||
}> {
|
||||
const before = new Set(this.list().map((session) => session.id));
|
||||
const result = await this.join(request);
|
||||
const spoken = this.speak(
|
||||
result.session.id,
|
||||
request.message ?? "Say exactly: Google Meet speech test complete.",
|
||||
).spoken;
|
||||
const result = await this.join({
|
||||
...request,
|
||||
message: request.message ?? "Say exactly: Google Meet speech test complete.",
|
||||
});
|
||||
const health = result.session.chrome?.health;
|
||||
return {
|
||||
createdSession: !before.has(result.session.id),
|
||||
@@ -410,7 +412,7 @@ export class GoogleMeetRuntime {
|
||||
manualActionRequired: health?.manualActionRequired,
|
||||
manualActionReason: health?.manualActionReason,
|
||||
manualActionMessage: health?.manualActionMessage,
|
||||
spoken,
|
||||
spoken: result.spoken ?? false,
|
||||
session: result.session,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -83,4 +83,5 @@ export type GoogleMeetSession = {
|
||||
|
||||
export type GoogleMeetJoinResult = {
|
||||
session: GoogleMeetSession;
|
||||
spoken?: boolean;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user