@blockrun/clawrouter 0.2.2 → 0.2.3
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.js +33 -34
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -875,7 +875,7 @@ async function logUsage(entry) {
|
|
|
875
875
|
// src/proxy.ts
|
|
876
876
|
var BLOCKRUN_API = "https://blockrun.ai/api";
|
|
877
877
|
var AUTO_MODEL = "blockrun/auto";
|
|
878
|
-
var USER_AGENT = "clawrouter/0.2.
|
|
878
|
+
var USER_AGENT = "clawrouter/0.2.3";
|
|
879
879
|
function buildModelPricing() {
|
|
880
880
|
const map = /* @__PURE__ */ new Map();
|
|
881
881
|
for (const m of BLOCKRUN_MODELS) {
|
|
@@ -1033,49 +1033,48 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts) {
|
|
|
1033
1033
|
}
|
|
1034
1034
|
|
|
1035
1035
|
// src/index.ts
|
|
1036
|
+
async function startProxyInBackground(api) {
|
|
1037
|
+
const { key: walletKey, address, source } = await resolveOrGenerateWalletKey();
|
|
1038
|
+
if (source === "generated") {
|
|
1039
|
+
api.logger.info(`Generated new wallet: ${address}`);
|
|
1040
|
+
api.logger.info(`Fund with USDC on Base to start using ClawRouter.`);
|
|
1041
|
+
} else if (source === "saved") {
|
|
1042
|
+
api.logger.info(`Using saved wallet: ${address}`);
|
|
1043
|
+
} else {
|
|
1044
|
+
api.logger.info(`Using wallet from BLOCKRUN_WALLET_KEY: ${address}`);
|
|
1045
|
+
}
|
|
1046
|
+
const routingConfig = api.pluginConfig?.routing;
|
|
1047
|
+
const proxy = await startProxy({
|
|
1048
|
+
walletKey,
|
|
1049
|
+
routingConfig,
|
|
1050
|
+
onReady: (port) => {
|
|
1051
|
+
api.logger.info(`BlockRun x402 proxy listening on port ${port}`);
|
|
1052
|
+
},
|
|
1053
|
+
onError: (error) => {
|
|
1054
|
+
api.logger.error(`BlockRun proxy error: ${error.message}`);
|
|
1055
|
+
},
|
|
1056
|
+
onRouted: (decision) => {
|
|
1057
|
+
const cost = decision.costEstimate.toFixed(4);
|
|
1058
|
+
const saved = (decision.savings * 100).toFixed(0);
|
|
1059
|
+
api.logger.info(`${decision.model} $${cost} (saved ${saved}%)`);
|
|
1060
|
+
}
|
|
1061
|
+
});
|
|
1062
|
+
setActiveProxy(proxy);
|
|
1063
|
+
api.logger.info(`BlockRun provider active \u2014 ${proxy.baseUrl}/v1 (smart routing enabled)`);
|
|
1064
|
+
}
|
|
1036
1065
|
var plugin = {
|
|
1037
1066
|
id: "clawrouter",
|
|
1038
1067
|
name: "ClawRouter",
|
|
1039
1068
|
description: "Smart LLM router \u2014 30+ models, x402 micropayments, 78% cost savings",
|
|
1040
|
-
version: "0.2.
|
|
1069
|
+
version: "0.2.3",
|
|
1041
1070
|
register(api) {
|
|
1042
1071
|
api.registerProvider(blockrunProvider);
|
|
1043
1072
|
api.logger.info("BlockRun provider registered (30+ models via x402)");
|
|
1044
|
-
|
|
1045
|
-
async activate(api) {
|
|
1046
|
-
const { key: walletKey, address, source } = await resolveOrGenerateWalletKey();
|
|
1047
|
-
if (source === "generated") {
|
|
1048
|
-
api.logger.info(`Generated new wallet: ${address}`);
|
|
1049
|
-
api.logger.info(`Fund with USDC on Base to start using ClawRouter.`);
|
|
1050
|
-
} else if (source === "saved") {
|
|
1051
|
-
api.logger.info(`Using saved wallet: ${address}`);
|
|
1052
|
-
} else {
|
|
1053
|
-
api.logger.info(`Using wallet from BLOCKRUN_WALLET_KEY: ${address}`);
|
|
1054
|
-
}
|
|
1055
|
-
const routingConfig = api.pluginConfig?.routing;
|
|
1056
|
-
try {
|
|
1057
|
-
const proxy = await startProxy({
|
|
1058
|
-
walletKey,
|
|
1059
|
-
routingConfig,
|
|
1060
|
-
onReady: (port) => {
|
|
1061
|
-
api.logger.info(`BlockRun x402 proxy listening on port ${port}`);
|
|
1062
|
-
},
|
|
1063
|
-
onError: (error) => {
|
|
1064
|
-
api.logger.error(`BlockRun proxy error: ${error.message}`);
|
|
1065
|
-
},
|
|
1066
|
-
onRouted: (decision) => {
|
|
1067
|
-
const cost = decision.costEstimate.toFixed(4);
|
|
1068
|
-
const saved = (decision.savings * 100).toFixed(0);
|
|
1069
|
-
api.logger.info(`${decision.model} $${cost} (saved ${saved}%)`);
|
|
1070
|
-
}
|
|
1071
|
-
});
|
|
1072
|
-
setActiveProxy(proxy);
|
|
1073
|
-
api.logger.info(`BlockRun provider active \u2014 ${proxy.baseUrl}/v1 (smart routing enabled)`);
|
|
1074
|
-
} catch (err) {
|
|
1073
|
+
startProxyInBackground(api).catch((err) => {
|
|
1075
1074
|
api.logger.error(
|
|
1076
1075
|
`Failed to start BlockRun proxy: ${err instanceof Error ? err.message : String(err)}`
|
|
1077
1076
|
);
|
|
1078
|
-
}
|
|
1077
|
+
});
|
|
1079
1078
|
}
|
|
1080
1079
|
};
|
|
1081
1080
|
var index_default = plugin;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/auth.ts","../src/models.ts","../src/provider.ts","../src/proxy.ts","../src/x402.ts","../src/router/rules.ts","../src/router/llm-classifier.ts","../src/router/selector.ts","../src/router/config.ts","../src/router/index.ts","../src/logger.ts","../src/index.ts"],"sourcesContent":["/**\n * BlockRun Auth Methods for OpenClaw\n *\n * Provides wallet-based authentication for the BlockRun provider.\n * Operators configure their wallet private key, which is used to\n * sign x402 micropayments for LLM inference.\n *\n * Three methods:\n * 1. Auto-generate — create a new wallet on first run, save to ~/.openclaw/blockrun/wallet.key\n * 2. Environment variable — read from BLOCKRUN_WALLET_KEY\n * 3. Manual input — operator enters private key via wizard\n */\n\nimport { writeFile, readFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { generatePrivateKey, privateKeyToAccount } from \"viem/accounts\";\nimport type { ProviderAuthMethod, ProviderAuthContext, ProviderAuthResult } from \"./types.js\";\n\nconst WALLET_DIR = join(homedir(), \".openclaw\", \"blockrun\");\nconst WALLET_FILE = join(WALLET_DIR, \"wallet.key\");\n\n/**\n * Try to load a previously auto-generated wallet key from disk.\n */\nasync function loadSavedWallet(): Promise<string | undefined> {\n try {\n const key = (await readFile(WALLET_FILE, \"utf-8\")).trim();\n if (key.startsWith(\"0x\") && key.length === 66) return key;\n } catch {\n // File doesn't exist yet\n }\n return undefined;\n}\n\n/**\n * Generate a new wallet, save to disk, return the private key.\n */\nasync function generateAndSaveWallet(): Promise<{ key: string; address: string }> {\n const key = generatePrivateKey();\n const account = privateKeyToAccount(key);\n await mkdir(WALLET_DIR, { recursive: true });\n await writeFile(WALLET_FILE, key + \"\\n\", { mode: 0o600 });\n return { key, address: account.address };\n}\n\n/**\n * Resolve wallet key: load saved → env var → auto-generate.\n * Called by index.ts before the auth wizard runs.\n */\nexport async function resolveOrGenerateWalletKey(): Promise<{ key: string; address: string; source: \"saved\" | \"env\" | \"generated\" }> {\n // 1. Previously saved wallet\n const saved = await loadSavedWallet();\n if (saved) {\n const account = privateKeyToAccount(saved as `0x${string}`);\n return { key: saved, address: account.address, source: \"saved\" };\n }\n\n // 2. Environment variable\n const envKey = process.env.BLOCKRUN_WALLET_KEY;\n if (typeof envKey === \"string\" && envKey.startsWith(\"0x\") && envKey.length === 66) {\n const account = privateKeyToAccount(envKey as `0x${string}`);\n return { key: envKey, address: account.address, source: \"env\" };\n }\n\n // 3. Auto-generate\n const { key, address } = await generateAndSaveWallet();\n return { key, address, source: \"generated\" };\n}\n\n/**\n * Auth method: operator enters their wallet private key directly.\n */\nexport const walletKeyAuth: ProviderAuthMethod = {\n id: \"wallet-key\",\n label: \"Wallet Private Key\",\n hint: \"Enter your EVM wallet private key (0x...) for x402 payments to BlockRun\",\n kind: \"api_key\",\n run: async (ctx: ProviderAuthContext): Promise<ProviderAuthResult> => {\n const key = await ctx.prompter.text({\n message: \"Enter your wallet private key (0x...)\",\n validate: (value: string) => {\n const trimmed = value.trim();\n if (!trimmed.startsWith(\"0x\")) return \"Key must start with 0x\";\n if (trimmed.length !== 66) return \"Key must be 66 characters (0x + 64 hex)\";\n if (!/^0x[0-9a-fA-F]{64}$/.test(trimmed)) return \"Key must be valid hex\";\n return undefined;\n },\n });\n\n if (!key || typeof key !== \"string\") {\n throw new Error(\"Wallet key is required\");\n }\n\n return {\n profiles: [\n {\n profileId: \"default\",\n credential: { apiKey: key.trim() },\n },\n ],\n notes: [\n \"Wallet key stored securely in OpenClaw credentials.\",\n \"Your wallet signs x402 USDC payments on Base for each LLM call.\",\n \"Fund your wallet with USDC on Base to start using BlockRun models.\",\n ],\n };\n },\n};\n\n/**\n * Auth method: read wallet key from BLOCKRUN_WALLET_KEY environment variable.\n */\nexport const envKeyAuth: ProviderAuthMethod = {\n id: \"env-key\",\n label: \"Environment Variable\",\n hint: \"Use BLOCKRUN_WALLET_KEY environment variable\",\n kind: \"api_key\",\n run: async (): Promise<ProviderAuthResult> => {\n const key = process.env.BLOCKRUN_WALLET_KEY;\n\n if (!key) {\n throw new Error(\n \"BLOCKRUN_WALLET_KEY environment variable is not set. \" +\n \"Set it to your EVM wallet private key (0x...).\",\n );\n }\n\n return {\n profiles: [\n {\n profileId: \"default\",\n credential: { apiKey: key.trim() },\n },\n ],\n notes: [\"Using wallet key from BLOCKRUN_WALLET_KEY environment variable.\"],\n };\n },\n};\n","/**\n * BlockRun Model Definitions for OpenClaw\n *\n * Maps BlockRun's 30+ AI models to OpenClaw's ModelDefinitionConfig format.\n * All models use the \"openai-completions\" API since BlockRun is OpenAI-compatible.\n *\n * Pricing is in USD per 1M tokens. Operators pay these rates via x402;\n * they set their own markup when reselling to end users (Phase 2).\n */\n\nimport type { ModelDefinitionConfig, ModelProviderConfig } from \"./types.js\";\n\ntype BlockRunModel = {\n id: string;\n name: string;\n inputPrice: number;\n outputPrice: number;\n contextWindow: number;\n maxOutput: number;\n reasoning?: boolean;\n vision?: boolean;\n};\n\nexport const BLOCKRUN_MODELS: BlockRunModel[] = [\n // Smart routing meta-model — proxy replaces with actual model\n { id: \"blockrun/auto\", name: \"BlockRun Smart Router\", inputPrice: 0, outputPrice: 0, contextWindow: 1_050_000, maxOutput: 128_000 },\n\n\n // OpenAI GPT-5 Family\n { id: \"openai/gpt-5.2\", name: \"GPT-5.2\", inputPrice: 1.75, outputPrice: 14.0, contextWindow: 400000, maxOutput: 128000, reasoning: true, vision: true },\n { id: \"openai/gpt-5-mini\", name: \"GPT-5 Mini\", inputPrice: 0.25, outputPrice: 2.0, contextWindow: 200000, maxOutput: 65536 },\n { id: \"openai/gpt-5-nano\", name: \"GPT-5 Nano\", inputPrice: 0.05, outputPrice: 0.4, contextWindow: 128000, maxOutput: 32768 },\n { id: \"openai/gpt-5.2-pro\", name: \"GPT-5.2 Pro\", inputPrice: 21.0, outputPrice: 168.0, contextWindow: 400000, maxOutput: 128000, reasoning: true },\n\n // OpenAI GPT-4 Family\n { id: \"openai/gpt-4.1\", name: \"GPT-4.1\", inputPrice: 2.0, outputPrice: 8.0, contextWindow: 128000, maxOutput: 16384, vision: true },\n { id: \"openai/gpt-4.1-mini\", name: \"GPT-4.1 Mini\", inputPrice: 0.4, outputPrice: 1.6, contextWindow: 128000, maxOutput: 16384 },\n { id: \"openai/gpt-4.1-nano\", name: \"GPT-4.1 Nano\", inputPrice: 0.1, outputPrice: 0.4, contextWindow: 128000, maxOutput: 16384 },\n { id: \"openai/gpt-4o\", name: \"GPT-4o\", inputPrice: 2.5, outputPrice: 10.0, contextWindow: 128000, maxOutput: 16384, vision: true },\n { id: \"openai/gpt-4o-mini\", name: \"GPT-4o Mini\", inputPrice: 0.15, outputPrice: 0.6, contextWindow: 128000, maxOutput: 16384 },\n\n // OpenAI O-series (Reasoning)\n { id: \"openai/o1\", name: \"o1\", inputPrice: 15.0, outputPrice: 60.0, contextWindow: 200000, maxOutput: 100000, reasoning: true },\n { id: \"openai/o1-mini\", name: \"o1-mini\", inputPrice: 1.1, outputPrice: 4.4, contextWindow: 128000, maxOutput: 65536, reasoning: true },\n { id: \"openai/o3\", name: \"o3\", inputPrice: 2.0, outputPrice: 8.0, contextWindow: 200000, maxOutput: 100000, reasoning: true },\n { id: \"openai/o3-mini\", name: \"o3-mini\", inputPrice: 1.1, outputPrice: 4.4, contextWindow: 128000, maxOutput: 65536, reasoning: true },\n { id: \"openai/o4-mini\", name: \"o4-mini\", inputPrice: 1.1, outputPrice: 4.4, contextWindow: 128000, maxOutput: 65536, reasoning: true },\n\n // Anthropic\n { id: \"anthropic/claude-haiku-4.5\", name: \"Claude Haiku 4.5\", inputPrice: 1.0, outputPrice: 5.0, contextWindow: 200000, maxOutput: 8192 },\n { id: \"anthropic/claude-sonnet-4\", name: \"Claude Sonnet 4\", inputPrice: 3.0, outputPrice: 15.0, contextWindow: 200000, maxOutput: 64000, reasoning: true },\n { id: \"anthropic/claude-opus-4\", name: \"Claude Opus 4\", inputPrice: 15.0, outputPrice: 75.0, contextWindow: 200000, maxOutput: 32000, reasoning: true },\n { id: \"anthropic/claude-opus-4.5\", name: \"Claude Opus 4.5\", inputPrice: 15.0, outputPrice: 75.0, contextWindow: 200000, maxOutput: 32000, reasoning: true },\n\n // Google\n { id: \"google/gemini-3-pro-preview\", name: \"Gemini 3 Pro Preview\", inputPrice: 2.0, outputPrice: 12.0, contextWindow: 1050000, maxOutput: 65536, reasoning: true, vision: true },\n { id: \"google/gemini-2.5-pro\", name: \"Gemini 2.5 Pro\", inputPrice: 1.25, outputPrice: 10.0, contextWindow: 1050000, maxOutput: 65536, reasoning: true, vision: true },\n { id: \"google/gemini-2.5-flash\", name: \"Gemini 2.5 Flash\", inputPrice: 0.15, outputPrice: 0.6, contextWindow: 1000000, maxOutput: 65536 },\n\n // DeepSeek\n { id: \"deepseek/deepseek-chat\", name: \"DeepSeek V3.2 Chat\", inputPrice: 0.28, outputPrice: 0.42, contextWindow: 128000, maxOutput: 8192 },\n { id: \"deepseek/deepseek-reasoner\", name: \"DeepSeek V3.2 Reasoner\", inputPrice: 0.28, outputPrice: 0.42, contextWindow: 128000, maxOutput: 8192, reasoning: true },\n\n // xAI / Grok\n { id: \"xai/grok-3\", name: \"Grok 3\", inputPrice: 3.0, outputPrice: 15.0, contextWindow: 131072, maxOutput: 16384, reasoning: true },\n { id: \"xai/grok-3-fast\", name: \"Grok 3 Fast\", inputPrice: 5.0, outputPrice: 25.0, contextWindow: 131072, maxOutput: 16384, reasoning: true },\n { id: \"xai/grok-3-mini\", name: \"Grok 3 Mini\", inputPrice: 0.3, outputPrice: 0.5, contextWindow: 131072, maxOutput: 16384 },\n];\n\n/**\n * Convert BlockRun model definitions to OpenClaw ModelDefinitionConfig format.\n */\nfunction toOpenClawModel(m: BlockRunModel): ModelDefinitionConfig {\n return {\n id: m.id,\n name: m.name,\n api: \"openai-completions\",\n reasoning: m.reasoning ?? false,\n input: m.vision ? [\"text\", \"image\"] : [\"text\"],\n cost: {\n input: m.inputPrice,\n output: m.outputPrice,\n cacheRead: 0,\n cacheWrite: 0,\n },\n contextWindow: m.contextWindow,\n maxTokens: m.maxOutput,\n };\n}\n\n/**\n * All BlockRun models in OpenClaw format.\n */\nexport const OPENCLAW_MODELS: ModelDefinitionConfig[] = BLOCKRUN_MODELS.map(toOpenClawModel);\n\n/**\n * Build a ModelProviderConfig for BlockRun.\n *\n * @param baseUrl - The proxy's local base URL (e.g., \"http://127.0.0.1:12345\")\n */\nexport function buildProviderModels(baseUrl: string): ModelProviderConfig {\n return {\n baseUrl: `${baseUrl}/v1`,\n api: \"openai-completions\",\n models: OPENCLAW_MODELS,\n };\n}\n","/**\n * BlockRun ProviderPlugin for OpenClaw\n *\n * Registers BlockRun as an LLM provider in OpenClaw.\n * Uses a local x402 proxy to handle micropayments transparently —\n * pi-ai sees a standard OpenAI-compatible API at localhost.\n */\n\nimport type { ProviderPlugin, AuthProfileCredential } from \"./types.js\";\nimport { walletKeyAuth, envKeyAuth } from \"./auth.js\";\nimport { buildProviderModels } from \"./models.js\";\nimport type { ProxyHandle } from \"./proxy.js\";\n\n/**\n * State for the running proxy (set when the plugin activates).\n */\nlet activeProxy: ProxyHandle | null = null;\n\n/**\n * Update the proxy handle (called from index.ts when the proxy starts).\n */\nexport function setActiveProxy(proxy: ProxyHandle): void {\n activeProxy = proxy;\n}\n\nexport function getActiveProxy(): ProxyHandle | null {\n return activeProxy;\n}\n\n/**\n * BlockRun provider plugin definition.\n */\nexport const blockrunProvider: ProviderPlugin = {\n id: \"blockrun\",\n label: \"BlockRun\",\n docsPath: \"https://blockrun.ai/docs\",\n aliases: [\"br\"],\n envVars: [\"BLOCKRUN_WALLET_KEY\"],\n\n // Model definitions — dynamically set to proxy URL\n get models() {\n if (!activeProxy) {\n // Fallback: point to BlockRun API directly (won't handle x402, but\n // allows config loading before proxy starts)\n return buildProviderModels(\"https://blockrun.ai/api\");\n }\n return buildProviderModels(activeProxy.baseUrl);\n },\n\n // Auth methods\n auth: [envKeyAuth, walletKeyAuth],\n\n // Format the stored credential as the wallet key\n formatApiKey: (cred: AuthProfileCredential): string => {\n if (\"apiKey\" in cred && typeof cred.apiKey === \"string\") {\n return cred.apiKey;\n }\n throw new Error(\"BlockRun credential must contain an apiKey (wallet private key)\");\n },\n};\n","/**\n * Local x402 Proxy Server\n *\n * Sits between OpenClaw's pi-ai (which makes standard OpenAI-format requests)\n * and BlockRun's API (which requires x402 micropayments).\n *\n * Flow:\n * pi-ai → http://localhost:{port}/v1/chat/completions\n * → proxy forwards to https://blockrun.ai/api/v1/chat/completions\n * → gets 402 → @x402/fetch signs payment → retries\n * → streams response back to pi-ai\n *\n * Phase 2 additions:\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 } from \"./x402.js\";\nimport { route, getFallbackChain, DEFAULT_ROUTING_CONFIG, type RouterOptions, type RoutingDecision, type RoutingConfig, type ModelPricing } from \"./router/index.js\";\nimport { BLOCKRUN_MODELS } from \"./models.js\";\nimport { logUsage, type UsageEntry } from \"./logger.js\";\n\nconst BLOCKRUN_API = \"https://blockrun.ai/api\";\nconst AUTO_MODEL = \"blockrun/auto\";\nconst USER_AGENT = \"clawrouter/0.2.2\";\n\nexport type ProxyOptions = {\n walletKey: string;\n apiBase?: string;\n port?: number;\n routingConfig?: Partial<RoutingConfig>;\n onReady?: (port: number) => void;\n onError?: (error: Error) => void;\n onPayment?: (info: { model: string; amount: string; network: string }) => void;\n onRouted?: (decision: RoutingDecision) => void;\n};\n\nexport type ProxyHandle = {\n port: number;\n baseUrl: string;\n close: () => Promise<void>;\n};\n\n/**\n * Build model pricing map from BLOCKRUN_MODELS.\n */\nfunction buildModelPricing(): Map<string, ModelPricing> {\n const map = new Map<string, ModelPricing>();\n for (const m of BLOCKRUN_MODELS) {\n if (m.id === AUTO_MODEL) continue; // skip meta-model\n map.set(m.id, { inputPrice: m.inputPrice, outputPrice: m.outputPrice });\n }\n return map;\n}\n\n/**\n * Merge partial routing config overrides with defaults.\n */\nfunction mergeRoutingConfig(overrides?: Partial<RoutingConfig>): RoutingConfig {\n if (!overrides) return DEFAULT_ROUTING_CONFIG;\n return {\n ...DEFAULT_ROUTING_CONFIG,\n ...overrides,\n classifier: { ...DEFAULT_ROUTING_CONFIG.classifier, ...overrides.classifier },\n scoring: { ...DEFAULT_ROUTING_CONFIG.scoring, ...overrides.scoring },\n tiers: { ...DEFAULT_ROUTING_CONFIG.tiers, ...overrides.tiers },\n overrides: { ...DEFAULT_ROUTING_CONFIG.overrides, ...overrides.overrides },\n };\n}\n\n/**\n * 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 payFetch = createPaymentFetch(options.walletKey as `0x${string}`);\n\n // Build router options\n const routingConfig = mergeRoutingConfig(options.routingConfig);\n const modelPricing = buildModelPricing();\n const routerOpts: RouterOptions = {\n config: routingConfig,\n modelPricing,\n payFetch,\n apiBase,\n };\n\n const server = createServer(async (req: IncomingMessage, res: ServerResponse) => {\n // Health check\n if (req.url === \"/health\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ status: \"ok\", wallet: account.address }));\n return;\n }\n\n // Only proxy paths starting with /v1\n if (!req.url?.startsWith(\"/v1\")) {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Not found\" }));\n return;\n }\n\n try {\n await proxyRequest(req, res, apiBase, payFetch, options, routerOpts);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n options.onError?.(error);\n\n if (!res.headersSent) {\n res.writeHead(502, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({\n error: { message: `Proxy error: ${error.message}`, type: \"proxy_error\" },\n }));\n }\n }\n });\n\n // Listen on requested port (0 = random available port)\n const listenPort = options.port ?? 0;\n\n return new Promise<ProxyHandle>((resolve, reject) => {\n server.on(\"error\", reject);\n\n server.listen(listenPort, \"127.0.0.1\", () => {\n const addr = server.address() as AddressInfo;\n const port = addr.port;\n const baseUrl = `http://127.0.0.1:${port}`;\n\n options.onReady?.(port);\n\n resolve({\n port,\n baseUrl,\n close: () =>\n new Promise<void>((res, rej) => {\n server.close((err) => (err ? rej(err) : res()));\n }),\n });\n });\n });\n}\n\n/**\n * Proxy a single request through x402 payment flow to BlockRun API.\n *\n * When model is \"blockrun/auto\", runs the smart router to pick the\n * cheapest capable model before forwarding.\n */\nasync function proxyRequest(\n req: IncomingMessage,\n res: ServerResponse,\n apiBase: string,\n payFetch: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>,\n options: ProxyOptions,\n routerOpts: RouterOptions,\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 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\n if (parsed.model === AUTO_MODEL) {\n // Extract prompt from messages\n type ChatMessage = { role: string; content: string };\n const messages = parsed.messages as ChatMessage[] | undefined;\n let lastUserMsg: ChatMessage | undefined;\n if (messages) {\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].role === \"user\") { lastUserMsg = messages[i]; break; }\n }\n }\n const systemMsg = messages?.find((m: ChatMessage) => m.role === \"system\");\n const prompt = typeof lastUserMsg?.content === \"string\" ? lastUserMsg.content : \"\";\n const systemPrompt = typeof systemMsg?.content === \"string\" ? systemMsg.content : undefined;\n const maxTokens = (parsed.max_tokens as number) || 4096;\n\n routingDecision = await route(prompt, systemPrompt, maxTokens, routerOpts);\n\n // Replace model in body\n parsed.model = 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 // Forward headers, stripping host, connection, and content-length\n // (content-length may be wrong after body modification for routing)\n const headers: Record<string, string> = {};\n for (const [key, value] of Object.entries(req.headers)) {\n if (key === \"host\" || key === \"connection\" || key === \"transfer-encoding\" || key === \"content-length\") continue;\n if (typeof value === \"string\") {\n headers[key] = value;\n }\n }\n // Ensure content-type is set\n if (!headers[\"content-type\"]) {\n headers[\"content-type\"] = \"application/json\";\n }\n // Set User-Agent for BlockRun API tracking\n headers[\"user-agent\"] = USER_AGENT;\n\n // Make the request through x402-wrapped fetch\n // This handles: request → 402 → sign payment → retry with PAYMENT-SIGNATURE header\n const upstream = await payFetch(upstreamUrl, {\n method: req.method ?? \"POST\",\n headers,\n body: body.length > 0 ? body : undefined,\n });\n\n // Forward status and headers from upstream\n const responseHeaders: Record<string, string> = {};\n upstream.headers.forEach((value, key) => {\n // Skip hop-by-hop headers\n if (key === \"transfer-encoding\" || key === \"connection\") return;\n responseHeaders[key] = value;\n });\n\n res.writeHead(upstream.status, responseHeaders);\n\n // Stream the response body\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 }\n } finally {\n reader.releaseLock();\n }\n }\n\n res.end();\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\nimport { signTypedData, privateKeyToAccount } from \"viem/accounts\";\n\nconst BASE_CHAIN_ID = 8453;\nconst USDC_BASE = \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\" as const;\n\nconst USDC_DOMAIN = {\n name: \"USD Coin\",\n version: \"2\",\n chainId: BASE_CHAIN_ID,\n verifyingContract: USDC_BASE,\n} as const;\n\nconst TRANSFER_TYPES = {\n TransferWithAuthorization: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n ],\n} as const;\n\nfunction createNonce(): `0x${string}` {\n const bytes = new Uint8Array(32);\n crypto.getRandomValues(bytes);\n return `0x${Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('')}` as `0x${string}`;\n}\n\ninterface PaymentOption {\n scheme: string;\n network: string;\n amount?: string;\n maxAmountRequired?: string;\n asset: string;\n payTo: string;\n maxTimeoutSeconds?: number;\n extra?: { name?: string; version?: string };\n}\n\ninterface PaymentRequired {\n accepts: PaymentOption[];\n resource?: { url?: string; description?: string };\n}\n\nfunction parsePaymentRequired(headerValue: string): PaymentRequired {\n const decoded = atob(headerValue);\n return JSON.parse(decoded) as PaymentRequired;\n}\n\nasync function createPaymentPayload(\n privateKey: `0x${string}`,\n fromAddress: string,\n recipient: string,\n amount: string,\n resourceUrl: string\n): Promise<string> {\n const now = Math.floor(Date.now() / 1000);\n const validAfter = now - 600;\n const validBefore = now + 300;\n const nonce = createNonce();\n\n const signature = await signTypedData({\n privateKey,\n domain: USDC_DOMAIN,\n types: TRANSFER_TYPES,\n primaryType: \"TransferWithAuthorization\",\n message: {\n from: fromAddress as `0x${string}`,\n to: recipient as `0x${string}`,\n value: BigInt(amount),\n validAfter: BigInt(validAfter),\n validBefore: BigInt(validBefore),\n nonce,\n },\n });\n\n const paymentData = {\n x402Version: 2,\n resource: {\n url: resourceUrl,\n description: \"BlockRun AI API call\",\n mimeType: \"application/json\",\n },\n accepted: {\n scheme: \"exact\",\n network: \"eip155:8453\",\n amount,\n asset: USDC_BASE,\n payTo: recipient,\n maxTimeoutSeconds: 300,\n extra: { name: \"USD Coin\", version: \"2\" },\n },\n payload: {\n signature,\n authorization: {\n from: fromAddress,\n to: recipient,\n value: amount,\n validAfter: validAfter.toString(),\n validBefore: validBefore.toString(),\n nonce,\n },\n },\n extensions: {},\n };\n\n return btoa(JSON.stringify(paymentData));\n}\n\n/**\n * Create a fetch wrapper that handles x402 payment automatically.\n */\nexport function createPaymentFetch(privateKey: `0x${string}`): (input: RequestInfo | URL, init?: RequestInit) => Promise<Response> {\n const account = privateKeyToAccount(privateKey);\n const walletAddress = account.address;\n\n return async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n const url = typeof input === \"string\" ? input : input instanceof URL ? input.href : input.url;\n\n // First request - may get 402\n const response = await fetch(input, init);\n\n if (response.status !== 402) {\n return response;\n }\n\n // Parse 402 payment requirements\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 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 // 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","/**\n * Rule-Based Classifier (v2 — Weighted Scoring)\n *\n * Scores a request across 14 weighted dimensions and maps the aggregate\n * score to a tier using configurable boundaries. Confidence is calibrated\n * via sigmoid — low confidence triggers the fallback classifier.\n *\n * Handles 70-80% of requests in < 1ms with zero cost.\n */\n\nimport type { Tier, ScoringResult, ScoringConfig } from \"./types.js\";\n\ntype DimensionScore = { name: string; score: number; signal: string | null };\n\n// ─── Dimension Scorers ───\n// Each returns a score in [-1, 1] and an optional signal string.\n\nfunction scoreTokenCount(\n estimatedTokens: number,\n thresholds: { simple: number; complex: number },\n): DimensionScore {\n if (estimatedTokens < thresholds.simple) {\n return { name: \"tokenCount\", score: -1.0, signal: `short (${estimatedTokens} tokens)` };\n }\n if (estimatedTokens > thresholds.complex) {\n return { name: \"tokenCount\", score: 1.0, signal: `long (${estimatedTokens} tokens)` };\n }\n return { name: \"tokenCount\", score: 0, signal: null };\n}\n\nfunction scoreKeywordMatch(\n text: string,\n keywords: string[],\n name: string,\n signalLabel: string,\n thresholds: { low: number; high: number },\n scores: { none: number; low: number; high: number },\n): DimensionScore {\n const matches = keywords.filter((kw) => text.includes(kw.toLowerCase()));\n if (matches.length >= thresholds.high) {\n return { name, score: scores.high, signal: `${signalLabel} (${matches.slice(0, 3).join(\", \")})` };\n }\n if (matches.length >= thresholds.low) {\n return { name, score: scores.low, signal: `${signalLabel} (${matches.slice(0, 3).join(\", \")})` };\n }\n return { name, score: scores.none, signal: null };\n}\n\nfunction scoreMultiStep(text: string): DimensionScore {\n const patterns = [/first.*then/i, /step \\d/i, /\\d\\.\\s/];\n const hits = patterns.filter((p) => p.test(text));\n if (hits.length > 0) {\n return { name: \"multiStepPatterns\", score: 0.5, signal: \"multi-step\" };\n }\n return { name: \"multiStepPatterns\", score: 0, signal: null };\n}\n\nfunction scoreQuestionComplexity(prompt: string): DimensionScore {\n const count = (prompt.match(/\\?/g) || []).length;\n if (count > 3) {\n return { name: \"questionComplexity\", score: 0.5, signal: `${count} questions` };\n }\n return { name: \"questionComplexity\", score: 0, signal: null };\n}\n\n// ─── Main Classifier ───\n\nexport function classifyByRules(\n prompt: string,\n systemPrompt: string | undefined,\n estimatedTokens: number,\n config: ScoringConfig,\n): ScoringResult {\n const text = `${systemPrompt ?? \"\"} ${prompt}`.toLowerCase();\n\n // Score all 14 dimensions\n const dimensions: DimensionScore[] = [\n // Original 8 dimensions\n scoreTokenCount(estimatedTokens, config.tokenCountThresholds),\n scoreKeywordMatch(text, config.codeKeywords, \"codePresence\", \"code\",\n { low: 1, high: 2 }, { none: 0, low: 0.5, high: 1.0 }),\n scoreKeywordMatch(text, config.reasoningKeywords, \"reasoningMarkers\", \"reasoning\",\n { low: 1, high: 2 }, { none: 0, low: 0.7, high: 1.0 }),\n scoreKeywordMatch(text, config.technicalKeywords, \"technicalTerms\", \"technical\",\n { low: 2, high: 4 }, { none: 0, low: 0.5, high: 1.0 }),\n scoreKeywordMatch(text, config.creativeKeywords, \"creativeMarkers\", \"creative\",\n { low: 1, high: 2 }, { none: 0, low: 0.5, high: 0.7 }),\n scoreKeywordMatch(text, config.simpleKeywords, \"simpleIndicators\", \"simple\",\n { low: 1, high: 2 }, { none: 0, low: -1.0, high: -1.0 }),\n scoreMultiStep(text),\n scoreQuestionComplexity(prompt),\n\n // 6 new dimensions\n scoreKeywordMatch(text, config.imperativeVerbs, \"imperativeVerbs\", \"imperative\",\n { low: 1, high: 2 }, { none: 0, low: 0.3, high: 0.5 }),\n scoreKeywordMatch(text, config.constraintIndicators, \"constraintCount\", \"constraints\",\n { low: 1, high: 3 }, { none: 0, low: 0.3, high: 0.7 }),\n scoreKeywordMatch(text, config.outputFormatKeywords, \"outputFormat\", \"format\",\n { low: 1, high: 2 }, { none: 0, low: 0.4, high: 0.7 }),\n scoreKeywordMatch(text, config.referenceKeywords, \"referenceComplexity\", \"references\",\n { low: 1, high: 2 }, { none: 0, low: 0.3, high: 0.5 }),\n scoreKeywordMatch(text, config.negationKeywords, \"negationComplexity\", \"negation\",\n { low: 2, high: 3 }, { none: 0, low: 0.3, high: 0.5 }),\n scoreKeywordMatch(text, config.domainSpecificKeywords, \"domainSpecificity\", \"domain-specific\",\n { low: 1, high: 2 }, { none: 0, low: 0.5, high: 0.8 }),\n ];\n\n // Collect signals\n const signals = dimensions\n .filter((d) => d.signal !== null)\n .map((d) => d.signal!);\n\n // Compute weighted score\n const weights = config.dimensionWeights;\n let weightedScore = 0;\n for (const d of dimensions) {\n const w = weights[d.name] ?? 0;\n weightedScore += d.score * w;\n }\n\n // Count reasoning markers for override\n const reasoningMatches = config.reasoningKeywords.filter((kw) =>\n text.includes(kw.toLowerCase()),\n );\n\n // Direct reasoning override: 2+ reasoning markers = high confidence REASONING\n if (reasoningMatches.length >= 2) {\n const confidence = calibrateConfidence(\n Math.max(weightedScore, 0.3), // ensure positive for confidence calc\n config.confidenceSteepness,\n );\n return {\n score: weightedScore,\n tier: \"REASONING\",\n confidence: Math.max(confidence, 0.85),\n signals,\n };\n }\n\n // Map weighted score to tier using boundaries\n const { simpleMedium, mediumComplex, complexReasoning } = config.tierBoundaries;\n let tier: Tier;\n let distanceFromBoundary: number;\n\n if (weightedScore < simpleMedium) {\n tier = \"SIMPLE\";\n distanceFromBoundary = simpleMedium - weightedScore;\n } else if (weightedScore < mediumComplex) {\n tier = \"MEDIUM\";\n distanceFromBoundary = Math.min(\n weightedScore - simpleMedium,\n mediumComplex - weightedScore,\n );\n } else if (weightedScore < complexReasoning) {\n tier = \"COMPLEX\";\n distanceFromBoundary = Math.min(\n weightedScore - mediumComplex,\n complexReasoning - weightedScore,\n );\n } else {\n tier = \"REASONING\";\n distanceFromBoundary = weightedScore - complexReasoning;\n }\n\n // Calibrate confidence via sigmoid of distance from nearest boundary\n const confidence = calibrateConfidence(distanceFromBoundary, config.confidenceSteepness);\n\n // If confidence is below threshold → ambiguous\n if (confidence < config.confidenceThreshold) {\n return { score: weightedScore, tier: null, confidence, signals };\n }\n\n return { score: weightedScore, tier, confidence, signals };\n}\n\n/**\n * Sigmoid confidence calibration.\n * Maps distance from tier boundary to [0.5, 1.0] confidence range.\n */\nfunction calibrateConfidence(distance: number, steepness: number): number {\n return 1 / (1 + Math.exp(-steepness * distance));\n}\n","/**\n * LLM Classifier (Fallback)\n *\n * When the rule-based classifier returns ambiguous (score 1-2),\n * we send a classification request to the cheapest model.\n *\n * Cost per classification: ~$0.00003\n * Latency: ~200-400ms\n * Only triggered for ~20-30% of requests.\n */\n\nimport type { Tier } from \"./types.js\";\n\nconst CLASSIFIER_PROMPT = `You are a query complexity classifier. Classify the user's query into exactly one category.\n\nCategories:\n- SIMPLE: Factual Q&A, definitions, translations, short answers\n- MEDIUM: Summaries, explanations, moderate code generation\n- COMPLEX: Multi-step code, system design, creative writing, analysis\n- REASONING: Mathematical proofs, formal logic, step-by-step problem solving\n\nRespond with ONLY one word: SIMPLE, MEDIUM, COMPLEX, or REASONING.`;\n\n// In-memory cache: hash → { tier, expires }\nconst cache = new Map<string, { tier: Tier; expires: number }>();\n\nexport type LLMClassifierConfig = {\n model: string;\n maxTokens: number;\n temperature: number;\n truncationChars: number;\n cacheTtlMs: number;\n};\n\ntype PayFetch = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;\n\n/**\n * Classify a prompt using a cheap LLM.\n * Returns tier and confidence. Defaults to MEDIUM on any failure.\n */\nexport async function classifyByLLM(\n prompt: string,\n config: LLMClassifierConfig,\n payFetch: PayFetch,\n apiBase: string,\n): Promise<{ tier: Tier; confidence: number }> {\n const truncated = prompt.slice(0, config.truncationChars);\n\n // Check cache\n const cacheKey = simpleHash(truncated);\n const cached = cache.get(cacheKey);\n if (cached && cached.expires > Date.now()) {\n return { tier: cached.tier, confidence: 0.75 };\n }\n\n try {\n const response = await payFetch(`${apiBase}/v1/chat/completions`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model: config.model,\n messages: [\n { role: \"system\", content: CLASSIFIER_PROMPT },\n { role: \"user\", content: truncated },\n ],\n max_tokens: config.maxTokens,\n temperature: config.temperature,\n stream: false,\n }),\n });\n\n if (!response.ok) {\n return { tier: \"MEDIUM\", confidence: 0.5 };\n }\n\n const data = (await response.json()) as {\n choices?: Array<{ message?: { content?: string } }>;\n };\n\n const content = data.choices?.[0]?.message?.content?.trim().toUpperCase() ?? \"\";\n const tier = parseTier(content);\n\n // Cache result\n cache.set(cacheKey, { tier, expires: Date.now() + config.cacheTtlMs });\n\n // Prune if cache grows too large\n if (cache.size > 1000) {\n pruneCache();\n }\n\n return { tier, confidence: 0.75 };\n } catch {\n // Any error → safe default\n return { tier: \"MEDIUM\", confidence: 0.5 };\n }\n}\n\n/**\n * Parse tier from LLM response. Handles \"SIMPLE\", \"The query is SIMPLE\", etc.\n */\nfunction parseTier(text: string): Tier {\n if (/\\bREASONING\\b/.test(text)) return \"REASONING\";\n if (/\\bCOMPLEX\\b/.test(text)) return \"COMPLEX\";\n if (/\\bMEDIUM\\b/.test(text)) return \"MEDIUM\";\n if (/\\bSIMPLE\\b/.test(text)) return \"SIMPLE\";\n return \"MEDIUM\"; // safe default\n}\n\nfunction simpleHash(str: string): string {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = ((hash << 5) - hash) + char;\n hash |= 0;\n }\n return hash.toString(36);\n}\n\nfunction pruneCache(): void {\n const now = Date.now();\n for (const [key, value] of cache) {\n if (value.expires <= now) {\n cache.delete(key);\n }\n }\n}\n","/**\n * Tier → Model Selection\n *\n * Maps a classification tier to the cheapest capable model.\n * Builds RoutingDecision metadata with cost estimates and savings.\n */\n\nimport type { Tier, TierConfig, RoutingDecision } from \"./types.js\";\n\nexport type ModelPricing = {\n inputPrice: number; // per 1M tokens\n outputPrice: number; // per 1M tokens\n};\n\n/**\n * Select the primary model for a tier and build the RoutingDecision.\n */\nexport function selectModel(\n tier: Tier,\n confidence: number,\n method: \"rules\" | \"llm\",\n reasoning: string,\n tierConfigs: Record<Tier, TierConfig>,\n modelPricing: Map<string, ModelPricing>,\n estimatedInputTokens: number,\n maxOutputTokens: number,\n): RoutingDecision {\n const tierConfig = tierConfigs[tier];\n const model = tierConfig.primary;\n const pricing = modelPricing.get(model);\n\n const inputCost = pricing\n ? (estimatedInputTokens / 1_000_000) * pricing.inputPrice\n : 0;\n const outputCost = pricing\n ? (maxOutputTokens / 1_000_000) * pricing.outputPrice\n : 0;\n const costEstimate = inputCost + outputCost;\n\n // Baseline: what Claude Opus would cost (the premium default)\n const opusPricing = modelPricing.get(\"anthropic/claude-opus-4\");\n const baselineInput = opusPricing\n ? (estimatedInputTokens / 1_000_000) * opusPricing.inputPrice\n : 0;\n const baselineOutput = opusPricing\n ? (maxOutputTokens / 1_000_000) * opusPricing.outputPrice\n : 0;\n const baselineCost = baselineInput + baselineOutput;\n\n const savings =\n baselineCost > 0\n ? Math.max(0, (baselineCost - costEstimate) / baselineCost)\n : 0;\n\n return {\n model,\n tier,\n confidence,\n method,\n reasoning,\n costEstimate,\n baselineCost,\n savings,\n };\n}\n\n/**\n * Get the ordered fallback chain for a tier: [primary, ...fallbacks].\n */\nexport function getFallbackChain(\n tier: Tier,\n tierConfigs: Record<Tier, TierConfig>,\n): string[] {\n const config = tierConfigs[tier];\n return [config.primary, ...config.fallback];\n}\n","/**\n * Default Routing Config\n *\n * All routing parameters as a TypeScript constant.\n * Operators override via openclaw.yaml plugin config.\n *\n * Scoring uses 14 weighted dimensions with sigmoid confidence calibration.\n */\n\nimport type { RoutingConfig } from \"./types.js\";\n\nexport const DEFAULT_ROUTING_CONFIG: RoutingConfig = {\n version: \"2.0\",\n\n classifier: {\n llmModel: \"google/gemini-2.5-flash\",\n llmMaxTokens: 10,\n llmTemperature: 0,\n promptTruncationChars: 500,\n cacheTtlMs: 3_600_000, // 1 hour\n },\n\n scoring: {\n tokenCountThresholds: { simple: 50, complex: 500 },\n codeKeywords: [\n \"function\", \"class\", \"import\", \"def\", \"SELECT\", \"async\", \"await\",\n \"const\", \"let\", \"var\", \"return\", \"```\",\n ],\n reasoningKeywords: [\n \"prove\", \"theorem\", \"derive\", \"step by step\", \"chain of thought\",\n \"formally\", \"mathematical\", \"proof\", \"logically\",\n ],\n simpleKeywords: [\n \"what is\", \"define\", \"translate\", \"hello\", \"yes or no\",\n \"capital of\", \"how old\", \"who is\", \"when was\",\n ],\n technicalKeywords: [\n \"algorithm\", \"optimize\", \"architecture\", \"distributed\",\n \"kubernetes\", \"microservice\", \"database\", \"infrastructure\",\n ],\n creativeKeywords: [\n \"story\", \"poem\", \"compose\", \"brainstorm\", \"creative\",\n \"imagine\", \"write a\",\n ],\n\n // New dimension keyword lists\n imperativeVerbs: [\n \"build\", \"create\", \"implement\", \"design\", \"develop\", \"construct\",\n \"generate\", \"deploy\", \"configure\", \"set up\",\n ],\n constraintIndicators: [\n \"under\", \"at most\", \"at least\", \"within\", \"no more than\",\n \"o(\", \"maximum\", \"minimum\", \"limit\", \"budget\",\n ],\n outputFormatKeywords: [\n \"json\", \"yaml\", \"xml\", \"table\", \"csv\", \"markdown\",\n \"schema\", \"format as\", \"structured\",\n ],\n referenceKeywords: [\n \"above\", \"below\", \"previous\", \"following\", \"the docs\",\n \"the api\", \"the code\", \"earlier\", \"attached\",\n ],\n negationKeywords: [\n \"don't\", \"do not\", \"avoid\", \"never\", \"without\",\n \"except\", \"exclude\", \"no longer\",\n ],\n domainSpecificKeywords: [\n \"quantum\", \"fpga\", \"vlsi\", \"risc-v\", \"asic\", \"photonics\",\n \"genomics\", \"proteomics\", \"topological\", \"homomorphic\",\n \"zero-knowledge\", \"lattice-based\",\n ],\n\n // Dimension weights (sum to 1.0)\n dimensionWeights: {\n tokenCount: 0.08,\n codePresence: 0.15,\n reasoningMarkers: 0.18,\n technicalTerms: 0.10,\n creativeMarkers: 0.05,\n simpleIndicators: 0.12,\n multiStepPatterns: 0.12,\n questionComplexity: 0.05,\n imperativeVerbs: 0.03,\n constraintCount: 0.04,\n outputFormat: 0.03,\n referenceComplexity: 0.02,\n negationComplexity: 0.01,\n domainSpecificity: 0.02,\n },\n\n // Tier boundaries on weighted score axis\n tierBoundaries: {\n simpleMedium: 0.0,\n mediumComplex: 0.15,\n complexReasoning: 0.25,\n },\n\n // Sigmoid steepness for confidence calibration\n confidenceSteepness: 12,\n // Below this confidence → ambiguous (null tier)\n confidenceThreshold: 0.70,\n },\n\n tiers: {\n SIMPLE: {\n primary: \"google/gemini-2.5-flash\",\n fallback: [\"deepseek/deepseek-chat\", \"openai/gpt-4o-mini\"],\n },\n MEDIUM: {\n primary: \"deepseek/deepseek-chat\",\n fallback: [\"google/gemini-2.5-flash\", \"openai/gpt-4o-mini\"],\n },\n COMPLEX: {\n primary: \"anthropic/claude-opus-4\",\n fallback: [\"anthropic/claude-sonnet-4\", \"openai/gpt-4o\"],\n },\n REASONING: {\n primary: \"openai/o3\",\n fallback: [\"google/gemini-2.5-pro\", \"anthropic/claude-sonnet-4\"],\n },\n },\n\n overrides: {\n maxTokensForceComplex: 100_000,\n structuredOutputMinTier: \"MEDIUM\",\n },\n};\n","/**\n * Smart Router Entry Point\n *\n * Classifies requests and routes to the cheapest capable model.\n * Uses hybrid approach: rules first (< 1ms), LLM fallback for ambiguous cases.\n */\n\nimport type { Tier, RoutingDecision, RoutingConfig } from \"./types.js\";\nimport { classifyByRules } from \"./rules.js\";\nimport { classifyByLLM } from \"./llm-classifier.js\";\nimport { selectModel, getFallbackChain, type ModelPricing } from \"./selector.js\";\n\nexport type RouterOptions = {\n config: RoutingConfig;\n modelPricing: Map<string, ModelPricing>;\n payFetch: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;\n apiBase: string;\n};\n\n/**\n * Route a request to the cheapest capable model.\n *\n * 1. Check overrides (large context, structured output)\n * 2. Run rule-based classifier\n * 3. If ambiguous, run LLM classifier\n * 4. Select model for tier\n * 5. Return RoutingDecision with metadata\n */\nexport async function route(\n prompt: string,\n systemPrompt: string | undefined,\n maxOutputTokens: number,\n options: RouterOptions,\n): Promise<RoutingDecision> {\n const { config, modelPricing, payFetch, apiBase } = options;\n\n // Estimate input tokens (~4 chars per token)\n const fullText = `${systemPrompt ?? \"\"} ${prompt}`;\n const estimatedTokens = Math.ceil(fullText.length / 4);\n\n // --- Override: large context → force COMPLEX ---\n if (estimatedTokens > config.overrides.maxTokensForceComplex) {\n return selectModel(\n \"COMPLEX\",\n 0.95,\n \"rules\",\n `Input exceeds ${config.overrides.maxTokensForceComplex} tokens`,\n config.tiers,\n modelPricing,\n estimatedTokens,\n maxOutputTokens,\n );\n }\n\n // Structured output detection\n const hasStructuredOutput = systemPrompt\n ? /json|structured|schema/i.test(systemPrompt)\n : false;\n\n // --- Rule-based classification ---\n const ruleResult = classifyByRules(\n prompt,\n systemPrompt,\n estimatedTokens,\n config.scoring,\n );\n\n let tier: Tier;\n let confidence: number;\n let method: \"rules\" | \"llm\" = \"rules\";\n let reasoning = `score=${ruleResult.score} | ${ruleResult.signals.join(\", \")}`;\n\n if (ruleResult.tier !== null) {\n tier = ruleResult.tier;\n confidence = ruleResult.confidence;\n } else {\n // Ambiguous — LLM classifier fallback\n const llmResult = await classifyByLLM(\n prompt,\n {\n model: config.classifier.llmModel,\n maxTokens: config.classifier.llmMaxTokens,\n temperature: config.classifier.llmTemperature,\n truncationChars: config.classifier.promptTruncationChars,\n cacheTtlMs: config.classifier.cacheTtlMs,\n },\n payFetch,\n apiBase,\n );\n\n tier = llmResult.tier;\n confidence = llmResult.confidence;\n method = \"llm\";\n reasoning += ` | ambiguous -> LLM: ${tier}`;\n }\n\n // Apply structured output minimum tier\n if (hasStructuredOutput) {\n const tierRank: Record<Tier, number> = { SIMPLE: 0, MEDIUM: 1, COMPLEX: 2, REASONING: 3 };\n const minTier = config.overrides.structuredOutputMinTier;\n if (tierRank[tier] < tierRank[minTier]) {\n reasoning += ` | upgraded to ${minTier} (structured output)`;\n tier = minTier;\n }\n }\n\n return selectModel(\n tier,\n confidence,\n method,\n reasoning,\n config.tiers,\n modelPricing,\n estimatedTokens,\n maxOutputTokens,\n );\n}\n\nexport { getFallbackChain } from \"./selector.js\";\nexport { DEFAULT_ROUTING_CONFIG } from \"./config.js\";\nexport type { RoutingDecision, Tier, RoutingConfig } from \"./types.js\";\nexport type { ModelPricing } from \"./selector.js\";\n","/**\n * Usage Logger\n *\n * Logs every LLM request as a JSON line to a daily log file.\n * Files: ~/.openclaw/blockrun/logs/usage-YYYY-MM-DD.jsonl\n *\n * MVP: append-only JSON lines. No rotation, no cleanup.\n * Logging never breaks the request flow — all errors are swallowed.\n */\n\nimport { appendFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\nexport type UsageEntry = {\n timestamp: string;\n model: string;\n cost: number;\n latencyMs: number;\n};\n\nconst LOG_DIR = join(homedir(), \".openclaw\", \"blockrun\", \"logs\");\nlet dirReady = false;\n\nasync function ensureDir(): Promise<void> {\n if (dirReady) return;\n await mkdir(LOG_DIR, { recursive: true });\n dirReady = true;\n}\n\n/**\n * Log a usage entry as a JSON line.\n */\nexport async function logUsage(entry: UsageEntry): Promise<void> {\n try {\n await ensureDir();\n const date = entry.timestamp.slice(0, 10); // YYYY-MM-DD\n const file = join(LOG_DIR, `usage-${date}.jsonl`);\n await appendFile(file, JSON.stringify(entry) + \"\\n\");\n } catch {\n // Never break the request flow\n }\n}\n","/**\n * @blockrun/clawrouter\n *\n * Smart LLM router for OpenClaw — 30+ models, x402 micropayments, 78% cost savings.\n * Routes each request to the cheapest model that can handle it.\n *\n * Usage:\n * # Install the plugin\n * openclaw plugin install @blockrun/clawrouter\n *\n * # Fund your wallet with USDC on Base (address printed on install)\n *\n * # Use smart routing (auto-picks cheapest model)\n * openclaw config set model blockrun/auto\n *\n * # Or use any specific BlockRun model\n * openclaw config set model openai/gpt-5.2\n */\n\nimport type { OpenClawPluginDefinition, OpenClawPluginApi } from \"./types.js\";\nimport { blockrunProvider, setActiveProxy } from \"./provider.js\";\nimport { startProxy } from \"./proxy.js\";\nimport { resolveOrGenerateWalletKey } from \"./auth.js\";\nimport type { RoutingConfig } from \"./router/index.js\";\n\nconst plugin: OpenClawPluginDefinition = {\n id: \"clawrouter\",\n name: \"ClawRouter\",\n description: \"Smart LLM router — 30+ models, x402 micropayments, 78% cost savings\",\n version: \"0.2.2\",\n\n register(api: OpenClawPluginApi) {\n // Register BlockRun as a provider\n api.registerProvider(blockrunProvider);\n\n api.logger.info(\"BlockRun provider registered (30+ models via x402)\");\n },\n\n async activate(api: OpenClawPluginApi) {\n // Resolve wallet key: saved file → env var → auto-generate\n const { key: walletKey, address, source } = await resolveOrGenerateWalletKey();\n\n // Log wallet source\n if (source === \"generated\") {\n api.logger.info(`Generated new wallet: ${address}`);\n api.logger.info(`Fund with USDC on Base to start using ClawRouter.`);\n } else if (source === \"saved\") {\n api.logger.info(`Using saved wallet: ${address}`);\n } else {\n api.logger.info(`Using wallet from BLOCKRUN_WALLET_KEY: ${address}`);\n }\n\n // Resolve routing config overrides from plugin config\n const routingConfig = api.pluginConfig?.routing as Partial<RoutingConfig> | undefined;\n\n // Start the local x402 proxy\n try {\n const proxy = await startProxy({\n walletKey,\n routingConfig,\n onReady: (port) => {\n api.logger.info(`BlockRun x402 proxy listening on port ${port}`);\n },\n onError: (error) => {\n api.logger.error(`BlockRun proxy error: ${error.message}`);\n },\n onRouted: (decision) => {\n const cost = decision.costEstimate.toFixed(4);\n const saved = (decision.savings * 100).toFixed(0);\n api.logger.info(`${decision.model} $${cost} (saved ${saved}%)`);\n },\n });\n\n setActiveProxy(proxy);\n api.logger.info(`BlockRun provider active — ${proxy.baseUrl}/v1 (smart routing enabled)`);\n } catch (err) {\n api.logger.error(\n `Failed to start BlockRun proxy: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n },\n};\n\n\nexport default plugin;\n\n// Re-export for programmatic use\nexport { startProxy } from \"./proxy.js\";\nexport { blockrunProvider } from \"./provider.js\";\nexport { OPENCLAW_MODELS, BLOCKRUN_MODELS, buildProviderModels } from \"./models.js\";\nexport { route, DEFAULT_ROUTING_CONFIG } from \"./router/index.js\";\nexport type { RoutingDecision, RoutingConfig, Tier } from \"./router/index.js\";\nexport { logUsage } from \"./logger.js\";\nexport type { UsageEntry } from \"./logger.js\";\n"],"mappings":"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","names":["privateKeyToAccount","privateKeyToAccount","confidence","mkdir","join","homedir","privateKeyToAccount"]}
|
|
1
|
+
{"version":3,"sources":["../src/auth.ts","../src/models.ts","../src/provider.ts","../src/proxy.ts","../src/x402.ts","../src/router/rules.ts","../src/router/llm-classifier.ts","../src/router/selector.ts","../src/router/config.ts","../src/router/index.ts","../src/logger.ts","../src/index.ts"],"sourcesContent":["/**\n * BlockRun Auth Methods for OpenClaw\n *\n * Provides wallet-based authentication for the BlockRun provider.\n * Operators configure their wallet private key, which is used to\n * sign x402 micropayments for LLM inference.\n *\n * Three methods:\n * 1. Auto-generate — create a new wallet on first run, save to ~/.openclaw/blockrun/wallet.key\n * 2. Environment variable — read from BLOCKRUN_WALLET_KEY\n * 3. Manual input — operator enters private key via wizard\n */\n\nimport { writeFile, readFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { generatePrivateKey, privateKeyToAccount } from \"viem/accounts\";\nimport type { ProviderAuthMethod, ProviderAuthContext, ProviderAuthResult } from \"./types.js\";\n\nconst WALLET_DIR = join(homedir(), \".openclaw\", \"blockrun\");\nconst WALLET_FILE = join(WALLET_DIR, \"wallet.key\");\n\n/**\n * Try to load a previously auto-generated wallet key from disk.\n */\nasync function loadSavedWallet(): Promise<string | undefined> {\n try {\n const key = (await readFile(WALLET_FILE, \"utf-8\")).trim();\n if (key.startsWith(\"0x\") && key.length === 66) return key;\n } catch {\n // File doesn't exist yet\n }\n return undefined;\n}\n\n/**\n * Generate a new wallet, save to disk, return the private key.\n */\nasync function generateAndSaveWallet(): Promise<{ key: string; address: string }> {\n const key = generatePrivateKey();\n const account = privateKeyToAccount(key);\n await mkdir(WALLET_DIR, { recursive: true });\n await writeFile(WALLET_FILE, key + \"\\n\", { mode: 0o600 });\n return { key, address: account.address };\n}\n\n/**\n * Resolve wallet key: load saved → env var → auto-generate.\n * Called by index.ts before the auth wizard runs.\n */\nexport async function resolveOrGenerateWalletKey(): Promise<{ key: string; address: string; source: \"saved\" | \"env\" | \"generated\" }> {\n // 1. Previously saved wallet\n const saved = await loadSavedWallet();\n if (saved) {\n const account = privateKeyToAccount(saved as `0x${string}`);\n return { key: saved, address: account.address, source: \"saved\" };\n }\n\n // 2. Environment variable\n const envKey = process.env.BLOCKRUN_WALLET_KEY;\n if (typeof envKey === \"string\" && envKey.startsWith(\"0x\") && envKey.length === 66) {\n const account = privateKeyToAccount(envKey as `0x${string}`);\n return { key: envKey, address: account.address, source: \"env\" };\n }\n\n // 3. Auto-generate\n const { key, address } = await generateAndSaveWallet();\n return { key, address, source: \"generated\" };\n}\n\n/**\n * Auth method: operator enters their wallet private key directly.\n */\nexport const walletKeyAuth: ProviderAuthMethod = {\n id: \"wallet-key\",\n label: \"Wallet Private Key\",\n hint: \"Enter your EVM wallet private key (0x...) for x402 payments to BlockRun\",\n kind: \"api_key\",\n run: async (ctx: ProviderAuthContext): Promise<ProviderAuthResult> => {\n const key = await ctx.prompter.text({\n message: \"Enter your wallet private key (0x...)\",\n validate: (value: string) => {\n const trimmed = value.trim();\n if (!trimmed.startsWith(\"0x\")) return \"Key must start with 0x\";\n if (trimmed.length !== 66) return \"Key must be 66 characters (0x + 64 hex)\";\n if (!/^0x[0-9a-fA-F]{64}$/.test(trimmed)) return \"Key must be valid hex\";\n return undefined;\n },\n });\n\n if (!key || typeof key !== \"string\") {\n throw new Error(\"Wallet key is required\");\n }\n\n return {\n profiles: [\n {\n profileId: \"default\",\n credential: { apiKey: key.trim() },\n },\n ],\n notes: [\n \"Wallet key stored securely in OpenClaw credentials.\",\n \"Your wallet signs x402 USDC payments on Base for each LLM call.\",\n \"Fund your wallet with USDC on Base to start using BlockRun models.\",\n ],\n };\n },\n};\n\n/**\n * Auth method: read wallet key from BLOCKRUN_WALLET_KEY environment variable.\n */\nexport const envKeyAuth: ProviderAuthMethod = {\n id: \"env-key\",\n label: \"Environment Variable\",\n hint: \"Use BLOCKRUN_WALLET_KEY environment variable\",\n kind: \"api_key\",\n run: async (): Promise<ProviderAuthResult> => {\n const key = process.env.BLOCKRUN_WALLET_KEY;\n\n if (!key) {\n throw new Error(\n \"BLOCKRUN_WALLET_KEY environment variable is not set. \" +\n \"Set it to your EVM wallet private key (0x...).\",\n );\n }\n\n return {\n profiles: [\n {\n profileId: \"default\",\n credential: { apiKey: key.trim() },\n },\n ],\n notes: [\"Using wallet key from BLOCKRUN_WALLET_KEY environment variable.\"],\n };\n },\n};\n","/**\n * BlockRun Model Definitions for OpenClaw\n *\n * Maps BlockRun's 30+ AI models to OpenClaw's ModelDefinitionConfig format.\n * All models use the \"openai-completions\" API since BlockRun is OpenAI-compatible.\n *\n * Pricing is in USD per 1M tokens. Operators pay these rates via x402;\n * they set their own markup when reselling to end users (Phase 2).\n */\n\nimport type { ModelDefinitionConfig, ModelProviderConfig } from \"./types.js\";\n\ntype BlockRunModel = {\n id: string;\n name: string;\n inputPrice: number;\n outputPrice: number;\n contextWindow: number;\n maxOutput: number;\n reasoning?: boolean;\n vision?: boolean;\n};\n\nexport const BLOCKRUN_MODELS: BlockRunModel[] = [\n // Smart routing meta-model — proxy replaces with actual model\n { id: \"blockrun/auto\", name: \"BlockRun Smart Router\", inputPrice: 0, outputPrice: 0, contextWindow: 1_050_000, maxOutput: 128_000 },\n\n\n // OpenAI GPT-5 Family\n { id: \"openai/gpt-5.2\", name: \"GPT-5.2\", inputPrice: 1.75, outputPrice: 14.0, contextWindow: 400000, maxOutput: 128000, reasoning: true, vision: true },\n { id: \"openai/gpt-5-mini\", name: \"GPT-5 Mini\", inputPrice: 0.25, outputPrice: 2.0, contextWindow: 200000, maxOutput: 65536 },\n { id: \"openai/gpt-5-nano\", name: \"GPT-5 Nano\", inputPrice: 0.05, outputPrice: 0.4, contextWindow: 128000, maxOutput: 32768 },\n { id: \"openai/gpt-5.2-pro\", name: \"GPT-5.2 Pro\", inputPrice: 21.0, outputPrice: 168.0, contextWindow: 400000, maxOutput: 128000, reasoning: true },\n\n // OpenAI GPT-4 Family\n { id: \"openai/gpt-4.1\", name: \"GPT-4.1\", inputPrice: 2.0, outputPrice: 8.0, contextWindow: 128000, maxOutput: 16384, vision: true },\n { id: \"openai/gpt-4.1-mini\", name: \"GPT-4.1 Mini\", inputPrice: 0.4, outputPrice: 1.6, contextWindow: 128000, maxOutput: 16384 },\n { id: \"openai/gpt-4.1-nano\", name: \"GPT-4.1 Nano\", inputPrice: 0.1, outputPrice: 0.4, contextWindow: 128000, maxOutput: 16384 },\n { id: \"openai/gpt-4o\", name: \"GPT-4o\", inputPrice: 2.5, outputPrice: 10.0, contextWindow: 128000, maxOutput: 16384, vision: true },\n { id: \"openai/gpt-4o-mini\", name: \"GPT-4o Mini\", inputPrice: 0.15, outputPrice: 0.6, contextWindow: 128000, maxOutput: 16384 },\n\n // OpenAI O-series (Reasoning)\n { id: \"openai/o1\", name: \"o1\", inputPrice: 15.0, outputPrice: 60.0, contextWindow: 200000, maxOutput: 100000, reasoning: true },\n { id: \"openai/o1-mini\", name: \"o1-mini\", inputPrice: 1.1, outputPrice: 4.4, contextWindow: 128000, maxOutput: 65536, reasoning: true },\n { id: \"openai/o3\", name: \"o3\", inputPrice: 2.0, outputPrice: 8.0, contextWindow: 200000, maxOutput: 100000, reasoning: true },\n { id: \"openai/o3-mini\", name: \"o3-mini\", inputPrice: 1.1, outputPrice: 4.4, contextWindow: 128000, maxOutput: 65536, reasoning: true },\n { id: \"openai/o4-mini\", name: \"o4-mini\", inputPrice: 1.1, outputPrice: 4.4, contextWindow: 128000, maxOutput: 65536, reasoning: true },\n\n // Anthropic\n { id: \"anthropic/claude-haiku-4.5\", name: \"Claude Haiku 4.5\", inputPrice: 1.0, outputPrice: 5.0, contextWindow: 200000, maxOutput: 8192 },\n { id: \"anthropic/claude-sonnet-4\", name: \"Claude Sonnet 4\", inputPrice: 3.0, outputPrice: 15.0, contextWindow: 200000, maxOutput: 64000, reasoning: true },\n { id: \"anthropic/claude-opus-4\", name: \"Claude Opus 4\", inputPrice: 15.0, outputPrice: 75.0, contextWindow: 200000, maxOutput: 32000, reasoning: true },\n { id: \"anthropic/claude-opus-4.5\", name: \"Claude Opus 4.5\", inputPrice: 15.0, outputPrice: 75.0, contextWindow: 200000, maxOutput: 32000, reasoning: true },\n\n // Google\n { id: \"google/gemini-3-pro-preview\", name: \"Gemini 3 Pro Preview\", inputPrice: 2.0, outputPrice: 12.0, contextWindow: 1050000, maxOutput: 65536, reasoning: true, vision: true },\n { id: \"google/gemini-2.5-pro\", name: \"Gemini 2.5 Pro\", inputPrice: 1.25, outputPrice: 10.0, contextWindow: 1050000, maxOutput: 65536, reasoning: true, vision: true },\n { id: \"google/gemini-2.5-flash\", name: \"Gemini 2.5 Flash\", inputPrice: 0.15, outputPrice: 0.6, contextWindow: 1000000, maxOutput: 65536 },\n\n // DeepSeek\n { id: \"deepseek/deepseek-chat\", name: \"DeepSeek V3.2 Chat\", inputPrice: 0.28, outputPrice: 0.42, contextWindow: 128000, maxOutput: 8192 },\n { id: \"deepseek/deepseek-reasoner\", name: \"DeepSeek V3.2 Reasoner\", inputPrice: 0.28, outputPrice: 0.42, contextWindow: 128000, maxOutput: 8192, reasoning: true },\n\n // xAI / Grok\n { id: \"xai/grok-3\", name: \"Grok 3\", inputPrice: 3.0, outputPrice: 15.0, contextWindow: 131072, maxOutput: 16384, reasoning: true },\n { id: \"xai/grok-3-fast\", name: \"Grok 3 Fast\", inputPrice: 5.0, outputPrice: 25.0, contextWindow: 131072, maxOutput: 16384, reasoning: true },\n { id: \"xai/grok-3-mini\", name: \"Grok 3 Mini\", inputPrice: 0.3, outputPrice: 0.5, contextWindow: 131072, maxOutput: 16384 },\n];\n\n/**\n * Convert BlockRun model definitions to OpenClaw ModelDefinitionConfig format.\n */\nfunction toOpenClawModel(m: BlockRunModel): ModelDefinitionConfig {\n return {\n id: m.id,\n name: m.name,\n api: \"openai-completions\",\n reasoning: m.reasoning ?? false,\n input: m.vision ? [\"text\", \"image\"] : [\"text\"],\n cost: {\n input: m.inputPrice,\n output: m.outputPrice,\n cacheRead: 0,\n cacheWrite: 0,\n },\n contextWindow: m.contextWindow,\n maxTokens: m.maxOutput,\n };\n}\n\n/**\n * All BlockRun models in OpenClaw format.\n */\nexport const OPENCLAW_MODELS: ModelDefinitionConfig[] = BLOCKRUN_MODELS.map(toOpenClawModel);\n\n/**\n * Build a ModelProviderConfig for BlockRun.\n *\n * @param baseUrl - The proxy's local base URL (e.g., \"http://127.0.0.1:12345\")\n */\nexport function buildProviderModels(baseUrl: string): ModelProviderConfig {\n return {\n baseUrl: `${baseUrl}/v1`,\n api: \"openai-completions\",\n models: OPENCLAW_MODELS,\n };\n}\n","/**\n * BlockRun ProviderPlugin for OpenClaw\n *\n * Registers BlockRun as an LLM provider in OpenClaw.\n * Uses a local x402 proxy to handle micropayments transparently —\n * pi-ai sees a standard OpenAI-compatible API at localhost.\n */\n\nimport type { ProviderPlugin, AuthProfileCredential } from \"./types.js\";\nimport { walletKeyAuth, envKeyAuth } from \"./auth.js\";\nimport { buildProviderModels } from \"./models.js\";\nimport type { ProxyHandle } from \"./proxy.js\";\n\n/**\n * State for the running proxy (set when the plugin activates).\n */\nlet activeProxy: ProxyHandle | null = null;\n\n/**\n * Update the proxy handle (called from index.ts when the proxy starts).\n */\nexport function setActiveProxy(proxy: ProxyHandle): void {\n activeProxy = proxy;\n}\n\nexport function getActiveProxy(): ProxyHandle | null {\n return activeProxy;\n}\n\n/**\n * BlockRun provider plugin definition.\n */\nexport const blockrunProvider: ProviderPlugin = {\n id: \"blockrun\",\n label: \"BlockRun\",\n docsPath: \"https://blockrun.ai/docs\",\n aliases: [\"br\"],\n envVars: [\"BLOCKRUN_WALLET_KEY\"],\n\n // Model definitions — dynamically set to proxy URL\n get models() {\n if (!activeProxy) {\n // Fallback: point to BlockRun API directly (won't handle x402, but\n // allows config loading before proxy starts)\n return buildProviderModels(\"https://blockrun.ai/api\");\n }\n return buildProviderModels(activeProxy.baseUrl);\n },\n\n // Auth methods\n auth: [envKeyAuth, walletKeyAuth],\n\n // Format the stored credential as the wallet key\n formatApiKey: (cred: AuthProfileCredential): string => {\n if (\"apiKey\" in cred && typeof cred.apiKey === \"string\") {\n return cred.apiKey;\n }\n throw new Error(\"BlockRun credential must contain an apiKey (wallet private key)\");\n },\n};\n","/**\n * Local x402 Proxy Server\n *\n * Sits between OpenClaw's pi-ai (which makes standard OpenAI-format requests)\n * and BlockRun's API (which requires x402 micropayments).\n *\n * Flow:\n * pi-ai → http://localhost:{port}/v1/chat/completions\n * → proxy forwards to https://blockrun.ai/api/v1/chat/completions\n * → gets 402 → @x402/fetch signs payment → retries\n * → streams response back to pi-ai\n *\n * Phase 2 additions:\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 } from \"./x402.js\";\nimport { route, getFallbackChain, DEFAULT_ROUTING_CONFIG, type RouterOptions, type RoutingDecision, type RoutingConfig, type ModelPricing } from \"./router/index.js\";\nimport { BLOCKRUN_MODELS } from \"./models.js\";\nimport { logUsage, type UsageEntry } from \"./logger.js\";\n\nconst BLOCKRUN_API = \"https://blockrun.ai/api\";\nconst AUTO_MODEL = \"blockrun/auto\";\nconst USER_AGENT = \"clawrouter/0.2.3\";\n\nexport type ProxyOptions = {\n walletKey: string;\n apiBase?: string;\n port?: number;\n routingConfig?: Partial<RoutingConfig>;\n onReady?: (port: number) => void;\n onError?: (error: Error) => void;\n onPayment?: (info: { model: string; amount: string; network: string }) => void;\n onRouted?: (decision: RoutingDecision) => void;\n};\n\nexport type ProxyHandle = {\n port: number;\n baseUrl: string;\n close: () => Promise<void>;\n};\n\n/**\n * Build model pricing map from BLOCKRUN_MODELS.\n */\nfunction buildModelPricing(): Map<string, ModelPricing> {\n const map = new Map<string, ModelPricing>();\n for (const m of BLOCKRUN_MODELS) {\n if (m.id === AUTO_MODEL) continue; // skip meta-model\n map.set(m.id, { inputPrice: m.inputPrice, outputPrice: m.outputPrice });\n }\n return map;\n}\n\n/**\n * Merge partial routing config overrides with defaults.\n */\nfunction mergeRoutingConfig(overrides?: Partial<RoutingConfig>): RoutingConfig {\n if (!overrides) return DEFAULT_ROUTING_CONFIG;\n return {\n ...DEFAULT_ROUTING_CONFIG,\n ...overrides,\n classifier: { ...DEFAULT_ROUTING_CONFIG.classifier, ...overrides.classifier },\n scoring: { ...DEFAULT_ROUTING_CONFIG.scoring, ...overrides.scoring },\n tiers: { ...DEFAULT_ROUTING_CONFIG.tiers, ...overrides.tiers },\n overrides: { ...DEFAULT_ROUTING_CONFIG.overrides, ...overrides.overrides },\n };\n}\n\n/**\n * 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 payFetch = createPaymentFetch(options.walletKey as `0x${string}`);\n\n // Build router options\n const routingConfig = mergeRoutingConfig(options.routingConfig);\n const modelPricing = buildModelPricing();\n const routerOpts: RouterOptions = {\n config: routingConfig,\n modelPricing,\n payFetch,\n apiBase,\n };\n\n const server = createServer(async (req: IncomingMessage, res: ServerResponse) => {\n // Health check\n if (req.url === \"/health\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ status: \"ok\", wallet: account.address }));\n return;\n }\n\n // Only proxy paths starting with /v1\n if (!req.url?.startsWith(\"/v1\")) {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Not found\" }));\n return;\n }\n\n try {\n await proxyRequest(req, res, apiBase, payFetch, options, routerOpts);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n options.onError?.(error);\n\n if (!res.headersSent) {\n res.writeHead(502, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({\n error: { message: `Proxy error: ${error.message}`, type: \"proxy_error\" },\n }));\n }\n }\n });\n\n // Listen on requested port (0 = random available port)\n const listenPort = options.port ?? 0;\n\n return new Promise<ProxyHandle>((resolve, reject) => {\n server.on(\"error\", reject);\n\n server.listen(listenPort, \"127.0.0.1\", () => {\n const addr = server.address() as AddressInfo;\n const port = addr.port;\n const baseUrl = `http://127.0.0.1:${port}`;\n\n options.onReady?.(port);\n\n resolve({\n port,\n baseUrl,\n close: () =>\n new Promise<void>((res, rej) => {\n server.close((err) => (err ? rej(err) : res()));\n }),\n });\n });\n });\n}\n\n/**\n * Proxy a single request through x402 payment flow to BlockRun API.\n *\n * When model is \"blockrun/auto\", runs the smart router to pick the\n * cheapest capable model before forwarding.\n */\nasync function proxyRequest(\n req: IncomingMessage,\n res: ServerResponse,\n apiBase: string,\n payFetch: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>,\n options: ProxyOptions,\n routerOpts: RouterOptions,\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 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\n if (parsed.model === AUTO_MODEL) {\n // Extract prompt from messages\n type ChatMessage = { role: string; content: string };\n const messages = parsed.messages as ChatMessage[] | undefined;\n let lastUserMsg: ChatMessage | undefined;\n if (messages) {\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].role === \"user\") { lastUserMsg = messages[i]; break; }\n }\n }\n const systemMsg = messages?.find((m: ChatMessage) => m.role === \"system\");\n const prompt = typeof lastUserMsg?.content === \"string\" ? lastUserMsg.content : \"\";\n const systemPrompt = typeof systemMsg?.content === \"string\" ? systemMsg.content : undefined;\n const maxTokens = (parsed.max_tokens as number) || 4096;\n\n routingDecision = await route(prompt, systemPrompt, maxTokens, routerOpts);\n\n // Replace model in body\n parsed.model = 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 // Forward headers, stripping host, connection, and content-length\n // (content-length may be wrong after body modification for routing)\n const headers: Record<string, string> = {};\n for (const [key, value] of Object.entries(req.headers)) {\n if (key === \"host\" || key === \"connection\" || key === \"transfer-encoding\" || key === \"content-length\") continue;\n if (typeof value === \"string\") {\n headers[key] = value;\n }\n }\n // Ensure content-type is set\n if (!headers[\"content-type\"]) {\n headers[\"content-type\"] = \"application/json\";\n }\n // Set User-Agent for BlockRun API tracking\n headers[\"user-agent\"] = USER_AGENT;\n\n // Make the request through x402-wrapped fetch\n // This handles: request → 402 → sign payment → retry with PAYMENT-SIGNATURE header\n const upstream = await payFetch(upstreamUrl, {\n method: req.method ?? \"POST\",\n headers,\n body: body.length > 0 ? body : undefined,\n });\n\n // Forward status and headers from upstream\n const responseHeaders: Record<string, string> = {};\n upstream.headers.forEach((value, key) => {\n // Skip hop-by-hop headers\n if (key === \"transfer-encoding\" || key === \"connection\") return;\n responseHeaders[key] = value;\n });\n\n res.writeHead(upstream.status, responseHeaders);\n\n // Stream the response body\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 }\n } finally {\n reader.releaseLock();\n }\n }\n\n res.end();\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\nimport { signTypedData, privateKeyToAccount } from \"viem/accounts\";\n\nconst BASE_CHAIN_ID = 8453;\nconst USDC_BASE = \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\" as const;\n\nconst USDC_DOMAIN = {\n name: \"USD Coin\",\n version: \"2\",\n chainId: BASE_CHAIN_ID,\n verifyingContract: USDC_BASE,\n} as const;\n\nconst TRANSFER_TYPES = {\n TransferWithAuthorization: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n ],\n} as const;\n\nfunction createNonce(): `0x${string}` {\n const bytes = new Uint8Array(32);\n crypto.getRandomValues(bytes);\n return `0x${Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('')}` as `0x${string}`;\n}\n\ninterface PaymentOption {\n scheme: string;\n network: string;\n amount?: string;\n maxAmountRequired?: string;\n asset: string;\n payTo: string;\n maxTimeoutSeconds?: number;\n extra?: { name?: string; version?: string };\n}\n\ninterface PaymentRequired {\n accepts: PaymentOption[];\n resource?: { url?: string; description?: string };\n}\n\nfunction parsePaymentRequired(headerValue: string): PaymentRequired {\n const decoded = atob(headerValue);\n return JSON.parse(decoded) as PaymentRequired;\n}\n\nasync function createPaymentPayload(\n privateKey: `0x${string}`,\n fromAddress: string,\n recipient: string,\n amount: string,\n resourceUrl: string\n): Promise<string> {\n const now = Math.floor(Date.now() / 1000);\n const validAfter = now - 600;\n const validBefore = now + 300;\n const nonce = createNonce();\n\n const signature = await signTypedData({\n privateKey,\n domain: USDC_DOMAIN,\n types: TRANSFER_TYPES,\n primaryType: \"TransferWithAuthorization\",\n message: {\n from: fromAddress as `0x${string}`,\n to: recipient as `0x${string}`,\n value: BigInt(amount),\n validAfter: BigInt(validAfter),\n validBefore: BigInt(validBefore),\n nonce,\n },\n });\n\n const paymentData = {\n x402Version: 2,\n resource: {\n url: resourceUrl,\n description: \"BlockRun AI API call\",\n mimeType: \"application/json\",\n },\n accepted: {\n scheme: \"exact\",\n network: \"eip155:8453\",\n amount,\n asset: USDC_BASE,\n payTo: recipient,\n maxTimeoutSeconds: 300,\n extra: { name: \"USD Coin\", version: \"2\" },\n },\n payload: {\n signature,\n authorization: {\n from: fromAddress,\n to: recipient,\n value: amount,\n validAfter: validAfter.toString(),\n validBefore: validBefore.toString(),\n nonce,\n },\n },\n extensions: {},\n };\n\n return btoa(JSON.stringify(paymentData));\n}\n\n/**\n * Create a fetch wrapper that handles x402 payment automatically.\n */\nexport function createPaymentFetch(privateKey: `0x${string}`): (input: RequestInfo | URL, init?: RequestInit) => Promise<Response> {\n const account = privateKeyToAccount(privateKey);\n const walletAddress = account.address;\n\n return async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n const url = typeof input === \"string\" ? input : input instanceof URL ? input.href : input.url;\n\n // First request - may get 402\n const response = await fetch(input, init);\n\n if (response.status !== 402) {\n return response;\n }\n\n // Parse 402 payment requirements\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 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 // 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","/**\n * Rule-Based Classifier (v2 — Weighted Scoring)\n *\n * Scores a request across 14 weighted dimensions and maps the aggregate\n * score to a tier using configurable boundaries. Confidence is calibrated\n * via sigmoid — low confidence triggers the fallback classifier.\n *\n * Handles 70-80% of requests in < 1ms with zero cost.\n */\n\nimport type { Tier, ScoringResult, ScoringConfig } from \"./types.js\";\n\ntype DimensionScore = { name: string; score: number; signal: string | null };\n\n// ─── Dimension Scorers ───\n// Each returns a score in [-1, 1] and an optional signal string.\n\nfunction scoreTokenCount(\n estimatedTokens: number,\n thresholds: { simple: number; complex: number },\n): DimensionScore {\n if (estimatedTokens < thresholds.simple) {\n return { name: \"tokenCount\", score: -1.0, signal: `short (${estimatedTokens} tokens)` };\n }\n if (estimatedTokens > thresholds.complex) {\n return { name: \"tokenCount\", score: 1.0, signal: `long (${estimatedTokens} tokens)` };\n }\n return { name: \"tokenCount\", score: 0, signal: null };\n}\n\nfunction scoreKeywordMatch(\n text: string,\n keywords: string[],\n name: string,\n signalLabel: string,\n thresholds: { low: number; high: number },\n scores: { none: number; low: number; high: number },\n): DimensionScore {\n const matches = keywords.filter((kw) => text.includes(kw.toLowerCase()));\n if (matches.length >= thresholds.high) {\n return { name, score: scores.high, signal: `${signalLabel} (${matches.slice(0, 3).join(\", \")})` };\n }\n if (matches.length >= thresholds.low) {\n return { name, score: scores.low, signal: `${signalLabel} (${matches.slice(0, 3).join(\", \")})` };\n }\n return { name, score: scores.none, signal: null };\n}\n\nfunction scoreMultiStep(text: string): DimensionScore {\n const patterns = [/first.*then/i, /step \\d/i, /\\d\\.\\s/];\n const hits = patterns.filter((p) => p.test(text));\n if (hits.length > 0) {\n return { name: \"multiStepPatterns\", score: 0.5, signal: \"multi-step\" };\n }\n return { name: \"multiStepPatterns\", score: 0, signal: null };\n}\n\nfunction scoreQuestionComplexity(prompt: string): DimensionScore {\n const count = (prompt.match(/\\?/g) || []).length;\n if (count > 3) {\n return { name: \"questionComplexity\", score: 0.5, signal: `${count} questions` };\n }\n return { name: \"questionComplexity\", score: 0, signal: null };\n}\n\n// ─── Main Classifier ───\n\nexport function classifyByRules(\n prompt: string,\n systemPrompt: string | undefined,\n estimatedTokens: number,\n config: ScoringConfig,\n): ScoringResult {\n const text = `${systemPrompt ?? \"\"} ${prompt}`.toLowerCase();\n\n // Score all 14 dimensions\n const dimensions: DimensionScore[] = [\n // Original 8 dimensions\n scoreTokenCount(estimatedTokens, config.tokenCountThresholds),\n scoreKeywordMatch(text, config.codeKeywords, \"codePresence\", \"code\",\n { low: 1, high: 2 }, { none: 0, low: 0.5, high: 1.0 }),\n scoreKeywordMatch(text, config.reasoningKeywords, \"reasoningMarkers\", \"reasoning\",\n { low: 1, high: 2 }, { none: 0, low: 0.7, high: 1.0 }),\n scoreKeywordMatch(text, config.technicalKeywords, \"technicalTerms\", \"technical\",\n { low: 2, high: 4 }, { none: 0, low: 0.5, high: 1.0 }),\n scoreKeywordMatch(text, config.creativeKeywords, \"creativeMarkers\", \"creative\",\n { low: 1, high: 2 }, { none: 0, low: 0.5, high: 0.7 }),\n scoreKeywordMatch(text, config.simpleKeywords, \"simpleIndicators\", \"simple\",\n { low: 1, high: 2 }, { none: 0, low: -1.0, high: -1.0 }),\n scoreMultiStep(text),\n scoreQuestionComplexity(prompt),\n\n // 6 new dimensions\n scoreKeywordMatch(text, config.imperativeVerbs, \"imperativeVerbs\", \"imperative\",\n { low: 1, high: 2 }, { none: 0, low: 0.3, high: 0.5 }),\n scoreKeywordMatch(text, config.constraintIndicators, \"constraintCount\", \"constraints\",\n { low: 1, high: 3 }, { none: 0, low: 0.3, high: 0.7 }),\n scoreKeywordMatch(text, config.outputFormatKeywords, \"outputFormat\", \"format\",\n { low: 1, high: 2 }, { none: 0, low: 0.4, high: 0.7 }),\n scoreKeywordMatch(text, config.referenceKeywords, \"referenceComplexity\", \"references\",\n { low: 1, high: 2 }, { none: 0, low: 0.3, high: 0.5 }),\n scoreKeywordMatch(text, config.negationKeywords, \"negationComplexity\", \"negation\",\n { low: 2, high: 3 }, { none: 0, low: 0.3, high: 0.5 }),\n scoreKeywordMatch(text, config.domainSpecificKeywords, \"domainSpecificity\", \"domain-specific\",\n { low: 1, high: 2 }, { none: 0, low: 0.5, high: 0.8 }),\n ];\n\n // Collect signals\n const signals = dimensions\n .filter((d) => d.signal !== null)\n .map((d) => d.signal!);\n\n // Compute weighted score\n const weights = config.dimensionWeights;\n let weightedScore = 0;\n for (const d of dimensions) {\n const w = weights[d.name] ?? 0;\n weightedScore += d.score * w;\n }\n\n // Count reasoning markers for override\n const reasoningMatches = config.reasoningKeywords.filter((kw) =>\n text.includes(kw.toLowerCase()),\n );\n\n // Direct reasoning override: 2+ reasoning markers = high confidence REASONING\n if (reasoningMatches.length >= 2) {\n const confidence = calibrateConfidence(\n Math.max(weightedScore, 0.3), // ensure positive for confidence calc\n config.confidenceSteepness,\n );\n return {\n score: weightedScore,\n tier: \"REASONING\",\n confidence: Math.max(confidence, 0.85),\n signals,\n };\n }\n\n // Map weighted score to tier using boundaries\n const { simpleMedium, mediumComplex, complexReasoning } = config.tierBoundaries;\n let tier: Tier;\n let distanceFromBoundary: number;\n\n if (weightedScore < simpleMedium) {\n tier = \"SIMPLE\";\n distanceFromBoundary = simpleMedium - weightedScore;\n } else if (weightedScore < mediumComplex) {\n tier = \"MEDIUM\";\n distanceFromBoundary = Math.min(\n weightedScore - simpleMedium,\n mediumComplex - weightedScore,\n );\n } else if (weightedScore < complexReasoning) {\n tier = \"COMPLEX\";\n distanceFromBoundary = Math.min(\n weightedScore - mediumComplex,\n complexReasoning - weightedScore,\n );\n } else {\n tier = \"REASONING\";\n distanceFromBoundary = weightedScore - complexReasoning;\n }\n\n // Calibrate confidence via sigmoid of distance from nearest boundary\n const confidence = calibrateConfidence(distanceFromBoundary, config.confidenceSteepness);\n\n // If confidence is below threshold → ambiguous\n if (confidence < config.confidenceThreshold) {\n return { score: weightedScore, tier: null, confidence, signals };\n }\n\n return { score: weightedScore, tier, confidence, signals };\n}\n\n/**\n * Sigmoid confidence calibration.\n * Maps distance from tier boundary to [0.5, 1.0] confidence range.\n */\nfunction calibrateConfidence(distance: number, steepness: number): number {\n return 1 / (1 + Math.exp(-steepness * distance));\n}\n","/**\n * LLM Classifier (Fallback)\n *\n * When the rule-based classifier returns ambiguous (score 1-2),\n * we send a classification request to the cheapest model.\n *\n * Cost per classification: ~$0.00003\n * Latency: ~200-400ms\n * Only triggered for ~20-30% of requests.\n */\n\nimport type { Tier } from \"./types.js\";\n\nconst CLASSIFIER_PROMPT = `You are a query complexity classifier. Classify the user's query into exactly one category.\n\nCategories:\n- SIMPLE: Factual Q&A, definitions, translations, short answers\n- MEDIUM: Summaries, explanations, moderate code generation\n- COMPLEX: Multi-step code, system design, creative writing, analysis\n- REASONING: Mathematical proofs, formal logic, step-by-step problem solving\n\nRespond with ONLY one word: SIMPLE, MEDIUM, COMPLEX, or REASONING.`;\n\n// In-memory cache: hash → { tier, expires }\nconst cache = new Map<string, { tier: Tier; expires: number }>();\n\nexport type LLMClassifierConfig = {\n model: string;\n maxTokens: number;\n temperature: number;\n truncationChars: number;\n cacheTtlMs: number;\n};\n\ntype PayFetch = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;\n\n/**\n * Classify a prompt using a cheap LLM.\n * Returns tier and confidence. Defaults to MEDIUM on any failure.\n */\nexport async function classifyByLLM(\n prompt: string,\n config: LLMClassifierConfig,\n payFetch: PayFetch,\n apiBase: string,\n): Promise<{ tier: Tier; confidence: number }> {\n const truncated = prompt.slice(0, config.truncationChars);\n\n // Check cache\n const cacheKey = simpleHash(truncated);\n const cached = cache.get(cacheKey);\n if (cached && cached.expires > Date.now()) {\n return { tier: cached.tier, confidence: 0.75 };\n }\n\n try {\n const response = await payFetch(`${apiBase}/v1/chat/completions`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model: config.model,\n messages: [\n { role: \"system\", content: CLASSIFIER_PROMPT },\n { role: \"user\", content: truncated },\n ],\n max_tokens: config.maxTokens,\n temperature: config.temperature,\n stream: false,\n }),\n });\n\n if (!response.ok) {\n return { tier: \"MEDIUM\", confidence: 0.5 };\n }\n\n const data = (await response.json()) as {\n choices?: Array<{ message?: { content?: string } }>;\n };\n\n const content = data.choices?.[0]?.message?.content?.trim().toUpperCase() ?? \"\";\n const tier = parseTier(content);\n\n // Cache result\n cache.set(cacheKey, { tier, expires: Date.now() + config.cacheTtlMs });\n\n // Prune if cache grows too large\n if (cache.size > 1000) {\n pruneCache();\n }\n\n return { tier, confidence: 0.75 };\n } catch {\n // Any error → safe default\n return { tier: \"MEDIUM\", confidence: 0.5 };\n }\n}\n\n/**\n * Parse tier from LLM response. Handles \"SIMPLE\", \"The query is SIMPLE\", etc.\n */\nfunction parseTier(text: string): Tier {\n if (/\\bREASONING\\b/.test(text)) return \"REASONING\";\n if (/\\bCOMPLEX\\b/.test(text)) return \"COMPLEX\";\n if (/\\bMEDIUM\\b/.test(text)) return \"MEDIUM\";\n if (/\\bSIMPLE\\b/.test(text)) return \"SIMPLE\";\n return \"MEDIUM\"; // safe default\n}\n\nfunction simpleHash(str: string): string {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = ((hash << 5) - hash) + char;\n hash |= 0;\n }\n return hash.toString(36);\n}\n\nfunction pruneCache(): void {\n const now = Date.now();\n for (const [key, value] of cache) {\n if (value.expires <= now) {\n cache.delete(key);\n }\n }\n}\n","/**\n * Tier → Model Selection\n *\n * Maps a classification tier to the cheapest capable model.\n * Builds RoutingDecision metadata with cost estimates and savings.\n */\n\nimport type { Tier, TierConfig, RoutingDecision } from \"./types.js\";\n\nexport type ModelPricing = {\n inputPrice: number; // per 1M tokens\n outputPrice: number; // per 1M tokens\n};\n\n/**\n * Select the primary model for a tier and build the RoutingDecision.\n */\nexport function selectModel(\n tier: Tier,\n confidence: number,\n method: \"rules\" | \"llm\",\n reasoning: string,\n tierConfigs: Record<Tier, TierConfig>,\n modelPricing: Map<string, ModelPricing>,\n estimatedInputTokens: number,\n maxOutputTokens: number,\n): RoutingDecision {\n const tierConfig = tierConfigs[tier];\n const model = tierConfig.primary;\n const pricing = modelPricing.get(model);\n\n const inputCost = pricing\n ? (estimatedInputTokens / 1_000_000) * pricing.inputPrice\n : 0;\n const outputCost = pricing\n ? (maxOutputTokens / 1_000_000) * pricing.outputPrice\n : 0;\n const costEstimate = inputCost + outputCost;\n\n // Baseline: what Claude Opus would cost (the premium default)\n const opusPricing = modelPricing.get(\"anthropic/claude-opus-4\");\n const baselineInput = opusPricing\n ? (estimatedInputTokens / 1_000_000) * opusPricing.inputPrice\n : 0;\n const baselineOutput = opusPricing\n ? (maxOutputTokens / 1_000_000) * opusPricing.outputPrice\n : 0;\n const baselineCost = baselineInput + baselineOutput;\n\n const savings =\n baselineCost > 0\n ? Math.max(0, (baselineCost - costEstimate) / baselineCost)\n : 0;\n\n return {\n model,\n tier,\n confidence,\n method,\n reasoning,\n costEstimate,\n baselineCost,\n savings,\n };\n}\n\n/**\n * Get the ordered fallback chain for a tier: [primary, ...fallbacks].\n */\nexport function getFallbackChain(\n tier: Tier,\n tierConfigs: Record<Tier, TierConfig>,\n): string[] {\n const config = tierConfigs[tier];\n return [config.primary, ...config.fallback];\n}\n","/**\n * Default Routing Config\n *\n * All routing parameters as a TypeScript constant.\n * Operators override via openclaw.yaml plugin config.\n *\n * Scoring uses 14 weighted dimensions with sigmoid confidence calibration.\n */\n\nimport type { RoutingConfig } from \"./types.js\";\n\nexport const DEFAULT_ROUTING_CONFIG: RoutingConfig = {\n version: \"2.0\",\n\n classifier: {\n llmModel: \"google/gemini-2.5-flash\",\n llmMaxTokens: 10,\n llmTemperature: 0,\n promptTruncationChars: 500,\n cacheTtlMs: 3_600_000, // 1 hour\n },\n\n scoring: {\n tokenCountThresholds: { simple: 50, complex: 500 },\n codeKeywords: [\n \"function\", \"class\", \"import\", \"def\", \"SELECT\", \"async\", \"await\",\n \"const\", \"let\", \"var\", \"return\", \"```\",\n ],\n reasoningKeywords: [\n \"prove\", \"theorem\", \"derive\", \"step by step\", \"chain of thought\",\n \"formally\", \"mathematical\", \"proof\", \"logically\",\n ],\n simpleKeywords: [\n \"what is\", \"define\", \"translate\", \"hello\", \"yes or no\",\n \"capital of\", \"how old\", \"who is\", \"when was\",\n ],\n technicalKeywords: [\n \"algorithm\", \"optimize\", \"architecture\", \"distributed\",\n \"kubernetes\", \"microservice\", \"database\", \"infrastructure\",\n ],\n creativeKeywords: [\n \"story\", \"poem\", \"compose\", \"brainstorm\", \"creative\",\n \"imagine\", \"write a\",\n ],\n\n // New dimension keyword lists\n imperativeVerbs: [\n \"build\", \"create\", \"implement\", \"design\", \"develop\", \"construct\",\n \"generate\", \"deploy\", \"configure\", \"set up\",\n ],\n constraintIndicators: [\n \"under\", \"at most\", \"at least\", \"within\", \"no more than\",\n \"o(\", \"maximum\", \"minimum\", \"limit\", \"budget\",\n ],\n outputFormatKeywords: [\n \"json\", \"yaml\", \"xml\", \"table\", \"csv\", \"markdown\",\n \"schema\", \"format as\", \"structured\",\n ],\n referenceKeywords: [\n \"above\", \"below\", \"previous\", \"following\", \"the docs\",\n \"the api\", \"the code\", \"earlier\", \"attached\",\n ],\n negationKeywords: [\n \"don't\", \"do not\", \"avoid\", \"never\", \"without\",\n \"except\", \"exclude\", \"no longer\",\n ],\n domainSpecificKeywords: [\n \"quantum\", \"fpga\", \"vlsi\", \"risc-v\", \"asic\", \"photonics\",\n \"genomics\", \"proteomics\", \"topological\", \"homomorphic\",\n \"zero-knowledge\", \"lattice-based\",\n ],\n\n // Dimension weights (sum to 1.0)\n dimensionWeights: {\n tokenCount: 0.08,\n codePresence: 0.15,\n reasoningMarkers: 0.18,\n technicalTerms: 0.10,\n creativeMarkers: 0.05,\n simpleIndicators: 0.12,\n multiStepPatterns: 0.12,\n questionComplexity: 0.05,\n imperativeVerbs: 0.03,\n constraintCount: 0.04,\n outputFormat: 0.03,\n referenceComplexity: 0.02,\n negationComplexity: 0.01,\n domainSpecificity: 0.02,\n },\n\n // Tier boundaries on weighted score axis\n tierBoundaries: {\n simpleMedium: 0.0,\n mediumComplex: 0.15,\n complexReasoning: 0.25,\n },\n\n // Sigmoid steepness for confidence calibration\n confidenceSteepness: 12,\n // Below this confidence → ambiguous (null tier)\n confidenceThreshold: 0.70,\n },\n\n tiers: {\n SIMPLE: {\n primary: \"google/gemini-2.5-flash\",\n fallback: [\"deepseek/deepseek-chat\", \"openai/gpt-4o-mini\"],\n },\n MEDIUM: {\n primary: \"deepseek/deepseek-chat\",\n fallback: [\"google/gemini-2.5-flash\", \"openai/gpt-4o-mini\"],\n },\n COMPLEX: {\n primary: \"anthropic/claude-opus-4\",\n fallback: [\"anthropic/claude-sonnet-4\", \"openai/gpt-4o\"],\n },\n REASONING: {\n primary: \"openai/o3\",\n fallback: [\"google/gemini-2.5-pro\", \"anthropic/claude-sonnet-4\"],\n },\n },\n\n overrides: {\n maxTokensForceComplex: 100_000,\n structuredOutputMinTier: \"MEDIUM\",\n },\n};\n","/**\n * Smart Router Entry Point\n *\n * Classifies requests and routes to the cheapest capable model.\n * Uses hybrid approach: rules first (< 1ms), LLM fallback for ambiguous cases.\n */\n\nimport type { Tier, RoutingDecision, RoutingConfig } from \"./types.js\";\nimport { classifyByRules } from \"./rules.js\";\nimport { classifyByLLM } from \"./llm-classifier.js\";\nimport { selectModel, getFallbackChain, type ModelPricing } from \"./selector.js\";\n\nexport type RouterOptions = {\n config: RoutingConfig;\n modelPricing: Map<string, ModelPricing>;\n payFetch: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;\n apiBase: string;\n};\n\n/**\n * Route a request to the cheapest capable model.\n *\n * 1. Check overrides (large context, structured output)\n * 2. Run rule-based classifier\n * 3. If ambiguous, run LLM classifier\n * 4. Select model for tier\n * 5. Return RoutingDecision with metadata\n */\nexport async function route(\n prompt: string,\n systemPrompt: string | undefined,\n maxOutputTokens: number,\n options: RouterOptions,\n): Promise<RoutingDecision> {\n const { config, modelPricing, payFetch, apiBase } = options;\n\n // Estimate input tokens (~4 chars per token)\n const fullText = `${systemPrompt ?? \"\"} ${prompt}`;\n const estimatedTokens = Math.ceil(fullText.length / 4);\n\n // --- Override: large context → force COMPLEX ---\n if (estimatedTokens > config.overrides.maxTokensForceComplex) {\n return selectModel(\n \"COMPLEX\",\n 0.95,\n \"rules\",\n `Input exceeds ${config.overrides.maxTokensForceComplex} tokens`,\n config.tiers,\n modelPricing,\n estimatedTokens,\n maxOutputTokens,\n );\n }\n\n // Structured output detection\n const hasStructuredOutput = systemPrompt\n ? /json|structured|schema/i.test(systemPrompt)\n : false;\n\n // --- Rule-based classification ---\n const ruleResult = classifyByRules(\n prompt,\n systemPrompt,\n estimatedTokens,\n config.scoring,\n );\n\n let tier: Tier;\n let confidence: number;\n let method: \"rules\" | \"llm\" = \"rules\";\n let reasoning = `score=${ruleResult.score} | ${ruleResult.signals.join(\", \")}`;\n\n if (ruleResult.tier !== null) {\n tier = ruleResult.tier;\n confidence = ruleResult.confidence;\n } else {\n // Ambiguous — LLM classifier fallback\n const llmResult = await classifyByLLM(\n prompt,\n {\n model: config.classifier.llmModel,\n maxTokens: config.classifier.llmMaxTokens,\n temperature: config.classifier.llmTemperature,\n truncationChars: config.classifier.promptTruncationChars,\n cacheTtlMs: config.classifier.cacheTtlMs,\n },\n payFetch,\n apiBase,\n );\n\n tier = llmResult.tier;\n confidence = llmResult.confidence;\n method = \"llm\";\n reasoning += ` | ambiguous -> LLM: ${tier}`;\n }\n\n // Apply structured output minimum tier\n if (hasStructuredOutput) {\n const tierRank: Record<Tier, number> = { SIMPLE: 0, MEDIUM: 1, COMPLEX: 2, REASONING: 3 };\n const minTier = config.overrides.structuredOutputMinTier;\n if (tierRank[tier] < tierRank[minTier]) {\n reasoning += ` | upgraded to ${minTier} (structured output)`;\n tier = minTier;\n }\n }\n\n return selectModel(\n tier,\n confidence,\n method,\n reasoning,\n config.tiers,\n modelPricing,\n estimatedTokens,\n maxOutputTokens,\n );\n}\n\nexport { getFallbackChain } from \"./selector.js\";\nexport { DEFAULT_ROUTING_CONFIG } from \"./config.js\";\nexport type { RoutingDecision, Tier, RoutingConfig } from \"./types.js\";\nexport type { ModelPricing } from \"./selector.js\";\n","/**\n * Usage Logger\n *\n * Logs every LLM request as a JSON line to a daily log file.\n * Files: ~/.openclaw/blockrun/logs/usage-YYYY-MM-DD.jsonl\n *\n * MVP: append-only JSON lines. No rotation, no cleanup.\n * Logging never breaks the request flow — all errors are swallowed.\n */\n\nimport { appendFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\nexport type UsageEntry = {\n timestamp: string;\n model: string;\n cost: number;\n latencyMs: number;\n};\n\nconst LOG_DIR = join(homedir(), \".openclaw\", \"blockrun\", \"logs\");\nlet dirReady = false;\n\nasync function ensureDir(): Promise<void> {\n if (dirReady) return;\n await mkdir(LOG_DIR, { recursive: true });\n dirReady = true;\n}\n\n/**\n * Log a usage entry as a JSON line.\n */\nexport async function logUsage(entry: UsageEntry): Promise<void> {\n try {\n await ensureDir();\n const date = entry.timestamp.slice(0, 10); // YYYY-MM-DD\n const file = join(LOG_DIR, `usage-${date}.jsonl`);\n await appendFile(file, JSON.stringify(entry) + \"\\n\");\n } catch {\n // Never break the request flow\n }\n}\n","/**\n * @blockrun/clawrouter\n *\n * Smart LLM router for OpenClaw — 30+ models, x402 micropayments, 78% cost savings.\n * Routes each request to the cheapest model that can handle it.\n *\n * Usage:\n * # Install the plugin\n * openclaw plugin install @blockrun/clawrouter\n *\n * # Fund your wallet with USDC on Base (address printed on install)\n *\n * # Use smart routing (auto-picks cheapest model)\n * openclaw config set model blockrun/auto\n *\n * # Or use any specific BlockRun model\n * openclaw config set model openai/gpt-5.2\n */\n\nimport type { OpenClawPluginDefinition, OpenClawPluginApi } from \"./types.js\";\nimport { blockrunProvider, setActiveProxy } from \"./provider.js\";\nimport { startProxy } from \"./proxy.js\";\nimport { resolveOrGenerateWalletKey } from \"./auth.js\";\nimport type { RoutingConfig } from \"./router/index.js\";\n\n/**\n * Start the x402 proxy in the background.\n * Called from register() because OpenClaw's loader only invokes register(),\n * treating activate() as an alias (def.register ?? def.activate).\n */\nasync function startProxyInBackground(api: OpenClawPluginApi): Promise<void> {\n // Resolve wallet key: saved file → env var → auto-generate\n const { key: walletKey, address, source } = await resolveOrGenerateWalletKey();\n\n // Log wallet source\n if (source === \"generated\") {\n api.logger.info(`Generated new wallet: ${address}`);\n api.logger.info(`Fund with USDC on Base to start using ClawRouter.`);\n } else if (source === \"saved\") {\n api.logger.info(`Using saved wallet: ${address}`);\n } else {\n api.logger.info(`Using wallet from BLOCKRUN_WALLET_KEY: ${address}`);\n }\n\n // Resolve routing config overrides from plugin config\n const routingConfig = api.pluginConfig?.routing as Partial<RoutingConfig> | undefined;\n\n const proxy = await startProxy({\n walletKey,\n routingConfig,\n onReady: (port) => {\n api.logger.info(`BlockRun x402 proxy listening on port ${port}`);\n },\n onError: (error) => {\n api.logger.error(`BlockRun proxy error: ${error.message}`);\n },\n onRouted: (decision) => {\n const cost = decision.costEstimate.toFixed(4);\n const saved = (decision.savings * 100).toFixed(0);\n api.logger.info(`${decision.model} $${cost} (saved ${saved}%)`);\n },\n });\n\n setActiveProxy(proxy);\n api.logger.info(`BlockRun provider active — ${proxy.baseUrl}/v1 (smart routing enabled)`);\n}\n\nconst plugin: OpenClawPluginDefinition = {\n id: \"clawrouter\",\n name: \"ClawRouter\",\n description: \"Smart LLM router — 30+ models, x402 micropayments, 78% cost savings\",\n version: \"0.2.3\",\n\n register(api: OpenClawPluginApi) {\n // Register BlockRun as a provider (sync — available immediately)\n api.registerProvider(blockrunProvider);\n api.logger.info(\"BlockRun provider registered (30+ models via x402)\");\n\n // Start x402 proxy in background (fire-and-forget)\n // OpenClaw only calls register(), not activate() — so all init goes here.\n // The loader ignores async returns, but the proxy starts in the background\n // and setActiveProxy() makes it available to the provider once ready.\n startProxyInBackground(api).catch((err) => {\n api.logger.error(\n `Failed to start BlockRun proxy: ${err instanceof Error ? err.message : String(err)}`,\n );\n });\n },\n};\n\n\nexport default plugin;\n\n// Re-export for programmatic use\nexport { startProxy } from \"./proxy.js\";\nexport { blockrunProvider } from \"./provider.js\";\nexport { OPENCLAW_MODELS, BLOCKRUN_MODELS, buildProviderModels } from \"./models.js\";\nexport { route, DEFAULT_ROUTING_CONFIG } from \"./router/index.js\";\nexport type { RoutingDecision, RoutingConfig, Tier } from \"./router/index.js\";\nexport { logUsage } from \"./logger.js\";\nexport type { UsageEntry } from \"./logger.js\";\n"],"mappings":"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","names":["privateKeyToAccount","privateKeyToAccount","confidence","mkdir","join","homedir","privateKeyToAccount"]}
|