feat: add tools option to ClaudeAgentOptions

Add support for the `tools` option matching the TypeScript SDK, which
controls the base set of available tools separately from allowed/disallowed
tool filtering.

Supports three modes:
- Array of tool names: `["Read", "Edit", "Bash"]`
- Empty array: `[]` (disables all built-in tools)
- Preset object: `{"type": "preset", "preset": "claude_code"}`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Ashwin Bhat 2025-12-03 17:47:34 -08:00
parent 243703531b
commit 18e852a131
No known key found for this signature in database
3 changed files with 66 additions and 0 deletions

View file

@ -185,6 +185,18 @@ class SubprocessCLITransport(Transport):
["--append-system-prompt", self._options.system_prompt["append"]]
)
# Handle tools option (base set of tools)
if self._options.tools is not None:
tools = self._options.tools
if isinstance(tools, list):
if len(tools) == 0:
cmd.extend(["--tools", ""])
else:
cmd.extend(["--tools", ",".join(tools)])
else:
# Preset object - 'claude_code' preset maps to 'default'
cmd.extend(["--tools", "default"])
if self._options.allowed_tools:
cmd.extend(["--allowedTools", ",".join(self._options.allowed_tools)])

View file

@ -26,6 +26,13 @@ class SystemPromptPreset(TypedDict):
append: NotRequired[str]
class ToolsPreset(TypedDict):
"""Tools preset configuration."""
type: Literal["preset"]
preset: Literal["claude_code"]
@dataclass
class AgentDefinition:
"""Agent definition configuration."""
@ -603,6 +610,7 @@ Message = UserMessage | AssistantMessage | SystemMessage | ResultMessage | Strea
class ClaudeAgentOptions:
"""Query options for Claude SDK."""
tools: list[str] | ToolsPreset | None = None
allowed_tools: list[str] = field(default_factory=list)
system_prompt: str | SystemPromptPreset | None = None
mcp_servers: dict[str, McpServerConfig] | str | Path = field(default_factory=dict)

View file

@ -647,3 +647,49 @@ class TestSubprocessCLITransport:
assert network["allowLocalBinding"] is True
assert network["httpProxyPort"] == 8080
assert network["socksProxyPort"] == 8081
def test_build_command_with_tools_array(self):
"""Test building CLI command with tools as array of tool names."""
transport = SubprocessCLITransport(
prompt="test",
options=make_options(tools=["Read", "Edit", "Bash"]),
)
cmd = transport._build_command()
assert "--tools" in cmd
tools_idx = cmd.index("--tools")
assert cmd[tools_idx + 1] == "Read,Edit,Bash"
def test_build_command_with_tools_empty_array(self):
"""Test building CLI command with tools as empty array (disables all tools)."""
transport = SubprocessCLITransport(
prompt="test",
options=make_options(tools=[]),
)
cmd = transport._build_command()
assert "--tools" in cmd
tools_idx = cmd.index("--tools")
assert cmd[tools_idx + 1] == ""
def test_build_command_with_tools_preset(self):
"""Test building CLI command with tools preset."""
transport = SubprocessCLITransport(
prompt="test",
options=make_options(tools={"type": "preset", "preset": "claude_code"}),
)
cmd = transport._build_command()
assert "--tools" in cmd
tools_idx = cmd.index("--tools")
assert cmd[tools_idx + 1] == "default"
def test_build_command_without_tools(self):
"""Test building CLI command without tools option (default None)."""
transport = SubprocessCLITransport(
prompt="test",
options=make_options(),
)
cmd = transport._build_command()
assert "--tools" not in cmd