@@ -4,6 +4,7 @@ import "../../test-helpers/pi-coding-agent-token-mock.js";
44import { estimateToolResultReductionPotential } from "../tool-result-truncation.js" ;
55
66let PREEMPTIVE_OVERFLOW_ERROR_TEXT : typeof import ( "./preemptive-compaction.js" ) . PREEMPTIVE_OVERFLOW_ERROR_TEXT ;
7+ let buildPrePromptContextBudgetStatus : typeof import ( "./preemptive-compaction.js" ) . buildPrePromptContextBudgetStatus ;
78let estimatePrePromptTokens : typeof import ( "./preemptive-compaction.js" ) . estimatePrePromptTokens ;
89let formatPrePromptPrecheckLog : typeof import ( "./preemptive-compaction.js" ) . formatPrePromptPrecheckLog ;
910let shouldPreemptivelyCompactBeforePrompt : typeof import ( "./preemptive-compaction.js" ) . shouldPreemptivelyCompactBeforePrompt ;
@@ -12,6 +13,7 @@ beforeAll(async () => {
1213 vi . resetModules ( ) ;
1314 ( {
1415 PREEMPTIVE_OVERFLOW_ERROR_TEXT ,
16+ buildPrePromptContextBudgetStatus,
1517 estimatePrePromptTokens,
1618 formatPrePromptPrecheckLog,
1719 shouldPreemptivelyCompactBeforePrompt,
@@ -131,6 +133,51 @@ describe("preemptive-compaction", () => {
131133 expect ( line ) . toContain ( "unwindowedMessages=3" ) ;
132134 } ) ;
133135
136+ it ( "builds a durable estimated context budget status snapshot" , ( ) => {
137+ const result = shouldPreemptivelyCompactBeforePrompt ( {
138+ messages : [ makeAssistantHistory ( "short history" ) ] ,
139+ systemPrompt : "sys" ,
140+ prompt : "hello" ,
141+ contextTokenBudget : 10_000 ,
142+ reserveTokens : 1_000 ,
143+ } ) ;
144+
145+ const status = buildPrePromptContextBudgetStatus ( {
146+ result,
147+ provider : "anthropic" ,
148+ modelId : "claude-opus-4-6" ,
149+ messageCount : 1 ,
150+ unwindowedMessageCount : 3 ,
151+ contextTokenBudget : 10_000 ,
152+ reserveTokens : 1_000 ,
153+ sessionId : "session-1" ,
154+ sessionFile : "sessions/session-1.json" ,
155+ now : 123 ,
156+ } ) ;
157+
158+ expect ( status ) . toMatchObject ( {
159+ schemaVersion : 1 ,
160+ source : "pre-prompt-estimate" ,
161+ updatedAt : 123 ,
162+ provider : "anthropic" ,
163+ model : "claude-opus-4-6" ,
164+ route : "fits" ,
165+ shouldCompact : false ,
166+ contextTokenBudget : 10_000 ,
167+ promptBudgetBeforeReserve : result . promptBudgetBeforeReserve ,
168+ reserveTokens : 1_000 ,
169+ effectiveReserveTokens : result . effectiveReserveTokens ,
170+ overflowTokens : 0 ,
171+ messageCount : 1 ,
172+ unwindowedMessageCount : 3 ,
173+ sessionId : "session-1" ,
174+ sessionFile : "sessions/session-1.json" ,
175+ } ) ;
176+ expect ( status . remainingPromptBudgetTokens ) . toBe (
177+ result . promptBudgetBeforeReserve - result . estimatedPromptTokens ,
178+ ) ;
179+ } ) ;
180+
134181 it ( "uses the larger unwindowed message estimate when explicitly provided" , ( ) => {
135182 const result = shouldPreemptivelyCompactBeforePrompt ( {
136183 messages : [ makeAssistantHistory ( "small assembled window" ) ] ,
0 commit comments