fix(delegate-task): hide team tools from subagents
This commit is contained in:
@@ -12,10 +12,48 @@ import { createHephaestusAgent } from "./hephaestus"
|
|||||||
import { getAgentToolRestrictions } from "../shared/agent-tool-restrictions"
|
import { getAgentToolRestrictions } from "../shared/agent-tool-restrictions"
|
||||||
|
|
||||||
const TEST_MODEL = "anthropic/claude-sonnet-4-5"
|
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", () => {
|
describe("read-only agent tool restrictions", () => {
|
||||||
const FILE_WRITE_TOOLS = ["write", "edit", "apply_patch"]
|
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", () => {
|
describe("Oracle", () => {
|
||||||
test("denies all file-writing tools", () => {
|
test("denies all file-writing tools", () => {
|
||||||
// given
|
// given
|
||||||
|
|||||||
@@ -6,6 +6,21 @@ import { stripInvisibleAgentCharacters } from "./agent-display-names"
|
|||||||
* true = tool allowed, false = tool denied.
|
* true = tool allowed, false = tool denied.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const TEAM_TOOL_DENYLIST: Record<string, boolean> = {
|
||||||
|
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<string, boolean> = {
|
const EXPLORATION_AGENT_DENYLIST: Record<string, boolean> = {
|
||||||
write: false,
|
write: false,
|
||||||
edit: false,
|
edit: false,
|
||||||
@@ -45,12 +60,15 @@ const AGENT_RESTRICTIONS: Record<string, Record<string, boolean>> = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getAgentToolRestrictions(agentName: string): Record<string, boolean> {
|
export function getAgentToolRestrictions(agentName: string): Record<string, boolean> {
|
||||||
// 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)
|
const stripped = stripInvisibleAgentCharacters(agentName)
|
||||||
return AGENT_RESTRICTIONS[stripped]
|
const agentRestrictions = AGENT_RESTRICTIONS[stripped]
|
||||||
?? Object.entries(AGENT_RESTRICTIONS).find(([key]) => key.toLowerCase() === stripped.toLowerCase())?.[1]
|
?? Object.entries(AGENT_RESTRICTIONS).find(([key]) => key.toLowerCase() === stripped.toLowerCase())?.[1]
|
||||||
?? {}
|
?? {}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...TEAM_TOOL_DENYLIST,
|
||||||
|
...agentRestrictions,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hasAgentToolRestrictions(agentName: string): boolean {
|
export function hasAgentToolRestrictions(agentName: string): boolean {
|
||||||
|
|||||||
@@ -1,5 +1,20 @@
|
|||||||
const { describe, test, expect, beforeEach, afterEach, mock, spyOn } = require("bun:test")
|
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", () => {
|
describe("executeSyncContinuation - toast cleanup error paths", () => {
|
||||||
let removeTaskCalls: string[] = []
|
let removeTaskCalls: string[] = []
|
||||||
let addTaskCalls: any[] = []
|
let addTaskCalls: any[] = []
|
||||||
@@ -532,6 +547,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => {
|
|||||||
question: false,
|
question: false,
|
||||||
write: false,
|
write: false,
|
||||||
edit: false,
|
edit: false,
|
||||||
|
...TEAM_TOOL_DENIALS,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -602,6 +618,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => {
|
|||||||
question: false,
|
question: false,
|
||||||
write: false,
|
write: false,
|
||||||
edit: false,
|
edit: false,
|
||||||
|
...TEAM_TOOL_DENIALS,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -670,6 +687,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => {
|
|||||||
task: true,
|
task: true,
|
||||||
call_omo_agent: true,
|
call_omo_agent: true,
|
||||||
question: false,
|
question: false,
|
||||||
|
...TEAM_TOOL_DENIALS,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user