> ## Documentation Index
> Fetch the complete documentation index at: https://docs.upsonic.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Creating ToolKit

> Organize related tools in a class with filtering, async mode, and configuration

## Getting Started

Create a class that extends `ToolKit` and mark methods with `@tool` to expose them to the agent.

```python theme={null}
from upsonic import Agent, Task
from upsonic.tools import tool, ToolKit

class MathToolKit(ToolKit):
    @tool
    def add(self, a: float, b: float) -> float:
        """Add two numbers."""
        return a + b

    @tool
    def multiply(self, a: float, b: float) -> float:
        """Multiply two numbers."""
        return a * b

    def _validate(self, x: float) -> bool:
        """Internal helper -- not exposed (no @tool)."""
        return x >= 0

agent = Agent(model="anthropic/claude-sonnet-4-6", name="Math Agent")
task = Task(description="Calculate (15 + 27) * 2", tools=[MathToolKit()])
result = agent.print_do(task)
```

## Filtering Tools

Control which methods are registered at instantiation time.

### `include_tools` -- Add Non-Decorated Methods

Adds named methods to the tool set alongside any `@tool`-decorated ones.

```python theme={null}
from upsonic import Agent, Task
from upsonic.tools import tool, ToolKit

class FileToolKit(ToolKit):
    @tool
    def read_file(self, path: str) -> str:
        """Read a file."""
        return f"Contents of {path}"

    def write_file(self, path: str, content: str) -> str:
        """Write a file. Not @tool-decorated by default."""
        return f"Wrote to {path}"

agent = Agent(model="anthropic/claude-sonnet-4-6", name="File Agent")
# 'read_file' (decorated) + 'write_file' (explicitly included) are both available
task = Task(
    description="Read config.txt then write 'done' to output.txt",
    tools=[FileToolKit(include_tools=["write_file"])],
)
result = agent.print_do(task)
```

### `exclude_tools` -- Remove Tools

Removes named methods. Always takes priority over `include_tools` and `@tool`.

```python theme={null}
from upsonic import Agent, Task
from upsonic.tools import tool, ToolKit

class AdminToolKit(ToolKit):
    @tool
    def list_users(self) -> str:
        """List all users."""
        return "alice, bob, charlie"

    @tool
    def delete_user(self, name: str) -> str:
        """Delete a user."""
        return f"Deleted {name}"

agent = Agent(model="anthropic/claude-sonnet-4-6", name="Admin Agent")
# Only 'list_users' is available -- 'delete_user' is blocked
task = Task(
    description="List all users",
    tools=[AdminToolKit(exclude_tools=["delete_user"])],
)
result = agent.print_do(task)
```

## Async Tools

Set `use_async=True` to register **all public async methods** and drop all sync methods.

```python theme={null}
from upsonic import Agent, Task
from upsonic.tools import tool, ToolKit

class SearchToolKit(ToolKit):
    @tool
    def sync_search(self, query: str) -> str:
        """Sync search -- dropped when use_async=True."""
        return f"Sync: {query}"

    async def async_search(self, query: str) -> str:
        """Async search -- auto-discovered by use_async."""
        return f"Async: {query}"

    async def async_suggest(self, query: str) -> str:
        """Async suggestions -- also auto-discovered."""
        return f"Suggestions for: {query}"

agent = Agent(model="anthropic/claude-sonnet-4-6", name="Search Agent")
# Only 'async_search' and 'async_suggest' are registered
task = Task(
    description="Search for 'upsonic framework'",
    tools=[SearchToolKit(use_async=True)],
)
result = agent.print_do(task)
```

Combine with `include_tools` to keep a specific sync method:

```python theme={null}
from upsonic import Agent, Task
from upsonic.tools import tool, ToolKit

class SearchToolKit(ToolKit):
    @tool
    def sync_search(self, query: str) -> str:
        """Sync fallback search."""
        return f"Sync: {query}"

    async def async_search(self, query: str) -> str:
        """Async search."""
        return f"Async: {query}"

agent = Agent(model="anthropic/claude-sonnet-4-6", name="Search Agent")
# Both async AND the explicitly included sync method are registered
task = Task(
    description="Search for 'upsonic framework'",
    tools=[SearchToolKit(use_async=True, include_tools=["sync_search"])],
)
result = agent.print_do(task)
```

## Configuration

### Toolkit-Wide Defaults

Pass config fields to `__init__` to apply them to every tool in the toolkit.

```python theme={null}
from upsonic import Agent, Task
from upsonic.tools import tool, ToolKit

class PaymentToolKit(ToolKit):
    @tool
    def charge(self, amount: float) -> str:
        """Charge a payment."""
        return f"Charged ${amount}"

    @tool
    def refund(self, amount: float) -> str:
        """Refund a payment."""
        return f"Refunded ${amount}"

agent = Agent(model="anthropic/claude-sonnet-4-6", name="Payment Agent")
task = Task(
    description="Charge $49.99",
    # Both 'charge' and 'refund' get timeout=120s and require confirmation
    tools=[PaymentToolKit(timeout=120.0, requires_confirmation=True)],
)
result = agent.print_do(task)
```

### Per-Tool Config via `@tool`

Set config on individual methods. The toolkit `__init__` overrides overlapping fields.

```python theme={null}
from upsonic import Agent, Task
from upsonic.tools import tool, ToolKit

class DeployToolKit(ToolKit):
    @tool(requires_confirmation=True, timeout=300.0)
    def deploy(self, env: str) -> str:
        """Deploy to an environment."""
        return f"Deployed to {env}"

    @tool(timeout=30.0)
    def check_status(self, env: str) -> str:
        """Check deployment status."""
        return f"{env} is healthy"

# timeout=60.0 overrides BOTH decorator timeouts (300.0 and 30.0)
# requires_confirmation=True on 'deploy' survives (not overridden)
toolkit = DeployToolKit(timeout=60.0)

agent = Agent(model="anthropic/claude-sonnet-4-6", name="Deploy Agent")
task = Task(description="Check the status of production", tools=[toolkit])
result = agent.print_do(task)
```

| Source     | Priority | Scope       |
| ---------- | -------- | ----------- |
| `__init__` | Highest  | All tools   |
| `@tool()`  | Lower    | Single tool |

## Building Reusable ToolKits

Accept `**kwargs` and forward to `super().__init__()` so users can pass filtering and config parameters without modifying the class.

```python theme={null}
from typing import Any
from upsonic import Agent, Task
from upsonic.tools import tool, ToolKit

class GitHubToolKit(ToolKit):
    def __init__(self, api_token: str, **kwargs: Any):
        super().__init__(**kwargs)
        self.api_token = api_token

    @tool
    def list_repos(self, org: str) -> str:
        """List repositories for an organization."""
        return f"Repos for {org}: repo1, repo2"

    @tool
    def create_issue(self, repo: str, title: str) -> str:
        """Create a GitHub issue."""
        return f"Created '{title}' in {repo}"

    @tool
    def close_issue(self, repo: str, issue_number: int) -> str:
        """Close a GitHub issue."""
        return f"Closed #{issue_number} in {repo}"

# Users can filter and configure at instantiation
toolkit = GitHubToolKit(
    api_token="ghp_...",
    exclude_tools=["close_issue"],
    timeout=60.0,
)

agent = Agent(model="anthropic/claude-sonnet-4-6", name="GitHub Agent")
task = Task(
    description="List repos for 'upsonic' and create an issue titled 'Bug fix' in repo1",
    tools=[toolkit],
)
result = agent.print_do(task)
```

## Runtime Tool Management

Add or remove tools after agent creation.

```python theme={null}
from upsonic import Agent, Task
from upsonic.tools import tool, ToolKit

class MathToolKit(ToolKit):
    @tool
    def add(self, a: float, b: float) -> float:
        """Add two numbers."""
        return a + b

    @tool
    def subtract(self, a: float, b: float) -> float:
        """Subtract b from a."""
        return a - b

    @tool
    def multiply(self, a: float, b: float) -> float:
        """Multiply two numbers."""
        return a * b

toolkit = MathToolKit()
agent = Agent(model="anthropic/claude-sonnet-4-6", name="Math Agent", tools=[toolkit])

# Remove one method by name (toolkit stays registered)
agent.remove_tools("add")

task = Task(description="Subtract 10 from 50, then multiply by 3")
result = agent.print_do(task)

# Remove the entire toolkit (removes all remaining methods)
agent.remove_tools(toolkit)
```

## Toolkit-Level Instructions

Inject custom guidance into the agent's system prompt that applies to all tools in the toolkit. The LLM sees these instructions before making any tool calls.

```python theme={null}
from typing import Any
from upsonic import Agent, Task
from upsonic.tools import tool, ToolKit

class PaymentToolKit(ToolKit):
    def __init__(self, **kwargs: Any):
        super().__init__(
            instructions="Always validate the amount is positive before calling any payment tool. Never process payments above $10,000 without confirmation.",
            add_instructions=True,
            **kwargs
        )

    @tool
    def charge(self, amount: float, currency: str = "USD") -> str:
        """
        Charge a payment.

        Args:
            amount: Amount to charge
            currency: Currency code

        Returns:
            Transaction ID
        """
        return f"txn_{amount}_{currency}"

    @tool
    def refund(self, transaction_id: str) -> str:
        """
        Refund a transaction.

        Args:
            transaction_id: ID of the transaction to refund

        Returns:
            Refund confirmation
        """
        return f"refunded_{transaction_id}"

agent = Agent(model="anthropic/claude-sonnet-4-6", name="Payment Agent")
task = Task(description="Charge $49.99 in EUR", tools=[PaymentToolKit()])
result = agent.print_do(task)
```

## Parameter Reference

| Parameter                        | Type        | Effect                                                                |
| -------------------------------- | ----------- | --------------------------------------------------------------------- |
| `include_tools`                  | `list[str]` | Adds named methods to the tool set (additive)                         |
| `exclude_tools`                  | `list[str]` | Removes named methods (always wins)                                   |
| `use_async`                      | `bool`      | Registers all public async methods, drops all sync                    |
| `instructions`                   | `str`       | Instructions for the LLM, injected into the system prompt             |
| `add_instructions`               | `bool`      | If True, toolkit instructions are appended to system prompt           |
| `timeout`                        | `float`     | Execution timeout in seconds                                          |
| `max_retries`                    | `int`       | Maximum retry attempts on failure                                     |
| `requires_confirmation`          | `bool`      | Pause for user confirmation before execution                          |
| `requires_user_input`            | `bool`      | Pause and prompt the user for input before execution                  |
| `user_input_fields`              | `list[str]` | Field names to prompt the user for when `requires_user_input` is True |
| `external_execution`             | `bool`      | Tool execution is handled by an external process                      |
| `show_result`                    | `bool`      | Show output to user instead of sending it back to the LLM             |
| `stop_after_tool_call`           | `bool`      | Terminate the agent run after this tool executes                      |
| `sequential`                     | `bool`      | Disable parallel execution for this tool                              |
| `cache_results`                  | `bool`      | Cache results based on arguments                                      |
| `cache_dir`                      | `str`       | Directory to store cache files                                        |
| `cache_ttl`                      | `int`       | Cache time-to-live in seconds                                         |
| `tool_hooks`                     | `ToolHooks` | Before/after callables for tool execution lifecycle                   |
| `strict`                         | `bool`      | Enforce strict JSON schema validation                                 |
| `docstring_format`               | `str`       | Docstring format: `"google"`, `"numpy"`, `"sphinx"`, or `"auto"`      |
| `require_parameter_descriptions` | `bool`      | Raise error if required parameter descriptions are missing            |
