Metadata-Version: 2.4
Name: useveto
Version: 0.1.0
Summary: Runtime authorization for AI agents — Python SDK
Project-URL: Homepage, https://veto.tools
Project-URL: Documentation, https://docs.veto.tools
Project-URL: Repository, https://github.com/useveto/veto
Project-URL: Issues, https://github.com/useveto/veto/issues
Author-email: Veto <hello@veto.tools>
License-Expression: MIT
License-File: LICENSE
Keywords: agents,ai,authorization,mcp,security
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries
Classifier: Typing :: Typed
Requires-Python: >=3.9
Requires-Dist: httpx>=0.24.0
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: respx>=0.20; extra == 'dev'
Requires-Dist: ruff>=0.4; extra == 'dev'
Description-Content-Type: text/markdown

# useveto

Runtime authorization for AI agents — Python SDK.

[![PyPI](https://img.shields.io/pypi/v/useveto)](https://pypi.org/project/useveto/)
[![License: MIT](https://img.shields.io/badge/License-MIT-emerald.svg)](https://opensource.org/licenses/MIT)
[![Python](https://img.shields.io/pypi/pyversions/useveto)](https://pypi.org/project/useveto/)

## What is Veto?

Veto intercepts every tool call your AI agent makes, evaluates it against your policies, and decides: **allow**, **deny**, or **escalate**. Sub-10ms. Default deny.

- **Default deny** — no matching policy = blocked
- **Full audit trail** — every decision logged
- **Edge-first** — powered by Cloudflare Workers
- **Sync + async** — both clients included

## Install

```bash
pip install useveto
```

## Quick Start

```python
from veto import VetoClient

client = VetoClient(api_key="veto_...")

# Check if an agent can perform an action
result = client.authorize("agent-uuid", "file.write", {"path": "/etc/passwd"})

if not result.allowed:
    print(f"Blocked: {result.reason}")
```

### Async

```python
from veto import AsyncVetoClient

async with AsyncVetoClient(api_key="veto_...") as client:
    result = await client.authorize("agent-uuid", "send_email", {
        "to": "user@example.com",
        "subject": "Refund confirmation",
    })
```

## LangChain Integration

```python
from veto import VetoClient, VetoError

veto = VetoClient(api_key="veto_...")

def veto_tool_wrapper(tool_func, tool_name: str, agent_id: str):
    """Wrap any LangChain tool with Veto authorization."""
    def wrapper(*args, **kwargs):
        result = veto.authorize(agent_id, tool_name, kwargs)
        if not result.allowed:
            return f"Authorization denied: {result.reason}"
        return tool_func(*args, **kwargs)
    wrapper.__name__ = tool_func.__name__
    wrapper.__doc__ = tool_func.__doc__
    return wrapper
```

## CrewAI Integration

```python
from veto import VetoClient

veto = VetoClient(api_key="veto_...")

def before_tool_callback(agent_id: str):
    def callback(tool_name: str, tool_input: dict) -> bool:
        result = veto.authorize(agent_id, tool_name, tool_input)
        return result.allowed
    return callback
```

## API Reference

### `VetoClient` / `AsyncVetoClient`

```python
client = VetoClient(
    api_key="veto_...",       # required
    endpoint="https://api.veto.tools",  # optional
    timeout=5.0,              # optional, seconds
)
```

#### Authorization

```python
client.authorize(agent_id, tool_name, parameters={}) -> AuthorizationResult
```

#### Agents

```python
client.create_agent(CreateAgentInput(name="Bot", description="...")) -> Agent
client.list_agents() -> List[Agent]
client.get_agent(agent_id) -> Agent
client.delete_agent(agent_id) -> None
```

#### Policies

```python
client.create_policy(CreatePolicyInput(
    agent_id="...",
    name="Allow reads",
    rules=[PolicyRule(type="tool_allowlist", tools=["file.read"])],
    priority=10,
)) -> Policy

client.list_policies(agent_id=None) -> List[Policy]
client.get_policy(policy_id) -> Policy
client.update_policy(policy_id, UpdatePolicyInput(name="New name")) -> Policy
client.delete_policy(policy_id) -> None
```

#### Audit Logs

```python
client.query_audit_log(
    agent_id=None,
    tool_name=None,
    result=None,  # "allowed" | "denied" | "escalated"
    limit=100,
    offset=0,
) -> PaginatedAuditLogResponse
```

### Error Handling

```python
from veto import VetoError, UnauthorizedError, RateLimitError

try:
    result = client.authorize("agent", "tool")
except RateLimitError as e:
    print(f"Retry after {e.retry_after_ms}ms")
except UnauthorizedError:
    print("Invalid API key")
except VetoError as e:
    print(f"{e.code}: {e}")
```

### Context Manager

```python
# Sync
with VetoClient(api_key="veto_...") as client:
    result = client.authorize("agent-1", "file.read")

# Async
async with AsyncVetoClient(api_key="veto_...") as client:
    result = await client.authorize("agent-1", "file.read")
```

## Links

- **Website:** [veto.tools](https://veto.tools)
- **Dashboard:** [app.veto.tools](https://app.veto.tools)
- **API Docs:** [docs.veto.tools](https://docs.veto.tools)
- **GitHub:** [github.com/useveto/veto](https://github.com/useveto/veto)

## License

MIT
