From 58db38e0883e969bb6e5a3271bbf3abc9172ec92 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 30 May 2026 16:34:24 -0400 Subject: [PATCH] fix(voice-call): clamp telephony tts timeout --- .../voice-call/src/telephony-tts.test.ts | 18 ++++++++++++++++++ extensions/voice-call/src/telephony-tts.ts | 7 +++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/extensions/voice-call/src/telephony-tts.test.ts b/extensions/voice-call/src/telephony-tts.test.ts index cb435b5c059..75313b6ff4d 100644 --- a/extensions/voice-call/src/telephony-tts.test.ts +++ b/extensions/voice-call/src/telephony-tts.test.ts @@ -1,3 +1,4 @@ +import { MAX_TIMER_TIMEOUT_MS } from "openclaw/plugin-sdk/number-runtime"; import { afterEach, describe, expect, it, vi } from "vitest"; import type { VoiceCallTtsConfig } from "./config.js"; import type { CoreConfig } from "./core-bridge.js"; @@ -179,6 +180,23 @@ describe("createTelephonyTtsProvider deepMerge hardening", () => { expect(provider.synthesisTimeoutMs).toBe(15000); }); + it("clamps oversized configured timeoutMs", () => { + const provider = createTelephonyTtsProvider({ + coreConfig: { + messages: { tts: { provider: "openai", timeoutMs: Number.MAX_SAFE_INTEGER } }, + }, + runtime: { + textToSpeechTelephony: async () => ({ + success: true, + audioBuffer: Buffer.alloc(2), + sampleRate: 8000, + }), + }, + }); + + expect(provider.synthesisTimeoutMs).toBe(MAX_TIMER_TIMEOUT_MS); + }); + it("keeps the telephony timeout default when timeoutMs is not configured", () => { const provider = createTelephonyTtsProvider({ coreConfig: createCoreConfig(), diff --git a/extensions/voice-call/src/telephony-tts.ts b/extensions/voice-call/src/telephony-tts.ts index 4d7a8ed1f42..6302914429d 100644 --- a/extensions/voice-call/src/telephony-tts.ts +++ b/extensions/voice-call/src/telephony-tts.ts @@ -1,3 +1,4 @@ +import { resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime"; import { parseTtsDirectives, type SpeechModelOverridePolicy, @@ -60,8 +61,10 @@ export function createTelephonyTtsProvider(params: { ); const providerConfigs = collectTelephonyProviderConfigs(ttsConfig); const activeProvider = normalizeProviderId(ttsConfig?.provider); - const synthesisTimeoutMs = - mergedConfig.messages?.tts?.timeoutMs ?? TELEPHONY_DEFAULT_TTS_TIMEOUT_MS; + const synthesisTimeoutMs = resolveTimerTimeoutMs( + mergedConfig.messages?.tts?.timeoutMs, + TELEPHONY_DEFAULT_TTS_TIMEOUT_MS, + ); return { synthesisTimeoutMs,