Metadata-Version: 2.4
Name: gateforge-sdk
Version: 0.2.12
Summary: Privacy-first LLMOps SDK — Auto-init, decorators, session management, prompt system with cache
Project-URL: Homepage, https://gateforge.dev
Project-URL: Documentation, https://gateforge.dev/docs
Project-URL: Repository, https://github.com/gateforge/gateforge-sdk
Project-URL: Dashboard, https://app.gateforge.dev
Project-URL: Bug Tracker, https://github.com/gateforge/gateforge-sdk/issues
Author-email: Gateforge Team <support@gateforge.dev>
License: MIT
License-File: LICENSE
Keywords: anthropic,gemini,llm,llmops,mlops,openai,pii,privacy
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.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27.0
Requires-Dist: pii-firewall[langdetect,presidio,transformers]
Provides-Extra: all
Requires-Dist: anthropic>=0.40.0; extra == 'all'
Requires-Dist: google-genai>=1.0.0; extra == 'all'
Requires-Dist: openai>=1.0.0; extra == 'all'
Requires-Dist: opentelemetry-api>=1.20.0; extra == 'all'
Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.20.0; extra == 'all'
Requires-Dist: opentelemetry-sdk>=1.20.0; extra == 'all'
Provides-Extra: anthropic
Requires-Dist: anthropic>=0.40.0; extra == 'anthropic'
Provides-Extra: dev
Requires-Dist: build>=1.0.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: twine>=5.0.0; extra == 'dev'
Provides-Extra: gemini
Requires-Dist: google-genai>=1.0.0; extra == 'gemini'
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-exporter-otlp-proto-grpc>=1.20.0; extra == 'otel'
Requires-Dist: opentelemetry-sdk>=1.20.0; extra == 'otel'
Description-Content-Type: text/markdown

# Gateforge SDK (Python)

**Privacy-first LLMOps SDK** — Transparent client wrapping with automatic PII masking, cost tracking, A/B testing, guardrails, agent tracing, and prompt management.

[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
[![PyPI](https://img.shields.io/pypi/v/gateforge-sdk.svg)](https://pypi.org/project/gateforge-sdk/)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)

---

## What it does

Gateforge wraps your existing provider client (OpenAI, Anthropic, Gemini) with a transparent proxy. Your code is unchanged — the SDK intercepts each call to run the full pipeline locally:

```
Your code
    │
    ▼
pre-call  → A/B variant selection → system prompt injection
          → PII anonymize (local)
          → input guardrail check
    │
    ▼
LLM provider (sees masked content only)
    │
    ▼
post-call → PII rehydrate (local)
          → output guardrail check
          → cost + latency compute
          → span emission (metadata only)
    │
    ▼
Your code receives: original PII restored, guardrails applied
```

**Content never leaves your environment.** Only metadata (tokens, cost, latency, PII types) is sent to Gateforge.

---

## Installation

```bash
pip install gateforge-sdk
```

With provider extras:
```bash
pip install gateforge-sdk[openai]      # OpenAI only
pip install gateforge-sdk[anthropic]   # Anthropic only
pip install gateforge-sdk[gemini]      # Google Gemini only
pip install gateforge-sdk[all]         # All providers
pip install gateforge-sdk[dev]         # Development tools
```

Get your API key at [https://app.gateforge.dev/dashboard/keys](https://app.gateforge.dev/dashboard/keys).

---

## Quick Start

### Option 1: Auto-Init (Recommended)

```python
import gateforge

# Auto-initialize from environment variables
# Reads: GATEFORGE_API_KEY, OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY
gateforge.auto_init()

# Now you can use providers directly
from openai import OpenAI
client = OpenAI(api_key="sk-...")  # Works without explicit wrapping!
```

### Option 2: Manual Init with Wrapping

```python
import gateforge
from openai import OpenAI

gateforge.init(api_key="gf-live-YOUR_KEY")

# Wrap your client
client = gateforge.wrap_openai(OpenAI(api_key="sk-..."))

# Use exactly as before — pipeline runs automatically
response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Hello!"}],
)
```

### Option 3: Auto-Detection

```python
import gateforge
from openai import OpenAI
from anthropic import Anthropic
from google import genai

gateforge.init(api_key="gf-live-...")

# Auto-detects provider
client1 = gateforge.wrap(OpenAI(api_key="sk-..."))
client2 = gateforge.wrap(Anthropic(api_key="sk-ant-..."))
client3 = gateforge.wrap(genai.Client(api_key="AIza-..."))
```

---

## Key Features

### 1. Auto-Initialization

```python
import gateforge

# Set environment variables:
# export GATEFORGE_API_KEY=gf-live-xxx
# export OPENAI_API_KEY=sk-xxx

gateforge.auto_init(enable_pii=False, enable_guardrails=False)
# Privacy-first: PII and guardrails disabled by default
```

### 2. Decorator-Based Tracing

```python
import gateforge

# Tool with automatic tracing
@gateforge.tool()
def get_weather(location: str) -> str:
    import requests
    return requests.get(f"https://wttr.in/{location}?format=3").text

# Agent with automatic tracing
@gateforge.agent()
def weather_agent(message: str) -> str:
    return get_weather("Madrid")

# Session to group multiple calls
with gateforge.session(user_id="user-123"):
    response = weather_agent("What's the weather?")
```

### 3. Conversation Management

```python
from gateforge import SessionManager, trace

# Manage sessions
manager = SessionManager()
session = manager.create_session(
    user_id="user-123",
    tags=["weather-chat"],
)

# Use in trace
with trace(conversation_id=session.conversation_id):
    response = run_agent(message)

# Track activity
manager.touch(session.conversation_id)
session.set_metadata("last_model", "gpt-4o-mini")
```

### 4. Prompt System

```python
from gateforge import Prompt, PromptBuilder, PromptCache

# Create prompt with variables
prompt = Prompt(
    name="greeting",
    content="Hello, {{name}}! You are {{role}}.",
    variables={"name": "User", "role": "a developer"},
)
rendered = prompt.render(name="Alice")  # "Hello, Alice!..."

# Compose prompts
builder = PromptBuilder()
builder.add_system("You are helpful")
builder.add_user("What's the weather?")
builder.add_variable("location", "Madrid")
prompt = builder.build()

# Cache prompts (memory + file + backend)
cache = PromptCache(memory_ttl=300, file_ttl=3600)
cache.set(prompt)
retrieved = cache.get("greeting")
```

---

## Provider Wrappers

All wrappers are transparent — input params and return types match the underlying SDK.

### OpenAI

```python
import gateforge
from openai import OpenAI, AsyncOpenAI

gateforge.init(api_key="gf-live-...")

# Sync
client = gateforge.wrap_openai(OpenAI(api_key="sk-..."))
response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Hello!"}],
)

# Async
async_client = gateforge.wrap_openai(AsyncOpenAI(api_key="sk-..."))
response = await async_client.chat.completions.create(...)

# Streaming
for chunk in client.chat.completions.create(..., stream=True):
    print(chunk.choices[0].delta.content, end="")
```

### Anthropic

```python
import gateforge
from anthropic import Anthropic

client = gateforge.wrap_anthropic(Anthropic(api_key="sk-ant-..."))
response = client.messages.create(
    model="claude-haiku-4-5",
    max_tokens=512,
    messages=[{"role": "user", "content": "Hello!"}],
)
```

### Gemini

```python
import gateforge
from google import genai

client = gateforge.wrap_gemini(genai.Client(api_key="AIza-..."))
response = client.models.generate_content(
    model="gemini-2.5-flash",
    contents=[{"role": "user", "parts": [{"text": "Hello!"}]}],
)
```

---

## Agent Tracing

### Basic Multi-Step Trace

```python
import gateforge
from openai import OpenAI

gateforge.init(api_key="gf-live-...")
client = gateforge.wrap_openai(OpenAI(api_key="sk-..."))

with gateforge.trace(conversation_id="conv_abc123"):
    # Each LLM call gets auto-incremented step number
    r1 = client.chat.completions.create(...)  # step 1
    r2 = client.chat.completions.create(...)  # step 2
```

### Agent with Tool Calls

```python
import gateforge

@gateforge.tool()
def search_flights(destination: str, date: str) -> list:
    ...

@gateforge.tool()
def book_flight(flight_id: str, passenger: str) -> str:
    ...

@gateforge.agent()
def travel_agent(request: str) -> str:
    flights = search_flights("Paris", "2026-06-10")
    confirmation = book_flight(flights[0]["id"], "John Doe")
    return f"Booked: {confirmation}"

# All tool calls automatically traced
with gateforge.session(user_id="user-123"):
    response = travel_agent("Book me a flight to Paris")
```

### Session Management

```python
from gateforge import SessionManager, get_current_conversation_id

manager = SessionManager()

# Create session
session = manager.create_session(user_id="user-123")

# Get current conversation from active trace
cid = get_current_conversation_id()

# List sessions
sessions = manager.list_sessions(user_id="user-123", limit=10)

# Serialize for persistence
data = manager.to_dict()  # Save to DB
manager2 = SessionManager.from_dict(data)  # Load
```

---

## A/B Testing

```python
from gateforge import CallOptions

response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Help me write an email"}],
    gateforge_options=CallOptions(
        experiment_id="exp_email_v2",
        session_id="user_123",  # Deterministic variant
    ),
)
# Variant A or B injected automatically
```

---

## Guardrails

```python
from gateforge import CallOptions, GuardrailBlocked

try:
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": "..."}],
        gateforge_options=CallOptions(guardrails=True),
    )
except GuardrailBlocked as e:
    print(f"Blocked by rule: {e.rule_id}")
```

---

## PII Protection

### Detected Entities

| Category | Examples |
|----------|----------|
| **Personal** | Names, emails, phones, addresses |
| **Financial** | Credit cards, bank accounts, SSN |
| **Healthcare** | Medical records, symptoms, diagnoses |
| **Technical** | IP addresses, URLs, API keys |
| **Custom** | Your own regex patterns |

### Direct Anonymization

```python
import gateforge

result = gateforge.anonymize("My email is john@example.com")
print(result["sanitized"])  # "My email is [EMAIL_001]"
print(result["entities"])   # ["EMAIL"]

original = gateforge.rehydrate("[EMAIL_001]", context=result["context"])
print(original)  # "john@example.com"
```

---

## CallOptions Reference

```python
from gateforge import CallOptions

response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[...],
    gateforge_options=CallOptions(
        # Trace grouping
        conversation_id="conv_abc",
        
        # A/B testing
        experiment_id="exp_abc",
        session_id="user_123",
        
        # Feature overrides
        pii=True,
        guardrails=True,
        track_cost=False,
    ),
)
```

---

## API Reference

### Initialization

| Function | Description |
|----------|-------------|
| `gateforge.init(api_key, ...)` | Manual initialization |
| `gateforge.auto_init()` | Auto from environment |

### Wrapping

| Function | Description |
|----------|-------------|
| `gateforge.wrap(client)` | Auto-detect provider |
| `gateforge.wrap_openai(client)` | Wrap OpenAI |
| `gateforge.wrap_anthropic(client)` | Wrap Anthropic |
| `gateforge.wrap_gemini(client)` | Wrap Gemini |

### Tracing

| Function | Description |
|----------|-------------|
| `gateforge.trace(conversation_id)` | Context manager for traces |
| `gateforge.continue_session(id)` | Resume existing conversation |
| `gateforge.session(user_id)` | Session context manager |
| `gateforge.tool()` | Decorator for tool tracing |
| `gateforge.agent()` | Decorator for agent tracing |

### Session Management

| Function | Description |
|----------|-------------|
| `SessionManager()` | Create session manager |
| `manager.create_session()` | Create new session |
| `manager.get_session(id)` | Get existing session |
| `manager.list_sessions()` | List with filters |
| `get_current_conversation_id()` | Get active trace ID |
| `get_current_trace_info()` | Get full trace info |

### Prompts

| Function | Description |
|----------|-------------|
| `Prompt(...)` | Create prompt |
| `PromptBuilder()` | Compose prompts |
| `PromptCache()` | Multi-level cache |
| `gateforge.get_prompt(name)` | Get from cache/backend |
| `gateforge.set_prompt(prompt)` | Set in cache |

### Utilities

| Function | Description |
|----------|-------------|
| `gateforge.anonymize(text)` | Anonymize PII |
| `gateforge.rehydrate(text, ctx)` | Restore PII |
| `gateforge.track_metrics(data)` | Send metadata |

---

## Supported Models

### OpenAI
- GPT-4o, GPT-4o-mini
- GPT-4.1, GPT-4.1-mini, GPT-4.1-nano

### Anthropic
- Claude Haiku 4-5
- Claude Sonnet 4-5
- Claude Opus 4

### Google Gemini
- Gemini 2.5 Flash
- Gemini 2.5 Pro

---

## Dashboard

[https://app.gateforge.dev/dashboard](https://app.gateforge.dev/dashboard)

- Request volume and trends
- Cost breakdown by model/provider
- Latency analytics
- PII detection statistics
- A/B experiment results
- Guardrail violation alerts
- Agent waterfall traces
- API key management

---

## Changelog

### 0.2.6 (2026-06-07) - Phase 3 Complete
- ✅ `Prompt` class with variables and rendering
- ✅ `PromptCache` with multi-level caching (memory + file)
- ✅ `PromptBuilder` for prompt composition
- ✅ `get_prompt()` / `set_prompt()` helpers
- ✅ 40 tests for Phase 3 features

### 0.2.5 (2026-06-07) - Phase 2 Complete
- ✅ `SessionManager` for session lifecycle
- ✅ `SessionState` with metadata, tags, timestamps
- ✅ `get_current_conversation_id()` helper
- ✅ `get_current_trace_info()` helper
- ✅ Conversation threading support
- ✅ 35 tests for Phase 2 features

### 0.2.4 (2026-06-07)
- ✅ Fixed `@agent()` to use active conversation_id when nested
- ✅ Added `nested` metadata for agent events

### 0.2.3 (2026-06-07) - Phase 1 Complete
- ✅ `auto_init()` for environment-based initialization
- ✅ `@gateforge.tool()` decorator
- ✅ `@gateforge.agent()` decorator
- ✅ `gateforge.session()` context manager
- ✅ 24 tests for Phase 1 features

### 0.2.2 and earlier
- Auto-download spaCy model
- PII firewall integration
- Provider wrappers (OpenAI, Anthropic, Gemini)
- A/B testing, guardrails, tracing

---

## Documentation

- [Phase 1 Complete](https://github.com/gateforge/gateforge-sdk/blob/main/PHASE1_COMPLETE.md)
- [Phase 2 Complete](https://github.com/gateforge/gateforge-sdk/blob/main/PHASE2_COMPLETE.md)
- [Phase 3 Complete](https://github.com/gateforge/gateforge-sdk/blob/main/PHASE3_COMPLETE.md)

---

## Troubleshooting

**`ImportError: No module named 'gateforge'`**
```bash
pip install gateforge-sdk
```

**`RuntimeError: Call gateforge.init() first`**
```python
gateforge.init(api_key="gf-live-...")
# Or use auto_init:
gateforge.auto_init()
```

**PII not detected**
1. Check domain setting matches your data
2. Add custom patterns in dashboard

**Steps not appearing in trace**
1. Ensure `tracing_enabled=True`
2. Confirm `conversation_id` is active

---

## Links

- [Website](https://gateforge.dev)
- [Dashboard](https://app.gateforge.dev)
- [PyPI](https://pypi.org/project/gateforge-sdk/)
- [Issues](https://github.com/gateforge/gateforge-sdk/issues)

---

## License

MIT — see [LICENSE](LICENSE). The SDK is open source; the Gateforge service is commercial with a free tier (1,000 requests/month).
