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
|
+
[](https://pypi.org/project/blockrun-llm/)
|
|
47
|
+
[](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
|