@blockrun/clawrouter 0.3.0 → 0.3.2

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/dist/index.d.ts CHANGED
@@ -181,6 +181,7 @@ type ClassifierConfig = {
181
181
  type OverridesConfig = {
182
182
  maxTokensForceComplex: number;
183
183
  structuredOutputMinTier: Tier;
184
+ ambiguousDefaultTier: Tier;
184
185
  };
185
186
  type RoutingConfig = {
186
187
  version: string;
@@ -217,25 +218,24 @@ declare const DEFAULT_ROUTING_CONFIG: RoutingConfig;
217
218
  * Smart Router Entry Point
218
219
  *
219
220
  * Classifies requests and routes to the cheapest capable model.
220
- * Uses hybrid approach: rules first (< 1ms), LLM fallback for ambiguous cases.
221
+ * 100% local rules-based scoring handles all requests in <1ms.
222
+ * Ambiguous cases default to configurable tier (MEDIUM by default).
221
223
  */
222
224
 
223
225
  type RouterOptions = {
224
226
  config: RoutingConfig;
225
227
  modelPricing: Map<string, ModelPricing>;
226
- payFetch: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
227
- apiBase: string;
228
228
  };
229
229
  /**
230
230
  * Route a request to the cheapest capable model.
231
231
  *
232
232
  * 1. Check overrides (large context, structured output)
233
- * 2. Run rule-based classifier
234
- * 3. If ambiguous, run LLM classifier
233
+ * 2. Run rule-based classifier (14 weighted dimensions, <1ms)
234
+ * 3. If ambiguous, default to configurable tier (no external API calls)
235
235
  * 4. Select model for tier
236
236
  * 5. Return RoutingDecision with metadata
237
237
  */
238
- declare function route(prompt: string, systemPrompt: string | undefined, maxOutputTokens: number, options: RouterOptions): Promise<RoutingDecision>;
238
+ declare function route(prompt: string, systemPrompt: string | undefined, maxOutputTokens: number, options: RouterOptions): RoutingDecision;
239
239
 
240
240
  /**
241
241
  * Local x402 Proxy Server
package/dist/index.js CHANGED
@@ -324,7 +324,16 @@ function createPaymentFetch(privateKey) {
324
324
  if (paymentHeader2) {
325
325
  return handle402(input, init, url, endpointPath, paymentHeader2);
326
326
  }
327
- return response2;
327
+ paymentCache.invalidate(endpointPath);
328
+ const cleanResponse = await fetch(input, init);
329
+ if (cleanResponse.status !== 402) {
330
+ return cleanResponse;
331
+ }
332
+ const cleanHeader = cleanResponse.headers.get("x-payment-required");
333
+ if (!cleanHeader) {
334
+ throw new Error("402 response missing x-payment-required header");
335
+ }
336
+ return handle402(input, init, url, endpointPath, cleanHeader);
328
337
  }
329
338
  const response = await fetch(input, init);
330
339
  if (response.status !== 402) {
@@ -558,79 +567,6 @@ function calibrateConfidence(distance, steepness) {
558
567
  return 1 / (1 + Math.exp(-steepness * distance));
559
568
  }
560
569
 
561
- // src/router/llm-classifier.ts
562
- var CLASSIFIER_PROMPT = `You are a query complexity classifier. Classify the user's query into exactly one category.
563
-
564
- Categories:
565
- - SIMPLE: Factual Q&A, definitions, translations, short answers
566
- - MEDIUM: Summaries, explanations, moderate code generation
567
- - COMPLEX: Multi-step code, system design, creative writing, analysis
568
- - REASONING: Mathematical proofs, formal logic, step-by-step problem solving
569
-
570
- Respond with ONLY one word: SIMPLE, MEDIUM, COMPLEX, or REASONING.`;
571
- var cache = /* @__PURE__ */ new Map();
572
- async function classifyByLLM(prompt, config, payFetch, apiBase) {
573
- const truncated = prompt.slice(0, config.truncationChars);
574
- const cacheKey = simpleHash(truncated);
575
- const cached = cache.get(cacheKey);
576
- if (cached && cached.expires > Date.now()) {
577
- return { tier: cached.tier, confidence: 0.75 };
578
- }
579
- try {
580
- const response = await payFetch(`${apiBase}/v1/chat/completions`, {
581
- method: "POST",
582
- headers: { "Content-Type": "application/json" },
583
- body: JSON.stringify({
584
- model: config.model,
585
- messages: [
586
- { role: "system", content: CLASSIFIER_PROMPT },
587
- { role: "user", content: truncated }
588
- ],
589
- max_tokens: config.maxTokens,
590
- temperature: config.temperature,
591
- stream: false
592
- })
593
- });
594
- if (!response.ok) {
595
- return { tier: "MEDIUM", confidence: 0.5 };
596
- }
597
- const data = await response.json();
598
- const content = data.choices?.[0]?.message?.content?.trim().toUpperCase() ?? "";
599
- const tier = parseTier(content);
600
- cache.set(cacheKey, { tier, expires: Date.now() + config.cacheTtlMs });
601
- if (cache.size > 1e3) {
602
- pruneCache();
603
- }
604
- return { tier, confidence: 0.75 };
605
- } catch {
606
- return { tier: "MEDIUM", confidence: 0.5 };
607
- }
608
- }
609
- function parseTier(text) {
610
- if (/\bREASONING\b/.test(text)) return "REASONING";
611
- if (/\bCOMPLEX\b/.test(text)) return "COMPLEX";
612
- if (/\bMEDIUM\b/.test(text)) return "MEDIUM";
613
- if (/\bSIMPLE\b/.test(text)) return "SIMPLE";
614
- return "MEDIUM";
615
- }
616
- function simpleHash(str) {
617
- let hash = 0;
618
- for (let i = 0; i < str.length; i++) {
619
- const char = str.charCodeAt(i);
620
- hash = (hash << 5) - hash + char;
621
- hash |= 0;
622
- }
623
- return hash.toString(36);
624
- }
625
- function pruneCache() {
626
- const now = Date.now();
627
- for (const [key, value] of cache) {
628
- if (value.expires <= now) {
629
- cache.delete(key);
630
- }
631
- }
632
- }
633
-
634
570
  // src/router/selector.ts
635
571
  function selectModel(tier, confidence, method, reasoning, tierConfigs, modelPricing, estimatedInputTokens, maxOutputTokens) {
636
572
  const tierConfig = tierConfigs[tier];
@@ -843,13 +779,14 @@ var DEFAULT_ROUTING_CONFIG = {
843
779
  },
844
780
  overrides: {
845
781
  maxTokensForceComplex: 1e5,
846
- structuredOutputMinTier: "MEDIUM"
782
+ structuredOutputMinTier: "MEDIUM",
783
+ ambiguousDefaultTier: "MEDIUM"
847
784
  }
848
785
  };
849
786
 
850
787
  // src/router/index.ts
851
- async function route(prompt, systemPrompt, maxOutputTokens, options) {
852
- const { config, modelPricing, payFetch, apiBase } = options;
788
+ function route(prompt, systemPrompt, maxOutputTokens, options) {
789
+ const { config, modelPricing } = options;
853
790
  const fullText = `${systemPrompt ?? ""} ${prompt}`;
854
791
  const estimatedTokens = Math.ceil(fullText.length / 4);
855
792
  if (estimatedTokens > config.overrides.maxTokensForceComplex) {
@@ -879,22 +816,9 @@ async function route(prompt, systemPrompt, maxOutputTokens, options) {
879
816
  tier = ruleResult.tier;
880
817
  confidence = ruleResult.confidence;
881
818
  } else {
882
- const llmResult = await classifyByLLM(
883
- prompt,
884
- {
885
- model: config.classifier.llmModel,
886
- maxTokens: config.classifier.llmMaxTokens,
887
- temperature: config.classifier.llmTemperature,
888
- truncationChars: config.classifier.promptTruncationChars,
889
- cacheTtlMs: config.classifier.cacheTtlMs
890
- },
891
- payFetch,
892
- apiBase
893
- );
894
- tier = llmResult.tier;
895
- confidence = llmResult.confidence;
896
- method = "llm";
897
- reasoning += ` | ambiguous -> LLM: ${tier}`;
819
+ tier = config.overrides.ambiguousDefaultTier;
820
+ confidence = 0.5;
821
+ reasoning += ` | ambiguous -> default: ${tier}`;
898
822
  }
899
823
  if (hasStructuredOutput) {
900
824
  const tierRank = { SIMPLE: 0, MEDIUM: 1, COMPLEX: 2, REASONING: 3 };
@@ -1016,7 +940,7 @@ var RequestDeduplicator = class {
1016
940
  // src/proxy.ts
1017
941
  var BLOCKRUN_API = "https://blockrun.ai/api";
1018
942
  var AUTO_MODEL = "blockrun/auto";
1019
- var USER_AGENT = "clawrouter/0.3.0";
943
+ var USER_AGENT = "clawrouter/0.3.2";
1020
944
  var HEARTBEAT_INTERVAL_MS = 2e3;
1021
945
  function buildModelPricing() {
1022
946
  const map = /* @__PURE__ */ new Map();
@@ -1043,7 +967,7 @@ function estimateAmount(modelId, bodyLength, maxTokens) {
1043
967
  const estimatedInputTokens = Math.ceil(bodyLength / 4);
1044
968
  const estimatedOutputTokens = maxTokens || model.maxOutput || 4096;
1045
969
  const costUsd = estimatedInputTokens / 1e6 * model.inputPrice + estimatedOutputTokens / 1e6 * model.outputPrice;
1046
- const amountMicros = Math.ceil(costUsd * 1.2 * 1e6);
970
+ const amountMicros = Math.max(100, Math.ceil(costUsd * 1.2 * 1e6));
1047
971
  return amountMicros.toString();
1048
972
  }
1049
973
  async function startProxy(options) {
@@ -1054,10 +978,7 @@ async function startProxy(options) {
1054
978
  const modelPricing = buildModelPricing();
1055
979
  const routerOpts = {
1056
980
  config: routingConfig,
1057
- modelPricing,
1058
- payFetch: (input, init) => payFetch(input, init),
1059
- // router doesn't need preAuth
1060
- apiBase
981
+ modelPricing
1061
982
  };
1062
983
  const deduplicator = new RequestDeduplicator();
1063
984
  const server = createServer(async (req, res) => {
@@ -1141,7 +1062,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
1141
1062
  const systemMsg = messages?.find((m) => m.role === "system");
1142
1063
  const prompt = typeof lastUserMsg?.content === "string" ? lastUserMsg.content : "";
1143
1064
  const systemPrompt = typeof systemMsg?.content === "string" ? systemMsg.content : void 0;
1144
- routingDecision = await route(prompt, systemPrompt, maxTokens, routerOpts);
1065
+ routingDecision = route(prompt, systemPrompt, maxTokens, routerOpts);
1145
1066
  parsed.model = routingDecision.model;
1146
1067
  modelId = routingDecision.model;
1147
1068
  body = Buffer.from(JSON.stringify(parsed));
@@ -1330,7 +1251,7 @@ var plugin = {
1330
1251
  id: "clawrouter",
1331
1252
  name: "ClawRouter",
1332
1253
  description: "Smart LLM router \u2014 30+ models, x402 micropayments, 78% cost savings",
1333
- version: "0.3.0",
1254
+ version: "0.3.2",
1334
1255
  register(api) {
1335
1256
  api.registerProvider(blockrunProvider);
1336
1257
  api.logger.info("BlockRun provider registered (30+ models via x402)");
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/auth.ts","../src/models.ts","../src/provider.ts","../src/proxy.ts","../src/x402.ts","../src/payment-cache.ts","../src/router/rules.ts","../src/router/llm-classifier.ts","../src/router/selector.ts","../src/router/config.ts","../src/router/index.ts","../src/logger.ts","../src/dedup.ts","../src/index.ts"],"sourcesContent":["/**\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\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<{ key: string; address: string; source: \"saved\" | \"env\" | \"generated\" }> {\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 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 { id: \"blockrun/auto\", name: \"BlockRun Smart Router\", inputPrice: 0, outputPrice: 0, contextWindow: 1_050_000, maxOutput: 128_000 },\n\n\n // OpenAI GPT-5 Family\n { id: \"openai/gpt-5.2\", name: \"GPT-5.2\", inputPrice: 1.75, outputPrice: 14.0, contextWindow: 400000, maxOutput: 128000, reasoning: true, vision: true },\n { id: \"openai/gpt-5-mini\", name: \"GPT-5 Mini\", inputPrice: 0.25, outputPrice: 2.0, contextWindow: 200000, maxOutput: 65536 },\n { id: \"openai/gpt-5-nano\", name: \"GPT-5 Nano\", inputPrice: 0.05, outputPrice: 0.4, contextWindow: 128000, maxOutput: 32768 },\n { id: \"openai/gpt-5.2-pro\", name: \"GPT-5.2 Pro\", inputPrice: 21.0, outputPrice: 168.0, contextWindow: 400000, maxOutput: 128000, reasoning: true },\n\n // OpenAI GPT-4 Family\n { id: \"openai/gpt-4.1\", name: \"GPT-4.1\", inputPrice: 2.0, outputPrice: 8.0, contextWindow: 128000, maxOutput: 16384, vision: true },\n { id: \"openai/gpt-4.1-mini\", name: \"GPT-4.1 Mini\", inputPrice: 0.4, outputPrice: 1.6, contextWindow: 128000, maxOutput: 16384 },\n { id: \"openai/gpt-4.1-nano\", name: \"GPT-4.1 Nano\", inputPrice: 0.1, outputPrice: 0.4, contextWindow: 128000, maxOutput: 16384 },\n { id: \"openai/gpt-4o\", name: \"GPT-4o\", inputPrice: 2.5, outputPrice: 10.0, contextWindow: 128000, maxOutput: 16384, vision: true },\n { id: \"openai/gpt-4o-mini\", name: \"GPT-4o Mini\", inputPrice: 0.15, outputPrice: 0.6, contextWindow: 128000, maxOutput: 16384 },\n\n // OpenAI O-series (Reasoning)\n { id: \"openai/o1\", name: \"o1\", inputPrice: 15.0, outputPrice: 60.0, contextWindow: 200000, maxOutput: 100000, reasoning: true },\n { id: \"openai/o1-mini\", name: \"o1-mini\", inputPrice: 1.1, outputPrice: 4.4, contextWindow: 128000, maxOutput: 65536, reasoning: true },\n { id: \"openai/o3\", name: \"o3\", inputPrice: 2.0, outputPrice: 8.0, contextWindow: 200000, maxOutput: 100000, reasoning: true },\n { id: \"openai/o3-mini\", name: \"o3-mini\", inputPrice: 1.1, outputPrice: 4.4, contextWindow: 128000, maxOutput: 65536, reasoning: true },\n { id: \"openai/o4-mini\", name: \"o4-mini\", inputPrice: 1.1, outputPrice: 4.4, contextWindow: 128000, maxOutput: 65536, reasoning: true },\n\n // Anthropic\n { id: \"anthropic/claude-haiku-4.5\", name: \"Claude Haiku 4.5\", inputPrice: 1.0, outputPrice: 5.0, contextWindow: 200000, maxOutput: 8192 },\n { id: \"anthropic/claude-sonnet-4\", name: \"Claude Sonnet 4\", inputPrice: 3.0, outputPrice: 15.0, contextWindow: 200000, maxOutput: 64000, reasoning: true },\n { id: \"anthropic/claude-opus-4\", name: \"Claude Opus 4\", inputPrice: 15.0, outputPrice: 75.0, contextWindow: 200000, maxOutput: 32000, reasoning: true },\n { id: \"anthropic/claude-opus-4.5\", name: \"Claude Opus 4.5\", inputPrice: 15.0, outputPrice: 75.0, contextWindow: 200000, maxOutput: 32000, reasoning: true },\n\n // Google\n { id: \"google/gemini-3-pro-preview\", name: \"Gemini 3 Pro Preview\", inputPrice: 2.0, outputPrice: 12.0, contextWindow: 1050000, maxOutput: 65536, reasoning: true, vision: true },\n { id: \"google/gemini-2.5-pro\", name: \"Gemini 2.5 Pro\", inputPrice: 1.25, outputPrice: 10.0, contextWindow: 1050000, maxOutput: 65536, reasoning: true, vision: true },\n { id: \"google/gemini-2.5-flash\", name: \"Gemini 2.5 Flash\", inputPrice: 0.15, outputPrice: 0.6, contextWindow: 1000000, maxOutput: 65536 },\n\n // DeepSeek\n { id: \"deepseek/deepseek-chat\", name: \"DeepSeek V3.2 Chat\", inputPrice: 0.28, outputPrice: 0.42, contextWindow: 128000, maxOutput: 8192 },\n { id: \"deepseek/deepseek-reasoner\", name: \"DeepSeek V3.2 Reasoner\", inputPrice: 0.28, outputPrice: 0.42, contextWindow: 128000, maxOutput: 8192, reasoning: true },\n\n // xAI / Grok\n { id: \"xai/grok-3\", name: \"Grok 3\", inputPrice: 3.0, outputPrice: 15.0, contextWindow: 131072, maxOutput: 16384, reasoning: true },\n { id: \"xai/grok-3-fast\", name: \"Grok 3 Fast\", inputPrice: 5.0, outputPrice: 25.0, contextWindow: 131072, maxOutput: 16384, reasoning: true },\n { id: \"xai/grok-3-mini\", name: \"Grok 3 Mini\", inputPrice: 0.3, outputPrice: 0.5, contextWindow: 131072, maxOutput: 16384 },\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, AuthProfileCredential } from \"./types.js\";\nimport { walletKeyAuth, envKeyAuth } from \"./auth.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 // Auth methods\n auth: [envKeyAuth, walletKeyAuth],\n\n // Format the stored credential as the wallet key\n formatApiKey: (cred: AuthProfileCredential): string => {\n if (\"apiKey\" in cred && typeof cred.apiKey === \"string\") {\n return cred.apiKey;\n }\n throw new Error(\"BlockRun credential must contain an apiKey (wallet private key)\");\n },\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 { route, getFallbackChain, DEFAULT_ROUTING_CONFIG, type RouterOptions, type RoutingDecision, type RoutingConfig, type ModelPricing } from \"./router/index.js\";\nimport { BLOCKRUN_MODELS } from \"./models.js\";\nimport { logUsage, type UsageEntry } from \"./logger.js\";\nimport { RequestDeduplicator, type CachedResponse } from \"./dedup.js\";\n\nconst BLOCKRUN_API = \"https://blockrun.ai/api\";\nconst AUTO_MODEL = \"blockrun/auto\";\nconst USER_AGENT = \"clawrouter/0.3.0\";\nconst HEARTBEAT_INTERVAL_MS = 2_000;\n\nexport type ProxyOptions = {\n walletKey: string;\n apiBase?: string;\n port?: number;\n routingConfig?: Partial<RoutingConfig>;\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};\n\nexport type ProxyHandle = {\n port: number;\n baseUrl: string;\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(modelId: string, bodyLength: number, maxTokens: number): 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 const amountMicros = Math.ceil(costUsd * 1.2 * 1_000_000);\n return amountMicros.toString();\n}\n\n/**\n * Start the local x402 proxy server.\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 // Create x402 payment-enabled fetch from wallet private key\n const account = privateKeyToAccount(options.walletKey as `0x${string}`);\n const { fetch: payFetch, cache: paymentCache } = createPaymentFetch(options.walletKey as `0x${string}`);\n\n // Build router options (pass the new payFetch signature — it accepts preAuth as 3rd arg)\n const routingConfig = mergeRoutingConfig(options.routingConfig);\n const modelPricing = buildModelPricing();\n const routerOpts: RouterOptions = {\n config: routingConfig,\n modelPricing,\n payFetch: (input, init) => payFetch(input, init), // router doesn't need preAuth\n apiBase,\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\n if (req.url === \"/health\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ status: \"ok\", wallet: account.address }));\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(req, res, apiBase, payFetch, options, routerOpts, deduplicator);\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(JSON.stringify({\n error: { message: `Proxy error: ${error.message}`, type: \"proxy_error\" },\n }));\n } else if (!res.writableEnded) {\n // Headers already sent (streaming) — send error as SSE event\n res.write(`data: ${JSON.stringify({ error: { message: error.message, type: \"proxy_error\" } })}\\n\\n`);\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n }\n }\n });\n\n // Listen on requested port (0 = random available port)\n const listenPort = options.port ?? 0;\n\n return new Promise<ProxyHandle>((resolve, reject) => {\n server.on(\"error\", reject);\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 close: () =>\n new Promise<void>((res, rej) => {\n server.close((err) => (err ? rej(err) : res()));\n }),\n });\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 */\nasync function proxyRequest(\n req: IncomingMessage,\n res: ServerResponse,\n apiBase: string,\n payFetch: (input: RequestInfo | URL, init?: RequestInit, preAuth?: PreAuthParams) => Promise<Response>,\n options: ProxyOptions,\n routerOpts: RouterOptions,\n deduplicator: RequestDeduplicator,\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 if (parsed.model === AUTO_MODEL) {\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\") { lastUserMsg = messages[i]; break; }\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 = await route(prompt, systemPrompt, maxTokens, routerOpts);\n\n // Replace model in body\n parsed.model = routingDecision.model;\n modelId = routingDecision.model;\n body = Buffer.from(JSON.stringify(parsed));\n\n options.onRouted?.(routingDecision);\n }\n } catch {\n // JSON parse error — forward body as-is\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 // --- 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 (key === \"host\" || key === \"connection\" || key === \"transfer-encoding\" || key === \"content-length\") 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 // --- Payment pre-auth: estimate amount to skip 402 round trip ---\n let preAuth: PreAuthParams | undefined;\n if (modelId) {\n const estimated = estimateAmount(modelId, body.length, maxTokens);\n if (estimated) {\n preAuth = { estimatedAmount: estimated };\n }\n }\n\n try {\n // Make the request through x402-wrapped fetch (with optional pre-auth)\n const upstream = await payFetch(upstreamUrl, {\n method: req.method ?? \"POST\",\n headers,\n body: body.length > 0 ? body : undefined,\n }, preAuth);\n\n // Clear heartbeat — real data is about to flow\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n heartbeatInterval = undefined;\n }\n\n // --- Stream response and collect for dedup cache ---\n const responseChunks: Buffer[] = [];\n\n if (headersSentEarly) {\n // Streaming: headers already sent. Check for upstream errors.\n if (upstream.status !== 200) {\n const errBody = await upstream.text();\n const errEvent = `data: ${JSON.stringify({ error: { message: errBody, type: \"upstream_error\", status: upstream.status } })}\\n\\n`;\n res.write(errEvent);\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n\n // Cache the error response for dedup\n const errBuf = Buffer.from(errEvent + \"data: [DONE]\\n\\n\");\n deduplicator.complete(dedupKey, {\n status: 200, // we already sent 200\n headers: { \"content-type\": \"text/event-stream\" },\n body: errBuf,\n completedAt: Date.now(),\n });\n return;\n }\n\n // Pipe upstream SSE data to client\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: 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 } catch (err) {\n // Clear heartbeat on error\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n }\n\n // Remove in-flight entry so retries aren't blocked\n deduplicator.removeInflight(dedupKey);\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, type CachedPaymentParams } 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).map(b => b.toString(16).padStart(2, '0')).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: (input: RequestInfo | URL, init?: RequestInit, preAuth?: PreAuthParams) => 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 // Fall through to normal 402 flow using THIS 402 response\n const paymentHeader = response.headers.get(\"x-payment-required\");\n if (paymentHeader) {\n return handle402(input, init, url, endpointPath, paymentHeader);\n }\n // No payment header in rejection — return as-is\n return response;\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 { name, score: scores.high, signal: `${signalLabel} (${matches.slice(0, 3).join(\", \")})` };\n }\n if (matches.length >= thresholds.low) {\n return { name, score: scores.low, signal: `${signalLabel} (${matches.slice(0, 3).join(\", \")})` };\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\n // Score all 14 dimensions\n const dimensions: DimensionScore[] = [\n // Original 8 dimensions\n scoreTokenCount(estimatedTokens, config.tokenCountThresholds),\n scoreKeywordMatch(text, config.codeKeywords, \"codePresence\", \"code\",\n { low: 1, high: 2 }, { none: 0, low: 0.5, high: 1.0 }),\n scoreKeywordMatch(text, config.reasoningKeywords, \"reasoningMarkers\", \"reasoning\",\n { low: 1, high: 2 }, { none: 0, low: 0.7, high: 1.0 }),\n scoreKeywordMatch(text, config.technicalKeywords, \"technicalTerms\", \"technical\",\n { low: 2, high: 4 }, { none: 0, low: 0.5, high: 1.0 }),\n scoreKeywordMatch(text, config.creativeKeywords, \"creativeMarkers\", \"creative\",\n { low: 1, high: 2 }, { none: 0, low: 0.5, high: 0.7 }),\n scoreKeywordMatch(text, config.simpleKeywords, \"simpleIndicators\", \"simple\",\n { low: 1, high: 2 }, { none: 0, low: -1.0, high: -1.0 }),\n scoreMultiStep(text),\n scoreQuestionComplexity(prompt),\n\n // 6 new dimensions\n scoreKeywordMatch(text, config.imperativeVerbs, \"imperativeVerbs\", \"imperative\",\n { low: 1, high: 2 }, { none: 0, low: 0.3, high: 0.5 }),\n scoreKeywordMatch(text, config.constraintIndicators, \"constraintCount\", \"constraints\",\n { low: 1, high: 3 }, { none: 0, low: 0.3, high: 0.7 }),\n scoreKeywordMatch(text, config.outputFormatKeywords, \"outputFormat\", \"format\",\n { low: 1, high: 2 }, { none: 0, low: 0.4, high: 0.7 }),\n scoreKeywordMatch(text, config.referenceKeywords, \"referenceComplexity\", \"references\",\n { low: 1, high: 2 }, { none: 0, low: 0.3, high: 0.5 }),\n scoreKeywordMatch(text, config.negationKeywords, \"negationComplexity\", \"negation\",\n { low: 2, high: 3 }, { none: 0, low: 0.3, high: 0.5 }),\n scoreKeywordMatch(text, config.domainSpecificKeywords, \"domainSpecificity\", \"domain-specific\",\n { low: 1, high: 2 }, { none: 0, low: 0.5, high: 0.8 }),\n ];\n\n // Collect signals\n const signals = dimensions\n .filter((d) => d.signal !== null)\n .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\n const reasoningMatches = config.reasoningKeywords.filter((kw) =>\n text.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(\n weightedScore - simpleMedium,\n mediumComplex - weightedScore,\n );\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 * LLM Classifier (Fallback)\n *\n * When the rule-based classifier returns ambiguous (score 1-2),\n * we send a classification request to the cheapest model.\n *\n * Cost per classification: ~$0.00003\n * Latency: ~200-400ms\n * Only triggered for ~20-30% of requests.\n */\n\nimport type { Tier } from \"./types.js\";\n\nconst CLASSIFIER_PROMPT = `You are a query complexity classifier. Classify the user's query into exactly one category.\n\nCategories:\n- SIMPLE: Factual Q&A, definitions, translations, short answers\n- MEDIUM: Summaries, explanations, moderate code generation\n- COMPLEX: Multi-step code, system design, creative writing, analysis\n- REASONING: Mathematical proofs, formal logic, step-by-step problem solving\n\nRespond with ONLY one word: SIMPLE, MEDIUM, COMPLEX, or REASONING.`;\n\n// In-memory cache: hash → { tier, expires }\nconst cache = new Map<string, { tier: Tier; expires: number }>();\n\nexport type LLMClassifierConfig = {\n model: string;\n maxTokens: number;\n temperature: number;\n truncationChars: number;\n cacheTtlMs: number;\n};\n\ntype PayFetch = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;\n\n/**\n * Classify a prompt using a cheap LLM.\n * Returns tier and confidence. Defaults to MEDIUM on any failure.\n */\nexport async function classifyByLLM(\n prompt: string,\n config: LLMClassifierConfig,\n payFetch: PayFetch,\n apiBase: string,\n): Promise<{ tier: Tier; confidence: number }> {\n const truncated = prompt.slice(0, config.truncationChars);\n\n // Check cache\n const cacheKey = simpleHash(truncated);\n const cached = cache.get(cacheKey);\n if (cached && cached.expires > Date.now()) {\n return { tier: cached.tier, confidence: 0.75 };\n }\n\n try {\n const response = await payFetch(`${apiBase}/v1/chat/completions`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model: config.model,\n messages: [\n { role: \"system\", content: CLASSIFIER_PROMPT },\n { role: \"user\", content: truncated },\n ],\n max_tokens: config.maxTokens,\n temperature: config.temperature,\n stream: false,\n }),\n });\n\n if (!response.ok) {\n return { tier: \"MEDIUM\", confidence: 0.5 };\n }\n\n const data = (await response.json()) as {\n choices?: Array<{ message?: { content?: string } }>;\n };\n\n const content = data.choices?.[0]?.message?.content?.trim().toUpperCase() ?? \"\";\n const tier = parseTier(content);\n\n // Cache result\n cache.set(cacheKey, { tier, expires: Date.now() + config.cacheTtlMs });\n\n // Prune if cache grows too large\n if (cache.size > 1000) {\n pruneCache();\n }\n\n return { tier, confidence: 0.75 };\n } catch {\n // Any error → safe default\n return { tier: \"MEDIUM\", confidence: 0.5 };\n }\n}\n\n/**\n * Parse tier from LLM response. Handles \"SIMPLE\", \"The query is SIMPLE\", etc.\n */\nfunction parseTier(text: string): Tier {\n if (/\\bREASONING\\b/.test(text)) return \"REASONING\";\n if (/\\bCOMPLEX\\b/.test(text)) return \"COMPLEX\";\n if (/\\bMEDIUM\\b/.test(text)) return \"MEDIUM\";\n if (/\\bSIMPLE\\b/.test(text)) return \"SIMPLE\";\n return \"MEDIUM\"; // safe default\n}\n\nfunction simpleHash(str: string): string {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = ((hash << 5) - hash) + char;\n hash |= 0;\n }\n return hash.toString(36);\n}\n\nfunction pruneCache(): void {\n const now = Date.now();\n for (const [key, value] of cache) {\n if (value.expires <= now) {\n cache.delete(key);\n }\n }\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\n ? (estimatedInputTokens / 1_000_000) * pricing.inputPrice\n : 0;\n const outputCost = pricing\n ? (maxOutputTokens / 1_000_000) * pricing.outputPrice\n : 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\n ? (maxOutputTokens / 1_000_000) * opusPricing.outputPrice\n : 0;\n const baselineCost = baselineInput + baselineOutput;\n\n const savings =\n baselineCost > 0\n ? Math.max(0, (baselineCost - costEstimate) / baselineCost)\n : 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(\n tier: Tier,\n tierConfigs: Record<Tier, TierConfig>,\n): 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 codeKeywords: [\n \"function\", \"class\", \"import\", \"def\", \"SELECT\", \"async\", \"await\",\n \"const\", \"let\", \"var\", \"return\", \"```\",\n ],\n reasoningKeywords: [\n \"prove\", \"theorem\", \"derive\", \"step by step\", \"chain of thought\",\n \"formally\", \"mathematical\", \"proof\", \"logically\",\n ],\n simpleKeywords: [\n \"what is\", \"define\", \"translate\", \"hello\", \"yes or no\",\n \"capital of\", \"how old\", \"who is\", \"when was\",\n ],\n technicalKeywords: [\n \"algorithm\", \"optimize\", \"architecture\", \"distributed\",\n \"kubernetes\", \"microservice\", \"database\", \"infrastructure\",\n ],\n creativeKeywords: [\n \"story\", \"poem\", \"compose\", \"brainstorm\", \"creative\",\n \"imagine\", \"write a\",\n ],\n\n // New dimension keyword lists\n imperativeVerbs: [\n \"build\", \"create\", \"implement\", \"design\", \"develop\", \"construct\",\n \"generate\", \"deploy\", \"configure\", \"set up\",\n ],\n constraintIndicators: [\n \"under\", \"at most\", \"at least\", \"within\", \"no more than\",\n \"o(\", \"maximum\", \"minimum\", \"limit\", \"budget\",\n ],\n outputFormatKeywords: [\n \"json\", \"yaml\", \"xml\", \"table\", \"csv\", \"markdown\",\n \"schema\", \"format as\", \"structured\",\n ],\n referenceKeywords: [\n \"above\", \"below\", \"previous\", \"following\", \"the docs\",\n \"the api\", \"the code\", \"earlier\", \"attached\",\n ],\n negationKeywords: [\n \"don't\", \"do not\", \"avoid\", \"never\", \"without\",\n \"except\", \"exclude\", \"no longer\",\n ],\n domainSpecificKeywords: [\n \"quantum\", \"fpga\", \"vlsi\", \"risc-v\", \"asic\", \"photonics\",\n \"genomics\", \"proteomics\", \"topological\", \"homomorphic\",\n \"zero-knowledge\", \"lattice-based\",\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.10,\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.70,\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: \"openai/o3\",\n fallback: [\"google/gemini-2.5-pro\", \"anthropic/claude-sonnet-4\"],\n },\n },\n\n overrides: {\n maxTokensForceComplex: 100_000,\n structuredOutputMinTier: \"MEDIUM\",\n },\n};\n","/**\n * Smart Router Entry Point\n *\n * Classifies requests and routes to the cheapest capable model.\n * Uses hybrid approach: rules first (< 1ms), LLM fallback for ambiguous cases.\n */\n\nimport type { Tier, RoutingDecision, RoutingConfig } from \"./types.js\";\nimport { classifyByRules } from \"./rules.js\";\nimport { classifyByLLM } from \"./llm-classifier.js\";\nimport { selectModel, getFallbackChain, type ModelPricing } from \"./selector.js\";\n\nexport type RouterOptions = {\n config: RoutingConfig;\n modelPricing: Map<string, ModelPricing>;\n payFetch: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;\n apiBase: string;\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\n * 3. If ambiguous, run LLM classifier\n * 4. Select model for tier\n * 5. Return RoutingDecision with metadata\n */\nexport async function route(\n prompt: string,\n systemPrompt: string | undefined,\n maxOutputTokens: number,\n options: RouterOptions,\n): Promise<RoutingDecision> {\n const { config, modelPricing, payFetch, apiBase } = 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\n ? /json|structured|schema/i.test(systemPrompt)\n : false;\n\n // --- Rule-based classification ---\n const ruleResult = classifyByRules(\n prompt,\n systemPrompt,\n estimatedTokens,\n config.scoring,\n );\n\n let tier: Tier;\n let confidence: number;\n let 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 — LLM classifier fallback\n const llmResult = await classifyByLLM(\n prompt,\n {\n model: config.classifier.llmModel,\n maxTokens: config.classifier.llmMaxTokens,\n temperature: config.classifier.llmTemperature,\n truncationChars: config.classifier.promptTruncationChars,\n cacheTtlMs: config.classifier.cacheTtlMs,\n },\n payFetch,\n apiBase,\n );\n\n tier = llmResult.tier;\n confidence = llmResult.confidence;\n method = \"llm\";\n reasoning += ` | ambiguous -> LLM: ${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\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 return createHash(\"sha256\").update(body).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(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 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 * @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 plugin 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 config set model blockrun/auto\n *\n * # Or use any specific BlockRun model\n * openclaw config set model openai/gpt-5.2\n */\n\nimport type { OpenClawPluginDefinition, OpenClawPluginApi } from \"./types.js\";\nimport { blockrunProvider, setActiveProxy } from \"./provider.js\";\nimport { startProxy } from \"./proxy.js\";\nimport { resolveOrGenerateWalletKey } from \"./auth.js\";\nimport type { RoutingConfig } from \"./router/index.js\";\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 // 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(`${decision.model} $${cost} (saved ${saved}%)`);\n },\n });\n\n setActiveProxy(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: \"0.3.0\",\n\n register(api: OpenClawPluginApi) {\n // Register BlockRun as a provider (sync — available immediately)\n api.registerProvider(blockrunProvider);\n api.logger.info(\"BlockRun provider registered (30+ models via x402)\");\n\n // Start x402 proxy in background (fire-and-forget)\n // OpenClaw only calls register(), not activate() — so all init goes here.\n // The loader ignores async returns, but the proxy starts in the background\n // and setActiveProxy() makes it available to the provider once ready.\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\n\nexport default plugin;\n\n// Re-export for programmatic use\nexport { startProxy } 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\";\n"],"mappings":"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","names":["privateKeyToAccount","privateKeyToAccount","privateKeyToAccount","response","paymentHeader","confidence","mkdir","join","homedir","DEFAULT_TTL_MS","privateKeyToAccount"]}
1
+ {"version":3,"sources":["../src/auth.ts","../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/index.ts"],"sourcesContent":["/**\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\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<{ key: string; address: string; source: \"saved\" | \"env\" | \"generated\" }> {\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 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 { id: \"blockrun/auto\", name: \"BlockRun Smart Router\", inputPrice: 0, outputPrice: 0, contextWindow: 1_050_000, maxOutput: 128_000 },\n\n\n // OpenAI GPT-5 Family\n { id: \"openai/gpt-5.2\", name: \"GPT-5.2\", inputPrice: 1.75, outputPrice: 14.0, contextWindow: 400000, maxOutput: 128000, reasoning: true, vision: true },\n { id: \"openai/gpt-5-mini\", name: \"GPT-5 Mini\", inputPrice: 0.25, outputPrice: 2.0, contextWindow: 200000, maxOutput: 65536 },\n { id: \"openai/gpt-5-nano\", name: \"GPT-5 Nano\", inputPrice: 0.05, outputPrice: 0.4, contextWindow: 128000, maxOutput: 32768 },\n { id: \"openai/gpt-5.2-pro\", name: \"GPT-5.2 Pro\", inputPrice: 21.0, outputPrice: 168.0, contextWindow: 400000, maxOutput: 128000, reasoning: true },\n\n // OpenAI GPT-4 Family\n { id: \"openai/gpt-4.1\", name: \"GPT-4.1\", inputPrice: 2.0, outputPrice: 8.0, contextWindow: 128000, maxOutput: 16384, vision: true },\n { id: \"openai/gpt-4.1-mini\", name: \"GPT-4.1 Mini\", inputPrice: 0.4, outputPrice: 1.6, contextWindow: 128000, maxOutput: 16384 },\n { id: \"openai/gpt-4.1-nano\", name: \"GPT-4.1 Nano\", inputPrice: 0.1, outputPrice: 0.4, contextWindow: 128000, maxOutput: 16384 },\n { id: \"openai/gpt-4o\", name: \"GPT-4o\", inputPrice: 2.5, outputPrice: 10.0, contextWindow: 128000, maxOutput: 16384, vision: true },\n { id: \"openai/gpt-4o-mini\", name: \"GPT-4o Mini\", inputPrice: 0.15, outputPrice: 0.6, contextWindow: 128000, maxOutput: 16384 },\n\n // OpenAI O-series (Reasoning)\n { id: \"openai/o1\", name: \"o1\", inputPrice: 15.0, outputPrice: 60.0, contextWindow: 200000, maxOutput: 100000, reasoning: true },\n { id: \"openai/o1-mini\", name: \"o1-mini\", inputPrice: 1.1, outputPrice: 4.4, contextWindow: 128000, maxOutput: 65536, reasoning: true },\n { id: \"openai/o3\", name: \"o3\", inputPrice: 2.0, outputPrice: 8.0, contextWindow: 200000, maxOutput: 100000, reasoning: true },\n { id: \"openai/o3-mini\", name: \"o3-mini\", inputPrice: 1.1, outputPrice: 4.4, contextWindow: 128000, maxOutput: 65536, reasoning: true },\n { id: \"openai/o4-mini\", name: \"o4-mini\", inputPrice: 1.1, outputPrice: 4.4, contextWindow: 128000, maxOutput: 65536, reasoning: true },\n\n // Anthropic\n { id: \"anthropic/claude-haiku-4.5\", name: \"Claude Haiku 4.5\", inputPrice: 1.0, outputPrice: 5.0, contextWindow: 200000, maxOutput: 8192 },\n { id: \"anthropic/claude-sonnet-4\", name: \"Claude Sonnet 4\", inputPrice: 3.0, outputPrice: 15.0, contextWindow: 200000, maxOutput: 64000, reasoning: true },\n { id: \"anthropic/claude-opus-4\", name: \"Claude Opus 4\", inputPrice: 15.0, outputPrice: 75.0, contextWindow: 200000, maxOutput: 32000, reasoning: true },\n { id: \"anthropic/claude-opus-4.5\", name: \"Claude Opus 4.5\", inputPrice: 15.0, outputPrice: 75.0, contextWindow: 200000, maxOutput: 32000, reasoning: true },\n\n // Google\n { id: \"google/gemini-3-pro-preview\", name: \"Gemini 3 Pro Preview\", inputPrice: 2.0, outputPrice: 12.0, contextWindow: 1050000, maxOutput: 65536, reasoning: true, vision: true },\n { id: \"google/gemini-2.5-pro\", name: \"Gemini 2.5 Pro\", inputPrice: 1.25, outputPrice: 10.0, contextWindow: 1050000, maxOutput: 65536, reasoning: true, vision: true },\n { id: \"google/gemini-2.5-flash\", name: \"Gemini 2.5 Flash\", inputPrice: 0.15, outputPrice: 0.6, contextWindow: 1000000, maxOutput: 65536 },\n\n // DeepSeek\n { id: \"deepseek/deepseek-chat\", name: \"DeepSeek V3.2 Chat\", inputPrice: 0.28, outputPrice: 0.42, contextWindow: 128000, maxOutput: 8192 },\n { id: \"deepseek/deepseek-reasoner\", name: \"DeepSeek V3.2 Reasoner\", inputPrice: 0.28, outputPrice: 0.42, contextWindow: 128000, maxOutput: 8192, reasoning: true },\n\n // xAI / Grok\n { id: \"xai/grok-3\", name: \"Grok 3\", inputPrice: 3.0, outputPrice: 15.0, contextWindow: 131072, maxOutput: 16384, reasoning: true },\n { id: \"xai/grok-3-fast\", name: \"Grok 3 Fast\", inputPrice: 5.0, outputPrice: 25.0, contextWindow: 131072, maxOutput: 16384, reasoning: true },\n { id: \"xai/grok-3-mini\", name: \"Grok 3 Mini\", inputPrice: 0.3, outputPrice: 0.5, contextWindow: 131072, maxOutput: 16384 },\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, AuthProfileCredential } from \"./types.js\";\nimport { walletKeyAuth, envKeyAuth } from \"./auth.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 // Auth methods\n auth: [envKeyAuth, walletKeyAuth],\n\n // Format the stored credential as the wallet key\n formatApiKey: (cred: AuthProfileCredential): string => {\n if (\"apiKey\" in cred && typeof cred.apiKey === \"string\") {\n return cred.apiKey;\n }\n throw new Error(\"BlockRun credential must contain an apiKey (wallet private key)\");\n },\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 { route, getFallbackChain, DEFAULT_ROUTING_CONFIG, type RouterOptions, type RoutingDecision, type RoutingConfig, type ModelPricing } from \"./router/index.js\";\nimport { BLOCKRUN_MODELS } from \"./models.js\";\nimport { logUsage, type UsageEntry } from \"./logger.js\";\nimport { RequestDeduplicator, type CachedResponse } from \"./dedup.js\";\n\nconst BLOCKRUN_API = \"https://blockrun.ai/api\";\nconst AUTO_MODEL = \"blockrun/auto\";\nconst USER_AGENT = \"clawrouter/0.3.2\";\nconst HEARTBEAT_INTERVAL_MS = 2_000;\n\nexport type ProxyOptions = {\n walletKey: string;\n apiBase?: string;\n port?: number;\n routingConfig?: Partial<RoutingConfig>;\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};\n\nexport type ProxyHandle = {\n port: number;\n baseUrl: string;\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(modelId: string, bodyLength: number, maxTokens: number): 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 * 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 // Create x402 payment-enabled fetch from wallet private key\n const account = privateKeyToAccount(options.walletKey as `0x${string}`);\n const { fetch: payFetch, cache: paymentCache } = createPaymentFetch(options.walletKey as `0x${string}`);\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\n if (req.url === \"/health\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ status: \"ok\", wallet: account.address }));\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(req, res, apiBase, payFetch, options, routerOpts, deduplicator);\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(JSON.stringify({\n error: { message: `Proxy error: ${error.message}`, type: \"proxy_error\" },\n }));\n } else if (!res.writableEnded) {\n // Headers already sent (streaming) — send error as SSE event\n res.write(`data: ${JSON.stringify({ error: { message: error.message, type: \"proxy_error\" } })}\\n\\n`);\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n }\n }\n });\n\n // Listen on requested port (0 = random available port)\n const listenPort = options.port ?? 0;\n\n return new Promise<ProxyHandle>((resolve, reject) => {\n server.on(\"error\", reject);\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 close: () =>\n new Promise<void>((res, rej) => {\n server.close((err) => (err ? rej(err) : res()));\n }),\n });\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 */\nasync function proxyRequest(\n req: IncomingMessage,\n res: ServerResponse,\n apiBase: string,\n payFetch: (input: RequestInfo | URL, init?: RequestInit, preAuth?: PreAuthParams) => Promise<Response>,\n options: ProxyOptions,\n routerOpts: RouterOptions,\n deduplicator: RequestDeduplicator,\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 if (parsed.model === AUTO_MODEL) {\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\") { lastUserMsg = messages[i]; break; }\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 body = Buffer.from(JSON.stringify(parsed));\n\n options.onRouted?.(routingDecision);\n }\n } catch {\n // JSON parse error — forward body as-is\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 // --- 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 (key === \"host\" || key === \"connection\" || key === \"transfer-encoding\" || key === \"content-length\") 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 // --- Payment pre-auth: estimate amount to skip 402 round trip ---\n let preAuth: PreAuthParams | undefined;\n if (modelId) {\n const estimated = estimateAmount(modelId, body.length, maxTokens);\n if (estimated) {\n preAuth = { estimatedAmount: estimated };\n }\n }\n\n try {\n // Make the request through x402-wrapped fetch (with optional pre-auth)\n const upstream = await payFetch(upstreamUrl, {\n method: req.method ?? \"POST\",\n headers,\n body: body.length > 0 ? body : undefined,\n }, preAuth);\n\n // Clear heartbeat — real data is about to flow\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n heartbeatInterval = undefined;\n }\n\n // --- Stream response and collect for dedup cache ---\n const responseChunks: Buffer[] = [];\n\n if (headersSentEarly) {\n // Streaming: headers already sent. Check for upstream errors.\n if (upstream.status !== 200) {\n const errBody = await upstream.text();\n const errEvent = `data: ${JSON.stringify({ error: { message: errBody, type: \"upstream_error\", status: upstream.status } })}\\n\\n`;\n res.write(errEvent);\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n\n // Cache the error response for dedup\n const errBuf = Buffer.from(errEvent + \"data: [DONE]\\n\\n\");\n deduplicator.complete(dedupKey, {\n status: 200, // we already sent 200\n headers: { \"content-type\": \"text/event-stream\" },\n body: errBuf,\n completedAt: Date.now(),\n });\n return;\n }\n\n // Pipe upstream SSE data to client\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: 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 } catch (err) {\n // Clear heartbeat on error\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n }\n\n // Remove in-flight entry so retries aren't blocked\n deduplicator.removeInflight(dedupKey);\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, type CachedPaymentParams } 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).map(b => b.toString(16).padStart(2, '0')).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: (input: RequestInfo | URL, init?: RequestInit, preAuth?: PreAuthParams) => 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 { name, score: scores.high, signal: `${signalLabel} (${matches.slice(0, 3).join(\", \")})` };\n }\n if (matches.length >= thresholds.low) {\n return { name, score: scores.low, signal: `${signalLabel} (${matches.slice(0, 3).join(\", \")})` };\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\n // Score all 14 dimensions\n const dimensions: DimensionScore[] = [\n // Original 8 dimensions\n scoreTokenCount(estimatedTokens, config.tokenCountThresholds),\n scoreKeywordMatch(text, config.codeKeywords, \"codePresence\", \"code\",\n { low: 1, high: 2 }, { none: 0, low: 0.5, high: 1.0 }),\n scoreKeywordMatch(text, config.reasoningKeywords, \"reasoningMarkers\", \"reasoning\",\n { low: 1, high: 2 }, { none: 0, low: 0.7, high: 1.0 }),\n scoreKeywordMatch(text, config.technicalKeywords, \"technicalTerms\", \"technical\",\n { low: 2, high: 4 }, { none: 0, low: 0.5, high: 1.0 }),\n scoreKeywordMatch(text, config.creativeKeywords, \"creativeMarkers\", \"creative\",\n { low: 1, high: 2 }, { none: 0, low: 0.5, high: 0.7 }),\n scoreKeywordMatch(text, config.simpleKeywords, \"simpleIndicators\", \"simple\",\n { low: 1, high: 2 }, { none: 0, low: -1.0, high: -1.0 }),\n scoreMultiStep(text),\n scoreQuestionComplexity(prompt),\n\n // 6 new dimensions\n scoreKeywordMatch(text, config.imperativeVerbs, \"imperativeVerbs\", \"imperative\",\n { low: 1, high: 2 }, { none: 0, low: 0.3, high: 0.5 }),\n scoreKeywordMatch(text, config.constraintIndicators, \"constraintCount\", \"constraints\",\n { low: 1, high: 3 }, { none: 0, low: 0.3, high: 0.7 }),\n scoreKeywordMatch(text, config.outputFormatKeywords, \"outputFormat\", \"format\",\n { low: 1, high: 2 }, { none: 0, low: 0.4, high: 0.7 }),\n scoreKeywordMatch(text, config.referenceKeywords, \"referenceComplexity\", \"references\",\n { low: 1, high: 2 }, { none: 0, low: 0.3, high: 0.5 }),\n scoreKeywordMatch(text, config.negationKeywords, \"negationComplexity\", \"negation\",\n { low: 2, high: 3 }, { none: 0, low: 0.3, high: 0.5 }),\n scoreKeywordMatch(text, config.domainSpecificKeywords, \"domainSpecificity\", \"domain-specific\",\n { low: 1, high: 2 }, { none: 0, low: 0.5, high: 0.8 }),\n ];\n\n // Collect signals\n const signals = dimensions\n .filter((d) => d.signal !== null)\n .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\n const reasoningMatches = config.reasoningKeywords.filter((kw) =>\n text.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(\n weightedScore - simpleMedium,\n mediumComplex - weightedScore,\n );\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\n ? (estimatedInputTokens / 1_000_000) * pricing.inputPrice\n : 0;\n const outputCost = pricing\n ? (maxOutputTokens / 1_000_000) * pricing.outputPrice\n : 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\n ? (maxOutputTokens / 1_000_000) * opusPricing.outputPrice\n : 0;\n const baselineCost = baselineInput + baselineOutput;\n\n const savings =\n baselineCost > 0\n ? Math.max(0, (baselineCost - costEstimate) / baselineCost)\n : 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(\n tier: Tier,\n tierConfigs: Record<Tier, TierConfig>,\n): 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 codeKeywords: [\n \"function\", \"class\", \"import\", \"def\", \"SELECT\", \"async\", \"await\",\n \"const\", \"let\", \"var\", \"return\", \"```\",\n ],\n reasoningKeywords: [\n \"prove\", \"theorem\", \"derive\", \"step by step\", \"chain of thought\",\n \"formally\", \"mathematical\", \"proof\", \"logically\",\n ],\n simpleKeywords: [\n \"what is\", \"define\", \"translate\", \"hello\", \"yes or no\",\n \"capital of\", \"how old\", \"who is\", \"when was\",\n ],\n technicalKeywords: [\n \"algorithm\", \"optimize\", \"architecture\", \"distributed\",\n \"kubernetes\", \"microservice\", \"database\", \"infrastructure\",\n ],\n creativeKeywords: [\n \"story\", \"poem\", \"compose\", \"brainstorm\", \"creative\",\n \"imagine\", \"write a\",\n ],\n\n // New dimension keyword lists\n imperativeVerbs: [\n \"build\", \"create\", \"implement\", \"design\", \"develop\", \"construct\",\n \"generate\", \"deploy\", \"configure\", \"set up\",\n ],\n constraintIndicators: [\n \"under\", \"at most\", \"at least\", \"within\", \"no more than\",\n \"o(\", \"maximum\", \"minimum\", \"limit\", \"budget\",\n ],\n outputFormatKeywords: [\n \"json\", \"yaml\", \"xml\", \"table\", \"csv\", \"markdown\",\n \"schema\", \"format as\", \"structured\",\n ],\n referenceKeywords: [\n \"above\", \"below\", \"previous\", \"following\", \"the docs\",\n \"the api\", \"the code\", \"earlier\", \"attached\",\n ],\n negationKeywords: [\n \"don't\", \"do not\", \"avoid\", \"never\", \"without\",\n \"except\", \"exclude\", \"no longer\",\n ],\n domainSpecificKeywords: [\n \"quantum\", \"fpga\", \"vlsi\", \"risc-v\", \"asic\", \"photonics\",\n \"genomics\", \"proteomics\", \"topological\", \"homomorphic\",\n \"zero-knowledge\", \"lattice-based\",\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.10,\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.70,\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: \"openai/o3\",\n fallback: [\"google/gemini-2.5-pro\", \"anthropic/claude-sonnet-4\"],\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, getFallbackChain, 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\n ? /json|structured|schema/i.test(systemPrompt)\n : false;\n\n // --- Rule-based classification ---\n const ruleResult = classifyByRules(\n prompt,\n systemPrompt,\n estimatedTokens,\n config.scoring,\n );\n\n let tier: Tier;\n let confidence: number;\n let 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\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 return createHash(\"sha256\").update(body).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(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 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 * @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 plugin 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 config set model blockrun/auto\n *\n * # Or use any specific BlockRun model\n * openclaw config set model openai/gpt-5.2\n */\n\nimport type { OpenClawPluginDefinition, OpenClawPluginApi } from \"./types.js\";\nimport { blockrunProvider, setActiveProxy } from \"./provider.js\";\nimport { startProxy } from \"./proxy.js\";\nimport { resolveOrGenerateWalletKey } from \"./auth.js\";\nimport type { RoutingConfig } from \"./router/index.js\";\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 // 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(`${decision.model} $${cost} (saved ${saved}%)`);\n },\n });\n\n setActiveProxy(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: \"0.3.2\",\n\n register(api: OpenClawPluginApi) {\n // Register BlockRun as a provider (sync — available immediately)\n api.registerProvider(blockrunProvider);\n api.logger.info(\"BlockRun provider registered (30+ models via x402)\");\n\n // Start x402 proxy in background (fire-and-forget)\n // OpenClaw only calls register(), not activate() — so all init goes here.\n // The loader ignores async returns, but the proxy starts in the background\n // and setActiveProxy() makes it available to the provider once ready.\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\n\nexport default plugin;\n\n// Re-export for programmatic use\nexport { startProxy } 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\";\n"],"mappings":"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","names":["privateKeyToAccount","privateKeyToAccount","privateKeyToAccount","response","paymentHeader","confidence","mkdir","join","homedir","DEFAULT_TTL_MS","privateKeyToAccount"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blockrun/clawrouter",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
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",