Merge pull request #1911 from jkoelker/preserve-default-agent

fix(config): normalize configured default_agent
This commit is contained in:
YeonGyu-Kim 2026-02-17 15:59:36 +09:00 committed by GitHub
commit 8384fd1d07
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 161 additions and 5 deletions

View File

@ -23,9 +23,12 @@ type AgentConfigRecord = Record<string, Record<string, unknown> | undefined> & {
plan?: Record<string, unknown>;
};
function hasConfiguredDefaultAgent(config: Record<string, unknown>): boolean {
function getConfiguredDefaultAgent(config: Record<string, unknown>): string | undefined {
const defaultAgent = config.default_agent;
return typeof defaultAgent === "string" && defaultAgent.trim().length > 0;
if (typeof defaultAgent !== "string") return undefined;
const trimmedDefaultAgent = defaultAgent.trim();
return trimmedDefaultAgent.length > 0 ? trimmedDefaultAgent : undefined;
}
export async function applyAgentConfig(params: {
@ -107,11 +110,15 @@ export async function applyAgentConfig(params: {
const plannerEnabled = params.pluginConfig.sisyphus_agent?.planner_enabled ?? true;
const replacePlan = params.pluginConfig.sisyphus_agent?.replace_plan ?? true;
const shouldDemotePlan = plannerEnabled && replacePlan;
const configuredDefaultAgent = getConfiguredDefaultAgent(params.config);
const configAgent = params.config.agent as AgentConfigRecord | undefined;
if (isSisyphusEnabled && builtinAgents.sisyphus) {
if (!hasConfiguredDefaultAgent(params.config)) {
if (configuredDefaultAgent) {
(params.config as { default_agent?: string }).default_agent =
getAgentDisplayName(configuredDefaultAgent);
} else {
(params.config as { default_agent?: string }).default_agent =
getAgentDisplayName("sisyphus");
}

View File

@ -350,7 +350,55 @@ describe("Agent permission defaults", () => {
})
describe("default_agent behavior with Sisyphus orchestration", () => {
test("preserves existing default_agent when already set", async () => {
test("canonicalizes configured default_agent with surrounding whitespace", async () => {
// given
const pluginConfig: OhMyOpenCodeConfig = {}
const config: Record<string, unknown> = {
model: "anthropic/claude-opus-4-6",
default_agent: " hephaestus ",
agent: {},
}
const handler = createConfigHandler({
ctx: { directory: "/tmp" },
pluginConfig,
modelCacheState: {
anthropicContext1MEnabled: false,
modelContextLimitsCache: new Map(),
},
})
// when
await handler(config)
// then
expect(config.default_agent).toBe(getAgentDisplayName("hephaestus"))
})
test("canonicalizes configured default_agent when key uses mixed case", async () => {
// given
const pluginConfig: OhMyOpenCodeConfig = {}
const config: Record<string, unknown> = {
model: "anthropic/claude-opus-4-6",
default_agent: "HePhAeStUs",
agent: {},
}
const handler = createConfigHandler({
ctx: { directory: "/tmp" },
pluginConfig,
modelCacheState: {
anthropicContext1MEnabled: false,
modelContextLimitsCache: new Map(),
},
})
// when
await handler(config)
// then
expect(config.default_agent).toBe(getAgentDisplayName("hephaestus"))
})
test("canonicalizes configured default_agent key to display name", async () => {
// #given
const pluginConfig: OhMyOpenCodeConfig = {}
const config: Record<string, unknown> = {
@ -371,7 +419,32 @@ describe("default_agent behavior with Sisyphus orchestration", () => {
await handler(config)
// #then
expect(config.default_agent).toBe("hephaestus")
expect(config.default_agent).toBe(getAgentDisplayName("hephaestus"))
})
test("preserves existing display-name default_agent", async () => {
// #given
const pluginConfig: OhMyOpenCodeConfig = {}
const displayName = getAgentDisplayName("hephaestus")
const config: Record<string, unknown> = {
model: "anthropic/claude-opus-4-6",
default_agent: displayName,
agent: {},
}
const handler = createConfigHandler({
ctx: { directory: "/tmp" },
pluginConfig,
modelCacheState: {
anthropicContext1MEnabled: false,
modelContextLimitsCache: new Map(),
},
})
// #when
await handler(config)
// #then
expect(config.default_agent).toBe(displayName)
})
test("sets default_agent to sisyphus when missing", async () => {
@ -396,6 +469,82 @@ describe("default_agent behavior with Sisyphus orchestration", () => {
// #then
expect(config.default_agent).toBe(getAgentDisplayName("sisyphus"))
})
test("sets default_agent to sisyphus when configured default_agent is empty after trim", async () => {
// given
const pluginConfig: OhMyOpenCodeConfig = {}
const config: Record<string, unknown> = {
model: "anthropic/claude-opus-4-6",
default_agent: " ",
agent: {},
}
const handler = createConfigHandler({
ctx: { directory: "/tmp" },
pluginConfig,
modelCacheState: {
anthropicContext1MEnabled: false,
modelContextLimitsCache: new Map(),
},
})
// when
await handler(config)
// then
expect(config.default_agent).toBe(getAgentDisplayName("sisyphus"))
})
test("preserves custom default_agent names while trimming whitespace", async () => {
// given
const pluginConfig: OhMyOpenCodeConfig = {}
const config: Record<string, unknown> = {
model: "anthropic/claude-opus-4-6",
default_agent: " Custom Agent ",
agent: {},
}
const handler = createConfigHandler({
ctx: { directory: "/tmp" },
pluginConfig,
modelCacheState: {
anthropicContext1MEnabled: false,
modelContextLimitsCache: new Map(),
},
})
// when
await handler(config)
// then
expect(config.default_agent).toBe("Custom Agent")
})
test("does not normalize configured default_agent when Sisyphus is disabled", async () => {
// given
const pluginConfig: OhMyOpenCodeConfig = {
sisyphus_agent: {
disabled: true,
},
}
const config: Record<string, unknown> = {
model: "anthropic/claude-opus-4-6",
default_agent: " HePhAeStUs ",
agent: {},
}
const handler = createConfigHandler({
ctx: { directory: "/tmp" },
pluginConfig,
modelCacheState: {
anthropicContext1MEnabled: false,
modelContextLimitsCache: new Map(),
},
})
// when
await handler(config)
// then
expect(config.default_agent).toBe(" HePhAeStUs ")
})
})
describe("Prometheus category config resolution", () => {