fix: refresh model preset settings on resume (#1052)
Co-authored-by: Letta <noreply@letta.com> Co-authored-by: letta-code <248085862+letta-code@users.noreply.github.com> Co-authored-by: jnjpng <jnjpng@users.noreply.github.com>
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
* Model resolution and handling utilities
|
||||
*/
|
||||
import modelsData from "../models.json";
|
||||
import { OPENAI_CODEX_PROVIDER_NAME } from "../providers/openai-codex-provider";
|
||||
|
||||
export const models = modelsData;
|
||||
|
||||
@@ -186,6 +187,68 @@ export function getModelUpdateArgs(
|
||||
return modelInfo?.updateArgs;
|
||||
}
|
||||
|
||||
type AgentModelSnapshot = {
|
||||
model?: string | null;
|
||||
llm_config?: {
|
||||
model?: string | null;
|
||||
model_endpoint_type?: string | null;
|
||||
reasoning_effort?: string | null;
|
||||
enable_reasoner?: boolean | null;
|
||||
} | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolve the current model preset + updateArgs for an existing agent.
|
||||
*
|
||||
* Used during startup/resume refresh to re-apply only preset-defined fields
|
||||
* (without requiring an explicit --model flag).
|
||||
*/
|
||||
export function getModelPresetUpdateForAgent(
|
||||
agent: AgentModelSnapshot,
|
||||
): { modelHandle: string; updateArgs: Record<string, unknown> } | null {
|
||||
const directHandle =
|
||||
typeof agent.model === "string" && agent.model.length > 0
|
||||
? agent.model
|
||||
: null;
|
||||
|
||||
const endpointType = agent.llm_config?.model_endpoint_type;
|
||||
const llmModel = agent.llm_config?.model;
|
||||
const llmDerivedHandle =
|
||||
typeof endpointType === "string" &&
|
||||
endpointType.length > 0 &&
|
||||
typeof llmModel === "string" &&
|
||||
llmModel.length > 0
|
||||
? `${
|
||||
endpointType === "chatgpt_oauth"
|
||||
? OPENAI_CODEX_PROVIDER_NAME
|
||||
: endpointType
|
||||
}/${llmModel}`
|
||||
: typeof llmModel === "string" && llmModel.includes("/")
|
||||
? llmModel
|
||||
: null;
|
||||
|
||||
const modelHandle = directHandle ?? llmDerivedHandle;
|
||||
if (!modelHandle) return null;
|
||||
|
||||
const modelInfo = getModelInfoForLlmConfig(modelHandle, {
|
||||
reasoning_effort: agent.llm_config?.reasoning_effort ?? null,
|
||||
enable_reasoner: agent.llm_config?.enable_reasoner ?? null,
|
||||
});
|
||||
|
||||
const updateArgs =
|
||||
(modelInfo?.updateArgs as Record<string, unknown> | undefined) ??
|
||||
getModelUpdateArgs(modelHandle);
|
||||
|
||||
if (!updateArgs || Object.keys(updateArgs).length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
modelHandle: modelInfo?.handle ?? modelHandle,
|
||||
updateArgs,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a model entry by handle with fuzzy matching support
|
||||
* @param handle - The full model handle
|
||||
|
||||
@@ -878,23 +878,56 @@ export async function handleHeadlessCommand(
|
||||
(!forceNew && !fromAfFile)
|
||||
);
|
||||
|
||||
// If resuming and a model or system prompt was specified, apply those changes
|
||||
if (isResumingAgent && (model || systemPromptPreset)) {
|
||||
// If resuming, always refresh model settings from presets to keep
|
||||
// preset-derived fields in sync, then apply optional command-line
|
||||
// overrides (model/system prompt).
|
||||
if (isResumingAgent) {
|
||||
const { updateAgentLLMConfig } = await import("./agent/modify");
|
||||
|
||||
if (model) {
|
||||
const { resolveModel } = await import("./agent/model");
|
||||
const modelHandle = resolveModel(model);
|
||||
if (!modelHandle) {
|
||||
if (typeof modelHandle !== "string") {
|
||||
console.error(`Error: Invalid model "${model}"`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Always apply model update - different model IDs can share the same
|
||||
// handle but have different settings (e.g., gpt-5.2-medium vs gpt-5.2-xhigh)
|
||||
const { updateAgentLLMConfig } = await import("./agent/modify");
|
||||
const updateArgs = getModelUpdateArgs(model);
|
||||
await updateAgentLLMConfig(agent.id, modelHandle, updateArgs);
|
||||
// Refresh agent state after model update
|
||||
agent = await client.agents.retrieve(agent.id);
|
||||
} else {
|
||||
const { getModelPresetUpdateForAgent } = await import("./agent/model");
|
||||
const presetRefresh = getModelPresetUpdateForAgent(agent);
|
||||
if (presetRefresh) {
|
||||
// Resume preset refresh is intentionally scoped for now.
|
||||
// We only force-refresh max_output_tokens + parallel_tool_calls.
|
||||
// Other preset fields available in models.json (for example:
|
||||
// context_window, reasoning_effort, enable_reasoner,
|
||||
// max_reasoning_tokens, verbosity, temperature,
|
||||
// thinking_budget) are intentionally not auto-applied yet.
|
||||
const resumeRefreshUpdateArgs: Record<string, unknown> = {};
|
||||
if (typeof presetRefresh.updateArgs.max_output_tokens === "number") {
|
||||
resumeRefreshUpdateArgs.max_output_tokens =
|
||||
presetRefresh.updateArgs.max_output_tokens;
|
||||
}
|
||||
if (typeof presetRefresh.updateArgs.parallel_tool_calls === "boolean") {
|
||||
resumeRefreshUpdateArgs.parallel_tool_calls =
|
||||
presetRefresh.updateArgs.parallel_tool_calls;
|
||||
}
|
||||
|
||||
if (Object.keys(resumeRefreshUpdateArgs).length > 0) {
|
||||
await updateAgentLLMConfig(
|
||||
agent.id,
|
||||
presetRefresh.modelHandle,
|
||||
resumeRefreshUpdateArgs,
|
||||
);
|
||||
// Refresh agent state after model update
|
||||
agent = await client.agents.retrieve(agent.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (systemPromptPreset) {
|
||||
|
||||
46
src/index.ts
46
src/index.ts
@@ -1789,8 +1789,12 @@ async function main(): Promise<void> {
|
||||
);
|
||||
setIsResumingSession(resuming);
|
||||
|
||||
// If resuming and a model or system prompt was specified, apply those changes
|
||||
if (resuming && (model || systemPromptPreset)) {
|
||||
// If resuming, always refresh model settings from presets to keep
|
||||
// preset-derived fields in sync, then apply optional command-line
|
||||
// overrides (model/system prompt).
|
||||
if (resuming) {
|
||||
const { updateAgentLLMConfig } = await import("./agent/modify");
|
||||
|
||||
if (model) {
|
||||
const { resolveModel, getModelUpdateArgs } = await import(
|
||||
"./agent/model"
|
||||
@@ -1803,11 +1807,47 @@ async function main(): Promise<void> {
|
||||
|
||||
// Always apply model update - different model IDs can share the same
|
||||
// handle but have different settings (e.g., gpt-5.2-medium vs gpt-5.2-xhigh)
|
||||
const { updateAgentLLMConfig } = await import("./agent/modify");
|
||||
const updateArgs = getModelUpdateArgs(model);
|
||||
await updateAgentLLMConfig(agent.id, modelHandle, updateArgs);
|
||||
// Refresh agent state after model update
|
||||
agent = await client.agents.retrieve(agent.id);
|
||||
} else {
|
||||
const { getModelPresetUpdateForAgent } = await import(
|
||||
"./agent/model"
|
||||
);
|
||||
const presetRefresh = getModelPresetUpdateForAgent(agent);
|
||||
if (presetRefresh) {
|
||||
// Resume preset refresh is intentionally scoped for now.
|
||||
// We only force-refresh max_output_tokens + parallel_tool_calls.
|
||||
// Other preset fields available in models.json (for example:
|
||||
// context_window, reasoning_effort, enable_reasoner,
|
||||
// max_reasoning_tokens, verbosity, temperature,
|
||||
// thinking_budget) are intentionally not auto-applied yet.
|
||||
const resumeRefreshUpdateArgs: Record<string, unknown> = {};
|
||||
if (
|
||||
typeof presetRefresh.updateArgs.max_output_tokens === "number"
|
||||
) {
|
||||
resumeRefreshUpdateArgs.max_output_tokens =
|
||||
presetRefresh.updateArgs.max_output_tokens;
|
||||
}
|
||||
if (
|
||||
typeof presetRefresh.updateArgs.parallel_tool_calls ===
|
||||
"boolean"
|
||||
) {
|
||||
resumeRefreshUpdateArgs.parallel_tool_calls =
|
||||
presetRefresh.updateArgs.parallel_tool_calls;
|
||||
}
|
||||
|
||||
if (Object.keys(resumeRefreshUpdateArgs).length > 0) {
|
||||
await updateAgentLLMConfig(
|
||||
agent.id,
|
||||
presetRefresh.modelHandle,
|
||||
resumeRefreshUpdateArgs,
|
||||
);
|
||||
// Refresh agent state after model update
|
||||
agent = await client.agents.retrieve(agent.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (systemPromptPreset) {
|
||||
|
||||
234
src/models.json
234
src/models.json
@@ -10,7 +10,8 @@
|
||||
"context_window": 200000,
|
||||
"max_output_tokens": 128000,
|
||||
"reasoning_effort": "high",
|
||||
"enable_reasoner": true
|
||||
"enable_reasoner": true,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -22,7 +23,8 @@
|
||||
"context_window": 1000000,
|
||||
"max_output_tokens": 128000,
|
||||
"reasoning_effort": "high",
|
||||
"enable_reasoner": true
|
||||
"enable_reasoner": true,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -34,7 +36,8 @@
|
||||
"context_window": 200000,
|
||||
"max_output_tokens": 128000,
|
||||
"reasoning_effort": "none",
|
||||
"enable_reasoner": false
|
||||
"enable_reasoner": false,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -47,7 +50,8 @@
|
||||
"max_output_tokens": 128000,
|
||||
"reasoning_effort": "low",
|
||||
"enable_reasoner": true,
|
||||
"max_reasoning_tokens": 4000
|
||||
"max_reasoning_tokens": 4000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -60,7 +64,8 @@
|
||||
"max_output_tokens": 128000,
|
||||
"reasoning_effort": "medium",
|
||||
"enable_reasoner": true,
|
||||
"max_reasoning_tokens": 12000
|
||||
"max_reasoning_tokens": 12000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -73,7 +78,8 @@
|
||||
"max_output_tokens": 128000,
|
||||
"reasoning_effort": "xhigh",
|
||||
"enable_reasoner": true,
|
||||
"max_reasoning_tokens": 31999
|
||||
"max_reasoning_tokens": 31999,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -84,7 +90,8 @@
|
||||
"updateArgs": {
|
||||
"context_window": 180000,
|
||||
"max_output_tokens": 64000,
|
||||
"max_reasoning_tokens": 31999
|
||||
"max_reasoning_tokens": 31999,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -95,7 +102,8 @@
|
||||
"updateArgs": {
|
||||
"enable_reasoner": false,
|
||||
"context_window": 180000,
|
||||
"max_output_tokens": 64000
|
||||
"max_output_tokens": 64000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -108,7 +116,8 @@
|
||||
"context_window": 200000,
|
||||
"max_output_tokens": 128000,
|
||||
"reasoning_effort": "high",
|
||||
"enable_reasoner": true
|
||||
"enable_reasoner": true,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -120,7 +129,8 @@
|
||||
"context_window": 200000,
|
||||
"max_output_tokens": 128000,
|
||||
"reasoning_effort": "none",
|
||||
"enable_reasoner": false
|
||||
"enable_reasoner": false,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -133,7 +143,8 @@
|
||||
"max_output_tokens": 128000,
|
||||
"reasoning_effort": "low",
|
||||
"enable_reasoner": true,
|
||||
"max_reasoning_tokens": 4000
|
||||
"max_reasoning_tokens": 4000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -146,7 +157,8 @@
|
||||
"max_output_tokens": 128000,
|
||||
"reasoning_effort": "medium",
|
||||
"enable_reasoner": true,
|
||||
"max_reasoning_tokens": 12000
|
||||
"max_reasoning_tokens": 12000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -159,7 +171,8 @@
|
||||
"max_output_tokens": 128000,
|
||||
"reasoning_effort": "xhigh",
|
||||
"enable_reasoner": true,
|
||||
"max_reasoning_tokens": 31999
|
||||
"max_reasoning_tokens": 31999,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -170,7 +183,8 @@
|
||||
"updateArgs": {
|
||||
"context_window": 180000,
|
||||
"max_output_tokens": 64000,
|
||||
"max_reasoning_tokens": 31999
|
||||
"max_reasoning_tokens": 31999,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -183,7 +197,8 @@
|
||||
"updateArgs": {
|
||||
"context_window": 180000,
|
||||
"max_output_tokens": 64000,
|
||||
"max_reasoning_tokens": 31999
|
||||
"max_reasoning_tokens": 31999,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -194,7 +209,8 @@
|
||||
"isFeatured": true,
|
||||
"updateArgs": {
|
||||
"context_window": 180000,
|
||||
"max_output_tokens": 64000
|
||||
"max_output_tokens": 64000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -206,7 +222,8 @@
|
||||
"reasoning_effort": "none",
|
||||
"verbosity": "low",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -218,7 +235,8 @@
|
||||
"reasoning_effort": "low",
|
||||
"verbosity": "low",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -230,7 +248,8 @@
|
||||
"reasoning_effort": "medium",
|
||||
"verbosity": "low",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -243,7 +262,8 @@
|
||||
"reasoning_effort": "high",
|
||||
"verbosity": "low",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -255,7 +275,8 @@
|
||||
"reasoning_effort": "xhigh",
|
||||
"verbosity": "low",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -267,7 +288,8 @@
|
||||
"reasoning_effort": "medium",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -279,7 +301,8 @@
|
||||
"reasoning_effort": "high",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -291,7 +314,8 @@
|
||||
"reasoning_effort": "medium",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -303,7 +327,8 @@
|
||||
"reasoning_effort": "high",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -315,7 +340,8 @@
|
||||
"reasoning_effort": "medium",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -327,7 +353,8 @@
|
||||
"reasoning_effort": "high",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -339,7 +366,8 @@
|
||||
"reasoning_effort": "medium",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -351,7 +379,8 @@
|
||||
"reasoning_effort": "high",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -363,7 +392,8 @@
|
||||
"reasoning_effort": "xhigh",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -375,7 +405,8 @@
|
||||
"reasoning_effort": "medium",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -387,7 +418,8 @@
|
||||
"reasoning_effort": "none",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -399,7 +431,8 @@
|
||||
"reasoning_effort": "low",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -412,7 +445,8 @@
|
||||
"reasoning_effort": "medium",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -424,7 +458,8 @@
|
||||
"reasoning_effort": "high",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -436,7 +471,8 @@
|
||||
"reasoning_effort": "xhigh",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -448,7 +484,8 @@
|
||||
"reasoning_effort": "none",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -460,7 +497,8 @@
|
||||
"reasoning_effort": "low",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -473,7 +511,8 @@
|
||||
"reasoning_effort": "medium",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -485,7 +524,8 @@
|
||||
"reasoning_effort": "high",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -497,7 +537,8 @@
|
||||
"reasoning_effort": "xhigh",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -509,7 +550,8 @@
|
||||
"reasoning_effort": "none",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -521,7 +563,8 @@
|
||||
"reasoning_effort": "low",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -533,7 +576,8 @@
|
||||
"reasoning_effort": "medium",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -545,7 +589,8 @@
|
||||
"reasoning_effort": "high",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -557,7 +602,8 @@
|
||||
"reasoning_effort": "none",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -570,7 +616,8 @@
|
||||
"reasoning_effort": "medium",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -582,7 +629,8 @@
|
||||
"reasoning_effort": "high",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -594,7 +642,8 @@
|
||||
"reasoning_effort": "medium",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -606,7 +655,8 @@
|
||||
"reasoning_effort": "high",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -618,7 +668,8 @@
|
||||
"reasoning_effort": "xhigh",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -630,7 +681,8 @@
|
||||
"reasoning_effort": "minimal",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -642,7 +694,8 @@
|
||||
"reasoning_effort": "low",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -654,7 +707,8 @@
|
||||
"reasoning_effort": "medium",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -666,7 +720,8 @@
|
||||
"reasoning_effort": "high",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -678,7 +733,8 @@
|
||||
"reasoning_effort": "medium",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -690,7 +746,8 @@
|
||||
"reasoning_effort": "medium",
|
||||
"verbosity": "medium",
|
||||
"context_window": 272000,
|
||||
"max_output_tokens": 128000
|
||||
"max_output_tokens": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -701,7 +758,8 @@
|
||||
"isFeatured": true,
|
||||
"free": true,
|
||||
"updateArgs": {
|
||||
"context_window": 200000
|
||||
"context_window": 200000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -712,7 +770,8 @@
|
||||
"isFeatured": true,
|
||||
"free": true,
|
||||
"updateArgs": {
|
||||
"context_window": 200000
|
||||
"context_window": 200000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -724,7 +783,8 @@
|
||||
"free": true,
|
||||
"updateArgs": {
|
||||
"context_window": 160000,
|
||||
"max_output_tokens": 64000
|
||||
"max_output_tokens": 64000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -736,7 +796,8 @@
|
||||
"free": true,
|
||||
"updateArgs": {
|
||||
"context_window": 160000,
|
||||
"max_output_tokens": 64000
|
||||
"max_output_tokens": 64000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -746,7 +807,8 @@
|
||||
"description": "Minimax's latest model",
|
||||
"updateArgs": {
|
||||
"context_window": 160000,
|
||||
"max_output_tokens": 64000
|
||||
"max_output_tokens": 64000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -755,7 +817,8 @@
|
||||
"label": "Kimi K2",
|
||||
"description": "Kimi's K2 model",
|
||||
"updateArgs": {
|
||||
"context_window": 262144
|
||||
"context_window": 262144,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -766,7 +829,8 @@
|
||||
"updateArgs": {
|
||||
"context_window": 256000,
|
||||
"max_output_tokens": 16000,
|
||||
"temperature": 1.0
|
||||
"temperature": 1.0,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -776,7 +840,8 @@
|
||||
"description": "Kimi's latest coding model",
|
||||
"isFeatured": true,
|
||||
"updateArgs": {
|
||||
"context_window": 262144
|
||||
"context_window": 262144,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -785,7 +850,8 @@
|
||||
"label": "DeepSeek Chat V3.1",
|
||||
"description": "DeepSeek V3.1 model",
|
||||
"updateArgs": {
|
||||
"context_window": 128000
|
||||
"context_window": 128000,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -794,7 +860,11 @@
|
||||
"label": "Gemini 3.1 Pro",
|
||||
"description": "Google's latest and smartest model",
|
||||
"isFeatured": true,
|
||||
"updateArgs": { "context_window": 180000, "temperature": 1.0 }
|
||||
"updateArgs": {
|
||||
"context_window": 180000,
|
||||
"temperature": 1.0,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "gemini-3",
|
||||
@@ -802,7 +872,11 @@
|
||||
"label": "Gemini 3 Pro",
|
||||
"description": "Google's smartest model",
|
||||
"isFeatured": true,
|
||||
"updateArgs": { "context_window": 180000, "temperature": 1.0 }
|
||||
"updateArgs": {
|
||||
"context_window": 180000,
|
||||
"temperature": 1.0,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "gemini-3-flash",
|
||||
@@ -810,55 +884,63 @@
|
||||
"label": "Gemini 3 Flash",
|
||||
"description": "Google's fastest Gemini 3 model",
|
||||
"isFeatured": true,
|
||||
"updateArgs": { "context_window": 180000, "temperature": 1.0 }
|
||||
"updateArgs": {
|
||||
"context_window": 180000,
|
||||
"temperature": 1.0,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "gemini-flash",
|
||||
"handle": "google_ai/gemini-2.5-flash",
|
||||
"label": "Gemini 2.5 Flash",
|
||||
"description": "Google's fastest model",
|
||||
"updateArgs": { "context_window": 180000 }
|
||||
"updateArgs": { "context_window": 180000, "parallel_tool_calls": true }
|
||||
},
|
||||
{
|
||||
"id": "gemini-pro",
|
||||
"handle": "google_ai/gemini-2.5-pro",
|
||||
"label": "Gemini 2.5 Pro",
|
||||
"description": "Google's last generation flagship model",
|
||||
"updateArgs": { "context_window": 180000 }
|
||||
"updateArgs": { "context_window": 180000, "parallel_tool_calls": true }
|
||||
},
|
||||
{
|
||||
"id": "gpt-4.1",
|
||||
"handle": "openai/gpt-4.1",
|
||||
"label": "GPT-4.1",
|
||||
"description": "OpenAI's most recent non-reasoner model",
|
||||
"updateArgs": { "context_window": 1047576 }
|
||||
"updateArgs": { "context_window": 1047576, "parallel_tool_calls": true }
|
||||
},
|
||||
{
|
||||
"id": "gpt-4.1-mini",
|
||||
"handle": "openai/gpt-4.1-mini-2025-04-14",
|
||||
"label": "GPT-4.1-Mini",
|
||||
"description": "OpenAI's most recent non-reasoner model (mini version)",
|
||||
"updateArgs": { "context_window": 1047576 }
|
||||
"updateArgs": { "context_window": 1047576, "parallel_tool_calls": true }
|
||||
},
|
||||
{
|
||||
"id": "gpt-4.1-nano",
|
||||
"handle": "openai/gpt-4.1-nano-2025-04-14",
|
||||
"label": "GPT-4.1-Nano",
|
||||
"description": "OpenAI's most recent non-reasoner model (nano version)",
|
||||
"updateArgs": { "context_window": 1047576 }
|
||||
"updateArgs": { "context_window": 1047576, "parallel_tool_calls": true }
|
||||
},
|
||||
{
|
||||
"id": "o4-mini",
|
||||
"handle": "openai/o4-mini",
|
||||
"label": "o4-mini",
|
||||
"description": "OpenAI's latest o-series reasoning model",
|
||||
"updateArgs": { "context_window": 180000 }
|
||||
"updateArgs": { "context_window": 180000, "parallel_tool_calls": true }
|
||||
},
|
||||
{
|
||||
"id": "gemini-3-vertex",
|
||||
"handle": "google_vertex/gemini-3-pro-preview",
|
||||
"label": "Gemini 3 Pro",
|
||||
"description": "Google's smartest Gemini 3 Pro model (via Vertex AI)",
|
||||
"updateArgs": { "context_window": 180000, "temperature": 1.0 }
|
||||
"updateArgs": {
|
||||
"context_window": 180000,
|
||||
"temperature": 1.0,
|
||||
"parallel_tool_calls": true
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
81
src/tests/agent/model-preset-refresh.wiring.test.ts
Normal file
81
src/tests/agent/model-preset-refresh.wiring.test.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
describe("model preset refresh wiring", () => {
|
||||
test("model.ts exports preset refresh helper", () => {
|
||||
const path = fileURLToPath(
|
||||
new URL("../../agent/model.ts", import.meta.url),
|
||||
);
|
||||
const source = readFileSync(path, "utf-8");
|
||||
|
||||
expect(source).toContain("export function getModelPresetUpdateForAgent(");
|
||||
expect(source).toContain("OPENAI_CODEX_PROVIDER_NAME");
|
||||
expect(source).toContain("getModelInfoForLlmConfig(modelHandle");
|
||||
});
|
||||
|
||||
test("modify.ts keeps direct updateArgs-driven model update flow", () => {
|
||||
const path = fileURLToPath(
|
||||
new URL("../../agent/modify.ts", import.meta.url),
|
||||
);
|
||||
const source = readFileSync(path, "utf-8");
|
||||
|
||||
const start = source.indexOf("export async function updateAgentLLMConfig(");
|
||||
const end = source.indexOf(
|
||||
"export interface SystemPromptUpdateResult",
|
||||
start,
|
||||
);
|
||||
expect(start).toBeGreaterThanOrEqual(0);
|
||||
expect(end).toBeGreaterThan(start);
|
||||
const updateSegment = source.slice(start, end);
|
||||
|
||||
expect(updateSegment).toContain(
|
||||
"buildModelSettings(modelHandle, updateArgs)",
|
||||
);
|
||||
expect(updateSegment).toContain("getModelContextWindow(modelHandle)");
|
||||
expect(updateSegment).not.toContain(
|
||||
"const currentAgent = await client.agents.retrieve(",
|
||||
);
|
||||
expect(source).not.toContain(
|
||||
'hasUpdateArg(updateArgs, "parallel_tool_calls")',
|
||||
);
|
||||
});
|
||||
|
||||
test("interactive resume flow refreshes model preset without explicit --model", () => {
|
||||
const path = fileURLToPath(new URL("../../index.ts", import.meta.url));
|
||||
const source = readFileSync(path, "utf-8");
|
||||
|
||||
expect(source).toContain("if (resuming)");
|
||||
expect(source).toContain("getModelPresetUpdateForAgent");
|
||||
expect(source).toContain(
|
||||
"const presetRefresh = getModelPresetUpdateForAgent(agent)",
|
||||
);
|
||||
expect(source).toContain("resumeRefreshUpdateArgs");
|
||||
expect(source).toContain("presetRefresh.updateArgs.max_output_tokens");
|
||||
expect(source).toContain("presetRefresh.updateArgs.parallel_tool_calls");
|
||||
expect(source).toContain("await updateAgentLLMConfig(");
|
||||
expect(source).toContain("presetRefresh.modelHandle");
|
||||
expect(source).not.toContain(
|
||||
"await updateAgentLLMConfig(\n agent.id,\n presetRefresh.modelHandle,\n presetRefresh.updateArgs,",
|
||||
);
|
||||
});
|
||||
|
||||
test("headless resume flow refreshes model preset without explicit --model", () => {
|
||||
const path = fileURLToPath(new URL("../../headless.ts", import.meta.url));
|
||||
const source = readFileSync(path, "utf-8");
|
||||
|
||||
expect(source).toContain("if (isResumingAgent)");
|
||||
expect(source).toContain("getModelPresetUpdateForAgent");
|
||||
expect(source).toContain(
|
||||
"const presetRefresh = getModelPresetUpdateForAgent(agent)",
|
||||
);
|
||||
expect(source).toContain("resumeRefreshUpdateArgs");
|
||||
expect(source).toContain("presetRefresh.updateArgs.max_output_tokens");
|
||||
expect(source).toContain("presetRefresh.updateArgs.parallel_tool_calls");
|
||||
expect(source).toContain("await updateAgentLLMConfig(");
|
||||
expect(source).toContain("presetRefresh.modelHandle");
|
||||
expect(source).not.toContain(
|
||||
"await updateAgentLLMConfig(\n agent.id,\n presetRefresh.modelHandle,\n presetRefresh.updateArgs,",
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user