diff --git a/CHANGELOG.md b/CHANGELOG.md index aac7ee61817..53ab2e5ee7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -71,6 +71,7 @@ Docs: https://docs.openclaw.ai - TUI/session isolation for `/new`: make `/new` allocate a unique `tui-` session key instead of resetting the shared agent session, so multiple TUI clients on the same agent stop receiving each other’s replies; also sanitize `/new` and `/reset` failure text before rendering in-terminal. Landed from contributor PR #39238 by @widingmarcus-cyber. Thanks @widingmarcus-cyber. - Synology Chat/rate-limit env parsing: honor `SYNOLOGY_RATE_LIMIT=0` as an explicit value while still falling back to the default limit for malformed env values instead of partially parsing them. Landed from contributor PR #39197 by @scoootscooob. Thanks @scoootscooob. - Voice-call/OpenAI Realtime STT config defaults: honor explicit `vadThreshold: 0` and `silenceDurationMs: 0` instead of silently replacing them with defaults. Landed from contributor PR #39196 by @scoootscooob. Thanks @scoootscooob. +- Voice-call/OpenAI TTS speed config: honor explicit `speed: 0` instead of silently replacing it with the default speed. Landed from contributor PR #39318 by @ql-wade. Thanks @ql-wade. - Cron/file permission hardening: enforce owner-only (`0600`) cron store/backup/run-log files and harden cron store + run-log directories to `0700`, including pre-existing directories from older installs. (#36078) Thanks @aerelune. - Gateway/remote WS break-glass hostname support: honor `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1` for `ws://` hostname URLs (not only private IP literals) across onboarding validation and runtime gateway connection checks, while still rejecting public IP literals and non-unicast IPv6 endpoints. (#36930) Thanks @manju-rn. - Routing/binding lookup scalability: pre-index route bindings by channel/account and avoid full binding-list rescans on channel-account cache rollover, preventing multi-second `resolveAgentRoute` stalls in large binding configurations. (#36915) Thanks @songchenghao. diff --git a/extensions/voice-call/src/providers/tts-openai.test.ts b/extensions/voice-call/src/providers/tts-openai.test.ts new file mode 100644 index 00000000000..cf53ca842db --- /dev/null +++ b/extensions/voice-call/src/providers/tts-openai.test.ts @@ -0,0 +1,30 @@ +import { describe, expect, it } from "vitest"; +import type { OpenAITTSConfig } from "./tts-openai.js"; +import { OpenAITTSProvider } from "./tts-openai.js"; + +type ProviderInternals = OpenAITTSProvider & { + speed: number; +}; + +function createProvider(config: OpenAITTSConfig): ProviderInternals { + return new OpenAITTSProvider(config) as ProviderInternals; +} + +describe("OpenAITTSProvider constructor defaults", () => { + it("uses speed: 0 when explicitly configured", () => { + const provider = createProvider({ + apiKey: "sk-test", + speed: 0, + }); + + expect(provider.speed).toBe(0); + }); + + it("falls back to speed default when undefined", () => { + const provider = createProvider({ + apiKey: "sk-test", + }); + + expect(provider.speed).toBe(1.0); + }); +}); diff --git a/extensions/voice-call/src/providers/tts-openai.ts b/extensions/voice-call/src/providers/tts-openai.ts index d1c95420392..a1ff70082cd 100644 --- a/extensions/voice-call/src/providers/tts-openai.ts +++ b/extensions/voice-call/src/providers/tts-openai.ts @@ -82,7 +82,7 @@ export class OpenAITTSProvider { this.model = config.model || "gpt-4o-mini-tts"; // Default to coral - good balance of quality and natural tone this.voice = (config.voice as OpenAITTSVoice) || "coral"; - this.speed = config.speed || 1.0; + this.speed = config.speed ?? 1.0; this.instructions = config.instructions; if (!this.apiKey) {