Skip to main content

Python SDK for building Agentpack tools

Project description

agentpack

Zero-Config Python SDK for Agentpack Tools

Drop a .py file in your repo and get a production-ready, containerized, gRPC-enabled tool—instantly. No servers. No Docker. No infrastructure code.

Installation

pip install agentpack
# or
poetry add agentpack
# or
uv pip install agentpack

Quick Start

1. Write ONLY Business Logic

# tools/greet.py
from pydantic import BaseModel
from agentpack import tool, ExecutionContext

class GreetInput(BaseModel):
    name: str

class GreetOutput(BaseModel):
    greeting: str

@tool(
    name="greet",
    description="Greet a person by name",
    input_schema=GreetInput,
    output_schema=GreetOutput,
)
async def greet(input: GreetInput, ctx: ExecutionContext) -> GreetOutput:
    ctx.logger.info("Greeting user", name=input.name)
    return GreetOutput(greeting=f"Hello, {input.name}!")

2. That's It!

No step 2. Agentpack Builder automatically:

  • Discovers tools in tools/ directory
  • Generates .agentpack-manifest.json
  • Creates optimized Dockerfile
  • Builds OCI image with gRPC runtime
  • Deploys to container backend

Agentpack Runtime automatically:

  • Loads tools from manifest
  • Starts gRPC server (port 50051)
  • Handles execution via Rust core
  • Provides full observability

Zero-Config Architecture

┌─────────────────────────────────────────────────┐
│  YOU: Write tools/calculator.py                 │
│  ↓                                              │
│  BUILDER: Scan → Manifest → Dockerfile → Image │
│  ↓                                              │
│  RUNTIME: Load → gRPC Server → Execute         │
│  ↓                                              │
│  RUST CORE: Orchestrate with Tower middleware  │
└─────────────────────────────────────────────────┘

You own: Business logic (100% focus) Agentpack owns: Servers, containers, orchestration, observability

Features

Built-In, Zero Setup:

  • Type-Safe: Full type inference with Pydantic
  • Validated: Automatic input/output validation
  • Observable: OpenTelemetry tracing (no config)
  • Secure: Secret management via dashboard
  • Resilient: HTTP client with automatic retries
  • Structured Logging: Request-scoped context
  • gRPC: High-performance protocol (auto-configured)
  • Containerized: OCI images with base runtime
  • Sandboxed: gVisor/Firecracker isolation

Execution Context

Every tool handler receives ctx with production-ready utilities:

Secrets

# Get optional secret
api_key = await ctx.secrets.get("API_KEY")

# Get required secret (raises if missing)
api_key = await ctx.secrets.require("API_KEY")

# Secrets configured via Agentpack Dashboard:
# - vault://kv/my-secret
# - aws-sm://secret-name
# - gcp-sm://projects/*/secrets/*

HTTP Client

# GET with automatic retries
response = await ctx.http.get(
    "https://api.example.com/data",
    params={"limit": 10},
    headers={"Authorization": f"Bearer {token}"},
)

# POST, PUT, DELETE also available
response = await ctx.http.post(
    "https://api.example.com/data",
    json={"name": "value"},
)

Logger

ctx.logger.info("Processing request", user_id="123")
ctx.logger.error("Something went wrong", error=str(err))

# Logs automatically include:
# - Request ID
# - Trace ID
# - Tool name
# - Timestamp

Tracer (OpenTelemetry)

span = ctx.trace.start_span("external-api-call")
try:
    # ... do work ...
    span.set_attribute("items.count", len(items))
finally:
    span.end()

# Traces sent to OpenTelemetry Collector automatically

Examples

See examples/ directory:

Simple Tool (examples/calculator.py)

from enum import Enum
from pydantic import BaseModel
from agentpack import tool, ExecutionContext

class Operation(str, Enum):
    ADD = "add"
    SUBTRACT = "subtract"
    MULTIPLY = "multiply"
    DIVIDE = "divide"

class CalculatorInput(BaseModel):
    operation: Operation
    a: float
    b: float

class CalculatorOutput(BaseModel):
    result: float
    operation: str

@tool(
    name="calculator",
    description="Perform basic arithmetic operations",
    input_schema=CalculatorInput,
    output_schema=CalculatorOutput,
)
async def calculator(input: CalculatorInput, ctx: ExecutionContext) -> CalculatorOutput:
    # Pure business logic
    if input.operation == Operation.ADD:
        result = input.a + input.b
    elif input.operation == Operation.SUBTRACT:
        result = input.a - input.b
    elif input.operation == Operation.MULTIPLY:
        result = input.a * input.b
    elif input.operation == Operation.DIVIDE:
        if input.b == 0:
            raise ValueError("Division by zero")
        result = input.a / input.b

    return CalculatorOutput(
        result=result,
        operation=f"{input.a} {input.operation.value} {input.b}"
    )

External API Tool (examples/weather.py)

Demonstrates:

  • Secret management (ctx.secrets.require())
  • HTTP client with retries (ctx.http.get())
  • Structured logging
  • Input validation with Pydantic

API Reference

@tool Decorator

Create a tool definition.

from pydantic import BaseModel
from agentpack import tool, ExecutionContext

class MyInput(BaseModel):
    value: int

class MyOutput(BaseModel):
    result: int

@tool(
    name="my_tool",                    # Unique tool identifier
    description="My tool description", # Human-readable description
    input_schema=MyInput,              # Pydantic input model
    output_schema=MyOutput,            # Pydantic output model
)
async def my_tool(input: MyInput, ctx: ExecutionContext) -> MyOutput:
    return MyOutput(result=input.value * 2)

Parameters:

  • name (str): Unique tool name
  • description (str): Human-readable description
  • input_schema (BaseModel): Pydantic input validation model
  • output_schema (BaseModel): Pydantic output validation model

Returns: Tool instance (internal use by runtime)

Error Handling

from agentpack import (
    ToolError,
    ValidationError,
    SecretNotFoundError,
    HttpError,
)

async def my_handler(input: MyInput, ctx: ExecutionContext) -> MyOutput:
    # Validation errors raised automatically by Pydantic

    # Secret not found
    key = await ctx.secrets.require("API_KEY")  # raises SecretNotFoundError

    # HTTP errors from external APIs
    response = await ctx.http.get("...")  # raises HttpError on failure

    # Custom errors
    if not input.valid:
        raise ToolError("Invalid input", "INVALID_INPUT")

Multi-File Tools

Tools can have dependencies:

tools/
├── calculator/
│   ├── __init__.py      # Entry point (exports tool)
│   ├── operations.py    # Helper functions
│   └── types.py         # Shared types
└── weather.py           # Single-file tool

Builder discovers both patterns automatically:

  • Single-file: tools/weather.py
  • Multi-file: tools/calculator/__init__.py

Testing

import pytest
from pydantic import BaseModel
from agentpack import tool, ExecutionContext

class TestInput(BaseModel):
    value: int

class TestOutput(BaseModel):
    result: int

@tool(
    name="test_tool",
    description="Test tool",
    input_schema=TestInput,
    output_schema=TestOutput,
)
async def test_tool(input: TestInput, ctx: ExecutionContext) -> TestOutput:
    return TestOutput(result=input.value * 2)

@pytest.mark.asyncio
async def test_my_tool():
    # Create mock context
    from agentpack.context import create_execution_context
    from agentpack.types import RequestMetadata

    metadata = RequestMetadata(request_id="123")
    ctx = create_execution_context(metadata)

    # Execute tool
    result = await test_tool.execute({"value": 5}, ctx)
    assert result.result == 10

Deployment

Nothing to do! Builder + Runtime handle everything:

  1. Build: agentpack build (or automatic via GitHub App)
  2. Deploy: Automatic to Agentpack infrastructure
  3. Scale: Automatic based on load
  4. Monitor: Traces/logs in dashboard

Configuration

Optional agentpack.yaml for advanced settings:

version: 0.1
project: my-tools

agents:
  - name: default
    model: { provider: anthropic, name: claude-3-5-sonnet }
    tools: ["*"]  # All tools in tools/

resources:
  - name: stripe_secret
    type: secret
    source: vault://kv/stripe

policies:
  outbound_network:
    allow: ["*.stripe.com", "*.openai.com"]

Thin SDK Philosophy

This SDK is intentionally minimal:

  • @tool decorator for definitions
  • ExecutionContext types
  • ✅ Error classes
  • ❌ NO server creation
  • ❌ NO Docker setup
  • ❌ NO deployment code

All orchestration lives in Rust core for:

  • Consistent cross-language behavior
  • Performance (Tower middleware)
  • Security (policy enforcement)
  • Observability (OpenTelemetry)

Type Checking

The SDK is fully typed and works with mypy:

mypy tools/ --strict

Troubleshooting

"Tool not found" error

  • Ensure tool is in tools/ directory
  • Check file exports tool with @tool decorator
  • Verify .agentpack-manifest.json was generated

Validation errors

  • Check Pydantic model matches input
  • Use Optional[T] or = Field(default=...) for optional fields
  • Test with mock data

Secret not found

  • Configure secrets in Agentpack Dashboard
  • Use correct secret key name
  • Check environment variables in development

Related Packages

  • agentpack-runtime-python - Internal gRPC runtime (private)
  • @agentpack/sdk - TypeScript SDK (same zero-config approach)

License

MIT OR Apache-2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

agentpack-0.1.0.tar.gz (25.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

agentpack-0.1.0-py3-none-any.whl (12.6 kB view details)

Uploaded Python 3

File details

Details for the file agentpack-0.1.0.tar.gz.

File metadata

  • Download URL: agentpack-0.1.0.tar.gz
  • Upload date:
  • Size: 25.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for agentpack-0.1.0.tar.gz
Algorithm Hash digest
SHA256 d398dee12a6ca0b54ff89bfdb4f3e80df590c9d776a73a6f93d7851211667503
MD5 0d205fa53ceff257b97758a6ffd17519
BLAKE2b-256 9d2b3a18e00408ccf04f4649f3ed926decb10f06706c057ec47970373725e488

See more details on using hashes here.

File details

Details for the file agentpack-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: agentpack-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 12.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for agentpack-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a69f8b08cf6c959d30d0cb8cc0adb802fc222a85cb125f8eacac450ce3634e40
MD5 4afee69b766b1eeaab92b5a27c19ca32
BLAKE2b-256 ce3f1a74ff566f882fb24eff8652bcfca02a5e6517d433dca4479ce410ffc320

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page