fix(context-window): prioritize config over model for context window resolution
resolveContextWindowInfo now uses config > model > default priority so explicit --context-window flag overrides model defaults. Also adds --context-window CLI option to the run command. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
74c0ca0ddc
commit
40a2e8ae55
3 changed files with 32 additions and 13 deletions
|
|
@ -28,6 +28,7 @@ type RunOptions = {
|
|||
runLog?: boolean;
|
||||
toolsAllow?: string[];
|
||||
toolsDeny?: string[];
|
||||
contextWindow?: number;
|
||||
help?: boolean;
|
||||
};
|
||||
|
||||
|
|
@ -49,6 +50,7 @@ ${cyan("Options:")}
|
|||
${yellow("--session")} ID Session ID for persistence
|
||||
${yellow("--debug")} Enable debug logging
|
||||
${yellow("--run-log")} Enable structured run logging (run-log.jsonl)
|
||||
${yellow("--context-window")} N Override context window token count
|
||||
${yellow("--help")}, -h Show this help
|
||||
|
||||
${cyan("Tools Configuration:")}
|
||||
|
|
@ -141,6 +143,11 @@ function parseArgs(argv: string[]): { opts: RunOptions; prompt: string } {
|
|||
opts.toolsDeny = value?.split(",").map((s) => s.trim()) ?? [];
|
||||
continue;
|
||||
}
|
||||
if (arg === "--context-window") {
|
||||
const value = args.shift();
|
||||
opts.contextWindow = value ? parseInt(value, 10) : undefined;
|
||||
continue;
|
||||
}
|
||||
if (arg === "--") {
|
||||
promptParts.push(...args);
|
||||
break;
|
||||
|
|
@ -213,6 +220,7 @@ export async function runCommand(args: string[]): Promise<void> {
|
|||
debug: opts.debug,
|
||||
enableRunLog,
|
||||
tools: toolsConfig,
|
||||
contextWindowTokens: opts.contextWindow,
|
||||
});
|
||||
|
||||
const sessionDir = join(DATA_DIR, "sessions", agent.sessionId);
|
||||
|
|
|
|||
|
|
@ -24,15 +24,15 @@ describe("guard", () => {
|
|||
});
|
||||
|
||||
describe("resolveContextWindowInfo", () => {
|
||||
it("should prioritize model context window", () => {
|
||||
it("should prioritize config over model (explicit override wins)", () => {
|
||||
const result = resolveContextWindowInfo({
|
||||
modelContextWindow: 100_000,
|
||||
configContextTokens: 50_000,
|
||||
defaultTokens: 200_000,
|
||||
});
|
||||
|
||||
expect(result.tokens).toBe(100_000);
|
||||
expect(result.source).toBe("model");
|
||||
expect(result.tokens).toBe(50_000);
|
||||
expect(result.source).toBe("config");
|
||||
});
|
||||
|
||||
it("should fall back to config when model is undefined", () => {
|
||||
|
|
@ -105,13 +105,23 @@ describe("guard", () => {
|
|||
expect(result.source).toBe("config");
|
||||
});
|
||||
|
||||
it("should floor decimal values", () => {
|
||||
it("should floor decimal values from model", () => {
|
||||
const result = resolveContextWindowInfo({
|
||||
modelContextWindow: 100_000.9,
|
||||
});
|
||||
|
||||
expect(result.tokens).toBe(100_000);
|
||||
});
|
||||
|
||||
it("should use model when config is not provided", () => {
|
||||
const result = resolveContextWindowInfo({
|
||||
modelContextWindow: 100_000,
|
||||
defaultTokens: 200_000,
|
||||
});
|
||||
|
||||
expect(result.tokens).toBe(100_000);
|
||||
expect(result.source).toBe("model");
|
||||
});
|
||||
});
|
||||
|
||||
describe("evaluateContextWindowGuard", () => {
|
||||
|
|
|
|||
|
|
@ -27,28 +27,29 @@ function normalizePositiveInt(value: unknown): number | null {
|
|||
/**
|
||||
* Resolve context window information
|
||||
*
|
||||
* Priority: model > config > default
|
||||
* Priority: config > model > default
|
||||
* (Explicit config override always wins — allows capping context for testing/cost control)
|
||||
*/
|
||||
export function resolveContextWindowInfo(params: {
|
||||
/** Model's contextWindow property */
|
||||
modelContextWindow?: number | undefined;
|
||||
/** Context tokens specified in config */
|
||||
/** Context tokens specified in config (explicit override, highest priority) */
|
||||
configContextTokens?: number | undefined;
|
||||
/** Default value */
|
||||
defaultTokens?: number | undefined;
|
||||
}): ContextWindowInfo {
|
||||
// 1. Try getting from model
|
||||
const fromModel = normalizePositiveInt(params.modelContextWindow);
|
||||
if (fromModel) {
|
||||
return { tokens: fromModel, source: "model" };
|
||||
}
|
||||
|
||||
// 2. Try getting from config
|
||||
// 1. Explicit config override always wins
|
||||
const fromConfig = normalizePositiveInt(params.configContextTokens);
|
||||
if (fromConfig) {
|
||||
return { tokens: fromConfig, source: "config" };
|
||||
}
|
||||
|
||||
// 2. Try getting from model
|
||||
const fromModel = normalizePositiveInt(params.modelContextWindow);
|
||||
if (fromModel) {
|
||||
return { tokens: fromModel, source: "model" };
|
||||
}
|
||||
|
||||
// 3. Use default value
|
||||
return {
|
||||
tokens: Math.floor(params.defaultTokens ?? DEFAULT_CONTEXT_TOKENS),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue