fix: Default model selection (#533)

* fix: Default model selection

* cr
This commit is contained in:
Brace Sproul 2025-07-25 12:05:27 -07:00 • committed by GitHub
parent f61ea79b13
commit 3ec90ef6e6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 110 additions and 107 deletions

View file

@ -15,7 +15,7 @@ import {
loadModel,
supportsParallelToolCallsParam,
Task,
} from "../../../../utils/load-model.js";
} from "../../../../utils/llms/index.js";
import { Command, END } from "@langchain/langgraph";
import { getMessageContentString } from "@open-swe/shared/messages";
import {

View file

@ -5,7 +5,7 @@ import {
loadModel,
supportsParallelToolCallsParam,
Task,
} from "../../../utils/load-model.js";
} from "../../../utils/llms/index.js";
import { getMessageString } from "../../../utils/message/content.js";
export async function createIssueFieldsFromMessages(

View file

@ -9,7 +9,7 @@ import {
loadModel,
supportsParallelToolCallsParam,
Task,
} from "../../../utils/load-model.js";
} from "../../../utils/llms/index.js";
import { getMissingMessages } from "../../../utils/github/issue-messages.js";
import { getMessageString } from "../../../utils/message/content.js";
import { isHumanMessage } from "@langchain/core/messages";

View file

@ -2,7 +2,7 @@ import {
loadModel,
supportsParallelToolCallsParam,
Task,
} from "../../../../utils/load-model.js";
} from "../../../../utils/llms/index.js";
import {
createGetURLContentTool,
createShellTool,

View file

@ -6,7 +6,7 @@ import {
loadModel,
supportsParallelToolCallsParam,
Task,
} from "../../../../utils/load-model.js";
} from "../../../../utils/llms/index.js";
import {
PlannerGraphState,
PlannerGraphUpdate,

View file

@ -9,7 +9,7 @@ import {
loadModel,
supportsParallelToolCallsParam,
Task,
} from "../../../utils/load-model.js";
} from "../../../utils/llms/index.js";
import { getMessageString } from "../../../utils/message/content.js";
import { formatUserRequestPrompt } from "../../../utils/user-request.js";
import { formatCustomRulesPrompt } from "../../../utils/custom-rules.js";

View file

@ -17,7 +17,7 @@ import {
loadModel,
supportsParallelToolCallsParam,
Task,
} from "../../../utils/load-model.js";
} from "../../../utils/llms/index.js";
import { FallbackRunnable } from "../../../utils/runtime-fallback.js";
const systemPromptIdentifyChanges = `You are operating as an agentic coding assistant built by LangChain. You've previously been given a task to generate a plan of action for, to address the user's initial request.

View file

@ -18,7 +18,7 @@ import {
loadModel,
supportsParallelToolCallsParam,
Task,
} from "../../../utils/load-model.js";
} from "../../../utils/llms/index.js";
import { z } from "zod";
import { createLogger, LogLevel } from "../../../utils/logger.js";
import {

View file

@ -4,7 +4,7 @@ import {
GraphUpdate,
PlanItem,
} from "@open-swe/shared/open-swe/types";
import { loadModel, Task } from "../../../utils/load-model.js";
import { loadModel, Task } from "../../../utils/llms/index.js";
import { getMessageContentString } from "@open-swe/shared/messages";
import { getMessageString } from "../../../utils/message/content.js";
import { createLogger, LogLevel } from "../../../utils/logger.js";

View file

@ -8,7 +8,7 @@ import {
loadModel,
supportsParallelToolCallsParam,
Task,
} from "../../../../utils/load-model.js";
} from "../../../../utils/llms/index.js";
import {
createShellTool,
createApplyPatchTool,

View file

@ -20,7 +20,7 @@ import {
loadModel,
supportsParallelToolCallsParam,
Task,
} from "../../../utils/load-model.js";
} from "../../../utils/llms/index.js";
import { formatPlanPromptWithSummaries } from "../../../utils/plan-prompt.js";
import { formatUserRequestPrompt } from "../../../utils/user-request.js";
import { AIMessage, BaseMessage, ToolMessage } from "@langchain/core/messages";

View file

@ -5,7 +5,7 @@ import {
GraphUpdate,
PlanItem,
} from "@open-swe/shared/open-swe/types";
import { loadModel, Task } from "../../../utils/load-model.js";
import { loadModel, Task } from "../../../utils/llms/index.js";
import {
AIMessage,
BaseMessage,

View file

@ -10,7 +10,7 @@ import {
loadModel,
supportsParallelToolCallsParam,
Task,
} from "../../../utils/load-model.js";
} from "../../../utils/llms/index.js";
import { z } from "zod";
import {
getActiveTask,

View file

@ -18,7 +18,7 @@ import {
loadModel,
supportsParallelToolCallsParam,
Task,
} from "../../../utils/load-model.js";
} from "../../../utils/llms/index.js";
import { GraphConfig, PlanItem } from "@open-swe/shared/open-swe/types";
import { z } from "zod";
import { addTaskPlanToIssue } from "../../../utils/github/issue-task.js";

View file

@ -2,7 +2,7 @@ import {
loadModel,
supportsParallelToolCallsParam,
Task,
} from "../../../../utils/load-model.js";
} from "../../../../utils/llms/index.js";
import {
ReviewerGraphState,
ReviewerGraphUpdate,

View file

@ -15,7 +15,7 @@ import {
loadModel,
supportsParallelToolCallsParam,
Task,
} from "../../utils/load-model.js";
} from "../../utils/llms/index.js";
import { trackCachePerformance } from "../../utils/caching.js";
const logger = createLogger(LogLevel.INFO, "SharedDiagnoseError");

View file

@ -2,7 +2,7 @@ import { tool } from "@langchain/core/tools";
import { createLogger, LogLevel } from "../../utils/logger.js";
import { createSearchDocumentForToolFields } from "@open-swe/shared/open-swe/tools";
import { FireCrawlLoader } from "@langchain/community/document_loaders/web/firecrawl";
import { loadModel, Task } from "../../utils/load-model.js";
import { loadModel, Task } from "../../utils/llms/index.js";
import { GraphConfig, GraphState } from "@open-swe/shared/open-swe/types";
import { getMessageContentString } from "@open-swe/shared/messages";
import { DOCUMENT_SEARCH_PROMPT } from "./prompt.js";

View file

@ -0,0 +1,33 @@
export enum Task {
/**
* Used for programmer tasks. This includes: writing code,
* generating plans, taking context gathering actions, etc.
*/
PROGRAMMER = "programmer",
/**
* Used for routing tasks. This includes: initial request
* routing to different agents.
*/
ROUTER = "router",
/**
* Used for summarizing tasks. This includes: summarizing
* the conversation history, summarizing actions taken during
* a task execution, etc. Should be a slightly advanced model.
*/
SUMMARIZER = "summarizer",
}
export const TASK_TO_CONFIG_DEFAULTS_MAP = {
[Task.PROGRAMMER]: {
modelName: "anthropic:claude-sonnet-4-0",
temperature: 0,
},
[Task.ROUTER]: {
modelName: "anthropic:claude-3-5-haiku-latest",
temperature: 0,
},
[Task.SUMMARIZER]: {
modelName: "openai:gpt-4.1-mini",
temperature: 0,
},
};

View file

@ -0,0 +1,2 @@
export * from "./load-model.js";
export * from "./constants.js";

View file

@ -0,0 +1,28 @@
import { GraphConfig } from "@open-swe/shared/open-swe/types";
import { getModelManager } from "./model-manager.js";
import { FallbackRunnable } from "../runtime-fallback.js";
import { Task, TASK_TO_CONFIG_DEFAULTS_MAP } from "./constants.js";
export async function loadModel(config: GraphConfig, task: Task) {
const modelManager = getModelManager();
const model = await modelManager.loadModel(config, task);
if (!model) {
throw new Error(`Model loading returned undefined for task: ${task}`);
}
const fallbackModel = new FallbackRunnable(model, config, task, modelManager);
return fallbackModel;
}
const MODELS_NO_PARALLEL_TOOL_CALLING = ["openai:o3", "openai:o3-mini"];
export function supportsParallelToolCallsParam(
config: GraphConfig,
task: Task,
): boolean {
const modelStr =
config.configurable?.[`${task}ModelName`] ??
TASK_TO_CONFIG_DEFAULTS_MAP[task].modelName;
return !MODELS_NO_PARALLEL_TOOL_CALLING.some((model) => modelStr === model);
}

View file

@ -3,10 +3,11 @@ import {
initChatModel,
} from "langchain/chat_models/universal";
import { GraphConfig } from "@open-swe/shared/open-swe/types";
import { createLogger, LogLevel } from "./logger.js";
import { Task } from "./load-model.js";
import { createLogger, LogLevel } from "../logger.js";
import { Task } from "./constants.js";
import { isAllowedUser } from "@open-swe/shared/github/allowed-users";
import { decryptSecret } from "@open-swe/shared/crypto";
import { TASK_TO_CONFIG_DEFAULTS_MAP } from "./constants.js";
const logger = createLogger(LogLevel.INFO, "ModelManager");
@ -242,19 +243,19 @@ export class ModelManager {
[Task.PROGRAMMER]: {
modelName:
config.configurable?.[`${task}ModelName`] ??
"anthropic:claude-sonnet-4-0",
TASK_TO_CONFIG_DEFAULTS_MAP[task].modelName,
temperature: config.configurable?.[`${task}Temperature`] ?? 0,
},
[Task.ROUTER]: {
modelName:
config.configurable?.[`${task}ModelName`] ??
"anthropic:claude-3-5-haiku-latest",
TASK_TO_CONFIG_DEFAULTS_MAP[task].modelName,
temperature: config.configurable?.[`${task}Temperature`] ?? 0,
},
[Task.SUMMARIZER]: {
modelName:
config.configurable?.[`${task}ModelName`] ??
"google-genai:gemini-2.5-pro",
TASK_TO_CONFIG_DEFAULTS_MAP[task].modelName,
temperature: config.configurable?.[`${task}Temperature`] ?? 0,
},
};
@ -307,7 +308,7 @@ export class ModelManager {
openai: {
[Task.PROGRAMMER]: "gpt-4o",
[Task.ROUTER]: "gpt-4o-mini",
[Task.SUMMARIZER]: "gpt-4o",
[Task.SUMMARIZER]: "gpt-4.1-mini",
},
};

View file

@ -1,61 +0,0 @@
import { GraphConfig } from "@open-swe/shared/open-swe/types";
import { getModelManager } from "./model-manager.js";
import { FallbackRunnable } from "./runtime-fallback.js";
export enum Task {
/**
* Used for programmer tasks. This includes: writing code,
* generating plans, taking context gathering actions, etc.
*/
PROGRAMMER = "programmer",
/**
* Used for routing tasks. This includes: initial request
* routing to different agents.
*/
ROUTER = "router",
/**
* Used for summarizing tasks. This includes: summarizing
* the conversation history, summarizing actions taken during
* a task execution, etc. Should be a slightly advanced model.
*/
SUMMARIZER = "summarizer",
}
const TASK_TO_CONFIG_DEFAULTS_MAP = {
[Task.PROGRAMMER]: {
modelName: "anthropic:claude-sonnet-4-0",
temperature: 0,
},
[Task.ROUTER]: {
modelName: "anthropic:claude-3-5-haiku-latest",
temperature: 0,
},
[Task.SUMMARIZER]: {
modelName: "openai:gpt-4.1-mini",
temperature: 0,
},
};
export async function loadModel(config: GraphConfig, task: Task) {
const modelManager = getModelManager();
const model = await modelManager.loadModel(config, task);
if (!model) {
throw new Error(`Model loading returned undefined for task: ${task}`);
}
const fallbackModel = new FallbackRunnable(model, config, task, modelManager);
return fallbackModel;
}
const MODELS_NO_PARALLEL_TOOL_CALLING = ["openai:o3", "openai:o3-mini"];
export function supportsParallelToolCallsParam(
config: GraphConfig,
task: Task,
): boolean {
const modelStr =
config.configurable?.[`${task}ModelName`] ??
TASK_TO_CONFIG_DEFAULTS_MAP[task].modelName;
return !MODELS_NO_PARALLEL_TOOL_CALLING.some((model) => modelStr === model);
}

View file

@ -1,5 +1,5 @@
import { GraphConfig } from "@open-swe/shared/open-swe/types";
import { loadModel, Task } from "../load-model.js";
import { loadModel, Task } from "../llms/index.js";
import { createLogger, LogLevel } from "../logger.js";
import { DOCUMENT_TOC_GENERATION_PROMPT } from "./prompt.js";
import { getMessageContentString } from "@open-swe/shared/messages";

View file

@ -1,6 +1,6 @@
import { GraphConfig } from "@open-swe/shared/open-swe/types";
import { Task } from "./load-model.js";
import { ModelManager } from "./model-manager.js";
import { Task } from "./llms/index.js";
import { ModelManager } from "./llms/model-manager.js";
import { createLogger, LogLevel } from "./logger.js";
import { Runnable, RunnableConfig } from "@langchain/core/runnables";
import { StructuredToolInterface } from "@langchain/core/tools";

View file

@ -1,20 +1,20 @@
export const MODEL_OPTIONS = [
// {
// label: "Claude Sonnet 4 (Extended Thinking)",
// value: "anthropic:extended-thinking:claude-sonnet-4-0",
// },
// {
// label: "Claude Opus 4 (Extended Thinking)",
// value: "anthropic:extended-thinking:claude-opus-4-0",
// },
{
label: "Claude Sonnet 4 (Extended Thinking)",
value: "anthropic:extended-thinking:claude-sonnet-4-0",
},
{
label: "Claude Opus 4 (Extended Thinking)",
value: "anthropic:extended-thinking:claude-opus-4-0",
},
{
label: "Claude Sonnet 4",
value: "anthropic:claude-sonnet-4-0",
},
// {
// label: "Claude Opus 4",
// value: "anthropic:claude-opus-4-0",
// },
{
label: "Claude Opus 4",
value: "anthropic:claude-opus-4-0",
},
{
label: "Claude 3.7 Sonnet",
value: "anthropic:claude-3-7-sonnet-latest",
@ -27,10 +27,10 @@ export const MODEL_OPTIONS = [
label: "Claude 3.5 Haiku",
value: "anthropic:claude-3-5-haiku-latest",
},
// {
// label: "o4",
// value: "openai:o4",
// },
{
label: "o4",
value: "openai:o4",
},
{
label: "o4 mini",
value: "openai:o4-mini",
@ -60,12 +60,12 @@ export const MODEL_OPTIONS = [
value: "openai:gpt-4.1-mini",
},
{
label: "Gemini 2.5 Pro Preview",
value: "google-genai:gemini-2.5-pro-preview-05-06",
label: "Gemini 2.5 Pro",
value: "google-genai:gemini-2.5-pro",
},
{
label: "Gemini 2.5 Flash Preview",
value: "google-genai:gemini-2.5-flash-preview-05-20",
label: "Gemini 2.5 Flash",
value: "google-genai:gemini-2.5-flash",
},
];