feat: use session-reported Claude CLI context windows

This commit is contained in:
amosblomqvist
2026-10-28 20:36:42 +02:00
parent 17c94be327
commit 074ba7afe4
15 changed files with 359 additions and 36 deletions
+23 -3
View File
@@ -36,6 +36,7 @@
import type { AgentMessage } from "@earendil-works/pi-agent-core";
import type { AssistantMessage, Message, ToolResultMessage, UserMessage } from "@earendil-works/pi-ai";
import { QUESTION_TOOLS } from "./pending.ts";
import { CLAUDE_CODE_PROVIDER } from "./contracts/claude-code.ts";
import {
CONCLUDE_ACK_TEXT,
HANDOFF_TEXT,
@@ -90,7 +91,26 @@ declare module "@earendil-works/pi-agent-core" {
}
/** A record message: a native pi message (or our marker) plus the record id. */
export type LhMessage = (UserMessage | AssistantMessage | ToolResultMessage | LhMarkerMessage) & { id: string };
export type LhMessage = (UserMessage | AssistantMessage | ToolResultMessage | LhMarkerMessage) & {
id: string;
/** CLI-reported effective context budget, not a catalog model maximum.
* App-only metadata: never transmitted as provider/model message content. */
cliContextWindow?: number;
};
/** Latest response only: never borrow an older process/model's window when
* a fresh response has no metadata. Compaction invalidates the old report. */
export function cliContextWindowOf(messages: readonly LhMessage[]): { model: string; tokens: number } | null {
for (let i = messages.length - 1; i >= 0; i--) {
const message = messages[i]!;
if (message.role === "custom" && message.customType === "compaction") return null;
if (message.role !== "assistant") continue;
const tokens = message.cliContextWindow;
return message.provider === CLAUDE_CODE_PROVIDER && typeof tokens === "number" && Number.isSafeInteger(tokens) && tokens > 0
? { model: `${message.provider}:${message.model}`, tokens } : null;
}
return null;
}
/** A record message list is assignable to the agent's context — that IS
* the replay (ui-stream/chat-handler assign it to initialState.messages). */
@@ -617,8 +637,8 @@ export function toLlmMessages(messages: readonly AgentMessage[]): Message[] {
});
continue;
}
// Strip the record id: the wire carries the native shape only.
const { id: _id, ...native } = m as LhMessage;
// Strip app-only id/CLI context metadata: the wire carries the native shape only.
const { id: _id, cliContextWindow: _cliContextWindow, ...native } = m as LhMessage;
out.push(native as Message);
// Repair unanswered calls from completed generations, not calls in
// failed generations. Pi filters error/aborted assistants itself;