diff --git a/CHANGELOG.md b/CHANGELOG.md index 8325adf2894..1d82c2d4389 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,9 @@ Docs: https://docs.openclaw.ai - Plugins/startup: remove ownerless bundled runtime-dependency install locks after a short grace window and include lock owner details when startup times out waiting for a plugin runtime-deps lock. Thanks @steipete. +- Live tests/voice: accept common STT variants for OpenClaw and ElevenLabs + brand names so provider smoke tests fail on real regressions rather than + equivalent transcripts. - Agents/replies: forward sanitized underlying agent failure details on external channels instead of replacing unknown failures with a generic retry message. Thanks @steipete. diff --git a/extensions/elevenlabs/elevenlabs.live.test.ts b/extensions/elevenlabs/elevenlabs.live.test.ts index 49267bfbe66..bbcdfcd6606 100644 --- a/extensions/elevenlabs/elevenlabs.live.test.ts +++ b/extensions/elevenlabs/elevenlabs.live.test.ts @@ -61,7 +61,7 @@ describeLive("elevenlabs plugin live", () => { const normalized = normalizeTranscriptForMatch(transcript?.text ?? ""); expect(normalized).toContain("openclaw"); - expect(normalized).toContain("elevenlabs"); + expect(normalized).toMatch(/(?:elevenlabs|11labs)/); }, 90_000); it("streams realtime STT through the registered transcription provider", async () => { diff --git a/test/helpers/stt-live-audio.test.ts b/test/helpers/stt-live-audio.test.ts new file mode 100644 index 00000000000..5c7484711fd --- /dev/null +++ b/test/helpers/stt-live-audio.test.ts @@ -0,0 +1,11 @@ +import { describe, expect, it } from "vitest"; +import { normalizeTranscriptForMatch } from "./stt-live-audio.js"; + +describe("normalizeTranscriptForMatch", () => { + it("normalizes punctuation and common OpenClaw live transcription variants", () => { + expect(normalizeTranscriptForMatch("Open-Claw integration OK")).toBe("openclawintegrationok"); + expect(normalizeTranscriptForMatch("Testing OpenFlaw realtime transcription")).toMatch( + /open(?:claw|flaw)/, + ); + }); +}); diff --git a/test/helpers/stt-live-audio.ts b/test/helpers/stt-live-audio.ts index e9c87d13a76..646d104ec8b 100644 --- a/test/helpers/stt-live-audio.ts +++ b/test/helpers/stt-live-audio.ts @@ -12,6 +12,10 @@ export function normalizeTranscriptForMatch(value: string): string { return value.toLowerCase().replace(/[^a-z0-9]+/g, ""); } +type ExpectedTranscriptMatch = RegExp | string; + +const DEFAULT_OPENCLAW_TRANSCRIPT_MATCH = /open(?:claw|flaw)/; + export async function waitForLiveExpectation(expectation: () => void, timeoutMs = 30_000) { const started = Date.now(); let lastError: unknown; @@ -86,7 +90,7 @@ export async function runRealtimeSttLiveTest(params: { provider: RealtimeTranscriptionProviderPlugin; providerConfig: RealtimeTranscriptionProviderConfig; audio: Buffer; - expectedNormalizedText?: string; + expectedNormalizedText?: ExpectedTranscriptMatch; timeoutMs?: number; closeBeforeWait?: boolean; chunkSize?: number; @@ -95,7 +99,7 @@ export async function runRealtimeSttLiveTest(params: { const transcripts: string[] = []; const partials: string[] = []; const errors: Error[] = []; - const expected = params.expectedNormalizedText ?? "openclaw"; + const expected = params.expectedNormalizedText ?? DEFAULT_OPENCLAW_TRANSCRIPT_MATCH; const session = params.provider.createSession({ providerConfig: params.providerConfig, onPartial: (partial) => partials.push(partial), @@ -119,7 +123,12 @@ export async function runRealtimeSttLiveTest(params: { if (errors[0]) { throw errors[0]; } - expect(normalizeTranscriptForMatch(transcripts.join(" "))).toContain(expected); + const normalized = normalizeTranscriptForMatch(transcripts.join(" ")); + if (typeof expected === "string") { + expect(normalized).toContain(expected); + } else { + expect(normalized).toMatch(expected); + } }, params.timeoutMs ?? 60_000); } finally { session.close();