import { describe, expect, test } from "bun:test"; import { applyGrouping } from "../groupToolUses"; // Helper: build minimal tool-use assistant message function makeToolUseMsg( uuid: string, messageId: string, toolUseId: string, toolName: string ): any { return { type: "assistant", uuid, timestamp: Date.now(), message: { id: messageId, content: [{ type: "tool_use", id: toolUseId, name: toolName, input: {} }], }, }; } // Helper: build minimal tool-result user message function makeToolResultMsg(uuid: string, toolUseId: string): any { return { type: "user", uuid, timestamp: Date.now(), message: { content: [{ type: "tool_result", tool_use_id: toolUseId, content: "ok" }], }, }; } // Helper: build minimal text assistant message function makeTextMsg(uuid: string, text: string): any { return { type: "assistant", uuid, timestamp: Date.now(), message: { id: `msg-${uuid}`, content: [{ type: "text", text }] }, }; } // Minimal tool definitions const groupableTool: any = { name: "Grep", renderGroupedToolUse: true }; const nonGroupableTool: any = { name: "Bash", renderGroupedToolUse: undefined }; // ─── applyGrouping ──────────────────────────────────────────────────── describe("applyGrouping", () => { test("returns all messages in verbose mode", () => { const msgs = [ makeToolUseMsg("u1", "m1", "tu1", "Grep"), makeToolUseMsg("u2", "m1", "tu2", "Grep"), ]; const result = applyGrouping(msgs, [groupableTool], true); expect(result.messages).toHaveLength(2); expect(result.messages).toBe(msgs); // same reference }); test("does not group when tool lacks renderGroupedToolUse", () => { const msgs = [ makeToolUseMsg("u1", "m1", "tu1", "Bash"), makeToolUseMsg("u2", "m1", "tu2", "Bash"), ]; const result = applyGrouping(msgs, [nonGroupableTool]); expect(result.messages).toHaveLength(2); // Both messages should pass through as-is expect(result.messages[0]).toBe(msgs[0]); }); test("does not group single tool use", () => { const msgs = [makeToolUseMsg("u1", "m1", "tu1", "Grep")]; const result = applyGrouping(msgs, [groupableTool]); expect(result.messages).toHaveLength(1); expect((result.messages[0] as any).type).toBe("assistant"); }); test("groups 2+ tool uses of same type from same message", () => { const msgs = [ makeToolUseMsg("u1", "m1", "tu1", "Grep"), makeToolUseMsg("u2", "m1", "tu2", "Grep"), makeToolUseMsg("u3", "m1", "tu3", "Grep"), ]; const result = applyGrouping(msgs, [groupableTool]); expect(result.messages).toHaveLength(1); const grouped = result.messages[0] as any; expect(grouped.type).toBe("grouped_tool_use"); expect(grouped.toolName).toBe("Grep"); expect(grouped.messages).toHaveLength(3); }); test("does not group tool uses from different messages", () => { const msgs = [ makeToolUseMsg("u1", "m1", "tu1", "Grep"), makeToolUseMsg("u2", "m2", "tu2", "Grep"), ]; const result = applyGrouping(msgs, [groupableTool]); // Each belongs to a different message.id, so no group (< 2 per group) expect(result.messages).toHaveLength(2); }); test("collects tool results for grouped uses", () => { const msgs = [ makeToolUseMsg("u1", "m1", "tu1", "Grep"), makeToolUseMsg("u2", "m1", "tu2", "Grep"), makeToolResultMsg("u3", "tu1"), makeToolResultMsg("u4", "tu2"), ]; const result = applyGrouping(msgs, [groupableTool]); const grouped = result.messages[0] as any; expect(grouped.type).toBe("grouped_tool_use"); expect(grouped.results).toHaveLength(2); }); test("skips user messages whose tool_results are all grouped", () => { const msgs = [ makeToolUseMsg("u1", "m1", "tu1", "Grep"), makeToolUseMsg("u2", "m1", "tu2", "Grep"), makeToolResultMsg("u3", "tu1"), makeToolResultMsg("u4", "tu2"), ]; const result = applyGrouping(msgs, [groupableTool]); // Only the grouped message should remain — result messages are consumed expect(result.messages).toHaveLength(1); }); test("preserves non-grouped messages alongside groups", () => { const msgs = [ makeTextMsg("u0", "thinking..."), makeToolUseMsg("u1", "m1", "tu1", "Grep"), makeToolUseMsg("u2", "m1", "tu2", "Grep"), makeTextMsg("u3", "done"), ]; const result = applyGrouping(msgs, [groupableTool]); expect(result.messages).toHaveLength(3); // text + grouped + text expect((result.messages[0] as any).type).toBe("assistant"); expect((result.messages[1] as any).type).toBe("grouped_tool_use"); expect((result.messages[2] as any).type).toBe("assistant"); }); test("handles empty messages array", () => { const result = applyGrouping([], [groupableTool]); expect(result.messages).toHaveLength(0); }); test("handles empty tools array", () => { const msgs = [makeToolUseMsg("u1", "m1", "tu1", "Grep")]; const result = applyGrouping(msgs, []); expect(result.messages).toHaveLength(1); }); });