Metadata-Version: 2.4
Name: altrace-ai
Version: 0.1.0
Summary: Python SDK for Altrace AI agent governance
Project-URL: Homepage, https://github.com/altrace-dev-role/altrace-python
Project-URL: Repository, https://github.com/altrace-dev-role/altrace-python
Author-email: Karthik Nerella <k4rthik.nerella@gmail.com>
License-Expression: Apache-2.0
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
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 :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: httpx<1,>=0.24.0
Provides-Extra: all
Requires-Dist: anthropic>=0.30.0; extra == 'all'
Requires-Dist: autogen-agentchat>=0.4; extra == 'all'
Requires-Dist: crewai>=0.100; extra == 'all'
Requires-Dist: langchain-core>=0.3; extra == 'all'
Requires-Dist: openai>=1.0.0; extra == 'all'
Requires-Dist: prometheus-client>=0.20.0; extra == 'all'
Requires-Dist: requests>=2.28.0; extra == 'all'
Provides-Extra: anthropic
Requires-Dist: anthropic>=0.30.0; extra == 'anthropic'
Provides-Extra: autogen
Requires-Dist: autogen-agentchat>=0.4; extra == 'autogen'
Provides-Extra: crewai
Requires-Dist: crewai>=0.100; extra == 'crewai'
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
Requires-Dist: pytest-mock>=3.10; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: respx>=0.20; extra == 'dev'
Provides-Extra: langchain
Requires-Dist: langchain-core>=0.3; extra == 'langchain'
Provides-Extra: metrics
Requires-Dist: prometheus-client>=0.20.0; extra == 'metrics'
Provides-Extra: openai
Requires-Dist: openai>=1.0.0; extra == 'openai'
Provides-Extra: otel
Requires-Dist: opentelemetry-api>=1.20.0; extra == 'otel'
Requires-Dist: opentelemetry-sdk>=1.20.0; extra == 'otel'
Provides-Extra: requests
Requires-Dist: requests>=2.28.0; extra == 'requests'
Description-Content-Type: text/markdown

# Altrace Python SDK

Governance SDK for AI agents. Routes Anthropic and OpenAI API traffic through the Altrace proxy for budget enforcement, kill switches, cost attribution, and evidence-grounded validation. Includes framework adapters for LangChain, CrewAI, and AutoGen.

413 tests passing.

## Installation

```bash
pip install altrace              # Core SDK
pip install altrace[anthropic]   # Anthropic provider
pip install altrace[openai]      # OpenAI provider
pip install altrace[langchain]   # LangChain adapter
pip install altrace[crewai]      # CrewAI adapter
pip install altrace[autogen]     # AutoGen adapter
pip install altrace[all]         # Everything
```

## Quick Start

### Anthropic

```python
from altrace import patch_anthropic, AltraceConfig
import anthropic

config = AltraceConfig(
    proxy_url="http://altrace:8080",
    team="backend",
    virtual_key="vk_altrace_abc123",
)

client = anthropic.Anthropic(api_key="sk-ant-xxx")
patch_anthropic(client, config)

# All requests now route through the Altrace proxy
response = client.messages.create(
    model="claude-sonnet-4-5-20250929",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello"}],
)
```

### OpenAI

```python
from altrace import patch_openai, AltraceConfig
import openai

config = AltraceConfig(
    proxy_url="http://altrace:8080",
    team="backend",
    virtual_key="vk_altrace_xyz789",
)

client = openai.OpenAI(api_key="sk-xxx")
patch_openai(client, config)

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Hello"}],
)
```

You can also use `create_anthropic_client(config)` and `create_openai_client(config)` to create pre-configured client instances directly.

## Framework Adapters

### LangChain

```python
from altrace import AltraceConfig, EvidenceRecorder
from altrace.adapters.langchain import AltraceMiddleware
from langchain_anthropic import ChatAnthropic

config = AltraceConfig.from_env()
evidence = EvidenceRecorder()
middleware = AltraceMiddleware(config, evidence)
model = ChatAnthropic(model="claude-sonnet-4-20250514")
model = model.with_middleware(middleware)
```

### CrewAI

```python
from altrace import AltraceConfig, EvidenceRecorder
from altrace.adapters.crewai import instrument

config = AltraceConfig.from_env()
evidence = EvidenceRecorder()
instrument(config, evidence)  # Call once at startup
```

### AutoGen

```python
from altrace import AltraceConfig, EvidenceRecorder
from altrace.adapters.autogen import GovernedClient
from autogen_core.models import OpenAIChatCompletionClient

config = AltraceConfig.from_env()
evidence = EvidenceRecorder()
inner = OpenAIChatCompletionClient(model="gpt-4o")
client = GovernedClient(inner, config, evidence)
```

## Evidence Recording

Record tool invocations as evidence for evidence-grounded validation. The proxy enforces that destructive tool calls (e.g., `issue_refund`) are preceded by prerequisite evidence-gathering calls (e.g., `lookup_order`).

```python
from altrace import AltraceClient

client = AltraceClient()
client.patch_httpx()

# Record prerequisite tool usage (attached to next request)
client.record_evidence("lookup_order")
client.record_evidence("verify_identity")
```

## Governance Block Handling

```python
from altrace import AltraceClient, GovernanceBlockError

client = AltraceClient(raise_on_block=True)
client.patch_httpx()

try:
    resp = httpx.post("https://api.anthropic.com/v1/messages", json={...})
except GovernanceBlockError as e:
    print(f"Blocked: {e.block.reason}")
    print(f"Suggestion: {e.block.suggestion}")
    if e.block.missing_evidence:
        print(f"Missing evidence: {e.block.missing_evidence}")
```

### Callback on Block

```python
from altrace import AltraceClient
from altrace.feedback import GovernanceBlock

def on_governance_block(block: GovernanceBlock):
    logger.warning("Governance block: %s", block.reason)
    if block.is_retriable:
        logger.info("Suggestion: %s", block.suggestion)

client = AltraceClient(on_block=on_governance_block)
client.patch_httpx()
```

## CLI

```bash
altrace-sdk configure     # Show current config from environment
altrace-sdk status        # Check proxy connectivity
altrace-sdk verify        # Verify SDK installation
altrace-sdk verify --json # JSON output
```

## Configuration

| Environment Variable | Config Field | Default | Description |
|---|---|---|---|
| `ALTRACE_PROXY_URL` | `proxy_url` | `http://localhost:8080` | Altrace proxy URL |
| `ALTRACE_TEAM` | `team` | (required) | Team name for attribution |
| `ALTRACE_AGENT_ID` | `agent_id` | `""` | Agent identifier |
| `ALTRACE_RUN_ID` | `run_id` | `""` | Run ID for correlation |
| `ALTRACE_VK` | `virtual_key` | `None` | VirtualKey for proxy auth |
| `ALTRACE_AUTO_RETRY` | `auto_retry` | `true` | Auto-retry on retriable blocks |
| `ALTRACE_MAX_RETRIES` | `max_retries` | `3` | Max retry attempts |

## Exports

All primary symbols are available from the top-level `altrace` package:

```python
from altrace import (
    AltraceClient, AltraceConfig,
    patch_anthropic, patch_openai,
    create_anthropic_client, create_openai_client,
    EvidenceRecorder, GovernanceBlock, GovernanceBlockError,
    MetricsCollector, RetryConfig,
    Action, BlockReason, DecisionResult, RecoveryType,
)
```

## Requirements

- Python 3.10+
- httpx >= 0.24.0

## License

Apache 2.0
