Metadata-Version: 2.4
Name: pomerene
Version: 0.1.0
Summary: Official Python client for the Pomerene deterministic trajectory cache (api.pomerene.io)
Project-URL: Homepage, https://pomerene.io
Project-URL: Source, https://github.com/kylemaa/pomerene/tree/main/clients/python
Author: Nothing New LLC
License: MIT
Requires-Python: >=3.9
Requires-Dist: httpx>=0.24
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == 'dev'
Description-Content-Type: text/markdown

# Pomerene Python client

Official Python client for the [Pomerene](https://pomerene.io) Cloud API — a deterministic trajectory cache for agentic systems. No LLM runs on the cache hit path; on a miss your live agent runs and the trajectory is recorded for next time.

> Mirrors the contract in [`packages/cloud/openapi.yaml`](../../packages/cloud/openapi.yaml).

## Install

```bash
pip install pomerene
```

## Quick start

```python
from pomerene import PomereneClient, with_cache

client = PomereneClient("atc_live_…")  # defaults to https://api.pomerene.io

cached = with_cache(
    my_agent,                                       # your existing (input) -> output
    cache=client,
    extract_goal=lambda q: q["question"],           # what clusters as "the same task"
    extract_context=lambda q: {"userId": q["userId"]},  # what gates a hit
    to_output=lambda traj, q: traj.outcome,         # rebuild output from cache
)

answer = cached({"question": "How do I reset my password?", "userId": "u1"})
```

Call `cached` exactly like your original agent. First time a task is seen → your agent runs and the result is recorded. A later semantically similar task → instant cached answer, no LLM call.

## Direct API

```python
res = client.lookup(goal, {"userId": "u1"})
if res.hit:
    use(res.trajectory.outcome)

# R10 cascade (specific path, then abstract fallback):
res = client.lookup_with_fallback(goal, ctx, abstract_goal)

# Record a trajectory; pass raw context and the server classifies it:
client.store(entry, context={"userId": "u1"})

stats = client.stats()  # usage + quota dict
```

## Resilience (defaults)

- **lookup fails open** — returns a synthetic miss on transport failure (your agent runs live; a cloud outage can't break it). `lookup_fail_open=False` to disable.
- **store fails closed** — a dropped write raises `PomereneError`. `store_fail_open=True` to disable.
- **retries** — 3 attempts with backoff (0.1/0.5/2s) on 5xx/408/429/network. `max_retries=n`.
- **circuit breaker** — opens for 30s after 5 consecutive failures. `reset_circuit()`.

`PomereneClient` is a context manager (`with PomereneClient(...) as c:`) and accepts a custom `http_client=httpx.Client(...)`.

## Test

```bash
pip install -e ".[dev]"
pytest        # runs against an httpx.MockTransport — no network
python example.py   # needs POMERENE_API_KEY
```
