Metadata-Version: 2.5
Name: vantio-agent-sdk
Version: 3.0.10
Summary: Vantio Optics Python SDK — shield() for Sight Loop observe. Metadata only; no prompts.
Project-URL: Homepage, https://vantio.ai
Project-URL: Optics, https://vantio.ai/optics
Project-URL: Pricing, https://vantio.ai/pricing
Project-URL: Repository, https://github.com/vantioai/vantio-open-core
Project-URL: Issues, https://github.com/vantioai/vantio-open-core/issues
Project-URL: Documentation, https://vantio.ai/optics
Author-email: "Vantio AI, Inc." <hello@vantio.ai>
License: MIT
Keywords: agent,ai,governance,observability,optics,security,sight-loop,tracing,vantio,vantio-optics
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
Description-Content-Type: text/markdown

# vantio-agent-sdk · Vantio Optics (Python)

> Vantio Optics open-core SDK for Sight Loop observe — `shield()` telemetry for Python agents. Metadata only; no prompts. Current PyPI release: **3.0.10**.

```bash
pip install vantio-agent-sdk
```

Optics: [vantio.ai/optics](https://vantio.ai/optics)

`vantio run python agent.py` (CLI 0.3.4+) loads this wrap for the whole interpreter. You can also use `shield()` when you want a trace id inside the process. Optics records **urllib** (urlopen and custom openers) and **http.client** to in-scope LLM hosts. If **requests**, **httpx**, **aiohttp**, **urllib3**, or **pycurl** are already installed, those are recorded the same way. `socket.connect` / `connect_ex` / `create_connection` to in-scope hosts share host-block and observe. `subprocess` / `os.system` / `asyncio` curl and wget spawns to in-scope hosts share host-block, observe, file-body and curl `-F` size from stat, stdin size when stdin is a file, `wget -i` URL lines, and Gate PII rewrite of inline argv bodies (file contents and stdin pipes are not read). Spawned httpie shares host-block and inline `--raw` / field redaction; aria2c shares host-block from argv URLs. With a Gate key, the same wrap can block a destination, redact PII, or enforce a spend limit on HTTP bodies. Browsers stay outside this wrap.

**Providers:** OpenAI (including regional), Anthropic, Google Gemini, Azure OpenAI, Azure AI, Cohere, Mistral, Groq, Together AI, Perplexity, xAI, DeepSeek, Fireworks, OpenRouter, Cerebras, Voyage AI, SambaNova, DeepInfra, Amazon Bedrock, Google Vertex AI, Hugging Face Inference, Replicate, Ollama, hosted NVIDIA NIM.

## v3.0.x — Breaking change from v2.x

v3.0.0+ is a complete rewrite. The old `VantioSession` / `VANTIO_PROXY_ENDPOINT` API is removed.
The new API uses `@shield` (a decorator or async context manager) with zero dependencies and no proxy — observe runs inside your SDK, not through an external endpoint.

**Migrate from v2.x:**
```python
# Old (v2.x) — remove this
from vantio.session import VantioSession
with VantioSession(agent_name="my-agent") as session: ...

# New (v3.x) — use this instead
from vantio import shield
@shield
async def run_agent(): ...
# or: async with shield() as ctx: ...
```

---

## shield() — trace context

```python
from vantio import shield, report_anomaly

# Decorator form
@shield
async def run_agent():
    result = await call_openai(prompt)
    return result

# Context manager form
async with shield() as ctx:
    print(f"Trace ID: {ctx.trace_id}")
    result = await run_agent()
```

### get_current_trace_id()

Returns the active trace ID for the current async context, or `None` outside a `shield()` frame.

```python
from vantio import shield, get_current_trace_id

async with shield() as ctx:
    trace_id = get_current_trace_id()  # same as ctx.trace_id

get_current_trace_id()  # None — outside shield() frame
```

---

## fetch_policy() — policy retrieval

Fetches your tenant's governance policy from `GET /api/v1/config`. Fails open — if the
control plane is unreachable, a permissive default policy is returned so your agent never
stalls waiting for governance.

```python
from vantio import fetch_policy, redact_pii
import os

policy = fetch_policy(os.environ["VANTIO_API_KEY"])

# Check enforcement flags
if policy.enforce:
    if "api.openai.com" in policy.blocked_hosts:
        raise RuntimeError("OpenAI is blocked by policy")

# Use with redact_pii for SDK-side PII scrubbing
if policy.pii_redact:
    result = redact_pii(user_input, policy.pii_types)
    prompt = result.text   # PII scrubbed before the LLM call
```

`VantioPolicy` fields:

| Field | Type | Description |
|-------|------|-------------|
| `enforce` | `bool` | Master switch — when `False`, calls are observed but never blocked/redacted |
| `pii_redact` | `bool` | Whether to redact PII from requests |
| `pii_types` | `list[str]` | PII categories to redact (`"ssn"`, `"email"`, `"credit_card"`, `"phone"`) |
| `allowed_hosts` | `list[str]` | Allow-list of LLM hosts; empty = all known hosts allowed |
| `blocked_hosts` | `list[str]` | Deny-list of LLM hosts |
| `max_request_bytes` | `int` | Hard cap on outbound request size; `0` = no limit |
| `spend_cap_usd` | `float` | Soft USD spend cap; `0` = no cap |

---

## redact_pii() — local PII scrubbing

Pure, side-effect-free local PII redaction using the same patterns as the CLI interceptor
and `@vantio/agent-sdk`. No content leaves the process.

```python
from vantio import redact_pii

result = redact_pii("Contact bob@example.com or call 555-123-4567")
# result.text       → "Contact [VANTIO_REDACTED:EMAIL] or call [VANTIO_REDACTED:PHONE]"
# result.redactions → ["email", "phone"]
```

Pass a custom `pii_types` list to control which categories are scanned (values are
case-insensitive):

```python
result = redact_pii(text, pii_types=["email", "ssn"])
```

Built-in categories: `ssn`, `email`, `credit_card`, `phone`.

`RedactionResult` fields:

| Field | Type | Description |
|-------|------|-------------|
| `text` | `str` | Input string with PII replaced by `[VANTIO_REDACTED:LABEL]` tokens |
| `redactions` | `list[str]` | Category name per matched span (one entry per replacement) |

---

## report_anomaly() — cloud ingest

```python
async with shield():
    await run_agent()
    await report_anomaly(
        target_host="api.openai.com",
        bytes_severed=14382,
        # Valid values: "OBSERVED" | "ALLOWED" | "REDACTED" | "BLOCKED_HOST" | "BLOCKED_SIZE" | "BLOCKED_SPEND"
        action_taken="BLOCKED_HOST",
    )
```

`report_anomaly()` must be called within a `shield()` context. It is a no-op unless
`VANTIO_CLOUD_INGEST=true`. Non-fatal — never crashes the agent.

---

## Environment variables

| Variable | Description |
|---|---|
| `VANTIO_API_KEY` | Your API key from [vantio.ai/dashboard](https://vantio.ai/dashboard) |
| `VANTIO_INGEST_URL` | Ingest endpoint (default: `https://vantio.ai`) |
| `VANTIO_CLOUD_INGEST` | Set to `true` to enable cloud routing — `report_anomaly()` is a no-op without this |
| `VANTIO_AUDIT_MODE` | Set to `1` to flag events as audit mode |
| `VANTIO_TELEMETRY_DISABLED` | Set to `1` to opt out of anonymous usage telemetry |
| `DO_NOT_TRACK` | Set to `1` to opt out of anonymous usage telemetry |

---

## Anonymous telemetry (opt-out)

The SDK sends a single **anonymous** usage ping per process the first time `shield()` runs.
It contains only aggregate, non-identifying metadata — a random anonymous id, the Python
version, the OS string, and an event name. It **never** sends prompts, completions, API
keys, emails, or any content/PII. Fire-and-forget on a daemon thread; never blocks.

```bash
export VANTIO_TELEMETRY_DISABLED=1   # or
export DO_NOT_TRACK=1
```

---

## Zero required dependencies

Core tracing requires only the Python standard library (`contextvars`, `asyncio`, `hashlib`,
`hmac`, `re`). Cloud ingest and anonymous telemetry use `urllib.request` and `threading`.
This package does not depend on aiohttp, requests, or httpx.

While the wrap is active (`vantio run python` or `shield()`), Optics records urllib calls to in-scope LLM hosts (OpenAI,
Anthropic, Bedrock, Vertex AI, Hugging Face Inference, Replicate, Ollama, NVIDIA NIM, and
the rest of the catalog). If `requests`, `httpx`, or `aiohttp` are already installed in the agent
environment, those are recorded the same way. They are optional; installing this
package does not pull them in. `socket.connect` / `create_connection` to in-scope hosts
share host-block and observe. `subprocess` curl to in-scope hosts shares host-block and
observe; curl bodies are not rewritten. Browsers stay outside this wrap.
