# wzrd-client

Tiny Python client for WZRD model selection priors.

The goal is deliberately small:

- call `wzrd.pick()` before an LLM request
- optionally pass candidate model names from your framework or router
- use the result as the next execution choice

This is an attention prior, not a full router.
If you pass candidate model names, `pick()` scores them against the live feed.
If you do not, it returns the strongest live signal it can find for the task hint.

Install with `pip install wzrd-client`, then `import wzrd` and call `wzrd.pick()` before each inference choice.

## Earn CCM While Routing

The full self-serve loop is:

```python
import wzrd

choice = wzrd.pick_details("code")

agent = wzrd.WZRDAgent.from_env()
agent.authenticate()
agent.report_pick(choice, quality_score=0.9)

print(agent.earned()["claimable_ccm"])

result = agent.claim()  # gasless relay — no SOL needed
print(result.status, result.tx_sig)
```

No manual onboarding. No founder approval. No SOL required. An agent can discover the package, authenticate with its own Solana keypair, report real routing decisions, claim CCM rewards via the gasless relay, and compound the loop — all on its own.

## Router wrapper

If you want a thin client wrapper, use `WZRDRouter` from `wzrd.router`.
It only wraps clients that expose `client.chat.completions.create(...)`.
Explicit model names pass through unchanged. To trigger WZRD routing, pass
`model=None` or a task sentinel like `model="code"` or `model="chat"`.

## Install

```bash
pip install wzrd-client
```

## Quick start

```python
import wzrd

model = wzrd.pick("code")
print(model)
```

## Agent auth and CCM loop

If you want an agent to authenticate, report routing decisions, and enter the CCM reward loop:

```python
import wzrd

choice = wzrd.pick_details("code")

agent = wzrd.WZRDAgent.from_env()
session = agent.authenticate()  # uses ~/.config/solana/id.json by default
status = agent.status()
receipt = agent.report_pick(choice, quality_score=0.9, latency_ms=1200)

print(session.pubkey)
print(status["next_step"])
print(receipt["contribution_id"])
```

`WZRDAgent.authenticate()` signs the exact server challenge message and sends the signature in the Solana base58 format the API expects. Keypair loading supports:

- `~/.config/solana/id.json`
- `WZRD_AGENT_KEYPAIR_PATH` or `SOLANA_KEYPAIR_PATH`
- `WZRD_AGENT_KEYPAIR` or `SOLANA_KEYPAIR` as a base58 secret or JSON byte array

Authenticated helpers:

- `agent.challenge()` returns the nonce + message format
- `agent.authenticate()` stores the Bearer token on the client
- `agent.status()` reads `/v1/agent/status`
- `agent.earned()` reads `/v1/agent/earned` — surfaces signup bonus, signal rewards, and claimable CCM
- `agent.report(...)` posts a manual contribution
- `agent.report_pick(choice, ...)` reports a `pick_details()` result with WZRD metadata attached
- `agent.claim_status()` checks if a merkle proof exists for this wallet
- `agent.claim()` claims CCM via the gasless relay — returns `ClaimResult(status, tx_sig, cumulative_total)`

The signup bonus is recorded on first auth, then becomes claimable after the next merkle publication cycle (every ~5 minutes). Claims are gasless — the server pays transaction fees. Per-wallet cooldown: 60s.

Candidate-aware routing:

```python
import wzrd

model = wzrd.pick(
    "code",
    candidates=[
        "openrouter/qwen/qwen3.5-9b",
        "openrouter/qwen/qwen3.5-35b-a3b",
        "anthropic/claude-sonnet-4.6",
    ],
)
```

If you want the metadata for logging or telemetry, use:

```python
choice = wzrd.pick_details("code")
print(choice.model, choice.score, choice.trend, choice.confidence)
```

## Environment variables

- `WZRD_API_URL`: signal endpoint override
- `WZRD_API_BASE_URL`: API root for agent auth/report calls
- `WZRD_AGENT_TOKEN`: existing Bearer token for `WZRDAgent`
- `WZRD_AGENT_KEYPAIR_PATH`: path to Solana JSON keypair
- `WZRD_AGENT_KEYPAIR`: Solana base58 secret or JSON byte array
- `WZRD_TIMEOUT_SECONDS`: request timeout
- `WZRD_CACHE_TTL_SECONDS`: cache TTL for fetched signals
- `WZRD_FEED_LIMIT`: number of feed rows to request

## What it returns

- `pick()` returns a model name string
- `pick_details()` returns a structured record
- `shortlist()` returns ranked records
- `compare()` explains the relative signal strength between two models
- `WZRDAgent` authenticates an agent wallet and reports contributions into the CCM loop
