Metadata-Version: 2.4
Name: verityinc-sdk
Version: 0.1.1
Summary: Python SDK for Verity — exactly-once effect protection for AI agents and autonomous systems
Project-URL: Homepage, https://useverity.io
Project-URL: Documentation, https://useverity.io/docs
Project-URL: Repository, https://github.com/verityinc/verity-python
Project-URL: Issues, https://github.com/verityinc/verity-python/issues
Author-email: "Verity Systems, Inc." <dev@useverity.io>
License: MIT
Keywords: ai-agents,autonomous-systems,crash-recovery,durable-execution,effect-ledger,exactly-once,fence-token,idempotency,verity
Classifier: Development Status :: 3 - Alpha
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: httpx<1,>=0.27
Provides-Extra: dev
Requires-Dist: mypy>=1.13; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: respx>=0.22; extra == 'dev'
Requires-Dist: ruff>=0.8; extra == 'dev'
Description-Content-Type: text/markdown

# verity-sdk (Python)

**Exactly-once effect protection for AI agents and autonomous systems.**

The Python SDK for [Verity](https://useverity.io) — ensures real-world actions like payments, refunds, emails, and infrastructure provisioning happen exactly once, are safe to retry, and are fully auditable.

```bash
pip install verityinc-sdk
```

## Quick Start

```python
from verity import VerityClient

verity = VerityClient(
    base_url="https://api.useverity.io/v1",
    api_key="vk_live_xxxxxx",
    namespace="payments",
)

# Protect a side effect — Verity guarantees it runs exactly once
charge = await verity.protect("charge-order-456", {
    "act": lambda: stripe.Charge.create(amount=5000, currency="usd"),
})
```

If an agent crashes mid-flight, the next attempt either returns the cached result (if already committed) or uses `observe()` to detect the completed action in the external system — preventing duplicate charges.

## With Crash Recovery (Observe)

```python
charge = await verity.protect("charge-order-789", {
    "observe": async_check_stripe,
    "act": async_create_charge,
})

async def async_check_stripe():
    """Check if a prior agent already completed this charge."""
    existing = stripe.Charge.list(metadata={"order_id": "789"})
    return existing.data[0] if existing.data else None

async def async_create_charge():
    return stripe.Charge.create(
        amount=5000,
        currency="usd",
        metadata={"order_id": "789"},
    )
```

## Workflow Mode (Multi-Effect)

```python
run = verity.workflow("refund_flow").case("order_123").run()

# effectKey = "order_123:notify_customer"
await run.protect("notify_customer", {
    "act": lambda: email_service.send(to=customer.email, template="refund"),
})

# effectKey = "order_123:refund_payment"
await run.protect("refund_payment", {
    "act": lambda: stripe.Refund.create(charge=charge_id),
})
```

If a crash occurs between steps, the retry run skips already-committed effects and resumes from where it left off.

## Configuration

```python
from verity import VerityClient

verity = VerityClient(
    # Required
    base_url="https://api.useverity.io/v1",
    api_key="vk_live_xxxxxx",

    # Optional
    namespace="payments",           # default namespace
    agent_id="worker-1",            # identifies this agent in audit logs
    auto_renew=True,                # auto-renew leases in background
    renew_at_fraction=0.65,         # renew at 65% of lease duration
    request_timeout_ms=20_000,      # HTTP timeout per request

    # Conflict retry (when another agent holds the lease)
    conflict_retry={
        "enabled": True,
        "max_attempts": 12,
        "initial_delay_ms": 500,
        "max_delay_ms": 15_000,
        "jitter": True,
    },

    # Custom logger
    logger=my_logger,               # any logging.Logger instance
)
```

## Error Handling

```python
from verity import VerityClient
from verity.errors import (
    CommitUncertainError,
    LeaseConflictError,
    EffectPreviouslyFailedError,
)

try:
    await verity.protect("charge-order-456", {"act": charge})
except CommitUncertainError as e:
    # Action SUCCEEDED but Verity couldn't confirm the commit.
    # DO NOT RETRY — halt and reconcile manually.
    print(f"Action ran but commit uncertain: {e.result}")
    await alert_ops(e)
except LeaseConflictError:
    # Another agent is processing this effect
    print("Effect is being handled by another agent")
except EffectPreviouslyFailedError as e:
    # Prior failure — admin reset required via Explorer
    print(f"Prior failure: {e.cached_error}")
```

## How It Works

Every call to `protect()` follows the **lease → observe → act → commit** protocol:

1. **Lease** — acquire exclusive, time-bound access to the effect
2. **Observe** *(optional)* — check the external system for a prior completion
3. **Act** — execute the real-world side effect
4. **Commit** — record the result in Verity's ledger

```
Agent A                          Verity                         Stripe
  │                                │                              │
  ├── request_lease ──────────────►│                              │
  │◄── granted (fence_token: 1) ──┤                              │
  │                                │                              │
  ├── stripe.Charge.create ────────────────────────────────────────►
  │◄── { id: "ch_xxx" } ──────────────────────────────────────────┤
  │                                │                              │
  ├── commit(result) ─────────────►│                              │
  │◄── accepted ──────────────────┤                              │
```

## Parity with TypeScript SDK

This SDK provides **full feature parity** with the [TypeScript SDK](https://github.com/verityinc/verity/tree/main/packages/sdk):

| Feature | TypeScript | Python |
|---|---|---|
| `protect()` standalone | `verity.protect()` | `await verity.protect()` |
| Workflow builder | `verity.workflow().case().run()` | `verity.workflow().case().run()` |
| Auto lease renewal | `setInterval` + `unref()` | `asyncio.create_task()` |
| Conflict retry with backoff | ✅ | ✅ |
| Observe/Act pattern | ✅ | ✅ |
| Fence token validation | ✅ | ✅ |
| CommitUncertainError | ✅ | ✅ |
| Per-effect namespace | ✅ | ✅ |
| Key suffix | ✅ | ✅ |
| Custom logger | `logger: { warn, error }` | `logger: logging.Logger` |
| Typed request bodies | Exported types | `@dataclass` exports |

## Requirements

- **Python** >= 3.10
- **httpx** >= 0.27
- Zero other runtime dependencies

## Development

```bash
# Install with dev dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Type check
mypy src/

# Lint
ruff check src/
```

## License

Proprietary — Verity Systems, Inc.

