Skip to main content

Getting Started

Create a class that extends ToolKit and mark methods with @tool to expose them to the agent.
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.
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.
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.
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:
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.
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.
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)
SourcePriorityScope
__init__HighestAll tools
@tool()LowerSingle tool

Building Reusable ToolKits

Accept **kwargs and forward to super().__init__() so users can pass filtering and config parameters without modifying the class.
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.
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.
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

ParameterTypeEffect
include_toolslist[str]Adds named methods to the tool set (additive)
exclude_toolslist[str]Removes named methods (always wins)
use_asyncboolRegisters all public async methods, drops all sync
instructionsstrInstructions for the LLM, injected into the system prompt
add_instructionsboolIf True, toolkit instructions are appended to system prompt
timeoutfloatExecution timeout in seconds
max_retriesintMaximum retry attempts on failure
requires_confirmationboolPause for user confirmation before execution
requires_user_inputboolPause and prompt the user for input before execution
user_input_fieldslist[str]Field names to prompt the user for when requires_user_input is True
external_executionboolTool execution is handled by an external process
show_resultboolShow output to user instead of sending it back to the LLM
stop_after_tool_callboolTerminate the agent run after this tool executes
sequentialboolDisable parallel execution for this tool
cache_resultsboolCache results based on arguments
cache_dirstrDirectory to store cache files
cache_ttlintCache time-to-live in seconds
tool_hooksToolHooksBefore/after callables for tool execution lifecycle
strictboolEnforce strict JSON schema validation
docstring_formatstrDocstring format: "google", "numpy", "sphinx", or "auto"
require_parameter_descriptionsboolRaise error if required parameter descriptions are missing