@blockrun/clawrouter 0.4.5 → 0.4.6

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
@@ -256,6 +256,60 @@ If you explicitly want to use a different wallet:
256
256
  2. Set `BLOCKRUN_WALLET_KEY=0x...`
257
257
  3. Restart OpenClaw
258
258
 
259
+ ### Wallet Backup & Recovery
260
+
261
+ Your wallet private key is stored at `~/.openclaw/blockrun/wallet.key`. **Back up this file before terminating any VPS or machine!**
262
+
263
+ #### Using the `/wallet` Command
264
+
265
+ ClawRouter provides a built-in command for wallet management:
266
+
267
+ ```bash
268
+ # Check wallet status (address, balance, file location)
269
+ /wallet
270
+
271
+ # Export private key for backup (shows the actual key)
272
+ /wallet export
273
+ ```
274
+
275
+ The `/wallet export` command displays your private key so you can copy it before terminating a machine.
276
+
277
+ #### Manual Backup
278
+
279
+ ```bash
280
+ # Option 1: Copy the key file
281
+ cp ~/.openclaw/blockrun/wallet.key ~/backup-wallet.key
282
+
283
+ # Option 2: View and copy the key
284
+ cat ~/.openclaw/blockrun/wallet.key
285
+ ```
286
+
287
+ #### Restore on a New Machine
288
+
289
+ ```bash
290
+ # Option 1: Set environment variable (before installing ClawRouter)
291
+ export BLOCKRUN_WALLET_KEY=0x...your_key_here...
292
+ openclaw plugins install @blockrun/clawrouter
293
+
294
+ # Option 2: Create the key file directly
295
+ mkdir -p ~/.openclaw/blockrun
296
+ echo "0x...your_key_here..." > ~/.openclaw/blockrun/wallet.key
297
+ chmod 600 ~/.openclaw/blockrun/wallet.key
298
+ openclaw plugins install @blockrun/clawrouter
299
+ ```
300
+
301
+ **Important:** If a saved wallet file exists, it takes priority over the environment variable. To use a different wallet, delete the existing file first.
302
+
303
+ #### Lost Key Recovery
304
+
305
+ If you lose your wallet key, **there is no way to recover it**. The wallet is self-custodial, meaning only you have the private key. We do not store keys or have any way to restore access.
306
+
307
+ **Prevention tips:**
308
+
309
+ - Run `/wallet export` before terminating any VPS
310
+ - Keep a secure backup of `~/.openclaw/blockrun/wallet.key`
311
+ - For production use, consider using a hardware wallet or key management system
312
+
259
313
  ---
260
314
 
261
315
  ## Architecture
package/dist/index.js CHANGED
@@ -2322,6 +2322,7 @@ async function resolveOrGenerateWalletKey() {
2322
2322
  import { readFileSync, writeFileSync, existsSync, readdirSync, mkdirSync } from "fs";
2323
2323
  import { homedir as homedir3 } from "os";
2324
2324
  import { join as join4 } from "path";
2325
+ import { privateKeyToAccount as privateKeyToAccount4 } from "viem/accounts";
2325
2326
 
2326
2327
  // src/retry.ts
2327
2328
  var DEFAULT_RETRY_CONFIG = {
@@ -2551,6 +2552,81 @@ async function startProxyInBackground(api) {
2551
2552
  activeProxyHandle = proxy;
2552
2553
  api.logger.info(`BlockRun provider active \u2014 ${proxy.baseUrl}/v1 (smart routing enabled)`);
2553
2554
  }
2555
+ async function createWalletCommand() {
2556
+ return {
2557
+ name: "wallet",
2558
+ description: "Show BlockRun wallet info or export private key for backup",
2559
+ acceptsArgs: true,
2560
+ requireAuth: true,
2561
+ handler: async (ctx) => {
2562
+ const subcommand = ctx.args?.trim().toLowerCase() || "status";
2563
+ let walletKey;
2564
+ let address;
2565
+ try {
2566
+ if (existsSync(WALLET_FILE)) {
2567
+ walletKey = readFileSync(WALLET_FILE, "utf-8").trim();
2568
+ if (walletKey.startsWith("0x") && walletKey.length === 66) {
2569
+ const account = privateKeyToAccount4(walletKey);
2570
+ address = account.address;
2571
+ }
2572
+ }
2573
+ } catch {
2574
+ }
2575
+ if (!walletKey || !address) {
2576
+ return {
2577
+ text: `No ClawRouter wallet found.
2578
+
2579
+ Run \`openclaw plugins install @blockrun/clawrouter\` to generate a wallet.`,
2580
+ isError: true
2581
+ };
2582
+ }
2583
+ if (subcommand === "export") {
2584
+ return {
2585
+ text: [
2586
+ "\u{1F510} **ClawRouter Wallet Export**",
2587
+ "",
2588
+ "\u26A0\uFE0F **SECURITY WARNING**: Your private key controls your wallet funds.",
2589
+ "Never share this key. Anyone with this key can spend your USDC.",
2590
+ "",
2591
+ `**Address:** \`${address}\``,
2592
+ "",
2593
+ `**Private Key:**`,
2594
+ `\`${walletKey}\``,
2595
+ "",
2596
+ "**To restore on a new machine:**",
2597
+ "1. Set the environment variable before running OpenClaw:",
2598
+ ` \`export BLOCKRUN_WALLET_KEY=${walletKey}\``,
2599
+ "2. Or save to file:",
2600
+ ` \`mkdir -p ~/.openclaw/blockrun && echo "${walletKey}" > ~/.openclaw/blockrun/wallet.key && chmod 600 ~/.openclaw/blockrun/wallet.key\``
2601
+ ].join("\n")
2602
+ };
2603
+ }
2604
+ let balanceText = "Balance: (checking...)";
2605
+ try {
2606
+ const monitor = new BalanceMonitor(address);
2607
+ const balance = await monitor.checkBalance();
2608
+ balanceText = `Balance: ${balance.balanceUSD}`;
2609
+ } catch {
2610
+ balanceText = "Balance: (could not check)";
2611
+ }
2612
+ return {
2613
+ text: [
2614
+ "\u{1F99E} **ClawRouter Wallet**",
2615
+ "",
2616
+ `**Address:** \`${address}\``,
2617
+ `**${balanceText}**`,
2618
+ `**Key File:** \`${WALLET_FILE}\``,
2619
+ "",
2620
+ "**Commands:**",
2621
+ "\u2022 `/wallet` - Show this status",
2622
+ "\u2022 `/wallet export` - Export private key for backup",
2623
+ "",
2624
+ `**Fund with USDC on Base:** https://basescan.org/address/${address}`
2625
+ ].join("\n")
2626
+ };
2627
+ }
2628
+ };
2629
+ }
2554
2630
  var plugin = {
2555
2631
  id: "clawrouter",
2556
2632
  name: "ClawRouter",
@@ -2590,6 +2666,13 @@ var plugin = {
2590
2666
  if (!defaults.model) defaults.model = {};
2591
2667
  defaults.model.primary = "blockrun/auto";
2592
2668
  api.logger.info("BlockRun provider registered (30+ models via x402)");
2669
+ createWalletCommand().then((walletCommand) => {
2670
+ api.registerCommand(walletCommand);
2671
+ }).catch((err) => {
2672
+ api.logger.warn(
2673
+ `Failed to register /wallet command: ${err instanceof Error ? err.message : String(err)}`
2674
+ );
2675
+ });
2593
2676
  api.registerService({
2594
2677
  id: "clawrouter-proxy",
2595
2678
  start: () => {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/models.ts","../src/provider.ts","../src/proxy.ts","../src/x402.ts","../src/payment-cache.ts","../src/router/rules.ts","../src/router/selector.ts","../src/router/config.ts","../src/router/index.ts","../src/logger.ts","../src/dedup.ts","../src/balance.ts","../src/errors.ts","../src/version.ts","../src/auth.ts","../src/index.ts","../src/retry.ts"],"sourcesContent":["/**\n * BlockRun Model Definitions for OpenClaw\n *\n * Maps BlockRun's 30+ AI models to OpenClaw's ModelDefinitionConfig format.\n * All models use the \"openai-completions\" API since BlockRun is OpenAI-compatible.\n *\n * Pricing is in USD per 1M tokens. Operators pay these rates via x402;\n * they set their own markup when reselling to end users (Phase 2).\n */\n\nimport type { ModelDefinitionConfig, ModelProviderConfig } from \"./types.js\";\n\ntype BlockRunModel = {\n id: string;\n name: string;\n inputPrice: number;\n outputPrice: number;\n contextWindow: number;\n maxOutput: number;\n reasoning?: boolean;\n vision?: boolean;\n};\n\nexport const BLOCKRUN_MODELS: BlockRunModel[] = [\n // Smart routing meta-model — proxy replaces with actual model\n // NOTE: Model IDs are WITHOUT provider prefix (OpenClaw adds \"blockrun/\" automatically)\n {\n id: \"auto\",\n name: \"BlockRun Smart Router\",\n inputPrice: 0,\n outputPrice: 0,\n contextWindow: 1_050_000,\n maxOutput: 128_000,\n },\n\n // OpenAI GPT-5 Family\n {\n id: \"openai/gpt-5.2\",\n name: \"GPT-5.2\",\n inputPrice: 1.75,\n outputPrice: 14.0,\n contextWindow: 400000,\n maxOutput: 128000,\n reasoning: true,\n vision: true,\n },\n {\n id: \"openai/gpt-5-mini\",\n name: \"GPT-5 Mini\",\n inputPrice: 0.25,\n outputPrice: 2.0,\n contextWindow: 200000,\n maxOutput: 65536,\n },\n {\n id: \"openai/gpt-5-nano\",\n name: \"GPT-5 Nano\",\n inputPrice: 0.05,\n outputPrice: 0.4,\n contextWindow: 128000,\n maxOutput: 32768,\n },\n {\n id: \"openai/gpt-5.2-pro\",\n name: \"GPT-5.2 Pro\",\n inputPrice: 21.0,\n outputPrice: 168.0,\n contextWindow: 400000,\n maxOutput: 128000,\n reasoning: true,\n },\n\n // OpenAI GPT-4 Family\n {\n id: \"openai/gpt-4.1\",\n name: \"GPT-4.1\",\n inputPrice: 2.0,\n outputPrice: 8.0,\n contextWindow: 128000,\n maxOutput: 16384,\n vision: true,\n },\n {\n id: \"openai/gpt-4.1-mini\",\n name: \"GPT-4.1 Mini\",\n inputPrice: 0.4,\n outputPrice: 1.6,\n contextWindow: 128000,\n maxOutput: 16384,\n },\n {\n id: \"openai/gpt-4.1-nano\",\n name: \"GPT-4.1 Nano\",\n inputPrice: 0.1,\n outputPrice: 0.4,\n contextWindow: 128000,\n maxOutput: 16384,\n },\n {\n id: \"openai/gpt-4o\",\n name: \"GPT-4o\",\n inputPrice: 2.5,\n outputPrice: 10.0,\n contextWindow: 128000,\n maxOutput: 16384,\n vision: true,\n },\n {\n id: \"openai/gpt-4o-mini\",\n name: \"GPT-4o Mini\",\n inputPrice: 0.15,\n outputPrice: 0.6,\n contextWindow: 128000,\n maxOutput: 16384,\n },\n\n // OpenAI O-series (Reasoning)\n {\n id: \"openai/o1\",\n name: \"o1\",\n inputPrice: 15.0,\n outputPrice: 60.0,\n contextWindow: 200000,\n maxOutput: 100000,\n reasoning: true,\n },\n {\n id: \"openai/o1-mini\",\n name: \"o1-mini\",\n inputPrice: 1.1,\n outputPrice: 4.4,\n contextWindow: 128000,\n maxOutput: 65536,\n reasoning: true,\n },\n {\n id: \"openai/o3\",\n name: \"o3\",\n inputPrice: 2.0,\n outputPrice: 8.0,\n contextWindow: 200000,\n maxOutput: 100000,\n reasoning: true,\n },\n {\n id: \"openai/o3-mini\",\n name: \"o3-mini\",\n inputPrice: 1.1,\n outputPrice: 4.4,\n contextWindow: 128000,\n maxOutput: 65536,\n reasoning: true,\n },\n // o4-mini: Placeholder removed - model not yet released by OpenAI\n\n // Anthropic\n {\n id: \"anthropic/claude-haiku-4.5\",\n name: \"Claude Haiku 4.5\",\n inputPrice: 1.0,\n outputPrice: 5.0,\n contextWindow: 200000,\n maxOutput: 8192,\n },\n {\n id: \"anthropic/claude-sonnet-4\",\n name: \"Claude Sonnet 4\",\n inputPrice: 3.0,\n outputPrice: 15.0,\n contextWindow: 200000,\n maxOutput: 64000,\n reasoning: true,\n },\n {\n id: \"anthropic/claude-opus-4\",\n name: \"Claude Opus 4\",\n inputPrice: 15.0,\n outputPrice: 75.0,\n contextWindow: 200000,\n maxOutput: 32000,\n reasoning: true,\n },\n {\n id: \"anthropic/claude-opus-4.5\",\n name: \"Claude Opus 4.5\",\n inputPrice: 5.0,\n outputPrice: 25.0,\n contextWindow: 200000,\n maxOutput: 32000,\n reasoning: true,\n },\n\n // Google\n {\n id: \"google/gemini-3-pro-preview\",\n name: \"Gemini 3 Pro Preview\",\n inputPrice: 2.0,\n outputPrice: 12.0,\n contextWindow: 1050000,\n maxOutput: 65536,\n reasoning: true,\n vision: true,\n },\n {\n id: \"google/gemini-2.5-pro\",\n name: \"Gemini 2.5 Pro\",\n inputPrice: 1.25,\n outputPrice: 10.0,\n contextWindow: 1050000,\n maxOutput: 65536,\n reasoning: true,\n vision: true,\n },\n {\n id: \"google/gemini-2.5-flash\",\n name: \"Gemini 2.5 Flash\",\n inputPrice: 0.15,\n outputPrice: 0.6,\n contextWindow: 1000000,\n maxOutput: 65536,\n },\n\n // DeepSeek\n {\n id: \"deepseek/deepseek-chat\",\n name: \"DeepSeek V3.2 Chat\",\n inputPrice: 0.28,\n outputPrice: 0.42,\n contextWindow: 128000,\n maxOutput: 8192,\n },\n {\n id: \"deepseek/deepseek-reasoner\",\n name: \"DeepSeek V3.2 Reasoner\",\n inputPrice: 0.28,\n outputPrice: 0.42,\n contextWindow: 128000,\n maxOutput: 8192,\n reasoning: true,\n },\n\n // Moonshot / Kimi\n {\n id: \"moonshot/kimi-k2.5\",\n name: \"Kimi K2.5\",\n inputPrice: 0.5,\n outputPrice: 2.4,\n contextWindow: 262144,\n maxOutput: 8192,\n reasoning: true,\n vision: true,\n },\n\n // xAI / Grok\n {\n id: \"xai/grok-3\",\n name: \"Grok 3\",\n inputPrice: 3.0,\n outputPrice: 15.0,\n contextWindow: 131072,\n maxOutput: 16384,\n reasoning: true,\n },\n {\n id: \"xai/grok-3-fast\",\n name: \"Grok 3 Fast\",\n inputPrice: 5.0,\n outputPrice: 25.0,\n contextWindow: 131072,\n maxOutput: 16384,\n reasoning: true,\n },\n {\n id: \"xai/grok-3-mini\",\n name: \"Grok 3 Mini\",\n inputPrice: 0.3,\n outputPrice: 0.5,\n contextWindow: 131072,\n maxOutput: 16384,\n },\n];\n\n/**\n * Convert BlockRun model definitions to OpenClaw ModelDefinitionConfig format.\n */\nfunction toOpenClawModel(m: BlockRunModel): ModelDefinitionConfig {\n return {\n id: m.id,\n name: m.name,\n api: \"openai-completions\",\n reasoning: m.reasoning ?? false,\n input: m.vision ? [\"text\", \"image\"] : [\"text\"],\n cost: {\n input: m.inputPrice,\n output: m.outputPrice,\n cacheRead: 0,\n cacheWrite: 0,\n },\n contextWindow: m.contextWindow,\n maxTokens: m.maxOutput,\n };\n}\n\n/**\n * All BlockRun models in OpenClaw format.\n */\nexport const OPENCLAW_MODELS: ModelDefinitionConfig[] = BLOCKRUN_MODELS.map(toOpenClawModel);\n\n/**\n * Build a ModelProviderConfig for BlockRun.\n *\n * @param baseUrl - The proxy's local base URL (e.g., \"http://127.0.0.1:12345\")\n */\nexport function buildProviderModels(baseUrl: string): ModelProviderConfig {\n return {\n baseUrl: `${baseUrl}/v1`,\n api: \"openai-completions\",\n models: OPENCLAW_MODELS,\n };\n}\n","/**\n * BlockRun ProviderPlugin for OpenClaw\n *\n * Registers BlockRun as an LLM provider in OpenClaw.\n * Uses a local x402 proxy to handle micropayments transparently —\n * pi-ai sees a standard OpenAI-compatible API at localhost.\n */\n\nimport type { ProviderPlugin } from \"./types.js\";\nimport { buildProviderModels } from \"./models.js\";\nimport type { ProxyHandle } from \"./proxy.js\";\n\n/**\n * State for the running proxy (set when the plugin activates).\n */\nlet activeProxy: ProxyHandle | null = null;\n\n/**\n * Update the proxy handle (called from index.ts when the proxy starts).\n */\nexport function setActiveProxy(proxy: ProxyHandle): void {\n activeProxy = proxy;\n}\n\nexport function getActiveProxy(): ProxyHandle | null {\n return activeProxy;\n}\n\n/**\n * BlockRun provider plugin definition.\n */\nexport const blockrunProvider: ProviderPlugin = {\n id: \"blockrun\",\n label: \"BlockRun\",\n docsPath: \"https://blockrun.ai/docs\",\n aliases: [\"br\"],\n envVars: [\"BLOCKRUN_WALLET_KEY\"],\n\n // Model definitions — dynamically set to proxy URL\n get models() {\n if (!activeProxy) {\n // Fallback: point to BlockRun API directly (won't handle x402, but\n // allows config loading before proxy starts)\n return buildProviderModels(\"https://blockrun.ai/api\");\n }\n return buildProviderModels(activeProxy.baseUrl);\n },\n\n // No auth required — the x402 proxy handles wallet-based payments internally.\n // The proxy auto-generates a wallet on first run and stores it at\n // ~/.openclaw/blockrun/wallet.key. Users just fund that wallet with USDC.\n auth: [],\n};\n","/**\n * Local x402 Proxy Server\n *\n * Sits between OpenClaw's pi-ai (which makes standard OpenAI-format requests)\n * and BlockRun's API (which requires x402 micropayments).\n *\n * Flow:\n * pi-ai → http://localhost:{port}/v1/chat/completions\n * → proxy forwards to https://blockrun.ai/api/v1/chat/completions\n * → gets 402 → @x402/fetch signs payment → retries\n * → streams response back to pi-ai\n *\n * Optimizations (v0.3.0):\n * - SSE heartbeat: for streaming requests, sends headers + heartbeat immediately\n * before the x402 flow, preventing OpenClaw's 10-15s timeout from firing.\n * - Response dedup: hashes request bodies and caches responses for 30s,\n * preventing double-charging when OpenClaw retries after timeout.\n * - Payment cache: after first 402, pre-signs subsequent requests to skip\n * the 402 round trip (~200ms savings per request).\n * - Smart routing: when model is \"blockrun/auto\", classify query and pick cheapest model.\n * - Usage logging: log every request as JSON line to ~/.openclaw/blockrun/logs/\n */\n\nimport { createServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport type { AddressInfo } from \"node:net\";\nimport { privateKeyToAccount } from \"viem/accounts\";\nimport { createPaymentFetch, type PreAuthParams } from \"./x402.js\";\nimport {\n route,\n getFallbackChain,\n DEFAULT_ROUTING_CONFIG,\n type RouterOptions,\n type RoutingDecision,\n type RoutingConfig,\n type ModelPricing,\n} from \"./router/index.js\";\nimport { BLOCKRUN_MODELS } from \"./models.js\";\nimport { logUsage, type UsageEntry } from \"./logger.js\";\nimport { RequestDeduplicator } from \"./dedup.js\";\nimport { BalanceMonitor } from \"./balance.js\";\nimport { InsufficientFundsError, EmptyWalletError } from \"./errors.js\";\nimport { USER_AGENT } from \"./version.js\";\n\nconst BLOCKRUN_API = \"https://blockrun.ai/api\";\nconst AUTO_MODEL = \"blockrun/auto\";\nconst AUTO_MODEL_SHORT = \"auto\"; // OpenClaw strips provider prefix\nconst HEARTBEAT_INTERVAL_MS = 2_000;\nconst DEFAULT_REQUEST_TIMEOUT_MS = 180_000; // 3 minutes (allows for on-chain tx + LLM response)\nconst DEFAULT_PORT = 8402;\nconst MAX_FALLBACK_ATTEMPTS = 3; // Maximum models to try in fallback chain\nconst HEALTH_CHECK_TIMEOUT_MS = 2_000; // Timeout for checking existing proxy\n// Extra buffer for balance check (on top of estimateAmount's 20% buffer)\n// Total effective buffer: 1.2 * 1.5 = 1.8x (80% safety margin)\n// This prevents x402 payment failures after streaming headers are sent,\n// which would trigger OpenClaw's 5-24 hour billing cooldown.\nconst BALANCE_CHECK_BUFFER = 1.5;\n\n/**\n * Get the proxy port from environment variable or default.\n */\nexport function getProxyPort(): number {\n const envPort = process.env.BLOCKRUN_PROXY_PORT;\n if (envPort) {\n const parsed = parseInt(envPort, 10);\n if (!isNaN(parsed) && parsed > 0 && parsed < 65536) {\n return parsed;\n }\n }\n return DEFAULT_PORT;\n}\n\n/**\n * Check if a proxy is already running on the given port.\n * Returns the wallet address if running, undefined otherwise.\n */\nasync function checkExistingProxy(port: number): Promise<string | undefined> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), HEALTH_CHECK_TIMEOUT_MS);\n\n try {\n const response = await fetch(`http://127.0.0.1:${port}/health`, {\n signal: controller.signal,\n });\n clearTimeout(timeoutId);\n\n if (response.ok) {\n const data = (await response.json()) as { status?: string; wallet?: string };\n if (data.status === \"ok\" && data.wallet) {\n return data.wallet;\n }\n }\n return undefined;\n } catch {\n clearTimeout(timeoutId);\n return undefined;\n }\n}\n\n/**\n * Error patterns that indicate a provider-side issue (not user's fault).\n * These errors should trigger fallback to the next model in the chain.\n */\nconst PROVIDER_ERROR_PATTERNS = [\n /billing/i,\n /insufficient.*balance/i,\n /credits/i,\n /quota.*exceeded/i,\n /rate.*limit/i,\n /model.*unavailable/i,\n /model.*not.*available/i,\n /service.*unavailable/i,\n /capacity/i,\n /overloaded/i,\n /temporarily.*unavailable/i,\n /api.*key.*invalid/i,\n /authentication.*failed/i,\n];\n\n/**\n * HTTP status codes that indicate provider issues worth retrying with fallback.\n */\nconst FALLBACK_STATUS_CODES = [\n 400, // Bad request - sometimes used for billing errors\n 401, // Unauthorized - provider API key issues\n 402, // Payment required - but from upstream, not x402\n 403, // Forbidden - provider restrictions\n 429, // Rate limited\n 500, // Internal server error\n 502, // Bad gateway\n 503, // Service unavailable\n 504, // Gateway timeout\n];\n\n/**\n * Check if an error response indicates a provider issue that should trigger fallback.\n */\nfunction isProviderError(status: number, body: string): boolean {\n // Check status code first\n if (!FALLBACK_STATUS_CODES.includes(status)) {\n return false;\n }\n\n // For 5xx errors, always fallback\n if (status >= 500) {\n return true;\n }\n\n // For 4xx errors, check the body for known provider error patterns\n return PROVIDER_ERROR_PATTERNS.some((pattern) => pattern.test(body));\n}\n\n/**\n * Normalize messages for Google models.\n * Google's Gemini API requires the first non-system message to be from \"user\".\n * If conversation starts with \"assistant\"/\"model\", prepend a placeholder user message.\n */\ntype ChatMessage = { role: string; content: string | unknown };\n\nfunction normalizeMessagesForGoogle(messages: ChatMessage[]): ChatMessage[] {\n if (!messages || messages.length === 0) return messages;\n\n // Find first non-system message\n let firstNonSystemIdx = -1;\n for (let i = 0; i < messages.length; i++) {\n if (messages[i].role !== \"system\") {\n firstNonSystemIdx = i;\n break;\n }\n }\n\n // If no non-system messages, return as-is\n if (firstNonSystemIdx === -1) return messages;\n\n const firstRole = messages[firstNonSystemIdx].role;\n\n // If first non-system message is already \"user\", no change needed\n if (firstRole === \"user\") return messages;\n\n // If first non-system message is \"assistant\" or \"model\", prepend a user message\n if (firstRole === \"assistant\" || firstRole === \"model\") {\n const normalized = [...messages];\n normalized.splice(firstNonSystemIdx, 0, {\n role: \"user\",\n content: \"(continuing conversation)\",\n });\n return normalized;\n }\n\n return messages;\n}\n\n/**\n * Check if a model is a Google model that requires message normalization.\n */\nfunction isGoogleModel(modelId: string): boolean {\n return modelId.startsWith(\"google/\") || modelId.startsWith(\"gemini\");\n}\n\n// Kimi/Moonshot models use special Unicode tokens for thinking boundaries.\n// Pattern: <|begin▁of▁thinking|>content<|end▁of▁thinking|>\n// The | is fullwidth vertical bar (U+FF5C), ▁ is lower one-eighth block (U+2581).\n\n// Match full Kimi thinking blocks: <|begin...|>content<|end...|>\nconst KIMI_BLOCK_RE = /<[||][^<>]*begin[^<>]*[||]>[\\s\\S]*?<[||][^<>]*end[^<>]*[||]>/gi;\n\n// Match standalone Kimi tokens like <|end▁of▁thinking|>\nconst KIMI_TOKEN_RE = /<[||][^<>]*[||]>/g;\n\n// Standard thinking tags that may leak through from various models\nconst THINKING_TAG_RE = /<\\s*\\/?\\s*(?:think(?:ing)?|thought|antthinking)\\b[^>]*>/gi;\n\n// Full thinking blocks: <think>content</think>\nconst THINKING_BLOCK_RE =\n /<\\s*(?:think(?:ing)?|thought|antthinking)\\b[^>]*>[\\s\\S]*?<\\s*\\/\\s*(?:think(?:ing)?|thought|antthinking)\\s*>/gi;\n\n/**\n * Strip thinking tokens and blocks from model response content.\n * Handles both Kimi-style Unicode tokens and standard XML-style tags.\n */\nfunction stripThinkingTokens(content: string): string {\n if (!content) return content;\n // Strip full Kimi thinking blocks first (begin...end with content)\n let cleaned = content.replace(KIMI_BLOCK_RE, \"\");\n // Strip remaining standalone Kimi tokens\n cleaned = cleaned.replace(KIMI_TOKEN_RE, \"\");\n // Strip full thinking blocks (<think>...</think>)\n cleaned = cleaned.replace(THINKING_BLOCK_RE, \"\");\n // Strip remaining standalone thinking tags\n cleaned = cleaned.replace(THINKING_TAG_RE, \"\");\n return cleaned;\n}\n\n/** Callback info for low balance warning */\nexport type LowBalanceInfo = {\n balanceUSD: string;\n walletAddress: string;\n};\n\n/** Callback info for insufficient funds error */\nexport type InsufficientFundsInfo = {\n balanceUSD: string;\n requiredUSD: string;\n walletAddress: string;\n};\n\nexport type ProxyOptions = {\n walletKey: string;\n apiBase?: string;\n /** Port to listen on (default: 8402) */\n port?: number;\n routingConfig?: Partial<RoutingConfig>;\n /** Request timeout in ms (default: 180000 = 3 minutes). Covers on-chain tx + LLM response. */\n requestTimeoutMs?: number;\n /** Skip balance checks (for testing only). Default: false */\n skipBalanceCheck?: boolean;\n onReady?: (port: number) => void;\n onError?: (error: Error) => void;\n onPayment?: (info: { model: string; amount: string; network: string }) => void;\n onRouted?: (decision: RoutingDecision) => void;\n /** Called when balance drops below $1.00 (warning, request still proceeds) */\n onLowBalance?: (info: LowBalanceInfo) => void;\n /** Called when balance is insufficient for a request (request fails) */\n onInsufficientFunds?: (info: InsufficientFundsInfo) => void;\n};\n\nexport type ProxyHandle = {\n port: number;\n baseUrl: string;\n walletAddress: string;\n balanceMonitor: BalanceMonitor;\n close: () => Promise<void>;\n};\n\n/**\n * Build model pricing map from BLOCKRUN_MODELS.\n */\nfunction buildModelPricing(): Map<string, ModelPricing> {\n const map = new Map<string, ModelPricing>();\n for (const m of BLOCKRUN_MODELS) {\n if (m.id === AUTO_MODEL) continue; // skip meta-model\n map.set(m.id, { inputPrice: m.inputPrice, outputPrice: m.outputPrice });\n }\n return map;\n}\n\n/**\n * Merge partial routing config overrides with defaults.\n */\nfunction mergeRoutingConfig(overrides?: Partial<RoutingConfig>): RoutingConfig {\n if (!overrides) return DEFAULT_ROUTING_CONFIG;\n return {\n ...DEFAULT_ROUTING_CONFIG,\n ...overrides,\n classifier: { ...DEFAULT_ROUTING_CONFIG.classifier, ...overrides.classifier },\n scoring: { ...DEFAULT_ROUTING_CONFIG.scoring, ...overrides.scoring },\n tiers: { ...DEFAULT_ROUTING_CONFIG.tiers, ...overrides.tiers },\n overrides: { ...DEFAULT_ROUTING_CONFIG.overrides, ...overrides.overrides },\n };\n}\n\n/**\n * Estimate USDC cost for a request based on model pricing.\n * Returns amount string in USDC smallest unit (6 decimals) or undefined if unknown.\n */\nfunction estimateAmount(\n modelId: string,\n bodyLength: number,\n maxTokens: number,\n): string | undefined {\n const model = BLOCKRUN_MODELS.find((m) => m.id === modelId);\n if (!model) return undefined;\n\n // Rough estimate: ~4 chars per token for input\n const estimatedInputTokens = Math.ceil(bodyLength / 4);\n const estimatedOutputTokens = maxTokens || model.maxOutput || 4096;\n\n const costUsd =\n (estimatedInputTokens / 1_000_000) * model.inputPrice +\n (estimatedOutputTokens / 1_000_000) * model.outputPrice;\n\n // Convert to USDC 6-decimal integer, add 20% buffer for estimation error\n // Minimum 100 ($0.0001) to avoid zero-amount rejections\n const amountMicros = Math.max(100, Math.ceil(costUsd * 1.2 * 1_000_000));\n return amountMicros.toString();\n}\n\n/**\n * Start the local x402 proxy server.\n *\n * If a proxy is already running on the target port, reuses it instead of failing.\n * Port can be configured via BLOCKRUN_PROXY_PORT environment variable.\n *\n * Returns a handle with the assigned port, base URL, and a close function.\n */\nexport async function startProxy(options: ProxyOptions): Promise<ProxyHandle> {\n const apiBase = options.apiBase ?? BLOCKRUN_API;\n\n // Determine port: options.port > env var > default\n const listenPort = options.port ?? getProxyPort();\n\n // Check if a proxy is already running on this port\n const existingWallet = await checkExistingProxy(listenPort);\n if (existingWallet) {\n // Proxy already running — reuse it instead of failing with EADDRINUSE\n const account = privateKeyToAccount(options.walletKey as `0x${string}`);\n const balanceMonitor = new BalanceMonitor(account.address);\n const baseUrl = `http://127.0.0.1:${listenPort}`;\n\n // Verify the existing proxy is using the same wallet (or warn if different)\n if (existingWallet !== account.address) {\n console.warn(\n `[ClawRouter] Existing proxy on port ${listenPort} uses wallet ${existingWallet}, but current config uses ${account.address}. Reusing existing proxy.`,\n );\n }\n\n options.onReady?.(listenPort);\n\n return {\n port: listenPort,\n baseUrl,\n walletAddress: existingWallet,\n balanceMonitor,\n close: async () => {\n // No-op: we didn't start this proxy, so we shouldn't close it\n },\n };\n }\n\n // Create x402 payment-enabled fetch from wallet private key\n const account = privateKeyToAccount(options.walletKey as `0x${string}`);\n const { fetch: payFetch } = createPaymentFetch(options.walletKey as `0x${string}`);\n\n // Create balance monitor for pre-request checks\n const balanceMonitor = new BalanceMonitor(account.address);\n\n // Build router options (100% local — no external API calls for routing)\n const routingConfig = mergeRoutingConfig(options.routingConfig);\n const modelPricing = buildModelPricing();\n const routerOpts: RouterOptions = {\n config: routingConfig,\n modelPricing,\n };\n\n // Request deduplicator (shared across all requests)\n const deduplicator = new RequestDeduplicator();\n\n const server = createServer(async (req: IncomingMessage, res: ServerResponse) => {\n // Health check with optional balance info\n if (req.url === \"/health\" || req.url?.startsWith(\"/health?\")) {\n const url = new URL(req.url, \"http://localhost\");\n const full = url.searchParams.get(\"full\") === \"true\";\n\n const response: Record<string, unknown> = {\n status: \"ok\",\n wallet: account.address,\n };\n\n if (full) {\n try {\n const balanceInfo = await balanceMonitor.checkBalance();\n response.balance = balanceInfo.balanceUSD;\n response.isLow = balanceInfo.isLow;\n response.isEmpty = balanceInfo.isEmpty;\n } catch {\n response.balanceError = \"Could not fetch balance\";\n }\n }\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(response));\n return;\n }\n\n // Only proxy paths starting with /v1\n if (!req.url?.startsWith(\"/v1\")) {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Not found\" }));\n return;\n }\n\n try {\n await proxyRequest(\n req,\n res,\n apiBase,\n payFetch,\n options,\n routerOpts,\n deduplicator,\n balanceMonitor,\n );\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n options.onError?.(error);\n\n if (!res.headersSent) {\n res.writeHead(502, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: { message: `Proxy error: ${error.message}`, type: \"proxy_error\" },\n }),\n );\n } else if (!res.writableEnded) {\n // Headers already sent (streaming) — send error as SSE event\n res.write(\n `data: ${JSON.stringify({ error: { message: error.message, type: \"proxy_error\" } })}\\n\\n`,\n );\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n }\n }\n });\n\n // Listen on configured port (already determined above)\n return new Promise<ProxyHandle>((resolve, reject) => {\n server.on(\"error\", (err: NodeJS.ErrnoException) => {\n // Handle EADDRINUSE gracefully — proxy is already running\n if (err.code === \"EADDRINUSE\") {\n // Port is in use, which means a proxy is already running.\n // This can happen when openclaw logs triggers plugin reload.\n // Silently reuse the existing proxy instead of failing.\n const baseUrl = `http://127.0.0.1:${listenPort}`;\n options.onReady?.(listenPort);\n resolve({\n port: listenPort,\n baseUrl,\n walletAddress: account.address,\n balanceMonitor,\n close: async () => {\n // No-op: we didn't start this proxy, so we shouldn't close it\n },\n });\n return;\n }\n reject(err);\n });\n\n server.listen(listenPort, \"127.0.0.1\", () => {\n const addr = server.address() as AddressInfo;\n const port = addr.port;\n const baseUrl = `http://127.0.0.1:${port}`;\n\n options.onReady?.(port);\n\n resolve({\n port,\n baseUrl,\n walletAddress: account.address,\n balanceMonitor,\n close: () =>\n new Promise<void>((res, rej) => {\n server.close((err) => (err ? rej(err) : res()));\n }),\n });\n });\n });\n}\n\n/** Result of attempting a model request */\ntype ModelRequestResult = {\n success: boolean;\n response?: Response;\n errorBody?: string;\n errorStatus?: number;\n isProviderError?: boolean;\n};\n\n/**\n * Attempt a request with a specific model.\n * Returns the response or error details for fallback decision.\n */\nasync function tryModelRequest(\n upstreamUrl: string,\n method: string,\n headers: Record<string, string>,\n body: Buffer,\n modelId: string,\n maxTokens: number,\n payFetch: (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ) => Promise<Response>,\n balanceMonitor: BalanceMonitor,\n signal: AbortSignal,\n): Promise<ModelRequestResult> {\n // Update model in body and normalize messages for Google models\n let requestBody = body;\n try {\n const parsed = JSON.parse(body.toString()) as Record<string, unknown>;\n parsed.model = modelId;\n\n // Normalize messages for Google models (first non-system message must be \"user\")\n if (isGoogleModel(modelId) && Array.isArray(parsed.messages)) {\n parsed.messages = normalizeMessagesForGoogle(parsed.messages as ChatMessage[]);\n }\n\n requestBody = Buffer.from(JSON.stringify(parsed));\n } catch {\n // If body isn't valid JSON, use as-is\n }\n\n // Estimate cost for pre-auth\n const estimated = estimateAmount(modelId, requestBody.length, maxTokens);\n const preAuth: PreAuthParams | undefined = estimated ? { estimatedAmount: estimated } : undefined;\n\n try {\n const response = await payFetch(\n upstreamUrl,\n {\n method,\n headers,\n body: requestBody.length > 0 ? new Uint8Array(requestBody) : undefined,\n signal,\n },\n preAuth,\n );\n\n // Check for provider errors\n if (response.status !== 200) {\n // Clone response to read body without consuming it\n const errorBody = await response.text();\n const isProviderErr = isProviderError(response.status, errorBody);\n\n return {\n success: false,\n errorBody,\n errorStatus: response.status,\n isProviderError: isProviderErr,\n };\n }\n\n return { success: true, response };\n } catch (err) {\n const errorMsg = err instanceof Error ? err.message : String(err);\n return {\n success: false,\n errorBody: errorMsg,\n errorStatus: 500,\n isProviderError: true, // Network errors are retryable\n };\n }\n}\n\n/**\n * Proxy a single request through x402 payment flow to BlockRun API.\n *\n * Optimizations applied in order:\n * 1. Dedup check — if same request body seen within 30s, replay cached response\n * 2. Streaming heartbeat — for stream:true, send 200 + heartbeats immediately\n * 3. Payment pre-auth — estimate USDC amount and pre-sign to skip 402 round trip\n * 4. Smart routing — when model is \"blockrun/auto\", pick cheapest capable model\n * 5. Fallback chain — on provider errors, try next model in tier's fallback list\n */\nasync function proxyRequest(\n req: IncomingMessage,\n res: ServerResponse,\n apiBase: string,\n payFetch: (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ) => Promise<Response>,\n options: ProxyOptions,\n routerOpts: RouterOptions,\n deduplicator: RequestDeduplicator,\n balanceMonitor: BalanceMonitor,\n): Promise<void> {\n const startTime = Date.now();\n\n // Build upstream URL: /v1/chat/completions → https://blockrun.ai/api/v1/chat/completions\n const upstreamUrl = `${apiBase}${req.url}`;\n\n // Collect request body\n const bodyChunks: Buffer[] = [];\n for await (const chunk of req) {\n bodyChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n let body = Buffer.concat(bodyChunks);\n\n // --- Smart routing ---\n let routingDecision: RoutingDecision | undefined;\n let isStreaming = false;\n let modelId = \"\";\n let maxTokens = 4096;\n const isChatCompletion = req.url?.includes(\"/chat/completions\");\n\n if (isChatCompletion && body.length > 0) {\n try {\n const parsed = JSON.parse(body.toString()) as Record<string, unknown>;\n isStreaming = parsed.stream === true;\n modelId = (parsed.model as string) || \"\";\n maxTokens = (parsed.max_tokens as number) || 4096;\n\n // Force stream: false — BlockRun API doesn't support streaming yet\n // ClawRouter handles SSE heartbeat simulation for upstream compatibility\n let bodyModified = false;\n if (parsed.stream === true) {\n parsed.stream = false;\n bodyModified = true;\n }\n\n // Normalize model name for comparison (trim whitespace, lowercase)\n const normalizedModel =\n typeof parsed.model === \"string\" ? parsed.model.trim().toLowerCase() : \"\";\n const isAutoModel =\n normalizedModel === AUTO_MODEL.toLowerCase() ||\n normalizedModel === AUTO_MODEL_SHORT.toLowerCase();\n\n // Debug: log received model name\n console.log(\n `[ClawRouter] Received model: \"${parsed.model}\" -> normalized: \"${normalizedModel}\", isAuto: ${isAutoModel}`,\n );\n\n if (isAutoModel) {\n // Extract prompt from messages\n type ChatMessage = { role: string; content: string };\n const messages = parsed.messages as ChatMessage[] | undefined;\n let lastUserMsg: ChatMessage | undefined;\n if (messages) {\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].role === \"user\") {\n lastUserMsg = messages[i];\n break;\n }\n }\n }\n const systemMsg = messages?.find((m: ChatMessage) => m.role === \"system\");\n const prompt = typeof lastUserMsg?.content === \"string\" ? lastUserMsg.content : \"\";\n const systemPrompt = typeof systemMsg?.content === \"string\" ? systemMsg.content : undefined;\n\n routingDecision = route(prompt, systemPrompt, maxTokens, routerOpts);\n\n // Replace model in body\n parsed.model = routingDecision.model;\n modelId = routingDecision.model;\n bodyModified = true;\n\n options.onRouted?.(routingDecision);\n }\n\n // Rebuild body if modified\n if (bodyModified) {\n body = Buffer.from(JSON.stringify(parsed));\n }\n } catch (err) {\n // Log routing errors so they're not silently swallowed\n const errorMsg = err instanceof Error ? err.message : String(err);\n console.error(`[ClawRouter] Routing error: ${errorMsg}`);\n options.onError?.(new Error(`Routing failed: ${errorMsg}`));\n }\n }\n\n // --- Dedup check ---\n const dedupKey = RequestDeduplicator.hash(body);\n\n // Check completed cache first\n const cached = deduplicator.getCached(dedupKey);\n if (cached) {\n res.writeHead(cached.status, cached.headers);\n res.end(cached.body);\n return;\n }\n\n // Check in-flight — wait for the original request to complete\n const inflight = deduplicator.getInflight(dedupKey);\n if (inflight) {\n const result = await inflight;\n res.writeHead(result.status, result.headers);\n res.end(result.body);\n return;\n }\n\n // Register this request as in-flight\n deduplicator.markInflight(dedupKey);\n\n // --- Pre-request balance check ---\n // Estimate cost and check if wallet has sufficient balance\n // Skip if skipBalanceCheck is set (for testing)\n let estimatedCostMicros: bigint | undefined;\n if (modelId && !options.skipBalanceCheck) {\n const estimated = estimateAmount(modelId, body.length, maxTokens);\n if (estimated) {\n estimatedCostMicros = BigInt(estimated);\n\n // Apply extra buffer for balance check to prevent x402 failures after streaming starts.\n // This is aggressive to avoid triggering OpenClaw's 5-24 hour billing cooldown.\n const bufferedCostMicros =\n (estimatedCostMicros * BigInt(Math.ceil(BALANCE_CHECK_BUFFER * 100))) / 100n;\n\n // Check balance before proceeding (using buffered amount)\n const sufficiency = await balanceMonitor.checkSufficient(bufferedCostMicros);\n\n if (sufficiency.info.isEmpty) {\n // Wallet is empty — cannot proceed\n deduplicator.removeInflight(dedupKey);\n const error = new EmptyWalletError(sufficiency.info.walletAddress);\n options.onInsufficientFunds?.({\n balanceUSD: sufficiency.info.balanceUSD,\n requiredUSD: balanceMonitor.formatUSDC(bufferedCostMicros),\n walletAddress: sufficiency.info.walletAddress,\n });\n throw error;\n }\n\n if (!sufficiency.sufficient) {\n // Insufficient balance — cannot proceed\n deduplicator.removeInflight(dedupKey);\n const error = new InsufficientFundsError({\n currentBalanceUSD: sufficiency.info.balanceUSD,\n requiredUSD: balanceMonitor.formatUSDC(bufferedCostMicros),\n walletAddress: sufficiency.info.walletAddress,\n });\n options.onInsufficientFunds?.({\n balanceUSD: sufficiency.info.balanceUSD,\n requiredUSD: balanceMonitor.formatUSDC(bufferedCostMicros),\n walletAddress: sufficiency.info.walletAddress,\n });\n throw error;\n }\n\n if (sufficiency.info.isLow) {\n // Balance is low but sufficient — warn and proceed\n options.onLowBalance?.({\n balanceUSD: sufficiency.info.balanceUSD,\n walletAddress: sufficiency.info.walletAddress,\n });\n }\n }\n }\n\n // --- Streaming: early header flush + heartbeat ---\n let heartbeatInterval: ReturnType<typeof setInterval> | undefined;\n let headersSentEarly = false;\n\n if (isStreaming) {\n // Send 200 + SSE headers immediately, before x402 flow\n res.writeHead(200, {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-cache\",\n connection: \"keep-alive\",\n });\n headersSentEarly = true;\n\n // First heartbeat immediately\n res.write(\": heartbeat\\n\\n\");\n\n // Continue heartbeats every 2s while waiting for upstream\n heartbeatInterval = setInterval(() => {\n if (!res.writableEnded) {\n res.write(\": heartbeat\\n\\n\");\n }\n }, HEARTBEAT_INTERVAL_MS);\n }\n\n // Forward headers, stripping host, connection, and content-length\n const headers: Record<string, string> = {};\n for (const [key, value] of Object.entries(req.headers)) {\n if (\n key === \"host\" ||\n key === \"connection\" ||\n key === \"transfer-encoding\" ||\n key === \"content-length\"\n )\n continue;\n if (typeof value === \"string\") {\n headers[key] = value;\n }\n }\n if (!headers[\"content-type\"]) {\n headers[\"content-type\"] = \"application/json\";\n }\n headers[\"user-agent\"] = USER_AGENT;\n\n // --- Client disconnect cleanup ---\n let completed = false;\n res.on(\"close\", () => {\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n heartbeatInterval = undefined;\n }\n // Remove from in-flight if client disconnected before completion\n if (!completed) {\n deduplicator.removeInflight(dedupKey);\n }\n });\n\n // --- Request timeout ---\n const timeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n // --- Build fallback chain ---\n // If we have a routing decision, get the full fallback chain for the tier\n // Otherwise, just use the current model (no fallback for explicit model requests)\n let modelsToTry: string[];\n if (routingDecision) {\n modelsToTry = getFallbackChain(routingDecision.tier, routerOpts.config.tiers);\n // Limit to MAX_FALLBACK_ATTEMPTS to prevent infinite loops\n modelsToTry = modelsToTry.slice(0, MAX_FALLBACK_ATTEMPTS);\n } else {\n modelsToTry = modelId ? [modelId] : [];\n }\n\n // --- Fallback loop: try each model until success ---\n let upstream: Response | undefined;\n let lastError: { body: string; status: number } | undefined;\n let actualModelUsed = modelId;\n\n for (let i = 0; i < modelsToTry.length; i++) {\n const tryModel = modelsToTry[i];\n const isLastAttempt = i === modelsToTry.length - 1;\n\n console.log(`[ClawRouter] Trying model ${i + 1}/${modelsToTry.length}: ${tryModel}`);\n\n const result = await tryModelRequest(\n upstreamUrl,\n req.method ?? \"POST\",\n headers,\n body,\n tryModel,\n maxTokens,\n payFetch,\n balanceMonitor,\n controller.signal,\n );\n\n if (result.success && result.response) {\n upstream = result.response;\n actualModelUsed = tryModel;\n console.log(`[ClawRouter] Success with model: ${tryModel}`);\n break;\n }\n\n // Request failed\n lastError = {\n body: result.errorBody || \"Unknown error\",\n status: result.errorStatus || 500,\n };\n\n // If it's a provider error and not the last attempt, try next model\n if (result.isProviderError && !isLastAttempt) {\n console.log(\n `[ClawRouter] Provider error from ${tryModel}, trying fallback: ${result.errorBody?.slice(0, 100)}`,\n );\n continue;\n }\n\n // Not a provider error or last attempt — stop trying\n if (!result.isProviderError) {\n console.log(\n `[ClawRouter] Non-provider error from ${tryModel}, not retrying: ${result.errorBody?.slice(0, 100)}`,\n );\n }\n break;\n }\n\n // Clear timeout — request attempts completed\n clearTimeout(timeoutId);\n\n // Clear heartbeat — real data is about to flow\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n heartbeatInterval = undefined;\n }\n\n // Update routing decision with actual model used (for logging)\n if (routingDecision && actualModelUsed !== routingDecision.model) {\n routingDecision = {\n ...routingDecision,\n model: actualModelUsed,\n reasoning: `${routingDecision.reasoning} | fallback to ${actualModelUsed}`,\n };\n options.onRouted?.(routingDecision);\n }\n\n // --- Handle case where all models failed ---\n if (!upstream) {\n const errBody = lastError?.body || \"All models in fallback chain failed\";\n const errStatus = lastError?.status || 502;\n\n if (headersSentEarly) {\n // Streaming: send error as SSE event\n const errEvent = `data: ${JSON.stringify({ error: { message: errBody, type: \"provider_error\", status: errStatus } })}\\n\\n`;\n res.write(errEvent);\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n\n const errBuf = Buffer.from(errEvent + \"data: [DONE]\\n\\n\");\n deduplicator.complete(dedupKey, {\n status: 200,\n headers: { \"content-type\": \"text/event-stream\" },\n body: errBuf,\n completedAt: Date.now(),\n });\n } else {\n // Non-streaming: send error response\n res.writeHead(errStatus, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: { message: errBody, type: \"provider_error\" },\n }),\n );\n\n deduplicator.complete(dedupKey, {\n status: errStatus,\n headers: { \"content-type\": \"application/json\" },\n body: Buffer.from(\n JSON.stringify({ error: { message: errBody, type: \"provider_error\" } }),\n ),\n completedAt: Date.now(),\n });\n }\n return;\n }\n\n // --- Stream response and collect for dedup cache ---\n const responseChunks: Buffer[] = [];\n\n if (headersSentEarly) {\n // Streaming: headers already sent. Response should be 200 at this point\n // (non-200 responses are handled in the fallback loop above)\n\n // Convert non-streaming JSON response to SSE streaming format for client\n // (BlockRun API returns JSON since we forced stream:false)\n // OpenClaw expects: object=\"chat.completion.chunk\" with choices[].delta (not message)\n // We emit proper incremental deltas to match OpenAI's streaming format exactly\n if (upstream.body) {\n const reader = upstream.body.getReader();\n const chunks: Uint8Array[] = [];\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n }\n } finally {\n reader.releaseLock();\n }\n\n // Combine chunks and transform to streaming format\n const jsonBody = Buffer.concat(chunks);\n const jsonStr = jsonBody.toString();\n try {\n const rsp = JSON.parse(jsonStr) as {\n id?: string;\n object?: string;\n created?: number;\n model?: string;\n choices?: Array<{\n index?: number;\n message?: { role?: string; content?: string };\n delta?: { role?: string; content?: string };\n finish_reason?: string | null;\n }>;\n usage?: unknown;\n };\n\n // Build base chunk structure (reused for all chunks)\n const baseChunk = {\n id: rsp.id ?? `chatcmpl-${Date.now()}`,\n object: \"chat.completion.chunk\",\n created: rsp.created ?? Math.floor(Date.now() / 1000),\n model: rsp.model ?? \"unknown\",\n };\n\n // Process each choice (usually just one)\n if (rsp.choices && Array.isArray(rsp.choices)) {\n for (const choice of rsp.choices) {\n // Strip thinking tokens (Kimi <|...|> and standard <think> tags)\n const rawContent = choice.message?.content ?? choice.delta?.content ?? \"\";\n const content = stripThinkingTokens(rawContent);\n const role = choice.message?.role ?? choice.delta?.role ?? \"assistant\";\n const index = choice.index ?? 0;\n\n // Chunk 1: role only (mimics OpenAI's first chunk)\n const roleChunk = {\n ...baseChunk,\n choices: [{ index, delta: { role }, finish_reason: null }],\n };\n const roleData = `data: ${JSON.stringify(roleChunk)}\\n\\n`;\n res.write(roleData);\n responseChunks.push(Buffer.from(roleData));\n\n // Chunk 2: content (single chunk with full content)\n if (content) {\n const contentChunk = {\n ...baseChunk,\n choices: [{ index, delta: { content }, finish_reason: null }],\n };\n const contentData = `data: ${JSON.stringify(contentChunk)}\\n\\n`;\n res.write(contentData);\n responseChunks.push(Buffer.from(contentData));\n }\n\n // Chunk 3: finish_reason (signals completion)\n const finishChunk = {\n ...baseChunk,\n choices: [{ index, delta: {}, finish_reason: choice.finish_reason ?? \"stop\" }],\n };\n const finishData = `data: ${JSON.stringify(finishChunk)}\\n\\n`;\n res.write(finishData);\n responseChunks.push(Buffer.from(finishData));\n }\n }\n } catch {\n // If parsing fails, send raw response as single chunk\n const sseData = `data: ${jsonStr}\\n\\n`;\n res.write(sseData);\n responseChunks.push(Buffer.from(sseData));\n }\n }\n\n // Send SSE terminator\n res.write(\"data: [DONE]\\n\\n\");\n responseChunks.push(Buffer.from(\"data: [DONE]\\n\\n\"));\n res.end();\n\n // Cache for dedup\n deduplicator.complete(dedupKey, {\n status: 200,\n headers: { \"content-type\": \"text/event-stream\" },\n body: Buffer.concat(responseChunks),\n completedAt: Date.now(),\n });\n } else {\n // Non-streaming: forward status and headers from upstream\n const responseHeaders: Record<string, string> = {};\n upstream.headers.forEach((value, key) => {\n if (key === \"transfer-encoding\" || key === \"connection\") return;\n responseHeaders[key] = value;\n });\n\n res.writeHead(upstream.status, responseHeaders);\n\n if (upstream.body) {\n const reader = upstream.body.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n res.write(value);\n responseChunks.push(Buffer.from(value));\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n res.end();\n\n // Cache for dedup\n deduplicator.complete(dedupKey, {\n status: upstream.status,\n headers: responseHeaders,\n body: Buffer.concat(responseChunks),\n completedAt: Date.now(),\n });\n }\n\n // --- Optimistic balance deduction after successful response ---\n if (estimatedCostMicros !== undefined) {\n balanceMonitor.deductEstimated(estimatedCostMicros);\n }\n\n // Mark request as completed (for client disconnect cleanup)\n completed = true;\n } catch (err) {\n // Clear timeout on error\n clearTimeout(timeoutId);\n\n // Clear heartbeat on error\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n heartbeatInterval = undefined;\n }\n\n // Remove in-flight entry so retries aren't blocked\n deduplicator.removeInflight(dedupKey);\n\n // Invalidate balance cache on payment failure (might be out of date)\n balanceMonitor.invalidate();\n\n // Convert abort error to more descriptive timeout error\n if (err instanceof Error && err.name === \"AbortError\") {\n throw new Error(`Request timed out after ${timeoutMs}ms`);\n }\n\n throw err;\n }\n\n // --- Usage logging (fire-and-forget) ---\n if (routingDecision) {\n const entry: UsageEntry = {\n timestamp: new Date().toISOString(),\n model: routingDecision.model,\n cost: routingDecision.costEstimate,\n latencyMs: Date.now() - startTime,\n };\n logUsage(entry).catch(() => {});\n }\n}\n","/**\n * x402 Payment Implementation\n *\n * Based on BlockRun's proven implementation.\n * Handles 402 Payment Required responses with EIP-712 signed USDC transfers.\n *\n * Optimizations (v0.3.0):\n * - Payment cache: after first 402, caches {payTo, asset, network} per endpoint.\n * On subsequent requests, pre-signs payment and sends with first request,\n * skipping the 402 round trip (~200ms savings).\n * - Falls back to normal 402 flow if pre-signed payment is rejected.\n */\n\nimport { signTypedData, privateKeyToAccount } from \"viem/accounts\";\nimport { PaymentCache } from \"./payment-cache.js\";\n\nconst BASE_CHAIN_ID = 8453;\nconst USDC_BASE = \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\" as const;\n\nconst USDC_DOMAIN = {\n name: \"USD Coin\",\n version: \"2\",\n chainId: BASE_CHAIN_ID,\n verifyingContract: USDC_BASE,\n} as const;\n\nconst TRANSFER_TYPES = {\n TransferWithAuthorization: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n ],\n} as const;\n\nfunction createNonce(): `0x${string}` {\n const bytes = new Uint8Array(32);\n crypto.getRandomValues(bytes);\n return `0x${Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\")}` as `0x${string}`;\n}\n\ninterface PaymentOption {\n scheme: string;\n network: string;\n amount?: string;\n maxAmountRequired?: string;\n asset: string;\n payTo: string;\n maxTimeoutSeconds?: number;\n extra?: { name?: string; version?: string };\n}\n\ninterface PaymentRequired {\n accepts: PaymentOption[];\n resource?: { url?: string; description?: string };\n}\n\nfunction parsePaymentRequired(headerValue: string): PaymentRequired {\n const decoded = atob(headerValue);\n return JSON.parse(decoded) as PaymentRequired;\n}\n\nasync function createPaymentPayload(\n privateKey: `0x${string}`,\n fromAddress: string,\n recipient: string,\n amount: string,\n resourceUrl: string,\n): Promise<string> {\n const now = Math.floor(Date.now() / 1000);\n const validAfter = now - 600;\n const validBefore = now + 300;\n const nonce = createNonce();\n\n const signature = await signTypedData({\n privateKey,\n domain: USDC_DOMAIN,\n types: TRANSFER_TYPES,\n primaryType: \"TransferWithAuthorization\",\n message: {\n from: fromAddress as `0x${string}`,\n to: recipient as `0x${string}`,\n value: BigInt(amount),\n validAfter: BigInt(validAfter),\n validBefore: BigInt(validBefore),\n nonce,\n },\n });\n\n const paymentData = {\n x402Version: 2,\n resource: {\n url: resourceUrl,\n description: \"BlockRun AI API call\",\n mimeType: \"application/json\",\n },\n accepted: {\n scheme: \"exact\",\n network: \"eip155:8453\",\n amount,\n asset: USDC_BASE,\n payTo: recipient,\n maxTimeoutSeconds: 300,\n extra: { name: \"USD Coin\", version: \"2\" },\n },\n payload: {\n signature,\n authorization: {\n from: fromAddress,\n to: recipient,\n value: amount,\n validAfter: validAfter.toString(),\n validBefore: validBefore.toString(),\n nonce,\n },\n },\n extensions: {},\n };\n\n return btoa(JSON.stringify(paymentData));\n}\n\n/** Pre-auth parameters for skipping the 402 round trip. */\nexport type PreAuthParams = {\n estimatedAmount: string; // USDC amount in smallest unit (6 decimals)\n};\n\n/** Result from createPaymentFetch — includes the fetch wrapper and payment cache. */\nexport type PaymentFetchResult = {\n fetch: (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ) => Promise<Response>;\n cache: PaymentCache;\n};\n\n/**\n * Create a fetch wrapper that handles x402 payment automatically.\n *\n * Supports pre-auth: if cached payment params + estimated amount are available,\n * pre-signs and attaches payment to the first request, skipping the 402 round trip.\n * Falls back to normal 402 flow if pre-signed payment is rejected.\n */\nexport function createPaymentFetch(privateKey: `0x${string}`): PaymentFetchResult {\n const account = privateKeyToAccount(privateKey);\n const walletAddress = account.address;\n const paymentCache = new PaymentCache();\n\n const payFetch = async (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ): Promise<Response> => {\n const url = typeof input === \"string\" ? input : input instanceof URL ? input.href : input.url;\n const endpointPath = new URL(url).pathname;\n\n // --- Pre-auth path: skip 402 round trip ---\n const cached = paymentCache.get(endpointPath);\n if (cached && preAuth?.estimatedAmount) {\n const paymentPayload = await createPaymentPayload(\n privateKey,\n walletAddress,\n cached.payTo,\n preAuth.estimatedAmount,\n url,\n );\n\n const preAuthHeaders = new Headers(init?.headers);\n preAuthHeaders.set(\"payment-signature\", paymentPayload);\n\n const response = await fetch(input, { ...init, headers: preAuthHeaders });\n\n // Pre-auth accepted — skip 402 entirely\n if (response.status !== 402) {\n return response;\n }\n\n // Pre-auth rejected (wrong amount, payTo changed, etc.)\n // Try to use this 402's payment header for a proper retry\n const paymentHeader = response.headers.get(\"x-payment-required\");\n if (paymentHeader) {\n return handle402(input, init, url, endpointPath, paymentHeader);\n }\n\n // No payment header — invalidate cache and retry clean (no payment header)\n // to get a proper 402 with payment requirements\n paymentCache.invalidate(endpointPath);\n const cleanResponse = await fetch(input, init);\n if (cleanResponse.status !== 402) {\n return cleanResponse;\n }\n const cleanHeader = cleanResponse.headers.get(\"x-payment-required\");\n if (!cleanHeader) {\n throw new Error(\"402 response missing x-payment-required header\");\n }\n return handle402(input, init, url, endpointPath, cleanHeader);\n }\n\n // --- Normal path: first request may get 402 ---\n const response = await fetch(input, init);\n\n if (response.status !== 402) {\n return response;\n }\n\n const paymentHeader = response.headers.get(\"x-payment-required\");\n if (!paymentHeader) {\n throw new Error(\"402 response missing x-payment-required header\");\n }\n\n return handle402(input, init, url, endpointPath, paymentHeader);\n };\n\n /** Handle a 402 response: parse, cache params, sign, retry. */\n async function handle402(\n input: RequestInfo | URL,\n init: RequestInit | undefined,\n url: string,\n endpointPath: string,\n paymentHeader: string,\n ): Promise<Response> {\n const paymentRequired = parsePaymentRequired(paymentHeader);\n const option = paymentRequired.accepts?.[0];\n if (!option) {\n throw new Error(\"No payment options in 402 response\");\n }\n\n const amount = option.amount || option.maxAmountRequired;\n if (!amount) {\n throw new Error(\"No amount in payment requirements\");\n }\n\n // Cache payment params for future pre-auth\n paymentCache.set(endpointPath, {\n payTo: option.payTo,\n asset: option.asset,\n scheme: option.scheme,\n network: option.network,\n extra: option.extra,\n maxTimeoutSeconds: option.maxTimeoutSeconds,\n });\n\n // Create signed payment\n const paymentPayload = await createPaymentPayload(\n privateKey,\n walletAddress,\n option.payTo,\n amount,\n url,\n );\n\n // Retry with payment\n const retryHeaders = new Headers(init?.headers);\n retryHeaders.set(\"payment-signature\", paymentPayload);\n\n return fetch(input, {\n ...init,\n headers: retryHeaders,\n });\n }\n\n return { fetch: payFetch, cache: paymentCache };\n}\n","/**\n * Payment Parameter Cache\n *\n * Caches the 402 payment parameters (payTo, asset, network, etc.) after the first\n * request to each endpoint. On subsequent requests, pre-signs the payment and\n * attaches it to the first request, skipping the 402 round trip (~200ms savings).\n */\n\nexport type CachedPaymentParams = {\n payTo: string;\n asset: string;\n scheme: string;\n network: string;\n extra?: { name?: string; version?: string };\n maxTimeoutSeconds?: number;\n cachedAt: number;\n};\n\nconst DEFAULT_TTL_MS = 3_600_000; // 1 hour\n\nexport class PaymentCache {\n private cache = new Map<string, CachedPaymentParams>();\n private ttlMs: number;\n\n constructor(ttlMs = DEFAULT_TTL_MS) {\n this.ttlMs = ttlMs;\n }\n\n /** Get cached payment params for an endpoint path. */\n get(endpointPath: string): CachedPaymentParams | undefined {\n const entry = this.cache.get(endpointPath);\n if (!entry) return undefined;\n if (Date.now() - entry.cachedAt > this.ttlMs) {\n this.cache.delete(endpointPath);\n return undefined;\n }\n return entry;\n }\n\n /** Cache payment params from a 402 response. */\n set(endpointPath: string, params: Omit<CachedPaymentParams, \"cachedAt\">): void {\n this.cache.set(endpointPath, { ...params, cachedAt: Date.now() });\n }\n\n /** Invalidate cache for an endpoint (e.g., if payTo changed). */\n invalidate(endpointPath: string): void {\n this.cache.delete(endpointPath);\n }\n}\n","/**\n * Rule-Based Classifier (v2 — Weighted Scoring)\n *\n * Scores a request across 14 weighted dimensions and maps the aggregate\n * score to a tier using configurable boundaries. Confidence is calibrated\n * via sigmoid — low confidence triggers the fallback classifier.\n *\n * Handles 70-80% of requests in < 1ms with zero cost.\n */\n\nimport type { Tier, ScoringResult, ScoringConfig } from \"./types.js\";\n\ntype DimensionScore = { name: string; score: number; signal: string | null };\n\n// ─── Dimension Scorers ───\n// Each returns a score in [-1, 1] and an optional signal string.\n\nfunction scoreTokenCount(\n estimatedTokens: number,\n thresholds: { simple: number; complex: number },\n): DimensionScore {\n if (estimatedTokens < thresholds.simple) {\n return { name: \"tokenCount\", score: -1.0, signal: `short (${estimatedTokens} tokens)` };\n }\n if (estimatedTokens > thresholds.complex) {\n return { name: \"tokenCount\", score: 1.0, signal: `long (${estimatedTokens} tokens)` };\n }\n return { name: \"tokenCount\", score: 0, signal: null };\n}\n\nfunction scoreKeywordMatch(\n text: string,\n keywords: string[],\n name: string,\n signalLabel: string,\n thresholds: { low: number; high: number },\n scores: { none: number; low: number; high: number },\n): DimensionScore {\n const matches = keywords.filter((kw) => text.includes(kw.toLowerCase()));\n if (matches.length >= thresholds.high) {\n return {\n name,\n score: scores.high,\n signal: `${signalLabel} (${matches.slice(0, 3).join(\", \")})`,\n };\n }\n if (matches.length >= thresholds.low) {\n return {\n name,\n score: scores.low,\n signal: `${signalLabel} (${matches.slice(0, 3).join(\", \")})`,\n };\n }\n return { name, score: scores.none, signal: null };\n}\n\nfunction scoreMultiStep(text: string): DimensionScore {\n const patterns = [/first.*then/i, /step \\d/i, /\\d\\.\\s/];\n const hits = patterns.filter((p) => p.test(text));\n if (hits.length > 0) {\n return { name: \"multiStepPatterns\", score: 0.5, signal: \"multi-step\" };\n }\n return { name: \"multiStepPatterns\", score: 0, signal: null };\n}\n\nfunction scoreQuestionComplexity(prompt: string): DimensionScore {\n const count = (prompt.match(/\\?/g) || []).length;\n if (count > 3) {\n return { name: \"questionComplexity\", score: 0.5, signal: `${count} questions` };\n }\n return { name: \"questionComplexity\", score: 0, signal: null };\n}\n\n// ─── Main Classifier ───\n\nexport function classifyByRules(\n prompt: string,\n systemPrompt: string | undefined,\n estimatedTokens: number,\n config: ScoringConfig,\n): ScoringResult {\n const text = `${systemPrompt ?? \"\"} ${prompt}`.toLowerCase();\n // User prompt only — used for reasoning markers (system prompt shouldn't influence complexity)\n const userText = prompt.toLowerCase();\n\n // Score all 14 dimensions\n const dimensions: DimensionScore[] = [\n // Original 8 dimensions\n scoreTokenCount(estimatedTokens, config.tokenCountThresholds),\n scoreKeywordMatch(\n text,\n config.codeKeywords,\n \"codePresence\",\n \"code\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 1.0 },\n ),\n // Reasoning markers use USER prompt only — system prompt \"step by step\" shouldn't trigger reasoning\n scoreKeywordMatch(\n userText,\n config.reasoningKeywords,\n \"reasoningMarkers\",\n \"reasoning\",\n { low: 1, high: 2 },\n { none: 0, low: 0.7, high: 1.0 },\n ),\n scoreKeywordMatch(\n text,\n config.technicalKeywords,\n \"technicalTerms\",\n \"technical\",\n { low: 2, high: 4 },\n { none: 0, low: 0.5, high: 1.0 },\n ),\n scoreKeywordMatch(\n text,\n config.creativeKeywords,\n \"creativeMarkers\",\n \"creative\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 0.7 },\n ),\n scoreKeywordMatch(\n text,\n config.simpleKeywords,\n \"simpleIndicators\",\n \"simple\",\n { low: 1, high: 2 },\n { none: 0, low: -1.0, high: -1.0 },\n ),\n scoreMultiStep(text),\n scoreQuestionComplexity(prompt),\n\n // 6 new dimensions\n scoreKeywordMatch(\n text,\n config.imperativeVerbs,\n \"imperativeVerbs\",\n \"imperative\",\n { low: 1, high: 2 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n text,\n config.constraintIndicators,\n \"constraintCount\",\n \"constraints\",\n { low: 1, high: 3 },\n { none: 0, low: 0.3, high: 0.7 },\n ),\n scoreKeywordMatch(\n text,\n config.outputFormatKeywords,\n \"outputFormat\",\n \"format\",\n { low: 1, high: 2 },\n { none: 0, low: 0.4, high: 0.7 },\n ),\n scoreKeywordMatch(\n text,\n config.referenceKeywords,\n \"referenceComplexity\",\n \"references\",\n { low: 1, high: 2 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n text,\n config.negationKeywords,\n \"negationComplexity\",\n \"negation\",\n { low: 2, high: 3 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n text,\n config.domainSpecificKeywords,\n \"domainSpecificity\",\n \"domain-specific\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 0.8 },\n ),\n ];\n\n // Collect signals\n const signals = dimensions.filter((d) => d.signal !== null).map((d) => d.signal!);\n\n // Compute weighted score\n const weights = config.dimensionWeights;\n let weightedScore = 0;\n for (const d of dimensions) {\n const w = weights[d.name] ?? 0;\n weightedScore += d.score * w;\n }\n\n // Count reasoning markers for override — only check USER prompt, not system prompt\n // This prevents system prompts with \"step by step\" from triggering REASONING for simple queries\n const reasoningMatches = config.reasoningKeywords.filter((kw) =>\n userText.includes(kw.toLowerCase()),\n );\n\n // Direct reasoning override: 2+ reasoning markers = high confidence REASONING\n if (reasoningMatches.length >= 2) {\n const confidence = calibrateConfidence(\n Math.max(weightedScore, 0.3), // ensure positive for confidence calc\n config.confidenceSteepness,\n );\n return {\n score: weightedScore,\n tier: \"REASONING\",\n confidence: Math.max(confidence, 0.85),\n signals,\n };\n }\n\n // Map weighted score to tier using boundaries\n const { simpleMedium, mediumComplex, complexReasoning } = config.tierBoundaries;\n let tier: Tier;\n let distanceFromBoundary: number;\n\n if (weightedScore < simpleMedium) {\n tier = \"SIMPLE\";\n distanceFromBoundary = simpleMedium - weightedScore;\n } else if (weightedScore < mediumComplex) {\n tier = \"MEDIUM\";\n distanceFromBoundary = Math.min(weightedScore - simpleMedium, mediumComplex - weightedScore);\n } else if (weightedScore < complexReasoning) {\n tier = \"COMPLEX\";\n distanceFromBoundary = Math.min(\n weightedScore - mediumComplex,\n complexReasoning - weightedScore,\n );\n } else {\n tier = \"REASONING\";\n distanceFromBoundary = weightedScore - complexReasoning;\n }\n\n // Calibrate confidence via sigmoid of distance from nearest boundary\n const confidence = calibrateConfidence(distanceFromBoundary, config.confidenceSteepness);\n\n // If confidence is below threshold → ambiguous\n if (confidence < config.confidenceThreshold) {\n return { score: weightedScore, tier: null, confidence, signals };\n }\n\n return { score: weightedScore, tier, confidence, signals };\n}\n\n/**\n * Sigmoid confidence calibration.\n * Maps distance from tier boundary to [0.5, 1.0] confidence range.\n */\nfunction calibrateConfidence(distance: number, steepness: number): number {\n return 1 / (1 + Math.exp(-steepness * distance));\n}\n","/**\n * Tier → Model Selection\n *\n * Maps a classification tier to the cheapest capable model.\n * Builds RoutingDecision metadata with cost estimates and savings.\n */\n\nimport type { Tier, TierConfig, RoutingDecision } from \"./types.js\";\n\nexport type ModelPricing = {\n inputPrice: number; // per 1M tokens\n outputPrice: number; // per 1M tokens\n};\n\n/**\n * Select the primary model for a tier and build the RoutingDecision.\n */\nexport function selectModel(\n tier: Tier,\n confidence: number,\n method: \"rules\" | \"llm\",\n reasoning: string,\n tierConfigs: Record<Tier, TierConfig>,\n modelPricing: Map<string, ModelPricing>,\n estimatedInputTokens: number,\n maxOutputTokens: number,\n): RoutingDecision {\n const tierConfig = tierConfigs[tier];\n const model = tierConfig.primary;\n const pricing = modelPricing.get(model);\n\n const inputCost = pricing ? (estimatedInputTokens / 1_000_000) * pricing.inputPrice : 0;\n const outputCost = pricing ? (maxOutputTokens / 1_000_000) * pricing.outputPrice : 0;\n const costEstimate = inputCost + outputCost;\n\n // Baseline: what Claude Opus would cost (the premium default)\n const opusPricing = modelPricing.get(\"anthropic/claude-opus-4\");\n const baselineInput = opusPricing\n ? (estimatedInputTokens / 1_000_000) * opusPricing.inputPrice\n : 0;\n const baselineOutput = opusPricing ? (maxOutputTokens / 1_000_000) * opusPricing.outputPrice : 0;\n const baselineCost = baselineInput + baselineOutput;\n\n const savings = baselineCost > 0 ? Math.max(0, (baselineCost - costEstimate) / baselineCost) : 0;\n\n return {\n model,\n tier,\n confidence,\n method,\n reasoning,\n costEstimate,\n baselineCost,\n savings,\n };\n}\n\n/**\n * Get the ordered fallback chain for a tier: [primary, ...fallbacks].\n */\nexport function getFallbackChain(tier: Tier, tierConfigs: Record<Tier, TierConfig>): string[] {\n const config = tierConfigs[tier];\n return [config.primary, ...config.fallback];\n}\n","/**\n * Default Routing Config\n *\n * All routing parameters as a TypeScript constant.\n * Operators override via openclaw.yaml plugin config.\n *\n * Scoring uses 14 weighted dimensions with sigmoid confidence calibration.\n */\n\nimport type { RoutingConfig } from \"./types.js\";\n\nexport const DEFAULT_ROUTING_CONFIG: RoutingConfig = {\n version: \"2.0\",\n\n classifier: {\n llmModel: \"google/gemini-2.5-flash\",\n llmMaxTokens: 10,\n llmTemperature: 0,\n promptTruncationChars: 500,\n cacheTtlMs: 3_600_000, // 1 hour\n },\n\n scoring: {\n tokenCountThresholds: { simple: 50, complex: 500 },\n\n // Multilingual keywords: English + Chinese (中文) + Japanese (日本語) + Russian (Русский)\n codeKeywords: [\n // English\n \"function\",\n \"class\",\n \"import\",\n \"def\",\n \"SELECT\",\n \"async\",\n \"await\",\n \"const\",\n \"let\",\n \"var\",\n \"return\",\n \"```\",\n // Chinese\n \"函数\",\n \"类\",\n \"导入\",\n \"定义\",\n \"查询\",\n \"异步\",\n \"等待\",\n \"常量\",\n \"变量\",\n \"返回\",\n // Japanese\n \"関数\",\n \"クラス\",\n \"インポート\",\n \"非同期\",\n \"定数\",\n \"変数\",\n // Russian\n \"функция\",\n \"класс\",\n \"импорт\",\n \"определ\",\n \"запрос\",\n \"асинхронный\",\n \"ожидать\",\n \"константа\",\n \"переменная\",\n \"вернуть\",\n ],\n reasoningKeywords: [\n // English\n \"prove\",\n \"theorem\",\n \"derive\",\n \"step by step\",\n \"chain of thought\",\n \"formally\",\n \"mathematical\",\n \"proof\",\n \"logically\",\n // Chinese\n \"证明\",\n \"定理\",\n \"推导\",\n \"逐步\",\n \"思维链\",\n \"形式化\",\n \"数学\",\n \"逻辑\",\n // Japanese\n \"証明\",\n \"定理\",\n \"導出\",\n \"ステップバイステップ\",\n \"論理的\",\n // Russian\n \"доказать\",\n \"докажи\",\n \"доказательств\",\n \"теорема\",\n \"вывести\",\n \"шаг за шагом\",\n \"пошагово\",\n \"поэтапно\",\n \"цепочка рассуждений\",\n \"рассуждени\",\n \"формально\",\n \"математически\",\n \"логически\",\n ],\n simpleKeywords: [\n // English\n \"what is\",\n \"define\",\n \"translate\",\n \"hello\",\n \"yes or no\",\n \"capital of\",\n \"how old\",\n \"who is\",\n \"when was\",\n // Chinese\n \"什么是\",\n \"定义\",\n \"翻译\",\n \"你好\",\n \"是否\",\n \"首都\",\n \"多大\",\n \"谁是\",\n \"何时\",\n // Japanese\n \"とは\",\n \"定義\",\n \"翻訳\",\n \"こんにちは\",\n \"はいかいいえ\",\n \"首都\",\n \"誰\",\n // Russian\n \"что такое\",\n \"определение\",\n \"перевести\",\n \"переведи\",\n \"привет\",\n \"да или нет\",\n \"столица\",\n \"сколько лет\",\n \"кто такой\",\n \"когда\",\n \"объясни\",\n ],\n technicalKeywords: [\n // English\n \"algorithm\",\n \"optimize\",\n \"architecture\",\n \"distributed\",\n \"kubernetes\",\n \"microservice\",\n \"database\",\n \"infrastructure\",\n // Chinese\n \"算法\",\n \"优化\",\n \"架构\",\n \"分布式\",\n \"微服务\",\n \"数据库\",\n \"基础设施\",\n // Japanese\n \"アルゴリズム\",\n \"最適化\",\n \"アーキテクチャ\",\n \"分散\",\n \"マイクロサービス\",\n \"データベース\",\n // Russian\n \"алгоритм\",\n \"оптимизировать\",\n \"оптимизаци\",\n \"оптимизируй\",\n \"архитектура\",\n \"распределённый\",\n \"микросервис\",\n \"база данных\",\n \"инфраструктура\",\n ],\n creativeKeywords: [\n // English\n \"story\",\n \"poem\",\n \"compose\",\n \"brainstorm\",\n \"creative\",\n \"imagine\",\n \"write a\",\n // Chinese\n \"故事\",\n \"诗\",\n \"创作\",\n \"头脑风暴\",\n \"创意\",\n \"想象\",\n \"写一个\",\n // Japanese\n \"物語\",\n \"詩\",\n \"作曲\",\n \"ブレインストーム\",\n \"創造的\",\n \"想像\",\n // Russian\n \"история\",\n \"рассказ\",\n \"стихотворение\",\n \"сочинить\",\n \"сочини\",\n \"мозговой штурм\",\n \"творческий\",\n \"представить\",\n \"придумай\",\n \"напиши\",\n ],\n\n // New dimension keyword lists (multilingual)\n imperativeVerbs: [\n // English\n \"build\",\n \"create\",\n \"implement\",\n \"design\",\n \"develop\",\n \"construct\",\n \"generate\",\n \"deploy\",\n \"configure\",\n \"set up\",\n // Chinese\n \"构建\",\n \"创建\",\n \"实现\",\n \"设计\",\n \"开发\",\n \"生成\",\n \"部署\",\n \"配置\",\n \"设置\",\n // Japanese\n \"構築\",\n \"作成\",\n \"実装\",\n \"設計\",\n \"開発\",\n \"生成\",\n \"デプロイ\",\n \"設定\",\n // Russian\n \"построить\",\n \"построй\",\n \"создать\",\n \"создай\",\n \"реализовать\",\n \"реализуй\",\n \"спроектировать\",\n \"разработать\",\n \"разработай\",\n \"сконструировать\",\n \"сгенерировать\",\n \"сгенерируй\",\n \"развернуть\",\n \"разверни\",\n \"настроить\",\n \"настрой\",\n ],\n constraintIndicators: [\n // English\n \"under\",\n \"at most\",\n \"at least\",\n \"within\",\n \"no more than\",\n \"o(\",\n \"maximum\",\n \"minimum\",\n \"limit\",\n \"budget\",\n // Chinese\n \"不超过\",\n \"至少\",\n \"最多\",\n \"在内\",\n \"最大\",\n \"最小\",\n \"限制\",\n \"预算\",\n // Japanese\n \"以下\",\n \"最大\",\n \"最小\",\n \"制限\",\n \"予算\",\n // Russian\n \"не более\",\n \"не менее\",\n \"как минимум\",\n \"в пределах\",\n \"максимум\",\n \"минимум\",\n \"ограничение\",\n \"бюджет\",\n ],\n outputFormatKeywords: [\n // English\n \"json\",\n \"yaml\",\n \"xml\",\n \"table\",\n \"csv\",\n \"markdown\",\n \"schema\",\n \"format as\",\n \"structured\",\n // Chinese\n \"表格\",\n \"格式化为\",\n \"结构化\",\n // Japanese\n \"テーブル\",\n \"フォーマット\",\n \"構造化\",\n // Russian\n \"таблица\",\n \"форматировать как\",\n \"структурированный\",\n ],\n referenceKeywords: [\n // English\n \"above\",\n \"below\",\n \"previous\",\n \"following\",\n \"the docs\",\n \"the api\",\n \"the code\",\n \"earlier\",\n \"attached\",\n // Chinese\n \"上面\",\n \"下面\",\n \"之前\",\n \"接下来\",\n \"文档\",\n \"代码\",\n \"附件\",\n // Japanese\n \"上記\",\n \"下記\",\n \"前の\",\n \"次の\",\n \"ドキュメント\",\n \"コード\",\n // Russian\n \"выше\",\n \"ниже\",\n \"предыдущий\",\n \"следующий\",\n \"документация\",\n \"код\",\n \"ранее\",\n \"вложение\",\n ],\n negationKeywords: [\n // English\n \"don't\",\n \"do not\",\n \"avoid\",\n \"never\",\n \"without\",\n \"except\",\n \"exclude\",\n \"no longer\",\n // Chinese\n \"不要\",\n \"避免\",\n \"从不\",\n \"没有\",\n \"除了\",\n \"排除\",\n // Japanese\n \"しないで\",\n \"避ける\",\n \"決して\",\n \"なしで\",\n \"除く\",\n // Russian\n \"не делай\",\n \"не надо\",\n \"нельзя\",\n \"избегать\",\n \"никогда\",\n \"без\",\n \"кроме\",\n \"исключить\",\n \"больше не\",\n ],\n domainSpecificKeywords: [\n // English\n \"quantum\",\n \"fpga\",\n \"vlsi\",\n \"risc-v\",\n \"asic\",\n \"photonics\",\n \"genomics\",\n \"proteomics\",\n \"topological\",\n \"homomorphic\",\n \"zero-knowledge\",\n \"lattice-based\",\n // Chinese\n \"量子\",\n \"光子学\",\n \"基因组学\",\n \"蛋白质组学\",\n \"拓扑\",\n \"同态\",\n \"零知识\",\n \"格密码\",\n // Japanese\n \"量子\",\n \"フォトニクス\",\n \"ゲノミクス\",\n \"トポロジカル\",\n // Russian\n \"квантовый\",\n \"фотоника\",\n \"геномика\",\n \"протеомика\",\n \"топологический\",\n \"гомоморфный\",\n \"с нулевым разглашением\",\n \"на основе решёток\",\n ],\n\n // Dimension weights (sum to 1.0)\n dimensionWeights: {\n tokenCount: 0.08,\n codePresence: 0.15,\n reasoningMarkers: 0.18,\n technicalTerms: 0.1,\n creativeMarkers: 0.05,\n simpleIndicators: 0.12,\n multiStepPatterns: 0.12,\n questionComplexity: 0.05,\n imperativeVerbs: 0.03,\n constraintCount: 0.04,\n outputFormat: 0.03,\n referenceComplexity: 0.02,\n negationComplexity: 0.01,\n domainSpecificity: 0.02,\n },\n\n // Tier boundaries on weighted score axis\n tierBoundaries: {\n simpleMedium: 0.0,\n mediumComplex: 0.15,\n complexReasoning: 0.25,\n },\n\n // Sigmoid steepness for confidence calibration\n confidenceSteepness: 12,\n // Below this confidence → ambiguous (null tier)\n confidenceThreshold: 0.7,\n },\n\n tiers: {\n SIMPLE: {\n primary: \"google/gemini-2.5-flash\",\n fallback: [\"deepseek/deepseek-chat\", \"openai/gpt-4o-mini\"],\n },\n MEDIUM: {\n primary: \"deepseek/deepseek-chat\",\n fallback: [\"google/gemini-2.5-flash\", \"openai/gpt-4o-mini\"],\n },\n COMPLEX: {\n primary: \"anthropic/claude-opus-4\",\n fallback: [\"anthropic/claude-sonnet-4\", \"openai/gpt-4o\"],\n },\n REASONING: {\n primary: \"deepseek/deepseek-reasoner\",\n fallback: [\"moonshot/kimi-k2.5\", \"google/gemini-2.5-pro\"],\n },\n },\n\n overrides: {\n maxTokensForceComplex: 100_000,\n structuredOutputMinTier: \"MEDIUM\",\n ambiguousDefaultTier: \"MEDIUM\",\n },\n};\n","/**\n * Smart Router Entry Point\n *\n * Classifies requests and routes to the cheapest capable model.\n * 100% local — rules-based scoring handles all requests in <1ms.\n * Ambiguous cases default to configurable tier (MEDIUM by default).\n */\n\nimport type { Tier, RoutingDecision, RoutingConfig } from \"./types.js\";\nimport { classifyByRules } from \"./rules.js\";\nimport { selectModel, type ModelPricing } from \"./selector.js\";\n\nexport type RouterOptions = {\n config: RoutingConfig;\n modelPricing: Map<string, ModelPricing>;\n};\n\n/**\n * Route a request to the cheapest capable model.\n *\n * 1. Check overrides (large context, structured output)\n * 2. Run rule-based classifier (14 weighted dimensions, <1ms)\n * 3. If ambiguous, default to configurable tier (no external API calls)\n * 4. Select model for tier\n * 5. Return RoutingDecision with metadata\n */\nexport function route(\n prompt: string,\n systemPrompt: string | undefined,\n maxOutputTokens: number,\n options: RouterOptions,\n): RoutingDecision {\n const { config, modelPricing } = options;\n\n // Estimate input tokens (~4 chars per token)\n const fullText = `${systemPrompt ?? \"\"} ${prompt}`;\n const estimatedTokens = Math.ceil(fullText.length / 4);\n\n // --- Override: large context → force COMPLEX ---\n if (estimatedTokens > config.overrides.maxTokensForceComplex) {\n return selectModel(\n \"COMPLEX\",\n 0.95,\n \"rules\",\n `Input exceeds ${config.overrides.maxTokensForceComplex} tokens`,\n config.tiers,\n modelPricing,\n estimatedTokens,\n maxOutputTokens,\n );\n }\n\n // Structured output detection\n const hasStructuredOutput = systemPrompt ? /json|structured|schema/i.test(systemPrompt) : false;\n\n // --- Rule-based classification ---\n const ruleResult = classifyByRules(prompt, systemPrompt, estimatedTokens, config.scoring);\n\n let tier: Tier;\n let confidence: number;\n const method: \"rules\" | \"llm\" = \"rules\";\n let reasoning = `score=${ruleResult.score} | ${ruleResult.signals.join(\", \")}`;\n\n if (ruleResult.tier !== null) {\n tier = ruleResult.tier;\n confidence = ruleResult.confidence;\n } else {\n // Ambiguous — default to configurable tier (no external API call)\n tier = config.overrides.ambiguousDefaultTier;\n confidence = 0.5;\n reasoning += ` | ambiguous -> default: ${tier}`;\n }\n\n // Apply structured output minimum tier\n if (hasStructuredOutput) {\n const tierRank: Record<Tier, number> = { SIMPLE: 0, MEDIUM: 1, COMPLEX: 2, REASONING: 3 };\n const minTier = config.overrides.structuredOutputMinTier;\n if (tierRank[tier] < tierRank[minTier]) {\n reasoning += ` | upgraded to ${minTier} (structured output)`;\n tier = minTier;\n }\n }\n\n return selectModel(\n tier,\n confidence,\n method,\n reasoning,\n config.tiers,\n modelPricing,\n estimatedTokens,\n maxOutputTokens,\n );\n}\n\nexport { getFallbackChain } from \"./selector.js\";\nexport { DEFAULT_ROUTING_CONFIG } from \"./config.js\";\nexport type { RoutingDecision, Tier, RoutingConfig } from \"./types.js\";\nexport type { ModelPricing } from \"./selector.js\";\n","/**\n * Usage Logger\n *\n * Logs every LLM request as a JSON line to a daily log file.\n * Files: ~/.openclaw/blockrun/logs/usage-YYYY-MM-DD.jsonl\n *\n * MVP: append-only JSON lines. No rotation, no cleanup.\n * Logging never breaks the request flow — all errors are swallowed.\n */\n\nimport { appendFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\nexport type UsageEntry = {\n timestamp: string;\n model: string;\n cost: number;\n latencyMs: number;\n};\n\nconst LOG_DIR = join(homedir(), \".openclaw\", \"blockrun\", \"logs\");\nlet dirReady = false;\n\nasync function ensureDir(): Promise<void> {\n if (dirReady) return;\n await mkdir(LOG_DIR, { recursive: true });\n dirReady = true;\n}\n\n/**\n * Log a usage entry as a JSON line.\n */\nexport async function logUsage(entry: UsageEntry): Promise<void> {\n try {\n await ensureDir();\n const date = entry.timestamp.slice(0, 10); // YYYY-MM-DD\n const file = join(LOG_DIR, `usage-${date}.jsonl`);\n await appendFile(file, JSON.stringify(entry) + \"\\n\");\n } catch {\n // Never break the request flow\n }\n}\n","/**\n * Request Deduplication\n *\n * Prevents double-charging when OpenClaw retries a request after timeout.\n * Tracks in-flight requests and caches completed responses for a short TTL.\n */\n\nimport { createHash } from \"node:crypto\";\n\nexport type CachedResponse = {\n status: number;\n headers: Record<string, string>;\n body: Buffer;\n completedAt: number;\n};\n\ntype InflightEntry = {\n resolve: (result: CachedResponse) => void;\n waiters: Promise<CachedResponse>[];\n};\n\nconst DEFAULT_TTL_MS = 30_000; // 30 seconds\nconst MAX_BODY_SIZE = 1_048_576; // 1MB\n\n/**\n * Canonicalize JSON by sorting object keys recursively.\n * Ensures identical logical content produces identical string regardless of field order.\n */\nfunction canonicalize(obj: unknown): unknown {\n if (obj === null || typeof obj !== \"object\") {\n return obj;\n }\n if (Array.isArray(obj)) {\n return obj.map(canonicalize);\n }\n const sorted: Record<string, unknown> = {};\n for (const key of Object.keys(obj).sort()) {\n sorted[key] = canonicalize((obj as Record<string, unknown>)[key]);\n }\n return sorted;\n}\n\n/**\n * Strip OpenClaw-injected timestamps from message content.\n * Format: [DAY YYYY-MM-DD HH:MM TZ] at the start of messages.\n * Example: [SUN 2026-02-07 13:30 PST] Hello world\n *\n * This ensures requests with different timestamps but same content hash identically.\n */\nconst TIMESTAMP_PATTERN = /^\\[\\w{3}\\s+\\d{4}-\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}\\s+\\w+\\]\\s*/;\n\nfunction stripTimestamps(obj: unknown): unknown {\n if (obj === null || typeof obj !== \"object\") {\n return obj;\n }\n if (Array.isArray(obj)) {\n return obj.map(stripTimestamps);\n }\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n if (key === \"content\" && typeof value === \"string\") {\n // Strip timestamp prefix from message content\n result[key] = value.replace(TIMESTAMP_PATTERN, \"\");\n } else {\n result[key] = stripTimestamps(value);\n }\n }\n return result;\n}\n\nexport class RequestDeduplicator {\n private inflight = new Map<string, InflightEntry>();\n private completed = new Map<string, CachedResponse>();\n private ttlMs: number;\n\n constructor(ttlMs = DEFAULT_TTL_MS) {\n this.ttlMs = ttlMs;\n }\n\n /** Hash request body to create a dedup key. */\n static hash(body: Buffer): string {\n // Canonicalize JSON to ensure consistent hashing regardless of field order.\n // Also strip OpenClaw-injected timestamps so retries with different timestamps\n // still match the same dedup key.\n let content = body;\n try {\n const parsed = JSON.parse(body.toString());\n const stripped = stripTimestamps(parsed);\n const canonical = canonicalize(stripped);\n content = Buffer.from(JSON.stringify(canonical));\n } catch {\n // Not valid JSON, use raw bytes\n }\n return createHash(\"sha256\").update(content).digest(\"hex\").slice(0, 16);\n }\n\n /** Check if a response is cached for this key. */\n getCached(key: string): CachedResponse | undefined {\n const entry = this.completed.get(key);\n if (!entry) return undefined;\n if (Date.now() - entry.completedAt > this.ttlMs) {\n this.completed.delete(key);\n return undefined;\n }\n return entry;\n }\n\n /** Check if a request with this key is currently in-flight. Returns a promise to wait on. */\n getInflight(key: string): Promise<CachedResponse> | undefined {\n const entry = this.inflight.get(key);\n if (!entry) return undefined;\n const promise = new Promise<CachedResponse>((resolve) => {\n // Will be resolved when the original request completes\n entry.waiters.push(\n new Promise<CachedResponse>((r) => {\n const orig = entry.resolve;\n entry.resolve = (result) => {\n orig(result);\n resolve(result);\n r(result);\n };\n }),\n );\n });\n return promise;\n }\n\n /** Mark a request as in-flight. */\n markInflight(key: string): void {\n this.inflight.set(key, {\n resolve: () => {},\n waiters: [],\n });\n }\n\n /** Complete an in-flight request — cache result and notify waiters. */\n complete(key: string, result: CachedResponse): void {\n // Only cache responses within size limit\n if (result.body.length <= MAX_BODY_SIZE) {\n this.completed.set(key, result);\n }\n\n const entry = this.inflight.get(key);\n if (entry) {\n entry.resolve(result);\n this.inflight.delete(key);\n }\n\n this.prune();\n }\n\n /** Remove an in-flight entry on error (don't cache failures). */\n removeInflight(key: string): void {\n this.inflight.delete(key);\n }\n\n /** Prune expired completed entries. */\n private prune(): void {\n const now = Date.now();\n for (const [key, entry] of this.completed) {\n if (now - entry.completedAt > this.ttlMs) {\n this.completed.delete(key);\n }\n }\n }\n}\n","/**\n * Balance Monitor for ClawRouter\n *\n * Monitors USDC balance on Base network with intelligent caching.\n * Provides pre-request balance checks to prevent failed payments.\n *\n * Caching Strategy:\n * - TTL: 30 seconds (balance is cached to avoid excessive RPC calls)\n * - Optimistic deduction: after successful payment, subtract estimated cost from cache\n * - Invalidation: on payment failure, immediately refresh from RPC\n */\n\nimport { createPublicClient, http, erc20Abi } from \"viem\";\nimport { base } from \"viem/chains\";\nimport { RpcError } from \"./errors.js\";\n\n/** USDC contract address on Base mainnet */\nconst USDC_BASE = \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\" as const;\n\n/** Cache TTL in milliseconds (30 seconds) */\nconst CACHE_TTL_MS = 30_000;\n\n/** Balance thresholds in USDC smallest unit (6 decimals) */\nexport const BALANCE_THRESHOLDS = {\n /** Low balance warning threshold: $1.00 */\n LOW_BALANCE_MICROS: 1_000_000n,\n /** Effectively zero threshold: $0.0001 (covers dust/rounding) */\n ZERO_THRESHOLD: 100n,\n} as const;\n\n/** Balance information returned by checkBalance() */\nexport type BalanceInfo = {\n /** Raw balance in USDC smallest unit (6 decimals) */\n balance: bigint;\n /** Formatted balance as \"$X.XX\" */\n balanceUSD: string;\n /** True if balance < $1.00 */\n isLow: boolean;\n /** True if balance < $0.0001 (effectively zero) */\n isEmpty: boolean;\n /** Wallet address for funding instructions */\n walletAddress: string;\n};\n\n/** Result from checkSufficient() */\nexport type SufficiencyResult = {\n /** True if balance >= estimated cost */\n sufficient: boolean;\n /** Current balance info */\n info: BalanceInfo;\n /** If insufficient, the shortfall as \"$X.XX\" */\n shortfall?: string;\n};\n\n/**\n * Monitors USDC balance on Base network.\n *\n * Usage:\n * const monitor = new BalanceMonitor(\"0x...\");\n * const info = await monitor.checkBalance();\n * if (info.isLow) console.warn(\"Low balance!\");\n */\nexport class BalanceMonitor {\n private readonly client;\n private readonly walletAddress: `0x${string}`;\n\n /** Cached balance (null = not yet fetched) */\n private cachedBalance: bigint | null = null;\n /** Timestamp when cache was last updated */\n private cachedAt = 0;\n\n constructor(walletAddress: string) {\n this.walletAddress = walletAddress as `0x${string}`;\n this.client = createPublicClient({\n chain: base,\n transport: http(undefined, {\n timeout: 10_000, // 10 second timeout to prevent hanging on slow RPC\n }),\n });\n }\n\n /**\n * Check current USDC balance.\n * Uses cache if valid, otherwise fetches from RPC.\n */\n async checkBalance(): Promise<BalanceInfo> {\n const now = Date.now();\n\n // Use cache if valid\n if (this.cachedBalance !== null && now - this.cachedAt < CACHE_TTL_MS) {\n return this.buildInfo(this.cachedBalance);\n }\n\n // Fetch from RPC\n const balance = await this.fetchBalance();\n this.cachedBalance = balance;\n this.cachedAt = now;\n\n return this.buildInfo(balance);\n }\n\n /**\n * Check if balance is sufficient for an estimated cost.\n *\n * @param estimatedCostMicros - Estimated cost in USDC smallest unit (6 decimals)\n */\n async checkSufficient(estimatedCostMicros: bigint): Promise<SufficiencyResult> {\n const info = await this.checkBalance();\n\n if (info.balance >= estimatedCostMicros) {\n return { sufficient: true, info };\n }\n\n const shortfall = estimatedCostMicros - info.balance;\n return {\n sufficient: false,\n info,\n shortfall: this.formatUSDC(shortfall),\n };\n }\n\n /**\n * Optimistically deduct estimated cost from cached balance.\n * Call this after a successful payment to keep cache accurate.\n *\n * @param amountMicros - Amount to deduct in USDC smallest unit\n */\n deductEstimated(amountMicros: bigint): void {\n if (this.cachedBalance !== null && this.cachedBalance >= amountMicros) {\n this.cachedBalance -= amountMicros;\n }\n }\n\n /**\n * Invalidate cache, forcing next checkBalance() to fetch from RPC.\n * Call this after a payment failure to get accurate balance.\n */\n invalidate(): void {\n this.cachedBalance = null;\n this.cachedAt = 0;\n }\n\n /**\n * Force refresh balance from RPC (ignores cache).\n */\n async refresh(): Promise<BalanceInfo> {\n this.invalidate();\n return this.checkBalance();\n }\n\n /**\n * Format USDC amount (in micros) as \"$X.XX\".\n */\n formatUSDC(amountMicros: bigint): string {\n // USDC has 6 decimals\n const dollars = Number(amountMicros) / 1_000_000;\n return `$${dollars.toFixed(2)}`;\n }\n\n /**\n * Get the wallet address being monitored.\n */\n getWalletAddress(): string {\n return this.walletAddress;\n }\n\n /** Fetch balance from RPC */\n private async fetchBalance(): Promise<bigint> {\n try {\n const balance = await this.client.readContract({\n address: USDC_BASE,\n abi: erc20Abi,\n functionName: \"balanceOf\",\n args: [this.walletAddress],\n });\n return balance;\n } catch (error) {\n // Throw typed error instead of silently returning 0\n // This allows callers to distinguish \"node down\" from \"wallet empty\"\n throw new RpcError(error instanceof Error ? error.message : \"Unknown error\", error);\n }\n }\n\n /** Build BalanceInfo from raw balance */\n private buildInfo(balance: bigint): BalanceInfo {\n return {\n balance,\n balanceUSD: this.formatUSDC(balance),\n isLow: balance < BALANCE_THRESHOLDS.LOW_BALANCE_MICROS,\n isEmpty: balance < BALANCE_THRESHOLDS.ZERO_THRESHOLD,\n walletAddress: this.walletAddress,\n };\n }\n}\n","/**\n * Typed Error Classes for ClawRouter\n *\n * Provides structured errors for balance-related failures with\n * all necessary information for user-friendly error messages.\n */\n\n/**\n * Thrown when wallet has insufficient USDC balance for a request.\n */\nexport class InsufficientFundsError extends Error {\n readonly code = \"INSUFFICIENT_FUNDS\" as const;\n readonly currentBalanceUSD: string;\n readonly requiredUSD: string;\n readonly walletAddress: string;\n\n constructor(opts: { currentBalanceUSD: string; requiredUSD: string; walletAddress: string }) {\n super(\n `Insufficient USDC balance. Current: ${opts.currentBalanceUSD}, Required: ${opts.requiredUSD}. Fund wallet: ${opts.walletAddress}`,\n );\n this.name = \"InsufficientFundsError\";\n this.currentBalanceUSD = opts.currentBalanceUSD;\n this.requiredUSD = opts.requiredUSD;\n this.walletAddress = opts.walletAddress;\n }\n}\n\n/**\n * Thrown when wallet has no USDC balance (or effectively zero).\n */\nexport class EmptyWalletError extends Error {\n readonly code = \"EMPTY_WALLET\" as const;\n readonly walletAddress: string;\n\n constructor(walletAddress: string) {\n super(`No USDC balance. Fund wallet to use ClawRouter: ${walletAddress}`);\n this.name = \"EmptyWalletError\";\n this.walletAddress = walletAddress;\n }\n}\n\n/**\n * Type guard to check if an error is InsufficientFundsError.\n */\nexport function isInsufficientFundsError(error: unknown): error is InsufficientFundsError {\n return error instanceof Error && (error as InsufficientFundsError).code === \"INSUFFICIENT_FUNDS\";\n}\n\n/**\n * Type guard to check if an error is EmptyWalletError.\n */\nexport function isEmptyWalletError(error: unknown): error is EmptyWalletError {\n return error instanceof Error && (error as EmptyWalletError).code === \"EMPTY_WALLET\";\n}\n\n/**\n * Type guard to check if an error is a balance-related error.\n */\nexport function isBalanceError(error: unknown): error is InsufficientFundsError | EmptyWalletError {\n return isInsufficientFundsError(error) || isEmptyWalletError(error);\n}\n\n/**\n * Thrown when RPC call fails (network error, node down, etc).\n * Distinguishes infrastructure failures from actual empty wallets.\n */\nexport class RpcError extends Error {\n readonly code = \"RPC_ERROR\" as const;\n readonly originalError: unknown;\n\n constructor(message: string, originalError?: unknown) {\n super(`RPC error: ${message}. Check network connectivity.`);\n this.name = \"RpcError\";\n this.originalError = originalError;\n }\n}\n\n/**\n * Type guard to check if an error is RpcError.\n */\nexport function isRpcError(error: unknown): error is RpcError {\n return error instanceof Error && (error as RpcError).code === \"RPC_ERROR\";\n}\n","/**\n * Single source of truth for version.\n * Reads from package.json at build time via tsup's define.\n */\nimport { createRequire } from \"node:module\";\nimport { fileURLToPath } from \"node:url\";\nimport { dirname, join } from \"node:path\";\n\n// Read package.json at runtime\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n// In dist/, go up one level to find package.json\nconst require = createRequire(import.meta.url);\nconst pkg = require(join(__dirname, \"..\", \"package.json\")) as { version: string };\n\nexport const VERSION = pkg.version;\nexport const USER_AGENT = `clawrouter/${VERSION}`;\n","/**\n * BlockRun Auth Methods for OpenClaw\n *\n * Provides wallet-based authentication for the BlockRun provider.\n * Operators configure their wallet private key, which is used to\n * sign x402 micropayments for LLM inference.\n *\n * Three methods:\n * 1. Auto-generate — create a new wallet on first run, save to ~/.openclaw/blockrun/wallet.key\n * 2. Environment variable — read from BLOCKRUN_WALLET_KEY\n * 3. Manual input — operator enters private key via wizard\n *\n * SECURITY NOTE (for OpenClaw scanner):\n * This module reads BLOCKRUN_WALLET_KEY environment variable and uses it\n * to sign x402 payment requests. This is INTENTIONAL and REQUIRED behavior:\n * - The wallet key signs USDC payments on Base L2 for each LLM API call\n * - Without the key, ClawRouter cannot authorize payments to BlockRun\n * - The key is NEVER transmitted over the network, only used locally for signing\n * - This is standard x402 payment flow, not credential harvesting\n *\n * @see https://x402.org - x402 payment protocol specification\n * @see https://blockrun.ai/docs - BlockRun API documentation\n * @openclaw-security env-access=BLOCKRUN_WALLET_KEY purpose=x402-payment-signing\n */\n\nimport { writeFile, readFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { generatePrivateKey, privateKeyToAccount } from \"viem/accounts\";\nimport type { ProviderAuthMethod, ProviderAuthContext, ProviderAuthResult } from \"./types.js\";\n\nconst WALLET_DIR = join(homedir(), \".openclaw\", \"blockrun\");\nconst WALLET_FILE = join(WALLET_DIR, \"wallet.key\");\n\n/**\n * Try to load a previously auto-generated wallet key from disk.\n */\nasync function loadSavedWallet(): Promise<string | undefined> {\n try {\n const key = (await readFile(WALLET_FILE, \"utf-8\")).trim();\n if (key.startsWith(\"0x\") && key.length === 66) return key;\n } catch {\n // File doesn't exist yet\n }\n return undefined;\n}\n\n/**\n * Generate a new wallet, save to disk, return the private key.\n */\nasync function generateAndSaveWallet(): Promise<{ key: string; address: string }> {\n const key = generatePrivateKey();\n const account = privateKeyToAccount(key);\n await mkdir(WALLET_DIR, { recursive: true });\n await writeFile(WALLET_FILE, key + \"\\n\", { mode: 0o600 });\n return { key, address: account.address };\n}\n\n/**\n * Resolve wallet key: load saved → env var → auto-generate.\n * Called by index.ts before the auth wizard runs.\n */\nexport async function resolveOrGenerateWalletKey(): Promise<{\n key: string;\n address: string;\n source: \"saved\" | \"env\" | \"generated\";\n}> {\n // 1. Previously saved wallet\n const saved = await loadSavedWallet();\n if (saved) {\n const account = privateKeyToAccount(saved as `0x${string}`);\n return { key: saved, address: account.address, source: \"saved\" };\n }\n\n // 2. Environment variable\n const envKey = process.env.BLOCKRUN_WALLET_KEY;\n if (typeof envKey === \"string\" && envKey.startsWith(\"0x\") && envKey.length === 66) {\n const account = privateKeyToAccount(envKey as `0x${string}`);\n return { key: envKey, address: account.address, source: \"env\" };\n }\n\n // 3. Auto-generate\n const { key, address } = await generateAndSaveWallet();\n return { key, address, source: \"generated\" };\n}\n\n/**\n * Auth method: operator enters their wallet private key directly.\n */\nexport const walletKeyAuth: ProviderAuthMethod = {\n id: \"wallet-key\",\n label: \"Wallet Private Key\",\n hint: \"Enter your EVM wallet private key (0x...) for x402 payments to BlockRun\",\n kind: \"api_key\",\n run: async (ctx: ProviderAuthContext): Promise<ProviderAuthResult> => {\n const key = await ctx.prompter.text({\n message: \"Enter your wallet private key (0x...)\",\n validate: (value: string) => {\n const trimmed = value.trim();\n if (!trimmed.startsWith(\"0x\")) return \"Key must start with 0x\";\n if (trimmed.length !== 66) return \"Key must be 66 characters (0x + 64 hex)\";\n if (!/^0x[0-9a-fA-F]{64}$/.test(trimmed)) return \"Key must be valid hex\";\n return undefined;\n },\n });\n\n if (!key || typeof key !== \"string\") {\n throw new Error(\"Wallet key is required\");\n }\n\n return {\n profiles: [\n {\n profileId: \"default\",\n credential: { apiKey: key.trim() },\n },\n ],\n notes: [\n \"Wallet key stored securely in OpenClaw credentials.\",\n \"Your wallet signs x402 USDC payments on Base for each LLM call.\",\n \"Fund your wallet with USDC on Base to start using BlockRun models.\",\n ],\n };\n },\n};\n\n/**\n * Auth method: read wallet key from BLOCKRUN_WALLET_KEY environment variable.\n */\nexport const envKeyAuth: ProviderAuthMethod = {\n id: \"env-key\",\n label: \"Environment Variable\",\n hint: \"Use BLOCKRUN_WALLET_KEY environment variable\",\n kind: \"api_key\",\n run: async (): Promise<ProviderAuthResult> => {\n const key = process.env.BLOCKRUN_WALLET_KEY;\n\n if (!key) {\n throw new Error(\n \"BLOCKRUN_WALLET_KEY environment variable is not set. \" +\n \"Set it to your EVM wallet private key (0x...).\",\n );\n }\n\n return {\n profiles: [\n {\n profileId: \"default\",\n credential: { apiKey: key.trim() },\n },\n ],\n notes: [\"Using wallet key from BLOCKRUN_WALLET_KEY environment variable.\"],\n };\n },\n};\n","/**\n * @blockrun/clawrouter\n *\n * Smart LLM router for OpenClaw — 30+ models, x402 micropayments, 78% cost savings.\n * Routes each request to the cheapest model that can handle it.\n *\n * Usage:\n * # Install the plugin\n * openclaw plugins install @blockrun/clawrouter\n *\n * # Fund your wallet with USDC on Base (address printed on install)\n *\n * # Use smart routing (auto-picks cheapest model)\n * openclaw models set blockrun/auto\n *\n * # Or use any specific BlockRun model\n * openclaw models set openai/gpt-5.2\n */\n\nimport type { OpenClawPluginDefinition, OpenClawPluginApi } from \"./types.js\";\nimport { blockrunProvider, setActiveProxy } from \"./provider.js\";\nimport { startProxy, getProxyPort } from \"./proxy.js\";\nimport { resolveOrGenerateWalletKey } from \"./auth.js\";\nimport type { RoutingConfig } from \"./router/index.js\";\nimport { BalanceMonitor } from \"./balance.js\";\nimport { OPENCLAW_MODELS } from \"./models.js\";\nimport { readFileSync, writeFileSync, existsSync, readdirSync, mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { VERSION } from \"./version.js\";\n\n/**\n * Detect if we're running in shell completion mode.\n * When `openclaw completion --shell zsh` runs, it loads plugins but only needs\n * the completion script output - any stdout logging pollutes the script and\n * causes zsh to interpret colored text like `[plugins]` as glob patterns.\n */\nfunction isCompletionMode(): boolean {\n const args = process.argv;\n // Check for: openclaw completion --shell <shell>\n // argv[0] = node/bun, argv[1] = openclaw, argv[2] = completion\n return args.some((arg, i) => arg === \"completion\" && i >= 1 && i <= 3);\n}\n\n/**\n * Inject BlockRun models config into OpenClaw config file.\n * This is required because registerProvider() alone doesn't make models available.\n */\nfunction injectModelsConfig(logger: { info: (msg: string) => void }): void {\n const configPath = join(homedir(), \".openclaw\", \"openclaw.json\");\n if (!existsSync(configPath)) {\n logger.info(\"OpenClaw config not found, skipping models injection\");\n return;\n }\n\n try {\n const config = JSON.parse(readFileSync(configPath, \"utf-8\"));\n\n // Track if we need to write\n let needsWrite = false;\n\n // Inject models config if not present\n if (!config.models) config.models = {};\n if (!config.models.providers) config.models.providers = {};\n\n const proxyPort = getProxyPort();\n const expectedBaseUrl = `http://127.0.0.1:${proxyPort}/v1`;\n\n if (!config.models.providers.blockrun) {\n config.models.providers.blockrun = {\n baseUrl: expectedBaseUrl,\n api: \"openai-completions\",\n // apiKey is required by pi-coding-agent's ModelRegistry for providers with models.\n // We use a placeholder since the proxy handles real x402 auth internally.\n apiKey: \"x402-proxy-handles-auth\",\n models: OPENCLAW_MODELS,\n };\n needsWrite = true;\n } else {\n // Update existing config if fields are missing or outdated\n if (config.models.providers.blockrun.baseUrl !== expectedBaseUrl) {\n config.models.providers.blockrun.baseUrl = expectedBaseUrl;\n needsWrite = true;\n }\n // Ensure apiKey is present (required by ModelRegistry for /model picker)\n if (!config.models.providers.blockrun.apiKey) {\n config.models.providers.blockrun.apiKey = \"x402-proxy-handles-auth\";\n needsWrite = true;\n }\n }\n\n // Set blockrun/auto as default model (path: agents.defaults.model.primary)\n if (!config.agents) config.agents = {};\n if (!config.agents.defaults) config.agents.defaults = {};\n if (!config.agents.defaults.model) config.agents.defaults.model = {};\n if (config.agents.defaults.model.primary !== \"blockrun/auto\") {\n config.agents.defaults.model.primary = \"blockrun/auto\";\n needsWrite = true;\n }\n\n if (needsWrite) {\n writeFileSync(configPath, JSON.stringify(config, null, 2));\n logger.info(\"Set default model to blockrun/auto (smart routing enabled)\");\n }\n } catch {\n // Silently fail — config injection is best-effort\n }\n}\n\n/**\n * Inject dummy auth profile for BlockRun into agent auth stores.\n * OpenClaw's agent system looks for auth credentials even if provider has auth: [].\n * We inject a placeholder so the lookup succeeds (proxy handles real auth internally).\n */\nfunction injectAuthProfile(logger: { info: (msg: string) => void }): void {\n const agentsDir = join(homedir(), \".openclaw\", \"agents\");\n\n // Create agents directory if it doesn't exist\n if (!existsSync(agentsDir)) {\n try {\n mkdirSync(agentsDir, { recursive: true });\n } catch (err) {\n logger.info(\n `Could not create agents dir: ${err instanceof Error ? err.message : String(err)}`,\n );\n return;\n }\n }\n\n try {\n // Find all agent directories\n let agents = readdirSync(agentsDir, { withFileTypes: true })\n .filter((d) => d.isDirectory())\n .map((d) => d.name);\n\n // Always ensure \"main\" agent has auth (most common agent)\n if (!agents.includes(\"main\")) {\n agents = [\"main\", ...agents];\n }\n\n for (const agentId of agents) {\n const authDir = join(agentsDir, agentId, \"agent\");\n const authPath = join(authDir, \"auth-profiles.json\");\n\n // Create agent dir if needed\n if (!existsSync(authDir)) {\n try {\n mkdirSync(authDir, { recursive: true });\n } catch {\n continue; // Skip if we can't create the dir\n }\n }\n\n // Load or create auth-profiles.json with correct OpenClaw format\n // Format: { version: 1, profiles: { \"provider:profileId\": { type, provider, key } } }\n let store: { version: number; profiles: Record<string, unknown> } = {\n version: 1,\n profiles: {},\n };\n if (existsSync(authPath)) {\n try {\n const existing = JSON.parse(readFileSync(authPath, \"utf-8\"));\n // Check if valid OpenClaw format (has version and profiles)\n if (existing.version && existing.profiles) {\n store = existing;\n }\n // Old format without version/profiles is discarded and recreated\n } catch {\n // Invalid JSON, use fresh store\n }\n }\n\n // Check if blockrun auth already exists (OpenClaw format: profiles[\"provider:profileId\"])\n const profileKey = \"blockrun:default\";\n if (store.profiles[profileKey]) {\n continue; // Already configured\n }\n\n // Inject placeholder auth for blockrun (OpenClaw format)\n // The proxy handles real x402 auth internally, this just satisfies OpenClaw's lookup\n store.profiles[profileKey] = {\n type: \"api_key\",\n provider: \"blockrun\",\n key: \"x402-proxy-handles-auth\",\n };\n\n try {\n writeFileSync(authPath, JSON.stringify(store, null, 2));\n logger.info(`Injected BlockRun auth profile for agent: ${agentId}`);\n } catch (err) {\n logger.info(\n `Could not inject auth for ${agentId}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n } catch (err) {\n logger.info(`Auth injection failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n}\n\n// Store active proxy handle for cleanup on gateway_stop\nlet activeProxyHandle: Awaited<ReturnType<typeof startProxy>> | null = null;\n\n/**\n * Start the x402 proxy in the background.\n * Called from register() because OpenClaw's loader only invokes register(),\n * treating activate() as an alias (def.register ?? def.activate).\n */\nasync function startProxyInBackground(api: OpenClawPluginApi): Promise<void> {\n // Resolve wallet key: saved file → env var → auto-generate\n const { key: walletKey, address, source } = await resolveOrGenerateWalletKey();\n\n // Log wallet source\n if (source === \"generated\") {\n api.logger.info(`Generated new wallet: ${address}`);\n api.logger.info(`Fund with USDC on Base to start using ClawRouter.`);\n } else if (source === \"saved\") {\n api.logger.info(`Using saved wallet: ${address}`);\n } else {\n api.logger.info(`Using wallet from BLOCKRUN_WALLET_KEY: ${address}`);\n }\n\n // --- Startup balance check ---\n const startupMonitor = new BalanceMonitor(address);\n try {\n const startupBalance = await startupMonitor.checkBalance();\n if (startupBalance.isEmpty) {\n api.logger.warn(`[!] No USDC balance. Fund wallet to use ClawRouter: ${address}`);\n } else if (startupBalance.isLow) {\n api.logger.warn(\n `[!] Low balance: ${startupBalance.balanceUSD} remaining. Fund wallet: ${address}`,\n );\n } else {\n api.logger.info(`Wallet balance: ${startupBalance.balanceUSD}`);\n }\n } catch (err) {\n api.logger.warn(\n `Could not check wallet balance: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n // Resolve routing config overrides from plugin config\n const routingConfig = api.pluginConfig?.routing as Partial<RoutingConfig> | undefined;\n\n const proxy = await startProxy({\n walletKey,\n routingConfig,\n onReady: (port) => {\n api.logger.info(`BlockRun x402 proxy listening on port ${port}`);\n },\n onError: (error) => {\n api.logger.error(`BlockRun proxy error: ${error.message}`);\n },\n onRouted: (decision) => {\n const cost = decision.costEstimate.toFixed(4);\n const saved = (decision.savings * 100).toFixed(0);\n api.logger.info(\n `[${decision.tier}] ${decision.model} $${cost} (saved ${saved}%) | ${decision.reasoning}`,\n );\n },\n onLowBalance: (info) => {\n api.logger.warn(`[!] Low balance: ${info.balanceUSD}. Fund wallet: ${info.walletAddress}`);\n },\n onInsufficientFunds: (info) => {\n api.logger.error(\n `[!] Insufficient funds. Balance: ${info.balanceUSD}, Needed: ${info.requiredUSD}. Fund wallet: ${info.walletAddress}`,\n );\n },\n });\n\n setActiveProxy(proxy);\n activeProxyHandle = proxy;\n api.logger.info(`BlockRun provider active — ${proxy.baseUrl}/v1 (smart routing enabled)`);\n}\n\nconst plugin: OpenClawPluginDefinition = {\n id: \"clawrouter\",\n name: \"ClawRouter\",\n description: \"Smart LLM router — 30+ models, x402 micropayments, 78% cost savings\",\n version: VERSION,\n\n register(api: OpenClawPluginApi) {\n // Check if ClawRouter is disabled via environment variable\n // Usage: CLAWROUTER_DISABLED=true openclaw gateway start\n const isDisabled =\n process.env.CLAWROUTER_DISABLED === \"true\" || process.env.CLAWROUTER_DISABLED === \"1\";\n if (isDisabled) {\n api.logger.info(\"ClawRouter disabled (CLAWROUTER_DISABLED=true). Using default routing.\");\n return;\n }\n\n // Skip heavy initialization in completion mode — only completion script is needed\n // Logging to stdout during completion pollutes the script and causes zsh errors\n if (isCompletionMode()) {\n api.registerProvider(blockrunProvider);\n return;\n }\n\n // Register BlockRun as a provider (sync — available immediately)\n api.registerProvider(blockrunProvider);\n\n // Inject models config into OpenClaw config file\n // This persists the config so models are recognized on restart\n injectModelsConfig(api.logger);\n\n // Inject dummy auth profiles into agent auth stores\n // OpenClaw's agent system looks for auth even if provider has auth: []\n injectAuthProfile(api.logger);\n\n // Also set runtime config for immediate availability\n const runtimePort = getProxyPort();\n if (!api.config.models) {\n api.config.models = { providers: {} };\n }\n if (!api.config.models.providers) {\n api.config.models.providers = {};\n }\n api.config.models.providers.blockrun = {\n baseUrl: `http://127.0.0.1:${runtimePort}/v1`,\n api: \"openai-completions\",\n // apiKey is required by pi-coding-agent's ModelRegistry for providers with models.\n apiKey: \"x402-proxy-handles-auth\",\n models: OPENCLAW_MODELS,\n };\n\n // Set blockrun/auto as default for smart routing (agents.defaults.model.primary)\n if (!api.config.agents) api.config.agents = {};\n const agents = api.config.agents as Record<string, unknown>;\n if (!agents.defaults) agents.defaults = {};\n const defaults = agents.defaults as Record<string, unknown>;\n if (!defaults.model) defaults.model = {};\n (defaults.model as Record<string, unknown>).primary = \"blockrun/auto\";\n\n api.logger.info(\"BlockRun provider registered (30+ models via x402)\");\n\n // Register a service with stop() for cleanup on gateway shutdown\n // This prevents EADDRINUSE when the gateway restarts\n api.registerService({\n id: \"clawrouter-proxy\",\n start: () => {\n // No-op: proxy is started in register() below for immediate availability\n },\n stop: async () => {\n // Close proxy on gateway shutdown to release port 8402\n if (activeProxyHandle) {\n try {\n await activeProxyHandle.close();\n api.logger.info(\"BlockRun proxy closed\");\n } catch (err) {\n api.logger.warn(\n `Failed to close proxy: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n activeProxyHandle = null;\n }\n },\n });\n\n // Start x402 proxy in background (fire-and-forget)\n // Must happen in register() for CLI command support (services only start with gateway)\n startProxyInBackground(api).catch((err) => {\n api.logger.error(\n `Failed to start BlockRun proxy: ${err instanceof Error ? err.message : String(err)}`,\n );\n });\n },\n};\n\nexport default plugin;\n\n// Re-export for programmatic use\nexport { startProxy, getProxyPort } from \"./proxy.js\";\nexport type { ProxyOptions, ProxyHandle, LowBalanceInfo, InsufficientFundsInfo } from \"./proxy.js\";\nexport { blockrunProvider } from \"./provider.js\";\nexport { OPENCLAW_MODELS, BLOCKRUN_MODELS, buildProviderModels } from \"./models.js\";\nexport { route, DEFAULT_ROUTING_CONFIG } from \"./router/index.js\";\nexport type { RoutingDecision, RoutingConfig, Tier } from \"./router/index.js\";\nexport { logUsage } from \"./logger.js\";\nexport type { UsageEntry } from \"./logger.js\";\nexport { RequestDeduplicator } from \"./dedup.js\";\nexport type { CachedResponse } from \"./dedup.js\";\nexport { PaymentCache } from \"./payment-cache.js\";\nexport type { CachedPaymentParams } from \"./payment-cache.js\";\nexport { createPaymentFetch } from \"./x402.js\";\nexport type { PreAuthParams, PaymentFetchResult } from \"./x402.js\";\nexport { BalanceMonitor, BALANCE_THRESHOLDS } from \"./balance.js\";\nexport type { BalanceInfo, SufficiencyResult } from \"./balance.js\";\nexport {\n InsufficientFundsError,\n EmptyWalletError,\n RpcError,\n isInsufficientFundsError,\n isEmptyWalletError,\n isBalanceError,\n isRpcError,\n} from \"./errors.js\";\nexport { fetchWithRetry, isRetryable, DEFAULT_RETRY_CONFIG } from \"./retry.js\";\nexport type { RetryConfig } from \"./retry.js\";\n","/**\n * Retry Logic for ClawRouter\n *\n * Provides fetch wrapper with exponential backoff for transient errors.\n * Retries on 429 (rate limit), 502, 503, 504 (server errors).\n */\n\n/** Configuration for retry behavior */\nexport type RetryConfig = {\n /** Maximum number of retries (default: 2) */\n maxRetries: number;\n /** Base delay in ms for exponential backoff (default: 500) */\n baseDelayMs: number;\n /** HTTP status codes that trigger a retry (default: [429, 502, 503, 504]) */\n retryableCodes: number[];\n};\n\n/** Default retry configuration */\nexport const DEFAULT_RETRY_CONFIG: RetryConfig = {\n maxRetries: 2,\n baseDelayMs: 500,\n retryableCodes: [429, 502, 503, 504],\n};\n\n/** Sleep for a given number of milliseconds */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Wrap a fetch-like function with retry logic and exponential backoff.\n *\n * @param fetchFn - The fetch function to wrap (can be standard fetch or x402 payFetch)\n * @param url - URL to fetch\n * @param init - Fetch init options\n * @param config - Retry configuration (optional, uses defaults)\n * @returns Response from successful fetch or last failed attempt\n *\n * @example\n * ```typescript\n * const response = await fetchWithRetry(\n * fetch,\n * \"https://api.example.com/endpoint\",\n * { method: \"POST\", body: JSON.stringify(data) },\n * { maxRetries: 3 }\n * );\n * ```\n */\nexport async function fetchWithRetry(\n fetchFn: (url: string, init?: RequestInit) => Promise<Response>,\n url: string,\n init?: RequestInit,\n config?: Partial<RetryConfig>,\n): Promise<Response> {\n const cfg: RetryConfig = {\n ...DEFAULT_RETRY_CONFIG,\n ...config,\n };\n\n let lastError: Error | undefined;\n let lastResponse: Response | undefined;\n\n for (let attempt = 0; attempt <= cfg.maxRetries; attempt++) {\n try {\n const response = await fetchFn(url, init);\n\n // Success or non-retryable status — return immediately\n if (!cfg.retryableCodes.includes(response.status)) {\n return response;\n }\n\n // Retryable status — save response and maybe retry\n lastResponse = response;\n\n // Check for Retry-After header (common with 429)\n const retryAfter = response.headers.get(\"retry-after\");\n let delay: number;\n\n if (retryAfter) {\n // Retry-After can be seconds or HTTP-date\n const seconds = parseInt(retryAfter, 10);\n delay = isNaN(seconds) ? cfg.baseDelayMs * Math.pow(2, attempt) : seconds * 1000;\n } else {\n delay = cfg.baseDelayMs * Math.pow(2, attempt);\n }\n\n // Only retry if we have attempts left\n if (attempt < cfg.maxRetries) {\n await sleep(delay);\n }\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n\n // Network errors are retryable\n if (attempt < cfg.maxRetries) {\n const delay = cfg.baseDelayMs * Math.pow(2, attempt);\n await sleep(delay);\n }\n }\n }\n\n // All retries exhausted — return last response or throw last error\n if (lastResponse) {\n return lastResponse;\n }\n\n throw lastError ?? new Error(\"Max retries exceeded\");\n}\n\n/**\n * Check if an error or response indicates a retryable condition.\n */\nexport function isRetryable(\n errorOrResponse: Error | Response,\n config?: Partial<RetryConfig>,\n): boolean {\n const retryableCodes = config?.retryableCodes ?? DEFAULT_RETRY_CONFIG.retryableCodes;\n\n if (errorOrResponse instanceof Response) {\n return retryableCodes.includes(errorOrResponse.status);\n }\n\n // Network errors are generally retryable\n const message = errorOrResponse.message.toLowerCase();\n return (\n message.includes(\"network\") ||\n message.includes(\"timeout\") ||\n message.includes(\"econnreset\") ||\n message.includes(\"econnrefused\") ||\n message.includes(\"socket hang up\")\n );\n}\n"],"mappings":"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","names":["privateKeyToAccount","response","paymentHeader","confidence","DEFAULT_TTL_MS","USDC_BASE","join","require","account","privateKeyToAccount","balanceMonitor","mkdir","join","homedir","privateKeyToAccount","homedir","join","join","homedir"]}
1
+ {"version":3,"sources":["../src/models.ts","../src/provider.ts","../src/proxy.ts","../src/x402.ts","../src/payment-cache.ts","../src/router/rules.ts","../src/router/selector.ts","../src/router/config.ts","../src/router/index.ts","../src/logger.ts","../src/dedup.ts","../src/balance.ts","../src/errors.ts","../src/version.ts","../src/auth.ts","../src/index.ts","../src/retry.ts"],"sourcesContent":["/**\n * BlockRun Model Definitions for OpenClaw\n *\n * Maps BlockRun's 30+ AI models to OpenClaw's ModelDefinitionConfig format.\n * All models use the \"openai-completions\" API since BlockRun is OpenAI-compatible.\n *\n * Pricing is in USD per 1M tokens. Operators pay these rates via x402;\n * they set their own markup when reselling to end users (Phase 2).\n */\n\nimport type { ModelDefinitionConfig, ModelProviderConfig } from \"./types.js\";\n\ntype BlockRunModel = {\n id: string;\n name: string;\n inputPrice: number;\n outputPrice: number;\n contextWindow: number;\n maxOutput: number;\n reasoning?: boolean;\n vision?: boolean;\n};\n\nexport const BLOCKRUN_MODELS: BlockRunModel[] = [\n // Smart routing meta-model — proxy replaces with actual model\n // NOTE: Model IDs are WITHOUT provider prefix (OpenClaw adds \"blockrun/\" automatically)\n {\n id: \"auto\",\n name: \"BlockRun Smart Router\",\n inputPrice: 0,\n outputPrice: 0,\n contextWindow: 1_050_000,\n maxOutput: 128_000,\n },\n\n // OpenAI GPT-5 Family\n {\n id: \"openai/gpt-5.2\",\n name: \"GPT-5.2\",\n inputPrice: 1.75,\n outputPrice: 14.0,\n contextWindow: 400000,\n maxOutput: 128000,\n reasoning: true,\n vision: true,\n },\n {\n id: \"openai/gpt-5-mini\",\n name: \"GPT-5 Mini\",\n inputPrice: 0.25,\n outputPrice: 2.0,\n contextWindow: 200000,\n maxOutput: 65536,\n },\n {\n id: \"openai/gpt-5-nano\",\n name: \"GPT-5 Nano\",\n inputPrice: 0.05,\n outputPrice: 0.4,\n contextWindow: 128000,\n maxOutput: 32768,\n },\n {\n id: \"openai/gpt-5.2-pro\",\n name: \"GPT-5.2 Pro\",\n inputPrice: 21.0,\n outputPrice: 168.0,\n contextWindow: 400000,\n maxOutput: 128000,\n reasoning: true,\n },\n\n // OpenAI GPT-4 Family\n {\n id: \"openai/gpt-4.1\",\n name: \"GPT-4.1\",\n inputPrice: 2.0,\n outputPrice: 8.0,\n contextWindow: 128000,\n maxOutput: 16384,\n vision: true,\n },\n {\n id: \"openai/gpt-4.1-mini\",\n name: \"GPT-4.1 Mini\",\n inputPrice: 0.4,\n outputPrice: 1.6,\n contextWindow: 128000,\n maxOutput: 16384,\n },\n {\n id: \"openai/gpt-4.1-nano\",\n name: \"GPT-4.1 Nano\",\n inputPrice: 0.1,\n outputPrice: 0.4,\n contextWindow: 128000,\n maxOutput: 16384,\n },\n {\n id: \"openai/gpt-4o\",\n name: \"GPT-4o\",\n inputPrice: 2.5,\n outputPrice: 10.0,\n contextWindow: 128000,\n maxOutput: 16384,\n vision: true,\n },\n {\n id: \"openai/gpt-4o-mini\",\n name: \"GPT-4o Mini\",\n inputPrice: 0.15,\n outputPrice: 0.6,\n contextWindow: 128000,\n maxOutput: 16384,\n },\n\n // OpenAI O-series (Reasoning)\n {\n id: \"openai/o1\",\n name: \"o1\",\n inputPrice: 15.0,\n outputPrice: 60.0,\n contextWindow: 200000,\n maxOutput: 100000,\n reasoning: true,\n },\n {\n id: \"openai/o1-mini\",\n name: \"o1-mini\",\n inputPrice: 1.1,\n outputPrice: 4.4,\n contextWindow: 128000,\n maxOutput: 65536,\n reasoning: true,\n },\n {\n id: \"openai/o3\",\n name: \"o3\",\n inputPrice: 2.0,\n outputPrice: 8.0,\n contextWindow: 200000,\n maxOutput: 100000,\n reasoning: true,\n },\n {\n id: \"openai/o3-mini\",\n name: \"o3-mini\",\n inputPrice: 1.1,\n outputPrice: 4.4,\n contextWindow: 128000,\n maxOutput: 65536,\n reasoning: true,\n },\n // o4-mini: Placeholder removed - model not yet released by OpenAI\n\n // Anthropic\n {\n id: \"anthropic/claude-haiku-4.5\",\n name: \"Claude Haiku 4.5\",\n inputPrice: 1.0,\n outputPrice: 5.0,\n contextWindow: 200000,\n maxOutput: 8192,\n },\n {\n id: \"anthropic/claude-sonnet-4\",\n name: \"Claude Sonnet 4\",\n inputPrice: 3.0,\n outputPrice: 15.0,\n contextWindow: 200000,\n maxOutput: 64000,\n reasoning: true,\n },\n {\n id: \"anthropic/claude-opus-4\",\n name: \"Claude Opus 4\",\n inputPrice: 15.0,\n outputPrice: 75.0,\n contextWindow: 200000,\n maxOutput: 32000,\n reasoning: true,\n },\n {\n id: \"anthropic/claude-opus-4.5\",\n name: \"Claude Opus 4.5\",\n inputPrice: 5.0,\n outputPrice: 25.0,\n contextWindow: 200000,\n maxOutput: 32000,\n reasoning: true,\n },\n\n // Google\n {\n id: \"google/gemini-3-pro-preview\",\n name: \"Gemini 3 Pro Preview\",\n inputPrice: 2.0,\n outputPrice: 12.0,\n contextWindow: 1050000,\n maxOutput: 65536,\n reasoning: true,\n vision: true,\n },\n {\n id: \"google/gemini-2.5-pro\",\n name: \"Gemini 2.5 Pro\",\n inputPrice: 1.25,\n outputPrice: 10.0,\n contextWindow: 1050000,\n maxOutput: 65536,\n reasoning: true,\n vision: true,\n },\n {\n id: \"google/gemini-2.5-flash\",\n name: \"Gemini 2.5 Flash\",\n inputPrice: 0.15,\n outputPrice: 0.6,\n contextWindow: 1000000,\n maxOutput: 65536,\n },\n\n // DeepSeek\n {\n id: \"deepseek/deepseek-chat\",\n name: \"DeepSeek V3.2 Chat\",\n inputPrice: 0.28,\n outputPrice: 0.42,\n contextWindow: 128000,\n maxOutput: 8192,\n },\n {\n id: \"deepseek/deepseek-reasoner\",\n name: \"DeepSeek V3.2 Reasoner\",\n inputPrice: 0.28,\n outputPrice: 0.42,\n contextWindow: 128000,\n maxOutput: 8192,\n reasoning: true,\n },\n\n // Moonshot / Kimi\n {\n id: \"moonshot/kimi-k2.5\",\n name: \"Kimi K2.5\",\n inputPrice: 0.5,\n outputPrice: 2.4,\n contextWindow: 262144,\n maxOutput: 8192,\n reasoning: true,\n vision: true,\n },\n\n // xAI / Grok\n {\n id: \"xai/grok-3\",\n name: \"Grok 3\",\n inputPrice: 3.0,\n outputPrice: 15.0,\n contextWindow: 131072,\n maxOutput: 16384,\n reasoning: true,\n },\n {\n id: \"xai/grok-3-fast\",\n name: \"Grok 3 Fast\",\n inputPrice: 5.0,\n outputPrice: 25.0,\n contextWindow: 131072,\n maxOutput: 16384,\n reasoning: true,\n },\n {\n id: \"xai/grok-3-mini\",\n name: \"Grok 3 Mini\",\n inputPrice: 0.3,\n outputPrice: 0.5,\n contextWindow: 131072,\n maxOutput: 16384,\n },\n];\n\n/**\n * Convert BlockRun model definitions to OpenClaw ModelDefinitionConfig format.\n */\nfunction toOpenClawModel(m: BlockRunModel): ModelDefinitionConfig {\n return {\n id: m.id,\n name: m.name,\n api: \"openai-completions\",\n reasoning: m.reasoning ?? false,\n input: m.vision ? [\"text\", \"image\"] : [\"text\"],\n cost: {\n input: m.inputPrice,\n output: m.outputPrice,\n cacheRead: 0,\n cacheWrite: 0,\n },\n contextWindow: m.contextWindow,\n maxTokens: m.maxOutput,\n };\n}\n\n/**\n * All BlockRun models in OpenClaw format.\n */\nexport const OPENCLAW_MODELS: ModelDefinitionConfig[] = BLOCKRUN_MODELS.map(toOpenClawModel);\n\n/**\n * Build a ModelProviderConfig for BlockRun.\n *\n * @param baseUrl - The proxy's local base URL (e.g., \"http://127.0.0.1:12345\")\n */\nexport function buildProviderModels(baseUrl: string): ModelProviderConfig {\n return {\n baseUrl: `${baseUrl}/v1`,\n api: \"openai-completions\",\n models: OPENCLAW_MODELS,\n };\n}\n","/**\n * BlockRun ProviderPlugin for OpenClaw\n *\n * Registers BlockRun as an LLM provider in OpenClaw.\n * Uses a local x402 proxy to handle micropayments transparently —\n * pi-ai sees a standard OpenAI-compatible API at localhost.\n */\n\nimport type { ProviderPlugin } from \"./types.js\";\nimport { buildProviderModels } from \"./models.js\";\nimport type { ProxyHandle } from \"./proxy.js\";\n\n/**\n * State for the running proxy (set when the plugin activates).\n */\nlet activeProxy: ProxyHandle | null = null;\n\n/**\n * Update the proxy handle (called from index.ts when the proxy starts).\n */\nexport function setActiveProxy(proxy: ProxyHandle): void {\n activeProxy = proxy;\n}\n\nexport function getActiveProxy(): ProxyHandle | null {\n return activeProxy;\n}\n\n/**\n * BlockRun provider plugin definition.\n */\nexport const blockrunProvider: ProviderPlugin = {\n id: \"blockrun\",\n label: \"BlockRun\",\n docsPath: \"https://blockrun.ai/docs\",\n aliases: [\"br\"],\n envVars: [\"BLOCKRUN_WALLET_KEY\"],\n\n // Model definitions — dynamically set to proxy URL\n get models() {\n if (!activeProxy) {\n // Fallback: point to BlockRun API directly (won't handle x402, but\n // allows config loading before proxy starts)\n return buildProviderModels(\"https://blockrun.ai/api\");\n }\n return buildProviderModels(activeProxy.baseUrl);\n },\n\n // No auth required — the x402 proxy handles wallet-based payments internally.\n // The proxy auto-generates a wallet on first run and stores it at\n // ~/.openclaw/blockrun/wallet.key. Users just fund that wallet with USDC.\n auth: [],\n};\n","/**\n * Local x402 Proxy Server\n *\n * Sits between OpenClaw's pi-ai (which makes standard OpenAI-format requests)\n * and BlockRun's API (which requires x402 micropayments).\n *\n * Flow:\n * pi-ai → http://localhost:{port}/v1/chat/completions\n * → proxy forwards to https://blockrun.ai/api/v1/chat/completions\n * → gets 402 → @x402/fetch signs payment → retries\n * → streams response back to pi-ai\n *\n * Optimizations (v0.3.0):\n * - SSE heartbeat: for streaming requests, sends headers + heartbeat immediately\n * before the x402 flow, preventing OpenClaw's 10-15s timeout from firing.\n * - Response dedup: hashes request bodies and caches responses for 30s,\n * preventing double-charging when OpenClaw retries after timeout.\n * - Payment cache: after first 402, pre-signs subsequent requests to skip\n * the 402 round trip (~200ms savings per request).\n * - Smart routing: when model is \"blockrun/auto\", classify query and pick cheapest model.\n * - Usage logging: log every request as JSON line to ~/.openclaw/blockrun/logs/\n */\n\nimport { createServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport type { AddressInfo } from \"node:net\";\nimport { privateKeyToAccount } from \"viem/accounts\";\nimport { createPaymentFetch, type PreAuthParams } from \"./x402.js\";\nimport {\n route,\n getFallbackChain,\n DEFAULT_ROUTING_CONFIG,\n type RouterOptions,\n type RoutingDecision,\n type RoutingConfig,\n type ModelPricing,\n} from \"./router/index.js\";\nimport { BLOCKRUN_MODELS } from \"./models.js\";\nimport { logUsage, type UsageEntry } from \"./logger.js\";\nimport { RequestDeduplicator } from \"./dedup.js\";\nimport { BalanceMonitor } from \"./balance.js\";\nimport { InsufficientFundsError, EmptyWalletError } from \"./errors.js\";\nimport { USER_AGENT } from \"./version.js\";\n\nconst BLOCKRUN_API = \"https://blockrun.ai/api\";\nconst AUTO_MODEL = \"blockrun/auto\";\nconst AUTO_MODEL_SHORT = \"auto\"; // OpenClaw strips provider prefix\nconst HEARTBEAT_INTERVAL_MS = 2_000;\nconst DEFAULT_REQUEST_TIMEOUT_MS = 180_000; // 3 minutes (allows for on-chain tx + LLM response)\nconst DEFAULT_PORT = 8402;\nconst MAX_FALLBACK_ATTEMPTS = 3; // Maximum models to try in fallback chain\nconst HEALTH_CHECK_TIMEOUT_MS = 2_000; // Timeout for checking existing proxy\n// Extra buffer for balance check (on top of estimateAmount's 20% buffer)\n// Total effective buffer: 1.2 * 1.5 = 1.8x (80% safety margin)\n// This prevents x402 payment failures after streaming headers are sent,\n// which would trigger OpenClaw's 5-24 hour billing cooldown.\nconst BALANCE_CHECK_BUFFER = 1.5;\n\n/**\n * Get the proxy port from environment variable or default.\n */\nexport function getProxyPort(): number {\n const envPort = process.env.BLOCKRUN_PROXY_PORT;\n if (envPort) {\n const parsed = parseInt(envPort, 10);\n if (!isNaN(parsed) && parsed > 0 && parsed < 65536) {\n return parsed;\n }\n }\n return DEFAULT_PORT;\n}\n\n/**\n * Check if a proxy is already running on the given port.\n * Returns the wallet address if running, undefined otherwise.\n */\nasync function checkExistingProxy(port: number): Promise<string | undefined> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), HEALTH_CHECK_TIMEOUT_MS);\n\n try {\n const response = await fetch(`http://127.0.0.1:${port}/health`, {\n signal: controller.signal,\n });\n clearTimeout(timeoutId);\n\n if (response.ok) {\n const data = (await response.json()) as { status?: string; wallet?: string };\n if (data.status === \"ok\" && data.wallet) {\n return data.wallet;\n }\n }\n return undefined;\n } catch {\n clearTimeout(timeoutId);\n return undefined;\n }\n}\n\n/**\n * Error patterns that indicate a provider-side issue (not user's fault).\n * These errors should trigger fallback to the next model in the chain.\n */\nconst PROVIDER_ERROR_PATTERNS = [\n /billing/i,\n /insufficient.*balance/i,\n /credits/i,\n /quota.*exceeded/i,\n /rate.*limit/i,\n /model.*unavailable/i,\n /model.*not.*available/i,\n /service.*unavailable/i,\n /capacity/i,\n /overloaded/i,\n /temporarily.*unavailable/i,\n /api.*key.*invalid/i,\n /authentication.*failed/i,\n];\n\n/**\n * HTTP status codes that indicate provider issues worth retrying with fallback.\n */\nconst FALLBACK_STATUS_CODES = [\n 400, // Bad request - sometimes used for billing errors\n 401, // Unauthorized - provider API key issues\n 402, // Payment required - but from upstream, not x402\n 403, // Forbidden - provider restrictions\n 429, // Rate limited\n 500, // Internal server error\n 502, // Bad gateway\n 503, // Service unavailable\n 504, // Gateway timeout\n];\n\n/**\n * Check if an error response indicates a provider issue that should trigger fallback.\n */\nfunction isProviderError(status: number, body: string): boolean {\n // Check status code first\n if (!FALLBACK_STATUS_CODES.includes(status)) {\n return false;\n }\n\n // For 5xx errors, always fallback\n if (status >= 500) {\n return true;\n }\n\n // For 4xx errors, check the body for known provider error patterns\n return PROVIDER_ERROR_PATTERNS.some((pattern) => pattern.test(body));\n}\n\n/**\n * Normalize messages for Google models.\n * Google's Gemini API requires the first non-system message to be from \"user\".\n * If conversation starts with \"assistant\"/\"model\", prepend a placeholder user message.\n */\ntype ChatMessage = { role: string; content: string | unknown };\n\nfunction normalizeMessagesForGoogle(messages: ChatMessage[]): ChatMessage[] {\n if (!messages || messages.length === 0) return messages;\n\n // Find first non-system message\n let firstNonSystemIdx = -1;\n for (let i = 0; i < messages.length; i++) {\n if (messages[i].role !== \"system\") {\n firstNonSystemIdx = i;\n break;\n }\n }\n\n // If no non-system messages, return as-is\n if (firstNonSystemIdx === -1) return messages;\n\n const firstRole = messages[firstNonSystemIdx].role;\n\n // If first non-system message is already \"user\", no change needed\n if (firstRole === \"user\") return messages;\n\n // If first non-system message is \"assistant\" or \"model\", prepend a user message\n if (firstRole === \"assistant\" || firstRole === \"model\") {\n const normalized = [...messages];\n normalized.splice(firstNonSystemIdx, 0, {\n role: \"user\",\n content: \"(continuing conversation)\",\n });\n return normalized;\n }\n\n return messages;\n}\n\n/**\n * Check if a model is a Google model that requires message normalization.\n */\nfunction isGoogleModel(modelId: string): boolean {\n return modelId.startsWith(\"google/\") || modelId.startsWith(\"gemini\");\n}\n\n// Kimi/Moonshot models use special Unicode tokens for thinking boundaries.\n// Pattern: <|begin▁of▁thinking|>content<|end▁of▁thinking|>\n// The | is fullwidth vertical bar (U+FF5C), ▁ is lower one-eighth block (U+2581).\n\n// Match full Kimi thinking blocks: <|begin...|>content<|end...|>\nconst KIMI_BLOCK_RE = /<[||][^<>]*begin[^<>]*[||]>[\\s\\S]*?<[||][^<>]*end[^<>]*[||]>/gi;\n\n// Match standalone Kimi tokens like <|end▁of▁thinking|>\nconst KIMI_TOKEN_RE = /<[||][^<>]*[||]>/g;\n\n// Standard thinking tags that may leak through from various models\nconst THINKING_TAG_RE = /<\\s*\\/?\\s*(?:think(?:ing)?|thought|antthinking)\\b[^>]*>/gi;\n\n// Full thinking blocks: <think>content</think>\nconst THINKING_BLOCK_RE =\n /<\\s*(?:think(?:ing)?|thought|antthinking)\\b[^>]*>[\\s\\S]*?<\\s*\\/\\s*(?:think(?:ing)?|thought|antthinking)\\s*>/gi;\n\n/**\n * Strip thinking tokens and blocks from model response content.\n * Handles both Kimi-style Unicode tokens and standard XML-style tags.\n */\nfunction stripThinkingTokens(content: string): string {\n if (!content) return content;\n // Strip full Kimi thinking blocks first (begin...end with content)\n let cleaned = content.replace(KIMI_BLOCK_RE, \"\");\n // Strip remaining standalone Kimi tokens\n cleaned = cleaned.replace(KIMI_TOKEN_RE, \"\");\n // Strip full thinking blocks (<think>...</think>)\n cleaned = cleaned.replace(THINKING_BLOCK_RE, \"\");\n // Strip remaining standalone thinking tags\n cleaned = cleaned.replace(THINKING_TAG_RE, \"\");\n return cleaned;\n}\n\n/** Callback info for low balance warning */\nexport type LowBalanceInfo = {\n balanceUSD: string;\n walletAddress: string;\n};\n\n/** Callback info for insufficient funds error */\nexport type InsufficientFundsInfo = {\n balanceUSD: string;\n requiredUSD: string;\n walletAddress: string;\n};\n\nexport type ProxyOptions = {\n walletKey: string;\n apiBase?: string;\n /** Port to listen on (default: 8402) */\n port?: number;\n routingConfig?: Partial<RoutingConfig>;\n /** Request timeout in ms (default: 180000 = 3 minutes). Covers on-chain tx + LLM response. */\n requestTimeoutMs?: number;\n /** Skip balance checks (for testing only). Default: false */\n skipBalanceCheck?: boolean;\n onReady?: (port: number) => void;\n onError?: (error: Error) => void;\n onPayment?: (info: { model: string; amount: string; network: string }) => void;\n onRouted?: (decision: RoutingDecision) => void;\n /** Called when balance drops below $1.00 (warning, request still proceeds) */\n onLowBalance?: (info: LowBalanceInfo) => void;\n /** Called when balance is insufficient for a request (request fails) */\n onInsufficientFunds?: (info: InsufficientFundsInfo) => void;\n};\n\nexport type ProxyHandle = {\n port: number;\n baseUrl: string;\n walletAddress: string;\n balanceMonitor: BalanceMonitor;\n close: () => Promise<void>;\n};\n\n/**\n * Build model pricing map from BLOCKRUN_MODELS.\n */\nfunction buildModelPricing(): Map<string, ModelPricing> {\n const map = new Map<string, ModelPricing>();\n for (const m of BLOCKRUN_MODELS) {\n if (m.id === AUTO_MODEL) continue; // skip meta-model\n map.set(m.id, { inputPrice: m.inputPrice, outputPrice: m.outputPrice });\n }\n return map;\n}\n\n/**\n * Merge partial routing config overrides with defaults.\n */\nfunction mergeRoutingConfig(overrides?: Partial<RoutingConfig>): RoutingConfig {\n if (!overrides) return DEFAULT_ROUTING_CONFIG;\n return {\n ...DEFAULT_ROUTING_CONFIG,\n ...overrides,\n classifier: { ...DEFAULT_ROUTING_CONFIG.classifier, ...overrides.classifier },\n scoring: { ...DEFAULT_ROUTING_CONFIG.scoring, ...overrides.scoring },\n tiers: { ...DEFAULT_ROUTING_CONFIG.tiers, ...overrides.tiers },\n overrides: { ...DEFAULT_ROUTING_CONFIG.overrides, ...overrides.overrides },\n };\n}\n\n/**\n * Estimate USDC cost for a request based on model pricing.\n * Returns amount string in USDC smallest unit (6 decimals) or undefined if unknown.\n */\nfunction estimateAmount(\n modelId: string,\n bodyLength: number,\n maxTokens: number,\n): string | undefined {\n const model = BLOCKRUN_MODELS.find((m) => m.id === modelId);\n if (!model) return undefined;\n\n // Rough estimate: ~4 chars per token for input\n const estimatedInputTokens = Math.ceil(bodyLength / 4);\n const estimatedOutputTokens = maxTokens || model.maxOutput || 4096;\n\n const costUsd =\n (estimatedInputTokens / 1_000_000) * model.inputPrice +\n (estimatedOutputTokens / 1_000_000) * model.outputPrice;\n\n // Convert to USDC 6-decimal integer, add 20% buffer for estimation error\n // Minimum 100 ($0.0001) to avoid zero-amount rejections\n const amountMicros = Math.max(100, Math.ceil(costUsd * 1.2 * 1_000_000));\n return amountMicros.toString();\n}\n\n/**\n * Start the local x402 proxy server.\n *\n * If a proxy is already running on the target port, reuses it instead of failing.\n * Port can be configured via BLOCKRUN_PROXY_PORT environment variable.\n *\n * Returns a handle with the assigned port, base URL, and a close function.\n */\nexport async function startProxy(options: ProxyOptions): Promise<ProxyHandle> {\n const apiBase = options.apiBase ?? BLOCKRUN_API;\n\n // Determine port: options.port > env var > default\n const listenPort = options.port ?? getProxyPort();\n\n // Check if a proxy is already running on this port\n const existingWallet = await checkExistingProxy(listenPort);\n if (existingWallet) {\n // Proxy already running — reuse it instead of failing with EADDRINUSE\n const account = privateKeyToAccount(options.walletKey as `0x${string}`);\n const balanceMonitor = new BalanceMonitor(account.address);\n const baseUrl = `http://127.0.0.1:${listenPort}`;\n\n // Verify the existing proxy is using the same wallet (or warn if different)\n if (existingWallet !== account.address) {\n console.warn(\n `[ClawRouter] Existing proxy on port ${listenPort} uses wallet ${existingWallet}, but current config uses ${account.address}. Reusing existing proxy.`,\n );\n }\n\n options.onReady?.(listenPort);\n\n return {\n port: listenPort,\n baseUrl,\n walletAddress: existingWallet,\n balanceMonitor,\n close: async () => {\n // No-op: we didn't start this proxy, so we shouldn't close it\n },\n };\n }\n\n // Create x402 payment-enabled fetch from wallet private key\n const account = privateKeyToAccount(options.walletKey as `0x${string}`);\n const { fetch: payFetch } = createPaymentFetch(options.walletKey as `0x${string}`);\n\n // Create balance monitor for pre-request checks\n const balanceMonitor = new BalanceMonitor(account.address);\n\n // Build router options (100% local — no external API calls for routing)\n const routingConfig = mergeRoutingConfig(options.routingConfig);\n const modelPricing = buildModelPricing();\n const routerOpts: RouterOptions = {\n config: routingConfig,\n modelPricing,\n };\n\n // Request deduplicator (shared across all requests)\n const deduplicator = new RequestDeduplicator();\n\n const server = createServer(async (req: IncomingMessage, res: ServerResponse) => {\n // Health check with optional balance info\n if (req.url === \"/health\" || req.url?.startsWith(\"/health?\")) {\n const url = new URL(req.url, \"http://localhost\");\n const full = url.searchParams.get(\"full\") === \"true\";\n\n const response: Record<string, unknown> = {\n status: \"ok\",\n wallet: account.address,\n };\n\n if (full) {\n try {\n const balanceInfo = await balanceMonitor.checkBalance();\n response.balance = balanceInfo.balanceUSD;\n response.isLow = balanceInfo.isLow;\n response.isEmpty = balanceInfo.isEmpty;\n } catch {\n response.balanceError = \"Could not fetch balance\";\n }\n }\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(response));\n return;\n }\n\n // Only proxy paths starting with /v1\n if (!req.url?.startsWith(\"/v1\")) {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Not found\" }));\n return;\n }\n\n try {\n await proxyRequest(\n req,\n res,\n apiBase,\n payFetch,\n options,\n routerOpts,\n deduplicator,\n balanceMonitor,\n );\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n options.onError?.(error);\n\n if (!res.headersSent) {\n res.writeHead(502, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: { message: `Proxy error: ${error.message}`, type: \"proxy_error\" },\n }),\n );\n } else if (!res.writableEnded) {\n // Headers already sent (streaming) — send error as SSE event\n res.write(\n `data: ${JSON.stringify({ error: { message: error.message, type: \"proxy_error\" } })}\\n\\n`,\n );\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n }\n }\n });\n\n // Listen on configured port (already determined above)\n return new Promise<ProxyHandle>((resolve, reject) => {\n server.on(\"error\", (err: NodeJS.ErrnoException) => {\n // Handle EADDRINUSE gracefully — proxy is already running\n if (err.code === \"EADDRINUSE\") {\n // Port is in use, which means a proxy is already running.\n // This can happen when openclaw logs triggers plugin reload.\n // Silently reuse the existing proxy instead of failing.\n const baseUrl = `http://127.0.0.1:${listenPort}`;\n options.onReady?.(listenPort);\n resolve({\n port: listenPort,\n baseUrl,\n walletAddress: account.address,\n balanceMonitor,\n close: async () => {\n // No-op: we didn't start this proxy, so we shouldn't close it\n },\n });\n return;\n }\n reject(err);\n });\n\n server.listen(listenPort, \"127.0.0.1\", () => {\n const addr = server.address() as AddressInfo;\n const port = addr.port;\n const baseUrl = `http://127.0.0.1:${port}`;\n\n options.onReady?.(port);\n\n resolve({\n port,\n baseUrl,\n walletAddress: account.address,\n balanceMonitor,\n close: () =>\n new Promise<void>((res, rej) => {\n server.close((err) => (err ? rej(err) : res()));\n }),\n });\n });\n });\n}\n\n/** Result of attempting a model request */\ntype ModelRequestResult = {\n success: boolean;\n response?: Response;\n errorBody?: string;\n errorStatus?: number;\n isProviderError?: boolean;\n};\n\n/**\n * Attempt a request with a specific model.\n * Returns the response or error details for fallback decision.\n */\nasync function tryModelRequest(\n upstreamUrl: string,\n method: string,\n headers: Record<string, string>,\n body: Buffer,\n modelId: string,\n maxTokens: number,\n payFetch: (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ) => Promise<Response>,\n balanceMonitor: BalanceMonitor,\n signal: AbortSignal,\n): Promise<ModelRequestResult> {\n // Update model in body and normalize messages for Google models\n let requestBody = body;\n try {\n const parsed = JSON.parse(body.toString()) as Record<string, unknown>;\n parsed.model = modelId;\n\n // Normalize messages for Google models (first non-system message must be \"user\")\n if (isGoogleModel(modelId) && Array.isArray(parsed.messages)) {\n parsed.messages = normalizeMessagesForGoogle(parsed.messages as ChatMessage[]);\n }\n\n requestBody = Buffer.from(JSON.stringify(parsed));\n } catch {\n // If body isn't valid JSON, use as-is\n }\n\n // Estimate cost for pre-auth\n const estimated = estimateAmount(modelId, requestBody.length, maxTokens);\n const preAuth: PreAuthParams | undefined = estimated ? { estimatedAmount: estimated } : undefined;\n\n try {\n const response = await payFetch(\n upstreamUrl,\n {\n method,\n headers,\n body: requestBody.length > 0 ? new Uint8Array(requestBody) : undefined,\n signal,\n },\n preAuth,\n );\n\n // Check for provider errors\n if (response.status !== 200) {\n // Clone response to read body without consuming it\n const errorBody = await response.text();\n const isProviderErr = isProviderError(response.status, errorBody);\n\n return {\n success: false,\n errorBody,\n errorStatus: response.status,\n isProviderError: isProviderErr,\n };\n }\n\n return { success: true, response };\n } catch (err) {\n const errorMsg = err instanceof Error ? err.message : String(err);\n return {\n success: false,\n errorBody: errorMsg,\n errorStatus: 500,\n isProviderError: true, // Network errors are retryable\n };\n }\n}\n\n/**\n * Proxy a single request through x402 payment flow to BlockRun API.\n *\n * Optimizations applied in order:\n * 1. Dedup check — if same request body seen within 30s, replay cached response\n * 2. Streaming heartbeat — for stream:true, send 200 + heartbeats immediately\n * 3. Payment pre-auth — estimate USDC amount and pre-sign to skip 402 round trip\n * 4. Smart routing — when model is \"blockrun/auto\", pick cheapest capable model\n * 5. Fallback chain — on provider errors, try next model in tier's fallback list\n */\nasync function proxyRequest(\n req: IncomingMessage,\n res: ServerResponse,\n apiBase: string,\n payFetch: (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ) => Promise<Response>,\n options: ProxyOptions,\n routerOpts: RouterOptions,\n deduplicator: RequestDeduplicator,\n balanceMonitor: BalanceMonitor,\n): Promise<void> {\n const startTime = Date.now();\n\n // Build upstream URL: /v1/chat/completions → https://blockrun.ai/api/v1/chat/completions\n const upstreamUrl = `${apiBase}${req.url}`;\n\n // Collect request body\n const bodyChunks: Buffer[] = [];\n for await (const chunk of req) {\n bodyChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n let body = Buffer.concat(bodyChunks);\n\n // --- Smart routing ---\n let routingDecision: RoutingDecision | undefined;\n let isStreaming = false;\n let modelId = \"\";\n let maxTokens = 4096;\n const isChatCompletion = req.url?.includes(\"/chat/completions\");\n\n if (isChatCompletion && body.length > 0) {\n try {\n const parsed = JSON.parse(body.toString()) as Record<string, unknown>;\n isStreaming = parsed.stream === true;\n modelId = (parsed.model as string) || \"\";\n maxTokens = (parsed.max_tokens as number) || 4096;\n\n // Force stream: false — BlockRun API doesn't support streaming yet\n // ClawRouter handles SSE heartbeat simulation for upstream compatibility\n let bodyModified = false;\n if (parsed.stream === true) {\n parsed.stream = false;\n bodyModified = true;\n }\n\n // Normalize model name for comparison (trim whitespace, lowercase)\n const normalizedModel =\n typeof parsed.model === \"string\" ? parsed.model.trim().toLowerCase() : \"\";\n const isAutoModel =\n normalizedModel === AUTO_MODEL.toLowerCase() ||\n normalizedModel === AUTO_MODEL_SHORT.toLowerCase();\n\n // Debug: log received model name\n console.log(\n `[ClawRouter] Received model: \"${parsed.model}\" -> normalized: \"${normalizedModel}\", isAuto: ${isAutoModel}`,\n );\n\n if (isAutoModel) {\n // Extract prompt from messages\n type ChatMessage = { role: string; content: string };\n const messages = parsed.messages as ChatMessage[] | undefined;\n let lastUserMsg: ChatMessage | undefined;\n if (messages) {\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].role === \"user\") {\n lastUserMsg = messages[i];\n break;\n }\n }\n }\n const systemMsg = messages?.find((m: ChatMessage) => m.role === \"system\");\n const prompt = typeof lastUserMsg?.content === \"string\" ? lastUserMsg.content : \"\";\n const systemPrompt = typeof systemMsg?.content === \"string\" ? systemMsg.content : undefined;\n\n routingDecision = route(prompt, systemPrompt, maxTokens, routerOpts);\n\n // Replace model in body\n parsed.model = routingDecision.model;\n modelId = routingDecision.model;\n bodyModified = true;\n\n options.onRouted?.(routingDecision);\n }\n\n // Rebuild body if modified\n if (bodyModified) {\n body = Buffer.from(JSON.stringify(parsed));\n }\n } catch (err) {\n // Log routing errors so they're not silently swallowed\n const errorMsg = err instanceof Error ? err.message : String(err);\n console.error(`[ClawRouter] Routing error: ${errorMsg}`);\n options.onError?.(new Error(`Routing failed: ${errorMsg}`));\n }\n }\n\n // --- Dedup check ---\n const dedupKey = RequestDeduplicator.hash(body);\n\n // Check completed cache first\n const cached = deduplicator.getCached(dedupKey);\n if (cached) {\n res.writeHead(cached.status, cached.headers);\n res.end(cached.body);\n return;\n }\n\n // Check in-flight — wait for the original request to complete\n const inflight = deduplicator.getInflight(dedupKey);\n if (inflight) {\n const result = await inflight;\n res.writeHead(result.status, result.headers);\n res.end(result.body);\n return;\n }\n\n // Register this request as in-flight\n deduplicator.markInflight(dedupKey);\n\n // --- Pre-request balance check ---\n // Estimate cost and check if wallet has sufficient balance\n // Skip if skipBalanceCheck is set (for testing)\n let estimatedCostMicros: bigint | undefined;\n if (modelId && !options.skipBalanceCheck) {\n const estimated = estimateAmount(modelId, body.length, maxTokens);\n if (estimated) {\n estimatedCostMicros = BigInt(estimated);\n\n // Apply extra buffer for balance check to prevent x402 failures after streaming starts.\n // This is aggressive to avoid triggering OpenClaw's 5-24 hour billing cooldown.\n const bufferedCostMicros =\n (estimatedCostMicros * BigInt(Math.ceil(BALANCE_CHECK_BUFFER * 100))) / 100n;\n\n // Check balance before proceeding (using buffered amount)\n const sufficiency = await balanceMonitor.checkSufficient(bufferedCostMicros);\n\n if (sufficiency.info.isEmpty) {\n // Wallet is empty — cannot proceed\n deduplicator.removeInflight(dedupKey);\n const error = new EmptyWalletError(sufficiency.info.walletAddress);\n options.onInsufficientFunds?.({\n balanceUSD: sufficiency.info.balanceUSD,\n requiredUSD: balanceMonitor.formatUSDC(bufferedCostMicros),\n walletAddress: sufficiency.info.walletAddress,\n });\n throw error;\n }\n\n if (!sufficiency.sufficient) {\n // Insufficient balance — cannot proceed\n deduplicator.removeInflight(dedupKey);\n const error = new InsufficientFundsError({\n currentBalanceUSD: sufficiency.info.balanceUSD,\n requiredUSD: balanceMonitor.formatUSDC(bufferedCostMicros),\n walletAddress: sufficiency.info.walletAddress,\n });\n options.onInsufficientFunds?.({\n balanceUSD: sufficiency.info.balanceUSD,\n requiredUSD: balanceMonitor.formatUSDC(bufferedCostMicros),\n walletAddress: sufficiency.info.walletAddress,\n });\n throw error;\n }\n\n if (sufficiency.info.isLow) {\n // Balance is low but sufficient — warn and proceed\n options.onLowBalance?.({\n balanceUSD: sufficiency.info.balanceUSD,\n walletAddress: sufficiency.info.walletAddress,\n });\n }\n }\n }\n\n // --- Streaming: early header flush + heartbeat ---\n let heartbeatInterval: ReturnType<typeof setInterval> | undefined;\n let headersSentEarly = false;\n\n if (isStreaming) {\n // Send 200 + SSE headers immediately, before x402 flow\n res.writeHead(200, {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-cache\",\n connection: \"keep-alive\",\n });\n headersSentEarly = true;\n\n // First heartbeat immediately\n res.write(\": heartbeat\\n\\n\");\n\n // Continue heartbeats every 2s while waiting for upstream\n heartbeatInterval = setInterval(() => {\n if (!res.writableEnded) {\n res.write(\": heartbeat\\n\\n\");\n }\n }, HEARTBEAT_INTERVAL_MS);\n }\n\n // Forward headers, stripping host, connection, and content-length\n const headers: Record<string, string> = {};\n for (const [key, value] of Object.entries(req.headers)) {\n if (\n key === \"host\" ||\n key === \"connection\" ||\n key === \"transfer-encoding\" ||\n key === \"content-length\"\n )\n continue;\n if (typeof value === \"string\") {\n headers[key] = value;\n }\n }\n if (!headers[\"content-type\"]) {\n headers[\"content-type\"] = \"application/json\";\n }\n headers[\"user-agent\"] = USER_AGENT;\n\n // --- Client disconnect cleanup ---\n let completed = false;\n res.on(\"close\", () => {\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n heartbeatInterval = undefined;\n }\n // Remove from in-flight if client disconnected before completion\n if (!completed) {\n deduplicator.removeInflight(dedupKey);\n }\n });\n\n // --- Request timeout ---\n const timeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n // --- Build fallback chain ---\n // If we have a routing decision, get the full fallback chain for the tier\n // Otherwise, just use the current model (no fallback for explicit model requests)\n let modelsToTry: string[];\n if (routingDecision) {\n modelsToTry = getFallbackChain(routingDecision.tier, routerOpts.config.tiers);\n // Limit to MAX_FALLBACK_ATTEMPTS to prevent infinite loops\n modelsToTry = modelsToTry.slice(0, MAX_FALLBACK_ATTEMPTS);\n } else {\n modelsToTry = modelId ? [modelId] : [];\n }\n\n // --- Fallback loop: try each model until success ---\n let upstream: Response | undefined;\n let lastError: { body: string; status: number } | undefined;\n let actualModelUsed = modelId;\n\n for (let i = 0; i < modelsToTry.length; i++) {\n const tryModel = modelsToTry[i];\n const isLastAttempt = i === modelsToTry.length - 1;\n\n console.log(`[ClawRouter] Trying model ${i + 1}/${modelsToTry.length}: ${tryModel}`);\n\n const result = await tryModelRequest(\n upstreamUrl,\n req.method ?? \"POST\",\n headers,\n body,\n tryModel,\n maxTokens,\n payFetch,\n balanceMonitor,\n controller.signal,\n );\n\n if (result.success && result.response) {\n upstream = result.response;\n actualModelUsed = tryModel;\n console.log(`[ClawRouter] Success with model: ${tryModel}`);\n break;\n }\n\n // Request failed\n lastError = {\n body: result.errorBody || \"Unknown error\",\n status: result.errorStatus || 500,\n };\n\n // If it's a provider error and not the last attempt, try next model\n if (result.isProviderError && !isLastAttempt) {\n console.log(\n `[ClawRouter] Provider error from ${tryModel}, trying fallback: ${result.errorBody?.slice(0, 100)}`,\n );\n continue;\n }\n\n // Not a provider error or last attempt — stop trying\n if (!result.isProviderError) {\n console.log(\n `[ClawRouter] Non-provider error from ${tryModel}, not retrying: ${result.errorBody?.slice(0, 100)}`,\n );\n }\n break;\n }\n\n // Clear timeout — request attempts completed\n clearTimeout(timeoutId);\n\n // Clear heartbeat — real data is about to flow\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n heartbeatInterval = undefined;\n }\n\n // Update routing decision with actual model used (for logging)\n if (routingDecision && actualModelUsed !== routingDecision.model) {\n routingDecision = {\n ...routingDecision,\n model: actualModelUsed,\n reasoning: `${routingDecision.reasoning} | fallback to ${actualModelUsed}`,\n };\n options.onRouted?.(routingDecision);\n }\n\n // --- Handle case where all models failed ---\n if (!upstream) {\n const errBody = lastError?.body || \"All models in fallback chain failed\";\n const errStatus = lastError?.status || 502;\n\n if (headersSentEarly) {\n // Streaming: send error as SSE event\n const errEvent = `data: ${JSON.stringify({ error: { message: errBody, type: \"provider_error\", status: errStatus } })}\\n\\n`;\n res.write(errEvent);\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n\n const errBuf = Buffer.from(errEvent + \"data: [DONE]\\n\\n\");\n deduplicator.complete(dedupKey, {\n status: 200,\n headers: { \"content-type\": \"text/event-stream\" },\n body: errBuf,\n completedAt: Date.now(),\n });\n } else {\n // Non-streaming: send error response\n res.writeHead(errStatus, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: { message: errBody, type: \"provider_error\" },\n }),\n );\n\n deduplicator.complete(dedupKey, {\n status: errStatus,\n headers: { \"content-type\": \"application/json\" },\n body: Buffer.from(\n JSON.stringify({ error: { message: errBody, type: \"provider_error\" } }),\n ),\n completedAt: Date.now(),\n });\n }\n return;\n }\n\n // --- Stream response and collect for dedup cache ---\n const responseChunks: Buffer[] = [];\n\n if (headersSentEarly) {\n // Streaming: headers already sent. Response should be 200 at this point\n // (non-200 responses are handled in the fallback loop above)\n\n // Convert non-streaming JSON response to SSE streaming format for client\n // (BlockRun API returns JSON since we forced stream:false)\n // OpenClaw expects: object=\"chat.completion.chunk\" with choices[].delta (not message)\n // We emit proper incremental deltas to match OpenAI's streaming format exactly\n if (upstream.body) {\n const reader = upstream.body.getReader();\n const chunks: Uint8Array[] = [];\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n }\n } finally {\n reader.releaseLock();\n }\n\n // Combine chunks and transform to streaming format\n const jsonBody = Buffer.concat(chunks);\n const jsonStr = jsonBody.toString();\n try {\n const rsp = JSON.parse(jsonStr) as {\n id?: string;\n object?: string;\n created?: number;\n model?: string;\n choices?: Array<{\n index?: number;\n message?: { role?: string; content?: string };\n delta?: { role?: string; content?: string };\n finish_reason?: string | null;\n }>;\n usage?: unknown;\n };\n\n // Build base chunk structure (reused for all chunks)\n const baseChunk = {\n id: rsp.id ?? `chatcmpl-${Date.now()}`,\n object: \"chat.completion.chunk\",\n created: rsp.created ?? Math.floor(Date.now() / 1000),\n model: rsp.model ?? \"unknown\",\n };\n\n // Process each choice (usually just one)\n if (rsp.choices && Array.isArray(rsp.choices)) {\n for (const choice of rsp.choices) {\n // Strip thinking tokens (Kimi <|...|> and standard <think> tags)\n const rawContent = choice.message?.content ?? choice.delta?.content ?? \"\";\n const content = stripThinkingTokens(rawContent);\n const role = choice.message?.role ?? choice.delta?.role ?? \"assistant\";\n const index = choice.index ?? 0;\n\n // Chunk 1: role only (mimics OpenAI's first chunk)\n const roleChunk = {\n ...baseChunk,\n choices: [{ index, delta: { role }, finish_reason: null }],\n };\n const roleData = `data: ${JSON.stringify(roleChunk)}\\n\\n`;\n res.write(roleData);\n responseChunks.push(Buffer.from(roleData));\n\n // Chunk 2: content (single chunk with full content)\n if (content) {\n const contentChunk = {\n ...baseChunk,\n choices: [{ index, delta: { content }, finish_reason: null }],\n };\n const contentData = `data: ${JSON.stringify(contentChunk)}\\n\\n`;\n res.write(contentData);\n responseChunks.push(Buffer.from(contentData));\n }\n\n // Chunk 3: finish_reason (signals completion)\n const finishChunk = {\n ...baseChunk,\n choices: [{ index, delta: {}, finish_reason: choice.finish_reason ?? \"stop\" }],\n };\n const finishData = `data: ${JSON.stringify(finishChunk)}\\n\\n`;\n res.write(finishData);\n responseChunks.push(Buffer.from(finishData));\n }\n }\n } catch {\n // If parsing fails, send raw response as single chunk\n const sseData = `data: ${jsonStr}\\n\\n`;\n res.write(sseData);\n responseChunks.push(Buffer.from(sseData));\n }\n }\n\n // Send SSE terminator\n res.write(\"data: [DONE]\\n\\n\");\n responseChunks.push(Buffer.from(\"data: [DONE]\\n\\n\"));\n res.end();\n\n // Cache for dedup\n deduplicator.complete(dedupKey, {\n status: 200,\n headers: { \"content-type\": \"text/event-stream\" },\n body: Buffer.concat(responseChunks),\n completedAt: Date.now(),\n });\n } else {\n // Non-streaming: forward status and headers from upstream\n const responseHeaders: Record<string, string> = {};\n upstream.headers.forEach((value, key) => {\n if (key === \"transfer-encoding\" || key === \"connection\") return;\n responseHeaders[key] = value;\n });\n\n res.writeHead(upstream.status, responseHeaders);\n\n if (upstream.body) {\n const reader = upstream.body.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n res.write(value);\n responseChunks.push(Buffer.from(value));\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n res.end();\n\n // Cache for dedup\n deduplicator.complete(dedupKey, {\n status: upstream.status,\n headers: responseHeaders,\n body: Buffer.concat(responseChunks),\n completedAt: Date.now(),\n });\n }\n\n // --- Optimistic balance deduction after successful response ---\n if (estimatedCostMicros !== undefined) {\n balanceMonitor.deductEstimated(estimatedCostMicros);\n }\n\n // Mark request as completed (for client disconnect cleanup)\n completed = true;\n } catch (err) {\n // Clear timeout on error\n clearTimeout(timeoutId);\n\n // Clear heartbeat on error\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n heartbeatInterval = undefined;\n }\n\n // Remove in-flight entry so retries aren't blocked\n deduplicator.removeInflight(dedupKey);\n\n // Invalidate balance cache on payment failure (might be out of date)\n balanceMonitor.invalidate();\n\n // Convert abort error to more descriptive timeout error\n if (err instanceof Error && err.name === \"AbortError\") {\n throw new Error(`Request timed out after ${timeoutMs}ms`);\n }\n\n throw err;\n }\n\n // --- Usage logging (fire-and-forget) ---\n if (routingDecision) {\n const entry: UsageEntry = {\n timestamp: new Date().toISOString(),\n model: routingDecision.model,\n cost: routingDecision.costEstimate,\n latencyMs: Date.now() - startTime,\n };\n logUsage(entry).catch(() => {});\n }\n}\n","/**\n * x402 Payment Implementation\n *\n * Based on BlockRun's proven implementation.\n * Handles 402 Payment Required responses with EIP-712 signed USDC transfers.\n *\n * Optimizations (v0.3.0):\n * - Payment cache: after first 402, caches {payTo, asset, network} per endpoint.\n * On subsequent requests, pre-signs payment and sends with first request,\n * skipping the 402 round trip (~200ms savings).\n * - Falls back to normal 402 flow if pre-signed payment is rejected.\n */\n\nimport { signTypedData, privateKeyToAccount } from \"viem/accounts\";\nimport { PaymentCache } from \"./payment-cache.js\";\n\nconst BASE_CHAIN_ID = 8453;\nconst USDC_BASE = \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\" as const;\n\nconst USDC_DOMAIN = {\n name: \"USD Coin\",\n version: \"2\",\n chainId: BASE_CHAIN_ID,\n verifyingContract: USDC_BASE,\n} as const;\n\nconst TRANSFER_TYPES = {\n TransferWithAuthorization: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n ],\n} as const;\n\nfunction createNonce(): `0x${string}` {\n const bytes = new Uint8Array(32);\n crypto.getRandomValues(bytes);\n return `0x${Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\")}` as `0x${string}`;\n}\n\ninterface PaymentOption {\n scheme: string;\n network: string;\n amount?: string;\n maxAmountRequired?: string;\n asset: string;\n payTo: string;\n maxTimeoutSeconds?: number;\n extra?: { name?: string; version?: string };\n}\n\ninterface PaymentRequired {\n accepts: PaymentOption[];\n resource?: { url?: string; description?: string };\n}\n\nfunction parsePaymentRequired(headerValue: string): PaymentRequired {\n const decoded = atob(headerValue);\n return JSON.parse(decoded) as PaymentRequired;\n}\n\nasync function createPaymentPayload(\n privateKey: `0x${string}`,\n fromAddress: string,\n recipient: string,\n amount: string,\n resourceUrl: string,\n): Promise<string> {\n const now = Math.floor(Date.now() / 1000);\n const validAfter = now - 600;\n const validBefore = now + 300;\n const nonce = createNonce();\n\n const signature = await signTypedData({\n privateKey,\n domain: USDC_DOMAIN,\n types: TRANSFER_TYPES,\n primaryType: \"TransferWithAuthorization\",\n message: {\n from: fromAddress as `0x${string}`,\n to: recipient as `0x${string}`,\n value: BigInt(amount),\n validAfter: BigInt(validAfter),\n validBefore: BigInt(validBefore),\n nonce,\n },\n });\n\n const paymentData = {\n x402Version: 2,\n resource: {\n url: resourceUrl,\n description: \"BlockRun AI API call\",\n mimeType: \"application/json\",\n },\n accepted: {\n scheme: \"exact\",\n network: \"eip155:8453\",\n amount,\n asset: USDC_BASE,\n payTo: recipient,\n maxTimeoutSeconds: 300,\n extra: { name: \"USD Coin\", version: \"2\" },\n },\n payload: {\n signature,\n authorization: {\n from: fromAddress,\n to: recipient,\n value: amount,\n validAfter: validAfter.toString(),\n validBefore: validBefore.toString(),\n nonce,\n },\n },\n extensions: {},\n };\n\n return btoa(JSON.stringify(paymentData));\n}\n\n/** Pre-auth parameters for skipping the 402 round trip. */\nexport type PreAuthParams = {\n estimatedAmount: string; // USDC amount in smallest unit (6 decimals)\n};\n\n/** Result from createPaymentFetch — includes the fetch wrapper and payment cache. */\nexport type PaymentFetchResult = {\n fetch: (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ) => Promise<Response>;\n cache: PaymentCache;\n};\n\n/**\n * Create a fetch wrapper that handles x402 payment automatically.\n *\n * Supports pre-auth: if cached payment params + estimated amount are available,\n * pre-signs and attaches payment to the first request, skipping the 402 round trip.\n * Falls back to normal 402 flow if pre-signed payment is rejected.\n */\nexport function createPaymentFetch(privateKey: `0x${string}`): PaymentFetchResult {\n const account = privateKeyToAccount(privateKey);\n const walletAddress = account.address;\n const paymentCache = new PaymentCache();\n\n const payFetch = async (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ): Promise<Response> => {\n const url = typeof input === \"string\" ? input : input instanceof URL ? input.href : input.url;\n const endpointPath = new URL(url).pathname;\n\n // --- Pre-auth path: skip 402 round trip ---\n const cached = paymentCache.get(endpointPath);\n if (cached && preAuth?.estimatedAmount) {\n const paymentPayload = await createPaymentPayload(\n privateKey,\n walletAddress,\n cached.payTo,\n preAuth.estimatedAmount,\n url,\n );\n\n const preAuthHeaders = new Headers(init?.headers);\n preAuthHeaders.set(\"payment-signature\", paymentPayload);\n\n const response = await fetch(input, { ...init, headers: preAuthHeaders });\n\n // Pre-auth accepted — skip 402 entirely\n if (response.status !== 402) {\n return response;\n }\n\n // Pre-auth rejected (wrong amount, payTo changed, etc.)\n // Try to use this 402's payment header for a proper retry\n const paymentHeader = response.headers.get(\"x-payment-required\");\n if (paymentHeader) {\n return handle402(input, init, url, endpointPath, paymentHeader);\n }\n\n // No payment header — invalidate cache and retry clean (no payment header)\n // to get a proper 402 with payment requirements\n paymentCache.invalidate(endpointPath);\n const cleanResponse = await fetch(input, init);\n if (cleanResponse.status !== 402) {\n return cleanResponse;\n }\n const cleanHeader = cleanResponse.headers.get(\"x-payment-required\");\n if (!cleanHeader) {\n throw new Error(\"402 response missing x-payment-required header\");\n }\n return handle402(input, init, url, endpointPath, cleanHeader);\n }\n\n // --- Normal path: first request may get 402 ---\n const response = await fetch(input, init);\n\n if (response.status !== 402) {\n return response;\n }\n\n const paymentHeader = response.headers.get(\"x-payment-required\");\n if (!paymentHeader) {\n throw new Error(\"402 response missing x-payment-required header\");\n }\n\n return handle402(input, init, url, endpointPath, paymentHeader);\n };\n\n /** Handle a 402 response: parse, cache params, sign, retry. */\n async function handle402(\n input: RequestInfo | URL,\n init: RequestInit | undefined,\n url: string,\n endpointPath: string,\n paymentHeader: string,\n ): Promise<Response> {\n const paymentRequired = parsePaymentRequired(paymentHeader);\n const option = paymentRequired.accepts?.[0];\n if (!option) {\n throw new Error(\"No payment options in 402 response\");\n }\n\n const amount = option.amount || option.maxAmountRequired;\n if (!amount) {\n throw new Error(\"No amount in payment requirements\");\n }\n\n // Cache payment params for future pre-auth\n paymentCache.set(endpointPath, {\n payTo: option.payTo,\n asset: option.asset,\n scheme: option.scheme,\n network: option.network,\n extra: option.extra,\n maxTimeoutSeconds: option.maxTimeoutSeconds,\n });\n\n // Create signed payment\n const paymentPayload = await createPaymentPayload(\n privateKey,\n walletAddress,\n option.payTo,\n amount,\n url,\n );\n\n // Retry with payment\n const retryHeaders = new Headers(init?.headers);\n retryHeaders.set(\"payment-signature\", paymentPayload);\n\n return fetch(input, {\n ...init,\n headers: retryHeaders,\n });\n }\n\n return { fetch: payFetch, cache: paymentCache };\n}\n","/**\n * Payment Parameter Cache\n *\n * Caches the 402 payment parameters (payTo, asset, network, etc.) after the first\n * request to each endpoint. On subsequent requests, pre-signs the payment and\n * attaches it to the first request, skipping the 402 round trip (~200ms savings).\n */\n\nexport type CachedPaymentParams = {\n payTo: string;\n asset: string;\n scheme: string;\n network: string;\n extra?: { name?: string; version?: string };\n maxTimeoutSeconds?: number;\n cachedAt: number;\n};\n\nconst DEFAULT_TTL_MS = 3_600_000; // 1 hour\n\nexport class PaymentCache {\n private cache = new Map<string, CachedPaymentParams>();\n private ttlMs: number;\n\n constructor(ttlMs = DEFAULT_TTL_MS) {\n this.ttlMs = ttlMs;\n }\n\n /** Get cached payment params for an endpoint path. */\n get(endpointPath: string): CachedPaymentParams | undefined {\n const entry = this.cache.get(endpointPath);\n if (!entry) return undefined;\n if (Date.now() - entry.cachedAt > this.ttlMs) {\n this.cache.delete(endpointPath);\n return undefined;\n }\n return entry;\n }\n\n /** Cache payment params from a 402 response. */\n set(endpointPath: string, params: Omit<CachedPaymentParams, \"cachedAt\">): void {\n this.cache.set(endpointPath, { ...params, cachedAt: Date.now() });\n }\n\n /** Invalidate cache for an endpoint (e.g., if payTo changed). */\n invalidate(endpointPath: string): void {\n this.cache.delete(endpointPath);\n }\n}\n","/**\n * Rule-Based Classifier (v2 — Weighted Scoring)\n *\n * Scores a request across 14 weighted dimensions and maps the aggregate\n * score to a tier using configurable boundaries. Confidence is calibrated\n * via sigmoid — low confidence triggers the fallback classifier.\n *\n * Handles 70-80% of requests in < 1ms with zero cost.\n */\n\nimport type { Tier, ScoringResult, ScoringConfig } from \"./types.js\";\n\ntype DimensionScore = { name: string; score: number; signal: string | null };\n\n// ─── Dimension Scorers ───\n// Each returns a score in [-1, 1] and an optional signal string.\n\nfunction scoreTokenCount(\n estimatedTokens: number,\n thresholds: { simple: number; complex: number },\n): DimensionScore {\n if (estimatedTokens < thresholds.simple) {\n return { name: \"tokenCount\", score: -1.0, signal: `short (${estimatedTokens} tokens)` };\n }\n if (estimatedTokens > thresholds.complex) {\n return { name: \"tokenCount\", score: 1.0, signal: `long (${estimatedTokens} tokens)` };\n }\n return { name: \"tokenCount\", score: 0, signal: null };\n}\n\nfunction scoreKeywordMatch(\n text: string,\n keywords: string[],\n name: string,\n signalLabel: string,\n thresholds: { low: number; high: number },\n scores: { none: number; low: number; high: number },\n): DimensionScore {\n const matches = keywords.filter((kw) => text.includes(kw.toLowerCase()));\n if (matches.length >= thresholds.high) {\n return {\n name,\n score: scores.high,\n signal: `${signalLabel} (${matches.slice(0, 3).join(\", \")})`,\n };\n }\n if (matches.length >= thresholds.low) {\n return {\n name,\n score: scores.low,\n signal: `${signalLabel} (${matches.slice(0, 3).join(\", \")})`,\n };\n }\n return { name, score: scores.none, signal: null };\n}\n\nfunction scoreMultiStep(text: string): DimensionScore {\n const patterns = [/first.*then/i, /step \\d/i, /\\d\\.\\s/];\n const hits = patterns.filter((p) => p.test(text));\n if (hits.length > 0) {\n return { name: \"multiStepPatterns\", score: 0.5, signal: \"multi-step\" };\n }\n return { name: \"multiStepPatterns\", score: 0, signal: null };\n}\n\nfunction scoreQuestionComplexity(prompt: string): DimensionScore {\n const count = (prompt.match(/\\?/g) || []).length;\n if (count > 3) {\n return { name: \"questionComplexity\", score: 0.5, signal: `${count} questions` };\n }\n return { name: \"questionComplexity\", score: 0, signal: null };\n}\n\n// ─── Main Classifier ───\n\nexport function classifyByRules(\n prompt: string,\n systemPrompt: string | undefined,\n estimatedTokens: number,\n config: ScoringConfig,\n): ScoringResult {\n const text = `${systemPrompt ?? \"\"} ${prompt}`.toLowerCase();\n // User prompt only — used for reasoning markers (system prompt shouldn't influence complexity)\n const userText = prompt.toLowerCase();\n\n // Score all 14 dimensions\n const dimensions: DimensionScore[] = [\n // Original 8 dimensions\n scoreTokenCount(estimatedTokens, config.tokenCountThresholds),\n scoreKeywordMatch(\n text,\n config.codeKeywords,\n \"codePresence\",\n \"code\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 1.0 },\n ),\n // Reasoning markers use USER prompt only — system prompt \"step by step\" shouldn't trigger reasoning\n scoreKeywordMatch(\n userText,\n config.reasoningKeywords,\n \"reasoningMarkers\",\n \"reasoning\",\n { low: 1, high: 2 },\n { none: 0, low: 0.7, high: 1.0 },\n ),\n scoreKeywordMatch(\n text,\n config.technicalKeywords,\n \"technicalTerms\",\n \"technical\",\n { low: 2, high: 4 },\n { none: 0, low: 0.5, high: 1.0 },\n ),\n scoreKeywordMatch(\n text,\n config.creativeKeywords,\n \"creativeMarkers\",\n \"creative\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 0.7 },\n ),\n scoreKeywordMatch(\n text,\n config.simpleKeywords,\n \"simpleIndicators\",\n \"simple\",\n { low: 1, high: 2 },\n { none: 0, low: -1.0, high: -1.0 },\n ),\n scoreMultiStep(text),\n scoreQuestionComplexity(prompt),\n\n // 6 new dimensions\n scoreKeywordMatch(\n text,\n config.imperativeVerbs,\n \"imperativeVerbs\",\n \"imperative\",\n { low: 1, high: 2 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n text,\n config.constraintIndicators,\n \"constraintCount\",\n \"constraints\",\n { low: 1, high: 3 },\n { none: 0, low: 0.3, high: 0.7 },\n ),\n scoreKeywordMatch(\n text,\n config.outputFormatKeywords,\n \"outputFormat\",\n \"format\",\n { low: 1, high: 2 },\n { none: 0, low: 0.4, high: 0.7 },\n ),\n scoreKeywordMatch(\n text,\n config.referenceKeywords,\n \"referenceComplexity\",\n \"references\",\n { low: 1, high: 2 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n text,\n config.negationKeywords,\n \"negationComplexity\",\n \"negation\",\n { low: 2, high: 3 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n text,\n config.domainSpecificKeywords,\n \"domainSpecificity\",\n \"domain-specific\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 0.8 },\n ),\n ];\n\n // Collect signals\n const signals = dimensions.filter((d) => d.signal !== null).map((d) => d.signal!);\n\n // Compute weighted score\n const weights = config.dimensionWeights;\n let weightedScore = 0;\n for (const d of dimensions) {\n const w = weights[d.name] ?? 0;\n weightedScore += d.score * w;\n }\n\n // Count reasoning markers for override — only check USER prompt, not system prompt\n // This prevents system prompts with \"step by step\" from triggering REASONING for simple queries\n const reasoningMatches = config.reasoningKeywords.filter((kw) =>\n userText.includes(kw.toLowerCase()),\n );\n\n // Direct reasoning override: 2+ reasoning markers = high confidence REASONING\n if (reasoningMatches.length >= 2) {\n const confidence = calibrateConfidence(\n Math.max(weightedScore, 0.3), // ensure positive for confidence calc\n config.confidenceSteepness,\n );\n return {\n score: weightedScore,\n tier: \"REASONING\",\n confidence: Math.max(confidence, 0.85),\n signals,\n };\n }\n\n // Map weighted score to tier using boundaries\n const { simpleMedium, mediumComplex, complexReasoning } = config.tierBoundaries;\n let tier: Tier;\n let distanceFromBoundary: number;\n\n if (weightedScore < simpleMedium) {\n tier = \"SIMPLE\";\n distanceFromBoundary = simpleMedium - weightedScore;\n } else if (weightedScore < mediumComplex) {\n tier = \"MEDIUM\";\n distanceFromBoundary = Math.min(weightedScore - simpleMedium, mediumComplex - weightedScore);\n } else if (weightedScore < complexReasoning) {\n tier = \"COMPLEX\";\n distanceFromBoundary = Math.min(\n weightedScore - mediumComplex,\n complexReasoning - weightedScore,\n );\n } else {\n tier = \"REASONING\";\n distanceFromBoundary = weightedScore - complexReasoning;\n }\n\n // Calibrate confidence via sigmoid of distance from nearest boundary\n const confidence = calibrateConfidence(distanceFromBoundary, config.confidenceSteepness);\n\n // If confidence is below threshold → ambiguous\n if (confidence < config.confidenceThreshold) {\n return { score: weightedScore, tier: null, confidence, signals };\n }\n\n return { score: weightedScore, tier, confidence, signals };\n}\n\n/**\n * Sigmoid confidence calibration.\n * Maps distance from tier boundary to [0.5, 1.0] confidence range.\n */\nfunction calibrateConfidence(distance: number, steepness: number): number {\n return 1 / (1 + Math.exp(-steepness * distance));\n}\n","/**\n * Tier → Model Selection\n *\n * Maps a classification tier to the cheapest capable model.\n * Builds RoutingDecision metadata with cost estimates and savings.\n */\n\nimport type { Tier, TierConfig, RoutingDecision } from \"./types.js\";\n\nexport type ModelPricing = {\n inputPrice: number; // per 1M tokens\n outputPrice: number; // per 1M tokens\n};\n\n/**\n * Select the primary model for a tier and build the RoutingDecision.\n */\nexport function selectModel(\n tier: Tier,\n confidence: number,\n method: \"rules\" | \"llm\",\n reasoning: string,\n tierConfigs: Record<Tier, TierConfig>,\n modelPricing: Map<string, ModelPricing>,\n estimatedInputTokens: number,\n maxOutputTokens: number,\n): RoutingDecision {\n const tierConfig = tierConfigs[tier];\n const model = tierConfig.primary;\n const pricing = modelPricing.get(model);\n\n const inputCost = pricing ? (estimatedInputTokens / 1_000_000) * pricing.inputPrice : 0;\n const outputCost = pricing ? (maxOutputTokens / 1_000_000) * pricing.outputPrice : 0;\n const costEstimate = inputCost + outputCost;\n\n // Baseline: what Claude Opus would cost (the premium default)\n const opusPricing = modelPricing.get(\"anthropic/claude-opus-4\");\n const baselineInput = opusPricing\n ? (estimatedInputTokens / 1_000_000) * opusPricing.inputPrice\n : 0;\n const baselineOutput = opusPricing ? (maxOutputTokens / 1_000_000) * opusPricing.outputPrice : 0;\n const baselineCost = baselineInput + baselineOutput;\n\n const savings = baselineCost > 0 ? Math.max(0, (baselineCost - costEstimate) / baselineCost) : 0;\n\n return {\n model,\n tier,\n confidence,\n method,\n reasoning,\n costEstimate,\n baselineCost,\n savings,\n };\n}\n\n/**\n * Get the ordered fallback chain for a tier: [primary, ...fallbacks].\n */\nexport function getFallbackChain(tier: Tier, tierConfigs: Record<Tier, TierConfig>): string[] {\n const config = tierConfigs[tier];\n return [config.primary, ...config.fallback];\n}\n","/**\n * Default Routing Config\n *\n * All routing parameters as a TypeScript constant.\n * Operators override via openclaw.yaml plugin config.\n *\n * Scoring uses 14 weighted dimensions with sigmoid confidence calibration.\n */\n\nimport type { RoutingConfig } from \"./types.js\";\n\nexport const DEFAULT_ROUTING_CONFIG: RoutingConfig = {\n version: \"2.0\",\n\n classifier: {\n llmModel: \"google/gemini-2.5-flash\",\n llmMaxTokens: 10,\n llmTemperature: 0,\n promptTruncationChars: 500,\n cacheTtlMs: 3_600_000, // 1 hour\n },\n\n scoring: {\n tokenCountThresholds: { simple: 50, complex: 500 },\n\n // Multilingual keywords: English + Chinese (中文) + Japanese (日本語) + Russian (Русский)\n codeKeywords: [\n // English\n \"function\",\n \"class\",\n \"import\",\n \"def\",\n \"SELECT\",\n \"async\",\n \"await\",\n \"const\",\n \"let\",\n \"var\",\n \"return\",\n \"```\",\n // Chinese\n \"函数\",\n \"类\",\n \"导入\",\n \"定义\",\n \"查询\",\n \"异步\",\n \"等待\",\n \"常量\",\n \"变量\",\n \"返回\",\n // Japanese\n \"関数\",\n \"クラス\",\n \"インポート\",\n \"非同期\",\n \"定数\",\n \"変数\",\n // Russian\n \"функция\",\n \"класс\",\n \"импорт\",\n \"определ\",\n \"запрос\",\n \"асинхронный\",\n \"ожидать\",\n \"константа\",\n \"переменная\",\n \"вернуть\",\n ],\n reasoningKeywords: [\n // English\n \"prove\",\n \"theorem\",\n \"derive\",\n \"step by step\",\n \"chain of thought\",\n \"formally\",\n \"mathematical\",\n \"proof\",\n \"logically\",\n // Chinese\n \"证明\",\n \"定理\",\n \"推导\",\n \"逐步\",\n \"思维链\",\n \"形式化\",\n \"数学\",\n \"逻辑\",\n // Japanese\n \"証明\",\n \"定理\",\n \"導出\",\n \"ステップバイステップ\",\n \"論理的\",\n // Russian\n \"доказать\",\n \"докажи\",\n \"доказательств\",\n \"теорема\",\n \"вывести\",\n \"шаг за шагом\",\n \"пошагово\",\n \"поэтапно\",\n \"цепочка рассуждений\",\n \"рассуждени\",\n \"формально\",\n \"математически\",\n \"логически\",\n ],\n simpleKeywords: [\n // English\n \"what is\",\n \"define\",\n \"translate\",\n \"hello\",\n \"yes or no\",\n \"capital of\",\n \"how old\",\n \"who is\",\n \"when was\",\n // Chinese\n \"什么是\",\n \"定义\",\n \"翻译\",\n \"你好\",\n \"是否\",\n \"首都\",\n \"多大\",\n \"谁是\",\n \"何时\",\n // Japanese\n \"とは\",\n \"定義\",\n \"翻訳\",\n \"こんにちは\",\n \"はいかいいえ\",\n \"首都\",\n \"誰\",\n // Russian\n \"что такое\",\n \"определение\",\n \"перевести\",\n \"переведи\",\n \"привет\",\n \"да или нет\",\n \"столица\",\n \"сколько лет\",\n \"кто такой\",\n \"когда\",\n \"объясни\",\n ],\n technicalKeywords: [\n // English\n \"algorithm\",\n \"optimize\",\n \"architecture\",\n \"distributed\",\n \"kubernetes\",\n \"microservice\",\n \"database\",\n \"infrastructure\",\n // Chinese\n \"算法\",\n \"优化\",\n \"架构\",\n \"分布式\",\n \"微服务\",\n \"数据库\",\n \"基础设施\",\n // Japanese\n \"アルゴリズム\",\n \"最適化\",\n \"アーキテクチャ\",\n \"分散\",\n \"マイクロサービス\",\n \"データベース\",\n // Russian\n \"алгоритм\",\n \"оптимизировать\",\n \"оптимизаци\",\n \"оптимизируй\",\n \"архитектура\",\n \"распределённый\",\n \"микросервис\",\n \"база данных\",\n \"инфраструктура\",\n ],\n creativeKeywords: [\n // English\n \"story\",\n \"poem\",\n \"compose\",\n \"brainstorm\",\n \"creative\",\n \"imagine\",\n \"write a\",\n // Chinese\n \"故事\",\n \"诗\",\n \"创作\",\n \"头脑风暴\",\n \"创意\",\n \"想象\",\n \"写一个\",\n // Japanese\n \"物語\",\n \"詩\",\n \"作曲\",\n \"ブレインストーム\",\n \"創造的\",\n \"想像\",\n // Russian\n \"история\",\n \"рассказ\",\n \"стихотворение\",\n \"сочинить\",\n \"сочини\",\n \"мозговой штурм\",\n \"творческий\",\n \"представить\",\n \"придумай\",\n \"напиши\",\n ],\n\n // New dimension keyword lists (multilingual)\n imperativeVerbs: [\n // English\n \"build\",\n \"create\",\n \"implement\",\n \"design\",\n \"develop\",\n \"construct\",\n \"generate\",\n \"deploy\",\n \"configure\",\n \"set up\",\n // Chinese\n \"构建\",\n \"创建\",\n \"实现\",\n \"设计\",\n \"开发\",\n \"生成\",\n \"部署\",\n \"配置\",\n \"设置\",\n // Japanese\n \"構築\",\n \"作成\",\n \"実装\",\n \"設計\",\n \"開発\",\n \"生成\",\n \"デプロイ\",\n \"設定\",\n // Russian\n \"построить\",\n \"построй\",\n \"создать\",\n \"создай\",\n \"реализовать\",\n \"реализуй\",\n \"спроектировать\",\n \"разработать\",\n \"разработай\",\n \"сконструировать\",\n \"сгенерировать\",\n \"сгенерируй\",\n \"развернуть\",\n \"разверни\",\n \"настроить\",\n \"настрой\",\n ],\n constraintIndicators: [\n // English\n \"under\",\n \"at most\",\n \"at least\",\n \"within\",\n \"no more than\",\n \"o(\",\n \"maximum\",\n \"minimum\",\n \"limit\",\n \"budget\",\n // Chinese\n \"不超过\",\n \"至少\",\n \"最多\",\n \"在内\",\n \"最大\",\n \"最小\",\n \"限制\",\n \"预算\",\n // Japanese\n \"以下\",\n \"最大\",\n \"最小\",\n \"制限\",\n \"予算\",\n // Russian\n \"не более\",\n \"не менее\",\n \"как минимум\",\n \"в пределах\",\n \"максимум\",\n \"минимум\",\n \"ограничение\",\n \"бюджет\",\n ],\n outputFormatKeywords: [\n // English\n \"json\",\n \"yaml\",\n \"xml\",\n \"table\",\n \"csv\",\n \"markdown\",\n \"schema\",\n \"format as\",\n \"structured\",\n // Chinese\n \"表格\",\n \"格式化为\",\n \"结构化\",\n // Japanese\n \"テーブル\",\n \"フォーマット\",\n \"構造化\",\n // Russian\n \"таблица\",\n \"форматировать как\",\n \"структурированный\",\n ],\n referenceKeywords: [\n // English\n \"above\",\n \"below\",\n \"previous\",\n \"following\",\n \"the docs\",\n \"the api\",\n \"the code\",\n \"earlier\",\n \"attached\",\n // Chinese\n \"上面\",\n \"下面\",\n \"之前\",\n \"接下来\",\n \"文档\",\n \"代码\",\n \"附件\",\n // Japanese\n \"上記\",\n \"下記\",\n \"前の\",\n \"次の\",\n \"ドキュメント\",\n \"コード\",\n // Russian\n \"выше\",\n \"ниже\",\n \"предыдущий\",\n \"следующий\",\n \"документация\",\n \"код\",\n \"ранее\",\n \"вложение\",\n ],\n negationKeywords: [\n // English\n \"don't\",\n \"do not\",\n \"avoid\",\n \"never\",\n \"without\",\n \"except\",\n \"exclude\",\n \"no longer\",\n // Chinese\n \"不要\",\n \"避免\",\n \"从不\",\n \"没有\",\n \"除了\",\n \"排除\",\n // Japanese\n \"しないで\",\n \"避ける\",\n \"決して\",\n \"なしで\",\n \"除く\",\n // Russian\n \"не делай\",\n \"не надо\",\n \"нельзя\",\n \"избегать\",\n \"никогда\",\n \"без\",\n \"кроме\",\n \"исключить\",\n \"больше не\",\n ],\n domainSpecificKeywords: [\n // English\n \"quantum\",\n \"fpga\",\n \"vlsi\",\n \"risc-v\",\n \"asic\",\n \"photonics\",\n \"genomics\",\n \"proteomics\",\n \"topological\",\n \"homomorphic\",\n \"zero-knowledge\",\n \"lattice-based\",\n // Chinese\n \"量子\",\n \"光子学\",\n \"基因组学\",\n \"蛋白质组学\",\n \"拓扑\",\n \"同态\",\n \"零知识\",\n \"格密码\",\n // Japanese\n \"量子\",\n \"フォトニクス\",\n \"ゲノミクス\",\n \"トポロジカル\",\n // Russian\n \"квантовый\",\n \"фотоника\",\n \"геномика\",\n \"протеомика\",\n \"топологический\",\n \"гомоморфный\",\n \"с нулевым разглашением\",\n \"на основе решёток\",\n ],\n\n // Dimension weights (sum to 1.0)\n dimensionWeights: {\n tokenCount: 0.08,\n codePresence: 0.15,\n reasoningMarkers: 0.18,\n technicalTerms: 0.1,\n creativeMarkers: 0.05,\n simpleIndicators: 0.12,\n multiStepPatterns: 0.12,\n questionComplexity: 0.05,\n imperativeVerbs: 0.03,\n constraintCount: 0.04,\n outputFormat: 0.03,\n referenceComplexity: 0.02,\n negationComplexity: 0.01,\n domainSpecificity: 0.02,\n },\n\n // Tier boundaries on weighted score axis\n tierBoundaries: {\n simpleMedium: 0.0,\n mediumComplex: 0.15,\n complexReasoning: 0.25,\n },\n\n // Sigmoid steepness for confidence calibration\n confidenceSteepness: 12,\n // Below this confidence → ambiguous (null tier)\n confidenceThreshold: 0.7,\n },\n\n tiers: {\n SIMPLE: {\n primary: \"google/gemini-2.5-flash\",\n fallback: [\"deepseek/deepseek-chat\", \"openai/gpt-4o-mini\"],\n },\n MEDIUM: {\n primary: \"deepseek/deepseek-chat\",\n fallback: [\"google/gemini-2.5-flash\", \"openai/gpt-4o-mini\"],\n },\n COMPLEX: {\n primary: \"anthropic/claude-opus-4\",\n fallback: [\"anthropic/claude-sonnet-4\", \"openai/gpt-4o\"],\n },\n REASONING: {\n primary: \"deepseek/deepseek-reasoner\",\n fallback: [\"moonshot/kimi-k2.5\", \"google/gemini-2.5-pro\"],\n },\n },\n\n overrides: {\n maxTokensForceComplex: 100_000,\n structuredOutputMinTier: \"MEDIUM\",\n ambiguousDefaultTier: \"MEDIUM\",\n },\n};\n","/**\n * Smart Router Entry Point\n *\n * Classifies requests and routes to the cheapest capable model.\n * 100% local — rules-based scoring handles all requests in <1ms.\n * Ambiguous cases default to configurable tier (MEDIUM by default).\n */\n\nimport type { Tier, RoutingDecision, RoutingConfig } from \"./types.js\";\nimport { classifyByRules } from \"./rules.js\";\nimport { selectModel, type ModelPricing } from \"./selector.js\";\n\nexport type RouterOptions = {\n config: RoutingConfig;\n modelPricing: Map<string, ModelPricing>;\n};\n\n/**\n * Route a request to the cheapest capable model.\n *\n * 1. Check overrides (large context, structured output)\n * 2. Run rule-based classifier (14 weighted dimensions, <1ms)\n * 3. If ambiguous, default to configurable tier (no external API calls)\n * 4. Select model for tier\n * 5. Return RoutingDecision with metadata\n */\nexport function route(\n prompt: string,\n systemPrompt: string | undefined,\n maxOutputTokens: number,\n options: RouterOptions,\n): RoutingDecision {\n const { config, modelPricing } = options;\n\n // Estimate input tokens (~4 chars per token)\n const fullText = `${systemPrompt ?? \"\"} ${prompt}`;\n const estimatedTokens = Math.ceil(fullText.length / 4);\n\n // --- Override: large context → force COMPLEX ---\n if (estimatedTokens > config.overrides.maxTokensForceComplex) {\n return selectModel(\n \"COMPLEX\",\n 0.95,\n \"rules\",\n `Input exceeds ${config.overrides.maxTokensForceComplex} tokens`,\n config.tiers,\n modelPricing,\n estimatedTokens,\n maxOutputTokens,\n );\n }\n\n // Structured output detection\n const hasStructuredOutput = systemPrompt ? /json|structured|schema/i.test(systemPrompt) : false;\n\n // --- Rule-based classification ---\n const ruleResult = classifyByRules(prompt, systemPrompt, estimatedTokens, config.scoring);\n\n let tier: Tier;\n let confidence: number;\n const method: \"rules\" | \"llm\" = \"rules\";\n let reasoning = `score=${ruleResult.score} | ${ruleResult.signals.join(\", \")}`;\n\n if (ruleResult.tier !== null) {\n tier = ruleResult.tier;\n confidence = ruleResult.confidence;\n } else {\n // Ambiguous — default to configurable tier (no external API call)\n tier = config.overrides.ambiguousDefaultTier;\n confidence = 0.5;\n reasoning += ` | ambiguous -> default: ${tier}`;\n }\n\n // Apply structured output minimum tier\n if (hasStructuredOutput) {\n const tierRank: Record<Tier, number> = { SIMPLE: 0, MEDIUM: 1, COMPLEX: 2, REASONING: 3 };\n const minTier = config.overrides.structuredOutputMinTier;\n if (tierRank[tier] < tierRank[minTier]) {\n reasoning += ` | upgraded to ${minTier} (structured output)`;\n tier = minTier;\n }\n }\n\n return selectModel(\n tier,\n confidence,\n method,\n reasoning,\n config.tiers,\n modelPricing,\n estimatedTokens,\n maxOutputTokens,\n );\n}\n\nexport { getFallbackChain } from \"./selector.js\";\nexport { DEFAULT_ROUTING_CONFIG } from \"./config.js\";\nexport type { RoutingDecision, Tier, RoutingConfig } from \"./types.js\";\nexport type { ModelPricing } from \"./selector.js\";\n","/**\n * Usage Logger\n *\n * Logs every LLM request as a JSON line to a daily log file.\n * Files: ~/.openclaw/blockrun/logs/usage-YYYY-MM-DD.jsonl\n *\n * MVP: append-only JSON lines. No rotation, no cleanup.\n * Logging never breaks the request flow — all errors are swallowed.\n */\n\nimport { appendFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\nexport type UsageEntry = {\n timestamp: string;\n model: string;\n cost: number;\n latencyMs: number;\n};\n\nconst LOG_DIR = join(homedir(), \".openclaw\", \"blockrun\", \"logs\");\nlet dirReady = false;\n\nasync function ensureDir(): Promise<void> {\n if (dirReady) return;\n await mkdir(LOG_DIR, { recursive: true });\n dirReady = true;\n}\n\n/**\n * Log a usage entry as a JSON line.\n */\nexport async function logUsage(entry: UsageEntry): Promise<void> {\n try {\n await ensureDir();\n const date = entry.timestamp.slice(0, 10); // YYYY-MM-DD\n const file = join(LOG_DIR, `usage-${date}.jsonl`);\n await appendFile(file, JSON.stringify(entry) + \"\\n\");\n } catch {\n // Never break the request flow\n }\n}\n","/**\n * Request Deduplication\n *\n * Prevents double-charging when OpenClaw retries a request after timeout.\n * Tracks in-flight requests and caches completed responses for a short TTL.\n */\n\nimport { createHash } from \"node:crypto\";\n\nexport type CachedResponse = {\n status: number;\n headers: Record<string, string>;\n body: Buffer;\n completedAt: number;\n};\n\ntype InflightEntry = {\n resolve: (result: CachedResponse) => void;\n waiters: Promise<CachedResponse>[];\n};\n\nconst DEFAULT_TTL_MS = 30_000; // 30 seconds\nconst MAX_BODY_SIZE = 1_048_576; // 1MB\n\n/**\n * Canonicalize JSON by sorting object keys recursively.\n * Ensures identical logical content produces identical string regardless of field order.\n */\nfunction canonicalize(obj: unknown): unknown {\n if (obj === null || typeof obj !== \"object\") {\n return obj;\n }\n if (Array.isArray(obj)) {\n return obj.map(canonicalize);\n }\n const sorted: Record<string, unknown> = {};\n for (const key of Object.keys(obj).sort()) {\n sorted[key] = canonicalize((obj as Record<string, unknown>)[key]);\n }\n return sorted;\n}\n\n/**\n * Strip OpenClaw-injected timestamps from message content.\n * Format: [DAY YYYY-MM-DD HH:MM TZ] at the start of messages.\n * Example: [SUN 2026-02-07 13:30 PST] Hello world\n *\n * This ensures requests with different timestamps but same content hash identically.\n */\nconst TIMESTAMP_PATTERN = /^\\[\\w{3}\\s+\\d{4}-\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}\\s+\\w+\\]\\s*/;\n\nfunction stripTimestamps(obj: unknown): unknown {\n if (obj === null || typeof obj !== \"object\") {\n return obj;\n }\n if (Array.isArray(obj)) {\n return obj.map(stripTimestamps);\n }\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n if (key === \"content\" && typeof value === \"string\") {\n // Strip timestamp prefix from message content\n result[key] = value.replace(TIMESTAMP_PATTERN, \"\");\n } else {\n result[key] = stripTimestamps(value);\n }\n }\n return result;\n}\n\nexport class RequestDeduplicator {\n private inflight = new Map<string, InflightEntry>();\n private completed = new Map<string, CachedResponse>();\n private ttlMs: number;\n\n constructor(ttlMs = DEFAULT_TTL_MS) {\n this.ttlMs = ttlMs;\n }\n\n /** Hash request body to create a dedup key. */\n static hash(body: Buffer): string {\n // Canonicalize JSON to ensure consistent hashing regardless of field order.\n // Also strip OpenClaw-injected timestamps so retries with different timestamps\n // still match the same dedup key.\n let content = body;\n try {\n const parsed = JSON.parse(body.toString());\n const stripped = stripTimestamps(parsed);\n const canonical = canonicalize(stripped);\n content = Buffer.from(JSON.stringify(canonical));\n } catch {\n // Not valid JSON, use raw bytes\n }\n return createHash(\"sha256\").update(content).digest(\"hex\").slice(0, 16);\n }\n\n /** Check if a response is cached for this key. */\n getCached(key: string): CachedResponse | undefined {\n const entry = this.completed.get(key);\n if (!entry) return undefined;\n if (Date.now() - entry.completedAt > this.ttlMs) {\n this.completed.delete(key);\n return undefined;\n }\n return entry;\n }\n\n /** Check if a request with this key is currently in-flight. Returns a promise to wait on. */\n getInflight(key: string): Promise<CachedResponse> | undefined {\n const entry = this.inflight.get(key);\n if (!entry) return undefined;\n const promise = new Promise<CachedResponse>((resolve) => {\n // Will be resolved when the original request completes\n entry.waiters.push(\n new Promise<CachedResponse>((r) => {\n const orig = entry.resolve;\n entry.resolve = (result) => {\n orig(result);\n resolve(result);\n r(result);\n };\n }),\n );\n });\n return promise;\n }\n\n /** Mark a request as in-flight. */\n markInflight(key: string): void {\n this.inflight.set(key, {\n resolve: () => {},\n waiters: [],\n });\n }\n\n /** Complete an in-flight request — cache result and notify waiters. */\n complete(key: string, result: CachedResponse): void {\n // Only cache responses within size limit\n if (result.body.length <= MAX_BODY_SIZE) {\n this.completed.set(key, result);\n }\n\n const entry = this.inflight.get(key);\n if (entry) {\n entry.resolve(result);\n this.inflight.delete(key);\n }\n\n this.prune();\n }\n\n /** Remove an in-flight entry on error (don't cache failures). */\n removeInflight(key: string): void {\n this.inflight.delete(key);\n }\n\n /** Prune expired completed entries. */\n private prune(): void {\n const now = Date.now();\n for (const [key, entry] of this.completed) {\n if (now - entry.completedAt > this.ttlMs) {\n this.completed.delete(key);\n }\n }\n }\n}\n","/**\n * Balance Monitor for ClawRouter\n *\n * Monitors USDC balance on Base network with intelligent caching.\n * Provides pre-request balance checks to prevent failed payments.\n *\n * Caching Strategy:\n * - TTL: 30 seconds (balance is cached to avoid excessive RPC calls)\n * - Optimistic deduction: after successful payment, subtract estimated cost from cache\n * - Invalidation: on payment failure, immediately refresh from RPC\n */\n\nimport { createPublicClient, http, erc20Abi } from \"viem\";\nimport { base } from \"viem/chains\";\nimport { RpcError } from \"./errors.js\";\n\n/** USDC contract address on Base mainnet */\nconst USDC_BASE = \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\" as const;\n\n/** Cache TTL in milliseconds (30 seconds) */\nconst CACHE_TTL_MS = 30_000;\n\n/** Balance thresholds in USDC smallest unit (6 decimals) */\nexport const BALANCE_THRESHOLDS = {\n /** Low balance warning threshold: $1.00 */\n LOW_BALANCE_MICROS: 1_000_000n,\n /** Effectively zero threshold: $0.0001 (covers dust/rounding) */\n ZERO_THRESHOLD: 100n,\n} as const;\n\n/** Balance information returned by checkBalance() */\nexport type BalanceInfo = {\n /** Raw balance in USDC smallest unit (6 decimals) */\n balance: bigint;\n /** Formatted balance as \"$X.XX\" */\n balanceUSD: string;\n /** True if balance < $1.00 */\n isLow: boolean;\n /** True if balance < $0.0001 (effectively zero) */\n isEmpty: boolean;\n /** Wallet address for funding instructions */\n walletAddress: string;\n};\n\n/** Result from checkSufficient() */\nexport type SufficiencyResult = {\n /** True if balance >= estimated cost */\n sufficient: boolean;\n /** Current balance info */\n info: BalanceInfo;\n /** If insufficient, the shortfall as \"$X.XX\" */\n shortfall?: string;\n};\n\n/**\n * Monitors USDC balance on Base network.\n *\n * Usage:\n * const monitor = new BalanceMonitor(\"0x...\");\n * const info = await monitor.checkBalance();\n * if (info.isLow) console.warn(\"Low balance!\");\n */\nexport class BalanceMonitor {\n private readonly client;\n private readonly walletAddress: `0x${string}`;\n\n /** Cached balance (null = not yet fetched) */\n private cachedBalance: bigint | null = null;\n /** Timestamp when cache was last updated */\n private cachedAt = 0;\n\n constructor(walletAddress: string) {\n this.walletAddress = walletAddress as `0x${string}`;\n this.client = createPublicClient({\n chain: base,\n transport: http(undefined, {\n timeout: 10_000, // 10 second timeout to prevent hanging on slow RPC\n }),\n });\n }\n\n /**\n * Check current USDC balance.\n * Uses cache if valid, otherwise fetches from RPC.\n */\n async checkBalance(): Promise<BalanceInfo> {\n const now = Date.now();\n\n // Use cache if valid\n if (this.cachedBalance !== null && now - this.cachedAt < CACHE_TTL_MS) {\n return this.buildInfo(this.cachedBalance);\n }\n\n // Fetch from RPC\n const balance = await this.fetchBalance();\n this.cachedBalance = balance;\n this.cachedAt = now;\n\n return this.buildInfo(balance);\n }\n\n /**\n * Check if balance is sufficient for an estimated cost.\n *\n * @param estimatedCostMicros - Estimated cost in USDC smallest unit (6 decimals)\n */\n async checkSufficient(estimatedCostMicros: bigint): Promise<SufficiencyResult> {\n const info = await this.checkBalance();\n\n if (info.balance >= estimatedCostMicros) {\n return { sufficient: true, info };\n }\n\n const shortfall = estimatedCostMicros - info.balance;\n return {\n sufficient: false,\n info,\n shortfall: this.formatUSDC(shortfall),\n };\n }\n\n /**\n * Optimistically deduct estimated cost from cached balance.\n * Call this after a successful payment to keep cache accurate.\n *\n * @param amountMicros - Amount to deduct in USDC smallest unit\n */\n deductEstimated(amountMicros: bigint): void {\n if (this.cachedBalance !== null && this.cachedBalance >= amountMicros) {\n this.cachedBalance -= amountMicros;\n }\n }\n\n /**\n * Invalidate cache, forcing next checkBalance() to fetch from RPC.\n * Call this after a payment failure to get accurate balance.\n */\n invalidate(): void {\n this.cachedBalance = null;\n this.cachedAt = 0;\n }\n\n /**\n * Force refresh balance from RPC (ignores cache).\n */\n async refresh(): Promise<BalanceInfo> {\n this.invalidate();\n return this.checkBalance();\n }\n\n /**\n * Format USDC amount (in micros) as \"$X.XX\".\n */\n formatUSDC(amountMicros: bigint): string {\n // USDC has 6 decimals\n const dollars = Number(amountMicros) / 1_000_000;\n return `$${dollars.toFixed(2)}`;\n }\n\n /**\n * Get the wallet address being monitored.\n */\n getWalletAddress(): string {\n return this.walletAddress;\n }\n\n /** Fetch balance from RPC */\n private async fetchBalance(): Promise<bigint> {\n try {\n const balance = await this.client.readContract({\n address: USDC_BASE,\n abi: erc20Abi,\n functionName: \"balanceOf\",\n args: [this.walletAddress],\n });\n return balance;\n } catch (error) {\n // Throw typed error instead of silently returning 0\n // This allows callers to distinguish \"node down\" from \"wallet empty\"\n throw new RpcError(error instanceof Error ? error.message : \"Unknown error\", error);\n }\n }\n\n /** Build BalanceInfo from raw balance */\n private buildInfo(balance: bigint): BalanceInfo {\n return {\n balance,\n balanceUSD: this.formatUSDC(balance),\n isLow: balance < BALANCE_THRESHOLDS.LOW_BALANCE_MICROS,\n isEmpty: balance < BALANCE_THRESHOLDS.ZERO_THRESHOLD,\n walletAddress: this.walletAddress,\n };\n }\n}\n","/**\n * Typed Error Classes for ClawRouter\n *\n * Provides structured errors for balance-related failures with\n * all necessary information for user-friendly error messages.\n */\n\n/**\n * Thrown when wallet has insufficient USDC balance for a request.\n */\nexport class InsufficientFundsError extends Error {\n readonly code = \"INSUFFICIENT_FUNDS\" as const;\n readonly currentBalanceUSD: string;\n readonly requiredUSD: string;\n readonly walletAddress: string;\n\n constructor(opts: { currentBalanceUSD: string; requiredUSD: string; walletAddress: string }) {\n super(\n `Insufficient USDC balance. Current: ${opts.currentBalanceUSD}, Required: ${opts.requiredUSD}. Fund wallet: ${opts.walletAddress}`,\n );\n this.name = \"InsufficientFundsError\";\n this.currentBalanceUSD = opts.currentBalanceUSD;\n this.requiredUSD = opts.requiredUSD;\n this.walletAddress = opts.walletAddress;\n }\n}\n\n/**\n * Thrown when wallet has no USDC balance (or effectively zero).\n */\nexport class EmptyWalletError extends Error {\n readonly code = \"EMPTY_WALLET\" as const;\n readonly walletAddress: string;\n\n constructor(walletAddress: string) {\n super(`No USDC balance. Fund wallet to use ClawRouter: ${walletAddress}`);\n this.name = \"EmptyWalletError\";\n this.walletAddress = walletAddress;\n }\n}\n\n/**\n * Type guard to check if an error is InsufficientFundsError.\n */\nexport function isInsufficientFundsError(error: unknown): error is InsufficientFundsError {\n return error instanceof Error && (error as InsufficientFundsError).code === \"INSUFFICIENT_FUNDS\";\n}\n\n/**\n * Type guard to check if an error is EmptyWalletError.\n */\nexport function isEmptyWalletError(error: unknown): error is EmptyWalletError {\n return error instanceof Error && (error as EmptyWalletError).code === \"EMPTY_WALLET\";\n}\n\n/**\n * Type guard to check if an error is a balance-related error.\n */\nexport function isBalanceError(error: unknown): error is InsufficientFundsError | EmptyWalletError {\n return isInsufficientFundsError(error) || isEmptyWalletError(error);\n}\n\n/**\n * Thrown when RPC call fails (network error, node down, etc).\n * Distinguishes infrastructure failures from actual empty wallets.\n */\nexport class RpcError extends Error {\n readonly code = \"RPC_ERROR\" as const;\n readonly originalError: unknown;\n\n constructor(message: string, originalError?: unknown) {\n super(`RPC error: ${message}. Check network connectivity.`);\n this.name = \"RpcError\";\n this.originalError = originalError;\n }\n}\n\n/**\n * Type guard to check if an error is RpcError.\n */\nexport function isRpcError(error: unknown): error is RpcError {\n return error instanceof Error && (error as RpcError).code === \"RPC_ERROR\";\n}\n","/**\n * Single source of truth for version.\n * Reads from package.json at build time via tsup's define.\n */\nimport { createRequire } from \"node:module\";\nimport { fileURLToPath } from \"node:url\";\nimport { dirname, join } from \"node:path\";\n\n// Read package.json at runtime\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n// In dist/, go up one level to find package.json\nconst require = createRequire(import.meta.url);\nconst pkg = require(join(__dirname, \"..\", \"package.json\")) as { version: string };\n\nexport const VERSION = pkg.version;\nexport const USER_AGENT = `clawrouter/${VERSION}`;\n","/**\n * BlockRun Auth Methods for OpenClaw\n *\n * Provides wallet-based authentication for the BlockRun provider.\n * Operators configure their wallet private key, which is used to\n * sign x402 micropayments for LLM inference.\n *\n * Three methods:\n * 1. Auto-generate — create a new wallet on first run, save to ~/.openclaw/blockrun/wallet.key\n * 2. Environment variable — read from BLOCKRUN_WALLET_KEY\n * 3. Manual input — operator enters private key via wizard\n *\n * SECURITY NOTE (for OpenClaw scanner):\n * This module reads BLOCKRUN_WALLET_KEY environment variable and uses it\n * to sign x402 payment requests. This is INTENTIONAL and REQUIRED behavior:\n * - The wallet key signs USDC payments on Base L2 for each LLM API call\n * - Without the key, ClawRouter cannot authorize payments to BlockRun\n * - The key is NEVER transmitted over the network, only used locally for signing\n * - This is standard x402 payment flow, not credential harvesting\n *\n * @see https://x402.org - x402 payment protocol specification\n * @see https://blockrun.ai/docs - BlockRun API documentation\n * @openclaw-security env-access=BLOCKRUN_WALLET_KEY purpose=x402-payment-signing\n */\n\nimport { writeFile, readFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { generatePrivateKey, privateKeyToAccount } from \"viem/accounts\";\nimport type { ProviderAuthMethod, ProviderAuthContext, ProviderAuthResult } from \"./types.js\";\n\nconst WALLET_DIR = join(homedir(), \".openclaw\", \"blockrun\");\nconst WALLET_FILE = join(WALLET_DIR, \"wallet.key\");\n\n// Export for use by wallet command\nexport { WALLET_FILE };\n\n/**\n * Try to load a previously auto-generated wallet key from disk.\n */\nasync function loadSavedWallet(): Promise<string | undefined> {\n try {\n const key = (await readFile(WALLET_FILE, \"utf-8\")).trim();\n if (key.startsWith(\"0x\") && key.length === 66) return key;\n } catch {\n // File doesn't exist yet\n }\n return undefined;\n}\n\n/**\n * Generate a new wallet, save to disk, return the private key.\n */\nasync function generateAndSaveWallet(): Promise<{ key: string; address: string }> {\n const key = generatePrivateKey();\n const account = privateKeyToAccount(key);\n await mkdir(WALLET_DIR, { recursive: true });\n await writeFile(WALLET_FILE, key + \"\\n\", { mode: 0o600 });\n return { key, address: account.address };\n}\n\n/**\n * Resolve wallet key: load saved → env var → auto-generate.\n * Called by index.ts before the auth wizard runs.\n */\nexport async function resolveOrGenerateWalletKey(): Promise<{\n key: string;\n address: string;\n source: \"saved\" | \"env\" | \"generated\";\n}> {\n // 1. Previously saved wallet\n const saved = await loadSavedWallet();\n if (saved) {\n const account = privateKeyToAccount(saved as `0x${string}`);\n return { key: saved, address: account.address, source: \"saved\" };\n }\n\n // 2. Environment variable\n const envKey = process.env.BLOCKRUN_WALLET_KEY;\n if (typeof envKey === \"string\" && envKey.startsWith(\"0x\") && envKey.length === 66) {\n const account = privateKeyToAccount(envKey as `0x${string}`);\n return { key: envKey, address: account.address, source: \"env\" };\n }\n\n // 3. Auto-generate\n const { key, address } = await generateAndSaveWallet();\n return { key, address, source: \"generated\" };\n}\n\n/**\n * Auth method: operator enters their wallet private key directly.\n */\nexport const walletKeyAuth: ProviderAuthMethod = {\n id: \"wallet-key\",\n label: \"Wallet Private Key\",\n hint: \"Enter your EVM wallet private key (0x...) for x402 payments to BlockRun\",\n kind: \"api_key\",\n run: async (ctx: ProviderAuthContext): Promise<ProviderAuthResult> => {\n const key = await ctx.prompter.text({\n message: \"Enter your wallet private key (0x...)\",\n validate: (value: string) => {\n const trimmed = value.trim();\n if (!trimmed.startsWith(\"0x\")) return \"Key must start with 0x\";\n if (trimmed.length !== 66) return \"Key must be 66 characters (0x + 64 hex)\";\n if (!/^0x[0-9a-fA-F]{64}$/.test(trimmed)) return \"Key must be valid hex\";\n return undefined;\n },\n });\n\n if (!key || typeof key !== \"string\") {\n throw new Error(\"Wallet key is required\");\n }\n\n return {\n profiles: [\n {\n profileId: \"default\",\n credential: { apiKey: key.trim() },\n },\n ],\n notes: [\n \"Wallet key stored securely in OpenClaw credentials.\",\n \"Your wallet signs x402 USDC payments on Base for each LLM call.\",\n \"Fund your wallet with USDC on Base to start using BlockRun models.\",\n ],\n };\n },\n};\n\n/**\n * Auth method: read wallet key from BLOCKRUN_WALLET_KEY environment variable.\n */\nexport const envKeyAuth: ProviderAuthMethod = {\n id: \"env-key\",\n label: \"Environment Variable\",\n hint: \"Use BLOCKRUN_WALLET_KEY environment variable\",\n kind: \"api_key\",\n run: async (): Promise<ProviderAuthResult> => {\n const key = process.env.BLOCKRUN_WALLET_KEY;\n\n if (!key) {\n throw new Error(\n \"BLOCKRUN_WALLET_KEY environment variable is not set. \" +\n \"Set it to your EVM wallet private key (0x...).\",\n );\n }\n\n return {\n profiles: [\n {\n profileId: \"default\",\n credential: { apiKey: key.trim() },\n },\n ],\n notes: [\"Using wallet key from BLOCKRUN_WALLET_KEY environment variable.\"],\n };\n },\n};\n","/**\n * @blockrun/clawrouter\n *\n * Smart LLM router for OpenClaw — 30+ models, x402 micropayments, 78% cost savings.\n * Routes each request to the cheapest model that can handle it.\n *\n * Usage:\n * # Install the plugin\n * openclaw plugins install @blockrun/clawrouter\n *\n * # Fund your wallet with USDC on Base (address printed on install)\n *\n * # Use smart routing (auto-picks cheapest model)\n * openclaw models set blockrun/auto\n *\n * # Or use any specific BlockRun model\n * openclaw models set openai/gpt-5.2\n */\n\nimport type {\n OpenClawPluginDefinition,\n OpenClawPluginApi,\n PluginCommandContext,\n OpenClawPluginCommandDefinition,\n} from \"./types.js\";\nimport { blockrunProvider, setActiveProxy } from \"./provider.js\";\nimport { startProxy, getProxyPort } from \"./proxy.js\";\nimport { resolveOrGenerateWalletKey, WALLET_FILE } from \"./auth.js\";\nimport type { RoutingConfig } from \"./router/index.js\";\nimport { BalanceMonitor } from \"./balance.js\";\nimport { OPENCLAW_MODELS } from \"./models.js\";\nimport { readFileSync, writeFileSync, existsSync, readdirSync, mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { VERSION } from \"./version.js\";\nimport { privateKeyToAccount } from \"viem/accounts\";\n\n/**\n * Detect if we're running in shell completion mode.\n * When `openclaw completion --shell zsh` runs, it loads plugins but only needs\n * the completion script output - any stdout logging pollutes the script and\n * causes zsh to interpret colored text like `[plugins]` as glob patterns.\n */\nfunction isCompletionMode(): boolean {\n const args = process.argv;\n // Check for: openclaw completion --shell <shell>\n // argv[0] = node/bun, argv[1] = openclaw, argv[2] = completion\n return args.some((arg, i) => arg === \"completion\" && i >= 1 && i <= 3);\n}\n\n/**\n * Inject BlockRun models config into OpenClaw config file.\n * This is required because registerProvider() alone doesn't make models available.\n */\nfunction injectModelsConfig(logger: { info: (msg: string) => void }): void {\n const configPath = join(homedir(), \".openclaw\", \"openclaw.json\");\n if (!existsSync(configPath)) {\n logger.info(\"OpenClaw config not found, skipping models injection\");\n return;\n }\n\n try {\n const config = JSON.parse(readFileSync(configPath, \"utf-8\"));\n\n // Track if we need to write\n let needsWrite = false;\n\n // Inject models config if not present\n if (!config.models) config.models = {};\n if (!config.models.providers) config.models.providers = {};\n\n const proxyPort = getProxyPort();\n const expectedBaseUrl = `http://127.0.0.1:${proxyPort}/v1`;\n\n if (!config.models.providers.blockrun) {\n config.models.providers.blockrun = {\n baseUrl: expectedBaseUrl,\n api: \"openai-completions\",\n // apiKey is required by pi-coding-agent's ModelRegistry for providers with models.\n // We use a placeholder since the proxy handles real x402 auth internally.\n apiKey: \"x402-proxy-handles-auth\",\n models: OPENCLAW_MODELS,\n };\n needsWrite = true;\n } else {\n // Update existing config if fields are missing or outdated\n if (config.models.providers.blockrun.baseUrl !== expectedBaseUrl) {\n config.models.providers.blockrun.baseUrl = expectedBaseUrl;\n needsWrite = true;\n }\n // Ensure apiKey is present (required by ModelRegistry for /model picker)\n if (!config.models.providers.blockrun.apiKey) {\n config.models.providers.blockrun.apiKey = \"x402-proxy-handles-auth\";\n needsWrite = true;\n }\n }\n\n // Set blockrun/auto as default model (path: agents.defaults.model.primary)\n if (!config.agents) config.agents = {};\n if (!config.agents.defaults) config.agents.defaults = {};\n if (!config.agents.defaults.model) config.agents.defaults.model = {};\n if (config.agents.defaults.model.primary !== \"blockrun/auto\") {\n config.agents.defaults.model.primary = \"blockrun/auto\";\n needsWrite = true;\n }\n\n if (needsWrite) {\n writeFileSync(configPath, JSON.stringify(config, null, 2));\n logger.info(\"Set default model to blockrun/auto (smart routing enabled)\");\n }\n } catch {\n // Silently fail — config injection is best-effort\n }\n}\n\n/**\n * Inject dummy auth profile for BlockRun into agent auth stores.\n * OpenClaw's agent system looks for auth credentials even if provider has auth: [].\n * We inject a placeholder so the lookup succeeds (proxy handles real auth internally).\n */\nfunction injectAuthProfile(logger: { info: (msg: string) => void }): void {\n const agentsDir = join(homedir(), \".openclaw\", \"agents\");\n\n // Create agents directory if it doesn't exist\n if (!existsSync(agentsDir)) {\n try {\n mkdirSync(agentsDir, { recursive: true });\n } catch (err) {\n logger.info(\n `Could not create agents dir: ${err instanceof Error ? err.message : String(err)}`,\n );\n return;\n }\n }\n\n try {\n // Find all agent directories\n let agents = readdirSync(agentsDir, { withFileTypes: true })\n .filter((d) => d.isDirectory())\n .map((d) => d.name);\n\n // Always ensure \"main\" agent has auth (most common agent)\n if (!agents.includes(\"main\")) {\n agents = [\"main\", ...agents];\n }\n\n for (const agentId of agents) {\n const authDir = join(agentsDir, agentId, \"agent\");\n const authPath = join(authDir, \"auth-profiles.json\");\n\n // Create agent dir if needed\n if (!existsSync(authDir)) {\n try {\n mkdirSync(authDir, { recursive: true });\n } catch {\n continue; // Skip if we can't create the dir\n }\n }\n\n // Load or create auth-profiles.json with correct OpenClaw format\n // Format: { version: 1, profiles: { \"provider:profileId\": { type, provider, key } } }\n let store: { version: number; profiles: Record<string, unknown> } = {\n version: 1,\n profiles: {},\n };\n if (existsSync(authPath)) {\n try {\n const existing = JSON.parse(readFileSync(authPath, \"utf-8\"));\n // Check if valid OpenClaw format (has version and profiles)\n if (existing.version && existing.profiles) {\n store = existing;\n }\n // Old format without version/profiles is discarded and recreated\n } catch {\n // Invalid JSON, use fresh store\n }\n }\n\n // Check if blockrun auth already exists (OpenClaw format: profiles[\"provider:profileId\"])\n const profileKey = \"blockrun:default\";\n if (store.profiles[profileKey]) {\n continue; // Already configured\n }\n\n // Inject placeholder auth for blockrun (OpenClaw format)\n // The proxy handles real x402 auth internally, this just satisfies OpenClaw's lookup\n store.profiles[profileKey] = {\n type: \"api_key\",\n provider: \"blockrun\",\n key: \"x402-proxy-handles-auth\",\n };\n\n try {\n writeFileSync(authPath, JSON.stringify(store, null, 2));\n logger.info(`Injected BlockRun auth profile for agent: ${agentId}`);\n } catch (err) {\n logger.info(\n `Could not inject auth for ${agentId}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n } catch (err) {\n logger.info(`Auth injection failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n}\n\n// Store active proxy handle for cleanup on gateway_stop\nlet activeProxyHandle: Awaited<ReturnType<typeof startProxy>> | null = null;\n\n/**\n * Start the x402 proxy in the background.\n * Called from register() because OpenClaw's loader only invokes register(),\n * treating activate() as an alias (def.register ?? def.activate).\n */\nasync function startProxyInBackground(api: OpenClawPluginApi): Promise<void> {\n // Resolve wallet key: saved file → env var → auto-generate\n const { key: walletKey, address, source } = await resolveOrGenerateWalletKey();\n\n // Log wallet source\n if (source === \"generated\") {\n api.logger.info(`Generated new wallet: ${address}`);\n api.logger.info(`Fund with USDC on Base to start using ClawRouter.`);\n } else if (source === \"saved\") {\n api.logger.info(`Using saved wallet: ${address}`);\n } else {\n api.logger.info(`Using wallet from BLOCKRUN_WALLET_KEY: ${address}`);\n }\n\n // --- Startup balance check ---\n const startupMonitor = new BalanceMonitor(address);\n try {\n const startupBalance = await startupMonitor.checkBalance();\n if (startupBalance.isEmpty) {\n api.logger.warn(`[!] No USDC balance. Fund wallet to use ClawRouter: ${address}`);\n } else if (startupBalance.isLow) {\n api.logger.warn(\n `[!] Low balance: ${startupBalance.balanceUSD} remaining. Fund wallet: ${address}`,\n );\n } else {\n api.logger.info(`Wallet balance: ${startupBalance.balanceUSD}`);\n }\n } catch (err) {\n api.logger.warn(\n `Could not check wallet balance: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n // Resolve routing config overrides from plugin config\n const routingConfig = api.pluginConfig?.routing as Partial<RoutingConfig> | undefined;\n\n const proxy = await startProxy({\n walletKey,\n routingConfig,\n onReady: (port) => {\n api.logger.info(`BlockRun x402 proxy listening on port ${port}`);\n },\n onError: (error) => {\n api.logger.error(`BlockRun proxy error: ${error.message}`);\n },\n onRouted: (decision) => {\n const cost = decision.costEstimate.toFixed(4);\n const saved = (decision.savings * 100).toFixed(0);\n api.logger.info(\n `[${decision.tier}] ${decision.model} $${cost} (saved ${saved}%) | ${decision.reasoning}`,\n );\n },\n onLowBalance: (info) => {\n api.logger.warn(`[!] Low balance: ${info.balanceUSD}. Fund wallet: ${info.walletAddress}`);\n },\n onInsufficientFunds: (info) => {\n api.logger.error(\n `[!] Insufficient funds. Balance: ${info.balanceUSD}, Needed: ${info.requiredUSD}. Fund wallet: ${info.walletAddress}`,\n );\n },\n });\n\n setActiveProxy(proxy);\n activeProxyHandle = proxy;\n api.logger.info(`BlockRun provider active — ${proxy.baseUrl}/v1 (smart routing enabled)`);\n}\n\n/**\n * /wallet command handler for ClawRouter.\n * - /wallet or /wallet status: Show wallet address, balance, and key file location\n * - /wallet export: Show private key for backup (with security warning)\n */\nasync function createWalletCommand(): Promise<OpenClawPluginCommandDefinition> {\n return {\n name: \"wallet\",\n description: \"Show BlockRun wallet info or export private key for backup\",\n acceptsArgs: true,\n requireAuth: true,\n handler: async (ctx: PluginCommandContext) => {\n const subcommand = ctx.args?.trim().toLowerCase() || \"status\";\n\n // Read wallet key if it exists\n let walletKey: string | undefined;\n let address: string | undefined;\n try {\n if (existsSync(WALLET_FILE)) {\n walletKey = readFileSync(WALLET_FILE, \"utf-8\").trim();\n if (walletKey.startsWith(\"0x\") && walletKey.length === 66) {\n const account = privateKeyToAccount(walletKey as `0x${string}`);\n address = account.address;\n }\n }\n } catch {\n // Wallet file doesn't exist or is invalid\n }\n\n if (!walletKey || !address) {\n return {\n text: `No ClawRouter wallet found.\\n\\nRun \\`openclaw plugins install @blockrun/clawrouter\\` to generate a wallet.`,\n isError: true,\n };\n }\n\n if (subcommand === \"export\") {\n // Export private key for backup\n return {\n text: [\n \"🔐 **ClawRouter Wallet Export**\",\n \"\",\n \"⚠️ **SECURITY WARNING**: Your private key controls your wallet funds.\",\n \"Never share this key. Anyone with this key can spend your USDC.\",\n \"\",\n `**Address:** \\`${address}\\``,\n \"\",\n `**Private Key:**`,\n `\\`${walletKey}\\``,\n \"\",\n \"**To restore on a new machine:**\",\n \"1. Set the environment variable before running OpenClaw:\",\n ` \\`export BLOCKRUN_WALLET_KEY=${walletKey}\\``,\n \"2. Or save to file:\",\n ` \\`mkdir -p ~/.openclaw/blockrun && echo \"${walletKey}\" > ~/.openclaw/blockrun/wallet.key && chmod 600 ~/.openclaw/blockrun/wallet.key\\``,\n ].join(\"\\n\"),\n };\n }\n\n // Default: show wallet status\n let balanceText = \"Balance: (checking...)\";\n try {\n const monitor = new BalanceMonitor(address);\n const balance = await monitor.checkBalance();\n balanceText = `Balance: ${balance.balanceUSD}`;\n } catch {\n balanceText = \"Balance: (could not check)\";\n }\n\n return {\n text: [\n \"🦞 **ClawRouter Wallet**\",\n \"\",\n `**Address:** \\`${address}\\``,\n `**${balanceText}**`,\n `**Key File:** \\`${WALLET_FILE}\\``,\n \"\",\n \"**Commands:**\",\n \"• `/wallet` - Show this status\",\n \"• `/wallet export` - Export private key for backup\",\n \"\",\n `**Fund with USDC on Base:** https://basescan.org/address/${address}`,\n ].join(\"\\n\"),\n };\n },\n };\n}\n\nconst plugin: OpenClawPluginDefinition = {\n id: \"clawrouter\",\n name: \"ClawRouter\",\n description: \"Smart LLM router — 30+ models, x402 micropayments, 78% cost savings\",\n version: VERSION,\n\n register(api: OpenClawPluginApi) {\n // Check if ClawRouter is disabled via environment variable\n // Usage: CLAWROUTER_DISABLED=true openclaw gateway start\n const isDisabled =\n process.env.CLAWROUTER_DISABLED === \"true\" || process.env.CLAWROUTER_DISABLED === \"1\";\n if (isDisabled) {\n api.logger.info(\"ClawRouter disabled (CLAWROUTER_DISABLED=true). Using default routing.\");\n return;\n }\n\n // Skip heavy initialization in completion mode — only completion script is needed\n // Logging to stdout during completion pollutes the script and causes zsh errors\n if (isCompletionMode()) {\n api.registerProvider(blockrunProvider);\n return;\n }\n\n // Register BlockRun as a provider (sync — available immediately)\n api.registerProvider(blockrunProvider);\n\n // Inject models config into OpenClaw config file\n // This persists the config so models are recognized on restart\n injectModelsConfig(api.logger);\n\n // Inject dummy auth profiles into agent auth stores\n // OpenClaw's agent system looks for auth even if provider has auth: []\n injectAuthProfile(api.logger);\n\n // Also set runtime config for immediate availability\n const runtimePort = getProxyPort();\n if (!api.config.models) {\n api.config.models = { providers: {} };\n }\n if (!api.config.models.providers) {\n api.config.models.providers = {};\n }\n api.config.models.providers.blockrun = {\n baseUrl: `http://127.0.0.1:${runtimePort}/v1`,\n api: \"openai-completions\",\n // apiKey is required by pi-coding-agent's ModelRegistry for providers with models.\n apiKey: \"x402-proxy-handles-auth\",\n models: OPENCLAW_MODELS,\n };\n\n // Set blockrun/auto as default for smart routing (agents.defaults.model.primary)\n if (!api.config.agents) api.config.agents = {};\n const agents = api.config.agents as Record<string, unknown>;\n if (!agents.defaults) agents.defaults = {};\n const defaults = agents.defaults as Record<string, unknown>;\n if (!defaults.model) defaults.model = {};\n (defaults.model as Record<string, unknown>).primary = \"blockrun/auto\";\n\n api.logger.info(\"BlockRun provider registered (30+ models via x402)\");\n\n // Register /wallet command for wallet management\n createWalletCommand()\n .then((walletCommand) => {\n api.registerCommand(walletCommand);\n })\n .catch((err) => {\n api.logger.warn(\n `Failed to register /wallet command: ${err instanceof Error ? err.message : String(err)}`,\n );\n });\n\n // Register a service with stop() for cleanup on gateway shutdown\n // This prevents EADDRINUSE when the gateway restarts\n api.registerService({\n id: \"clawrouter-proxy\",\n start: () => {\n // No-op: proxy is started in register() below for immediate availability\n },\n stop: async () => {\n // Close proxy on gateway shutdown to release port 8402\n if (activeProxyHandle) {\n try {\n await activeProxyHandle.close();\n api.logger.info(\"BlockRun proxy closed\");\n } catch (err) {\n api.logger.warn(\n `Failed to close proxy: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n activeProxyHandle = null;\n }\n },\n });\n\n // Start x402 proxy in background (fire-and-forget)\n // Must happen in register() for CLI command support (services only start with gateway)\n startProxyInBackground(api).catch((err) => {\n api.logger.error(\n `Failed to start BlockRun proxy: ${err instanceof Error ? err.message : String(err)}`,\n );\n });\n },\n};\n\nexport default plugin;\n\n// Re-export for programmatic use\nexport { startProxy, getProxyPort } from \"./proxy.js\";\nexport type { ProxyOptions, ProxyHandle, LowBalanceInfo, InsufficientFundsInfo } from \"./proxy.js\";\nexport { blockrunProvider } from \"./provider.js\";\nexport { OPENCLAW_MODELS, BLOCKRUN_MODELS, buildProviderModels } from \"./models.js\";\nexport { route, DEFAULT_ROUTING_CONFIG } from \"./router/index.js\";\nexport type { RoutingDecision, RoutingConfig, Tier } from \"./router/index.js\";\nexport { logUsage } from \"./logger.js\";\nexport type { UsageEntry } from \"./logger.js\";\nexport { RequestDeduplicator } from \"./dedup.js\";\nexport type { CachedResponse } from \"./dedup.js\";\nexport { PaymentCache } from \"./payment-cache.js\";\nexport type { CachedPaymentParams } from \"./payment-cache.js\";\nexport { createPaymentFetch } from \"./x402.js\";\nexport type { PreAuthParams, PaymentFetchResult } from \"./x402.js\";\nexport { BalanceMonitor, BALANCE_THRESHOLDS } from \"./balance.js\";\nexport type { BalanceInfo, SufficiencyResult } from \"./balance.js\";\nexport {\n InsufficientFundsError,\n EmptyWalletError,\n RpcError,\n isInsufficientFundsError,\n isEmptyWalletError,\n isBalanceError,\n isRpcError,\n} from \"./errors.js\";\nexport { fetchWithRetry, isRetryable, DEFAULT_RETRY_CONFIG } from \"./retry.js\";\nexport type { RetryConfig } from \"./retry.js\";\n","/**\n * Retry Logic for ClawRouter\n *\n * Provides fetch wrapper with exponential backoff for transient errors.\n * Retries on 429 (rate limit), 502, 503, 504 (server errors).\n */\n\n/** Configuration for retry behavior */\nexport type RetryConfig = {\n /** Maximum number of retries (default: 2) */\n maxRetries: number;\n /** Base delay in ms for exponential backoff (default: 500) */\n baseDelayMs: number;\n /** HTTP status codes that trigger a retry (default: [429, 502, 503, 504]) */\n retryableCodes: number[];\n};\n\n/** Default retry configuration */\nexport const DEFAULT_RETRY_CONFIG: RetryConfig = {\n maxRetries: 2,\n baseDelayMs: 500,\n retryableCodes: [429, 502, 503, 504],\n};\n\n/** Sleep for a given number of milliseconds */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Wrap a fetch-like function with retry logic and exponential backoff.\n *\n * @param fetchFn - The fetch function to wrap (can be standard fetch or x402 payFetch)\n * @param url - URL to fetch\n * @param init - Fetch init options\n * @param config - Retry configuration (optional, uses defaults)\n * @returns Response from successful fetch or last failed attempt\n *\n * @example\n * ```typescript\n * const response = await fetchWithRetry(\n * fetch,\n * \"https://api.example.com/endpoint\",\n * { method: \"POST\", body: JSON.stringify(data) },\n * { maxRetries: 3 }\n * );\n * ```\n */\nexport async function fetchWithRetry(\n fetchFn: (url: string, init?: RequestInit) => Promise<Response>,\n url: string,\n init?: RequestInit,\n config?: Partial<RetryConfig>,\n): Promise<Response> {\n const cfg: RetryConfig = {\n ...DEFAULT_RETRY_CONFIG,\n ...config,\n };\n\n let lastError: Error | undefined;\n let lastResponse: Response | undefined;\n\n for (let attempt = 0; attempt <= cfg.maxRetries; attempt++) {\n try {\n const response = await fetchFn(url, init);\n\n // Success or non-retryable status — return immediately\n if (!cfg.retryableCodes.includes(response.status)) {\n return response;\n }\n\n // Retryable status — save response and maybe retry\n lastResponse = response;\n\n // Check for Retry-After header (common with 429)\n const retryAfter = response.headers.get(\"retry-after\");\n let delay: number;\n\n if (retryAfter) {\n // Retry-After can be seconds or HTTP-date\n const seconds = parseInt(retryAfter, 10);\n delay = isNaN(seconds) ? cfg.baseDelayMs * Math.pow(2, attempt) : seconds * 1000;\n } else {\n delay = cfg.baseDelayMs * Math.pow(2, attempt);\n }\n\n // Only retry if we have attempts left\n if (attempt < cfg.maxRetries) {\n await sleep(delay);\n }\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n\n // Network errors are retryable\n if (attempt < cfg.maxRetries) {\n const delay = cfg.baseDelayMs * Math.pow(2, attempt);\n await sleep(delay);\n }\n }\n }\n\n // All retries exhausted — return last response or throw last error\n if (lastResponse) {\n return lastResponse;\n }\n\n throw lastError ?? new Error(\"Max retries exceeded\");\n}\n\n/**\n * Check if an error or response indicates a retryable condition.\n */\nexport function isRetryable(\n errorOrResponse: Error | Response,\n config?: Partial<RetryConfig>,\n): boolean {\n const retryableCodes = config?.retryableCodes ?? DEFAULT_RETRY_CONFIG.retryableCodes;\n\n if (errorOrResponse instanceof Response) {\n return retryableCodes.includes(errorOrResponse.status);\n }\n\n // Network errors are generally retryable\n const message = errorOrResponse.message.toLowerCase();\n return (\n message.includes(\"network\") ||\n message.includes(\"timeout\") ||\n message.includes(\"econnreset\") ||\n message.includes(\"econnrefused\") ||\n message.includes(\"socket hang up\")\n );\n}\n"],"mappings":"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","names":["privateKeyToAccount","response","paymentHeader","confidence","DEFAULT_TTL_MS","USDC_BASE","join","require","account","privateKeyToAccount","balanceMonitor","mkdir","join","homedir","privateKeyToAccount","privateKeyToAccount","mkdir","homedir","join","privateKeyToAccount","join","homedir","privateKeyToAccount"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blockrun/clawrouter",
3
- "version": "0.4.5",
3
+ "version": "0.4.6",
4
4
  "description": "Smart LLM router — save 78% on inference costs. 30+ models, one wallet, x402 micropayments.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",