@blockrun/clawrouter 0.9.18 → 0.9.20

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.
package/README.md CHANGED
@@ -72,7 +72,7 @@ Choose your routing strategy with `/model <profile>`:
72
72
  **Other shortcuts:**
73
73
 
74
74
  - **Model aliases:** `/model br-sonnet`, `/model grok`, `/model gpt5`, `/model o3`
75
- - **Specific models:** `blockrun/openai/gpt-4o` or `blockrun/anthropic/claude-sonnet-4`
75
+ - **Specific models:** `blockrun/openai/gpt-4o` or `blockrun/anthropic/claude-sonnet-4.6`
76
76
  - **Bring your wallet:** `export BLOCKRUN_WALLET_KEY=0x...`
77
77
 
78
78
  ---
@@ -186,7 +186,7 @@ Compared to **$25/M** for Claude Opus = **92% savings** on a typical workload.
186
186
  | o3-mini | $1.10 | $4.40 | 128K | \* |
187
187
  | **Anthropic** | | | | |
188
188
  | claude-opus-4.5 | $5.00 | $25.00 | 200K | \* |
189
- | claude-sonnet-4 | $3.00 | $15.00 | 200K | \* |
189
+ | claude-sonnet-4.6 | $3.00 | $15.00 | 200K | \* |
190
190
  | claude-haiku-4.5 | $1.00 | $5.00 | 200K | |
191
191
  | **Google** | | | | |
192
192
  | gemini-2.5-pro | $1.25 | $10.00 | 1M | \* |
package/dist/cli.js CHANGED
@@ -38,13 +38,11 @@ var PaymentCache = class {
38
38
 
39
39
  // src/x402.ts
40
40
  var BASE_CHAIN_ID = 8453;
41
- var USDC_BASE = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
42
- var USDC_DOMAIN = {
43
- name: "USD Coin",
44
- version: "2",
45
- chainId: BASE_CHAIN_ID,
46
- verifyingContract: USDC_BASE
47
- };
41
+ var BASE_SEPOLIA_CHAIN_ID = 84532;
42
+ var DEFAULT_TOKEN_NAME = "USD Coin";
43
+ var DEFAULT_TOKEN_VERSION = "2";
44
+ var DEFAULT_NETWORK = "eip155:8453";
45
+ var DEFAULT_MAX_TIMEOUT_SECONDS = 300;
48
46
  var TRANSFER_TYPES = {
49
47
  TransferWithAuthorization: [
50
48
  { name: "from", type: "address" },
@@ -60,18 +58,78 @@ function createNonce() {
60
58
  crypto.getRandomValues(bytes);
61
59
  return `0x${Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("")}`;
62
60
  }
63
- function parsePaymentRequired(headerValue) {
64
- const decoded = atob(headerValue);
61
+ function decodeBase64Json(value) {
62
+ const normalized = value.replace(/-/g, "+").replace(/_/g, "/");
63
+ const padding = (4 - normalized.length % 4) % 4;
64
+ const padded = normalized + "=".repeat(padding);
65
+ const decoded = Buffer.from(padded, "base64").toString("utf8");
65
66
  return JSON.parse(decoded);
66
67
  }
67
- async function createPaymentPayload(privateKey, fromAddress, recipient, amount, resourceUrl) {
68
+ function encodeBase64Json(value) {
69
+ return Buffer.from(JSON.stringify(value), "utf8").toString("base64");
70
+ }
71
+ function parsePaymentRequired(headerValue) {
72
+ return decodeBase64Json(headerValue);
73
+ }
74
+ function normalizeNetwork(network) {
75
+ if (!network || network.trim().length === 0) {
76
+ return DEFAULT_NETWORK;
77
+ }
78
+ return network.trim().toLowerCase();
79
+ }
80
+ function resolveChainId(network) {
81
+ const eip155Match = network.match(/^eip155:(\d+)$/i);
82
+ if (eip155Match) {
83
+ const parsed = Number.parseInt(eip155Match[1], 10);
84
+ if (Number.isFinite(parsed) && parsed > 0) {
85
+ return parsed;
86
+ }
87
+ }
88
+ if (network === "base") return BASE_CHAIN_ID;
89
+ if (network === "base-sepolia") return BASE_SEPOLIA_CHAIN_ID;
90
+ return BASE_CHAIN_ID;
91
+ }
92
+ function parseHexAddress(value) {
93
+ if (!value) return void 0;
94
+ const direct = value.match(/^0x[a-fA-F0-9]{40}$/);
95
+ if (direct) {
96
+ return direct[0];
97
+ }
98
+ const caipSuffix = value.match(/0x[a-fA-F0-9]{40}$/);
99
+ if (caipSuffix) {
100
+ return caipSuffix[0];
101
+ }
102
+ return void 0;
103
+ }
104
+ function requireHexAddress(value, field) {
105
+ const parsed = parseHexAddress(value);
106
+ if (!parsed) {
107
+ throw new Error(`Invalid ${field} in payment requirements: ${String(value)}`);
108
+ }
109
+ return parsed;
110
+ }
111
+ function setPaymentHeaders(headers, payload) {
112
+ headers.set("payment-signature", payload);
113
+ headers.set("x-payment", payload);
114
+ }
115
+ async function createPaymentPayload(privateKey, fromAddress, option, amount, requestUrl, resource) {
116
+ const network = normalizeNetwork(option.network);
117
+ const chainId = resolveChainId(network);
118
+ const recipient = requireHexAddress(option.payTo, "payTo");
119
+ const verifyingContract = requireHexAddress(option.asset, "asset");
120
+ const maxTimeoutSeconds = typeof option.maxTimeoutSeconds === "number" && option.maxTimeoutSeconds > 0 ? Math.floor(option.maxTimeoutSeconds) : DEFAULT_MAX_TIMEOUT_SECONDS;
68
121
  const now = Math.floor(Date.now() / 1e3);
69
122
  const validAfter = now - 600;
70
- const validBefore = now + 300;
123
+ const validBefore = now + maxTimeoutSeconds;
71
124
  const nonce = createNonce();
72
125
  const signature = await signTypedData({
73
126
  privateKey,
74
- domain: USDC_DOMAIN,
127
+ domain: {
128
+ name: option.extra?.name || DEFAULT_TOKEN_NAME,
129
+ version: option.extra?.version || DEFAULT_TOKEN_VERSION,
130
+ chainId,
131
+ verifyingContract
132
+ },
75
133
  types: TRANSFER_TYPES,
76
134
  primaryType: "TransferWithAuthorization",
77
135
  message: {
@@ -86,18 +144,18 @@ async function createPaymentPayload(privateKey, fromAddress, recipient, amount,
86
144
  const paymentData = {
87
145
  x402Version: 2,
88
146
  resource: {
89
- url: resourceUrl,
90
- description: "BlockRun AI API call",
147
+ url: resource?.url || requestUrl,
148
+ description: resource?.description || "BlockRun AI API call",
91
149
  mimeType: "application/json"
92
150
  },
93
151
  accepted: {
94
- scheme: "exact",
95
- network: "eip155:8453",
152
+ scheme: option.scheme,
153
+ network,
96
154
  amount,
97
- asset: USDC_BASE,
98
- payTo: recipient,
99
- maxTimeoutSeconds: 300,
100
- extra: { name: "USD Coin", version: "2" }
155
+ asset: option.asset,
156
+ payTo: option.payTo,
157
+ maxTimeoutSeconds: option.maxTimeoutSeconds,
158
+ extra: option.extra
101
159
  },
102
160
  payload: {
103
161
  signature,
@@ -112,7 +170,7 @@ async function createPaymentPayload(privateKey, fromAddress, recipient, amount,
112
170
  },
113
171
  extensions: {}
114
172
  };
115
- return btoa(JSON.stringify(paymentData));
173
+ return encodeBase64Json(paymentData);
116
174
  }
117
175
  function createPaymentFetch(privateKey) {
118
176
  const account = privateKeyToAccount(privateKey);
@@ -126,12 +184,23 @@ function createPaymentFetch(privateKey) {
126
184
  const paymentPayload = await createPaymentPayload(
127
185
  privateKey,
128
186
  walletAddress,
129
- cached.payTo,
187
+ {
188
+ scheme: cached.scheme,
189
+ network: cached.network,
190
+ asset: cached.asset,
191
+ payTo: cached.payTo,
192
+ maxTimeoutSeconds: cached.maxTimeoutSeconds,
193
+ extra: cached.extra
194
+ },
130
195
  preAuth.estimatedAmount,
131
- url
196
+ url,
197
+ {
198
+ url: cached.resourceUrl,
199
+ description: cached.resourceDescription
200
+ }
132
201
  );
133
202
  const preAuthHeaders = new Headers(init?.headers);
134
- preAuthHeaders.set("payment-signature", paymentPayload);
203
+ setPaymentHeaders(preAuthHeaders, paymentPayload);
135
204
  const response2 = await fetch(input, { ...init, headers: preAuthHeaders });
136
205
  if (response2.status !== 402) {
137
206
  return response2;
@@ -177,17 +246,20 @@ function createPaymentFetch(privateKey) {
177
246
  scheme: option.scheme,
178
247
  network: option.network,
179
248
  extra: option.extra,
180
- maxTimeoutSeconds: option.maxTimeoutSeconds
249
+ maxTimeoutSeconds: option.maxTimeoutSeconds,
250
+ resourceUrl: paymentRequired.resource?.url,
251
+ resourceDescription: paymentRequired.resource?.description
181
252
  });
182
253
  const paymentPayload = await createPaymentPayload(
183
254
  privateKey,
184
255
  walletAddress,
185
- option.payTo,
256
+ option,
186
257
  amount,
187
- url
258
+ url,
259
+ paymentRequired.resource
188
260
  );
189
261
  const retryHeaders = new Headers(init?.headers);
190
- retryHeaders.set("payment-signature", paymentPayload);
262
+ setPaymentHeaders(retryHeaders, paymentPayload);
191
263
  return fetch(input, {
192
264
  ...init,
193
265
  headers: retryHeaders
@@ -1159,7 +1231,7 @@ var DEFAULT_ROUTING_CONFIG = {
1159
1231
  "openai/gpt-5.2",
1160
1232
  // Newer and cheaper input than gpt-4o
1161
1233
  "openai/gpt-4o",
1162
- "anthropic/claude-sonnet-4"
1234
+ "anthropic/claude-sonnet-4.6"
1163
1235
  ]
1164
1236
  },
1165
1237
  REASONING: {
@@ -1212,22 +1284,22 @@ var DEFAULT_ROUTING_CONFIG = {
1212
1284
  "moonshot/kimi-k2.5",
1213
1285
  "google/gemini-2.5-pro",
1214
1286
  "xai/grok-4-0709",
1215
- "anthropic/claude-sonnet-4"
1287
+ "anthropic/claude-sonnet-4.6"
1216
1288
  ]
1217
1289
  },
1218
1290
  COMPLEX: {
1219
1291
  primary: "anthropic/claude-opus-4.6",
1220
1292
  // Best quality for complex tasks
1221
1293
  fallback: [
1222
- "anthropic/claude-opus-4.5",
1223
- "anthropic/claude-sonnet-4",
1224
1294
  "openai/gpt-5.2-codex",
1295
+ "anthropic/claude-opus-4.5",
1296
+ "anthropic/claude-sonnet-4.6",
1225
1297
  "google/gemini-3-pro-preview",
1226
1298
  "moonshot/kimi-k2.5"
1227
1299
  ]
1228
1300
  },
1229
1301
  REASONING: {
1230
- primary: "anthropic/claude-sonnet-4",
1302
+ primary: "anthropic/claude-sonnet-4.6",
1231
1303
  // $3/$15 - best for reasoning/instructions
1232
1304
  fallback: [
1233
1305
  "anthropic/claude-opus-4.6",
@@ -1253,10 +1325,10 @@ var DEFAULT_ROUTING_CONFIG = {
1253
1325
  MEDIUM: {
1254
1326
  primary: "xai/grok-code-fast-1",
1255
1327
  // Code specialist for agentic coding
1256
- fallback: ["moonshot/kimi-k2.5", "anthropic/claude-haiku-4.5", "anthropic/claude-sonnet-4"]
1328
+ fallback: ["moonshot/kimi-k2.5", "anthropic/claude-haiku-4.5", "anthropic/claude-sonnet-4.6"]
1257
1329
  },
1258
1330
  COMPLEX: {
1259
- primary: "anthropic/claude-sonnet-4",
1331
+ primary: "anthropic/claude-sonnet-4.6",
1260
1332
  fallback: [
1261
1333
  "anthropic/claude-opus-4.6",
1262
1334
  // Latest Opus - best agentic
@@ -1266,7 +1338,7 @@ var DEFAULT_ROUTING_CONFIG = {
1266
1338
  ]
1267
1339
  },
1268
1340
  REASONING: {
1269
- primary: "anthropic/claude-sonnet-4",
1341
+ primary: "anthropic/claude-sonnet-4.6",
1270
1342
  // Strong tool use + reasoning for agentic tasks
1271
1343
  fallback: [
1272
1344
  "anthropic/claude-opus-4.6",
@@ -1357,18 +1429,18 @@ function route(prompt, systemPrompt, maxOutputTokens, options) {
1357
1429
  // src/models.ts
1358
1430
  var MODEL_ALIASES = {
1359
1431
  // Claude - short names
1360
- claude: "anthropic/claude-sonnet-4",
1361
- sonnet: "anthropic/claude-sonnet-4",
1432
+ claude: "anthropic/claude-sonnet-4.6",
1433
+ sonnet: "anthropic/claude-sonnet-4.6",
1362
1434
  opus: "anthropic/claude-opus-4.6",
1363
1435
  // Updated to latest Opus 4.6
1364
1436
  "opus-46": "anthropic/claude-opus-4.6",
1365
1437
  "opus-45": "anthropic/claude-opus-4.5",
1366
1438
  haiku: "anthropic/claude-haiku-4.5",
1367
1439
  // Claude - provider/shortname patterns (common in agent frameworks)
1368
- "anthropic/sonnet": "anthropic/claude-sonnet-4",
1440
+ "anthropic/sonnet": "anthropic/claude-sonnet-4.6",
1369
1441
  "anthropic/opus": "anthropic/claude-opus-4.6",
1370
1442
  "anthropic/haiku": "anthropic/claude-haiku-4.5",
1371
- "anthropic/claude": "anthropic/claude-sonnet-4",
1443
+ "anthropic/claude": "anthropic/claude-sonnet-4.6",
1372
1444
  // OpenAI
1373
1445
  gpt: "openai/gpt-4o",
1374
1446
  gpt4: "openai/gpt-4o",
@@ -1564,8 +1636,8 @@ var BLOCKRUN_MODELS = [
1564
1636
  agentic: true
1565
1637
  },
1566
1638
  {
1567
- id: "anthropic/claude-sonnet-4",
1568
- name: "Claude Sonnet 4",
1639
+ id: "anthropic/claude-sonnet-4.6",
1640
+ name: "Claude Sonnet 4.6",
1569
1641
  inputPrice: 3,
1570
1642
  outputPrice: 15,
1571
1643
  contextWindow: 2e5,
@@ -2294,7 +2366,7 @@ var RpcError = class extends Error {
2294
2366
  };
2295
2367
 
2296
2368
  // src/balance.ts
2297
- var USDC_BASE2 = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
2369
+ var USDC_BASE = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
2298
2370
  var CACHE_TTL_MS = 3e4;
2299
2371
  var BALANCE_THRESHOLDS = {
2300
2372
  /** Low balance warning threshold: $1.00 */
@@ -2393,7 +2465,7 @@ var BalanceMonitor = class {
2393
2465
  async fetchBalance() {
2394
2466
  try {
2395
2467
  const balance = await this.client.readContract({
2396
- address: USDC_BASE2,
2468
+ address: USDC_BASE,
2397
2469
  abi: erc20Abi,
2398
2470
  functionName: "balanceOf",
2399
2471
  args: [this.walletAddress]