From be2acd49b58232cdd3ad54f5b9d7189d0346d6f4 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 9 May 2026 16:30:40 +0900 Subject: [PATCH] fix(delegate-task): hide team tools from subagents --- src/agents/tool-restrictions.test.ts | 38 +++++++++++++++++++ src/shared/agent-tool-restrictions.ts | 24 ++++++++++-- .../delegate-task/sync-continuation.test.ts | 18 +++++++++ 3 files changed, 77 insertions(+), 3 deletions(-) diff --git a/src/agents/tool-restrictions.test.ts b/src/agents/tool-restrictions.test.ts index 572429827..f4e881b04 100644 --- a/src/agents/tool-restrictions.test.ts +++ b/src/agents/tool-restrictions.test.ts @@ -12,10 +12,48 @@ import { createHephaestusAgent } from "./hephaestus" import { getAgentToolRestrictions } from "../shared/agent-tool-restrictions" const TEST_MODEL = "anthropic/claude-sonnet-4-5" +const TEAM_TOOL_NAMES = [ + "team_create", + "team_delete", + "team_shutdown_request", + "team_approve_shutdown", + "team_reject_shutdown", + "team_send_message", + "team_task_create", + "team_task_list", + "team_task_update", + "team_task_get", + "team_status", + "team_list", +] as const describe("read-only agent tool restrictions", () => { const FILE_WRITE_TOOLS = ["write", "edit", "apply_patch"] + test("denies team tools for every delegated subagent prompt", () => { + // given + const restrictedAgentNames = [ + "explore", + "librarian", + "oracle", + "metis", + "momus", + "multimodal-looker", + "sisyphus-junior", + "custom-worker", + ] + + // when + const restrictions = restrictedAgentNames.map((agentName) => getAgentToolRestrictions(agentName)) + + // then + for (const restriction of restrictions) { + for (const toolName of TEAM_TOOL_NAMES) { + expect(restriction[toolName]).toBe(false) + } + } + }) + describe("Oracle", () => { test("denies all file-writing tools", () => { // given diff --git a/src/shared/agent-tool-restrictions.ts b/src/shared/agent-tool-restrictions.ts index 8bd7c4f88..d84a2dfbe 100644 --- a/src/shared/agent-tool-restrictions.ts +++ b/src/shared/agent-tool-restrictions.ts @@ -6,6 +6,21 @@ import { stripInvisibleAgentCharacters } from "./agent-display-names" * true = tool allowed, false = tool denied. */ +const TEAM_TOOL_DENYLIST: Record = { + team_create: false, + team_delete: false, + team_shutdown_request: false, + team_approve_shutdown: false, + team_reject_shutdown: false, + team_send_message: false, + team_task_create: false, + team_task_list: false, + team_task_update: false, + team_task_get: false, + team_status: false, + team_list: false, +} + const EXPLORATION_AGENT_DENYLIST: Record = { write: false, edit: false, @@ -45,12 +60,15 @@ const AGENT_RESTRICTIONS: Record> = { } export function getAgentToolRestrictions(agentName: string): Record { - // Custom/unknown agents get no restrictions (empty object), matching Claude Code's - // trust model where project-registered agents retain full tool access including bash. const stripped = stripInvisibleAgentCharacters(agentName) - return AGENT_RESTRICTIONS[stripped] + const agentRestrictions = AGENT_RESTRICTIONS[stripped] ?? Object.entries(AGENT_RESTRICTIONS).find(([key]) => key.toLowerCase() === stripped.toLowerCase())?.[1] ?? {} + + return { + ...TEAM_TOOL_DENYLIST, + ...agentRestrictions, + } } export function hasAgentToolRestrictions(agentName: string): boolean { diff --git a/src/tools/delegate-task/sync-continuation.test.ts b/src/tools/delegate-task/sync-continuation.test.ts index 37757dbeb..9f2a690ef 100644 --- a/src/tools/delegate-task/sync-continuation.test.ts +++ b/src/tools/delegate-task/sync-continuation.test.ts @@ -1,5 +1,20 @@ const { describe, test, expect, beforeEach, afterEach, mock, spyOn } = require("bun:test") +const TEAM_TOOL_DENIALS = { + team_create: false, + team_delete: false, + team_shutdown_request: false, + team_approve_shutdown: false, + team_reject_shutdown: false, + team_send_message: false, + team_task_create: false, + team_task_list: false, + team_task_update: false, + team_task_get: false, + team_status: false, + team_list: false, +} + describe("executeSyncContinuation - toast cleanup error paths", () => { let removeTaskCalls: string[] = [] let addTaskCalls: any[] = [] @@ -532,6 +547,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { question: false, write: false, edit: false, + ...TEAM_TOOL_DENIALS, }) }) @@ -602,6 +618,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { question: false, write: false, edit: false, + ...TEAM_TOOL_DENIALS, }) }) @@ -670,6 +687,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { task: true, call_omo_agent: true, question: false, + ...TEAM_TOOL_DENIALS, }) }) })