Metadata-Version: 2.4
Name: tame-ai-sdk
Version: 0.1.1
Summary: Python SDK for protecting AI agent tool calls with TAME runtime policies.
Author: TAME
License-Expression: MIT
Project-URL: Homepage, https://tame.sh
Project-URL: Repository, https://github.com/franpfeiffer/tame
Keywords: ai,agents,security,runtime,guardrails
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
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
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# tame-ai-sdk

Python SDK for protecting AI agent tool calls with TAME runtime policies.

## Install

```bash
pip install tame-ai-sdk
```

For local development in this repo:

```bash
cd packages/sdk-python
python -m pip install -e .
```

## Configure

```bash
TAME_BASE_URL=https://tame.sh
TAME_API_KEY=tame_sk_replace_me
TAME_ENVIRONMENT=production
```

Use a runtime API key in agent hosts. Use a control API key only for dashboards, policy management, and administrative reads.

## Usage

```python
import os
from tame_ai import TameClient, TameToolError

tame = TameClient(
    base_url=os.environ["TAME_BASE_URL"],
    api_key=os.environ["TAME_API_KEY"],
    agent_id="code-pipeline-agent",
    context={"environment": os.getenv("TAME_ENVIRONMENT", "production")},
    failure_mode="fail_closed",
)

def real_apply_patch(args):
    return {"applied": True}

apply_patch = tame.protect_tool(
    name="apply_patch",
    execute=real_apply_patch,
)

try:
    result = apply_patch({
        "repository": "checkout-service",
        "file_path": "src/auth/session.py",
        "risk_score": 95,
    })
except TameToolError as error:
    print(error.decision["reason"])
```

TAME checks the tool call before execution. If a policy blocks the call or requires approval, the SDK raises `TameToolError` and the protected tool is not executed.

## Decision Metadata

Decision responses include protection-signal fields:

```python
decision = tame.check_tool_call(
    tool={"name": "send_http_request", "arguments": {"url": "https://example.com/path"}},
)

print(decision["policies_evaluated"])
print(decision["applicable_policies"])
print(decision.get("policy_warning"))
```

If `applicable_policies` is `0`, the runtime allowed by default because no enabled policy matched the agent/tool/conditions. Treat `policy_warning` as an integration warning, not as a block.

## Failure Modes

`failure_mode="fail_closed"` is the default. If TAME is unavailable, tool execution fails before the real function runs.

`failure_mode="fail_open"` returns an allow decision when TAME is unavailable:

```python
tame = TameClient(
    base_url=os.environ["TAME_BASE_URL"],
    api_key=os.environ["TAME_API_KEY"],
    agent_id="support-agent",
    failure_mode="fail_open",
    timeout_ms=1000,
)
```

Use fail-open only for low-risk workflows.

## Approval Flow

```python
decision = tame.check_tool_call(
    tool={"name": "issue_refund", "arguments": {"amount": 250}},
)

if decision["result"] == "require_approval":
    approval = tame.wait_for_approval(decision["approval_id"])
    if approval["status"] == "approved":
        resumed = tame.check_approved_tool_call(
            decision["approval_id"],
            tool={"name": "issue_refund", "arguments": {"amount": 250}},
        )
```

## Memory Writes

```python
write_memory = tame.protect_memory_write(
    source="customer-support-agent",
    content=lambda item: item["memory"],
    write=lambda item: vector_store.add_texts([item["memory"]]),
)

write_memory({"memory": "Customer prefers email follow-up."})
```

If TAME quarantines the write, `TameMemoryWriteError` is raised and your store is not updated.

## Lifecycle and Model Telemetry

```python
tame.record_agent_event(
    event_type="model.completed",
    trace_id="trace_123",
    payload={
        "provider": "your-provider",
        "model": "your-model-name",
        "outcome": "success",
    },
)
```

Send metadata only: never prompts, completions, credentials, or raw customer data.

## OpenAI Function Calls

```python
from tame_ai import protect_openai_tool

handler = protect_openai_tool(
    tame,
    name="get_customer",
    execute=lambda args: crm.get_customer(args["customer_id"]),
)

result = handler(openai_tool_call)
```

## LangGraph, AutoGen, and CrewAI

The SDK intentionally keeps framework adapters thin. Wrap the underlying callable before registering it with the framework:

```python
from tame_ai.integrations import protect_langgraph_tool, protect_autogen_tool, protect_crewai_tool

safe_lookup = protect_langgraph_tool(tame, name="get_customer", execute=get_customer)
safe_refund = protect_autogen_tool(tame, name="issue_refund", execute=issue_refund)
safe_export = protect_crewai_tool(tame, name="export_customers", execute=export_customers)
```

The protected callable has the same behavior as `tame.protect_tool(...)`: decision first, execution only on allow, completion telemetry best-effort after success.

## Policy Field Notes

Agent IDs are validated server-side. Use stable IDs with letters, numbers, dots, underscores, colons, or hyphens. Avoid spaces and slashes.

For URL policies, prefer server-side host operators:

- `host_in`
- `host_not_in`
- `starts_with`
- `contains`
- `matches`

This avoids every Python integrator having to derive a URL host field manually.
