diff --git a/src/plugin-handlers/config-handler.test.ts b/src/plugin-handlers/config-handler.test.ts index e88f2b4e..08c58f6f 100644 --- a/src/plugin-handlers/config-handler.test.ts +++ b/src/plugin-handlers/config-handler.test.ts @@ -943,3 +943,108 @@ describe("config-handler plugin loading error boundary (#1559)", () => { expect(commands["test-cmd"]).toBeDefined() }) }) + +describe("per-agent todowrite/todoread deny when task_system enabled", () => { + const PRIMARY_AGENTS = ["sisyphus", "hephaestus", "atlas", "prometheus", "sisyphus-junior"] + + test("denies todowrite and todoread for primary agents when task_system is enabled", async () => { + //#given + spyOn(agents, "createBuiltinAgents" as any).mockResolvedValue({ + sisyphus: { name: "sisyphus", prompt: "test", mode: "primary" }, + hephaestus: { name: "hephaestus", prompt: "test", mode: "primary" }, + atlas: { name: "atlas", prompt: "test", mode: "primary" }, + prometheus: { name: "prometheus", prompt: "test", mode: "primary" }, + "sisyphus-junior": { name: "sisyphus-junior", prompt: "test", mode: "subagent" }, + oracle: { name: "oracle", prompt: "test", mode: "subagent" }, + }) + + const pluginConfig: OhMyOpenCodeConfig = { + experimental: { task_system: true }, + } + const config: Record = { + model: "anthropic/claude-opus-4-6", + agent: {}, + } + const handler = createConfigHandler({ + ctx: { directory: "/tmp" }, + pluginConfig, + modelCacheState: { + anthropicContext1MEnabled: false, + modelContextLimitsCache: new Map(), + }, + }) + + //#when + await handler(config) + + //#then + const agentResult = config.agent as Record }> + for (const agentName of PRIMARY_AGENTS) { + expect(agentResult[agentName]?.permission?.todowrite).toBe("deny") + expect(agentResult[agentName]?.permission?.todoread).toBe("deny") + } + }) + + test("does not deny todowrite/todoread when task_system is disabled", async () => { + //#given + spyOn(agents, "createBuiltinAgents" as any).mockResolvedValue({ + sisyphus: { name: "sisyphus", prompt: "test", mode: "primary" }, + hephaestus: { name: "hephaestus", prompt: "test", mode: "primary" }, + }) + + const pluginConfig: OhMyOpenCodeConfig = { + experimental: { task_system: false }, + } + const config: Record = { + model: "anthropic/claude-opus-4-6", + agent: {}, + } + const handler = createConfigHandler({ + ctx: { directory: "/tmp" }, + pluginConfig, + modelCacheState: { + anthropicContext1MEnabled: false, + modelContextLimitsCache: new Map(), + }, + }) + + //#when + await handler(config) + + //#then + const agentResult = config.agent as Record }> + expect(agentResult.sisyphus?.permission?.todowrite).toBeUndefined() + expect(agentResult.sisyphus?.permission?.todoread).toBeUndefined() + expect(agentResult.hephaestus?.permission?.todowrite).toBeUndefined() + expect(agentResult.hephaestus?.permission?.todoread).toBeUndefined() + }) + + test("does not deny todowrite/todoread when task_system is undefined", async () => { + //#given + spyOn(agents, "createBuiltinAgents" as any).mockResolvedValue({ + sisyphus: { name: "sisyphus", prompt: "test", mode: "primary" }, + }) + + const pluginConfig: OhMyOpenCodeConfig = {} + const config: Record = { + model: "anthropic/claude-opus-4-6", + agent: {}, + } + const handler = createConfigHandler({ + ctx: { directory: "/tmp" }, + pluginConfig, + modelCacheState: { + anthropicContext1MEnabled: false, + modelContextLimitsCache: new Map(), + }, + }) + + //#when + await handler(config) + + //#then + const agentResult = config.agent as Record }> + expect(agentResult.sisyphus?.permission?.todowrite).toBeUndefined() + expect(agentResult.sisyphus?.permission?.todoread).toBeUndefined() + }) +}) diff --git a/src/plugin-handlers/config-handler.ts b/src/plugin-handlers/config-handler.ts index ea7c2856..ed9bf0f7 100644 --- a/src/plugin-handlers/config-handler.ts +++ b/src/plugin-handlers/config-handler.ts @@ -436,6 +436,11 @@ export function createConfigHandler(deps: ConfigHandlerDeps) { // In CLI run mode, deny Question tool for all agents (no TUI to answer questions) const isCliRunMode = process.env.OPENCODE_CLI_RUN_MODE === "true"; const questionPermission = isCliRunMode ? "deny" : "allow"; + + // When task system is enabled, deny todowrite/todoread per-agent so models never see them + const todoPermission = pluginConfig.experimental?.task_system + ? { todowrite: "deny" as const, todoread: "deny" as const } + : {}; if (agentResult.librarian) { const agent = agentResult.librarian as AgentWithPermission; @@ -447,23 +452,23 @@ export function createConfigHandler(deps: ConfigHandlerDeps) { } if (agentResult["atlas"]) { const agent = agentResult["atlas"] as AgentWithPermission; - agent.permission = { ...agent.permission, task: "allow", call_omo_agent: "deny", "task_*": "allow", teammate: "allow" }; + agent.permission = { ...agent.permission, ...todoPermission, task: "allow", call_omo_agent: "deny", "task_*": "allow", teammate: "allow" }; } if (agentResult.sisyphus) { const agent = agentResult.sisyphus as AgentWithPermission; - agent.permission = { ...agent.permission, call_omo_agent: "deny", task: "allow", question: questionPermission, "task_*": "allow", teammate: "allow" }; + agent.permission = { ...agent.permission, ...todoPermission, call_omo_agent: "deny", task: "allow", question: questionPermission, "task_*": "allow", teammate: "allow" }; } if (agentResult.hephaestus) { const agent = agentResult.hephaestus as AgentWithPermission; - agent.permission = { ...agent.permission, call_omo_agent: "deny", task: "allow", question: questionPermission }; + agent.permission = { ...agent.permission, ...todoPermission, call_omo_agent: "deny", task: "allow", question: questionPermission }; } if (agentResult["prometheus"]) { const agent = agentResult["prometheus"] as AgentWithPermission; - agent.permission = { ...agent.permission, call_omo_agent: "deny", task: "allow", question: questionPermission, "task_*": "allow", teammate: "allow" }; + agent.permission = { ...agent.permission, ...todoPermission, call_omo_agent: "deny", task: "allow", question: questionPermission, "task_*": "allow", teammate: "allow" }; } if (agentResult["sisyphus-junior"]) { const agent = agentResult["sisyphus-junior"] as AgentWithPermission; - agent.permission = { ...agent.permission, task: "allow", "task_*": "allow", teammate: "allow" }; + agent.permission = { ...agent.permission, ...todoPermission, task: "allow", "task_*": "allow", teammate: "allow" }; } config.permission = {