Skip to content

Commit 79be940

Browse files
giodl73-repoGio Della-Libera
andauthored
fix(agents): log pre-prompt compaction fits decisions (#84676)
Co-authored-by: Gio Della-Libera <giodl@microsoft.com>
1 parent 0671a2a commit 79be940

3 files changed

Lines changed: 100 additions & 9 deletions

File tree

src/agents/pi-embedded-runner/run/attempt.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ import {
389389
} from "./midturn-precheck.js";
390390
import {
391391
PREEMPTIVE_OVERFLOW_ERROR_TEXT,
392+
formatPrePromptPrecheckLog,
392393
shouldPreemptivelyCompactBeforePrompt,
393394
} from "./preemptive-compaction.js";
394395
import {
@@ -4010,6 +4011,25 @@ export async function runEmbeddedAttempt(
40104011
agentId: sessionAgentId,
40114012
}),
40124013
});
4014+
if (preemptiveCompaction) {
4015+
log.debug(
4016+
formatPrePromptPrecheckLog({
4017+
result: preemptiveCompaction,
4018+
provider: params.provider,
4019+
modelId: params.modelId,
4020+
messageCount: activeSession.messages.length,
4021+
contextTokenBudget,
4022+
reserveTokens,
4023+
...(params.sessionKey ? { sessionKey: params.sessionKey } : {}),
4024+
...(params.sessionId ? { sessionId: params.sessionId } : {}),
4025+
...(contextEnginePromptAuthority === "preassembly_may_overflow" &&
4026+
unwindowedContextEngineMessagesForPrecheck
4027+
? { unwindowedMessageCount: unwindowedContextEngineMessagesForPrecheck.length }
4028+
: {}),
4029+
...(params.sessionFile ? { sessionFile: params.sessionFile } : {}),
4030+
}),
4031+
);
4032+
}
40134033
if (preemptiveCompaction?.route === "truncate_tool_results_only") {
40144034
const toolResultMaxChars = resolveLiveToolResultMaxChars({
40154035
contextWindowTokens: contextTokenBudget,

src/agents/pi-embedded-runner/run/preemptive-compaction.test.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@ import { estimateToolResultReductionPotential } from "../tool-result-truncation.
55

66
let PREEMPTIVE_OVERFLOW_ERROR_TEXT: typeof import("./preemptive-compaction.js").PREEMPTIVE_OVERFLOW_ERROR_TEXT;
77
let estimatePrePromptTokens: typeof import("./preemptive-compaction.js").estimatePrePromptTokens;
8+
let formatPrePromptPrecheckLog: typeof import("./preemptive-compaction.js").formatPrePromptPrecheckLog;
89
let shouldPreemptivelyCompactBeforePrompt: typeof import("./preemptive-compaction.js").shouldPreemptivelyCompactBeforePrompt;
910

1011
beforeAll(async () => {
1112
vi.resetModules();
1213
({
1314
PREEMPTIVE_OVERFLOW_ERROR_TEXT,
1415
estimatePrePromptTokens,
16+
formatPrePromptPrecheckLog,
1517
shouldPreemptivelyCompactBeforePrompt,
1618
} = await import("./preemptive-compaction.js"));
1719
});
@@ -93,6 +95,42 @@ describe("preemptive-compaction", () => {
9395
expect(result.estimatedPromptTokens).toBeLessThan(result.promptBudgetBeforeReserve);
9496
});
9597

98+
it("formats all-route pre-prompt diagnostics for a fits decision", () => {
99+
const result = shouldPreemptivelyCompactBeforePrompt({
100+
messages: [makeAssistantHistory("short history")],
101+
systemPrompt: "sys",
102+
prompt: "hello",
103+
contextTokenBudget: 10_000,
104+
reserveTokens: 1_000,
105+
});
106+
const line = formatPrePromptPrecheckLog({
107+
result,
108+
sessionKey: "discord:channel:thread",
109+
sessionId: "session-1",
110+
provider: "anthropic",
111+
modelId: "claude-opus-4-6",
112+
messageCount: 1,
113+
unwindowedMessageCount: 3,
114+
contextTokenBudget: 10_000,
115+
reserveTokens: 1_000,
116+
sessionFile: "sessions/session-1.json",
117+
});
118+
119+
expect(line).toContain("[context-overflow-precheck] pre-prompt check");
120+
expect(line).toContain("sessionKey=discord:channel:thread");
121+
expect(line).toContain("provider=anthropic/claude-opus-4-6");
122+
expect(line).toContain("route=fits");
123+
expect(line).toContain(`estimatedPromptTokens=${result.estimatedPromptTokens}`);
124+
expect(line).toContain(`promptBudgetBeforeReserve=${result.promptBudgetBeforeReserve}`);
125+
expect(line).toContain("overflowTokens=0");
126+
expect(line).toContain(`toolResultReducibleChars=${result.toolResultReducibleChars}`);
127+
expect(line).toContain("reserveTokens=1000");
128+
expect(line).toContain(`effectiveReserveTokens=${result.effectiveReserveTokens}`);
129+
expect(line).toContain("contextTokenBudget=10000");
130+
expect(line).toContain("messages=1");
131+
expect(line).toContain("unwindowedMessages=3");
132+
});
133+
96134
it("uses the larger unwindowed message estimate when explicitly provided", () => {
97135
const result = shouldPreemptivelyCompactBeforePrompt({
98136
messages: [makeAssistantHistory("small assembled window")],

src/agents/pi-embedded-runner/run/preemptive-compaction.ts

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@ const TRUNCATION_ROUTE_BUFFER_TOKENS = 512;
1616

1717
export type { PreemptiveCompactionRoute } from "./preemptive-compaction.types.js";
1818

19+
export type PreemptiveCompactionDecision = {
20+
route: PreemptiveCompactionRoute;
21+
shouldCompact: boolean;
22+
estimatedPromptTokens: number;
23+
promptBudgetBeforeReserve: number;
24+
overflowTokens: number;
25+
toolResultReducibleChars: number;
26+
effectiveReserveTokens: number;
27+
};
28+
1929
export function estimatePrePromptTokens(params: {
2030
messages: AgentMessage[];
2131
systemPrompt?: string;
@@ -46,15 +56,7 @@ export function shouldPreemptivelyCompactBeforePrompt(params: {
4656
contextTokenBudget: number;
4757
reserveTokens: number;
4858
toolResultMaxChars?: number;
49-
}): {
50-
route: PreemptiveCompactionRoute;
51-
shouldCompact: boolean;
52-
estimatedPromptTokens: number;
53-
promptBudgetBeforeReserve: number;
54-
overflowTokens: number;
55-
toolResultReducibleChars: number;
56-
effectiveReserveTokens: number;
57-
} {
59+
}): PreemptiveCompactionDecision {
5860
let messagesForPressure = params.messages;
5961
let estimatedPromptTokens = estimatePrePromptTokens({
6062
messages: params.messages,
@@ -117,3 +119,34 @@ export function shouldPreemptivelyCompactBeforePrompt(params: {
117119
effectiveReserveTokens,
118120
};
119121
}
122+
123+
export function formatPrePromptPrecheckLog(params: {
124+
result: PreemptiveCompactionDecision;
125+
sessionKey?: string;
126+
sessionId?: string;
127+
provider: string;
128+
modelId: string;
129+
messageCount: number;
130+
unwindowedMessageCount?: number;
131+
contextTokenBudget: number;
132+
reserveTokens: number;
133+
sessionFile?: string;
134+
}): string {
135+
const { result } = params;
136+
return (
137+
`[context-overflow-precheck] pre-prompt check ` +
138+
`sessionKey=${params.sessionKey ?? params.sessionId ?? "unknown"} ` +
139+
`provider=${params.provider}/${params.modelId} ` +
140+
`route=${result.route} ` +
141+
`estimatedPromptTokens=${result.estimatedPromptTokens} ` +
142+
`promptBudgetBeforeReserve=${result.promptBudgetBeforeReserve} ` +
143+
`overflowTokens=${result.overflowTokens} ` +
144+
`toolResultReducibleChars=${result.toolResultReducibleChars} ` +
145+
`reserveTokens=${params.reserveTokens} ` +
146+
`effectiveReserveTokens=${result.effectiveReserveTokens} ` +
147+
`contextTokenBudget=${params.contextTokenBudget} ` +
148+
`messages=${params.messageCount} ` +
149+
`unwindowedMessages=${params.unwindowedMessageCount ?? params.messageCount} ` +
150+
`sessionFile=${params.sessionFile}`
151+
);
152+
}

0 commit comments

Comments
 (0)