Metadata-Version: 2.4
Name: vorim
Version: 3.8.1
Summary: Official Python SDK for Vorim AI — AI Agent Identity, Permissions & Audit
Project-URL: Homepage, https://vorim.ai
Project-URL: Repository, https://github.com/Kzino/vorim-protocol
Project-URL: Issues, https://github.com/Kzino/vorim-protocol/issues
Project-URL: Documentation, https://vorim.ai/docs
Author-email: Vorim AI <hello@vorim.ai>
License-Expression: MIT
Keywords: agent-identity,ai-agent,audit,crewai,ed25519,langchain,openai,permissions,trust,vorim
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: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: cryptography>=42
Requires-Dist: httpx>=0.25.0
Provides-Extra: all
Requires-Dist: crewai>=0.80.0; extra == 'all'
Requires-Dist: langchain-core>=0.3.0; extra == 'all'
Requires-Dist: openai>=1.0.0; extra == 'all'
Provides-Extra: crewai
Requires-Dist: crewai>=0.80.0; extra == 'crewai'
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: respx>=0.22; extra == 'dev'
Provides-Extra: langchain
Requires-Dist: langchain-core>=0.3.0; extra == 'langchain'
Provides-Extra: openai
Requires-Dist: openai>=1.0.0; extra == 'openai'
Description-Content-Type: text/markdown

# vorim

Official Python SDK for [Vorim AI](https://vorim.ai) — the identity, permissions, and audit layer for AI agents.

Vorim AI provides cryptographic agent identities (Ed25519), fine-grained permissions (7 scopes), immutable audit trails, and trust scoring (0-100) for production AI agent deployments. EU AI Act compliant out of the box.

[![PyPI](https://img.shields.io/pypi/v/vorim)](https://pypi.org/project/vorim/)
[![Python](https://img.shields.io/pypi/pyversions/vorim)](https://pypi.org/project/vorim/)
[![License](https://img.shields.io/pypi/l/vorim)](https://github.com/Kzino/vorim-protocol/blob/main/LICENSE)

> **[vorim.ai](https://vorim.ai)** — Create a free account and get your API key in 30 seconds.
> **[Documentation](https://vorim.ai/docs)** — Full API reference, framework integrations, and examples.
> **[Quick Start](https://vorim.ai/quickstart)** — Set up in under 5 minutes.

## Install

```bash
pip install vorim
```

With framework integrations:

```bash
pip install vorim[langchain]    # LangChain / LangGraph
pip install vorim[crewai]       # CrewAI
pip install vorim[openai]       # OpenAI Agents SDK
pip install vorim[all]          # All integrations
```

Requires Python 3.10+.

## Quick Start

```python
from vorim import Vorim

vorim = Vorim(api_key="agid_sk_live_...")

# Register an agent (returns Ed25519 keypair, private key shown once)
result = vorim.register(
    name="invoice-processor",
    capabilities=["read_documents", "extract_data"],
    scopes=["agent:read", "agent:execute"],
)
print(result.agent.agent_id)    # agid_acme_a1b2c3d4
print(result.agent.trust_score) # 50

# Check permissions (<5ms via Redis)
check = vorim.check(result.agent.agent_id, "agent:execute")

if check.allowed:
    # Emit audit event
    vorim.emit(
        agent_id=result.agent.agent_id,
        event_type="tool_call",
        action="process_invoice",
        resource="INV-2026-0042",
        result="success",
        latency_ms=142,
    )

# Verify any agent's trust (public, no auth required)
trust = vorim.verify(result.agent.agent_id)
print(f"Trust score: {trust.trust_score}/100")
```

## Async Client

```python
from vorim import AsyncVorim

async with AsyncVorim(api_key="agid_sk_live_...") as vorim:
    result = await vorim.register(
        name="my-agent",
        capabilities=["search"],
        scopes=["agent:read"],
    )

    trust = await vorim.verify(result.agent.agent_id)
    print(f"Trust score: {trust.trust_score}/100")
```

## API Reference

### `Vorim(api_key, base_url?, timeout?, auto_sign=True)`

| Method | Description |
|--------|-------------|
| `register(name, capabilities, scopes)` | Register an agent; caches the returned Ed25519 private key for auto-signing |
| `check(agent_id, scope)` | Check if agent has permission (sub-5ms) |
| `emit(agent_id, event_type, action, ..., sign=None)` | Emit an audit event. Auto-signed if the agent's key is in the keyring |
| `emit_batch(events, sign=None)` | Emit up to 1,000 audit events. Auto-signs each one |
| `verify(agent_id)` | Verify agent identity and trust score (public) |
| `get_agent(agent_id)` | Get agent details |
| `list_agents(status?, page?, per_page?)` | List agents with filtering |
| `revoke(agent_id)` | Permanently revoke an agent |
| `grant(agent_id, scope, valid_until?, rate_limit?)` | Grant a permission scope |
| `use_agent_key(agent_id, private_key_pem)` | Restore a private key into the in-memory keyring after process restart |
| `forget_agent_key(agent_id)` | Remove a private key from the keyring |

Module-level helpers: `canonical_payload_v1(event)` and `canonical_payload_v0(event)` (return the bytes that get signed) and `sign_payload(payload, private_key_pem)` (returns `ed25519:<base64>`).

`AsyncVorim` has the same interface with `await` on all methods.

### Per-event signing (auto-signing)

From v3.7.0, every audit event is signed at source with the agent's Ed25519 private key — no code change required. `register()` caches the returned key in memory and `emit()` attaches the signature transparently.

**Canonical form.** Since 3.7.0 the SDK defaults to **v1** canonical form: RFC 8785 JSON Canonicalization Scheme (JCS) over the whole event minus `signature` and `canonical_form`. v1 brings metadata, replayable-evidence fields (`model_version`, `tool_catalogue_hash`, `system_prompt_hash`, `prev_event_hash`), and delegation context (`on_behalf_of`, `delegator_agent_id`, `delegation_chain_id`, `delegation_depth`) under the signature. The previous v0 form was a pipe-joined six-field string `event_type|action|resource|input_hash|output_hash|result` and is now deprecated — passing `canonical_form="v0"` explicitly still works for verifier-compat scenarios but logs a deprecation warning. Use `@vorim/verify@0.2.0+` (or the v1 helpers in this package) to verify v1 events offline.

```python
result = vorim.register(name="agent", capabilities=[], scopes=[])

# Auto-signed. The signature is attached before the request leaves the process.
vorim.emit(
    agent_id=result.agent.agent_id,
    event_type="tool_call",
    action="transfer_funds",
    result="success",
)
```

To verify signatures server-side, the API operator sets `VORIM_VERIFY_AUDIT_SIGNATURES=true`.

**Restoring keys across process restarts.** The in-memory keyring is lost on restart. Load the private key from your secret store:

```python
vorim.use_agent_key(agent_id, private_key_pem)
vorim.forget_agent_key(agent_id)  # revoke from memory
```

**Opting out.** Per event with `sign=False`, or globally with `auto_sign=False`:

```python
vorim.emit(agent_id=..., event_type=..., action=..., result=..., sign=False)
vorim = Vorim(api_key=..., auto_sign=False)
```

### Runtime Control (gate actions before they happen)

Ask Vorim whether an action should proceed **before** your agent performs it.
`before_action()` returns a typed decision and, by default, **raises on deny**
(a denial is in the response body, not the HTTP status).

```python
from vorim import Vorim, VorimDeniedError

vorim = Vorim(api_key="agid_sk_live_...")

try:
    decision = vorim.before_action(
        agent_id="agid_acme_a1b2c3d4",      # always the public agid_* id
        action_type="tool_call",
        action_target="sendEmail",
        required_scope="agent:communicate",
        payload={"to": "customer@example.com", "body": "..."},
    )

    payload = decision.modified_payload or {"to": "customer@example.com"}

    if decision.decision in ("allow", "modify"):
        send_email(payload)
    elif decision.decision == "escalate":
        resolved = vorim.wait_for_decision_resolution(decision.decision_id)
        if resolved.decision == "allow":
            send_email(payload)

    # Link the post-action audit event back to the decision.
    vorim.emit(
        agent_id="agid_acme_a1b2c3d4",
        event_type="tool_call",
        action="sendEmail",
        result="success",
        decision_id=decision.decision_id,   # correlates audit ↔ decision
    )
except VorimDeniedError as err:
    print("Action denied:", err.decision.reason)
```

**Verdicts:** `allow` · `deny` (raises `VorimDeniedError` by default) ·
`modify` (use `decision.modified_payload`) · `escalate` (poll
`wait_for_decision_resolution`) · `fallback`.

> **`modify` is client-cooperative.** Vorim returns the sanitised
> `modified_payload`; your agent must send it in place of the original. The
> platform does not sit inline and does not currently enforce that you do —
> carry `decision_id` into the matching `emit()` so the action stays auditable.

**Fail-open:** if the decision API is unreachable, `before_action()` returns a
synthetic `fallback` decision. Pass `runtime_fail_open=False` to the constructor
to fail closed. A reachable server returning `deny` always denies. `AsyncVorim`
exposes the same async methods.

> Requires an API key with the `runtime:decide` scope and a Growth+ plan.
> `modify` verdicts come from policy rules provisioned by Vorim (rule-authoring
> API ships in a later release).

### Permission Scopes

| Scope | Description |
|-------|-------------|
| `agent:read` | Read data on behalf of owner |
| `agent:write` | Write or modify data |
| `agent:execute` | Trigger actions or tool calls |
| `agent:transact` | Financial or contractual actions |
| `agent:communicate` | Send messages or emails |
| `agent:delegate` | Sub-delegate to other agents |
| `agent:elevate` | Request permission elevation |

## Framework Integrations

### LangChain / LangGraph

```python
from vorim import Vorim
from vorim.integrations.langchain import vorim_tool, VorimCallbackHandler

vorim = Vorim(api_key="agid_sk_live_...")

@vorim_tool(vorim, agent_id="agid_acme_...", permission="agent:execute")
def search(query: str) -> str:
    """Search documents."""
    return f"Results for {query}"

# search() is now a standard LangChain tool with built-in permission checks + audit
```

### CrewAI

```python
from vorim import Vorim
from vorim.integrations.crewai import register_crew

vorim = Vorim(api_key="agid_sk_live_...")

crew = register_crew(vorim, {
    "crew_name": "content-pipeline",
    "members": [
        {
            "role": "researcher",
            "name": "crew-researcher",
            "capabilities": ["web_search"],
            "scopes": ["agent:read", "agent:execute"],
        },
    ],
})
```

### OpenAI Function Calling

```python
from openai import OpenAI
from vorim import Vorim
from vorim.integrations.openai_agents import VorimToolRegistry

vorim = Vorim(api_key="agid_sk_live_...")
client = OpenAI()

registry = VorimToolRegistry(vorim=vorim, agent_id="agid_acme_...")
registry.add(
    name="search",
    description="Search documents",
    parameters={"type": "object", "properties": {"query": {"type": "string"}}},
    execute=lambda args: f"Results for {args['query']}",
)

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Search for AI papers"}],
    tools=registry.to_openai_tools(),
)

# Permission checked + audited automatically
tool_messages = registry.execute_tool_calls(
    response.choices[0].message.tool_calls or []
)
```

## Resources

- [Full Documentation](https://vorim.ai/docs)
- [Protocol Specification](https://github.com/Kzino/vorim-protocol)
- [TypeScript SDK (@vorim/sdk)](https://www.npmjs.com/package/@vorim/sdk)

## License

MIT
