From 101dadbce2aa11169c208d13383bf70641ff2331 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Wed, 18 Feb 2026 15:51:31 +0900 Subject: [PATCH] fix(agents): block apply_patch tool for all read-only agents Oracle, Librarian, Explore, Momus, and Metis could modify files via apply_patch despite being read-only agents. Also fixed duplicate task entries in Librarian and Explore restriction lists. --- src/agents/explore.ts | 2 +- src/agents/librarian.ts | 2 +- src/agents/metis.ts | 1 + src/agents/momus.ts | 2 +- src/agents/oracle.ts | 2 +- src/agents/tool-restrictions.test.ts | 99 ++++++++++++++++++++++++++++ 6 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 src/agents/tool-restrictions.test.ts diff --git a/src/agents/explore.ts b/src/agents/explore.ts index 1baae542..f1c853aa 100644 --- a/src/agents/explore.ts +++ b/src/agents/explore.ts @@ -28,7 +28,7 @@ export function createExploreAgent(model: string): AgentConfig { const restrictions = createAgentToolRestrictions([ "write", "edit", - "task", + "apply_patch", "task", "call_omo_agent", ]) diff --git a/src/agents/librarian.ts b/src/agents/librarian.ts index c13b9f10..62f934c5 100644 --- a/src/agents/librarian.ts +++ b/src/agents/librarian.ts @@ -25,7 +25,7 @@ export function createLibrarianAgent(model: string): AgentConfig { const restrictions = createAgentToolRestrictions([ "write", "edit", - "task", + "apply_patch", "task", "call_omo_agent", ]) diff --git a/src/agents/metis.ts b/src/agents/metis.ts index f25c96c9..99bcd71d 100644 --- a/src/agents/metis.ts +++ b/src/agents/metis.ts @@ -306,6 +306,7 @@ User confirms the button works as expected. const metisRestrictions = createAgentToolRestrictions([ "write", "edit", + "apply_patch", "task", ]) diff --git a/src/agents/momus.ts b/src/agents/momus.ts index 457e354b..b3fd5a12 100644 --- a/src/agents/momus.ts +++ b/src/agents/momus.ts @@ -192,7 +192,7 @@ export function createMomusAgent(model: string): AgentConfig { const restrictions = createAgentToolRestrictions([ "write", "edit", - "task", + "apply_patch", "task", ]) diff --git a/src/agents/oracle.ts b/src/agents/oracle.ts index 19713627..d67c022f 100644 --- a/src/agents/oracle.ts +++ b/src/agents/oracle.ts @@ -146,7 +146,7 @@ export function createOracleAgent(model: string): AgentConfig { const restrictions = createAgentToolRestrictions([ "write", "edit", - "task", + "apply_patch", "task", ]) diff --git a/src/agents/tool-restrictions.test.ts b/src/agents/tool-restrictions.test.ts new file mode 100644 index 00000000..685acbc1 --- /dev/null +++ b/src/agents/tool-restrictions.test.ts @@ -0,0 +1,99 @@ +import { describe, test, expect } from "bun:test" +import { createOracleAgent } from "./oracle" +import { createLibrarianAgent } from "./librarian" +import { createExploreAgent } from "./explore" +import { createMomusAgent } from "./momus" +import { createMetisAgent } from "./metis" + +const TEST_MODEL = "anthropic/claude-sonnet-4-5" + +describe("read-only agent tool restrictions", () => { + const FILE_WRITE_TOOLS = ["write", "edit", "apply_patch"] + + describe("Oracle", () => { + test("denies all file-writing tools", () => { + // given + const agent = createOracleAgent(TEST_MODEL) + + // when + const permission = agent.permission as Record + + // then + for (const tool of FILE_WRITE_TOOLS) { + expect(permission[tool]).toBe("deny") + } + }) + + test("denies task but allows call_omo_agent for research", () => { + // given + const agent = createOracleAgent(TEST_MODEL) + + // when + const permission = agent.permission as Record + + // then + expect(permission["task"]).toBe("deny") + expect(permission["call_omo_agent"]).toBeUndefined() + }) + }) + + describe("Librarian", () => { + test("denies all file-writing tools", () => { + // given + const agent = createLibrarianAgent(TEST_MODEL) + + // when + const permission = agent.permission as Record + + // then + for (const tool of FILE_WRITE_TOOLS) { + expect(permission[tool]).toBe("deny") + } + }) + }) + + describe("Explore", () => { + test("denies all file-writing tools", () => { + // given + const agent = createExploreAgent(TEST_MODEL) + + // when + const permission = agent.permission as Record + + // then + for (const tool of FILE_WRITE_TOOLS) { + expect(permission[tool]).toBe("deny") + } + }) + }) + + describe("Momus", () => { + test("denies all file-writing tools", () => { + // given + const agent = createMomusAgent(TEST_MODEL) + + // when + const permission = agent.permission as Record + + // then + for (const tool of FILE_WRITE_TOOLS) { + expect(permission[tool]).toBe("deny") + } + }) + }) + + describe("Metis", () => { + test("denies all file-writing tools", () => { + // given + const agent = createMetisAgent(TEST_MODEL) + + // when + const permission = agent.permission as Record + + // then + for (const tool of FILE_WRITE_TOOLS) { + expect(permission[tool]).toBe("deny") + } + }) + }) +})