bridgenode-llm 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1728 @@
1
+ Metadata-Version: 2.4
2
+ Name: bridgenode-llm
3
+ Version: 0.1.0
4
+ Summary: BridgeNode SDK - Pay-per-request AI (LLM, Image, Video, Music, Voice) via x402 on Base and Solana
5
+ Project-URL: Homepage, https://bridgenode.cc
6
+ Project-URL: Documentation, https://github.com/BlockRunAI/awesome-blockrun/tree/main/docs
7
+ Project-URL: Repository, https://github.com/bridgenode/bridgenode-llm
8
+ Author-email: BridgeNode <hello@bridgenode.cc>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: ai,base,claude,dall-e,free-models,gemini,image-generation,llm,micropayments,nvidia,openai,usdc,x402,zai
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
+ Requires-Python: >=3.9
22
+ Requires-Dist: eth-account>=0.11.0
23
+ Requires-Dist: httpx>=0.25.0
24
+ Requires-Dist: pydantic>=2.0.0
25
+ Requires-Dist: python-dotenv>=1.0.0
26
+ Requires-Dist: qrcode[pil]>=7.0
27
+ Provides-Extra: anthropic
28
+ Requires-Dist: anthropic>=0.40.0; extra == 'anthropic'
29
+ Provides-Extra: dev
30
+ Requires-Dist: black==24.10.0; extra == 'dev'
31
+ Requires-Dist: mypy>=1.0.0; extra == 'dev'
32
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
33
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
34
+ Requires-Dist: ruff==0.14.11; extra == 'dev'
35
+ Provides-Extra: solana
36
+ Requires-Dist: solana<0.40,>=0.36; extra == 'solana'
37
+ Requires-Dist: x402[svm]>=2.0.0; extra == 'solana'
38
+ Description-Content-Type: text/markdown
39
+
40
+ # BlockRun LLM SDK (Python)
41
+
42
+ > **blockrun-llm** is a Python SDK for accessing 80+ large language models (GPT-5.x, Claude 4.x, Gemini 3.x, DeepSeek, Grok 4.x, GLM, MiniMax, Moonshot and more) plus image / video / music generation, Grok Live Search, prediction-market data (Predexon), Exa neural web search, and Pyth-backed market data — all with automatic pay-per-request USDC micropayments via the x402 protocol. No API keys required; your wallet signature is your authentication. Built for AI agents that need to operate autonomously.
43
+ >
44
+ > 🆓 **Includes 8 fully-free NVIDIA-hosted models** — DeepSeek V4 Flash (1M context), Nemotron Nano Omni (vision), Qwen3 Next + Coder, Llama 4 Maverick, Mistral Small 4, plus `gpt-oss-120b/20b` (hidden from `/v1/models` but direct calls still work). Zero USDC, no rate-limit gimmicks. Use `routing_profile="free"` or call any `nvidia/*` model directly.
45
+
46
+ [![PyPI](https://img.shields.io/pypi/v/blockrun-llm.svg)](https://pypi.org/project/blockrun-llm/)
47
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
48
+
49
+ **BlockRun assumes Claude Code as the agent runtime.**
50
+
51
+ ## Supported Chains
52
+
53
+ | Chain | Network | Payment | Status |
54
+ |-------|---------|---------|--------|
55
+ | **Base** | Base Mainnet (Chain ID: 8453) | USDC | ✅ Primary |
56
+ | **Base Testnet** | Base Sepolia (Chain ID: 84532) | Testnet USDC | ✅ Development |
57
+ | **Solana** | Solana Mainnet | USDC (SPL) | ✅ New |
58
+
59
+
60
+ **Protocol:** x402 v2
61
+
62
+ ## Installation
63
+
64
+ ```bash
65
+ pip install blockrun-llm # Base chain (EVM/USDC) — includes all core deps
66
+ pip install blockrun-llm[solana] # Base + Solana (USDC SPL) payments
67
+ pip install blockrun-llm[dev] # Base + dev tools (pytest, black, ruff, mypy)
68
+ pip install blockrun-llm[dev,solana] # Everything
69
+ ```
70
+
71
+ ## Quick Start
72
+
73
+ ```python
74
+ from bridgenode_llm import LLMClient
75
+
76
+ client = LLMClient() # Uses BRIDGENODE_WALLET_KEY (never sent to server)
77
+ response = client.chat("openai/gpt-5.2", "Hello!")
78
+ ```
79
+
80
+ That's it. The SDK handles x402 payment automatically.
81
+
82
+ ### Try It Free (No USDC Required)
83
+
84
+ Want to kick the tires before funding a wallet? Route to BlockRun's free NVIDIA tier:
85
+
86
+ ```python
87
+ from bridgenode_llm import LLMClient
88
+
89
+ client = LLMClient() # Wallet still required for signing, but $0 charged
90
+
91
+ # Option 1: call a free model directly
92
+ response = client.chat("nvidia/deepseek-v4-flash", "Explain x402 in 1 sentence")
93
+
94
+ # Option 2: let the smart router pick the best free model per request
95
+ result = client.smart_chat("What is 2+2?", routing_profile="free")
96
+ print(result.model) # e.g. 'nvidia/deepseek-v4-flash' (cheapest capable for SIMPLE tier)
97
+ print(result.response) # '4'
98
+ ```
99
+
100
+ **Available free models** (input + output both $0, all NVIDIA-hosted):
101
+
102
+ | Model ID | Context | Best For |
103
+ |----------|---------|----------|
104
+ | `nvidia/deepseek-v4-flash` | 1M | DeepSeek V4 Flash — 284B / 13B active MoE, ~5× faster than V4 Pro. Best free chat / summarization / light reasoning |
105
+ | `nvidia/nemotron-3-nano-omni-30b-a3b-reasoning` | 256K | Only vision-capable free model — text + images + video (≤2 min) + audio (≤1 hr) |
106
+ | `nvidia/llama-4-maverick` | 131K | Meta Llama 4 Maverick MoE |
107
+ | `nvidia/qwen3-coder-480b` | 131K | Coding-optimised 480B MoE |
108
+ | `nvidia/mistral-small-4-119b` | 131K | ⚠️ Upstream timing out as of 2026-06-07 — avoid until NVIDIA recovers it |
109
+ | `nvidia/gpt-oss-120b` | 128K | OpenAI open-weight 120B — 123 tok/s. Hidden from `/v1/models` (so SmartChat won't auto-pick it) but direct calls still work |
110
+ | `nvidia/gpt-oss-20b` | 128K | OpenAI open-weight 20B — 155 tok/s. Hidden from `/v1/models` but direct calls still work |
111
+
112
+ > Need V4-Pro-class reasoning? Use the paid `deepseek/deepseek-v4-pro` ($0.435/$0.87 — the 75% launch promo became the permanent list price after 2026-05-31) — `nvidia/deepseek-v4-pro` is hidden because NVIDIA's NIM deployment is hung; backend MODEL_REDIRECTS forwards calls to V4 Flash.
113
+
114
+ > **Privacy note for `gpt-oss-120b/20b`**: NVIDIA's free build.nvidia.com tier reserves the right to use prompts/outputs for service improvement. The models are hidden from `/v1/models` so SmartChat won't auto-route to them, but direct calls still work — use them only when prompts contain no sensitive data.
115
+
116
+ > **Retired**: `nvidia/qwen3-next-80b-a3b-thinking` hit NVIDIA end-of-life 2026-05-21 (HTTP 410). The gateway auto-redirects pinned callers to `nvidia/llama-4-maverick`.
117
+
118
+ ## Solana Support
119
+
120
+ Pay for AI calls with Solana USDC via [sol.blockrun.ai](https://sol.bridgenode.cc):
121
+
122
+ ```python
123
+ from bridgenode_llm import SolanaLLMClient
124
+
125
+ # SOLANA_WALLET_KEY env var (bs58-encoded Solana secret key)
126
+ client = SolanaLLMClient()
127
+
128
+ # Or pass key directly
129
+ client = SolanaLLMClient(private_key="your-bs58-solana-key")
130
+
131
+ # Same API as LLMClient
132
+ response = client.chat("openai/gpt-5.2", "gm Solana")
133
+ print(response)
134
+
135
+ # DeepSeek on Solana
136
+ answer = client.chat("deepseek/deepseek-chat", "Explain Solana consensus", temperature=0.5)
137
+ ```
138
+
139
+ **Agent setup (auto-loads or creates a wallet):**
140
+ ```python
141
+ from bridgenode_llm import setup_agent_solana_wallet
142
+
143
+ client = setup_agent_solana_wallet() # uses ~/.blockrun/.solana-session, env, or creates one
144
+ client.chat("openai/gpt-5.2", "gm Solana")
145
+ ```
146
+
147
+ **Setup:**
148
+ ```bash
149
+ pip install blockrun-llm[solana]
150
+ export SOLANA_WALLET_KEY="your-bs58-solana-key"
151
+ ```
152
+
153
+ **Endpoint:** `https://sol.bridgenode.cc/api`
154
+ **Payment:** Solana USDC (SPL Token, mainnet)
155
+
156
+ > **Base vs Solana keys are not interchangeable.** A Solana key is base58
157
+ > (~44 chars for a seed, ~88 for a full keypair); a Base/EVM key is `0x` + 64
158
+ > hex chars. Pass a Solana key to `SolanaLLMClient` — **not** `LLMClient` /
159
+ > `setup_agent_wallet()`. If you do mix them up, the SDK now tells you exactly
160
+ > what to switch to instead of failing with a cryptic "must be 66 characters"
161
+ > error.
162
+
163
+ ## Smart Routing (ClawRouter)
164
+
165
+ Let the SDK automatically pick the cheapest capable model for each request:
166
+
167
+ ```python
168
+ from bridgenode_llm import LLMClient
169
+
170
+ client = LLMClient()
171
+
172
+ # Auto-routes to cheapest capable model
173
+ result = client.smart_chat("What is 2+2?")
174
+ print(result.response) # '4'
175
+ print(result.model) # 'moonshot/kimi-k2.6' (Moonshot flagship — vision + reasoning_content)
176
+ print(f"Saved {result.routing.savings * 100:.0f}%") # 'Saved 94%'
177
+
178
+ # Complex reasoning task -> routes to reasoning model
179
+ result = client.smart_chat("Prove the Riemann hypothesis step by step")
180
+ print(result.model) # 'deepseek/deepseek-reasoner'
181
+ ```
182
+
183
+ ### Routing Profiles
184
+
185
+ | Profile | Description | Best For |
186
+ |---------|-------------|----------|
187
+ | `free` | NVIDIA free tier — smart-routes across <!-- br:models.free -->8<!-- /br:models.free --> models (DeepSeek V4 Pro/Flash, Nemotron Nano Omni, Qwen3, GLM-4.7, Llama 4, Mistral) | Zero-cost testing, dev, prod |
188
+ | `eco` | Cheapest models per tier (DeepSeek, NVIDIA) | Cost-sensitive production |
189
+ | `auto` | Best balance of cost/quality (default) | General use |
190
+ | `premium` | Top-tier models (OpenAI, Anthropic) | Quality-critical tasks |
191
+
192
+ ```python
193
+ # Use premium models for complex tasks
194
+ result = client.smart_chat(
195
+ "Write production-grade async Python code",
196
+ routing_profile="premium"
197
+ )
198
+ print(result.model) # 'openai/gpt-5.4'
199
+ ```
200
+
201
+ ### How It Works
202
+
203
+ ClawRouter uses a 14-dimension rule-based classifier to analyze each request:
204
+
205
+ - **Token count** - Short vs long prompts
206
+ - **Code presence** - Programming keywords
207
+ - **Reasoning markers** - "prove", "step by step", etc.
208
+ - **Technical terms** - Architecture, optimization, etc.
209
+ - **Creative markers** - Story, poem, brainstorm, etc.
210
+ - **Agentic patterns** - Multi-step, tool use indicators
211
+
212
+ The classifier runs in <1ms, 100% locally, and routes to one of four tiers:
213
+
214
+ | Tier | Example Tasks | Auto Profile Model |
215
+ |------|---------------|-------------------|
216
+ | SIMPLE | "What is 2+2?", definitions | moonshot/kimi-k2.6 |
217
+ | MEDIUM | Code snippets, explanations | google/gemini-2.5-flash |
218
+ | COMPLEX | Architecture, long documents | google/gemini-3.1-pro |
219
+ | REASONING | Proofs, multi-step reasoning | deepseek/deepseek-reasoner |
220
+
221
+ ## How Payment Works
222
+
223
+ No API keys, no subscription. You hold USDC on Base in your own wallet, and
224
+ **each request pays for itself** with an on-chain micropayment. There are two
225
+ phases:
226
+
227
+ ### Phase 1 — Fund your wallet once (USDC on Base)
228
+
229
+ You only do this when your balance runs low. Three ways:
230
+
231
+ ```python
232
+ from bridgenode_llm import LLMClient
233
+
234
+ client = LLMClient() # auto-detects wallet from BRIDGENODE_WALLET_KEY
235
+
236
+ # (a) Buy USDC with a card / bank (FREE) — mint a one-time Coinbase Onramp link
237
+ link = client.onramp(client.get_wallet_address())
238
+ print(link["url"]) # open https://pay.coinbase.com/... to buy USDC on Base
239
+ # The link is single-use and expires in ~5 min — mint it at click time, never cache it.
240
+
241
+ # (b) Transfer existing Base USDC to your wallet address
242
+ print(client.get_wallet_address()) # send USDC on Base to this 0x… address
243
+
244
+ # (c) Skip funding entirely — the free NVIDIA models cost $0
245
+ client.chat("nvidia/deepseek-v4-flash", "Hello!") # routing_profile="free" also works
246
+ ```
247
+
248
+ `$5` of USDC covers thousands of paid requests. Check your balance any time:
249
+
250
+ ```python
251
+ print(f"Balance: ${client.get_balance():.2f} USDC")
252
+ ```
253
+
254
+ ### Phase 2 — Every request pays itself (automatic x402)
255
+
256
+ ```python
257
+ reply = client.chat("anthropic/claude-sonnet-4.6", "Explain x402 in one line")
258
+ ```
259
+
260
+ That single call does all of this under the hood:
261
+
262
+ 1. You send the request to BlockRun's gateway.
263
+ 2. The gateway returns `402 Payment Required` with the price.
264
+ 3. The SDK signs a USDC payment on Base **locally** (EIP-712) — your private
265
+ key never leaves your machine.
266
+ 4. The request is retried with the signed payment proof.
267
+ 5. The gateway settles on-chain and returns the AI response.
268
+
269
+ One call, no separate pay step.
270
+
271
+ ### What it costs, and how to verify it
272
+
273
+ - **Pay-as-you-go, per call.** You pay only the gateway price of each request
274
+ (see [Available Models](#available-models)). The free NVIDIA models are `$0`.
275
+ - **Track spend.** `client.get_spending()` returns this session's
276
+ `{total_usd, calls}`. Every paid call also appends a line to
277
+ `~/.blockrun/cost_log.jsonl`; summarize/export it with
278
+ `bridgenode_llm.billing` (`get_cost_log_summary`, `export_cost_log_csv`) — see
279
+ [Billing & Cost Tracking](#billing--cost-tracking).
280
+ - **Verify settlements on-chain.** Each settlement returns a tx hash you can
281
+ inspect on BaseScan — `https://basescan.org/tx/<hash>`, or view all activity
282
+ for your wallet at `https://basescan.org/address/<your-address>`.
283
+ - **Non-custodial.** Your wallet is yours; the key is only used for local
284
+ signing and **never leaves your machine**. No deposits held by BlockRun.
285
+
286
+ ## Available Models
287
+
288
+ ### OpenAI GPT-5.5 Family
289
+ Released 2026-04-23 — first fully retrained base since GPT-4.5. 1M context, 128K output, native agent + computer use.
290
+
291
+ | Model | Input Price | Output Price | Context |
292
+ |-------|-------------|--------------|---------|
293
+ | `openai/gpt-5.5` | $5.00/M | $30.00/M | 1M |
294
+
295
+ ### OpenAI GPT-5.4 Family
296
+ | Model | Input Price | Output Price | Context |
297
+ |-------|-------------|--------------|---------|
298
+ | `openai/gpt-5.4` | $2.50/M | $15.00/M | 1M |
299
+ | `openai/gpt-5.4-pro` | $30.00/M | $180.00/M | 1M |
300
+ | `openai/gpt-5.4-mini` | $0.75/M | $4.50/M | 400K |
301
+ | `openai/gpt-5.4-nano` | $0.20/M | $1.25/M | 1M |
302
+
303
+ ### OpenAI GPT-5 Family
304
+ | Model | Input Price | Output Price | Context |
305
+ |-------|-------------|--------------|---------|
306
+ | `openai/gpt-5.3` | $1.75/M | $14.00/M | 128K |
307
+ | `openai/gpt-5.2` | $1.75/M | $14.00/M | 400K |
308
+ | `openai/gpt-5-mini` | $0.25/M | $2.00/M | 200K |
309
+ | `openai/gpt-5.2-pro` | $21.00/M | $168.00/M | 400K |
310
+ | `openai/gpt-5.3-codex` | $1.75/M | $14.00/M | 400K |
311
+
312
+ ### OpenAI GPT-4o Family
313
+ | Model | Input Price | Output Price | Context |
314
+ |-------|-------------|--------------|---------|
315
+ | `openai/gpt-4o` | $2.50/M | $10.00/M | 128K |
316
+ | `openai/gpt-4o-mini` | $0.15/M | $0.60/M | 128K |
317
+
318
+ ### OpenAI O-Series (Reasoning)
319
+ | Model | Input Price | Output Price | Context |
320
+ |-------|-------------|--------------|---------|
321
+ | `openai/o1` | $15.00/M | $60.00/M | 200K |
322
+ | `openai/o3` | $2.00/M | $8.00/M | 200K |
323
+ | `openai/o3-mini` | $1.10/M | $4.40/M | 128K |
324
+
325
+ ### Anthropic Claude
326
+ | Model | Input Price | Output Price | Context | Notes |
327
+ |-------|-------------|--------------|---------|-------|
328
+ | `anthropic/claude-opus-4.8` | $5.00/M | $25.00/M | 1M | Most capable Claude — agentic coding + adaptive thinking, 128K output |
329
+ | `anthropic/claude-opus-4.7` | $5.00/M | $25.00/M | 1M | Agentic coding + adaptive thinking, 128K output |
330
+ | `anthropic/claude-opus-4.6` | $5.00/M | $25.00/M | 200K | Hidden from `/v1/models` (superseded by 4.7); direct calls still work |
331
+ | `anthropic/claude-opus-4.5` | $5.00/M | $25.00/M | 200K | |
332
+ | `anthropic/claude-sonnet-4.6` | $3.00/M | $15.00/M | 200K | |
333
+ | `anthropic/claude-haiku-4.5` | $1.00/M | $5.00/M | 200K | |
334
+
335
+ ### Google Gemini
336
+ | Model | Input Price | Output Price | Context |
337
+ |-------|-------------|--------------|---------|
338
+ | `google/gemini-3.1-pro` | $2.00/M | $12.00/M | 1M |
339
+ | `google/gemini-3.5-flash` | $0.50/M | $3.00/M | 1M |
340
+ | `google/gemini-3-flash-preview` | $0.50/M | $3.00/M | 1M |
341
+ | `google/gemini-2.5-pro` | $1.25/M | $10.00/M | 1M |
342
+ | `google/gemini-2.5-flash` | $0.30/M | $2.50/M | 1M |
343
+ | `google/gemini-3.1-flash-lite` | $0.25/M | $1.50/M | 1M |
344
+ | `google/gemini-2.5-flash-lite` | $0.10/M | $0.40/M | 1M |
345
+
346
+ ### DeepSeek
347
+
348
+ V4 family launched 2026-04-24. DeepSeek upstream now serves the legacy
349
+ `deepseek-chat` / `deepseek-reasoner` aliases as V4 Flash non-thinking /
350
+ thinking modes. V4 Pro is the new flagship paid SKU — 1.6T MoE / 49B active,
351
+ 1M context, MMLU-Pro 87.5, GPQA 90.1, SWE-bench 80.6, LiveCodeBench 93.5.
352
+
353
+ | Model | Input Price | Output Price | Context | Notes |
354
+ |-------|-------------|--------------|---------|-------|
355
+ | `deepseek/deepseek-v4-pro` | $0.435/M | $0.87/M | 1M | V4 flagship — strongest open-weight reasoner. The 75% launch promo became the permanent list price after 2026-05-31 |
356
+ | `deepseek/deepseek-chat` | $0.20/M | $0.40/M | 1M | V4 Flash non-thinking (paid endpoint with 5MB request bodies; same upstream as `nvidia/deepseek-v4-flash`) |
357
+ | `deepseek/deepseek-reasoner` | $0.20/M | $0.40/M | 1M | V4 Flash thinking (same upstream as `deepseek-chat`, thinking enabled by default) |
358
+
359
+ ### MiniMax
360
+ | Model | Input Price | Output Price | Context | Notes |
361
+ |-------|-------------|--------------|---------|-------|
362
+ | `minimax/minimax-m3` | $0.30/M | $1.20/M | 1M | M3 flagship — strong reasoning + coding, 1M context |
363
+ | `minimax/minimax-m2.7` | $0.30/M | $1.20/M | 200K | |
364
+
365
+ ### xAI Grok
366
+
367
+ Grok 4.3 and Grok Build are resold through BlockRun's OpenRouter credit pool
368
+ (same pattern as `deepseek/deepseek-v4-pro` and `minimax/minimax-m3`). Older
369
+ Grok chat SKUs (grok-3/4/4.1-fast families) are hidden from `/v1/models` but
370
+ direct calls by full ID still work.
371
+
372
+ | Model | Input Price | Output Price | Context | Notes |
373
+ |-------|-------------|--------------|---------|-------|
374
+ | `xai/grok-4.3` | $1.50/M | $4.00/M | 1M | Reasoning model, vision-capable, tuned for agentic workflows |
375
+ | `xai/grok-build-0.1` | $1.50/M | $3.00/M | 256K | Fast agentic coding model — interactive software-engineering workflows |
376
+
377
+ ### ZAI
378
+
379
+ The GLM flat-rate launch promos have fully ended (glm-5.1 on 2026-06-05;
380
+ glm-5 and glm-5-turbo on 2026-06-06) — the whole family now bills per-token.
381
+
382
+ | Model | Input Price | Output Price | Context | Notes |
383
+ |-------|-------------|--------------|---------|-------|
384
+ | `zai/glm-5.2` | $1.40/M | $4.40/M | 1M | Z.AI's newest flagship — 1M-token context, top open-source on long-horizon coding |
385
+ | `zai/glm-5.1` | $1.40/M | $4.40/M | 200K | #1 open-source on SWE-Bench Pro, 8-hour autonomous execution |
386
+ | `zai/glm-5` | $0.60/M | $1.92/M | 200K | |
387
+ | `zai/glm-5-turbo` | $1.20/M | $4.00/M | 200K | |
388
+
389
+ ### NVIDIA (Free & Hosted)
390
+
391
+ Free tier refreshed 2026-04-28: added `nvidia/deepseek-v4-flash` (1M context)
392
+ and `nvidia/nemotron-3-nano-omni-30b-a3b-reasoning` (vision). `nvidia/gpt-oss-120b`
393
+ and `nvidia/gpt-oss-20b` were briefly delisted over privacy concerns
394
+ (NVIDIA's free build.nvidia.com tier reserves the right to use prompts for
395
+ service improvement) but **re-enabled 2026-04-30 with `available: true` +
396
+ `hidden: true`** — they no longer appear in `/v1/models` (so SmartChat won't
397
+ auto-pick them) but direct calls by full ID still return HTTP 200.
398
+ `nvidia/deepseek-v4-pro`, `nvidia/deepseek-v3.2`, and `nvidia/glm-4.7` are
399
+ hidden because NVIDIA's NIM deployment is hung — backend MODEL_REDIRECTS
400
+ auto-forwards calls to V4 Flash / qwen3-coder. `nvidia/qwen3-next-80b-a3b-thinking`
401
+ hit NVIDIA end-of-life 2026-05-21 (HTTP 410) and is auto-redirected to
402
+ `nvidia/llama-4-maverick`.
403
+
404
+ | Model | Input Price | Output Price | Context | Notes |
405
+ |-------|-------------|--------------|---------|-------|
406
+ | `nvidia/deepseek-v4-flash` | **FREE** | **FREE** | 1M | DeepSeek V4 Flash — 284B / 13B active MoE, ~5× faster than V4 Pro. Best free chat / summarization |
407
+ | `nvidia/nemotron-3-nano-omni-30b-a3b-reasoning` | **FREE** | **FREE** | 256K | First vision-capable free model — RGB images, mp4 video |
408
+ | `nvidia/mistral-small-4-119b` | **FREE** | **FREE** | 131K | ⚠️ Upstream timing out as of 2026-06-07 |
409
+ | `nvidia/llama-4-maverick` | **FREE** | **FREE** | 131K | Meta Llama 4 Maverick MoE |
410
+ | `nvidia/qwen3-coder-480b` | **FREE** | **FREE** | 131K | Coding-optimised 480B MoE |
411
+ | `nvidia/gpt-oss-120b` | **FREE** | **FREE** | 128K | OpenAI open-weight 120B — 123 tok/s. Hidden from `/v1/models`; direct calls work |
412
+ | `nvidia/gpt-oss-20b` | **FREE** | **FREE** | 128K | OpenAI open-weight 20B — 155 tok/s. Hidden from `/v1/models`; direct calls work |
413
+ | `moonshot/kimi-k2.5` | $0.60/M | $3.00/M | 262K | Kimi K2.5 direct from Moonshot (replaces `nvidia/kimi-k2.5`) |
414
+ | `moonshot/kimi-k2.6` | $0.95/M | $4.00/M | 256K | Moonshot flagship (vision + reasoning_content) |
415
+
416
+ ### Testnet Models (Base Sepolia)
417
+ | Model | Price |
418
+ |-------|-------|
419
+ | `openai/gpt-oss-20b` | $0.001/request |
420
+ | `openai/gpt-oss-120b` | $0.002/request |
421
+
422
+ *Testnet models use flat pricing (no token counting) for simplicity.*
423
+
424
+ ### Verifying Models End-to-End
425
+
426
+ The SDK ships two runnable sweep scripts under `examples/`:
427
+
428
+ ```bash
429
+ # Chat LLMs — every chat model the SDK exposes
430
+ python examples/sweep_all_chat_models.py --output-json sweep-results.json
431
+
432
+ # Image + music models (video excluded — long polling, expensive per clip)
433
+ python examples/sweep_all_media_models.py --output-json sweep-media-results.json
434
+ ```
435
+
436
+ Each script captures per-model status, latency, token counts, and per-call
437
+ cost, prints a grouped report, and exits non-zero if any expected-to-work
438
+ model fails. Useful before a release or after router/catalog changes.
439
+
440
+ `smart_chat()` and `chat()` accept an optional `fallback_models=[...]` list —
441
+ on timeout / 5xx / network error the SDK transparently walks the chain
442
+ before raising. `smart_chat()` populates this from the tier's fallback list
443
+ automatically.
444
+
445
+ ### Image Generation
446
+
447
+ | Model | Price |
448
+ |-------|-------|
449
+ | `openai/dall-e-3` | $0.04/image |
450
+ | `openai/gpt-image-1` | $0.02/image |
451
+ | `openai/gpt-image-2` | $0.06/image (reasoning-driven, multilingual text rendering, character consistency) |
452
+ | `google/nano-banana` | $0.05/image |
453
+ | `google/nano-banana-pro` | $0.10/image |
454
+ | `xai/grok-imagine-image` | $0.02/image |
455
+ | `xai/grok-imagine-image-pro` | $0.07/image |
456
+ | `zai/cogview-4` | $0.015/image |
457
+
458
+ Image editing (`client.edit` / `client.image_edit`) hits the `/v1/images/image2image` endpoint and supports `openai/gpt-image-1`, `openai/gpt-image-2`, `google/nano-banana`, and `google/nano-banana-pro`. Pass a list of source images to fuse multiple inputs (openai/* up to 4, google/* up to 3).
459
+
460
+ **`quality` (Solana only).** On Solana, `image` and `image_edit` accept
461
+ `quality="low" | "medium" | "high" | "auto"` for `openai/gpt-image-*` — `low`
462
+ meaningfully cuts generation time:
463
+
464
+ ```python
465
+ sol = SolanaLLMClient()
466
+ result = sol.image("a red apple", model="openai/gpt-image-2", quality="low")
467
+ ```
468
+
469
+ This is deliberately absent from the Base `ImageClient`: the Base gateway has
470
+ no `quality` field and would silently ignore the value, so passing it there
471
+ raises `TypeError` rather than quietly doing nothing.
472
+
473
+ ### Video Generation
474
+ | Model | Price | Default 5s 720p |
475
+ |-------|-------|-----------------|
476
+ | `xai/grok-imagine-video` | $0.050/sec | 8s ≈ $0.40 |
477
+ | `bytedance/seedance-1.5-pro` | $4.32 / M tok (flat) | ≈ $0.46 |
478
+ | `bytedance/seedance-2.0-fast` | $11.20 / M text · $6.60 / M image | ≈ $1.19 t2v / $0.70 i2v |
479
+ | `bytedance/seedance-2.0` | $14.00 / M text · $8.60 / M image | ≈ $1.49 t2v / $0.91 i2v |
480
+
481
+ Seedance is billed by token360 in tokens (~20,256 tok/sec at 720p). Drop
482
+ `resolution="480p"` for ~half the cost, or bump to `1080p` / `4K`.
483
+ Seedance defaults to `720p` with synced audio on text-to-video; image- or
484
+ face-conditioned paths default audio off. Grok ignores `resolution` and
485
+ `generate_audio`.
486
+
487
+ ```python
488
+ from bridgenode_llm import VideoClient
489
+
490
+ client = VideoClient()
491
+ result = client.generate("a red apple slowly spinning on a wooden table")
492
+ print(result.data[0].url) # permanent MP4 URL
493
+ print(result.data[0].duration_seconds) # 8
494
+
495
+ # Image-to-video
496
+ result = client.generate(
497
+ "the subject turns its head and smiles",
498
+ image_url="https://example.com/portrait.jpg",
499
+ )
500
+
501
+ # Character-consistency video (Seedance 2.0 fast/pro). Pass a ta_xxxxxx
502
+ # asset to keep the same face across clips — either a Virtual Portrait
503
+ # (AI character, PortraitClient, $0.01) or a RealFace (real person,
504
+ # RealFaceClient, $0.01, no KYC). Mutually exclusive with image_url.
505
+ result = client.generate(
506
+ "the subject smiles warmly and waves at the camera",
507
+ model="bytedance/seedance-2.0",
508
+ real_face_asset_id="ta_abc123xyz",
509
+ resolution="1080p",
510
+ generate_audio=True,
511
+ )
512
+
513
+ # First-and-last-frame interpolation (Seedance only): the model tweens
514
+ # from image_url (first frame) to last_frame_url (final frame).
515
+ # Priced identically to image-to-video.
516
+ result = client.generate(
517
+ "the flower blooms in golden morning light",
518
+ model="bytedance/seedance-1.5-pro",
519
+ image_url="https://example.com/bud.jpg",
520
+ last_frame_url="https://example.com/bloom.jpg",
521
+ )
522
+
523
+ # Omni / multi-reference (Seedance 2.0 only): up to 9 reference images
524
+ # for character/style consistency. Cite them as "image 1", "image 2"
525
+ # in the prompt. Mutually exclusive with image_url / last_frame_url /
526
+ # real_face_asset_id.
527
+ result = client.generate(
528
+ "the character from image 1 walks through the city from image 2",
529
+ model="bytedance/seedance-2.0",
530
+ reference_image_urls=[
531
+ "https://example.com/character.jpg",
532
+ "https://example.com/city.jpg",
533
+ ],
534
+ )
535
+
536
+ # input_type — declare the seed mode you intend, and get an error instead of
537
+ # a surprise. The gateway infers the mode from the seed fields above; if your
538
+ # declared value disagrees it returns 400 WITHOUT charging.
539
+ #
540
+ # Worth it when the seed fields are built dynamically: if `image_url` comes
541
+ # back empty, the request quietly degrades to text-to-video and you still pay
542
+ # for the clip. Declaring input_type="image" turns that into a 400 instead.
543
+ result = client.generate(
544
+ "the portrait turns to face the camera",
545
+ model="bytedance/seedance-2.0",
546
+ image_url=maybe_empty_url, # if this is falsy...
547
+ input_type="image", # ...you get a 400, not a text-to-video bill
548
+ )
549
+ ```
550
+
551
+ ### Text-to-Speech & Sound Effects (`SpeechClient`)
552
+
553
+ BlockRun Voice (ElevenLabs) — OpenAI-compatible TTS plus cinematic sound
554
+ effects. TTS price scales with character count: `(chars / 1000) × model
555
+ rate`, minimum $0.001/request. Synthesis is synchronous (<1s for Flash).
556
+
557
+ | Model | Price | Max Input | Notes |
558
+ |-------|-------|-----------|-------|
559
+ | `elevenlabs/flash-v2.5` | $0.05/1k chars | 40k chars | ~75ms latency, 32 languages (default) |
560
+ | `elevenlabs/turbo-v2.5` | $0.05/1k chars | 40k chars | ~250ms latency, balanced quality |
561
+ | `elevenlabs/multilingual-v2` | $0.10/1k chars | 10k chars | Long-form narration, audiobooks |
562
+ | `elevenlabs/v3` | $0.10/1k chars | 5k chars | Max expressiveness, 70+ languages |
563
+ | `elevenlabs/sound-effects` | $0.05/generation | 1k chars | Sound effects up to 22s |
564
+
565
+ ```python
566
+ from bridgenode_llm import SpeechClient
567
+
568
+ client = SpeechClient()
569
+
570
+ # Text-to-speech (voice aliases: sarah, george, laura, charlie,
571
+ # river, roger, callum, harry — or any raw ElevenLabs voice_id)
572
+ result = client.generate("Welcome to BlockRun.", voice="george")
573
+ print(result.data[0].url) # audio URL (mp3 by default)
574
+
575
+ # Other formats / speed
576
+ result = client.generate(
577
+ "Breaking news from the world of micropayments.",
578
+ model="elevenlabs/v3",
579
+ response_format="wav",
580
+ speed=1.1,
581
+ )
582
+
583
+ # Sound effects (flat $0.05/generation)
584
+ result = client.sound_effect("rain on a tin roof, distant thunder")
585
+
586
+ # List voices (free, rate-limited)
587
+ voices = client.list_voices()
588
+ ```
589
+
590
+ ## Virtual Portraits (`PortraitClient`)
591
+
592
+ `PortraitClient` wraps `POST /v1/portrait/enroll` ($0.01 USDC, one-time,
593
+ no KYC) and the free `GET /v1/wallet/<address>/portraits` listing endpoint.
594
+ Enroll an AI-generated character image, get back a `ta_xxxxxxxx` asset id,
595
+ then reuse it as `real_face_asset_id` on Seedance 2.0 / 2.0-fast to keep
596
+ the same character across as many videos as you want.
597
+
598
+ > Need a **real person's** likeness instead? Use
599
+ > [`RealFaceClient`](#real-person-faces-realfaceclient) below — it
600
+ > enrolls a real face for **$0.01** via a quick on-phone liveness check,
601
+ > **no KYC**. Virtual Portraits are for AI-generated personas, mascots,
602
+ > avatars, and virtual spokespeople; RealFace is for real people. Both
603
+ > return a `ta_xxxxxx` id usable as `real_face_asset_id` on Seedance
604
+ > 2.0 / 2.0-fast.
605
+
606
+ ```python
607
+ from bridgenode_llm import PortraitClient, VideoClient
608
+
609
+ portraits = PortraitClient()
610
+ portrait = portraits.enroll(
611
+ name="My Spokesperson",
612
+ image_url="https://example.com/character.jpg",
613
+ )
614
+ print(portrait.asset_id) # ta_abcdef1234567890
615
+ print(portrait.settlement.tx_hash) # 0x9f3a… (BaseScan-verifiable)
616
+
617
+ # Reuse the same ta_ id on any Seedance 2.0 / 2.0-fast call
618
+ video = VideoClient()
619
+ clip = video.generate(
620
+ "the character smiles warmly and waves at the camera",
621
+ model="bytedance/seedance-2.0-fast",
622
+ real_face_asset_id=portrait.asset_id,
623
+ )
624
+ print(clip.data[0].url)
625
+
626
+ # Browse this wallet's enrolled portraits (free, rate-limited)
627
+ listing = portraits.list_portraits()
628
+ for p in listing.portraits:
629
+ print(p.assetId, p.name, p.enrollmentTxHash)
630
+ ```
631
+
632
+ Settlement is held until the upstream registration succeeds — if the
633
+ image fails the content filter or exceeds 10 MB, the route returns 502
634
+ and **no payment is taken**, safe to retry with a different image.
635
+
636
+ ## Real-Person Faces (`RealFaceClient`)
637
+
638
+ `RealFaceClient` enrolls a **real person's** likeness so you can keep the
639
+ same human face across multiple Seedance 2.0 / 2.0-fast videos. Unlike a
640
+ Virtual Portrait (an AI-generated character), RealFace proves the enroller
641
+ is the person in the photo via a brief **on-phone liveness check** (nod +
642
+ blink, ~1 minute) — **no KYC**, no government ID, no account login.
643
+
644
+ Enrollment is a three-step flow:
645
+
646
+ 1. **`init(name)`** — *free*. Returns a `group_id` and an `h5_link` the
647
+ real person opens on their phone (render it as a QR code).
648
+ 2. **phone liveness** — the rights-holder opens the link, allows camera
649
+ access, nods + blinks (~60s). Nothing is sent to BlockRun in this step.
650
+ 3. **`enroll(name, image_url, group_id)`** — **$0.01 USDC**, one-time.
651
+ Uploads the face photo, matches it against the live capture, and
652
+ returns a `ta_xxxxxxxx` asset id.
653
+
654
+ ```python
655
+ from bridgenode_llm import RealFaceClient, VideoClient
656
+
657
+ faces = RealFaceClient()
658
+
659
+ # 1. Start enrollment (free). Show init.h5_link as a QR for the person.
660
+ init = faces.init(name="Jane — Q3 spokesperson")
661
+ print(init.h5_link) # they scan + do the liveness check
662
+
663
+ # 2. Block until they finish the phone liveness check.
664
+ faces.wait_for_active(init.group_id)
665
+
666
+ # 3. Finalize ($0.01) with the person's face photo.
667
+ rf = faces.enroll(
668
+ name="Jane — Q3 spokesperson",
669
+ image_url="https://example.com/jane.jpg",
670
+ group_id=init.group_id,
671
+ )
672
+ print(rf.asset_id) # ta_abcdef1234567890
673
+ print(rf.settlement.tx_hash) # 0x9f3a… (BaseScan-verifiable)
674
+
675
+ # Reuse the ta_ id on any Seedance 2.0 / 2.0-fast call
676
+ video = VideoClient()
677
+ clip = video.generate(
678
+ "she smiles warmly and waves at the camera",
679
+ model="bytedance/seedance-2.0-fast",
680
+ real_face_asset_id=rf.asset_id,
681
+ )
682
+ print(clip.data[0].url)
683
+
684
+ # Browse this wallet's enrolled RealFaces (free, rate-limited)
685
+ listing = faces.list_realfaces()
686
+ for r in listing.realfaces:
687
+ print(r.assetId, r.name, r.enrollmentTxHash)
688
+ ```
689
+
690
+ Settlement happens only *after* the face is successfully matched and
691
+ registered, so failed enrollments return an error with **no charge**:
692
+ `425` = group not active yet (finish the phone check first), `422` = the
693
+ photo did not match the live capture (use a clearer front-facing photo),
694
+ `502` = upstream upload failure (safe to retry). The H5 session expires
695
+ ~120s after each `init`; call `init(group_id=…)` to refresh an expired
696
+ link.
697
+
698
+ ## Voice Calls (`VoiceClient`)
699
+
700
+ `VoiceClient` wraps `POST /v1/voice/call` (paid, $0.54/call) and
701
+ `GET /v1/voice/call/{call_id}` (free polling) — AI-powered outbound phone
702
+ calls powered by Bland.ai. The agent dials the recipient and runs a real-time
703
+ conversation based on your `task` instructions. US + Canada destinations.
704
+
705
+ ```python
706
+ from bridgenode_llm import VoiceClient
707
+
708
+ client = VoiceClient()
709
+
710
+ # Initiate (paid $0.54)
711
+ result = client.call(
712
+ to="+14155552671",
713
+ task="You are a friendly assistant calling to confirm a 3pm dentist appointment.",
714
+ voice="maya", # nat / josh / maya / june / paige / derek / florian
715
+ max_duration=5, # minutes (1–30)
716
+ )
717
+ print(result["call_id"])
718
+
719
+ # Poll for transcript + recording (free)
720
+ status = client.get_status(result["call_id"])
721
+ print(status.get("status"), status.get("recording_url"))
722
+ ```
723
+
724
+ Bring your own caller-ID: pass `from_="+14155552671"` (must be a BlockRun
725
+ phone number you own; buy via `PhoneClient.buy_number()` or
726
+ `/v1/phone/numbers/buy`). If you omit `from_` and your wallet owns exactly one
727
+ active number, the backend auto-picks it; with multiple active numbers you'll
728
+ get a `400 ambiguous_from` and the error body lists your candidates.
729
+
730
+ ## Phone Numbers (`PhoneClient`)
731
+
732
+ `PhoneClient` wraps `/v1/phone/*` — Twilio-backed phone lookup and
733
+ wallet-bound number provisioning. Buy a number once to use it as caller ID in
734
+ `VoiceClient`; the number is leased for 30 days and tied to your wallet.
735
+
736
+ ```python
737
+ from bridgenode_llm import PhoneClient
738
+
739
+ client = PhoneClient()
740
+
741
+ # Carrier + line-type lookup ($0.01)
742
+ info = client.lookup("+14155552671")
743
+
744
+ # Carrier + SIM-swap/forwarding fraud signals ($0.05)
745
+ fraud = client.lookup_fraud("+14155552671")
746
+
747
+ # Buy a number — 30-day lease, wallet-bound ($5.00).
748
+ # Payment is held until Twilio confirms the purchase, so failed buys never charge you.
749
+ bought = client.buy_number(country="US", area_code="415")
750
+ print(bought["phone_number"], bought["expires_at"])
751
+
752
+ # List, renew, release
753
+ print(client.list_numbers()) # $0.001
754
+ client.renew_number(bought["phone_number"]) # $5.00, +30 days
755
+ client.release_number(bought["phone_number"]) # free
756
+ ```
757
+
758
+ ## Surf — Crypto Intelligence (`SurfClient`)
759
+
760
+ `SurfClient` wraps `/v1/surf/*` — the asksurf.ai partner gateway, ~83 crypto
761
+ endpoints across exchanges, on-chain SQL, prediction markets (Polymarket +
762
+ Kalshi), wallets, social analytics, and project intelligence. Tiered pricing:
763
+ $0.001 / $0.005 / $0.020 per call (tier 1 / 2 / 3).
764
+
765
+ ```python
766
+ from bridgenode_llm import SurfClient
767
+
768
+ client = SurfClient()
769
+
770
+ # Discovery
771
+ print(SurfClient.endpoints()) # full catalog
772
+ print(client.price("market/ranking")) # 0.001
773
+ print(client.endpoint_info("onchain/sql")) # {'method': 'POST', 'tier': 3, ...}
774
+
775
+ # GET — pass query params (validated against the catalog)
776
+ btc_price = client.get("exchange/price", {"pair": "BTC/USDT"})
777
+ holders = client.get("token/holders", {"address": "0x...", "chain": "ethereum"})
778
+
779
+ # POST — JSON body
780
+ rows = client.post("onchain/sql", {"query": "SELECT count() FROM ethereum.blocks"})
781
+
782
+ # Generic helper — auto-routes GET vs POST from the catalog
783
+ result = client.call("token/holders", params={"address": "0x...", "chain": "ethereum"})
784
+ ```
785
+
786
+ ## Standalone Search (`SearchClient`)
787
+
788
+ `SearchClient` wraps `POST /v1/search` — standalone Grok Live Search with
789
+ automatic x402 payment. Pricing: `$0.025/source + margin`
790
+ (10 sources ≈ `$0.26`).
791
+
792
+ ```python
793
+ from bridgenode_llm import SearchClient
794
+
795
+ client = SearchClient()
796
+ result = client.search(
797
+ "Latest news on x402 adoption",
798
+ sources=["x", "web"],
799
+ max_results=10,
800
+ )
801
+ print(result.summary)
802
+ for url in result.citations or []:
803
+ print(url)
804
+ ```
805
+
806
+ ## Market Data (`PriceClient`)
807
+
808
+ Pyth-backed realtime quotes and OHLC history across crypto, FX, commodities
809
+ and 12 global equity markets. Crypto / FX / commodity are **fully free**
810
+ across price, history and list; stocks (`stocks/{market}` and the `usstock`
811
+ legacy alias) charge `$0.001` per price or history call. Pass
812
+ `require_wallet=False` when you only need free endpoints.
813
+
814
+ ```python
815
+ from bridgenode_llm import PriceClient
816
+
817
+ # Free usage — no wallet
818
+ p = PriceClient(require_wallet=False)
819
+ btc = p.price("crypto", "BTC-USD")
820
+ eur = p.price("fx", "EUR-USD")
821
+ symbols = p.list_symbols("crypto", q="sol", limit=20)
822
+
823
+ # Paid — requires a wallet
824
+ p2 = PriceClient()
825
+ aapl = p2.price("stocks", "AAPL", market="us")
826
+ bars = p2.history(
827
+ "stocks", "AAPL",
828
+ market="us",
829
+ resolution="D",
830
+ from_ts=1_700_000_000,
831
+ to_ts=1_710_000_000,
832
+ )
833
+ ```
834
+
835
+ Supported stock markets: `us, hk, jp, kr, gb, de, fr, nl, ie, lu, cn, ca`.
836
+
837
+ ## Multi-chain RPC (`RpcClient`)
838
+
839
+ Standard JSON-RPC 2.0 access to 40+ chains through one endpoint — Ethereum,
840
+ Base, Solana, Polygon, BSC, Arbitrum, Optimism, Avalanche, Bitcoin, Sui, and
841
+ more (powered by Tatum's RPC gateway). No API key, no per-chain endpoints:
842
+ flat **$0.002 per call** in USDC; a JSON-RPC batch charges per element.
843
+
844
+ ```python
845
+ from bridgenode_llm import RpcClient
846
+
847
+ client = RpcClient()
848
+
849
+ # EVM chains speak eth_* JSON-RPC
850
+ block = client.call("ethereum", "eth_blockNumber")
851
+ print(int(block.result, 16))
852
+
853
+ balance = client.call(
854
+ "base", "eth_getBalance",
855
+ ["0x4200000000000000000000000000000000000006", "latest"],
856
+ )
857
+
858
+ # Non-EVM chains speak their native JSON-RPC
859
+ slot = client.call("solana", "getSlot")
860
+ utxo_tip = client.call("bitcoin", "getblockcount")
861
+
862
+ # Batch: one payment, per-element pricing ($0.002 x N)
863
+ out = client.batch("polygon", [
864
+ {"method": "eth_blockNumber"},
865
+ {"method": "eth_gasPrice"},
866
+ ])
867
+
868
+ print(block.network) # "ethereum" (canonical key from X-Network)
869
+ print(block.cache_hit) # True if served from the gateway's hot cache
870
+ print(block.tx_hash) # x402 settlement tx
871
+ ```
872
+
873
+ 40 curated chains are exported as `bridgenode_llm.SUPPORTED_NETWORKS`; common
874
+ aliases (`eth`, `arb`, `op`, `matic`, `bnb`, `avax`, `sol`, `btc`, `xrp`,
875
+ `dot`, ...) resolve server-side (`bridgenode_llm.NETWORK_ALIASES`). Unknown but
876
+ well-formed slugs fall through to a generic `{slug}-mainnet` gateway attempt,
877
+ so new chains work without an SDK update. Hot, low-volatility reads
878
+ (`eth_chainId`, mined blocks/receipts, `getTransaction`, ...) are served from
879
+ a method-aware gateway cache — same price, lower latency.
880
+
881
+ ## DeFi Data (Powered by DefiLlama)
882
+
883
+ GET passthrough to DefiLlama — protocols, TVL, yields, token prices.
884
+ $0.005/call ($0.001 for price lookups). Methods live on `LLMClient` /
885
+ `AsyncLLMClient` / `SolanaLLMClient`:
886
+
887
+ ```python
888
+ client = LLMClient()
889
+
890
+ protocols = client.defi_protocols() # all protocols + TVL
891
+ aave = client.defi_protocol("aave") # one protocol + historical TVL
892
+ chains = client.defi_chains() # TVL by chain
893
+ pools = client.defi_yields() # yield pools (APY/TVL)
894
+ prices = client.defi_prices(["coingecko:bitcoin", "base:0x833589..."])
895
+
896
+ # Generic escape hatch
897
+ data = client.defi("protocol/uniswap-v3")
898
+ ```
899
+
900
+ ## DEX Swaps (Powered by 0x)
901
+
902
+ Free passthrough to the 0x Swap + Gasless APIs — **no x402 payment**
903
+ (BlockRun takes an on-chain affiliate fee on executed swaps instead).
904
+
905
+ ```python
906
+ # Indicative price, then firm quote (Permit2)
907
+ price = client.dex_price(chainId=8453, sellToken="0x...", buyToken="0x...",
908
+ sellAmount="1000000")
909
+ quote = client.dex_quote(chainId=8453, sellToken="0x...", buyToken="0x...",
910
+ sellAmount="1000000", taker="0xYourWallet")
911
+
912
+ # Gasless flow: quote -> sign trade.eip712 -> submit -> poll
913
+ gq = client.dex_gasless_quote(chainId=8453, sellToken="0x...",
914
+ buyToken="0x...", sellAmount="1000000",
915
+ taker="0xYourWallet")
916
+ res = client.dex_gasless_submit({"trade": {...signed...}})
917
+ status = client.dex_gasless_status(res["tradeHash"])
918
+
919
+ client.dex_chains() # supported swap chains
920
+ client.dex_gasless_chains() # supported gasless chains
921
+ ```
922
+
923
+ ## Cloud Compute (Powered by Modal)
924
+
925
+ Pay-per-call sandboxed compute — create a sandbox, run commands, tear it
926
+ down. $0.01/create (CPU; $0.05 with GPU), $0.001 per exec/status/terminate.
927
+
928
+ ```python
929
+ sb = client.modal_sandbox_create(image="python:3.11")
930
+ out = client.modal_sandbox_exec(sb["sandbox_id"], ["python", "-c", "print(40+2)"])
931
+ print(out["stdout"]) # 42
932
+ client.modal_sandbox_terminate(sb["sandbox_id"])
933
+ ```
934
+
935
+ ## Fund a Wallet with Fiat (Coinbase Onramp)
936
+
937
+ Mint a one-time `pay.coinbase.com` link to buy Base USDC with a card or bank
938
+ (60+ fiat currencies) — **FREE** (no x402 payment). The signature only
939
+ authenticates the wallet, so the funding address **must equal the signing
940
+ wallet**. Base / USDC only. The returned URL is single-use and expires in
941
+ ~5 min, so mint it at click time and never cache it.
942
+
943
+ ```python
944
+ link = client.onramp(client.get_wallet_address())
945
+ print(link["url"]) # https://pay.coinbase.com/... — open to buy USDC on Base
946
+ ```
947
+
948
+ ## Prediction Markets (Powered by Predexon v2)
949
+
950
+ Access real-time prediction market data from Polymarket, Kalshi, Limitless, sports, and Binance Futures via [Predexon](https://predexon.com). No API keys needed — pay-per-request via x402. Tier 1 endpoints are $0.001/call, Tier 2 (wallet identity / clustering) are $0.005/call.
951
+
952
+ Each method below is available on `LLMClient` (Base), `AsyncLLMClient`, and `SolanaLLMClient`.
953
+
954
+ ### Typed helpers
955
+
956
+ | Method | Endpoint | Tier |
957
+ |---|---|---|
958
+ | `pm_markets(**filters)` | canonical cross-venue markets | 1 |
959
+ | `pm_listings(**filters)` | venue-native executable listings | 1 |
960
+ | `pm_outcome(predexon_id)` | resolve a canonical outcome | 1 |
961
+ | `pm_polymarket_markets(**filters)` | Polymarket markets (offset pagination) | 1 |
962
+ | `pm_polymarket_events(**filters)` | Polymarket events (offset pagination) | 1 |
963
+ | `pm_polymarket_markets_keyset(**filters)` | Polymarket markets, cursor pagination | 1 |
964
+ | `pm_polymarket_events_keyset(**filters)` | Polymarket events, cursor pagination | 1 |
965
+ | `pm_polymarket_positions(**filters)` | per-wallet open positions + PnL | 1 |
966
+ | `pm_polymarket_trades(**filters)` | recent trades (token, side, price, tx_hash) | 1 |
967
+ | `pm_polymarket_leaderboard(**filters)` | trader leaderboard (window, sort_by) | 1 |
968
+ | `pm_kalshi_markets(**filters)` | Kalshi event contracts | 1 |
969
+ | `pm_limitless_markets(**filters)` | Limitless binary AMM markets | 1 |
970
+ | `pm_sports_categories()` | available sports categories | 1 |
971
+ | `pm_sports_markets(**filters)` | sports markets grouped by game | 1 |
972
+ | `pm_wallet_identity(wallet)` | identity + profile for one wallet | 2 |
973
+ | `pm_wallet_identities(addresses)` | bulk identity for ≤200 wallets (POST) | 2 |
974
+ | `pm_wallet_cluster(address)` | on-chain transfer + identity-proof cluster | 2 |
975
+
976
+ ```python
977
+ from bridgenode_llm import LLMClient
978
+
979
+ client = LLMClient()
980
+
981
+ # Canonical cross-venue snapshot
982
+ markets = client.pm_markets(status="active", limit=20)
983
+ listings = client.pm_listings(venue="polymarket", limit=20)
984
+
985
+ # Polymarket
986
+ events = client.pm_polymarket_events(limit=10)
987
+ positions = client.pm_polymarket_positions(user="0xABC123...")
988
+ top = client.pm_polymarket_leaderboard(window="7d", sort_by="pnl", limit=10)
989
+
990
+ # Sports + Kalshi + Limitless
991
+ games = client.pm_sports_markets(league="NBA", limit=10)
992
+ kalshi = client.pm_kalshi_markets(limit=10)
993
+ limitless = client.pm_limitless_markets(limit=10)
994
+
995
+ # Wallet identity (Tier 2)
996
+ profile = client.pm_wallet_identity("0xABC123...")
997
+ batch = client.pm_wallet_identities(["0xABC...", "0xDEF..."])
998
+ cluster = client.pm_wallet_cluster("0xABC123...")
999
+ ```
1000
+
1001
+ ### Generic passthrough
1002
+
1003
+ For endpoints without a typed helper, drop down to `pm()` (GET) or `pm_query()`
1004
+ (POST). Same pricing tiers, same return shape:
1005
+
1006
+ ```python
1007
+ candles = client.pm("polymarket/candlesticks/0x1234abcd...") # OHLCV
1008
+ btc = client.pm("binance/candles/BTCUSDT") # crypto candles
1009
+ pairs = client.pm("matching-markets/pairs") # cross-platform pairs
1010
+ ```
1011
+
1012
+ ## Exa Web Search (Powered by Exa)
1013
+
1014
+ Access [Exa](https://exa.ai)'s neural web search via x402. No API keys needed — pay-per-request in USDC. Available on both `LLMClient` (Base, recommended) and `SolanaLLMClient` (Solana).
1015
+
1016
+ | Endpoint | Method | Price |
1017
+ |---|---|---|
1018
+ | `exa_search` | Neural/keyword web search | $0.01/request |
1019
+ | `exa_find_similar` | Find semantically similar pages | $0.01/request |
1020
+ | `exa_contents` | Extract full text from URLs | $0.002/URL |
1021
+ | `exa_answer` | AI answer grounded in web search | $0.01/request |
1022
+
1023
+ ```python
1024
+ from bridgenode_llm import LLMClient
1025
+
1026
+ client = LLMClient() # uses BRIDGENODE_WALLET_KEY (Base USDC)
1027
+
1028
+ # Neural web search ($0.01/request)
1029
+ results = client.exa_search("latest AI safety research", numResults=5)
1030
+ results = client.exa_search("bitcoin ETF news", category="news", numResults=10)
1031
+
1032
+ # Find similar pages ($0.01/request)
1033
+ similar = client.exa_find_similar("https://openai.com/research/gpt-4", numResults=5)
1034
+
1035
+ # Extract content from URLs ($0.002/URL)
1036
+ content = client.exa_contents(["https://arxiv.org/abs/2303.08774"])
1037
+ content = client.exa_contents(
1038
+ ["https://example.com/page1", "https://example.com/page2"],
1039
+ text=True,
1040
+ highlights=True,
1041
+ )
1042
+
1043
+ # AI-generated answer from live web ($0.01/request)
1044
+ answer = client.exa_answer("What is the current state of AI safety research?")
1045
+
1046
+ # Generic proxy for any Exa endpoint
1047
+ result = client.exa("search", {"query": "transformer architecture", "numResults": 5})
1048
+ ```
1049
+
1050
+ For Solana payments use `from bridgenode_llm import SolanaLLMClient` — same method
1051
+ names, same call shape; the Solana gateway requires the backend to be configured
1052
+ with `EXA_API_KEY`, so prefer Base unless you need SOL/SPL settlement.
1053
+
1054
+ ## Standalone Search
1055
+
1056
+ Search web, X/Twitter, and news without using a chat model:
1057
+
1058
+ ```python
1059
+ from bridgenode_llm import LLMClient
1060
+
1061
+ client = LLMClient()
1062
+
1063
+ result = client.search("latest AI agent frameworks 2026")
1064
+ print(result.summary)
1065
+ for cite in result.citations or []:
1066
+ print(f" - {cite}")
1067
+
1068
+ # Filter by source type and date range
1069
+ result = client.search(
1070
+ "BlockRun x402",
1071
+ sources=["web", "x"],
1072
+ from_date="2026-01-01",
1073
+ max_results=5,
1074
+ )
1075
+ ```
1076
+
1077
+ ## Image Editing (img2img)
1078
+
1079
+ Edit existing images with text prompts. The source `image` must be a
1080
+ `data:image/...;base64,...` data URI (plain URLs are not accepted):
1081
+
1082
+ ```python
1083
+ from bridgenode_llm import LLMClient, ImageClient
1084
+
1085
+ # Via LLMClient
1086
+ client = LLMClient()
1087
+ result = client.image_edit(
1088
+ prompt="Make the sky purple and add northern lights",
1089
+ image="data:image/png;base64,...", # base64 data URI
1090
+ model="openai/gpt-image-1",
1091
+ )
1092
+ print(result.data[0].url)
1093
+
1094
+ # Via ImageClient
1095
+ img_client = ImageClient()
1096
+ result = img_client.edit("Add a rainbow", image="data:image/png;base64,...")
1097
+
1098
+ # Multi-image fusion — pass a list of data URIs (e.g. a reference + a logo).
1099
+ # openai/* accepts up to 4 source images, google/* up to 3.
1100
+ result = img_client.edit(
1101
+ "Place the logo on the model's t-shirt",
1102
+ image=["data:image/png;base64,...", "data:image/png;base64,..."],
1103
+ model="google/nano-banana",
1104
+ )
1105
+ print(result.data[0].url)
1106
+ ```
1107
+
1108
+ ## Usage Examples
1109
+
1110
+ ### Simple Chat
1111
+
1112
+ ```python
1113
+ from bridgenode_llm import LLMClient
1114
+
1115
+ client = LLMClient() # Uses BRIDGENODE_WALLET_KEY (never sent to server)
1116
+
1117
+ response = client.chat("openai/gpt-5.2", "Explain quantum computing")
1118
+ print(response)
1119
+
1120
+ # With system prompt
1121
+ response = client.chat(
1122
+ "anthropic/claude-sonnet-4.6",
1123
+ "Write a haiku",
1124
+ system="You are a creative poet."
1125
+ )
1126
+ ```
1127
+
1128
+ ### JSON Mode & Stop Sequences
1129
+
1130
+ `response_format` and `stop` are OpenAI-compatible and honored across **all** providers by
1131
+ the gateway — native for OpenAI/Azure, and emulated for Anthropic/Bedrock (a raw-JSON system
1132
+ instruction with code-fence stripping for JSON mode, `stop` mapped to `stop_sequences`).
1133
+
1134
+ ```python
1135
+ import json
1136
+ from bridgenode_llm import LLMClient
1137
+
1138
+ client = LLMClient()
1139
+
1140
+ # JSON mode — guaranteed parseable JSON, no markdown fences
1141
+ response = client.chat(
1142
+ "openai/gpt-4o",
1143
+ "List 3 primary colors as a JSON array under key 'colors'.",
1144
+ response_format={"type": "json_object"},
1145
+ )
1146
+ print(json.loads(response)) # {'colors': ['red', 'green', 'blue']}
1147
+
1148
+ # Stop sequences (str or list, up to 4)
1149
+ result = client.chat_completion(
1150
+ "openai/gpt-5.2",
1151
+ [{"role": "user", "content": "Count: Alpha Beta Gamma"}],
1152
+ stop=["Beta"],
1153
+ )
1154
+ print(result.choices[0].message.content) # "Count: Alpha "
1155
+ ```
1156
+
1157
+ ### Real-time Search (Live Search)
1158
+
1159
+ **Note:** Live Search can take 30-120+ seconds as it searches multiple sources. The SDK automatically uses a 5-minute timeout for search requests.
1160
+
1161
+ ```python
1162
+ from bridgenode_llm import LLMClient
1163
+
1164
+ client = LLMClient()
1165
+
1166
+ # Simple: Enable live search with search=True (default 10 sources, ~$0.26)
1167
+ response = client.chat(
1168
+ "openai/gpt-5.2",
1169
+ "What are the latest posts from @blockrunai?",
1170
+ search=True
1171
+ )
1172
+ print(response)
1173
+
1174
+ # Custom: Limit sources to reduce cost (5 sources, ~$0.13)
1175
+ response = client.chat(
1176
+ "openai/gpt-5.2",
1177
+ "What's trending on X?",
1178
+ search_parameters={"mode": "on", "max_search_results": 5}
1179
+ )
1180
+
1181
+ # Custom timeout (if 5 min isn't enough)
1182
+ client = LLMClient(search_timeout=600.0) # 10 minutes
1183
+ ```
1184
+
1185
+ ### Check Spending
1186
+
1187
+ ```python
1188
+ from bridgenode_llm import LLMClient
1189
+
1190
+ client = LLMClient()
1191
+
1192
+ response = client.chat("openai/gpt-5.2", "Explain quantum computing")
1193
+ print(response)
1194
+
1195
+ # Check how much was spent
1196
+ spending = client.get_spending()
1197
+ print(f"Spent ${spending['total_usd']:.4f} across {spending['calls']} calls")
1198
+ ```
1199
+
1200
+ ### Full Chat Completion
1201
+
1202
+ ```python
1203
+ from bridgenode_llm import LLMClient
1204
+
1205
+ client = LLMClient() # Uses BRIDGENODE_WALLET_KEY (never sent to server)
1206
+
1207
+ messages = [
1208
+ {"role": "system", "content": "You are a helpful assistant."},
1209
+ {"role": "user", "content": "How do I read a file in Python?"}
1210
+ ]
1211
+
1212
+ result = client.chat_completion("openai/gpt-5.2", messages)
1213
+ print(result.choices[0].message.content)
1214
+ ```
1215
+
1216
+ ### Async Usage
1217
+
1218
+ ```python
1219
+ import asyncio
1220
+ from bridgenode_llm import AsyncLLMClient
1221
+
1222
+ async def main():
1223
+ async with AsyncLLMClient() as client:
1224
+ # Simple chat
1225
+ response = await client.chat("openai/gpt-5.2", "Hello!")
1226
+ print(response)
1227
+
1228
+ # Multiple requests concurrently
1229
+ tasks = [
1230
+ client.chat("openai/gpt-5.2", "What is 2+2?"),
1231
+ client.chat("anthropic/claude-sonnet-4.6", "What is 3+3?"),
1232
+ client.chat("google/gemini-2.5-flash", "What is 4+4?"),
1233
+ ]
1234
+ responses = await asyncio.gather(*tasks)
1235
+ for r in responses:
1236
+ print(r)
1237
+
1238
+ asyncio.run(main())
1239
+ ```
1240
+
1241
+ ### List Available Models
1242
+
1243
+ ```python
1244
+ from bridgenode_llm import LLMClient
1245
+
1246
+ client = LLMClient()
1247
+ models = client.list_models()
1248
+
1249
+ for model in models:
1250
+ print(f"{model['id']}: ${model['inputPrice']}/M input, ${model['outputPrice']}/M output")
1251
+ ```
1252
+
1253
+ ## Testnet Usage
1254
+
1255
+ For development and testing without real USDC, use the testnet:
1256
+
1257
+ ```python
1258
+ from bridgenode_llm import testnet_client
1259
+
1260
+ # Create testnet client (uses Base Sepolia)
1261
+ client = testnet_client() # Uses BRIDGENODE_WALLET_KEY
1262
+
1263
+ # Chat with testnet model
1264
+ response = client.chat("openai/gpt-oss-20b", "Hello!")
1265
+ print(response)
1266
+
1267
+ # Check testnet USDC balance
1268
+ balance = client.get_balance()
1269
+ print(f"Testnet USDC: ${balance:.4f}")
1270
+ ```
1271
+
1272
+ ### Testnet Setup
1273
+
1274
+ 1. Get testnet ETH from [Alchemy Base Sepolia Faucet](https://www.alchemy.com/faucets/base-sepolia)
1275
+ 2. Get testnet USDC from [Circle USDC Faucet](https://faucet.circle.com/)
1276
+ 3. Set your wallet key: `export BRIDGENODE_WALLET_KEY=0x...`
1277
+
1278
+ ### Available Testnet Models
1279
+
1280
+ - `openai/gpt-oss-20b` - $0.001/request (flat price)
1281
+ - `openai/gpt-oss-120b` - $0.002/request (flat price)
1282
+
1283
+ ### Manual Testnet Configuration
1284
+
1285
+ ```python
1286
+ from bridgenode_llm import LLMClient
1287
+
1288
+ # Or configure manually
1289
+ client = LLMClient(api_url="https://testnet.bridgenode.cc/api")
1290
+ response = client.chat("openai/gpt-oss-20b", "Hello!")
1291
+ ```
1292
+
1293
+ ## Billing & Cost Tracking
1294
+
1295
+ Every paid call appends one line to `~/.blockrun/cost_log.jsonl` capturing
1296
+ timestamp, endpoint, cost, and (when available) `model`, `wallet`, `network`,
1297
+ and `client_kind`. The SDK ships a small reader / exporter on top so you can
1298
+ audit spending without leaving the Python ecosystem.
1299
+
1300
+ ### CLI
1301
+
1302
+ ```bash
1303
+ # Aggregated summary, default grouped by endpoint
1304
+ python -m bridgenode_llm.billing summary
1305
+
1306
+ # Group by model / month / wallet / network / client_kind / day
1307
+ python -m bridgenode_llm.billing summary --group-by model
1308
+ python -m bridgenode_llm.billing summary --group-by month --from 2026-04-01
1309
+
1310
+ # Filter by wallet (when one machine drives multiple keys)
1311
+ python -m bridgenode_llm.billing summary --wallet 0xCC8c... --network base-mainnet
1312
+
1313
+ # Export per-call records
1314
+ python -m bridgenode_llm.billing export csv --from 2026-05-01 --output may.csv
1315
+ python -m bridgenode_llm.billing export json --to 2026-05-09
1316
+ ```
1317
+
1318
+ ### Python API
1319
+
1320
+ ```python
1321
+ from bridgenode_llm import (
1322
+ get_cost_log_summary,
1323
+ export_cost_log_csv,
1324
+ export_cost_log_json,
1325
+ )
1326
+
1327
+ summary = get_cost_log_summary(group_by="model", from_date="2026-04-01")
1328
+ print(summary["total_usd"], summary["calls"])
1329
+ for model, slot in summary["groups"].items():
1330
+ print(f" {model:40s} {slot['calls']:>5} ${slot['cost_usd']:.4f}")
1331
+
1332
+ # Returns CSV / JSON text; pass output_path to also write to disk
1333
+ csv_text = export_cost_log_csv("bill.csv", from_date="2026-05-01")
1334
+ json_text = export_cost_log_json(from_date="2026-05-01")
1335
+ ```
1336
+
1337
+ ### Example output
1338
+
1339
+ Real session — four cheap chat calls across providers, then queried by model:
1340
+
1341
+ ```
1342
+ $ python -m bridgenode_llm.billing summary --from 2026-05-10 --group-by model
1343
+ ================================================================
1344
+ BLOCKRUN — LOCAL COST LOG SUMMARY
1345
+ ================================================================
1346
+ log file : /Users/me/.blockrun/cost_log.jsonl
1347
+ from : 2026-05-10
1348
+ group_by : model
1349
+ total : $0.0070 (9 calls)
1350
+
1351
+ KEY CALLS COST
1352
+ ---------------------------- ------- ----------
1353
+ deepseek/deepseek-chat 2 $0.0020
1354
+ google/gemini-2.5-flash-lite 1 $0.0010
1355
+ anthropic/claude-haiku-4.5 1 $0.0010
1356
+ zai/glm-5-turbo 1 $0.0010
1357
+ unknown 4 $0.0020
1358
+ ```
1359
+
1360
+ The four `unknown` rows are pre-existing entries from before this release —
1361
+ they had only `{ts, endpoint, cost_usd}` so the model column reads `unknown`.
1362
+ Calls made after upgrading carry the full metadata (wallet / network /
1363
+ client_kind / model). CSV export shows it directly:
1364
+
1365
+ ```
1366
+ $ python -m bridgenode_llm.billing export csv --from 2026-05-10 | head -3
1367
+ ts_iso,endpoint,model,wallet,network,client_kind,cost_usd
1368
+ 2026-05-10T03:38:28.198937+00:00,/v1/chat/completions,deepseek/deepseek-chat,0xCC8c...5EF8,base-mainnet,LLMClient,0.001
1369
+ 2026-05-10T03:38:31.192060+00:00,/v1/chat/completions,google/gemini-2.5-flash-lite,0xCC8c...5EF8,base-mainnet,LLMClient,0.001
1370
+ ```
1371
+
1372
+ ### Scope
1373
+
1374
+ The cost log is per-machine. It records calls made by this Python SDK only —
1375
+ calls from other clients (TS SDK, MCP, raw curl) are not included. For
1376
+ organization-wide billing, query the gateway's authoritative ledger.
1377
+
1378
+ ## Transaction Log (project-local, on-chain match)
1379
+
1380
+ The cost log above lives in `~/.blockrun/` and is hash-keyed JSON. When you'd
1381
+ rather have an **eyeballable text log next to your code** that matches the
1382
+ chain row-for-row, opt into the per-transaction log:
1383
+
1384
+ ```python
1385
+ from bridgenode_llm import LLMClient
1386
+
1387
+ # Default: writes ./log/transactions.log
1388
+ client = LLMClient(transaction_log=True)
1389
+
1390
+ # Or pick a path
1391
+ client = LLMClient(transaction_log="./var/blockrun.log")
1392
+
1393
+ # Or via env var: BRIDGENODE_TX_LOG=1 (default dir)
1394
+ # BRIDGENODE_TX_LOG=./var/blockrun.log
1395
+ ```
1396
+
1397
+ Works the same on `AsyncLLMClient`, `SolanaLLMClient`, and `AsyncSolanaLLMClient`.
1398
+
1399
+ Every paid call appends one row. Example:
1400
+
1401
+ ```
1402
+ 2026-05-21 15:44:46 chat anthropic/claude-sonnet-4.6 in= 3 out=4 $0.034137 0x6513d128…
1403
+ 2026-05-20 04:34:17 chat openai/gpt-5.5 in= 14 out=18 $0.001000 0x421796a3…
1404
+ ```
1405
+
1406
+ Columns: timestamp · endpoint tag (`chat`/`image`/`video`/`search`/…) · model
1407
+ (padded to 30) · `in=` prompt tokens · `out=` completion tokens · `$cost` to
1408
+ 6 decimals · first 10 chars of the **on-chain settlement hash**.
1409
+
1410
+ ### Why it matches the chain
1411
+
1412
+ The hash comes from the `X-PAYMENT-RESPONSE` header the x402 facilitator
1413
+ returns after settlement — Base txs use `transaction`, Solana uses
1414
+ `signature`. Both normalise to the truncated `0x…` / signature shown in
1415
+ the row, so each line is verifiable in one click:
1416
+
1417
+ - Base mainnet → `https://basescan.org/tx/<full hash>`
1418
+ - Solana mainnet → `https://solscan.io/tx/<full signature>`
1419
+
1420
+ Cached / free responses don't hit the chain, so they show `(no-tx)` instead.
1421
+
1422
+ ### Scope and trade-offs
1423
+
1424
+ - **Independent of the cache layer.** Enabling the log does not change
1425
+ `~/.blockrun/cache/`, `~/.blockrun/data/`, or `~/.blockrun/cost_log.jsonl`.
1426
+ - **Best-effort writes.** OSErrors are swallowed; a read-only filesystem can't
1427
+ break a paid call.
1428
+ - **Plain text only.** If you need a structured ledger as well, query
1429
+ `~/.blockrun/cost_log.jsonl` via `bridgenode_llm.billing`.
1430
+
1431
+ ### Programmatic access
1432
+
1433
+ ```python
1434
+ from bridgenode_llm import TransactionLogger, format_row
1435
+
1436
+ # Tail the project log
1437
+ logger = TransactionLogger("./log")
1438
+ for row in logger.entries()[-5:]:
1439
+ print(row)
1440
+
1441
+ # Build your own row (e.g. for tests or custom adapters)
1442
+ print(format_row(
1443
+ endpoint="/v1/chat/completions",
1444
+ model="openai/gpt-5.5",
1445
+ in_tokens=14,
1446
+ out_tokens=18,
1447
+ cost_usd=0.001,
1448
+ tx_hash="0x421796a3deadbeef",
1449
+ ))
1450
+ ```
1451
+
1452
+ ## Environment Variables
1453
+
1454
+ | Variable | Description | Required |
1455
+ |----------|-------------|----------|
1456
+ | `BRIDGENODE_WALLET_KEY` | Your Base chain wallet private key | Yes (or pass to constructor) |
1457
+ | `BRIDGENODE_API_URL` | API endpoint | No (default: https://bridgenode.cc/api) |
1458
+
1459
+ ## Setting Up Your Wallet
1460
+
1461
+ 1. Create a wallet on Base network (Coinbase Wallet, MetaMask, etc.)
1462
+ 2. Get some ETH on Base for gas (small amount, ~$1)
1463
+ 3. Get USDC on Base for API payments
1464
+ 4. Export your private key and set it as `BRIDGENODE_WALLET_KEY`
1465
+
1466
+ ```bash
1467
+ # .env file
1468
+ BRIDGENODE_WALLET_KEY=0x...your_private_key_here
1469
+ ```
1470
+
1471
+ ## Error Handling
1472
+
1473
+ ```python
1474
+ from bridgenode_llm import LLMClient, APIError, PaymentError
1475
+
1476
+ client = LLMClient()
1477
+
1478
+ try:
1479
+ response = client.chat("openai/gpt-5.2", "Hello!")
1480
+ except PaymentError as e:
1481
+ print(f"Payment failed: {e}")
1482
+ # Check your USDC balance
1483
+ except APIError as e:
1484
+ print(f"API error ({e.status_code}): {e}")
1485
+ ```
1486
+
1487
+ ## Testing
1488
+
1489
+ ### Running Unit Tests
1490
+
1491
+ Unit tests do not require API access or funded wallets:
1492
+
1493
+ ```bash
1494
+ pytest tests/unit # Run unit tests only
1495
+ pytest tests/unit --cov # Run with coverage report
1496
+ pytest tests/unit -v # Verbose output
1497
+ ```
1498
+
1499
+ ### Running Integration Tests
1500
+
1501
+ Integration tests call the production API and require:
1502
+ - A funded Base wallet with USDC ($1+ recommended)
1503
+ - `BRIDGENODE_WALLET_KEY` environment variable set
1504
+ - Estimated cost: ~$0.05 per test run
1505
+
1506
+ ```bash
1507
+ export BRIDGENODE_WALLET_KEY=0x...
1508
+ pytest tests/integration # Run integration tests only
1509
+ pytest # Run all tests
1510
+ ```
1511
+
1512
+ Integration tests are automatically skipped if `BRIDGENODE_WALLET_KEY` is not set.
1513
+
1514
+ ## Security
1515
+
1516
+ ### Private Key Safety
1517
+
1518
+ - **Private key stays local**: Your key is only used for signing on your machine
1519
+ - **No custody**: BlockRun never holds your funds
1520
+ - **Verify transactions**: All payments are on-chain and verifiable
1521
+
1522
+ ### Best Practices
1523
+
1524
+ **Private Key Management:**
1525
+ - Use environment variables, never hard-code keys
1526
+ - Use dedicated wallets for API payments (separate from main holdings)
1527
+ - Set spending limits by only funding payment wallets with small amounts
1528
+ - Never commit `.env` files to version control
1529
+ - Rotate keys periodically
1530
+
1531
+ **Input Validation:**
1532
+ The SDK validates all inputs before API requests:
1533
+ - Private keys (format, length, valid hex)
1534
+ - API URLs (HTTPS required for production, HTTP allowed for localhost)
1535
+ - Model names and parameters (ranges for max\_tokens, temperature, top\_p)
1536
+
1537
+ **Error Sanitization:**
1538
+ API errors are automatically sanitized to prevent sensitive information leaks.
1539
+
1540
+ **Monitoring:**
1541
+ ```python
1542
+ address = client.get_wallet_address()
1543
+ print(f"View transactions: https://basescan.org/address/{address}")
1544
+ ```
1545
+
1546
+ **Keep Updated:**
1547
+ ```bash
1548
+ pip install --upgrade blockrun-llm # Get security patches
1549
+ ```
1550
+
1551
+ ## Agent Wallet Setup
1552
+
1553
+ One-line setup for agent runtimes (Claude Code skills, MCP servers, etc.):
1554
+
1555
+ ```python
1556
+ from bridgenode_llm import setup_agent_wallet
1557
+
1558
+ # Auto-creates wallet if none exists, returns ready client
1559
+ client = setup_agent_wallet()
1560
+ response = client.chat("openai/gpt-5.4", "Hello!")
1561
+ ```
1562
+
1563
+ For Solana:
1564
+
1565
+ ```python
1566
+ from bridgenode_llm import setup_agent_solana_wallet
1567
+
1568
+ client = setup_agent_solana_wallet()
1569
+ response = client.chat("anthropic/claude-sonnet-4.6", "Hello!")
1570
+ ```
1571
+
1572
+ Check wallet status:
1573
+
1574
+ ```python
1575
+ from bridgenode_llm import status
1576
+
1577
+ status()
1578
+ # Wallet: 0xCC8c...5EF8
1579
+ # Balance: $5.30 USDC
1580
+ ```
1581
+
1582
+ ## Wallet Discovery and Migration
1583
+
1584
+ The SDK can discover compatible wallets for an explicit, user-confirmed
1585
+ migration. It never automatically makes a discovered provider wallet active:
1586
+
1587
+ ```python
1588
+ from bridgenode_llm.wallet import scan_wallets
1589
+ from bridgenode_llm.solana_wallet import scan_solana_wallets
1590
+
1591
+ # Scans ~/.<dir>/wallet.json for Base wallets
1592
+ base_wallets = scan_wallets()
1593
+
1594
+ # Scans ~/.<dir>/solana-wallet.json
1595
+ sol_wallets = scan_solana_wallets()
1596
+ ```
1597
+
1598
+ `get_or_create_wallet()` always uses `~/.blockrun/.session` (or an explicit
1599
+ wallet environment variable, or the legacy `~/.blockrun/wallet.key`). Review
1600
+ the discovered addresses and import one explicitly if you intend to switch
1601
+ wallets.
1602
+
1603
+ ### Upgrading from a provider wallet
1604
+
1605
+ Earlier versions adopted the most recently written provider wallet
1606
+ automatically. If you relied on that, the first run after upgrading creates a
1607
+ fresh BlockRun wallet and prints the addresses it found, so you can import the
1608
+ one you actually own:
1609
+
1610
+ ```
1611
+ NOTICE: BlockRun created a new wallet, but also found existing wallet(s)
1612
+ belonging to other applications on this system:
1613
+
1614
+ 0x88f9B82462f6C4bf4a0Fb15e5c3971559a316e7f
1615
+ ...
1616
+ ```
1617
+
1618
+ Adopt one deliberately:
1619
+
1620
+ ```python
1621
+ from bridgenode_llm import list_discovered_wallets, import_wallet
1622
+
1623
+ for w in list_discovered_wallets():
1624
+ print(w["address"], "from", w["source"])
1625
+
1626
+ import_wallet("0x88f9B82462f6C4bf4a0Fb15e5c3971559a316e7f")
1627
+ ```
1628
+
1629
+ `import_wallet()` writes your current wallet to
1630
+ `~/.blockrun/.session.backup-<timestamp>` before switching, so adopting a wallet
1631
+ never strands funds in the old one. Solana: `list_discovered_solana_wallets()`
1632
+ and `import_solana_wallet()`.
1633
+
1634
+ Addresses shown are derived from the discovered key itself, and `import_wallet()`
1635
+ matches on that derived address — so a wallet file cannot claim an address it
1636
+ cannot sign for, nor be adopted by one. `list_discovered_wallets()` never returns
1637
+ private keys.
1638
+
1639
+ For a single run without changing anything, use
1640
+ `export BRIDGENODE_WALLET_KEY=<private-key>`.
1641
+
1642
+ ## Response Caching
1643
+
1644
+ The SDK caches responses to avoid duplicate payments:
1645
+
1646
+ ```python
1647
+ from bridgenode_llm import clear_cache
1648
+
1649
+ # Automatic TTLs by endpoint:
1650
+ # - Prediction Markets: 30 minutes
1651
+ # - Search: 15 minutes
1652
+ # - Models: 24 hours
1653
+ # - Chat/Image: no cache (every call is unique)
1654
+
1655
+ # Manual cache management
1656
+ removed = clear_cache() # Remove all cached responses
1657
+ ```
1658
+
1659
+ Per-session spending is also available on any client (see also
1660
+ [Billing & Cost Tracking](#billing--cost-tracking) for the full surface):
1661
+
1662
+ ```python
1663
+ from bridgenode_llm import LLMClient
1664
+
1665
+ client = LLMClient()
1666
+ response = client.chat("openai/gpt-5.2", "Hello!")
1667
+
1668
+ spending = client.get_spending()
1669
+ print(f"Session: ${spending['total_usd']:.4f} across {spending['calls']} calls")
1670
+ ```
1671
+
1672
+ ## Anthropic SDK Compatibility
1673
+
1674
+ Use the official Anthropic Python SDK with BlockRun's API gateway and automatic x402 payments:
1675
+
1676
+ ```bash
1677
+ pip install blockrun-llm[anthropic]
1678
+ ```
1679
+
1680
+ ```python
1681
+ from bridgenode_llm import AnthropicClient
1682
+
1683
+ client = AnthropicClient() # Auto-detects wallet, auto-pays
1684
+
1685
+ response = client.messages.create(
1686
+ model="claude-sonnet-4-6",
1687
+ max_tokens=1024,
1688
+ messages=[{"role": "user", "content": "Hello!"}]
1689
+ )
1690
+ print(response.content[0].text)
1691
+
1692
+ # Works with any BlockRun model in Anthropic format
1693
+ response = client.messages.create(
1694
+ model="openai/gpt-5.4",
1695
+ max_tokens=1024,
1696
+ messages=[{"role": "user", "content": "Hello from GPT!"}]
1697
+ )
1698
+ ```
1699
+
1700
+ The `AnthropicClient` wraps `anthropic.Anthropic` with a custom httpx transport that handles x402 payment signing transparently. Your private key never leaves your machine.
1701
+
1702
+ ## Links
1703
+
1704
+ - [Website](https://bridgenode.cc)
1705
+ - [Documentation](https://github.com/BlockRunAI/awesome-blockrun/tree/main/docs)
1706
+ - [GitHub](https://github.com/blockrunai/blockrun-llm)
1707
+ - [Telegram](https://t.me/+mroQv4-4hGgzOGUx)
1708
+
1709
+ ## Frequently Asked Questions
1710
+
1711
+ ### What is blockrun-llm?
1712
+ blockrun-llm is a Python SDK that provides pay-per-request access to 43+ large language models from OpenAI, Anthropic, Google, DeepSeek, NVIDIA, ZAI, and more. It uses the x402 protocol for automatic USDC micropayments — no API keys, no subscriptions, no vendor lock-in.
1713
+
1714
+ ### How does payment work?
1715
+ When you make an API call, the SDK automatically handles x402 payment. It signs a USDC transaction locally using your wallet private key (which never leaves your machine), and includes the payment proof in the request header. Settlement is non-custodial and instant on Base or Solana.
1716
+
1717
+ ### What is smart routing / ClawRouter?
1718
+ ClawRouter is a built-in smart routing engine that analyzes your request across <!-- br:clawrouter.dimensions -->15<!-- /br:clawrouter.dimensions --> dimensions and automatically picks the cheapest model capable of handling it. Routing happens locally in under 1ms. It can save up to <!-- br:savings.autoVsBaselinePct -->87<!-- /br:savings.autoVsBaselinePct -->% on LLM costs compared to using premium models for every request.
1719
+
1720
+ ### How much does it cost?
1721
+ Pay only for what you use. Prices start at **FREE** (11 NVIDIA-hosted models). Paid models start at $0.10/M tokens. There are no minimums, subscriptions, or monthly fees. $5 in USDC gets you thousands of requests.
1722
+
1723
+ ### Can I use it with Solana?
1724
+ Yes. Install with `pip install blockrun-llm[solana]` and use `SolanaLLMClient` instead of `LLMClient`. Same API, different payment chain.
1725
+
1726
+ ## License
1727
+
1728
+ MIT