diff --git a/src/agents/tools/tts-tool.test.ts b/src/agents/tools/tts-tool.test.ts index fe9a6c1def9..32418b7a5fa 100644 --- a/src/agents/tools/tts-tool.test.ts +++ b/src/agents/tools/tts-tool.test.ts @@ -9,8 +9,15 @@ const { createTtsTool } = await import("./tts-tool.js"); describe("createTtsTool", () => { it("uses SILENT_REPLY_TOKEN in guidance text", () => { const tool = createTtsTool(); - expect(tool.description).toContain("QUIET_TOKEN"); expect(tool.description).not.toContain("NO_REPLY"); }); + + it("returns error even when channel arg is provided but no agentChannel", async () => { + const tool = createTtsTool(); + const result = await tool.execute("test-call", { text: "hello world", channel: "telegram" }); + const firstContent = result.content[0] as { type: string; text: string }; + expect(firstContent.text).toContain("requires a bound"); + expect((result.details as Record).error).toBe("no_channel"); + }); }); diff --git a/src/agents/tools/tts-tool.ts b/src/agents/tools/tts-tool.ts index 03ed3cd9a04..7951250afaf 100644 --- a/src/agents/tools/tts-tool.ts +++ b/src/agents/tools/tts-tool.ts @@ -27,11 +27,25 @@ export function createTtsTool(opts?: { const params = args as Record; const text = readStringParam(params, "text", { required: true }); const channel = readStringParam(params, "channel"); + const resolvedChannel = channel ?? opts?.agentChannel; + + if (!opts?.agentChannel) { + return { + content: [ + { + type: "text", + text: 'TTS requires a bound session channel for audio delivery. Use sessionTarget: "main" instead of "isolated".', + }, + ], + details: { error: "no_channel" }, + }; + } + const cfg = opts?.config ?? loadConfig(); const result = await textToSpeech({ text, cfg, - channel: channel ?? opts?.agentChannel, + channel: resolvedChannel, }); if (result.success && result.audioPath) {