fix(config): prevent plan agent from inheriting prometheus prompt on demote

Plan agent demote now only sets mode to 'subagent' without spreading
prometheus config. This ensures plan agent uses OpenCode's default
prompt instead of inheriting prometheus prompt.
This commit is contained in:
YeonGyu-Kim
2026-02-03 14:28:57 +09:00
parent bf87bf473f
commit f030992755
2 changed files with 15 additions and 101 deletions

View File

@@ -145,8 +145,8 @@ describe("Plan agent demote behavior", () => {
expect(ordered).toEqual(coreAgents)
})
test("plan agent should be demoted to subagent mode when replacePlan is true", async () => {
// given
test("plan agent should be demoted to subagent without inheriting prometheus prompt", async () => {
// #given
const pluginConfig: OhMyOpenCodeConfig = {
sisyphus_agent: {
planner_enabled: true,
@@ -172,62 +172,22 @@ describe("Plan agent demote behavior", () => {
},
})
// when
// #when
await handler(config)
// then
// #then - plan is demoted to subagent but does NOT inherit prometheus prompt
const agents = config.agent as Record<string, { mode?: string; name?: string; prompt?: string }>
expect(agents.plan).toBeDefined()
expect(agents.plan.mode).toBe("subagent")
expect(agents.plan.name).toBe("plan")
expect(agents.plan.prompt).toBe("original plan prompt")
expect(agents.plan.prompt).not.toBe(agents.prometheus?.prompt)
expect(agents.plan.prompt).toBeUndefined()
expect(agents.prometheus?.prompt).toBeDefined()
})
test("plan agent should not be demoted when replacePlan is false", async () => {
// given
const pluginConfig: OhMyOpenCodeConfig = {
sisyphus_agent: {
planner_enabled: true,
replace_plan: false,
},
}
const config: Record<string, unknown> = {
model: "anthropic/claude-opus-4-5",
agent: {
plan: {
name: "plan",
mode: "primary",
prompt: "original plan prompt",
},
},
}
const handler = createConfigHandler({
ctx: { directory: "/tmp" },
pluginConfig,
modelCacheState: {
anthropicContext1MEnabled: false,
modelContextLimitsCache: new Map(),
},
})
// when
await handler(config)
// then
const agents = config.agent as Record<string, { mode?: string; name?: string; prompt?: string }>
expect(agents.plan).toBeDefined()
expect(agents.plan.mode).toBe("primary")
expect(agents.plan.name).toBe("plan")
expect(agents.plan.prompt).toBe("original plan prompt")
})
test("plan agent should not be demoted when planner is disabled", async () => {
// given
test("plan agent remains unchanged when planner is disabled", async () => {
// #given
const pluginConfig: OhMyOpenCodeConfig = {
sisyphus_agent: {
planner_enabled: false,
replace_plan: true,
},
}
const config: Record<string, unknown> = {
@@ -249,50 +209,15 @@ describe("Plan agent demote behavior", () => {
},
})
// when
// #when
await handler(config)
// then
// #then - plan is not touched, prometheus is not created
const agents = config.agent as Record<string, { mode?: string; name?: string; prompt?: string }>
expect(agents.prometheus).toBeUndefined()
expect(agents.plan).toBeDefined()
expect(agents.plan.mode).toBe("primary")
})
test("preserves empty plan prompt when demoting", async () => {
// given
const pluginConfig: OhMyOpenCodeConfig = {
sisyphus_agent: {
planner_enabled: true,
replace_plan: true,
},
}
const config: Record<string, unknown> = {
model: "anthropic/claude-opus-4-5",
agent: {
plan: {
name: "plan",
mode: "primary",
prompt: "",
},
},
}
const handler = createConfigHandler({
ctx: { directory: "/tmp" },
pluginConfig,
modelCacheState: {
anthropicContext1MEnabled: false,
modelContextLimitsCache: new Map(),
},
})
// when
await handler(config)
// then
const agents = config.agent as Record<string, { prompt?: string }>
expect(agents.plan).toBeDefined()
expect(agents.plan.prompt).toBe("")
expect(agents.plan.prompt).toBe("original plan prompt")
})
test("prometheus should have mode 'all' to be callable via delegate_task", async () => {

View File

@@ -195,7 +195,7 @@ export function createConfigHandler(deps: ConfigHandlerDeps) {
const plannerEnabled =
pluginConfig.sisyphus_agent?.planner_enabled ?? true;
const replacePlan = pluginConfig.sisyphus_agent?.replace_plan ?? true;
const shouldReplacePlan = plannerEnabled && replacePlan;
const shouldDemotePlan = plannerEnabled && replacePlan;
type AgentConfig = Record<
string,
@@ -211,12 +211,6 @@ export function createConfigHandler(deps: ConfigHandlerDeps) {
};
const configAgent = config.agent as AgentConfig | undefined;
const { name: _planName, mode: _planMode, ...planConfigWithoutName } =
configAgent?.plan ?? {};
const planPrompt = (migrateAgentConfig(
planConfigWithoutName as Record<string, unknown>
) as { prompt?: string }).prompt;
if (isSisyphusEnabled && builtinAgents.sisyphus) {
(config as { default_agent?: string }).default_agent = "sisyphus";
@@ -345,7 +339,7 @@ export function createConfigHandler(deps: ConfigHandlerDeps) {
Object.entries(configAgent)
.filter(([key]) => {
if (key === "build") return false;
if (key === "plan" && shouldReplacePlan) return false;
if (key === "plan" && shouldDemotePlan) return false;
// Filter out agents that oh-my-opencode provides to prevent
// OpenCode defaults from overwriting user config in oh-my-opencode.json
// See: https://github.com/code-yeongyu/oh-my-opencode/issues/472
@@ -363,13 +357,8 @@ export function createConfigHandler(deps: ConfigHandlerDeps) {
? migrateAgentConfig(configAgent.build as Record<string, unknown>)
: {};
const planDemoteConfig = shouldReplacePlan && agentConfig["prometheus"]
? {
...agentConfig["prometheus"],
name: "plan",
mode: "subagent" as const,
...(typeof planPrompt === "string" ? { prompt: planPrompt } : {}),
}
const planDemoteConfig = shouldDemotePlan
? { mode: "subagent" as const }
: undefined;
config.agent = {