fix(agents): preserve model overrides with team mode
Filter host config agent aliases with the same protected builtin-name rules used for external agent sources so stale display-name entries cannot replace resolved user-configured models when team mode is enabled. Fixes #4429 Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -310,6 +310,62 @@ describe("applyAgentConfig builtin override protection", () => {
|
||||
expect(result.SiSyPhUs).toBeUndefined()
|
||||
})
|
||||
|
||||
test("filters host config agent display-name aliases before they override resolved builtin models", async () => {
|
||||
// given
|
||||
createBuiltinAgentsSpy.mockResolvedValue({
|
||||
sisyphus: {
|
||||
name: "sisyphus",
|
||||
prompt: "resolved sisyphus prompt",
|
||||
mode: "primary",
|
||||
model: "openai/gpt-5.5",
|
||||
},
|
||||
explore: {
|
||||
name: "explore",
|
||||
prompt: "resolved explore prompt",
|
||||
mode: "subagent",
|
||||
model: "minimax-cn-coding-plan/MiniMax-M2.5-highspeed",
|
||||
},
|
||||
atlas: builtinAtlasConfig,
|
||||
})
|
||||
const config = createBaseConfig()
|
||||
config.agent = {
|
||||
[getAgentListDisplayName("sisyphus")]: {
|
||||
name: getAgentListDisplayName("sisyphus"),
|
||||
prompt: "stale sisyphus prompt",
|
||||
mode: "primary",
|
||||
model: "anthropic/claude-opus-4-7",
|
||||
},
|
||||
[getAgentListDisplayName("explore")]: {
|
||||
name: getAgentListDisplayName("explore"),
|
||||
prompt: "stale explore prompt",
|
||||
mode: "subagent",
|
||||
model: "openai/gpt-5.4",
|
||||
},
|
||||
}
|
||||
const pluginConfig = {
|
||||
...createPluginConfig(),
|
||||
team_mode: { enabled: true },
|
||||
agents: {
|
||||
sisyphus: { model: "openai/gpt-5.5" },
|
||||
explore: { model: "minimax-cn-coding-plan/MiniMax-M2.5-highspeed" },
|
||||
},
|
||||
} as OhMyOpenCodeConfig
|
||||
|
||||
// when
|
||||
const result = await applyAgentConfig({
|
||||
config,
|
||||
pluginConfig,
|
||||
ctx: { directory: "/tmp" },
|
||||
pluginComponents: createPluginComponents(),
|
||||
})
|
||||
|
||||
// then
|
||||
expect((result[getAgentListDisplayName("sisyphus")] as AgentConfig).model).toBe("openai/gpt-5.5")
|
||||
expect((result[getAgentListDisplayName("explore")] as AgentConfig).model).toBe(
|
||||
"minimax-cn-coding-plan/MiniMax-M2.5-highspeed"
|
||||
)
|
||||
})
|
||||
|
||||
test("filters plugin agents whose key matches the builtin display-name alias", async () => {
|
||||
// given
|
||||
const pluginComponents = createPluginComponents()
|
||||
|
||||
@@ -259,24 +259,6 @@ export async function applyAgentConfig(params: {
|
||||
agentConfig["OpenCode-Builder"] = override ? { ...base, ...override } : base;
|
||||
}
|
||||
|
||||
const filteredConfigAgents = configAgent
|
||||
? Object.fromEntries(
|
||||
Object.entries(configAgent)
|
||||
.filter(([key]) => {
|
||||
if (key === "build") return false;
|
||||
if (key === "plan" && shouldDemotePlan) return false;
|
||||
if (key in builtinAgents) return false;
|
||||
return true;
|
||||
})
|
||||
.map(([key, value]) => {
|
||||
if (!value) return [key, value];
|
||||
const migrated = migrateAgentConfig(value as Record<string, unknown>);
|
||||
if (!migrated.mode) migrated.mode = "subagent";
|
||||
return [key, migrated];
|
||||
}),
|
||||
)
|
||||
: {};
|
||||
|
||||
const migratedBuild = configAgent?.build
|
||||
? migrateAgentConfig(configAgent.build as Record<string, unknown>)
|
||||
: {};
|
||||
@@ -292,6 +274,26 @@ export async function applyAgentConfig(params: {
|
||||
...Object.keys(agentConfig),
|
||||
...Object.keys(builtinAgents),
|
||||
]);
|
||||
const filteredConfigAgentSource = configAgent
|
||||
? filterProtectedAgentOverrides(
|
||||
Object.fromEntries(
|
||||
Object.entries(configAgent).filter(([key]) => {
|
||||
if (key === "build") return false;
|
||||
if (key === "plan" && shouldDemotePlan) return false;
|
||||
return true;
|
||||
}),
|
||||
),
|
||||
protectedBuiltinAgentNames,
|
||||
)
|
||||
: {};
|
||||
const filteredConfigAgents = Object.fromEntries(
|
||||
Object.entries(filteredConfigAgentSource).map(([key, value]) => {
|
||||
if (!value) return [key, value];
|
||||
const migrated = migrateAgentConfig(value as Record<string, unknown>);
|
||||
if (!migrated.mode) migrated.mode = "subagent";
|
||||
return [key, migrated];
|
||||
}),
|
||||
);
|
||||
const filteredUserAgents = filterProtectedAgentOverrides(
|
||||
userAgents,
|
||||
protectedBuiltinAgentNames,
|
||||
@@ -373,16 +375,17 @@ export async function applyAgentConfig(params: {
|
||||
protectedBuiltinAgentNames,
|
||||
);
|
||||
|
||||
const defaultedConfigAgents = configAgent
|
||||
? Object.fromEntries(
|
||||
Object.entries(configAgent).map(([key, value]) => {
|
||||
if (!value) return [key, value];
|
||||
const migrated = migrateAgentConfig(value as Record<string, unknown>);
|
||||
if (!migrated.mode) migrated.mode = "subagent";
|
||||
return [key, migrated];
|
||||
}),
|
||||
)
|
||||
const filteredConfigAgentSource = configAgent
|
||||
? filterProtectedAgentOverrides(configAgent, protectedBuiltinAgentNames)
|
||||
: {};
|
||||
const defaultedConfigAgents = Object.fromEntries(
|
||||
Object.entries(filteredConfigAgentSource).map(([key, value]) => {
|
||||
if (!value) return [key, value];
|
||||
const migrated = migrateAgentConfig(value as Record<string, unknown>);
|
||||
if (!migrated.mode) migrated.mode = "subagent";
|
||||
return [key, migrated];
|
||||
}),
|
||||
);
|
||||
|
||||
params.config.agent = {
|
||||
...builtinAgents,
|
||||
|
||||
Reference in New Issue
Block a user