fix(tts): update tool description to prevent duplicate audio delivery (#18046)

Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: 70c096abaa
Co-authored-by: zerone0x <39543393+zerone0x@users.noreply.github.com>
Co-authored-by: sebslight <19554889+sebslight@users.noreply.github.com>
Reviewed-by: @sebslight
This commit is contained in:
zerone0x
2026-02-16 21:09:02 +08:00
committed by GitHub
parent 39bb1b3322
commit c2a0cf0c28
4 changed files with 63 additions and 24 deletions

View File

@@ -165,7 +165,7 @@ describe("dispatchReplyFromConfig", () => {
expect(dispatcher.sendFinalReply).toHaveBeenCalledTimes(1);
});
it("does not provide onToolResult in group sessions", async () => {
it("suppresses group tool summaries but still forwards tool media", async () => {
mocks.tryFastAbortFromMessage.mockResolvedValue({
handled: false,
aborted: false,
@@ -182,11 +182,23 @@ describe("dispatchReplyFromConfig", () => {
opts: GetReplyOptions | undefined,
_cfg: OpenClawConfig,
) => {
expect(opts?.onToolResult).toBeUndefined();
expect(opts?.onToolResult).toBeDefined();
await opts?.onToolResult?.({ text: "🔧 exec: ls" });
await opts?.onToolResult?.({
text: "NO_REPLY",
mediaUrls: ["https://example.com/tts-group.opus"],
});
return { text: "hi" } satisfies ReplyPayload;
};
await dispatchReplyFromConfig({ ctx, cfg, dispatcher, replyResolver });
expect(dispatcher.sendToolResult).toHaveBeenCalledTimes(1);
const sent = (dispatcher.sendToolResult as ReturnType<typeof vi.fn>).mock.calls[0]?.[0] as
| ReplyPayload
| undefined;
expect(sent?.mediaUrls).toEqual(["https://example.com/tts-group.opus"]);
expect(sent?.text).toBeUndefined();
expect(dispatcher.sendFinalReply).toHaveBeenCalledTimes(1);
});
@@ -219,7 +231,7 @@ describe("dispatchReplyFromConfig", () => {
expect(dispatcher.sendFinalReply).toHaveBeenCalledTimes(1);
});
it("does not provide onToolResult for native slash commands", async () => {
it("suppresses native tool summaries but still forwards tool media", async () => {
mocks.tryFastAbortFromMessage.mockResolvedValue({
handled: false,
aborted: false,
@@ -237,11 +249,22 @@ describe("dispatchReplyFromConfig", () => {
opts: GetReplyOptions | undefined,
_cfg: OpenClawConfig,
) => {
expect(opts?.onToolResult).toBeUndefined();
expect(opts?.onToolResult).toBeDefined();
await opts?.onToolResult?.({ text: "🔧 tools/sessions_send" });
await opts?.onToolResult?.({
mediaUrl: "https://example.com/tts-native.opus",
});
return { text: "hi" } satisfies ReplyPayload;
};
await dispatchReplyFromConfig({ ctx, cfg, dispatcher, replyResolver });
expect(dispatcher.sendToolResult).toHaveBeenCalledTimes(1);
const sent = (dispatcher.sendToolResult as ReturnType<typeof vi.fn>).mock.calls[0]?.[0] as
| ReplyPayload
| undefined;
expect(sent?.mediaUrl).toBe("https://example.com/tts-native.opus");
expect(sent?.text).toBeUndefined();
expect(dispatcher.sendFinalReply).toHaveBeenCalledTimes(1);
});