@blockrun/clawrouter 0.3.19 → 0.3.21
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 +1 -1
- package/dist/index.js +20 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -667,7 +667,7 @@ declare function isRetryable(errorOrResponse: Error | Response, config?: Partial
|
|
|
667
667
|
*
|
|
668
668
|
* Usage:
|
|
669
669
|
* # Install the plugin
|
|
670
|
-
* openclaw
|
|
670
|
+
* openclaw plugins install @blockrun/clawrouter
|
|
671
671
|
*
|
|
672
672
|
* # Fund your wallet with USDC on Base (address printed on install)
|
|
673
673
|
*
|
package/dist/index.js
CHANGED
|
@@ -1215,11 +1215,21 @@ var BalanceMonitor = class {
|
|
|
1215
1215
|
}
|
|
1216
1216
|
};
|
|
1217
1217
|
|
|
1218
|
+
// src/version.ts
|
|
1219
|
+
import { createRequire } from "module";
|
|
1220
|
+
import { fileURLToPath } from "url";
|
|
1221
|
+
import { dirname, join as join2 } from "path";
|
|
1222
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
1223
|
+
var __dirname = dirname(__filename);
|
|
1224
|
+
var require2 = createRequire(import.meta.url);
|
|
1225
|
+
var pkg = require2(join2(__dirname, "..", "package.json"));
|
|
1226
|
+
var VERSION = pkg.version;
|
|
1227
|
+
var USER_AGENT = `clawrouter/${VERSION}`;
|
|
1228
|
+
|
|
1218
1229
|
// src/proxy.ts
|
|
1219
1230
|
var BLOCKRUN_API = "https://blockrun.ai/api";
|
|
1220
1231
|
var AUTO_MODEL = "blockrun/auto";
|
|
1221
1232
|
var AUTO_MODEL_SHORT = "auto";
|
|
1222
|
-
var USER_AGENT = "clawrouter/0.3.19";
|
|
1223
1233
|
var HEARTBEAT_INTERVAL_MS = 2e3;
|
|
1224
1234
|
var DEFAULT_REQUEST_TIMEOUT_MS = 18e4;
|
|
1225
1235
|
var DEFAULT_PORT = 8402;
|
|
@@ -1597,11 +1607,11 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
1597
1607
|
|
|
1598
1608
|
// src/auth.ts
|
|
1599
1609
|
import { writeFile, readFile, mkdir as mkdir2 } from "fs/promises";
|
|
1600
|
-
import { join as
|
|
1610
|
+
import { join as join3 } from "path";
|
|
1601
1611
|
import { homedir as homedir2 } from "os";
|
|
1602
1612
|
import { generatePrivateKey, privateKeyToAccount as privateKeyToAccount3 } from "viem/accounts";
|
|
1603
|
-
var WALLET_DIR =
|
|
1604
|
-
var WALLET_FILE =
|
|
1613
|
+
var WALLET_DIR = join3(homedir2(), ".openclaw", "blockrun");
|
|
1614
|
+
var WALLET_FILE = join3(WALLET_DIR, "wallet.key");
|
|
1605
1615
|
async function loadSavedWallet() {
|
|
1606
1616
|
try {
|
|
1607
1617
|
const key = (await readFile(WALLET_FILE, "utf-8")).trim();
|
|
@@ -1635,7 +1645,7 @@ async function resolveOrGenerateWalletKey() {
|
|
|
1635
1645
|
// src/index.ts
|
|
1636
1646
|
import { readFileSync, writeFileSync, existsSync, readdirSync, mkdirSync } from "fs";
|
|
1637
1647
|
import { homedir as homedir3 } from "os";
|
|
1638
|
-
import { join as
|
|
1648
|
+
import { join as join4 } from "path";
|
|
1639
1649
|
|
|
1640
1650
|
// src/retry.ts
|
|
1641
1651
|
var DEFAULT_RETRY_CONFIG = {
|
|
@@ -1699,7 +1709,7 @@ function isCompletionMode() {
|
|
|
1699
1709
|
return args.some((arg, i) => arg === "completion" && i >= 1 && i <= 3);
|
|
1700
1710
|
}
|
|
1701
1711
|
function injectModelsConfig(logger) {
|
|
1702
|
-
const configPath =
|
|
1712
|
+
const configPath = join4(homedir3(), ".openclaw", "openclaw.json");
|
|
1703
1713
|
if (!existsSync(configPath)) {
|
|
1704
1714
|
logger.info("OpenClaw config not found, skipping models injection");
|
|
1705
1715
|
return;
|
|
@@ -1722,7 +1732,7 @@ function injectModelsConfig(logger) {
|
|
|
1722
1732
|
}
|
|
1723
1733
|
}
|
|
1724
1734
|
function injectAuthProfile(logger) {
|
|
1725
|
-
const agentsDir =
|
|
1735
|
+
const agentsDir = join4(homedir3(), ".openclaw", "agents");
|
|
1726
1736
|
if (!existsSync(agentsDir)) {
|
|
1727
1737
|
try {
|
|
1728
1738
|
mkdirSync(agentsDir, { recursive: true });
|
|
@@ -1739,8 +1749,8 @@ function injectAuthProfile(logger) {
|
|
|
1739
1749
|
agents = ["main", ...agents];
|
|
1740
1750
|
}
|
|
1741
1751
|
for (const agentId of agents) {
|
|
1742
|
-
const authDir =
|
|
1743
|
-
const authPath =
|
|
1752
|
+
const authDir = join4(agentsDir, agentId, "agent");
|
|
1753
|
+
const authPath = join4(authDir, "auth-profiles.json");
|
|
1744
1754
|
if (!existsSync(authDir)) {
|
|
1745
1755
|
try {
|
|
1746
1756
|
mkdirSync(authDir, { recursive: true });
|
|
@@ -1838,7 +1848,7 @@ var plugin = {
|
|
|
1838
1848
|
id: "clawrouter",
|
|
1839
1849
|
name: "ClawRouter",
|
|
1840
1850
|
description: "Smart LLM router \u2014 30+ models, x402 micropayments, 78% cost savings",
|
|
1841
|
-
version:
|
|
1851
|
+
version: VERSION,
|
|
1842
1852
|
register(api) {
|
|
1843
1853
|
if (isCompletionMode()) {
|
|
1844
1854
|
api.registerProvider(blockrunProvider);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/models.ts","../src/provider.ts","../src/proxy.ts","../src/x402.ts","../src/payment-cache.ts","../src/router/rules.ts","../src/router/selector.ts","../src/router/config.ts","../src/router/index.ts","../src/logger.ts","../src/dedup.ts","../src/balance.ts","../src/errors.ts","../src/auth.ts","../src/index.ts","../src/retry.ts"],"sourcesContent":["/**\n * BlockRun Model Definitions for OpenClaw\n *\n * Maps BlockRun's 30+ AI models to OpenClaw's ModelDefinitionConfig format.\n * All models use the \"openai-completions\" API since BlockRun is OpenAI-compatible.\n *\n * Pricing is in USD per 1M tokens. Operators pay these rates via x402;\n * they set their own markup when reselling to end users (Phase 2).\n */\n\nimport type { ModelDefinitionConfig, ModelProviderConfig } from \"./types.js\";\n\ntype BlockRunModel = {\n id: string;\n name: string;\n inputPrice: number;\n outputPrice: number;\n contextWindow: number;\n maxOutput: number;\n reasoning?: boolean;\n vision?: boolean;\n};\n\nexport const BLOCKRUN_MODELS: BlockRunModel[] = [\n // Smart routing meta-model — proxy replaces with actual model\n {\n id: \"blockrun/auto\",\n name: \"BlockRun Smart Router\",\n inputPrice: 0,\n outputPrice: 0,\n contextWindow: 1_050_000,\n maxOutput: 128_000,\n },\n\n // OpenAI GPT-5 Family\n {\n id: \"openai/gpt-5.2\",\n name: \"GPT-5.2\",\n inputPrice: 1.75,\n outputPrice: 14.0,\n contextWindow: 400000,\n maxOutput: 128000,\n reasoning: true,\n vision: true,\n },\n {\n id: \"openai/gpt-5-mini\",\n name: \"GPT-5 Mini\",\n inputPrice: 0.25,\n outputPrice: 2.0,\n contextWindow: 200000,\n maxOutput: 65536,\n },\n {\n id: \"openai/gpt-5-nano\",\n name: \"GPT-5 Nano\",\n inputPrice: 0.05,\n outputPrice: 0.4,\n contextWindow: 128000,\n maxOutput: 32768,\n },\n {\n id: \"openai/gpt-5.2-pro\",\n name: \"GPT-5.2 Pro\",\n inputPrice: 21.0,\n outputPrice: 168.0,\n contextWindow: 400000,\n maxOutput: 128000,\n reasoning: true,\n },\n\n // OpenAI GPT-4 Family\n {\n id: \"openai/gpt-4.1\",\n name: \"GPT-4.1\",\n inputPrice: 2.0,\n outputPrice: 8.0,\n contextWindow: 128000,\n maxOutput: 16384,\n vision: true,\n },\n {\n id: \"openai/gpt-4.1-mini\",\n name: \"GPT-4.1 Mini\",\n inputPrice: 0.4,\n outputPrice: 1.6,\n contextWindow: 128000,\n maxOutput: 16384,\n },\n {\n id: \"openai/gpt-4.1-nano\",\n name: \"GPT-4.1 Nano\",\n inputPrice: 0.1,\n outputPrice: 0.4,\n contextWindow: 128000,\n maxOutput: 16384,\n },\n {\n id: \"openai/gpt-4o\",\n name: \"GPT-4o\",\n inputPrice: 2.5,\n outputPrice: 10.0,\n contextWindow: 128000,\n maxOutput: 16384,\n vision: true,\n },\n {\n id: \"openai/gpt-4o-mini\",\n name: \"GPT-4o Mini\",\n inputPrice: 0.15,\n outputPrice: 0.6,\n contextWindow: 128000,\n maxOutput: 16384,\n },\n\n // OpenAI O-series (Reasoning)\n {\n id: \"openai/o1\",\n name: \"o1\",\n inputPrice: 15.0,\n outputPrice: 60.0,\n contextWindow: 200000,\n maxOutput: 100000,\n reasoning: true,\n },\n {\n id: \"openai/o1-mini\",\n name: \"o1-mini\",\n inputPrice: 1.1,\n outputPrice: 4.4,\n contextWindow: 128000,\n maxOutput: 65536,\n reasoning: true,\n },\n {\n id: \"openai/o3\",\n name: \"o3\",\n inputPrice: 2.0,\n outputPrice: 8.0,\n contextWindow: 200000,\n maxOutput: 100000,\n reasoning: true,\n },\n {\n id: \"openai/o3-mini\",\n name: \"o3-mini\",\n inputPrice: 1.1,\n outputPrice: 4.4,\n contextWindow: 128000,\n maxOutput: 65536,\n reasoning: true,\n },\n // o4-mini: Placeholder removed - model not yet released by OpenAI\n\n // Anthropic\n {\n id: \"anthropic/claude-haiku-4.5\",\n name: \"Claude Haiku 4.5\",\n inputPrice: 1.0,\n outputPrice: 5.0,\n contextWindow: 200000,\n maxOutput: 8192,\n },\n {\n id: \"anthropic/claude-sonnet-4\",\n name: \"Claude Sonnet 4\",\n inputPrice: 3.0,\n outputPrice: 15.0,\n contextWindow: 200000,\n maxOutput: 64000,\n reasoning: true,\n },\n {\n id: \"anthropic/claude-opus-4\",\n name: \"Claude Opus 4\",\n inputPrice: 15.0,\n outputPrice: 75.0,\n contextWindow: 200000,\n maxOutput: 32000,\n reasoning: true,\n },\n {\n id: \"anthropic/claude-opus-4.5\",\n name: \"Claude Opus 4.5\",\n inputPrice: 5.0,\n outputPrice: 25.0,\n contextWindow: 200000,\n maxOutput: 32000,\n reasoning: true,\n },\n\n // Google\n {\n id: \"google/gemini-3-pro-preview\",\n name: \"Gemini 3 Pro Preview\",\n inputPrice: 2.0,\n outputPrice: 12.0,\n contextWindow: 1050000,\n maxOutput: 65536,\n reasoning: true,\n vision: true,\n },\n {\n id: \"google/gemini-2.5-pro\",\n name: \"Gemini 2.5 Pro\",\n inputPrice: 1.25,\n outputPrice: 10.0,\n contextWindow: 1050000,\n maxOutput: 65536,\n reasoning: true,\n vision: true,\n },\n {\n id: \"google/gemini-2.5-flash\",\n name: \"Gemini 2.5 Flash\",\n inputPrice: 0.15,\n outputPrice: 0.6,\n contextWindow: 1000000,\n maxOutput: 65536,\n },\n\n // DeepSeek\n {\n id: \"deepseek/deepseek-chat\",\n name: \"DeepSeek V3.2 Chat\",\n inputPrice: 0.28,\n outputPrice: 0.42,\n contextWindow: 128000,\n maxOutput: 8192,\n },\n {\n id: \"deepseek/deepseek-reasoner\",\n name: \"DeepSeek V3.2 Reasoner\",\n inputPrice: 0.28,\n outputPrice: 0.42,\n contextWindow: 128000,\n maxOutput: 8192,\n reasoning: true,\n },\n\n // Moonshot / Kimi\n {\n id: \"moonshot/kimi-k2.5\",\n name: \"Kimi K2.5\",\n inputPrice: 0.5,\n outputPrice: 2.4,\n contextWindow: 262144,\n maxOutput: 8192,\n reasoning: true,\n vision: true,\n },\n\n // xAI / Grok\n {\n id: \"xai/grok-3\",\n name: \"Grok 3\",\n inputPrice: 3.0,\n outputPrice: 15.0,\n contextWindow: 131072,\n maxOutput: 16384,\n reasoning: true,\n },\n {\n id: \"xai/grok-3-fast\",\n name: \"Grok 3 Fast\",\n inputPrice: 5.0,\n outputPrice: 25.0,\n contextWindow: 131072,\n maxOutput: 16384,\n reasoning: true,\n },\n {\n id: \"xai/grok-3-mini\",\n name: \"Grok 3 Mini\",\n inputPrice: 0.3,\n outputPrice: 0.5,\n contextWindow: 131072,\n maxOutput: 16384,\n },\n];\n\n/**\n * Convert BlockRun model definitions to OpenClaw ModelDefinitionConfig format.\n */\nfunction toOpenClawModel(m: BlockRunModel): ModelDefinitionConfig {\n return {\n id: m.id,\n name: m.name,\n api: \"openai-completions\",\n reasoning: m.reasoning ?? false,\n input: m.vision ? [\"text\", \"image\"] : [\"text\"],\n cost: {\n input: m.inputPrice,\n output: m.outputPrice,\n cacheRead: 0,\n cacheWrite: 0,\n },\n contextWindow: m.contextWindow,\n maxTokens: m.maxOutput,\n };\n}\n\n/**\n * All BlockRun models in OpenClaw format.\n */\nexport const OPENCLAW_MODELS: ModelDefinitionConfig[] = BLOCKRUN_MODELS.map(toOpenClawModel);\n\n/**\n * Build a ModelProviderConfig for BlockRun.\n *\n * @param baseUrl - The proxy's local base URL (e.g., \"http://127.0.0.1:12345\")\n */\nexport function buildProviderModels(baseUrl: string): ModelProviderConfig {\n return {\n baseUrl: `${baseUrl}/v1`,\n api: \"openai-completions\",\n models: OPENCLAW_MODELS,\n };\n}\n","/**\n * BlockRun ProviderPlugin for OpenClaw\n *\n * Registers BlockRun as an LLM provider in OpenClaw.\n * Uses a local x402 proxy to handle micropayments transparently —\n * pi-ai sees a standard OpenAI-compatible API at localhost.\n */\n\nimport type { ProviderPlugin } from \"./types.js\";\nimport { buildProviderModels } from \"./models.js\";\nimport type { ProxyHandle } from \"./proxy.js\";\n\n/**\n * State for the running proxy (set when the plugin activates).\n */\nlet activeProxy: ProxyHandle | null = null;\n\n/**\n * Update the proxy handle (called from index.ts when the proxy starts).\n */\nexport function setActiveProxy(proxy: ProxyHandle): void {\n activeProxy = proxy;\n}\n\nexport function getActiveProxy(): ProxyHandle | null {\n return activeProxy;\n}\n\n/**\n * BlockRun provider plugin definition.\n */\nexport const blockrunProvider: ProviderPlugin = {\n id: \"blockrun\",\n label: \"BlockRun\",\n docsPath: \"https://blockrun.ai/docs\",\n aliases: [\"br\"],\n envVars: [\"BLOCKRUN_WALLET_KEY\"],\n\n // Model definitions — dynamically set to proxy URL\n get models() {\n if (!activeProxy) {\n // Fallback: point to BlockRun API directly (won't handle x402, but\n // allows config loading before proxy starts)\n return buildProviderModels(\"https://blockrun.ai/api\");\n }\n return buildProviderModels(activeProxy.baseUrl);\n },\n\n // No auth required — the x402 proxy handles wallet-based payments internally.\n // The proxy auto-generates a wallet on first run and stores it at\n // ~/.openclaw/blockrun/wallet.key. Users just fund that wallet with USDC.\n auth: [],\n};\n","/**\n * Local x402 Proxy Server\n *\n * Sits between OpenClaw's pi-ai (which makes standard OpenAI-format requests)\n * and BlockRun's API (which requires x402 micropayments).\n *\n * Flow:\n * pi-ai → http://localhost:{port}/v1/chat/completions\n * → proxy forwards to https://blockrun.ai/api/v1/chat/completions\n * → gets 402 → @x402/fetch signs payment → retries\n * → streams response back to pi-ai\n *\n * Optimizations (v0.3.0):\n * - SSE heartbeat: for streaming requests, sends headers + heartbeat immediately\n * before the x402 flow, preventing OpenClaw's 10-15s timeout from firing.\n * - Response dedup: hashes request bodies and caches responses for 30s,\n * preventing double-charging when OpenClaw retries after timeout.\n * - Payment cache: after first 402, pre-signs subsequent requests to skip\n * the 402 round trip (~200ms savings per request).\n * - Smart routing: when model is \"blockrun/auto\", classify query and pick cheapest model.\n * - Usage logging: log every request as JSON line to ~/.openclaw/blockrun/logs/\n */\n\nimport { createServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport type { AddressInfo } from \"node:net\";\nimport { privateKeyToAccount } from \"viem/accounts\";\nimport { createPaymentFetch, type PreAuthParams } from \"./x402.js\";\nimport {\n route,\n DEFAULT_ROUTING_CONFIG,\n type RouterOptions,\n type RoutingDecision,\n type RoutingConfig,\n type ModelPricing,\n} from \"./router/index.js\";\nimport { BLOCKRUN_MODELS } from \"./models.js\";\nimport { logUsage, type UsageEntry } from \"./logger.js\";\nimport { RequestDeduplicator } from \"./dedup.js\";\nimport { BalanceMonitor } from \"./balance.js\";\nimport { InsufficientFundsError, EmptyWalletError } from \"./errors.js\";\n\nconst BLOCKRUN_API = \"https://blockrun.ai/api\";\nconst AUTO_MODEL = \"blockrun/auto\";\nconst AUTO_MODEL_SHORT = \"auto\"; // OpenClaw strips provider prefix\nconst USER_AGENT = \"clawrouter/0.3.19\";\nconst HEARTBEAT_INTERVAL_MS = 2_000;\nconst DEFAULT_REQUEST_TIMEOUT_MS = 180_000; // 3 minutes (allows for on-chain tx + LLM response)\nconst DEFAULT_PORT = 8402;\n\n/** Callback info for low balance warning */\nexport type LowBalanceInfo = {\n balanceUSD: string;\n walletAddress: string;\n};\n\n/** Callback info for insufficient funds error */\nexport type InsufficientFundsInfo = {\n balanceUSD: string;\n requiredUSD: string;\n walletAddress: string;\n};\n\nexport type ProxyOptions = {\n walletKey: string;\n apiBase?: string;\n /** Port to listen on (default: 8402) */\n port?: number;\n routingConfig?: Partial<RoutingConfig>;\n /** Request timeout in ms (default: 180000 = 3 minutes). Covers on-chain tx + LLM response. */\n requestTimeoutMs?: number;\n onReady?: (port: number) => void;\n onError?: (error: Error) => void;\n onPayment?: (info: { model: string; amount: string; network: string }) => void;\n onRouted?: (decision: RoutingDecision) => void;\n /** Called when balance drops below $1.00 (warning, request still proceeds) */\n onLowBalance?: (info: LowBalanceInfo) => void;\n /** Called when balance is insufficient for a request (request fails) */\n onInsufficientFunds?: (info: InsufficientFundsInfo) => void;\n};\n\nexport type ProxyHandle = {\n port: number;\n baseUrl: string;\n walletAddress: string;\n balanceMonitor: BalanceMonitor;\n close: () => Promise<void>;\n};\n\n/**\n * Build model pricing map from BLOCKRUN_MODELS.\n */\nfunction buildModelPricing(): Map<string, ModelPricing> {\n const map = new Map<string, ModelPricing>();\n for (const m of BLOCKRUN_MODELS) {\n if (m.id === AUTO_MODEL) continue; // skip meta-model\n map.set(m.id, { inputPrice: m.inputPrice, outputPrice: m.outputPrice });\n }\n return map;\n}\n\n/**\n * Merge partial routing config overrides with defaults.\n */\nfunction mergeRoutingConfig(overrides?: Partial<RoutingConfig>): RoutingConfig {\n if (!overrides) return DEFAULT_ROUTING_CONFIG;\n return {\n ...DEFAULT_ROUTING_CONFIG,\n ...overrides,\n classifier: { ...DEFAULT_ROUTING_CONFIG.classifier, ...overrides.classifier },\n scoring: { ...DEFAULT_ROUTING_CONFIG.scoring, ...overrides.scoring },\n tiers: { ...DEFAULT_ROUTING_CONFIG.tiers, ...overrides.tiers },\n overrides: { ...DEFAULT_ROUTING_CONFIG.overrides, ...overrides.overrides },\n };\n}\n\n/**\n * Estimate USDC cost for a request based on model pricing.\n * Returns amount string in USDC smallest unit (6 decimals) or undefined if unknown.\n */\nfunction estimateAmount(\n modelId: string,\n bodyLength: number,\n maxTokens: number,\n): string | undefined {\n const model = BLOCKRUN_MODELS.find((m) => m.id === modelId);\n if (!model) return undefined;\n\n // Rough estimate: ~4 chars per token for input\n const estimatedInputTokens = Math.ceil(bodyLength / 4);\n const estimatedOutputTokens = maxTokens || model.maxOutput || 4096;\n\n const costUsd =\n (estimatedInputTokens / 1_000_000) * model.inputPrice +\n (estimatedOutputTokens / 1_000_000) * model.outputPrice;\n\n // Convert to USDC 6-decimal integer, add 20% buffer for estimation error\n // Minimum 100 ($0.0001) to avoid zero-amount rejections\n const amountMicros = Math.max(100, Math.ceil(costUsd * 1.2 * 1_000_000));\n return amountMicros.toString();\n}\n\n/**\n * Start the local x402 proxy server.\n *\n * 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 } = createPaymentFetch(options.walletKey as `0x${string}`);\n\n // Create balance monitor for pre-request checks\n const balanceMonitor = new BalanceMonitor(account.address);\n\n // Build router options (100% local — no external API calls for routing)\n const routingConfig = mergeRoutingConfig(options.routingConfig);\n const modelPricing = buildModelPricing();\n const routerOpts: RouterOptions = {\n config: routingConfig,\n modelPricing,\n };\n\n // Request deduplicator (shared across all requests)\n const deduplicator = new RequestDeduplicator();\n\n const server = createServer(async (req: IncomingMessage, res: ServerResponse) => {\n // Health check with optional balance info\n if (req.url === \"/health\" || req.url?.startsWith(\"/health?\")) {\n const url = new URL(req.url, \"http://localhost\");\n const full = url.searchParams.get(\"full\") === \"true\";\n\n const response: Record<string, unknown> = {\n status: \"ok\",\n wallet: account.address,\n };\n\n if (full) {\n try {\n const balanceInfo = await balanceMonitor.checkBalance();\n response.balance = balanceInfo.balanceUSD;\n response.isLow = balanceInfo.isLow;\n response.isEmpty = balanceInfo.isEmpty;\n } catch {\n response.balanceError = \"Could not fetch balance\";\n }\n }\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(response));\n return;\n }\n\n // Only proxy paths starting with /v1\n if (!req.url?.startsWith(\"/v1\")) {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Not found\" }));\n return;\n }\n\n try {\n await proxyRequest(\n req,\n res,\n apiBase,\n payFetch,\n options,\n routerOpts,\n deduplicator,\n balanceMonitor,\n );\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n options.onError?.(error);\n\n if (!res.headersSent) {\n res.writeHead(502, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: { message: `Proxy error: ${error.message}`, type: \"proxy_error\" },\n }),\n );\n } else if (!res.writableEnded) {\n // Headers already sent (streaming) — send error as SSE event\n res.write(\n `data: ${JSON.stringify({ error: { message: error.message, type: \"proxy_error\" } })}\\n\\n`,\n );\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n }\n }\n });\n\n // Listen on requested port (default: 8402)\n const listenPort = options.port ?? DEFAULT_PORT;\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 walletAddress: account.address,\n balanceMonitor,\n close: () =>\n new Promise<void>((res, rej) => {\n server.close((err) => (err ? rej(err) : res()));\n }),\n });\n });\n });\n}\n\n/**\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: (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ) => Promise<Response>,\n options: ProxyOptions,\n routerOpts: RouterOptions,\n deduplicator: RequestDeduplicator,\n balanceMonitor: BalanceMonitor,\n): Promise<void> {\n const startTime = Date.now();\n\n // Build upstream URL: /v1/chat/completions → https://blockrun.ai/api/v1/chat/completions\n const upstreamUrl = `${apiBase}${req.url}`;\n\n // Collect request body\n const bodyChunks: Buffer[] = [];\n for await (const chunk of req) {\n bodyChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n let body = Buffer.concat(bodyChunks);\n\n // --- Smart routing ---\n let routingDecision: RoutingDecision | undefined;\n let isStreaming = false;\n let modelId = \"\";\n let maxTokens = 4096;\n const isChatCompletion = req.url?.includes(\"/chat/completions\");\n\n if (isChatCompletion && body.length > 0) {\n try {\n const parsed = JSON.parse(body.toString()) as Record<string, unknown>;\n isStreaming = parsed.stream === true;\n modelId = (parsed.model as string) || \"\";\n maxTokens = (parsed.max_tokens as number) || 4096;\n\n if (parsed.model === AUTO_MODEL || parsed.model === AUTO_MODEL_SHORT) {\n // Extract prompt from messages\n type ChatMessage = { role: string; content: string };\n const messages = parsed.messages as ChatMessage[] | undefined;\n let lastUserMsg: ChatMessage | undefined;\n if (messages) {\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].role === \"user\") {\n lastUserMsg = messages[i];\n break;\n }\n }\n }\n const systemMsg = messages?.find((m: ChatMessage) => m.role === \"system\");\n const prompt = typeof lastUserMsg?.content === \"string\" ? lastUserMsg.content : \"\";\n const systemPrompt = typeof systemMsg?.content === \"string\" ? systemMsg.content : undefined;\n\n routingDecision = route(prompt, systemPrompt, maxTokens, routerOpts);\n\n // Replace model in body\n parsed.model = routingDecision.model;\n modelId = routingDecision.model;\n 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 // --- Pre-request balance check ---\n // Estimate cost and check if wallet has sufficient balance\n let estimatedCostMicros: bigint | undefined;\n if (modelId) {\n const estimated = estimateAmount(modelId, body.length, maxTokens);\n if (estimated) {\n estimatedCostMicros = BigInt(estimated);\n\n // Check balance before proceeding\n const sufficiency = await balanceMonitor.checkSufficient(estimatedCostMicros);\n\n if (sufficiency.info.isEmpty) {\n // Wallet is empty — cannot proceed\n deduplicator.removeInflight(dedupKey);\n const error = new EmptyWalletError(sufficiency.info.walletAddress);\n options.onInsufficientFunds?.({\n balanceUSD: sufficiency.info.balanceUSD,\n requiredUSD: balanceMonitor.formatUSDC(estimatedCostMicros),\n walletAddress: sufficiency.info.walletAddress,\n });\n throw error;\n }\n\n if (!sufficiency.sufficient) {\n // Insufficient balance — cannot proceed\n deduplicator.removeInflight(dedupKey);\n const error = new InsufficientFundsError({\n currentBalanceUSD: sufficiency.info.balanceUSD,\n requiredUSD: balanceMonitor.formatUSDC(estimatedCostMicros),\n walletAddress: sufficiency.info.walletAddress,\n });\n options.onInsufficientFunds?.({\n balanceUSD: sufficiency.info.balanceUSD,\n requiredUSD: balanceMonitor.formatUSDC(estimatedCostMicros),\n walletAddress: sufficiency.info.walletAddress,\n });\n throw error;\n }\n\n if (sufficiency.info.isLow) {\n // Balance is low but sufficient — warn and proceed\n options.onLowBalance?.({\n balanceUSD: sufficiency.info.balanceUSD,\n walletAddress: sufficiency.info.walletAddress,\n });\n }\n }\n }\n\n // --- Streaming: early header flush + heartbeat ---\n let heartbeatInterval: ReturnType<typeof setInterval> | undefined;\n let headersSentEarly = false;\n\n if (isStreaming) {\n // Send 200 + SSE headers immediately, before x402 flow\n res.writeHead(200, {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-cache\",\n connection: \"keep-alive\",\n });\n headersSentEarly = true;\n\n // First heartbeat immediately\n res.write(\": heartbeat\\n\\n\");\n\n // Continue heartbeats every 2s while waiting for upstream\n heartbeatInterval = setInterval(() => {\n if (!res.writableEnded) {\n res.write(\": heartbeat\\n\\n\");\n }\n }, HEARTBEAT_INTERVAL_MS);\n }\n\n // Forward headers, stripping host, connection, and content-length\n const headers: Record<string, string> = {};\n for (const [key, value] of Object.entries(req.headers)) {\n if (\n key === \"host\" ||\n key === \"connection\" ||\n key === \"transfer-encoding\" ||\n key === \"content-length\"\n )\n continue;\n if (typeof value === \"string\") {\n headers[key] = value;\n }\n }\n if (!headers[\"content-type\"]) {\n headers[\"content-type\"] = \"application/json\";\n }\n headers[\"user-agent\"] = USER_AGENT;\n\n // --- Payment pre-auth: use already-estimated amount to skip 402 round trip ---\n let preAuth: PreAuthParams | undefined;\n if (estimatedCostMicros !== undefined) {\n preAuth = { estimatedAmount: estimatedCostMicros.toString() };\n }\n\n // --- Client disconnect cleanup ---\n let completed = false;\n res.on(\"close\", () => {\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n heartbeatInterval = undefined;\n }\n // Remove from in-flight if client disconnected before completion\n if (!completed) {\n deduplicator.removeInflight(dedupKey);\n }\n });\n\n // --- Request timeout ---\n const timeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n // Make the request through x402-wrapped fetch (with optional pre-auth)\n const upstream = await payFetch(\n upstreamUrl,\n {\n method: req.method ?? \"POST\",\n headers,\n body: body.length > 0 ? body : undefined,\n signal: controller.signal,\n },\n preAuth,\n );\n\n // Clear timeout — request succeeded\n clearTimeout(timeoutId);\n\n // Clear heartbeat — real data is about to flow\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n heartbeatInterval = undefined;\n }\n\n // --- 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\n // --- Optimistic balance deduction after successful response ---\n if (estimatedCostMicros !== undefined) {\n balanceMonitor.deductEstimated(estimatedCostMicros);\n }\n\n // Mark request as completed (for client disconnect cleanup)\n completed = true;\n } catch (err) {\n // Clear timeout on error\n clearTimeout(timeoutId);\n\n // Clear heartbeat on error\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n heartbeatInterval = undefined;\n }\n\n // Remove in-flight entry so retries aren't blocked\n deduplicator.removeInflight(dedupKey);\n\n // Invalidate balance cache on payment failure (might be out of date)\n balanceMonitor.invalidate();\n\n // Convert abort error to more descriptive timeout error\n if (err instanceof Error && err.name === \"AbortError\") {\n throw new Error(`Request timed out after ${timeoutMs}ms`);\n }\n\n throw err;\n }\n\n // --- Usage logging (fire-and-forget) ---\n if (routingDecision) {\n const entry: UsageEntry = {\n timestamp: new Date().toISOString(),\n model: routingDecision.model,\n cost: routingDecision.costEstimate,\n latencyMs: Date.now() - startTime,\n };\n logUsage(entry).catch(() => {});\n }\n}\n","/**\n * x402 Payment Implementation\n *\n * Based on BlockRun's proven implementation.\n * Handles 402 Payment Required responses with EIP-712 signed USDC transfers.\n *\n * Optimizations (v0.3.0):\n * - Payment cache: after first 402, caches {payTo, asset, network} per endpoint.\n * On subsequent requests, pre-signs payment and sends with first request,\n * skipping the 402 round trip (~200ms savings).\n * - Falls back to normal 402 flow if pre-signed payment is rejected.\n */\n\nimport { signTypedData, privateKeyToAccount } from \"viem/accounts\";\nimport { PaymentCache } from \"./payment-cache.js\";\n\nconst BASE_CHAIN_ID = 8453;\nconst USDC_BASE = \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\" as const;\n\nconst USDC_DOMAIN = {\n name: \"USD Coin\",\n version: \"2\",\n chainId: BASE_CHAIN_ID,\n verifyingContract: USDC_BASE,\n} as const;\n\nconst TRANSFER_TYPES = {\n TransferWithAuthorization: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n ],\n} as const;\n\nfunction createNonce(): `0x${string}` {\n const bytes = new Uint8Array(32);\n crypto.getRandomValues(bytes);\n return `0x${Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\")}` as `0x${string}`;\n}\n\ninterface PaymentOption {\n scheme: string;\n network: string;\n amount?: string;\n maxAmountRequired?: string;\n asset: string;\n payTo: string;\n maxTimeoutSeconds?: number;\n extra?: { name?: string; version?: string };\n}\n\ninterface PaymentRequired {\n accepts: PaymentOption[];\n resource?: { url?: string; description?: string };\n}\n\nfunction parsePaymentRequired(headerValue: string): PaymentRequired {\n const decoded = atob(headerValue);\n return JSON.parse(decoded) as PaymentRequired;\n}\n\nasync function createPaymentPayload(\n privateKey: `0x${string}`,\n fromAddress: string,\n recipient: string,\n amount: string,\n resourceUrl: string,\n): Promise<string> {\n const now = Math.floor(Date.now() / 1000);\n const validAfter = now - 600;\n const validBefore = now + 300;\n const nonce = createNonce();\n\n const signature = await signTypedData({\n privateKey,\n domain: USDC_DOMAIN,\n types: TRANSFER_TYPES,\n primaryType: \"TransferWithAuthorization\",\n message: {\n from: fromAddress as `0x${string}`,\n to: recipient as `0x${string}`,\n value: BigInt(amount),\n validAfter: BigInt(validAfter),\n validBefore: BigInt(validBefore),\n nonce,\n },\n });\n\n const paymentData = {\n x402Version: 2,\n resource: {\n url: resourceUrl,\n description: \"BlockRun AI API call\",\n mimeType: \"application/json\",\n },\n accepted: {\n scheme: \"exact\",\n network: \"eip155:8453\",\n amount,\n asset: USDC_BASE,\n payTo: recipient,\n maxTimeoutSeconds: 300,\n extra: { name: \"USD Coin\", version: \"2\" },\n },\n payload: {\n signature,\n authorization: {\n from: fromAddress,\n to: recipient,\n value: amount,\n validAfter: validAfter.toString(),\n validBefore: validBefore.toString(),\n nonce,\n },\n },\n extensions: {},\n };\n\n return btoa(JSON.stringify(paymentData));\n}\n\n/** Pre-auth parameters for skipping the 402 round trip. */\nexport type PreAuthParams = {\n estimatedAmount: string; // USDC amount in smallest unit (6 decimals)\n};\n\n/** Result from createPaymentFetch — includes the fetch wrapper and payment cache. */\nexport type PaymentFetchResult = {\n fetch: (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ) => Promise<Response>;\n cache: PaymentCache;\n};\n\n/**\n * Create a fetch wrapper that handles x402 payment automatically.\n *\n * Supports pre-auth: if cached payment params + estimated amount are available,\n * pre-signs and attaches payment to the first request, skipping the 402 round trip.\n * Falls back to normal 402 flow if pre-signed payment is rejected.\n */\nexport function createPaymentFetch(privateKey: `0x${string}`): PaymentFetchResult {\n const account = privateKeyToAccount(privateKey);\n const walletAddress = account.address;\n const paymentCache = new PaymentCache();\n\n const payFetch = async (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ): Promise<Response> => {\n const url = typeof input === \"string\" ? input : input instanceof URL ? input.href : input.url;\n const endpointPath = new URL(url).pathname;\n\n // --- Pre-auth path: skip 402 round trip ---\n const cached = paymentCache.get(endpointPath);\n if (cached && preAuth?.estimatedAmount) {\n const paymentPayload = await createPaymentPayload(\n privateKey,\n walletAddress,\n cached.payTo,\n preAuth.estimatedAmount,\n url,\n );\n\n const preAuthHeaders = new Headers(init?.headers);\n preAuthHeaders.set(\"payment-signature\", paymentPayload);\n\n const response = await fetch(input, { ...init, headers: preAuthHeaders });\n\n // Pre-auth accepted — skip 402 entirely\n if (response.status !== 402) {\n return response;\n }\n\n // Pre-auth rejected (wrong amount, payTo changed, etc.)\n // Try to use this 402's payment header for a proper retry\n const paymentHeader = response.headers.get(\"x-payment-required\");\n if (paymentHeader) {\n return handle402(input, init, url, endpointPath, paymentHeader);\n }\n\n // No payment header — invalidate cache and retry clean (no payment header)\n // to get a proper 402 with payment requirements\n paymentCache.invalidate(endpointPath);\n const cleanResponse = await fetch(input, init);\n if (cleanResponse.status !== 402) {\n return cleanResponse;\n }\n const cleanHeader = cleanResponse.headers.get(\"x-payment-required\");\n if (!cleanHeader) {\n throw new Error(\"402 response missing x-payment-required header\");\n }\n return handle402(input, init, url, endpointPath, cleanHeader);\n }\n\n // --- Normal path: first request may get 402 ---\n const response = await fetch(input, init);\n\n if (response.status !== 402) {\n return response;\n }\n\n const paymentHeader = response.headers.get(\"x-payment-required\");\n if (!paymentHeader) {\n throw new Error(\"402 response missing x-payment-required header\");\n }\n\n return handle402(input, init, url, endpointPath, paymentHeader);\n };\n\n /** Handle a 402 response: parse, cache params, sign, retry. */\n async function handle402(\n input: RequestInfo | URL,\n init: RequestInit | undefined,\n url: string,\n endpointPath: string,\n paymentHeader: string,\n ): Promise<Response> {\n const paymentRequired = parsePaymentRequired(paymentHeader);\n const option = paymentRequired.accepts?.[0];\n if (!option) {\n throw new Error(\"No payment options in 402 response\");\n }\n\n const amount = option.amount || option.maxAmountRequired;\n if (!amount) {\n throw new Error(\"No amount in payment requirements\");\n }\n\n // Cache payment params for future pre-auth\n paymentCache.set(endpointPath, {\n payTo: option.payTo,\n asset: option.asset,\n scheme: option.scheme,\n network: option.network,\n extra: option.extra,\n maxTimeoutSeconds: option.maxTimeoutSeconds,\n });\n\n // Create signed payment\n const paymentPayload = await createPaymentPayload(\n privateKey,\n walletAddress,\n option.payTo,\n amount,\n url,\n );\n\n // Retry with payment\n const retryHeaders = new Headers(init?.headers);\n retryHeaders.set(\"payment-signature\", paymentPayload);\n\n return fetch(input, {\n ...init,\n headers: retryHeaders,\n });\n }\n\n return { fetch: payFetch, cache: paymentCache };\n}\n","/**\n * Payment Parameter Cache\n *\n * Caches the 402 payment parameters (payTo, asset, network, etc.) after the first\n * request to each endpoint. On subsequent requests, pre-signs the payment and\n * attaches it to the first request, skipping the 402 round trip (~200ms savings).\n */\n\nexport type CachedPaymentParams = {\n payTo: string;\n asset: string;\n scheme: string;\n network: string;\n extra?: { name?: string; version?: string };\n maxTimeoutSeconds?: number;\n cachedAt: number;\n};\n\nconst DEFAULT_TTL_MS = 3_600_000; // 1 hour\n\nexport class PaymentCache {\n private cache = new Map<string, CachedPaymentParams>();\n private ttlMs: number;\n\n constructor(ttlMs = DEFAULT_TTL_MS) {\n this.ttlMs = ttlMs;\n }\n\n /** Get cached payment params for an endpoint path. */\n get(endpointPath: string): CachedPaymentParams | undefined {\n const entry = this.cache.get(endpointPath);\n if (!entry) return undefined;\n if (Date.now() - entry.cachedAt > this.ttlMs) {\n this.cache.delete(endpointPath);\n return undefined;\n }\n return entry;\n }\n\n /** Cache payment params from a 402 response. */\n set(endpointPath: string, params: Omit<CachedPaymentParams, \"cachedAt\">): void {\n this.cache.set(endpointPath, { ...params, cachedAt: Date.now() });\n }\n\n /** Invalidate cache for an endpoint (e.g., if payTo changed). */\n invalidate(endpointPath: string): void {\n this.cache.delete(endpointPath);\n }\n}\n","/**\n * Rule-Based Classifier (v2 — Weighted Scoring)\n *\n * Scores a request across 14 weighted dimensions and maps the aggregate\n * score to a tier using configurable boundaries. Confidence is calibrated\n * via sigmoid — low confidence triggers the fallback classifier.\n *\n * Handles 70-80% of requests in < 1ms with zero cost.\n */\n\nimport type { Tier, ScoringResult, ScoringConfig } from \"./types.js\";\n\ntype DimensionScore = { name: string; score: number; signal: string | null };\n\n// ─── Dimension Scorers ───\n// Each returns a score in [-1, 1] and an optional signal string.\n\nfunction scoreTokenCount(\n estimatedTokens: number,\n thresholds: { simple: number; complex: number },\n): DimensionScore {\n if (estimatedTokens < thresholds.simple) {\n return { name: \"tokenCount\", score: -1.0, signal: `short (${estimatedTokens} tokens)` };\n }\n if (estimatedTokens > thresholds.complex) {\n return { name: \"tokenCount\", score: 1.0, signal: `long (${estimatedTokens} tokens)` };\n }\n return { name: \"tokenCount\", score: 0, signal: null };\n}\n\nfunction scoreKeywordMatch(\n text: string,\n keywords: string[],\n name: string,\n signalLabel: string,\n thresholds: { low: number; high: number },\n scores: { none: number; low: number; high: number },\n): DimensionScore {\n const matches = keywords.filter((kw) => text.includes(kw.toLowerCase()));\n if (matches.length >= thresholds.high) {\n return {\n name,\n score: scores.high,\n signal: `${signalLabel} (${matches.slice(0, 3).join(\", \")})`,\n };\n }\n if (matches.length >= thresholds.low) {\n return {\n name,\n score: scores.low,\n signal: `${signalLabel} (${matches.slice(0, 3).join(\", \")})`,\n };\n }\n return { name, score: scores.none, signal: null };\n}\n\nfunction scoreMultiStep(text: string): DimensionScore {\n const patterns = [/first.*then/i, /step \\d/i, /\\d\\.\\s/];\n const hits = patterns.filter((p) => p.test(text));\n if (hits.length > 0) {\n return { name: \"multiStepPatterns\", score: 0.5, signal: \"multi-step\" };\n }\n return { name: \"multiStepPatterns\", score: 0, signal: null };\n}\n\nfunction scoreQuestionComplexity(prompt: string): DimensionScore {\n const count = (prompt.match(/\\?/g) || []).length;\n if (count > 3) {\n return { name: \"questionComplexity\", score: 0.5, signal: `${count} questions` };\n }\n return { name: \"questionComplexity\", score: 0, signal: null };\n}\n\n// ─── Main Classifier ───\n\nexport function classifyByRules(\n prompt: string,\n systemPrompt: string | undefined,\n estimatedTokens: number,\n config: ScoringConfig,\n): ScoringResult {\n const text = `${systemPrompt ?? \"\"} ${prompt}`.toLowerCase();\n\n // Score all 14 dimensions\n const dimensions: DimensionScore[] = [\n // Original 8 dimensions\n scoreTokenCount(estimatedTokens, config.tokenCountThresholds),\n scoreKeywordMatch(\n text,\n config.codeKeywords,\n \"codePresence\",\n \"code\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 1.0 },\n ),\n scoreKeywordMatch(\n text,\n config.reasoningKeywords,\n \"reasoningMarkers\",\n \"reasoning\",\n { low: 1, high: 2 },\n { none: 0, low: 0.7, high: 1.0 },\n ),\n scoreKeywordMatch(\n text,\n config.technicalKeywords,\n \"technicalTerms\",\n \"technical\",\n { low: 2, high: 4 },\n { none: 0, low: 0.5, high: 1.0 },\n ),\n scoreKeywordMatch(\n text,\n config.creativeKeywords,\n \"creativeMarkers\",\n \"creative\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 0.7 },\n ),\n scoreKeywordMatch(\n text,\n config.simpleKeywords,\n \"simpleIndicators\",\n \"simple\",\n { low: 1, high: 2 },\n { none: 0, low: -1.0, high: -1.0 },\n ),\n scoreMultiStep(text),\n scoreQuestionComplexity(prompt),\n\n // 6 new dimensions\n scoreKeywordMatch(\n text,\n config.imperativeVerbs,\n \"imperativeVerbs\",\n \"imperative\",\n { low: 1, high: 2 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n text,\n config.constraintIndicators,\n \"constraintCount\",\n \"constraints\",\n { low: 1, high: 3 },\n { none: 0, low: 0.3, high: 0.7 },\n ),\n scoreKeywordMatch(\n text,\n config.outputFormatKeywords,\n \"outputFormat\",\n \"format\",\n { low: 1, high: 2 },\n { none: 0, low: 0.4, high: 0.7 },\n ),\n scoreKeywordMatch(\n text,\n config.referenceKeywords,\n \"referenceComplexity\",\n \"references\",\n { low: 1, high: 2 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n text,\n config.negationKeywords,\n \"negationComplexity\",\n \"negation\",\n { low: 2, high: 3 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n text,\n config.domainSpecificKeywords,\n \"domainSpecificity\",\n \"domain-specific\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 0.8 },\n ),\n ];\n\n // Collect signals\n const signals = dimensions.filter((d) => d.signal !== null).map((d) => d.signal!);\n\n // Compute weighted score\n const weights = config.dimensionWeights;\n let weightedScore = 0;\n for (const d of dimensions) {\n const w = weights[d.name] ?? 0;\n weightedScore += d.score * w;\n }\n\n // Count reasoning markers for override\n const reasoningMatches = config.reasoningKeywords.filter((kw) => text.includes(kw.toLowerCase()));\n\n // Direct reasoning override: 2+ reasoning markers = high confidence REASONING\n if (reasoningMatches.length >= 2) {\n const confidence = calibrateConfidence(\n Math.max(weightedScore, 0.3), // ensure positive for confidence calc\n config.confidenceSteepness,\n );\n return {\n score: weightedScore,\n tier: \"REASONING\",\n confidence: Math.max(confidence, 0.85),\n signals,\n };\n }\n\n // Map weighted score to tier using boundaries\n const { simpleMedium, mediumComplex, complexReasoning } = config.tierBoundaries;\n let tier: Tier;\n let distanceFromBoundary: number;\n\n if (weightedScore < simpleMedium) {\n tier = \"SIMPLE\";\n distanceFromBoundary = simpleMedium - weightedScore;\n } else if (weightedScore < mediumComplex) {\n tier = \"MEDIUM\";\n distanceFromBoundary = Math.min(weightedScore - simpleMedium, mediumComplex - weightedScore);\n } else if (weightedScore < complexReasoning) {\n tier = \"COMPLEX\";\n distanceFromBoundary = Math.min(\n weightedScore - mediumComplex,\n complexReasoning - weightedScore,\n );\n } else {\n tier = \"REASONING\";\n distanceFromBoundary = weightedScore - complexReasoning;\n }\n\n // Calibrate confidence via sigmoid of distance from nearest boundary\n const confidence = calibrateConfidence(distanceFromBoundary, config.confidenceSteepness);\n\n // If confidence is below threshold → ambiguous\n if (confidence < config.confidenceThreshold) {\n return { score: weightedScore, tier: null, confidence, signals };\n }\n\n return { score: weightedScore, tier, confidence, signals };\n}\n\n/**\n * Sigmoid confidence calibration.\n * Maps distance from tier boundary to [0.5, 1.0] confidence range.\n */\nfunction calibrateConfidence(distance: number, steepness: number): number {\n return 1 / (1 + Math.exp(-steepness * distance));\n}\n","/**\n * Tier → Model Selection\n *\n * Maps a classification tier to the cheapest capable model.\n * Builds RoutingDecision metadata with cost estimates and savings.\n */\n\nimport type { Tier, TierConfig, RoutingDecision } from \"./types.js\";\n\nexport type ModelPricing = {\n inputPrice: number; // per 1M tokens\n outputPrice: number; // per 1M tokens\n};\n\n/**\n * Select the primary model for a tier and build the RoutingDecision.\n */\nexport function selectModel(\n tier: Tier,\n confidence: number,\n method: \"rules\" | \"llm\",\n reasoning: string,\n tierConfigs: Record<Tier, TierConfig>,\n modelPricing: Map<string, ModelPricing>,\n estimatedInputTokens: number,\n maxOutputTokens: number,\n): RoutingDecision {\n const tierConfig = tierConfigs[tier];\n const model = tierConfig.primary;\n const pricing = modelPricing.get(model);\n\n const inputCost = pricing ? (estimatedInputTokens / 1_000_000) * pricing.inputPrice : 0;\n const outputCost = pricing ? (maxOutputTokens / 1_000_000) * pricing.outputPrice : 0;\n const costEstimate = inputCost + outputCost;\n\n // Baseline: what Claude Opus would cost (the premium default)\n const opusPricing = modelPricing.get(\"anthropic/claude-opus-4\");\n const baselineInput = opusPricing\n ? (estimatedInputTokens / 1_000_000) * opusPricing.inputPrice\n : 0;\n const baselineOutput = opusPricing ? (maxOutputTokens / 1_000_000) * opusPricing.outputPrice : 0;\n const baselineCost = baselineInput + baselineOutput;\n\n const savings = baselineCost > 0 ? Math.max(0, (baselineCost - costEstimate) / baselineCost) : 0;\n\n return {\n model,\n tier,\n confidence,\n method,\n reasoning,\n costEstimate,\n baselineCost,\n savings,\n };\n}\n\n/**\n * Get the ordered fallback chain for a tier: [primary, ...fallbacks].\n */\nexport function getFallbackChain(tier: Tier, tierConfigs: Record<Tier, TierConfig>): string[] {\n const config = tierConfigs[tier];\n return [config.primary, ...config.fallback];\n}\n","/**\n * Default Routing Config\n *\n * All routing parameters as a TypeScript constant.\n * Operators override via openclaw.yaml plugin config.\n *\n * Scoring uses 14 weighted dimensions with sigmoid confidence calibration.\n */\n\nimport type { RoutingConfig } from \"./types.js\";\n\nexport const DEFAULT_ROUTING_CONFIG: RoutingConfig = {\n version: \"2.0\",\n\n classifier: {\n llmModel: \"google/gemini-2.5-flash\",\n llmMaxTokens: 10,\n llmTemperature: 0,\n promptTruncationChars: 500,\n cacheTtlMs: 3_600_000, // 1 hour\n },\n\n scoring: {\n tokenCountThresholds: { simple: 50, complex: 500 },\n codeKeywords: [\n \"function\",\n \"class\",\n \"import\",\n \"def\",\n \"SELECT\",\n \"async\",\n \"await\",\n \"const\",\n \"let\",\n \"var\",\n \"return\",\n \"```\",\n ],\n reasoningKeywords: [\n \"prove\",\n \"theorem\",\n \"derive\",\n \"step by step\",\n \"chain of thought\",\n \"formally\",\n \"mathematical\",\n \"proof\",\n \"logically\",\n ],\n simpleKeywords: [\n \"what is\",\n \"define\",\n \"translate\",\n \"hello\",\n \"yes or no\",\n \"capital of\",\n \"how old\",\n \"who is\",\n \"when was\",\n ],\n technicalKeywords: [\n \"algorithm\",\n \"optimize\",\n \"architecture\",\n \"distributed\",\n \"kubernetes\",\n \"microservice\",\n \"database\",\n \"infrastructure\",\n ],\n creativeKeywords: [\"story\", \"poem\", \"compose\", \"brainstorm\", \"creative\", \"imagine\", \"write a\"],\n\n // New dimension keyword lists\n imperativeVerbs: [\n \"build\",\n \"create\",\n \"implement\",\n \"design\",\n \"develop\",\n \"construct\",\n \"generate\",\n \"deploy\",\n \"configure\",\n \"set up\",\n ],\n constraintIndicators: [\n \"under\",\n \"at most\",\n \"at least\",\n \"within\",\n \"no more than\",\n \"o(\",\n \"maximum\",\n \"minimum\",\n \"limit\",\n \"budget\",\n ],\n outputFormatKeywords: [\n \"json\",\n \"yaml\",\n \"xml\",\n \"table\",\n \"csv\",\n \"markdown\",\n \"schema\",\n \"format as\",\n \"structured\",\n ],\n referenceKeywords: [\n \"above\",\n \"below\",\n \"previous\",\n \"following\",\n \"the docs\",\n \"the api\",\n \"the code\",\n \"earlier\",\n \"attached\",\n ],\n negationKeywords: [\n \"don't\",\n \"do not\",\n \"avoid\",\n \"never\",\n \"without\",\n \"except\",\n \"exclude\",\n \"no longer\",\n ],\n domainSpecificKeywords: [\n \"quantum\",\n \"fpga\",\n \"vlsi\",\n \"risc-v\",\n \"asic\",\n \"photonics\",\n \"genomics\",\n \"proteomics\",\n \"topological\",\n \"homomorphic\",\n \"zero-knowledge\",\n \"lattice-based\",\n ],\n\n // Dimension weights (sum to 1.0)\n dimensionWeights: {\n tokenCount: 0.08,\n codePresence: 0.15,\n reasoningMarkers: 0.18,\n technicalTerms: 0.1,\n creativeMarkers: 0.05,\n simpleIndicators: 0.12,\n multiStepPatterns: 0.12,\n questionComplexity: 0.05,\n imperativeVerbs: 0.03,\n constraintCount: 0.04,\n outputFormat: 0.03,\n referenceComplexity: 0.02,\n negationComplexity: 0.01,\n domainSpecificity: 0.02,\n },\n\n // Tier boundaries on weighted score axis\n tierBoundaries: {\n simpleMedium: 0.0,\n mediumComplex: 0.15,\n complexReasoning: 0.25,\n },\n\n // Sigmoid steepness for confidence calibration\n confidenceSteepness: 12,\n // Below this confidence → ambiguous (null tier)\n confidenceThreshold: 0.7,\n },\n\n tiers: {\n SIMPLE: {\n primary: \"google/gemini-2.5-flash\",\n fallback: [\"deepseek/deepseek-chat\", \"openai/gpt-4o-mini\"],\n },\n MEDIUM: {\n primary: \"deepseek/deepseek-chat\",\n fallback: [\"google/gemini-2.5-flash\", \"openai/gpt-4o-mini\"],\n },\n COMPLEX: {\n primary: \"anthropic/claude-opus-4\",\n fallback: [\"anthropic/claude-sonnet-4\", \"openai/gpt-4o\"],\n },\n REASONING: {\n primary: \"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, type ModelPricing } from \"./selector.js\";\n\nexport type RouterOptions = {\n config: RoutingConfig;\n modelPricing: Map<string, ModelPricing>;\n};\n\n/**\n * Route a request to the cheapest capable model.\n *\n * 1. Check overrides (large context, structured output)\n * 2. Run rule-based classifier (14 weighted dimensions, <1ms)\n * 3. If ambiguous, default to configurable tier (no external API calls)\n * 4. Select model for tier\n * 5. Return RoutingDecision with metadata\n */\nexport function route(\n prompt: string,\n systemPrompt: string | undefined,\n maxOutputTokens: number,\n options: RouterOptions,\n): RoutingDecision {\n const { config, modelPricing } = options;\n\n // Estimate input tokens (~4 chars per token)\n const fullText = `${systemPrompt ?? \"\"} ${prompt}`;\n const estimatedTokens = Math.ceil(fullText.length / 4);\n\n // --- Override: large context → force COMPLEX ---\n if (estimatedTokens > config.overrides.maxTokensForceComplex) {\n return selectModel(\n \"COMPLEX\",\n 0.95,\n \"rules\",\n `Input exceeds ${config.overrides.maxTokensForceComplex} tokens`,\n config.tiers,\n modelPricing,\n estimatedTokens,\n maxOutputTokens,\n );\n }\n\n // Structured output detection\n const hasStructuredOutput = systemPrompt ? /json|structured|schema/i.test(systemPrompt) : false;\n\n // --- Rule-based classification ---\n const ruleResult = classifyByRules(prompt, systemPrompt, estimatedTokens, config.scoring);\n\n let tier: Tier;\n let confidence: number;\n const method: \"rules\" | \"llm\" = \"rules\";\n let reasoning = `score=${ruleResult.score} | ${ruleResult.signals.join(\", \")}`;\n\n if (ruleResult.tier !== null) {\n tier = ruleResult.tier;\n confidence = ruleResult.confidence;\n } else {\n // Ambiguous — default to configurable tier (no external API call)\n tier = config.overrides.ambiguousDefaultTier;\n confidence = 0.5;\n reasoning += ` | ambiguous -> default: ${tier}`;\n }\n\n // Apply structured output minimum tier\n if (hasStructuredOutput) {\n const tierRank: Record<Tier, number> = { SIMPLE: 0, MEDIUM: 1, COMPLEX: 2, REASONING: 3 };\n const minTier = config.overrides.structuredOutputMinTier;\n if (tierRank[tier] < tierRank[minTier]) {\n reasoning += ` | upgraded to ${minTier} (structured output)`;\n tier = minTier;\n }\n }\n\n return selectModel(\n tier,\n confidence,\n method,\n reasoning,\n config.tiers,\n modelPricing,\n estimatedTokens,\n maxOutputTokens,\n );\n}\n\nexport { getFallbackChain } from \"./selector.js\";\nexport { DEFAULT_ROUTING_CONFIG } from \"./config.js\";\nexport type { RoutingDecision, Tier, RoutingConfig } from \"./types.js\";\nexport type { ModelPricing } from \"./selector.js\";\n","/**\n * Usage Logger\n *\n * Logs every LLM request as a JSON line to a daily log file.\n * Files: ~/.openclaw/blockrun/logs/usage-YYYY-MM-DD.jsonl\n *\n * MVP: append-only JSON lines. No rotation, no cleanup.\n * Logging never breaks the request flow — all errors are swallowed.\n */\n\nimport { appendFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\nexport type UsageEntry = {\n timestamp: string;\n model: string;\n cost: number;\n latencyMs: number;\n};\n\nconst LOG_DIR = join(homedir(), \".openclaw\", \"blockrun\", \"logs\");\nlet dirReady = false;\n\nasync function ensureDir(): Promise<void> {\n if (dirReady) return;\n await mkdir(LOG_DIR, { recursive: true });\n dirReady = true;\n}\n\n/**\n * Log a usage entry as a JSON line.\n */\nexport async function logUsage(entry: UsageEntry): Promise<void> {\n try {\n await ensureDir();\n const date = entry.timestamp.slice(0, 10); // YYYY-MM-DD\n const file = join(LOG_DIR, `usage-${date}.jsonl`);\n await appendFile(file, JSON.stringify(entry) + \"\\n\");\n } catch {\n // Never break the request flow\n }\n}\n","/**\n * Request Deduplication\n *\n * Prevents double-charging when OpenClaw retries a request after timeout.\n * Tracks in-flight requests and caches completed responses for a short TTL.\n */\n\nimport { createHash } from \"node:crypto\";\n\nexport type CachedResponse = {\n status: number;\n headers: Record<string, string>;\n body: Buffer;\n completedAt: number;\n};\n\ntype InflightEntry = {\n resolve: (result: CachedResponse) => void;\n waiters: Promise<CachedResponse>[];\n};\n\nconst DEFAULT_TTL_MS = 30_000; // 30 seconds\nconst MAX_BODY_SIZE = 1_048_576; // 1MB\n\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(\n new Promise<CachedResponse>((r) => {\n const orig = entry.resolve;\n entry.resolve = (result) => {\n orig(result);\n resolve(result);\n r(result);\n };\n }),\n );\n });\n return promise;\n }\n\n /** Mark a request as in-flight. */\n markInflight(key: string): void {\n this.inflight.set(key, {\n resolve: () => {},\n waiters: [],\n });\n }\n\n /** Complete an in-flight request — cache result and notify waiters. */\n complete(key: string, result: CachedResponse): void {\n // Only cache responses within size limit\n if (result.body.length <= MAX_BODY_SIZE) {\n this.completed.set(key, result);\n }\n\n const entry = this.inflight.get(key);\n if (entry) {\n entry.resolve(result);\n this.inflight.delete(key);\n }\n\n this.prune();\n }\n\n /** Remove an in-flight entry on error (don't cache failures). */\n removeInflight(key: string): void {\n this.inflight.delete(key);\n }\n\n /** Prune expired completed entries. */\n private prune(): void {\n const now = Date.now();\n for (const [key, entry] of this.completed) {\n if (now - entry.completedAt > this.ttlMs) {\n this.completed.delete(key);\n }\n }\n }\n}\n","/**\n * Balance Monitor for ClawRouter\n *\n * Monitors USDC balance on Base network with intelligent caching.\n * Provides pre-request balance checks to prevent failed payments.\n *\n * Caching Strategy:\n * - TTL: 30 seconds (balance is cached to avoid excessive RPC calls)\n * - Optimistic deduction: after successful payment, subtract estimated cost from cache\n * - Invalidation: on payment failure, immediately refresh from RPC\n */\n\nimport { createPublicClient, http, erc20Abi } from \"viem\";\nimport { base } from \"viem/chains\";\nimport { RpcError } from \"./errors.js\";\n\n/** USDC contract address on Base mainnet */\nconst USDC_BASE = \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\" as const;\n\n/** Cache TTL in milliseconds (30 seconds) */\nconst CACHE_TTL_MS = 30_000;\n\n/** Balance thresholds in USDC smallest unit (6 decimals) */\nexport const BALANCE_THRESHOLDS = {\n /** Low balance warning threshold: $1.00 */\n LOW_BALANCE_MICROS: 1_000_000n,\n /** Effectively zero threshold: $0.0001 (covers dust/rounding) */\n ZERO_THRESHOLD: 100n,\n} as const;\n\n/** Balance information returned by checkBalance() */\nexport type BalanceInfo = {\n /** Raw balance in USDC smallest unit (6 decimals) */\n balance: bigint;\n /** Formatted balance as \"$X.XX\" */\n balanceUSD: string;\n /** True if balance < $1.00 */\n isLow: boolean;\n /** True if balance < $0.0001 (effectively zero) */\n isEmpty: boolean;\n /** Wallet address for funding instructions */\n walletAddress: string;\n};\n\n/** Result from checkSufficient() */\nexport type SufficiencyResult = {\n /** True if balance >= estimated cost */\n sufficient: boolean;\n /** Current balance info */\n info: BalanceInfo;\n /** If insufficient, the shortfall as \"$X.XX\" */\n shortfall?: string;\n};\n\n/**\n * Monitors USDC balance on Base network.\n *\n * Usage:\n * const monitor = new BalanceMonitor(\"0x...\");\n * const info = await monitor.checkBalance();\n * if (info.isLow) console.warn(\"Low balance!\");\n */\nexport class BalanceMonitor {\n private readonly client;\n private readonly walletAddress: `0x${string}`;\n\n /** Cached balance (null = not yet fetched) */\n private cachedBalance: bigint | null = null;\n /** Timestamp when cache was last updated */\n private cachedAt = 0;\n\n constructor(walletAddress: string) {\n this.walletAddress = walletAddress as `0x${string}`;\n this.client = createPublicClient({\n chain: base,\n transport: http(undefined, {\n timeout: 10_000, // 10 second timeout to prevent hanging on slow RPC\n }),\n });\n }\n\n /**\n * Check current USDC balance.\n * Uses cache if valid, otherwise fetches from RPC.\n */\n async checkBalance(): Promise<BalanceInfo> {\n const now = Date.now();\n\n // Use cache if valid\n if (this.cachedBalance !== null && now - this.cachedAt < CACHE_TTL_MS) {\n return this.buildInfo(this.cachedBalance);\n }\n\n // Fetch from RPC\n const balance = await this.fetchBalance();\n this.cachedBalance = balance;\n this.cachedAt = now;\n\n return this.buildInfo(balance);\n }\n\n /**\n * Check if balance is sufficient for an estimated cost.\n *\n * @param estimatedCostMicros - Estimated cost in USDC smallest unit (6 decimals)\n */\n async checkSufficient(estimatedCostMicros: bigint): Promise<SufficiencyResult> {\n const info = await this.checkBalance();\n\n if (info.balance >= estimatedCostMicros) {\n return { sufficient: true, info };\n }\n\n const shortfall = estimatedCostMicros - info.balance;\n return {\n sufficient: false,\n info,\n shortfall: this.formatUSDC(shortfall),\n };\n }\n\n /**\n * Optimistically deduct estimated cost from cached balance.\n * Call this after a successful payment to keep cache accurate.\n *\n * @param amountMicros - Amount to deduct in USDC smallest unit\n */\n deductEstimated(amountMicros: bigint): void {\n if (this.cachedBalance !== null && this.cachedBalance >= amountMicros) {\n this.cachedBalance -= amountMicros;\n }\n }\n\n /**\n * Invalidate cache, forcing next checkBalance() to fetch from RPC.\n * Call this after a payment failure to get accurate balance.\n */\n invalidate(): void {\n this.cachedBalance = null;\n this.cachedAt = 0;\n }\n\n /**\n * Force refresh balance from RPC (ignores cache).\n */\n async refresh(): Promise<BalanceInfo> {\n this.invalidate();\n return this.checkBalance();\n }\n\n /**\n * Format USDC amount (in micros) as \"$X.XX\".\n */\n formatUSDC(amountMicros: bigint): string {\n // USDC has 6 decimals\n const dollars = Number(amountMicros) / 1_000_000;\n return `$${dollars.toFixed(2)}`;\n }\n\n /**\n * Get the wallet address being monitored.\n */\n getWalletAddress(): string {\n return this.walletAddress;\n }\n\n /** Fetch balance from RPC */\n private async fetchBalance(): Promise<bigint> {\n try {\n const balance = await this.client.readContract({\n address: USDC_BASE,\n abi: erc20Abi,\n functionName: \"balanceOf\",\n args: [this.walletAddress],\n });\n return balance;\n } catch (error) {\n // Throw typed error instead of silently returning 0\n // This allows callers to distinguish \"node down\" from \"wallet empty\"\n throw new RpcError(error instanceof Error ? error.message : \"Unknown error\", error);\n }\n }\n\n /** Build BalanceInfo from raw balance */\n private buildInfo(balance: bigint): BalanceInfo {\n return {\n balance,\n balanceUSD: this.formatUSDC(balance),\n isLow: balance < BALANCE_THRESHOLDS.LOW_BALANCE_MICROS,\n isEmpty: balance < BALANCE_THRESHOLDS.ZERO_THRESHOLD,\n walletAddress: this.walletAddress,\n };\n }\n}\n","/**\n * Typed Error Classes for ClawRouter\n *\n * Provides structured errors for balance-related failures with\n * all necessary information for user-friendly error messages.\n */\n\n/**\n * Thrown when wallet has insufficient USDC balance for a request.\n */\nexport class InsufficientFundsError extends Error {\n readonly code = \"INSUFFICIENT_FUNDS\" as const;\n readonly currentBalanceUSD: string;\n readonly requiredUSD: string;\n readonly walletAddress: string;\n\n constructor(opts: { currentBalanceUSD: string; requiredUSD: string; walletAddress: string }) {\n super(\n `Insufficient USDC balance. Current: ${opts.currentBalanceUSD}, Required: ${opts.requiredUSD}. Fund wallet: ${opts.walletAddress}`,\n );\n this.name = \"InsufficientFundsError\";\n this.currentBalanceUSD = opts.currentBalanceUSD;\n this.requiredUSD = opts.requiredUSD;\n this.walletAddress = opts.walletAddress;\n }\n}\n\n/**\n * Thrown when wallet has no USDC balance (or effectively zero).\n */\nexport class EmptyWalletError extends Error {\n readonly code = \"EMPTY_WALLET\" as const;\n readonly walletAddress: string;\n\n constructor(walletAddress: string) {\n super(`No USDC balance. Fund wallet to use ClawRouter: ${walletAddress}`);\n this.name = \"EmptyWalletError\";\n this.walletAddress = walletAddress;\n }\n}\n\n/**\n * Type guard to check if an error is InsufficientFundsError.\n */\nexport function isInsufficientFundsError(error: unknown): error is InsufficientFundsError {\n return error instanceof Error && (error as InsufficientFundsError).code === \"INSUFFICIENT_FUNDS\";\n}\n\n/**\n * Type guard to check if an error is EmptyWalletError.\n */\nexport function isEmptyWalletError(error: unknown): error is EmptyWalletError {\n return error instanceof Error && (error as EmptyWalletError).code === \"EMPTY_WALLET\";\n}\n\n/**\n * Type guard to check if an error is a balance-related error.\n */\nexport function isBalanceError(error: unknown): error is InsufficientFundsError | EmptyWalletError {\n return isInsufficientFundsError(error) || isEmptyWalletError(error);\n}\n\n/**\n * Thrown when RPC call fails (network error, node down, etc).\n * Distinguishes infrastructure failures from actual empty wallets.\n */\nexport class RpcError extends Error {\n readonly code = \"RPC_ERROR\" as const;\n readonly originalError: unknown;\n\n constructor(message: string, originalError?: unknown) {\n super(`RPC error: ${message}. Check network connectivity.`);\n this.name = \"RpcError\";\n this.originalError = originalError;\n }\n}\n\n/**\n * Type guard to check if an error is RpcError.\n */\nexport function isRpcError(error: unknown): error is RpcError {\n return error instanceof Error && (error as RpcError).code === \"RPC_ERROR\";\n}\n","/**\n * 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<{\n key: string;\n address: string;\n source: \"saved\" | \"env\" | \"generated\";\n}> {\n // 1. Previously saved wallet\n const saved = await loadSavedWallet();\n if (saved) {\n const account = privateKeyToAccount(saved as `0x${string}`);\n return { key: saved, address: account.address, source: \"saved\" };\n }\n\n // 2. Environment variable\n const envKey = process.env.BLOCKRUN_WALLET_KEY;\n if (typeof envKey === \"string\" && envKey.startsWith(\"0x\") && envKey.length === 66) {\n const account = privateKeyToAccount(envKey as `0x${string}`);\n return { key: envKey, address: account.address, source: \"env\" };\n }\n\n // 3. Auto-generate\n const { key, address } = await generateAndSaveWallet();\n return { key, address, source: \"generated\" };\n}\n\n/**\n * Auth method: operator enters their wallet private key directly.\n */\nexport const walletKeyAuth: ProviderAuthMethod = {\n id: \"wallet-key\",\n label: \"Wallet Private Key\",\n hint: \"Enter your EVM wallet private key (0x...) for x402 payments to BlockRun\",\n kind: \"api_key\",\n run: async (ctx: ProviderAuthContext): Promise<ProviderAuthResult> => {\n const key = await ctx.prompter.text({\n message: \"Enter your wallet private key (0x...)\",\n validate: (value: string) => {\n const trimmed = value.trim();\n if (!trimmed.startsWith(\"0x\")) return \"Key must start with 0x\";\n if (trimmed.length !== 66) return \"Key must be 66 characters (0x + 64 hex)\";\n if (!/^0x[0-9a-fA-F]{64}$/.test(trimmed)) return \"Key must be valid hex\";\n return undefined;\n },\n });\n\n if (!key || typeof key !== \"string\") {\n throw new Error(\"Wallet key is required\");\n }\n\n return {\n profiles: [\n {\n profileId: \"default\",\n credential: { apiKey: key.trim() },\n },\n ],\n notes: [\n \"Wallet key stored securely in OpenClaw credentials.\",\n \"Your wallet signs x402 USDC payments on Base for each LLM call.\",\n \"Fund your wallet with USDC on Base to start using BlockRun models.\",\n ],\n };\n },\n};\n\n/**\n * Auth method: read wallet key from BLOCKRUN_WALLET_KEY environment variable.\n */\nexport const envKeyAuth: ProviderAuthMethod = {\n id: \"env-key\",\n label: \"Environment Variable\",\n hint: \"Use BLOCKRUN_WALLET_KEY environment variable\",\n kind: \"api_key\",\n run: async (): Promise<ProviderAuthResult> => {\n const key = process.env.BLOCKRUN_WALLET_KEY;\n\n if (!key) {\n throw new Error(\n \"BLOCKRUN_WALLET_KEY environment variable is not set. \" +\n \"Set it to your EVM wallet private key (0x...).\",\n );\n }\n\n return {\n profiles: [\n {\n profileId: \"default\",\n credential: { apiKey: key.trim() },\n },\n ],\n notes: [\"Using wallet key from BLOCKRUN_WALLET_KEY environment variable.\"],\n };\n },\n};\n","/**\n * @blockrun/clawrouter\n *\n * Smart LLM router for OpenClaw — 30+ models, x402 micropayments, 78% cost savings.\n * Routes each request to the cheapest model that can handle it.\n *\n * Usage:\n * # Install the plugin\n * openclaw 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 models set blockrun/auto\n *\n * # Or use any specific BlockRun model\n * openclaw models set openai/gpt-5.2\n */\n\nimport type { OpenClawPluginDefinition, OpenClawPluginApi } from \"./types.js\";\nimport { blockrunProvider, setActiveProxy } from \"./provider.js\";\nimport { startProxy } from \"./proxy.js\";\nimport { resolveOrGenerateWalletKey } from \"./auth.js\";\nimport type { RoutingConfig } from \"./router/index.js\";\nimport { BalanceMonitor } from \"./balance.js\";\nimport { OPENCLAW_MODELS } from \"./models.js\";\nimport { readFileSync, writeFileSync, existsSync, readdirSync, mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\n/**\n * Detect if we're running in shell completion mode.\n * When `openclaw completion --shell zsh` runs, it loads plugins but only needs\n * the completion script output - any stdout logging pollutes the script and\n * causes zsh to interpret colored text like `[plugins]` as glob patterns.\n */\nfunction isCompletionMode(): boolean {\n const args = process.argv;\n // Check for: openclaw completion --shell <shell>\n // argv[0] = node/bun, argv[1] = openclaw, argv[2] = completion\n return args.some((arg, i) => arg === \"completion\" && i >= 1 && i <= 3);\n}\n\n/**\n * Inject BlockRun models config into OpenClaw config file.\n * This is required because registerProvider() alone doesn't make models available.\n */\nfunction injectModelsConfig(logger: { info: (msg: string) => void }): void {\n const configPath = join(homedir(), \".openclaw\", \"openclaw.json\");\n if (!existsSync(configPath)) {\n logger.info(\"OpenClaw config not found, skipping models injection\");\n return;\n }\n\n try {\n const config = JSON.parse(readFileSync(configPath, \"utf-8\"));\n\n // Check if already configured\n if (config.models?.providers?.blockrun) {\n return; // Already configured\n }\n\n // Inject models config\n if (!config.models) config.models = {};\n if (!config.models.providers) config.models.providers = {};\n\n config.models.providers.blockrun = {\n baseUrl: \"http://127.0.0.1:8402/v1\",\n api: \"openai-completions\",\n models: OPENCLAW_MODELS,\n };\n\n writeFileSync(configPath, JSON.stringify(config, null, 2));\n logger.info(\"Injected BlockRun models into OpenClaw config\");\n } catch {\n // Silently fail — config injection is best-effort\n }\n}\n\n/**\n * Inject dummy auth profile for BlockRun into agent auth stores.\n * OpenClaw's agent system looks for auth credentials even if provider has auth: [].\n * We inject a placeholder so the lookup succeeds (proxy handles real auth internally).\n */\nfunction injectAuthProfile(logger: { info: (msg: string) => void }): void {\n const agentsDir = join(homedir(), \".openclaw\", \"agents\");\n\n // Create agents directory if it doesn't exist\n if (!existsSync(agentsDir)) {\n try {\n mkdirSync(agentsDir, { recursive: true });\n } catch (err) {\n logger.info(\n `Could not create agents dir: ${err instanceof Error ? err.message : String(err)}`,\n );\n return;\n }\n }\n\n try {\n // Find all agent directories\n let agents = readdirSync(agentsDir, { withFileTypes: true })\n .filter((d) => d.isDirectory())\n .map((d) => d.name);\n\n // Always ensure \"main\" agent has auth (most common agent)\n if (!agents.includes(\"main\")) {\n agents = [\"main\", ...agents];\n }\n\n for (const agentId of agents) {\n const authDir = join(agentsDir, agentId, \"agent\");\n const authPath = join(authDir, \"auth-profiles.json\");\n\n // Create agent dir if needed\n if (!existsSync(authDir)) {\n try {\n mkdirSync(authDir, { recursive: true });\n } catch {\n continue; // Skip if we can't create the dir\n }\n }\n\n // Load or create auth-profiles.json with correct OpenClaw format\n // Format: { version: 1, profiles: { \"provider:profileId\": { type, provider, key } } }\n let store: { version: number; profiles: Record<string, unknown> } = { version: 1, profiles: {} };\n if (existsSync(authPath)) {\n try {\n const existing = JSON.parse(readFileSync(authPath, \"utf-8\"));\n // Check if valid OpenClaw format (has version and profiles)\n if (existing.version && existing.profiles) {\n store = existing;\n }\n // Old format without version/profiles is discarded and recreated\n } catch {\n // Invalid JSON, use fresh store\n }\n }\n\n // Check if blockrun auth already exists (OpenClaw format: profiles[\"provider:profileId\"])\n const profileKey = \"blockrun:default\";\n if (store.profiles[profileKey]) {\n continue; // Already configured\n }\n\n // Inject placeholder auth for blockrun (OpenClaw format)\n // The proxy handles real x402 auth internally, this just satisfies OpenClaw's lookup\n store.profiles[profileKey] = {\n type: \"api_key\",\n provider: \"blockrun\",\n key: \"x402-proxy-handles-auth\",\n };\n\n try {\n writeFileSync(authPath, JSON.stringify(store, null, 2));\n logger.info(`Injected BlockRun auth profile for agent: ${agentId}`);\n } catch (err) {\n logger.info(\n `Could not inject auth for ${agentId}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n } catch (err) {\n logger.info(`Auth injection failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n}\n\n/**\n * Start the x402 proxy in the background.\n * Called from register() because OpenClaw's loader only invokes register(),\n * treating activate() as an alias (def.register ?? def.activate).\n */\nasync function startProxyInBackground(api: OpenClawPluginApi): Promise<void> {\n // Resolve wallet key: saved file → env var → auto-generate\n const { key: walletKey, address, source } = await resolveOrGenerateWalletKey();\n\n // Log wallet source\n if (source === \"generated\") {\n api.logger.info(`Generated new wallet: ${address}`);\n api.logger.info(`Fund with USDC on Base to start using ClawRouter.`);\n } else if (source === \"saved\") {\n api.logger.info(`Using saved wallet: ${address}`);\n } else {\n api.logger.info(`Using wallet from BLOCKRUN_WALLET_KEY: ${address}`);\n }\n\n // --- Startup balance check ---\n const startupMonitor = new BalanceMonitor(address);\n try {\n const startupBalance = await startupMonitor.checkBalance();\n if (startupBalance.isEmpty) {\n api.logger.warn(`[!] No USDC balance. Fund wallet to use ClawRouter: ${address}`);\n } else if (startupBalance.isLow) {\n api.logger.warn(\n `[!] Low balance: ${startupBalance.balanceUSD} remaining. Fund wallet: ${address}`,\n );\n } else {\n api.logger.info(`Wallet balance: ${startupBalance.balanceUSD}`);\n }\n } catch (err) {\n api.logger.warn(\n `Could not check wallet balance: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n // Resolve routing config overrides from plugin config\n const routingConfig = api.pluginConfig?.routing as Partial<RoutingConfig> | undefined;\n\n const proxy = await startProxy({\n walletKey,\n routingConfig,\n onReady: (port) => {\n api.logger.info(`BlockRun x402 proxy listening on port ${port}`);\n },\n onError: (error) => {\n api.logger.error(`BlockRun proxy error: ${error.message}`);\n },\n onRouted: (decision) => {\n const cost = decision.costEstimate.toFixed(4);\n const saved = (decision.savings * 100).toFixed(0);\n api.logger.info(`${decision.model} $${cost} (saved ${saved}%)`);\n },\n onLowBalance: (info) => {\n api.logger.warn(`[!] Low balance: ${info.balanceUSD}. Fund wallet: ${info.walletAddress}`);\n },\n onInsufficientFunds: (info) => {\n api.logger.error(\n `[!] Insufficient funds. Balance: ${info.balanceUSD}, Needed: ${info.requiredUSD}. Fund wallet: ${info.walletAddress}`,\n );\n },\n });\n\n setActiveProxy(proxy);\n 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.19\",\n\n register(api: OpenClawPluginApi) {\n // Skip heavy initialization in completion mode — only completion script is needed\n // Logging to stdout during completion pollutes the script and causes zsh errors\n if (isCompletionMode()) {\n api.registerProvider(blockrunProvider);\n return;\n }\n\n // Register BlockRun as a provider (sync — available immediately)\n api.registerProvider(blockrunProvider);\n\n // Inject models config into OpenClaw config file\n // This persists the config so models are recognized on restart\n injectModelsConfig(api.logger);\n\n // Inject dummy auth profiles into agent auth stores\n // OpenClaw's agent system looks for auth even if provider has auth: []\n injectAuthProfile(api.logger);\n\n // Also set runtime config for immediate availability\n if (!api.config.models) {\n api.config.models = { providers: {} };\n }\n if (!api.config.models.providers) {\n api.config.models.providers = {};\n }\n api.config.models.providers.blockrun = {\n baseUrl: \"http://127.0.0.1:8402/v1\",\n api: \"openai-completions\",\n models: OPENCLAW_MODELS,\n };\n\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\nexport default plugin;\n\n// Re-export for programmatic use\nexport { startProxy } from \"./proxy.js\";\nexport type { ProxyOptions, ProxyHandle, LowBalanceInfo, InsufficientFundsInfo } from \"./proxy.js\";\nexport { blockrunProvider } from \"./provider.js\";\nexport { OPENCLAW_MODELS, BLOCKRUN_MODELS, buildProviderModels } from \"./models.js\";\nexport { route, DEFAULT_ROUTING_CONFIG } from \"./router/index.js\";\nexport type { RoutingDecision, RoutingConfig, Tier } from \"./router/index.js\";\nexport { logUsage } from \"./logger.js\";\nexport type { UsageEntry } from \"./logger.js\";\nexport { RequestDeduplicator } from \"./dedup.js\";\nexport type { CachedResponse } from \"./dedup.js\";\nexport { PaymentCache } from \"./payment-cache.js\";\nexport type { CachedPaymentParams } from \"./payment-cache.js\";\nexport { createPaymentFetch } from \"./x402.js\";\nexport type { PreAuthParams, PaymentFetchResult } from \"./x402.js\";\nexport { BalanceMonitor, BALANCE_THRESHOLDS } from \"./balance.js\";\nexport type { BalanceInfo, SufficiencyResult } from \"./balance.js\";\nexport {\n InsufficientFundsError,\n EmptyWalletError,\n RpcError,\n isInsufficientFundsError,\n isEmptyWalletError,\n isBalanceError,\n isRpcError,\n} from \"./errors.js\";\nexport { fetchWithRetry, isRetryable, DEFAULT_RETRY_CONFIG } from \"./retry.js\";\nexport type { RetryConfig } from \"./retry.js\";\n","/**\n * Retry Logic for ClawRouter\n *\n * Provides fetch wrapper with exponential backoff for transient errors.\n * Retries on 429 (rate limit), 502, 503, 504 (server errors).\n */\n\n/** Configuration for retry behavior */\nexport type RetryConfig = {\n /** Maximum number of retries (default: 2) */\n maxRetries: number;\n /** Base delay in ms for exponential backoff (default: 500) */\n baseDelayMs: number;\n /** HTTP status codes that trigger a retry (default: [429, 502, 503, 504]) */\n retryableCodes: number[];\n};\n\n/** Default retry configuration */\nexport const DEFAULT_RETRY_CONFIG: RetryConfig = {\n maxRetries: 2,\n baseDelayMs: 500,\n retryableCodes: [429, 502, 503, 504],\n};\n\n/** Sleep for a given number of milliseconds */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Wrap a fetch-like function with retry logic and exponential backoff.\n *\n * @param fetchFn - The fetch function to wrap (can be standard fetch or x402 payFetch)\n * @param url - URL to fetch\n * @param init - Fetch init options\n * @param config - Retry configuration (optional, uses defaults)\n * @returns Response from successful fetch or last failed attempt\n *\n * @example\n * ```typescript\n * const response = await fetchWithRetry(\n * fetch,\n * \"https://api.example.com/endpoint\",\n * { method: \"POST\", body: JSON.stringify(data) },\n * { maxRetries: 3 }\n * );\n * ```\n */\nexport async function fetchWithRetry(\n fetchFn: (url: string, init?: RequestInit) => Promise<Response>,\n url: string,\n init?: RequestInit,\n config?: Partial<RetryConfig>,\n): Promise<Response> {\n const cfg: RetryConfig = {\n ...DEFAULT_RETRY_CONFIG,\n ...config,\n };\n\n let lastError: Error | undefined;\n let lastResponse: Response | undefined;\n\n for (let attempt = 0; attempt <= cfg.maxRetries; attempt++) {\n try {\n const response = await fetchFn(url, init);\n\n // Success or non-retryable status — return immediately\n if (!cfg.retryableCodes.includes(response.status)) {\n return response;\n }\n\n // Retryable status — save response and maybe retry\n lastResponse = response;\n\n // Check for Retry-After header (common with 429)\n const retryAfter = response.headers.get(\"retry-after\");\n let delay: number;\n\n if (retryAfter) {\n // Retry-After can be seconds or HTTP-date\n const seconds = parseInt(retryAfter, 10);\n delay = isNaN(seconds) ? cfg.baseDelayMs * Math.pow(2, attempt) : seconds * 1000;\n } else {\n delay = cfg.baseDelayMs * Math.pow(2, attempt);\n }\n\n // Only retry if we have attempts left\n if (attempt < cfg.maxRetries) {\n await sleep(delay);\n }\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n\n // Network errors are retryable\n if (attempt < cfg.maxRetries) {\n const delay = cfg.baseDelayMs * Math.pow(2, attempt);\n await sleep(delay);\n }\n }\n }\n\n // All retries exhausted — return last response or throw last error\n if (lastResponse) {\n return lastResponse;\n }\n\n throw lastError ?? new Error(\"Max retries exceeded\");\n}\n\n/**\n * Check if an error or response indicates a retryable condition.\n */\nexport function isRetryable(\n errorOrResponse: Error | Response,\n config?: Partial<RetryConfig>,\n): boolean {\n const retryableCodes = config?.retryableCodes ?? DEFAULT_RETRY_CONFIG.retryableCodes;\n\n if (errorOrResponse instanceof Response) {\n return retryableCodes.includes(errorOrResponse.status);\n }\n\n // Network errors are generally retryable\n const message = errorOrResponse.message.toLowerCase();\n return (\n message.includes(\"network\") ||\n message.includes(\"timeout\") ||\n message.includes(\"econnreset\") ||\n message.includes(\"econnrefused\") ||\n message.includes(\"socket hang up\")\n );\n}\n"],"mappings":"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","names":["privateKeyToAccount","response","paymentHeader","confidence","DEFAULT_TTL_MS","USDC_BASE","privateKeyToAccount","mkdir","join","homedir","privateKeyToAccount","homedir","join","join","homedir"]}
|
|
1
|
+
{"version":3,"sources":["../src/models.ts","../src/provider.ts","../src/proxy.ts","../src/x402.ts","../src/payment-cache.ts","../src/router/rules.ts","../src/router/selector.ts","../src/router/config.ts","../src/router/index.ts","../src/logger.ts","../src/dedup.ts","../src/balance.ts","../src/errors.ts","../src/version.ts","../src/auth.ts","../src/index.ts","../src/retry.ts"],"sourcesContent":["/**\n * BlockRun Model Definitions for OpenClaw\n *\n * Maps BlockRun's 30+ AI models to OpenClaw's ModelDefinitionConfig format.\n * All models use the \"openai-completions\" API since BlockRun is OpenAI-compatible.\n *\n * Pricing is in USD per 1M tokens. Operators pay these rates via x402;\n * they set their own markup when reselling to end users (Phase 2).\n */\n\nimport type { ModelDefinitionConfig, ModelProviderConfig } from \"./types.js\";\n\ntype BlockRunModel = {\n id: string;\n name: string;\n inputPrice: number;\n outputPrice: number;\n contextWindow: number;\n maxOutput: number;\n reasoning?: boolean;\n vision?: boolean;\n};\n\nexport const BLOCKRUN_MODELS: BlockRunModel[] = [\n // Smart routing meta-model — proxy replaces with actual model\n {\n id: \"blockrun/auto\",\n name: \"BlockRun Smart Router\",\n inputPrice: 0,\n outputPrice: 0,\n contextWindow: 1_050_000,\n maxOutput: 128_000,\n },\n\n // OpenAI GPT-5 Family\n {\n id: \"openai/gpt-5.2\",\n name: \"GPT-5.2\",\n inputPrice: 1.75,\n outputPrice: 14.0,\n contextWindow: 400000,\n maxOutput: 128000,\n reasoning: true,\n vision: true,\n },\n {\n id: \"openai/gpt-5-mini\",\n name: \"GPT-5 Mini\",\n inputPrice: 0.25,\n outputPrice: 2.0,\n contextWindow: 200000,\n maxOutput: 65536,\n },\n {\n id: \"openai/gpt-5-nano\",\n name: \"GPT-5 Nano\",\n inputPrice: 0.05,\n outputPrice: 0.4,\n contextWindow: 128000,\n maxOutput: 32768,\n },\n {\n id: \"openai/gpt-5.2-pro\",\n name: \"GPT-5.2 Pro\",\n inputPrice: 21.0,\n outputPrice: 168.0,\n contextWindow: 400000,\n maxOutput: 128000,\n reasoning: true,\n },\n\n // OpenAI GPT-4 Family\n {\n id: \"openai/gpt-4.1\",\n name: \"GPT-4.1\",\n inputPrice: 2.0,\n outputPrice: 8.0,\n contextWindow: 128000,\n maxOutput: 16384,\n vision: true,\n },\n {\n id: \"openai/gpt-4.1-mini\",\n name: \"GPT-4.1 Mini\",\n inputPrice: 0.4,\n outputPrice: 1.6,\n contextWindow: 128000,\n maxOutput: 16384,\n },\n {\n id: \"openai/gpt-4.1-nano\",\n name: \"GPT-4.1 Nano\",\n inputPrice: 0.1,\n outputPrice: 0.4,\n contextWindow: 128000,\n maxOutput: 16384,\n },\n {\n id: \"openai/gpt-4o\",\n name: \"GPT-4o\",\n inputPrice: 2.5,\n outputPrice: 10.0,\n contextWindow: 128000,\n maxOutput: 16384,\n vision: true,\n },\n {\n id: \"openai/gpt-4o-mini\",\n name: \"GPT-4o Mini\",\n inputPrice: 0.15,\n outputPrice: 0.6,\n contextWindow: 128000,\n maxOutput: 16384,\n },\n\n // OpenAI O-series (Reasoning)\n {\n id: \"openai/o1\",\n name: \"o1\",\n inputPrice: 15.0,\n outputPrice: 60.0,\n contextWindow: 200000,\n maxOutput: 100000,\n reasoning: true,\n },\n {\n id: \"openai/o1-mini\",\n name: \"o1-mini\",\n inputPrice: 1.1,\n outputPrice: 4.4,\n contextWindow: 128000,\n maxOutput: 65536,\n reasoning: true,\n },\n {\n id: \"openai/o3\",\n name: \"o3\",\n inputPrice: 2.0,\n outputPrice: 8.0,\n contextWindow: 200000,\n maxOutput: 100000,\n reasoning: true,\n },\n {\n id: \"openai/o3-mini\",\n name: \"o3-mini\",\n inputPrice: 1.1,\n outputPrice: 4.4,\n contextWindow: 128000,\n maxOutput: 65536,\n reasoning: true,\n },\n // o4-mini: Placeholder removed - model not yet released by OpenAI\n\n // Anthropic\n {\n id: \"anthropic/claude-haiku-4.5\",\n name: \"Claude Haiku 4.5\",\n inputPrice: 1.0,\n outputPrice: 5.0,\n contextWindow: 200000,\n maxOutput: 8192,\n },\n {\n id: \"anthropic/claude-sonnet-4\",\n name: \"Claude Sonnet 4\",\n inputPrice: 3.0,\n outputPrice: 15.0,\n contextWindow: 200000,\n maxOutput: 64000,\n reasoning: true,\n },\n {\n id: \"anthropic/claude-opus-4\",\n name: \"Claude Opus 4\",\n inputPrice: 15.0,\n outputPrice: 75.0,\n contextWindow: 200000,\n maxOutput: 32000,\n reasoning: true,\n },\n {\n id: \"anthropic/claude-opus-4.5\",\n name: \"Claude Opus 4.5\",\n inputPrice: 5.0,\n outputPrice: 25.0,\n contextWindow: 200000,\n maxOutput: 32000,\n reasoning: true,\n },\n\n // Google\n {\n id: \"google/gemini-3-pro-preview\",\n name: \"Gemini 3 Pro Preview\",\n inputPrice: 2.0,\n outputPrice: 12.0,\n contextWindow: 1050000,\n maxOutput: 65536,\n reasoning: true,\n vision: true,\n },\n {\n id: \"google/gemini-2.5-pro\",\n name: \"Gemini 2.5 Pro\",\n inputPrice: 1.25,\n outputPrice: 10.0,\n contextWindow: 1050000,\n maxOutput: 65536,\n reasoning: true,\n vision: true,\n },\n {\n id: \"google/gemini-2.5-flash\",\n name: \"Gemini 2.5 Flash\",\n inputPrice: 0.15,\n outputPrice: 0.6,\n contextWindow: 1000000,\n maxOutput: 65536,\n },\n\n // DeepSeek\n {\n id: \"deepseek/deepseek-chat\",\n name: \"DeepSeek V3.2 Chat\",\n inputPrice: 0.28,\n outputPrice: 0.42,\n contextWindow: 128000,\n maxOutput: 8192,\n },\n {\n id: \"deepseek/deepseek-reasoner\",\n name: \"DeepSeek V3.2 Reasoner\",\n inputPrice: 0.28,\n outputPrice: 0.42,\n contextWindow: 128000,\n maxOutput: 8192,\n reasoning: true,\n },\n\n // Moonshot / Kimi\n {\n id: \"moonshot/kimi-k2.5\",\n name: \"Kimi K2.5\",\n inputPrice: 0.5,\n outputPrice: 2.4,\n contextWindow: 262144,\n maxOutput: 8192,\n reasoning: true,\n vision: true,\n },\n\n // xAI / Grok\n {\n id: \"xai/grok-3\",\n name: \"Grok 3\",\n inputPrice: 3.0,\n outputPrice: 15.0,\n contextWindow: 131072,\n maxOutput: 16384,\n reasoning: true,\n },\n {\n id: \"xai/grok-3-fast\",\n name: \"Grok 3 Fast\",\n inputPrice: 5.0,\n outputPrice: 25.0,\n contextWindow: 131072,\n maxOutput: 16384,\n reasoning: true,\n },\n {\n id: \"xai/grok-3-mini\",\n name: \"Grok 3 Mini\",\n inputPrice: 0.3,\n outputPrice: 0.5,\n contextWindow: 131072,\n maxOutput: 16384,\n },\n];\n\n/**\n * Convert BlockRun model definitions to OpenClaw ModelDefinitionConfig format.\n */\nfunction toOpenClawModel(m: BlockRunModel): ModelDefinitionConfig {\n return {\n id: m.id,\n name: m.name,\n api: \"openai-completions\",\n reasoning: m.reasoning ?? false,\n input: m.vision ? [\"text\", \"image\"] : [\"text\"],\n cost: {\n input: m.inputPrice,\n output: m.outputPrice,\n cacheRead: 0,\n cacheWrite: 0,\n },\n contextWindow: m.contextWindow,\n maxTokens: m.maxOutput,\n };\n}\n\n/**\n * All BlockRun models in OpenClaw format.\n */\nexport const OPENCLAW_MODELS: ModelDefinitionConfig[] = BLOCKRUN_MODELS.map(toOpenClawModel);\n\n/**\n * Build a ModelProviderConfig for BlockRun.\n *\n * @param baseUrl - The proxy's local base URL (e.g., \"http://127.0.0.1:12345\")\n */\nexport function buildProviderModels(baseUrl: string): ModelProviderConfig {\n return {\n baseUrl: `${baseUrl}/v1`,\n api: \"openai-completions\",\n models: OPENCLAW_MODELS,\n };\n}\n","/**\n * BlockRun ProviderPlugin for OpenClaw\n *\n * Registers BlockRun as an LLM provider in OpenClaw.\n * Uses a local x402 proxy to handle micropayments transparently —\n * pi-ai sees a standard OpenAI-compatible API at localhost.\n */\n\nimport type { ProviderPlugin } from \"./types.js\";\nimport { buildProviderModels } from \"./models.js\";\nimport type { ProxyHandle } from \"./proxy.js\";\n\n/**\n * State for the running proxy (set when the plugin activates).\n */\nlet activeProxy: ProxyHandle | null = null;\n\n/**\n * Update the proxy handle (called from index.ts when the proxy starts).\n */\nexport function setActiveProxy(proxy: ProxyHandle): void {\n activeProxy = proxy;\n}\n\nexport function getActiveProxy(): ProxyHandle | null {\n return activeProxy;\n}\n\n/**\n * BlockRun provider plugin definition.\n */\nexport const blockrunProvider: ProviderPlugin = {\n id: \"blockrun\",\n label: \"BlockRun\",\n docsPath: \"https://blockrun.ai/docs\",\n aliases: [\"br\"],\n envVars: [\"BLOCKRUN_WALLET_KEY\"],\n\n // Model definitions — dynamically set to proxy URL\n get models() {\n if (!activeProxy) {\n // Fallback: point to BlockRun API directly (won't handle x402, but\n // allows config loading before proxy starts)\n return buildProviderModels(\"https://blockrun.ai/api\");\n }\n return buildProviderModels(activeProxy.baseUrl);\n },\n\n // No auth required — the x402 proxy handles wallet-based payments internally.\n // The proxy auto-generates a wallet on first run and stores it at\n // ~/.openclaw/blockrun/wallet.key. Users just fund that wallet with USDC.\n auth: [],\n};\n","/**\n * Local x402 Proxy Server\n *\n * Sits between OpenClaw's pi-ai (which makes standard OpenAI-format requests)\n * and BlockRun's API (which requires x402 micropayments).\n *\n * Flow:\n * pi-ai → http://localhost:{port}/v1/chat/completions\n * → proxy forwards to https://blockrun.ai/api/v1/chat/completions\n * → gets 402 → @x402/fetch signs payment → retries\n * → streams response back to pi-ai\n *\n * Optimizations (v0.3.0):\n * - SSE heartbeat: for streaming requests, sends headers + heartbeat immediately\n * before the x402 flow, preventing OpenClaw's 10-15s timeout from firing.\n * - Response dedup: hashes request bodies and caches responses for 30s,\n * preventing double-charging when OpenClaw retries after timeout.\n * - Payment cache: after first 402, pre-signs subsequent requests to skip\n * the 402 round trip (~200ms savings per request).\n * - Smart routing: when model is \"blockrun/auto\", classify query and pick cheapest model.\n * - Usage logging: log every request as JSON line to ~/.openclaw/blockrun/logs/\n */\n\nimport { createServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport type { AddressInfo } from \"node:net\";\nimport { privateKeyToAccount } from \"viem/accounts\";\nimport { createPaymentFetch, type PreAuthParams } from \"./x402.js\";\nimport {\n route,\n DEFAULT_ROUTING_CONFIG,\n type RouterOptions,\n type RoutingDecision,\n type RoutingConfig,\n type ModelPricing,\n} from \"./router/index.js\";\nimport { BLOCKRUN_MODELS } from \"./models.js\";\nimport { logUsage, type UsageEntry } from \"./logger.js\";\nimport { RequestDeduplicator } from \"./dedup.js\";\nimport { BalanceMonitor } from \"./balance.js\";\nimport { InsufficientFundsError, EmptyWalletError } from \"./errors.js\";\nimport { USER_AGENT } from \"./version.js\";\n\nconst BLOCKRUN_API = \"https://blockrun.ai/api\";\nconst AUTO_MODEL = \"blockrun/auto\";\nconst AUTO_MODEL_SHORT = \"auto\"; // OpenClaw strips provider prefix\nconst HEARTBEAT_INTERVAL_MS = 2_000;\nconst DEFAULT_REQUEST_TIMEOUT_MS = 180_000; // 3 minutes (allows for on-chain tx + LLM response)\nconst DEFAULT_PORT = 8402;\n\n/** Callback info for low balance warning */\nexport type LowBalanceInfo = {\n balanceUSD: string;\n walletAddress: string;\n};\n\n/** Callback info for insufficient funds error */\nexport type InsufficientFundsInfo = {\n balanceUSD: string;\n requiredUSD: string;\n walletAddress: string;\n};\n\nexport type ProxyOptions = {\n walletKey: string;\n apiBase?: string;\n /** Port to listen on (default: 8402) */\n port?: number;\n routingConfig?: Partial<RoutingConfig>;\n /** Request timeout in ms (default: 180000 = 3 minutes). Covers on-chain tx + LLM response. */\n requestTimeoutMs?: number;\n onReady?: (port: number) => void;\n onError?: (error: Error) => void;\n onPayment?: (info: { model: string; amount: string; network: string }) => void;\n onRouted?: (decision: RoutingDecision) => void;\n /** Called when balance drops below $1.00 (warning, request still proceeds) */\n onLowBalance?: (info: LowBalanceInfo) => void;\n /** Called when balance is insufficient for a request (request fails) */\n onInsufficientFunds?: (info: InsufficientFundsInfo) => void;\n};\n\nexport type ProxyHandle = {\n port: number;\n baseUrl: string;\n walletAddress: string;\n balanceMonitor: BalanceMonitor;\n close: () => Promise<void>;\n};\n\n/**\n * Build model pricing map from BLOCKRUN_MODELS.\n */\nfunction buildModelPricing(): Map<string, ModelPricing> {\n const map = new Map<string, ModelPricing>();\n for (const m of BLOCKRUN_MODELS) {\n if (m.id === AUTO_MODEL) continue; // skip meta-model\n map.set(m.id, { inputPrice: m.inputPrice, outputPrice: m.outputPrice });\n }\n return map;\n}\n\n/**\n * Merge partial routing config overrides with defaults.\n */\nfunction mergeRoutingConfig(overrides?: Partial<RoutingConfig>): RoutingConfig {\n if (!overrides) return DEFAULT_ROUTING_CONFIG;\n return {\n ...DEFAULT_ROUTING_CONFIG,\n ...overrides,\n classifier: { ...DEFAULT_ROUTING_CONFIG.classifier, ...overrides.classifier },\n scoring: { ...DEFAULT_ROUTING_CONFIG.scoring, ...overrides.scoring },\n tiers: { ...DEFAULT_ROUTING_CONFIG.tiers, ...overrides.tiers },\n overrides: { ...DEFAULT_ROUTING_CONFIG.overrides, ...overrides.overrides },\n };\n}\n\n/**\n * Estimate USDC cost for a request based on model pricing.\n * Returns amount string in USDC smallest unit (6 decimals) or undefined if unknown.\n */\nfunction estimateAmount(\n modelId: string,\n bodyLength: number,\n maxTokens: number,\n): string | undefined {\n const model = BLOCKRUN_MODELS.find((m) => m.id === modelId);\n if (!model) return undefined;\n\n // Rough estimate: ~4 chars per token for input\n const estimatedInputTokens = Math.ceil(bodyLength / 4);\n const estimatedOutputTokens = maxTokens || model.maxOutput || 4096;\n\n const costUsd =\n (estimatedInputTokens / 1_000_000) * model.inputPrice +\n (estimatedOutputTokens / 1_000_000) * model.outputPrice;\n\n // Convert to USDC 6-decimal integer, add 20% buffer for estimation error\n // Minimum 100 ($0.0001) to avoid zero-amount rejections\n const amountMicros = Math.max(100, Math.ceil(costUsd * 1.2 * 1_000_000));\n return amountMicros.toString();\n}\n\n/**\n * Start the local x402 proxy server.\n *\n * 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 } = createPaymentFetch(options.walletKey as `0x${string}`);\n\n // Create balance monitor for pre-request checks\n const balanceMonitor = new BalanceMonitor(account.address);\n\n // Build router options (100% local — no external API calls for routing)\n const routingConfig = mergeRoutingConfig(options.routingConfig);\n const modelPricing = buildModelPricing();\n const routerOpts: RouterOptions = {\n config: routingConfig,\n modelPricing,\n };\n\n // Request deduplicator (shared across all requests)\n const deduplicator = new RequestDeduplicator();\n\n const server = createServer(async (req: IncomingMessage, res: ServerResponse) => {\n // Health check with optional balance info\n if (req.url === \"/health\" || req.url?.startsWith(\"/health?\")) {\n const url = new URL(req.url, \"http://localhost\");\n const full = url.searchParams.get(\"full\") === \"true\";\n\n const response: Record<string, unknown> = {\n status: \"ok\",\n wallet: account.address,\n };\n\n if (full) {\n try {\n const balanceInfo = await balanceMonitor.checkBalance();\n response.balance = balanceInfo.balanceUSD;\n response.isLow = balanceInfo.isLow;\n response.isEmpty = balanceInfo.isEmpty;\n } catch {\n response.balanceError = \"Could not fetch balance\";\n }\n }\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(response));\n return;\n }\n\n // Only proxy paths starting with /v1\n if (!req.url?.startsWith(\"/v1\")) {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Not found\" }));\n return;\n }\n\n try {\n await proxyRequest(\n req,\n res,\n apiBase,\n payFetch,\n options,\n routerOpts,\n deduplicator,\n balanceMonitor,\n );\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n options.onError?.(error);\n\n if (!res.headersSent) {\n res.writeHead(502, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: { message: `Proxy error: ${error.message}`, type: \"proxy_error\" },\n }),\n );\n } else if (!res.writableEnded) {\n // Headers already sent (streaming) — send error as SSE event\n res.write(\n `data: ${JSON.stringify({ error: { message: error.message, type: \"proxy_error\" } })}\\n\\n`,\n );\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n }\n }\n });\n\n // Listen on requested port (default: 8402)\n const listenPort = options.port ?? DEFAULT_PORT;\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 walletAddress: account.address,\n balanceMonitor,\n close: () =>\n new Promise<void>((res, rej) => {\n server.close((err) => (err ? rej(err) : res()));\n }),\n });\n });\n });\n}\n\n/**\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: (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ) => Promise<Response>,\n options: ProxyOptions,\n routerOpts: RouterOptions,\n deduplicator: RequestDeduplicator,\n balanceMonitor: BalanceMonitor,\n): Promise<void> {\n const startTime = Date.now();\n\n // Build upstream URL: /v1/chat/completions → https://blockrun.ai/api/v1/chat/completions\n const upstreamUrl = `${apiBase}${req.url}`;\n\n // Collect request body\n const bodyChunks: Buffer[] = [];\n for await (const chunk of req) {\n bodyChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n let body = Buffer.concat(bodyChunks);\n\n // --- Smart routing ---\n let routingDecision: RoutingDecision | undefined;\n let isStreaming = false;\n let modelId = \"\";\n let maxTokens = 4096;\n const isChatCompletion = req.url?.includes(\"/chat/completions\");\n\n if (isChatCompletion && body.length > 0) {\n try {\n const parsed = JSON.parse(body.toString()) as Record<string, unknown>;\n isStreaming = parsed.stream === true;\n modelId = (parsed.model as string) || \"\";\n maxTokens = (parsed.max_tokens as number) || 4096;\n\n if (parsed.model === AUTO_MODEL || parsed.model === AUTO_MODEL_SHORT) {\n // Extract prompt from messages\n type ChatMessage = { role: string; content: string };\n const messages = parsed.messages as ChatMessage[] | undefined;\n let lastUserMsg: ChatMessage | undefined;\n if (messages) {\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].role === \"user\") {\n lastUserMsg = messages[i];\n break;\n }\n }\n }\n const systemMsg = messages?.find((m: ChatMessage) => m.role === \"system\");\n const prompt = typeof lastUserMsg?.content === \"string\" ? lastUserMsg.content : \"\";\n const systemPrompt = typeof systemMsg?.content === \"string\" ? systemMsg.content : undefined;\n\n routingDecision = route(prompt, systemPrompt, maxTokens, routerOpts);\n\n // Replace model in body\n parsed.model = routingDecision.model;\n modelId = routingDecision.model;\n 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 // --- Pre-request balance check ---\n // Estimate cost and check if wallet has sufficient balance\n let estimatedCostMicros: bigint | undefined;\n if (modelId) {\n const estimated = estimateAmount(modelId, body.length, maxTokens);\n if (estimated) {\n estimatedCostMicros = BigInt(estimated);\n\n // Check balance before proceeding\n const sufficiency = await balanceMonitor.checkSufficient(estimatedCostMicros);\n\n if (sufficiency.info.isEmpty) {\n // Wallet is empty — cannot proceed\n deduplicator.removeInflight(dedupKey);\n const error = new EmptyWalletError(sufficiency.info.walletAddress);\n options.onInsufficientFunds?.({\n balanceUSD: sufficiency.info.balanceUSD,\n requiredUSD: balanceMonitor.formatUSDC(estimatedCostMicros),\n walletAddress: sufficiency.info.walletAddress,\n });\n throw error;\n }\n\n if (!sufficiency.sufficient) {\n // Insufficient balance — cannot proceed\n deduplicator.removeInflight(dedupKey);\n const error = new InsufficientFundsError({\n currentBalanceUSD: sufficiency.info.balanceUSD,\n requiredUSD: balanceMonitor.formatUSDC(estimatedCostMicros),\n walletAddress: sufficiency.info.walletAddress,\n });\n options.onInsufficientFunds?.({\n balanceUSD: sufficiency.info.balanceUSD,\n requiredUSD: balanceMonitor.formatUSDC(estimatedCostMicros),\n walletAddress: sufficiency.info.walletAddress,\n });\n throw error;\n }\n\n if (sufficiency.info.isLow) {\n // Balance is low but sufficient — warn and proceed\n options.onLowBalance?.({\n balanceUSD: sufficiency.info.balanceUSD,\n walletAddress: sufficiency.info.walletAddress,\n });\n }\n }\n }\n\n // --- Streaming: early header flush + heartbeat ---\n let heartbeatInterval: ReturnType<typeof setInterval> | undefined;\n let headersSentEarly = false;\n\n if (isStreaming) {\n // Send 200 + SSE headers immediately, before x402 flow\n res.writeHead(200, {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-cache\",\n connection: \"keep-alive\",\n });\n headersSentEarly = true;\n\n // First heartbeat immediately\n res.write(\": heartbeat\\n\\n\");\n\n // Continue heartbeats every 2s while waiting for upstream\n heartbeatInterval = setInterval(() => {\n if (!res.writableEnded) {\n res.write(\": heartbeat\\n\\n\");\n }\n }, HEARTBEAT_INTERVAL_MS);\n }\n\n // Forward headers, stripping host, connection, and content-length\n const headers: Record<string, string> = {};\n for (const [key, value] of Object.entries(req.headers)) {\n if (\n key === \"host\" ||\n key === \"connection\" ||\n key === \"transfer-encoding\" ||\n key === \"content-length\"\n )\n continue;\n if (typeof value === \"string\") {\n headers[key] = value;\n }\n }\n if (!headers[\"content-type\"]) {\n headers[\"content-type\"] = \"application/json\";\n }\n headers[\"user-agent\"] = USER_AGENT;\n\n // --- Payment pre-auth: use already-estimated amount to skip 402 round trip ---\n let preAuth: PreAuthParams | undefined;\n if (estimatedCostMicros !== undefined) {\n preAuth = { estimatedAmount: estimatedCostMicros.toString() };\n }\n\n // --- Client disconnect cleanup ---\n let completed = false;\n res.on(\"close\", () => {\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n heartbeatInterval = undefined;\n }\n // Remove from in-flight if client disconnected before completion\n if (!completed) {\n deduplicator.removeInflight(dedupKey);\n }\n });\n\n // --- Request timeout ---\n const timeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n // Make the request through x402-wrapped fetch (with optional pre-auth)\n const upstream = await payFetch(\n upstreamUrl,\n {\n method: req.method ?? \"POST\",\n headers,\n body: body.length > 0 ? body : undefined,\n signal: controller.signal,\n },\n preAuth,\n );\n\n // Clear timeout — request succeeded\n clearTimeout(timeoutId);\n\n // Clear heartbeat — real data is about to flow\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n heartbeatInterval = undefined;\n }\n\n // --- 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\n // --- Optimistic balance deduction after successful response ---\n if (estimatedCostMicros !== undefined) {\n balanceMonitor.deductEstimated(estimatedCostMicros);\n }\n\n // Mark request as completed (for client disconnect cleanup)\n completed = true;\n } catch (err) {\n // Clear timeout on error\n clearTimeout(timeoutId);\n\n // Clear heartbeat on error\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n heartbeatInterval = undefined;\n }\n\n // Remove in-flight entry so retries aren't blocked\n deduplicator.removeInflight(dedupKey);\n\n // Invalidate balance cache on payment failure (might be out of date)\n balanceMonitor.invalidate();\n\n // Convert abort error to more descriptive timeout error\n if (err instanceof Error && err.name === \"AbortError\") {\n throw new Error(`Request timed out after ${timeoutMs}ms`);\n }\n\n throw err;\n }\n\n // --- Usage logging (fire-and-forget) ---\n if (routingDecision) {\n const entry: UsageEntry = {\n timestamp: new Date().toISOString(),\n model: routingDecision.model,\n cost: routingDecision.costEstimate,\n latencyMs: Date.now() - startTime,\n };\n logUsage(entry).catch(() => {});\n }\n}\n","/**\n * x402 Payment Implementation\n *\n * Based on BlockRun's proven implementation.\n * Handles 402 Payment Required responses with EIP-712 signed USDC transfers.\n *\n * Optimizations (v0.3.0):\n * - Payment cache: after first 402, caches {payTo, asset, network} per endpoint.\n * On subsequent requests, pre-signs payment and sends with first request,\n * skipping the 402 round trip (~200ms savings).\n * - Falls back to normal 402 flow if pre-signed payment is rejected.\n */\n\nimport { signTypedData, privateKeyToAccount } from \"viem/accounts\";\nimport { PaymentCache } from \"./payment-cache.js\";\n\nconst BASE_CHAIN_ID = 8453;\nconst USDC_BASE = \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\" as const;\n\nconst USDC_DOMAIN = {\n name: \"USD Coin\",\n version: \"2\",\n chainId: BASE_CHAIN_ID,\n verifyingContract: USDC_BASE,\n} as const;\n\nconst TRANSFER_TYPES = {\n TransferWithAuthorization: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n ],\n} as const;\n\nfunction createNonce(): `0x${string}` {\n const bytes = new Uint8Array(32);\n crypto.getRandomValues(bytes);\n return `0x${Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\")}` as `0x${string}`;\n}\n\ninterface PaymentOption {\n scheme: string;\n network: string;\n amount?: string;\n maxAmountRequired?: string;\n asset: string;\n payTo: string;\n maxTimeoutSeconds?: number;\n extra?: { name?: string; version?: string };\n}\n\ninterface PaymentRequired {\n accepts: PaymentOption[];\n resource?: { url?: string; description?: string };\n}\n\nfunction parsePaymentRequired(headerValue: string): PaymentRequired {\n const decoded = atob(headerValue);\n return JSON.parse(decoded) as PaymentRequired;\n}\n\nasync function createPaymentPayload(\n privateKey: `0x${string}`,\n fromAddress: string,\n recipient: string,\n amount: string,\n resourceUrl: string,\n): Promise<string> {\n const now = Math.floor(Date.now() / 1000);\n const validAfter = now - 600;\n const validBefore = now + 300;\n const nonce = createNonce();\n\n const signature = await signTypedData({\n privateKey,\n domain: USDC_DOMAIN,\n types: TRANSFER_TYPES,\n primaryType: \"TransferWithAuthorization\",\n message: {\n from: fromAddress as `0x${string}`,\n to: recipient as `0x${string}`,\n value: BigInt(amount),\n validAfter: BigInt(validAfter),\n validBefore: BigInt(validBefore),\n nonce,\n },\n });\n\n const paymentData = {\n x402Version: 2,\n resource: {\n url: resourceUrl,\n description: \"BlockRun AI API call\",\n mimeType: \"application/json\",\n },\n accepted: {\n scheme: \"exact\",\n network: \"eip155:8453\",\n amount,\n asset: USDC_BASE,\n payTo: recipient,\n maxTimeoutSeconds: 300,\n extra: { name: \"USD Coin\", version: \"2\" },\n },\n payload: {\n signature,\n authorization: {\n from: fromAddress,\n to: recipient,\n value: amount,\n validAfter: validAfter.toString(),\n validBefore: validBefore.toString(),\n nonce,\n },\n },\n extensions: {},\n };\n\n return btoa(JSON.stringify(paymentData));\n}\n\n/** Pre-auth parameters for skipping the 402 round trip. */\nexport type PreAuthParams = {\n estimatedAmount: string; // USDC amount in smallest unit (6 decimals)\n};\n\n/** Result from createPaymentFetch — includes the fetch wrapper and payment cache. */\nexport type PaymentFetchResult = {\n fetch: (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ) => Promise<Response>;\n cache: PaymentCache;\n};\n\n/**\n * Create a fetch wrapper that handles x402 payment automatically.\n *\n * Supports pre-auth: if cached payment params + estimated amount are available,\n * pre-signs and attaches payment to the first request, skipping the 402 round trip.\n * Falls back to normal 402 flow if pre-signed payment is rejected.\n */\nexport function createPaymentFetch(privateKey: `0x${string}`): PaymentFetchResult {\n const account = privateKeyToAccount(privateKey);\n const walletAddress = account.address;\n const paymentCache = new PaymentCache();\n\n const payFetch = async (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ): Promise<Response> => {\n const url = typeof input === \"string\" ? input : input instanceof URL ? input.href : input.url;\n const endpointPath = new URL(url).pathname;\n\n // --- Pre-auth path: skip 402 round trip ---\n const cached = paymentCache.get(endpointPath);\n if (cached && preAuth?.estimatedAmount) {\n const paymentPayload = await createPaymentPayload(\n privateKey,\n walletAddress,\n cached.payTo,\n preAuth.estimatedAmount,\n url,\n );\n\n const preAuthHeaders = new Headers(init?.headers);\n preAuthHeaders.set(\"payment-signature\", paymentPayload);\n\n const response = await fetch(input, { ...init, headers: preAuthHeaders });\n\n // Pre-auth accepted — skip 402 entirely\n if (response.status !== 402) {\n return response;\n }\n\n // Pre-auth rejected (wrong amount, payTo changed, etc.)\n // Try to use this 402's payment header for a proper retry\n const paymentHeader = response.headers.get(\"x-payment-required\");\n if (paymentHeader) {\n return handle402(input, init, url, endpointPath, paymentHeader);\n }\n\n // No payment header — invalidate cache and retry clean (no payment header)\n // to get a proper 402 with payment requirements\n paymentCache.invalidate(endpointPath);\n const cleanResponse = await fetch(input, init);\n if (cleanResponse.status !== 402) {\n return cleanResponse;\n }\n const cleanHeader = cleanResponse.headers.get(\"x-payment-required\");\n if (!cleanHeader) {\n throw new Error(\"402 response missing x-payment-required header\");\n }\n return handle402(input, init, url, endpointPath, cleanHeader);\n }\n\n // --- Normal path: first request may get 402 ---\n const response = await fetch(input, init);\n\n if (response.status !== 402) {\n return response;\n }\n\n const paymentHeader = response.headers.get(\"x-payment-required\");\n if (!paymentHeader) {\n throw new Error(\"402 response missing x-payment-required header\");\n }\n\n return handle402(input, init, url, endpointPath, paymentHeader);\n };\n\n /** Handle a 402 response: parse, cache params, sign, retry. */\n async function handle402(\n input: RequestInfo | URL,\n init: RequestInit | undefined,\n url: string,\n endpointPath: string,\n paymentHeader: string,\n ): Promise<Response> {\n const paymentRequired = parsePaymentRequired(paymentHeader);\n const option = paymentRequired.accepts?.[0];\n if (!option) {\n throw new Error(\"No payment options in 402 response\");\n }\n\n const amount = option.amount || option.maxAmountRequired;\n if (!amount) {\n throw new Error(\"No amount in payment requirements\");\n }\n\n // Cache payment params for future pre-auth\n paymentCache.set(endpointPath, {\n payTo: option.payTo,\n asset: option.asset,\n scheme: option.scheme,\n network: option.network,\n extra: option.extra,\n maxTimeoutSeconds: option.maxTimeoutSeconds,\n });\n\n // Create signed payment\n const paymentPayload = await createPaymentPayload(\n privateKey,\n walletAddress,\n option.payTo,\n amount,\n url,\n );\n\n // Retry with payment\n const retryHeaders = new Headers(init?.headers);\n retryHeaders.set(\"payment-signature\", paymentPayload);\n\n return fetch(input, {\n ...init,\n headers: retryHeaders,\n });\n }\n\n return { fetch: payFetch, cache: paymentCache };\n}\n","/**\n * Payment Parameter Cache\n *\n * Caches the 402 payment parameters (payTo, asset, network, etc.) after the first\n * request to each endpoint. On subsequent requests, pre-signs the payment and\n * attaches it to the first request, skipping the 402 round trip (~200ms savings).\n */\n\nexport type CachedPaymentParams = {\n payTo: string;\n asset: string;\n scheme: string;\n network: string;\n extra?: { name?: string; version?: string };\n maxTimeoutSeconds?: number;\n cachedAt: number;\n};\n\nconst DEFAULT_TTL_MS = 3_600_000; // 1 hour\n\nexport class PaymentCache {\n private cache = new Map<string, CachedPaymentParams>();\n private ttlMs: number;\n\n constructor(ttlMs = DEFAULT_TTL_MS) {\n this.ttlMs = ttlMs;\n }\n\n /** Get cached payment params for an endpoint path. */\n get(endpointPath: string): CachedPaymentParams | undefined {\n const entry = this.cache.get(endpointPath);\n if (!entry) return undefined;\n if (Date.now() - entry.cachedAt > this.ttlMs) {\n this.cache.delete(endpointPath);\n return undefined;\n }\n return entry;\n }\n\n /** Cache payment params from a 402 response. */\n set(endpointPath: string, params: Omit<CachedPaymentParams, \"cachedAt\">): void {\n this.cache.set(endpointPath, { ...params, cachedAt: Date.now() });\n }\n\n /** Invalidate cache for an endpoint (e.g., if payTo changed). */\n invalidate(endpointPath: string): void {\n this.cache.delete(endpointPath);\n }\n}\n","/**\n * Rule-Based Classifier (v2 — Weighted Scoring)\n *\n * Scores a request across 14 weighted dimensions and maps the aggregate\n * score to a tier using configurable boundaries. Confidence is calibrated\n * via sigmoid — low confidence triggers the fallback classifier.\n *\n * Handles 70-80% of requests in < 1ms with zero cost.\n */\n\nimport type { Tier, ScoringResult, ScoringConfig } from \"./types.js\";\n\ntype DimensionScore = { name: string; score: number; signal: string | null };\n\n// ─── Dimension Scorers ───\n// Each returns a score in [-1, 1] and an optional signal string.\n\nfunction scoreTokenCount(\n estimatedTokens: number,\n thresholds: { simple: number; complex: number },\n): DimensionScore {\n if (estimatedTokens < thresholds.simple) {\n return { name: \"tokenCount\", score: -1.0, signal: `short (${estimatedTokens} tokens)` };\n }\n if (estimatedTokens > thresholds.complex) {\n return { name: \"tokenCount\", score: 1.0, signal: `long (${estimatedTokens} tokens)` };\n }\n return { name: \"tokenCount\", score: 0, signal: null };\n}\n\nfunction scoreKeywordMatch(\n text: string,\n keywords: string[],\n name: string,\n signalLabel: string,\n thresholds: { low: number; high: number },\n scores: { none: number; low: number; high: number },\n): DimensionScore {\n const matches = keywords.filter((kw) => text.includes(kw.toLowerCase()));\n if (matches.length >= thresholds.high) {\n return {\n name,\n score: scores.high,\n signal: `${signalLabel} (${matches.slice(0, 3).join(\", \")})`,\n };\n }\n if (matches.length >= thresholds.low) {\n return {\n name,\n score: scores.low,\n signal: `${signalLabel} (${matches.slice(0, 3).join(\", \")})`,\n };\n }\n return { name, score: scores.none, signal: null };\n}\n\nfunction scoreMultiStep(text: string): DimensionScore {\n const patterns = [/first.*then/i, /step \\d/i, /\\d\\.\\s/];\n const hits = patterns.filter((p) => p.test(text));\n if (hits.length > 0) {\n return { name: \"multiStepPatterns\", score: 0.5, signal: \"multi-step\" };\n }\n return { name: \"multiStepPatterns\", score: 0, signal: null };\n}\n\nfunction scoreQuestionComplexity(prompt: string): DimensionScore {\n const count = (prompt.match(/\\?/g) || []).length;\n if (count > 3) {\n return { name: \"questionComplexity\", score: 0.5, signal: `${count} questions` };\n }\n return { name: \"questionComplexity\", score: 0, signal: null };\n}\n\n// ─── Main Classifier ───\n\nexport function classifyByRules(\n prompt: string,\n systemPrompt: string | undefined,\n estimatedTokens: number,\n config: ScoringConfig,\n): ScoringResult {\n const text = `${systemPrompt ?? \"\"} ${prompt}`.toLowerCase();\n\n // Score all 14 dimensions\n const dimensions: DimensionScore[] = [\n // Original 8 dimensions\n scoreTokenCount(estimatedTokens, config.tokenCountThresholds),\n scoreKeywordMatch(\n text,\n config.codeKeywords,\n \"codePresence\",\n \"code\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 1.0 },\n ),\n scoreKeywordMatch(\n text,\n config.reasoningKeywords,\n \"reasoningMarkers\",\n \"reasoning\",\n { low: 1, high: 2 },\n { none: 0, low: 0.7, high: 1.0 },\n ),\n scoreKeywordMatch(\n text,\n config.technicalKeywords,\n \"technicalTerms\",\n \"technical\",\n { low: 2, high: 4 },\n { none: 0, low: 0.5, high: 1.0 },\n ),\n scoreKeywordMatch(\n text,\n config.creativeKeywords,\n \"creativeMarkers\",\n \"creative\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 0.7 },\n ),\n scoreKeywordMatch(\n text,\n config.simpleKeywords,\n \"simpleIndicators\",\n \"simple\",\n { low: 1, high: 2 },\n { none: 0, low: -1.0, high: -1.0 },\n ),\n scoreMultiStep(text),\n scoreQuestionComplexity(prompt),\n\n // 6 new dimensions\n scoreKeywordMatch(\n text,\n config.imperativeVerbs,\n \"imperativeVerbs\",\n \"imperative\",\n { low: 1, high: 2 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n text,\n config.constraintIndicators,\n \"constraintCount\",\n \"constraints\",\n { low: 1, high: 3 },\n { none: 0, low: 0.3, high: 0.7 },\n ),\n scoreKeywordMatch(\n text,\n config.outputFormatKeywords,\n \"outputFormat\",\n \"format\",\n { low: 1, high: 2 },\n { none: 0, low: 0.4, high: 0.7 },\n ),\n scoreKeywordMatch(\n text,\n config.referenceKeywords,\n \"referenceComplexity\",\n \"references\",\n { low: 1, high: 2 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n text,\n config.negationKeywords,\n \"negationComplexity\",\n \"negation\",\n { low: 2, high: 3 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n text,\n config.domainSpecificKeywords,\n \"domainSpecificity\",\n \"domain-specific\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 0.8 },\n ),\n ];\n\n // Collect signals\n const signals = dimensions.filter((d) => d.signal !== null).map((d) => d.signal!);\n\n // Compute weighted score\n const weights = config.dimensionWeights;\n let weightedScore = 0;\n for (const d of dimensions) {\n const w = weights[d.name] ?? 0;\n weightedScore += d.score * w;\n }\n\n // Count reasoning markers for override\n const reasoningMatches = config.reasoningKeywords.filter((kw) => text.includes(kw.toLowerCase()));\n\n // Direct reasoning override: 2+ reasoning markers = high confidence REASONING\n if (reasoningMatches.length >= 2) {\n const confidence = calibrateConfidence(\n Math.max(weightedScore, 0.3), // ensure positive for confidence calc\n config.confidenceSteepness,\n );\n return {\n score: weightedScore,\n tier: \"REASONING\",\n confidence: Math.max(confidence, 0.85),\n signals,\n };\n }\n\n // Map weighted score to tier using boundaries\n const { simpleMedium, mediumComplex, complexReasoning } = config.tierBoundaries;\n let tier: Tier;\n let distanceFromBoundary: number;\n\n if (weightedScore < simpleMedium) {\n tier = \"SIMPLE\";\n distanceFromBoundary = simpleMedium - weightedScore;\n } else if (weightedScore < mediumComplex) {\n tier = \"MEDIUM\";\n distanceFromBoundary = Math.min(weightedScore - simpleMedium, mediumComplex - weightedScore);\n } else if (weightedScore < complexReasoning) {\n tier = \"COMPLEX\";\n distanceFromBoundary = Math.min(\n weightedScore - mediumComplex,\n complexReasoning - weightedScore,\n );\n } else {\n tier = \"REASONING\";\n distanceFromBoundary = weightedScore - complexReasoning;\n }\n\n // Calibrate confidence via sigmoid of distance from nearest boundary\n const confidence = calibrateConfidence(distanceFromBoundary, config.confidenceSteepness);\n\n // If confidence is below threshold → ambiguous\n if (confidence < config.confidenceThreshold) {\n return { score: weightedScore, tier: null, confidence, signals };\n }\n\n return { score: weightedScore, tier, confidence, signals };\n}\n\n/**\n * Sigmoid confidence calibration.\n * Maps distance from tier boundary to [0.5, 1.0] confidence range.\n */\nfunction calibrateConfidence(distance: number, steepness: number): number {\n return 1 / (1 + Math.exp(-steepness * distance));\n}\n","/**\n * Tier → Model Selection\n *\n * Maps a classification tier to the cheapest capable model.\n * Builds RoutingDecision metadata with cost estimates and savings.\n */\n\nimport type { Tier, TierConfig, RoutingDecision } from \"./types.js\";\n\nexport type ModelPricing = {\n inputPrice: number; // per 1M tokens\n outputPrice: number; // per 1M tokens\n};\n\n/**\n * Select the primary model for a tier and build the RoutingDecision.\n */\nexport function selectModel(\n tier: Tier,\n confidence: number,\n method: \"rules\" | \"llm\",\n reasoning: string,\n tierConfigs: Record<Tier, TierConfig>,\n modelPricing: Map<string, ModelPricing>,\n estimatedInputTokens: number,\n maxOutputTokens: number,\n): RoutingDecision {\n const tierConfig = tierConfigs[tier];\n const model = tierConfig.primary;\n const pricing = modelPricing.get(model);\n\n const inputCost = pricing ? (estimatedInputTokens / 1_000_000) * pricing.inputPrice : 0;\n const outputCost = pricing ? (maxOutputTokens / 1_000_000) * pricing.outputPrice : 0;\n const costEstimate = inputCost + outputCost;\n\n // Baseline: what Claude Opus would cost (the premium default)\n const opusPricing = modelPricing.get(\"anthropic/claude-opus-4\");\n const baselineInput = opusPricing\n ? (estimatedInputTokens / 1_000_000) * opusPricing.inputPrice\n : 0;\n const baselineOutput = opusPricing ? (maxOutputTokens / 1_000_000) * opusPricing.outputPrice : 0;\n const baselineCost = baselineInput + baselineOutput;\n\n const savings = baselineCost > 0 ? Math.max(0, (baselineCost - costEstimate) / baselineCost) : 0;\n\n return {\n model,\n tier,\n confidence,\n method,\n reasoning,\n costEstimate,\n baselineCost,\n savings,\n };\n}\n\n/**\n * Get the ordered fallback chain for a tier: [primary, ...fallbacks].\n */\nexport function getFallbackChain(tier: Tier, tierConfigs: Record<Tier, TierConfig>): string[] {\n const config = tierConfigs[tier];\n return [config.primary, ...config.fallback];\n}\n","/**\n * Default Routing Config\n *\n * All routing parameters as a TypeScript constant.\n * Operators override via openclaw.yaml plugin config.\n *\n * Scoring uses 14 weighted dimensions with sigmoid confidence calibration.\n */\n\nimport type { RoutingConfig } from \"./types.js\";\n\nexport const DEFAULT_ROUTING_CONFIG: RoutingConfig = {\n version: \"2.0\",\n\n classifier: {\n llmModel: \"google/gemini-2.5-flash\",\n llmMaxTokens: 10,\n llmTemperature: 0,\n promptTruncationChars: 500,\n cacheTtlMs: 3_600_000, // 1 hour\n },\n\n scoring: {\n tokenCountThresholds: { simple: 50, complex: 500 },\n codeKeywords: [\n \"function\",\n \"class\",\n \"import\",\n \"def\",\n \"SELECT\",\n \"async\",\n \"await\",\n \"const\",\n \"let\",\n \"var\",\n \"return\",\n \"```\",\n ],\n reasoningKeywords: [\n \"prove\",\n \"theorem\",\n \"derive\",\n \"step by step\",\n \"chain of thought\",\n \"formally\",\n \"mathematical\",\n \"proof\",\n \"logically\",\n ],\n simpleKeywords: [\n \"what is\",\n \"define\",\n \"translate\",\n \"hello\",\n \"yes or no\",\n \"capital of\",\n \"how old\",\n \"who is\",\n \"when was\",\n ],\n technicalKeywords: [\n \"algorithm\",\n \"optimize\",\n \"architecture\",\n \"distributed\",\n \"kubernetes\",\n \"microservice\",\n \"database\",\n \"infrastructure\",\n ],\n creativeKeywords: [\"story\", \"poem\", \"compose\", \"brainstorm\", \"creative\", \"imagine\", \"write a\"],\n\n // New dimension keyword lists\n imperativeVerbs: [\n \"build\",\n \"create\",\n \"implement\",\n \"design\",\n \"develop\",\n \"construct\",\n \"generate\",\n \"deploy\",\n \"configure\",\n \"set up\",\n ],\n constraintIndicators: [\n \"under\",\n \"at most\",\n \"at least\",\n \"within\",\n \"no more than\",\n \"o(\",\n \"maximum\",\n \"minimum\",\n \"limit\",\n \"budget\",\n ],\n outputFormatKeywords: [\n \"json\",\n \"yaml\",\n \"xml\",\n \"table\",\n \"csv\",\n \"markdown\",\n \"schema\",\n \"format as\",\n \"structured\",\n ],\n referenceKeywords: [\n \"above\",\n \"below\",\n \"previous\",\n \"following\",\n \"the docs\",\n \"the api\",\n \"the code\",\n \"earlier\",\n \"attached\",\n ],\n negationKeywords: [\n \"don't\",\n \"do not\",\n \"avoid\",\n \"never\",\n \"without\",\n \"except\",\n \"exclude\",\n \"no longer\",\n ],\n domainSpecificKeywords: [\n \"quantum\",\n \"fpga\",\n \"vlsi\",\n \"risc-v\",\n \"asic\",\n \"photonics\",\n \"genomics\",\n \"proteomics\",\n \"topological\",\n \"homomorphic\",\n \"zero-knowledge\",\n \"lattice-based\",\n ],\n\n // Dimension weights (sum to 1.0)\n dimensionWeights: {\n tokenCount: 0.08,\n codePresence: 0.15,\n reasoningMarkers: 0.18,\n technicalTerms: 0.1,\n creativeMarkers: 0.05,\n simpleIndicators: 0.12,\n multiStepPatterns: 0.12,\n questionComplexity: 0.05,\n imperativeVerbs: 0.03,\n constraintCount: 0.04,\n outputFormat: 0.03,\n referenceComplexity: 0.02,\n negationComplexity: 0.01,\n domainSpecificity: 0.02,\n },\n\n // Tier boundaries on weighted score axis\n tierBoundaries: {\n simpleMedium: 0.0,\n mediumComplex: 0.15,\n complexReasoning: 0.25,\n },\n\n // Sigmoid steepness for confidence calibration\n confidenceSteepness: 12,\n // Below this confidence → ambiguous (null tier)\n confidenceThreshold: 0.7,\n },\n\n tiers: {\n SIMPLE: {\n primary: \"google/gemini-2.5-flash\",\n fallback: [\"deepseek/deepseek-chat\", \"openai/gpt-4o-mini\"],\n },\n MEDIUM: {\n primary: \"deepseek/deepseek-chat\",\n fallback: [\"google/gemini-2.5-flash\", \"openai/gpt-4o-mini\"],\n },\n COMPLEX: {\n primary: \"anthropic/claude-opus-4\",\n fallback: [\"anthropic/claude-sonnet-4\", \"openai/gpt-4o\"],\n },\n REASONING: {\n primary: \"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, type ModelPricing } from \"./selector.js\";\n\nexport type RouterOptions = {\n config: RoutingConfig;\n modelPricing: Map<string, ModelPricing>;\n};\n\n/**\n * Route a request to the cheapest capable model.\n *\n * 1. Check overrides (large context, structured output)\n * 2. Run rule-based classifier (14 weighted dimensions, <1ms)\n * 3. If ambiguous, default to configurable tier (no external API calls)\n * 4. Select model for tier\n * 5. Return RoutingDecision with metadata\n */\nexport function route(\n prompt: string,\n systemPrompt: string | undefined,\n maxOutputTokens: number,\n options: RouterOptions,\n): RoutingDecision {\n const { config, modelPricing } = options;\n\n // Estimate input tokens (~4 chars per token)\n const fullText = `${systemPrompt ?? \"\"} ${prompt}`;\n const estimatedTokens = Math.ceil(fullText.length / 4);\n\n // --- Override: large context → force COMPLEX ---\n if (estimatedTokens > config.overrides.maxTokensForceComplex) {\n return selectModel(\n \"COMPLEX\",\n 0.95,\n \"rules\",\n `Input exceeds ${config.overrides.maxTokensForceComplex} tokens`,\n config.tiers,\n modelPricing,\n estimatedTokens,\n maxOutputTokens,\n );\n }\n\n // Structured output detection\n const hasStructuredOutput = systemPrompt ? /json|structured|schema/i.test(systemPrompt) : false;\n\n // --- Rule-based classification ---\n const ruleResult = classifyByRules(prompt, systemPrompt, estimatedTokens, config.scoring);\n\n let tier: Tier;\n let confidence: number;\n const method: \"rules\" | \"llm\" = \"rules\";\n let reasoning = `score=${ruleResult.score} | ${ruleResult.signals.join(\", \")}`;\n\n if (ruleResult.tier !== null) {\n tier = ruleResult.tier;\n confidence = ruleResult.confidence;\n } else {\n // Ambiguous — default to configurable tier (no external API call)\n tier = config.overrides.ambiguousDefaultTier;\n confidence = 0.5;\n reasoning += ` | ambiguous -> default: ${tier}`;\n }\n\n // Apply structured output minimum tier\n if (hasStructuredOutput) {\n const tierRank: Record<Tier, number> = { SIMPLE: 0, MEDIUM: 1, COMPLEX: 2, REASONING: 3 };\n const minTier = config.overrides.structuredOutputMinTier;\n if (tierRank[tier] < tierRank[minTier]) {\n reasoning += ` | upgraded to ${minTier} (structured output)`;\n tier = minTier;\n }\n }\n\n return selectModel(\n tier,\n confidence,\n method,\n reasoning,\n config.tiers,\n modelPricing,\n estimatedTokens,\n maxOutputTokens,\n );\n}\n\nexport { getFallbackChain } from \"./selector.js\";\nexport { DEFAULT_ROUTING_CONFIG } from \"./config.js\";\nexport type { RoutingDecision, Tier, RoutingConfig } from \"./types.js\";\nexport type { ModelPricing } from \"./selector.js\";\n","/**\n * Usage Logger\n *\n * Logs every LLM request as a JSON line to a daily log file.\n * Files: ~/.openclaw/blockrun/logs/usage-YYYY-MM-DD.jsonl\n *\n * MVP: append-only JSON lines. No rotation, no cleanup.\n * Logging never breaks the request flow — all errors are swallowed.\n */\n\nimport { appendFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\nexport type UsageEntry = {\n timestamp: string;\n model: string;\n cost: number;\n latencyMs: number;\n};\n\nconst LOG_DIR = join(homedir(), \".openclaw\", \"blockrun\", \"logs\");\nlet dirReady = false;\n\nasync function ensureDir(): Promise<void> {\n if (dirReady) return;\n await mkdir(LOG_DIR, { recursive: true });\n dirReady = true;\n}\n\n/**\n * Log a usage entry as a JSON line.\n */\nexport async function logUsage(entry: UsageEntry): Promise<void> {\n try {\n await ensureDir();\n const date = entry.timestamp.slice(0, 10); // YYYY-MM-DD\n const file = join(LOG_DIR, `usage-${date}.jsonl`);\n await appendFile(file, JSON.stringify(entry) + \"\\n\");\n } catch {\n // Never break the request flow\n }\n}\n","/**\n * Request Deduplication\n *\n * Prevents double-charging when OpenClaw retries a request after timeout.\n * Tracks in-flight requests and caches completed responses for a short TTL.\n */\n\nimport { createHash } from \"node:crypto\";\n\nexport type CachedResponse = {\n status: number;\n headers: Record<string, string>;\n body: Buffer;\n completedAt: number;\n};\n\ntype InflightEntry = {\n resolve: (result: CachedResponse) => void;\n waiters: Promise<CachedResponse>[];\n};\n\nconst DEFAULT_TTL_MS = 30_000; // 30 seconds\nconst MAX_BODY_SIZE = 1_048_576; // 1MB\n\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(\n new Promise<CachedResponse>((r) => {\n const orig = entry.resolve;\n entry.resolve = (result) => {\n orig(result);\n resolve(result);\n r(result);\n };\n }),\n );\n });\n return promise;\n }\n\n /** Mark a request as in-flight. */\n markInflight(key: string): void {\n this.inflight.set(key, {\n resolve: () => {},\n waiters: [],\n });\n }\n\n /** Complete an in-flight request — cache result and notify waiters. */\n complete(key: string, result: CachedResponse): void {\n // Only cache responses within size limit\n if (result.body.length <= MAX_BODY_SIZE) {\n this.completed.set(key, result);\n }\n\n const entry = this.inflight.get(key);\n if (entry) {\n entry.resolve(result);\n this.inflight.delete(key);\n }\n\n this.prune();\n }\n\n /** Remove an in-flight entry on error (don't cache failures). */\n removeInflight(key: string): void {\n this.inflight.delete(key);\n }\n\n /** Prune expired completed entries. */\n private prune(): void {\n const now = Date.now();\n for (const [key, entry] of this.completed) {\n if (now - entry.completedAt > this.ttlMs) {\n this.completed.delete(key);\n }\n }\n }\n}\n","/**\n * Balance Monitor for ClawRouter\n *\n * Monitors USDC balance on Base network with intelligent caching.\n * Provides pre-request balance checks to prevent failed payments.\n *\n * Caching Strategy:\n * - TTL: 30 seconds (balance is cached to avoid excessive RPC calls)\n * - Optimistic deduction: after successful payment, subtract estimated cost from cache\n * - Invalidation: on payment failure, immediately refresh from RPC\n */\n\nimport { createPublicClient, http, erc20Abi } from \"viem\";\nimport { base } from \"viem/chains\";\nimport { RpcError } from \"./errors.js\";\n\n/** USDC contract address on Base mainnet */\nconst USDC_BASE = \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\" as const;\n\n/** Cache TTL in milliseconds (30 seconds) */\nconst CACHE_TTL_MS = 30_000;\n\n/** Balance thresholds in USDC smallest unit (6 decimals) */\nexport const BALANCE_THRESHOLDS = {\n /** Low balance warning threshold: $1.00 */\n LOW_BALANCE_MICROS: 1_000_000n,\n /** Effectively zero threshold: $0.0001 (covers dust/rounding) */\n ZERO_THRESHOLD: 100n,\n} as const;\n\n/** Balance information returned by checkBalance() */\nexport type BalanceInfo = {\n /** Raw balance in USDC smallest unit (6 decimals) */\n balance: bigint;\n /** Formatted balance as \"$X.XX\" */\n balanceUSD: string;\n /** True if balance < $1.00 */\n isLow: boolean;\n /** True if balance < $0.0001 (effectively zero) */\n isEmpty: boolean;\n /** Wallet address for funding instructions */\n walletAddress: string;\n};\n\n/** Result from checkSufficient() */\nexport type SufficiencyResult = {\n /** True if balance >= estimated cost */\n sufficient: boolean;\n /** Current balance info */\n info: BalanceInfo;\n /** If insufficient, the shortfall as \"$X.XX\" */\n shortfall?: string;\n};\n\n/**\n * Monitors USDC balance on Base network.\n *\n * Usage:\n * const monitor = new BalanceMonitor(\"0x...\");\n * const info = await monitor.checkBalance();\n * if (info.isLow) console.warn(\"Low balance!\");\n */\nexport class BalanceMonitor {\n private readonly client;\n private readonly walletAddress: `0x${string}`;\n\n /** Cached balance (null = not yet fetched) */\n private cachedBalance: bigint | null = null;\n /** Timestamp when cache was last updated */\n private cachedAt = 0;\n\n constructor(walletAddress: string) {\n this.walletAddress = walletAddress as `0x${string}`;\n this.client = createPublicClient({\n chain: base,\n transport: http(undefined, {\n timeout: 10_000, // 10 second timeout to prevent hanging on slow RPC\n }),\n });\n }\n\n /**\n * Check current USDC balance.\n * Uses cache if valid, otherwise fetches from RPC.\n */\n async checkBalance(): Promise<BalanceInfo> {\n const now = Date.now();\n\n // Use cache if valid\n if (this.cachedBalance !== null && now - this.cachedAt < CACHE_TTL_MS) {\n return this.buildInfo(this.cachedBalance);\n }\n\n // Fetch from RPC\n const balance = await this.fetchBalance();\n this.cachedBalance = balance;\n this.cachedAt = now;\n\n return this.buildInfo(balance);\n }\n\n /**\n * Check if balance is sufficient for an estimated cost.\n *\n * @param estimatedCostMicros - Estimated cost in USDC smallest unit (6 decimals)\n */\n async checkSufficient(estimatedCostMicros: bigint): Promise<SufficiencyResult> {\n const info = await this.checkBalance();\n\n if (info.balance >= estimatedCostMicros) {\n return { sufficient: true, info };\n }\n\n const shortfall = estimatedCostMicros - info.balance;\n return {\n sufficient: false,\n info,\n shortfall: this.formatUSDC(shortfall),\n };\n }\n\n /**\n * Optimistically deduct estimated cost from cached balance.\n * Call this after a successful payment to keep cache accurate.\n *\n * @param amountMicros - Amount to deduct in USDC smallest unit\n */\n deductEstimated(amountMicros: bigint): void {\n if (this.cachedBalance !== null && this.cachedBalance >= amountMicros) {\n this.cachedBalance -= amountMicros;\n }\n }\n\n /**\n * Invalidate cache, forcing next checkBalance() to fetch from RPC.\n * Call this after a payment failure to get accurate balance.\n */\n invalidate(): void {\n this.cachedBalance = null;\n this.cachedAt = 0;\n }\n\n /**\n * Force refresh balance from RPC (ignores cache).\n */\n async refresh(): Promise<BalanceInfo> {\n this.invalidate();\n return this.checkBalance();\n }\n\n /**\n * Format USDC amount (in micros) as \"$X.XX\".\n */\n formatUSDC(amountMicros: bigint): string {\n // USDC has 6 decimals\n const dollars = Number(amountMicros) / 1_000_000;\n return `$${dollars.toFixed(2)}`;\n }\n\n /**\n * Get the wallet address being monitored.\n */\n getWalletAddress(): string {\n return this.walletAddress;\n }\n\n /** Fetch balance from RPC */\n private async fetchBalance(): Promise<bigint> {\n try {\n const balance = await this.client.readContract({\n address: USDC_BASE,\n abi: erc20Abi,\n functionName: \"balanceOf\",\n args: [this.walletAddress],\n });\n return balance;\n } catch (error) {\n // Throw typed error instead of silently returning 0\n // This allows callers to distinguish \"node down\" from \"wallet empty\"\n throw new RpcError(error instanceof Error ? error.message : \"Unknown error\", error);\n }\n }\n\n /** Build BalanceInfo from raw balance */\n private buildInfo(balance: bigint): BalanceInfo {\n return {\n balance,\n balanceUSD: this.formatUSDC(balance),\n isLow: balance < BALANCE_THRESHOLDS.LOW_BALANCE_MICROS,\n isEmpty: balance < BALANCE_THRESHOLDS.ZERO_THRESHOLD,\n walletAddress: this.walletAddress,\n };\n }\n}\n","/**\n * Typed Error Classes for ClawRouter\n *\n * Provides structured errors for balance-related failures with\n * all necessary information for user-friendly error messages.\n */\n\n/**\n * Thrown when wallet has insufficient USDC balance for a request.\n */\nexport class InsufficientFundsError extends Error {\n readonly code = \"INSUFFICIENT_FUNDS\" as const;\n readonly currentBalanceUSD: string;\n readonly requiredUSD: string;\n readonly walletAddress: string;\n\n constructor(opts: { currentBalanceUSD: string; requiredUSD: string; walletAddress: string }) {\n super(\n `Insufficient USDC balance. Current: ${opts.currentBalanceUSD}, Required: ${opts.requiredUSD}. Fund wallet: ${opts.walletAddress}`,\n );\n this.name = \"InsufficientFundsError\";\n this.currentBalanceUSD = opts.currentBalanceUSD;\n this.requiredUSD = opts.requiredUSD;\n this.walletAddress = opts.walletAddress;\n }\n}\n\n/**\n * Thrown when wallet has no USDC balance (or effectively zero).\n */\nexport class EmptyWalletError extends Error {\n readonly code = \"EMPTY_WALLET\" as const;\n readonly walletAddress: string;\n\n constructor(walletAddress: string) {\n super(`No USDC balance. Fund wallet to use ClawRouter: ${walletAddress}`);\n this.name = \"EmptyWalletError\";\n this.walletAddress = walletAddress;\n }\n}\n\n/**\n * Type guard to check if an error is InsufficientFundsError.\n */\nexport function isInsufficientFundsError(error: unknown): error is InsufficientFundsError {\n return error instanceof Error && (error as InsufficientFundsError).code === \"INSUFFICIENT_FUNDS\";\n}\n\n/**\n * Type guard to check if an error is EmptyWalletError.\n */\nexport function isEmptyWalletError(error: unknown): error is EmptyWalletError {\n return error instanceof Error && (error as EmptyWalletError).code === \"EMPTY_WALLET\";\n}\n\n/**\n * Type guard to check if an error is a balance-related error.\n */\nexport function isBalanceError(error: unknown): error is InsufficientFundsError | EmptyWalletError {\n return isInsufficientFundsError(error) || isEmptyWalletError(error);\n}\n\n/**\n * Thrown when RPC call fails (network error, node down, etc).\n * Distinguishes infrastructure failures from actual empty wallets.\n */\nexport class RpcError extends Error {\n readonly code = \"RPC_ERROR\" as const;\n readonly originalError: unknown;\n\n constructor(message: string, originalError?: unknown) {\n super(`RPC error: ${message}. Check network connectivity.`);\n this.name = \"RpcError\";\n this.originalError = originalError;\n }\n}\n\n/**\n * Type guard to check if an error is RpcError.\n */\nexport function isRpcError(error: unknown): error is RpcError {\n return error instanceof Error && (error as RpcError).code === \"RPC_ERROR\";\n}\n","/**\n * Single source of truth for version.\n * Reads from package.json at build time via tsup's define.\n */\nimport { createRequire } from \"node:module\";\nimport { fileURLToPath } from \"node:url\";\nimport { dirname, join } from \"node:path\";\n\n// Read package.json at runtime\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n// In dist/, go up one level to find package.json\nconst require = createRequire(import.meta.url);\nconst pkg = require(join(__dirname, \"..\", \"package.json\")) as { version: string };\n\nexport const VERSION = pkg.version;\nexport const USER_AGENT = `clawrouter/${VERSION}`;\n","/**\n * BlockRun Auth Methods for OpenClaw\n *\n * Provides wallet-based authentication for the BlockRun provider.\n * Operators configure their wallet private key, which is used to\n * sign x402 micropayments for LLM inference.\n *\n * Three methods:\n * 1. Auto-generate — create a new wallet on first run, save to ~/.openclaw/blockrun/wallet.key\n * 2. Environment variable — read from BLOCKRUN_WALLET_KEY\n * 3. Manual input — operator enters private key via wizard\n */\n\nimport { writeFile, readFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { generatePrivateKey, privateKeyToAccount } from \"viem/accounts\";\nimport type { ProviderAuthMethod, ProviderAuthContext, ProviderAuthResult } from \"./types.js\";\n\nconst WALLET_DIR = join(homedir(), \".openclaw\", \"blockrun\");\nconst WALLET_FILE = join(WALLET_DIR, \"wallet.key\");\n\n/**\n * Try to load a previously auto-generated wallet key from disk.\n */\nasync function loadSavedWallet(): Promise<string | undefined> {\n try {\n const key = (await readFile(WALLET_FILE, \"utf-8\")).trim();\n if (key.startsWith(\"0x\") && key.length === 66) return key;\n } catch {\n // File doesn't exist yet\n }\n return undefined;\n}\n\n/**\n * Generate a new wallet, save to disk, return the private key.\n */\nasync function generateAndSaveWallet(): Promise<{ key: string; address: string }> {\n const key = generatePrivateKey();\n const account = privateKeyToAccount(key);\n await mkdir(WALLET_DIR, { recursive: true });\n await writeFile(WALLET_FILE, key + \"\\n\", { mode: 0o600 });\n return { key, address: account.address };\n}\n\n/**\n * Resolve wallet key: load saved → env var → auto-generate.\n * Called by index.ts before the auth wizard runs.\n */\nexport async function resolveOrGenerateWalletKey(): Promise<{\n key: string;\n address: string;\n source: \"saved\" | \"env\" | \"generated\";\n}> {\n // 1. Previously saved wallet\n const saved = await loadSavedWallet();\n if (saved) {\n const account = privateKeyToAccount(saved as `0x${string}`);\n return { key: saved, address: account.address, source: \"saved\" };\n }\n\n // 2. Environment variable\n const envKey = process.env.BLOCKRUN_WALLET_KEY;\n if (typeof envKey === \"string\" && envKey.startsWith(\"0x\") && envKey.length === 66) {\n const account = privateKeyToAccount(envKey as `0x${string}`);\n return { key: envKey, address: account.address, source: \"env\" };\n }\n\n // 3. Auto-generate\n const { key, address } = await generateAndSaveWallet();\n return { key, address, source: \"generated\" };\n}\n\n/**\n * Auth method: operator enters their wallet private key directly.\n */\nexport const walletKeyAuth: ProviderAuthMethod = {\n id: \"wallet-key\",\n label: \"Wallet Private Key\",\n hint: \"Enter your EVM wallet private key (0x...) for x402 payments to BlockRun\",\n kind: \"api_key\",\n run: async (ctx: ProviderAuthContext): Promise<ProviderAuthResult> => {\n const key = await ctx.prompter.text({\n message: \"Enter your wallet private key (0x...)\",\n validate: (value: string) => {\n const trimmed = value.trim();\n if (!trimmed.startsWith(\"0x\")) return \"Key must start with 0x\";\n if (trimmed.length !== 66) return \"Key must be 66 characters (0x + 64 hex)\";\n if (!/^0x[0-9a-fA-F]{64}$/.test(trimmed)) return \"Key must be valid hex\";\n return undefined;\n },\n });\n\n if (!key || typeof key !== \"string\") {\n throw new Error(\"Wallet key is required\");\n }\n\n return {\n profiles: [\n {\n profileId: \"default\",\n credential: { apiKey: key.trim() },\n },\n ],\n notes: [\n \"Wallet key stored securely in OpenClaw credentials.\",\n \"Your wallet signs x402 USDC payments on Base for each LLM call.\",\n \"Fund your wallet with USDC on Base to start using BlockRun models.\",\n ],\n };\n },\n};\n\n/**\n * Auth method: read wallet key from BLOCKRUN_WALLET_KEY environment variable.\n */\nexport const envKeyAuth: ProviderAuthMethod = {\n id: \"env-key\",\n label: \"Environment Variable\",\n hint: \"Use BLOCKRUN_WALLET_KEY environment variable\",\n kind: \"api_key\",\n run: async (): Promise<ProviderAuthResult> => {\n const key = process.env.BLOCKRUN_WALLET_KEY;\n\n if (!key) {\n throw new Error(\n \"BLOCKRUN_WALLET_KEY environment variable is not set. \" +\n \"Set it to your EVM wallet private key (0x...).\",\n );\n }\n\n return {\n profiles: [\n {\n profileId: \"default\",\n credential: { apiKey: key.trim() },\n },\n ],\n notes: [\"Using wallet key from BLOCKRUN_WALLET_KEY environment variable.\"],\n };\n },\n};\n","/**\n * @blockrun/clawrouter\n *\n * Smart LLM router for OpenClaw — 30+ models, x402 micropayments, 78% cost savings.\n * Routes each request to the cheapest model that can handle it.\n *\n * Usage:\n * # Install the plugin\n * openclaw plugins install @blockrun/clawrouter\n *\n * # Fund your wallet with USDC on Base (address printed on install)\n *\n * # Use smart routing (auto-picks cheapest model)\n * openclaw models set blockrun/auto\n *\n * # Or use any specific BlockRun model\n * openclaw models set openai/gpt-5.2\n */\n\nimport type { OpenClawPluginDefinition, OpenClawPluginApi } from \"./types.js\";\nimport { blockrunProvider, setActiveProxy } from \"./provider.js\";\nimport { startProxy } from \"./proxy.js\";\nimport { resolveOrGenerateWalletKey } from \"./auth.js\";\nimport type { RoutingConfig } from \"./router/index.js\";\nimport { BalanceMonitor } from \"./balance.js\";\nimport { OPENCLAW_MODELS } from \"./models.js\";\nimport { readFileSync, writeFileSync, existsSync, readdirSync, mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { VERSION } from \"./version.js\";\n\n/**\n * Detect if we're running in shell completion mode.\n * When `openclaw completion --shell zsh` runs, it loads plugins but only needs\n * the completion script output - any stdout logging pollutes the script and\n * causes zsh to interpret colored text like `[plugins]` as glob patterns.\n */\nfunction isCompletionMode(): boolean {\n const args = process.argv;\n // Check for: openclaw completion --shell <shell>\n // argv[0] = node/bun, argv[1] = openclaw, argv[2] = completion\n return args.some((arg, i) => arg === \"completion\" && i >= 1 && i <= 3);\n}\n\n/**\n * Inject BlockRun models config into OpenClaw config file.\n * This is required because registerProvider() alone doesn't make models available.\n */\nfunction injectModelsConfig(logger: { info: (msg: string) => void }): void {\n const configPath = join(homedir(), \".openclaw\", \"openclaw.json\");\n if (!existsSync(configPath)) {\n logger.info(\"OpenClaw config not found, skipping models injection\");\n return;\n }\n\n try {\n const config = JSON.parse(readFileSync(configPath, \"utf-8\"));\n\n // Check if already configured\n if (config.models?.providers?.blockrun) {\n return; // Already configured\n }\n\n // Inject models config\n if (!config.models) config.models = {};\n if (!config.models.providers) config.models.providers = {};\n\n config.models.providers.blockrun = {\n baseUrl: \"http://127.0.0.1:8402/v1\",\n api: \"openai-completions\",\n models: OPENCLAW_MODELS,\n };\n\n writeFileSync(configPath, JSON.stringify(config, null, 2));\n logger.info(\"Injected BlockRun models into OpenClaw config\");\n } catch {\n // Silently fail — config injection is best-effort\n }\n}\n\n/**\n * Inject dummy auth profile for BlockRun into agent auth stores.\n * OpenClaw's agent system looks for auth credentials even if provider has auth: [].\n * We inject a placeholder so the lookup succeeds (proxy handles real auth internally).\n */\nfunction injectAuthProfile(logger: { info: (msg: string) => void }): void {\n const agentsDir = join(homedir(), \".openclaw\", \"agents\");\n\n // Create agents directory if it doesn't exist\n if (!existsSync(agentsDir)) {\n try {\n mkdirSync(agentsDir, { recursive: true });\n } catch (err) {\n logger.info(\n `Could not create agents dir: ${err instanceof Error ? err.message : String(err)}`,\n );\n return;\n }\n }\n\n try {\n // Find all agent directories\n let agents = readdirSync(agentsDir, { withFileTypes: true })\n .filter((d) => d.isDirectory())\n .map((d) => d.name);\n\n // Always ensure \"main\" agent has auth (most common agent)\n if (!agents.includes(\"main\")) {\n agents = [\"main\", ...agents];\n }\n\n for (const agentId of agents) {\n const authDir = join(agentsDir, agentId, \"agent\");\n const authPath = join(authDir, \"auth-profiles.json\");\n\n // Create agent dir if needed\n if (!existsSync(authDir)) {\n try {\n mkdirSync(authDir, { recursive: true });\n } catch {\n continue; // Skip if we can't create the dir\n }\n }\n\n // Load or create auth-profiles.json with correct OpenClaw format\n // Format: { version: 1, profiles: { \"provider:profileId\": { type, provider, key } } }\n let store: { version: number; profiles: Record<string, unknown> } = { version: 1, profiles: {} };\n if (existsSync(authPath)) {\n try {\n const existing = JSON.parse(readFileSync(authPath, \"utf-8\"));\n // Check if valid OpenClaw format (has version and profiles)\n if (existing.version && existing.profiles) {\n store = existing;\n }\n // Old format without version/profiles is discarded and recreated\n } catch {\n // Invalid JSON, use fresh store\n }\n }\n\n // Check if blockrun auth already exists (OpenClaw format: profiles[\"provider:profileId\"])\n const profileKey = \"blockrun:default\";\n if (store.profiles[profileKey]) {\n continue; // Already configured\n }\n\n // Inject placeholder auth for blockrun (OpenClaw format)\n // The proxy handles real x402 auth internally, this just satisfies OpenClaw's lookup\n store.profiles[profileKey] = {\n type: \"api_key\",\n provider: \"blockrun\",\n key: \"x402-proxy-handles-auth\",\n };\n\n try {\n writeFileSync(authPath, JSON.stringify(store, null, 2));\n logger.info(`Injected BlockRun auth profile for agent: ${agentId}`);\n } catch (err) {\n logger.info(\n `Could not inject auth for ${agentId}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n } catch (err) {\n logger.info(`Auth injection failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n}\n\n/**\n * Start the x402 proxy in the background.\n * Called from register() because OpenClaw's loader only invokes register(),\n * treating activate() as an alias (def.register ?? def.activate).\n */\nasync function startProxyInBackground(api: OpenClawPluginApi): Promise<void> {\n // Resolve wallet key: saved file → env var → auto-generate\n const { key: walletKey, address, source } = await resolveOrGenerateWalletKey();\n\n // Log wallet source\n if (source === \"generated\") {\n api.logger.info(`Generated new wallet: ${address}`);\n api.logger.info(`Fund with USDC on Base to start using ClawRouter.`);\n } else if (source === \"saved\") {\n api.logger.info(`Using saved wallet: ${address}`);\n } else {\n api.logger.info(`Using wallet from BLOCKRUN_WALLET_KEY: ${address}`);\n }\n\n // --- Startup balance check ---\n const startupMonitor = new BalanceMonitor(address);\n try {\n const startupBalance = await startupMonitor.checkBalance();\n if (startupBalance.isEmpty) {\n api.logger.warn(`[!] No USDC balance. Fund wallet to use ClawRouter: ${address}`);\n } else if (startupBalance.isLow) {\n api.logger.warn(\n `[!] Low balance: ${startupBalance.balanceUSD} remaining. Fund wallet: ${address}`,\n );\n } else {\n api.logger.info(`Wallet balance: ${startupBalance.balanceUSD}`);\n }\n } catch (err) {\n api.logger.warn(\n `Could not check wallet balance: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n // Resolve routing config overrides from plugin config\n const routingConfig = api.pluginConfig?.routing as Partial<RoutingConfig> | undefined;\n\n const proxy = await startProxy({\n walletKey,\n routingConfig,\n onReady: (port) => {\n api.logger.info(`BlockRun x402 proxy listening on port ${port}`);\n },\n onError: (error) => {\n api.logger.error(`BlockRun proxy error: ${error.message}`);\n },\n onRouted: (decision) => {\n const cost = decision.costEstimate.toFixed(4);\n const saved = (decision.savings * 100).toFixed(0);\n api.logger.info(`${decision.model} $${cost} (saved ${saved}%)`);\n },\n onLowBalance: (info) => {\n api.logger.warn(`[!] Low balance: ${info.balanceUSD}. Fund wallet: ${info.walletAddress}`);\n },\n onInsufficientFunds: (info) => {\n api.logger.error(\n `[!] Insufficient funds. Balance: ${info.balanceUSD}, Needed: ${info.requiredUSD}. Fund wallet: ${info.walletAddress}`,\n );\n },\n });\n\n setActiveProxy(proxy);\n api.logger.info(`BlockRun provider active — ${proxy.baseUrl}/v1 (smart routing enabled)`);\n}\n\nconst plugin: OpenClawPluginDefinition = {\n id: \"clawrouter\",\n name: \"ClawRouter\",\n description: \"Smart LLM router — 30+ models, x402 micropayments, 78% cost savings\",\n version: VERSION,\n\n register(api: OpenClawPluginApi) {\n // Skip heavy initialization in completion mode — only completion script is needed\n // Logging to stdout during completion pollutes the script and causes zsh errors\n if (isCompletionMode()) {\n api.registerProvider(blockrunProvider);\n return;\n }\n\n // Register BlockRun as a provider (sync — available immediately)\n api.registerProvider(blockrunProvider);\n\n // Inject models config into OpenClaw config file\n // This persists the config so models are recognized on restart\n injectModelsConfig(api.logger);\n\n // Inject dummy auth profiles into agent auth stores\n // OpenClaw's agent system looks for auth even if provider has auth: []\n injectAuthProfile(api.logger);\n\n // Also set runtime config for immediate availability\n if (!api.config.models) {\n api.config.models = { providers: {} };\n }\n if (!api.config.models.providers) {\n api.config.models.providers = {};\n }\n api.config.models.providers.blockrun = {\n baseUrl: \"http://127.0.0.1:8402/v1\",\n api: \"openai-completions\",\n models: OPENCLAW_MODELS,\n };\n\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\nexport default plugin;\n\n// Re-export for programmatic use\nexport { startProxy } from \"./proxy.js\";\nexport type { ProxyOptions, ProxyHandle, LowBalanceInfo, InsufficientFundsInfo } from \"./proxy.js\";\nexport { blockrunProvider } from \"./provider.js\";\nexport { OPENCLAW_MODELS, BLOCKRUN_MODELS, buildProviderModels } from \"./models.js\";\nexport { route, DEFAULT_ROUTING_CONFIG } from \"./router/index.js\";\nexport type { RoutingDecision, RoutingConfig, Tier } from \"./router/index.js\";\nexport { logUsage } from \"./logger.js\";\nexport type { UsageEntry } from \"./logger.js\";\nexport { RequestDeduplicator } from \"./dedup.js\";\nexport type { CachedResponse } from \"./dedup.js\";\nexport { PaymentCache } from \"./payment-cache.js\";\nexport type { CachedPaymentParams } from \"./payment-cache.js\";\nexport { createPaymentFetch } from \"./x402.js\";\nexport type { PreAuthParams, PaymentFetchResult } from \"./x402.js\";\nexport { BalanceMonitor, BALANCE_THRESHOLDS } from \"./balance.js\";\nexport type { BalanceInfo, SufficiencyResult } from \"./balance.js\";\nexport {\n InsufficientFundsError,\n EmptyWalletError,\n RpcError,\n isInsufficientFundsError,\n isEmptyWalletError,\n isBalanceError,\n isRpcError,\n} from \"./errors.js\";\nexport { fetchWithRetry, isRetryable, DEFAULT_RETRY_CONFIG } from \"./retry.js\";\nexport type { RetryConfig } from \"./retry.js\";\n","/**\n * Retry Logic for ClawRouter\n *\n * Provides fetch wrapper with exponential backoff for transient errors.\n * Retries on 429 (rate limit), 502, 503, 504 (server errors).\n */\n\n/** Configuration for retry behavior */\nexport type RetryConfig = {\n /** Maximum number of retries (default: 2) */\n maxRetries: number;\n /** Base delay in ms for exponential backoff (default: 500) */\n baseDelayMs: number;\n /** HTTP status codes that trigger a retry (default: [429, 502, 503, 504]) */\n retryableCodes: number[];\n};\n\n/** Default retry configuration */\nexport const DEFAULT_RETRY_CONFIG: RetryConfig = {\n maxRetries: 2,\n baseDelayMs: 500,\n retryableCodes: [429, 502, 503, 504],\n};\n\n/** Sleep for a given number of milliseconds */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Wrap a fetch-like function with retry logic and exponential backoff.\n *\n * @param fetchFn - The fetch function to wrap (can be standard fetch or x402 payFetch)\n * @param url - URL to fetch\n * @param init - Fetch init options\n * @param config - Retry configuration (optional, uses defaults)\n * @returns Response from successful fetch or last failed attempt\n *\n * @example\n * ```typescript\n * const response = await fetchWithRetry(\n * fetch,\n * \"https://api.example.com/endpoint\",\n * { method: \"POST\", body: JSON.stringify(data) },\n * { maxRetries: 3 }\n * );\n * ```\n */\nexport async function fetchWithRetry(\n fetchFn: (url: string, init?: RequestInit) => Promise<Response>,\n url: string,\n init?: RequestInit,\n config?: Partial<RetryConfig>,\n): Promise<Response> {\n const cfg: RetryConfig = {\n ...DEFAULT_RETRY_CONFIG,\n ...config,\n };\n\n let lastError: Error | undefined;\n let lastResponse: Response | undefined;\n\n for (let attempt = 0; attempt <= cfg.maxRetries; attempt++) {\n try {\n const response = await fetchFn(url, init);\n\n // Success or non-retryable status — return immediately\n if (!cfg.retryableCodes.includes(response.status)) {\n return response;\n }\n\n // Retryable status — save response and maybe retry\n lastResponse = response;\n\n // Check for Retry-After header (common with 429)\n const retryAfter = response.headers.get(\"retry-after\");\n let delay: number;\n\n if (retryAfter) {\n // Retry-After can be seconds or HTTP-date\n const seconds = parseInt(retryAfter, 10);\n delay = isNaN(seconds) ? cfg.baseDelayMs * Math.pow(2, attempt) : seconds * 1000;\n } else {\n delay = cfg.baseDelayMs * Math.pow(2, attempt);\n }\n\n // Only retry if we have attempts left\n if (attempt < cfg.maxRetries) {\n await sleep(delay);\n }\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n\n // Network errors are retryable\n if (attempt < cfg.maxRetries) {\n const delay = cfg.baseDelayMs * Math.pow(2, attempt);\n await sleep(delay);\n }\n }\n }\n\n // All retries exhausted — return last response or throw last error\n if (lastResponse) {\n return lastResponse;\n }\n\n throw lastError ?? new Error(\"Max retries exceeded\");\n}\n\n/**\n * Check if an error or response indicates a retryable condition.\n */\nexport function isRetryable(\n errorOrResponse: Error | Response,\n config?: Partial<RetryConfig>,\n): boolean {\n const retryableCodes = config?.retryableCodes ?? DEFAULT_RETRY_CONFIG.retryableCodes;\n\n if (errorOrResponse instanceof Response) {\n return retryableCodes.includes(errorOrResponse.status);\n }\n\n // Network errors are generally retryable\n const message = errorOrResponse.message.toLowerCase();\n return (\n message.includes(\"network\") ||\n message.includes(\"timeout\") ||\n message.includes(\"econnreset\") ||\n message.includes(\"econnrefused\") ||\n message.includes(\"socket hang up\")\n );\n}\n"],"mappings":"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","names":["privateKeyToAccount","response","paymentHeader","confidence","DEFAULT_TTL_MS","USDC_BASE","join","require","privateKeyToAccount","mkdir","join","homedir","privateKeyToAccount","homedir","join","join","homedir"]}
|
package/package.json
CHANGED