diff --git a/src/agents/compaction.tool-result-details.test.ts b/src/agents/compaction.tool-result-details.test.ts index 79c883a729f..f76fd951168 100644 --- a/src/agents/compaction.tool-result-details.test.ts +++ b/src/agents/compaction.tool-result-details.test.ts @@ -3,7 +3,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; const piCodingAgentMocks = vi.hoisted(() => ({ generateSummary: vi.fn(async () => "summary"), - estimateTokens: vi.fn(() => 1), + estimateTokens: vi.fn((_message: unknown) => 1), })); vi.mock("@mariozechner/pi-coding-agent", async () => { @@ -17,7 +17,7 @@ vi.mock("@mariozechner/pi-coding-agent", async () => { }; }); -import { summarizeWithFallback } from "./compaction.js"; +import { isOversizedForSummary, summarizeWithFallback } from "./compaction.js"; describe("compaction toolResult details stripping", () => { beforeEach(() => { @@ -64,4 +64,23 @@ describe("compaction toolResult details stripping", () => { expect(serialized).not.toContain("Ignore previous instructions"); expect(serialized).not.toContain('"details"'); }); + + it("ignores toolResult.details when evaluating oversized messages", () => { + piCodingAgentMocks.estimateTokens.mockImplementation((message: unknown) => { + const record = message as { details?: unknown }; + return record.details ? 10_000 : 10; + }); + + const toolResult = { + role: "toolResult", + toolCallId: "call_1", + toolName: "browser", + isError: false, + content: [{ type: "text", text: "ok" }], + details: { raw: "x".repeat(100_000) }, + timestamp: 2, + } as unknown as AgentMessage; + + expect(isOversizedForSummary(toolResult, 1_000)).toBe(false); + }); }); diff --git a/src/agents/compaction.ts b/src/agents/compaction.ts index da83723c3f6..25163471839 100644 --- a/src/agents/compaction.ts +++ b/src/agents/compaction.ts @@ -152,7 +152,7 @@ export function computeAdaptiveChunkRatio(messages: AgentMessage[], contextWindo * If single message > 50% of context, it can't be summarized safely. */ export function isOversizedForSummary(msg: AgentMessage, contextWindow: number): boolean { - const tokens = estimateTokens(msg) * SAFETY_MARGIN; + const tokens = estimateCompactionMessageTokens(msg) * SAFETY_MARGIN; return tokens > contextWindow * 0.5; } @@ -240,7 +240,7 @@ export async function summarizeWithFallback(params: { for (const msg of messages) { if (isOversizedForSummary(msg, contextWindow)) { const role = (msg as { role?: string }).role ?? "message"; - const tokens = estimateTokens(msg); + const tokens = estimateCompactionMessageTokens(msg); oversizedNotes.push( `[Large ${role} (~${Math.round(tokens / 1000)}K tokens) omitted from summary]`, );