fix(codex): cap native reserve for small windows

This commit is contained in:
Peter Steinberger
2026-05-30 07:57:15 +02:00
parent 4021ea58ad
commit 466bfbe78c
2 changed files with 46 additions and 1 deletions

View File

@@ -112,6 +112,41 @@ describe("Codex app-server startup binding", () => {
expect(savedBinding).toBeUndefined();
});
it("caps the default native reserve so small context windows keep prompt budget", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
const agentDir = path.join(tempDir, "agent");
await writeExistingBinding(sessionFile, workspaceDir, { dynamicToolsFingerprint: "[]" });
await writeSessionRecord(sessionFile, { totalTokens: 100 });
const rolloutDir = path.join(agentDir, "codex-home", "sessions");
await fs.mkdir(rolloutDir, { recursive: true });
await fs.writeFile(
path.join(rolloutDir, "rollout-thread-existing.jsonl"),
`${JSON.stringify({
payload: {
type: "token_count",
info: {
last_token_usage: {
total_tokens: 100,
},
model_context_window: 16_000,
},
},
})}\n`,
);
const binding = await rotateOversizedCodexAppServerStartupBinding({
binding: await readCodexAppServerBinding(sessionFile),
sessionFile,
agentDir,
config: undefined,
});
expect(binding?.threadId).toBe("thread-existing");
const savedBinding = await readCodexAppServerBinding(sessionFile);
expect(savedBinding?.threadId).toBe("thread-existing");
});
it("honors shorthand byte units for native rollout limits", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");

View File

@@ -13,6 +13,8 @@ import { clearCodexAppServerBinding, type CodexAppServerThreadBinding } from "./
// thread that is already too close to the server-side window for the next turn.
const CODEX_APP_SERVER_NATIVE_THREAD_FALLBACK_MAX_TOKENS = 300_000;
const CODEX_APP_SERVER_NATIVE_THREAD_DEFAULT_RESERVE_TOKENS = 20_000;
const CODEX_APP_SERVER_NATIVE_THREAD_MIN_PROMPT_BUDGET_TOKENS = 8_000;
const CODEX_APP_SERVER_NATIVE_THREAD_MIN_PROMPT_BUDGET_RATIO = 0.5;
const CODEX_APP_SERVER_BYTE_UNITS: Record<string, number> = {
b: 1,
k: 1024,
@@ -250,7 +252,15 @@ function resolveCodexAppServerNativeThreadTokenFuse(params: {
: 0;
const contextWindow =
params.modelContextWindow ?? CODEX_APP_SERVER_NATIVE_THREAD_FALLBACK_MAX_TOKENS;
return Math.max(1, contextWindow - params.reserveTokens - projectedTurnTokens);
const minPromptBudget = Math.min(
CODEX_APP_SERVER_NATIVE_THREAD_MIN_PROMPT_BUDGET_TOKENS,
Math.max(1, Math.floor(contextWindow * CODEX_APP_SERVER_NATIVE_THREAD_MIN_PROMPT_BUDGET_RATIO)),
);
const effectiveReserveTokens = Math.min(
params.reserveTokens,
Math.max(0, contextWindow - minPromptBudget),
);
return Math.max(1, contextWindow - effectiveReserveTokens - projectedTurnTokens);
}
function maxFiniteNumber(values: Array<number | undefined>): number | undefined {