From fd1ba2c7feaedb78e5d87107f6e6a274044121b8 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Thu, 18 Jun 2026 23:15:18 +0200 Subject: [PATCH] test(coding-agent): seed auto-compaction queue fixture --- ...gent-session-auto-compaction-queue.test.ts | 103 ++++++++++-------- 1 file changed, 59 insertions(+), 44 deletions(-) diff --git a/packages/coding-agent/test/agent-session-auto-compaction-queue.test.ts b/packages/coding-agent/test/agent-session-auto-compaction-queue.test.ts index 1abe3e28..7fd56b46 100644 --- a/packages/coding-agent/test/agent-session-auto-compaction-queue.test.ts +++ b/packages/coding-agent/test/agent-session-auto-compaction-queue.test.ts @@ -2,7 +2,12 @@ import { existsSync, mkdirSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { Agent } from "@earendil-works/pi-agent-core"; -import { type AssistantMessage, getModel } from "@earendil-works/pi-ai"; +import { + type AssistantMessage, + createAssistantMessageEventStream, + fauxAssistantMessage, + getModel, +} from "@earendil-works/pi-ai"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { AgentSession } from "../src/core/agent-session.ts"; import { AuthStorage } from "../src/core/auth-storage.ts"; @@ -11,51 +16,10 @@ import { SessionManager } from "../src/core/session-manager.ts"; import { SettingsManager } from "../src/core/settings-manager.ts"; import { createTestResourceLoader } from "./utilities.ts"; -vi.mock("../src/core/compaction/index.js", () => ({ - calculateContextTokens: (usage: { - input: number; - output: number; - cacheRead: number; - cacheWrite: number; - totalTokens?: number; - }) => usage.totalTokens ?? usage.input + usage.output + usage.cacheRead + usage.cacheWrite, - collectEntriesForBranchSummary: () => ({ entries: [], commonAncestorId: null }), - compact: async () => ({ - summary: "compacted", - firstKeptEntryId: "entry-1", - tokensBefore: 100, - details: {}, - }), - estimateContextTokens: ( - messages: Array<{ - role: string; - usage?: { input: number; output: number; cacheRead: number; cacheWrite: number; totalTokens?: number }; - stopReason?: string; - }>, - ) => { - // Walk backwards to find last non-error, non-aborted assistant with usage - for (let i = messages.length - 1; i >= 0; i--) { - const msg = messages[i]; - if (msg.role === "assistant" && msg.stopReason !== "error" && msg.stopReason !== "aborted" && msg.usage) { - const tokens = - msg.usage.totalTokens ?? msg.usage.input + msg.usage.output + msg.usage.cacheRead + msg.usage.cacheWrite; - return { tokens, usageTokens: tokens, trailingTokens: 0, lastUsageIndex: i }; - } - } - return { tokens: 0, usageTokens: 0, trailingTokens: 0, lastUsageIndex: null }; - }, - generateBranchSummary: async () => ({ summary: "", aborted: false, readFiles: [], modifiedFiles: [] }), - prepareCompaction: () => ({ dummy: true }), - shouldCompact: ( - contextTokens: number, - contextWindow: number, - settings: { enabled: boolean; reserveTokens: number }, - ) => settings.enabled && contextTokens > contextWindow - settings.reserveTokens, -})); - describe("AgentSession auto-compaction queue resume", () => { let session: AgentSession; let sessionManager: SessionManager; + let settingsManager: SettingsManager; let tempDir: string; beforeEach(() => { @@ -73,7 +37,7 @@ describe("AgentSession auto-compaction queue resume", () => { }); sessionManager = SessionManager.inMemory(); - const settingsManager = SettingsManager.create(tempDir, tempDir); + settingsManager = SettingsManager.create(tempDir, tempDir); const authStorage = AuthStorage.create(join(tempDir, "auth.json")); authStorage.setRuntimeApiKey("anthropic", "test-key"); const modelRegistry = ModelRegistry.create(authStorage, tempDir); @@ -98,6 +62,57 @@ describe("AgentSession auto-compaction queue resume", () => { }); it("should resume after threshold compaction when only agent-level queued messages exist", async () => { + settingsManager.applyOverrides({ compaction: { keepRecentTokens: 1 } }); + const model = session.model!; + const now = Date.now(); + sessionManager.appendMessage({ + role: "user", + content: [{ type: "text", text: "message to compact" }], + timestamp: now - 1000, + }); + sessionManager.appendMessage({ + role: "assistant", + content: [{ type: "text", text: "assistant response to compact" }], + api: model.api, + provider: model.provider, + model: model.id, + usage: { + input: 100, + output: 0, + cacheRead: 0, + cacheWrite: 0, + totalTokens: 100, + cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }, + }, + stopReason: "stop", + timestamp: now - 500, + }); + session.agent.state.messages = sessionManager.buildSessionContext().messages; + session.agent.streamFn = (summaryModel) => { + const stream = createAssistantMessageEventStream(); + queueMicrotask(() => { + stream.push({ + type: "done", + reason: "stop", + message: { + ...fauxAssistantMessage("compacted"), + api: summaryModel.api, + provider: summaryModel.provider, + model: summaryModel.id, + usage: { + input: 10, + output: 0, + cacheRead: 0, + cacheWrite: 0, + totalTokens: 10, + cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }, + }, + }, + }); + }); + return stream; + }; + session.agent.followUp({ role: "custom", customType: "test",