@blockrun/clawrouter 0.12.62 → 0.12.64

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,257 @@
1
+ # Advanced Features
2
+
3
+ ClawRouter v0.5+ includes intelligent routing features that work automatically.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Response Cache](#response-cache)
8
+ - [Agentic Auto-Detection](#agentic-auto-detection)
9
+ - [Tool Detection](#tool-detection)
10
+ - [Context-Length-Aware Routing](#context-length-aware-routing)
11
+ - [Model Aliases](#model-aliases)
12
+ - [Free Tier Fallback](#free-tier-fallback)
13
+ - [Session Persistence](#session-persistence)
14
+ - [Cost Tracking with /stats](#cost-tracking-with-stats)
15
+
16
+ ---
17
+
18
+ ## Response Cache
19
+
20
+ ClawRouter includes LLM response caching inspired by LiteLLM's caching system. Identical requests return cached responses, saving both cost and latency.
21
+
22
+ **How it works:**
23
+
24
+ ```
25
+ Request: "What is 2+2?"
26
+ First call: → API ($0.001) → Cache response
27
+ Second call: → Cache HIT → Return instantly ($0)
28
+ ```
29
+
30
+ **Features:**
31
+
32
+ | Feature | Default | Description |
33
+ | ------------ | ----------- | -------------------------- |
34
+ | TTL | 10 minutes | Responses expire after TTL |
35
+ | Max size | 200 entries | LRU eviction when full |
36
+ | Item limit | 1MB | Large responses skipped |
37
+ | Auto-enabled | Yes | No config needed |
38
+
39
+ **Cache key generation:**
40
+
41
+ The cache key is a SHA-256 hash of the request body (model + messages + params), with normalization:
42
+
43
+ - Message timestamps stripped (OpenClaw injects `[Mon 2024-01-15 10:30 UTC]`)
44
+ - Keys sorted for consistent hashing
45
+ - Stream mode, user, and request_id fields excluded
46
+
47
+ **Bypass cache:**
48
+
49
+ ```typescript
50
+ // Via header
51
+ fetch("/v1/chat/completions", {
52
+ headers: { "Cache-Control": "no-cache" }
53
+ })
54
+
55
+ // Via body
56
+ {
57
+ "model": "blockrun/auto",
58
+ "cache": false, // or "no_cache": true
59
+ "messages": [...]
60
+ }
61
+ ```
62
+
63
+ **Check cache stats:**
64
+
65
+ ```bash
66
+ curl http://localhost:8402/cache
67
+ ```
68
+
69
+ Response:
70
+
71
+ ```json
72
+ {
73
+ "size": 42,
74
+ "maxSize": 200,
75
+ "hits": 156,
76
+ "misses": 89,
77
+ "evictions": 3,
78
+ "hitRate": "63.7%"
79
+ }
80
+ ```
81
+
82
+ **Configuration:**
83
+
84
+ Response caching is enabled by default with sensible defaults. For advanced tuning, the cache can be configured programmatically:
85
+
86
+ ```typescript
87
+ import { ResponseCache } from "@blockrun/clawrouter";
88
+
89
+ const cache = new ResponseCache({
90
+ maxSize: 500, // Max cached responses
91
+ defaultTTL: 300, // 5 minutes
92
+ maxItemSize: 2_097_152, // 2MB max per item
93
+ enabled: true,
94
+ });
95
+ ```
96
+
97
+ ---
98
+
99
+ ## Agentic Auto-Detection
100
+
101
+ ClawRouter automatically detects multi-step agentic tasks and routes to models optimized for autonomous execution:
102
+
103
+ ```
104
+ "what is 2+2" → gemini-flash (standard)
105
+ "build the project then run tests" → kimi-k2.5 (auto-agentic)
106
+ "fix the bug and make sure it works" → kimi-k2.5 (auto-agentic)
107
+ ```
108
+
109
+ **How it works:**
110
+
111
+ - Detects agentic keywords: file ops ("read", "edit"), execution ("run", "test", "deploy"), iteration ("fix", "debug", "verify")
112
+ - Threshold: 2+ signals triggers auto-switch to agentic tiers
113
+ - No config needed — works automatically
114
+
115
+ **Agentic tier models** (optimized for multi-step autonomy):
116
+
117
+ | Tier | Agentic Model | Why |
118
+ | --------- | ----------------- | ------------------------------ |
119
+ | SIMPLE | claude-haiku-4.5 | Fast + reliable tool use |
120
+ | MEDIUM | kimi-k2.5 | 200+ tool chains, 76% cheaper |
121
+ | COMPLEX | claude-sonnet-4.6 | Best balance for complex tasks |
122
+ | REASONING | kimi-k2.5 | Extended reasoning + execution |
123
+
124
+ ### Force Agentic Mode
125
+
126
+ You can also force agentic mode via config:
127
+
128
+ ```yaml
129
+ # openclaw.yaml
130
+ plugins:
131
+ - id: "@blockrun/clawrouter"
132
+ config:
133
+ routing:
134
+ overrides:
135
+ agenticMode: true # Always use agentic tiers
136
+ ```
137
+
138
+ ---
139
+
140
+ ## Tool Detection
141
+
142
+ When your request includes a `tools` array (function calling), ClawRouter automatically switches to agentic tiers:
143
+
144
+ ```typescript
145
+ // Request with tools → auto-agentic mode
146
+ {
147
+ model: "blockrun/auto",
148
+ messages: [{ role: "user", content: "Check the weather" }],
149
+ tools: [{ type: "function", function: { name: "get_weather", ... } }]
150
+ }
151
+ // → Routes to claude-haiku-4.5 (excellent tool use)
152
+ // → Instead of gemini-flash (may produce malformed tool calls)
153
+ ```
154
+
155
+ **Why this matters:** Some models (like `deepseek-reasoner`) are optimized for chain-of-thought reasoning but can generate malformed tool calls. Tool detection ensures requests with functions go to models proven to handle tool use correctly.
156
+
157
+ ---
158
+
159
+ ## Context-Length-Aware Routing
160
+
161
+ ClawRouter automatically filters out models that can't handle your context size:
162
+
163
+ ```
164
+ 150K token request:
165
+ Full chain: [grok-4-fast (131K), deepseek (128K), kimi (262K), gemini (1M)]
166
+ Filtered: [kimi (262K), gemini (1M)]
167
+ → Skips models that would fail with "context too long" errors
168
+ ```
169
+
170
+ This prevents wasted API calls and faster fallback to capable models.
171
+
172
+ ---
173
+
174
+ ## Model Aliases
175
+
176
+ Use short aliases instead of full model paths:
177
+
178
+ ```bash
179
+ /model free # gpt-oss-120b (FREE!)
180
+ /model br-sonnet # anthropic/claude-sonnet-4.6
181
+ /model br-opus # anthropic/claude-opus-4
182
+ /model br-haiku # anthropic/claude-haiku-4.5
183
+ /model gpt # openai/gpt-4o
184
+ /model gpt5 # openai/gpt-5.2
185
+ /model deepseek # deepseek/deepseek-chat
186
+ /model reasoner # deepseek/deepseek-reasoner
187
+ /model kimi # moonshot/kimi-k2.5
188
+ /model gemini # google/gemini-2.5-pro
189
+ /model flash # google/gemini-2.5-flash
190
+ /model grok # xai/grok-3
191
+ /model grok-fast # xai/grok-4-fast-reasoning
192
+ ```
193
+
194
+ All aliases work with `/model blockrun/xxx` or just `/model xxx`.
195
+
196
+ ---
197
+
198
+ ## Free Tier Fallback
199
+
200
+ When your wallet balance hits $0, ClawRouter automatically falls back to the free model (`gpt-oss-120b`):
201
+
202
+ ```
203
+ Wallet: $0.00
204
+ Request: "Help me write a function"
205
+ → Routes to gpt-oss-120b (FREE)
206
+ → No "insufficient funds" error
207
+ → Keep building while you top up
208
+ ```
209
+
210
+ You'll never get blocked by an empty wallet — the free tier keeps you running.
211
+
212
+ ---
213
+
214
+ ## Session Persistence
215
+
216
+ For multi-turn conversations, ClawRouter pins the model to prevent mid-task switching:
217
+
218
+ ```
219
+ Turn 1: "Build a React component" → claude-sonnet-4.6
220
+ Turn 2: "Add dark mode support" → claude-sonnet-4.6 (pinned)
221
+ Turn 3: "Now add tests" → claude-sonnet-4.6 (pinned)
222
+ ```
223
+
224
+ Sessions are identified by conversation ID and persist for 1 hour of inactivity.
225
+
226
+ ---
227
+
228
+ ## Cost Tracking with /stats
229
+
230
+ Track your savings in real-time:
231
+
232
+ ```bash
233
+ # In any OpenClaw conversation
234
+ /stats
235
+ ```
236
+
237
+ Output:
238
+
239
+ ```
240
+ +============================================================+
241
+ | ClawRouter Usage Statistics |
242
+ +============================================================+
243
+ | Period: last 7 days |
244
+ | Total Requests: 442 |
245
+ | Total Cost: $1.73 |
246
+ | Baseline Cost (Opus): $20.13 |
247
+ | Total Saved: $18.40 (91.4%) |
248
+ +------------------------------------------------------------+
249
+ | Routing by Tier: |
250
+ | SIMPLE =========== 55.0% (243) |
251
+ | MEDIUM ====== 30.8% (136) |
252
+ | COMPLEX = 7.2% (32) |
253
+ | REASONING = 7.0% (31) |
254
+ +============================================================+
255
+ ```
256
+
257
+ Stats are stored locally at `~/.openclaw/blockrun/logs/` and aggregated on demand.
@@ -0,0 +1,380 @@
1
+ # Image Generation & Editing
2
+
3
+ Generate and edit images via BlockRun's image API with x402 micropayments — no API keys, pay per image.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Quick Start](#quick-start)
8
+ - [Models & Pricing](#models--pricing)
9
+ - [API Reference](#api-reference)
10
+ - [POST /v1/images/generations](#post-v1imagesgenerations)
11
+ - [POST /v1/images/image2image](#post-v1imagesimage2image)
12
+ - [Code Examples](#code-examples)
13
+ - [Image Generation](#image-generation-examples)
14
+ - [Image Editing (img2img)](#image-editing-examples)
15
+ - [In-Chat Commands](#in-chat-commands)
16
+ - [Notes](#notes)
17
+
18
+ ---
19
+
20
+ ## Quick Start
21
+
22
+ ClawRouter runs a local proxy on port `8402` that handles x402 payments automatically. Point any OpenAI-compatible client at it:
23
+
24
+ ```bash
25
+ curl -X POST http://localhost:8402/v1/images/generations \
26
+ -H "Content-Type: application/json" \
27
+ -d '{
28
+ "model": "google/nano-banana",
29
+ "prompt": "a golden retriever surfing on a wave",
30
+ "size": "1024x1024",
31
+ "n": 1
32
+ }'
33
+ ```
34
+
35
+ Response:
36
+
37
+ ```json
38
+ {
39
+ "created": 1741460000,
40
+ "data": [
41
+ {
42
+ "url": "https://files.catbox.moe/abc123.png"
43
+ }
44
+ ]
45
+ }
46
+ ```
47
+
48
+ The returned URL is a publicly hosted image, ready to use in Telegram, Discord, or any client.
49
+
50
+ ---
51
+
52
+ ## Models & Pricing
53
+
54
+ | Model ID | Shorthand | Price | Max Size | Provider |
55
+ | -------------------------- | --------------- | ----------- | ---------- | ----------------- |
56
+ | `google/nano-banana` | `nano-banana` | $0.05/image | 1024×1024 | Google Gemini Flash |
57
+ | `google/nano-banana-pro` | `banana-pro` | $0.10/image | 4096×4096 | Google Gemini Pro |
58
+ | `openai/dall-e-3` | `dall-e-3` | $0.04/image | 1792×1024 | OpenAI DALL-E 3 |
59
+ | `openai/gpt-image-1` | `gpt-image` | $0.02/image | 1536×1024 | OpenAI GPT Image |
60
+ | `black-forest/flux-1.1-pro`| `flux` | $0.04/image | 1024×1024 | Black Forest Labs |
61
+
62
+ Default model: `google/nano-banana`.
63
+
64
+ ---
65
+
66
+ ## API Reference
67
+
68
+ ### `POST /v1/images/generations`
69
+
70
+ OpenAI-compatible endpoint. Route via ClawRouter proxy (`http://localhost:8402`) for automatic x402 payment handling.
71
+
72
+ **Request body:**
73
+
74
+ | Field | Type | Required | Description |
75
+ | -------- | -------- | -------- | ------------------------------------------------ |
76
+ | `model` | `string` | Yes | Model ID (see table above) |
77
+ | `prompt` | `string` | Yes | Text description of the image to generate |
78
+ | `size` | `string` | No | Image dimensions, e.g. `"1024x1024"` (default) |
79
+ | `n` | `number` | No | Number of images (default: `1`) |
80
+
81
+ **Response:**
82
+
83
+ ```typescript
84
+ {
85
+ created: number; // Unix timestamp
86
+ data: Array<{
87
+ url: string; // Publicly hosted image URL
88
+ revised_prompt?: string; // Model's rewritten prompt (dall-e-3 only)
89
+ }>;
90
+ }
91
+ ```
92
+
93
+ ### `POST /v1/images/image2image`
94
+
95
+ Edit an existing image using AI. Route via ClawRouter proxy (`http://localhost:8402`) for automatic x402 payment handling.
96
+
97
+ **Request body:**
98
+
99
+ | Field | Type | Required | Description |
100
+ | -------- | -------- | -------- | -------------------------------------------------------------- |
101
+ | `model` | `string` | No | Model ID (default: `openai/gpt-image-1`) |
102
+ | `prompt` | `string` | Yes | Text description of the edit to apply |
103
+ | `image` | `string` | Yes | Source image — see **Image input formats** below |
104
+ | `mask` | `string` | No | Mask image (white = area to edit) — same formats as `image` |
105
+ | `size` | `string` | No | Output dimensions, e.g. `"1024x1024"` (default) |
106
+
107
+ **Image input formats** — the `image` and `mask` fields accept any of:
108
+
109
+ | Format | Example | Description |
110
+ | ------------------- | ------------------------------------ | ---------------------------------------------- |
111
+ | Local file path | `"/Users/me/photo.png"` | Absolute path — ClawRouter reads the file |
112
+ | Home-relative path | `"~/photo.png"` | Expands `~` to home directory |
113
+ | HTTP/HTTPS URL | `"https://example.com/photo.png"` | ClawRouter downloads the image automatically |
114
+ | Base64 data URI | `"data:image/png;base64,iVBOR..."` | Passed through directly (no conversion needed) |
115
+
116
+ Supported image formats: **PNG**, **JPG/JPEG**, **WebP**.
117
+
118
+ **Response:**
119
+
120
+ ```typescript
121
+ {
122
+ created: number; // Unix timestamp
123
+ data: Array<{
124
+ url: string; // Locally cached image URL (http://localhost:8402/images/...)
125
+ revised_prompt?: string; // Model's rewritten prompt
126
+ }>;
127
+ }
128
+ ```
129
+
130
+ ---
131
+
132
+ ## Code Examples
133
+
134
+ ### Image Generation Examples {#image-generation-examples}
135
+
136
+ ### curl
137
+
138
+ ```bash
139
+ # Default model (nano-banana, $0.05)
140
+ curl -X POST http://localhost:8402/v1/images/generations \
141
+ -H "Content-Type: application/json" \
142
+ -d '{
143
+ "model": "google/nano-banana",
144
+ "prompt": "a futuristic city at sunset, cyberpunk style",
145
+ "size": "1024x1024",
146
+ "n": 1
147
+ }'
148
+
149
+ # DALL-E 3 with landscape size ($0.04)
150
+ curl -X POST http://localhost:8402/v1/images/generations \
151
+ -H "Content-Type: application/json" \
152
+ -d '{
153
+ "model": "openai/dall-e-3",
154
+ "prompt": "a serene Japanese garden in autumn",
155
+ "size": "1792x1024",
156
+ "n": 1
157
+ }'
158
+ ```
159
+
160
+ ### TypeScript / Node.js
161
+
162
+ ```typescript
163
+ const response = await fetch("http://localhost:8402/v1/images/generations", {
164
+ method: "POST",
165
+ headers: { "Content-Type": "application/json" },
166
+ body: JSON.stringify({
167
+ model: "google/nano-banana",
168
+ prompt: "a golden retriever surfing on a wave",
169
+ size: "1024x1024",
170
+ n: 1,
171
+ }),
172
+ });
173
+
174
+ const result = await response.json() as {
175
+ created: number;
176
+ data: Array<{ url: string; revised_prompt?: string }>;
177
+ };
178
+
179
+ const imageUrl = result.data[0].url;
180
+ console.log(imageUrl); // https://files.catbox.moe/xxx.png
181
+ ```
182
+
183
+ ### Python
184
+
185
+ ```python
186
+ import requests
187
+
188
+ response = requests.post(
189
+ "http://localhost:8402/v1/images/generations",
190
+ json={
191
+ "model": "google/nano-banana",
192
+ "prompt": "a golden retriever surfing on a wave",
193
+ "size": "1024x1024",
194
+ "n": 1,
195
+ }
196
+ )
197
+
198
+ result = response.json()
199
+ image_url = result["data"][0]["url"]
200
+ print(image_url)
201
+ ```
202
+
203
+ ### OpenAI SDK (drop-in)
204
+
205
+ ```typescript
206
+ import OpenAI from "openai";
207
+
208
+ const client = new OpenAI({
209
+ apiKey: "blockrun", // any non-empty string
210
+ baseURL: "http://localhost:8402/v1",
211
+ });
212
+
213
+ const response = await client.images.generate({
214
+ model: "google/nano-banana",
215
+ prompt: "a golden retriever surfing on a wave",
216
+ size: "1024x1024",
217
+ n: 1,
218
+ });
219
+
220
+ console.log(response.data[0].url);
221
+ ```
222
+
223
+ ### startProxy (programmatic)
224
+
225
+ If you're using ClawRouter as a library:
226
+
227
+ ```typescript
228
+ import { startProxy } from "@blockrun/clawrouter";
229
+
230
+ const proxy = await startProxy({ walletKey: process.env.BLOCKRUN_WALLET_KEY! });
231
+
232
+ const response = await fetch(`${proxy.baseUrl}/v1/images/generations`, {
233
+ method: "POST",
234
+ headers: { "Content-Type": "application/json" },
235
+ body: JSON.stringify({
236
+ model: "openai/dall-e-3",
237
+ prompt: "a serene Japanese garden in autumn",
238
+ size: "1792x1024",
239
+ n: 1,
240
+ }),
241
+ });
242
+
243
+ const { data } = await response.json();
244
+ console.log(data[0].url);
245
+
246
+ await proxy.close();
247
+ ```
248
+
249
+ ### Image Editing Examples {#image-editing-examples}
250
+
251
+ ### curl
252
+
253
+ ```bash
254
+ # Using a local file path (simplest)
255
+ curl -X POST http://localhost:8402/v1/images/image2image \
256
+ -H "Content-Type: application/json" \
257
+ -d '{
258
+ "prompt": "add sunglasses to the person",
259
+ "image": "~/photo.png"
260
+ }'
261
+
262
+ # Using an image URL
263
+ curl -X POST http://localhost:8402/v1/images/image2image \
264
+ -H "Content-Type: application/json" \
265
+ -d '{
266
+ "prompt": "change the background to a sunset beach",
267
+ "image": "https://example.com/photo.png"
268
+ }'
269
+
270
+ # With a mask (inpainting — white = area to edit)
271
+ curl -X POST http://localhost:8402/v1/images/image2image \
272
+ -H "Content-Type: application/json" \
273
+ -d '{
274
+ "prompt": "replace the background with a starry sky",
275
+ "image": "~/photo.png",
276
+ "mask": "~/mask.png"
277
+ }'
278
+
279
+ # With explicit model, size, and base64 data URI
280
+ curl -X POST http://localhost:8402/v1/images/image2image \
281
+ -H "Content-Type: application/json" \
282
+ -d '{
283
+ "model": "openai/gpt-image-1",
284
+ "prompt": "add a crown",
285
+ "image": "data:image/png;base64,iVBOR...",
286
+ "size": "1536x1024"
287
+ }'
288
+ ```
289
+
290
+ ### TypeScript / Node.js
291
+
292
+ ```typescript
293
+ // ClawRouter reads the file for you — no base64 encoding needed
294
+ const response = await fetch("http://localhost:8402/v1/images/image2image", {
295
+ method: "POST",
296
+ headers: { "Content-Type": "application/json" },
297
+ body: JSON.stringify({
298
+ prompt: "change the background to a starry sky",
299
+ image: "/Users/me/photo.png", // or "~/photo.png" or an HTTPS URL
300
+ }),
301
+ });
302
+
303
+ const result = (await response.json()) as {
304
+ created: number;
305
+ data: Array<{ url: string; revised_prompt?: string }>;
306
+ };
307
+
308
+ console.log(result.data[0].url); // http://localhost:8402/images/xxx.png
309
+ ```
310
+
311
+ ### Python
312
+
313
+ ```python
314
+ import requests
315
+
316
+ response = requests.post(
317
+ "http://localhost:8402/v1/images/image2image",
318
+ json={
319
+ "prompt": "add a hat to the person",
320
+ "image": "~/photo.png", # or an absolute path or HTTPS URL
321
+ },
322
+ )
323
+
324
+ result = response.json()
325
+ print(result["data"][0]["url"])
326
+ ```
327
+
328
+ ---
329
+
330
+ ## In-Chat Commands
331
+
332
+ When using ClawRouter with OpenClaw, generate and edit images directly from any conversation:
333
+
334
+ ### `/imagegen` — Generate images
335
+
336
+ ```
337
+ /imagegen a dog dancing on the beach
338
+ /imagegen --model dall-e-3 a futuristic city at sunset
339
+ /imagegen --model banana-pro --size 2048x2048 mountain landscape
340
+ ```
341
+
342
+ | Flag | Default | Description |
343
+ | --------- | ------------- | --------------------- |
344
+ | `--model` | `nano-banana` | Model shorthand or ID |
345
+ | `--size` | `1024x1024` | Image dimensions |
346
+
347
+ ### `/img2img` — Edit images
348
+
349
+ ```
350
+ /img2img --image ~/photo.png change the background to a starry sky
351
+ /img2img --image ./cat.jpg --mask ./mask.png remove the background
352
+ /img2img --image /tmp/portrait.png --size 1536x1024 add a hat
353
+ ```
354
+
355
+ | Flag | Default | Description |
356
+ | --------- | -------------- | ------------------------------------- |
357
+ | `--image` | _(required)_ | Local image file path (supports `~/`) |
358
+ | `--mask` | _(none)_ | Mask image (white = area to edit) |
359
+ | `--model` | `gpt-image-1` | Model to use |
360
+ | `--size` | `1024x1024` | Output size |
361
+
362
+ ### Model shorthands
363
+
364
+ | Shorthand | Full ID |
365
+ | ------------- | --------------------------- |
366
+ | `nano-banana` | `google/nano-banana` |
367
+ | `banana-pro` | `google/nano-banana-pro` |
368
+ | `dall-e-3` | `openai/dall-e-3` |
369
+ | `gpt-image` | `openai/gpt-image-1` |
370
+ | `flux` | `black-forest/flux-1.1-pro` |
371
+
372
+ ---
373
+
374
+ ## Notes
375
+
376
+ - **Local image caching** — All images (generated and edited) are cached locally at `~/.openclaw/blockrun/images/` and served via `http://localhost:8402/images/`. Both base64 data URIs and HTTP URLs from upstream are downloaded and replaced with localhost URLs.
377
+ - **Payment** — Each image costs the listed price in USDC, deducted from your wallet via x402. Make sure your wallet is funded before generating or editing.
378
+ - **No DALL-E content policy bypass** — DALL-E 3 and GPT Image 1 still apply OpenAI's content policy. Use `flux` or `nano-banana` for more flexibility with generation.
379
+ - **Size limits** — Requesting a size larger than the model's max will return an error. Check the table above before setting `--size`.
380
+ - **Image editing** — The `/v1/images/image2image` endpoint currently supports `openai/gpt-image-1` (default). The `image` and `mask` fields accept local file paths (`~/photo.png`, `/abs/path.png`), HTTP/HTTPS URLs, or base64 data URIs. ClawRouter handles file reading and URL downloading automatically. Supported formats: PNG, JPG/JPEG, WebP.