|
1 | 1 | import { rmSync } from "node:fs"; |
2 | 2 | import path from "node:path"; |
3 | 3 | import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts"; |
| 4 | +import { MAX_TIMER_TIMEOUT_MS } from "openclaw/plugin-sdk/number-runtime"; |
4 | 5 | import type { ReplyPayload } from "openclaw/plugin-sdk/reply-payload"; |
5 | 6 | import { |
6 | 7 | clearRuntimeConfigSnapshot, |
@@ -418,6 +419,50 @@ describe("speech-core native voice-note routing", () => {
|
418 | 419 | expect(request.timeoutMs).toBe(600_000); |
419 | 420 | }); |
420 | 421 | |
| 422 | +it("caps oversized provider default TTS timeouts before synthesis", async () => { |
| 423 | +installSpeechProviders([ |
| 424 | +createMockSpeechProvider("mock", { defaultTimeoutMs: Number.MAX_SAFE_INTEGER }), |
| 425 | +]); |
| 426 | + |
| 427 | +const result = await synthesizeSpeech({ |
| 428 | +text: "Use capped provider timeout.", |
| 429 | +cfg: { |
| 430 | +messages: { |
| 431 | +tts: { |
| 432 | +enabled: true, |
| 433 | +provider: "mock", |
| 434 | +}, |
| 435 | +}, |
| 436 | +} as OpenClawConfig, |
| 437 | +disableFallback: true, |
| 438 | +}); |
| 439 | + |
| 440 | +expect(result.success).toBe(true); |
| 441 | +const request = requireFirstSynthesisRequest("provider default capped timeout request"); |
| 442 | +expect(request.timeoutMs).toBe(MAX_TIMER_TIMEOUT_MS); |
| 443 | +}); |
| 444 | + |
| 445 | +it("ignores nonpositive provider default TTS timeouts", async () => { |
| 446 | +installSpeechProviders([createMockSpeechProvider("mock", { defaultTimeoutMs: 0 })]); |
| 447 | + |
| 448 | +const result = await synthesizeSpeech({ |
| 449 | +text: "Use fallback timeout.", |
| 450 | +cfg: { |
| 451 | +messages: { |
| 452 | +tts: { |
| 453 | +enabled: true, |
| 454 | +provider: "mock", |
| 455 | +}, |
| 456 | +}, |
| 457 | +} as OpenClawConfig, |
| 458 | +disableFallback: true, |
| 459 | +}); |
| 460 | + |
| 461 | +expect(result.success).toBe(true); |
| 462 | +const request = requireFirstSynthesisRequest("provider default fallback timeout request"); |
| 463 | +expect(request.timeoutMs).toBe(30_000); |
| 464 | +}); |
| 465 | + |
421 | 466 | it("keeps explicit TTS config timeout ahead of provider default timeout", async () => { |
422 | 467 | installSpeechProviders([createMockSpeechProvider("mock", { defaultTimeoutMs: 600_000 })]); |
423 | 468 | |
@@ -439,6 +484,32 @@ describe("speech-core native voice-note routing", () => {
|
439 | 484 | expect(request.timeoutMs).toBe(45_000); |
440 | 485 | }); |
441 | 486 | |
| 487 | +it("caps oversized voice model TTS timeouts before synthesis", async () => { |
| 488 | +installSpeechProviders([createMockSpeechProvider("mock", { autoSelectOrder: 1 })]); |
| 489 | + |
| 490 | +const result = await synthesizeSpeech({ |
| 491 | +text: "Use capped explicit timeout.", |
| 492 | +cfg: { |
| 493 | +agents: { |
| 494 | +defaults: { |
| 495 | +voiceModel: { primary: "mock", timeoutMs: Number.MAX_SAFE_INTEGER }, |
| 496 | +}, |
| 497 | +}, |
| 498 | +messages: { |
| 499 | +tts: { |
| 500 | +enabled: true, |
| 501 | +provider: "mock", |
| 502 | +}, |
| 503 | +}, |
| 504 | +} as OpenClawConfig, |
| 505 | +disableFallback: true, |
| 506 | +}); |
| 507 | + |
| 508 | +expect(result.success).toBe(true); |
| 509 | +const request = requireFirstSynthesisRequest("voice model capped timeout request"); |
| 510 | +expect(request.timeoutMs).toBe(MAX_TIMER_TIMEOUT_MS); |
| 511 | +}); |
| 512 | + |
442 | 513 | it("uses agents.defaults.voiceModel as the default speech provider and model", async () => { |
443 | 514 | installSpeechProviders([ |
444 | 515 | createMockSpeechProvider("mock", { autoSelectOrder: 1 }), |
|