| import "./run.overflow-compaction.mocks.shared.js"; |
| import { beforeEach, describe, expect, it, vi } from "vitest"; |
| import { pickFallbackThinkingLevel } from "../pi-embedded-helpers.js"; |
| import { runEmbeddedPiAgent } from "./run.js"; |
| import { |
| makeAttemptResult, |
| makeCompactionSuccess, |
| makeOverflowError, |
| mockOverflowRetrySuccess, |
| queueOverflowAttemptWithOversizedToolOutput, |
| } from "./run.overflow-compaction.fixture.js"; |
| import { mockedGlobalHookRunner } from "./run.overflow-compaction.mocks.shared.js"; |
| import { |
| mockedContextEngine, |
| mockedCompactDirect, |
| mockedRunEmbeddedAttempt, |
| mockedSessionLikelyHasOversizedToolResults, |
| mockedTruncateOversizedToolResultsInSession, |
| overflowBaseRunParams, |
| } from "./run.overflow-compaction.shared-test.js"; |
| const mockedPickFallbackThinkingLevel = vi.mocked(pickFallbackThinkingLevel); |
|
|
| describe("runEmbeddedPiAgent overflow compaction trigger routing", () => { |
| beforeEach(() => { |
| vi.clearAllMocks(); |
| mockedRunEmbeddedAttempt.mockReset(); |
| mockedCompactDirect.mockReset(); |
| mockedSessionLikelyHasOversizedToolResults.mockReset(); |
| mockedTruncateOversizedToolResultsInSession.mockReset(); |
| mockedGlobalHookRunner.runBeforeAgentStart.mockReset(); |
| mockedGlobalHookRunner.runBeforeCompaction.mockReset(); |
| mockedGlobalHookRunner.runAfterCompaction.mockReset(); |
| mockedContextEngine.info.ownsCompaction = false; |
| mockedCompactDirect.mockResolvedValue({ |
| ok: false, |
| compacted: false, |
| reason: "nothing to compact", |
| }); |
| mockedSessionLikelyHasOversizedToolResults.mockReturnValue(false); |
| mockedTruncateOversizedToolResultsInSession.mockResolvedValue({ |
| truncated: false, |
| truncatedCount: 0, |
| reason: "no oversized tool results", |
| }); |
| mockedGlobalHookRunner.hasHooks.mockImplementation(() => false); |
| }); |
|
|
| it("passes precomputed legacy before_agent_start result into the attempt", async () => { |
| const legacyResult = { |
| modelOverride: "legacy-model", |
| prependContext: "legacy context", |
| }; |
| mockedGlobalHookRunner.hasHooks.mockImplementation( |
| (hookName) => hookName === "before_agent_start", |
| ); |
| mockedGlobalHookRunner.runBeforeAgentStart.mockResolvedValueOnce(legacyResult); |
| mockedRunEmbeddedAttempt.mockResolvedValueOnce(makeAttemptResult({ promptError: null })); |
|
|
| await runEmbeddedPiAgent({ |
| sessionId: "test-session", |
| sessionKey: "test-key", |
| sessionFile: "/tmp/session.json", |
| workspaceDir: "/tmp/workspace", |
| prompt: "hello", |
| timeoutMs: 30000, |
| runId: "run-legacy-pass-through", |
| }); |
|
|
| expect(mockedGlobalHookRunner.runBeforeAgentStart).toHaveBeenCalledTimes(1); |
| expect(mockedRunEmbeddedAttempt).toHaveBeenCalledWith( |
| expect.objectContaining({ |
| legacyBeforeAgentStartResult: legacyResult, |
| }), |
| ); |
| }); |
|
|
| it("passes resolved auth profile into run attempts for context-engine afterTurn propagation", async () => { |
| mockedRunEmbeddedAttempt.mockResolvedValueOnce(makeAttemptResult({ promptError: null })); |
|
|
| await runEmbeddedPiAgent({ |
| ...overflowBaseRunParams, |
| runId: "run-auth-profile-passthrough", |
| }); |
|
|
| expect(mockedRunEmbeddedAttempt).toHaveBeenCalledWith( |
| expect.objectContaining({ |
| authProfileId: "test-profile", |
| authProfileIdSource: "auto", |
| }), |
| ); |
| }); |
|
|
| it("passes trigger=overflow when retrying compaction after context overflow", async () => { |
| mockOverflowRetrySuccess({ |
| runEmbeddedAttempt: mockedRunEmbeddedAttempt, |
| compactDirect: mockedCompactDirect, |
| }); |
|
|
| await runEmbeddedPiAgent(overflowBaseRunParams); |
|
|
| expect(mockedCompactDirect).toHaveBeenCalledTimes(1); |
| expect(mockedCompactDirect).toHaveBeenCalledWith( |
| expect.objectContaining({ |
| sessionId: "test-session", |
| sessionFile: "/tmp/session.json", |
| runtimeContext: expect.objectContaining({ |
| trigger: "overflow", |
| authProfileId: "test-profile", |
| }), |
| }), |
| ); |
| }); |
|
|
| it("passes observed overflow token counts into compaction when providers report them", async () => { |
| const overflowError = new Error( |
| '400 {"type":"error","error":{"type":"invalid_request_error","message":"prompt is too long: 277403 tokens > 200000 maximum"}}', |
| ); |
|
|
| mockedRunEmbeddedAttempt |
| .mockResolvedValueOnce(makeAttemptResult({ promptError: overflowError })) |
| .mockResolvedValueOnce(makeAttemptResult({ promptError: null })); |
| mockedCompactDirect.mockResolvedValueOnce( |
| makeCompactionSuccess({ |
| summary: "Compacted session", |
| firstKeptEntryId: "entry-8", |
| tokensBefore: 277403, |
| }), |
| ); |
|
|
| const result = await runEmbeddedPiAgent(overflowBaseRunParams); |
|
|
| expect(mockedCompactDirect).toHaveBeenCalledWith( |
| expect.objectContaining({ |
| currentTokenCount: 277403, |
| }), |
| ); |
| expect(result.meta.error).toBeUndefined(); |
| }); |
|
|
| it("does not reset compaction attempt budget after successful tool-result truncation", async () => { |
| const overflowError = queueOverflowAttemptWithOversizedToolOutput( |
| mockedRunEmbeddedAttempt, |
| makeOverflowError(), |
| ); |
| mockedRunEmbeddedAttempt |
| .mockResolvedValueOnce(makeAttemptResult({ promptError: overflowError })) |
| .mockResolvedValueOnce(makeAttemptResult({ promptError: overflowError })) |
| .mockResolvedValueOnce(makeAttemptResult({ promptError: overflowError })); |
|
|
| mockedCompactDirect |
| .mockResolvedValueOnce({ |
| ok: false, |
| compacted: false, |
| reason: "nothing to compact", |
| }) |
| .mockResolvedValueOnce( |
| makeCompactionSuccess({ |
| summary: "Compacted 2", |
| firstKeptEntryId: "entry-5", |
| tokensBefore: 160000, |
| }), |
| ) |
| .mockResolvedValueOnce( |
| makeCompactionSuccess({ |
| summary: "Compacted 3", |
| firstKeptEntryId: "entry-7", |
| tokensBefore: 140000, |
| }), |
| ); |
|
|
| mockedSessionLikelyHasOversizedToolResults.mockReturnValue(true); |
| mockedTruncateOversizedToolResultsInSession.mockResolvedValueOnce({ |
| truncated: true, |
| truncatedCount: 1, |
| }); |
|
|
| const result = await runEmbeddedPiAgent(overflowBaseRunParams); |
|
|
| expect(mockedCompactDirect).toHaveBeenCalledTimes(3); |
| expect(mockedTruncateOversizedToolResultsInSession).toHaveBeenCalledTimes(1); |
| expect(mockedRunEmbeddedAttempt).toHaveBeenCalledTimes(4); |
| expect(result.meta.error?.kind).toBe("context_overflow"); |
| }); |
|
|
| it("fires compaction hooks during overflow recovery for ownsCompaction engines", async () => { |
| mockedContextEngine.info.ownsCompaction = true; |
| mockedGlobalHookRunner.hasHooks.mockImplementation( |
| (hookName) => hookName === "before_compaction" || hookName === "after_compaction", |
| ); |
| mockedRunEmbeddedAttempt |
| .mockResolvedValueOnce(makeAttemptResult({ promptError: makeOverflowError() })) |
| .mockResolvedValueOnce(makeAttemptResult({ promptError: null })); |
| mockedCompactDirect.mockResolvedValueOnce({ |
| ok: true, |
| compacted: true, |
| result: { |
| summary: "engine-owned compaction", |
| tokensAfter: 50, |
| }, |
| }); |
|
|
| await runEmbeddedPiAgent(overflowBaseRunParams); |
|
|
| expect(mockedGlobalHookRunner.runBeforeCompaction).toHaveBeenCalledWith( |
| { messageCount: -1, sessionFile: "/tmp/session.json" }, |
| expect.objectContaining({ |
| sessionKey: "test-key", |
| }), |
| ); |
| expect(mockedGlobalHookRunner.runAfterCompaction).toHaveBeenCalledWith( |
| { |
| messageCount: -1, |
| compactedCount: -1, |
| tokenCount: 50, |
| sessionFile: "/tmp/session.json", |
| }, |
| expect.objectContaining({ |
| sessionKey: "test-key", |
| }), |
| ); |
| }); |
|
|
| it("guards thrown engine-owned overflow compaction attempts", async () => { |
| mockedContextEngine.info.ownsCompaction = true; |
| mockedGlobalHookRunner.hasHooks.mockImplementation( |
| (hookName) => hookName === "before_compaction" || hookName === "after_compaction", |
| ); |
| mockedRunEmbeddedAttempt.mockResolvedValueOnce( |
| makeAttemptResult({ promptError: makeOverflowError() }), |
| ); |
| mockedCompactDirect.mockRejectedValueOnce(new Error("engine boom")); |
|
|
| const result = await runEmbeddedPiAgent(overflowBaseRunParams); |
|
|
| expect(mockedCompactDirect).toHaveBeenCalledTimes(1); |
| expect(mockedGlobalHookRunner.runBeforeCompaction).toHaveBeenCalledTimes(1); |
| expect(mockedGlobalHookRunner.runAfterCompaction).not.toHaveBeenCalled(); |
| expect(result.meta.error?.kind).toBe("context_overflow"); |
| expect(result.payloads?.[0]?.isError).toBe(true); |
| }); |
|
|
| it("returns retry_limit when repeated retries never converge", async () => { |
| mockedRunEmbeddedAttempt.mockClear(); |
| mockedCompactDirect.mockClear(); |
| mockedPickFallbackThinkingLevel.mockClear(); |
| mockedRunEmbeddedAttempt.mockResolvedValue( |
| makeAttemptResult({ promptError: new Error("unsupported reasoning mode") }), |
| ); |
| mockedPickFallbackThinkingLevel.mockReturnValue("low"); |
|
|
| const result = await runEmbeddedPiAgent(overflowBaseRunParams); |
|
|
| expect(mockedRunEmbeddedAttempt).toHaveBeenCalledTimes(32); |
| expect(mockedCompactDirect).not.toHaveBeenCalled(); |
| expect(result.meta.error?.kind).toBe("retry_limit"); |
| expect(result.payloads?.[0]?.isError).toBe(true); |
| }); |
| }); |
|
|