diff --git a/src/agent/modify.ts b/src/agent/modify.ts index 59bf9ea..23ae0e0 100644 --- a/src/agent/modify.ts +++ b/src/agent/modify.ts @@ -182,21 +182,32 @@ function buildModelSettings( * @param agentId - The agent ID * @param modelHandle - The model handle (e.g., "anthropic/claude-sonnet-4-5-20250929") * @param updateArgs - Additional config args (context_window, reasoning_effort, enable_reasoner, etc.) - * @param preserveParallelToolCalls - If true, preserves the parallel_tool_calls setting when updating the model + * @param options - Optional update behavior overrides * @returns The updated agent state from the server (includes llm_config and model_settings) */ +export interface UpdateAgentLLMConfigOptions { + preserveContextWindow?: boolean; +} + export async function updateAgentLLMConfig( agentId: string, modelHandle: string, updateArgs?: Record, + options?: UpdateAgentLLMConfigOptions, ): Promise { const client = await getClient(); const modelSettings = buildModelSettings(modelHandle, updateArgs); - // First try updateArgs, then fall back to API-cached context window for BYOK models + const explicitContextWindow = updateArgs?.context_window as + | number + | undefined; + const shouldPreserveContextWindow = options?.preserveContextWindow === true; + // Resume refresh updates should not implicitly reset context window. const contextWindow = - (updateArgs?.context_window as number | undefined) ?? - (await getModelContextWindow(modelHandle)); + explicitContextWindow ?? + (!shouldPreserveContextWindow + ? await getModelContextWindow(modelHandle) + : undefined); const hasModelSettings = Object.keys(modelSettings).length > 0; // MiniMax doesn't have a dedicated ModelSettings class, so model_settings diff --git a/src/headless.ts b/src/headless.ts index b31804e..f6c04db 100644 --- a/src/headless.ts +++ b/src/headless.ts @@ -918,6 +918,7 @@ export async function handleHeadlessCommand( agent.id, presetRefresh.modelHandle, resumeRefreshUpdateArgs, + { preserveContextWindow: true }, ); } } diff --git a/src/index.ts b/src/index.ts index 88a6c09..0f3f4c1 100755 --- a/src/index.ts +++ b/src/index.ts @@ -1761,6 +1761,7 @@ async function main(): Promise { agent.id, presetRefresh.modelHandle, resumeRefreshUpdateArgs, + { preserveContextWindow: true }, ); } } diff --git a/src/tests/agent/model-preset-refresh.wiring.test.ts b/src/tests/agent/model-preset-refresh.wiring.test.ts index e3cfeb5..6d5d011 100644 --- a/src/tests/agent/model-preset-refresh.wiring.test.ts +++ b/src/tests/agent/model-preset-refresh.wiring.test.ts @@ -14,7 +14,7 @@ describe("model preset refresh wiring", () => { expect(source).toContain("getModelInfoForLlmConfig(modelHandle"); }); - test("modify.ts keeps direct updateArgs-driven model update flow", () => { + test("modify.ts supports preserving context window during resume refresh", () => { const path = fileURLToPath( new URL("../../agent/modify.ts", import.meta.url), ); @@ -32,7 +32,14 @@ describe("model preset refresh wiring", () => { expect(updateSegment).toContain( "buildModelSettings(modelHandle, updateArgs)", ); + expect(source).toContain("export interface UpdateAgentLLMConfigOptions"); + expect(updateSegment).toContain("options?: UpdateAgentLLMConfigOptions"); + expect(updateSegment).toContain("shouldPreserveContextWindow"); expect(updateSegment).toContain("getModelContextWindow(modelHandle)"); + expect(updateSegment).toContain("options?.preserveContextWindow === true"); + expect(updateSegment).not.toContain( + "(updateArgs?.context_window as number | undefined) ??\n (await getModelContextWindow(modelHandle));", + ); expect(updateSegment).not.toContain( "const currentAgent = await client.agents.retrieve(", ); @@ -175,6 +182,9 @@ describe("model preset refresh wiring", () => { expect(source).toContain("needsUpdate"); expect(source).toContain("await updateAgentLLMConfig("); expect(source).toContain("presetRefresh.modelHandle"); + expect(source).toMatch( + /resumeRefreshUpdateArgs,\s*\{\s*preserveContextWindow:\s*true\s*\},/, + ); expect(source).not.toContain( "await updateAgentLLMConfig(\n agent.id,\n presetRefresh.modelHandle,\n presetRefresh.updateArgs,", ); @@ -194,6 +204,9 @@ describe("model preset refresh wiring", () => { expect(source).toContain("needsUpdate"); expect(source).toContain("await updateAgentLLMConfig("); expect(source).toContain("presetRefresh.modelHandle"); + expect(source).toMatch( + /resumeRefreshUpdateArgs,\s*\{\s*preserveContextWindow:\s*true\s*\},/, + ); expect(source).not.toContain( "await updateAgentLLMConfig(\n agent.id,\n presetRefresh.modelHandle,\n presetRefresh.updateArgs,", );