anthropics / anthropics/claude-agent-sdk-typescript
AgentDefinition.tools is intersected with Options.tools, making sub-agent tool sets dependent on session base
- Langage dominant
- Shell
- Étoiles
- 1.8k
- Forks
- 226
- Métriques de merge des PR
- Aucune PR mergée en 30 j
Description
## Problem
`AgentDefinition.tools` is documented as: *"Array of allowed tool names. If omitted, inherits all tools from parent."* This implies that when set, the agent gets exactly those tools.
In practice, `AgentDefinition.tools` is **intersected** with `Options.tools` (the session-level base tool set). Sub-agents cannot have tools that aren't in the session base. This makes it impossible to restrict the main-thread agent's tools without also restricting all sub-agents.
## Observed Behavior
In `cli.js`, the tool resolution function (`Os` in minified source) works as follows:
```
1. Start with Options.tools (session base — shared across ALL agents)
2. Remove ALL_AGENT_DISALLOWED_TOOLS (Task, TaskOutput, AskUserQuestion, EnterPlanMode, TaskStop, etc.)
3. Remove AgentDefinition.disallowedTools
4. If AgentDefinition.tools is defined → INTERSECT with the result from step 3
5. If AgentDefinition.tools is undefined → use all remaining tools from step 3
```
The sub-agent spawning function (`tC` in minified source) passes the **parent's** `Options.tools` as the base:
```javascript
// In tC (sub-agent runner):
resolvedTools = Os(agentDefinition, toolUseContext.options.tools, isAsync).resolvedTools
```
This means every agent — main thread and sub-agents — shares the same base tool set.
## Concrete Failure Scenario
A coordinator pattern where the main-thread agent should only have orchestration tools, and sub-agents should have execution tools:
```typescript
const result = query({
prompt: "...",
options: {
tools: ['Task', 'TodoWrite', 'AskUserQuestion'], // Restrict coordinator
agent: 'Coordinator',
agents: {
Coordinator: {
description: 'Delegates work',
tools: ['Task', 'TodoWrite', 'AskUserQuestion'],
prompt: '...',
},
Coder: {
description: 'Writes code',
tools: ['Read', 'Edit', 'Write', 'Bash', 'Grep', 'Glob'],
prompt: '...',
},
},
},
});
```
**Expected:** Coordinator gets `[Task, TodoWrite, AskUserQuestion]`. Coder gets `[Read, Edit, Write, Bash, Grep, Glob]`.
**Actual:** After `ALL_AGENT_DISALLOWED_TOOLS` strips `Task/TodoWrite/AskUserQuestion` from the base, the intersection with `Options.tools` leaves the Coder with an **empty tool set** — none of `[Read, Edit, Write, Bash, Grep, Glob]` are in the base `[Task, TodoWrite, AskUserQuestion]`.
## Workaround
Leave `Options.tools` unrestricted (full tool set) so sub-agents work, then use `PreToolUse` hooks to block the coordinator from using direct tools. This results in a reject-and-retry pattern: the coordinator attempts a disallowed tool, the hook blocks it with an error, the model retries with delegation.
## Expected Behavior
`AgentDefinition.tools` should define each agent's tool set **independently**, not as a filter on the session base. When a sub-agent specifies `tools: ['Read', 'Edit', 'Write']`, it should get exactly those tools regardless of what `Options.tools` is set to.
Alternatively, provide a mechanism to restrict the main-thread agent's tools without affecting sub-agent tool resolution — e.g., an `Options.mainAgentTools` or `Options.mainAgentDisallowedTools` that only applies to the main thread.
Guide de contribution
Aucun guide de contribution indexé pour ce dépôt
Évaluation
Cette issue n'a pas encore été évaluée.