diff --git a/CHANGELOG.md b/CHANGELOG.md index 64c92a26f11..dd68d02d47c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,7 @@ Docs: https://docs.openclaw.ai - Google Meet: stop advertising legacy `mode: "realtime"` to agents and config UIs, while keeping it as a hidden compatibility alias for `mode: "agent"`, so new joins use the STT -> OpenClaw agent -> TTS path instead of selecting the direct realtime voice fallback. - Google Meet: add `chrome.audioBufferBytes` for generated command-pair SoX audio commands and lower the default buffer from SoX's 8192 bytes to 4096 bytes to reduce Chrome talk-back latency. - Google Meet: split realtime provider config into agent-mode transcription and bidi-mode voice providers, and migrate legacy Gemini Live bidi configs with `doctor --fix`, so Gemini Live can back direct bidi fallback without breaking the default OpenClaw agent talk-back path. +- Google Meet: expose `voiceCall.postDtmfSpeechDelayMs` in the plugin manifest schema and setup hints, so manifest-based config editing accepts the runtime-supported Twilio delay key. Thanks @vincentkoc. - Telegram: render shared interactive reply buttons in reply delivery so plugin approval messages show inline keyboards. (#76238) Thanks @keshavbotagent. - Agents/cli-runner: drop a saved `claude-cli` resume sessionId at preparation time when its on-disk transcript no longer exists in `~/.claude/projects/`, so a stale binding from a half-installed `update.run` cannot trap follow-up runs (auto-reply / Telegram direct) in a `claude --resume` timeout loop; the run starts fresh and the new sessionId is written back through the existing post-run flow. (#77030; refs #77011) Thanks @openperf. - Release validation: install the cross-OS TypeScript harness through Windows-safe Node/npm shims so native Windows package checks reach the OpenClaw smoke suites instead of exiting before artifact capture. Thanks @vincentkoc. diff --git a/extensions/google-meet/index.test.ts b/extensions/google-meet/index.test.ts index 87fba57c8d8..fd62355bc01 100644 --- a/extensions/google-meet/index.test.ts +++ b/extensions/google-meet/index.test.ts @@ -4,6 +4,7 @@ import { tmpdir } from "node:os"; import path from "node:path"; import { PassThrough, Writable } from "node:stream"; import { createContext, Script } from "node:vm"; +import { validateJsonSchemaValue, type JsonSchemaObject } from "openclaw/plugin-sdk/config-schema"; import type { RealtimeTranscriptionProviderPlugin } from "openclaw/plugin-sdk/realtime-transcription"; import type { RealtimeVoiceProviderPlugin } from "openclaw/plugin-sdk/realtime-voice"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; @@ -479,17 +480,13 @@ describe("google-meet plugin", () => { }); }); - it("declares barge-in config metadata in the plugin entry and manifest", () => { + it("declares advanced config metadata in the plugin entry and manifest", () => { const manifest = JSON.parse( readFileSync(new URL("./openclaw.plugin.json", import.meta.url), "utf8"), ) as { uiHints?: Record; - configSchema?: { - properties?: { - chrome?: { - properties?: Record; - }; - }; + configSchema?: JsonSchemaObject & { + properties?: Record }>; }; }; const entry = plugin as unknown as { @@ -504,6 +501,7 @@ describe("google-meet plugin", () => { "chrome.bargeInRmsThreshold": expect.objectContaining({ advanced: true }), "chrome.bargeInPeakThreshold": expect.objectContaining({ advanced: true }), "chrome.bargeInCooldownMs": expect.objectContaining({ advanced: true }), + "voiceCall.postDtmfSpeechDelayMs": expect.objectContaining({ advanced: true }), }); expect(manifest.uiHints).toMatchObject({ "chrome.audioBufferBytes": expect.objectContaining({ advanced: true }), @@ -511,6 +509,7 @@ describe("google-meet plugin", () => { "chrome.bargeInRmsThreshold": expect.objectContaining({ advanced: true }), "chrome.bargeInPeakThreshold": expect.objectContaining({ advanced: true }), "chrome.bargeInCooldownMs": expect.objectContaining({ advanced: true }), + "voiceCall.postDtmfSpeechDelayMs": expect.objectContaining({ advanced: true }), }); expect(manifest.configSchema?.properties?.chrome?.properties).toMatchObject({ audioBufferBytes: expect.objectContaining({ type: "number", default: 4096 }), @@ -522,6 +521,19 @@ describe("google-meet plugin", () => { bargeInPeakThreshold: expect.objectContaining({ type: "number", default: 2500 }), bargeInCooldownMs: expect.objectContaining({ type: "number", default: 900 }), }); + expect(manifest.configSchema?.properties?.voiceCall?.properties).toMatchObject({ + postDtmfSpeechDelayMs: expect.objectContaining({ type: "number", default: 5000 }), + }); + const result = validateJsonSchemaValue({ + schema: manifest.configSchema!, + cacheKey: "google-meet.manifest.voice-call-post-dtmf-speech-delay", + value: { + voiceCall: { + postDtmfSpeechDelayMs: 750, + }, + }, + }); + expect(result.ok).toBe(true); }); it("resolves the realtime consult agent id", () => { diff --git a/extensions/google-meet/openclaw.plugin.json b/extensions/google-meet/openclaw.plugin.json index b909b035a6d..554c539007f 100644 --- a/extensions/google-meet/openclaw.plugin.json +++ b/extensions/google-meet/openclaw.plugin.json @@ -144,6 +144,11 @@ "help": "Compatibility setting from the old post-connect DTMF flow. Twilio Meet joins now play DTMF before realtime connect.", "advanced": true }, + "voiceCall.postDtmfSpeechDelayMs": { + "label": "Legacy Post-DTMF Speech Delay (ms)", + "help": "Compatibility setting from the old delayed-speech flow. Twilio Meet joins now carry the intro as the initial Voice Call message.", + "advanced": true + }, "voiceCall.introMessage": { "label": "Voice Call Intro Message", "advanced": true @@ -421,6 +426,10 @@ "type": "number", "default": 2500 }, + "postDtmfSpeechDelayMs": { + "type": "number", + "default": 5000 + }, "introMessage": { "type": "string" }