import type { AgentMessage } from "@mariozechner/pi-agent-core"; import { describe, expect, it } from "vitest"; import { __testing } from "./compaction-safeguard.js"; const { collectToolFailures, formatToolFailuresSection } = __testing; describe("compaction-safeguard tool failures", () => { it("formats tool failures with meta and summary", () => { const messages: AgentMessage[] = [ { role: "toolResult", toolCallId: "call-1", toolName: "exec", isError: true, details: { status: "failed", exitCode: 1 }, content: [{ type: "text", text: "ENOENT: missing file" }], timestamp: Date.now(), }, { role: "toolResult", toolCallId: "call-2", toolName: "read", isError: false, content: [{ type: "text", text: "ok" }], timestamp: Date.now(), }, ]; const failures = collectToolFailures(messages); expect(failures).toHaveLength(1); const section = formatToolFailuresSection(failures); expect(section).toContain("## Tool Failures"); expect(section).toContain("exec (status=failed exitCode=1): ENOENT: missing file"); }); it("dedupes by toolCallId and handles empty output", () => { const messages: AgentMessage[] = [ { role: "toolResult", toolCallId: "call-1", toolName: "exec", isError: true, details: { exitCode: 2 }, content: [], timestamp: Date.now(), }, { role: "toolResult", toolCallId: "call-1", toolName: "exec", isError: true, content: [{ type: "text", text: "ignored" }], timestamp: Date.now(), }, ]; const failures = collectToolFailures(messages); expect(failures).toHaveLength(1); const section = formatToolFailuresSection(failures); expect(section).toContain("exec (exitCode=2): failed"); }); it("caps the number of failures and adds overflow line", () => { const messages: AgentMessage[] = Array.from({ length: 9 }, (_, idx) => ({ role: "toolResult", toolCallId: `call-${idx}`, toolName: "exec", isError: true, content: [{ type: "text", text: `error ${idx}` }], timestamp: Date.now(), })); const failures = collectToolFailures(messages); const section = formatToolFailuresSection(failures); expect(section).toContain("## Tool Failures"); expect(section).toContain("...and 1 more"); }); it("omits section when there are no tool failures", () => { const messages: AgentMessage[] = [ { role: "toolResult", toolCallId: "ok", toolName: "exec", isError: false, content: [{ type: "text", text: "ok" }], timestamp: Date.now(), }, ]; const failures = collectToolFailures(messages); const section = formatToolFailuresSection(failures); expect(section).toBe(""); }); });