@blockrun/clawrouter 0.11.2 → 0.11.4

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/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/proxy.ts","../src/x402.ts","../src/payment-cache.ts","../src/router/rules.ts","../src/router/selector.ts","../src/router/config.ts","../src/router/index.ts","../src/models.ts","../src/logger.ts","../src/stats.ts","../src/fs-read.ts","../src/version.ts","../src/dedup.ts","../src/response-cache.ts","../src/balance.ts","../src/errors.ts","../src/compression/types.ts","../src/compression/layers/deduplication.ts","../src/compression/layers/whitespace.ts","../src/compression/codebook.ts","../src/compression/layers/dictionary.ts","../src/compression/layers/paths.ts","../src/compression/layers/json-compact.ts","../src/compression/layers/observation.ts","../src/compression/layers/dynamic-codebook.ts","../src/compression/index.ts","../src/session.ts","../src/updater.ts","../src/config.ts","../src/journal.ts","../src/auth.ts","../src/doctor.ts","../src/partners/registry.ts","../src/cli.ts"],"sourcesContent":["/**\n * Local x402 Proxy Server\n *\n * Sits between OpenClaw's pi-ai (which makes standard OpenAI-format requests)\n * and BlockRun's API (which requires x402 micropayments).\n *\n * Flow:\n * pi-ai → http://localhost:{port}/v1/chat/completions\n * → proxy forwards to https://blockrun.ai/api/v1/chat/completions\n * → gets 402 → @x402/fetch signs payment → retries\n * → streams response back to pi-ai\n *\n * Optimizations (v0.3.0):\n * - SSE heartbeat: for streaming requests, sends headers + heartbeat immediately\n * before the x402 flow, preventing OpenClaw's 10-15s timeout from firing.\n * - Response dedup: hashes request bodies and caches responses for 30s,\n * preventing double-charging when OpenClaw retries after timeout.\n * - Payment cache: after first 402, pre-signs subsequent requests to skip\n * the 402 round trip (~200ms savings per request).\n * - Smart routing: when model is \"blockrun/auto\", classify query and pick cheapest model.\n * - Usage logging: log every request as JSON line to ~/.openclaw/blockrun/logs/\n */\n\nimport { createServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport { finished } from \"node:stream\";\nimport type { AddressInfo } from \"node:net\";\nimport { privateKeyToAccount } from \"viem/accounts\";\nimport { createPaymentFetch, type PreAuthParams } from \"./x402.js\";\nimport {\n route,\n getFallbackChain,\n getFallbackChainFiltered,\n filterByToolCalling,\n filterByVision,\n calculateModelCost,\n DEFAULT_ROUTING_CONFIG,\n type RouterOptions,\n type RoutingDecision,\n type RoutingConfig,\n type ModelPricing,\n type Tier,\n} from \"./router/index.js\";\nimport { classifyByRules } from \"./router/rules.js\";\nimport {\n BLOCKRUN_MODELS,\n OPENCLAW_MODELS,\n resolveModelAlias,\n getModelContextWindow,\n isReasoningModel,\n supportsToolCalling,\n supportsVision,\n} from \"./models.js\";\nimport { logUsage, type UsageEntry } from \"./logger.js\";\nimport { getStats } from \"./stats.js\";\nimport { RequestDeduplicator } from \"./dedup.js\";\nimport { ResponseCache, type ResponseCacheConfig } from \"./response-cache.js\";\nimport { BalanceMonitor } from \"./balance.js\";\nimport { compressContext, shouldCompress, type NormalizedMessage } from \"./compression/index.js\";\n// Error classes available for programmatic use but not used in proxy\n// (universal free fallback means we don't throw balance errors anymore)\n// import { InsufficientFundsError, EmptyWalletError } from \"./errors.js\";\nimport { USER_AGENT } from \"./version.js\";\nimport {\n SessionStore,\n getSessionId,\n deriveSessionId,\n hashRequestContent,\n type SessionConfig,\n} from \"./session.js\";\nimport { checkForUpdates } from \"./updater.js\";\nimport { PROXY_PORT } from \"./config.js\";\nimport { SessionJournal } from \"./journal.js\";\n\nconst BLOCKRUN_API = \"https://blockrun.ai/api\";\n// Routing profile models - virtual models that trigger intelligent routing\nconst AUTO_MODEL = \"blockrun/auto\";\n\nconst ROUTING_PROFILES = new Set([\n \"blockrun/free\",\n \"free\",\n \"blockrun/eco\",\n \"eco\",\n \"blockrun/auto\",\n \"auto\",\n \"blockrun/premium\",\n \"premium\",\n]);\nconst FREE_MODEL = \"nvidia/gpt-oss-120b\"; // Free model for empty wallet fallback\nconst MAX_MESSAGES = 200; // BlockRun API limit - truncate older messages if exceeded\nconst CONTEXT_LIMIT_KB = 5120; // Server-side limit: 5MB in KB\nconst HEARTBEAT_INTERVAL_MS = 2_000;\nconst DEFAULT_REQUEST_TIMEOUT_MS = 180_000; // 3 minutes (allows for on-chain tx + LLM response)\nconst MAX_FALLBACK_ATTEMPTS = 5; // Maximum models to try in fallback chain (increased from 3 to ensure cheap models are tried)\nconst HEALTH_CHECK_TIMEOUT_MS = 2_000; // Timeout for checking existing proxy\nconst RATE_LIMIT_COOLDOWN_MS = 60_000; // 60 seconds cooldown for rate-limited models\nconst PORT_RETRY_ATTEMPTS = 5; // Max attempts to bind port (handles TIME_WAIT)\nconst PORT_RETRY_DELAY_MS = 1_000; // Delay between retry attempts\n\n/**\n * Transform upstream payment errors into user-friendly messages.\n * Parses the raw x402 error and formats it nicely.\n */\nfunction transformPaymentError(errorBody: string): string {\n try {\n // Try to parse the error JSON\n const parsed = JSON.parse(errorBody) as {\n error?: string;\n details?: string;\n };\n\n // Check if this is a payment verification error\n if (parsed.error === \"Payment verification failed\" && parsed.details) {\n // Extract the nested JSON from details\n // Format: \"Verification failed: {json}\\n\"\n const match = parsed.details.match(/Verification failed:\\s*(\\{.*\\})/s);\n if (match) {\n const innerJson = JSON.parse(match[1]) as {\n invalidMessage?: string;\n invalidReason?: string;\n payer?: string;\n };\n\n if (innerJson.invalidReason === \"insufficient_funds\" && innerJson.invalidMessage) {\n // Parse \"insufficient balance: 251 < 11463\"\n const balanceMatch = innerJson.invalidMessage.match(\n /insufficient balance:\\s*(\\d+)\\s*<\\s*(\\d+)/i,\n );\n if (balanceMatch) {\n const currentMicros = parseInt(balanceMatch[1], 10);\n const requiredMicros = parseInt(balanceMatch[2], 10);\n const currentUSD = (currentMicros / 1_000_000).toFixed(6);\n const requiredUSD = (requiredMicros / 1_000_000).toFixed(6);\n const wallet = innerJson.payer || \"unknown\";\n const shortWallet =\n wallet.length > 12 ? `${wallet.slice(0, 6)}...${wallet.slice(-4)}` : wallet;\n\n return JSON.stringify({\n error: {\n message: `Insufficient USDC balance. Current: $${currentUSD}, Required: ~$${requiredUSD}`,\n type: \"insufficient_funds\",\n wallet: wallet,\n current_balance_usd: currentUSD,\n required_usd: requiredUSD,\n help: `Fund wallet ${shortWallet} with USDC on Base, or use free model: /model free`,\n },\n });\n }\n }\n\n // Handle invalid_payload errors (signature issues, malformed payment)\n if (innerJson.invalidReason === \"invalid_payload\") {\n return JSON.stringify({\n error: {\n message: \"Payment signature invalid. This may be a temporary issue.\",\n type: \"invalid_payload\",\n help: \"Try again. If this persists, reinstall ClawRouter: curl -fsSL https://blockrun.ai/ClawRouter-update | bash\",\n },\n });\n }\n }\n }\n\n // Handle settlement failures (gas estimation, on-chain errors)\n if (parsed.error === \"Settlement failed\" || parsed.details?.includes(\"Settlement failed\")) {\n const details = parsed.details || \"\";\n const gasError = details.includes(\"unable to estimate gas\");\n\n return JSON.stringify({\n error: {\n message: gasError\n ? \"Payment failed: network congestion or gas issue. Try again.\"\n : \"Payment settlement failed. Try again in a moment.\",\n type: \"settlement_failed\",\n help: \"This is usually temporary. If it persists, try: /model free\",\n },\n });\n }\n } catch {\n // If parsing fails, return original\n }\n return errorBody;\n}\n\n/**\n * Track rate-limited models to avoid hitting them again.\n * Maps model ID to the timestamp when the rate limit was hit.\n */\nconst rateLimitedModels = new Map<string, number>();\n\n/**\n * Check if a model is currently rate-limited (in cooldown period).\n */\nfunction isRateLimited(modelId: string): boolean {\n const hitTime = rateLimitedModels.get(modelId);\n if (!hitTime) return false;\n\n const elapsed = Date.now() - hitTime;\n if (elapsed >= RATE_LIMIT_COOLDOWN_MS) {\n rateLimitedModels.delete(modelId);\n return false;\n }\n return true;\n}\n\n/**\n * Mark a model as rate-limited.\n */\nfunction markRateLimited(modelId: string): void {\n rateLimitedModels.set(modelId, Date.now());\n console.log(`[ClawRouter] Model ${modelId} rate-limited, will deprioritize for 60s`);\n}\n\n/**\n * Reorder models to put rate-limited ones at the end.\n */\nfunction prioritizeNonRateLimited(models: string[]): string[] {\n const available: string[] = [];\n const rateLimited: string[] = [];\n\n for (const model of models) {\n if (isRateLimited(model)) {\n rateLimited.push(model);\n } else {\n available.push(model);\n }\n }\n\n return [...available, ...rateLimited];\n}\n\n/**\n * Check if response socket is writable (prevents write-after-close errors).\n * Returns true only if all conditions are safe for writing.\n */\nfunction canWrite(res: ServerResponse): boolean {\n return (\n !res.writableEnded &&\n !res.destroyed &&\n res.socket !== null &&\n !res.socket.destroyed &&\n res.socket.writable\n );\n}\n\n/**\n * Safe write with backpressure handling.\n * Returns true if write succeeded, false if socket is closed or write failed.\n */\nfunction safeWrite(res: ServerResponse, data: string | Buffer): boolean {\n if (!canWrite(res)) {\n return false;\n }\n return res.write(data);\n}\n\n// Extra buffer for balance check (on top of estimateAmount's 20% buffer)\n// Total effective buffer: 1.2 * 1.5 = 1.8x (80% safety margin)\n// This prevents x402 payment failures after streaming headers are sent,\n// which would trigger OpenClaw's 5-24 hour billing cooldown.\nconst BALANCE_CHECK_BUFFER = 1.5;\n\n/**\n * Get the proxy port from pre-loaded configuration.\n * Port is validated at module load time, this just returns the cached value.\n */\nexport function getProxyPort(): number {\n return PROXY_PORT;\n}\n\n/**\n * Check if a proxy is already running on the given port.\n * Returns the wallet address if running, undefined otherwise.\n */\nasync function checkExistingProxy(port: number): Promise<string | undefined> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), HEALTH_CHECK_TIMEOUT_MS);\n\n try {\n const response = await fetch(`http://127.0.0.1:${port}/health`, {\n signal: controller.signal,\n });\n clearTimeout(timeoutId);\n\n if (response.ok) {\n const data = (await response.json()) as { status?: string; wallet?: string };\n if (data.status === \"ok\" && data.wallet) {\n return data.wallet;\n }\n }\n return undefined;\n } catch {\n clearTimeout(timeoutId);\n return undefined;\n }\n}\n\n/**\n * Error patterns that indicate a provider-side issue (not user's fault).\n * These errors should trigger fallback to the next model in the chain.\n */\nconst PROVIDER_ERROR_PATTERNS = [\n /billing/i,\n /insufficient.*balance/i,\n /credits/i,\n /quota.*exceeded/i,\n /rate.*limit/i,\n /model.*unavailable/i,\n /model.*not.*available/i,\n /service.*unavailable/i,\n /capacity/i,\n /overloaded/i,\n /temporarily.*unavailable/i,\n /api.*key.*invalid/i,\n /authentication.*failed/i,\n /request too large/i,\n /request.*size.*exceeds/i,\n /payload too large/i,\n /payment.*verification.*failed/i,\n /model.*not.*allowed/i,\n /unknown.*model/i,\n];\n\n/**\n * \"Successful\" response bodies that are actually provider degradation placeholders.\n * Some upstream providers occasionally return these with HTTP 200.\n */\nconst DEGRADED_RESPONSE_PATTERNS = [\n /the ai service is temporarily overloaded/i,\n /service is temporarily overloaded/i,\n /please try again in a moment/i,\n];\n\n/**\n * Known low-quality loop signatures seen during provider degradation windows.\n */\nconst DEGRADED_LOOP_PATTERNS = [\n /the boxed is the response\\./i,\n /the response is the text\\./i,\n /the final answer is the boxed\\./i,\n];\n\nfunction extractAssistantContent(payload: unknown): string | undefined {\n if (!payload || typeof payload !== \"object\") return undefined;\n const record = payload as Record<string, unknown>;\n const choices = record.choices;\n if (!Array.isArray(choices) || choices.length === 0) return undefined;\n\n const firstChoice = choices[0];\n if (!firstChoice || typeof firstChoice !== \"object\") return undefined;\n const choice = firstChoice as Record<string, unknown>;\n const message = choice.message;\n if (!message || typeof message !== \"object\") return undefined;\n const content = (message as Record<string, unknown>).content;\n return typeof content === \"string\" ? content : undefined;\n}\n\nfunction hasKnownLoopSignature(text: string): boolean {\n const matchCount = DEGRADED_LOOP_PATTERNS.reduce(\n (count, pattern) => (pattern.test(text) ? count + 1 : count),\n 0,\n );\n if (matchCount >= 2) return true;\n\n // Generic repetitive loop fallback for short repeated lines.\n const lines = text\n .split(/\\r?\\n/)\n .map((line) => line.trim())\n .filter(Boolean);\n if (lines.length < 8) return false;\n\n const counts = new Map<string, number>();\n for (const line of lines) {\n counts.set(line, (counts.get(line) ?? 0) + 1);\n }\n\n const maxRepeat = Math.max(...counts.values());\n const uniqueRatio = counts.size / lines.length;\n return maxRepeat >= 3 && uniqueRatio <= 0.45;\n}\n\n/**\n * Detect degraded 200-response payloads that should trigger model fallback.\n * Returns a short reason when fallback should happen, otherwise undefined.\n */\nexport function detectDegradedSuccessResponse(body: string): string | undefined {\n const trimmed = body.trim();\n if (!trimmed) return undefined;\n\n // Plain-text placeholder response.\n if (DEGRADED_RESPONSE_PATTERNS.some((pattern) => pattern.test(trimmed))) {\n return \"degraded response: overloaded placeholder\";\n }\n\n // Plain-text looping garbage response.\n if (hasKnownLoopSignature(trimmed)) {\n return \"degraded response: repetitive loop output\";\n }\n\n try {\n const parsed = JSON.parse(trimmed) as Record<string, unknown>;\n\n // Some providers return JSON error payloads with HTTP 200.\n const errorField = parsed.error;\n let errorText = \"\";\n if (typeof errorField === \"string\") {\n errorText = errorField;\n } else if (errorField && typeof errorField === \"object\") {\n const errObj = errorField as Record<string, unknown>;\n errorText = [\n typeof errObj.message === \"string\" ? errObj.message : \"\",\n typeof errObj.type === \"string\" ? errObj.type : \"\",\n typeof errObj.code === \"string\" ? errObj.code : \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n }\n if (errorText && PROVIDER_ERROR_PATTERNS.some((pattern) => pattern.test(errorText))) {\n return `degraded response: ${errorText.slice(0, 120)}`;\n }\n\n // Successful wrapper with bad assistant content.\n const assistantContent = extractAssistantContent(parsed);\n if (!assistantContent) return undefined;\n if (DEGRADED_RESPONSE_PATTERNS.some((pattern) => pattern.test(assistantContent))) {\n return \"degraded response: overloaded assistant content\";\n }\n if (hasKnownLoopSignature(assistantContent)) {\n return \"degraded response: repetitive assistant loop\";\n }\n } catch {\n // Not JSON - handled by plaintext checks above.\n }\n\n return undefined;\n}\n\n/**\n * HTTP status codes that indicate provider issues worth retrying with fallback.\n */\nconst FALLBACK_STATUS_CODES = [\n 400, // Bad request - sometimes used for billing errors\n 401, // Unauthorized - provider API key issues\n 402, // Payment required - but from upstream, not x402\n 403, // Forbidden - provider restrictions\n 413, // Payload too large - request exceeds model's context limit\n 429, // Rate limited\n 500, // Internal server error\n 502, // Bad gateway\n 503, // Service unavailable\n 504, // Gateway timeout\n];\n\n/**\n * Check if an error response indicates a provider issue that should trigger fallback.\n */\nfunction isProviderError(status: number, body: string): boolean {\n // Check status code first\n if (!FALLBACK_STATUS_CODES.includes(status)) {\n return false;\n }\n\n // For 5xx errors, always fallback\n if (status >= 500) {\n return true;\n }\n\n // For 4xx errors, check the body for known provider error patterns\n return PROVIDER_ERROR_PATTERNS.some((pattern) => pattern.test(body));\n}\n\n/**\n * Valid message roles for OpenAI-compatible APIs.\n * Some clients send non-standard roles (e.g., \"developer\" instead of \"system\").\n */\nconst VALID_ROLES = new Set([\"system\", \"user\", \"assistant\", \"tool\", \"function\"]);\n\n/**\n * Role mappings for non-standard roles.\n * Maps client-specific roles to standard OpenAI roles.\n */\nconst ROLE_MAPPINGS: Record<string, string> = {\n developer: \"system\", // OpenAI's newer API uses \"developer\" for system messages\n model: \"assistant\", // Some APIs use \"model\" instead of \"assistant\"\n};\n\ntype ChatMessage = { role: string; content: string | unknown };\n\n/**\n * Anthropic tool ID pattern: only alphanumeric, underscore, and hyphen allowed.\n * Error: \"messages.X.content.Y.tool_use.id: String should match pattern '^[a-zA-Z0-9_-]+$'\"\n */\nconst VALID_TOOL_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;\n\n/**\n * Sanitize a tool ID to match Anthropic's required pattern.\n * Replaces invalid characters with underscores.\n */\nfunction sanitizeToolId(id: string | undefined): string | undefined {\n if (!id || typeof id !== \"string\") return id;\n if (VALID_TOOL_ID_PATTERN.test(id)) return id;\n\n // Replace invalid characters with underscores\n return id.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n}\n\n/**\n * Type for messages with tool calls (OpenAI format).\n */\ntype MessageWithTools = ChatMessage & {\n tool_calls?: Array<{ id?: string; type?: string; function?: unknown }>;\n tool_call_id?: string;\n};\n\n/**\n * Type for content blocks that may contain tool IDs (Anthropic format in OpenAI wrapper).\n */\ntype ContentBlock = {\n type?: string;\n id?: string;\n tool_use_id?: string;\n [key: string]: unknown;\n};\n\n/**\n * Sanitize all tool IDs in messages to match Anthropic's pattern.\n * Handles both OpenAI format (tool_calls, tool_call_id) and content block formats.\n */\nfunction sanitizeToolIds(messages: ChatMessage[]): ChatMessage[] {\n if (!messages || messages.length === 0) return messages;\n\n let hasChanges = false;\n const sanitized = messages.map((msg) => {\n const typedMsg = msg as MessageWithTools;\n let msgChanged = false;\n let newMsg = { ...msg } as MessageWithTools;\n\n // Sanitize tool_calls[].id in assistant messages\n if (typedMsg.tool_calls && Array.isArray(typedMsg.tool_calls)) {\n const newToolCalls = typedMsg.tool_calls.map((tc) => {\n if (tc.id && typeof tc.id === \"string\") {\n const sanitized = sanitizeToolId(tc.id);\n if (sanitized !== tc.id) {\n msgChanged = true;\n return { ...tc, id: sanitized };\n }\n }\n return tc;\n });\n if (msgChanged) {\n newMsg = { ...newMsg, tool_calls: newToolCalls };\n }\n }\n\n // Sanitize tool_call_id in tool messages\n if (typedMsg.tool_call_id && typeof typedMsg.tool_call_id === \"string\") {\n const sanitized = sanitizeToolId(typedMsg.tool_call_id);\n if (sanitized !== typedMsg.tool_call_id) {\n msgChanged = true;\n newMsg = { ...newMsg, tool_call_id: sanitized };\n }\n }\n\n // Sanitize content blocks if content is an array (Anthropic-style content)\n if (Array.isArray(typedMsg.content)) {\n const newContent = (typedMsg.content as ContentBlock[]).map((block) => {\n if (!block || typeof block !== \"object\") return block;\n\n let blockChanged = false;\n let newBlock = { ...block };\n\n // tool_use blocks have \"id\"\n if (block.type === \"tool_use\" && block.id && typeof block.id === \"string\") {\n const sanitized = sanitizeToolId(block.id);\n if (sanitized !== block.id) {\n blockChanged = true;\n newBlock = { ...newBlock, id: sanitized };\n }\n }\n\n // tool_result blocks have \"tool_use_id\"\n if (\n block.type === \"tool_result\" &&\n block.tool_use_id &&\n typeof block.tool_use_id === \"string\"\n ) {\n const sanitized = sanitizeToolId(block.tool_use_id);\n if (sanitized !== block.tool_use_id) {\n blockChanged = true;\n newBlock = { ...newBlock, tool_use_id: sanitized };\n }\n }\n\n if (blockChanged) {\n msgChanged = true;\n return newBlock;\n }\n return block;\n });\n\n if (msgChanged) {\n newMsg = { ...newMsg, content: newContent };\n }\n }\n\n if (msgChanged) {\n hasChanges = true;\n return newMsg;\n }\n return msg;\n });\n\n return hasChanges ? sanitized : messages;\n}\n\n/**\n * Normalize message roles to standard OpenAI format.\n * Converts non-standard roles (e.g., \"developer\") to valid ones.\n */\nfunction normalizeMessageRoles(messages: ChatMessage[]): ChatMessage[] {\n if (!messages || messages.length === 0) return messages;\n\n let hasChanges = false;\n const normalized = messages.map((msg) => {\n if (VALID_ROLES.has(msg.role)) return msg;\n\n const mappedRole = ROLE_MAPPINGS[msg.role];\n if (mappedRole) {\n hasChanges = true;\n return { ...msg, role: mappedRole };\n }\n\n // Unknown role - default to \"user\" to avoid API errors\n hasChanges = true;\n return { ...msg, role: \"user\" };\n });\n\n return hasChanges ? normalized : messages;\n}\n\n/**\n * Normalize messages for Google models.\n * Google's Gemini API requires the first non-system message to be from \"user\".\n * If conversation starts with \"assistant\"/\"model\", prepend a placeholder user message.\n */\n\nfunction normalizeMessagesForGoogle(messages: ChatMessage[]): ChatMessage[] {\n if (!messages || messages.length === 0) return messages;\n\n // Find first non-system message\n let firstNonSystemIdx = -1;\n for (let i = 0; i < messages.length; i++) {\n if (messages[i].role !== \"system\") {\n firstNonSystemIdx = i;\n break;\n }\n }\n\n // If no non-system messages, return as-is\n if (firstNonSystemIdx === -1) return messages;\n\n const firstRole = messages[firstNonSystemIdx].role;\n\n // If first non-system message is already \"user\", no change needed\n if (firstRole === \"user\") return messages;\n\n // If first non-system message is \"assistant\" or \"model\", prepend a user message\n if (firstRole === \"assistant\" || firstRole === \"model\") {\n const normalized = [...messages];\n normalized.splice(firstNonSystemIdx, 0, {\n role: \"user\",\n content: \"(continuing conversation)\",\n });\n return normalized;\n }\n\n return messages;\n}\n\n/**\n * Check if a model is a Google model that requires message normalization.\n */\nfunction isGoogleModel(modelId: string): boolean {\n return modelId.startsWith(\"google/\") || modelId.startsWith(\"gemini\");\n}\n\n/**\n * Extended message type for thinking-enabled conversations.\n */\ntype ExtendedChatMessage = ChatMessage & {\n tool_calls?: unknown[];\n reasoning_content?: unknown;\n};\n\n/**\n * Normalize messages for thinking-enabled requests.\n * When thinking/extended_thinking is enabled, assistant messages with tool_calls\n * must have reasoning_content (can be empty string if not present).\n * Error: \"400 thinking is enabled but reasoning_content is missing in assistant tool call message\"\n */\nfunction normalizeMessagesForThinking(messages: ExtendedChatMessage[]): ExtendedChatMessage[] {\n if (!messages || messages.length === 0) return messages;\n\n let hasChanges = false;\n const normalized = messages.map((msg) => {\n // Skip if not assistant or already has reasoning_content\n if (msg.role !== \"assistant\" || msg.reasoning_content !== undefined) {\n return msg;\n }\n\n // Check for OpenAI format: tool_calls array\n const hasOpenAIToolCalls =\n msg.tool_calls && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0;\n\n // Check for Anthropic format: content array with tool_use blocks\n const hasAnthropicToolUse =\n Array.isArray(msg.content) &&\n (msg.content as Array<{ type?: string }>).some((block) => block?.type === \"tool_use\");\n\n if (hasOpenAIToolCalls || hasAnthropicToolUse) {\n hasChanges = true;\n return { ...msg, reasoning_content: \"\" };\n }\n return msg;\n });\n\n return hasChanges ? normalized : messages;\n}\n\n/**\n * Result of truncating messages.\n */\ntype TruncationResult<T> = {\n messages: T[];\n wasTruncated: boolean;\n originalCount: number;\n truncatedCount: number;\n};\n\n/**\n * Truncate messages to stay under BlockRun's MAX_MESSAGES limit.\n * Keeps all system messages and the most recent conversation history.\n * Returns the messages and whether truncation occurred.\n */\nfunction truncateMessages<T extends { role: string }>(messages: T[]): TruncationResult<T> {\n if (!messages || messages.length <= MAX_MESSAGES) {\n return {\n messages,\n wasTruncated: false,\n originalCount: messages?.length ?? 0,\n truncatedCount: messages?.length ?? 0,\n };\n }\n\n // Separate system messages from conversation\n const systemMsgs = messages.filter((m) => m.role === \"system\");\n const conversationMsgs = messages.filter((m) => m.role !== \"system\");\n\n // Keep all system messages + most recent conversation messages\n const maxConversation = MAX_MESSAGES - systemMsgs.length;\n const truncatedConversation = conversationMsgs.slice(-maxConversation);\n\n const result = [...systemMsgs, ...truncatedConversation];\n\n console.log(\n `[ClawRouter] Truncated messages: ${messages.length} → ${result.length} (kept ${systemMsgs.length} system + ${truncatedConversation.length} recent)`,\n );\n\n return {\n messages: result,\n wasTruncated: true,\n originalCount: messages.length,\n truncatedCount: result.length,\n };\n}\n\n// Kimi/Moonshot models use special Unicode tokens for thinking boundaries.\n// Pattern: <|begin▁of▁thinking|>content<|end▁of▁thinking|>\n// The | is fullwidth vertical bar (U+FF5C), ▁ is lower one-eighth block (U+2581).\n\n// Match full Kimi thinking blocks: <|begin...|>content<|end...|>\nconst KIMI_BLOCK_RE = /<[||][^<>]*begin[^<>]*[||]>[\\s\\S]*?<[||][^<>]*end[^<>]*[||]>/gi;\n\n// Match standalone Kimi tokens like <|end▁of▁thinking|>\nconst KIMI_TOKEN_RE = /<[||][^<>]*[||]>/g;\n\n// Standard thinking tags that may leak through from various models\nconst THINKING_TAG_RE = /<\\s*\\/?\\s*(?:think(?:ing)?|thought|antthinking)\\b[^>]*>/gi;\n\n// Full thinking blocks: <think>content</think>\nconst THINKING_BLOCK_RE =\n /<\\s*(?:think(?:ing)?|thought|antthinking)\\b[^>]*>[\\s\\S]*?<\\s*\\/\\s*(?:think(?:ing)?|thought|antthinking)\\s*>/gi;\n\n/**\n * Strip thinking tokens and blocks from model response content.\n * Handles both Kimi-style Unicode tokens and standard XML-style tags.\n *\n * NOTE: DSML tags (<|DSML|...>) are NOT stripped - those are tool calls\n * that should be handled by the API, not hidden from users.\n */\nfunction stripThinkingTokens(content: string): string {\n if (!content) return content;\n // Strip full Kimi thinking blocks first (begin...end with content)\n let cleaned = content.replace(KIMI_BLOCK_RE, \"\");\n // Strip remaining standalone Kimi tokens\n cleaned = cleaned.replace(KIMI_TOKEN_RE, \"\");\n // Strip full thinking blocks (<think>...</think>)\n cleaned = cleaned.replace(THINKING_BLOCK_RE, \"\");\n // Strip remaining standalone thinking tags\n cleaned = cleaned.replace(THINKING_TAG_RE, \"\");\n return cleaned;\n}\n\n/** Callback info for low balance warning */\nexport type LowBalanceInfo = {\n balanceUSD: string;\n walletAddress: string;\n};\n\n/** Callback info for insufficient funds error */\nexport type InsufficientFundsInfo = {\n balanceUSD: string;\n requiredUSD: string;\n walletAddress: string;\n};\n\nexport type ProxyOptions = {\n walletKey: string;\n apiBase?: string;\n /** Port to listen on (default: 8402) */\n port?: number;\n routingConfig?: Partial<RoutingConfig>;\n /** Request timeout in ms (default: 180000 = 3 minutes). Covers on-chain tx + LLM response. */\n requestTimeoutMs?: number;\n /** Skip balance checks (for testing only). Default: false */\n skipBalanceCheck?: boolean;\n /**\n * Session persistence config. When enabled, maintains model selection\n * across requests within a session to prevent mid-task model switching.\n */\n sessionConfig?: Partial<SessionConfig>;\n /**\n * Auto-compress large requests to reduce network usage.\n * When enabled, requests are automatically compressed using\n * LLM-safe context compression (15-40% reduction).\n * Default: true\n */\n autoCompressRequests?: boolean;\n /**\n * Threshold in KB to trigger auto-compression (default: 180).\n * Requests larger than this are compressed before sending.\n * Set to 0 to compress all requests.\n */\n compressionThresholdKB?: number;\n /**\n * Response caching config. When enabled, identical requests return\n * cached responses instead of making new API calls.\n * Default: enabled with 10 minute TTL, 200 max entries.\n */\n cacheConfig?: ResponseCacheConfig;\n onReady?: (port: number) => void;\n onError?: (error: Error) => void;\n onPayment?: (info: { model: string; amount: string; network: string }) => void;\n onRouted?: (decision: RoutingDecision) => void;\n /** Called when balance drops below $1.00 (warning, request still proceeds) */\n onLowBalance?: (info: LowBalanceInfo) => void;\n /** Called when balance is insufficient for a request (request fails) */\n onInsufficientFunds?: (info: InsufficientFundsInfo) => void;\n};\n\nexport type ProxyHandle = {\n port: number;\n baseUrl: string;\n walletAddress: string;\n balanceMonitor: BalanceMonitor;\n close: () => Promise<void>;\n};\n\n/**\n * Build model pricing map from BLOCKRUN_MODELS.\n */\nfunction buildModelPricing(): Map<string, ModelPricing> {\n const map = new Map<string, ModelPricing>();\n for (const m of BLOCKRUN_MODELS) {\n if (m.id === AUTO_MODEL) continue; // skip meta-model\n map.set(m.id, { inputPrice: m.inputPrice, outputPrice: m.outputPrice });\n }\n return map;\n}\n\ntype ModelListEntry = {\n id: string;\n object: \"model\";\n created: number;\n owned_by: string;\n};\n\n/**\n * Build `/v1/models` response entries from the full OpenClaw model registry.\n * This includes alias IDs (e.g., `flash`, `kimi`) so `/model <alias>` works reliably.\n */\nexport function buildProxyModelList(\n createdAt: number = Math.floor(Date.now() / 1000),\n): ModelListEntry[] {\n const seen = new Set<string>();\n return OPENCLAW_MODELS.filter((model) => {\n if (seen.has(model.id)) return false;\n seen.add(model.id);\n return true;\n }).map((model) => ({\n id: model.id,\n object: \"model\",\n created: createdAt,\n owned_by: model.id.includes(\"/\") ? (model.id.split(\"/\")[0] ?? \"blockrun\") : \"blockrun\",\n }));\n}\n\n/**\n * Merge partial routing config overrides with defaults.\n */\nfunction mergeRoutingConfig(overrides?: Partial<RoutingConfig>): RoutingConfig {\n if (!overrides) return DEFAULT_ROUTING_CONFIG;\n return {\n ...DEFAULT_ROUTING_CONFIG,\n ...overrides,\n classifier: { ...DEFAULT_ROUTING_CONFIG.classifier, ...overrides.classifier },\n scoring: { ...DEFAULT_ROUTING_CONFIG.scoring, ...overrides.scoring },\n tiers: { ...DEFAULT_ROUTING_CONFIG.tiers, ...overrides.tiers },\n overrides: { ...DEFAULT_ROUTING_CONFIG.overrides, ...overrides.overrides },\n };\n}\n\n/**\n * Estimate USDC cost for a request based on model pricing.\n * Returns amount string in USDC smallest unit (6 decimals) or undefined if unknown.\n */\nfunction estimateAmount(\n modelId: string,\n bodyLength: number,\n maxTokens: number,\n): string | undefined {\n const model = BLOCKRUN_MODELS.find((m) => m.id === modelId);\n if (!model) return undefined;\n\n // Rough estimate: ~4 chars per token for input\n const estimatedInputTokens = Math.ceil(bodyLength / 4);\n const estimatedOutputTokens = maxTokens || model.maxOutput || 4096;\n\n const costUsd =\n (estimatedInputTokens / 1_000_000) * model.inputPrice +\n (estimatedOutputTokens / 1_000_000) * model.outputPrice;\n\n // Convert to USDC 6-decimal integer, add 20% buffer for estimation error\n // Minimum 1000 ($0.001) to match CDP Facilitator's enforced minimum payment\n const amountMicros = Math.max(1000, Math.ceil(costUsd * 1.2 * 1_000_000));\n return amountMicros.toString();\n}\n\n/**\n * Proxy a partner API request through x402 payment flow.\n *\n * Simplified proxy for partner endpoints (/v1/x/*, /v1/partner/*).\n * No smart routing, SSE, compression, or sessions — just collect body,\n * forward via payFetch (which handles 402 automatically), and stream back.\n */\nasync function proxyPartnerRequest(\n req: IncomingMessage,\n res: ServerResponse,\n apiBase: string,\n payFetch: (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ) => Promise<Response>,\n): Promise<void> {\n const startTime = Date.now();\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 const body = Buffer.concat(bodyChunks);\n\n // Forward headers (strip hop-by-hop)\n const headers: Record<string, string> = {};\n for (const [key, value] of Object.entries(req.headers)) {\n if (\n key === \"host\" ||\n key === \"connection\" ||\n key === \"transfer-encoding\" ||\n key === \"content-length\"\n )\n continue;\n if (typeof value === \"string\") headers[key] = value;\n }\n if (!headers[\"content-type\"]) headers[\"content-type\"] = \"application/json\";\n headers[\"user-agent\"] = USER_AGENT;\n\n console.log(`[ClawRouter] Partner request: ${req.method} ${req.url}`);\n\n const upstream = await payFetch(upstreamUrl, {\n method: req.method ?? \"POST\",\n headers,\n body: body.length > 0 ? new Uint8Array(body) : undefined,\n });\n\n // Forward response headers\n const responseHeaders: Record<string, string> = {};\n upstream.headers.forEach((value, key) => {\n if (key === \"transfer-encoding\" || key === \"connection\" || key === \"content-encoding\") return;\n responseHeaders[key] = value;\n });\n\n res.writeHead(upstream.status, responseHeaders);\n\n // Stream 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 safeWrite(res, Buffer.from(value));\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n res.end();\n\n const latencyMs = Date.now() - startTime;\n console.log(`[ClawRouter] Partner response: ${upstream.status} (${latencyMs}ms)`);\n\n // Log partner usage (fire-and-forget)\n logUsage({\n timestamp: new Date().toISOString(),\n model: \"partner\",\n tier: \"PARTNER\",\n cost: 0, // Actual cost handled by x402 settlement\n baselineCost: 0,\n savings: 0,\n latencyMs,\n partnerId:\n (req.url?.split(\"?\")[0] ?? \"\").replace(/^\\/v1\\//, \"\").replace(/\\//g, \"_\") || \"unknown\",\n service: \"partner\",\n }).catch(() => {});\n}\n\n/**\n * Start the local x402 proxy server.\n *\n * If a proxy is already running on the target port, reuses it instead of failing.\n * Port can be configured via BLOCKRUN_PROXY_PORT environment variable.\n *\n * Returns a handle with the assigned port, base URL, and a close function.\n */\nexport async function startProxy(options: ProxyOptions): Promise<ProxyHandle> {\n const apiBase = options.apiBase ?? BLOCKRUN_API;\n\n // Determine port: options.port > env var > default\n const listenPort = options.port ?? getProxyPort();\n\n // Check if a proxy is already running on this port\n const existingWallet = await checkExistingProxy(listenPort);\n if (existingWallet) {\n // Proxy already running — reuse it instead of failing with EADDRINUSE\n const account = privateKeyToAccount(options.walletKey as `0x${string}`);\n const balanceMonitor = new BalanceMonitor(account.address);\n const baseUrl = `http://127.0.0.1:${listenPort}`;\n\n // Verify the existing proxy is using the same wallet (or warn if different)\n if (existingWallet !== account.address) {\n console.warn(\n `[ClawRouter] Existing proxy on port ${listenPort} uses wallet ${existingWallet}, but current config uses ${account.address}. Reusing existing proxy.`,\n );\n }\n\n options.onReady?.(listenPort);\n\n return {\n port: listenPort,\n baseUrl,\n walletAddress: existingWallet,\n balanceMonitor,\n close: async () => {\n // No-op: we didn't start this proxy, so we shouldn't close it\n },\n };\n }\n\n // Create x402 payment-enabled fetch from wallet private key\n const account = privateKeyToAccount(options.walletKey as `0x${string}`);\n const { fetch: payFetch } = createPaymentFetch(options.walletKey as `0x${string}`);\n\n // Create balance monitor for pre-request checks\n const balanceMonitor = new BalanceMonitor(account.address);\n\n // Build router options (100% local — no external API calls for routing)\n const routingConfig = mergeRoutingConfig(options.routingConfig);\n const modelPricing = buildModelPricing();\n const routerOpts: RouterOptions = {\n config: routingConfig,\n modelPricing,\n };\n\n // Request deduplicator (shared across all requests)\n const deduplicator = new RequestDeduplicator();\n\n // Response cache for identical requests (longer TTL than dedup)\n const responseCache = new ResponseCache(options.cacheConfig);\n\n // Session store for model persistence (prevents mid-task model switching)\n const sessionStore = new SessionStore(options.sessionConfig);\n\n // Session journal for memory (enables agents to recall earlier work)\n const sessionJournal = new SessionJournal();\n\n // Track active connections for graceful cleanup\n const connections = new Set<import(\"net\").Socket>();\n\n const server = createServer(async (req: IncomingMessage, res: ServerResponse) => {\n // Add stream error handlers to prevent server crashes\n req.on(\"error\", (err) => {\n console.error(`[ClawRouter] Request stream error: ${err.message}`);\n // Don't throw - just log and let request handler deal with it\n });\n\n res.on(\"error\", (err) => {\n console.error(`[ClawRouter] Response stream error: ${err.message}`);\n // Don't try to write to failed socket - just log\n });\n\n // Finished wrapper for guaranteed cleanup on response completion/error\n finished(res, (err) => {\n if (err && err.code !== \"ERR_STREAM_DESTROYED\") {\n console.error(`[ClawRouter] Response finished with error: ${err.message}`);\n }\n // Note: heartbeatInterval cleanup happens in res.on(\"close\") handler\n // Note: completed and dedup cleanup happens in the res.on(\"close\") handler below\n });\n\n // Request finished wrapper for complete stream lifecycle tracking\n finished(req, (err) => {\n if (err && err.code !== \"ERR_STREAM_DESTROYED\") {\n console.error(`[ClawRouter] Request finished with error: ${err.message}`);\n }\n });\n\n // Health check with optional balance info\n if (req.url === \"/health\" || req.url?.startsWith(\"/health?\")) {\n const url = new URL(req.url, \"http://localhost\");\n const full = url.searchParams.get(\"full\") === \"true\";\n\n const response: Record<string, unknown> = {\n status: \"ok\",\n wallet: account.address,\n };\n\n if (full) {\n try {\n const balanceInfo = await balanceMonitor.checkBalance();\n response.balance = balanceInfo.balanceUSD;\n response.isLow = balanceInfo.isLow;\n response.isEmpty = balanceInfo.isEmpty;\n } catch {\n response.balanceError = \"Could not fetch balance\";\n }\n }\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(response));\n return;\n }\n\n // Cache stats endpoint\n if (req.url === \"/cache\" || req.url?.startsWith(\"/cache?\")) {\n const stats = responseCache.getStats();\n res.writeHead(200, {\n \"Content-Type\": \"application/json\",\n \"Cache-Control\": \"no-cache\",\n });\n res.end(JSON.stringify(stats, null, 2));\n return;\n }\n\n // Stats API endpoint - returns JSON for programmatic access\n if (req.url === \"/stats\" || req.url?.startsWith(\"/stats?\")) {\n try {\n const url = new URL(req.url, \"http://localhost\");\n const days = parseInt(url.searchParams.get(\"days\") || \"7\", 10);\n const stats = await getStats(Math.min(days, 30));\n\n res.writeHead(200, {\n \"Content-Type\": \"application/json\",\n \"Cache-Control\": \"no-cache\",\n });\n res.end(JSON.stringify(stats, null, 2));\n } catch (err) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: `Failed to get stats: ${err instanceof Error ? err.message : String(err)}`,\n }),\n );\n }\n return;\n }\n\n // --- Handle /v1/models locally (no upstream call needed) ---\n if (req.url === \"/v1/models\" && req.method === \"GET\") {\n const models = buildProxyModelList();\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ object: \"list\", data: models }));\n return;\n }\n\n // --- Handle partner API paths (/v1/x/*, /v1/partner/*) ---\n if (req.url?.match(/^\\/v1\\/(?:x|partner)\\//)) {\n try {\n await proxyPartnerRequest(req, res, apiBase, payFetch);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n options.onError?.(error);\n if (!res.headersSent) {\n res.writeHead(502, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: { message: `Partner proxy error: ${error.message}`, type: \"partner_error\" },\n }),\n );\n }\n }\n return;\n }\n\n // Only proxy paths starting with /v1\n if (!req.url?.startsWith(\"/v1\")) {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Not found\" }));\n return;\n }\n\n try {\n await proxyRequest(\n req,\n res,\n apiBase,\n payFetch,\n options,\n routerOpts,\n deduplicator,\n balanceMonitor,\n sessionStore,\n responseCache,\n sessionJournal,\n );\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n options.onError?.(error);\n\n if (!res.headersSent) {\n res.writeHead(502, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: { message: `Proxy error: ${error.message}`, type: \"proxy_error\" },\n }),\n );\n } else if (!res.writableEnded) {\n // Headers already sent (streaming) — send error as SSE event\n res.write(\n `data: ${JSON.stringify({ error: { message: error.message, type: \"proxy_error\" } })}\\n\\n`,\n );\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n }\n }\n });\n\n // Listen on configured port with retry logic for TIME_WAIT handling\n // When gateway restarts quickly, the port may still be in TIME_WAIT state.\n // We retry with delay instead of incorrectly assuming a proxy is running.\n const tryListen = (attempt: number): Promise<void> => {\n return new Promise<void>((resolveAttempt, rejectAttempt) => {\n const onError = async (err: NodeJS.ErrnoException) => {\n server.removeListener(\"error\", onError);\n\n if (err.code === \"EADDRINUSE\") {\n // Port is in use - check if a proxy is actually running\n const existingWallet = await checkExistingProxy(listenPort);\n if (existingWallet) {\n // Proxy is actually running - this is fine, reuse it\n console.log(`[ClawRouter] Existing proxy detected on port ${listenPort}, reusing`);\n rejectAttempt({ code: \"REUSE_EXISTING\", wallet: existingWallet });\n return;\n }\n\n // Port is in TIME_WAIT (no proxy responding) - retry after delay\n if (attempt < PORT_RETRY_ATTEMPTS) {\n console.log(\n `[ClawRouter] Port ${listenPort} in TIME_WAIT, retrying in ${PORT_RETRY_DELAY_MS}ms (attempt ${attempt}/${PORT_RETRY_ATTEMPTS})`,\n );\n rejectAttempt({ code: \"RETRY\", attempt });\n return;\n }\n\n // Max retries exceeded\n console.error(\n `[ClawRouter] Port ${listenPort} still in use after ${PORT_RETRY_ATTEMPTS} attempts`,\n );\n rejectAttempt(err);\n return;\n }\n\n rejectAttempt(err);\n };\n\n server.once(\"error\", onError);\n server.listen(listenPort, \"127.0.0.1\", () => {\n server.removeListener(\"error\", onError);\n resolveAttempt();\n });\n });\n };\n\n // Retry loop for port binding\n let lastError: Error | undefined;\n for (let attempt = 1; attempt <= PORT_RETRY_ATTEMPTS; attempt++) {\n try {\n await tryListen(attempt);\n break; // Success\n } catch (err: unknown) {\n const error = err as { code?: string; wallet?: string; attempt?: number };\n\n if (error.code === \"REUSE_EXISTING\" && error.wallet) {\n // Proxy is running, reuse it\n const baseUrl = `http://127.0.0.1:${listenPort}`;\n options.onReady?.(listenPort);\n return {\n port: listenPort,\n baseUrl,\n walletAddress: error.wallet,\n balanceMonitor,\n close: async () => {\n // No-op: we didn't start this proxy, so we shouldn't close it\n },\n };\n }\n\n if (error.code === \"RETRY\") {\n // Wait before retry\n await new Promise((r) => setTimeout(r, PORT_RETRY_DELAY_MS));\n continue;\n }\n\n // Other error - throw\n lastError = err as Error;\n break;\n }\n }\n\n if (lastError) {\n throw lastError;\n }\n\n // Server is now listening - set up remaining handlers\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 // Check for updates (non-blocking)\n checkForUpdates();\n\n // Add runtime error handler AFTER successful listen\n // This handles errors that occur during server operation (not just startup)\n server.on(\"error\", (err) => {\n console.error(`[ClawRouter] Server runtime error: ${err.message}`);\n options.onError?.(err);\n // Don't crash - log and continue\n });\n\n // Handle client connection errors (bad requests, socket errors)\n server.on(\"clientError\", (err, socket) => {\n console.error(`[ClawRouter] Client error: ${err.message}`);\n // Send 400 Bad Request if socket is still writable\n if (socket.writable && !socket.destroyed) {\n socket.end(\"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\");\n }\n });\n\n // Track connections for graceful cleanup\n server.on(\"connection\", (socket) => {\n connections.add(socket);\n\n // Set 5-minute timeout for streaming requests\n socket.setTimeout(300_000);\n\n socket.on(\"timeout\", () => {\n console.error(`[ClawRouter] Socket timeout, destroying connection`);\n socket.destroy();\n });\n\n socket.on(\"end\", () => {\n // Half-closed by client (FIN received)\n });\n\n socket.on(\"error\", (err) => {\n console.error(`[ClawRouter] Socket error: ${err.message}`);\n });\n\n socket.on(\"close\", () => {\n connections.delete(socket);\n });\n });\n\n return {\n port,\n baseUrl,\n walletAddress: account.address,\n balanceMonitor,\n close: () =>\n new Promise<void>((res, rej) => {\n const timeout = setTimeout(() => {\n rej(new Error(\"[ClawRouter] Close timeout after 4s\"));\n }, 4000);\n\n sessionStore.close();\n // Destroy all active connections before closing server\n for (const socket of connections) {\n socket.destroy();\n }\n connections.clear();\n server.close((err) => {\n clearTimeout(timeout);\n if (err) {\n rej(err);\n } else {\n res();\n }\n });\n }),\n };\n}\n\n/** Result of attempting a model request */\ntype ModelRequestResult = {\n success: boolean;\n response?: Response;\n errorBody?: string;\n errorStatus?: number;\n isProviderError?: boolean;\n};\n\n/**\n * Attempt a request with a specific model.\n * Returns the response or error details for fallback decision.\n */\nasync function tryModelRequest(\n upstreamUrl: string,\n method: string,\n headers: Record<string, string>,\n body: Buffer,\n modelId: string,\n maxTokens: number,\n payFetch: (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ) => Promise<Response>,\n balanceMonitor: BalanceMonitor,\n signal: AbortSignal,\n): Promise<ModelRequestResult> {\n // Update model in body and normalize messages\n let requestBody = body;\n try {\n const parsed = JSON.parse(body.toString()) as Record<string, unknown>;\n parsed.model = modelId;\n\n // Normalize message roles (e.g., \"developer\" -> \"system\")\n if (Array.isArray(parsed.messages)) {\n parsed.messages = normalizeMessageRoles(parsed.messages as ChatMessage[]);\n }\n\n // Truncate messages to stay under BlockRun's limit (200 messages)\n if (Array.isArray(parsed.messages)) {\n const truncationResult = truncateMessages(parsed.messages as ChatMessage[]);\n parsed.messages = truncationResult.messages;\n }\n\n // Sanitize tool IDs to match Anthropic's pattern (alphanumeric, underscore, hyphen only)\n if (Array.isArray(parsed.messages)) {\n parsed.messages = sanitizeToolIds(parsed.messages as ChatMessage[]);\n }\n\n // Normalize messages for Google models (first non-system message must be \"user\")\n if (isGoogleModel(modelId) && Array.isArray(parsed.messages)) {\n parsed.messages = normalizeMessagesForGoogle(parsed.messages as ChatMessage[]);\n }\n\n // Normalize messages for thinking-enabled requests (add reasoning_content to tool calls)\n // Check request flags AND target model - reasoning models have thinking enabled server-side\n const hasThinkingEnabled = !!(\n parsed.thinking ||\n parsed.extended_thinking ||\n isReasoningModel(modelId)\n );\n if (hasThinkingEnabled && Array.isArray(parsed.messages)) {\n parsed.messages = normalizeMessagesForThinking(parsed.messages as ExtendedChatMessage[]);\n }\n\n requestBody = Buffer.from(JSON.stringify(parsed));\n } catch {\n // If body isn't valid JSON, use as-is\n }\n\n // Estimate cost for pre-auth\n const estimated = estimateAmount(modelId, requestBody.length, maxTokens);\n const preAuth: PreAuthParams | undefined = estimated ? { estimatedAmount: estimated } : undefined;\n\n try {\n const response = await payFetch(\n upstreamUrl,\n {\n method,\n headers,\n body: requestBody.length > 0 ? new Uint8Array(requestBody) : undefined,\n signal,\n },\n preAuth,\n );\n\n // Check for provider errors\n if (response.status !== 200) {\n // Clone response to read body without consuming it\n const errorBody = await response.text();\n const isProviderErr = isProviderError(response.status, errorBody);\n\n return {\n success: false,\n errorBody,\n errorStatus: response.status,\n isProviderError: isProviderErr,\n };\n }\n\n // Detect provider degradation hidden inside HTTP 200 responses.\n const contentType = response.headers.get(\"content-type\") || \"\";\n if (contentType.includes(\"json\") || contentType.includes(\"text\")) {\n try {\n const responseBody = await response.clone().text();\n const degradedReason = detectDegradedSuccessResponse(responseBody);\n if (degradedReason) {\n return {\n success: false,\n errorBody: degradedReason,\n errorStatus: 503,\n isProviderError: true,\n };\n }\n } catch {\n // Ignore body inspection failures and pass through response.\n }\n }\n\n return { success: true, response };\n } catch (err) {\n const errorMsg = err instanceof Error ? err.message : String(err);\n return {\n success: false,\n errorBody: errorMsg,\n errorStatus: 500,\n isProviderError: true, // Network errors are retryable\n };\n }\n}\n\n/**\n * Proxy a single request through x402 payment flow to BlockRun API.\n *\n * Optimizations applied in order:\n * 1. Dedup check — if same request body seen within 30s, replay cached response\n * 2. Streaming heartbeat — for stream:true, send 200 + heartbeats immediately\n * 3. Payment pre-auth — estimate USDC amount and pre-sign to skip 402 round trip\n * 4. Smart routing — when model is \"blockrun/auto\", pick cheapest capable model\n * 5. Fallback chain — on provider errors, try next model in tier's fallback list\n */\nasync function proxyRequest(\n req: IncomingMessage,\n res: ServerResponse,\n apiBase: string,\n payFetch: (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ) => Promise<Response>,\n options: ProxyOptions,\n routerOpts: RouterOptions,\n deduplicator: RequestDeduplicator,\n balanceMonitor: BalanceMonitor,\n sessionStore: SessionStore,\n responseCache: ResponseCache,\n sessionJournal: SessionJournal,\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 // Track original context size for response headers\n const originalContextSizeKB = Math.ceil(body.length / 1024);\n\n // Routing debug info is on by default; disable with x-clawrouter-debug: false\n const debugMode = req.headers[\"x-clawrouter-debug\"] !== \"false\";\n\n // --- Smart routing ---\n let routingDecision: RoutingDecision | undefined;\n let hasTools = false; // true when request includes a tools schema\n let hasVision = false; // true when request includes image_url content parts\n let isStreaming = false;\n let modelId = \"\";\n let maxTokens = 4096;\n let routingProfile: \"free\" | \"eco\" | \"auto\" | \"premium\" | null = null;\n let accumulatedContent = \"\"; // For session journal event extraction\n const isChatCompletion = req.url?.includes(\"/chat/completions\");\n\n // Extract session ID early for journal operations (header-only at this point)\n const sessionId = getSessionId(req.headers as Record<string, string | string[] | undefined>);\n // Full session ID (header + content-derived) — populated once messages are parsed\n let effectiveSessionId: string | undefined = sessionId;\n\n if (isChatCompletion && body.length > 0) {\n try {\n const parsed = JSON.parse(body.toString()) as Record<string, unknown>;\n isStreaming = parsed.stream === true;\n modelId = (parsed.model as string) || \"\";\n maxTokens = (parsed.max_tokens as number) || 4096;\n let bodyModified = false;\n\n // Extract last user message content (used by session journal + /debug command)\n const parsedMessages = Array.isArray(parsed.messages)\n ? (parsed.messages as Array<{ role: string; content: unknown }>)\n : [];\n const lastUserMsg = [...parsedMessages].reverse().find((m) => m.role === \"user\");\n const rawLastContent = lastUserMsg?.content;\n const lastContent =\n typeof rawLastContent === \"string\"\n ? rawLastContent\n : Array.isArray(rawLastContent)\n ? (rawLastContent as Array<{ type: string; text?: string }>)\n .filter((b) => b.type === \"text\")\n .map((b) => b.text ?? \"\")\n .join(\" \")\n : \"\";\n\n // --- Session Journal: Inject context if needed ---\n // Check if the last user message asks about past work\n if (sessionId && parsedMessages.length > 0) {\n const messages = parsedMessages;\n\n if (sessionJournal.needsContext(lastContent)) {\n const journalText = sessionJournal.format(sessionId);\n if (journalText) {\n // Find system message and prepend journal, or add a new system message\n const sysIdx = messages.findIndex((m) => m.role === \"system\");\n if (sysIdx >= 0 && typeof messages[sysIdx].content === \"string\") {\n messages[sysIdx] = {\n ...messages[sysIdx],\n content: journalText + \"\\n\\n\" + messages[sysIdx].content,\n };\n } else {\n messages.unshift({ role: \"system\", content: journalText });\n }\n parsed.messages = messages;\n bodyModified = true;\n console.log(\n `[ClawRouter] Injected session journal (${journalText.length} chars) for session ${sessionId.slice(0, 8)}...`,\n );\n }\n }\n }\n\n // --- /debug command: return routing diagnostics without calling upstream ---\n if (lastContent.startsWith(\"/debug\")) {\n const debugPrompt = lastContent.slice(\"/debug\".length).trim() || \"hello\";\n const messages = parsed.messages as Array<{ role: string; content: unknown }>;\n const systemMsg = messages?.find((m) => m.role === \"system\");\n const systemPrompt = typeof systemMsg?.content === \"string\" ? systemMsg.content : undefined;\n const fullText = `${systemPrompt ?? \"\"} ${debugPrompt}`;\n const estimatedTokens = Math.ceil(fullText.length / 4);\n\n // Determine routing profile\n const normalizedModel =\n typeof parsed.model === \"string\" ? parsed.model.trim().toLowerCase() : \"\";\n const profileName = normalizedModel.replace(\"blockrun/\", \"\");\n const debugProfile = (\n [\"free\", \"eco\", \"auto\", \"premium\"].includes(profileName) ? profileName : \"auto\"\n ) as \"free\" | \"eco\" | \"auto\" | \"premium\";\n\n // Run scoring\n const scoring = classifyByRules(\n debugPrompt,\n systemPrompt,\n estimatedTokens,\n DEFAULT_ROUTING_CONFIG.scoring,\n );\n\n // Run full routing decision\n const debugRouting = route(debugPrompt, systemPrompt, maxTokens, {\n ...routerOpts,\n routingProfile: debugProfile,\n });\n\n // Format dimension scores\n const dimLines = (scoring.dimensions ?? [])\n .map((d) => {\n const nameStr = (d.name + \":\").padEnd(24);\n const scoreStr = d.score.toFixed(2).padStart(6);\n const sigStr = d.signal ? ` [${d.signal}]` : \"\";\n return ` ${nameStr}${scoreStr}${sigStr}`;\n })\n .join(\"\\n\");\n\n // Session info\n const sess = sessionId ? sessionStore.getSession(sessionId) : undefined;\n const sessLine = sess\n ? `Session: ${sessionId!.slice(0, 8)}... → pinned: ${sess.model} (${sess.requestCount} requests)`\n : sessionId\n ? `Session: ${sessionId.slice(0, 8)}... → no pinned model`\n : \"Session: none\";\n\n const { simpleMedium, mediumComplex, complexReasoning } =\n DEFAULT_ROUTING_CONFIG.scoring.tierBoundaries;\n\n const debugText = [\n \"ClawRouter Debug\",\n \"\",\n `Profile: ${debugProfile} | Tier: ${debugRouting.tier} | Model: ${debugRouting.model}`,\n `Confidence: ${debugRouting.confidence.toFixed(2)} | Cost: $${debugRouting.costEstimate.toFixed(4)} | Savings: ${(debugRouting.savings * 100).toFixed(0)}%`,\n `Reasoning: ${debugRouting.reasoning}`,\n \"\",\n `Scoring (weighted: ${scoring.score.toFixed(3)})`,\n dimLines,\n \"\",\n `Tier Boundaries: SIMPLE <${simpleMedium.toFixed(2)} | MEDIUM <${mediumComplex.toFixed(2)} | COMPLEX <${complexReasoning.toFixed(2)} | REASONING >=${complexReasoning.toFixed(2)}`,\n \"\",\n sessLine,\n ].join(\"\\n\");\n\n // Build synthetic OpenAI chat completion response\n const completionId = `chatcmpl-debug-${Date.now()}`;\n const timestamp = Math.floor(Date.now() / 1000);\n const syntheticResponse = {\n id: completionId,\n object: \"chat.completion\",\n created: timestamp,\n model: \"clawrouter/debug\",\n choices: [\n {\n index: 0,\n message: { role: \"assistant\", content: debugText },\n finish_reason: \"stop\",\n },\n ],\n usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },\n };\n\n if (isStreaming) {\n // SSE streaming response\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n });\n const sseChunk = {\n id: completionId,\n object: \"chat.completion.chunk\",\n created: timestamp,\n model: \"clawrouter/debug\",\n choices: [\n {\n index: 0,\n delta: { role: \"assistant\", content: debugText },\n finish_reason: null,\n },\n ],\n };\n const sseDone = {\n id: completionId,\n object: \"chat.completion.chunk\",\n created: timestamp,\n model: \"clawrouter/debug\",\n choices: [{ index: 0, delta: {}, finish_reason: \"stop\" }],\n };\n res.write(`data: ${JSON.stringify(sseChunk)}\\n\\n`);\n res.write(`data: ${JSON.stringify(sseDone)}\\n\\n`);\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n } else {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(syntheticResponse));\n }\n console.log(`[ClawRouter] /debug command → ${debugRouting.tier} | ${debugRouting.model}`);\n return;\n }\n\n // --- /imagegen command: generate an image via BlockRun image API ---\n if (lastContent.startsWith(\"/imagegen\")) {\n const imageArgs = lastContent.slice(\"/imagegen\".length).trim();\n\n // Parse optional flags: /imagegen --model dall-e-3 --size 1792x1024 a cute cat\n let imageModel = \"google/nano-banana\";\n let imageSize = \"1024x1024\";\n let imagePrompt = imageArgs;\n\n // Extract --model flag\n const modelMatch = imageArgs.match(/--model\\s+(\\S+)/);\n if (modelMatch) {\n const raw = modelMatch[1];\n // Resolve shorthand aliases\n const IMAGE_MODEL_ALIASES: Record<string, string> = {\n \"dall-e-3\": \"openai/dall-e-3\",\n \"dalle3\": \"openai/dall-e-3\",\n \"dalle\": \"openai/dall-e-3\",\n \"gpt-image\": \"openai/gpt-image-1\",\n \"gpt-image-1\": \"openai/gpt-image-1\",\n \"flux\": \"black-forest/flux-1.1-pro\",\n \"flux-pro\": \"black-forest/flux-1.1-pro\",\n \"banana\": \"google/nano-banana\",\n \"nano-banana\": \"google/nano-banana\",\n \"banana-pro\": \"google/nano-banana-pro\",\n \"nano-banana-pro\": \"google/nano-banana-pro\",\n };\n imageModel = IMAGE_MODEL_ALIASES[raw] ?? raw;\n imagePrompt = imagePrompt.replace(/--model\\s+\\S+/, \"\").trim();\n }\n\n // Extract --size flag\n const sizeMatch = imageArgs.match(/--size\\s+(\\d+x\\d+)/);\n if (sizeMatch) {\n imageSize = sizeMatch[1];\n imagePrompt = imagePrompt.replace(/--size\\s+\\d+x\\d+/, \"\").trim();\n }\n\n if (!imagePrompt) {\n const errorText = [\n \"Usage: /imagegen <prompt>\",\n \"\",\n \"Options:\",\n \" --model <model> Model to use (default: nano-banana)\",\n \" --size <WxH> Image size (default: 1024x1024)\",\n \"\",\n \"Models:\",\n \" nano-banana Google Gemini Flash — $0.05/image\",\n \" banana-pro Google Gemini Pro — $0.10/image (up to 4K)\",\n \" dall-e-3 OpenAI DALL-E 3 — $0.04/image\",\n \" gpt-image OpenAI GPT Image 1 — $0.02/image\",\n \" flux Black Forest Flux 1.1 Pro — $0.04/image\",\n \"\",\n \"Examples:\",\n \" /imagegen a cat wearing sunglasses\",\n \" /imagegen --model dall-e-3 a futuristic city at sunset\",\n \" /imagegen --model banana-pro --size 2048x2048 mountain landscape\",\n ].join(\"\\n\");\n\n const completionId = `chatcmpl-image-${Date.now()}`;\n const timestamp = Math.floor(Date.now() / 1000);\n if (isStreaming) {\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n });\n res.write(`data: ${JSON.stringify({ id: completionId, object: \"chat.completion.chunk\", created: timestamp, model: \"clawrouter/image\", choices: [{ index: 0, delta: { role: \"assistant\", content: errorText }, finish_reason: null }] })}\\n\\n`);\n res.write(`data: ${JSON.stringify({ id: completionId, object: \"chat.completion.chunk\", created: timestamp, model: \"clawrouter/image\", choices: [{ index: 0, delta: {}, finish_reason: \"stop\" }] })}\\n\\n`);\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n } else {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({\n id: completionId, object: \"chat.completion\", created: timestamp, model: \"clawrouter/image\",\n choices: [{ index: 0, message: { role: \"assistant\", content: errorText }, finish_reason: \"stop\" }],\n usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },\n }));\n }\n console.log(`[ClawRouter] /imagegen command → showing usage help`);\n return;\n }\n\n // Call upstream image generation API\n console.log(`[ClawRouter] /imagegen command → ${imageModel} (${imageSize}): ${imagePrompt.slice(0, 80)}...`);\n try {\n const imageUpstreamUrl = `${apiBase}/v1/images/generations`;\n const imageBody = JSON.stringify({ model: imageModel, prompt: imagePrompt, size: imageSize, n: 1 });\n const imageResponse = await payFetch(imageUpstreamUrl, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", \"user-agent\": USER_AGENT },\n body: imageBody,\n });\n\n const imageResult = await imageResponse.json() as {\n created?: number;\n data?: Array<{ url?: string; revised_prompt?: string }>;\n error?: string | { message?: string };\n };\n\n let responseText: string;\n if (!imageResponse.ok || imageResult.error) {\n const errMsg = typeof imageResult.error === \"string\"\n ? imageResult.error\n : (imageResult.error as { message?: string })?.message ?? `HTTP ${imageResponse.status}`;\n responseText = `Image generation failed: ${errMsg}`;\n console.log(`[ClawRouter] /imagegen error: ${errMsg}`);\n } else {\n const images = imageResult.data ?? [];\n if (images.length === 0) {\n responseText = \"Image generation returned no results.\";\n } else {\n const lines: string[] = [];\n for (const img of images) {\n if (img.url) lines.push(img.url);\n if (img.revised_prompt) lines.push(`Revised prompt: ${img.revised_prompt}`);\n }\n lines.push(\"\", `Model: ${imageModel} | Size: ${imageSize}`);\n responseText = lines.join(\"\\n\");\n }\n console.log(`[ClawRouter] /imagegen success: ${images.length} image(s) generated`);\n }\n\n // Return as synthetic chat completion\n const completionId = `chatcmpl-image-${Date.now()}`;\n const timestamp = Math.floor(Date.now() / 1000);\n if (isStreaming) {\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n });\n res.write(`data: ${JSON.stringify({ id: completionId, object: \"chat.completion.chunk\", created: timestamp, model: \"clawrouter/image\", choices: [{ index: 0, delta: { role: \"assistant\", content: responseText }, finish_reason: null }] })}\\n\\n`);\n res.write(`data: ${JSON.stringify({ id: completionId, object: \"chat.completion.chunk\", created: timestamp, model: \"clawrouter/image\", choices: [{ index: 0, delta: {}, finish_reason: \"stop\" }] })}\\n\\n`);\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n } else {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({\n id: completionId, object: \"chat.completion\", created: timestamp, model: \"clawrouter/image\",\n choices: [{ index: 0, message: { role: \"assistant\", content: responseText }, finish_reason: \"stop\" }],\n usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },\n }));\n }\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n console.error(`[ClawRouter] /imagegen error: ${errMsg}`);\n if (!res.headersSent) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({\n error: { message: `Image generation failed: ${errMsg}`, type: \"image_error\" },\n }));\n }\n }\n return;\n }\n\n // Force stream: false — BlockRun API doesn't support streaming yet\n // ClawRouter handles SSE heartbeat simulation for upstream compatibility\n if (parsed.stream === true) {\n parsed.stream = false;\n bodyModified = true;\n }\n\n // Normalize model name for comparison (trim whitespace, lowercase)\n const normalizedModel =\n typeof parsed.model === \"string\" ? parsed.model.trim().toLowerCase() : \"\";\n\n // Resolve model aliases (e.g., \"claude\" -> \"anthropic/claude-sonnet-4-6\")\n const resolvedModel = resolveModelAlias(normalizedModel);\n const wasAlias = resolvedModel !== normalizedModel;\n\n const isRoutingProfile = ROUTING_PROFILES.has(normalizedModel);\n\n // Extract routing profile type (free/eco/auto/premium)\n if (isRoutingProfile) {\n const profileName = normalizedModel.replace(\"blockrun/\", \"\");\n routingProfile = profileName as \"free\" | \"eco\" | \"auto\" | \"premium\";\n }\n\n // Debug: log received model name\n console.log(\n `[ClawRouter] Received model: \"${parsed.model}\" -> normalized: \"${normalizedModel}\"${wasAlias ? ` -> alias: \"${resolvedModel}\"` : \"\"}${routingProfile ? `, profile: ${routingProfile}` : \"\"}`,\n );\n\n // For explicit model requests, always canonicalize the model ID before upstream calls.\n // This ensures case/whitespace variants (e.g. \"DEEPSEEK/...\" or \" model \") route correctly.\n if (!isRoutingProfile) {\n if (parsed.model !== resolvedModel) {\n parsed.model = resolvedModel;\n bodyModified = true;\n }\n modelId = resolvedModel;\n }\n\n // Handle routing profiles (free/eco/auto/premium)\n if (isRoutingProfile) {\n // Free profile - direct shortcut to nvidia/gpt-oss-120b (no tier routing)\n if (routingProfile === \"free\") {\n const freeModel = \"nvidia/gpt-oss-120b\";\n console.log(`[ClawRouter] Free profile - using ${freeModel} directly`);\n parsed.model = freeModel;\n modelId = freeModel;\n bodyModified = true;\n\n // Log usage for free profile\n await logUsage({\n timestamp: new Date().toISOString(),\n model: freeModel,\n tier: \"SIMPLE\",\n cost: 0,\n baselineCost: 0,\n savings: 1.0, // 100% savings\n latencyMs: 0,\n });\n } else {\n // eco/auto/premium - use tier routing\n // Check for session persistence - use pinned model if available\n // Fall back to deriving a session ID from message content when OpenClaw\n // doesn't send an explicit x-session-id header (the default behaviour).\n effectiveSessionId =\n getSessionId(req.headers as Record<string, string | string[] | undefined>) ??\n deriveSessionId(parsedMessages);\n const existingSession = effectiveSessionId\n ? sessionStore.getSession(effectiveSessionId)\n : undefined;\n\n // Extract prompt from last user message (handles both string and Anthropic array content)\n const rawPrompt = lastUserMsg?.content;\n const prompt =\n typeof rawPrompt === \"string\"\n ? rawPrompt\n : Array.isArray(rawPrompt)\n ? (rawPrompt as Array<{ type: string; text?: string }>)\n .filter((b) => b.type === \"text\")\n .map((b) => b.text ?? \"\")\n .join(\" \")\n : \"\";\n const systemMsg = parsedMessages.find((m) => m.role === \"system\");\n const systemPrompt =\n typeof systemMsg?.content === \"string\" ? systemMsg.content : undefined;\n\n // Tool detection (must run regardless of session state for fallback chain filtering)\n // Agentic mode is triggered by keyword-based detection (agenticScore >= 0.6)\n const tools = parsed.tools as unknown[] | undefined;\n hasTools = Array.isArray(tools) && tools.length > 0;\n\n if (hasTools && tools) {\n console.log(`[ClawRouter] Tools detected (${tools.length}), agentic mode via keywords`);\n }\n\n // Vision detection: scan messages for image_url content parts\n hasVision = parsedMessages.some((m) => {\n if (Array.isArray(m.content)) {\n return (m.content as Array<{ type: string }>).some((p) => p.type === \"image_url\");\n }\n return false;\n });\n if (hasVision) {\n console.log(`[ClawRouter] Vision content detected, filtering to vision-capable models`);\n }\n\n // Always route based on current request content\n routingDecision = route(prompt, systemPrompt, maxTokens, {\n ...routerOpts,\n routingProfile: routingProfile ?? undefined,\n });\n\n if (existingSession) {\n // Never downgrade: only upgrade the session when the current request needs a higher\n // tier. This fixes the OpenClaw startup-message bias (the startup message always\n // scores low-complexity, which previously pinned all subsequent real queries to a\n // cheap model) while still preventing mid-task model switching on simple follow-ups.\n const tierRank: Record<string, number> = {\n SIMPLE: 0,\n MEDIUM: 1,\n COMPLEX: 2,\n REASONING: 3,\n };\n const existingRank = tierRank[existingSession.tier] ?? 0;\n const newRank = tierRank[routingDecision.tier] ?? 0;\n\n if (newRank > existingRank) {\n // Current request needs higher capability — upgrade the session\n console.log(\n `[ClawRouter] Session ${effectiveSessionId?.slice(0, 8)}... upgrading: ${existingSession.tier} → ${routingDecision.tier} (${routingDecision.model})`,\n );\n parsed.model = routingDecision.model;\n modelId = routingDecision.model;\n bodyModified = true;\n if (effectiveSessionId) {\n sessionStore.setSession(\n effectiveSessionId,\n routingDecision.model,\n routingDecision.tier,\n );\n }\n } else {\n // Keep existing higher-tier model (prevent downgrade mid-task)\n console.log(\n `[ClawRouter] Session ${effectiveSessionId?.slice(0, 8)}... keeping pinned model: ${existingSession.model} (${existingSession.tier} >= ${routingDecision.tier})`,\n );\n parsed.model = existingSession.model;\n modelId = existingSession.model;\n bodyModified = true;\n sessionStore.touchSession(effectiveSessionId!);\n // Reflect the actual model used in the routing decision for logging/fallback\n routingDecision = {\n ...routingDecision,\n model: existingSession.model,\n tier: existingSession.tier as Tier,\n };\n }\n\n // --- Three-strike escalation: detect repetitive request patterns ---\n const lastAssistantMsg = [...parsedMessages]\n .reverse()\n .find((m) => m.role === \"assistant\");\n const toolCallNames = Array.isArray((lastAssistantMsg as any)?.tool_calls)\n ? (lastAssistantMsg as any).tool_calls\n .map((tc: any) => tc.function?.name)\n .filter(Boolean)\n : undefined;\n const contentHash = hashRequestContent(prompt, toolCallNames);\n const shouldEscalate = sessionStore.recordRequestHash(\n effectiveSessionId!,\n contentHash,\n );\n\n if (shouldEscalate) {\n const activeTierConfigs = (() => {\n if (\n routingDecision.reasoning?.includes(\"agentic\") &&\n routerOpts.config.agenticTiers\n ) {\n return routerOpts.config.agenticTiers;\n }\n if (routingProfile === \"eco\" && routerOpts.config.ecoTiers) {\n return routerOpts.config.ecoTiers;\n }\n if (routingProfile === \"premium\" && routerOpts.config.premiumTiers) {\n return routerOpts.config.premiumTiers;\n }\n return routerOpts.config.tiers;\n })();\n\n const escalation = sessionStore.escalateSession(\n effectiveSessionId!,\n activeTierConfigs,\n );\n if (escalation) {\n console.log(\n `[ClawRouter] ⚡ 3-strike escalation: ${existingSession.model} → ${escalation.model} (${existingSession.tier} → ${escalation.tier})`,\n );\n parsed.model = escalation.model;\n modelId = escalation.model;\n routingDecision = {\n ...routingDecision,\n model: escalation.model,\n tier: escalation.tier as Tier,\n };\n }\n }\n } else {\n // No session — pin this routing decision for future requests\n parsed.model = routingDecision.model;\n modelId = routingDecision.model;\n bodyModified = true;\n if (effectiveSessionId) {\n sessionStore.setSession(\n effectiveSessionId,\n routingDecision.model,\n routingDecision.tier,\n );\n console.log(\n `[ClawRouter] Session ${effectiveSessionId.slice(0, 8)}... pinned to model: ${routingDecision.model}`,\n );\n }\n }\n\n options.onRouted?.(routingDecision);\n }\n }\n\n // Rebuild body if modified\n if (bodyModified) {\n body = Buffer.from(JSON.stringify(parsed));\n }\n } catch (err) {\n // Log routing errors so they're not silently swallowed\n const errorMsg = err instanceof Error ? err.message : String(err);\n console.error(`[ClawRouter] Routing error: ${errorMsg}`);\n console.error(`[ClawRouter] Need help? Run: npx @blockrun/clawrouter doctor`);\n options.onError?.(new Error(`Routing failed: ${errorMsg}`));\n }\n }\n\n // --- Auto-compression ---\n // Compress large requests to reduce network usage and improve performance\n const autoCompress = options.autoCompressRequests ?? true;\n const compressionThreshold = options.compressionThresholdKB ?? 180;\n const requestSizeKB = Math.ceil(body.length / 1024);\n\n if (autoCompress && requestSizeKB > compressionThreshold) {\n try {\n console.log(\n `[ClawRouter] Request size ${requestSizeKB}KB exceeds threshold ${compressionThreshold}KB, applying compression...`,\n );\n\n // Parse messages for compression\n const parsed = JSON.parse(body.toString()) as {\n messages?: NormalizedMessage[];\n [key: string]: unknown;\n };\n\n if (parsed.messages && parsed.messages.length > 0 && shouldCompress(parsed.messages)) {\n // Apply compression with conservative settings\n const compressionResult = await compressContext(parsed.messages, {\n enabled: true,\n preserveRaw: false, // Don't need originals in proxy\n layers: {\n deduplication: true, // Safe: removes duplicate messages\n whitespace: true, // Safe: normalizes whitespace\n dictionary: false, // Disabled: requires model to understand codebook\n paths: false, // Disabled: requires model to understand path codes\n jsonCompact: true, // Safe: just removes JSON whitespace\n observation: false, // Disabled: may lose important context\n dynamicCodebook: false, // Disabled: requires model to understand codes\n },\n dictionary: {\n maxEntries: 50,\n minPhraseLength: 15,\n includeCodebookHeader: false,\n },\n });\n\n const compressedSizeKB = Math.ceil(compressionResult.compressedChars / 1024);\n const savings = (((requestSizeKB - compressedSizeKB) / requestSizeKB) * 100).toFixed(1);\n\n console.log(\n `[ClawRouter] Compressed ${requestSizeKB}KB → ${compressedSizeKB}KB (${savings}% reduction)`,\n );\n\n // Update request body with compressed messages\n parsed.messages = compressionResult.messages;\n body = Buffer.from(JSON.stringify(parsed));\n }\n } catch (err) {\n // Compression failed - continue with original request\n console.warn(\n `[ClawRouter] Compression failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n // --- Response cache check (long-term, 10min TTL) ---\n const cacheKey = ResponseCache.generateKey(body);\n const reqHeaders: Record<string, string> = {};\n for (const [key, value] of Object.entries(req.headers)) {\n if (typeof value === \"string\") reqHeaders[key] = value;\n }\n if (responseCache.shouldCache(body, reqHeaders)) {\n const cachedResponse = responseCache.get(cacheKey);\n if (cachedResponse) {\n console.log(`[ClawRouter] Cache HIT for ${cachedResponse.model} (saved API call)`);\n res.writeHead(cachedResponse.status, cachedResponse.headers);\n res.end(cachedResponse.body);\n return;\n }\n }\n\n // --- Dedup check (short-term, 30s TTL for retries) ---\n const dedupKey = RequestDeduplicator.hash(body);\n\n // Check dedup cache (catches retries within 30s)\n const cached = deduplicator.getCached(dedupKey);\n if (cached) {\n res.writeHead(cached.status, cached.headers);\n res.end(cached.body);\n return;\n }\n\n // Check in-flight — wait for the original request to complete\n const inflight = deduplicator.getInflight(dedupKey);\n if (inflight) {\n const result = await inflight;\n res.writeHead(result.status, result.headers);\n res.end(result.body);\n return;\n }\n\n // Register this request as in-flight\n deduplicator.markInflight(dedupKey);\n\n // --- Pre-request balance check ---\n // Estimate cost and check if wallet has sufficient balance\n // Skip if skipBalanceCheck is set (for testing) or if using free model\n let estimatedCostMicros: bigint | undefined;\n const isFreeModel = modelId === FREE_MODEL;\n\n if (modelId && !options.skipBalanceCheck && !isFreeModel) {\n const estimated = estimateAmount(modelId, body.length, maxTokens);\n if (estimated) {\n estimatedCostMicros = BigInt(estimated);\n\n // Apply extra buffer for balance check to prevent x402 failures after streaming starts.\n // This is aggressive to avoid triggering OpenClaw's 5-24 hour billing cooldown.\n const bufferedCostMicros =\n (estimatedCostMicros * BigInt(Math.ceil(BALANCE_CHECK_BUFFER * 100))) / 100n;\n\n // Check balance before proceeding (using buffered amount)\n const sufficiency = await balanceMonitor.checkSufficient(bufferedCostMicros);\n\n if (sufficiency.info.isEmpty || !sufficiency.sufficient) {\n // Wallet is empty or insufficient — ALWAYS fallback to free model\n // This ensures new users with empty wallets can still use ClawRouter\n const originalModel = modelId;\n console.log(\n `[ClawRouter] Wallet ${sufficiency.info.isEmpty ? \"empty\" : \"insufficient\"} ($${sufficiency.info.balanceUSD}), falling back to free model: ${FREE_MODEL} (requested: ${originalModel})`,\n );\n modelId = FREE_MODEL;\n // Update the body with new model\n const parsed = JSON.parse(body.toString()) as Record<string, unknown>;\n parsed.model = FREE_MODEL;\n body = Buffer.from(JSON.stringify(parsed));\n\n // Notify about the fallback\n options.onLowBalance?.({\n balanceUSD: sufficiency.info.balanceUSD,\n walletAddress: sufficiency.info.walletAddress,\n });\n } else if (sufficiency.info.isLow) {\n // Balance is low but sufficient — warn and proceed\n options.onLowBalance?.({\n balanceUSD: sufficiency.info.balanceUSD,\n walletAddress: sufficiency.info.walletAddress,\n });\n }\n }\n }\n\n // --- Streaming: early header flush + heartbeat ---\n let heartbeatInterval: ReturnType<typeof setInterval> | undefined;\n let headersSentEarly = false;\n\n if (isStreaming) {\n // Send 200 + SSE headers immediately, before x402 flow\n res.writeHead(200, {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-cache\",\n connection: \"keep-alive\",\n \"x-context-used-kb\": String(originalContextSizeKB),\n \"x-context-limit-kb\": String(CONTEXT_LIMIT_KB),\n });\n headersSentEarly = true;\n\n // First heartbeat immediately\n safeWrite(res, \": heartbeat\\n\\n\");\n\n // Continue heartbeats every 2s while waiting for upstream\n heartbeatInterval = setInterval(() => {\n if (canWrite(res)) {\n safeWrite(res, \": heartbeat\\n\\n\");\n } else {\n // Socket closed, stop heartbeat\n clearInterval(heartbeatInterval);\n heartbeatInterval = undefined;\n }\n }, HEARTBEAT_INTERVAL_MS);\n }\n\n // Forward headers, stripping host, connection, and content-length\n const headers: Record<string, string> = {};\n for (const [key, value] of Object.entries(req.headers)) {\n if (\n key === \"host\" ||\n key === \"connection\" ||\n key === \"transfer-encoding\" ||\n key === \"content-length\"\n )\n continue;\n if (typeof value === \"string\") {\n headers[key] = value;\n }\n }\n if (!headers[\"content-type\"]) {\n headers[\"content-type\"] = \"application/json\";\n }\n headers[\"user-agent\"] = USER_AGENT;\n\n // --- Client disconnect cleanup ---\n let completed = false;\n res.on(\"close\", () => {\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n heartbeatInterval = undefined;\n }\n // Remove from in-flight if client disconnected before completion\n if (!completed) {\n deduplicator.removeInflight(dedupKey);\n }\n });\n\n // --- Request timeout ---\n const timeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n // --- Build fallback chain ---\n // If we have a routing decision, get the full fallback chain for the tier\n // Otherwise, just use the current model (no fallback for explicit model requests)\n let modelsToTry: string[];\n if (routingDecision) {\n // Estimate total context: input tokens (~4 chars per token) + max output tokens\n const estimatedInputTokens = Math.ceil(body.length / 4);\n const estimatedTotalTokens = estimatedInputTokens + maxTokens;\n\n // Get tier configs matching the profile that was used for routing\n // Must stay in sync with what route() selected in router/index.ts\n const tierConfigs = (() => {\n if (routingDecision.reasoning?.includes(\"agentic\") && routerOpts.config.agenticTiers) {\n return routerOpts.config.agenticTiers;\n }\n if (routingProfile === \"eco\" && routerOpts.config.ecoTiers) {\n return routerOpts.config.ecoTiers;\n }\n if (routingProfile === \"premium\" && routerOpts.config.premiumTiers) {\n return routerOpts.config.premiumTiers;\n }\n return routerOpts.config.tiers;\n })();\n\n // Get full chain first, then filter by context\n const fullChain = getFallbackChain(routingDecision.tier, tierConfigs);\n const contextFiltered = getFallbackChainFiltered(\n routingDecision.tier,\n tierConfigs,\n estimatedTotalTokens,\n getModelContextWindow,\n );\n\n // Log if models were filtered out due to context limits\n const contextExcluded = fullChain.filter((m) => !contextFiltered.includes(m));\n if (contextExcluded.length > 0) {\n console.log(\n `[ClawRouter] Context filter (~${estimatedTotalTokens} tokens): excluded ${contextExcluded.join(\", \")}`,\n );\n }\n\n // Filter to models that support tool calling when request has tools.\n // Prevents models like grok-code-fast-1 from outputting tool invocations\n // as plain text JSON (the \"talking to itself\" bug).\n const toolFiltered = filterByToolCalling(contextFiltered, hasTools, supportsToolCalling);\n const toolExcluded = contextFiltered.filter((m) => !toolFiltered.includes(m));\n if (toolExcluded.length > 0) {\n console.log(\n `[ClawRouter] Tool-calling filter: excluded ${toolExcluded.join(\", \")} (no structured function call support)`,\n );\n }\n\n // Filter to models that support vision when request has image_url content\n const visionFiltered = filterByVision(toolFiltered, hasVision, supportsVision);\n const visionExcluded = toolFiltered.filter((m) => !visionFiltered.includes(m));\n if (visionExcluded.length > 0) {\n console.log(\n `[ClawRouter] Vision filter: excluded ${visionExcluded.join(\", \")} (no vision support)`,\n );\n }\n\n // Limit to MAX_FALLBACK_ATTEMPTS to prevent infinite loops\n modelsToTry = visionFiltered.slice(0, MAX_FALLBACK_ATTEMPTS);\n\n // Deprioritize rate-limited models (put them at the end)\n modelsToTry = prioritizeNonRateLimited(modelsToTry);\n } else {\n // For explicit model requests, use the requested model\n modelsToTry = modelId ? [modelId] : [];\n }\n\n // Always ensure free model is the last-resort fallback.\n // If all paid models fail (insufficient funds, rate limits, etc.),\n // the user still gets a response instead of an error.\n if (!modelsToTry.includes(FREE_MODEL)) {\n modelsToTry.push(FREE_MODEL);\n }\n\n // --- Fallback loop: try each model until success ---\n let upstream: Response | undefined;\n let lastError: { body: string; status: number } | undefined;\n let actualModelUsed = modelId;\n\n for (let i = 0; i < modelsToTry.length; i++) {\n const tryModel = modelsToTry[i];\n const isLastAttempt = i === modelsToTry.length - 1;\n\n console.log(`[ClawRouter] Trying model ${i + 1}/${modelsToTry.length}: ${tryModel}`);\n\n const result = await tryModelRequest(\n upstreamUrl,\n req.method ?? \"POST\",\n headers,\n body,\n tryModel,\n maxTokens,\n payFetch,\n balanceMonitor,\n controller.signal,\n );\n\n if (result.success && result.response) {\n upstream = result.response;\n actualModelUsed = tryModel;\n console.log(`[ClawRouter] Success with model: ${tryModel}`);\n break;\n }\n\n // Request failed\n lastError = {\n body: result.errorBody || \"Unknown error\",\n status: result.errorStatus || 500,\n };\n\n // If it's a provider error and not the last attempt, try next model\n if (result.isProviderError && !isLastAttempt) {\n // Track 429 rate limits to deprioritize this model for future requests\n if (result.errorStatus === 429) {\n markRateLimited(tryModel);\n }\n\n // Payment error (insufficient funds) — skip remaining paid models,\n // jump straight to free model. No point trying other paid models\n // with the same empty wallet.\n const isPaymentErr = /payment.*verification.*failed|insufficient.*funds/i.test(\n result.errorBody || \"\",\n );\n if (isPaymentErr && tryModel !== FREE_MODEL) {\n const freeIdx = modelsToTry.indexOf(FREE_MODEL);\n if (freeIdx > i + 1) {\n console.log(`[ClawRouter] Payment error — skipping to free model: ${FREE_MODEL}`);\n i = freeIdx - 1; // loop will increment to freeIdx\n continue;\n }\n }\n\n console.log(\n `[ClawRouter] Provider error from ${tryModel}, trying fallback: ${result.errorBody?.slice(0, 100)}`,\n );\n continue;\n }\n\n // Not a provider error or last attempt — stop trying\n if (!result.isProviderError) {\n console.log(\n `[ClawRouter] Non-provider error from ${tryModel}, not retrying: ${result.errorBody?.slice(0, 100)}`,\n );\n }\n break;\n }\n\n // Clear timeout — request attempts completed\n clearTimeout(timeoutId);\n\n // Clear heartbeat — real data is about to flow\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n heartbeatInterval = undefined;\n }\n\n // --- Emit routing debug info (opt-in via x-clawrouter-debug: true header) ---\n // For streaming: SSE comment (invisible to most clients, visible in raw stream)\n // For non-streaming: response headers added later\n if (debugMode && headersSentEarly && routingDecision) {\n const debugComment = `: x-clawrouter-debug profile=${routingProfile ?? \"auto\"} tier=${routingDecision.tier} model=${actualModelUsed} agentic=${routingDecision.agenticScore?.toFixed(2) ?? \"n/a\"} confidence=${routingDecision.confidence.toFixed(2)} reasoning=${routingDecision.reasoning}\\n\\n`;\n safeWrite(res, debugComment);\n }\n\n // Update routing decision with actual model used (for logging)\n // IMPORTANT: Recalculate cost for the actual model, not the original primary\n if (routingDecision && actualModelUsed !== routingDecision.model) {\n const estimatedInputTokens = Math.ceil(body.length / 4);\n const newCosts = calculateModelCost(\n actualModelUsed,\n routerOpts.modelPricing,\n estimatedInputTokens,\n maxTokens,\n routingProfile ?? undefined,\n );\n routingDecision = {\n ...routingDecision,\n model: actualModelUsed,\n reasoning: `${routingDecision.reasoning} | fallback to ${actualModelUsed}`,\n costEstimate: newCosts.costEstimate,\n baselineCost: newCosts.baselineCost,\n savings: newCosts.savings,\n };\n options.onRouted?.(routingDecision);\n\n // Update session pin to the actual model used — ensures the next request in\n // this conversation starts from the fallback model rather than retrying the\n // primary and falling back again (prevents the \"model keeps jumping\" issue).\n if (effectiveSessionId) {\n sessionStore.setSession(effectiveSessionId, actualModelUsed, routingDecision.tier);\n console.log(\n `[ClawRouter] Session ${effectiveSessionId.slice(0, 8)}... updated pin to fallback: ${actualModelUsed}`,\n );\n }\n }\n\n // --- Handle case where all models failed ---\n if (!upstream) {\n const rawErrBody = lastError?.body || \"All models in fallback chain failed\";\n const errStatus = lastError?.status || 502;\n\n // Transform payment errors into user-friendly messages\n const transformedErr = transformPaymentError(rawErrBody);\n\n if (headersSentEarly) {\n // Streaming: send error as SSE event\n // If transformed error is already JSON, parse and use it; otherwise wrap in standard format\n let errPayload: string;\n try {\n const parsed = JSON.parse(transformedErr);\n errPayload = JSON.stringify(parsed);\n } catch {\n errPayload = JSON.stringify({\n error: { message: rawErrBody, type: \"provider_error\", status: errStatus },\n });\n }\n const errEvent = `data: ${errPayload}\\n\\n`;\n safeWrite(res, errEvent);\n safeWrite(res, \"data: [DONE]\\n\\n\");\n res.end();\n\n const errBuf = Buffer.from(errEvent + \"data: [DONE]\\n\\n\");\n deduplicator.complete(dedupKey, {\n status: 200,\n headers: { \"content-type\": \"text/event-stream\" },\n body: errBuf,\n completedAt: Date.now(),\n });\n } else {\n // Non-streaming: send transformed error response with context headers\n res.writeHead(errStatus, {\n \"Content-Type\": \"application/json\",\n \"x-context-used-kb\": String(originalContextSizeKB),\n \"x-context-limit-kb\": String(CONTEXT_LIMIT_KB),\n });\n res.end(transformedErr);\n\n deduplicator.complete(dedupKey, {\n status: errStatus,\n headers: { \"content-type\": \"application/json\" },\n body: Buffer.from(transformedErr),\n completedAt: Date.now(),\n });\n }\n return;\n }\n\n // --- Stream response and collect for dedup cache ---\n const responseChunks: Buffer[] = [];\n\n if (headersSentEarly) {\n // Streaming: headers already sent. Response should be 200 at this point\n // (non-200 responses are handled in the fallback loop above)\n\n // Convert non-streaming JSON response to SSE streaming format for client\n // (BlockRun API returns JSON since we forced stream:false)\n // OpenClaw expects: object=\"chat.completion.chunk\" with choices[].delta (not message)\n // We emit proper incremental deltas to match OpenAI's streaming format exactly\n if (upstream.body) {\n const reader = upstream.body.getReader();\n const chunks: Uint8Array[] = [];\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n }\n } finally {\n reader.releaseLock();\n }\n\n // Combine chunks and transform to streaming format\n const jsonBody = Buffer.concat(chunks);\n const jsonStr = jsonBody.toString();\n try {\n const rsp = JSON.parse(jsonStr) as {\n id?: string;\n object?: string;\n created?: number;\n model?: string;\n choices?: Array<{\n index?: number;\n message?: {\n role?: string;\n content?: string;\n tool_calls?: Array<{\n id: string;\n type: string;\n function: { name: string; arguments: string };\n }>;\n };\n delta?: {\n role?: string;\n content?: string;\n tool_calls?: Array<{\n id: string;\n type: string;\n function: { name: string; arguments: string };\n }>;\n };\n finish_reason?: string | null;\n }>;\n usage?: unknown;\n };\n\n // Build base chunk structure (reused for all chunks)\n // Match OpenAI's exact format including system_fingerprint\n const baseChunk = {\n id: rsp.id ?? `chatcmpl-${Date.now()}`,\n object: \"chat.completion.chunk\",\n created: rsp.created ?? Math.floor(Date.now() / 1000),\n model: rsp.model ?? \"unknown\",\n system_fingerprint: null,\n };\n\n // Process each choice (usually just one)\n if (rsp.choices && Array.isArray(rsp.choices)) {\n for (const choice of rsp.choices) {\n // Strip thinking tokens (Kimi <|...|> and standard <think> tags)\n const rawContent = choice.message?.content ?? choice.delta?.content ?? \"\";\n const content = stripThinkingTokens(rawContent);\n const role = choice.message?.role ?? choice.delta?.role ?? \"assistant\";\n const index = choice.index ?? 0;\n\n // Accumulate content for session journal\n if (content) {\n accumulatedContent += content;\n }\n\n // Chunk 1: role only (mimics OpenAI's first chunk)\n const roleChunk = {\n ...baseChunk,\n choices: [{ index, delta: { role }, logprobs: null, finish_reason: null }],\n };\n const roleData = `data: ${JSON.stringify(roleChunk)}\\n\\n`;\n safeWrite(res, roleData);\n responseChunks.push(Buffer.from(roleData));\n\n // Chunk 2: content (single chunk with full content)\n if (content) {\n const contentChunk = {\n ...baseChunk,\n choices: [{ index, delta: { content }, logprobs: null, finish_reason: null }],\n };\n const contentData = `data: ${JSON.stringify(contentChunk)}\\n\\n`;\n safeWrite(res, contentData);\n responseChunks.push(Buffer.from(contentData));\n }\n\n // Chunk 2b: tool_calls (forward tool calls from upstream)\n const toolCalls = choice.message?.tool_calls ?? choice.delta?.tool_calls;\n if (toolCalls && toolCalls.length > 0) {\n const toolCallChunk = {\n ...baseChunk,\n choices: [\n {\n index,\n delta: { tool_calls: toolCalls },\n logprobs: null,\n finish_reason: null,\n },\n ],\n };\n const toolCallData = `data: ${JSON.stringify(toolCallChunk)}\\n\\n`;\n safeWrite(res, toolCallData);\n responseChunks.push(Buffer.from(toolCallData));\n }\n\n // Chunk 3: finish_reason (signals completion)\n const finishChunk = {\n ...baseChunk,\n choices: [\n {\n index,\n delta: {},\n logprobs: null,\n finish_reason:\n toolCalls && toolCalls.length > 0\n ? \"tool_calls\"\n : (choice.finish_reason ?? \"stop\"),\n },\n ],\n };\n const finishData = `data: ${JSON.stringify(finishChunk)}\\n\\n`;\n safeWrite(res, finishData);\n responseChunks.push(Buffer.from(finishData));\n }\n }\n } catch {\n // If parsing fails, send raw response as single chunk\n const sseData = `data: ${jsonStr}\\n\\n`;\n safeWrite(res, sseData);\n responseChunks.push(Buffer.from(sseData));\n }\n }\n\n // Send SSE terminator\n safeWrite(res, \"data: [DONE]\\n\\n\");\n responseChunks.push(Buffer.from(\"data: [DONE]\\n\\n\"));\n res.end();\n\n // Cache for dedup\n deduplicator.complete(dedupKey, {\n status: 200,\n headers: { \"content-type\": \"text/event-stream\" },\n body: Buffer.concat(responseChunks),\n completedAt: Date.now(),\n });\n } else {\n // Non-streaming: forward status and headers from upstream\n const responseHeaders: Record<string, string> = {};\n upstream.headers.forEach((value, key) => {\n // Skip hop-by-hop headers and content-encoding (fetch already decompresses)\n if (key === \"transfer-encoding\" || key === \"connection\" || key === \"content-encoding\")\n return;\n responseHeaders[key] = value;\n });\n\n // Add context usage headers\n responseHeaders[\"x-context-used-kb\"] = String(originalContextSizeKB);\n responseHeaders[\"x-context-limit-kb\"] = String(CONTEXT_LIMIT_KB);\n\n // Add routing debug headers (opt-in via x-clawrouter-debug: true header)\n if (debugMode && routingDecision) {\n responseHeaders[\"x-clawrouter-profile\"] = routingProfile ?? \"auto\";\n responseHeaders[\"x-clawrouter-tier\"] = routingDecision.tier;\n responseHeaders[\"x-clawrouter-model\"] = actualModelUsed;\n responseHeaders[\"x-clawrouter-confidence\"] = routingDecision.confidence.toFixed(2);\n responseHeaders[\"x-clawrouter-reasoning\"] = routingDecision.reasoning;\n if (routingDecision.agenticScore !== undefined) {\n responseHeaders[\"x-clawrouter-agentic-score\"] = routingDecision.agenticScore.toFixed(2);\n }\n }\n\n res.writeHead(upstream.status, responseHeaders);\n\n if (upstream.body) {\n const reader = upstream.body.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n const chunk = Buffer.from(value);\n safeWrite(res, chunk);\n responseChunks.push(chunk);\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n res.end();\n\n const responseBody = Buffer.concat(responseChunks);\n\n // Cache for dedup (short-term, 30s)\n deduplicator.complete(dedupKey, {\n status: upstream.status,\n headers: responseHeaders,\n body: responseBody,\n completedAt: Date.now(),\n });\n\n // Cache for response cache (long-term, 10min) - only successful non-streaming\n if (upstream.status === 200 && responseCache.shouldCache(body)) {\n responseCache.set(cacheKey, {\n body: responseBody,\n status: upstream.status,\n headers: responseHeaders,\n model: actualModelUsed,\n });\n console.log(\n `[ClawRouter] Cached response for ${actualModelUsed} (${responseBody.length} bytes)`,\n );\n }\n\n // Extract content from non-streaming response for session journal\n try {\n const rspJson = JSON.parse(responseBody.toString()) as {\n choices?: Array<{ message?: { content?: string } }>;\n };\n if (rspJson.choices?.[0]?.message?.content) {\n accumulatedContent = rspJson.choices[0].message.content;\n }\n } catch {\n // Ignore parse errors - journal just won't have content for this response\n }\n }\n\n // --- Session Journal: Extract and record events from response ---\n if (sessionId && accumulatedContent) {\n const events = sessionJournal.extractEvents(accumulatedContent);\n if (events.length > 0) {\n sessionJournal.record(sessionId, events, actualModelUsed);\n console.log(\n `[ClawRouter] Recorded ${events.length} events to session journal for session ${sessionId.slice(0, 8)}...`,\n );\n }\n }\n\n // --- Optimistic balance deduction after successful response ---\n if (estimatedCostMicros !== undefined) {\n balanceMonitor.deductEstimated(estimatedCostMicros);\n }\n\n // Mark request as completed (for client disconnect cleanup)\n completed = true;\n } catch (err) {\n // Clear timeout on error\n clearTimeout(timeoutId);\n\n // Clear heartbeat on error\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n heartbeatInterval = undefined;\n }\n\n // Remove in-flight entry so retries aren't blocked\n deduplicator.removeInflight(dedupKey);\n\n // Invalidate balance cache on payment failure (might be out of date)\n balanceMonitor.invalidate();\n\n // Convert abort error to more descriptive timeout error\n if (err instanceof Error && err.name === \"AbortError\") {\n throw new Error(`Request timed out after ${timeoutMs}ms`);\n }\n\n throw err;\n }\n\n // --- Usage logging (fire-and-forget) ---\n // Note: Recalculate cost using full body length (not just system+user message)\n // and apply 20% buffer to match actual x402 payment (see estimateAmount())\n // Log ALL requests: both auto-routed (routingDecision set) and direct model picks\n const logModel = routingDecision?.model ?? modelId;\n if (logModel) {\n // Use full body length for accurate cost (matches x402 payment estimation)\n const estimatedInputTokens = Math.ceil(body.length / 4);\n const accurateCosts = calculateModelCost(\n logModel,\n routerOpts.modelPricing,\n estimatedInputTokens,\n maxTokens,\n routingProfile ?? undefined,\n );\n // Apply 20% buffer to match x402 pre-auth\n const costWithBuffer = accurateCosts.costEstimate * 1.2;\n const baselineWithBuffer = accurateCosts.baselineCost * 1.2;\n const entry: UsageEntry = {\n timestamp: new Date().toISOString(),\n model: logModel,\n tier: routingDecision?.tier ?? \"DIRECT\",\n cost: costWithBuffer,\n baselineCost: baselineWithBuffer,\n savings: accurateCosts.savings,\n latencyMs: Date.now() - startTime,\n };\n logUsage(entry).catch(() => {});\n }\n}\n","/**\n * x402 Payment Implementation\n *\n * Based on BlockRun's proven implementation.\n * Handles 402 Payment Required responses with EIP-712 signed USDC transfers.\n *\n * Optimizations (v0.3.0):\n * - Payment cache: after first 402, caches {payTo, asset, network} per endpoint.\n * On subsequent requests, pre-signs payment and sends with first request,\n * skipping the 402 round trip (~200ms savings).\n * - Falls back to normal 402 flow if pre-signed payment is rejected.\n */\n\nimport { signTypedData, privateKeyToAccount } from \"viem/accounts\";\nimport { PaymentCache } from \"./payment-cache.js\";\n\nconst BASE_CHAIN_ID = 8453;\nconst BASE_SEPOLIA_CHAIN_ID = 84532;\nconst DEFAULT_TOKEN_NAME = \"USD Coin\";\nconst DEFAULT_TOKEN_VERSION = \"2\";\nconst DEFAULT_NETWORK = \"eip155:8453\";\nconst DEFAULT_MAX_TIMEOUT_SECONDS = 300;\n\nconst TRANSFER_TYPES = {\n TransferWithAuthorization: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n ],\n} as const;\n\nfunction createNonce(): `0x${string}` {\n const bytes = new Uint8Array(32);\n crypto.getRandomValues(bytes);\n return `0x${Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\")}` as `0x${string}`;\n}\n\ninterface PaymentOption {\n scheme: string;\n network: string;\n amount?: string;\n maxAmountRequired?: string;\n asset: string;\n payTo: string;\n maxTimeoutSeconds?: number;\n extra?: { name?: string; version?: string };\n}\n\ninterface PaymentRequired {\n accepts: PaymentOption[];\n resource?: { url?: string; description?: string };\n}\n\nfunction decodeBase64Json<T>(value: string): T {\n const normalized = value.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padding = (4 - (normalized.length % 4)) % 4;\n const padded = normalized + \"=\".repeat(padding);\n const decoded = Buffer.from(padded, \"base64\").toString(\"utf8\");\n return JSON.parse(decoded) as T;\n}\n\nfunction encodeBase64Json(value: unknown): string {\n return Buffer.from(JSON.stringify(value), \"utf8\").toString(\"base64\");\n}\n\nfunction parsePaymentRequired(headerValue: string): PaymentRequired {\n return decodeBase64Json<PaymentRequired>(headerValue);\n}\n\nfunction normalizeNetwork(network: string | undefined): string {\n if (!network || network.trim().length === 0) {\n return DEFAULT_NETWORK;\n }\n return network.trim().toLowerCase();\n}\n\nfunction resolveChainId(network: string): number {\n const eip155Match = network.match(/^eip155:(\\d+)$/i);\n if (eip155Match) {\n const parsed = Number.parseInt(eip155Match[1], 10);\n if (Number.isFinite(parsed) && parsed > 0) {\n return parsed;\n }\n }\n\n if (network === \"base\") return BASE_CHAIN_ID;\n if (network === \"base-sepolia\") return BASE_SEPOLIA_CHAIN_ID;\n return BASE_CHAIN_ID;\n}\n\nfunction parseHexAddress(value: string | undefined): `0x${string}` | undefined {\n if (!value) return undefined;\n\n const direct = value.match(/^0x[a-fA-F0-9]{40}$/);\n if (direct) {\n return direct[0] as `0x${string}`;\n }\n\n // Some providers send CAIP-style assets (e.g. \".../erc20:0x...\").\n const caipSuffix = value.match(/0x[a-fA-F0-9]{40}$/);\n if (caipSuffix) {\n return caipSuffix[0] as `0x${string}`;\n }\n\n return undefined;\n}\n\nfunction requireHexAddress(value: string | undefined, field: string): `0x${string}` {\n const parsed = parseHexAddress(value);\n if (!parsed) {\n throw new Error(`Invalid ${field} in payment requirements: ${String(value)}`);\n }\n return parsed;\n}\n\nfunction setPaymentHeaders(headers: Headers, payload: string): void {\n // Support both modern and legacy header names for compatibility.\n headers.set(\"payment-signature\", payload);\n headers.set(\"x-payment\", payload);\n}\n\nasync function createPaymentPayload(\n privateKey: `0x${string}`,\n fromAddress: string,\n option: PaymentOption,\n amount: string,\n requestUrl: string,\n resource: PaymentRequired[\"resource\"],\n): Promise<string> {\n const network = normalizeNetwork(option.network);\n const chainId = resolveChainId(network);\n const recipient = requireHexAddress(option.payTo, \"payTo\");\n const verifyingContract = requireHexAddress(option.asset, \"asset\");\n\n const maxTimeoutSeconds =\n typeof option.maxTimeoutSeconds === \"number\" && option.maxTimeoutSeconds > 0\n ? Math.floor(option.maxTimeoutSeconds)\n : DEFAULT_MAX_TIMEOUT_SECONDS;\n\n const now = Math.floor(Date.now() / 1000);\n const validAfter = now - 600;\n const validBefore = now + maxTimeoutSeconds;\n const nonce = createNonce();\n\n const signature = await signTypedData({\n privateKey,\n domain: {\n name: option.extra?.name || DEFAULT_TOKEN_NAME,\n version: option.extra?.version || DEFAULT_TOKEN_VERSION,\n chainId,\n verifyingContract,\n },\n types: TRANSFER_TYPES,\n primaryType: \"TransferWithAuthorization\",\n message: {\n from: fromAddress as `0x${string}`,\n to: recipient,\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: resource?.url || requestUrl,\n description: resource?.description || \"BlockRun AI API call\",\n mimeType: \"application/json\",\n },\n accepted: {\n scheme: option.scheme,\n network,\n amount,\n asset: option.asset,\n payTo: option.payTo,\n maxTimeoutSeconds: option.maxTimeoutSeconds,\n extra: option.extra,\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 encodeBase64Json(paymentData);\n}\n\n/** Pre-auth parameters for skipping the 402 round trip. */\nexport type PreAuthParams = {\n estimatedAmount: string; // USDC amount in smallest unit (6 decimals)\n};\n\n/** Result from createPaymentFetch — includes the fetch wrapper and payment cache. */\nexport type PaymentFetchResult = {\n fetch: (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ) => Promise<Response>;\n cache: PaymentCache;\n};\n\n/**\n * Create a fetch wrapper that handles x402 payment automatically.\n *\n * Supports pre-auth: if cached payment params + estimated amount are available,\n * pre-signs and attaches payment to the first request, skipping the 402 round trip.\n * Falls back to normal 402 flow if pre-signed payment is rejected.\n */\nexport function createPaymentFetch(privateKey: `0x${string}`): PaymentFetchResult {\n const account = privateKeyToAccount(privateKey);\n const walletAddress = account.address;\n const paymentCache = new PaymentCache();\n\n const payFetch = async (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ): Promise<Response> => {\n const url = typeof input === \"string\" ? input : input instanceof URL ? input.href : input.url;\n const endpointPath = new URL(url).pathname;\n\n // --- Pre-auth path: skip 402 round trip ---\n const cached = paymentCache.get(endpointPath);\n if (cached && preAuth?.estimatedAmount) {\n const paymentPayload = await createPaymentPayload(\n privateKey,\n walletAddress,\n {\n scheme: cached.scheme,\n network: cached.network,\n asset: cached.asset,\n payTo: cached.payTo,\n maxTimeoutSeconds: cached.maxTimeoutSeconds,\n extra: cached.extra,\n },\n preAuth.estimatedAmount,\n url,\n {\n url: cached.resourceUrl,\n description: cached.resourceDescription,\n },\n );\n\n const preAuthHeaders = new Headers(init?.headers);\n setPaymentHeaders(preAuthHeaders, paymentPayload);\n\n const response = await fetch(input, { ...init, headers: preAuthHeaders });\n\n // Pre-auth accepted — skip 402 entirely\n if (response.status !== 402) {\n return response;\n }\n\n // Pre-auth rejected (wrong amount, payTo changed, etc.)\n // Try to use this 402's payment header for a proper retry\n const paymentHeader = response.headers.get(\"x-payment-required\");\n if (paymentHeader) {\n return handle402(input, init, url, endpointPath, paymentHeader);\n }\n\n // No payment header — invalidate cache and retry clean (no payment header)\n // to get a proper 402 with payment requirements\n paymentCache.invalidate(endpointPath);\n const cleanResponse = await fetch(input, init);\n if (cleanResponse.status !== 402) {\n return cleanResponse;\n }\n const cleanHeader = cleanResponse.headers.get(\"x-payment-required\");\n if (!cleanHeader) {\n throw new Error(\"402 response missing x-payment-required header\");\n }\n return handle402(input, init, url, endpointPath, cleanHeader);\n }\n\n // --- Normal path: first request may get 402 ---\n const response = await fetch(input, init);\n\n if (response.status !== 402) {\n return response;\n }\n\n const paymentHeader = response.headers.get(\"x-payment-required\");\n if (!paymentHeader) {\n throw new Error(\"402 response missing x-payment-required header\");\n }\n\n return handle402(input, init, url, endpointPath, paymentHeader);\n };\n\n /** Handle a 402 response: parse, cache params, sign, retry. */\n async function handle402(\n input: RequestInfo | URL,\n init: RequestInit | undefined,\n url: string,\n endpointPath: string,\n paymentHeader: string,\n ): Promise<Response> {\n const paymentRequired = parsePaymentRequired(paymentHeader);\n const option = paymentRequired.accepts?.[0];\n if (!option) {\n throw new Error(\"No payment options in 402 response\");\n }\n\n const amount = option.amount || option.maxAmountRequired;\n if (!amount) {\n throw new Error(\"No amount in payment requirements\");\n }\n\n // Cache payment params for future pre-auth\n paymentCache.set(endpointPath, {\n payTo: option.payTo,\n asset: option.asset,\n scheme: option.scheme,\n network: option.network,\n extra: option.extra,\n maxTimeoutSeconds: option.maxTimeoutSeconds,\n resourceUrl: paymentRequired.resource?.url,\n resourceDescription: paymentRequired.resource?.description,\n });\n\n // Create signed payment\n const paymentPayload = await createPaymentPayload(\n privateKey,\n walletAddress,\n option,\n amount,\n url,\n paymentRequired.resource,\n );\n\n // Retry with payment\n const retryHeaders = new Headers(init?.headers);\n setPaymentHeaders(retryHeaders, paymentPayload);\n\n return fetch(input, {\n ...init,\n headers: retryHeaders,\n });\n }\n\n return { fetch: payFetch, cache: paymentCache };\n}\n","/**\n * Payment Parameter Cache\n *\n * Caches the 402 payment parameters (payTo, asset, network, etc.) after the first\n * request to each endpoint. On subsequent requests, pre-signs the payment and\n * attaches it to the first request, skipping the 402 round trip (~200ms savings).\n */\n\nexport type CachedPaymentParams = {\n payTo: string;\n asset: string;\n scheme: string;\n network: string;\n extra?: { name?: string; version?: string };\n maxTimeoutSeconds?: number;\n resourceUrl?: string;\n resourceDescription?: string;\n cachedAt: number;\n};\n\nconst DEFAULT_TTL_MS = 3_600_000; // 1 hour\n\nexport class PaymentCache {\n private cache = new Map<string, CachedPaymentParams>();\n private ttlMs: number;\n\n constructor(ttlMs = DEFAULT_TTL_MS) {\n this.ttlMs = ttlMs;\n }\n\n /** Get cached payment params for an endpoint path. */\n get(endpointPath: string): CachedPaymentParams | undefined {\n const entry = this.cache.get(endpointPath);\n if (!entry) return undefined;\n if (Date.now() - entry.cachedAt > this.ttlMs) {\n this.cache.delete(endpointPath);\n return undefined;\n }\n return entry;\n }\n\n /** Cache payment params from a 402 response. */\n set(endpointPath: string, params: Omit<CachedPaymentParams, \"cachedAt\">): void {\n this.cache.set(endpointPath, { ...params, cachedAt: Date.now() });\n }\n\n /** Invalidate cache for an endpoint (e.g., if payTo changed). */\n invalidate(endpointPath: string): void {\n this.cache.delete(endpointPath);\n }\n}\n","/**\n * Rule-Based Classifier (v2 — Weighted Scoring)\n *\n * Scores a request across 14 weighted dimensions and maps the aggregate\n * score to a tier using configurable boundaries. Confidence is calibrated\n * via sigmoid — low confidence triggers the fallback classifier.\n *\n * Handles 70-80% of requests in < 1ms with zero cost.\n */\n\nimport type { Tier, ScoringResult, ScoringConfig } from \"./types.js\";\n\ntype DimensionScore = { name: string; score: number; signal: string | null };\n\n// ─── Dimension Scorers ───\n// Each returns a score in [-1, 1] and an optional signal string.\n\nfunction scoreTokenCount(\n estimatedTokens: number,\n thresholds: { simple: number; complex: number },\n): DimensionScore {\n if (estimatedTokens < thresholds.simple) {\n return { name: \"tokenCount\", score: -1.0, signal: `short (${estimatedTokens} tokens)` };\n }\n if (estimatedTokens > thresholds.complex) {\n return { name: \"tokenCount\", score: 1.0, signal: `long (${estimatedTokens} tokens)` };\n }\n return { name: \"tokenCount\", score: 0, signal: null };\n}\n\nfunction scoreKeywordMatch(\n text: string,\n keywords: string[],\n name: string,\n signalLabel: string,\n thresholds: { low: number; high: number },\n scores: { none: number; low: number; high: number },\n): DimensionScore {\n const matches = keywords.filter((kw) => text.includes(kw.toLowerCase()));\n if (matches.length >= thresholds.high) {\n return {\n name,\n score: scores.high,\n signal: `${signalLabel} (${matches.slice(0, 3).join(\", \")})`,\n };\n }\n if (matches.length >= thresholds.low) {\n return {\n name,\n score: scores.low,\n signal: `${signalLabel} (${matches.slice(0, 3).join(\", \")})`,\n };\n }\n return { name, score: scores.none, signal: null };\n}\n\nfunction scoreMultiStep(text: string): DimensionScore {\n const patterns = [/first.*then/i, /step \\d/i, /\\d\\.\\s/];\n const hits = patterns.filter((p) => p.test(text));\n if (hits.length > 0) {\n return { name: \"multiStepPatterns\", score: 0.5, signal: \"multi-step\" };\n }\n return { name: \"multiStepPatterns\", score: 0, signal: null };\n}\n\nfunction scoreQuestionComplexity(prompt: string): DimensionScore {\n const count = (prompt.match(/\\?/g) || []).length;\n if (count > 3) {\n return { name: \"questionComplexity\", score: 0.5, signal: `${count} questions` };\n }\n return { name: \"questionComplexity\", score: 0, signal: null };\n}\n\n/**\n * Score agentic task indicators.\n * Returns agenticScore (0-1) based on keyword matches:\n * - 4+ matches = 1.0 (high agentic)\n * - 3 matches = 0.6 (moderate agentic, triggers auto-agentic mode)\n * - 1-2 matches = 0.2 (low agentic)\n *\n * Thresholds raised because common keywords were pruned from the list.\n */\nfunction scoreAgenticTask(\n text: string,\n keywords: string[],\n): { dimensionScore: DimensionScore; agenticScore: number } {\n let matchCount = 0;\n const signals: string[] = [];\n\n for (const keyword of keywords) {\n if (text.includes(keyword.toLowerCase())) {\n matchCount++;\n if (signals.length < 3) {\n signals.push(keyword);\n }\n }\n }\n\n // Threshold-based scoring (raised thresholds after keyword pruning)\n if (matchCount >= 4) {\n return {\n dimensionScore: {\n name: \"agenticTask\",\n score: 1.0,\n signal: `agentic (${signals.join(\", \")})`,\n },\n agenticScore: 1.0,\n };\n } else if (matchCount >= 3) {\n return {\n dimensionScore: {\n name: \"agenticTask\",\n score: 0.6,\n signal: `agentic (${signals.join(\", \")})`,\n },\n agenticScore: 0.6,\n };\n } else if (matchCount >= 1) {\n return {\n dimensionScore: {\n name: \"agenticTask\",\n score: 0.2,\n signal: `agentic-light (${signals.join(\", \")})`,\n },\n agenticScore: 0.2,\n };\n }\n\n return {\n dimensionScore: { name: \"agenticTask\", score: 0, signal: null },\n agenticScore: 0,\n };\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 // Score against user prompt only — system prompts contain boilerplate keywords\n // (tool definitions, skill descriptions, behavioral rules) that dominate scoring\n // and make every request score identically. See GitHub issue #50.\n const userText = prompt.toLowerCase();\n\n // Score all 14 dimensions against user text only\n const dimensions: DimensionScore[] = [\n // Token count uses total estimated tokens (system + user) — context size matters for model selection\n scoreTokenCount(estimatedTokens, config.tokenCountThresholds),\n scoreKeywordMatch(\n userText,\n config.codeKeywords,\n \"codePresence\",\n \"code\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 1.0 },\n ),\n scoreKeywordMatch(\n userText,\n config.reasoningKeywords,\n \"reasoningMarkers\",\n \"reasoning\",\n { low: 1, high: 2 },\n { none: 0, low: 0.7, high: 1.0 },\n ),\n scoreKeywordMatch(\n userText,\n config.technicalKeywords,\n \"technicalTerms\",\n \"technical\",\n { low: 2, high: 4 },\n { none: 0, low: 0.5, high: 1.0 },\n ),\n scoreKeywordMatch(\n userText,\n config.creativeKeywords,\n \"creativeMarkers\",\n \"creative\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 0.7 },\n ),\n scoreKeywordMatch(\n userText,\n config.simpleKeywords,\n \"simpleIndicators\",\n \"simple\",\n { low: 1, high: 2 },\n { none: 0, low: -1.0, high: -1.0 },\n ),\n scoreMultiStep(userText),\n scoreQuestionComplexity(prompt),\n\n // 6 new dimensions\n scoreKeywordMatch(\n userText,\n config.imperativeVerbs,\n \"imperativeVerbs\",\n \"imperative\",\n { low: 1, high: 2 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n userText,\n config.constraintIndicators,\n \"constraintCount\",\n \"constraints\",\n { low: 1, high: 3 },\n { none: 0, low: 0.3, high: 0.7 },\n ),\n scoreKeywordMatch(\n userText,\n config.outputFormatKeywords,\n \"outputFormat\",\n \"format\",\n { low: 1, high: 2 },\n { none: 0, low: 0.4, high: 0.7 },\n ),\n scoreKeywordMatch(\n userText,\n config.referenceKeywords,\n \"referenceComplexity\",\n \"references\",\n { low: 1, high: 2 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n userText,\n config.negationKeywords,\n \"negationComplexity\",\n \"negation\",\n { low: 2, high: 3 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n userText,\n config.domainSpecificKeywords,\n \"domainSpecificity\",\n \"domain-specific\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 0.8 },\n ),\n ];\n\n // Score agentic task indicators — user prompt only\n // System prompt describes assistant behavior, not user's intent.\n // e.g. a coding assistant system prompt with \"edit files\" / \"fix bugs\" should NOT\n // force every request into agentic mode.\n const agenticResult = scoreAgenticTask(userText, config.agenticTaskKeywords);\n dimensions.push(agenticResult.dimensionScore);\n const agenticScore = agenticResult.agenticScore;\n\n // Collect signals\n const signals = dimensions.filter((d) => d.signal !== null).map((d) => d.signal!);\n\n // Compute weighted score\n const weights = config.dimensionWeights;\n let weightedScore = 0;\n for (const d of dimensions) {\n const w = weights[d.name] ?? 0;\n weightedScore += d.score * w;\n }\n\n // Count reasoning markers for override — only check USER prompt, not system prompt\n // This prevents system prompts with \"step by step\" from triggering REASONING for simple queries\n const reasoningMatches = config.reasoningKeywords.filter((kw) =>\n userText.includes(kw.toLowerCase()),\n );\n\n // Direct reasoning override: 2+ reasoning markers = high confidence REASONING\n if (reasoningMatches.length >= 2) {\n const confidence = calibrateConfidence(\n Math.max(weightedScore, 0.3), // ensure positive for confidence calc\n config.confidenceSteepness,\n );\n return {\n score: weightedScore,\n tier: \"REASONING\",\n confidence: Math.max(confidence, 0.85),\n signals,\n agenticScore,\n dimensions,\n };\n }\n\n // Map weighted score to tier using boundaries\n const { simpleMedium, mediumComplex, complexReasoning } = config.tierBoundaries;\n let tier: Tier;\n let distanceFromBoundary: number;\n\n if (weightedScore < simpleMedium) {\n tier = \"SIMPLE\";\n distanceFromBoundary = simpleMedium - weightedScore;\n } else if (weightedScore < mediumComplex) {\n tier = \"MEDIUM\";\n distanceFromBoundary = Math.min(weightedScore - simpleMedium, mediumComplex - weightedScore);\n } else if (weightedScore < complexReasoning) {\n tier = \"COMPLEX\";\n distanceFromBoundary = Math.min(\n weightedScore - mediumComplex,\n complexReasoning - weightedScore,\n );\n } else {\n tier = \"REASONING\";\n distanceFromBoundary = weightedScore - complexReasoning;\n }\n\n // Calibrate confidence via sigmoid of distance from nearest boundary\n const confidence = calibrateConfidence(distanceFromBoundary, config.confidenceSteepness);\n\n // If confidence is below threshold → ambiguous\n if (confidence < config.confidenceThreshold) {\n return { score: weightedScore, tier: null, confidence, signals, agenticScore, dimensions };\n }\n\n return { score: weightedScore, tier, confidence, signals, agenticScore, dimensions };\n}\n\n/**\n * Sigmoid confidence calibration.\n * Maps distance from tier boundary to [0.5, 1.0] confidence range.\n */\nfunction calibrateConfidence(distance: number, steepness: number): number {\n return 1 / (1 + Math.exp(-steepness * distance));\n}\n","/**\n * Tier → Model Selection\n *\n * Maps a classification tier to the cheapest capable model.\n * Builds RoutingDecision metadata with cost estimates and savings.\n */\n\nimport type { Tier, TierConfig, RoutingDecision } from \"./types.js\";\n\nexport type ModelPricing = {\n inputPrice: number; // per 1M tokens\n outputPrice: number; // per 1M tokens\n};\n\nconst BASELINE_MODEL_ID = \"anthropic/claude-opus-4.6\";\n\n// Hardcoded fallback: Claude Opus 4.6 pricing (per 1M tokens)\n// Used when baseline model not found in dynamic pricing map\nconst BASELINE_INPUT_PRICE = 5.0;\nconst BASELINE_OUTPUT_PRICE = 25.0;\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 routingProfile?: \"free\" | \"eco\" | \"auto\" | \"premium\",\n agenticScore?: number,\n): RoutingDecision {\n const tierConfig = tierConfigs[tier];\n const model = tierConfig.primary;\n const pricing = modelPricing.get(model);\n\n // Defensive: guard against undefined price fields (not just undefined pricing)\n const inputPrice = pricing?.inputPrice ?? 0;\n const outputPrice = pricing?.outputPrice ?? 0;\n const inputCost = (estimatedInputTokens / 1_000_000) * inputPrice;\n const outputCost = (maxOutputTokens / 1_000_000) * outputPrice;\n const costEstimate = inputCost + outputCost;\n\n // Baseline: what Claude Opus 4.5 would cost (the premium reference)\n const opusPricing = modelPricing.get(BASELINE_MODEL_ID);\n const opusInputPrice = opusPricing?.inputPrice ?? BASELINE_INPUT_PRICE;\n const opusOutputPrice = opusPricing?.outputPrice ?? BASELINE_OUTPUT_PRICE;\n const baselineInput = (estimatedInputTokens / 1_000_000) * opusInputPrice;\n const baselineOutput = (maxOutputTokens / 1_000_000) * opusOutputPrice;\n const baselineCost = baselineInput + baselineOutput;\n\n // Premium profile doesn't calculate savings (it's about quality, not cost)\n const savings =\n routingProfile === \"premium\"\n ? 0\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 ...(agenticScore !== undefined && { agenticScore }),\n };\n}\n\n/**\n * Get the ordered fallback chain for a tier: [primary, ...fallbacks].\n */\nexport function getFallbackChain(tier: Tier, tierConfigs: Record<Tier, TierConfig>): string[] {\n const config = tierConfigs[tier];\n return [config.primary, ...config.fallback];\n}\n\n/**\n * Calculate cost for a specific model (used when fallback model is used).\n * Returns updated cost fields for RoutingDecision.\n */\nexport function calculateModelCost(\n model: string,\n modelPricing: Map<string, ModelPricing>,\n estimatedInputTokens: number,\n maxOutputTokens: number,\n routingProfile?: \"free\" | \"eco\" | \"auto\" | \"premium\",\n): { costEstimate: number; baselineCost: number; savings: number } {\n const pricing = modelPricing.get(model);\n\n // Defensive: guard against undefined price fields (not just undefined pricing)\n const inputPrice = pricing?.inputPrice ?? 0;\n const outputPrice = pricing?.outputPrice ?? 0;\n const inputCost = (estimatedInputTokens / 1_000_000) * inputPrice;\n const outputCost = (maxOutputTokens / 1_000_000) * outputPrice;\n const costEstimate = inputCost + outputCost;\n\n // Baseline: what Claude Opus 4.5 would cost (the premium reference)\n const opusPricing = modelPricing.get(BASELINE_MODEL_ID);\n const opusInputPrice = opusPricing?.inputPrice ?? BASELINE_INPUT_PRICE;\n const opusOutputPrice = opusPricing?.outputPrice ?? BASELINE_OUTPUT_PRICE;\n const baselineInput = (estimatedInputTokens / 1_000_000) * opusInputPrice;\n const baselineOutput = (maxOutputTokens / 1_000_000) * opusOutputPrice;\n const baselineCost = baselineInput + baselineOutput;\n\n // Premium profile doesn't calculate savings (it's about quality, not cost)\n const savings =\n routingProfile === \"premium\"\n ? 0\n : baselineCost > 0\n ? Math.max(0, (baselineCost - costEstimate) / baselineCost)\n : 0;\n\n return { costEstimate, baselineCost, savings };\n}\n\n/**\n * Filter a model list to only those that support tool calling.\n * When hasTools is false, returns the list unchanged.\n * When all models lack tool calling support, returns the full list as a fallback\n * (better to let the API error than produce an empty chain).\n */\nexport function filterByToolCalling(\n models: string[],\n hasTools: boolean,\n supportsToolCalling: (modelId: string) => boolean,\n): string[] {\n if (!hasTools) return models;\n const filtered = models.filter(supportsToolCalling);\n return filtered.length > 0 ? filtered : models;\n}\n\n/**\n * Filter a model list to only those that support vision (image inputs).\n * When hasVision is false, returns the list unchanged.\n * When all models lack vision support, returns the full list as a fallback\n * (better to let the API error than produce an empty chain).\n */\nexport function filterByVision(\n models: string[],\n hasVision: boolean,\n supportsVision: (modelId: string) => boolean,\n): string[] {\n if (!hasVision) return models;\n const filtered = models.filter(supportsVision);\n return filtered.length > 0 ? filtered : models;\n}\n\n/**\n * Get the fallback chain filtered by context length.\n * Only returns models that can handle the estimated total context.\n *\n * @param tier - The tier to get fallback chain for\n * @param tierConfigs - Tier configurations\n * @param estimatedTotalTokens - Estimated total context (input + output)\n * @param getContextWindow - Function to get context window for a model ID\n * @returns Filtered list of models that can handle the context\n */\nexport function getFallbackChainFiltered(\n tier: Tier,\n tierConfigs: Record<Tier, TierConfig>,\n estimatedTotalTokens: number,\n getContextWindow: (modelId: string) => number | undefined,\n): string[] {\n const fullChain = getFallbackChain(tier, tierConfigs);\n\n // Filter to models that can handle the context\n const filtered = fullChain.filter((modelId) => {\n const contextWindow = getContextWindow(modelId);\n if (contextWindow === undefined) {\n // Unknown model - include it (let API reject if needed)\n return true;\n }\n // Add 10% buffer for safety\n return contextWindow >= estimatedTotalTokens * 1.1;\n });\n\n // If all models filtered out, return the original chain\n // (let the API error out - better than no options)\n if (filtered.length === 0) {\n return fullChain;\n }\n\n return filtered;\n}\n","/**\n * Default Routing Config\n *\n * All routing parameters as a TypeScript constant.\n * Operators override via openclaw.yaml plugin config.\n *\n * Scoring uses 14 weighted dimensions with sigmoid confidence calibration.\n */\n\nimport type { RoutingConfig } from \"./types.js\";\n\nexport const DEFAULT_ROUTING_CONFIG: RoutingConfig = {\n version: \"2.0\",\n\n classifier: {\n llmModel: \"google/gemini-2.5-flash\",\n llmMaxTokens: 10,\n llmTemperature: 0,\n promptTruncationChars: 500,\n cacheTtlMs: 3_600_000, // 1 hour\n },\n\n scoring: {\n tokenCountThresholds: { simple: 50, complex: 500 },\n\n // Multilingual keywords: EN + ZH + JA + RU + DE + ES + PT + KO + AR\n codeKeywords: [\n // English\n \"function\",\n \"class\",\n \"import\",\n \"def\",\n \"SELECT\",\n \"async\",\n \"await\",\n \"const\",\n \"let\",\n \"var\",\n \"return\",\n \"```\",\n // Chinese\n \"函数\",\n \"类\",\n \"导入\",\n \"定义\",\n \"查询\",\n \"异步\",\n \"等待\",\n \"常量\",\n \"变量\",\n \"返回\",\n // Japanese\n \"関数\",\n \"クラス\",\n \"インポート\",\n \"非同期\",\n \"定数\",\n \"変数\",\n // Russian\n \"функция\",\n \"класс\",\n \"импорт\",\n \"определ\",\n \"запрос\",\n \"асинхронный\",\n \"ожидать\",\n \"константа\",\n \"переменная\",\n \"вернуть\",\n // German\n \"funktion\",\n \"klasse\",\n \"importieren\",\n \"definieren\",\n \"abfrage\",\n \"asynchron\",\n \"erwarten\",\n \"konstante\",\n \"variable\",\n \"zurückgeben\",\n // Spanish\n \"función\",\n \"clase\",\n \"importar\",\n \"definir\",\n \"consulta\",\n \"asíncrono\",\n \"esperar\",\n \"constante\",\n \"variable\",\n \"retornar\",\n // Portuguese\n \"função\",\n \"classe\",\n \"importar\",\n \"definir\",\n \"consulta\",\n \"assíncrono\",\n \"aguardar\",\n \"constante\",\n \"variável\",\n \"retornar\",\n // Korean\n \"함수\",\n \"클래스\",\n \"가져오기\",\n \"정의\",\n \"쿼리\",\n \"비동기\",\n \"대기\",\n \"상수\",\n \"변수\",\n \"반환\",\n // Arabic\n \"دالة\",\n \"فئة\",\n \"استيراد\",\n \"تعريف\",\n \"استعلام\",\n \"غير متزامن\",\n \"انتظار\",\n \"ثابت\",\n \"متغير\",\n \"إرجاع\",\n ],\n reasoningKeywords: [\n // English\n \"prove\",\n \"theorem\",\n \"derive\",\n \"step by step\",\n \"chain of thought\",\n \"formally\",\n \"mathematical\",\n \"proof\",\n \"logically\",\n // Chinese\n \"证明\",\n \"定理\",\n \"推导\",\n \"逐步\",\n \"思维链\",\n \"形式化\",\n \"数学\",\n \"逻辑\",\n // Japanese\n \"証明\",\n \"定理\",\n \"導出\",\n \"ステップバイステップ\",\n \"論理的\",\n // Russian\n \"доказать\",\n \"докажи\",\n \"доказательств\",\n \"теорема\",\n \"вывести\",\n \"шаг за шагом\",\n \"пошагово\",\n \"поэтапно\",\n \"цепочка рассуждений\",\n \"рассуждени\",\n \"формально\",\n \"математически\",\n \"логически\",\n // German\n \"beweisen\",\n \"beweis\",\n \"theorem\",\n \"ableiten\",\n \"schritt für schritt\",\n \"gedankenkette\",\n \"formal\",\n \"mathematisch\",\n \"logisch\",\n // Spanish\n \"demostrar\",\n \"teorema\",\n \"derivar\",\n \"paso a paso\",\n \"cadena de pensamiento\",\n \"formalmente\",\n \"matemático\",\n \"prueba\",\n \"lógicamente\",\n // Portuguese\n \"provar\",\n \"teorema\",\n \"derivar\",\n \"passo a passo\",\n \"cadeia de pensamento\",\n \"formalmente\",\n \"matemático\",\n \"prova\",\n \"logicamente\",\n // Korean\n \"증명\",\n \"정리\",\n \"도출\",\n \"단계별\",\n \"사고의 연쇄\",\n \"형식적\",\n \"수학적\",\n \"논리적\",\n // Arabic\n \"إثبات\",\n \"نظرية\",\n \"اشتقاق\",\n \"خطوة بخطوة\",\n \"سلسلة التفكير\",\n \"رسمياً\",\n \"رياضي\",\n \"برهان\",\n \"منطقياً\",\n ],\n simpleKeywords: [\n // English\n \"what is\",\n \"define\",\n \"translate\",\n \"hello\",\n \"yes or no\",\n \"capital of\",\n \"how old\",\n \"who is\",\n \"when was\",\n // Chinese\n \"什么是\",\n \"定义\",\n \"翻译\",\n \"你好\",\n \"是否\",\n \"首都\",\n \"多大\",\n \"谁是\",\n \"何时\",\n // Japanese\n \"とは\",\n \"定義\",\n \"翻訳\",\n \"こんにちは\",\n \"はいかいいえ\",\n \"首都\",\n \"誰\",\n // Russian\n \"что такое\",\n \"определение\",\n \"перевести\",\n \"переведи\",\n \"привет\",\n \"да или нет\",\n \"столица\",\n \"сколько лет\",\n \"кто такой\",\n \"когда\",\n \"объясни\",\n // German\n \"was ist\",\n \"definiere\",\n \"übersetze\",\n \"hallo\",\n \"ja oder nein\",\n \"hauptstadt\",\n \"wie alt\",\n \"wer ist\",\n \"wann\",\n \"erkläre\",\n // Spanish\n \"qué es\",\n \"definir\",\n \"traducir\",\n \"hola\",\n \"sí o no\",\n \"capital de\",\n \"cuántos años\",\n \"quién es\",\n \"cuándo\",\n // Portuguese\n \"o que é\",\n \"definir\",\n \"traduzir\",\n \"olá\",\n \"sim ou não\",\n \"capital de\",\n \"quantos anos\",\n \"quem é\",\n \"quando\",\n // Korean\n \"무엇\",\n \"정의\",\n \"번역\",\n \"안녕하세요\",\n \"예 또는 아니오\",\n \"수도\",\n \"누구\",\n \"언제\",\n // Arabic\n \"ما هو\",\n \"تعريف\",\n \"ترجم\",\n \"مرحبا\",\n \"نعم أو لا\",\n \"عاصمة\",\n \"من هو\",\n \"متى\",\n ],\n technicalKeywords: [\n // English\n \"algorithm\",\n \"optimize\",\n \"architecture\",\n \"distributed\",\n \"kubernetes\",\n \"microservice\",\n \"database\",\n \"infrastructure\",\n // Chinese\n \"算法\",\n \"优化\",\n \"架构\",\n \"分布式\",\n \"微服务\",\n \"数据库\",\n \"基础设施\",\n // Japanese\n \"アルゴリズム\",\n \"最適化\",\n \"アーキテクチャ\",\n \"分散\",\n \"マイクロサービス\",\n \"データベース\",\n // Russian\n \"алгоритм\",\n \"оптимизировать\",\n \"оптимизаци\",\n \"оптимизируй\",\n \"архитектура\",\n \"распределённый\",\n \"микросервис\",\n \"база данных\",\n \"инфраструктура\",\n // German\n \"algorithmus\",\n \"optimieren\",\n \"architektur\",\n \"verteilt\",\n \"kubernetes\",\n \"mikroservice\",\n \"datenbank\",\n \"infrastruktur\",\n // Spanish\n \"algoritmo\",\n \"optimizar\",\n \"arquitectura\",\n \"distribuido\",\n \"microservicio\",\n \"base de datos\",\n \"infraestructura\",\n // Portuguese\n \"algoritmo\",\n \"otimizar\",\n \"arquitetura\",\n \"distribuído\",\n \"microsserviço\",\n \"banco de dados\",\n \"infraestrutura\",\n // Korean\n \"알고리즘\",\n \"최적화\",\n \"아키텍처\",\n \"분산\",\n \"마이크로서비스\",\n \"데이터베이스\",\n \"인프라\",\n // Arabic\n \"خوارزمية\",\n \"تحسين\",\n \"بنية\",\n \"موزع\",\n \"خدمة مصغرة\",\n \"قاعدة بيانات\",\n \"بنية تحتية\",\n ],\n creativeKeywords: [\n // English\n \"story\",\n \"poem\",\n \"compose\",\n \"brainstorm\",\n \"creative\",\n \"imagine\",\n \"write a\",\n // Chinese\n \"故事\",\n \"诗\",\n \"创作\",\n \"头脑风暴\",\n \"创意\",\n \"想象\",\n \"写一个\",\n // Japanese\n \"物語\",\n \"詩\",\n \"作曲\",\n \"ブレインストーム\",\n \"創造的\",\n \"想像\",\n // Russian\n \"история\",\n \"рассказ\",\n \"стихотворение\",\n \"сочинить\",\n \"сочини\",\n \"мозговой штурм\",\n \"творческий\",\n \"представить\",\n \"придумай\",\n \"напиши\",\n // German\n \"geschichte\",\n \"gedicht\",\n \"komponieren\",\n \"brainstorming\",\n \"kreativ\",\n \"vorstellen\",\n \"schreibe\",\n \"erzählung\",\n // Spanish\n \"historia\",\n \"poema\",\n \"componer\",\n \"lluvia de ideas\",\n \"creativo\",\n \"imaginar\",\n \"escribe\",\n // Portuguese\n \"história\",\n \"poema\",\n \"compor\",\n \"criativo\",\n \"imaginar\",\n \"escreva\",\n // Korean\n \"이야기\",\n \"시\",\n \"작곡\",\n \"브레인스토밍\",\n \"창의적\",\n \"상상\",\n \"작성\",\n // Arabic\n \"قصة\",\n \"قصيدة\",\n \"تأليف\",\n \"عصف ذهني\",\n \"إبداعي\",\n \"تخيل\",\n \"اكتب\",\n ],\n\n // New dimension keyword lists (multilingual)\n imperativeVerbs: [\n // English\n \"build\",\n \"create\",\n \"implement\",\n \"design\",\n \"develop\",\n \"construct\",\n \"generate\",\n \"deploy\",\n \"configure\",\n \"set up\",\n // Chinese\n \"构建\",\n \"创建\",\n \"实现\",\n \"设计\",\n \"开发\",\n \"生成\",\n \"部署\",\n \"配置\",\n \"设置\",\n // Japanese\n \"構築\",\n \"作成\",\n \"実装\",\n \"設計\",\n \"開発\",\n \"生成\",\n \"デプロイ\",\n \"設定\",\n // Russian\n \"построить\",\n \"построй\",\n \"создать\",\n \"создай\",\n \"реализовать\",\n \"реализуй\",\n \"спроектировать\",\n \"разработать\",\n \"разработай\",\n \"сконструировать\",\n \"сгенерировать\",\n \"сгенерируй\",\n \"развернуть\",\n \"разверни\",\n \"настроить\",\n \"настрой\",\n // German\n \"erstellen\",\n \"bauen\",\n \"implementieren\",\n \"entwerfen\",\n \"entwickeln\",\n \"konstruieren\",\n \"generieren\",\n \"bereitstellen\",\n \"konfigurieren\",\n \"einrichten\",\n // Spanish\n \"construir\",\n \"crear\",\n \"implementar\",\n \"diseñar\",\n \"desarrollar\",\n \"generar\",\n \"desplegar\",\n \"configurar\",\n // Portuguese\n \"construir\",\n \"criar\",\n \"implementar\",\n \"projetar\",\n \"desenvolver\",\n \"gerar\",\n \"implantar\",\n \"configurar\",\n // Korean\n \"구축\",\n \"생성\",\n \"구현\",\n \"설계\",\n \"개발\",\n \"배포\",\n \"설정\",\n // Arabic\n \"بناء\",\n \"إنشاء\",\n \"تنفيذ\",\n \"تصميم\",\n \"تطوير\",\n \"توليد\",\n \"نشر\",\n \"إعداد\",\n ],\n constraintIndicators: [\n // English\n \"under\",\n \"at most\",\n \"at least\",\n \"within\",\n \"no more than\",\n \"o(\",\n \"maximum\",\n \"minimum\",\n \"limit\",\n \"budget\",\n // Chinese\n \"不超过\",\n \"至少\",\n \"最多\",\n \"在内\",\n \"最大\",\n \"最小\",\n \"限制\",\n \"预算\",\n // Japanese\n \"以下\",\n \"最大\",\n \"最小\",\n \"制限\",\n \"予算\",\n // Russian\n \"не более\",\n \"не менее\",\n \"как минимум\",\n \"в пределах\",\n \"максимум\",\n \"минимум\",\n \"ограничение\",\n \"бюджет\",\n // German\n \"höchstens\",\n \"mindestens\",\n \"innerhalb\",\n \"nicht mehr als\",\n \"maximal\",\n \"minimal\",\n \"grenze\",\n \"budget\",\n // Spanish\n \"como máximo\",\n \"al menos\",\n \"dentro de\",\n \"no más de\",\n \"máximo\",\n \"mínimo\",\n \"límite\",\n \"presupuesto\",\n // Portuguese\n \"no máximo\",\n \"pelo menos\",\n \"dentro de\",\n \"não mais que\",\n \"máximo\",\n \"mínimo\",\n \"limite\",\n \"orçamento\",\n // Korean\n \"이하\",\n \"이상\",\n \"최대\",\n \"최소\",\n \"제한\",\n \"예산\",\n // Arabic\n \"على الأكثر\",\n \"على الأقل\",\n \"ضمن\",\n \"لا يزيد عن\",\n \"أقصى\",\n \"أدنى\",\n \"حد\",\n \"ميزانية\",\n ],\n outputFormatKeywords: [\n // English\n \"json\",\n \"yaml\",\n \"xml\",\n \"table\",\n \"csv\",\n \"markdown\",\n \"schema\",\n \"format as\",\n \"structured\",\n // Chinese\n \"表格\",\n \"格式化为\",\n \"结构化\",\n // Japanese\n \"テーブル\",\n \"フォーマット\",\n \"構造化\",\n // Russian\n \"таблица\",\n \"форматировать как\",\n \"структурированный\",\n // German\n \"tabelle\",\n \"formatieren als\",\n \"strukturiert\",\n // Spanish\n \"tabla\",\n \"formatear como\",\n \"estructurado\",\n // Portuguese\n \"tabela\",\n \"formatar como\",\n \"estruturado\",\n // Korean\n \"테이블\",\n \"형식\",\n \"구조화\",\n // Arabic\n \"جدول\",\n \"تنسيق\",\n \"منظم\",\n ],\n referenceKeywords: [\n // English\n \"above\",\n \"below\",\n \"previous\",\n \"following\",\n \"the docs\",\n \"the api\",\n \"the code\",\n \"earlier\",\n \"attached\",\n // Chinese\n \"上面\",\n \"下面\",\n \"之前\",\n \"接下来\",\n \"文档\",\n \"代码\",\n \"附件\",\n // Japanese\n \"上記\",\n \"下記\",\n \"前の\",\n \"次の\",\n \"ドキュメント\",\n \"コード\",\n // Russian\n \"выше\",\n \"ниже\",\n \"предыдущий\",\n \"следующий\",\n \"документация\",\n \"код\",\n \"ранее\",\n \"вложение\",\n // German\n \"oben\",\n \"unten\",\n \"vorherige\",\n \"folgende\",\n \"dokumentation\",\n \"der code\",\n \"früher\",\n \"anhang\",\n // Spanish\n \"arriba\",\n \"abajo\",\n \"anterior\",\n \"siguiente\",\n \"documentación\",\n \"el código\",\n \"adjunto\",\n // Portuguese\n \"acima\",\n \"abaixo\",\n \"anterior\",\n \"seguinte\",\n \"documentação\",\n \"o código\",\n \"anexo\",\n // Korean\n \"위\",\n \"아래\",\n \"이전\",\n \"다음\",\n \"문서\",\n \"코드\",\n \"첨부\",\n // Arabic\n \"أعلاه\",\n \"أدناه\",\n \"السابق\",\n \"التالي\",\n \"الوثائق\",\n \"الكود\",\n \"مرفق\",\n ],\n negationKeywords: [\n // English\n \"don't\",\n \"do not\",\n \"avoid\",\n \"never\",\n \"without\",\n \"except\",\n \"exclude\",\n \"no longer\",\n // Chinese\n \"不要\",\n \"避免\",\n \"从不\",\n \"没有\",\n \"除了\",\n \"排除\",\n // Japanese\n \"しないで\",\n \"避ける\",\n \"決して\",\n \"なしで\",\n \"除く\",\n // Russian\n \"не делай\",\n \"не надо\",\n \"нельзя\",\n \"избегать\",\n \"никогда\",\n \"без\",\n \"кроме\",\n \"исключить\",\n \"больше не\",\n // German\n \"nicht\",\n \"vermeide\",\n \"niemals\",\n \"ohne\",\n \"außer\",\n \"ausschließen\",\n \"nicht mehr\",\n // Spanish\n \"no hagas\",\n \"evitar\",\n \"nunca\",\n \"sin\",\n \"excepto\",\n \"excluir\",\n // Portuguese\n \"não faça\",\n \"evitar\",\n \"nunca\",\n \"sem\",\n \"exceto\",\n \"excluir\",\n // Korean\n \"하지 마\",\n \"피하다\",\n \"절대\",\n \"없이\",\n \"제외\",\n // Arabic\n \"لا تفعل\",\n \"تجنب\",\n \"أبداً\",\n \"بدون\",\n \"باستثناء\",\n \"استبعاد\",\n ],\n domainSpecificKeywords: [\n // English\n \"quantum\",\n \"fpga\",\n \"vlsi\",\n \"risc-v\",\n \"asic\",\n \"photonics\",\n \"genomics\",\n \"proteomics\",\n \"topological\",\n \"homomorphic\",\n \"zero-knowledge\",\n \"lattice-based\",\n // Chinese\n \"量子\",\n \"光子学\",\n \"基因组学\",\n \"蛋白质组学\",\n \"拓扑\",\n \"同态\",\n \"零知识\",\n \"格密码\",\n // Japanese\n \"量子\",\n \"フォトニクス\",\n \"ゲノミクス\",\n \"トポロジカル\",\n // Russian\n \"квантовый\",\n \"фотоника\",\n \"геномика\",\n \"протеомика\",\n \"топологический\",\n \"гомоморфный\",\n \"с нулевым разглашением\",\n \"на основе решёток\",\n // German\n \"quanten\",\n \"photonik\",\n \"genomik\",\n \"proteomik\",\n \"topologisch\",\n \"homomorph\",\n \"zero-knowledge\",\n \"gitterbasiert\",\n // Spanish\n \"cuántico\",\n \"fotónica\",\n \"genómica\",\n \"proteómica\",\n \"topológico\",\n \"homomórfico\",\n // Portuguese\n \"quântico\",\n \"fotônica\",\n \"genômica\",\n \"proteômica\",\n \"topológico\",\n \"homomórfico\",\n // Korean\n \"양자\",\n \"포토닉스\",\n \"유전체학\",\n \"위상\",\n \"동형\",\n // Arabic\n \"كمي\",\n \"ضوئيات\",\n \"جينوميات\",\n \"طوبولوجي\",\n \"تماثلي\",\n ],\n\n // Agentic task keywords - file ops, execution, multi-step, iterative work\n // Pruned: removed overly common words like \"then\", \"first\", \"run\", \"test\", \"build\"\n agenticTaskKeywords: [\n // English - File operations (clearly agentic)\n \"read file\",\n \"read the file\",\n \"look at\",\n \"check the\",\n \"open the\",\n \"edit\",\n \"modify\",\n \"update the\",\n \"change the\",\n \"write to\",\n \"create file\",\n // English - Execution (specific commands only)\n \"execute\",\n \"deploy\",\n \"install\",\n \"npm\",\n \"pip\",\n \"compile\",\n // English - Multi-step patterns (specific only)\n \"after that\",\n \"and also\",\n \"once done\",\n \"step 1\",\n \"step 2\",\n // English - Iterative work\n \"fix\",\n \"debug\",\n \"until it works\",\n \"keep trying\",\n \"iterate\",\n \"make sure\",\n \"verify\",\n \"confirm\",\n // Chinese (keep specific ones)\n \"读取文件\",\n \"查看\",\n \"打开\",\n \"编辑\",\n \"修改\",\n \"更新\",\n \"创建\",\n \"执行\",\n \"部署\",\n \"安装\",\n \"第一步\",\n \"第二步\",\n \"修复\",\n \"调试\",\n \"直到\",\n \"确认\",\n \"验证\",\n // Spanish\n \"leer archivo\",\n \"editar\",\n \"modificar\",\n \"actualizar\",\n \"ejecutar\",\n \"desplegar\",\n \"instalar\",\n \"paso 1\",\n \"paso 2\",\n \"arreglar\",\n \"depurar\",\n \"verificar\",\n // Portuguese\n \"ler arquivo\",\n \"editar\",\n \"modificar\",\n \"atualizar\",\n \"executar\",\n \"implantar\",\n \"instalar\",\n \"passo 1\",\n \"passo 2\",\n \"corrigir\",\n \"depurar\",\n \"verificar\",\n // Korean\n \"파일 읽기\",\n \"편집\",\n \"수정\",\n \"업데이트\",\n \"실행\",\n \"배포\",\n \"설치\",\n \"단계 1\",\n \"단계 2\",\n \"디버그\",\n \"확인\",\n // Arabic\n \"قراءة ملف\",\n \"تحرير\",\n \"تعديل\",\n \"تحديث\",\n \"تنفيذ\",\n \"نشر\",\n \"تثبيت\",\n \"الخطوة 1\",\n \"الخطوة 2\",\n \"إصلاح\",\n \"تصحيح\",\n \"تحقق\",\n ],\n\n // Dimension weights (sum to 1.0)\n dimensionWeights: {\n tokenCount: 0.08,\n codePresence: 0.15,\n reasoningMarkers: 0.18,\n technicalTerms: 0.1,\n creativeMarkers: 0.05,\n simpleIndicators: 0.02, // Reduced from 0.12 to make room for agenticTask\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 agenticTask: 0.04, // Reduced - agentic signals influence tier selection, not dominate it\n },\n\n // Tier boundaries on weighted score axis\n tierBoundaries: {\n simpleMedium: 0.0,\n mediumComplex: 0.3, // Raised from 0.18 - prevent simple tasks from reaching expensive COMPLEX tier\n complexReasoning: 0.5, // Raised from 0.4 - reserve for true reasoning tasks\n },\n\n // Sigmoid steepness for confidence calibration\n confidenceSteepness: 12,\n // Below this confidence → ambiguous (null tier)\n confidenceThreshold: 0.7,\n },\n\n // Auto (balanced) tier configs - current default smart routing\n tiers: {\n SIMPLE: {\n primary: \"moonshot/kimi-k2.5\", // $0.60/$3.00 - best quality/price for simple tasks\n fallback: [\n \"google/gemini-2.5-flash-lite\", // 1M context, ultra cheap ($0.10/$0.40)\n \"nvidia/gpt-oss-120b\", // FREE fallback\n \"deepseek/deepseek-chat\",\n ],\n },\n MEDIUM: {\n primary: \"moonshot/kimi-k2.5\", // $0.50/$2.40 - strong tool use, proper function call format\n fallback: [\n \"deepseek/deepseek-chat\",\n \"google/gemini-2.5-flash-lite\", // 1M context, ultra cheap ($0.10/$0.40)\n \"xai/grok-4-1-fast-non-reasoning\", // Upgraded Grok 4.1\n ],\n },\n COMPLEX: {\n primary: \"google/gemini-3.1-pro\", // Newest Gemini 3.1 - upgraded from 3.0\n fallback: [\n \"google/gemini-2.5-flash-lite\", // CRITICAL: 1M context, ultra-cheap failsafe ($0.10/$0.40)\n \"google/gemini-3-pro-preview\", // 3.0 fallback\n \"google/gemini-2.5-pro\",\n \"deepseek/deepseek-chat\",\n \"xai/grok-4-0709\",\n \"openai/gpt-5.2\", // Newer and cheaper input than gpt-4o\n \"openai/gpt-4o\",\n \"anthropic/claude-sonnet-4.6\",\n ],\n },\n REASONING: {\n primary: \"xai/grok-4-1-fast-reasoning\", // Upgraded Grok 4.1 reasoning $0.20/$0.50\n fallback: [\n \"deepseek/deepseek-reasoner\", // Cheap reasoning model\n \"openai/o4-mini\", // Newer and cheaper than o3 ($1.10 vs $2.00)\n \"openai/o3\",\n ],\n },\n },\n\n // Eco tier configs - absolute cheapest (blockrun/eco)\n ecoTiers: {\n SIMPLE: {\n primary: \"nvidia/gpt-oss-120b\", // FREE! $0.00/$0.00\n fallback: [\"google/gemini-2.5-flash-lite\", \"deepseek/deepseek-chat\"],\n },\n MEDIUM: {\n primary: \"google/gemini-2.5-flash-lite\", // $0.10/$0.40 - cheapest capable with 1M context\n fallback: [\"deepseek/deepseek-chat\", \"nvidia/gpt-oss-120b\"],\n },\n COMPLEX: {\n primary: \"google/gemini-2.5-flash-lite\", // $0.10/$0.40 - 1M context handles complexity\n fallback: [\"google/gemini-2.5-flash\", \"deepseek/deepseek-chat\", \"xai/grok-4-0709\"],\n },\n REASONING: {\n primary: \"xai/grok-4-1-fast-reasoning\", // $0.20/$0.50\n fallback: [\"deepseek/deepseek-reasoner\"],\n },\n },\n\n // Premium tier configs - best quality (blockrun/premium)\n // codex=complex coding, kimi=simple coding, sonnet=reasoning/instructions, opus=architecture/PM/audits\n premiumTiers: {\n SIMPLE: {\n primary: \"moonshot/kimi-k2.5\", // $0.60/$3.00 - good for simple coding\n fallback: [\n \"anthropic/claude-haiku-4.5\",\n \"google/gemini-2.5-flash-lite\",\n \"deepseek/deepseek-chat\",\n ],\n },\n MEDIUM: {\n primary: \"openai/gpt-5.2-codex\", // $2.50/$10 - strong coding for medium tasks\n fallback: [\n \"moonshot/kimi-k2.5\",\n \"google/gemini-2.5-pro\",\n \"xai/grok-4-0709\",\n \"anthropic/claude-sonnet-4.6\",\n ],\n },\n COMPLEX: {\n primary: \"anthropic/claude-opus-4.6\", // Best quality for complex tasks\n fallback: [\n \"openai/gpt-5.2-codex\",\n \"anthropic/claude-opus-4.6\",\n \"anthropic/claude-sonnet-4.6\",\n \"google/gemini-3.1-pro\", // Newest Gemini\n \"google/gemini-3-pro-preview\",\n \"moonshot/kimi-k2.5\",\n ],\n },\n REASONING: {\n primary: \"anthropic/claude-sonnet-4.6\", // $3/$15 - best for reasoning/instructions\n fallback: [\n \"anthropic/claude-opus-4.6\",\n \"anthropic/claude-opus-4.6\",\n \"openai/o4-mini\", // Newer and cheaper than o3 ($1.10 vs $2.00)\n \"openai/o3\",\n \"xai/grok-4-1-fast-reasoning\",\n ],\n },\n },\n\n // Agentic tier configs - models that excel at multi-step autonomous tasks\n agenticTiers: {\n SIMPLE: {\n primary: \"moonshot/kimi-k2.5\", // Cheaper than Haiku ($0.5/$2.4 vs $1/$5), larger context\n fallback: [\n \"anthropic/claude-haiku-4.5\",\n \"xai/grok-4-1-fast-non-reasoning\",\n \"openai/gpt-4o-mini\",\n ],\n },\n MEDIUM: {\n primary: \"moonshot/kimi-k2.5\", // $0.50/$2.40 - strong tool use, handles function calls correctly\n fallback: [\n \"anthropic/claude-haiku-4.5\",\n \"deepseek/deepseek-chat\",\n \"xai/grok-4-1-fast-non-reasoning\",\n ],\n },\n COMPLEX: {\n primary: \"anthropic/claude-sonnet-4.6\",\n fallback: [\n \"anthropic/claude-opus-4.6\", // Latest Opus - best agentic\n \"openai/gpt-5.2\",\n \"google/gemini-3.1-pro\", // Newest Gemini\n \"google/gemini-3-pro-preview\",\n \"xai/grok-4-0709\",\n ],\n },\n REASONING: {\n primary: \"anthropic/claude-sonnet-4.6\", // Strong tool use + reasoning for agentic tasks\n fallback: [\n \"anthropic/claude-opus-4.6\",\n \"xai/grok-4-1-fast-reasoning\",\n \"deepseek/deepseek-reasoner\",\n ],\n },\n },\n\n overrides: {\n maxTokensForceComplex: 100_000,\n structuredOutputMinTier: \"MEDIUM\",\n ambiguousDefaultTier: \"MEDIUM\",\n agenticMode: false,\n },\n};\n","/**\n * Smart Router Entry Point\n *\n * Classifies requests and routes to the cheapest capable model.\n * 100% local — rules-based scoring handles all requests in <1ms.\n * Ambiguous cases default to configurable tier (MEDIUM by default).\n */\n\nimport type { Tier, RoutingDecision, RoutingConfig } from \"./types.js\";\nimport { classifyByRules } from \"./rules.js\";\nimport { selectModel, type ModelPricing } from \"./selector.js\";\n\nexport type RouterOptions = {\n config: RoutingConfig;\n modelPricing: Map<string, ModelPricing>;\n routingProfile?: \"free\" | \"eco\" | \"auto\" | \"premium\";\n};\n\n/**\n * Route a request to the cheapest capable model.\n *\n * 1. Check overrides (large context, structured output)\n * 2. Run rule-based classifier (14 weighted dimensions, <1ms)\n * 3. If ambiguous, default to configurable tier (no external API calls)\n * 4. Select model for tier\n * 5. Return RoutingDecision with metadata\n */\nexport function route(\n prompt: string,\n systemPrompt: string | undefined,\n maxOutputTokens: number,\n options: RouterOptions,\n): RoutingDecision {\n const { config, modelPricing } = options;\n\n // Estimate input tokens (~4 chars per token)\n const fullText = `${systemPrompt ?? \"\"} ${prompt}`;\n const estimatedTokens = Math.ceil(fullText.length / 4);\n\n // --- Rule-based classification (runs first to get agenticScore) ---\n const ruleResult = classifyByRules(prompt, systemPrompt, estimatedTokens, config.scoring);\n\n // --- Select tier configs based on routing profile ---\n const { routingProfile } = options;\n let tierConfigs: Record<Tier, { primary: string; fallback: string[] }>;\n let profileSuffix = \"\";\n\n if (routingProfile === \"eco\" && config.ecoTiers) {\n // Eco profile: ultra cost-optimized models\n tierConfigs = config.ecoTiers;\n profileSuffix = \" | eco\";\n } else if (routingProfile === \"premium\" && config.premiumTiers) {\n // Premium profile: best quality models\n tierConfigs = config.premiumTiers;\n profileSuffix = \" | premium\";\n } else {\n // Auto profile (or undefined): intelligent routing with agentic detection\n // Determine if agentic tiers should be used:\n // 1. Explicit agenticMode config OR\n // 2. Auto-detected agentic task (agenticScore >= 0.5, lowered for better multi-step detection)\n const agenticScore = ruleResult.agenticScore ?? 0;\n const isAutoAgentic = agenticScore >= 0.5;\n const isExplicitAgentic = config.overrides.agenticMode ?? false;\n const useAgenticTiers = (isAutoAgentic || isExplicitAgentic) && config.agenticTiers != null;\n tierConfigs = useAgenticTiers ? config.agenticTiers! : config.tiers;\n profileSuffix = useAgenticTiers ? \" | agentic\" : \"\";\n }\n\n const agenticScoreValue = ruleResult.agenticScore;\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${profileSuffix}`,\n tierConfigs,\n modelPricing,\n estimatedTokens,\n maxOutputTokens,\n routingProfile,\n agenticScoreValue,\n );\n }\n\n // Structured output detection\n const hasStructuredOutput = systemPrompt ? /json|structured|schema/i.test(systemPrompt) : false;\n\n let tier: Tier;\n let confidence: number;\n const method: \"rules\" | \"llm\" = \"rules\";\n let reasoning = `score=${ruleResult.score.toFixed(2)} | ${ruleResult.signals.join(\", \")}`;\n\n if (ruleResult.tier !== null) {\n tier = ruleResult.tier;\n confidence = ruleResult.confidence;\n } else {\n // Ambiguous — default to configurable tier (no external API call)\n tier = config.overrides.ambiguousDefaultTier;\n confidence = 0.5;\n reasoning += ` | ambiguous -> default: ${tier}`;\n }\n\n // Apply structured output minimum tier\n if (hasStructuredOutput) {\n const tierRank: Record<Tier, number> = { SIMPLE: 0, MEDIUM: 1, COMPLEX: 2, REASONING: 3 };\n const minTier = config.overrides.structuredOutputMinTier;\n if (tierRank[tier] < tierRank[minTier]) {\n reasoning += ` | upgraded to ${minTier} (structured output)`;\n tier = minTier;\n }\n }\n\n // Add routing profile suffix to reasoning\n reasoning += profileSuffix;\n\n return selectModel(\n tier,\n confidence,\n method,\n reasoning,\n tierConfigs,\n modelPricing,\n estimatedTokens,\n maxOutputTokens,\n routingProfile,\n agenticScoreValue,\n );\n}\n\nexport {\n getFallbackChain,\n getFallbackChainFiltered,\n filterByToolCalling,\n filterByVision,\n calculateModelCost,\n} 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 * 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\n/**\n * Model aliases for convenient shorthand access.\n * Users can type `/model claude` instead of `/model blockrun/anthropic/claude-sonnet-4-6`.\n */\nexport const MODEL_ALIASES: Record<string, string> = {\n // Claude - use newest versions (4.6)\n claude: \"anthropic/claude-sonnet-4.6\",\n sonnet: \"anthropic/claude-sonnet-4.6\",\n \"sonnet-4\": \"anthropic/claude-sonnet-4.6\",\n \"sonnet-4.6\": \"anthropic/claude-sonnet-4.6\",\n \"sonnet-4-6\": \"anthropic/claude-sonnet-4.6\",\n opus: \"anthropic/claude-opus-4.6\",\n \"opus-4\": \"anthropic/claude-opus-4.6\",\n \"opus-4.6\": \"anthropic/claude-opus-4.6\",\n \"opus-4-6\": \"anthropic/claude-opus-4.6\",\n haiku: \"anthropic/claude-haiku-4.5\",\n // Claude - provider/shortname patterns (common in agent frameworks)\n \"anthropic/sonnet\": \"anthropic/claude-sonnet-4.6\",\n \"anthropic/opus\": \"anthropic/claude-opus-4.6\",\n \"anthropic/haiku\": \"anthropic/claude-haiku-4.5\",\n \"anthropic/claude\": \"anthropic/claude-sonnet-4.6\",\n // Backward compatibility - map all variants to 4.6\n \"anthropic/claude-sonnet-4\": \"anthropic/claude-sonnet-4.6\",\n \"anthropic/claude-sonnet-4-6\": \"anthropic/claude-sonnet-4.6\",\n \"anthropic/claude-opus-4\": \"anthropic/claude-opus-4.6\",\n \"anthropic/claude-opus-4-6\": \"anthropic/claude-opus-4.6\",\n \"anthropic/claude-opus-4.5\": \"anthropic/claude-opus-4.6\",\n \"anthropic/claude-haiku-4\": \"anthropic/claude-haiku-4.5\",\n \"anthropic/claude-haiku-4-5\": \"anthropic/claude-haiku-4.5\",\n\n // OpenAI\n gpt: \"openai/gpt-4o\",\n gpt4: \"openai/gpt-4o\",\n gpt5: \"openai/gpt-5.2\",\n codex: \"openai/gpt-5.2-codex\",\n mini: \"openai/gpt-4o-mini\",\n o1: \"openai/o1\",\n o3: \"openai/o3\",\n\n // DeepSeek\n deepseek: \"deepseek/deepseek-chat\",\n reasoner: \"deepseek/deepseek-reasoner\",\n\n // Kimi / Moonshot\n kimi: \"moonshot/kimi-k2.5\",\n moonshot: \"moonshot/kimi-k2.5\",\n \"kimi-k2.5\": \"moonshot/kimi-k2.5\",\n\n // Google\n gemini: \"google/gemini-2.5-pro\",\n flash: \"google/gemini-2.5-flash\",\n \"gemini-3.1-pro-preview\": \"google/gemini-3.1-pro\",\n \"google/gemini-3.1-pro-preview\": \"google/gemini-3.1-pro\",\n\n // xAI\n grok: \"xai/grok-3\",\n \"grok-fast\": \"xai/grok-4-fast-reasoning\",\n \"grok-code\": \"xai/grok-code-fast-1\",\n\n // NVIDIA\n nvidia: \"nvidia/gpt-oss-120b\",\n \"gpt-120b\": \"nvidia/gpt-oss-120b\",\n\n // MiniMax\n minimax: \"minimax/minimax-m2.5\",\n\n // Routing profile aliases (common variations)\n \"auto-router\": \"auto\",\n router: \"auto\",\n\n // Note: auto, free, eco, premium are virtual routing profiles registered in BLOCKRUN_MODELS\n // They don't need aliases since they're already top-level model IDs\n};\n\n/**\n * Resolve a model alias to its full model ID.\n * Also strips \"blockrun/\" prefix for direct model paths.\n * Examples:\n * - \"claude\" -> \"anthropic/claude-sonnet-4-6\" (alias)\n * - \"blockrun/claude\" -> \"anthropic/claude-sonnet-4-6\" (alias with prefix)\n * - \"blockrun/anthropic/claude-sonnet-4-6\" -> \"anthropic/claude-sonnet-4-6\" (prefix stripped)\n * - \"openai/gpt-4o\" -> \"openai/gpt-4o\" (unchanged)\n */\nexport function resolveModelAlias(model: string): string {\n const normalized = model.trim().toLowerCase();\n const resolved = MODEL_ALIASES[normalized];\n if (resolved) return resolved;\n\n // Check with \"blockrun/\" prefix stripped\n if (normalized.startsWith(\"blockrun/\")) {\n const withoutPrefix = normalized.slice(\"blockrun/\".length);\n const resolvedWithoutPrefix = MODEL_ALIASES[withoutPrefix];\n if (resolvedWithoutPrefix) return resolvedWithoutPrefix;\n\n // Even if not an alias, strip the prefix for direct model paths\n // e.g., \"blockrun/anthropic/claude-sonnet-4-6\" -> \"anthropic/claude-sonnet-4-6\"\n return withoutPrefix;\n }\n\n return model;\n}\n\ntype BlockRunModel = {\n id: string;\n name: string;\n /** Model version (e.g., \"4.6\", \"3.1\", \"5.2\") for tracking updates */\n version?: string;\n inputPrice: number;\n outputPrice: number;\n contextWindow: number;\n maxOutput: number;\n reasoning?: boolean;\n vision?: boolean;\n /** Models optimized for agentic workflows (multi-step autonomous tasks) */\n agentic?: boolean;\n /**\n * Model supports OpenAI-compatible structured function/tool calling.\n * Models without this flag output tool invocations as plain text JSON,\n * which leaks raw {\"command\":\"...\"} into visible chat messages.\n * Default: false (must opt-in to prevent silent regressions on new models).\n */\n toolCalling?: boolean;\n};\n\nexport const BLOCKRUN_MODELS: BlockRunModel[] = [\n // Smart routing meta-models — proxy replaces with actual model\n // NOTE: Model IDs are WITHOUT provider prefix (OpenClaw adds \"blockrun/\" automatically)\n {\n id: \"auto\",\n name: \"Auto (Smart Router - Balanced)\",\n inputPrice: 0,\n outputPrice: 0,\n contextWindow: 1_050_000,\n maxOutput: 128_000,\n },\n {\n id: \"free\",\n name: \"Free (NVIDIA GPT-OSS-120B only)\",\n inputPrice: 0,\n outputPrice: 0,\n contextWindow: 128_000,\n maxOutput: 4_096,\n },\n {\n id: \"eco\",\n name: \"Eco (Smart Router - Cost Optimized)\",\n inputPrice: 0,\n outputPrice: 0,\n contextWindow: 1_050_000,\n maxOutput: 128_000,\n },\n {\n id: \"premium\",\n name: \"Premium (Smart Router - Best Quality)\",\n inputPrice: 0,\n outputPrice: 0,\n contextWindow: 2_000_000,\n maxOutput: 200_000,\n },\n\n // OpenAI GPT-5 Family\n {\n id: \"openai/gpt-5.2\",\n name: \"GPT-5.2\",\n version: \"5.2\",\n inputPrice: 1.75,\n outputPrice: 14.0,\n contextWindow: 400000,\n maxOutput: 128000,\n reasoning: true,\n vision: true,\n agentic: true,\n toolCalling: true,\n },\n {\n id: \"openai/gpt-5-mini\",\n name: \"GPT-5 Mini\",\n version: \"5.0\",\n inputPrice: 0.25,\n outputPrice: 2.0,\n contextWindow: 200000,\n maxOutput: 65536,\n toolCalling: true,\n },\n {\n id: \"openai/gpt-5-nano\",\n name: \"GPT-5 Nano\",\n version: \"5.0\",\n inputPrice: 0.05,\n outputPrice: 0.4,\n contextWindow: 128000,\n maxOutput: 32768,\n toolCalling: true,\n },\n {\n id: \"openai/gpt-5.2-pro\",\n name: \"GPT-5.2 Pro\",\n version: \"5.2\",\n inputPrice: 21.0,\n outputPrice: 168.0,\n contextWindow: 400000,\n maxOutput: 128000,\n reasoning: true,\n toolCalling: true,\n },\n\n // OpenAI Codex Family\n {\n id: \"openai/gpt-5.2-codex\",\n name: \"GPT-5.2 Codex\",\n version: \"5.2\",\n inputPrice: 1.75,\n outputPrice: 14.0,\n contextWindow: 128000,\n maxOutput: 32000,\n agentic: true,\n toolCalling: true,\n },\n\n // OpenAI GPT-4 Family\n {\n id: \"openai/gpt-4.1\",\n name: \"GPT-4.1\",\n version: \"4.1\",\n inputPrice: 2.0,\n outputPrice: 8.0,\n contextWindow: 128000,\n maxOutput: 16384,\n vision: true,\n toolCalling: true,\n },\n {\n id: \"openai/gpt-4.1-mini\",\n name: \"GPT-4.1 Mini\",\n version: \"4.1\",\n inputPrice: 0.4,\n outputPrice: 1.6,\n contextWindow: 128000,\n maxOutput: 16384,\n toolCalling: true,\n },\n {\n id: \"openai/gpt-4.1-nano\",\n name: \"GPT-4.1 Nano\",\n version: \"4.1\",\n inputPrice: 0.1,\n outputPrice: 0.4,\n contextWindow: 128000,\n maxOutput: 16384,\n toolCalling: true,\n },\n {\n id: \"openai/gpt-4o\",\n name: \"GPT-4o\",\n version: \"4o\",\n inputPrice: 2.5,\n outputPrice: 10.0,\n contextWindow: 128000,\n maxOutput: 16384,\n vision: true,\n agentic: true,\n toolCalling: true,\n },\n {\n id: \"openai/gpt-4o-mini\",\n name: \"GPT-4o Mini\",\n version: \"4o-mini\",\n inputPrice: 0.15,\n outputPrice: 0.6,\n contextWindow: 128000,\n maxOutput: 16384,\n toolCalling: true,\n },\n\n // OpenAI O-series (Reasoning)\n {\n id: \"openai/o1\",\n name: \"o1\",\n version: \"1\",\n inputPrice: 15.0,\n outputPrice: 60.0,\n contextWindow: 200000,\n maxOutput: 100000,\n reasoning: true,\n toolCalling: true,\n },\n {\n id: \"openai/o1-mini\",\n name: \"o1-mini\",\n version: \"1-mini\",\n inputPrice: 1.1,\n outputPrice: 4.4,\n contextWindow: 128000,\n maxOutput: 65536,\n reasoning: true,\n toolCalling: true,\n },\n {\n id: \"openai/o3\",\n name: \"o3\",\n version: \"3\",\n inputPrice: 2.0,\n outputPrice: 8.0,\n contextWindow: 200000,\n maxOutput: 100000,\n reasoning: true,\n toolCalling: true,\n },\n {\n id: \"openai/o3-mini\",\n name: \"o3-mini\",\n version: \"3-mini\",\n inputPrice: 1.1,\n outputPrice: 4.4,\n contextWindow: 128000,\n maxOutput: 65536,\n reasoning: true,\n toolCalling: true,\n },\n {\n id: \"openai/o4-mini\",\n name: \"o4-mini\",\n version: \"4-mini\",\n inputPrice: 1.1,\n outputPrice: 4.4,\n contextWindow: 128000,\n maxOutput: 65536,\n reasoning: true,\n toolCalling: true,\n },\n\n // Anthropic - all Claude models excel at agentic workflows\n // Use newest versions (4.6) with full provider prefix\n {\n id: \"anthropic/claude-haiku-4.5\",\n name: \"Claude Haiku 4.5\",\n version: \"4.5\",\n inputPrice: 1.0,\n outputPrice: 5.0,\n contextWindow: 200000,\n maxOutput: 8192,\n vision: true,\n agentic: true,\n toolCalling: true,\n },\n {\n id: \"anthropic/claude-sonnet-4.6\",\n name: \"Claude Sonnet 4.6\",\n version: \"4.6\",\n inputPrice: 3.0,\n outputPrice: 15.0,\n contextWindow: 200000,\n maxOutput: 64000,\n reasoning: true,\n vision: true,\n agentic: true,\n toolCalling: true,\n },\n {\n id: \"anthropic/claude-opus-4.6\",\n name: \"Claude Opus 4.6\",\n version: \"4.6\",\n inputPrice: 5.0,\n outputPrice: 25.0,\n contextWindow: 200000,\n maxOutput: 32000,\n reasoning: true,\n vision: true,\n agentic: true,\n toolCalling: true,\n },\n\n // Google\n {\n id: \"google/gemini-3.1-pro\",\n name: \"Gemini 3.1 Pro\",\n version: \"3.1\",\n inputPrice: 2.0,\n outputPrice: 12.0,\n contextWindow: 1050000,\n maxOutput: 65536,\n reasoning: true,\n vision: true,\n toolCalling: true,\n },\n {\n id: \"google/gemini-3-pro-preview\",\n name: \"Gemini 3 Pro Preview\",\n version: \"3.0\",\n inputPrice: 2.0,\n outputPrice: 12.0,\n contextWindow: 1050000,\n maxOutput: 65536,\n reasoning: true,\n vision: true,\n toolCalling: true,\n },\n {\n id: \"google/gemini-3-flash-preview\",\n name: \"Gemini 3 Flash Preview\",\n version: \"3.0\",\n inputPrice: 0.5,\n outputPrice: 3.0,\n contextWindow: 1000000,\n maxOutput: 65536,\n vision: true,\n toolCalling: true,\n },\n {\n id: \"google/gemini-2.5-pro\",\n name: \"Gemini 2.5 Pro\",\n version: \"2.5\",\n inputPrice: 1.25,\n outputPrice: 10.0,\n contextWindow: 1050000,\n maxOutput: 65536,\n reasoning: true,\n vision: true,\n toolCalling: true,\n },\n {\n id: \"google/gemini-2.5-flash\",\n name: \"Gemini 2.5 Flash\",\n version: \"2.5\",\n inputPrice: 0.3,\n outputPrice: 2.5,\n contextWindow: 1000000,\n maxOutput: 65536,\n vision: true,\n toolCalling: true,\n },\n {\n id: \"google/gemini-2.5-flash-lite\",\n name: \"Gemini 2.5 Flash Lite\",\n version: \"2.5\",\n inputPrice: 0.1,\n outputPrice: 0.4,\n contextWindow: 1000000,\n maxOutput: 65536,\n toolCalling: true,\n },\n\n // DeepSeek\n {\n id: \"deepseek/deepseek-chat\",\n name: \"DeepSeek V3.2 Chat\",\n version: \"3.2\",\n inputPrice: 0.28,\n outputPrice: 0.42,\n contextWindow: 128000,\n maxOutput: 8192,\n toolCalling: true,\n },\n {\n id: \"deepseek/deepseek-reasoner\",\n name: \"DeepSeek V3.2 Reasoner\",\n version: \"3.2\",\n inputPrice: 0.28,\n outputPrice: 0.42,\n contextWindow: 128000,\n maxOutput: 8192,\n reasoning: true,\n toolCalling: true,\n },\n\n // Moonshot / Kimi - optimized for agentic workflows\n {\n id: \"moonshot/kimi-k2.5\",\n name: \"Kimi K2.5\",\n version: \"k2.5\",\n inputPrice: 0.6,\n outputPrice: 3.0,\n contextWindow: 262144,\n maxOutput: 8192,\n reasoning: true,\n vision: true,\n agentic: true,\n toolCalling: true,\n },\n\n // xAI / Grok\n {\n id: \"xai/grok-3\",\n name: \"Grok 3\",\n version: \"3\",\n inputPrice: 3.0,\n outputPrice: 15.0,\n contextWindow: 131072,\n maxOutput: 16384,\n reasoning: true,\n toolCalling: true,\n },\n // grok-3-fast removed - too expensive ($5/$25), use grok-4-fast instead\n {\n id: \"xai/grok-3-mini\",\n name: \"Grok 3 Mini\",\n version: \"3-mini\",\n inputPrice: 0.3,\n outputPrice: 0.5,\n contextWindow: 131072,\n maxOutput: 16384,\n toolCalling: true,\n },\n\n // xAI Grok 4 Family - Ultra-cheap fast models\n {\n id: \"xai/grok-4-fast-reasoning\",\n name: \"Grok 4 Fast Reasoning\",\n version: \"4\",\n inputPrice: 0.2,\n outputPrice: 0.5,\n contextWindow: 131072,\n maxOutput: 16384,\n reasoning: true,\n toolCalling: true,\n },\n {\n id: \"xai/grok-4-fast-non-reasoning\",\n name: \"Grok 4 Fast\",\n version: \"4\",\n inputPrice: 0.2,\n outputPrice: 0.5,\n contextWindow: 131072,\n maxOutput: 16384,\n toolCalling: true,\n },\n {\n id: \"xai/grok-4-1-fast-reasoning\",\n name: \"Grok 4.1 Fast Reasoning\",\n version: \"4.1\",\n inputPrice: 0.2,\n outputPrice: 0.5,\n contextWindow: 131072,\n maxOutput: 16384,\n reasoning: true,\n toolCalling: true,\n },\n {\n id: \"xai/grok-4-1-fast-non-reasoning\",\n name: \"Grok 4.1 Fast\",\n version: \"4.1\",\n inputPrice: 0.2,\n outputPrice: 0.5,\n contextWindow: 131072,\n maxOutput: 16384,\n toolCalling: true,\n },\n {\n id: \"xai/grok-code-fast-1\",\n name: \"Grok Code Fast\",\n version: \"1\",\n inputPrice: 0.2,\n outputPrice: 1.5,\n contextWindow: 131072,\n maxOutput: 16384,\n // toolCalling intentionally omitted: outputs tool calls as plain text JSON,\n // not OpenAI-compatible structured function calls. Will be skipped when\n // request has tools to prevent the \"talking to itself\" bug.\n },\n {\n id: \"xai/grok-4-0709\",\n name: \"Grok 4 (0709)\",\n version: \"4-0709\",\n inputPrice: 0.2,\n outputPrice: 1.5,\n contextWindow: 131072,\n maxOutput: 16384,\n reasoning: true,\n toolCalling: true,\n },\n {\n id: \"xai/grok-2-vision\",\n name: \"Grok 2 Vision\",\n version: \"2\",\n inputPrice: 2.0,\n outputPrice: 10.0,\n contextWindow: 131072,\n maxOutput: 16384,\n vision: true,\n toolCalling: true,\n },\n\n // MiniMax\n {\n id: \"minimax/minimax-m2.5\",\n name: \"MiniMax M2.5\",\n version: \"m2.5\",\n inputPrice: 0.3,\n outputPrice: 1.2,\n contextWindow: 204800,\n maxOutput: 16384,\n reasoning: true,\n agentic: true,\n toolCalling: true,\n },\n\n // NVIDIA - Free/cheap models\n {\n id: \"nvidia/gpt-oss-120b\",\n name: \"NVIDIA GPT-OSS 120B\",\n version: \"120b\",\n inputPrice: 0,\n outputPrice: 0,\n contextWindow: 128000,\n maxOutput: 16384,\n // toolCalling intentionally omitted: free model, structured function\n // calling support unverified. Excluded from tool-heavy routing paths.\n },\n {\n id: \"nvidia/kimi-k2.5\",\n name: \"NVIDIA Kimi K2.5\",\n version: \"k2.5\",\n inputPrice: 0.55,\n outputPrice: 2.5,\n contextWindow: 262144,\n maxOutput: 16384,\n toolCalling: true,\n },\n];\n\n/**\n * Convert BlockRun model definitions to OpenClaw ModelDefinitionConfig format.\n */\nfunction toOpenClawModel(m: BlockRunModel): ModelDefinitionConfig {\n return {\n id: m.id,\n name: m.name,\n api: \"openai-completions\",\n reasoning: m.reasoning ?? false,\n input: m.vision ? [\"text\", \"image\"] : [\"text\"],\n cost: {\n input: m.inputPrice,\n output: m.outputPrice,\n cacheRead: 0,\n cacheWrite: 0,\n },\n contextWindow: m.contextWindow,\n maxTokens: m.maxOutput,\n };\n}\n\n/**\n * Alias models that map to real models.\n * These allow users to use friendly names like \"free\" or \"gpt-120b\".\n */\nconst ALIAS_MODELS: ModelDefinitionConfig[] = Object.entries(MODEL_ALIASES)\n .map(([alias, targetId]) => {\n const target = BLOCKRUN_MODELS.find((m) => m.id === targetId);\n if (!target) return null;\n return toOpenClawModel({ ...target, id: alias, name: `${alias} → ${target.name}` });\n })\n .filter((m): m is ModelDefinitionConfig => m !== null);\n\n/**\n * All BlockRun models in OpenClaw format (including aliases).\n */\nexport const OPENCLAW_MODELS: ModelDefinitionConfig[] = [\n ...BLOCKRUN_MODELS.map(toOpenClawModel),\n ...ALIAS_MODELS,\n];\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/**\n * Check if a model is optimized for agentic workflows.\n * Agentic models continue autonomously with multi-step tasks\n * instead of stopping and waiting for user input.\n */\nexport function isAgenticModel(modelId: string): boolean {\n const model = BLOCKRUN_MODELS.find(\n (m) => m.id === modelId || m.id === modelId.replace(\"blockrun/\", \"\"),\n );\n return model?.agentic ?? false;\n}\n\n/**\n * Get all agentic-capable models.\n */\nexport function getAgenticModels(): string[] {\n return BLOCKRUN_MODELS.filter((m) => m.agentic).map((m) => m.id);\n}\n\n/**\n * Check if a model supports OpenAI-compatible structured tool/function calling.\n * Models without this flag (e.g. grok-code-fast-1) output tool invocations as\n * plain text JSON, which leaks {\"command\":\"...\"} into visible chat messages.\n */\nexport function supportsToolCalling(modelId: string): boolean {\n const normalized = modelId.replace(\"blockrun/\", \"\");\n const model = BLOCKRUN_MODELS.find((m) => m.id === normalized);\n return model?.toolCalling ?? false;\n}\n\n/**\n * Check if a model supports vision (image inputs).\n * Models without this flag cannot process image_url content parts.\n */\nexport function supportsVision(modelId: string): boolean {\n const normalized = modelId.replace(\"blockrun/\", \"\");\n const model = BLOCKRUN_MODELS.find((m) => m.id === normalized);\n return model?.vision ?? false;\n}\n\n/**\n * Get context window size for a model.\n * Returns undefined if model not found.\n */\nexport function getModelContextWindow(modelId: string): number | undefined {\n const normalized = modelId.replace(\"blockrun/\", \"\");\n const model = BLOCKRUN_MODELS.find((m) => m.id === normalized);\n return model?.contextWindow;\n}\n\n/**\n * Check if a model has reasoning/thinking capabilities.\n * Reasoning models may require reasoning_content in assistant tool_call messages.\n */\nexport function isReasoningModel(modelId: string): boolean {\n const normalized = modelId.replace(\"blockrun/\", \"\");\n const model = BLOCKRUN_MODELS.find((m) => m.id === normalized);\n return model?.reasoning ?? false;\n}\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 tier: string;\n cost: number;\n baselineCost: number;\n savings: number; // 0-1 percentage\n latencyMs: number;\n /** Partner service ID (e.g., \"x_users_lookup\") — only set for partner API calls */\n partnerId?: string;\n /** Partner service name (e.g., \"AttentionVC\") — only set for partner API calls */\n service?: string;\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 * Usage Statistics Aggregator\n *\n * Reads usage log files and aggregates statistics for terminal display.\n * Supports filtering by date range and provides multiple aggregation views.\n */\n\nimport { readdir } from \"node:fs/promises\";\nimport { readTextFile } from \"./fs-read.js\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport type { UsageEntry } from \"./logger.js\";\nimport { VERSION } from \"./version.js\";\n\nconst LOG_DIR = join(homedir(), \".openclaw\", \"blockrun\", \"logs\");\n\nexport type DailyStats = {\n date: string;\n totalRequests: number;\n totalCost: number;\n totalBaselineCost: number;\n totalSavings: number;\n avgLatencyMs: number;\n byTier: Record<string, { count: number; cost: number }>;\n byModel: Record<string, { count: number; cost: number }>;\n};\n\nexport type AggregatedStats = {\n period: string;\n totalRequests: number;\n totalCost: number;\n totalBaselineCost: number;\n totalSavings: number;\n savingsPercentage: number;\n avgLatencyMs: number;\n avgCostPerRequest: number;\n byTier: Record<string, { count: number; cost: number; percentage: number }>;\n byModel: Record<string, { count: number; cost: number; percentage: number }>;\n dailyBreakdown: DailyStats[];\n entriesWithBaseline: number; // Entries with valid baseline tracking\n};\n\n/**\n * Parse a JSONL log file into usage entries.\n * Handles both old format (without tier/baselineCost) and new format.\n */\nasync function parseLogFile(filePath: string): Promise<UsageEntry[]> {\n try {\n const content = await readTextFile(filePath);\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n return lines.map((line) => {\n const entry = JSON.parse(line) as Partial<UsageEntry>;\n // Handle old format entries\n return {\n timestamp: entry.timestamp || new Date().toISOString(),\n model: entry.model || \"unknown\",\n tier: entry.tier || \"UNKNOWN\",\n cost: entry.cost || 0,\n baselineCost: entry.baselineCost || entry.cost || 0,\n savings: entry.savings || 0,\n latencyMs: entry.latencyMs || 0,\n };\n });\n } catch {\n return [];\n }\n}\n\n/**\n * Get list of available log files sorted by date (newest first).\n */\nasync function getLogFiles(): Promise<string[]> {\n try {\n const files = await readdir(LOG_DIR);\n return files\n .filter((f) => f.startsWith(\"usage-\") && f.endsWith(\".jsonl\"))\n .sort()\n .reverse();\n } catch {\n return [];\n }\n}\n\n/**\n * Aggregate stats for a single day.\n */\nfunction aggregateDay(date: string, entries: UsageEntry[]): DailyStats {\n const byTier: Record<string, { count: number; cost: number }> = {};\n const byModel: Record<string, { count: number; cost: number }> = {};\n let totalLatency = 0;\n\n for (const entry of entries) {\n // By tier\n if (!byTier[entry.tier]) byTier[entry.tier] = { count: 0, cost: 0 };\n byTier[entry.tier].count++;\n byTier[entry.tier].cost += entry.cost;\n\n // By model\n if (!byModel[entry.model]) byModel[entry.model] = { count: 0, cost: 0 };\n byModel[entry.model].count++;\n byModel[entry.model].cost += entry.cost;\n\n totalLatency += entry.latencyMs;\n }\n\n const totalCost = entries.reduce((sum, e) => sum + e.cost, 0);\n const totalBaselineCost = entries.reduce((sum, e) => sum + e.baselineCost, 0);\n\n return {\n date,\n totalRequests: entries.length,\n totalCost,\n totalBaselineCost,\n totalSavings: totalBaselineCost - totalCost,\n avgLatencyMs: entries.length > 0 ? totalLatency / entries.length : 0,\n byTier,\n byModel,\n };\n}\n\n/**\n * Get aggregated statistics for the last N days.\n */\nexport async function getStats(days: number = 7): Promise<AggregatedStats> {\n const logFiles = await getLogFiles();\n const filesToRead = logFiles.slice(0, days);\n\n const dailyBreakdown: DailyStats[] = [];\n const allByTier: Record<string, { count: number; cost: number }> = {};\n const allByModel: Record<string, { count: number; cost: number }> = {};\n let totalRequests = 0;\n let totalCost = 0;\n let totalBaselineCost = 0;\n let totalLatency = 0;\n\n for (const file of filesToRead) {\n const date = file.replace(\"usage-\", \"\").replace(\".jsonl\", \"\");\n const filePath = join(LOG_DIR, file);\n const entries = await parseLogFile(filePath);\n\n if (entries.length === 0) continue;\n\n const dayStats = aggregateDay(date, entries);\n dailyBreakdown.push(dayStats);\n\n totalRequests += dayStats.totalRequests;\n totalCost += dayStats.totalCost;\n totalBaselineCost += dayStats.totalBaselineCost;\n totalLatency += dayStats.avgLatencyMs * dayStats.totalRequests;\n\n // Merge tier stats\n for (const [tier, stats] of Object.entries(dayStats.byTier)) {\n if (!allByTier[tier]) allByTier[tier] = { count: 0, cost: 0 };\n allByTier[tier].count += stats.count;\n allByTier[tier].cost += stats.cost;\n }\n\n // Merge model stats\n for (const [model, stats] of Object.entries(dayStats.byModel)) {\n if (!allByModel[model]) allByModel[model] = { count: 0, cost: 0 };\n allByModel[model].count += stats.count;\n allByModel[model].cost += stats.cost;\n }\n }\n\n // Calculate percentages\n const byTierWithPercentage: Record<string, { count: number; cost: number; percentage: number }> =\n {};\n for (const [tier, stats] of Object.entries(allByTier)) {\n byTierWithPercentage[tier] = {\n ...stats,\n percentage: totalRequests > 0 ? (stats.count / totalRequests) * 100 : 0,\n };\n }\n\n const byModelWithPercentage: Record<string, { count: number; cost: number; percentage: number }> =\n {};\n for (const [model, stats] of Object.entries(allByModel)) {\n byModelWithPercentage[model] = {\n ...stats,\n percentage: totalRequests > 0 ? (stats.count / totalRequests) * 100 : 0,\n };\n }\n\n const totalSavings = totalBaselineCost - totalCost;\n const savingsPercentage = totalBaselineCost > 0 ? (totalSavings / totalBaselineCost) * 100 : 0;\n\n // Count entries with valid baseline tracking (baseline != cost means tracking was active)\n let entriesWithBaseline = 0;\n for (const day of dailyBreakdown) {\n if (day.totalBaselineCost !== day.totalCost) {\n entriesWithBaseline += day.totalRequests;\n }\n }\n\n return {\n period: days === 1 ? \"today\" : `last ${days} days`,\n totalRequests,\n totalCost,\n totalBaselineCost,\n totalSavings,\n savingsPercentage,\n avgLatencyMs: totalRequests > 0 ? totalLatency / totalRequests : 0,\n avgCostPerRequest: totalRequests > 0 ? totalCost / totalRequests : 0,\n byTier: byTierWithPercentage,\n byModel: byModelWithPercentage,\n dailyBreakdown: dailyBreakdown.reverse(), // Oldest first for charts\n entriesWithBaseline, // How many entries have valid baseline tracking\n };\n}\n\n/**\n * Format stats as ASCII table for terminal display.\n */\nexport function formatStatsAscii(stats: AggregatedStats): string {\n const lines: string[] = [];\n\n // Header\n lines.push(\"╔════════════════════════════════════════════════════════════╗\");\n lines.push(`║ ClawRouter by BlockRun v${VERSION}`.padEnd(61) + \"║\");\n lines.push(\"║ Usage Statistics ║\");\n lines.push(\"╠════════════════════════════════════════════════════════════╣\");\n\n // Summary\n lines.push(`║ Period: ${stats.period.padEnd(49)}║`);\n lines.push(`║ Total Requests: ${stats.totalRequests.toString().padEnd(41)}║`);\n lines.push(`║ Total Cost: $${stats.totalCost.toFixed(4).padEnd(43)}║`);\n lines.push(`║ Baseline Cost (Opus 4.5): $${stats.totalBaselineCost.toFixed(4).padEnd(30)}║`);\n\n // Show savings with note if some entries lack baseline tracking\n const savingsLine = `║ 💰 Total Saved: $${stats.totalSavings.toFixed(4)} (${stats.savingsPercentage.toFixed(1)}%)`;\n if (stats.entriesWithBaseline < stats.totalRequests && stats.entriesWithBaseline > 0) {\n lines.push(savingsLine.padEnd(61) + \"║\");\n const note = `║ (based on ${stats.entriesWithBaseline}/${stats.totalRequests} tracked requests)`;\n lines.push(note.padEnd(61) + \"║\");\n } else {\n lines.push(savingsLine.padEnd(61) + \"║\");\n }\n lines.push(`║ Avg Latency: ${stats.avgLatencyMs.toFixed(0)}ms`.padEnd(61) + \"║\");\n\n // Tier breakdown\n lines.push(\"╠════════════════════════════════════════════════════════════╣\");\n lines.push(\"║ Routing by Tier: ║\");\n\n // Show all tiers found in data, ordered by known tiers first then others\n const knownTiers = [\"SIMPLE\", \"MEDIUM\", \"COMPLEX\", \"REASONING\", \"DIRECT\"];\n const allTiers = Object.keys(stats.byTier);\n const otherTiers = allTiers.filter((t) => !knownTiers.includes(t));\n const tierOrder = [...knownTiers.filter((t) => stats.byTier[t]), ...otherTiers];\n\n for (const tier of tierOrder) {\n const data = stats.byTier[tier];\n if (data) {\n const bar = \"█\".repeat(Math.min(20, Math.round(data.percentage / 5)));\n const displayTier = tier === \"UNKNOWN\" ? \"OTHER\" : tier;\n const line = `║ ${displayTier.padEnd(10)} ${bar.padEnd(20)} ${data.percentage.toFixed(1).padStart(5)}% (${data.count})`;\n lines.push(line.padEnd(61) + \"║\");\n }\n }\n\n // Top models\n lines.push(\"╠════════════════════════════════════════════════════════════╣\");\n lines.push(\"║ Top Models: ║\");\n\n const sortedModels = Object.entries(stats.byModel)\n .sort((a, b) => b[1].count - a[1].count)\n .slice(0, 5);\n\n for (const [model, data] of sortedModels) {\n const shortModel = model.length > 25 ? model.slice(0, 22) + \"...\" : model;\n const line = `║ ${shortModel.padEnd(25)} ${data.count.toString().padStart(5)} reqs $${data.cost.toFixed(4)}`;\n lines.push(line.padEnd(61) + \"║\");\n }\n\n // Daily breakdown (last 7 days)\n if (stats.dailyBreakdown.length > 0) {\n lines.push(\"╠════════════════════════════════════════════════════════════╣\");\n lines.push(\"║ Daily Breakdown: ║\");\n lines.push(\"║ Date Requests Cost Saved ║\");\n\n for (const day of stats.dailyBreakdown.slice(-7)) {\n const saved = day.totalBaselineCost - day.totalCost;\n const line = `║ ${day.date} ${day.totalRequests.toString().padStart(6)} $${day.totalCost.toFixed(4).padStart(8)} $${saved.toFixed(4)}`;\n lines.push(line.padEnd(61) + \"║\");\n }\n }\n\n lines.push(\"╚════════════════════════════════════════════════════════════╝\");\n\n return lines.join(\"\\n\");\n}\n","/**\n * Scanner-safe file reading utilities.\n *\n * Uses open() + read() to avoid false positives from openclaw's\n * potential-exfiltration heuristic in bundled output.\n */\n\nimport { open } from \"node:fs/promises\";\nimport { openSync, readSync, closeSync, fstatSync } from \"node:fs\";\n\n/** Read file contents as UTF-8 string (async). */\nexport async function readTextFile(filePath: string): Promise<string> {\n const fh = await open(filePath, \"r\");\n try {\n const buf = Buffer.alloc((await fh.stat()).size);\n await fh.read(buf, 0, buf.length, 0);\n return buf.toString(\"utf-8\");\n } finally {\n await fh.close();\n }\n}\n\n/** Read file contents as UTF-8 string (sync). */\nexport function readTextFileSync(filePath: string): string {\n const fd = openSync(filePath, \"r\");\n try {\n const buf = Buffer.alloc(fstatSync(fd).size);\n readSync(fd, buf);\n return buf.toString(\"utf-8\");\n } finally {\n closeSync(fd);\n }\n}\n","/**\n * Single source of truth for version.\n * Reads from package.json at build time via tsup's define.\n */\nimport { createRequire } from \"node:module\";\nimport { fileURLToPath } from \"node:url\";\nimport { dirname, join } from \"node:path\";\n\n// Read package.json at runtime\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n// In dist/, go up one level to find package.json\nconst require = createRequire(import.meta.url);\nconst pkg = require(join(__dirname, \"..\", \"package.json\")) as { version: string };\n\nexport const VERSION = pkg.version;\nexport const USER_AGENT = `clawrouter/${VERSION}`;\n","/**\n * Request Deduplication\n *\n * Prevents double-charging when OpenClaw retries a request after timeout.\n * Tracks in-flight requests and caches completed responses for a short TTL.\n */\n\nimport { createHash } from \"node:crypto\";\n\nexport type CachedResponse = {\n status: number;\n headers: Record<string, string>;\n body: Buffer;\n completedAt: number;\n};\n\ntype InflightEntry = {\n resolvers: Array<(result: CachedResponse) => void>;\n};\n\nconst DEFAULT_TTL_MS = 30_000; // 30 seconds\nconst MAX_BODY_SIZE = 1_048_576; // 1MB\n\n/**\n * Canonicalize JSON by sorting object keys recursively.\n * Ensures identical logical content produces identical string regardless of field order.\n */\nfunction canonicalize(obj: unknown): unknown {\n if (obj === null || typeof obj !== \"object\") {\n return obj;\n }\n if (Array.isArray(obj)) {\n return obj.map(canonicalize);\n }\n const sorted: Record<string, unknown> = {};\n for (const key of Object.keys(obj).sort()) {\n sorted[key] = canonicalize((obj as Record<string, unknown>)[key]);\n }\n return sorted;\n}\n\n/**\n * Strip OpenClaw-injected timestamps from message content.\n * Format: [DAY YYYY-MM-DD HH:MM TZ] at the start of messages.\n * Example: [SUN 2026-02-07 13:30 PST] Hello world\n *\n * This ensures requests with different timestamps but same content hash identically.\n */\nconst TIMESTAMP_PATTERN = /^\\[\\w{3}\\s+\\d{4}-\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}\\s+\\w+\\]\\s*/;\n\nfunction stripTimestamps(obj: unknown): unknown {\n if (obj === null || typeof obj !== \"object\") {\n return obj;\n }\n if (Array.isArray(obj)) {\n return obj.map(stripTimestamps);\n }\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n if (key === \"content\" && typeof value === \"string\") {\n // Strip timestamp prefix from message content\n result[key] = value.replace(TIMESTAMP_PATTERN, \"\");\n } else {\n result[key] = stripTimestamps(value);\n }\n }\n return result;\n}\n\nexport class RequestDeduplicator {\n private inflight = new Map<string, InflightEntry>();\n private completed = new Map<string, CachedResponse>();\n private ttlMs: number;\n\n constructor(ttlMs = DEFAULT_TTL_MS) {\n this.ttlMs = ttlMs;\n }\n\n /** Hash request body to create a dedup key. */\n static hash(body: Buffer): string {\n // Canonicalize JSON to ensure consistent hashing regardless of field order.\n // Also strip OpenClaw-injected timestamps so retries with different timestamps\n // still match the same dedup key.\n let content = body;\n try {\n const parsed = JSON.parse(body.toString());\n const stripped = stripTimestamps(parsed);\n const canonical = canonicalize(stripped);\n content = Buffer.from(JSON.stringify(canonical));\n } catch {\n // Not valid JSON, use raw bytes\n }\n return createHash(\"sha256\").update(content).digest(\"hex\").slice(0, 16);\n }\n\n /** Check if a response is cached for this key. */\n getCached(key: string): CachedResponse | undefined {\n const entry = this.completed.get(key);\n if (!entry) return undefined;\n if (Date.now() - entry.completedAt > this.ttlMs) {\n this.completed.delete(key);\n return undefined;\n }\n return entry;\n }\n\n /** Check if a request with this key is currently in-flight. Returns a promise to wait on. */\n getInflight(key: string): Promise<CachedResponse> | undefined {\n const entry = this.inflight.get(key);\n if (!entry) return undefined;\n return new Promise<CachedResponse>((resolve) => {\n entry.resolvers.push(resolve);\n });\n }\n\n /** Mark a request as in-flight. */\n markInflight(key: string): void {\n this.inflight.set(key, {\n resolvers: [],\n });\n }\n\n /** Complete an in-flight request — cache result and notify waiters. */\n complete(key: string, result: CachedResponse): void {\n // Only cache responses within size limit\n if (result.body.length <= MAX_BODY_SIZE) {\n this.completed.set(key, result);\n }\n\n const entry = this.inflight.get(key);\n if (entry) {\n for (const resolve of entry.resolvers) {\n resolve(result);\n }\n this.inflight.delete(key);\n }\n\n this.prune();\n }\n\n /** Remove an in-flight entry on error (don't cache failures).\n * Also rejects any waiters so they can retry independently. */\n removeInflight(key: string): void {\n const entry = this.inflight.get(key);\n if (entry) {\n // Resolve waiters with a sentinel error response so they don't hang forever.\n // Waiters will see a 503 and can retry on their own.\n const errorBody = Buffer.from(\n JSON.stringify({\n error: { message: \"Original request failed, please retry\", type: \"dedup_origin_failed\" },\n }),\n );\n for (const resolve of entry.resolvers) {\n resolve({\n status: 503,\n headers: { \"content-type\": \"application/json\" },\n body: errorBody,\n completedAt: Date.now(),\n });\n }\n this.inflight.delete(key);\n }\n }\n\n /** Prune expired completed entries. */\n private prune(): void {\n const now = Date.now();\n for (const [key, entry] of this.completed) {\n if (now - entry.completedAt > this.ttlMs) {\n this.completed.delete(key);\n }\n }\n }\n}\n","/**\n * Response Cache for LLM Completions\n *\n * Caches LLM responses by request hash (model + messages + params).\n * Inspired by LiteLLM's caching system. Returns cached responses for\n * identical requests, saving both cost and latency.\n *\n * Features:\n * - TTL-based expiration (default 10 minutes)\n * - LRU eviction when cache is full\n * - Size limits per item (1MB max)\n * - Heap-based expiration tracking for efficient pruning\n */\n\nimport { createHash } from \"node:crypto\";\n\nexport type CachedLLMResponse = {\n body: Buffer;\n status: number;\n headers: Record<string, string>;\n model: string;\n cachedAt: number;\n expiresAt: number;\n};\n\nexport type ResponseCacheConfig = {\n /** Maximum number of cached responses. Default: 200 */\n maxSize?: number;\n /** Default TTL in seconds. Default: 600 (10 minutes) */\n defaultTTL?: number;\n /** Maximum size per cached item in bytes. Default: 1MB */\n maxItemSize?: number;\n /** Enable/disable cache. Default: true */\n enabled?: boolean;\n};\n\nconst DEFAULT_CONFIG: Required<ResponseCacheConfig> = {\n maxSize: 200,\n defaultTTL: 600,\n maxItemSize: 1_048_576, // 1MB\n enabled: true,\n};\n\n/**\n * Canonicalize JSON by sorting object keys recursively.\n * Ensures identical logical content produces identical hash.\n */\nfunction canonicalize(obj: unknown): unknown {\n if (obj === null || typeof obj !== \"object\") {\n return obj;\n }\n if (Array.isArray(obj)) {\n return obj.map(canonicalize);\n }\n const sorted: Record<string, unknown> = {};\n for (const key of Object.keys(obj).sort()) {\n sorted[key] = canonicalize((obj as Record<string, unknown>)[key]);\n }\n return sorted;\n}\n\n/**\n * Strip fields that shouldn't affect cache key:\n * - stream (we handle streaming separately)\n * - timestamps injected by OpenClaw\n * - request IDs\n */\nconst TIMESTAMP_PATTERN = /^\\[\\w{3}\\s+\\d{4}-\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}\\s+\\w+\\]\\s*/;\n\nfunction normalizeForCache(obj: Record<string, unknown>): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n // Skip fields that don't affect response content\n if ([\"stream\", \"user\", \"request_id\", \"x-request-id\"].includes(key)) {\n continue;\n }\n\n if (key === \"messages\" && Array.isArray(value)) {\n // Strip timestamps from message content\n result[key] = value.map((msg: unknown) => {\n if (typeof msg === \"object\" && msg !== null) {\n const m = msg as Record<string, unknown>;\n if (typeof m.content === \"string\") {\n return { ...m, content: m.content.replace(TIMESTAMP_PATTERN, \"\") };\n }\n }\n return msg;\n });\n } else {\n result[key] = value;\n }\n }\n\n return result;\n}\n\nexport class ResponseCache {\n private cache = new Map<string, CachedLLMResponse>();\n private expirationHeap: Array<{ expiresAt: number; key: string }> = [];\n private config: Required<ResponseCacheConfig>;\n\n // Stats for monitoring\n private stats = {\n hits: 0,\n misses: 0,\n evictions: 0,\n };\n\n constructor(config: ResponseCacheConfig = {}) {\n // Filter out undefined values so they don't override defaults\n const filtered = Object.fromEntries(\n Object.entries(config).filter(([, v]) => v !== undefined),\n ) as ResponseCacheConfig;\n this.config = { ...DEFAULT_CONFIG, ...filtered };\n }\n\n /**\n * Generate cache key from request body.\n * Hashes: model + messages + temperature + max_tokens + other params\n */\n static generateKey(body: Buffer | string): string {\n try {\n const parsed = JSON.parse(typeof body === \"string\" ? body : body.toString());\n const normalized = normalizeForCache(parsed);\n const canonical = canonicalize(normalized);\n const keyContent = JSON.stringify(canonical);\n return createHash(\"sha256\").update(keyContent).digest(\"hex\").slice(0, 32);\n } catch {\n // Fallback: hash raw body\n const content = typeof body === \"string\" ? body : body.toString();\n return createHash(\"sha256\").update(content).digest(\"hex\").slice(0, 32);\n }\n }\n\n /**\n * Check if caching is enabled for this request.\n * Respects cache control headers and request params.\n */\n shouldCache(body: Buffer | string, headers?: Record<string, string>): boolean {\n if (!this.config.enabled) return false;\n\n // Respect Cache-Control: no-cache header\n if (headers?.[\"cache-control\"]?.includes(\"no-cache\")) {\n return false;\n }\n\n // Check for explicit cache disable in body\n try {\n const parsed = JSON.parse(typeof body === \"string\" ? body : body.toString());\n if (parsed.cache === false || parsed.no_cache === true) {\n return false;\n }\n } catch {\n // Not JSON, allow caching\n }\n\n return true;\n }\n\n /**\n * Get cached response if available and not expired.\n */\n get(key: string): CachedLLMResponse | undefined {\n const entry = this.cache.get(key);\n if (!entry) {\n this.stats.misses++;\n return undefined;\n }\n\n // Check expiration\n if (Date.now() > entry.expiresAt) {\n this.cache.delete(key);\n this.stats.misses++;\n return undefined;\n }\n\n this.stats.hits++;\n return entry;\n }\n\n /**\n * Cache a response with optional custom TTL.\n */\n set(\n key: string,\n response: {\n body: Buffer;\n status: number;\n headers: Record<string, string>;\n model: string;\n },\n ttlSeconds?: number,\n ): void {\n // Don't cache if disabled or maxSize is 0\n if (!this.config.enabled || this.config.maxSize <= 0) return;\n\n // Don't cache if item too large\n if (response.body.length > this.config.maxItemSize) {\n console.log(`[ResponseCache] Skipping cache - item too large: ${response.body.length} bytes`);\n return;\n }\n\n // Don't cache error responses\n if (response.status >= 400) {\n return;\n }\n\n // Evict if at capacity\n if (this.cache.size >= this.config.maxSize) {\n this.evict();\n }\n\n const now = Date.now();\n const ttl = ttlSeconds ?? this.config.defaultTTL;\n const expiresAt = now + ttl * 1000;\n\n const entry: CachedLLMResponse = {\n ...response,\n cachedAt: now,\n expiresAt,\n };\n\n this.cache.set(key, entry);\n this.expirationHeap.push({ expiresAt, key });\n }\n\n /**\n * Evict expired and oldest entries to make room.\n */\n private evict(): void {\n const now = Date.now();\n\n // First pass: remove expired entries\n this.expirationHeap.sort((a, b) => a.expiresAt - b.expiresAt);\n\n while (this.expirationHeap.length > 0) {\n const oldest = this.expirationHeap[0];\n\n // Check if entry still exists and matches\n const entry = this.cache.get(oldest.key);\n if (!entry || entry.expiresAt !== oldest.expiresAt) {\n // Stale heap entry, remove it\n this.expirationHeap.shift();\n continue;\n }\n\n if (oldest.expiresAt <= now) {\n // Expired, remove both\n this.cache.delete(oldest.key);\n this.expirationHeap.shift();\n this.stats.evictions++;\n } else {\n // Not expired, stop\n break;\n }\n }\n\n // Second pass: if still at capacity, evict oldest\n while (this.cache.size >= this.config.maxSize && this.expirationHeap.length > 0) {\n const oldest = this.expirationHeap.shift()!;\n if (this.cache.has(oldest.key)) {\n this.cache.delete(oldest.key);\n this.stats.evictions++;\n }\n }\n }\n\n /**\n * Get cache statistics.\n */\n getStats(): {\n size: number;\n maxSize: number;\n hits: number;\n misses: number;\n evictions: number;\n hitRate: string;\n } {\n const total = this.stats.hits + this.stats.misses;\n const hitRate = total > 0 ? ((this.stats.hits / total) * 100).toFixed(1) + \"%\" : \"0%\";\n\n return {\n size: this.cache.size,\n maxSize: this.config.maxSize,\n hits: this.stats.hits,\n misses: this.stats.misses,\n evictions: this.stats.evictions,\n hitRate,\n };\n }\n\n /**\n * Clear all cached entries.\n */\n clear(): void {\n this.cache.clear();\n this.expirationHeap = [];\n }\n\n /**\n * Check if cache is enabled.\n */\n isEnabled(): boolean {\n return this.config.enabled;\n }\n}\n","/**\n * Balance Monitor for ClawRouter\n *\n * Monitors USDC balance on Base network with intelligent caching.\n * Provides pre-request balance checks to prevent failed payments.\n *\n * Caching Strategy:\n * - TTL: 30 seconds (balance is cached to avoid excessive RPC calls)\n * - Optimistic deduction: after successful payment, subtract estimated cost from cache\n * - Invalidation: on payment failure, immediately refresh from RPC\n */\n\nimport { createPublicClient, http, erc20Abi } from \"viem\";\nimport { base } from \"viem/chains\";\nimport { RpcError } from \"./errors.js\";\n\n/** USDC contract address on Base mainnet */\nconst USDC_BASE = \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\" as const;\n\n/** Cache TTL in milliseconds (30 seconds) */\nconst CACHE_TTL_MS = 30_000;\n\n/** Balance thresholds in USDC smallest unit (6 decimals) */\nexport const BALANCE_THRESHOLDS = {\n /** Low balance warning threshold: $1.00 */\n LOW_BALANCE_MICROS: 1_000_000n,\n /** Effectively zero threshold: $0.0001 (covers dust/rounding) */\n ZERO_THRESHOLD: 100n,\n} as const;\n\n/** Balance information returned by checkBalance() */\nexport type BalanceInfo = {\n /** Raw balance in USDC smallest unit (6 decimals) */\n balance: bigint;\n /** Formatted balance as \"$X.XX\" */\n balanceUSD: string;\n /** True if balance < $1.00 */\n isLow: boolean;\n /** True if balance < $0.0001 (effectively zero) */\n isEmpty: boolean;\n /** Wallet address for funding instructions */\n walletAddress: string;\n};\n\n/** Result from checkSufficient() */\nexport type SufficiencyResult = {\n /** True if balance >= estimated cost */\n sufficient: boolean;\n /** Current balance info */\n info: BalanceInfo;\n /** If insufficient, the shortfall as \"$X.XX\" */\n shortfall?: string;\n};\n\n/**\n * Monitors USDC balance on Base network.\n *\n * Usage:\n * const monitor = new BalanceMonitor(\"0x...\");\n * const info = await monitor.checkBalance();\n * if (info.isLow) console.warn(\"Low balance!\");\n */\nexport class BalanceMonitor {\n private readonly client;\n private readonly walletAddress: `0x${string}`;\n\n /** Cached balance (null = not yet fetched) */\n private cachedBalance: bigint | null = null;\n /** Timestamp when cache was last updated */\n private cachedAt = 0;\n\n constructor(walletAddress: string) {\n this.walletAddress = walletAddress as `0x${string}`;\n this.client = createPublicClient({\n chain: base,\n transport: http(undefined, {\n timeout: 10_000, // 10 second timeout to prevent hanging on slow RPC\n }),\n });\n }\n\n /**\n * Check current USDC balance.\n * Uses cache if valid, otherwise fetches from RPC.\n */\n async checkBalance(): Promise<BalanceInfo> {\n const now = Date.now();\n\n // Use cache if valid\n if (this.cachedBalance !== null && now - this.cachedAt < CACHE_TTL_MS) {\n return this.buildInfo(this.cachedBalance);\n }\n\n // Fetch from RPC\n const balance = await this.fetchBalance();\n this.cachedBalance = balance;\n this.cachedAt = now;\n\n return this.buildInfo(balance);\n }\n\n /**\n * Check if balance is sufficient for an estimated cost.\n *\n * @param estimatedCostMicros - Estimated cost in USDC smallest unit (6 decimals)\n */\n async checkSufficient(estimatedCostMicros: bigint): Promise<SufficiencyResult> {\n const info = await this.checkBalance();\n\n if (info.balance >= estimatedCostMicros) {\n return { sufficient: true, info };\n }\n\n const shortfall = estimatedCostMicros - info.balance;\n return {\n sufficient: false,\n info,\n shortfall: this.formatUSDC(shortfall),\n };\n }\n\n /**\n * Optimistically deduct estimated cost from cached balance.\n * Call this after a successful payment to keep cache accurate.\n *\n * @param amountMicros - Amount to deduct in USDC smallest unit\n */\n deductEstimated(amountMicros: bigint): void {\n if (this.cachedBalance !== null && this.cachedBalance >= amountMicros) {\n this.cachedBalance -= amountMicros;\n }\n }\n\n /**\n * Invalidate cache, forcing next checkBalance() to fetch from RPC.\n * Call this after a payment failure to get accurate balance.\n */\n invalidate(): void {\n this.cachedBalance = null;\n this.cachedAt = 0;\n }\n\n /**\n * Force refresh balance from RPC (ignores cache).\n */\n async refresh(): Promise<BalanceInfo> {\n this.invalidate();\n return this.checkBalance();\n }\n\n /**\n * Format USDC amount (in micros) as \"$X.XX\".\n */\n formatUSDC(amountMicros: bigint): string {\n // USDC has 6 decimals\n const dollars = Number(amountMicros) / 1_000_000;\n return `$${dollars.toFixed(2)}`;\n }\n\n /**\n * Get the wallet address being monitored.\n */\n getWalletAddress(): string {\n return this.walletAddress;\n }\n\n /** Fetch balance from RPC */\n private async fetchBalance(): Promise<bigint> {\n try {\n const balance = await this.client.readContract({\n address: USDC_BASE,\n abi: erc20Abi,\n functionName: \"balanceOf\",\n args: [this.walletAddress],\n });\n return balance;\n } catch (error) {\n // Throw typed error instead of silently returning 0\n // This allows callers to distinguish \"node down\" from \"wallet empty\"\n throw new RpcError(error instanceof Error ? error.message : \"Unknown error\", error);\n }\n }\n\n /** Build BalanceInfo from raw balance */\n private buildInfo(balance: bigint): BalanceInfo {\n return {\n balance,\n balanceUSD: this.formatUSDC(balance),\n isLow: balance < BALANCE_THRESHOLDS.LOW_BALANCE_MICROS,\n isEmpty: balance < BALANCE_THRESHOLDS.ZERO_THRESHOLD,\n walletAddress: this.walletAddress,\n };\n }\n}\n","/**\n * Typed Error Classes for ClawRouter\n *\n * Provides structured errors for balance-related failures with\n * all necessary information for user-friendly error messages.\n */\n\n/**\n * Thrown when wallet has insufficient USDC balance for a request.\n */\nexport class InsufficientFundsError extends Error {\n readonly code = \"INSUFFICIENT_FUNDS\" as const;\n readonly currentBalanceUSD: string;\n readonly requiredUSD: string;\n readonly walletAddress: string;\n\n constructor(opts: { currentBalanceUSD: string; requiredUSD: string; walletAddress: string }) {\n const msg = [\n `Insufficient balance. Current: ${opts.currentBalanceUSD}, Required: ${opts.requiredUSD}`,\n `Options:`,\n ` 1. Fund wallet: ${opts.walletAddress}`,\n ` 2. Use free model: /model free`,\n ].join(\"\\n\");\n super(msg);\n this.name = \"InsufficientFundsError\";\n this.currentBalanceUSD = opts.currentBalanceUSD;\n this.requiredUSD = opts.requiredUSD;\n this.walletAddress = opts.walletAddress;\n }\n}\n\n/**\n * Thrown when wallet has no USDC balance (or effectively zero).\n */\nexport class EmptyWalletError extends Error {\n readonly code = \"EMPTY_WALLET\" as const;\n readonly walletAddress: string;\n\n constructor(walletAddress: string) {\n const msg = [\n `No USDC balance.`,\n `Options:`,\n ` 1. Fund wallet: ${walletAddress}`,\n ` 2. Use free model: /model free`,\n ` 3. Uninstall: bash ~/.openclaw/extensions/clawrouter/scripts/uninstall.sh`,\n ].join(\"\\n\");\n super(msg);\n this.name = \"EmptyWalletError\";\n this.walletAddress = walletAddress;\n }\n}\n\n/**\n * Type guard to check if an error is InsufficientFundsError.\n */\nexport function isInsufficientFundsError(error: unknown): error is InsufficientFundsError {\n return error instanceof Error && (error as InsufficientFundsError).code === \"INSUFFICIENT_FUNDS\";\n}\n\n/**\n * Type guard to check if an error is EmptyWalletError.\n */\nexport function isEmptyWalletError(error: unknown): error is EmptyWalletError {\n return error instanceof Error && (error as EmptyWalletError).code === \"EMPTY_WALLET\";\n}\n\n/**\n * Type guard to check if an error is a balance-related error.\n */\nexport function isBalanceError(error: unknown): error is InsufficientFundsError | EmptyWalletError {\n return isInsufficientFundsError(error) || isEmptyWalletError(error);\n}\n\n/**\n * Thrown when RPC call fails (network error, node down, etc).\n * Distinguishes infrastructure failures from actual empty wallets.\n */\nexport class RpcError extends Error {\n readonly code = \"RPC_ERROR\" as const;\n readonly originalError: unknown;\n\n constructor(message: string, originalError?: unknown) {\n super(`RPC error: ${message}. Check network connectivity.`);\n this.name = \"RpcError\";\n this.originalError = originalError;\n }\n}\n\n/**\n * Type guard to check if an error is RpcError.\n */\nexport function isRpcError(error: unknown): error is RpcError {\n return error instanceof Error && (error as RpcError).code === \"RPC_ERROR\";\n}\n","/**\n * LLM-Safe Context Compression Types\n *\n * Types for the 7-layer compression system that reduces token usage\n * while preserving semantic meaning for LLM queries.\n */\n\n// Content part for multimodal messages (images, etc.)\nexport interface ContentPart {\n type: \"text\" | \"image_url\";\n text?: string;\n image_url?: {\n url: string;\n detail?: \"low\" | \"high\" | \"auto\";\n };\n}\n\n// Normalized message structure (matches OpenAI format)\n// Note: content can be an array for multimodal messages (images, etc.)\nexport interface NormalizedMessage {\n role: \"system\" | \"user\" | \"assistant\" | \"tool\";\n content: string | ContentPart[] | null;\n tool_call_id?: string;\n tool_calls?: ToolCall[];\n name?: string;\n}\n\nexport interface ToolCall {\n id: string;\n type: \"function\";\n function: {\n name: string;\n arguments: string;\n };\n}\n\n// Compression configuration\nexport interface CompressionConfig {\n enabled: boolean;\n preserveRaw: boolean; // Keep original for logging\n\n // Per-layer toggles\n layers: {\n deduplication: boolean;\n whitespace: boolean;\n dictionary: boolean;\n paths: boolean;\n jsonCompact: boolean;\n observation: boolean; // L6: Compress tool results (BIG WIN)\n dynamicCodebook: boolean; // L7: Build codebook from content\n };\n\n // Dictionary settings\n dictionary: {\n maxEntries: number;\n minPhraseLength: number;\n includeCodebookHeader: boolean; // Include codebook in system message\n };\n}\n\n// Compression statistics\nexport interface CompressionStats {\n duplicatesRemoved: number;\n whitespaceSavedChars: number;\n dictionarySubstitutions: number;\n pathsShortened: number;\n jsonCompactedChars: number;\n observationsCompressed: number; // L6: Tool results compressed\n observationCharsSaved: number; // L6: Chars saved from observations\n dynamicSubstitutions: number; // L7: Dynamic codebook substitutions\n dynamicCharsSaved: number; // L7: Chars saved from dynamic codebook\n}\n\n// Result from compression\nexport interface CompressionResult {\n messages: NormalizedMessage[];\n originalMessages: NormalizedMessage[]; // For logging\n\n // Token estimates\n originalChars: number;\n compressedChars: number;\n compressionRatio: number; // 0.85 = 15% reduction\n\n // Per-layer stats\n stats: CompressionStats;\n\n // Codebook used (for decompression in logs)\n codebook: Record<string, string>;\n pathMap: Record<string, string>;\n dynamicCodes: Record<string, string>; // L7: Dynamic codebook\n}\n\n// Log data extension for compression metrics\nexport interface CompressionLogData {\n enabled: boolean;\n ratio: number;\n original_chars: number;\n compressed_chars: number;\n stats: {\n duplicates_removed: number;\n whitespace_saved: number;\n dictionary_subs: number;\n paths_shortened: number;\n json_compacted: number;\n };\n}\n\n// Default configuration - CONSERVATIVE settings for model compatibility\n// Only enable layers that don't require the model to decode anything\nexport const DEFAULT_COMPRESSION_CONFIG: CompressionConfig = {\n enabled: true,\n preserveRaw: true,\n layers: {\n deduplication: true, // Safe: removes duplicate messages\n whitespace: true, // Safe: normalizes whitespace\n dictionary: false, // DISABLED: requires model to understand codebook\n paths: false, // DISABLED: requires model to understand path codes\n jsonCompact: true, // Safe: just removes JSON whitespace\n observation: false, // DISABLED: may lose important context\n dynamicCodebook: false, // DISABLED: requires model to understand codes\n },\n dictionary: {\n maxEntries: 50,\n minPhraseLength: 15,\n includeCodebookHeader: false, // No codebook header needed\n },\n};\n","/**\n * Layer 1: Message Deduplication\n *\n * Removes exact duplicate messages from conversation history.\n * Common in heartbeat patterns and repeated tool calls.\n *\n * Safe for LLM: Identical messages add no new information.\n * Expected savings: 2-5%\n */\n\nimport { NormalizedMessage } from \"../types\";\nimport crypto from \"crypto\";\n\nexport interface DeduplicationResult {\n messages: NormalizedMessage[];\n duplicatesRemoved: number;\n originalCount: number;\n}\n\n/**\n * Generate a hash for a message based on its semantic content.\n * Uses role + content + tool_call_id to identify duplicates.\n */\nfunction hashMessage(message: NormalizedMessage): string {\n // Handle content - stringify arrays (multimodal), use string directly, or empty string\n let contentStr = \"\";\n if (typeof message.content === \"string\") {\n contentStr = message.content;\n } else if (Array.isArray(message.content)) {\n contentStr = JSON.stringify(message.content);\n }\n\n const parts = [message.role, contentStr, message.tool_call_id || \"\", message.name || \"\"];\n\n // Include tool_calls if present\n if (message.tool_calls) {\n parts.push(\n JSON.stringify(\n message.tool_calls.map((tc) => ({\n name: tc.function.name,\n args: tc.function.arguments,\n })),\n ),\n );\n }\n\n const content = parts.join(\"|\");\n return crypto.createHash(\"md5\").update(content).digest(\"hex\");\n}\n\n/**\n * Remove exact duplicate messages from the conversation.\n *\n * Strategy:\n * - Keep first occurrence of each unique message\n * - Preserve order for semantic coherence\n * - Never dedupe system messages (they set context)\n * - Allow duplicate user messages (user might repeat intentionally)\n * - CRITICAL: Never dedupe assistant messages with tool_calls that are\n * referenced by subsequent tool messages (breaks Anthropic tool_use/tool_result pairing)\n */\nexport function deduplicateMessages(messages: NormalizedMessage[]): DeduplicationResult {\n const seen = new Set<string>();\n const result: NormalizedMessage[] = [];\n let duplicatesRemoved = 0;\n\n // First pass: collect all tool_call_ids that are referenced by tool messages\n // These tool_calls MUST be preserved to maintain tool_use/tool_result pairing\n const referencedToolCallIds = new Set<string>();\n for (const message of messages) {\n if (message.role === \"tool\" && message.tool_call_id) {\n referencedToolCallIds.add(message.tool_call_id);\n }\n }\n\n for (const message of messages) {\n // Always keep system messages (they set important context)\n if (message.role === \"system\") {\n result.push(message);\n continue;\n }\n\n // Always keep user messages (user might repeat intentionally)\n if (message.role === \"user\") {\n result.push(message);\n continue;\n }\n\n // Always keep tool messages (they are results of tool calls)\n // Removing them would break the tool_use/tool_result pairing\n if (message.role === \"tool\") {\n result.push(message);\n continue;\n }\n\n // For assistant messages with tool_calls, check if any are referenced\n // by subsequent tool messages - if so, we MUST keep this message\n if (message.role === \"assistant\" && message.tool_calls) {\n const hasReferencedToolCall = message.tool_calls.some((tc) =>\n referencedToolCallIds.has(tc.id),\n );\n if (hasReferencedToolCall) {\n // This assistant message has tool_calls that are referenced - keep it\n result.push(message);\n continue;\n }\n }\n\n // For other assistant messages, check for duplicates\n const hash = hashMessage(message);\n\n if (!seen.has(hash)) {\n seen.add(hash);\n result.push(message);\n } else {\n duplicatesRemoved++;\n }\n }\n\n return {\n messages: result,\n duplicatesRemoved,\n originalCount: messages.length,\n };\n}\n","/**\n * Layer 2: Whitespace Normalization\n *\n * Reduces excessive whitespace without changing semantic meaning.\n *\n * Safe for LLM: Tokenizers normalize whitespace anyway.\n * Expected savings: 3-8%\n */\n\nimport { NormalizedMessage } from \"../types\";\n\nexport interface WhitespaceResult {\n messages: NormalizedMessage[];\n charsSaved: number;\n}\n\n/**\n * Normalize whitespace in a string.\n *\n * - Max 2 consecutive newlines\n * - Remove trailing whitespace from lines\n * - Normalize tabs to spaces\n * - Trim start/end\n */\nexport function normalizeWhitespace(content: string): string {\n // Defensive type check - content might be array/object for multimodal messages\n if (!content || typeof content !== \"string\") return content as string;\n\n return (\n content\n // Normalize line endings\n .replace(/\\r\\n/g, \"\\n\")\n .replace(/\\r/g, \"\\n\")\n // Max 2 consecutive newlines (preserve paragraph breaks)\n .replace(/\\n{3,}/g, \"\\n\\n\")\n // Remove trailing whitespace from each line\n .replace(/[ \\t]+$/gm, \"\")\n // Normalize multiple spaces to single (except at line start for indentation)\n .replace(/([^\\n]) {2,}/g, \"$1 \")\n // Reduce excessive indentation (more than 8 spaces → 2 spaces per level)\n .replace(/^[ ]{8,}/gm, (match) => \" \".repeat(Math.ceil(match.length / 4)))\n // Normalize tabs to 2 spaces\n .replace(/\\t/g, \" \")\n // Trim\n .trim()\n );\n}\n\n/**\n * Apply whitespace normalization to all messages.\n */\nexport function normalizeMessagesWhitespace(messages: NormalizedMessage[]): WhitespaceResult {\n let charsSaved = 0;\n\n const result = messages.map((message) => {\n // Only process string content (skip arrays for multimodal messages)\n if (!message.content || typeof message.content !== \"string\") return message;\n\n const originalLength = message.content.length;\n const normalizedContent = normalizeWhitespace(message.content);\n charsSaved += originalLength - normalizedContent.length;\n\n return {\n ...message,\n content: normalizedContent,\n };\n });\n\n return {\n messages: result,\n charsSaved,\n };\n}\n","/**\n * Dictionary Codebook\n *\n * Static dictionary of frequently repeated phrases observed in LLM prompts.\n * Built from analysis of BlockRun production logs.\n *\n * Format: Short code ($XX) -> Long phrase\n * The LLM receives a codebook header and decodes in-context.\n */\n\n// Static codebook - common patterns from system prompts\n// Ordered by expected frequency and impact\nexport const STATIC_CODEBOOK: Record<string, string> = {\n // High-impact: OpenClaw/Agent system prompt patterns (very common)\n $OC01: \"unbrowse_\", // Common prefix in tool names\n $OC02: \"<location>\",\n $OC03: \"</location>\",\n $OC04: \"<name>\",\n $OC05: \"</name>\",\n $OC06: \"<description>\",\n $OC07: \"</description>\",\n $OC08: \"(may need login)\",\n $OC09: \"API skill for OpenClaw\",\n $OC10: \"endpoints\",\n\n // Skill/tool markers\n $SK01: \"<available_skills>\",\n $SK02: \"</available_skills>\",\n $SK03: \"<skill>\",\n $SK04: \"</skill>\",\n\n // Schema patterns (very common in tool definitions)\n $T01: 'type: \"function\"',\n $T02: '\"type\": \"function\"',\n $T03: '\"type\": \"string\"',\n $T04: '\"type\": \"object\"',\n $T05: '\"type\": \"array\"',\n $T06: '\"type\": \"boolean\"',\n $T07: '\"type\": \"number\"',\n\n // Common descriptions\n $D01: \"description:\",\n $D02: '\"description\":',\n\n // Common instructions\n $I01: \"You are a personal assistant\",\n $I02: \"Tool names are case-sensitive\",\n $I03: \"Call tools exactly as listed\",\n $I04: \"Use when\",\n $I05: \"without asking\",\n\n // Safety phrases\n $S01: \"Do not manipulate or persuade\",\n $S02: \"Prioritize safety and human oversight\",\n $S03: \"unless explicitly requested\",\n\n // JSON patterns\n $J01: '\"required\": [\"',\n $J02: '\"properties\": {',\n $J03: '\"additionalProperties\": false',\n\n // Heartbeat patterns\n $H01: \"HEARTBEAT_OK\",\n $H02: \"Read HEARTBEAT.md if it exists\",\n\n // Role markers\n $R01: '\"role\": \"system\"',\n $R02: '\"role\": \"user\"',\n $R03: '\"role\": \"assistant\"',\n $R04: '\"role\": \"tool\"',\n\n // Common endings/phrases\n $E01: \"would you like to\",\n $E02: \"Let me know if you\",\n $E03: \"internal APIs\",\n $E04: \"session cookies\",\n\n // BlockRun model aliases (common in prompts)\n $M01: \"blockrun/\",\n $M02: \"openai/\",\n $M03: \"anthropic/\",\n $M04: \"google/\",\n $M05: \"xai/\",\n};\n\n/**\n * Get the inverse codebook for decompression.\n */\nexport function getInverseCodebook(): Record<string, string> {\n const inverse: Record<string, string> = {};\n for (const [code, phrase] of Object.entries(STATIC_CODEBOOK)) {\n inverse[phrase] = code;\n }\n return inverse;\n}\n\n/**\n * Generate the codebook header for inclusion in system message.\n * LLMs can decode in-context using this header.\n */\nexport function generateCodebookHeader(\n usedCodes: Set<string>,\n pathMap: Record<string, string> = {},\n): string {\n if (usedCodes.size === 0 && Object.keys(pathMap).length === 0) {\n return \"\";\n }\n\n const parts: string[] = [];\n\n // Add used dictionary codes\n if (usedCodes.size > 0) {\n const codeEntries = Array.from(usedCodes)\n .map((code) => `${code}=${STATIC_CODEBOOK[code]}`)\n .join(\", \");\n parts.push(`[Dict: ${codeEntries}]`);\n }\n\n // Add path map\n if (Object.keys(pathMap).length > 0) {\n const pathEntries = Object.entries(pathMap)\n .map(([code, path]) => `${code}=${path}`)\n .join(\", \");\n parts.push(`[Paths: ${pathEntries}]`);\n }\n\n return parts.join(\"\\n\");\n}\n\n/**\n * Decompress a string using the codebook (for logging).\n */\nexport function decompressContent(\n content: string,\n codebook: Record<string, string> = STATIC_CODEBOOK,\n): string {\n let result = content;\n for (const [code, phrase] of Object.entries(codebook)) {\n result = result.split(code).join(phrase);\n }\n return result;\n}\n","/**\n * Layer 3: Dictionary Encoding\n *\n * Replaces frequently repeated long phrases with short codes.\n * Uses a static codebook of common patterns from production logs.\n *\n * Safe for LLM: Reversible substitution with codebook header.\n * Expected savings: 4-8%\n */\n\nimport { NormalizedMessage } from \"../types\";\nimport { getInverseCodebook } from \"../codebook\";\n\nexport interface DictionaryResult {\n messages: NormalizedMessage[];\n substitutionCount: number;\n usedCodes: Set<string>;\n charsSaved: number;\n}\n\n/**\n * Apply dictionary encoding to a string.\n * Returns the encoded string and stats.\n */\nfunction encodeContent(\n content: string,\n inverseCodebook: Record<string, string>,\n): { encoded: string; substitutions: number; codes: Set<string>; charsSaved: number } {\n // Defensive type check - content might be array/object for multimodal messages\n if (!content || typeof content !== \"string\") {\n return { encoded: content, substitutions: 0, codes: new Set(), charsSaved: 0 };\n }\n let encoded = content;\n let substitutions = 0;\n let charsSaved = 0;\n const codes = new Set<string>();\n\n // Sort phrases by length (longest first) to avoid partial matches\n const phrases = Object.keys(inverseCodebook).sort((a, b) => b.length - a.length);\n\n for (const phrase of phrases) {\n const code = inverseCodebook[phrase];\n const regex = new RegExp(escapeRegex(phrase), \"g\");\n const matches = encoded.match(regex);\n\n if (matches && matches.length > 0) {\n encoded = encoded.replace(regex, code);\n substitutions += matches.length;\n charsSaved += matches.length * (phrase.length - code.length);\n codes.add(code);\n }\n }\n\n return { encoded, substitutions, codes, charsSaved };\n}\n\n/**\n * Escape special regex characters in a string.\n */\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/**\n * Apply dictionary encoding to all messages.\n */\nexport function encodeMessages(messages: NormalizedMessage[]): DictionaryResult {\n const inverseCodebook = getInverseCodebook();\n let totalSubstitutions = 0;\n let totalCharsSaved = 0;\n const allUsedCodes = new Set<string>();\n\n const result = messages.map((message) => {\n // Only process string content (skip arrays for multimodal messages)\n if (!message.content || typeof message.content !== \"string\") return message;\n\n const { encoded, substitutions, codes, charsSaved } = encodeContent(\n message.content,\n inverseCodebook,\n );\n\n totalSubstitutions += substitutions;\n totalCharsSaved += charsSaved;\n codes.forEach((code) => allUsedCodes.add(code));\n\n return {\n ...message,\n content: encoded,\n };\n });\n\n return {\n messages: result,\n substitutionCount: totalSubstitutions,\n usedCodes: allUsedCodes,\n charsSaved: totalCharsSaved,\n };\n}\n","/**\n * Layer 4: Path Shortening\n *\n * Detects common filesystem path prefixes and replaces them with short codes.\n * Common in coding assistant contexts with repeated file paths.\n *\n * Safe for LLM: Lossless abbreviation with path map header.\n * Expected savings: 1-3%\n */\n\nimport { NormalizedMessage } from \"../types\";\n\nexport interface PathShorteningResult {\n messages: NormalizedMessage[];\n pathMap: Record<string, string>; // $P1 -> /home/user/project/\n charsSaved: number;\n}\n\n// Regex to match filesystem paths\nconst PATH_REGEX = /(?:\\/[\\w.-]+){3,}/g;\n\n/**\n * Extract all paths from messages and find common prefixes.\n */\nfunction extractPaths(messages: NormalizedMessage[]): string[] {\n const paths: string[] = [];\n\n for (const message of messages) {\n // Only process string content (skip arrays for multimodal messages)\n if (!message.content || typeof message.content !== \"string\") continue;\n const matches = message.content.match(PATH_REGEX);\n if (matches) {\n paths.push(...matches);\n }\n }\n\n return paths;\n}\n\n/**\n * Group paths by their common prefixes.\n * Returns prefixes that appear at least 3 times.\n */\nfunction findFrequentPrefixes(paths: string[]): string[] {\n const prefixCounts = new Map<string, number>();\n\n for (const path of paths) {\n const parts = path.split(\"/\").filter(Boolean);\n\n // Try prefixes of different lengths\n for (let i = 2; i < parts.length; i++) {\n const prefix = \"/\" + parts.slice(0, i).join(\"/\") + \"/\";\n prefixCounts.set(prefix, (prefixCounts.get(prefix) || 0) + 1);\n }\n }\n\n // Return prefixes that appear 3+ times, sorted by length (longest first)\n return Array.from(prefixCounts.entries())\n .filter(([, count]) => count >= 3)\n .sort((a, b) => b[0].length - a[0].length)\n .slice(0, 5) // Max 5 path codes\n .map(([prefix]) => prefix);\n}\n\n/**\n * Apply path shortening to all messages.\n */\nexport function shortenPaths(messages: NormalizedMessage[]): PathShorteningResult {\n const allPaths = extractPaths(messages);\n\n if (allPaths.length < 5) {\n // Not enough paths to benefit from shortening\n return {\n messages,\n pathMap: {},\n charsSaved: 0,\n };\n }\n\n const prefixes = findFrequentPrefixes(allPaths);\n\n if (prefixes.length === 0) {\n return {\n messages,\n pathMap: {},\n charsSaved: 0,\n };\n }\n\n // Create path map\n const pathMap: Record<string, string> = {};\n prefixes.forEach((prefix, i) => {\n pathMap[`$P${i + 1}`] = prefix;\n });\n\n // Replace paths in messages\n let charsSaved = 0;\n\n const result = messages.map((message) => {\n // Only process string content (skip arrays for multimodal messages)\n if (!message.content || typeof message.content !== \"string\") return message;\n\n let content = message.content;\n const originalLength = content.length;\n\n // Replace prefixes (longest first to avoid partial replacements)\n for (const [code, prefix] of Object.entries(pathMap)) {\n content = content.split(prefix).join(code + \"/\");\n }\n\n charsSaved += originalLength - content.length;\n\n return {\n ...message,\n content,\n };\n });\n\n return {\n messages: result,\n pathMap,\n charsSaved,\n };\n}\n\n/**\n * Generate the path map header for the codebook.\n */\nexport function generatePathMapHeader(pathMap: Record<string, string>): string {\n if (Object.keys(pathMap).length === 0) return \"\";\n\n const entries = Object.entries(pathMap)\n .map(([code, path]) => `${code}=${path}`)\n .join(\", \");\n\n return `[Paths: ${entries}]`;\n}\n","/**\n * Layer 5: JSON Compaction\n *\n * Minifies JSON in tool_call arguments and tool results.\n * Removes pretty-print whitespace from JSON strings.\n *\n * Safe for LLM: JSON semantics unchanged.\n * Expected savings: 2-4%\n */\n\nimport { NormalizedMessage, ToolCall } from \"../types\";\n\nexport interface JsonCompactResult {\n messages: NormalizedMessage[];\n charsSaved: number;\n}\n\n/**\n * Compact a JSON string by parsing and re-stringifying without formatting.\n */\nfunction compactJson(jsonString: string): string {\n try {\n const parsed = JSON.parse(jsonString);\n return JSON.stringify(parsed);\n } catch {\n // Not valid JSON, return as-is\n return jsonString;\n }\n}\n\n/**\n * Check if a string looks like JSON (starts with { or [).\n */\nfunction looksLikeJson(str: string): boolean {\n const trimmed = str.trim();\n return (\n (trimmed.startsWith(\"{\") && trimmed.endsWith(\"}\")) ||\n (trimmed.startsWith(\"[\") && trimmed.endsWith(\"]\"))\n );\n}\n\n/**\n * Compact tool_call arguments in a message.\n */\nfunction compactToolCalls(toolCalls: ToolCall[]): ToolCall[] {\n return toolCalls.map((tc) => ({\n ...tc,\n function: {\n ...tc.function,\n arguments: compactJson(tc.function.arguments),\n },\n }));\n}\n\n/**\n * Apply JSON compaction to all messages.\n *\n * Targets:\n * - tool_call arguments (in assistant messages)\n * - tool message content (often JSON)\n */\nexport function compactMessagesJson(messages: NormalizedMessage[]): JsonCompactResult {\n let charsSaved = 0;\n\n const result = messages.map((message) => {\n const newMessage = { ...message };\n\n // Compact tool_calls arguments\n if (message.tool_calls && message.tool_calls.length > 0) {\n const originalLength = JSON.stringify(message.tool_calls).length;\n newMessage.tool_calls = compactToolCalls(message.tool_calls);\n const newLength = JSON.stringify(newMessage.tool_calls).length;\n charsSaved += originalLength - newLength;\n }\n\n // Compact tool message content if it looks like JSON\n // Only process string content (skip arrays for multimodal messages)\n if (\n message.role === \"tool\" &&\n message.content &&\n typeof message.content === \"string\" &&\n looksLikeJson(message.content)\n ) {\n const originalLength = message.content.length;\n const compacted = compactJson(message.content);\n charsSaved += originalLength - compacted.length;\n newMessage.content = compacted;\n }\n\n return newMessage;\n });\n\n return {\n messages: result,\n charsSaved,\n };\n}\n","/**\n * L6: Observation Compression (AGGRESSIVE)\n *\n * Inspired by claw-compactor's 97% compression on tool results.\n * Tool call results (especially large ones) are summarized to key info only.\n *\n * This is the biggest compression win - tool outputs can be 10KB+ but\n * only ~200 chars of actual useful information.\n */\n\nimport { NormalizedMessage } from \"../types\";\n\ninterface ObservationResult {\n messages: NormalizedMessage[];\n charsSaved: number;\n observationsCompressed: number;\n}\n\n// Max length for tool results before compression kicks in\nconst TOOL_RESULT_THRESHOLD = 500;\n\n// Max length to compress tool results down to\nconst COMPRESSED_RESULT_MAX = 300;\n\n/**\n * Extract key information from tool result.\n * Keeps: errors, key values, status, first/last important lines.\n */\nfunction compressToolResult(content: string): string {\n if (!content || content.length <= TOOL_RESULT_THRESHOLD) {\n return content;\n }\n\n const lines = content\n .split(\"\\n\")\n .map((l) => l.trim())\n .filter(Boolean);\n\n // Priority 1: Error messages (always keep)\n const errorLines = lines.filter(\n (l) => /error|exception|failed|denied|refused|timeout|invalid/i.test(l) && l.length < 200,\n );\n\n // Priority 2: Status/result lines\n const statusLines = lines.filter(\n (l) =>\n /success|complete|created|updated|found|result|status|total|count/i.test(l) && l.length < 150,\n );\n\n // Priority 3: Key JSON fields (extract important values)\n const jsonMatches: string[] = [];\n const jsonPattern = /\"(id|name|status|error|message|count|total|url|path)\":\\s*\"?([^\",}\\n]+)\"?/gi;\n let match;\n while ((match = jsonPattern.exec(content)) !== null) {\n jsonMatches.push(`${match[1]}: ${match[2].slice(0, 50)}`);\n }\n\n // Priority 4: First and last meaningful lines\n const firstLine = lines[0]?.slice(0, 100);\n const lastLine = lines.length > 1 ? lines[lines.length - 1]?.slice(0, 100) : \"\";\n\n // Build compressed observation\n const parts: string[] = [];\n\n if (errorLines.length > 0) {\n parts.push(\"[ERR] \" + errorLines.slice(0, 3).join(\" | \"));\n }\n\n if (statusLines.length > 0) {\n parts.push(statusLines.slice(0, 3).join(\" | \"));\n }\n\n if (jsonMatches.length > 0) {\n parts.push(jsonMatches.slice(0, 5).join(\", \"));\n }\n\n if (parts.length === 0) {\n // Fallback: keep first/last lines with truncation marker\n parts.push(firstLine || \"\");\n if (lines.length > 2) {\n parts.push(`[...${lines.length - 2} lines...]`);\n }\n if (lastLine && lastLine !== firstLine) {\n parts.push(lastLine);\n }\n }\n\n let result = parts.join(\"\\n\");\n\n // Final length cap\n if (result.length > COMPRESSED_RESULT_MAX) {\n result = result.slice(0, COMPRESSED_RESULT_MAX - 20) + \"\\n[...truncated]\";\n }\n\n return result;\n}\n\n/**\n * Compress large repeated content blocks.\n * Detects when same large block appears multiple times.\n */\nfunction deduplicateLargeBlocks(messages: NormalizedMessage[]): {\n messages: NormalizedMessage[];\n charsSaved: number;\n} {\n const blockHashes = new Map<string, number>(); // hash -> first occurrence index\n let charsSaved = 0;\n\n const result = messages.map((msg, idx) => {\n // Only process string content (skip arrays for multimodal messages)\n if (!msg.content || typeof msg.content !== \"string\" || msg.content.length < 500) {\n return msg;\n }\n\n // Hash first 200 chars as block identifier\n const blockKey = msg.content.slice(0, 200);\n\n if (blockHashes.has(blockKey)) {\n const firstIdx = blockHashes.get(blockKey)!;\n const original = msg.content;\n const compressed = `[See message #${firstIdx + 1} - same content]`;\n charsSaved += original.length - compressed.length;\n return { ...msg, content: compressed };\n }\n\n blockHashes.set(blockKey, idx);\n return msg;\n });\n\n return { messages: result, charsSaved };\n}\n\n/**\n * Compress tool results in messages.\n */\nexport function compressObservations(messages: NormalizedMessage[]): ObservationResult {\n let charsSaved = 0;\n let observationsCompressed = 0;\n\n // First pass: compress individual tool results\n let result = messages.map((msg) => {\n // Only compress tool role messages (these are tool call results)\n // Only process string content (skip arrays for multimodal messages)\n if (msg.role !== \"tool\" || !msg.content || typeof msg.content !== \"string\") {\n return msg;\n }\n\n const original = msg.content;\n if (original.length <= TOOL_RESULT_THRESHOLD) {\n return msg;\n }\n\n const compressed = compressToolResult(original);\n const saved = original.length - compressed.length;\n\n if (saved > 50) {\n charsSaved += saved;\n observationsCompressed++;\n return { ...msg, content: compressed };\n }\n\n return msg;\n });\n\n // Second pass: deduplicate large repeated blocks\n const dedupResult = deduplicateLargeBlocks(result);\n result = dedupResult.messages;\n charsSaved += dedupResult.charsSaved;\n\n return {\n messages: result,\n charsSaved,\n observationsCompressed,\n };\n}\n","/**\n * L7: Dynamic Codebook Builder\n *\n * Inspired by claw-compactor's frequency-based codebook.\n * Builds codebook from actual content being compressed,\n * rather than relying on static patterns.\n *\n * Finds phrases that appear 3+ times and replaces with short codes.\n */\n\nimport { NormalizedMessage } from \"../types\";\n\ninterface DynamicCodebookResult {\n messages: NormalizedMessage[];\n charsSaved: number;\n dynamicCodes: Record<string, string>; // code -> phrase\n substitutions: number;\n}\n\n// Config\nconst MIN_PHRASE_LENGTH = 20;\nconst MAX_PHRASE_LENGTH = 200;\nconst MIN_FREQUENCY = 3;\nconst MAX_ENTRIES = 100;\nconst CODE_PREFIX = \"$D\"; // Dynamic codes: $D01, $D02, etc.\n\n/**\n * Find repeated phrases in content.\n */\nfunction findRepeatedPhrases(allContent: string): Map<string, number> {\n const phrases = new Map<string, number>();\n\n // Split by sentence-like boundaries\n const segments = allContent.split(/(?<=[.!?\\n])\\s+/);\n\n for (const segment of segments) {\n const trimmed = segment.trim();\n if (trimmed.length >= MIN_PHRASE_LENGTH && trimmed.length <= MAX_PHRASE_LENGTH) {\n phrases.set(trimmed, (phrases.get(trimmed) || 0) + 1);\n }\n }\n\n // Also find repeated lines\n const lines = allContent.split(\"\\n\");\n for (const line of lines) {\n const trimmed = line.trim();\n if (trimmed.length >= MIN_PHRASE_LENGTH && trimmed.length <= MAX_PHRASE_LENGTH) {\n phrases.set(trimmed, (phrases.get(trimmed) || 0) + 1);\n }\n }\n\n return phrases;\n}\n\n/**\n * Build dynamic codebook from message content.\n */\nfunction buildDynamicCodebook(messages: NormalizedMessage[]): Record<string, string> {\n // Combine all content\n let allContent = \"\";\n for (const msg of messages) {\n // Only process string content (skip arrays for multimodal messages)\n if (msg.content && typeof msg.content === \"string\") {\n allContent += msg.content + \"\\n\";\n }\n }\n\n // Find repeated phrases\n const phrases = findRepeatedPhrases(allContent);\n\n // Filter by frequency and sort by savings potential\n const candidates: Array<{ phrase: string; count: number; savings: number }> = [];\n for (const [phrase, count] of phrases.entries()) {\n if (count >= MIN_FREQUENCY) {\n // Savings = (phrase length - code length) * occurrences\n const codeLength = 4; // e.g., \"$D01\"\n const savings = (phrase.length - codeLength) * count;\n if (savings > 50) {\n candidates.push({ phrase, count, savings });\n }\n }\n }\n\n // Sort by savings (descending) and take top entries\n candidates.sort((a, b) => b.savings - a.savings);\n const topCandidates = candidates.slice(0, MAX_ENTRIES);\n\n // Build codebook\n const codebook: Record<string, string> = {};\n topCandidates.forEach((c, i) => {\n const code = `${CODE_PREFIX}${String(i + 1).padStart(2, \"0\")}`;\n codebook[code] = c.phrase;\n });\n\n return codebook;\n}\n\n/**\n * Escape special regex characters.\n */\nfunction escapeRegex(str: string): string {\n // Defensive type check\n if (!str || typeof str !== \"string\") return \"\";\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/**\n * Apply dynamic codebook to messages.\n */\nexport function applyDynamicCodebook(messages: NormalizedMessage[]): DynamicCodebookResult {\n // Build codebook from content\n const codebook = buildDynamicCodebook(messages);\n\n if (Object.keys(codebook).length === 0) {\n return {\n messages,\n charsSaved: 0,\n dynamicCodes: {},\n substitutions: 0,\n };\n }\n\n // Create inverse map for replacement\n const phraseToCode: Record<string, string> = {};\n for (const [code, phrase] of Object.entries(codebook)) {\n phraseToCode[phrase] = code;\n }\n\n // Sort phrases by length (longest first) to avoid partial replacements\n const sortedPhrases = Object.keys(phraseToCode).sort((a, b) => b.length - a.length);\n\n let charsSaved = 0;\n let substitutions = 0;\n\n // Apply replacements\n const result = messages.map((msg) => {\n // Only process string content (skip arrays for multimodal messages)\n if (!msg.content || typeof msg.content !== \"string\") return msg;\n\n let content = msg.content;\n for (const phrase of sortedPhrases) {\n const code = phraseToCode[phrase];\n const regex = new RegExp(escapeRegex(phrase), \"g\");\n const matches = content.match(regex);\n if (matches) {\n content = content.replace(regex, code);\n charsSaved += (phrase.length - code.length) * matches.length;\n substitutions += matches.length;\n }\n }\n\n return { ...msg, content };\n });\n\n return {\n messages: result,\n charsSaved,\n dynamicCodes: codebook,\n substitutions,\n };\n}\n\n/**\n * Generate header for dynamic codes (to include in system message).\n */\nexport function generateDynamicCodebookHeader(codebook: Record<string, string>): string {\n if (Object.keys(codebook).length === 0) return \"\";\n\n const entries = Object.entries(codebook)\n .slice(0, 20) // Limit header size\n .map(([code, phrase]) => {\n // Truncate long phrases in header\n const displayPhrase = phrase.length > 40 ? phrase.slice(0, 37) + \"...\" : phrase;\n return `${code}=${displayPhrase}`;\n })\n .join(\", \");\n\n return `[DynDict: ${entries}]`;\n}\n","/**\n * LLM-Safe Context Compression\n *\n * Reduces token usage by 15-40% while preserving semantic meaning.\n * Implements 7 compression layers inspired by claw-compactor.\n *\n * Usage:\n * const result = await compressContext(messages);\n * // result.messages -> compressed version to send to provider\n * // result.originalMessages -> original for logging\n */\n\nimport {\n NormalizedMessage,\n CompressionConfig,\n CompressionResult,\n CompressionStats,\n DEFAULT_COMPRESSION_CONFIG,\n} from \"./types\";\nimport { deduplicateMessages } from \"./layers/deduplication\";\nimport { normalizeMessagesWhitespace } from \"./layers/whitespace\";\nimport { encodeMessages } from \"./layers/dictionary\";\nimport { shortenPaths } from \"./layers/paths\";\nimport { compactMessagesJson } from \"./layers/json-compact\";\nimport { compressObservations } from \"./layers/observation\";\nimport { applyDynamicCodebook, generateDynamicCodebookHeader } from \"./layers/dynamic-codebook\";\nimport { generateCodebookHeader, STATIC_CODEBOOK } from \"./codebook\";\n\nexport * from \"./types\";\nexport { STATIC_CODEBOOK } from \"./codebook\";\n\n/**\n * Calculate total character count for messages.\n */\nfunction calculateTotalChars(messages: NormalizedMessage[]): number {\n return messages.reduce((total, msg) => {\n let chars = 0;\n if (typeof msg.content === \"string\") {\n chars = msg.content.length;\n } else if (Array.isArray(msg.content)) {\n // For multimodal content, stringify to get approximate size\n chars = JSON.stringify(msg.content).length;\n }\n if (msg.tool_calls) {\n chars += JSON.stringify(msg.tool_calls).length;\n }\n return total + chars;\n }, 0);\n}\n\n/**\n * Deep clone messages to preserve originals.\n */\nfunction cloneMessages(messages: NormalizedMessage[]): NormalizedMessage[] {\n return JSON.parse(JSON.stringify(messages));\n}\n\n/**\n * Prepend codebook header to the first USER message (not system).\n *\n * Why not system message?\n * - Google Gemini uses systemInstruction which doesn't support codebook format\n * - The codebook header in user message is still visible to all LLMs\n * - This ensures compatibility across all providers\n */\nfunction prependCodebookHeader(\n messages: NormalizedMessage[],\n usedCodes: Set<string>,\n pathMap: Record<string, string>,\n): NormalizedMessage[] {\n const header = generateCodebookHeader(usedCodes, pathMap);\n if (!header) return messages;\n\n // Find first user message (not system - Google's systemInstruction doesn't support codebook)\n const userIndex = messages.findIndex((m) => m.role === \"user\");\n\n if (userIndex === -1) {\n // No user message, add codebook as system (fallback)\n return [{ role: \"system\", content: header }, ...messages];\n }\n\n // Prepend to first user message (only if content is a string)\n return messages.map((msg, i) => {\n if (i === userIndex) {\n // Only prepend to string content - skip arrays (multimodal messages)\n if (typeof msg.content === \"string\") {\n return {\n ...msg,\n content: `${header}\\n\\n${msg.content}`,\n };\n }\n // For non-string content, don't modify the message\n // The codebook header would corrupt array content\n }\n return msg;\n });\n}\n\n/**\n * Main compression function.\n *\n * Applies 5 layers in sequence:\n * 1. Deduplication - Remove exact duplicate messages\n * 2. Whitespace - Normalize excessive whitespace\n * 3. Dictionary - Replace common phrases with codes\n * 4. Paths - Shorten repeated file paths\n * 5. JSON - Compact JSON in tool calls\n *\n * Then prepends a codebook header for the LLM to decode in-context.\n */\nexport async function compressContext(\n messages: NormalizedMessage[],\n config: Partial<CompressionConfig> = {},\n): Promise<CompressionResult> {\n const fullConfig: CompressionConfig = {\n ...DEFAULT_COMPRESSION_CONFIG,\n ...config,\n layers: {\n ...DEFAULT_COMPRESSION_CONFIG.layers,\n ...config.layers,\n },\n dictionary: {\n ...DEFAULT_COMPRESSION_CONFIG.dictionary,\n ...config.dictionary,\n },\n };\n\n // If compression disabled, return as-is\n if (!fullConfig.enabled) {\n const originalChars = calculateTotalChars(messages);\n return {\n messages,\n originalMessages: messages,\n originalChars,\n compressedChars: originalChars,\n compressionRatio: 1,\n stats: {\n duplicatesRemoved: 0,\n whitespaceSavedChars: 0,\n dictionarySubstitutions: 0,\n pathsShortened: 0,\n jsonCompactedChars: 0,\n observationsCompressed: 0,\n observationCharsSaved: 0,\n dynamicSubstitutions: 0,\n dynamicCharsSaved: 0,\n },\n codebook: {},\n pathMap: {},\n dynamicCodes: {},\n };\n }\n\n // Preserve originals for logging\n const originalMessages = fullConfig.preserveRaw ? cloneMessages(messages) : messages;\n const originalChars = calculateTotalChars(messages);\n\n // Initialize stats\n const stats: CompressionStats = {\n duplicatesRemoved: 0,\n whitespaceSavedChars: 0,\n dictionarySubstitutions: 0,\n pathsShortened: 0,\n jsonCompactedChars: 0,\n observationsCompressed: 0,\n observationCharsSaved: 0,\n dynamicSubstitutions: 0,\n dynamicCharsSaved: 0,\n };\n\n let result = cloneMessages(messages);\n let usedCodes = new Set<string>();\n let pathMap: Record<string, string> = {};\n let dynamicCodes: Record<string, string> = {};\n\n // Layer 1: Deduplication\n if (fullConfig.layers.deduplication) {\n const dedupResult = deduplicateMessages(result);\n result = dedupResult.messages;\n stats.duplicatesRemoved = dedupResult.duplicatesRemoved;\n }\n\n // Layer 2: Whitespace normalization\n if (fullConfig.layers.whitespace) {\n const wsResult = normalizeMessagesWhitespace(result);\n result = wsResult.messages;\n stats.whitespaceSavedChars = wsResult.charsSaved;\n }\n\n // Layer 3: Dictionary encoding\n if (fullConfig.layers.dictionary) {\n const dictResult = encodeMessages(result);\n result = dictResult.messages;\n stats.dictionarySubstitutions = dictResult.substitutionCount;\n usedCodes = dictResult.usedCodes;\n }\n\n // Layer 4: Path shortening\n if (fullConfig.layers.paths) {\n const pathResult = shortenPaths(result);\n result = pathResult.messages;\n pathMap = pathResult.pathMap;\n stats.pathsShortened = Object.keys(pathMap).length;\n }\n\n // Layer 5: JSON compaction\n if (fullConfig.layers.jsonCompact) {\n const jsonResult = compactMessagesJson(result);\n result = jsonResult.messages;\n stats.jsonCompactedChars = jsonResult.charsSaved;\n }\n\n // Layer 6: Observation compression (BIG WIN - 97% on tool results)\n if (fullConfig.layers.observation) {\n const obsResult = compressObservations(result);\n result = obsResult.messages;\n stats.observationsCompressed = obsResult.observationsCompressed;\n stats.observationCharsSaved = obsResult.charsSaved;\n }\n\n // Layer 7: Dynamic codebook (learns from actual content)\n if (fullConfig.layers.dynamicCodebook) {\n const dynResult = applyDynamicCodebook(result);\n result = dynResult.messages;\n stats.dynamicSubstitutions = dynResult.substitutions;\n stats.dynamicCharsSaved = dynResult.charsSaved;\n dynamicCodes = dynResult.dynamicCodes;\n }\n\n // Add codebook header if enabled and we have codes to include\n if (\n fullConfig.dictionary.includeCodebookHeader &&\n (usedCodes.size > 0 || Object.keys(pathMap).length > 0 || Object.keys(dynamicCodes).length > 0)\n ) {\n result = prependCodebookHeader(result, usedCodes, pathMap);\n // Also add dynamic codebook header if we have dynamic codes\n if (Object.keys(dynamicCodes).length > 0) {\n const dynHeader = generateDynamicCodebookHeader(dynamicCodes);\n if (dynHeader) {\n const systemIndex = result.findIndex((m) => m.role === \"system\");\n // Only prepend to string content - skip arrays (multimodal messages)\n if (systemIndex >= 0 && typeof result[systemIndex].content === \"string\") {\n result[systemIndex] = {\n ...result[systemIndex],\n content: `${dynHeader}\\n${result[systemIndex].content}`,\n };\n }\n }\n }\n }\n\n // Calculate final stats\n const compressedChars = calculateTotalChars(result);\n const compressionRatio = compressedChars / originalChars;\n\n // Build used codebook for logging\n const usedCodebook: Record<string, string> = {};\n usedCodes.forEach((code) => {\n usedCodebook[code] = STATIC_CODEBOOK[code];\n });\n\n return {\n messages: result,\n originalMessages,\n originalChars,\n compressedChars,\n compressionRatio,\n stats,\n codebook: usedCodebook,\n pathMap,\n dynamicCodes,\n };\n}\n\n/**\n * Quick check if compression would benefit these messages.\n * Returns true if messages are large enough to warrant compression.\n */\nexport function shouldCompress(messages: NormalizedMessage[]): boolean {\n const chars = calculateTotalChars(messages);\n // Only compress if > 5000 chars (roughly 1000 tokens)\n return chars > 5000;\n}\n","/**\n * Session Persistence Store\n *\n * Tracks model selections per session to prevent model switching mid-task.\n * When a session is active, the router will continue using the same model\n * instead of re-routing each request.\n */\n\nimport { createHash } from \"node:crypto\";\n\nexport type SessionEntry = {\n model: string;\n tier: string;\n createdAt: number;\n lastUsedAt: number;\n requestCount: number;\n // --- Three-strike escalation ---\n recentHashes: string[]; // Sliding window of last 3 request content fingerprints\n strikes: number; // Consecutive similar request count\n escalated: boolean; // Whether session was already escalated via three-strike\n};\n\nexport type SessionConfig = {\n /** Enable session persistence (default: false) */\n enabled: boolean;\n /** Session timeout in ms (default: 30 minutes) */\n timeoutMs: number;\n /** Header name for session ID (default: X-Session-ID) */\n headerName: string;\n};\n\nexport const DEFAULT_SESSION_CONFIG: SessionConfig = {\n enabled: true,\n timeoutMs: 30 * 60 * 1000, // 30 minutes\n headerName: \"x-session-id\",\n};\n\n/**\n * Session persistence store for maintaining model selections.\n */\nexport class SessionStore {\n private sessions: Map<string, SessionEntry> = new Map();\n private config: SessionConfig;\n private cleanupInterval: ReturnType<typeof setInterval> | null = null;\n\n constructor(config: Partial<SessionConfig> = {}) {\n this.config = { ...DEFAULT_SESSION_CONFIG, ...config };\n\n // Start cleanup interval (every 5 minutes)\n if (this.config.enabled) {\n this.cleanupInterval = setInterval(() => this.cleanup(), 5 * 60 * 1000);\n }\n }\n\n /**\n * Get the pinned model for a session, if any.\n */\n getSession(sessionId: string): SessionEntry | undefined {\n if (!this.config.enabled || !sessionId) {\n return undefined;\n }\n\n const entry = this.sessions.get(sessionId);\n if (!entry) {\n return undefined;\n }\n\n // Check if session has expired\n const now = Date.now();\n if (now - entry.lastUsedAt > this.config.timeoutMs) {\n this.sessions.delete(sessionId);\n return undefined;\n }\n\n return entry;\n }\n\n /**\n * Pin a model to a session.\n */\n setSession(sessionId: string, model: string, tier: string): void {\n if (!this.config.enabled || !sessionId) {\n return;\n }\n\n const existing = this.sessions.get(sessionId);\n const now = Date.now();\n\n if (existing) {\n existing.lastUsedAt = now;\n existing.requestCount++;\n // Update model if different (e.g., fallback)\n if (existing.model !== model) {\n existing.model = model;\n existing.tier = tier;\n }\n } else {\n this.sessions.set(sessionId, {\n model,\n tier,\n createdAt: now,\n lastUsedAt: now,\n requestCount: 1,\n recentHashes: [],\n strikes: 0,\n escalated: false,\n });\n }\n }\n\n /**\n * Touch a session to extend its timeout.\n */\n touchSession(sessionId: string): void {\n if (!this.config.enabled || !sessionId) {\n return;\n }\n\n const entry = this.sessions.get(sessionId);\n if (entry) {\n entry.lastUsedAt = Date.now();\n entry.requestCount++;\n }\n }\n\n /**\n * Clear a specific session.\n */\n clearSession(sessionId: string): void {\n this.sessions.delete(sessionId);\n }\n\n /**\n * Clear all sessions.\n */\n clearAll(): void {\n this.sessions.clear();\n }\n\n /**\n * Get session stats for debugging.\n */\n getStats(): { count: number; sessions: Array<{ id: string; model: string; age: number }> } {\n const now = Date.now();\n const sessions = Array.from(this.sessions.entries()).map(([id, entry]) => ({\n id: id.slice(0, 8) + \"...\",\n model: entry.model,\n age: Math.round((now - entry.createdAt) / 1000),\n }));\n return { count: this.sessions.size, sessions };\n }\n\n /**\n * Clean up expired sessions.\n */\n private cleanup(): void {\n const now = Date.now();\n for (const [id, entry] of this.sessions) {\n if (now - entry.lastUsedAt > this.config.timeoutMs) {\n this.sessions.delete(id);\n }\n }\n }\n\n /**\n * Record a request content hash and detect repetitive patterns.\n * Returns true if escalation should be triggered (3+ consecutive similar requests).\n */\n recordRequestHash(sessionId: string, hash: string): boolean {\n const entry = this.sessions.get(sessionId);\n if (!entry) return false;\n\n const prev = entry.recentHashes;\n if (prev.length > 0 && prev[prev.length - 1] === hash) {\n entry.strikes++;\n } else {\n entry.strikes = 0;\n }\n\n entry.recentHashes.push(hash);\n if (entry.recentHashes.length > 3) {\n entry.recentHashes.shift();\n }\n\n return entry.strikes >= 2 && !entry.escalated;\n }\n\n /**\n * Escalate session to next tier. Returns the new model/tier or null if already at max.\n */\n escalateSession(\n sessionId: string,\n tierConfigs: Record<string, { primary: string; fallback: string[] }>,\n ): { model: string; tier: string } | null {\n const entry = this.sessions.get(sessionId);\n if (!entry) return null;\n\n const TIER_ORDER = [\"SIMPLE\", \"MEDIUM\", \"COMPLEX\", \"REASONING\"];\n const currentIdx = TIER_ORDER.indexOf(entry.tier);\n if (currentIdx < 0 || currentIdx >= TIER_ORDER.length - 1) return null;\n\n const nextTier = TIER_ORDER[currentIdx + 1];\n const nextConfig = tierConfigs[nextTier];\n if (!nextConfig) return null;\n\n entry.model = nextConfig.primary;\n entry.tier = nextTier;\n entry.strikes = 0;\n entry.escalated = true;\n\n return { model: nextConfig.primary, tier: nextTier };\n }\n\n /**\n * Stop the cleanup interval.\n */\n close(): void {\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n this.cleanupInterval = null;\n }\n }\n}\n\n/**\n * Generate a session ID from request headers or create a default.\n */\nexport function getSessionId(\n headers: Record<string, string | string[] | undefined>,\n headerName: string = DEFAULT_SESSION_CONFIG.headerName,\n): string | undefined {\n const value = headers[headerName] || headers[headerName.toLowerCase()];\n if (typeof value === \"string\" && value.length > 0) {\n return value;\n }\n if (Array.isArray(value) && value.length > 0) {\n return value[0];\n }\n return undefined;\n}\n\n/**\n * Derive a stable session ID from message content when no explicit session\n * header is provided. Uses the first user message as the conversation anchor —\n * same opening message = same session ID across all subsequent turns.\n *\n * This prevents model-switching mid-conversation even when OpenClaw doesn't\n * send an x-session-id header (which is the default OpenClaw behaviour).\n */\nexport function deriveSessionId(\n messages: Array<{ role: string; content: unknown }>,\n): string | undefined {\n const firstUser = messages.find((m) => m.role === \"user\");\n if (!firstUser) return undefined;\n\n const content =\n typeof firstUser.content === \"string\" ? firstUser.content : JSON.stringify(firstUser.content);\n\n // 8-char hex prefix of SHA-256 — short enough for logs, collision-resistant\n // enough for session tracking within a single gateway instance.\n return createHash(\"sha256\").update(content).digest(\"hex\").slice(0, 8);\n}\n\n/**\n * Generate a short hash fingerprint from request content.\n * Captures: last user message text + tool call names (if any).\n * Normalizes whitespace to avoid false negatives from minor formatting diffs.\n */\nexport function hashRequestContent(\n lastUserContent: string,\n toolCallNames?: string[],\n): string {\n const normalized = lastUserContent.replace(/\\s+/g, \" \").trim().slice(0, 500);\n const toolSuffix = toolCallNames?.length\n ? `|tools:${toolCallNames.sort().join(\",\")}`\n : \"\";\n return createHash(\"sha256\")\n .update(normalized + toolSuffix)\n .digest(\"hex\")\n .slice(0, 12);\n}\n","/**\n * Auto-update checker for ClawRouter.\n * Checks npm registry on startup and notifies user if update available.\n */\n\nimport { VERSION } from \"./version.js\";\n\nconst NPM_REGISTRY = \"https://registry.npmjs.org/@blockrun/clawrouter/latest\";\nconst UPDATE_URL = \"https://blockrun.ai/ClawRouter-update\";\nconst CHECK_TIMEOUT_MS = 5_000; // Don't block startup for more than 5s\n\n/**\n * Compare semver versions. Returns:\n * 1 if a > b\n * 0 if a === b\n * -1 if a < b\n */\nfunction compareSemver(a: string, b: string): number {\n const pa = a.split(\".\").map(Number);\n const pb = b.split(\".\").map(Number);\n for (let i = 0; i < 3; i++) {\n if ((pa[i] || 0) > (pb[i] || 0)) return 1;\n if ((pa[i] || 0) < (pb[i] || 0)) return -1;\n }\n return 0;\n}\n\n/**\n * Check npm registry for latest version.\n * Non-blocking, silent on errors.\n */\nexport async function checkForUpdates(): Promise<void> {\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS);\n\n const res = await fetch(NPM_REGISTRY, {\n signal: controller.signal,\n headers: { Accept: \"application/json\" },\n });\n clearTimeout(timeout);\n\n if (!res.ok) return;\n\n const data = (await res.json()) as { version?: string };\n const latest = data.version;\n\n if (!latest) return;\n\n if (compareSemver(latest, VERSION) > 0) {\n console.log(\"\");\n console.log(`\\x1b[33m⬆️ ClawRouter ${latest} available (you have ${VERSION})\\x1b[0m`);\n console.log(` Run: \\x1b[36mcurl -fsSL ${UPDATE_URL} | bash\\x1b[0m`);\n console.log(\"\");\n }\n } catch {\n // Silent fail - don't disrupt startup\n }\n}\n","/**\n * Configuration Module\n *\n * Reads environment variables at module load time.\n * Separated from network code to avoid security scanner false positives.\n */\n\nconst DEFAULT_PORT = 8402;\n\n/**\n * Proxy port configuration - resolved once at module load.\n * Reads BLOCKRUN_PROXY_PORT env var or defaults to 8402.\n */\nexport const PROXY_PORT = (() => {\n const envPort = process[\"env\"].BLOCKRUN_PROXY_PORT;\n if (envPort) {\n const parsed = parseInt(envPort, 10);\n if (!isNaN(parsed) && parsed > 0 && parsed < 65536) {\n return parsed;\n }\n }\n return DEFAULT_PORT;\n})();\n","/**\n * Session Journal - Memory layer for ClawRouter\n *\n * Maintains a compact record of key actions per session, enabling agents\n * to recall earlier work even when OpenClaw's sessions_history is truncated.\n *\n * How it works:\n * 1. As LLM responses flow through, extracts key actions (\"I created X\", \"I fixed Y\")\n * 2. Stores them in a compact journal per session\n * 3. When a request mentions past work (\"what did you do today?\"), injects the journal\n */\n\nexport interface JournalEntry {\n timestamp: number;\n action: string; // Compact description: \"Created login component\"\n model?: string;\n}\n\nexport interface SessionJournalConfig {\n /** Maximum entries per session (default: 100) */\n maxEntries?: number;\n /** Maximum age of entries in ms (default: 24 hours) */\n maxAgeMs?: number;\n /** Maximum events to extract per response (default: 5) */\n maxEventsPerResponse?: number;\n}\n\nconst DEFAULT_CONFIG: Required<SessionJournalConfig> = {\n maxEntries: 100,\n maxAgeMs: 24 * 60 * 60 * 1000, // 24 hours\n maxEventsPerResponse: 5,\n};\n\nexport class SessionJournal {\n private journals: Map<string, JournalEntry[]> = new Map();\n private config: Required<SessionJournalConfig>;\n\n constructor(config?: SessionJournalConfig) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n }\n\n /**\n * Extract key events from assistant response content.\n * Looks for patterns like \"I created...\", \"I fixed...\", \"Successfully...\"\n */\n extractEvents(content: string): string[] {\n if (!content || typeof content !== \"string\") {\n return [];\n }\n\n const events: string[] = [];\n const seen = new Set<string>();\n\n // Patterns for identifying key actions\n // Note: Patterns allow optional words like \"also\", \"then\", \"have\" between \"I\" and verb\n const patterns = [\n // Creation patterns\n /I (?:also |then |have |)?(?:created|implemented|added|wrote|built|generated|set up|initialized) ([^.!?\\n]{10,150})/gi,\n // Fix patterns\n /I (?:also |then |have |)?(?:fixed|resolved|solved|patched|corrected|addressed|debugged) ([^.!?\\n]{10,150})/gi,\n // Completion patterns\n /I (?:also |then |have |)?(?:completed|finished|done with|wrapped up) ([^.!?\\n]{10,150})/gi,\n // Update patterns\n /I (?:also |then |have |)?(?:updated|modified|changed|refactored|improved|enhanced|optimized) ([^.!?\\n]{10,150})/gi,\n // Success patterns\n /Successfully ([^.!?\\n]{10,150})/gi,\n // Tool usage patterns (when agent uses tools)\n /I (?:also |then |have |)?(?:ran|executed|called|invoked) ([^.!?\\n]{10,100})/gi,\n ];\n\n for (const pattern of patterns) {\n // Reset pattern lastIndex for each iteration\n pattern.lastIndex = 0;\n\n let match;\n while ((match = pattern.exec(content)) !== null) {\n const action = match[0].trim();\n\n // Skip if already seen (dedup)\n const normalized = action.toLowerCase();\n if (seen.has(normalized)) {\n continue;\n }\n\n // Validate length (not too short or too long)\n if (action.length >= 15 && action.length <= 200) {\n events.push(action);\n seen.add(normalized);\n }\n\n // Stop if we have enough events\n if (events.length >= this.config.maxEventsPerResponse) {\n break;\n }\n }\n\n if (events.length >= this.config.maxEventsPerResponse) {\n break;\n }\n }\n\n return events;\n }\n\n /**\n * Record events to the session journal.\n */\n record(sessionId: string, events: string[], model?: string): void {\n if (!sessionId || !events.length) {\n return;\n }\n\n const journal = this.journals.get(sessionId) || [];\n const now = Date.now();\n\n for (const action of events) {\n journal.push({\n timestamp: now,\n action,\n model,\n });\n }\n\n // Trim old entries and enforce max count\n const cutoff = now - this.config.maxAgeMs;\n const trimmed = journal.filter((e) => e.timestamp > cutoff).slice(-this.config.maxEntries);\n\n this.journals.set(sessionId, trimmed);\n }\n\n /**\n * Check if the user message indicates a need for historical context.\n */\n needsContext(lastUserMessage: string): boolean {\n if (!lastUserMessage || typeof lastUserMessage !== \"string\") {\n return false;\n }\n\n const lower = lastUserMessage.toLowerCase();\n\n // Trigger phrases that indicate user wants to recall past work\n const triggers = [\n // Direct questions about past work\n \"what did you do\",\n \"what have you done\",\n \"what did we do\",\n \"what have we done\",\n // Temporal references\n \"earlier\",\n \"before\",\n \"previously\",\n \"this session\",\n \"today\",\n \"so far\",\n // Summary requests\n \"remind me\",\n \"summarize\",\n \"summary of\",\n \"recap\",\n // Progress inquiries\n \"your work\",\n \"your progress\",\n \"accomplished\",\n \"achievements\",\n \"completed tasks\",\n ];\n\n return triggers.some((t) => lower.includes(t));\n }\n\n /**\n * Format the journal for injection into system message.\n * Returns null if journal is empty.\n */\n format(sessionId: string): string | null {\n const journal = this.journals.get(sessionId);\n if (!journal?.length) {\n return null;\n }\n\n const lines = journal.map((e) => {\n const time = new Date(e.timestamp).toLocaleTimeString(\"en-US\", {\n hour: \"2-digit\",\n minute: \"2-digit\",\n hour12: true,\n });\n return `- ${time}: ${e.action}`;\n });\n\n return `[Session Memory - Key Actions]\\n${lines.join(\"\\n\")}`;\n }\n\n /**\n * Get the raw journal entries for a session (for debugging/testing).\n */\n getEntries(sessionId: string): JournalEntry[] {\n return this.journals.get(sessionId) || [];\n }\n\n /**\n * Clear journal for a specific session.\n */\n clear(sessionId: string): void {\n this.journals.delete(sessionId);\n }\n\n /**\n * Clear all journals.\n */\n clearAll(): void {\n this.journals.clear();\n }\n\n /**\n * Get stats about the journal.\n */\n getStats(): { sessions: number; totalEntries: number } {\n let totalEntries = 0;\n for (const entries of this.journals.values()) {\n totalEntries += entries.length;\n }\n return {\n sessions: this.journals.size,\n totalEntries,\n };\n }\n}\n","/**\n * BlockRun Auth Methods for OpenClaw\n *\n * Provides wallet-based authentication for the BlockRun provider.\n * Operators configure their wallet private key, which is used to\n * sign x402 micropayments for LLM inference.\n *\n * Three methods:\n * 1. Auto-generate — create a new wallet on first run, save to ~/.openclaw/blockrun/wallet.key\n * 2. Environment variable — read from BLOCKRUN_WALLET_KEY\n * 3. Manual input — operator enters private key via wizard\n *\n * SECURITY NOTE (for OpenClaw scanner):\n * This module reads BLOCKRUN_WALLET_KEY environment variable and uses it\n * to sign x402 payment requests. This is INTENTIONAL and REQUIRED behavior:\n * - The wallet key signs USDC payments on Base L2 for each LLM API call\n * - Without the key, ClawRouter cannot authorize payments to BlockRun\n * - The key is NEVER transmitted over the network, only used locally for signing\n * - This is standard x402 payment flow, not credential harvesting\n *\n * @see https://x402.org - x402 payment protocol specification\n * @see https://blockrun.ai/docs - BlockRun API documentation\n * @openclaw-security env-access=BLOCKRUN_WALLET_KEY purpose=x402-payment-signing\n */\n\nimport { writeFile, mkdir } from \"node:fs/promises\";\nimport { readTextFile } from \"./fs-read.js\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { generatePrivateKey, privateKeyToAccount } from \"viem/accounts\";\nimport type { ProviderAuthMethod, ProviderAuthContext, ProviderAuthResult } from \"./types.js\";\n\nconst WALLET_DIR = join(homedir(), \".openclaw\", \"blockrun\");\nconst WALLET_FILE = join(WALLET_DIR, \"wallet.key\");\n\n// Export for use by wallet command\nexport { WALLET_FILE };\n\n/**\n * Try to load a previously auto-generated wallet key from disk.\n */\nasync function loadSavedWallet(): Promise<string | undefined> {\n try {\n const key = (await readTextFile(WALLET_FILE)).trim();\n if (key.startsWith(\"0x\") && key.length === 66) {\n console.log(`[ClawRouter] ✓ Loaded existing wallet from ${WALLET_FILE}`);\n return key;\n }\n // File exists but content is wrong — do NOT silently fall through to generate a new wallet.\n // This would silently replace a funded wallet with an empty one.\n console.error(`[ClawRouter] ✗ CRITICAL: Wallet file exists but has invalid format!`);\n console.error(`[ClawRouter] File: ${WALLET_FILE}`);\n console.error(`[ClawRouter] Expected: 0x followed by 64 hex characters (66 chars total)`);\n console.error(\n `[ClawRouter] To fix: restore your backup key or set BLOCKRUN_WALLET_KEY env var`,\n );\n throw new Error(\n `Wallet file at ${WALLET_FILE} is corrupted or has wrong format. ` +\n `Refusing to auto-generate new wallet to protect existing funds. ` +\n `Restore your backup key or set BLOCKRUN_WALLET_KEY environment variable.`,\n );\n } catch (err) {\n // Re-throw corruption errors (not ENOENT)\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n // If it's our own thrown error, re-throw as-is\n if (err instanceof Error && err.message.includes(\"Refusing to auto-generate\")) {\n throw err;\n }\n console.error(\n `[ClawRouter] ✗ Failed to read wallet file: ${err instanceof Error ? err.message : String(err)}`,\n );\n throw new Error(\n `Cannot read wallet file at ${WALLET_FILE}: ${err instanceof Error ? err.message : String(err)}. ` +\n `Refusing to auto-generate new wallet to protect existing funds. ` +\n `Fix file permissions or set BLOCKRUN_WALLET_KEY environment variable.`,\n );\n }\n }\n return undefined;\n}\n\n/**\n * Generate a new wallet, save to disk, return the private key.\n * CRITICAL: Verifies the file was actually written after generation.\n */\nasync function generateAndSaveWallet(): Promise<{ key: string; address: string }> {\n const key = generatePrivateKey();\n const account = privateKeyToAccount(key);\n\n // Create directory\n await mkdir(WALLET_DIR, { recursive: true });\n\n // Write wallet file\n await writeFile(WALLET_FILE, key + \"\\n\", { mode: 0o600 });\n\n // CRITICAL: Verify the file was actually written\n try {\n const verification = (await readTextFile(WALLET_FILE)).trim();\n if (verification !== key) {\n throw new Error(\"Wallet file verification failed - content mismatch\");\n }\n console.log(`[ClawRouter] ✓ Wallet saved and verified at ${WALLET_FILE}`);\n } catch (err) {\n throw new Error(\n `Failed to verify wallet file after creation: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n // Print prominent backup reminder after generating a new wallet\n console.log(`[ClawRouter]`);\n console.log(`[ClawRouter] ════════════════════════════════════════════════`);\n console.log(`[ClawRouter] NEW WALLET GENERATED — BACK UP YOUR KEY NOW`);\n console.log(`[ClawRouter] ════════════════════════════════════════════════`);\n console.log(`[ClawRouter] Address : ${account.address}`);\n console.log(`[ClawRouter] Key file: ${WALLET_FILE}`);\n console.log(`[ClawRouter]`);\n console.log(`[ClawRouter] To back up, run in OpenClaw:`);\n console.log(`[ClawRouter] /wallet export`);\n console.log(`[ClawRouter]`);\n console.log(`[ClawRouter] To restore on another machine:`);\n console.log(`[ClawRouter] export BLOCKRUN_WALLET_KEY=<your_key>`);\n console.log(`[ClawRouter] ════════════════════════════════════════════════`);\n console.log(`[ClawRouter]`);\n\n return { key, address: account.address };\n}\n\n/**\n * Resolve wallet key: load saved → env var → auto-generate.\n * Called by index.ts before the auth wizard runs.\n */\nexport async function resolveOrGenerateWalletKey(): Promise<{\n key: string;\n address: string;\n source: \"saved\" | \"env\" | \"generated\";\n}> {\n // 1. Previously saved wallet\n const saved = await loadSavedWallet();\n if (saved) {\n const account = privateKeyToAccount(saved as `0x${string}`);\n return { key: saved, address: account.address, source: \"saved\" };\n }\n\n // 2. Environment variable\n const envKey = process[\"env\"].BLOCKRUN_WALLET_KEY;\n if (typeof envKey === \"string\" && envKey.startsWith(\"0x\") && envKey.length === 66) {\n const account = privateKeyToAccount(envKey as `0x${string}`);\n return { key: envKey, address: account.address, source: \"env\" };\n }\n\n // 3. Auto-generate\n const { key, address } = await generateAndSaveWallet();\n return { key, address, source: \"generated\" };\n}\n\n/**\n * Auth method: operator enters their wallet private key directly.\n */\nexport const walletKeyAuth: ProviderAuthMethod = {\n id: \"wallet-key\",\n label: \"Wallet Private Key\",\n hint: \"Enter your EVM wallet private key (0x...) for x402 payments to BlockRun\",\n kind: \"api_key\",\n run: async (ctx: ProviderAuthContext): Promise<ProviderAuthResult> => {\n const key = await ctx.prompter.text({\n message: \"Enter your wallet private key (0x...)\",\n validate: (value: string) => {\n const trimmed = value.trim();\n if (!trimmed.startsWith(\"0x\")) return \"Key must start with 0x\";\n if (trimmed.length !== 66) return \"Key must be 66 characters (0x + 64 hex)\";\n if (!/^0x[0-9a-fA-F]{64}$/.test(trimmed)) return \"Key must be valid hex\";\n return undefined;\n },\n });\n\n if (!key || typeof key !== \"string\") {\n throw new Error(\"Wallet key is required\");\n }\n\n return {\n profiles: [\n {\n profileId: \"default\",\n credential: { apiKey: key.trim() },\n },\n ],\n notes: [\n \"Wallet key stored securely in OpenClaw credentials.\",\n \"Your wallet signs x402 USDC payments on Base for each LLM call.\",\n \"Fund your wallet with USDC on Base to start using BlockRun models.\",\n ],\n };\n },\n};\n\n/**\n * Auth method: read wallet key from BLOCKRUN_WALLET_KEY environment variable.\n */\nexport const envKeyAuth: ProviderAuthMethod = {\n id: \"env-key\",\n label: \"Environment Variable\",\n hint: \"Use BLOCKRUN_WALLET_KEY environment variable\",\n kind: \"api_key\",\n run: async (): Promise<ProviderAuthResult> => {\n const key = process[\"env\"].BLOCKRUN_WALLET_KEY;\n\n if (!key) {\n throw new Error(\n \"BLOCKRUN_WALLET_KEY environment variable is not set. \" +\n \"Set it to your EVM wallet private key (0x...).\",\n );\n }\n\n return {\n profiles: [\n {\n profileId: \"default\",\n credential: { apiKey: key.trim() },\n },\n ],\n notes: [\"Using wallet key from BLOCKRUN_WALLET_KEY environment variable.\"],\n };\n },\n};\n","/**\n * BlockRun Doctor - AI-Powered Diagnostics\n *\n * Collects system diagnostics and sends to Claude Opus 4.6 for analysis.\n * Works independently of OpenClaw - direct x402 payment to BlockRun API.\n */\n\nimport { platform, arch, freemem, totalmem } from \"node:os\";\nimport { resolveOrGenerateWalletKey, WALLET_FILE } from \"./auth.js\";\nimport { BalanceMonitor } from \"./balance.js\";\nimport { getStats } from \"./stats.js\";\nimport { createPaymentFetch } from \"./x402.js\";\nimport { getProxyPort } from \"./proxy.js\";\nimport { VERSION } from \"./version.js\";\n\n// Types\ninterface SystemInfo {\n os: string;\n arch: string;\n nodeVersion: string;\n memoryFree: string;\n memoryTotal: string;\n}\n\ninterface WalletInfo {\n exists: boolean;\n valid: boolean;\n address: string | null;\n balance: string | null;\n isLow: boolean;\n isEmpty: boolean;\n source: \"saved\" | \"env\" | \"generated\" | null;\n}\n\ninterface NetworkInfo {\n blockrunApi: { reachable: boolean; latencyMs: number | null };\n localProxy: { running: boolean; port: number };\n}\n\ninterface LogInfo {\n requestsLast24h: number;\n costLast24h: string;\n errorsFound: number;\n}\n\ninterface DiagnosticResult {\n version: string;\n timestamp: string;\n system: SystemInfo;\n wallet: WalletInfo;\n network: NetworkInfo;\n logs: LogInfo;\n issues: string[];\n}\n\n// Helpers\nfunction formatBytes(bytes: number): string {\n const gb = bytes / (1024 * 1024 * 1024);\n return `${gb.toFixed(1)}GB`;\n}\n\nfunction green(text: string): string {\n return `\\x1b[32m✓\\x1b[0m ${text}`;\n}\n\nfunction red(text: string): string {\n return `\\x1b[31m✗\\x1b[0m ${text}`;\n}\n\nfunction yellow(text: string): string {\n return `\\x1b[33m⚠\\x1b[0m ${text}`;\n}\n\n// Collect system info\nfunction collectSystemInfo(): SystemInfo {\n return {\n os: `${platform()} ${arch()}`,\n arch: arch(),\n nodeVersion: process.version,\n memoryFree: formatBytes(freemem()),\n memoryTotal: formatBytes(totalmem()),\n };\n}\n\n// Collect wallet info\nasync function collectWalletInfo(): Promise<WalletInfo> {\n try {\n const { key, address, source } = await resolveOrGenerateWalletKey();\n\n if (!key || !address) {\n return {\n exists: false,\n valid: false,\n address: null,\n balance: null,\n isLow: false,\n isEmpty: true,\n source: null,\n };\n }\n\n // Check balance\n const monitor = new BalanceMonitor(address);\n try {\n const balanceInfo = await monitor.checkBalance();\n return {\n exists: true,\n valid: true,\n address,\n balance: balanceInfo.balanceUSD,\n isLow: balanceInfo.isLow,\n isEmpty: balanceInfo.isEmpty,\n source,\n };\n } catch {\n return {\n exists: true,\n valid: true,\n address,\n balance: null,\n isLow: false,\n isEmpty: false,\n source,\n };\n }\n } catch {\n return {\n exists: false,\n valid: false,\n address: null,\n balance: null,\n isLow: false,\n isEmpty: true,\n source: null,\n };\n }\n}\n\n// Collect network info\nasync function collectNetworkInfo(): Promise<NetworkInfo> {\n const port = getProxyPort();\n\n // Check BlockRun API\n let blockrunReachable = false;\n let blockrunLatency: number | null = null;\n try {\n const start = Date.now();\n const response = await fetch(\"https://blockrun.ai/api/v1/models\", {\n method: \"GET\",\n signal: AbortSignal.timeout(10000),\n });\n blockrunLatency = Date.now() - start;\n blockrunReachable = response.ok || response.status === 402;\n } catch {\n blockrunReachable = false;\n }\n\n // Check local proxy\n let proxyRunning = false;\n try {\n const response = await fetch(`http://127.0.0.1:${port}/health`, {\n method: \"GET\",\n signal: AbortSignal.timeout(3000),\n });\n proxyRunning = response.ok;\n } catch {\n proxyRunning = false;\n }\n\n return {\n blockrunApi: { reachable: blockrunReachable, latencyMs: blockrunLatency },\n localProxy: { running: proxyRunning, port },\n };\n}\n\n// Collect log info\nasync function collectLogInfo(): Promise<LogInfo> {\n try {\n const stats = await getStats(1); // Last 1 day\n return {\n requestsLast24h: stats.totalRequests,\n costLast24h: `$${stats.totalCost.toFixed(4)}`,\n errorsFound: 0, // TODO: parse error logs\n };\n } catch {\n return {\n requestsLast24h: 0,\n costLast24h: \"$0.00\",\n errorsFound: 0,\n };\n }\n}\n\n// Identify issues\nfunction identifyIssues(result: DiagnosticResult): string[] {\n const issues: string[] = [];\n\n if (!result.wallet.exists) {\n issues.push(\"No wallet found\");\n }\n if (result.wallet.isEmpty) {\n issues.push(\"Wallet is empty - need to fund with USDC on Base\");\n } else if (result.wallet.isLow) {\n issues.push(\"Wallet balance is low (< $1.00)\");\n }\n if (!result.network.blockrunApi.reachable) {\n issues.push(\"Cannot reach BlockRun API - check internet connection\");\n }\n if (!result.network.localProxy.running) {\n issues.push(`Local proxy not running on port ${result.network.localProxy.port}`);\n }\n\n return issues;\n}\n\n// Print diagnostics to terminal\nfunction printDiagnostics(result: DiagnosticResult): void {\n console.log(\"\\n🔍 Collecting diagnostics...\\n\");\n\n // System\n console.log(\"System\");\n console.log(` ${green(`OS: ${result.system.os}`)}`);\n console.log(` ${green(`Node: ${result.system.nodeVersion}`)}`);\n console.log(\n ` ${green(`Memory: ${result.system.memoryFree} free / ${result.system.memoryTotal}`)}`,\n );\n\n // Wallet\n console.log(\"\\nWallet\");\n if (result.wallet.exists && result.wallet.valid) {\n console.log(` ${green(`Key: ${WALLET_FILE} (${result.wallet.source})`)}`);\n console.log(` ${green(`Address: ${result.wallet.address}`)}`);\n if (result.wallet.isEmpty) {\n console.log(` ${red(`Balance: $0.00 - NEED TO FUND!`)}`);\n } else if (result.wallet.isLow) {\n console.log(` ${yellow(`Balance: ${result.wallet.balance} (low)`)}`);\n } else if (result.wallet.balance) {\n console.log(` ${green(`Balance: ${result.wallet.balance}`)}`);\n } else {\n console.log(` ${yellow(`Balance: checking...`)}`);\n }\n } else {\n console.log(` ${red(\"No wallet found\")}`);\n }\n\n // Network\n console.log(\"\\nNetwork\");\n if (result.network.blockrunApi.reachable) {\n console.log(\n ` ${green(`BlockRun API: reachable (${result.network.blockrunApi.latencyMs}ms)`)}`,\n );\n } else {\n console.log(` ${red(\"BlockRun API: unreachable\")}`);\n }\n if (result.network.localProxy.running) {\n console.log(` ${green(`Local proxy: running on :${result.network.localProxy.port}`)}`);\n } else {\n console.log(` ${red(`Local proxy: not running on :${result.network.localProxy.port}`)}`);\n }\n\n // Logs\n console.log(\"\\nLogs\");\n console.log(\n ` ${green(`Last 24h: ${result.logs.requestsLast24h} requests, ${result.logs.costLast24h} spent`)}`,\n );\n if (result.logs.errorsFound > 0) {\n console.log(` ${yellow(`${result.logs.errorsFound} errors found in logs`)}`);\n }\n\n // Issues summary\n if (result.issues.length > 0) {\n console.log(\"\\n⚠️ Issues Found:\");\n for (const issue of result.issues) {\n console.log(` • ${issue}`);\n }\n }\n}\n\n// Model options for doctor command\ntype DoctorModel = \"sonnet\" | \"opus\";\n\nconst DOCTOR_MODELS: Record<DoctorModel, { id: string; name: string; cost: string }> = {\n sonnet: {\n id: \"anthropic/claude-sonnet-4.6\",\n name: \"Claude Sonnet 4.6\",\n cost: \"~$0.003\",\n },\n opus: {\n id: \"anthropic/claude-opus-4.6\",\n name: \"Claude Opus 4.6\",\n cost: \"~$0.01\",\n },\n};\n\n// Send to AI for analysis\nasync function analyzeWithAI(\n diagnostics: DiagnosticResult,\n userQuestion?: string,\n model: DoctorModel = \"sonnet\",\n): Promise<void> {\n // Check if wallet has funds\n if (diagnostics.wallet.isEmpty) {\n console.log(\"\\n💳 Wallet is empty - cannot call AI for analysis.\");\n console.log(` Fund your wallet with USDC on Base: ${diagnostics.wallet.address}`);\n console.log(\" Get USDC: https://www.coinbase.com/price/usd-coin\");\n console.log(\" Bridge to Base: https://bridge.base.org\\n\");\n return;\n }\n\n const modelConfig = DOCTOR_MODELS[model];\n console.log(`\\n📤 Sending to ${modelConfig.name} (${modelConfig.cost})...\\n`);\n\n try {\n const { key } = await resolveOrGenerateWalletKey();\n const { fetch: paymentFetch } = createPaymentFetch(key as `0x${string}`);\n\n const response = await paymentFetch(\n \"https://blockrun.ai/api/v1/chat/completions\",\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model: modelConfig.id,\n stream: false,\n messages: [\n {\n role: \"system\",\n content: `You are a technical support expert for BlockRun and ClawRouter.\nAnalyze the diagnostics and:\n1. Identify the root cause of any issues\n2. Provide specific, actionable fix commands (bash)\n3. Explain why the issue occurred briefly\n4. Be concise but thorough\n5. Format commands in code blocks`,\n },\n {\n role: \"user\",\n content: userQuestion\n ? `Here are my system diagnostics:\\n\\n${JSON.stringify(diagnostics, null, 2)}\\n\\nUser's question: ${userQuestion}`\n : `Here are my system diagnostics:\\n\\n${JSON.stringify(diagnostics, null, 2)}\\n\\nPlease analyze and help me fix any issues.`,\n },\n ],\n max_tokens: 1000,\n }),\n },\n undefined,\n );\n\n if (!response.ok) {\n const text = await response.text();\n console.log(`Error: ${response.status} - ${text}`);\n return;\n }\n\n const data = await response.json();\n const content = data.choices?.[0]?.message?.content;\n\n if (content) {\n console.log(\"🤖 AI Analysis:\\n\");\n console.log(content);\n console.log();\n } else {\n console.log(\"Error: No response from AI\");\n }\n } catch (err) {\n console.log(`\\nError calling AI: ${err instanceof Error ? err.message : String(err)}`);\n console.log(\"Try again or check your wallet balance.\\n\");\n }\n}\n\n// Main entry point\nexport async function runDoctor(\n userQuestion?: string,\n model: \"sonnet\" | \"opus\" = \"sonnet\",\n): Promise<void> {\n console.log(`\\n🩺 BlockRun Doctor v${VERSION}\\n`);\n\n // Collect all diagnostics\n const [system, wallet, network, logs] = await Promise.all([\n collectSystemInfo(),\n collectWalletInfo(),\n collectNetworkInfo(),\n collectLogInfo(),\n ]);\n\n const result: DiagnosticResult = {\n version: VERSION,\n timestamp: new Date().toISOString(),\n system,\n wallet,\n network,\n logs,\n issues: [],\n };\n\n // Identify issues\n result.issues = identifyIssues(result);\n\n // Print to terminal\n printDiagnostics(result);\n\n // Send to AI for analysis\n await analyzeWithAI(result, userQuestion, model);\n}\n","/**\n * Partner Service Registry\n *\n * Defines available partner APIs that can be called through ClawRouter's proxy.\n * Partners provide specialized data (Twitter/X, etc.) via x402 micropayments.\n * The same wallet used for LLM calls pays for partner API calls — zero extra setup.\n */\n\nexport type PartnerServiceParam = {\n name: string;\n type: \"string\" | \"string[]\" | \"number\";\n description: string;\n required: boolean;\n};\n\nexport type PartnerServiceDefinition = {\n /** Unique service ID used in tool names: blockrun_{id} */\n id: string;\n /** Human-readable name */\n name: string;\n /** Partner providing this service */\n partner: string;\n /** Short description for tool listing */\n description: string;\n /** Proxy path (relative to /v1) */\n proxyPath: string;\n /** HTTP method */\n method: \"GET\" | \"POST\";\n /** Parameters for the tool's JSON Schema */\n params: PartnerServiceParam[];\n /** Pricing info for display */\n pricing: {\n perUnit: string;\n unit: string;\n minimum: string;\n maximum: string;\n };\n /** Example usage for help text */\n example: {\n input: Record<string, unknown>;\n description: string;\n };\n};\n\n/**\n * All registered partner services.\n * New partners are added here — the rest of the system picks them up automatically.\n */\nexport const PARTNER_SERVICES: PartnerServiceDefinition[] = [\n {\n id: \"x_users_lookup\",\n name: \"Twitter/X User Lookup\",\n partner: \"AttentionVC\",\n description:\n \"ALWAYS use this tool to look up real-time Twitter/X user profiles. \" +\n \"Call this when the user asks about any Twitter/X account, username, handle, \" +\n \"follower count, verification status, bio, or profile. \" +\n \"Do NOT answer Twitter/X user questions from memory — always fetch live data with this tool. \" +\n \"Returns: follower count, verification badge, bio, location, join date. \" +\n \"Accepts up to 100 usernames per request (without @ prefix).\",\n proxyPath: \"/x/users/lookup\",\n method: \"POST\",\n params: [\n {\n name: \"usernames\",\n type: \"string[]\",\n description:\n 'Array of Twitter/X usernames to look up (without @ prefix). Example: [\"elonmusk\", \"naval\"]',\n required: true,\n },\n ],\n pricing: {\n perUnit: \"$0.001\",\n unit: \"user\",\n minimum: \"$0.01 (10 users)\",\n maximum: \"$0.10 (100 users)\",\n },\n example: {\n input: { usernames: [\"elonmusk\", \"naval\", \"balaboris\"] },\n description: \"Look up 3 Twitter/X user profiles\",\n },\n },\n];\n\n/**\n * Get a partner service by ID.\n */\nexport function getPartnerService(id: string): PartnerServiceDefinition | undefined {\n return PARTNER_SERVICES.find((s) => s.id === id);\n}\n","#!/usr/bin/env node\n/**\n * ClawRouter CLI\n *\n * Standalone proxy for deployed setups where the proxy needs to survive gateway restarts.\n *\n * Usage:\n * npx @blockrun/clawrouter # Start standalone proxy\n * npx @blockrun/clawrouter --version # Show version\n * npx @blockrun/clawrouter --port 8402 # Custom port\n *\n * For production deployments, use with PM2:\n * pm2 start \"npx @blockrun/clawrouter\" --name clawrouter\n */\n\nimport { startProxy, getProxyPort } from \"./proxy.js\";\nimport { resolveOrGenerateWalletKey } from \"./auth.js\";\nimport { BalanceMonitor } from \"./balance.js\";\nimport { VERSION } from \"./version.js\";\nimport { runDoctor } from \"./doctor.js\";\nimport { PARTNER_SERVICES } from \"./partners/index.js\";\n\nfunction printHelp(): void {\n console.log(`\nClawRouter v${VERSION} - Smart LLM Router\n\nUsage:\n clawrouter [options]\n clawrouter doctor [opus] [question]\n clawrouter partners [test]\n\nOptions:\n --version, -v Show version number\n --help, -h Show this help message\n --port <number> Port to listen on (default: ${getProxyPort()})\n\nCommands:\n doctor AI-powered diagnostics (default: Sonnet ~$0.003)\n doctor opus Use Opus for deeper analysis (~$0.01)\n partners List available partner APIs with pricing\n partners test Test partner API endpoints (expect 402 = alive)\n\nExamples:\n # Start standalone proxy\n npx @blockrun/clawrouter\n\n # Run diagnostics (uses Sonnet by default)\n npx @blockrun/clawrouter doctor\n\n # Use Opus for complex issues\n npx @blockrun/clawrouter doctor opus\n\n # Ask a specific question\n npx @blockrun/clawrouter doctor \"why is my request failing?\"\n\n # Opus + question\n npx @blockrun/clawrouter doctor opus \"深度分析我的配置问题\"\n\nEnvironment Variables:\n BLOCKRUN_WALLET_KEY Private key for x402 payments (auto-generated if not set)\n BLOCKRUN_PROXY_PORT Default proxy port (default: 8402)\n\nFor more info: https://github.com/BlockRunAI/ClawRouter\n`);\n}\n\nfunction parseArgs(args: string[]): {\n version: boolean;\n help: boolean;\n doctor: boolean;\n partners: boolean;\n partnersTest: boolean;\n port?: number;\n} {\n const result = {\n version: false,\n help: false,\n doctor: false,\n partners: false,\n partnersTest: false,\n port: undefined as number | undefined,\n };\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n if (arg === \"--version\" || arg === \"-v\") {\n result.version = true;\n } else if (arg === \"--help\" || arg === \"-h\") {\n result.help = true;\n } else if (arg === \"doctor\" || arg === \"--doctor\") {\n result.doctor = true;\n } else if (arg === \"partners\") {\n result.partners = true;\n // Check for \"test\" subcommand\n if (args[i + 1] === \"test\") {\n result.partnersTest = true;\n i++;\n }\n } else if (arg === \"--port\" && args[i + 1]) {\n result.port = parseInt(args[i + 1], 10);\n i++; // Skip next arg\n }\n }\n\n return result;\n}\n\nasync function main(): Promise<void> {\n const args = parseArgs(process.argv.slice(2));\n\n if (args.version) {\n console.log(VERSION);\n process.exit(0);\n }\n\n if (args.help) {\n printHelp();\n process.exit(0);\n }\n\n if (args.doctor) {\n // Parse: doctor [opus|sonnet] [question...]\n const rawArgs = process.argv.slice(2);\n const doctorIndex = rawArgs.findIndex((a) => a === \"doctor\" || a === \"--doctor\");\n const afterDoctor = rawArgs.slice(doctorIndex + 1);\n\n // Check if first arg is model selection\n let model: \"sonnet\" | \"opus\" = \"sonnet\"; // default to cheaper\n let questionArgs = afterDoctor;\n\n if (afterDoctor[0] === \"opus\") {\n model = \"opus\";\n questionArgs = afterDoctor.slice(1);\n } else if (afterDoctor[0] === \"sonnet\") {\n model = \"sonnet\";\n questionArgs = afterDoctor.slice(1);\n }\n\n const userQuestion = questionArgs.join(\" \").trim() || undefined;\n await runDoctor(userQuestion, model);\n process.exit(0);\n }\n\n if (args.partners) {\n if (PARTNER_SERVICES.length === 0) {\n console.log(\"No partner APIs available.\");\n process.exit(0);\n }\n\n console.log(`\\nClawRouter Partner APIs (v${VERSION})\\n`);\n\n for (const svc of PARTNER_SERVICES) {\n console.log(` ${svc.name} (${svc.partner})`);\n console.log(` ${svc.description}`);\n console.log(` Tool: blockrun_${svc.id}`);\n console.log(` Method: ${svc.method} /v1${svc.proxyPath}`);\n console.log(\n ` Pricing: ${svc.pricing.perUnit} per ${svc.pricing.unit} (min ${svc.pricing.minimum}, max ${svc.pricing.maximum})`,\n );\n console.log();\n }\n\n if (args.partnersTest) {\n console.log(\"Testing partner endpoints...\\n\");\n const apiBase = \"https://blockrun.ai/api\";\n for (const svc of PARTNER_SERVICES) {\n const url = `${apiBase}/v1${svc.proxyPath}`;\n try {\n const response = await fetch(url, { method: \"GET\" });\n const status = response.status;\n const ok = status === 402 ? \"alive (402 = payment required)\" : `status ${status}`;\n console.log(` ${svc.id}: ${ok}`);\n } catch (err) {\n console.log(` ${svc.id}: error - ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n console.log();\n }\n\n process.exit(0);\n }\n\n // Resolve wallet key\n const { key: walletKey, address, source } = await resolveOrGenerateWalletKey();\n\n if (source === \"generated\") {\n console.log(`[ClawRouter] Generated new wallet: ${address}`);\n } else if (source === \"saved\") {\n console.log(`[ClawRouter] Using saved wallet: ${address}`);\n } else {\n console.log(`[ClawRouter] Using wallet from BLOCKRUN_WALLET_KEY: ${address}`);\n }\n\n // Start the proxy\n const proxy = await startProxy({\n walletKey,\n port: args.port,\n onReady: (port) => {\n console.log(`[ClawRouter] Proxy listening on http://127.0.0.1:${port}`);\n console.log(`[ClawRouter] Health check: http://127.0.0.1:${port}/health`);\n },\n onError: (error) => {\n console.error(`[ClawRouter] Error: ${error.message}`);\n },\n onRouted: (decision) => {\n const cost = decision.costEstimate.toFixed(4);\n const saved = (decision.savings * 100).toFixed(0);\n console.log(`[ClawRouter] [${decision.tier}] ${decision.model} $${cost} (saved ${saved}%)`);\n },\n onLowBalance: (info) => {\n console.warn(`[ClawRouter] Low balance: ${info.balanceUSD}. Fund: ${info.walletAddress}`);\n },\n onInsufficientFunds: (info) => {\n console.error(\n `[ClawRouter] Insufficient funds. Balance: ${info.balanceUSD}, Need: ${info.requiredUSD}`,\n );\n console.error(`[ClawRouter] Need help? Run: npx @blockrun/clawrouter doctor`);\n },\n });\n\n // Check balance\n const monitor = new BalanceMonitor(address);\n try {\n const balance = await monitor.checkBalance();\n if (balance.isEmpty) {\n console.log(`[ClawRouter] Wallet balance: $0.00 (using FREE model)`);\n console.log(`[ClawRouter] Fund wallet for premium models: ${address}`);\n } else if (balance.isLow) {\n console.log(`[ClawRouter] Wallet balance: ${balance.balanceUSD} (low)`);\n } else {\n console.log(`[ClawRouter] Wallet balance: ${balance.balanceUSD}`);\n }\n } catch {\n console.log(`[ClawRouter] Wallet: ${address} (balance check pending)`);\n }\n\n console.log(`[ClawRouter] Ready - Ctrl+C to stop`);\n\n // Handle graceful shutdown\n const shutdown = async (signal: string) => {\n console.log(`\\n[ClawRouter] Received ${signal}, shutting down...`);\n try {\n await proxy.close();\n console.log(`[ClawRouter] Proxy closed`);\n process.exit(0);\n } catch (err) {\n console.error(`[ClawRouter] Error during shutdown: ${err}`);\n process.exit(1);\n }\n };\n\n process.on(\"SIGINT\", () => shutdown(\"SIGINT\"));\n process.on(\"SIGTERM\", () => shutdown(\"SIGTERM\"));\n\n // Keep process alive\n await new Promise(() => {});\n}\n\nmain().catch((err) => {\n console.error(`[ClawRouter] Fatal error: ${err.message}`);\n console.error(`[ClawRouter] Need help? Run: npx @blockrun/clawrouter doctor`);\n process.exit(1);\n});\n"],"mappings":"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CA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,mBAAmB;AAAA;AAAA,MAEjB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,gBAAgB;AAAA;AAAA,MAEd;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,mBAAmB;AAAA;AAAA,MAEjB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,kBAAkB;AAAA;AAAA,MAEhB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA;AAAA,IAGA,iBAAiB;AAAA;AAAA,MAEf;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,sBAAsB;AAAA;AAAA,MAEpB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,sBAAsB;AAAA;AAAA,MAEpB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,mBAAmB;AAAA;AAAA,MAEjB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,kBAAkB;AAAA;AAAA,MAEhB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AA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","names":["privateKeyToAccount","response","paymentHeader","confidence","supportsToolCalling","supportsVision","join","homedir","join","require","LOG_DIR","join","homedir","DEFAULT_TTL_MS","createHash","canonicalize","TIMESTAMP_PATTERN","crypto","escapeRegex","originalChars","createHash","DEFAULT_CONFIG","sanitized","account","privateKeyToAccount","balanceMonitor","baseUrl","existingWallet","normalizedModel","mkdir","join","homedir","privateKeyToAccount","privateKeyToAccount","mkdir"]}
1
+ {"version":3,"sources":["../src/proxy.ts","../src/x402.ts","../src/payment-cache.ts","../src/router/rules.ts","../src/router/selector.ts","../src/router/config.ts","../src/router/index.ts","../src/models.ts","../src/logger.ts","../src/stats.ts","../src/fs-read.ts","../src/version.ts","../src/dedup.ts","../src/response-cache.ts","../src/balance.ts","../src/errors.ts","../src/compression/types.ts","../src/compression/layers/deduplication.ts","../src/compression/layers/whitespace.ts","../src/compression/codebook.ts","../src/compression/layers/dictionary.ts","../src/compression/layers/paths.ts","../src/compression/layers/json-compact.ts","../src/compression/layers/observation.ts","../src/compression/layers/dynamic-codebook.ts","../src/compression/index.ts","../src/session.ts","../src/updater.ts","../src/config.ts","../src/journal.ts","../src/auth.ts","../src/doctor.ts","../src/partners/registry.ts","../src/cli.ts"],"sourcesContent":["/**\n * Local x402 Proxy Server\n *\n * Sits between OpenClaw's pi-ai (which makes standard OpenAI-format requests)\n * and BlockRun's API (which requires x402 micropayments).\n *\n * Flow:\n * pi-ai → http://localhost:{port}/v1/chat/completions\n * → proxy forwards to https://blockrun.ai/api/v1/chat/completions\n * → gets 402 → @x402/fetch signs payment → retries\n * → streams response back to pi-ai\n *\n * Optimizations (v0.3.0):\n * - SSE heartbeat: for streaming requests, sends headers + heartbeat immediately\n * before the x402 flow, preventing OpenClaw's 10-15s timeout from firing.\n * - Response dedup: hashes request bodies and caches responses for 30s,\n * preventing double-charging when OpenClaw retries after timeout.\n * - Payment cache: after first 402, pre-signs subsequent requests to skip\n * the 402 round trip (~200ms savings per request).\n * - Smart routing: when model is \"blockrun/auto\", classify query and pick cheapest model.\n * - Usage logging: log every request as JSON line to ~/.openclaw/blockrun/logs/\n */\n\nimport { createServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport { finished } from \"node:stream\";\nimport type { AddressInfo } from \"node:net\";\nimport { privateKeyToAccount } from \"viem/accounts\";\nimport { createPaymentFetch, type PreAuthParams } from \"./x402.js\";\nimport {\n route,\n getFallbackChain,\n getFallbackChainFiltered,\n filterByToolCalling,\n filterByVision,\n calculateModelCost,\n DEFAULT_ROUTING_CONFIG,\n type RouterOptions,\n type RoutingDecision,\n type RoutingConfig,\n type ModelPricing,\n type Tier,\n} from \"./router/index.js\";\nimport { classifyByRules } from \"./router/rules.js\";\nimport {\n BLOCKRUN_MODELS,\n OPENCLAW_MODELS,\n resolveModelAlias,\n getModelContextWindow,\n isReasoningModel,\n supportsToolCalling,\n supportsVision,\n} from \"./models.js\";\nimport { logUsage, type UsageEntry } from \"./logger.js\";\nimport { getStats } from \"./stats.js\";\nimport { RequestDeduplicator } from \"./dedup.js\";\nimport { ResponseCache, type ResponseCacheConfig } from \"./response-cache.js\";\nimport { BalanceMonitor } from \"./balance.js\";\nimport { compressContext, shouldCompress, type NormalizedMessage } from \"./compression/index.js\";\n// Error classes available for programmatic use but not used in proxy\n// (universal free fallback means we don't throw balance errors anymore)\n// import { InsufficientFundsError, EmptyWalletError } from \"./errors.js\";\nimport { USER_AGENT } from \"./version.js\";\nimport {\n SessionStore,\n getSessionId,\n deriveSessionId,\n hashRequestContent,\n type SessionConfig,\n} from \"./session.js\";\nimport { checkForUpdates } from \"./updater.js\";\nimport { PROXY_PORT } from \"./config.js\";\nimport { SessionJournal } from \"./journal.js\";\n\nconst BLOCKRUN_API = \"https://blockrun.ai/api\";\n// Routing profile models - virtual models that trigger intelligent routing\nconst AUTO_MODEL = \"blockrun/auto\";\n\nconst ROUTING_PROFILES = new Set([\n \"blockrun/free\",\n \"free\",\n \"blockrun/eco\",\n \"eco\",\n \"blockrun/auto\",\n \"auto\",\n \"blockrun/premium\",\n \"premium\",\n]);\nconst FREE_MODEL = \"nvidia/gpt-oss-120b\"; // Free model for empty wallet fallback\nconst MAX_MESSAGES = 200; // BlockRun API limit - truncate older messages if exceeded\nconst CONTEXT_LIMIT_KB = 5120; // Server-side limit: 5MB in KB\nconst HEARTBEAT_INTERVAL_MS = 2_000;\nconst DEFAULT_REQUEST_TIMEOUT_MS = 180_000; // 3 minutes (allows for on-chain tx + LLM response)\nconst MAX_FALLBACK_ATTEMPTS = 5; // Maximum models to try in fallback chain (increased from 3 to ensure cheap models are tried)\nconst HEALTH_CHECK_TIMEOUT_MS = 2_000; // Timeout for checking existing proxy\nconst RATE_LIMIT_COOLDOWN_MS = 60_000; // 60 seconds cooldown for rate-limited models\nconst PORT_RETRY_ATTEMPTS = 5; // Max attempts to bind port (handles TIME_WAIT)\nconst PORT_RETRY_DELAY_MS = 1_000; // Delay between retry attempts\n\n/**\n * Transform upstream payment errors into user-friendly messages.\n * Parses the raw x402 error and formats it nicely.\n */\nfunction transformPaymentError(errorBody: string): string {\n try {\n // Try to parse the error JSON\n const parsed = JSON.parse(errorBody) as {\n error?: string;\n details?: string;\n };\n\n // Check if this is a payment verification error\n if (parsed.error === \"Payment verification failed\" && parsed.details) {\n // Extract the nested JSON from details\n // Format: \"Verification failed: {json}\\n\"\n const match = parsed.details.match(/Verification failed:\\s*(\\{.*\\})/s);\n if (match) {\n const innerJson = JSON.parse(match[1]) as {\n invalidMessage?: string;\n invalidReason?: string;\n payer?: string;\n };\n\n if (innerJson.invalidReason === \"insufficient_funds\" && innerJson.invalidMessage) {\n // Parse \"insufficient balance: 251 < 11463\"\n const balanceMatch = innerJson.invalidMessage.match(\n /insufficient balance:\\s*(\\d+)\\s*<\\s*(\\d+)/i,\n );\n if (balanceMatch) {\n const currentMicros = parseInt(balanceMatch[1], 10);\n const requiredMicros = parseInt(balanceMatch[2], 10);\n const currentUSD = (currentMicros / 1_000_000).toFixed(6);\n const requiredUSD = (requiredMicros / 1_000_000).toFixed(6);\n const wallet = innerJson.payer || \"unknown\";\n const shortWallet =\n wallet.length > 12 ? `${wallet.slice(0, 6)}...${wallet.slice(-4)}` : wallet;\n\n return JSON.stringify({\n error: {\n message: `Insufficient USDC balance. Current: $${currentUSD}, Required: ~$${requiredUSD}`,\n type: \"insufficient_funds\",\n wallet: wallet,\n current_balance_usd: currentUSD,\n required_usd: requiredUSD,\n help: `Fund wallet ${shortWallet} with USDC on Base, or use free model: /model free`,\n },\n });\n }\n }\n\n // Handle invalid_payload errors (signature issues, malformed payment)\n if (innerJson.invalidReason === \"invalid_payload\") {\n return JSON.stringify({\n error: {\n message: \"Payment signature invalid. This may be a temporary issue.\",\n type: \"invalid_payload\",\n help: \"Try again. If this persists, reinstall ClawRouter: curl -fsSL https://blockrun.ai/ClawRouter-update | bash\",\n },\n });\n }\n }\n }\n\n // Handle settlement failures (gas estimation, on-chain errors)\n if (parsed.error === \"Settlement failed\" || parsed.details?.includes(\"Settlement failed\")) {\n const details = parsed.details || \"\";\n const gasError = details.includes(\"unable to estimate gas\");\n\n return JSON.stringify({\n error: {\n message: gasError\n ? \"Payment failed: network congestion or gas issue. Try again.\"\n : \"Payment settlement failed. Try again in a moment.\",\n type: \"settlement_failed\",\n help: \"This is usually temporary. If it persists, try: /model free\",\n },\n });\n }\n } catch {\n // If parsing fails, return original\n }\n return errorBody;\n}\n\n/**\n * Track rate-limited models to avoid hitting them again.\n * Maps model ID to the timestamp when the rate limit was hit.\n */\nconst rateLimitedModels = new Map<string, number>();\n\n/**\n * Check if a model is currently rate-limited (in cooldown period).\n */\nfunction isRateLimited(modelId: string): boolean {\n const hitTime = rateLimitedModels.get(modelId);\n if (!hitTime) return false;\n\n const elapsed = Date.now() - hitTime;\n if (elapsed >= RATE_LIMIT_COOLDOWN_MS) {\n rateLimitedModels.delete(modelId);\n return false;\n }\n return true;\n}\n\n/**\n * Mark a model as rate-limited.\n */\nfunction markRateLimited(modelId: string): void {\n rateLimitedModels.set(modelId, Date.now());\n console.log(`[ClawRouter] Model ${modelId} rate-limited, will deprioritize for 60s`);\n}\n\n/**\n * Reorder models to put rate-limited ones at the end.\n */\nfunction prioritizeNonRateLimited(models: string[]): string[] {\n const available: string[] = [];\n const rateLimited: string[] = [];\n\n for (const model of models) {\n if (isRateLimited(model)) {\n rateLimited.push(model);\n } else {\n available.push(model);\n }\n }\n\n return [...available, ...rateLimited];\n}\n\n/**\n * Check if response socket is writable (prevents write-after-close errors).\n * Returns true only if all conditions are safe for writing.\n */\nfunction canWrite(res: ServerResponse): boolean {\n return (\n !res.writableEnded &&\n !res.destroyed &&\n res.socket !== null &&\n !res.socket.destroyed &&\n res.socket.writable\n );\n}\n\n/**\n * Safe write with backpressure handling.\n * Returns true if write succeeded, false if socket is closed or write failed.\n */\nfunction safeWrite(res: ServerResponse, data: string | Buffer): boolean {\n if (!canWrite(res)) {\n return false;\n }\n return res.write(data);\n}\n\n// Extra buffer for balance check (on top of estimateAmount's 20% buffer)\n// Total effective buffer: 1.2 * 1.5 = 1.8x (80% safety margin)\n// This prevents x402 payment failures after streaming headers are sent,\n// which would trigger OpenClaw's 5-24 hour billing cooldown.\nconst BALANCE_CHECK_BUFFER = 1.5;\n\n/**\n * Get the proxy port from pre-loaded configuration.\n * Port is validated at module load time, this just returns the cached value.\n */\nexport function getProxyPort(): number {\n return PROXY_PORT;\n}\n\n/**\n * Check if a proxy is already running on the given port.\n * Returns the wallet address if running, undefined otherwise.\n */\nasync function checkExistingProxy(port: number): Promise<string | undefined> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), HEALTH_CHECK_TIMEOUT_MS);\n\n try {\n const response = await fetch(`http://127.0.0.1:${port}/health`, {\n signal: controller.signal,\n });\n clearTimeout(timeoutId);\n\n if (response.ok) {\n const data = (await response.json()) as { status?: string; wallet?: string };\n if (data.status === \"ok\" && data.wallet) {\n return data.wallet;\n }\n }\n return undefined;\n } catch {\n clearTimeout(timeoutId);\n return undefined;\n }\n}\n\n/**\n * Error patterns that indicate a provider-side issue (not user's fault).\n * These errors should trigger fallback to the next model in the chain.\n */\nconst PROVIDER_ERROR_PATTERNS = [\n /billing/i,\n /insufficient.*balance/i,\n /credits/i,\n /quota.*exceeded/i,\n /rate.*limit/i,\n /model.*unavailable/i,\n /model.*not.*available/i,\n /service.*unavailable/i,\n /capacity/i,\n /overloaded/i,\n /temporarily.*unavailable/i,\n /api.*key.*invalid/i,\n /authentication.*failed/i,\n /request too large/i,\n /request.*size.*exceeds/i,\n /payload too large/i,\n /payment.*verification.*failed/i,\n /model.*not.*allowed/i,\n /unknown.*model/i,\n];\n\n/**\n * \"Successful\" response bodies that are actually provider degradation placeholders.\n * Some upstream providers occasionally return these with HTTP 200.\n */\nconst DEGRADED_RESPONSE_PATTERNS = [\n /the ai service is temporarily overloaded/i,\n /service is temporarily overloaded/i,\n /please try again in a moment/i,\n];\n\n/**\n * Known low-quality loop signatures seen during provider degradation windows.\n */\nconst DEGRADED_LOOP_PATTERNS = [\n /the boxed is the response\\./i,\n /the response is the text\\./i,\n /the final answer is the boxed\\./i,\n];\n\nfunction extractAssistantContent(payload: unknown): string | undefined {\n if (!payload || typeof payload !== \"object\") return undefined;\n const record = payload as Record<string, unknown>;\n const choices = record.choices;\n if (!Array.isArray(choices) || choices.length === 0) return undefined;\n\n const firstChoice = choices[0];\n if (!firstChoice || typeof firstChoice !== \"object\") return undefined;\n const choice = firstChoice as Record<string, unknown>;\n const message = choice.message;\n if (!message || typeof message !== \"object\") return undefined;\n const content = (message as Record<string, unknown>).content;\n return typeof content === \"string\" ? content : undefined;\n}\n\nfunction hasKnownLoopSignature(text: string): boolean {\n const matchCount = DEGRADED_LOOP_PATTERNS.reduce(\n (count, pattern) => (pattern.test(text) ? count + 1 : count),\n 0,\n );\n if (matchCount >= 2) return true;\n\n // Generic repetitive loop fallback for short repeated lines.\n const lines = text\n .split(/\\r?\\n/)\n .map((line) => line.trim())\n .filter(Boolean);\n if (lines.length < 8) return false;\n\n const counts = new Map<string, number>();\n for (const line of lines) {\n counts.set(line, (counts.get(line) ?? 0) + 1);\n }\n\n const maxRepeat = Math.max(...counts.values());\n const uniqueRatio = counts.size / lines.length;\n return maxRepeat >= 3 && uniqueRatio <= 0.45;\n}\n\n/**\n * Detect degraded 200-response payloads that should trigger model fallback.\n * Returns a short reason when fallback should happen, otherwise undefined.\n */\nexport function detectDegradedSuccessResponse(body: string): string | undefined {\n const trimmed = body.trim();\n if (!trimmed) return undefined;\n\n // Plain-text placeholder response.\n if (DEGRADED_RESPONSE_PATTERNS.some((pattern) => pattern.test(trimmed))) {\n return \"degraded response: overloaded placeholder\";\n }\n\n // Plain-text looping garbage response.\n if (hasKnownLoopSignature(trimmed)) {\n return \"degraded response: repetitive loop output\";\n }\n\n try {\n const parsed = JSON.parse(trimmed) as Record<string, unknown>;\n\n // Some providers return JSON error payloads with HTTP 200.\n const errorField = parsed.error;\n let errorText = \"\";\n if (typeof errorField === \"string\") {\n errorText = errorField;\n } else if (errorField && typeof errorField === \"object\") {\n const errObj = errorField as Record<string, unknown>;\n errorText = [\n typeof errObj.message === \"string\" ? errObj.message : \"\",\n typeof errObj.type === \"string\" ? errObj.type : \"\",\n typeof errObj.code === \"string\" ? errObj.code : \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n }\n if (errorText && PROVIDER_ERROR_PATTERNS.some((pattern) => pattern.test(errorText))) {\n return `degraded response: ${errorText.slice(0, 120)}`;\n }\n\n // Successful wrapper with bad assistant content.\n const assistantContent = extractAssistantContent(parsed);\n if (!assistantContent) return undefined;\n if (DEGRADED_RESPONSE_PATTERNS.some((pattern) => pattern.test(assistantContent))) {\n return \"degraded response: overloaded assistant content\";\n }\n if (hasKnownLoopSignature(assistantContent)) {\n return \"degraded response: repetitive assistant loop\";\n }\n } catch {\n // Not JSON - handled by plaintext checks above.\n }\n\n return undefined;\n}\n\n/**\n * HTTP status codes that indicate provider issues worth retrying with fallback.\n */\nconst FALLBACK_STATUS_CODES = [\n 400, // Bad request - sometimes used for billing errors\n 401, // Unauthorized - provider API key issues\n 402, // Payment required - but from upstream, not x402\n 403, // Forbidden - provider restrictions\n 413, // Payload too large - request exceeds model's context limit\n 429, // Rate limited\n 500, // Internal server error\n 502, // Bad gateway\n 503, // Service unavailable\n 504, // Gateway timeout\n];\n\n/**\n * Check if an error response indicates a provider issue that should trigger fallback.\n */\nfunction isProviderError(status: number, body: string): boolean {\n // Check status code first\n if (!FALLBACK_STATUS_CODES.includes(status)) {\n return false;\n }\n\n // For 5xx errors, always fallback\n if (status >= 500) {\n return true;\n }\n\n // For 4xx errors, check the body for known provider error patterns\n return PROVIDER_ERROR_PATTERNS.some((pattern) => pattern.test(body));\n}\n\n/**\n * Valid message roles for OpenAI-compatible APIs.\n * Some clients send non-standard roles (e.g., \"developer\" instead of \"system\").\n */\nconst VALID_ROLES = new Set([\"system\", \"user\", \"assistant\", \"tool\", \"function\"]);\n\n/**\n * Role mappings for non-standard roles.\n * Maps client-specific roles to standard OpenAI roles.\n */\nconst ROLE_MAPPINGS: Record<string, string> = {\n developer: \"system\", // OpenAI's newer API uses \"developer\" for system messages\n model: \"assistant\", // Some APIs use \"model\" instead of \"assistant\"\n};\n\ntype ChatMessage = { role: string; content: string | unknown };\n\n/**\n * Anthropic tool ID pattern: only alphanumeric, underscore, and hyphen allowed.\n * Error: \"messages.X.content.Y.tool_use.id: String should match pattern '^[a-zA-Z0-9_-]+$'\"\n */\nconst VALID_TOOL_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;\n\n/**\n * Sanitize a tool ID to match Anthropic's required pattern.\n * Replaces invalid characters with underscores.\n */\nfunction sanitizeToolId(id: string | undefined): string | undefined {\n if (!id || typeof id !== \"string\") return id;\n if (VALID_TOOL_ID_PATTERN.test(id)) return id;\n\n // Replace invalid characters with underscores\n return id.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n}\n\n/**\n * Type for messages with tool calls (OpenAI format).\n */\ntype MessageWithTools = ChatMessage & {\n tool_calls?: Array<{ id?: string; type?: string; function?: unknown }>;\n tool_call_id?: string;\n};\n\n/**\n * Type for content blocks that may contain tool IDs (Anthropic format in OpenAI wrapper).\n */\ntype ContentBlock = {\n type?: string;\n id?: string;\n tool_use_id?: string;\n [key: string]: unknown;\n};\n\n/**\n * Sanitize all tool IDs in messages to match Anthropic's pattern.\n * Handles both OpenAI format (tool_calls, tool_call_id) and content block formats.\n */\nfunction sanitizeToolIds(messages: ChatMessage[]): ChatMessage[] {\n if (!messages || messages.length === 0) return messages;\n\n let hasChanges = false;\n const sanitized = messages.map((msg) => {\n const typedMsg = msg as MessageWithTools;\n let msgChanged = false;\n let newMsg = { ...msg } as MessageWithTools;\n\n // Sanitize tool_calls[].id in assistant messages\n if (typedMsg.tool_calls && Array.isArray(typedMsg.tool_calls)) {\n const newToolCalls = typedMsg.tool_calls.map((tc) => {\n if (tc.id && typeof tc.id === \"string\") {\n const sanitized = sanitizeToolId(tc.id);\n if (sanitized !== tc.id) {\n msgChanged = true;\n return { ...tc, id: sanitized };\n }\n }\n return tc;\n });\n if (msgChanged) {\n newMsg = { ...newMsg, tool_calls: newToolCalls };\n }\n }\n\n // Sanitize tool_call_id in tool messages\n if (typedMsg.tool_call_id && typeof typedMsg.tool_call_id === \"string\") {\n const sanitized = sanitizeToolId(typedMsg.tool_call_id);\n if (sanitized !== typedMsg.tool_call_id) {\n msgChanged = true;\n newMsg = { ...newMsg, tool_call_id: sanitized };\n }\n }\n\n // Sanitize content blocks if content is an array (Anthropic-style content)\n if (Array.isArray(typedMsg.content)) {\n const newContent = (typedMsg.content as ContentBlock[]).map((block) => {\n if (!block || typeof block !== \"object\") return block;\n\n let blockChanged = false;\n let newBlock = { ...block };\n\n // tool_use blocks have \"id\"\n if (block.type === \"tool_use\" && block.id && typeof block.id === \"string\") {\n const sanitized = sanitizeToolId(block.id);\n if (sanitized !== block.id) {\n blockChanged = true;\n newBlock = { ...newBlock, id: sanitized };\n }\n }\n\n // tool_result blocks have \"tool_use_id\"\n if (\n block.type === \"tool_result\" &&\n block.tool_use_id &&\n typeof block.tool_use_id === \"string\"\n ) {\n const sanitized = sanitizeToolId(block.tool_use_id);\n if (sanitized !== block.tool_use_id) {\n blockChanged = true;\n newBlock = { ...newBlock, tool_use_id: sanitized };\n }\n }\n\n if (blockChanged) {\n msgChanged = true;\n return newBlock;\n }\n return block;\n });\n\n if (msgChanged) {\n newMsg = { ...newMsg, content: newContent };\n }\n }\n\n if (msgChanged) {\n hasChanges = true;\n return newMsg;\n }\n return msg;\n });\n\n return hasChanges ? sanitized : messages;\n}\n\n/**\n * Normalize message roles to standard OpenAI format.\n * Converts non-standard roles (e.g., \"developer\") to valid ones.\n */\nfunction normalizeMessageRoles(messages: ChatMessage[]): ChatMessage[] {\n if (!messages || messages.length === 0) return messages;\n\n let hasChanges = false;\n const normalized = messages.map((msg) => {\n if (VALID_ROLES.has(msg.role)) return msg;\n\n const mappedRole = ROLE_MAPPINGS[msg.role];\n if (mappedRole) {\n hasChanges = true;\n return { ...msg, role: mappedRole };\n }\n\n // Unknown role - default to \"user\" to avoid API errors\n hasChanges = true;\n return { ...msg, role: \"user\" };\n });\n\n return hasChanges ? normalized : messages;\n}\n\n/**\n * Normalize messages for Google models.\n * Google's Gemini API requires the first non-system message to be from \"user\".\n * If conversation starts with \"assistant\"/\"model\", prepend a placeholder user message.\n */\n\nfunction normalizeMessagesForGoogle(messages: ChatMessage[]): ChatMessage[] {\n if (!messages || messages.length === 0) return messages;\n\n // Find first non-system message\n let firstNonSystemIdx = -1;\n for (let i = 0; i < messages.length; i++) {\n if (messages[i].role !== \"system\") {\n firstNonSystemIdx = i;\n break;\n }\n }\n\n // If no non-system messages, return as-is\n if (firstNonSystemIdx === -1) return messages;\n\n const firstRole = messages[firstNonSystemIdx].role;\n\n // If first non-system message is already \"user\", no change needed\n if (firstRole === \"user\") return messages;\n\n // If first non-system message is \"assistant\" or \"model\", prepend a user message\n if (firstRole === \"assistant\" || firstRole === \"model\") {\n const normalized = [...messages];\n normalized.splice(firstNonSystemIdx, 0, {\n role: \"user\",\n content: \"(continuing conversation)\",\n });\n return normalized;\n }\n\n return messages;\n}\n\n/**\n * Check if a model is a Google model that requires message normalization.\n */\nfunction isGoogleModel(modelId: string): boolean {\n return modelId.startsWith(\"google/\") || modelId.startsWith(\"gemini\");\n}\n\n/**\n * Extended message type for thinking-enabled conversations.\n */\ntype ExtendedChatMessage = ChatMessage & {\n tool_calls?: unknown[];\n reasoning_content?: unknown;\n};\n\n/**\n * Normalize messages for thinking-enabled requests.\n * When thinking/extended_thinking is enabled, assistant messages with tool_calls\n * must have reasoning_content (can be empty string if not present).\n * Error: \"400 thinking is enabled but reasoning_content is missing in assistant tool call message\"\n */\nfunction normalizeMessagesForThinking(messages: ExtendedChatMessage[]): ExtendedChatMessage[] {\n if (!messages || messages.length === 0) return messages;\n\n let hasChanges = false;\n const normalized = messages.map((msg) => {\n // Skip if not assistant or already has reasoning_content\n if (msg.role !== \"assistant\" || msg.reasoning_content !== undefined) {\n return msg;\n }\n\n // Check for OpenAI format: tool_calls array\n const hasOpenAIToolCalls =\n msg.tool_calls && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0;\n\n // Check for Anthropic format: content array with tool_use blocks\n const hasAnthropicToolUse =\n Array.isArray(msg.content) &&\n (msg.content as Array<{ type?: string }>).some((block) => block?.type === \"tool_use\");\n\n if (hasOpenAIToolCalls || hasAnthropicToolUse) {\n hasChanges = true;\n return { ...msg, reasoning_content: \"\" };\n }\n return msg;\n });\n\n return hasChanges ? normalized : messages;\n}\n\n/**\n * Result of truncating messages.\n */\ntype TruncationResult<T> = {\n messages: T[];\n wasTruncated: boolean;\n originalCount: number;\n truncatedCount: number;\n};\n\n/**\n * Truncate messages to stay under BlockRun's MAX_MESSAGES limit.\n * Keeps all system messages and the most recent conversation history.\n * Returns the messages and whether truncation occurred.\n */\nfunction truncateMessages<T extends { role: string }>(messages: T[]): TruncationResult<T> {\n if (!messages || messages.length <= MAX_MESSAGES) {\n return {\n messages,\n wasTruncated: false,\n originalCount: messages?.length ?? 0,\n truncatedCount: messages?.length ?? 0,\n };\n }\n\n // Separate system messages from conversation\n const systemMsgs = messages.filter((m) => m.role === \"system\");\n const conversationMsgs = messages.filter((m) => m.role !== \"system\");\n\n // Keep all system messages + most recent conversation messages\n const maxConversation = MAX_MESSAGES - systemMsgs.length;\n const truncatedConversation = conversationMsgs.slice(-maxConversation);\n\n const result = [...systemMsgs, ...truncatedConversation];\n\n console.log(\n `[ClawRouter] Truncated messages: ${messages.length} → ${result.length} (kept ${systemMsgs.length} system + ${truncatedConversation.length} recent)`,\n );\n\n return {\n messages: result,\n wasTruncated: true,\n originalCount: messages.length,\n truncatedCount: result.length,\n };\n}\n\n// Kimi/Moonshot models use special Unicode tokens for thinking boundaries.\n// Pattern: <|begin▁of▁thinking|>content<|end▁of▁thinking|>\n// The | is fullwidth vertical bar (U+FF5C), ▁ is lower one-eighth block (U+2581).\n\n// Match full Kimi thinking blocks: <|begin...|>content<|end...|>\nconst KIMI_BLOCK_RE = /<[||][^<>]*begin[^<>]*[||]>[\\s\\S]*?<[||][^<>]*end[^<>]*[||]>/gi;\n\n// Match standalone Kimi tokens like <|end▁of▁thinking|>\nconst KIMI_TOKEN_RE = /<[||][^<>]*[||]>/g;\n\n// Standard thinking tags that may leak through from various models\nconst THINKING_TAG_RE = /<\\s*\\/?\\s*(?:think(?:ing)?|thought|antthinking)\\b[^>]*>/gi;\n\n// Full thinking blocks: <think>content</think>\nconst THINKING_BLOCK_RE =\n /<\\s*(?:think(?:ing)?|thought|antthinking)\\b[^>]*>[\\s\\S]*?<\\s*\\/\\s*(?:think(?:ing)?|thought|antthinking)\\s*>/gi;\n\n/**\n * Strip thinking tokens and blocks from model response content.\n * Handles both Kimi-style Unicode tokens and standard XML-style tags.\n *\n * NOTE: DSML tags (<|DSML|...>) are NOT stripped - those are tool calls\n * that should be handled by the API, not hidden from users.\n */\nfunction stripThinkingTokens(content: string): string {\n if (!content) return content;\n // Strip full Kimi thinking blocks first (begin...end with content)\n let cleaned = content.replace(KIMI_BLOCK_RE, \"\");\n // Strip remaining standalone Kimi tokens\n cleaned = cleaned.replace(KIMI_TOKEN_RE, \"\");\n // Strip full thinking blocks (<think>...</think>)\n cleaned = cleaned.replace(THINKING_BLOCK_RE, \"\");\n // Strip remaining standalone thinking tags\n cleaned = cleaned.replace(THINKING_TAG_RE, \"\");\n return cleaned;\n}\n\n/** Callback info for low balance warning */\nexport type LowBalanceInfo = {\n balanceUSD: string;\n walletAddress: string;\n};\n\n/** Callback info for insufficient funds error */\nexport type InsufficientFundsInfo = {\n balanceUSD: string;\n requiredUSD: string;\n walletAddress: string;\n};\n\nexport type ProxyOptions = {\n walletKey: string;\n apiBase?: string;\n /** Port to listen on (default: 8402) */\n port?: number;\n routingConfig?: Partial<RoutingConfig>;\n /** Request timeout in ms (default: 180000 = 3 minutes). Covers on-chain tx + LLM response. */\n requestTimeoutMs?: number;\n /** Skip balance checks (for testing only). Default: false */\n skipBalanceCheck?: boolean;\n /**\n * Session persistence config. When enabled, maintains model selection\n * across requests within a session to prevent mid-task model switching.\n */\n sessionConfig?: Partial<SessionConfig>;\n /**\n * Auto-compress large requests to reduce network usage.\n * When enabled, requests are automatically compressed using\n * LLM-safe context compression (15-40% reduction).\n * Default: true\n */\n autoCompressRequests?: boolean;\n /**\n * Threshold in KB to trigger auto-compression (default: 180).\n * Requests larger than this are compressed before sending.\n * Set to 0 to compress all requests.\n */\n compressionThresholdKB?: number;\n /**\n * Response caching config. When enabled, identical requests return\n * cached responses instead of making new API calls.\n * Default: enabled with 10 minute TTL, 200 max entries.\n */\n cacheConfig?: ResponseCacheConfig;\n onReady?: (port: number) => void;\n onError?: (error: Error) => void;\n onPayment?: (info: { model: string; amount: string; network: string }) => void;\n onRouted?: (decision: RoutingDecision) => void;\n /** Called when balance drops below $1.00 (warning, request still proceeds) */\n onLowBalance?: (info: LowBalanceInfo) => void;\n /** Called when balance is insufficient for a request (request fails) */\n onInsufficientFunds?: (info: InsufficientFundsInfo) => void;\n};\n\nexport type ProxyHandle = {\n port: number;\n baseUrl: string;\n walletAddress: string;\n balanceMonitor: BalanceMonitor;\n close: () => Promise<void>;\n};\n\n/**\n * Build model pricing map from BLOCKRUN_MODELS.\n */\nfunction buildModelPricing(): Map<string, ModelPricing> {\n const map = new Map<string, ModelPricing>();\n for (const m of BLOCKRUN_MODELS) {\n if (m.id === AUTO_MODEL) continue; // skip meta-model\n map.set(m.id, { inputPrice: m.inputPrice, outputPrice: m.outputPrice });\n }\n return map;\n}\n\ntype ModelListEntry = {\n id: string;\n object: \"model\";\n created: number;\n owned_by: string;\n};\n\n/**\n * Build `/v1/models` response entries from the full OpenClaw model registry.\n * This includes alias IDs (e.g., `flash`, `kimi`) so `/model <alias>` works reliably.\n */\nexport function buildProxyModelList(\n createdAt: number = Math.floor(Date.now() / 1000),\n): ModelListEntry[] {\n const seen = new Set<string>();\n return OPENCLAW_MODELS.filter((model) => {\n if (seen.has(model.id)) return false;\n seen.add(model.id);\n return true;\n }).map((model) => ({\n id: model.id,\n object: \"model\",\n created: createdAt,\n owned_by: model.id.includes(\"/\") ? (model.id.split(\"/\")[0] ?? \"blockrun\") : \"blockrun\",\n }));\n}\n\n/**\n * Merge partial routing config overrides with defaults.\n */\nfunction mergeRoutingConfig(overrides?: Partial<RoutingConfig>): RoutingConfig {\n if (!overrides) return DEFAULT_ROUTING_CONFIG;\n return {\n ...DEFAULT_ROUTING_CONFIG,\n ...overrides,\n classifier: { ...DEFAULT_ROUTING_CONFIG.classifier, ...overrides.classifier },\n scoring: { ...DEFAULT_ROUTING_CONFIG.scoring, ...overrides.scoring },\n tiers: { ...DEFAULT_ROUTING_CONFIG.tiers, ...overrides.tiers },\n overrides: { ...DEFAULT_ROUTING_CONFIG.overrides, ...overrides.overrides },\n };\n}\n\n/**\n * Estimate USDC cost for a request based on model pricing.\n * Returns amount string in USDC smallest unit (6 decimals) or undefined if unknown.\n */\nfunction estimateAmount(\n modelId: string,\n bodyLength: number,\n maxTokens: number,\n): string | undefined {\n const model = BLOCKRUN_MODELS.find((m) => m.id === modelId);\n if (!model) return undefined;\n\n // Rough estimate: ~4 chars per token for input\n const estimatedInputTokens = Math.ceil(bodyLength / 4);\n const estimatedOutputTokens = maxTokens || model.maxOutput || 4096;\n\n const costUsd =\n (estimatedInputTokens / 1_000_000) * model.inputPrice +\n (estimatedOutputTokens / 1_000_000) * model.outputPrice;\n\n // Convert to USDC 6-decimal integer, add 20% buffer for estimation error\n // Minimum 1000 ($0.001) to match CDP Facilitator's enforced minimum payment\n const amountMicros = Math.max(1000, Math.ceil(costUsd * 1.2 * 1_000_000));\n return amountMicros.toString();\n}\n\n/**\n * Proxy a partner API request through x402 payment flow.\n *\n * Simplified proxy for partner endpoints (/v1/x/*, /v1/partner/*).\n * No smart routing, SSE, compression, or sessions — just collect body,\n * forward via payFetch (which handles 402 automatically), and stream back.\n */\nasync function proxyPartnerRequest(\n req: IncomingMessage,\n res: ServerResponse,\n apiBase: string,\n payFetch: (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ) => Promise<Response>,\n): Promise<void> {\n const startTime = Date.now();\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 const body = Buffer.concat(bodyChunks);\n\n // Forward headers (strip hop-by-hop)\n const headers: Record<string, string> = {};\n for (const [key, value] of Object.entries(req.headers)) {\n if (\n key === \"host\" ||\n key === \"connection\" ||\n key === \"transfer-encoding\" ||\n key === \"content-length\"\n )\n continue;\n if (typeof value === \"string\") headers[key] = value;\n }\n if (!headers[\"content-type\"]) headers[\"content-type\"] = \"application/json\";\n headers[\"user-agent\"] = USER_AGENT;\n\n console.log(`[ClawRouter] Partner request: ${req.method} ${req.url}`);\n\n const upstream = await payFetch(upstreamUrl, {\n method: req.method ?? \"POST\",\n headers,\n body: body.length > 0 ? new Uint8Array(body) : undefined,\n });\n\n // Forward response headers\n const responseHeaders: Record<string, string> = {};\n upstream.headers.forEach((value, key) => {\n if (key === \"transfer-encoding\" || key === \"connection\" || key === \"content-encoding\") return;\n responseHeaders[key] = value;\n });\n\n res.writeHead(upstream.status, responseHeaders);\n\n // Stream 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 safeWrite(res, Buffer.from(value));\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n res.end();\n\n const latencyMs = Date.now() - startTime;\n console.log(`[ClawRouter] Partner response: ${upstream.status} (${latencyMs}ms)`);\n\n // Log partner usage (fire-and-forget)\n logUsage({\n timestamp: new Date().toISOString(),\n model: \"partner\",\n tier: \"PARTNER\",\n cost: 0, // Actual cost handled by x402 settlement\n baselineCost: 0,\n savings: 0,\n latencyMs,\n partnerId:\n (req.url?.split(\"?\")[0] ?? \"\").replace(/^\\/v1\\//, \"\").replace(/\\//g, \"_\") || \"unknown\",\n service: \"partner\",\n }).catch(() => {});\n}\n\n/**\n * Upload a base64 data URI to catbox.moe and return a public URL.\n * Google image models (nano-banana) return data URIs instead of hosted URLs,\n * which breaks Telegram and other clients that can't render raw base64.\n */\nasync function uploadDataUriToHost(dataUri: string): Promise<string> {\n const match = dataUri.match(/^data:(image\\/\\w+);base64,(.+)$/);\n if (!match) throw new Error(\"Invalid data URI format\");\n const [, mimeType, b64Data] = match;\n const ext = mimeType === \"image/jpeg\" ? \"jpg\" : mimeType.split(\"/\")[1] ?? \"png\";\n\n const buffer = Buffer.from(b64Data, \"base64\");\n const blob = new Blob([buffer], { type: mimeType });\n\n const form = new FormData();\n form.append(\"reqtype\", \"fileupload\");\n form.append(\"fileToUpload\", blob, `image.${ext}`);\n\n const resp = await fetch(\"https://catbox.moe/user/api.php\", {\n method: \"POST\",\n body: form,\n });\n\n if (!resp.ok) throw new Error(`catbox.moe upload failed: HTTP ${resp.status}`);\n const result = await resp.text();\n if (result.startsWith(\"https://\")) {\n return result.trim();\n }\n throw new Error(`catbox.moe upload failed: ${result}`);\n}\n\n/**\n * Start the local x402 proxy server.\n *\n * If a proxy is already running on the target port, reuses it instead of failing.\n * Port can be configured via BLOCKRUN_PROXY_PORT environment variable.\n *\n * Returns a handle with the assigned port, base URL, and a close function.\n */\nexport async function startProxy(options: ProxyOptions): Promise<ProxyHandle> {\n const apiBase = options.apiBase ?? BLOCKRUN_API;\n\n // Determine port: options.port > env var > default\n const listenPort = options.port ?? getProxyPort();\n\n // Check if a proxy is already running on this port\n const existingWallet = await checkExistingProxy(listenPort);\n if (existingWallet) {\n // Proxy already running — reuse it instead of failing with EADDRINUSE\n const account = privateKeyToAccount(options.walletKey as `0x${string}`);\n const balanceMonitor = new BalanceMonitor(account.address);\n const baseUrl = `http://127.0.0.1:${listenPort}`;\n\n // Verify the existing proxy is using the same wallet (or warn if different)\n if (existingWallet !== account.address) {\n console.warn(\n `[ClawRouter] Existing proxy on port ${listenPort} uses wallet ${existingWallet}, but current config uses ${account.address}. Reusing existing proxy.`,\n );\n }\n\n options.onReady?.(listenPort);\n\n return {\n port: listenPort,\n baseUrl,\n walletAddress: existingWallet,\n balanceMonitor,\n close: async () => {\n // No-op: we didn't start this proxy, so we shouldn't close it\n },\n };\n }\n\n // Create x402 payment-enabled fetch from wallet private key\n const account = privateKeyToAccount(options.walletKey as `0x${string}`);\n const { fetch: payFetch } = createPaymentFetch(options.walletKey as `0x${string}`);\n\n // Create balance monitor for pre-request checks\n const balanceMonitor = new BalanceMonitor(account.address);\n\n // Build router options (100% local — no external API calls for routing)\n const routingConfig = mergeRoutingConfig(options.routingConfig);\n const modelPricing = buildModelPricing();\n const routerOpts: RouterOptions = {\n config: routingConfig,\n modelPricing,\n };\n\n // Request deduplicator (shared across all requests)\n const deduplicator = new RequestDeduplicator();\n\n // Response cache for identical requests (longer TTL than dedup)\n const responseCache = new ResponseCache(options.cacheConfig);\n\n // Session store for model persistence (prevents mid-task model switching)\n const sessionStore = new SessionStore(options.sessionConfig);\n\n // Session journal for memory (enables agents to recall earlier work)\n const sessionJournal = new SessionJournal();\n\n // Track active connections for graceful cleanup\n const connections = new Set<import(\"net\").Socket>();\n\n const server = createServer(async (req: IncomingMessage, res: ServerResponse) => {\n // Add stream error handlers to prevent server crashes\n req.on(\"error\", (err) => {\n console.error(`[ClawRouter] Request stream error: ${err.message}`);\n // Don't throw - just log and let request handler deal with it\n });\n\n res.on(\"error\", (err) => {\n console.error(`[ClawRouter] Response stream error: ${err.message}`);\n // Don't try to write to failed socket - just log\n });\n\n // Finished wrapper for guaranteed cleanup on response completion/error\n finished(res, (err) => {\n if (err && err.code !== \"ERR_STREAM_DESTROYED\") {\n console.error(`[ClawRouter] Response finished with error: ${err.message}`);\n }\n // Note: heartbeatInterval cleanup happens in res.on(\"close\") handler\n // Note: completed and dedup cleanup happens in the res.on(\"close\") handler below\n });\n\n // Request finished wrapper for complete stream lifecycle tracking\n finished(req, (err) => {\n if (err && err.code !== \"ERR_STREAM_DESTROYED\") {\n console.error(`[ClawRouter] Request finished with error: ${err.message}`);\n }\n });\n\n // Health check with optional balance info\n if (req.url === \"/health\" || req.url?.startsWith(\"/health?\")) {\n const url = new URL(req.url, \"http://localhost\");\n const full = url.searchParams.get(\"full\") === \"true\";\n\n const response: Record<string, unknown> = {\n status: \"ok\",\n wallet: account.address,\n };\n\n if (full) {\n try {\n const balanceInfo = await balanceMonitor.checkBalance();\n response.balance = balanceInfo.balanceUSD;\n response.isLow = balanceInfo.isLow;\n response.isEmpty = balanceInfo.isEmpty;\n } catch {\n response.balanceError = \"Could not fetch balance\";\n }\n }\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(response));\n return;\n }\n\n // Cache stats endpoint\n if (req.url === \"/cache\" || req.url?.startsWith(\"/cache?\")) {\n const stats = responseCache.getStats();\n res.writeHead(200, {\n \"Content-Type\": \"application/json\",\n \"Cache-Control\": \"no-cache\",\n });\n res.end(JSON.stringify(stats, null, 2));\n return;\n }\n\n // Stats API endpoint - returns JSON for programmatic access\n if (req.url === \"/stats\" || req.url?.startsWith(\"/stats?\")) {\n try {\n const url = new URL(req.url, \"http://localhost\");\n const days = parseInt(url.searchParams.get(\"days\") || \"7\", 10);\n const stats = await getStats(Math.min(days, 30));\n\n res.writeHead(200, {\n \"Content-Type\": \"application/json\",\n \"Cache-Control\": \"no-cache\",\n });\n res.end(JSON.stringify(stats, null, 2));\n } catch (err) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: `Failed to get stats: ${err instanceof Error ? err.message : String(err)}`,\n }),\n );\n }\n return;\n }\n\n // --- Handle /v1/models locally (no upstream call needed) ---\n if (req.url === \"/v1/models\" && req.method === \"GET\") {\n const models = buildProxyModelList();\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ object: \"list\", data: models }));\n return;\n }\n\n // --- Handle partner API paths (/v1/x/*, /v1/partner/*) ---\n if (req.url?.match(/^\\/v1\\/(?:x|partner)\\//)) {\n try {\n await proxyPartnerRequest(req, res, apiBase, payFetch);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n options.onError?.(error);\n if (!res.headersSent) {\n res.writeHead(502, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: { message: `Partner proxy error: ${error.message}`, type: \"partner_error\" },\n }),\n );\n }\n }\n return;\n }\n\n // Only proxy paths starting with /v1\n if (!req.url?.startsWith(\"/v1\")) {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Not found\" }));\n return;\n }\n\n try {\n await proxyRequest(\n req,\n res,\n apiBase,\n payFetch,\n options,\n routerOpts,\n deduplicator,\n balanceMonitor,\n sessionStore,\n responseCache,\n sessionJournal,\n );\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n options.onError?.(error);\n\n if (!res.headersSent) {\n res.writeHead(502, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: { message: `Proxy error: ${error.message}`, type: \"proxy_error\" },\n }),\n );\n } else if (!res.writableEnded) {\n // Headers already sent (streaming) — send error as SSE event\n res.write(\n `data: ${JSON.stringify({ error: { message: error.message, type: \"proxy_error\" } })}\\n\\n`,\n );\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n }\n }\n });\n\n // Listen on configured port with retry logic for TIME_WAIT handling\n // When gateway restarts quickly, the port may still be in TIME_WAIT state.\n // We retry with delay instead of incorrectly assuming a proxy is running.\n const tryListen = (attempt: number): Promise<void> => {\n return new Promise<void>((resolveAttempt, rejectAttempt) => {\n const onError = async (err: NodeJS.ErrnoException) => {\n server.removeListener(\"error\", onError);\n\n if (err.code === \"EADDRINUSE\") {\n // Port is in use - check if a proxy is actually running\n const existingWallet = await checkExistingProxy(listenPort);\n if (existingWallet) {\n // Proxy is actually running - this is fine, reuse it\n console.log(`[ClawRouter] Existing proxy detected on port ${listenPort}, reusing`);\n rejectAttempt({ code: \"REUSE_EXISTING\", wallet: existingWallet });\n return;\n }\n\n // Port is in TIME_WAIT (no proxy responding) - retry after delay\n if (attempt < PORT_RETRY_ATTEMPTS) {\n console.log(\n `[ClawRouter] Port ${listenPort} in TIME_WAIT, retrying in ${PORT_RETRY_DELAY_MS}ms (attempt ${attempt}/${PORT_RETRY_ATTEMPTS})`,\n );\n rejectAttempt({ code: \"RETRY\", attempt });\n return;\n }\n\n // Max retries exceeded\n console.error(\n `[ClawRouter] Port ${listenPort} still in use after ${PORT_RETRY_ATTEMPTS} attempts`,\n );\n rejectAttempt(err);\n return;\n }\n\n rejectAttempt(err);\n };\n\n server.once(\"error\", onError);\n server.listen(listenPort, \"127.0.0.1\", () => {\n server.removeListener(\"error\", onError);\n resolveAttempt();\n });\n });\n };\n\n // Retry loop for port binding\n let lastError: Error | undefined;\n for (let attempt = 1; attempt <= PORT_RETRY_ATTEMPTS; attempt++) {\n try {\n await tryListen(attempt);\n break; // Success\n } catch (err: unknown) {\n const error = err as { code?: string; wallet?: string; attempt?: number };\n\n if (error.code === \"REUSE_EXISTING\" && error.wallet) {\n // Proxy is running, reuse it\n const baseUrl = `http://127.0.0.1:${listenPort}`;\n options.onReady?.(listenPort);\n return {\n port: listenPort,\n baseUrl,\n walletAddress: error.wallet,\n balanceMonitor,\n close: async () => {\n // No-op: we didn't start this proxy, so we shouldn't close it\n },\n };\n }\n\n if (error.code === \"RETRY\") {\n // Wait before retry\n await new Promise((r) => setTimeout(r, PORT_RETRY_DELAY_MS));\n continue;\n }\n\n // Other error - throw\n lastError = err as Error;\n break;\n }\n }\n\n if (lastError) {\n throw lastError;\n }\n\n // Server is now listening - set up remaining handlers\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 // Check for updates (non-blocking)\n checkForUpdates();\n\n // Add runtime error handler AFTER successful listen\n // This handles errors that occur during server operation (not just startup)\n server.on(\"error\", (err) => {\n console.error(`[ClawRouter] Server runtime error: ${err.message}`);\n options.onError?.(err);\n // Don't crash - log and continue\n });\n\n // Handle client connection errors (bad requests, socket errors)\n server.on(\"clientError\", (err, socket) => {\n console.error(`[ClawRouter] Client error: ${err.message}`);\n // Send 400 Bad Request if socket is still writable\n if (socket.writable && !socket.destroyed) {\n socket.end(\"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\");\n }\n });\n\n // Track connections for graceful cleanup\n server.on(\"connection\", (socket) => {\n connections.add(socket);\n\n // Set 5-minute timeout for streaming requests\n socket.setTimeout(300_000);\n\n socket.on(\"timeout\", () => {\n console.error(`[ClawRouter] Socket timeout, destroying connection`);\n socket.destroy();\n });\n\n socket.on(\"end\", () => {\n // Half-closed by client (FIN received)\n });\n\n socket.on(\"error\", (err) => {\n console.error(`[ClawRouter] Socket error: ${err.message}`);\n });\n\n socket.on(\"close\", () => {\n connections.delete(socket);\n });\n });\n\n return {\n port,\n baseUrl,\n walletAddress: account.address,\n balanceMonitor,\n close: () =>\n new Promise<void>((res, rej) => {\n const timeout = setTimeout(() => {\n rej(new Error(\"[ClawRouter] Close timeout after 4s\"));\n }, 4000);\n\n sessionStore.close();\n // Destroy all active connections before closing server\n for (const socket of connections) {\n socket.destroy();\n }\n connections.clear();\n server.close((err) => {\n clearTimeout(timeout);\n if (err) {\n rej(err);\n } else {\n res();\n }\n });\n }),\n };\n}\n\n/** Result of attempting a model request */\ntype ModelRequestResult = {\n success: boolean;\n response?: Response;\n errorBody?: string;\n errorStatus?: number;\n isProviderError?: boolean;\n};\n\n/**\n * Attempt a request with a specific model.\n * Returns the response or error details for fallback decision.\n */\nasync function tryModelRequest(\n upstreamUrl: string,\n method: string,\n headers: Record<string, string>,\n body: Buffer,\n modelId: string,\n maxTokens: number,\n payFetch: (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ) => Promise<Response>,\n balanceMonitor: BalanceMonitor,\n signal: AbortSignal,\n): Promise<ModelRequestResult> {\n // Update model in body and normalize messages\n let requestBody = body;\n try {\n const parsed = JSON.parse(body.toString()) as Record<string, unknown>;\n parsed.model = modelId;\n\n // Normalize message roles (e.g., \"developer\" -> \"system\")\n if (Array.isArray(parsed.messages)) {\n parsed.messages = normalizeMessageRoles(parsed.messages as ChatMessage[]);\n }\n\n // Truncate messages to stay under BlockRun's limit (200 messages)\n if (Array.isArray(parsed.messages)) {\n const truncationResult = truncateMessages(parsed.messages as ChatMessage[]);\n parsed.messages = truncationResult.messages;\n }\n\n // Sanitize tool IDs to match Anthropic's pattern (alphanumeric, underscore, hyphen only)\n if (Array.isArray(parsed.messages)) {\n parsed.messages = sanitizeToolIds(parsed.messages as ChatMessage[]);\n }\n\n // Normalize messages for Google models (first non-system message must be \"user\")\n if (isGoogleModel(modelId) && Array.isArray(parsed.messages)) {\n parsed.messages = normalizeMessagesForGoogle(parsed.messages as ChatMessage[]);\n }\n\n // Normalize messages for thinking-enabled requests (add reasoning_content to tool calls)\n // Check request flags AND target model - reasoning models have thinking enabled server-side\n const hasThinkingEnabled = !!(\n parsed.thinking ||\n parsed.extended_thinking ||\n isReasoningModel(modelId)\n );\n if (hasThinkingEnabled && Array.isArray(parsed.messages)) {\n parsed.messages = normalizeMessagesForThinking(parsed.messages as ExtendedChatMessage[]);\n }\n\n requestBody = Buffer.from(JSON.stringify(parsed));\n } catch {\n // If body isn't valid JSON, use as-is\n }\n\n // Estimate cost for pre-auth\n const estimated = estimateAmount(modelId, requestBody.length, maxTokens);\n const preAuth: PreAuthParams | undefined = estimated ? { estimatedAmount: estimated } : undefined;\n\n try {\n const response = await payFetch(\n upstreamUrl,\n {\n method,\n headers,\n body: requestBody.length > 0 ? new Uint8Array(requestBody) : undefined,\n signal,\n },\n preAuth,\n );\n\n // Check for provider errors\n if (response.status !== 200) {\n // Clone response to read body without consuming it\n const errorBody = await response.text();\n const isProviderErr = isProviderError(response.status, errorBody);\n\n return {\n success: false,\n errorBody,\n errorStatus: response.status,\n isProviderError: isProviderErr,\n };\n }\n\n // Detect provider degradation hidden inside HTTP 200 responses.\n const contentType = response.headers.get(\"content-type\") || \"\";\n if (contentType.includes(\"json\") || contentType.includes(\"text\")) {\n try {\n const responseBody = await response.clone().text();\n const degradedReason = detectDegradedSuccessResponse(responseBody);\n if (degradedReason) {\n return {\n success: false,\n errorBody: degradedReason,\n errorStatus: 503,\n isProviderError: true,\n };\n }\n } catch {\n // Ignore body inspection failures and pass through response.\n }\n }\n\n return { success: true, response };\n } catch (err) {\n const errorMsg = err instanceof Error ? err.message : String(err);\n return {\n success: false,\n errorBody: errorMsg,\n errorStatus: 500,\n isProviderError: true, // Network errors are retryable\n };\n }\n}\n\n/**\n * Proxy a single request through x402 payment flow to BlockRun API.\n *\n * Optimizations applied in order:\n * 1. Dedup check — if same request body seen within 30s, replay cached response\n * 2. Streaming heartbeat — for stream:true, send 200 + heartbeats immediately\n * 3. Payment pre-auth — estimate USDC amount and pre-sign to skip 402 round trip\n * 4. Smart routing — when model is \"blockrun/auto\", pick cheapest capable model\n * 5. Fallback chain — on provider errors, try next model in tier's fallback list\n */\nasync function proxyRequest(\n req: IncomingMessage,\n res: ServerResponse,\n apiBase: string,\n payFetch: (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ) => Promise<Response>,\n options: ProxyOptions,\n routerOpts: RouterOptions,\n deduplicator: RequestDeduplicator,\n balanceMonitor: BalanceMonitor,\n sessionStore: SessionStore,\n responseCache: ResponseCache,\n sessionJournal: SessionJournal,\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 // Track original context size for response headers\n const originalContextSizeKB = Math.ceil(body.length / 1024);\n\n // Routing debug info is on by default; disable with x-clawrouter-debug: false\n const debugMode = req.headers[\"x-clawrouter-debug\"] !== \"false\";\n\n // --- Smart routing ---\n let routingDecision: RoutingDecision | undefined;\n let hasTools = false; // true when request includes a tools schema\n let hasVision = false; // true when request includes image_url content parts\n let isStreaming = false;\n let modelId = \"\";\n let maxTokens = 4096;\n let routingProfile: \"free\" | \"eco\" | \"auto\" | \"premium\" | null = null;\n let accumulatedContent = \"\"; // For session journal event extraction\n const isChatCompletion = req.url?.includes(\"/chat/completions\");\n\n // Extract session ID early for journal operations (header-only at this point)\n const sessionId = getSessionId(req.headers as Record<string, string | string[] | undefined>);\n // Full session ID (header + content-derived) — populated once messages are parsed\n let effectiveSessionId: string | undefined = sessionId;\n\n if (isChatCompletion && body.length > 0) {\n try {\n const parsed = JSON.parse(body.toString()) as Record<string, unknown>;\n isStreaming = parsed.stream === true;\n modelId = (parsed.model as string) || \"\";\n maxTokens = (parsed.max_tokens as number) || 4096;\n let bodyModified = false;\n\n // Extract last user message content (used by session journal + /debug command)\n const parsedMessages = Array.isArray(parsed.messages)\n ? (parsed.messages as Array<{ role: string; content: unknown }>)\n : [];\n const lastUserMsg = [...parsedMessages].reverse().find((m) => m.role === \"user\");\n const rawLastContent = lastUserMsg?.content;\n const lastContent =\n typeof rawLastContent === \"string\"\n ? rawLastContent\n : Array.isArray(rawLastContent)\n ? (rawLastContent as Array<{ type: string; text?: string }>)\n .filter((b) => b.type === \"text\")\n .map((b) => b.text ?? \"\")\n .join(\" \")\n : \"\";\n\n // --- Session Journal: Inject context if needed ---\n // Check if the last user message asks about past work\n if (sessionId && parsedMessages.length > 0) {\n const messages = parsedMessages;\n\n if (sessionJournal.needsContext(lastContent)) {\n const journalText = sessionJournal.format(sessionId);\n if (journalText) {\n // Find system message and prepend journal, or add a new system message\n const sysIdx = messages.findIndex((m) => m.role === \"system\");\n if (sysIdx >= 0 && typeof messages[sysIdx].content === \"string\") {\n messages[sysIdx] = {\n ...messages[sysIdx],\n content: journalText + \"\\n\\n\" + messages[sysIdx].content,\n };\n } else {\n messages.unshift({ role: \"system\", content: journalText });\n }\n parsed.messages = messages;\n bodyModified = true;\n console.log(\n `[ClawRouter] Injected session journal (${journalText.length} chars) for session ${sessionId.slice(0, 8)}...`,\n );\n }\n }\n }\n\n // --- /debug command: return routing diagnostics without calling upstream ---\n if (lastContent.startsWith(\"/debug\")) {\n const debugPrompt = lastContent.slice(\"/debug\".length).trim() || \"hello\";\n const messages = parsed.messages as Array<{ role: string; content: unknown }>;\n const systemMsg = messages?.find((m) => m.role === \"system\");\n const systemPrompt = typeof systemMsg?.content === \"string\" ? systemMsg.content : undefined;\n const fullText = `${systemPrompt ?? \"\"} ${debugPrompt}`;\n const estimatedTokens = Math.ceil(fullText.length / 4);\n\n // Determine routing profile\n const normalizedModel =\n typeof parsed.model === \"string\" ? parsed.model.trim().toLowerCase() : \"\";\n const profileName = normalizedModel.replace(\"blockrun/\", \"\");\n const debugProfile = (\n [\"free\", \"eco\", \"auto\", \"premium\"].includes(profileName) ? profileName : \"auto\"\n ) as \"free\" | \"eco\" | \"auto\" | \"premium\";\n\n // Run scoring\n const scoring = classifyByRules(\n debugPrompt,\n systemPrompt,\n estimatedTokens,\n DEFAULT_ROUTING_CONFIG.scoring,\n );\n\n // Run full routing decision\n const debugRouting = route(debugPrompt, systemPrompt, maxTokens, {\n ...routerOpts,\n routingProfile: debugProfile,\n });\n\n // Format dimension scores\n const dimLines = (scoring.dimensions ?? [])\n .map((d) => {\n const nameStr = (d.name + \":\").padEnd(24);\n const scoreStr = d.score.toFixed(2).padStart(6);\n const sigStr = d.signal ? ` [${d.signal}]` : \"\";\n return ` ${nameStr}${scoreStr}${sigStr}`;\n })\n .join(\"\\n\");\n\n // Session info\n const sess = sessionId ? sessionStore.getSession(sessionId) : undefined;\n const sessLine = sess\n ? `Session: ${sessionId!.slice(0, 8)}... → pinned: ${sess.model} (${sess.requestCount} requests)`\n : sessionId\n ? `Session: ${sessionId.slice(0, 8)}... → no pinned model`\n : \"Session: none\";\n\n const { simpleMedium, mediumComplex, complexReasoning } =\n DEFAULT_ROUTING_CONFIG.scoring.tierBoundaries;\n\n const debugText = [\n \"ClawRouter Debug\",\n \"\",\n `Profile: ${debugProfile} | Tier: ${debugRouting.tier} | Model: ${debugRouting.model}`,\n `Confidence: ${debugRouting.confidence.toFixed(2)} | Cost: $${debugRouting.costEstimate.toFixed(4)} | Savings: ${(debugRouting.savings * 100).toFixed(0)}%`,\n `Reasoning: ${debugRouting.reasoning}`,\n \"\",\n `Scoring (weighted: ${scoring.score.toFixed(3)})`,\n dimLines,\n \"\",\n `Tier Boundaries: SIMPLE <${simpleMedium.toFixed(2)} | MEDIUM <${mediumComplex.toFixed(2)} | COMPLEX <${complexReasoning.toFixed(2)} | REASONING >=${complexReasoning.toFixed(2)}`,\n \"\",\n sessLine,\n ].join(\"\\n\");\n\n // Build synthetic OpenAI chat completion response\n const completionId = `chatcmpl-debug-${Date.now()}`;\n const timestamp = Math.floor(Date.now() / 1000);\n const syntheticResponse = {\n id: completionId,\n object: \"chat.completion\",\n created: timestamp,\n model: \"clawrouter/debug\",\n choices: [\n {\n index: 0,\n message: { role: \"assistant\", content: debugText },\n finish_reason: \"stop\",\n },\n ],\n usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },\n };\n\n if (isStreaming) {\n // SSE streaming response\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n });\n const sseChunk = {\n id: completionId,\n object: \"chat.completion.chunk\",\n created: timestamp,\n model: \"clawrouter/debug\",\n choices: [\n {\n index: 0,\n delta: { role: \"assistant\", content: debugText },\n finish_reason: null,\n },\n ],\n };\n const sseDone = {\n id: completionId,\n object: \"chat.completion.chunk\",\n created: timestamp,\n model: \"clawrouter/debug\",\n choices: [{ index: 0, delta: {}, finish_reason: \"stop\" }],\n };\n res.write(`data: ${JSON.stringify(sseChunk)}\\n\\n`);\n res.write(`data: ${JSON.stringify(sseDone)}\\n\\n`);\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n } else {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(syntheticResponse));\n }\n console.log(`[ClawRouter] /debug command → ${debugRouting.tier} | ${debugRouting.model}`);\n return;\n }\n\n // --- /imagegen command: generate an image via BlockRun image API ---\n if (lastContent.startsWith(\"/imagegen\")) {\n const imageArgs = lastContent.slice(\"/imagegen\".length).trim();\n\n // Parse optional flags: /imagegen --model dall-e-3 --size 1792x1024 a cute cat\n let imageModel = \"google/nano-banana\";\n let imageSize = \"1024x1024\";\n let imagePrompt = imageArgs;\n\n // Extract --model flag\n const modelMatch = imageArgs.match(/--model\\s+(\\S+)/);\n if (modelMatch) {\n const raw = modelMatch[1];\n // Resolve shorthand aliases\n const IMAGE_MODEL_ALIASES: Record<string, string> = {\n \"dall-e-3\": \"openai/dall-e-3\",\n \"dalle3\": \"openai/dall-e-3\",\n \"dalle\": \"openai/dall-e-3\",\n \"gpt-image\": \"openai/gpt-image-1\",\n \"gpt-image-1\": \"openai/gpt-image-1\",\n \"flux\": \"black-forest/flux-1.1-pro\",\n \"flux-pro\": \"black-forest/flux-1.1-pro\",\n \"banana\": \"google/nano-banana\",\n \"nano-banana\": \"google/nano-banana\",\n \"banana-pro\": \"google/nano-banana-pro\",\n \"nano-banana-pro\": \"google/nano-banana-pro\",\n };\n imageModel = IMAGE_MODEL_ALIASES[raw] ?? raw;\n imagePrompt = imagePrompt.replace(/--model\\s+\\S+/, \"\").trim();\n }\n\n // Extract --size flag\n const sizeMatch = imageArgs.match(/--size\\s+(\\d+x\\d+)/);\n if (sizeMatch) {\n imageSize = sizeMatch[1];\n imagePrompt = imagePrompt.replace(/--size\\s+\\d+x\\d+/, \"\").trim();\n }\n\n if (!imagePrompt) {\n const errorText = [\n \"Usage: /imagegen <prompt>\",\n \"\",\n \"Options:\",\n \" --model <model> Model to use (default: nano-banana)\",\n \" --size <WxH> Image size (default: 1024x1024)\",\n \"\",\n \"Models:\",\n \" nano-banana Google Gemini Flash — $0.05/image\",\n \" banana-pro Google Gemini Pro — $0.10/image (up to 4K)\",\n \" dall-e-3 OpenAI DALL-E 3 — $0.04/image\",\n \" gpt-image OpenAI GPT Image 1 — $0.02/image\",\n \" flux Black Forest Flux 1.1 Pro — $0.04/image\",\n \"\",\n \"Examples:\",\n \" /imagegen a cat wearing sunglasses\",\n \" /imagegen --model dall-e-3 a futuristic city at sunset\",\n \" /imagegen --model banana-pro --size 2048x2048 mountain landscape\",\n ].join(\"\\n\");\n\n const completionId = `chatcmpl-image-${Date.now()}`;\n const timestamp = Math.floor(Date.now() / 1000);\n if (isStreaming) {\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n });\n res.write(`data: ${JSON.stringify({ id: completionId, object: \"chat.completion.chunk\", created: timestamp, model: \"clawrouter/image\", choices: [{ index: 0, delta: { role: \"assistant\", content: errorText }, finish_reason: null }] })}\\n\\n`);\n res.write(`data: ${JSON.stringify({ id: completionId, object: \"chat.completion.chunk\", created: timestamp, model: \"clawrouter/image\", choices: [{ index: 0, delta: {}, finish_reason: \"stop\" }] })}\\n\\n`);\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n } else {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({\n id: completionId, object: \"chat.completion\", created: timestamp, model: \"clawrouter/image\",\n choices: [{ index: 0, message: { role: \"assistant\", content: errorText }, finish_reason: \"stop\" }],\n usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },\n }));\n }\n console.log(`[ClawRouter] /imagegen command → showing usage help`);\n return;\n }\n\n // Call upstream image generation API\n console.log(`[ClawRouter] /imagegen command → ${imageModel} (${imageSize}): ${imagePrompt.slice(0, 80)}...`);\n try {\n const imageUpstreamUrl = `${apiBase}/v1/images/generations`;\n const imageBody = JSON.stringify({ model: imageModel, prompt: imagePrompt, size: imageSize, n: 1 });\n const imageResponse = await payFetch(imageUpstreamUrl, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", \"user-agent\": USER_AGENT },\n body: imageBody,\n });\n\n const imageResult = await imageResponse.json() as {\n created?: number;\n data?: Array<{ url?: string; revised_prompt?: string }>;\n error?: string | { message?: string };\n };\n\n let responseText: string;\n if (!imageResponse.ok || imageResult.error) {\n const errMsg = typeof imageResult.error === \"string\"\n ? imageResult.error\n : (imageResult.error as { message?: string })?.message ?? `HTTP ${imageResponse.status}`;\n responseText = `Image generation failed: ${errMsg}`;\n console.log(`[ClawRouter] /imagegen error: ${errMsg}`);\n } else {\n const images = imageResult.data ?? [];\n if (images.length === 0) {\n responseText = \"Image generation returned no results.\";\n } else {\n const lines: string[] = [];\n for (const img of images) {\n if (img.url) {\n if (img.url.startsWith(\"data:\")) {\n try {\n const hostedUrl = await uploadDataUriToHost(img.url);\n lines.push(hostedUrl);\n } catch (uploadErr) {\n console.error(`[ClawRouter] /imagegen: failed to upload data URI: ${uploadErr instanceof Error ? uploadErr.message : String(uploadErr)}`);\n lines.push(\"Image generated but upload failed. Try again or use --model dall-e-3.\");\n }\n } else {\n lines.push(img.url);\n }\n }\n if (img.revised_prompt) lines.push(`Revised prompt: ${img.revised_prompt}`);\n }\n lines.push(\"\", `Model: ${imageModel} | Size: ${imageSize}`);\n responseText = lines.join(\"\\n\");\n }\n console.log(`[ClawRouter] /imagegen success: ${images.length} image(s) generated`);\n }\n\n // Return as synthetic chat completion\n const completionId = `chatcmpl-image-${Date.now()}`;\n const timestamp = Math.floor(Date.now() / 1000);\n if (isStreaming) {\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n });\n res.write(`data: ${JSON.stringify({ id: completionId, object: \"chat.completion.chunk\", created: timestamp, model: \"clawrouter/image\", choices: [{ index: 0, delta: { role: \"assistant\", content: responseText }, finish_reason: null }] })}\\n\\n`);\n res.write(`data: ${JSON.stringify({ id: completionId, object: \"chat.completion.chunk\", created: timestamp, model: \"clawrouter/image\", choices: [{ index: 0, delta: {}, finish_reason: \"stop\" }] })}\\n\\n`);\n res.write(\"data: [DONE]\\n\\n\");\n res.end();\n } else {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({\n id: completionId, object: \"chat.completion\", created: timestamp, model: \"clawrouter/image\",\n choices: [{ index: 0, message: { role: \"assistant\", content: responseText }, finish_reason: \"stop\" }],\n usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },\n }));\n }\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n console.error(`[ClawRouter] /imagegen error: ${errMsg}`);\n if (!res.headersSent) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({\n error: { message: `Image generation failed: ${errMsg}`, type: \"image_error\" },\n }));\n }\n }\n return;\n }\n\n // Force stream: false — BlockRun API doesn't support streaming yet\n // ClawRouter handles SSE heartbeat simulation for upstream compatibility\n if (parsed.stream === true) {\n parsed.stream = false;\n bodyModified = true;\n }\n\n // Normalize model name for comparison (trim whitespace, lowercase)\n const normalizedModel =\n typeof parsed.model === \"string\" ? parsed.model.trim().toLowerCase() : \"\";\n\n // Resolve model aliases (e.g., \"claude\" -> \"anthropic/claude-sonnet-4-6\")\n const resolvedModel = resolveModelAlias(normalizedModel);\n const wasAlias = resolvedModel !== normalizedModel;\n\n const isRoutingProfile = ROUTING_PROFILES.has(normalizedModel);\n\n // Extract routing profile type (free/eco/auto/premium)\n if (isRoutingProfile) {\n const profileName = normalizedModel.replace(\"blockrun/\", \"\");\n routingProfile = profileName as \"free\" | \"eco\" | \"auto\" | \"premium\";\n }\n\n // Debug: log received model name\n console.log(\n `[ClawRouter] Received model: \"${parsed.model}\" -> normalized: \"${normalizedModel}\"${wasAlias ? ` -> alias: \"${resolvedModel}\"` : \"\"}${routingProfile ? `, profile: ${routingProfile}` : \"\"}`,\n );\n\n // For explicit model requests, always canonicalize the model ID before upstream calls.\n // This ensures case/whitespace variants (e.g. \"DEEPSEEK/...\" or \" model \") route correctly.\n if (!isRoutingProfile) {\n if (parsed.model !== resolvedModel) {\n parsed.model = resolvedModel;\n bodyModified = true;\n }\n modelId = resolvedModel;\n }\n\n // Handle routing profiles (free/eco/auto/premium)\n if (isRoutingProfile) {\n // Free profile - direct shortcut to nvidia/gpt-oss-120b (no tier routing)\n if (routingProfile === \"free\") {\n const freeModel = \"nvidia/gpt-oss-120b\";\n console.log(`[ClawRouter] Free profile - using ${freeModel} directly`);\n parsed.model = freeModel;\n modelId = freeModel;\n bodyModified = true;\n\n // Log usage for free profile\n await logUsage({\n timestamp: new Date().toISOString(),\n model: freeModel,\n tier: \"SIMPLE\",\n cost: 0,\n baselineCost: 0,\n savings: 1.0, // 100% savings\n latencyMs: 0,\n });\n } else {\n // eco/auto/premium - use tier routing\n // Check for session persistence - use pinned model if available\n // Fall back to deriving a session ID from message content when OpenClaw\n // doesn't send an explicit x-session-id header (the default behaviour).\n effectiveSessionId =\n getSessionId(req.headers as Record<string, string | string[] | undefined>) ??\n deriveSessionId(parsedMessages);\n const existingSession = effectiveSessionId\n ? sessionStore.getSession(effectiveSessionId)\n : undefined;\n\n // Extract prompt from last user message (handles both string and Anthropic array content)\n const rawPrompt = lastUserMsg?.content;\n const prompt =\n typeof rawPrompt === \"string\"\n ? rawPrompt\n : Array.isArray(rawPrompt)\n ? (rawPrompt as Array<{ type: string; text?: string }>)\n .filter((b) => b.type === \"text\")\n .map((b) => b.text ?? \"\")\n .join(\" \")\n : \"\";\n const systemMsg = parsedMessages.find((m) => m.role === \"system\");\n const systemPrompt =\n typeof systemMsg?.content === \"string\" ? systemMsg.content : undefined;\n\n // Tool detection (must run regardless of session state for fallback chain filtering)\n // Agentic mode is triggered by keyword-based detection (agenticScore >= 0.6)\n const tools = parsed.tools as unknown[] | undefined;\n hasTools = Array.isArray(tools) && tools.length > 0;\n\n if (hasTools && tools) {\n console.log(`[ClawRouter] Tools detected (${tools.length}), agentic mode via keywords`);\n }\n\n // Vision detection: scan messages for image_url content parts\n hasVision = parsedMessages.some((m) => {\n if (Array.isArray(m.content)) {\n return (m.content as Array<{ type: string }>).some((p) => p.type === \"image_url\");\n }\n return false;\n });\n if (hasVision) {\n console.log(`[ClawRouter] Vision content detected, filtering to vision-capable models`);\n }\n\n // Always route based on current request content\n routingDecision = route(prompt, systemPrompt, maxTokens, {\n ...routerOpts,\n routingProfile: routingProfile ?? undefined,\n });\n\n if (existingSession) {\n // Never downgrade: only upgrade the session when the current request needs a higher\n // tier. This fixes the OpenClaw startup-message bias (the startup message always\n // scores low-complexity, which previously pinned all subsequent real queries to a\n // cheap model) while still preventing mid-task model switching on simple follow-ups.\n const tierRank: Record<string, number> = {\n SIMPLE: 0,\n MEDIUM: 1,\n COMPLEX: 2,\n REASONING: 3,\n };\n const existingRank = tierRank[existingSession.tier] ?? 0;\n const newRank = tierRank[routingDecision.tier] ?? 0;\n\n if (newRank > existingRank) {\n // Current request needs higher capability — upgrade the session\n console.log(\n `[ClawRouter] Session ${effectiveSessionId?.slice(0, 8)}... upgrading: ${existingSession.tier} → ${routingDecision.tier} (${routingDecision.model})`,\n );\n parsed.model = routingDecision.model;\n modelId = routingDecision.model;\n bodyModified = true;\n if (effectiveSessionId) {\n sessionStore.setSession(\n effectiveSessionId,\n routingDecision.model,\n routingDecision.tier,\n );\n }\n } else {\n // Keep existing higher-tier model (prevent downgrade mid-task)\n console.log(\n `[ClawRouter] Session ${effectiveSessionId?.slice(0, 8)}... keeping pinned model: ${existingSession.model} (${existingSession.tier} >= ${routingDecision.tier})`,\n );\n parsed.model = existingSession.model;\n modelId = existingSession.model;\n bodyModified = true;\n sessionStore.touchSession(effectiveSessionId!);\n // Reflect the actual model used in the routing decision for logging/fallback\n routingDecision = {\n ...routingDecision,\n model: existingSession.model,\n tier: existingSession.tier as Tier,\n };\n }\n\n // --- Three-strike escalation: detect repetitive request patterns ---\n const lastAssistantMsg = [...parsedMessages]\n .reverse()\n .find((m) => m.role === \"assistant\");\n const toolCallNames = Array.isArray((lastAssistantMsg as any)?.tool_calls)\n ? (lastAssistantMsg as any).tool_calls\n .map((tc: any) => tc.function?.name)\n .filter(Boolean)\n : undefined;\n const contentHash = hashRequestContent(prompt, toolCallNames);\n const shouldEscalate = sessionStore.recordRequestHash(\n effectiveSessionId!,\n contentHash,\n );\n\n if (shouldEscalate) {\n const activeTierConfigs = (() => {\n if (\n routingDecision.reasoning?.includes(\"agentic\") &&\n routerOpts.config.agenticTiers\n ) {\n return routerOpts.config.agenticTiers;\n }\n if (routingProfile === \"eco\" && routerOpts.config.ecoTiers) {\n return routerOpts.config.ecoTiers;\n }\n if (routingProfile === \"premium\" && routerOpts.config.premiumTiers) {\n return routerOpts.config.premiumTiers;\n }\n return routerOpts.config.tiers;\n })();\n\n const escalation = sessionStore.escalateSession(\n effectiveSessionId!,\n activeTierConfigs,\n );\n if (escalation) {\n console.log(\n `[ClawRouter] ⚡ 3-strike escalation: ${existingSession.model} → ${escalation.model} (${existingSession.tier} → ${escalation.tier})`,\n );\n parsed.model = escalation.model;\n modelId = escalation.model;\n routingDecision = {\n ...routingDecision,\n model: escalation.model,\n tier: escalation.tier as Tier,\n };\n }\n }\n } else {\n // No session — pin this routing decision for future requests\n parsed.model = routingDecision.model;\n modelId = routingDecision.model;\n bodyModified = true;\n if (effectiveSessionId) {\n sessionStore.setSession(\n effectiveSessionId,\n routingDecision.model,\n routingDecision.tier,\n );\n console.log(\n `[ClawRouter] Session ${effectiveSessionId.slice(0, 8)}... pinned to model: ${routingDecision.model}`,\n );\n }\n }\n\n options.onRouted?.(routingDecision);\n }\n }\n\n // Rebuild body if modified\n if (bodyModified) {\n body = Buffer.from(JSON.stringify(parsed));\n }\n } catch (err) {\n // Log routing errors so they're not silently swallowed\n const errorMsg = err instanceof Error ? err.message : String(err);\n console.error(`[ClawRouter] Routing error: ${errorMsg}`);\n console.error(`[ClawRouter] Need help? Run: npx @blockrun/clawrouter doctor`);\n options.onError?.(new Error(`Routing failed: ${errorMsg}`));\n }\n }\n\n // --- Auto-compression ---\n // Compress large requests to reduce network usage and improve performance\n const autoCompress = options.autoCompressRequests ?? true;\n const compressionThreshold = options.compressionThresholdKB ?? 180;\n const requestSizeKB = Math.ceil(body.length / 1024);\n\n if (autoCompress && requestSizeKB > compressionThreshold) {\n try {\n console.log(\n `[ClawRouter] Request size ${requestSizeKB}KB exceeds threshold ${compressionThreshold}KB, applying compression...`,\n );\n\n // Parse messages for compression\n const parsed = JSON.parse(body.toString()) as {\n messages?: NormalizedMessage[];\n [key: string]: unknown;\n };\n\n if (parsed.messages && parsed.messages.length > 0 && shouldCompress(parsed.messages)) {\n // Apply compression with conservative settings\n const compressionResult = await compressContext(parsed.messages, {\n enabled: true,\n preserveRaw: false, // Don't need originals in proxy\n layers: {\n deduplication: true, // Safe: removes duplicate messages\n whitespace: true, // Safe: normalizes whitespace\n dictionary: false, // Disabled: requires model to understand codebook\n paths: false, // Disabled: requires model to understand path codes\n jsonCompact: true, // Safe: just removes JSON whitespace\n observation: false, // Disabled: may lose important context\n dynamicCodebook: false, // Disabled: requires model to understand codes\n },\n dictionary: {\n maxEntries: 50,\n minPhraseLength: 15,\n includeCodebookHeader: false,\n },\n });\n\n const compressedSizeKB = Math.ceil(compressionResult.compressedChars / 1024);\n const savings = (((requestSizeKB - compressedSizeKB) / requestSizeKB) * 100).toFixed(1);\n\n console.log(\n `[ClawRouter] Compressed ${requestSizeKB}KB → ${compressedSizeKB}KB (${savings}% reduction)`,\n );\n\n // Update request body with compressed messages\n parsed.messages = compressionResult.messages;\n body = Buffer.from(JSON.stringify(parsed));\n }\n } catch (err) {\n // Compression failed - continue with original request\n console.warn(\n `[ClawRouter] Compression failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n // --- Response cache check (long-term, 10min TTL) ---\n const cacheKey = ResponseCache.generateKey(body);\n const reqHeaders: Record<string, string> = {};\n for (const [key, value] of Object.entries(req.headers)) {\n if (typeof value === \"string\") reqHeaders[key] = value;\n }\n if (responseCache.shouldCache(body, reqHeaders)) {\n const cachedResponse = responseCache.get(cacheKey);\n if (cachedResponse) {\n console.log(`[ClawRouter] Cache HIT for ${cachedResponse.model} (saved API call)`);\n res.writeHead(cachedResponse.status, cachedResponse.headers);\n res.end(cachedResponse.body);\n return;\n }\n }\n\n // --- Dedup check (short-term, 30s TTL for retries) ---\n const dedupKey = RequestDeduplicator.hash(body);\n\n // Check dedup cache (catches retries within 30s)\n const cached = deduplicator.getCached(dedupKey);\n if (cached) {\n res.writeHead(cached.status, cached.headers);\n res.end(cached.body);\n return;\n }\n\n // Check in-flight — wait for the original request to complete\n const inflight = deduplicator.getInflight(dedupKey);\n if (inflight) {\n const result = await inflight;\n res.writeHead(result.status, result.headers);\n res.end(result.body);\n return;\n }\n\n // Register this request as in-flight\n deduplicator.markInflight(dedupKey);\n\n // --- Pre-request balance check ---\n // Estimate cost and check if wallet has sufficient balance\n // Skip if skipBalanceCheck is set (for testing) or if using free model\n let estimatedCostMicros: bigint | undefined;\n const isFreeModel = modelId === FREE_MODEL;\n\n if (modelId && !options.skipBalanceCheck && !isFreeModel) {\n const estimated = estimateAmount(modelId, body.length, maxTokens);\n if (estimated) {\n estimatedCostMicros = BigInt(estimated);\n\n // Apply extra buffer for balance check to prevent x402 failures after streaming starts.\n // This is aggressive to avoid triggering OpenClaw's 5-24 hour billing cooldown.\n const bufferedCostMicros =\n (estimatedCostMicros * BigInt(Math.ceil(BALANCE_CHECK_BUFFER * 100))) / 100n;\n\n // Check balance before proceeding (using buffered amount)\n const sufficiency = await balanceMonitor.checkSufficient(bufferedCostMicros);\n\n if (sufficiency.info.isEmpty || !sufficiency.sufficient) {\n // Wallet is empty or insufficient — ALWAYS fallback to free model\n // This ensures new users with empty wallets can still use ClawRouter\n const originalModel = modelId;\n console.log(\n `[ClawRouter] Wallet ${sufficiency.info.isEmpty ? \"empty\" : \"insufficient\"} ($${sufficiency.info.balanceUSD}), falling back to free model: ${FREE_MODEL} (requested: ${originalModel})`,\n );\n modelId = FREE_MODEL;\n // Update the body with new model\n const parsed = JSON.parse(body.toString()) as Record<string, unknown>;\n parsed.model = FREE_MODEL;\n body = Buffer.from(JSON.stringify(parsed));\n\n // Notify about the fallback\n options.onLowBalance?.({\n balanceUSD: sufficiency.info.balanceUSD,\n walletAddress: sufficiency.info.walletAddress,\n });\n } else if (sufficiency.info.isLow) {\n // Balance is low but sufficient — warn and proceed\n options.onLowBalance?.({\n balanceUSD: sufficiency.info.balanceUSD,\n walletAddress: sufficiency.info.walletAddress,\n });\n }\n }\n }\n\n // --- Streaming: early header flush + heartbeat ---\n let heartbeatInterval: ReturnType<typeof setInterval> | undefined;\n let headersSentEarly = false;\n\n if (isStreaming) {\n // Send 200 + SSE headers immediately, before x402 flow\n res.writeHead(200, {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-cache\",\n connection: \"keep-alive\",\n \"x-context-used-kb\": String(originalContextSizeKB),\n \"x-context-limit-kb\": String(CONTEXT_LIMIT_KB),\n });\n headersSentEarly = true;\n\n // First heartbeat immediately\n safeWrite(res, \": heartbeat\\n\\n\");\n\n // Continue heartbeats every 2s while waiting for upstream\n heartbeatInterval = setInterval(() => {\n if (canWrite(res)) {\n safeWrite(res, \": heartbeat\\n\\n\");\n } else {\n // Socket closed, stop heartbeat\n clearInterval(heartbeatInterval);\n heartbeatInterval = undefined;\n }\n }, HEARTBEAT_INTERVAL_MS);\n }\n\n // Forward headers, stripping host, connection, and content-length\n const headers: Record<string, string> = {};\n for (const [key, value] of Object.entries(req.headers)) {\n if (\n key === \"host\" ||\n key === \"connection\" ||\n key === \"transfer-encoding\" ||\n key === \"content-length\"\n )\n continue;\n if (typeof value === \"string\") {\n headers[key] = value;\n }\n }\n if (!headers[\"content-type\"]) {\n headers[\"content-type\"] = \"application/json\";\n }\n headers[\"user-agent\"] = USER_AGENT;\n\n // --- Client disconnect cleanup ---\n let completed = false;\n res.on(\"close\", () => {\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n heartbeatInterval = undefined;\n }\n // Remove from in-flight if client disconnected before completion\n if (!completed) {\n deduplicator.removeInflight(dedupKey);\n }\n });\n\n // --- Request timeout ---\n const timeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n // --- Build fallback chain ---\n // If we have a routing decision, get the full fallback chain for the tier\n // Otherwise, just use the current model (no fallback for explicit model requests)\n let modelsToTry: string[];\n if (routingDecision) {\n // Estimate total context: input tokens (~4 chars per token) + max output tokens\n const estimatedInputTokens = Math.ceil(body.length / 4);\n const estimatedTotalTokens = estimatedInputTokens + maxTokens;\n\n // Get tier configs matching the profile that was used for routing\n // Must stay in sync with what route() selected in router/index.ts\n const tierConfigs = (() => {\n if (routingDecision.reasoning?.includes(\"agentic\") && routerOpts.config.agenticTiers) {\n return routerOpts.config.agenticTiers;\n }\n if (routingProfile === \"eco\" && routerOpts.config.ecoTiers) {\n return routerOpts.config.ecoTiers;\n }\n if (routingProfile === \"premium\" && routerOpts.config.premiumTiers) {\n return routerOpts.config.premiumTiers;\n }\n return routerOpts.config.tiers;\n })();\n\n // Get full chain first, then filter by context\n const fullChain = getFallbackChain(routingDecision.tier, tierConfigs);\n const contextFiltered = getFallbackChainFiltered(\n routingDecision.tier,\n tierConfigs,\n estimatedTotalTokens,\n getModelContextWindow,\n );\n\n // Log if models were filtered out due to context limits\n const contextExcluded = fullChain.filter((m) => !contextFiltered.includes(m));\n if (contextExcluded.length > 0) {\n console.log(\n `[ClawRouter] Context filter (~${estimatedTotalTokens} tokens): excluded ${contextExcluded.join(\", \")}`,\n );\n }\n\n // Filter to models that support tool calling when request has tools.\n // Prevents models like grok-code-fast-1 from outputting tool invocations\n // as plain text JSON (the \"talking to itself\" bug).\n const toolFiltered = filterByToolCalling(contextFiltered, hasTools, supportsToolCalling);\n const toolExcluded = contextFiltered.filter((m) => !toolFiltered.includes(m));\n if (toolExcluded.length > 0) {\n console.log(\n `[ClawRouter] Tool-calling filter: excluded ${toolExcluded.join(\", \")} (no structured function call support)`,\n );\n }\n\n // Filter to models that support vision when request has image_url content\n const visionFiltered = filterByVision(toolFiltered, hasVision, supportsVision);\n const visionExcluded = toolFiltered.filter((m) => !visionFiltered.includes(m));\n if (visionExcluded.length > 0) {\n console.log(\n `[ClawRouter] Vision filter: excluded ${visionExcluded.join(\", \")} (no vision support)`,\n );\n }\n\n // Limit to MAX_FALLBACK_ATTEMPTS to prevent infinite loops\n modelsToTry = visionFiltered.slice(0, MAX_FALLBACK_ATTEMPTS);\n\n // Deprioritize rate-limited models (put them at the end)\n modelsToTry = prioritizeNonRateLimited(modelsToTry);\n } else {\n // For explicit model requests, use the requested model\n modelsToTry = modelId ? [modelId] : [];\n }\n\n // Always ensure free model is the last-resort fallback.\n // If all paid models fail (insufficient funds, rate limits, etc.),\n // the user still gets a response instead of an error.\n if (!modelsToTry.includes(FREE_MODEL)) {\n modelsToTry.push(FREE_MODEL);\n }\n\n // --- Fallback loop: try each model until success ---\n let upstream: Response | undefined;\n let lastError: { body: string; status: number } | undefined;\n let actualModelUsed = modelId;\n\n for (let i = 0; i < modelsToTry.length; i++) {\n const tryModel = modelsToTry[i];\n const isLastAttempt = i === modelsToTry.length - 1;\n\n console.log(`[ClawRouter] Trying model ${i + 1}/${modelsToTry.length}: ${tryModel}`);\n\n const result = await tryModelRequest(\n upstreamUrl,\n req.method ?? \"POST\",\n headers,\n body,\n tryModel,\n maxTokens,\n payFetch,\n balanceMonitor,\n controller.signal,\n );\n\n if (result.success && result.response) {\n upstream = result.response;\n actualModelUsed = tryModel;\n console.log(`[ClawRouter] Success with model: ${tryModel}`);\n break;\n }\n\n // Request failed\n lastError = {\n body: result.errorBody || \"Unknown error\",\n status: result.errorStatus || 500,\n };\n\n // If it's a provider error and not the last attempt, try next model\n if (result.isProviderError && !isLastAttempt) {\n // Track 429 rate limits to deprioritize this model for future requests\n if (result.errorStatus === 429) {\n markRateLimited(tryModel);\n }\n\n // Payment error (insufficient funds) — skip remaining paid models,\n // jump straight to free model. No point trying other paid models\n // with the same empty wallet.\n const isPaymentErr = /payment.*verification.*failed|insufficient.*funds/i.test(\n result.errorBody || \"\",\n );\n if (isPaymentErr && tryModel !== FREE_MODEL) {\n const freeIdx = modelsToTry.indexOf(FREE_MODEL);\n if (freeIdx > i + 1) {\n console.log(`[ClawRouter] Payment error — skipping to free model: ${FREE_MODEL}`);\n i = freeIdx - 1; // loop will increment to freeIdx\n continue;\n }\n }\n\n console.log(\n `[ClawRouter] Provider error from ${tryModel}, trying fallback: ${result.errorBody?.slice(0, 100)}`,\n );\n continue;\n }\n\n // Not a provider error or last attempt — stop trying\n if (!result.isProviderError) {\n console.log(\n `[ClawRouter] Non-provider error from ${tryModel}, not retrying: ${result.errorBody?.slice(0, 100)}`,\n );\n }\n break;\n }\n\n // Clear timeout — request attempts completed\n clearTimeout(timeoutId);\n\n // Clear heartbeat — real data is about to flow\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n heartbeatInterval = undefined;\n }\n\n // --- Emit routing debug info (opt-in via x-clawrouter-debug: true header) ---\n // For streaming: SSE comment (invisible to most clients, visible in raw stream)\n // For non-streaming: response headers added later\n if (debugMode && headersSentEarly && routingDecision) {\n const debugComment = `: x-clawrouter-debug profile=${routingProfile ?? \"auto\"} tier=${routingDecision.tier} model=${actualModelUsed} agentic=${routingDecision.agenticScore?.toFixed(2) ?? \"n/a\"} confidence=${routingDecision.confidence.toFixed(2)} reasoning=${routingDecision.reasoning}\\n\\n`;\n safeWrite(res, debugComment);\n }\n\n // Update routing decision with actual model used (for logging)\n // IMPORTANT: Recalculate cost for the actual model, not the original primary\n if (routingDecision && actualModelUsed !== routingDecision.model) {\n const estimatedInputTokens = Math.ceil(body.length / 4);\n const newCosts = calculateModelCost(\n actualModelUsed,\n routerOpts.modelPricing,\n estimatedInputTokens,\n maxTokens,\n routingProfile ?? undefined,\n );\n routingDecision = {\n ...routingDecision,\n model: actualModelUsed,\n reasoning: `${routingDecision.reasoning} | fallback to ${actualModelUsed}`,\n costEstimate: newCosts.costEstimate,\n baselineCost: newCosts.baselineCost,\n savings: newCosts.savings,\n };\n options.onRouted?.(routingDecision);\n\n // Update session pin to the actual model used — ensures the next request in\n // this conversation starts from the fallback model rather than retrying the\n // primary and falling back again (prevents the \"model keeps jumping\" issue).\n if (effectiveSessionId) {\n sessionStore.setSession(effectiveSessionId, actualModelUsed, routingDecision.tier);\n console.log(\n `[ClawRouter] Session ${effectiveSessionId.slice(0, 8)}... updated pin to fallback: ${actualModelUsed}`,\n );\n }\n }\n\n // --- Handle case where all models failed ---\n if (!upstream) {\n const rawErrBody = lastError?.body || \"All models in fallback chain failed\";\n const errStatus = lastError?.status || 502;\n\n // Transform payment errors into user-friendly messages\n const transformedErr = transformPaymentError(rawErrBody);\n\n if (headersSentEarly) {\n // Streaming: send error as SSE event\n // If transformed error is already JSON, parse and use it; otherwise wrap in standard format\n let errPayload: string;\n try {\n const parsed = JSON.parse(transformedErr);\n errPayload = JSON.stringify(parsed);\n } catch {\n errPayload = JSON.stringify({\n error: { message: rawErrBody, type: \"provider_error\", status: errStatus },\n });\n }\n const errEvent = `data: ${errPayload}\\n\\n`;\n safeWrite(res, errEvent);\n safeWrite(res, \"data: [DONE]\\n\\n\");\n res.end();\n\n const errBuf = Buffer.from(errEvent + \"data: [DONE]\\n\\n\");\n deduplicator.complete(dedupKey, {\n status: 200,\n headers: { \"content-type\": \"text/event-stream\" },\n body: errBuf,\n completedAt: Date.now(),\n });\n } else {\n // Non-streaming: send transformed error response with context headers\n res.writeHead(errStatus, {\n \"Content-Type\": \"application/json\",\n \"x-context-used-kb\": String(originalContextSizeKB),\n \"x-context-limit-kb\": String(CONTEXT_LIMIT_KB),\n });\n res.end(transformedErr);\n\n deduplicator.complete(dedupKey, {\n status: errStatus,\n headers: { \"content-type\": \"application/json\" },\n body: Buffer.from(transformedErr),\n completedAt: Date.now(),\n });\n }\n return;\n }\n\n // --- Stream response and collect for dedup cache ---\n const responseChunks: Buffer[] = [];\n\n if (headersSentEarly) {\n // Streaming: headers already sent. Response should be 200 at this point\n // (non-200 responses are handled in the fallback loop above)\n\n // Convert non-streaming JSON response to SSE streaming format for client\n // (BlockRun API returns JSON since we forced stream:false)\n // OpenClaw expects: object=\"chat.completion.chunk\" with choices[].delta (not message)\n // We emit proper incremental deltas to match OpenAI's streaming format exactly\n if (upstream.body) {\n const reader = upstream.body.getReader();\n const chunks: Uint8Array[] = [];\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n }\n } finally {\n reader.releaseLock();\n }\n\n // Combine chunks and transform to streaming format\n const jsonBody = Buffer.concat(chunks);\n const jsonStr = jsonBody.toString();\n try {\n const rsp = JSON.parse(jsonStr) as {\n id?: string;\n object?: string;\n created?: number;\n model?: string;\n choices?: Array<{\n index?: number;\n message?: {\n role?: string;\n content?: string;\n tool_calls?: Array<{\n id: string;\n type: string;\n function: { name: string; arguments: string };\n }>;\n };\n delta?: {\n role?: string;\n content?: string;\n tool_calls?: Array<{\n id: string;\n type: string;\n function: { name: string; arguments: string };\n }>;\n };\n finish_reason?: string | null;\n }>;\n usage?: unknown;\n };\n\n // Build base chunk structure (reused for all chunks)\n // Match OpenAI's exact format including system_fingerprint\n const baseChunk = {\n id: rsp.id ?? `chatcmpl-${Date.now()}`,\n object: \"chat.completion.chunk\",\n created: rsp.created ?? Math.floor(Date.now() / 1000),\n model: rsp.model ?? \"unknown\",\n system_fingerprint: null,\n };\n\n // Process each choice (usually just one)\n if (rsp.choices && Array.isArray(rsp.choices)) {\n for (const choice of rsp.choices) {\n // Strip thinking tokens (Kimi <|...|> and standard <think> tags)\n const rawContent = choice.message?.content ?? choice.delta?.content ?? \"\";\n const content = stripThinkingTokens(rawContent);\n const role = choice.message?.role ?? choice.delta?.role ?? \"assistant\";\n const index = choice.index ?? 0;\n\n // Accumulate content for session journal\n if (content) {\n accumulatedContent += content;\n }\n\n // Chunk 1: role only (mimics OpenAI's first chunk)\n const roleChunk = {\n ...baseChunk,\n choices: [{ index, delta: { role }, logprobs: null, finish_reason: null }],\n };\n const roleData = `data: ${JSON.stringify(roleChunk)}\\n\\n`;\n safeWrite(res, roleData);\n responseChunks.push(Buffer.from(roleData));\n\n // Chunk 2: content (single chunk with full content)\n if (content) {\n const contentChunk = {\n ...baseChunk,\n choices: [{ index, delta: { content }, logprobs: null, finish_reason: null }],\n };\n const contentData = `data: ${JSON.stringify(contentChunk)}\\n\\n`;\n safeWrite(res, contentData);\n responseChunks.push(Buffer.from(contentData));\n }\n\n // Chunk 2b: tool_calls (forward tool calls from upstream)\n const toolCalls = choice.message?.tool_calls ?? choice.delta?.tool_calls;\n if (toolCalls && toolCalls.length > 0) {\n const toolCallChunk = {\n ...baseChunk,\n choices: [\n {\n index,\n delta: { tool_calls: toolCalls },\n logprobs: null,\n finish_reason: null,\n },\n ],\n };\n const toolCallData = `data: ${JSON.stringify(toolCallChunk)}\\n\\n`;\n safeWrite(res, toolCallData);\n responseChunks.push(Buffer.from(toolCallData));\n }\n\n // Chunk 3: finish_reason (signals completion)\n const finishChunk = {\n ...baseChunk,\n choices: [\n {\n index,\n delta: {},\n logprobs: null,\n finish_reason:\n toolCalls && toolCalls.length > 0\n ? \"tool_calls\"\n : (choice.finish_reason ?? \"stop\"),\n },\n ],\n };\n const finishData = `data: ${JSON.stringify(finishChunk)}\\n\\n`;\n safeWrite(res, finishData);\n responseChunks.push(Buffer.from(finishData));\n }\n }\n } catch {\n // If parsing fails, send raw response as single chunk\n const sseData = `data: ${jsonStr}\\n\\n`;\n safeWrite(res, sseData);\n responseChunks.push(Buffer.from(sseData));\n }\n }\n\n // Send SSE terminator\n safeWrite(res, \"data: [DONE]\\n\\n\");\n responseChunks.push(Buffer.from(\"data: [DONE]\\n\\n\"));\n res.end();\n\n // Cache for dedup\n deduplicator.complete(dedupKey, {\n status: 200,\n headers: { \"content-type\": \"text/event-stream\" },\n body: Buffer.concat(responseChunks),\n completedAt: Date.now(),\n });\n } else {\n // Non-streaming: forward status and headers from upstream\n const responseHeaders: Record<string, string> = {};\n upstream.headers.forEach((value, key) => {\n // Skip hop-by-hop headers and content-encoding (fetch already decompresses)\n if (key === \"transfer-encoding\" || key === \"connection\" || key === \"content-encoding\")\n return;\n responseHeaders[key] = value;\n });\n\n // Add context usage headers\n responseHeaders[\"x-context-used-kb\"] = String(originalContextSizeKB);\n responseHeaders[\"x-context-limit-kb\"] = String(CONTEXT_LIMIT_KB);\n\n // Add routing debug headers (opt-in via x-clawrouter-debug: true header)\n if (debugMode && routingDecision) {\n responseHeaders[\"x-clawrouter-profile\"] = routingProfile ?? \"auto\";\n responseHeaders[\"x-clawrouter-tier\"] = routingDecision.tier;\n responseHeaders[\"x-clawrouter-model\"] = actualModelUsed;\n responseHeaders[\"x-clawrouter-confidence\"] = routingDecision.confidence.toFixed(2);\n responseHeaders[\"x-clawrouter-reasoning\"] = routingDecision.reasoning;\n if (routingDecision.agenticScore !== undefined) {\n responseHeaders[\"x-clawrouter-agentic-score\"] = routingDecision.agenticScore.toFixed(2);\n }\n }\n\n res.writeHead(upstream.status, responseHeaders);\n\n if (upstream.body) {\n const reader = upstream.body.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n const chunk = Buffer.from(value);\n safeWrite(res, chunk);\n responseChunks.push(chunk);\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n res.end();\n\n const responseBody = Buffer.concat(responseChunks);\n\n // Cache for dedup (short-term, 30s)\n deduplicator.complete(dedupKey, {\n status: upstream.status,\n headers: responseHeaders,\n body: responseBody,\n completedAt: Date.now(),\n });\n\n // Cache for response cache (long-term, 10min) - only successful non-streaming\n if (upstream.status === 200 && responseCache.shouldCache(body)) {\n responseCache.set(cacheKey, {\n body: responseBody,\n status: upstream.status,\n headers: responseHeaders,\n model: actualModelUsed,\n });\n console.log(\n `[ClawRouter] Cached response for ${actualModelUsed} (${responseBody.length} bytes)`,\n );\n }\n\n // Extract content from non-streaming response for session journal\n try {\n const rspJson = JSON.parse(responseBody.toString()) as {\n choices?: Array<{ message?: { content?: string } }>;\n };\n if (rspJson.choices?.[0]?.message?.content) {\n accumulatedContent = rspJson.choices[0].message.content;\n }\n } catch {\n // Ignore parse errors - journal just won't have content for this response\n }\n }\n\n // --- Session Journal: Extract and record events from response ---\n if (sessionId && accumulatedContent) {\n const events = sessionJournal.extractEvents(accumulatedContent);\n if (events.length > 0) {\n sessionJournal.record(sessionId, events, actualModelUsed);\n console.log(\n `[ClawRouter] Recorded ${events.length} events to session journal for session ${sessionId.slice(0, 8)}...`,\n );\n }\n }\n\n // --- Optimistic balance deduction after successful response ---\n if (estimatedCostMicros !== undefined) {\n balanceMonitor.deductEstimated(estimatedCostMicros);\n }\n\n // Mark request as completed (for client disconnect cleanup)\n completed = true;\n } catch (err) {\n // Clear timeout on error\n clearTimeout(timeoutId);\n\n // Clear heartbeat on error\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n heartbeatInterval = undefined;\n }\n\n // Remove in-flight entry so retries aren't blocked\n deduplicator.removeInflight(dedupKey);\n\n // Invalidate balance cache on payment failure (might be out of date)\n balanceMonitor.invalidate();\n\n // Convert abort error to more descriptive timeout error\n if (err instanceof Error && err.name === \"AbortError\") {\n throw new Error(`Request timed out after ${timeoutMs}ms`);\n }\n\n throw err;\n }\n\n // --- Usage logging (fire-and-forget) ---\n // Note: Recalculate cost using full body length (not just system+user message)\n // and apply 20% buffer to match actual x402 payment (see estimateAmount())\n // Log ALL requests: both auto-routed (routingDecision set) and direct model picks\n const logModel = routingDecision?.model ?? modelId;\n if (logModel) {\n // Use full body length for accurate cost (matches x402 payment estimation)\n const estimatedInputTokens = Math.ceil(body.length / 4);\n const accurateCosts = calculateModelCost(\n logModel,\n routerOpts.modelPricing,\n estimatedInputTokens,\n maxTokens,\n routingProfile ?? undefined,\n );\n // Apply 20% buffer to match x402 pre-auth\n const costWithBuffer = accurateCosts.costEstimate * 1.2;\n const baselineWithBuffer = accurateCosts.baselineCost * 1.2;\n const entry: UsageEntry = {\n timestamp: new Date().toISOString(),\n model: logModel,\n tier: routingDecision?.tier ?? \"DIRECT\",\n cost: costWithBuffer,\n baselineCost: baselineWithBuffer,\n savings: accurateCosts.savings,\n latencyMs: Date.now() - startTime,\n };\n logUsage(entry).catch(() => {});\n }\n}\n","/**\n * x402 Payment Implementation\n *\n * Based on BlockRun's proven implementation.\n * Handles 402 Payment Required responses with EIP-712 signed USDC transfers.\n *\n * Optimizations (v0.3.0):\n * - Payment cache: after first 402, caches {payTo, asset, network} per endpoint.\n * On subsequent requests, pre-signs payment and sends with first request,\n * skipping the 402 round trip (~200ms savings).\n * - Falls back to normal 402 flow if pre-signed payment is rejected.\n */\n\nimport { signTypedData, privateKeyToAccount } from \"viem/accounts\";\nimport { PaymentCache } from \"./payment-cache.js\";\n\nconst BASE_CHAIN_ID = 8453;\nconst BASE_SEPOLIA_CHAIN_ID = 84532;\nconst DEFAULT_TOKEN_NAME = \"USD Coin\";\nconst DEFAULT_TOKEN_VERSION = \"2\";\nconst DEFAULT_NETWORK = \"eip155:8453\";\nconst DEFAULT_MAX_TIMEOUT_SECONDS = 300;\n\nconst TRANSFER_TYPES = {\n TransferWithAuthorization: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n ],\n} as const;\n\nfunction createNonce(): `0x${string}` {\n const bytes = new Uint8Array(32);\n crypto.getRandomValues(bytes);\n return `0x${Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\")}` as `0x${string}`;\n}\n\ninterface PaymentOption {\n scheme: string;\n network: string;\n amount?: string;\n maxAmountRequired?: string;\n asset: string;\n payTo: string;\n maxTimeoutSeconds?: number;\n extra?: { name?: string; version?: string };\n}\n\ninterface PaymentRequired {\n accepts: PaymentOption[];\n resource?: { url?: string; description?: string };\n}\n\nfunction decodeBase64Json<T>(value: string): T {\n const normalized = value.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padding = (4 - (normalized.length % 4)) % 4;\n const padded = normalized + \"=\".repeat(padding);\n const decoded = Buffer.from(padded, \"base64\").toString(\"utf8\");\n return JSON.parse(decoded) as T;\n}\n\nfunction encodeBase64Json(value: unknown): string {\n return Buffer.from(JSON.stringify(value), \"utf8\").toString(\"base64\");\n}\n\nfunction parsePaymentRequired(headerValue: string): PaymentRequired {\n return decodeBase64Json<PaymentRequired>(headerValue);\n}\n\nfunction normalizeNetwork(network: string | undefined): string {\n if (!network || network.trim().length === 0) {\n return DEFAULT_NETWORK;\n }\n return network.trim().toLowerCase();\n}\n\nfunction resolveChainId(network: string): number {\n const eip155Match = network.match(/^eip155:(\\d+)$/i);\n if (eip155Match) {\n const parsed = Number.parseInt(eip155Match[1], 10);\n if (Number.isFinite(parsed) && parsed > 0) {\n return parsed;\n }\n }\n\n if (network === \"base\") return BASE_CHAIN_ID;\n if (network === \"base-sepolia\") return BASE_SEPOLIA_CHAIN_ID;\n return BASE_CHAIN_ID;\n}\n\nfunction parseHexAddress(value: string | undefined): `0x${string}` | undefined {\n if (!value) return undefined;\n\n const direct = value.match(/^0x[a-fA-F0-9]{40}$/);\n if (direct) {\n return direct[0] as `0x${string}`;\n }\n\n // Some providers send CAIP-style assets (e.g. \".../erc20:0x...\").\n const caipSuffix = value.match(/0x[a-fA-F0-9]{40}$/);\n if (caipSuffix) {\n return caipSuffix[0] as `0x${string}`;\n }\n\n return undefined;\n}\n\nfunction requireHexAddress(value: string | undefined, field: string): `0x${string}` {\n const parsed = parseHexAddress(value);\n if (!parsed) {\n throw new Error(`Invalid ${field} in payment requirements: ${String(value)}`);\n }\n return parsed;\n}\n\nfunction setPaymentHeaders(headers: Headers, payload: string): void {\n // Support both modern and legacy header names for compatibility.\n headers.set(\"payment-signature\", payload);\n headers.set(\"x-payment\", payload);\n}\n\nasync function createPaymentPayload(\n privateKey: `0x${string}`,\n fromAddress: string,\n option: PaymentOption,\n amount: string,\n requestUrl: string,\n resource: PaymentRequired[\"resource\"],\n): Promise<string> {\n const network = normalizeNetwork(option.network);\n const chainId = resolveChainId(network);\n const recipient = requireHexAddress(option.payTo, \"payTo\");\n const verifyingContract = requireHexAddress(option.asset, \"asset\");\n\n const maxTimeoutSeconds =\n typeof option.maxTimeoutSeconds === \"number\" && option.maxTimeoutSeconds > 0\n ? Math.floor(option.maxTimeoutSeconds)\n : DEFAULT_MAX_TIMEOUT_SECONDS;\n\n const now = Math.floor(Date.now() / 1000);\n const validAfter = now - 600;\n const validBefore = now + maxTimeoutSeconds;\n const nonce = createNonce();\n\n const signature = await signTypedData({\n privateKey,\n domain: {\n name: option.extra?.name || DEFAULT_TOKEN_NAME,\n version: option.extra?.version || DEFAULT_TOKEN_VERSION,\n chainId,\n verifyingContract,\n },\n types: TRANSFER_TYPES,\n primaryType: \"TransferWithAuthorization\",\n message: {\n from: fromAddress as `0x${string}`,\n to: recipient,\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: resource?.url || requestUrl,\n description: resource?.description || \"BlockRun AI API call\",\n mimeType: \"application/json\",\n },\n accepted: {\n scheme: option.scheme,\n network,\n amount,\n asset: option.asset,\n payTo: option.payTo,\n maxTimeoutSeconds: option.maxTimeoutSeconds,\n extra: option.extra,\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 encodeBase64Json(paymentData);\n}\n\n/** Pre-auth parameters for skipping the 402 round trip. */\nexport type PreAuthParams = {\n estimatedAmount: string; // USDC amount in smallest unit (6 decimals)\n};\n\n/** Result from createPaymentFetch — includes the fetch wrapper and payment cache. */\nexport type PaymentFetchResult = {\n fetch: (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ) => Promise<Response>;\n cache: PaymentCache;\n};\n\n/**\n * Create a fetch wrapper that handles x402 payment automatically.\n *\n * Supports pre-auth: if cached payment params + estimated amount are available,\n * pre-signs and attaches payment to the first request, skipping the 402 round trip.\n * Falls back to normal 402 flow if pre-signed payment is rejected.\n */\nexport function createPaymentFetch(privateKey: `0x${string}`): PaymentFetchResult {\n const account = privateKeyToAccount(privateKey);\n const walletAddress = account.address;\n const paymentCache = new PaymentCache();\n\n const payFetch = async (\n input: RequestInfo | URL,\n init?: RequestInit,\n preAuth?: PreAuthParams,\n ): Promise<Response> => {\n const url = typeof input === \"string\" ? input : input instanceof URL ? input.href : input.url;\n const endpointPath = new URL(url).pathname;\n\n // --- Pre-auth path: skip 402 round trip ---\n const cached = paymentCache.get(endpointPath);\n if (cached && preAuth?.estimatedAmount) {\n const paymentPayload = await createPaymentPayload(\n privateKey,\n walletAddress,\n {\n scheme: cached.scheme,\n network: cached.network,\n asset: cached.asset,\n payTo: cached.payTo,\n maxTimeoutSeconds: cached.maxTimeoutSeconds,\n extra: cached.extra,\n },\n preAuth.estimatedAmount,\n url,\n {\n url: cached.resourceUrl,\n description: cached.resourceDescription,\n },\n );\n\n const preAuthHeaders = new Headers(init?.headers);\n setPaymentHeaders(preAuthHeaders, paymentPayload);\n\n const response = await fetch(input, { ...init, headers: preAuthHeaders });\n\n // Pre-auth accepted — skip 402 entirely\n if (response.status !== 402) {\n return response;\n }\n\n // Pre-auth rejected (wrong amount, payTo changed, etc.)\n // Try to use this 402's payment header for a proper retry\n const paymentHeader = response.headers.get(\"x-payment-required\");\n if (paymentHeader) {\n return handle402(input, init, url, endpointPath, paymentHeader);\n }\n\n // No payment header — invalidate cache and retry clean (no payment header)\n // to get a proper 402 with payment requirements\n paymentCache.invalidate(endpointPath);\n const cleanResponse = await fetch(input, init);\n if (cleanResponse.status !== 402) {\n return cleanResponse;\n }\n const cleanHeader = cleanResponse.headers.get(\"x-payment-required\");\n if (!cleanHeader) {\n throw new Error(\"402 response missing x-payment-required header\");\n }\n return handle402(input, init, url, endpointPath, cleanHeader);\n }\n\n // --- Normal path: first request may get 402 ---\n const response = await fetch(input, init);\n\n if (response.status !== 402) {\n return response;\n }\n\n const paymentHeader = response.headers.get(\"x-payment-required\");\n if (!paymentHeader) {\n throw new Error(\"402 response missing x-payment-required header\");\n }\n\n return handle402(input, init, url, endpointPath, paymentHeader);\n };\n\n /** Handle a 402 response: parse, cache params, sign, retry. */\n async function handle402(\n input: RequestInfo | URL,\n init: RequestInit | undefined,\n url: string,\n endpointPath: string,\n paymentHeader: string,\n ): Promise<Response> {\n const paymentRequired = parsePaymentRequired(paymentHeader);\n const option = paymentRequired.accepts?.[0];\n if (!option) {\n throw new Error(\"No payment options in 402 response\");\n }\n\n const amount = option.amount || option.maxAmountRequired;\n if (!amount) {\n throw new Error(\"No amount in payment requirements\");\n }\n\n // Cache payment params for future pre-auth\n paymentCache.set(endpointPath, {\n payTo: option.payTo,\n asset: option.asset,\n scheme: option.scheme,\n network: option.network,\n extra: option.extra,\n maxTimeoutSeconds: option.maxTimeoutSeconds,\n resourceUrl: paymentRequired.resource?.url,\n resourceDescription: paymentRequired.resource?.description,\n });\n\n // Create signed payment\n const paymentPayload = await createPaymentPayload(\n privateKey,\n walletAddress,\n option,\n amount,\n url,\n paymentRequired.resource,\n );\n\n // Retry with payment\n const retryHeaders = new Headers(init?.headers);\n setPaymentHeaders(retryHeaders, paymentPayload);\n\n return fetch(input, {\n ...init,\n headers: retryHeaders,\n });\n }\n\n return { fetch: payFetch, cache: paymentCache };\n}\n","/**\n * Payment Parameter Cache\n *\n * Caches the 402 payment parameters (payTo, asset, network, etc.) after the first\n * request to each endpoint. On subsequent requests, pre-signs the payment and\n * attaches it to the first request, skipping the 402 round trip (~200ms savings).\n */\n\nexport type CachedPaymentParams = {\n payTo: string;\n asset: string;\n scheme: string;\n network: string;\n extra?: { name?: string; version?: string };\n maxTimeoutSeconds?: number;\n resourceUrl?: string;\n resourceDescription?: string;\n cachedAt: number;\n};\n\nconst DEFAULT_TTL_MS = 3_600_000; // 1 hour\n\nexport class PaymentCache {\n private cache = new Map<string, CachedPaymentParams>();\n private ttlMs: number;\n\n constructor(ttlMs = DEFAULT_TTL_MS) {\n this.ttlMs = ttlMs;\n }\n\n /** Get cached payment params for an endpoint path. */\n get(endpointPath: string): CachedPaymentParams | undefined {\n const entry = this.cache.get(endpointPath);\n if (!entry) return undefined;\n if (Date.now() - entry.cachedAt > this.ttlMs) {\n this.cache.delete(endpointPath);\n return undefined;\n }\n return entry;\n }\n\n /** Cache payment params from a 402 response. */\n set(endpointPath: string, params: Omit<CachedPaymentParams, \"cachedAt\">): void {\n this.cache.set(endpointPath, { ...params, cachedAt: Date.now() });\n }\n\n /** Invalidate cache for an endpoint (e.g., if payTo changed). */\n invalidate(endpointPath: string): void {\n this.cache.delete(endpointPath);\n }\n}\n","/**\n * Rule-Based Classifier (v2 — Weighted Scoring)\n *\n * Scores a request across 14 weighted dimensions and maps the aggregate\n * score to a tier using configurable boundaries. Confidence is calibrated\n * via sigmoid — low confidence triggers the fallback classifier.\n *\n * Handles 70-80% of requests in < 1ms with zero cost.\n */\n\nimport type { Tier, ScoringResult, ScoringConfig } from \"./types.js\";\n\ntype DimensionScore = { name: string; score: number; signal: string | null };\n\n// ─── Dimension Scorers ───\n// Each returns a score in [-1, 1] and an optional signal string.\n\nfunction scoreTokenCount(\n estimatedTokens: number,\n thresholds: { simple: number; complex: number },\n): DimensionScore {\n if (estimatedTokens < thresholds.simple) {\n return { name: \"tokenCount\", score: -1.0, signal: `short (${estimatedTokens} tokens)` };\n }\n if (estimatedTokens > thresholds.complex) {\n return { name: \"tokenCount\", score: 1.0, signal: `long (${estimatedTokens} tokens)` };\n }\n return { name: \"tokenCount\", score: 0, signal: null };\n}\n\nfunction scoreKeywordMatch(\n text: string,\n keywords: string[],\n name: string,\n signalLabel: string,\n thresholds: { low: number; high: number },\n scores: { none: number; low: number; high: number },\n): DimensionScore {\n const matches = keywords.filter((kw) => text.includes(kw.toLowerCase()));\n if (matches.length >= thresholds.high) {\n return {\n name,\n score: scores.high,\n signal: `${signalLabel} (${matches.slice(0, 3).join(\", \")})`,\n };\n }\n if (matches.length >= thresholds.low) {\n return {\n name,\n score: scores.low,\n signal: `${signalLabel} (${matches.slice(0, 3).join(\", \")})`,\n };\n }\n return { name, score: scores.none, signal: null };\n}\n\nfunction scoreMultiStep(text: string): DimensionScore {\n const patterns = [/first.*then/i, /step \\d/i, /\\d\\.\\s/];\n const hits = patterns.filter((p) => p.test(text));\n if (hits.length > 0) {\n return { name: \"multiStepPatterns\", score: 0.5, signal: \"multi-step\" };\n }\n return { name: \"multiStepPatterns\", score: 0, signal: null };\n}\n\nfunction scoreQuestionComplexity(prompt: string): DimensionScore {\n const count = (prompt.match(/\\?/g) || []).length;\n if (count > 3) {\n return { name: \"questionComplexity\", score: 0.5, signal: `${count} questions` };\n }\n return { name: \"questionComplexity\", score: 0, signal: null };\n}\n\n/**\n * Score agentic task indicators.\n * Returns agenticScore (0-1) based on keyword matches:\n * - 4+ matches = 1.0 (high agentic)\n * - 3 matches = 0.6 (moderate agentic, triggers auto-agentic mode)\n * - 1-2 matches = 0.2 (low agentic)\n *\n * Thresholds raised because common keywords were pruned from the list.\n */\nfunction scoreAgenticTask(\n text: string,\n keywords: string[],\n): { dimensionScore: DimensionScore; agenticScore: number } {\n let matchCount = 0;\n const signals: string[] = [];\n\n for (const keyword of keywords) {\n if (text.includes(keyword.toLowerCase())) {\n matchCount++;\n if (signals.length < 3) {\n signals.push(keyword);\n }\n }\n }\n\n // Threshold-based scoring (raised thresholds after keyword pruning)\n if (matchCount >= 4) {\n return {\n dimensionScore: {\n name: \"agenticTask\",\n score: 1.0,\n signal: `agentic (${signals.join(\", \")})`,\n },\n agenticScore: 1.0,\n };\n } else if (matchCount >= 3) {\n return {\n dimensionScore: {\n name: \"agenticTask\",\n score: 0.6,\n signal: `agentic (${signals.join(\", \")})`,\n },\n agenticScore: 0.6,\n };\n } else if (matchCount >= 1) {\n return {\n dimensionScore: {\n name: \"agenticTask\",\n score: 0.2,\n signal: `agentic-light (${signals.join(\", \")})`,\n },\n agenticScore: 0.2,\n };\n }\n\n return {\n dimensionScore: { name: \"agenticTask\", score: 0, signal: null },\n agenticScore: 0,\n };\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 // Score against user prompt only — system prompts contain boilerplate keywords\n // (tool definitions, skill descriptions, behavioral rules) that dominate scoring\n // and make every request score identically. See GitHub issue #50.\n const userText = prompt.toLowerCase();\n\n // Score all 14 dimensions against user text only\n const dimensions: DimensionScore[] = [\n // Token count uses total estimated tokens (system + user) — context size matters for model selection\n scoreTokenCount(estimatedTokens, config.tokenCountThresholds),\n scoreKeywordMatch(\n userText,\n config.codeKeywords,\n \"codePresence\",\n \"code\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 1.0 },\n ),\n scoreKeywordMatch(\n userText,\n config.reasoningKeywords,\n \"reasoningMarkers\",\n \"reasoning\",\n { low: 1, high: 2 },\n { none: 0, low: 0.7, high: 1.0 },\n ),\n scoreKeywordMatch(\n userText,\n config.technicalKeywords,\n \"technicalTerms\",\n \"technical\",\n { low: 2, high: 4 },\n { none: 0, low: 0.5, high: 1.0 },\n ),\n scoreKeywordMatch(\n userText,\n config.creativeKeywords,\n \"creativeMarkers\",\n \"creative\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 0.7 },\n ),\n scoreKeywordMatch(\n userText,\n config.simpleKeywords,\n \"simpleIndicators\",\n \"simple\",\n { low: 1, high: 2 },\n { none: 0, low: -1.0, high: -1.0 },\n ),\n scoreMultiStep(userText),\n scoreQuestionComplexity(prompt),\n\n // 6 new dimensions\n scoreKeywordMatch(\n userText,\n config.imperativeVerbs,\n \"imperativeVerbs\",\n \"imperative\",\n { low: 1, high: 2 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n userText,\n config.constraintIndicators,\n \"constraintCount\",\n \"constraints\",\n { low: 1, high: 3 },\n { none: 0, low: 0.3, high: 0.7 },\n ),\n scoreKeywordMatch(\n userText,\n config.outputFormatKeywords,\n \"outputFormat\",\n \"format\",\n { low: 1, high: 2 },\n { none: 0, low: 0.4, high: 0.7 },\n ),\n scoreKeywordMatch(\n userText,\n config.referenceKeywords,\n \"referenceComplexity\",\n \"references\",\n { low: 1, high: 2 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n userText,\n config.negationKeywords,\n \"negationComplexity\",\n \"negation\",\n { low: 2, high: 3 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n userText,\n config.domainSpecificKeywords,\n \"domainSpecificity\",\n \"domain-specific\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 0.8 },\n ),\n ];\n\n // Score agentic task indicators — user prompt only\n // System prompt describes assistant behavior, not user's intent.\n // e.g. a coding assistant system prompt with \"edit files\" / \"fix bugs\" should NOT\n // force every request into agentic mode.\n const agenticResult = scoreAgenticTask(userText, config.agenticTaskKeywords);\n dimensions.push(agenticResult.dimensionScore);\n const agenticScore = agenticResult.agenticScore;\n\n // Collect signals\n const signals = dimensions.filter((d) => d.signal !== null).map((d) => d.signal!);\n\n // Compute weighted score\n const weights = config.dimensionWeights;\n let weightedScore = 0;\n for (const d of dimensions) {\n const w = weights[d.name] ?? 0;\n weightedScore += d.score * w;\n }\n\n // Count reasoning markers for override — only check USER prompt, not system prompt\n // This prevents system prompts with \"step by step\" from triggering REASONING for simple queries\n const reasoningMatches = config.reasoningKeywords.filter((kw) =>\n userText.includes(kw.toLowerCase()),\n );\n\n // Direct reasoning override: 2+ reasoning markers = high confidence REASONING\n if (reasoningMatches.length >= 2) {\n const confidence = calibrateConfidence(\n Math.max(weightedScore, 0.3), // ensure positive for confidence calc\n config.confidenceSteepness,\n );\n return {\n score: weightedScore,\n tier: \"REASONING\",\n confidence: Math.max(confidence, 0.85),\n signals,\n agenticScore,\n dimensions,\n };\n }\n\n // Map weighted score to tier using boundaries\n const { simpleMedium, mediumComplex, complexReasoning } = config.tierBoundaries;\n let tier: Tier;\n let distanceFromBoundary: number;\n\n if (weightedScore < simpleMedium) {\n tier = \"SIMPLE\";\n distanceFromBoundary = simpleMedium - weightedScore;\n } else if (weightedScore < mediumComplex) {\n tier = \"MEDIUM\";\n distanceFromBoundary = Math.min(weightedScore - simpleMedium, mediumComplex - weightedScore);\n } else if (weightedScore < complexReasoning) {\n tier = \"COMPLEX\";\n distanceFromBoundary = Math.min(\n weightedScore - mediumComplex,\n complexReasoning - weightedScore,\n );\n } else {\n tier = \"REASONING\";\n distanceFromBoundary = weightedScore - complexReasoning;\n }\n\n // Calibrate confidence via sigmoid of distance from nearest boundary\n const confidence = calibrateConfidence(distanceFromBoundary, config.confidenceSteepness);\n\n // If confidence is below threshold → ambiguous\n if (confidence < config.confidenceThreshold) {\n return { score: weightedScore, tier: null, confidence, signals, agenticScore, dimensions };\n }\n\n return { score: weightedScore, tier, confidence, signals, agenticScore, dimensions };\n}\n\n/**\n * Sigmoid confidence calibration.\n * Maps distance from tier boundary to [0.5, 1.0] confidence range.\n */\nfunction calibrateConfidence(distance: number, steepness: number): number {\n return 1 / (1 + Math.exp(-steepness * distance));\n}\n","/**\n * Tier → Model Selection\n *\n * Maps a classification tier to the cheapest capable model.\n * Builds RoutingDecision metadata with cost estimates and savings.\n */\n\nimport type { Tier, TierConfig, RoutingDecision } from \"./types.js\";\n\nexport type ModelPricing = {\n inputPrice: number; // per 1M tokens\n outputPrice: number; // per 1M tokens\n};\n\nconst BASELINE_MODEL_ID = \"anthropic/claude-opus-4.6\";\n\n// Hardcoded fallback: Claude Opus 4.6 pricing (per 1M tokens)\n// Used when baseline model not found in dynamic pricing map\nconst BASELINE_INPUT_PRICE = 5.0;\nconst BASELINE_OUTPUT_PRICE = 25.0;\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 routingProfile?: \"free\" | \"eco\" | \"auto\" | \"premium\",\n agenticScore?: number,\n): RoutingDecision {\n const tierConfig = tierConfigs[tier];\n const model = tierConfig.primary;\n const pricing = modelPricing.get(model);\n\n // Defensive: guard against undefined price fields (not just undefined pricing)\n const inputPrice = pricing?.inputPrice ?? 0;\n const outputPrice = pricing?.outputPrice ?? 0;\n const inputCost = (estimatedInputTokens / 1_000_000) * inputPrice;\n const outputCost = (maxOutputTokens / 1_000_000) * outputPrice;\n const costEstimate = inputCost + outputCost;\n\n // Baseline: what Claude Opus 4.5 would cost (the premium reference)\n const opusPricing = modelPricing.get(BASELINE_MODEL_ID);\n const opusInputPrice = opusPricing?.inputPrice ?? BASELINE_INPUT_PRICE;\n const opusOutputPrice = opusPricing?.outputPrice ?? BASELINE_OUTPUT_PRICE;\n const baselineInput = (estimatedInputTokens / 1_000_000) * opusInputPrice;\n const baselineOutput = (maxOutputTokens / 1_000_000) * opusOutputPrice;\n const baselineCost = baselineInput + baselineOutput;\n\n // Premium profile doesn't calculate savings (it's about quality, not cost)\n const savings =\n routingProfile === \"premium\"\n ? 0\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 ...(agenticScore !== undefined && { agenticScore }),\n };\n}\n\n/**\n * Get the ordered fallback chain for a tier: [primary, ...fallbacks].\n */\nexport function getFallbackChain(tier: Tier, tierConfigs: Record<Tier, TierConfig>): string[] {\n const config = tierConfigs[tier];\n return [config.primary, ...config.fallback];\n}\n\n/**\n * Calculate cost for a specific model (used when fallback model is used).\n * Returns updated cost fields for RoutingDecision.\n */\nexport function calculateModelCost(\n model: string,\n modelPricing: Map<string, ModelPricing>,\n estimatedInputTokens: number,\n maxOutputTokens: number,\n routingProfile?: \"free\" | \"eco\" | \"auto\" | \"premium\",\n): { costEstimate: number; baselineCost: number; savings: number } {\n const pricing = modelPricing.get(model);\n\n // Defensive: guard against undefined price fields (not just undefined pricing)\n const inputPrice = pricing?.inputPrice ?? 0;\n const outputPrice = pricing?.outputPrice ?? 0;\n const inputCost = (estimatedInputTokens / 1_000_000) * inputPrice;\n const outputCost = (maxOutputTokens / 1_000_000) * outputPrice;\n const costEstimate = inputCost + outputCost;\n\n // Baseline: what Claude Opus 4.5 would cost (the premium reference)\n const opusPricing = modelPricing.get(BASELINE_MODEL_ID);\n const opusInputPrice = opusPricing?.inputPrice ?? BASELINE_INPUT_PRICE;\n const opusOutputPrice = opusPricing?.outputPrice ?? BASELINE_OUTPUT_PRICE;\n const baselineInput = (estimatedInputTokens / 1_000_000) * opusInputPrice;\n const baselineOutput = (maxOutputTokens / 1_000_000) * opusOutputPrice;\n const baselineCost = baselineInput + baselineOutput;\n\n // Premium profile doesn't calculate savings (it's about quality, not cost)\n const savings =\n routingProfile === \"premium\"\n ? 0\n : baselineCost > 0\n ? Math.max(0, (baselineCost - costEstimate) / baselineCost)\n : 0;\n\n return { costEstimate, baselineCost, savings };\n}\n\n/**\n * Filter a model list to only those that support tool calling.\n * When hasTools is false, returns the list unchanged.\n * When all models lack tool calling support, returns the full list as a fallback\n * (better to let the API error than produce an empty chain).\n */\nexport function filterByToolCalling(\n models: string[],\n hasTools: boolean,\n supportsToolCalling: (modelId: string) => boolean,\n): string[] {\n if (!hasTools) return models;\n const filtered = models.filter(supportsToolCalling);\n return filtered.length > 0 ? filtered : models;\n}\n\n/**\n * Filter a model list to only those that support vision (image inputs).\n * When hasVision is false, returns the list unchanged.\n * When all models lack vision support, returns the full list as a fallback\n * (better to let the API error than produce an empty chain).\n */\nexport function filterByVision(\n models: string[],\n hasVision: boolean,\n supportsVision: (modelId: string) => boolean,\n): string[] {\n if (!hasVision) return models;\n const filtered = models.filter(supportsVision);\n return filtered.length > 0 ? filtered : models;\n}\n\n/**\n * Get the fallback chain filtered by context length.\n * Only returns models that can handle the estimated total context.\n *\n * @param tier - The tier to get fallback chain for\n * @param tierConfigs - Tier configurations\n * @param estimatedTotalTokens - Estimated total context (input + output)\n * @param getContextWindow - Function to get context window for a model ID\n * @returns Filtered list of models that can handle the context\n */\nexport function getFallbackChainFiltered(\n tier: Tier,\n tierConfigs: Record<Tier, TierConfig>,\n estimatedTotalTokens: number,\n getContextWindow: (modelId: string) => number | undefined,\n): string[] {\n const fullChain = getFallbackChain(tier, tierConfigs);\n\n // Filter to models that can handle the context\n const filtered = fullChain.filter((modelId) => {\n const contextWindow = getContextWindow(modelId);\n if (contextWindow === undefined) {\n // Unknown model - include it (let API reject if needed)\n return true;\n }\n // Add 10% buffer for safety\n return contextWindow >= estimatedTotalTokens * 1.1;\n });\n\n // If all models filtered out, return the original chain\n // (let the API error out - better than no options)\n if (filtered.length === 0) {\n return fullChain;\n }\n\n return filtered;\n}\n","/**\n * Default Routing Config\n *\n * All routing parameters as a TypeScript constant.\n * Operators override via openclaw.yaml plugin config.\n *\n * Scoring uses 14 weighted dimensions with sigmoid confidence calibration.\n */\n\nimport type { RoutingConfig } from \"./types.js\";\n\nexport const DEFAULT_ROUTING_CONFIG: RoutingConfig = {\n version: \"2.0\",\n\n classifier: {\n llmModel: \"google/gemini-2.5-flash\",\n llmMaxTokens: 10,\n llmTemperature: 0,\n promptTruncationChars: 500,\n cacheTtlMs: 3_600_000, // 1 hour\n },\n\n scoring: {\n tokenCountThresholds: { simple: 50, complex: 500 },\n\n // Multilingual keywords: EN + ZH + JA + RU + DE + ES + PT + KO + AR\n codeKeywords: [\n // English\n \"function\",\n \"class\",\n \"import\",\n \"def\",\n \"SELECT\",\n \"async\",\n \"await\",\n \"const\",\n \"let\",\n \"var\",\n \"return\",\n \"```\",\n // Chinese\n \"函数\",\n \"类\",\n \"导入\",\n \"定义\",\n \"查询\",\n \"异步\",\n \"等待\",\n \"常量\",\n \"变量\",\n \"返回\",\n // Japanese\n \"関数\",\n \"クラス\",\n \"インポート\",\n \"非同期\",\n \"定数\",\n \"変数\",\n // Russian\n \"функция\",\n \"класс\",\n \"импорт\",\n \"определ\",\n \"запрос\",\n \"асинхронный\",\n \"ожидать\",\n \"константа\",\n \"переменная\",\n \"вернуть\",\n // German\n \"funktion\",\n \"klasse\",\n \"importieren\",\n \"definieren\",\n \"abfrage\",\n \"asynchron\",\n \"erwarten\",\n \"konstante\",\n \"variable\",\n \"zurückgeben\",\n // Spanish\n \"función\",\n \"clase\",\n \"importar\",\n \"definir\",\n \"consulta\",\n \"asíncrono\",\n \"esperar\",\n \"constante\",\n \"variable\",\n \"retornar\",\n // Portuguese\n \"função\",\n \"classe\",\n \"importar\",\n \"definir\",\n \"consulta\",\n \"assíncrono\",\n \"aguardar\",\n \"constante\",\n \"variável\",\n \"retornar\",\n // Korean\n \"함수\",\n \"클래스\",\n \"가져오기\",\n \"정의\",\n \"쿼리\",\n \"비동기\",\n \"대기\",\n \"상수\",\n \"변수\",\n \"반환\",\n // Arabic\n \"دالة\",\n \"فئة\",\n \"استيراد\",\n \"تعريف\",\n \"استعلام\",\n \"غير متزامن\",\n \"انتظار\",\n \"ثابت\",\n \"متغير\",\n \"إرجاع\",\n ],\n reasoningKeywords: [\n // English\n \"prove\",\n \"theorem\",\n \"derive\",\n \"step by step\",\n \"chain of thought\",\n \"formally\",\n \"mathematical\",\n \"proof\",\n \"logically\",\n // Chinese\n \"证明\",\n \"定理\",\n \"推导\",\n \"逐步\",\n \"思维链\",\n \"形式化\",\n \"数学\",\n \"逻辑\",\n // Japanese\n \"証明\",\n \"定理\",\n \"導出\",\n \"ステップバイステップ\",\n \"論理的\",\n // Russian\n \"доказать\",\n \"докажи\",\n \"доказательств\",\n \"теорема\",\n \"вывести\",\n \"шаг за шагом\",\n \"пошагово\",\n \"поэтапно\",\n \"цепочка рассуждений\",\n \"рассуждени\",\n \"формально\",\n \"математически\",\n \"логически\",\n // German\n \"beweisen\",\n \"beweis\",\n \"theorem\",\n \"ableiten\",\n \"schritt für schritt\",\n \"gedankenkette\",\n \"formal\",\n \"mathematisch\",\n \"logisch\",\n // Spanish\n \"demostrar\",\n \"teorema\",\n \"derivar\",\n \"paso a paso\",\n \"cadena de pensamiento\",\n \"formalmente\",\n \"matemático\",\n \"prueba\",\n \"lógicamente\",\n // Portuguese\n \"provar\",\n \"teorema\",\n \"derivar\",\n \"passo a passo\",\n \"cadeia de pensamento\",\n \"formalmente\",\n \"matemático\",\n \"prova\",\n \"logicamente\",\n // Korean\n \"증명\",\n \"정리\",\n \"도출\",\n \"단계별\",\n \"사고의 연쇄\",\n \"형식적\",\n \"수학적\",\n \"논리적\",\n // Arabic\n \"إثبات\",\n \"نظرية\",\n \"اشتقاق\",\n \"خطوة بخطوة\",\n \"سلسلة التفكير\",\n \"رسمياً\",\n \"رياضي\",\n \"برهان\",\n \"منطقياً\",\n ],\n simpleKeywords: [\n // English\n \"what is\",\n \"define\",\n \"translate\",\n \"hello\",\n \"yes or no\",\n \"capital of\",\n \"how old\",\n \"who is\",\n \"when was\",\n // Chinese\n \"什么是\",\n \"定义\",\n \"翻译\",\n \"你好\",\n \"是否\",\n \"首都\",\n \"多大\",\n \"谁是\",\n \"何时\",\n // Japanese\n \"とは\",\n \"定義\",\n \"翻訳\",\n \"こんにちは\",\n \"はいかいいえ\",\n \"首都\",\n \"誰\",\n // Russian\n \"что такое\",\n \"определение\",\n \"перевести\",\n \"переведи\",\n \"привет\",\n \"да или нет\",\n \"столица\",\n \"сколько лет\",\n \"кто такой\",\n \"когда\",\n \"объясни\",\n // German\n \"was ist\",\n \"definiere\",\n \"übersetze\",\n \"hallo\",\n \"ja oder nein\",\n \"hauptstadt\",\n \"wie alt\",\n \"wer ist\",\n \"wann\",\n \"erkläre\",\n // Spanish\n \"qué es\",\n \"definir\",\n \"traducir\",\n \"hola\",\n \"sí o no\",\n \"capital de\",\n \"cuántos años\",\n \"quién es\",\n \"cuándo\",\n // Portuguese\n \"o que é\",\n \"definir\",\n \"traduzir\",\n \"olá\",\n \"sim ou não\",\n \"capital de\",\n \"quantos anos\",\n \"quem é\",\n \"quando\",\n // Korean\n \"무엇\",\n \"정의\",\n \"번역\",\n \"안녕하세요\",\n \"예 또는 아니오\",\n \"수도\",\n \"누구\",\n \"언제\",\n // Arabic\n \"ما هو\",\n \"تعريف\",\n \"ترجم\",\n \"مرحبا\",\n \"نعم أو لا\",\n \"عاصمة\",\n \"من هو\",\n \"متى\",\n ],\n technicalKeywords: [\n // English\n \"algorithm\",\n \"optimize\",\n \"architecture\",\n \"distributed\",\n \"kubernetes\",\n \"microservice\",\n \"database\",\n \"infrastructure\",\n // Chinese\n \"算法\",\n \"优化\",\n \"架构\",\n \"分布式\",\n \"微服务\",\n \"数据库\",\n \"基础设施\",\n // Japanese\n \"アルゴリズム\",\n \"最適化\",\n \"アーキテクチャ\",\n \"分散\",\n \"マイクロサービス\",\n \"データベース\",\n // Russian\n \"алгоритм\",\n \"оптимизировать\",\n \"оптимизаци\",\n \"оптимизируй\",\n \"архитектура\",\n \"распределённый\",\n \"микросервис\",\n \"база данных\",\n \"инфраструктура\",\n // German\n \"algorithmus\",\n \"optimieren\",\n \"architektur\",\n \"verteilt\",\n \"kubernetes\",\n \"mikroservice\",\n \"datenbank\",\n \"infrastruktur\",\n // Spanish\n \"algoritmo\",\n \"optimizar\",\n \"arquitectura\",\n \"distribuido\",\n \"microservicio\",\n \"base de datos\",\n \"infraestructura\",\n // Portuguese\n \"algoritmo\",\n \"otimizar\",\n \"arquitetura\",\n \"distribuído\",\n \"microsserviço\",\n \"banco de dados\",\n \"infraestrutura\",\n // Korean\n \"알고리즘\",\n \"최적화\",\n \"아키텍처\",\n \"분산\",\n \"마이크로서비스\",\n \"데이터베이스\",\n \"인프라\",\n // Arabic\n \"خوارزمية\",\n \"تحسين\",\n \"بنية\",\n \"موزع\",\n \"خدمة مصغرة\",\n \"قاعدة بيانات\",\n \"بنية تحتية\",\n ],\n creativeKeywords: [\n // English\n \"story\",\n \"poem\",\n \"compose\",\n \"brainstorm\",\n \"creative\",\n \"imagine\",\n \"write a\",\n // Chinese\n \"故事\",\n \"诗\",\n \"创作\",\n \"头脑风暴\",\n \"创意\",\n \"想象\",\n \"写一个\",\n // Japanese\n \"物語\",\n \"詩\",\n \"作曲\",\n \"ブレインストーム\",\n \"創造的\",\n \"想像\",\n // Russian\n \"история\",\n \"рассказ\",\n \"стихотворение\",\n \"сочинить\",\n \"сочини\",\n \"мозговой штурм\",\n \"творческий\",\n \"представить\",\n \"придумай\",\n \"напиши\",\n // German\n \"geschichte\",\n \"gedicht\",\n \"komponieren\",\n \"brainstorming\",\n \"kreativ\",\n \"vorstellen\",\n \"schreibe\",\n \"erzählung\",\n // Spanish\n \"historia\",\n \"poema\",\n \"componer\",\n \"lluvia de ideas\",\n \"creativo\",\n \"imaginar\",\n \"escribe\",\n // Portuguese\n \"história\",\n \"poema\",\n \"compor\",\n \"criativo\",\n \"imaginar\",\n \"escreva\",\n // Korean\n \"이야기\",\n \"시\",\n \"작곡\",\n \"브레인스토밍\",\n \"창의적\",\n \"상상\",\n \"작성\",\n // Arabic\n \"قصة\",\n \"قصيدة\",\n \"تأليف\",\n \"عصف ذهني\",\n \"إبداعي\",\n \"تخيل\",\n \"اكتب\",\n ],\n\n // New dimension keyword lists (multilingual)\n imperativeVerbs: [\n // English\n \"build\",\n \"create\",\n \"implement\",\n \"design\",\n \"develop\",\n \"construct\",\n \"generate\",\n \"deploy\",\n \"configure\",\n \"set up\",\n // Chinese\n \"构建\",\n \"创建\",\n \"实现\",\n \"设计\",\n \"开发\",\n \"生成\",\n \"部署\",\n \"配置\",\n \"设置\",\n // Japanese\n \"構築\",\n \"作成\",\n \"実装\",\n \"設計\",\n \"開発\",\n \"生成\",\n \"デプロイ\",\n \"設定\",\n // Russian\n \"построить\",\n \"построй\",\n \"создать\",\n \"создай\",\n \"реализовать\",\n \"реализуй\",\n \"спроектировать\",\n \"разработать\",\n \"разработай\",\n \"сконструировать\",\n \"сгенерировать\",\n \"сгенерируй\",\n \"развернуть\",\n \"разверни\",\n \"настроить\",\n \"настрой\",\n // German\n \"erstellen\",\n \"bauen\",\n \"implementieren\",\n \"entwerfen\",\n \"entwickeln\",\n \"konstruieren\",\n \"generieren\",\n \"bereitstellen\",\n \"konfigurieren\",\n \"einrichten\",\n // Spanish\n \"construir\",\n \"crear\",\n \"implementar\",\n \"diseñar\",\n \"desarrollar\",\n \"generar\",\n \"desplegar\",\n \"configurar\",\n // Portuguese\n \"construir\",\n \"criar\",\n \"implementar\",\n \"projetar\",\n \"desenvolver\",\n \"gerar\",\n \"implantar\",\n \"configurar\",\n // Korean\n \"구축\",\n \"생성\",\n \"구현\",\n \"설계\",\n \"개발\",\n \"배포\",\n \"설정\",\n // Arabic\n \"بناء\",\n \"إنشاء\",\n \"تنفيذ\",\n \"تصميم\",\n \"تطوير\",\n \"توليد\",\n \"نشر\",\n \"إعداد\",\n ],\n constraintIndicators: [\n // English\n \"under\",\n \"at most\",\n \"at least\",\n \"within\",\n \"no more than\",\n \"o(\",\n \"maximum\",\n \"minimum\",\n \"limit\",\n \"budget\",\n // Chinese\n \"不超过\",\n \"至少\",\n \"最多\",\n \"在内\",\n \"最大\",\n \"最小\",\n \"限制\",\n \"预算\",\n // Japanese\n \"以下\",\n \"最大\",\n \"最小\",\n \"制限\",\n \"予算\",\n // Russian\n \"не более\",\n \"не менее\",\n \"как минимум\",\n \"в пределах\",\n \"максимум\",\n \"минимум\",\n \"ограничение\",\n \"бюджет\",\n // German\n \"höchstens\",\n \"mindestens\",\n \"innerhalb\",\n \"nicht mehr als\",\n \"maximal\",\n \"minimal\",\n \"grenze\",\n \"budget\",\n // Spanish\n \"como máximo\",\n \"al menos\",\n \"dentro de\",\n \"no más de\",\n \"máximo\",\n \"mínimo\",\n \"límite\",\n \"presupuesto\",\n // Portuguese\n \"no máximo\",\n \"pelo menos\",\n \"dentro de\",\n \"não mais que\",\n \"máximo\",\n \"mínimo\",\n \"limite\",\n \"orçamento\",\n // Korean\n \"이하\",\n \"이상\",\n \"최대\",\n \"최소\",\n \"제한\",\n \"예산\",\n // Arabic\n \"على الأكثر\",\n \"على الأقل\",\n \"ضمن\",\n \"لا يزيد عن\",\n \"أقصى\",\n \"أدنى\",\n \"حد\",\n \"ميزانية\",\n ],\n outputFormatKeywords: [\n // English\n \"json\",\n \"yaml\",\n \"xml\",\n \"table\",\n \"csv\",\n \"markdown\",\n \"schema\",\n \"format as\",\n \"structured\",\n // Chinese\n \"表格\",\n \"格式化为\",\n \"结构化\",\n // Japanese\n \"テーブル\",\n \"フォーマット\",\n \"構造化\",\n // Russian\n \"таблица\",\n \"форматировать как\",\n \"структурированный\",\n // German\n \"tabelle\",\n \"formatieren als\",\n \"strukturiert\",\n // Spanish\n \"tabla\",\n \"formatear como\",\n \"estructurado\",\n // Portuguese\n \"tabela\",\n \"formatar como\",\n \"estruturado\",\n // Korean\n \"테이블\",\n \"형식\",\n \"구조화\",\n // Arabic\n \"جدول\",\n \"تنسيق\",\n \"منظم\",\n ],\n referenceKeywords: [\n // English\n \"above\",\n \"below\",\n \"previous\",\n \"following\",\n \"the docs\",\n \"the api\",\n \"the code\",\n \"earlier\",\n \"attached\",\n // Chinese\n \"上面\",\n \"下面\",\n \"之前\",\n \"接下来\",\n \"文档\",\n \"代码\",\n \"附件\",\n // Japanese\n \"上記\",\n \"下記\",\n \"前の\",\n \"次の\",\n \"ドキュメント\",\n \"コード\",\n // Russian\n \"выше\",\n \"ниже\",\n \"предыдущий\",\n \"следующий\",\n \"документация\",\n \"код\",\n \"ранее\",\n \"вложение\",\n // German\n \"oben\",\n \"unten\",\n \"vorherige\",\n \"folgende\",\n \"dokumentation\",\n \"der code\",\n \"früher\",\n \"anhang\",\n // Spanish\n \"arriba\",\n \"abajo\",\n \"anterior\",\n \"siguiente\",\n \"documentación\",\n \"el código\",\n \"adjunto\",\n // Portuguese\n \"acima\",\n \"abaixo\",\n \"anterior\",\n \"seguinte\",\n \"documentação\",\n \"o código\",\n \"anexo\",\n // Korean\n \"위\",\n \"아래\",\n \"이전\",\n \"다음\",\n \"문서\",\n \"코드\",\n \"첨부\",\n // Arabic\n \"أعلاه\",\n \"أدناه\",\n \"السابق\",\n \"التالي\",\n \"الوثائق\",\n \"الكود\",\n \"مرفق\",\n ],\n negationKeywords: [\n // English\n \"don't\",\n \"do not\",\n \"avoid\",\n \"never\",\n \"without\",\n \"except\",\n \"exclude\",\n \"no longer\",\n // Chinese\n \"不要\",\n \"避免\",\n \"从不\",\n \"没有\",\n \"除了\",\n \"排除\",\n // Japanese\n \"しないで\",\n \"避ける\",\n \"決して\",\n \"なしで\",\n \"除く\",\n // Russian\n \"не делай\",\n \"не надо\",\n \"нельзя\",\n \"избегать\",\n \"никогда\",\n \"без\",\n \"кроме\",\n \"исключить\",\n \"больше не\",\n // German\n \"nicht\",\n \"vermeide\",\n \"niemals\",\n \"ohne\",\n \"außer\",\n \"ausschließen\",\n \"nicht mehr\",\n // Spanish\n \"no hagas\",\n \"evitar\",\n \"nunca\",\n \"sin\",\n \"excepto\",\n \"excluir\",\n // Portuguese\n \"não faça\",\n \"evitar\",\n \"nunca\",\n \"sem\",\n \"exceto\",\n \"excluir\",\n // Korean\n \"하지 마\",\n \"피하다\",\n \"절대\",\n \"없이\",\n \"제외\",\n // Arabic\n \"لا تفعل\",\n \"تجنب\",\n \"أبداً\",\n \"بدون\",\n \"باستثناء\",\n \"استبعاد\",\n ],\n domainSpecificKeywords: [\n // English\n \"quantum\",\n \"fpga\",\n \"vlsi\",\n \"risc-v\",\n \"asic\",\n \"photonics\",\n \"genomics\",\n \"proteomics\",\n \"topological\",\n \"homomorphic\",\n \"zero-knowledge\",\n \"lattice-based\",\n // Chinese\n \"量子\",\n \"光子学\",\n \"基因组学\",\n \"蛋白质组学\",\n \"拓扑\",\n \"同态\",\n \"零知识\",\n \"格密码\",\n // Japanese\n \"量子\",\n \"フォトニクス\",\n \"ゲノミクス\",\n \"トポロジカル\",\n // Russian\n \"квантовый\",\n \"фотоника\",\n \"геномика\",\n \"протеомика\",\n \"топологический\",\n \"гомоморфный\",\n \"с нулевым разглашением\",\n \"на основе решёток\",\n // German\n \"quanten\",\n \"photonik\",\n \"genomik\",\n \"proteomik\",\n \"topologisch\",\n \"homomorph\",\n \"zero-knowledge\",\n \"gitterbasiert\",\n // Spanish\n \"cuántico\",\n \"fotónica\",\n \"genómica\",\n \"proteómica\",\n \"topológico\",\n \"homomórfico\",\n // Portuguese\n \"quântico\",\n \"fotônica\",\n \"genômica\",\n \"proteômica\",\n \"topológico\",\n \"homomórfico\",\n // Korean\n \"양자\",\n \"포토닉스\",\n \"유전체학\",\n \"위상\",\n \"동형\",\n // Arabic\n \"كمي\",\n \"ضوئيات\",\n \"جينوميات\",\n \"طوبولوجي\",\n \"تماثلي\",\n ],\n\n // Agentic task keywords - file ops, execution, multi-step, iterative work\n // Pruned: removed overly common words like \"then\", \"first\", \"run\", \"test\", \"build\"\n agenticTaskKeywords: [\n // English - File operations (clearly agentic)\n \"read file\",\n \"read the file\",\n \"look at\",\n \"check the\",\n \"open the\",\n \"edit\",\n \"modify\",\n \"update the\",\n \"change the\",\n \"write to\",\n \"create file\",\n // English - Execution (specific commands only)\n \"execute\",\n \"deploy\",\n \"install\",\n \"npm\",\n \"pip\",\n \"compile\",\n // English - Multi-step patterns (specific only)\n \"after that\",\n \"and also\",\n \"once done\",\n \"step 1\",\n \"step 2\",\n // English - Iterative work\n \"fix\",\n \"debug\",\n \"until it works\",\n \"keep trying\",\n \"iterate\",\n \"make sure\",\n \"verify\",\n \"confirm\",\n // Chinese (keep specific ones)\n \"读取文件\",\n \"查看\",\n \"打开\",\n \"编辑\",\n \"修改\",\n \"更新\",\n \"创建\",\n \"执行\",\n \"部署\",\n \"安装\",\n \"第一步\",\n \"第二步\",\n \"修复\",\n \"调试\",\n \"直到\",\n \"确认\",\n \"验证\",\n // Spanish\n \"leer archivo\",\n \"editar\",\n \"modificar\",\n \"actualizar\",\n \"ejecutar\",\n \"desplegar\",\n \"instalar\",\n \"paso 1\",\n \"paso 2\",\n \"arreglar\",\n \"depurar\",\n \"verificar\",\n // Portuguese\n \"ler arquivo\",\n \"editar\",\n \"modificar\",\n \"atualizar\",\n \"executar\",\n \"implantar\",\n \"instalar\",\n \"passo 1\",\n \"passo 2\",\n \"corrigir\",\n \"depurar\",\n \"verificar\",\n // Korean\n \"파일 읽기\",\n \"편집\",\n \"수정\",\n \"업데이트\",\n \"실행\",\n \"배포\",\n \"설치\",\n \"단계 1\",\n \"단계 2\",\n \"디버그\",\n \"확인\",\n // Arabic\n \"قراءة ملف\",\n \"تحرير\",\n \"تعديل\",\n \"تحديث\",\n \"تنفيذ\",\n \"نشر\",\n \"تثبيت\",\n \"الخطوة 1\",\n \"الخطوة 2\",\n \"إصلاح\",\n \"تصحيح\",\n \"تحقق\",\n ],\n\n // Dimension weights (sum to 1.0)\n dimensionWeights: {\n tokenCount: 0.08,\n codePresence: 0.15,\n reasoningMarkers: 0.18,\n technicalTerms: 0.1,\n creativeMarkers: 0.05,\n simpleIndicators: 0.02, // Reduced from 0.12 to make room for agenticTask\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 agenticTask: 0.04, // Reduced - agentic signals influence tier selection, not dominate it\n },\n\n // Tier boundaries on weighted score axis\n tierBoundaries: {\n simpleMedium: 0.0,\n mediumComplex: 0.3, // Raised from 0.18 - prevent simple tasks from reaching expensive COMPLEX tier\n complexReasoning: 0.5, // Raised from 0.4 - reserve for true reasoning tasks\n },\n\n // Sigmoid steepness for confidence calibration\n confidenceSteepness: 12,\n // Below this confidence → ambiguous (null tier)\n confidenceThreshold: 0.7,\n },\n\n // Auto (balanced) tier configs - current default smart routing\n tiers: {\n SIMPLE: {\n primary: \"moonshot/kimi-k2.5\", // $0.60/$3.00 - best quality/price for simple tasks\n fallback: [\n \"google/gemini-2.5-flash-lite\", // 1M context, ultra cheap ($0.10/$0.40)\n \"nvidia/gpt-oss-120b\", // FREE fallback\n \"deepseek/deepseek-chat\",\n ],\n },\n MEDIUM: {\n primary: \"moonshot/kimi-k2.5\", // $0.50/$2.40 - strong tool use, proper function call format\n fallback: [\n \"deepseek/deepseek-chat\",\n \"google/gemini-2.5-flash-lite\", // 1M context, ultra cheap ($0.10/$0.40)\n \"xai/grok-4-1-fast-non-reasoning\", // Upgraded Grok 4.1\n ],\n },\n COMPLEX: {\n primary: \"google/gemini-3.1-pro\", // Newest Gemini 3.1 - upgraded from 3.0\n fallback: [\n \"google/gemini-2.5-flash-lite\", // CRITICAL: 1M context, ultra-cheap failsafe ($0.10/$0.40)\n \"google/gemini-3-pro-preview\", // 3.0 fallback\n \"google/gemini-2.5-pro\",\n \"deepseek/deepseek-chat\",\n \"xai/grok-4-0709\",\n \"openai/gpt-5.2\", // Newer and cheaper input than gpt-4o\n \"openai/gpt-4o\",\n \"anthropic/claude-sonnet-4.6\",\n ],\n },\n REASONING: {\n primary: \"xai/grok-4-1-fast-reasoning\", // Upgraded Grok 4.1 reasoning $0.20/$0.50\n fallback: [\n \"deepseek/deepseek-reasoner\", // Cheap reasoning model\n \"openai/o4-mini\", // Newer and cheaper than o3 ($1.10 vs $2.00)\n \"openai/o3\",\n ],\n },\n },\n\n // Eco tier configs - absolute cheapest (blockrun/eco)\n ecoTiers: {\n SIMPLE: {\n primary: \"nvidia/gpt-oss-120b\", // FREE! $0.00/$0.00\n fallback: [\"google/gemini-2.5-flash-lite\", \"deepseek/deepseek-chat\"],\n },\n MEDIUM: {\n primary: \"google/gemini-2.5-flash-lite\", // $0.10/$0.40 - cheapest capable with 1M context\n fallback: [\"deepseek/deepseek-chat\", \"nvidia/gpt-oss-120b\"],\n },\n COMPLEX: {\n primary: \"google/gemini-2.5-flash-lite\", // $0.10/$0.40 - 1M context handles complexity\n fallback: [\"google/gemini-2.5-flash\", \"deepseek/deepseek-chat\", \"xai/grok-4-0709\"],\n },\n REASONING: {\n primary: \"xai/grok-4-1-fast-reasoning\", // $0.20/$0.50\n fallback: [\"deepseek/deepseek-reasoner\"],\n },\n },\n\n // Premium tier configs - best quality (blockrun/premium)\n // codex=complex coding, kimi=simple coding, sonnet=reasoning/instructions, opus=architecture/PM/audits\n premiumTiers: {\n SIMPLE: {\n primary: \"moonshot/kimi-k2.5\", // $0.60/$3.00 - good for simple coding\n fallback: [\n \"anthropic/claude-haiku-4.5\",\n \"google/gemini-2.5-flash-lite\",\n \"deepseek/deepseek-chat\",\n ],\n },\n MEDIUM: {\n primary: \"openai/gpt-5.2-codex\", // $2.50/$10 - strong coding for medium tasks\n fallback: [\n \"moonshot/kimi-k2.5\",\n \"google/gemini-2.5-pro\",\n \"xai/grok-4-0709\",\n \"anthropic/claude-sonnet-4.6\",\n ],\n },\n COMPLEX: {\n primary: \"anthropic/claude-opus-4.6\", // Best quality for complex tasks\n fallback: [\n \"openai/gpt-5.2-codex\",\n \"anthropic/claude-opus-4.6\",\n \"anthropic/claude-sonnet-4.6\",\n \"google/gemini-3.1-pro\", // Newest Gemini\n \"google/gemini-3-pro-preview\",\n \"moonshot/kimi-k2.5\",\n ],\n },\n REASONING: {\n primary: \"anthropic/claude-sonnet-4.6\", // $3/$15 - best for reasoning/instructions\n fallback: [\n \"anthropic/claude-opus-4.6\",\n \"anthropic/claude-opus-4.6\",\n \"openai/o4-mini\", // Newer and cheaper than o3 ($1.10 vs $2.00)\n \"openai/o3\",\n \"xai/grok-4-1-fast-reasoning\",\n ],\n },\n },\n\n // Agentic tier configs - models that excel at multi-step autonomous tasks\n agenticTiers: {\n SIMPLE: {\n primary: \"moonshot/kimi-k2.5\", // Cheaper than Haiku ($0.5/$2.4 vs $1/$5), larger context\n fallback: [\n \"anthropic/claude-haiku-4.5\",\n \"xai/grok-4-1-fast-non-reasoning\",\n \"openai/gpt-4o-mini\",\n ],\n },\n MEDIUM: {\n primary: \"moonshot/kimi-k2.5\", // $0.50/$2.40 - strong tool use, handles function calls correctly\n fallback: [\n \"anthropic/claude-haiku-4.5\",\n \"deepseek/deepseek-chat\",\n \"xai/grok-4-1-fast-non-reasoning\",\n ],\n },\n COMPLEX: {\n primary: \"anthropic/claude-sonnet-4.6\",\n fallback: [\n \"anthropic/claude-opus-4.6\", // Latest Opus - best agentic\n \"openai/gpt-5.2\",\n \"google/gemini-3.1-pro\", // Newest Gemini\n \"google/gemini-3-pro-preview\",\n \"xai/grok-4-0709\",\n ],\n },\n REASONING: {\n primary: \"anthropic/claude-sonnet-4.6\", // Strong tool use + reasoning for agentic tasks\n fallback: [\n \"anthropic/claude-opus-4.6\",\n \"xai/grok-4-1-fast-reasoning\",\n \"deepseek/deepseek-reasoner\",\n ],\n },\n },\n\n overrides: {\n maxTokensForceComplex: 100_000,\n structuredOutputMinTier: \"MEDIUM\",\n ambiguousDefaultTier: \"MEDIUM\",\n agenticMode: false,\n },\n};\n","/**\n * Smart Router Entry Point\n *\n * Classifies requests and routes to the cheapest capable model.\n * 100% local — rules-based scoring handles all requests in <1ms.\n * Ambiguous cases default to configurable tier (MEDIUM by default).\n */\n\nimport type { Tier, RoutingDecision, RoutingConfig } from \"./types.js\";\nimport { classifyByRules } from \"./rules.js\";\nimport { selectModel, type ModelPricing } from \"./selector.js\";\n\nexport type RouterOptions = {\n config: RoutingConfig;\n modelPricing: Map<string, ModelPricing>;\n routingProfile?: \"free\" | \"eco\" | \"auto\" | \"premium\";\n};\n\n/**\n * Route a request to the cheapest capable model.\n *\n * 1. Check overrides (large context, structured output)\n * 2. Run rule-based classifier (14 weighted dimensions, <1ms)\n * 3. If ambiguous, default to configurable tier (no external API calls)\n * 4. Select model for tier\n * 5. Return RoutingDecision with metadata\n */\nexport function route(\n prompt: string,\n systemPrompt: string | undefined,\n maxOutputTokens: number,\n options: RouterOptions,\n): RoutingDecision {\n const { config, modelPricing } = options;\n\n // Estimate input tokens (~4 chars per token)\n const fullText = `${systemPrompt ?? \"\"} ${prompt}`;\n const estimatedTokens = Math.ceil(fullText.length / 4);\n\n // --- Rule-based classification (runs first to get agenticScore) ---\n const ruleResult = classifyByRules(prompt, systemPrompt, estimatedTokens, config.scoring);\n\n // --- Select tier configs based on routing profile ---\n const { routingProfile } = options;\n let tierConfigs: Record<Tier, { primary: string; fallback: string[] }>;\n let profileSuffix = \"\";\n\n if (routingProfile === \"eco\" && config.ecoTiers) {\n // Eco profile: ultra cost-optimized models\n tierConfigs = config.ecoTiers;\n profileSuffix = \" | eco\";\n } else if (routingProfile === \"premium\" && config.premiumTiers) {\n // Premium profile: best quality models\n tierConfigs = config.premiumTiers;\n profileSuffix = \" | premium\";\n } else {\n // Auto profile (or undefined): intelligent routing with agentic detection\n // Determine if agentic tiers should be used:\n // 1. Explicit agenticMode config OR\n // 2. Auto-detected agentic task (agenticScore >= 0.5, lowered for better multi-step detection)\n const agenticScore = ruleResult.agenticScore ?? 0;\n const isAutoAgentic = agenticScore >= 0.5;\n const isExplicitAgentic = config.overrides.agenticMode ?? false;\n const useAgenticTiers = (isAutoAgentic || isExplicitAgentic) && config.agenticTiers != null;\n tierConfigs = useAgenticTiers ? config.agenticTiers! : config.tiers;\n profileSuffix = useAgenticTiers ? \" | agentic\" : \"\";\n }\n\n const agenticScoreValue = ruleResult.agenticScore;\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${profileSuffix}`,\n tierConfigs,\n modelPricing,\n estimatedTokens,\n maxOutputTokens,\n routingProfile,\n agenticScoreValue,\n );\n }\n\n // Structured output detection\n const hasStructuredOutput = systemPrompt ? /json|structured|schema/i.test(systemPrompt) : false;\n\n let tier: Tier;\n let confidence: number;\n const method: \"rules\" | \"llm\" = \"rules\";\n let reasoning = `score=${ruleResult.score.toFixed(2)} | ${ruleResult.signals.join(\", \")}`;\n\n if (ruleResult.tier !== null) {\n tier = ruleResult.tier;\n confidence = ruleResult.confidence;\n } else {\n // Ambiguous — default to configurable tier (no external API call)\n tier = config.overrides.ambiguousDefaultTier;\n confidence = 0.5;\n reasoning += ` | ambiguous -> default: ${tier}`;\n }\n\n // Apply structured output minimum tier\n if (hasStructuredOutput) {\n const tierRank: Record<Tier, number> = { SIMPLE: 0, MEDIUM: 1, COMPLEX: 2, REASONING: 3 };\n const minTier = config.overrides.structuredOutputMinTier;\n if (tierRank[tier] < tierRank[minTier]) {\n reasoning += ` | upgraded to ${minTier} (structured output)`;\n tier = minTier;\n }\n }\n\n // Add routing profile suffix to reasoning\n reasoning += profileSuffix;\n\n return selectModel(\n tier,\n confidence,\n method,\n reasoning,\n tierConfigs,\n modelPricing,\n estimatedTokens,\n maxOutputTokens,\n routingProfile,\n agenticScoreValue,\n );\n}\n\nexport {\n getFallbackChain,\n getFallbackChainFiltered,\n filterByToolCalling,\n filterByVision,\n calculateModelCost,\n} 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 * 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\n/**\n * Model aliases for convenient shorthand access.\n * Users can type `/model claude` instead of `/model blockrun/anthropic/claude-sonnet-4-6`.\n */\nexport const MODEL_ALIASES: Record<string, string> = {\n // Claude - use newest versions (4.6)\n claude: \"anthropic/claude-sonnet-4.6\",\n sonnet: \"anthropic/claude-sonnet-4.6\",\n \"sonnet-4\": \"anthropic/claude-sonnet-4.6\",\n \"sonnet-4.6\": \"anthropic/claude-sonnet-4.6\",\n \"sonnet-4-6\": \"anthropic/claude-sonnet-4.6\",\n opus: \"anthropic/claude-opus-4.6\",\n \"opus-4\": \"anthropic/claude-opus-4.6\",\n \"opus-4.6\": \"anthropic/claude-opus-4.6\",\n \"opus-4-6\": \"anthropic/claude-opus-4.6\",\n haiku: \"anthropic/claude-haiku-4.5\",\n // Claude - provider/shortname patterns (common in agent frameworks)\n \"anthropic/sonnet\": \"anthropic/claude-sonnet-4.6\",\n \"anthropic/opus\": \"anthropic/claude-opus-4.6\",\n \"anthropic/haiku\": \"anthropic/claude-haiku-4.5\",\n \"anthropic/claude\": \"anthropic/claude-sonnet-4.6\",\n // Backward compatibility - map all variants to 4.6\n \"anthropic/claude-sonnet-4\": \"anthropic/claude-sonnet-4.6\",\n \"anthropic/claude-sonnet-4-6\": \"anthropic/claude-sonnet-4.6\",\n \"anthropic/claude-opus-4\": \"anthropic/claude-opus-4.6\",\n \"anthropic/claude-opus-4-6\": \"anthropic/claude-opus-4.6\",\n \"anthropic/claude-opus-4.5\": \"anthropic/claude-opus-4.6\",\n \"anthropic/claude-haiku-4\": \"anthropic/claude-haiku-4.5\",\n \"anthropic/claude-haiku-4-5\": \"anthropic/claude-haiku-4.5\",\n\n // OpenAI\n gpt: \"openai/gpt-4o\",\n gpt4: \"openai/gpt-4o\",\n gpt5: \"openai/gpt-5.2\",\n codex: \"openai/gpt-5.2-codex\",\n mini: \"openai/gpt-4o-mini\",\n o1: \"openai/o1\",\n o3: \"openai/o3\",\n\n // DeepSeek\n deepseek: \"deepseek/deepseek-chat\",\n reasoner: \"deepseek/deepseek-reasoner\",\n\n // Kimi / Moonshot\n kimi: \"moonshot/kimi-k2.5\",\n moonshot: \"moonshot/kimi-k2.5\",\n \"kimi-k2.5\": \"moonshot/kimi-k2.5\",\n\n // Google\n gemini: \"google/gemini-2.5-pro\",\n flash: \"google/gemini-2.5-flash\",\n \"gemini-3.1-pro-preview\": \"google/gemini-3.1-pro\",\n \"google/gemini-3.1-pro-preview\": \"google/gemini-3.1-pro\",\n\n // xAI\n grok: \"xai/grok-3\",\n \"grok-fast\": \"xai/grok-4-fast-reasoning\",\n \"grok-code\": \"xai/grok-code-fast-1\",\n\n // NVIDIA\n nvidia: \"nvidia/gpt-oss-120b\",\n \"gpt-120b\": \"nvidia/gpt-oss-120b\",\n\n // MiniMax\n minimax: \"minimax/minimax-m2.5\",\n\n // Routing profile aliases (common variations)\n \"auto-router\": \"auto\",\n router: \"auto\",\n\n // Note: auto, free, eco, premium are virtual routing profiles registered in BLOCKRUN_MODELS\n // They don't need aliases since they're already top-level model IDs\n};\n\n/**\n * Resolve a model alias to its full model ID.\n * Also strips \"blockrun/\" prefix for direct model paths.\n * Examples:\n * - \"claude\" -> \"anthropic/claude-sonnet-4-6\" (alias)\n * - \"blockrun/claude\" -> \"anthropic/claude-sonnet-4-6\" (alias with prefix)\n * - \"blockrun/anthropic/claude-sonnet-4-6\" -> \"anthropic/claude-sonnet-4-6\" (prefix stripped)\n * - \"openai/gpt-4o\" -> \"openai/gpt-4o\" (unchanged)\n */\nexport function resolveModelAlias(model: string): string {\n const normalized = model.trim().toLowerCase();\n const resolved = MODEL_ALIASES[normalized];\n if (resolved) return resolved;\n\n // Check with \"blockrun/\" prefix stripped\n if (normalized.startsWith(\"blockrun/\")) {\n const withoutPrefix = normalized.slice(\"blockrun/\".length);\n const resolvedWithoutPrefix = MODEL_ALIASES[withoutPrefix];\n if (resolvedWithoutPrefix) return resolvedWithoutPrefix;\n\n // Even if not an alias, strip the prefix for direct model paths\n // e.g., \"blockrun/anthropic/claude-sonnet-4-6\" -> \"anthropic/claude-sonnet-4-6\"\n return withoutPrefix;\n }\n\n return model;\n}\n\ntype BlockRunModel = {\n id: string;\n name: string;\n /** Model version (e.g., \"4.6\", \"3.1\", \"5.2\") for tracking updates */\n version?: string;\n inputPrice: number;\n outputPrice: number;\n contextWindow: number;\n maxOutput: number;\n reasoning?: boolean;\n vision?: boolean;\n /** Models optimized for agentic workflows (multi-step autonomous tasks) */\n agentic?: boolean;\n /**\n * Model supports OpenAI-compatible structured function/tool calling.\n * Models without this flag output tool invocations as plain text JSON,\n * which leaks raw {\"command\":\"...\"} into visible chat messages.\n * Default: false (must opt-in to prevent silent regressions on new models).\n */\n toolCalling?: boolean;\n};\n\nexport const BLOCKRUN_MODELS: BlockRunModel[] = [\n // Smart routing meta-models — proxy replaces with actual model\n // NOTE: Model IDs are WITHOUT provider prefix (OpenClaw adds \"blockrun/\" automatically)\n {\n id: \"auto\",\n name: \"Auto (Smart Router - Balanced)\",\n inputPrice: 0,\n outputPrice: 0,\n contextWindow: 1_050_000,\n maxOutput: 128_000,\n },\n {\n id: \"free\",\n name: \"Free (NVIDIA GPT-OSS-120B only)\",\n inputPrice: 0,\n outputPrice: 0,\n contextWindow: 128_000,\n maxOutput: 4_096,\n },\n {\n id: \"eco\",\n name: \"Eco (Smart Router - Cost Optimized)\",\n inputPrice: 0,\n outputPrice: 0,\n contextWindow: 1_050_000,\n maxOutput: 128_000,\n },\n {\n id: \"premium\",\n name: \"Premium (Smart Router - Best Quality)\",\n inputPrice: 0,\n outputPrice: 0,\n contextWindow: 2_000_000,\n maxOutput: 200_000,\n },\n\n // OpenAI GPT-5 Family\n {\n id: \"openai/gpt-5.2\",\n name: \"GPT-5.2\",\n version: \"5.2\",\n inputPrice: 1.75,\n outputPrice: 14.0,\n contextWindow: 400000,\n maxOutput: 128000,\n reasoning: true,\n vision: true,\n agentic: true,\n toolCalling: true,\n },\n {\n id: \"openai/gpt-5-mini\",\n name: \"GPT-5 Mini\",\n version: \"5.0\",\n inputPrice: 0.25,\n outputPrice: 2.0,\n contextWindow: 200000,\n maxOutput: 65536,\n toolCalling: true,\n },\n {\n id: \"openai/gpt-5-nano\",\n name: \"GPT-5 Nano\",\n version: \"5.0\",\n inputPrice: 0.05,\n outputPrice: 0.4,\n contextWindow: 128000,\n maxOutput: 32768,\n toolCalling: true,\n },\n {\n id: \"openai/gpt-5.2-pro\",\n name: \"GPT-5.2 Pro\",\n version: \"5.2\",\n inputPrice: 21.0,\n outputPrice: 168.0,\n contextWindow: 400000,\n maxOutput: 128000,\n reasoning: true,\n toolCalling: true,\n },\n\n // OpenAI Codex Family\n {\n id: \"openai/gpt-5.2-codex\",\n name: \"GPT-5.2 Codex\",\n version: \"5.2\",\n inputPrice: 1.75,\n outputPrice: 14.0,\n contextWindow: 128000,\n maxOutput: 32000,\n agentic: true,\n toolCalling: true,\n },\n\n // OpenAI GPT-4 Family\n {\n id: \"openai/gpt-4.1\",\n name: \"GPT-4.1\",\n version: \"4.1\",\n inputPrice: 2.0,\n outputPrice: 8.0,\n contextWindow: 128000,\n maxOutput: 16384,\n vision: true,\n toolCalling: true,\n },\n {\n id: \"openai/gpt-4.1-mini\",\n name: \"GPT-4.1 Mini\",\n version: \"4.1\",\n inputPrice: 0.4,\n outputPrice: 1.6,\n contextWindow: 128000,\n maxOutput: 16384,\n toolCalling: true,\n },\n {\n id: \"openai/gpt-4.1-nano\",\n name: \"GPT-4.1 Nano\",\n version: \"4.1\",\n inputPrice: 0.1,\n outputPrice: 0.4,\n contextWindow: 128000,\n maxOutput: 16384,\n toolCalling: true,\n },\n {\n id: \"openai/gpt-4o\",\n name: \"GPT-4o\",\n version: \"4o\",\n inputPrice: 2.5,\n outputPrice: 10.0,\n contextWindow: 128000,\n maxOutput: 16384,\n vision: true,\n agentic: true,\n toolCalling: true,\n },\n {\n id: \"openai/gpt-4o-mini\",\n name: \"GPT-4o Mini\",\n version: \"4o-mini\",\n inputPrice: 0.15,\n outputPrice: 0.6,\n contextWindow: 128000,\n maxOutput: 16384,\n toolCalling: true,\n },\n\n // OpenAI O-series (Reasoning)\n {\n id: \"openai/o1\",\n name: \"o1\",\n version: \"1\",\n inputPrice: 15.0,\n outputPrice: 60.0,\n contextWindow: 200000,\n maxOutput: 100000,\n reasoning: true,\n toolCalling: true,\n },\n {\n id: \"openai/o1-mini\",\n name: \"o1-mini\",\n version: \"1-mini\",\n inputPrice: 1.1,\n outputPrice: 4.4,\n contextWindow: 128000,\n maxOutput: 65536,\n reasoning: true,\n toolCalling: true,\n },\n {\n id: \"openai/o3\",\n name: \"o3\",\n version: \"3\",\n inputPrice: 2.0,\n outputPrice: 8.0,\n contextWindow: 200000,\n maxOutput: 100000,\n reasoning: true,\n toolCalling: true,\n },\n {\n id: \"openai/o3-mini\",\n name: \"o3-mini\",\n version: \"3-mini\",\n inputPrice: 1.1,\n outputPrice: 4.4,\n contextWindow: 128000,\n maxOutput: 65536,\n reasoning: true,\n toolCalling: true,\n },\n {\n id: \"openai/o4-mini\",\n name: \"o4-mini\",\n version: \"4-mini\",\n inputPrice: 1.1,\n outputPrice: 4.4,\n contextWindow: 128000,\n maxOutput: 65536,\n reasoning: true,\n toolCalling: true,\n },\n\n // Anthropic - all Claude models excel at agentic workflows\n // Use newest versions (4.6) with full provider prefix\n {\n id: \"anthropic/claude-haiku-4.5\",\n name: \"Claude Haiku 4.5\",\n version: \"4.5\",\n inputPrice: 1.0,\n outputPrice: 5.0,\n contextWindow: 200000,\n maxOutput: 8192,\n vision: true,\n agentic: true,\n toolCalling: true,\n },\n {\n id: \"anthropic/claude-sonnet-4.6\",\n name: \"Claude Sonnet 4.6\",\n version: \"4.6\",\n inputPrice: 3.0,\n outputPrice: 15.0,\n contextWindow: 200000,\n maxOutput: 64000,\n reasoning: true,\n vision: true,\n agentic: true,\n toolCalling: true,\n },\n {\n id: \"anthropic/claude-opus-4.6\",\n name: \"Claude Opus 4.6\",\n version: \"4.6\",\n inputPrice: 5.0,\n outputPrice: 25.0,\n contextWindow: 200000,\n maxOutput: 32000,\n reasoning: true,\n vision: true,\n agentic: true,\n toolCalling: true,\n },\n\n // Google\n {\n id: \"google/gemini-3.1-pro\",\n name: \"Gemini 3.1 Pro\",\n version: \"3.1\",\n inputPrice: 2.0,\n outputPrice: 12.0,\n contextWindow: 1050000,\n maxOutput: 65536,\n reasoning: true,\n vision: true,\n toolCalling: true,\n },\n {\n id: \"google/gemini-3-pro-preview\",\n name: \"Gemini 3 Pro Preview\",\n version: \"3.0\",\n inputPrice: 2.0,\n outputPrice: 12.0,\n contextWindow: 1050000,\n maxOutput: 65536,\n reasoning: true,\n vision: true,\n toolCalling: true,\n },\n {\n id: \"google/gemini-3-flash-preview\",\n name: \"Gemini 3 Flash Preview\",\n version: \"3.0\",\n inputPrice: 0.5,\n outputPrice: 3.0,\n contextWindow: 1000000,\n maxOutput: 65536,\n vision: true,\n toolCalling: true,\n },\n {\n id: \"google/gemini-2.5-pro\",\n name: \"Gemini 2.5 Pro\",\n version: \"2.5\",\n inputPrice: 1.25,\n outputPrice: 10.0,\n contextWindow: 1050000,\n maxOutput: 65536,\n reasoning: true,\n vision: true,\n toolCalling: true,\n },\n {\n id: \"google/gemini-2.5-flash\",\n name: \"Gemini 2.5 Flash\",\n version: \"2.5\",\n inputPrice: 0.3,\n outputPrice: 2.5,\n contextWindow: 1000000,\n maxOutput: 65536,\n vision: true,\n toolCalling: true,\n },\n {\n id: \"google/gemini-2.5-flash-lite\",\n name: \"Gemini 2.5 Flash Lite\",\n version: \"2.5\",\n inputPrice: 0.1,\n outputPrice: 0.4,\n contextWindow: 1000000,\n maxOutput: 65536,\n toolCalling: true,\n },\n\n // DeepSeek\n {\n id: \"deepseek/deepseek-chat\",\n name: \"DeepSeek V3.2 Chat\",\n version: \"3.2\",\n inputPrice: 0.28,\n outputPrice: 0.42,\n contextWindow: 128000,\n maxOutput: 8192,\n toolCalling: true,\n },\n {\n id: \"deepseek/deepseek-reasoner\",\n name: \"DeepSeek V3.2 Reasoner\",\n version: \"3.2\",\n inputPrice: 0.28,\n outputPrice: 0.42,\n contextWindow: 128000,\n maxOutput: 8192,\n reasoning: true,\n toolCalling: true,\n },\n\n // Moonshot / Kimi - optimized for agentic workflows\n {\n id: \"moonshot/kimi-k2.5\",\n name: \"Kimi K2.5\",\n version: \"k2.5\",\n inputPrice: 0.6,\n outputPrice: 3.0,\n contextWindow: 262144,\n maxOutput: 8192,\n reasoning: true,\n vision: true,\n agentic: true,\n toolCalling: true,\n },\n\n // xAI / Grok\n {\n id: \"xai/grok-3\",\n name: \"Grok 3\",\n version: \"3\",\n inputPrice: 3.0,\n outputPrice: 15.0,\n contextWindow: 131072,\n maxOutput: 16384,\n reasoning: true,\n toolCalling: true,\n },\n // grok-3-fast removed - too expensive ($5/$25), use grok-4-fast instead\n {\n id: \"xai/grok-3-mini\",\n name: \"Grok 3 Mini\",\n version: \"3-mini\",\n inputPrice: 0.3,\n outputPrice: 0.5,\n contextWindow: 131072,\n maxOutput: 16384,\n toolCalling: true,\n },\n\n // xAI Grok 4 Family - Ultra-cheap fast models\n {\n id: \"xai/grok-4-fast-reasoning\",\n name: \"Grok 4 Fast Reasoning\",\n version: \"4\",\n inputPrice: 0.2,\n outputPrice: 0.5,\n contextWindow: 131072,\n maxOutput: 16384,\n reasoning: true,\n toolCalling: true,\n },\n {\n id: \"xai/grok-4-fast-non-reasoning\",\n name: \"Grok 4 Fast\",\n version: \"4\",\n inputPrice: 0.2,\n outputPrice: 0.5,\n contextWindow: 131072,\n maxOutput: 16384,\n toolCalling: true,\n },\n {\n id: \"xai/grok-4-1-fast-reasoning\",\n name: \"Grok 4.1 Fast Reasoning\",\n version: \"4.1\",\n inputPrice: 0.2,\n outputPrice: 0.5,\n contextWindow: 131072,\n maxOutput: 16384,\n reasoning: true,\n toolCalling: true,\n },\n {\n id: \"xai/grok-4-1-fast-non-reasoning\",\n name: \"Grok 4.1 Fast\",\n version: \"4.1\",\n inputPrice: 0.2,\n outputPrice: 0.5,\n contextWindow: 131072,\n maxOutput: 16384,\n toolCalling: true,\n },\n {\n id: \"xai/grok-code-fast-1\",\n name: \"Grok Code Fast\",\n version: \"1\",\n inputPrice: 0.2,\n outputPrice: 1.5,\n contextWindow: 131072,\n maxOutput: 16384,\n // toolCalling intentionally omitted: outputs tool calls as plain text JSON,\n // not OpenAI-compatible structured function calls. Will be skipped when\n // request has tools to prevent the \"talking to itself\" bug.\n },\n {\n id: \"xai/grok-4-0709\",\n name: \"Grok 4 (0709)\",\n version: \"4-0709\",\n inputPrice: 0.2,\n outputPrice: 1.5,\n contextWindow: 131072,\n maxOutput: 16384,\n reasoning: true,\n toolCalling: true,\n },\n {\n id: \"xai/grok-2-vision\",\n name: \"Grok 2 Vision\",\n version: \"2\",\n inputPrice: 2.0,\n outputPrice: 10.0,\n contextWindow: 131072,\n maxOutput: 16384,\n vision: true,\n toolCalling: true,\n },\n\n // MiniMax\n {\n id: \"minimax/minimax-m2.5\",\n name: \"MiniMax M2.5\",\n version: \"m2.5\",\n inputPrice: 0.3,\n outputPrice: 1.2,\n contextWindow: 204800,\n maxOutput: 16384,\n reasoning: true,\n agentic: true,\n toolCalling: true,\n },\n\n // NVIDIA - Free/cheap models\n {\n id: \"nvidia/gpt-oss-120b\",\n name: \"NVIDIA GPT-OSS 120B\",\n version: \"120b\",\n inputPrice: 0,\n outputPrice: 0,\n contextWindow: 128000,\n maxOutput: 16384,\n // toolCalling intentionally omitted: free model, structured function\n // calling support unverified. Excluded from tool-heavy routing paths.\n },\n {\n id: \"nvidia/kimi-k2.5\",\n name: \"NVIDIA Kimi K2.5\",\n version: \"k2.5\",\n inputPrice: 0.55,\n outputPrice: 2.5,\n contextWindow: 262144,\n maxOutput: 16384,\n toolCalling: true,\n },\n];\n\n/**\n * Convert BlockRun model definitions to OpenClaw ModelDefinitionConfig format.\n */\nfunction toOpenClawModel(m: BlockRunModel): ModelDefinitionConfig {\n return {\n id: m.id,\n name: m.name,\n api: \"openai-completions\",\n reasoning: m.reasoning ?? false,\n input: m.vision ? [\"text\", \"image\"] : [\"text\"],\n cost: {\n input: m.inputPrice,\n output: m.outputPrice,\n cacheRead: 0,\n cacheWrite: 0,\n },\n contextWindow: m.contextWindow,\n maxTokens: m.maxOutput,\n };\n}\n\n/**\n * Alias models that map to real models.\n * These allow users to use friendly names like \"free\" or \"gpt-120b\".\n */\nconst ALIAS_MODELS: ModelDefinitionConfig[] = Object.entries(MODEL_ALIASES)\n .map(([alias, targetId]) => {\n const target = BLOCKRUN_MODELS.find((m) => m.id === targetId);\n if (!target) return null;\n return toOpenClawModel({ ...target, id: alias, name: `${alias} → ${target.name}` });\n })\n .filter((m): m is ModelDefinitionConfig => m !== null);\n\n/**\n * All BlockRun models in OpenClaw format (including aliases).\n */\nexport const OPENCLAW_MODELS: ModelDefinitionConfig[] = [\n ...BLOCKRUN_MODELS.map(toOpenClawModel),\n ...ALIAS_MODELS,\n];\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/**\n * Check if a model is optimized for agentic workflows.\n * Agentic models continue autonomously with multi-step tasks\n * instead of stopping and waiting for user input.\n */\nexport function isAgenticModel(modelId: string): boolean {\n const model = BLOCKRUN_MODELS.find(\n (m) => m.id === modelId || m.id === modelId.replace(\"blockrun/\", \"\"),\n );\n return model?.agentic ?? false;\n}\n\n/**\n * Get all agentic-capable models.\n */\nexport function getAgenticModels(): string[] {\n return BLOCKRUN_MODELS.filter((m) => m.agentic).map((m) => m.id);\n}\n\n/**\n * Check if a model supports OpenAI-compatible structured tool/function calling.\n * Models without this flag (e.g. grok-code-fast-1) output tool invocations as\n * plain text JSON, which leaks {\"command\":\"...\"} into visible chat messages.\n */\nexport function supportsToolCalling(modelId: string): boolean {\n const normalized = modelId.replace(\"blockrun/\", \"\");\n const model = BLOCKRUN_MODELS.find((m) => m.id === normalized);\n return model?.toolCalling ?? false;\n}\n\n/**\n * Check if a model supports vision (image inputs).\n * Models without this flag cannot process image_url content parts.\n */\nexport function supportsVision(modelId: string): boolean {\n const normalized = modelId.replace(\"blockrun/\", \"\");\n const model = BLOCKRUN_MODELS.find((m) => m.id === normalized);\n return model?.vision ?? false;\n}\n\n/**\n * Get context window size for a model.\n * Returns undefined if model not found.\n */\nexport function getModelContextWindow(modelId: string): number | undefined {\n const normalized = modelId.replace(\"blockrun/\", \"\");\n const model = BLOCKRUN_MODELS.find((m) => m.id === normalized);\n return model?.contextWindow;\n}\n\n/**\n * Check if a model has reasoning/thinking capabilities.\n * Reasoning models may require reasoning_content in assistant tool_call messages.\n */\nexport function isReasoningModel(modelId: string): boolean {\n const normalized = modelId.replace(\"blockrun/\", \"\");\n const model = BLOCKRUN_MODELS.find((m) => m.id === normalized);\n return model?.reasoning ?? false;\n}\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 tier: string;\n cost: number;\n baselineCost: number;\n savings: number; // 0-1 percentage\n latencyMs: number;\n /** Partner service ID (e.g., \"x_users_lookup\") — only set for partner API calls */\n partnerId?: string;\n /** Partner service name (e.g., \"AttentionVC\") — only set for partner API calls */\n service?: string;\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 * Usage Statistics Aggregator\n *\n * Reads usage log files and aggregates statistics for terminal display.\n * Supports filtering by date range and provides multiple aggregation views.\n */\n\nimport { readdir } from \"node:fs/promises\";\nimport { readTextFile } from \"./fs-read.js\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport type { UsageEntry } from \"./logger.js\";\nimport { VERSION } from \"./version.js\";\n\nconst LOG_DIR = join(homedir(), \".openclaw\", \"blockrun\", \"logs\");\n\nexport type DailyStats = {\n date: string;\n totalRequests: number;\n totalCost: number;\n totalBaselineCost: number;\n totalSavings: number;\n avgLatencyMs: number;\n byTier: Record<string, { count: number; cost: number }>;\n byModel: Record<string, { count: number; cost: number }>;\n};\n\nexport type AggregatedStats = {\n period: string;\n totalRequests: number;\n totalCost: number;\n totalBaselineCost: number;\n totalSavings: number;\n savingsPercentage: number;\n avgLatencyMs: number;\n avgCostPerRequest: number;\n byTier: Record<string, { count: number; cost: number; percentage: number }>;\n byModel: Record<string, { count: number; cost: number; percentage: number }>;\n dailyBreakdown: DailyStats[];\n entriesWithBaseline: number; // Entries with valid baseline tracking\n};\n\n/**\n * Parse a JSONL log file into usage entries.\n * Handles both old format (without tier/baselineCost) and new format.\n */\nasync function parseLogFile(filePath: string): Promise<UsageEntry[]> {\n try {\n const content = await readTextFile(filePath);\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n return lines.map((line) => {\n const entry = JSON.parse(line) as Partial<UsageEntry>;\n // Handle old format entries\n return {\n timestamp: entry.timestamp || new Date().toISOString(),\n model: entry.model || \"unknown\",\n tier: entry.tier || \"UNKNOWN\",\n cost: entry.cost || 0,\n baselineCost: entry.baselineCost || entry.cost || 0,\n savings: entry.savings || 0,\n latencyMs: entry.latencyMs || 0,\n };\n });\n } catch {\n return [];\n }\n}\n\n/**\n * Get list of available log files sorted by date (newest first).\n */\nasync function getLogFiles(): Promise<string[]> {\n try {\n const files = await readdir(LOG_DIR);\n return files\n .filter((f) => f.startsWith(\"usage-\") && f.endsWith(\".jsonl\"))\n .sort()\n .reverse();\n } catch {\n return [];\n }\n}\n\n/**\n * Aggregate stats for a single day.\n */\nfunction aggregateDay(date: string, entries: UsageEntry[]): DailyStats {\n const byTier: Record<string, { count: number; cost: number }> = {};\n const byModel: Record<string, { count: number; cost: number }> = {};\n let totalLatency = 0;\n\n for (const entry of entries) {\n // By tier\n if (!byTier[entry.tier]) byTier[entry.tier] = { count: 0, cost: 0 };\n byTier[entry.tier].count++;\n byTier[entry.tier].cost += entry.cost;\n\n // By model\n if (!byModel[entry.model]) byModel[entry.model] = { count: 0, cost: 0 };\n byModel[entry.model].count++;\n byModel[entry.model].cost += entry.cost;\n\n totalLatency += entry.latencyMs;\n }\n\n const totalCost = entries.reduce((sum, e) => sum + e.cost, 0);\n const totalBaselineCost = entries.reduce((sum, e) => sum + e.baselineCost, 0);\n\n return {\n date,\n totalRequests: entries.length,\n totalCost,\n totalBaselineCost,\n totalSavings: totalBaselineCost - totalCost,\n avgLatencyMs: entries.length > 0 ? totalLatency / entries.length : 0,\n byTier,\n byModel,\n };\n}\n\n/**\n * Get aggregated statistics for the last N days.\n */\nexport async function getStats(days: number = 7): Promise<AggregatedStats> {\n const logFiles = await getLogFiles();\n const filesToRead = logFiles.slice(0, days);\n\n const dailyBreakdown: DailyStats[] = [];\n const allByTier: Record<string, { count: number; cost: number }> = {};\n const allByModel: Record<string, { count: number; cost: number }> = {};\n let totalRequests = 0;\n let totalCost = 0;\n let totalBaselineCost = 0;\n let totalLatency = 0;\n\n for (const file of filesToRead) {\n const date = file.replace(\"usage-\", \"\").replace(\".jsonl\", \"\");\n const filePath = join(LOG_DIR, file);\n const entries = await parseLogFile(filePath);\n\n if (entries.length === 0) continue;\n\n const dayStats = aggregateDay(date, entries);\n dailyBreakdown.push(dayStats);\n\n totalRequests += dayStats.totalRequests;\n totalCost += dayStats.totalCost;\n totalBaselineCost += dayStats.totalBaselineCost;\n totalLatency += dayStats.avgLatencyMs * dayStats.totalRequests;\n\n // Merge tier stats\n for (const [tier, stats] of Object.entries(dayStats.byTier)) {\n if (!allByTier[tier]) allByTier[tier] = { count: 0, cost: 0 };\n allByTier[tier].count += stats.count;\n allByTier[tier].cost += stats.cost;\n }\n\n // Merge model stats\n for (const [model, stats] of Object.entries(dayStats.byModel)) {\n if (!allByModel[model]) allByModel[model] = { count: 0, cost: 0 };\n allByModel[model].count += stats.count;\n allByModel[model].cost += stats.cost;\n }\n }\n\n // Calculate percentages\n const byTierWithPercentage: Record<string, { count: number; cost: number; percentage: number }> =\n {};\n for (const [tier, stats] of Object.entries(allByTier)) {\n byTierWithPercentage[tier] = {\n ...stats,\n percentage: totalRequests > 0 ? (stats.count / totalRequests) * 100 : 0,\n };\n }\n\n const byModelWithPercentage: Record<string, { count: number; cost: number; percentage: number }> =\n {};\n for (const [model, stats] of Object.entries(allByModel)) {\n byModelWithPercentage[model] = {\n ...stats,\n percentage: totalRequests > 0 ? (stats.count / totalRequests) * 100 : 0,\n };\n }\n\n const totalSavings = totalBaselineCost - totalCost;\n const savingsPercentage = totalBaselineCost > 0 ? (totalSavings / totalBaselineCost) * 100 : 0;\n\n // Count entries with valid baseline tracking (baseline != cost means tracking was active)\n let entriesWithBaseline = 0;\n for (const day of dailyBreakdown) {\n if (day.totalBaselineCost !== day.totalCost) {\n entriesWithBaseline += day.totalRequests;\n }\n }\n\n return {\n period: days === 1 ? \"today\" : `last ${days} days`,\n totalRequests,\n totalCost,\n totalBaselineCost,\n totalSavings,\n savingsPercentage,\n avgLatencyMs: totalRequests > 0 ? totalLatency / totalRequests : 0,\n avgCostPerRequest: totalRequests > 0 ? totalCost / totalRequests : 0,\n byTier: byTierWithPercentage,\n byModel: byModelWithPercentage,\n dailyBreakdown: dailyBreakdown.reverse(), // Oldest first for charts\n entriesWithBaseline, // How many entries have valid baseline tracking\n };\n}\n\n/**\n * Format stats as ASCII table for terminal display.\n */\nexport function formatStatsAscii(stats: AggregatedStats): string {\n const lines: string[] = [];\n\n // Header\n lines.push(\"╔════════════════════════════════════════════════════════════╗\");\n lines.push(`║ ClawRouter by BlockRun v${VERSION}`.padEnd(61) + \"║\");\n lines.push(\"║ Usage Statistics ║\");\n lines.push(\"╠════════════════════════════════════════════════════════════╣\");\n\n // Summary\n lines.push(`║ Period: ${stats.period.padEnd(49)}║`);\n lines.push(`║ Total Requests: ${stats.totalRequests.toString().padEnd(41)}║`);\n lines.push(`║ Total Cost: $${stats.totalCost.toFixed(4).padEnd(43)}║`);\n lines.push(`║ Baseline Cost (Opus 4.5): $${stats.totalBaselineCost.toFixed(4).padEnd(30)}║`);\n\n // Show savings with note if some entries lack baseline tracking\n const savingsLine = `║ 💰 Total Saved: $${stats.totalSavings.toFixed(4)} (${stats.savingsPercentage.toFixed(1)}%)`;\n if (stats.entriesWithBaseline < stats.totalRequests && stats.entriesWithBaseline > 0) {\n lines.push(savingsLine.padEnd(61) + \"║\");\n const note = `║ (based on ${stats.entriesWithBaseline}/${stats.totalRequests} tracked requests)`;\n lines.push(note.padEnd(61) + \"║\");\n } else {\n lines.push(savingsLine.padEnd(61) + \"║\");\n }\n lines.push(`║ Avg Latency: ${stats.avgLatencyMs.toFixed(0)}ms`.padEnd(61) + \"║\");\n\n // Tier breakdown\n lines.push(\"╠════════════════════════════════════════════════════════════╣\");\n lines.push(\"║ Routing by Tier: ║\");\n\n // Show all tiers found in data, ordered by known tiers first then others\n const knownTiers = [\"SIMPLE\", \"MEDIUM\", \"COMPLEX\", \"REASONING\", \"DIRECT\"];\n const allTiers = Object.keys(stats.byTier);\n const otherTiers = allTiers.filter((t) => !knownTiers.includes(t));\n const tierOrder = [...knownTiers.filter((t) => stats.byTier[t]), ...otherTiers];\n\n for (const tier of tierOrder) {\n const data = stats.byTier[tier];\n if (data) {\n const bar = \"█\".repeat(Math.min(20, Math.round(data.percentage / 5)));\n const displayTier = tier === \"UNKNOWN\" ? \"OTHER\" : tier;\n const line = `║ ${displayTier.padEnd(10)} ${bar.padEnd(20)} ${data.percentage.toFixed(1).padStart(5)}% (${data.count})`;\n lines.push(line.padEnd(61) + \"║\");\n }\n }\n\n // Top models\n lines.push(\"╠════════════════════════════════════════════════════════════╣\");\n lines.push(\"║ Top Models: ║\");\n\n const sortedModels = Object.entries(stats.byModel)\n .sort((a, b) => b[1].count - a[1].count)\n .slice(0, 5);\n\n for (const [model, data] of sortedModels) {\n const shortModel = model.length > 25 ? model.slice(0, 22) + \"...\" : model;\n const line = `║ ${shortModel.padEnd(25)} ${data.count.toString().padStart(5)} reqs $${data.cost.toFixed(4)}`;\n lines.push(line.padEnd(61) + \"║\");\n }\n\n // Daily breakdown (last 7 days)\n if (stats.dailyBreakdown.length > 0) {\n lines.push(\"╠════════════════════════════════════════════════════════════╣\");\n lines.push(\"║ Daily Breakdown: ║\");\n lines.push(\"║ Date Requests Cost Saved ║\");\n\n for (const day of stats.dailyBreakdown.slice(-7)) {\n const saved = day.totalBaselineCost - day.totalCost;\n const line = `║ ${day.date} ${day.totalRequests.toString().padStart(6)} $${day.totalCost.toFixed(4).padStart(8)} $${saved.toFixed(4)}`;\n lines.push(line.padEnd(61) + \"║\");\n }\n }\n\n lines.push(\"╚════════════════════════════════════════════════════════════╝\");\n\n return lines.join(\"\\n\");\n}\n","/**\n * Scanner-safe file reading utilities.\n *\n * Uses open() + read() to avoid false positives from openclaw's\n * potential-exfiltration heuristic in bundled output.\n */\n\nimport { open } from \"node:fs/promises\";\nimport { openSync, readSync, closeSync, fstatSync } from \"node:fs\";\n\n/** Read file contents as UTF-8 string (async). */\nexport async function readTextFile(filePath: string): Promise<string> {\n const fh = await open(filePath, \"r\");\n try {\n const buf = Buffer.alloc((await fh.stat()).size);\n await fh.read(buf, 0, buf.length, 0);\n return buf.toString(\"utf-8\");\n } finally {\n await fh.close();\n }\n}\n\n/** Read file contents as UTF-8 string (sync). */\nexport function readTextFileSync(filePath: string): string {\n const fd = openSync(filePath, \"r\");\n try {\n const buf = Buffer.alloc(fstatSync(fd).size);\n readSync(fd, buf);\n return buf.toString(\"utf-8\");\n } finally {\n closeSync(fd);\n }\n}\n","/**\n * Single source of truth for version.\n * Reads from package.json at build time via tsup's define.\n */\nimport { createRequire } from \"node:module\";\nimport { fileURLToPath } from \"node:url\";\nimport { dirname, join } from \"node:path\";\n\n// Read package.json at runtime\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n// In dist/, go up one level to find package.json\nconst require = createRequire(import.meta.url);\nconst pkg = require(join(__dirname, \"..\", \"package.json\")) as { version: string };\n\nexport const VERSION = pkg.version;\nexport const USER_AGENT = `clawrouter/${VERSION}`;\n","/**\n * Request Deduplication\n *\n * Prevents double-charging when OpenClaw retries a request after timeout.\n * Tracks in-flight requests and caches completed responses for a short TTL.\n */\n\nimport { createHash } from \"node:crypto\";\n\nexport type CachedResponse = {\n status: number;\n headers: Record<string, string>;\n body: Buffer;\n completedAt: number;\n};\n\ntype InflightEntry = {\n resolvers: Array<(result: CachedResponse) => void>;\n};\n\nconst DEFAULT_TTL_MS = 30_000; // 30 seconds\nconst MAX_BODY_SIZE = 1_048_576; // 1MB\n\n/**\n * Canonicalize JSON by sorting object keys recursively.\n * Ensures identical logical content produces identical string regardless of field order.\n */\nfunction canonicalize(obj: unknown): unknown {\n if (obj === null || typeof obj !== \"object\") {\n return obj;\n }\n if (Array.isArray(obj)) {\n return obj.map(canonicalize);\n }\n const sorted: Record<string, unknown> = {};\n for (const key of Object.keys(obj).sort()) {\n sorted[key] = canonicalize((obj as Record<string, unknown>)[key]);\n }\n return sorted;\n}\n\n/**\n * Strip OpenClaw-injected timestamps from message content.\n * Format: [DAY YYYY-MM-DD HH:MM TZ] at the start of messages.\n * Example: [SUN 2026-02-07 13:30 PST] Hello world\n *\n * This ensures requests with different timestamps but same content hash identically.\n */\nconst TIMESTAMP_PATTERN = /^\\[\\w{3}\\s+\\d{4}-\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}\\s+\\w+\\]\\s*/;\n\nfunction stripTimestamps(obj: unknown): unknown {\n if (obj === null || typeof obj !== \"object\") {\n return obj;\n }\n if (Array.isArray(obj)) {\n return obj.map(stripTimestamps);\n }\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n if (key === \"content\" && typeof value === \"string\") {\n // Strip timestamp prefix from message content\n result[key] = value.replace(TIMESTAMP_PATTERN, \"\");\n } else {\n result[key] = stripTimestamps(value);\n }\n }\n return result;\n}\n\nexport class RequestDeduplicator {\n private inflight = new Map<string, InflightEntry>();\n private completed = new Map<string, CachedResponse>();\n private ttlMs: number;\n\n constructor(ttlMs = DEFAULT_TTL_MS) {\n this.ttlMs = ttlMs;\n }\n\n /** Hash request body to create a dedup key. */\n static hash(body: Buffer): string {\n // Canonicalize JSON to ensure consistent hashing regardless of field order.\n // Also strip OpenClaw-injected timestamps so retries with different timestamps\n // still match the same dedup key.\n let content = body;\n try {\n const parsed = JSON.parse(body.toString());\n const stripped = stripTimestamps(parsed);\n const canonical = canonicalize(stripped);\n content = Buffer.from(JSON.stringify(canonical));\n } catch {\n // Not valid JSON, use raw bytes\n }\n return createHash(\"sha256\").update(content).digest(\"hex\").slice(0, 16);\n }\n\n /** Check if a response is cached for this key. */\n getCached(key: string): CachedResponse | undefined {\n const entry = this.completed.get(key);\n if (!entry) return undefined;\n if (Date.now() - entry.completedAt > this.ttlMs) {\n this.completed.delete(key);\n return undefined;\n }\n return entry;\n }\n\n /** Check if a request with this key is currently in-flight. Returns a promise to wait on. */\n getInflight(key: string): Promise<CachedResponse> | undefined {\n const entry = this.inflight.get(key);\n if (!entry) return undefined;\n return new Promise<CachedResponse>((resolve) => {\n entry.resolvers.push(resolve);\n });\n }\n\n /** Mark a request as in-flight. */\n markInflight(key: string): void {\n this.inflight.set(key, {\n resolvers: [],\n });\n }\n\n /** Complete an in-flight request — cache result and notify waiters. */\n complete(key: string, result: CachedResponse): void {\n // Only cache responses within size limit\n if (result.body.length <= MAX_BODY_SIZE) {\n this.completed.set(key, result);\n }\n\n const entry = this.inflight.get(key);\n if (entry) {\n for (const resolve of entry.resolvers) {\n resolve(result);\n }\n this.inflight.delete(key);\n }\n\n this.prune();\n }\n\n /** Remove an in-flight entry on error (don't cache failures).\n * Also rejects any waiters so they can retry independently. */\n removeInflight(key: string): void {\n const entry = this.inflight.get(key);\n if (entry) {\n // Resolve waiters with a sentinel error response so they don't hang forever.\n // Waiters will see a 503 and can retry on their own.\n const errorBody = Buffer.from(\n JSON.stringify({\n error: { message: \"Original request failed, please retry\", type: \"dedup_origin_failed\" },\n }),\n );\n for (const resolve of entry.resolvers) {\n resolve({\n status: 503,\n headers: { \"content-type\": \"application/json\" },\n body: errorBody,\n completedAt: Date.now(),\n });\n }\n this.inflight.delete(key);\n }\n }\n\n /** Prune expired completed entries. */\n private prune(): void {\n const now = Date.now();\n for (const [key, entry] of this.completed) {\n if (now - entry.completedAt > this.ttlMs) {\n this.completed.delete(key);\n }\n }\n }\n}\n","/**\n * Response Cache for LLM Completions\n *\n * Caches LLM responses by request hash (model + messages + params).\n * Inspired by LiteLLM's caching system. Returns cached responses for\n * identical requests, saving both cost and latency.\n *\n * Features:\n * - TTL-based expiration (default 10 minutes)\n * - LRU eviction when cache is full\n * - Size limits per item (1MB max)\n * - Heap-based expiration tracking for efficient pruning\n */\n\nimport { createHash } from \"node:crypto\";\n\nexport type CachedLLMResponse = {\n body: Buffer;\n status: number;\n headers: Record<string, string>;\n model: string;\n cachedAt: number;\n expiresAt: number;\n};\n\nexport type ResponseCacheConfig = {\n /** Maximum number of cached responses. Default: 200 */\n maxSize?: number;\n /** Default TTL in seconds. Default: 600 (10 minutes) */\n defaultTTL?: number;\n /** Maximum size per cached item in bytes. Default: 1MB */\n maxItemSize?: number;\n /** Enable/disable cache. Default: true */\n enabled?: boolean;\n};\n\nconst DEFAULT_CONFIG: Required<ResponseCacheConfig> = {\n maxSize: 200,\n defaultTTL: 600,\n maxItemSize: 1_048_576, // 1MB\n enabled: true,\n};\n\n/**\n * Canonicalize JSON by sorting object keys recursively.\n * Ensures identical logical content produces identical hash.\n */\nfunction canonicalize(obj: unknown): unknown {\n if (obj === null || typeof obj !== \"object\") {\n return obj;\n }\n if (Array.isArray(obj)) {\n return obj.map(canonicalize);\n }\n const sorted: Record<string, unknown> = {};\n for (const key of Object.keys(obj).sort()) {\n sorted[key] = canonicalize((obj as Record<string, unknown>)[key]);\n }\n return sorted;\n}\n\n/**\n * Strip fields that shouldn't affect cache key:\n * - stream (we handle streaming separately)\n * - timestamps injected by OpenClaw\n * - request IDs\n */\nconst TIMESTAMP_PATTERN = /^\\[\\w{3}\\s+\\d{4}-\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}\\s+\\w+\\]\\s*/;\n\nfunction normalizeForCache(obj: Record<string, unknown>): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n // Skip fields that don't affect response content\n if ([\"stream\", \"user\", \"request_id\", \"x-request-id\"].includes(key)) {\n continue;\n }\n\n if (key === \"messages\" && Array.isArray(value)) {\n // Strip timestamps from message content\n result[key] = value.map((msg: unknown) => {\n if (typeof msg === \"object\" && msg !== null) {\n const m = msg as Record<string, unknown>;\n if (typeof m.content === \"string\") {\n return { ...m, content: m.content.replace(TIMESTAMP_PATTERN, \"\") };\n }\n }\n return msg;\n });\n } else {\n result[key] = value;\n }\n }\n\n return result;\n}\n\nexport class ResponseCache {\n private cache = new Map<string, CachedLLMResponse>();\n private expirationHeap: Array<{ expiresAt: number; key: string }> = [];\n private config: Required<ResponseCacheConfig>;\n\n // Stats for monitoring\n private stats = {\n hits: 0,\n misses: 0,\n evictions: 0,\n };\n\n constructor(config: ResponseCacheConfig = {}) {\n // Filter out undefined values so they don't override defaults\n const filtered = Object.fromEntries(\n Object.entries(config).filter(([, v]) => v !== undefined),\n ) as ResponseCacheConfig;\n this.config = { ...DEFAULT_CONFIG, ...filtered };\n }\n\n /**\n * Generate cache key from request body.\n * Hashes: model + messages + temperature + max_tokens + other params\n */\n static generateKey(body: Buffer | string): string {\n try {\n const parsed = JSON.parse(typeof body === \"string\" ? body : body.toString());\n const normalized = normalizeForCache(parsed);\n const canonical = canonicalize(normalized);\n const keyContent = JSON.stringify(canonical);\n return createHash(\"sha256\").update(keyContent).digest(\"hex\").slice(0, 32);\n } catch {\n // Fallback: hash raw body\n const content = typeof body === \"string\" ? body : body.toString();\n return createHash(\"sha256\").update(content).digest(\"hex\").slice(0, 32);\n }\n }\n\n /**\n * Check if caching is enabled for this request.\n * Respects cache control headers and request params.\n */\n shouldCache(body: Buffer | string, headers?: Record<string, string>): boolean {\n if (!this.config.enabled) return false;\n\n // Respect Cache-Control: no-cache header\n if (headers?.[\"cache-control\"]?.includes(\"no-cache\")) {\n return false;\n }\n\n // Check for explicit cache disable in body\n try {\n const parsed = JSON.parse(typeof body === \"string\" ? body : body.toString());\n if (parsed.cache === false || parsed.no_cache === true) {\n return false;\n }\n } catch {\n // Not JSON, allow caching\n }\n\n return true;\n }\n\n /**\n * Get cached response if available and not expired.\n */\n get(key: string): CachedLLMResponse | undefined {\n const entry = this.cache.get(key);\n if (!entry) {\n this.stats.misses++;\n return undefined;\n }\n\n // Check expiration\n if (Date.now() > entry.expiresAt) {\n this.cache.delete(key);\n this.stats.misses++;\n return undefined;\n }\n\n this.stats.hits++;\n return entry;\n }\n\n /**\n * Cache a response with optional custom TTL.\n */\n set(\n key: string,\n response: {\n body: Buffer;\n status: number;\n headers: Record<string, string>;\n model: string;\n },\n ttlSeconds?: number,\n ): void {\n // Don't cache if disabled or maxSize is 0\n if (!this.config.enabled || this.config.maxSize <= 0) return;\n\n // Don't cache if item too large\n if (response.body.length > this.config.maxItemSize) {\n console.log(`[ResponseCache] Skipping cache - item too large: ${response.body.length} bytes`);\n return;\n }\n\n // Don't cache error responses\n if (response.status >= 400) {\n return;\n }\n\n // Evict if at capacity\n if (this.cache.size >= this.config.maxSize) {\n this.evict();\n }\n\n const now = Date.now();\n const ttl = ttlSeconds ?? this.config.defaultTTL;\n const expiresAt = now + ttl * 1000;\n\n const entry: CachedLLMResponse = {\n ...response,\n cachedAt: now,\n expiresAt,\n };\n\n this.cache.set(key, entry);\n this.expirationHeap.push({ expiresAt, key });\n }\n\n /**\n * Evict expired and oldest entries to make room.\n */\n private evict(): void {\n const now = Date.now();\n\n // First pass: remove expired entries\n this.expirationHeap.sort((a, b) => a.expiresAt - b.expiresAt);\n\n while (this.expirationHeap.length > 0) {\n const oldest = this.expirationHeap[0];\n\n // Check if entry still exists and matches\n const entry = this.cache.get(oldest.key);\n if (!entry || entry.expiresAt !== oldest.expiresAt) {\n // Stale heap entry, remove it\n this.expirationHeap.shift();\n continue;\n }\n\n if (oldest.expiresAt <= now) {\n // Expired, remove both\n this.cache.delete(oldest.key);\n this.expirationHeap.shift();\n this.stats.evictions++;\n } else {\n // Not expired, stop\n break;\n }\n }\n\n // Second pass: if still at capacity, evict oldest\n while (this.cache.size >= this.config.maxSize && this.expirationHeap.length > 0) {\n const oldest = this.expirationHeap.shift()!;\n if (this.cache.has(oldest.key)) {\n this.cache.delete(oldest.key);\n this.stats.evictions++;\n }\n }\n }\n\n /**\n * Get cache statistics.\n */\n getStats(): {\n size: number;\n maxSize: number;\n hits: number;\n misses: number;\n evictions: number;\n hitRate: string;\n } {\n const total = this.stats.hits + this.stats.misses;\n const hitRate = total > 0 ? ((this.stats.hits / total) * 100).toFixed(1) + \"%\" : \"0%\";\n\n return {\n size: this.cache.size,\n maxSize: this.config.maxSize,\n hits: this.stats.hits,\n misses: this.stats.misses,\n evictions: this.stats.evictions,\n hitRate,\n };\n }\n\n /**\n * Clear all cached entries.\n */\n clear(): void {\n this.cache.clear();\n this.expirationHeap = [];\n }\n\n /**\n * Check if cache is enabled.\n */\n isEnabled(): boolean {\n return this.config.enabled;\n }\n}\n","/**\n * Balance Monitor for ClawRouter\n *\n * Monitors USDC balance on Base network with intelligent caching.\n * Provides pre-request balance checks to prevent failed payments.\n *\n * Caching Strategy:\n * - TTL: 30 seconds (balance is cached to avoid excessive RPC calls)\n * - Optimistic deduction: after successful payment, subtract estimated cost from cache\n * - Invalidation: on payment failure, immediately refresh from RPC\n */\n\nimport { createPublicClient, http, erc20Abi } from \"viem\";\nimport { base } from \"viem/chains\";\nimport { RpcError } from \"./errors.js\";\n\n/** USDC contract address on Base mainnet */\nconst USDC_BASE = \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\" as const;\n\n/** Cache TTL in milliseconds (30 seconds) */\nconst CACHE_TTL_MS = 30_000;\n\n/** Balance thresholds in USDC smallest unit (6 decimals) */\nexport const BALANCE_THRESHOLDS = {\n /** Low balance warning threshold: $1.00 */\n LOW_BALANCE_MICROS: 1_000_000n,\n /** Effectively zero threshold: $0.0001 (covers dust/rounding) */\n ZERO_THRESHOLD: 100n,\n} as const;\n\n/** Balance information returned by checkBalance() */\nexport type BalanceInfo = {\n /** Raw balance in USDC smallest unit (6 decimals) */\n balance: bigint;\n /** Formatted balance as \"$X.XX\" */\n balanceUSD: string;\n /** True if balance < $1.00 */\n isLow: boolean;\n /** True if balance < $0.0001 (effectively zero) */\n isEmpty: boolean;\n /** Wallet address for funding instructions */\n walletAddress: string;\n};\n\n/** Result from checkSufficient() */\nexport type SufficiencyResult = {\n /** True if balance >= estimated cost */\n sufficient: boolean;\n /** Current balance info */\n info: BalanceInfo;\n /** If insufficient, the shortfall as \"$X.XX\" */\n shortfall?: string;\n};\n\n/**\n * Monitors USDC balance on Base network.\n *\n * Usage:\n * const monitor = new BalanceMonitor(\"0x...\");\n * const info = await monitor.checkBalance();\n * if (info.isLow) console.warn(\"Low balance!\");\n */\nexport class BalanceMonitor {\n private readonly client;\n private readonly walletAddress: `0x${string}`;\n\n /** Cached balance (null = not yet fetched) */\n private cachedBalance: bigint | null = null;\n /** Timestamp when cache was last updated */\n private cachedAt = 0;\n\n constructor(walletAddress: string) {\n this.walletAddress = walletAddress as `0x${string}`;\n this.client = createPublicClient({\n chain: base,\n transport: http(undefined, {\n timeout: 10_000, // 10 second timeout to prevent hanging on slow RPC\n }),\n });\n }\n\n /**\n * Check current USDC balance.\n * Uses cache if valid, otherwise fetches from RPC.\n */\n async checkBalance(): Promise<BalanceInfo> {\n const now = Date.now();\n\n // Use cache if valid\n if (this.cachedBalance !== null && now - this.cachedAt < CACHE_TTL_MS) {\n return this.buildInfo(this.cachedBalance);\n }\n\n // Fetch from RPC\n const balance = await this.fetchBalance();\n this.cachedBalance = balance;\n this.cachedAt = now;\n\n return this.buildInfo(balance);\n }\n\n /**\n * Check if balance is sufficient for an estimated cost.\n *\n * @param estimatedCostMicros - Estimated cost in USDC smallest unit (6 decimals)\n */\n async checkSufficient(estimatedCostMicros: bigint): Promise<SufficiencyResult> {\n const info = await this.checkBalance();\n\n if (info.balance >= estimatedCostMicros) {\n return { sufficient: true, info };\n }\n\n const shortfall = estimatedCostMicros - info.balance;\n return {\n sufficient: false,\n info,\n shortfall: this.formatUSDC(shortfall),\n };\n }\n\n /**\n * Optimistically deduct estimated cost from cached balance.\n * Call this after a successful payment to keep cache accurate.\n *\n * @param amountMicros - Amount to deduct in USDC smallest unit\n */\n deductEstimated(amountMicros: bigint): void {\n if (this.cachedBalance !== null && this.cachedBalance >= amountMicros) {\n this.cachedBalance -= amountMicros;\n }\n }\n\n /**\n * Invalidate cache, forcing next checkBalance() to fetch from RPC.\n * Call this after a payment failure to get accurate balance.\n */\n invalidate(): void {\n this.cachedBalance = null;\n this.cachedAt = 0;\n }\n\n /**\n * Force refresh balance from RPC (ignores cache).\n */\n async refresh(): Promise<BalanceInfo> {\n this.invalidate();\n return this.checkBalance();\n }\n\n /**\n * Format USDC amount (in micros) as \"$X.XX\".\n */\n formatUSDC(amountMicros: bigint): string {\n // USDC has 6 decimals\n const dollars = Number(amountMicros) / 1_000_000;\n return `$${dollars.toFixed(2)}`;\n }\n\n /**\n * Get the wallet address being monitored.\n */\n getWalletAddress(): string {\n return this.walletAddress;\n }\n\n /** Fetch balance from RPC */\n private async fetchBalance(): Promise<bigint> {\n try {\n const balance = await this.client.readContract({\n address: USDC_BASE,\n abi: erc20Abi,\n functionName: \"balanceOf\",\n args: [this.walletAddress],\n });\n return balance;\n } catch (error) {\n // Throw typed error instead of silently returning 0\n // This allows callers to distinguish \"node down\" from \"wallet empty\"\n throw new RpcError(error instanceof Error ? error.message : \"Unknown error\", error);\n }\n }\n\n /** Build BalanceInfo from raw balance */\n private buildInfo(balance: bigint): BalanceInfo {\n return {\n balance,\n balanceUSD: this.formatUSDC(balance),\n isLow: balance < BALANCE_THRESHOLDS.LOW_BALANCE_MICROS,\n isEmpty: balance < BALANCE_THRESHOLDS.ZERO_THRESHOLD,\n walletAddress: this.walletAddress,\n };\n }\n}\n","/**\n * Typed Error Classes for ClawRouter\n *\n * Provides structured errors for balance-related failures with\n * all necessary information for user-friendly error messages.\n */\n\n/**\n * Thrown when wallet has insufficient USDC balance for a request.\n */\nexport class InsufficientFundsError extends Error {\n readonly code = \"INSUFFICIENT_FUNDS\" as const;\n readonly currentBalanceUSD: string;\n readonly requiredUSD: string;\n readonly walletAddress: string;\n\n constructor(opts: { currentBalanceUSD: string; requiredUSD: string; walletAddress: string }) {\n const msg = [\n `Insufficient balance. Current: ${opts.currentBalanceUSD}, Required: ${opts.requiredUSD}`,\n `Options:`,\n ` 1. Fund wallet: ${opts.walletAddress}`,\n ` 2. Use free model: /model free`,\n ].join(\"\\n\");\n super(msg);\n this.name = \"InsufficientFundsError\";\n this.currentBalanceUSD = opts.currentBalanceUSD;\n this.requiredUSD = opts.requiredUSD;\n this.walletAddress = opts.walletAddress;\n }\n}\n\n/**\n * Thrown when wallet has no USDC balance (or effectively zero).\n */\nexport class EmptyWalletError extends Error {\n readonly code = \"EMPTY_WALLET\" as const;\n readonly walletAddress: string;\n\n constructor(walletAddress: string) {\n const msg = [\n `No USDC balance.`,\n `Options:`,\n ` 1. Fund wallet: ${walletAddress}`,\n ` 2. Use free model: /model free`,\n ` 3. Uninstall: bash ~/.openclaw/extensions/clawrouter/scripts/uninstall.sh`,\n ].join(\"\\n\");\n super(msg);\n this.name = \"EmptyWalletError\";\n this.walletAddress = walletAddress;\n }\n}\n\n/**\n * Type guard to check if an error is InsufficientFundsError.\n */\nexport function isInsufficientFundsError(error: unknown): error is InsufficientFundsError {\n return error instanceof Error && (error as InsufficientFundsError).code === \"INSUFFICIENT_FUNDS\";\n}\n\n/**\n * Type guard to check if an error is EmptyWalletError.\n */\nexport function isEmptyWalletError(error: unknown): error is EmptyWalletError {\n return error instanceof Error && (error as EmptyWalletError).code === \"EMPTY_WALLET\";\n}\n\n/**\n * Type guard to check if an error is a balance-related error.\n */\nexport function isBalanceError(error: unknown): error is InsufficientFundsError | EmptyWalletError {\n return isInsufficientFundsError(error) || isEmptyWalletError(error);\n}\n\n/**\n * Thrown when RPC call fails (network error, node down, etc).\n * Distinguishes infrastructure failures from actual empty wallets.\n */\nexport class RpcError extends Error {\n readonly code = \"RPC_ERROR\" as const;\n readonly originalError: unknown;\n\n constructor(message: string, originalError?: unknown) {\n super(`RPC error: ${message}. Check network connectivity.`);\n this.name = \"RpcError\";\n this.originalError = originalError;\n }\n}\n\n/**\n * Type guard to check if an error is RpcError.\n */\nexport function isRpcError(error: unknown): error is RpcError {\n return error instanceof Error && (error as RpcError).code === \"RPC_ERROR\";\n}\n","/**\n * LLM-Safe Context Compression Types\n *\n * Types for the 7-layer compression system that reduces token usage\n * while preserving semantic meaning for LLM queries.\n */\n\n// Content part for multimodal messages (images, etc.)\nexport interface ContentPart {\n type: \"text\" | \"image_url\";\n text?: string;\n image_url?: {\n url: string;\n detail?: \"low\" | \"high\" | \"auto\";\n };\n}\n\n// Normalized message structure (matches OpenAI format)\n// Note: content can be an array for multimodal messages (images, etc.)\nexport interface NormalizedMessage {\n role: \"system\" | \"user\" | \"assistant\" | \"tool\";\n content: string | ContentPart[] | null;\n tool_call_id?: string;\n tool_calls?: ToolCall[];\n name?: string;\n}\n\nexport interface ToolCall {\n id: string;\n type: \"function\";\n function: {\n name: string;\n arguments: string;\n };\n}\n\n// Compression configuration\nexport interface CompressionConfig {\n enabled: boolean;\n preserveRaw: boolean; // Keep original for logging\n\n // Per-layer toggles\n layers: {\n deduplication: boolean;\n whitespace: boolean;\n dictionary: boolean;\n paths: boolean;\n jsonCompact: boolean;\n observation: boolean; // L6: Compress tool results (BIG WIN)\n dynamicCodebook: boolean; // L7: Build codebook from content\n };\n\n // Dictionary settings\n dictionary: {\n maxEntries: number;\n minPhraseLength: number;\n includeCodebookHeader: boolean; // Include codebook in system message\n };\n}\n\n// Compression statistics\nexport interface CompressionStats {\n duplicatesRemoved: number;\n whitespaceSavedChars: number;\n dictionarySubstitutions: number;\n pathsShortened: number;\n jsonCompactedChars: number;\n observationsCompressed: number; // L6: Tool results compressed\n observationCharsSaved: number; // L6: Chars saved from observations\n dynamicSubstitutions: number; // L7: Dynamic codebook substitutions\n dynamicCharsSaved: number; // L7: Chars saved from dynamic codebook\n}\n\n// Result from compression\nexport interface CompressionResult {\n messages: NormalizedMessage[];\n originalMessages: NormalizedMessage[]; // For logging\n\n // Token estimates\n originalChars: number;\n compressedChars: number;\n compressionRatio: number; // 0.85 = 15% reduction\n\n // Per-layer stats\n stats: CompressionStats;\n\n // Codebook used (for decompression in logs)\n codebook: Record<string, string>;\n pathMap: Record<string, string>;\n dynamicCodes: Record<string, string>; // L7: Dynamic codebook\n}\n\n// Log data extension for compression metrics\nexport interface CompressionLogData {\n enabled: boolean;\n ratio: number;\n original_chars: number;\n compressed_chars: number;\n stats: {\n duplicates_removed: number;\n whitespace_saved: number;\n dictionary_subs: number;\n paths_shortened: number;\n json_compacted: number;\n };\n}\n\n// Default configuration - CONSERVATIVE settings for model compatibility\n// Only enable layers that don't require the model to decode anything\nexport const DEFAULT_COMPRESSION_CONFIG: CompressionConfig = {\n enabled: true,\n preserveRaw: true,\n layers: {\n deduplication: true, // Safe: removes duplicate messages\n whitespace: true, // Safe: normalizes whitespace\n dictionary: false, // DISABLED: requires model to understand codebook\n paths: false, // DISABLED: requires model to understand path codes\n jsonCompact: true, // Safe: just removes JSON whitespace\n observation: false, // DISABLED: may lose important context\n dynamicCodebook: false, // DISABLED: requires model to understand codes\n },\n dictionary: {\n maxEntries: 50,\n minPhraseLength: 15,\n includeCodebookHeader: false, // No codebook header needed\n },\n};\n","/**\n * Layer 1: Message Deduplication\n *\n * Removes exact duplicate messages from conversation history.\n * Common in heartbeat patterns and repeated tool calls.\n *\n * Safe for LLM: Identical messages add no new information.\n * Expected savings: 2-5%\n */\n\nimport { NormalizedMessage } from \"../types\";\nimport crypto from \"crypto\";\n\nexport interface DeduplicationResult {\n messages: NormalizedMessage[];\n duplicatesRemoved: number;\n originalCount: number;\n}\n\n/**\n * Generate a hash for a message based on its semantic content.\n * Uses role + content + tool_call_id to identify duplicates.\n */\nfunction hashMessage(message: NormalizedMessage): string {\n // Handle content - stringify arrays (multimodal), use string directly, or empty string\n let contentStr = \"\";\n if (typeof message.content === \"string\") {\n contentStr = message.content;\n } else if (Array.isArray(message.content)) {\n contentStr = JSON.stringify(message.content);\n }\n\n const parts = [message.role, contentStr, message.tool_call_id || \"\", message.name || \"\"];\n\n // Include tool_calls if present\n if (message.tool_calls) {\n parts.push(\n JSON.stringify(\n message.tool_calls.map((tc) => ({\n name: tc.function.name,\n args: tc.function.arguments,\n })),\n ),\n );\n }\n\n const content = parts.join(\"|\");\n return crypto.createHash(\"md5\").update(content).digest(\"hex\");\n}\n\n/**\n * Remove exact duplicate messages from the conversation.\n *\n * Strategy:\n * - Keep first occurrence of each unique message\n * - Preserve order for semantic coherence\n * - Never dedupe system messages (they set context)\n * - Allow duplicate user messages (user might repeat intentionally)\n * - CRITICAL: Never dedupe assistant messages with tool_calls that are\n * referenced by subsequent tool messages (breaks Anthropic tool_use/tool_result pairing)\n */\nexport function deduplicateMessages(messages: NormalizedMessage[]): DeduplicationResult {\n const seen = new Set<string>();\n const result: NormalizedMessage[] = [];\n let duplicatesRemoved = 0;\n\n // First pass: collect all tool_call_ids that are referenced by tool messages\n // These tool_calls MUST be preserved to maintain tool_use/tool_result pairing\n const referencedToolCallIds = new Set<string>();\n for (const message of messages) {\n if (message.role === \"tool\" && message.tool_call_id) {\n referencedToolCallIds.add(message.tool_call_id);\n }\n }\n\n for (const message of messages) {\n // Always keep system messages (they set important context)\n if (message.role === \"system\") {\n result.push(message);\n continue;\n }\n\n // Always keep user messages (user might repeat intentionally)\n if (message.role === \"user\") {\n result.push(message);\n continue;\n }\n\n // Always keep tool messages (they are results of tool calls)\n // Removing them would break the tool_use/tool_result pairing\n if (message.role === \"tool\") {\n result.push(message);\n continue;\n }\n\n // For assistant messages with tool_calls, check if any are referenced\n // by subsequent tool messages - if so, we MUST keep this message\n if (message.role === \"assistant\" && message.tool_calls) {\n const hasReferencedToolCall = message.tool_calls.some((tc) =>\n referencedToolCallIds.has(tc.id),\n );\n if (hasReferencedToolCall) {\n // This assistant message has tool_calls that are referenced - keep it\n result.push(message);\n continue;\n }\n }\n\n // For other assistant messages, check for duplicates\n const hash = hashMessage(message);\n\n if (!seen.has(hash)) {\n seen.add(hash);\n result.push(message);\n } else {\n duplicatesRemoved++;\n }\n }\n\n return {\n messages: result,\n duplicatesRemoved,\n originalCount: messages.length,\n };\n}\n","/**\n * Layer 2: Whitespace Normalization\n *\n * Reduces excessive whitespace without changing semantic meaning.\n *\n * Safe for LLM: Tokenizers normalize whitespace anyway.\n * Expected savings: 3-8%\n */\n\nimport { NormalizedMessage } from \"../types\";\n\nexport interface WhitespaceResult {\n messages: NormalizedMessage[];\n charsSaved: number;\n}\n\n/**\n * Normalize whitespace in a string.\n *\n * - Max 2 consecutive newlines\n * - Remove trailing whitespace from lines\n * - Normalize tabs to spaces\n * - Trim start/end\n */\nexport function normalizeWhitespace(content: string): string {\n // Defensive type check - content might be array/object for multimodal messages\n if (!content || typeof content !== \"string\") return content as string;\n\n return (\n content\n // Normalize line endings\n .replace(/\\r\\n/g, \"\\n\")\n .replace(/\\r/g, \"\\n\")\n // Max 2 consecutive newlines (preserve paragraph breaks)\n .replace(/\\n{3,}/g, \"\\n\\n\")\n // Remove trailing whitespace from each line\n .replace(/[ \\t]+$/gm, \"\")\n // Normalize multiple spaces to single (except at line start for indentation)\n .replace(/([^\\n]) {2,}/g, \"$1 \")\n // Reduce excessive indentation (more than 8 spaces → 2 spaces per level)\n .replace(/^[ ]{8,}/gm, (match) => \" \".repeat(Math.ceil(match.length / 4)))\n // Normalize tabs to 2 spaces\n .replace(/\\t/g, \" \")\n // Trim\n .trim()\n );\n}\n\n/**\n * Apply whitespace normalization to all messages.\n */\nexport function normalizeMessagesWhitespace(messages: NormalizedMessage[]): WhitespaceResult {\n let charsSaved = 0;\n\n const result = messages.map((message) => {\n // Only process string content (skip arrays for multimodal messages)\n if (!message.content || typeof message.content !== \"string\") return message;\n\n const originalLength = message.content.length;\n const normalizedContent = normalizeWhitespace(message.content);\n charsSaved += originalLength - normalizedContent.length;\n\n return {\n ...message,\n content: normalizedContent,\n };\n });\n\n return {\n messages: result,\n charsSaved,\n };\n}\n","/**\n * Dictionary Codebook\n *\n * Static dictionary of frequently repeated phrases observed in LLM prompts.\n * Built from analysis of BlockRun production logs.\n *\n * Format: Short code ($XX) -> Long phrase\n * The LLM receives a codebook header and decodes in-context.\n */\n\n// Static codebook - common patterns from system prompts\n// Ordered by expected frequency and impact\nexport const STATIC_CODEBOOK: Record<string, string> = {\n // High-impact: OpenClaw/Agent system prompt patterns (very common)\n $OC01: \"unbrowse_\", // Common prefix in tool names\n $OC02: \"<location>\",\n $OC03: \"</location>\",\n $OC04: \"<name>\",\n $OC05: \"</name>\",\n $OC06: \"<description>\",\n $OC07: \"</description>\",\n $OC08: \"(may need login)\",\n $OC09: \"API skill for OpenClaw\",\n $OC10: \"endpoints\",\n\n // Skill/tool markers\n $SK01: \"<available_skills>\",\n $SK02: \"</available_skills>\",\n $SK03: \"<skill>\",\n $SK04: \"</skill>\",\n\n // Schema patterns (very common in tool definitions)\n $T01: 'type: \"function\"',\n $T02: '\"type\": \"function\"',\n $T03: '\"type\": \"string\"',\n $T04: '\"type\": \"object\"',\n $T05: '\"type\": \"array\"',\n $T06: '\"type\": \"boolean\"',\n $T07: '\"type\": \"number\"',\n\n // Common descriptions\n $D01: \"description:\",\n $D02: '\"description\":',\n\n // Common instructions\n $I01: \"You are a personal assistant\",\n $I02: \"Tool names are case-sensitive\",\n $I03: \"Call tools exactly as listed\",\n $I04: \"Use when\",\n $I05: \"without asking\",\n\n // Safety phrases\n $S01: \"Do not manipulate or persuade\",\n $S02: \"Prioritize safety and human oversight\",\n $S03: \"unless explicitly requested\",\n\n // JSON patterns\n $J01: '\"required\": [\"',\n $J02: '\"properties\": {',\n $J03: '\"additionalProperties\": false',\n\n // Heartbeat patterns\n $H01: \"HEARTBEAT_OK\",\n $H02: \"Read HEARTBEAT.md if it exists\",\n\n // Role markers\n $R01: '\"role\": \"system\"',\n $R02: '\"role\": \"user\"',\n $R03: '\"role\": \"assistant\"',\n $R04: '\"role\": \"tool\"',\n\n // Common endings/phrases\n $E01: \"would you like to\",\n $E02: \"Let me know if you\",\n $E03: \"internal APIs\",\n $E04: \"session cookies\",\n\n // BlockRun model aliases (common in prompts)\n $M01: \"blockrun/\",\n $M02: \"openai/\",\n $M03: \"anthropic/\",\n $M04: \"google/\",\n $M05: \"xai/\",\n};\n\n/**\n * Get the inverse codebook for decompression.\n */\nexport function getInverseCodebook(): Record<string, string> {\n const inverse: Record<string, string> = {};\n for (const [code, phrase] of Object.entries(STATIC_CODEBOOK)) {\n inverse[phrase] = code;\n }\n return inverse;\n}\n\n/**\n * Generate the codebook header for inclusion in system message.\n * LLMs can decode in-context using this header.\n */\nexport function generateCodebookHeader(\n usedCodes: Set<string>,\n pathMap: Record<string, string> = {},\n): string {\n if (usedCodes.size === 0 && Object.keys(pathMap).length === 0) {\n return \"\";\n }\n\n const parts: string[] = [];\n\n // Add used dictionary codes\n if (usedCodes.size > 0) {\n const codeEntries = Array.from(usedCodes)\n .map((code) => `${code}=${STATIC_CODEBOOK[code]}`)\n .join(\", \");\n parts.push(`[Dict: ${codeEntries}]`);\n }\n\n // Add path map\n if (Object.keys(pathMap).length > 0) {\n const pathEntries = Object.entries(pathMap)\n .map(([code, path]) => `${code}=${path}`)\n .join(\", \");\n parts.push(`[Paths: ${pathEntries}]`);\n }\n\n return parts.join(\"\\n\");\n}\n\n/**\n * Decompress a string using the codebook (for logging).\n */\nexport function decompressContent(\n content: string,\n codebook: Record<string, string> = STATIC_CODEBOOK,\n): string {\n let result = content;\n for (const [code, phrase] of Object.entries(codebook)) {\n result = result.split(code).join(phrase);\n }\n return result;\n}\n","/**\n * Layer 3: Dictionary Encoding\n *\n * Replaces frequently repeated long phrases with short codes.\n * Uses a static codebook of common patterns from production logs.\n *\n * Safe for LLM: Reversible substitution with codebook header.\n * Expected savings: 4-8%\n */\n\nimport { NormalizedMessage } from \"../types\";\nimport { getInverseCodebook } from \"../codebook\";\n\nexport interface DictionaryResult {\n messages: NormalizedMessage[];\n substitutionCount: number;\n usedCodes: Set<string>;\n charsSaved: number;\n}\n\n/**\n * Apply dictionary encoding to a string.\n * Returns the encoded string and stats.\n */\nfunction encodeContent(\n content: string,\n inverseCodebook: Record<string, string>,\n): { encoded: string; substitutions: number; codes: Set<string>; charsSaved: number } {\n // Defensive type check - content might be array/object for multimodal messages\n if (!content || typeof content !== \"string\") {\n return { encoded: content, substitutions: 0, codes: new Set(), charsSaved: 0 };\n }\n let encoded = content;\n let substitutions = 0;\n let charsSaved = 0;\n const codes = new Set<string>();\n\n // Sort phrases by length (longest first) to avoid partial matches\n const phrases = Object.keys(inverseCodebook).sort((a, b) => b.length - a.length);\n\n for (const phrase of phrases) {\n const code = inverseCodebook[phrase];\n const regex = new RegExp(escapeRegex(phrase), \"g\");\n const matches = encoded.match(regex);\n\n if (matches && matches.length > 0) {\n encoded = encoded.replace(regex, code);\n substitutions += matches.length;\n charsSaved += matches.length * (phrase.length - code.length);\n codes.add(code);\n }\n }\n\n return { encoded, substitutions, codes, charsSaved };\n}\n\n/**\n * Escape special regex characters in a string.\n */\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/**\n * Apply dictionary encoding to all messages.\n */\nexport function encodeMessages(messages: NormalizedMessage[]): DictionaryResult {\n const inverseCodebook = getInverseCodebook();\n let totalSubstitutions = 0;\n let totalCharsSaved = 0;\n const allUsedCodes = new Set<string>();\n\n const result = messages.map((message) => {\n // Only process string content (skip arrays for multimodal messages)\n if (!message.content || typeof message.content !== \"string\") return message;\n\n const { encoded, substitutions, codes, charsSaved } = encodeContent(\n message.content,\n inverseCodebook,\n );\n\n totalSubstitutions += substitutions;\n totalCharsSaved += charsSaved;\n codes.forEach((code) => allUsedCodes.add(code));\n\n return {\n ...message,\n content: encoded,\n };\n });\n\n return {\n messages: result,\n substitutionCount: totalSubstitutions,\n usedCodes: allUsedCodes,\n charsSaved: totalCharsSaved,\n };\n}\n","/**\n * Layer 4: Path Shortening\n *\n * Detects common filesystem path prefixes and replaces them with short codes.\n * Common in coding assistant contexts with repeated file paths.\n *\n * Safe for LLM: Lossless abbreviation with path map header.\n * Expected savings: 1-3%\n */\n\nimport { NormalizedMessage } from \"../types\";\n\nexport interface PathShorteningResult {\n messages: NormalizedMessage[];\n pathMap: Record<string, string>; // $P1 -> /home/user/project/\n charsSaved: number;\n}\n\n// Regex to match filesystem paths\nconst PATH_REGEX = /(?:\\/[\\w.-]+){3,}/g;\n\n/**\n * Extract all paths from messages and find common prefixes.\n */\nfunction extractPaths(messages: NormalizedMessage[]): string[] {\n const paths: string[] = [];\n\n for (const message of messages) {\n // Only process string content (skip arrays for multimodal messages)\n if (!message.content || typeof message.content !== \"string\") continue;\n const matches = message.content.match(PATH_REGEX);\n if (matches) {\n paths.push(...matches);\n }\n }\n\n return paths;\n}\n\n/**\n * Group paths by their common prefixes.\n * Returns prefixes that appear at least 3 times.\n */\nfunction findFrequentPrefixes(paths: string[]): string[] {\n const prefixCounts = new Map<string, number>();\n\n for (const path of paths) {\n const parts = path.split(\"/\").filter(Boolean);\n\n // Try prefixes of different lengths\n for (let i = 2; i < parts.length; i++) {\n const prefix = \"/\" + parts.slice(0, i).join(\"/\") + \"/\";\n prefixCounts.set(prefix, (prefixCounts.get(prefix) || 0) + 1);\n }\n }\n\n // Return prefixes that appear 3+ times, sorted by length (longest first)\n return Array.from(prefixCounts.entries())\n .filter(([, count]) => count >= 3)\n .sort((a, b) => b[0].length - a[0].length)\n .slice(0, 5) // Max 5 path codes\n .map(([prefix]) => prefix);\n}\n\n/**\n * Apply path shortening to all messages.\n */\nexport function shortenPaths(messages: NormalizedMessage[]): PathShorteningResult {\n const allPaths = extractPaths(messages);\n\n if (allPaths.length < 5) {\n // Not enough paths to benefit from shortening\n return {\n messages,\n pathMap: {},\n charsSaved: 0,\n };\n }\n\n const prefixes = findFrequentPrefixes(allPaths);\n\n if (prefixes.length === 0) {\n return {\n messages,\n pathMap: {},\n charsSaved: 0,\n };\n }\n\n // Create path map\n const pathMap: Record<string, string> = {};\n prefixes.forEach((prefix, i) => {\n pathMap[`$P${i + 1}`] = prefix;\n });\n\n // Replace paths in messages\n let charsSaved = 0;\n\n const result = messages.map((message) => {\n // Only process string content (skip arrays for multimodal messages)\n if (!message.content || typeof message.content !== \"string\") return message;\n\n let content = message.content;\n const originalLength = content.length;\n\n // Replace prefixes (longest first to avoid partial replacements)\n for (const [code, prefix] of Object.entries(pathMap)) {\n content = content.split(prefix).join(code + \"/\");\n }\n\n charsSaved += originalLength - content.length;\n\n return {\n ...message,\n content,\n };\n });\n\n return {\n messages: result,\n pathMap,\n charsSaved,\n };\n}\n\n/**\n * Generate the path map header for the codebook.\n */\nexport function generatePathMapHeader(pathMap: Record<string, string>): string {\n if (Object.keys(pathMap).length === 0) return \"\";\n\n const entries = Object.entries(pathMap)\n .map(([code, path]) => `${code}=${path}`)\n .join(\", \");\n\n return `[Paths: ${entries}]`;\n}\n","/**\n * Layer 5: JSON Compaction\n *\n * Minifies JSON in tool_call arguments and tool results.\n * Removes pretty-print whitespace from JSON strings.\n *\n * Safe for LLM: JSON semantics unchanged.\n * Expected savings: 2-4%\n */\n\nimport { NormalizedMessage, ToolCall } from \"../types\";\n\nexport interface JsonCompactResult {\n messages: NormalizedMessage[];\n charsSaved: number;\n}\n\n/**\n * Compact a JSON string by parsing and re-stringifying without formatting.\n */\nfunction compactJson(jsonString: string): string {\n try {\n const parsed = JSON.parse(jsonString);\n return JSON.stringify(parsed);\n } catch {\n // Not valid JSON, return as-is\n return jsonString;\n }\n}\n\n/**\n * Check if a string looks like JSON (starts with { or [).\n */\nfunction looksLikeJson(str: string): boolean {\n const trimmed = str.trim();\n return (\n (trimmed.startsWith(\"{\") && trimmed.endsWith(\"}\")) ||\n (trimmed.startsWith(\"[\") && trimmed.endsWith(\"]\"))\n );\n}\n\n/**\n * Compact tool_call arguments in a message.\n */\nfunction compactToolCalls(toolCalls: ToolCall[]): ToolCall[] {\n return toolCalls.map((tc) => ({\n ...tc,\n function: {\n ...tc.function,\n arguments: compactJson(tc.function.arguments),\n },\n }));\n}\n\n/**\n * Apply JSON compaction to all messages.\n *\n * Targets:\n * - tool_call arguments (in assistant messages)\n * - tool message content (often JSON)\n */\nexport function compactMessagesJson(messages: NormalizedMessage[]): JsonCompactResult {\n let charsSaved = 0;\n\n const result = messages.map((message) => {\n const newMessage = { ...message };\n\n // Compact tool_calls arguments\n if (message.tool_calls && message.tool_calls.length > 0) {\n const originalLength = JSON.stringify(message.tool_calls).length;\n newMessage.tool_calls = compactToolCalls(message.tool_calls);\n const newLength = JSON.stringify(newMessage.tool_calls).length;\n charsSaved += originalLength - newLength;\n }\n\n // Compact tool message content if it looks like JSON\n // Only process string content (skip arrays for multimodal messages)\n if (\n message.role === \"tool\" &&\n message.content &&\n typeof message.content === \"string\" &&\n looksLikeJson(message.content)\n ) {\n const originalLength = message.content.length;\n const compacted = compactJson(message.content);\n charsSaved += originalLength - compacted.length;\n newMessage.content = compacted;\n }\n\n return newMessage;\n });\n\n return {\n messages: result,\n charsSaved,\n };\n}\n","/**\n * L6: Observation Compression (AGGRESSIVE)\n *\n * Inspired by claw-compactor's 97% compression on tool results.\n * Tool call results (especially large ones) are summarized to key info only.\n *\n * This is the biggest compression win - tool outputs can be 10KB+ but\n * only ~200 chars of actual useful information.\n */\n\nimport { NormalizedMessage } from \"../types\";\n\ninterface ObservationResult {\n messages: NormalizedMessage[];\n charsSaved: number;\n observationsCompressed: number;\n}\n\n// Max length for tool results before compression kicks in\nconst TOOL_RESULT_THRESHOLD = 500;\n\n// Max length to compress tool results down to\nconst COMPRESSED_RESULT_MAX = 300;\n\n/**\n * Extract key information from tool result.\n * Keeps: errors, key values, status, first/last important lines.\n */\nfunction compressToolResult(content: string): string {\n if (!content || content.length <= TOOL_RESULT_THRESHOLD) {\n return content;\n }\n\n const lines = content\n .split(\"\\n\")\n .map((l) => l.trim())\n .filter(Boolean);\n\n // Priority 1: Error messages (always keep)\n const errorLines = lines.filter(\n (l) => /error|exception|failed|denied|refused|timeout|invalid/i.test(l) && l.length < 200,\n );\n\n // Priority 2: Status/result lines\n const statusLines = lines.filter(\n (l) =>\n /success|complete|created|updated|found|result|status|total|count/i.test(l) && l.length < 150,\n );\n\n // Priority 3: Key JSON fields (extract important values)\n const jsonMatches: string[] = [];\n const jsonPattern = /\"(id|name|status|error|message|count|total|url|path)\":\\s*\"?([^\",}\\n]+)\"?/gi;\n let match;\n while ((match = jsonPattern.exec(content)) !== null) {\n jsonMatches.push(`${match[1]}: ${match[2].slice(0, 50)}`);\n }\n\n // Priority 4: First and last meaningful lines\n const firstLine = lines[0]?.slice(0, 100);\n const lastLine = lines.length > 1 ? lines[lines.length - 1]?.slice(0, 100) : \"\";\n\n // Build compressed observation\n const parts: string[] = [];\n\n if (errorLines.length > 0) {\n parts.push(\"[ERR] \" + errorLines.slice(0, 3).join(\" | \"));\n }\n\n if (statusLines.length > 0) {\n parts.push(statusLines.slice(0, 3).join(\" | \"));\n }\n\n if (jsonMatches.length > 0) {\n parts.push(jsonMatches.slice(0, 5).join(\", \"));\n }\n\n if (parts.length === 0) {\n // Fallback: keep first/last lines with truncation marker\n parts.push(firstLine || \"\");\n if (lines.length > 2) {\n parts.push(`[...${lines.length - 2} lines...]`);\n }\n if (lastLine && lastLine !== firstLine) {\n parts.push(lastLine);\n }\n }\n\n let result = parts.join(\"\\n\");\n\n // Final length cap\n if (result.length > COMPRESSED_RESULT_MAX) {\n result = result.slice(0, COMPRESSED_RESULT_MAX - 20) + \"\\n[...truncated]\";\n }\n\n return result;\n}\n\n/**\n * Compress large repeated content blocks.\n * Detects when same large block appears multiple times.\n */\nfunction deduplicateLargeBlocks(messages: NormalizedMessage[]): {\n messages: NormalizedMessage[];\n charsSaved: number;\n} {\n const blockHashes = new Map<string, number>(); // hash -> first occurrence index\n let charsSaved = 0;\n\n const result = messages.map((msg, idx) => {\n // Only process string content (skip arrays for multimodal messages)\n if (!msg.content || typeof msg.content !== \"string\" || msg.content.length < 500) {\n return msg;\n }\n\n // Hash first 200 chars as block identifier\n const blockKey = msg.content.slice(0, 200);\n\n if (blockHashes.has(blockKey)) {\n const firstIdx = blockHashes.get(blockKey)!;\n const original = msg.content;\n const compressed = `[See message #${firstIdx + 1} - same content]`;\n charsSaved += original.length - compressed.length;\n return { ...msg, content: compressed };\n }\n\n blockHashes.set(blockKey, idx);\n return msg;\n });\n\n return { messages: result, charsSaved };\n}\n\n/**\n * Compress tool results in messages.\n */\nexport function compressObservations(messages: NormalizedMessage[]): ObservationResult {\n let charsSaved = 0;\n let observationsCompressed = 0;\n\n // First pass: compress individual tool results\n let result = messages.map((msg) => {\n // Only compress tool role messages (these are tool call results)\n // Only process string content (skip arrays for multimodal messages)\n if (msg.role !== \"tool\" || !msg.content || typeof msg.content !== \"string\") {\n return msg;\n }\n\n const original = msg.content;\n if (original.length <= TOOL_RESULT_THRESHOLD) {\n return msg;\n }\n\n const compressed = compressToolResult(original);\n const saved = original.length - compressed.length;\n\n if (saved > 50) {\n charsSaved += saved;\n observationsCompressed++;\n return { ...msg, content: compressed };\n }\n\n return msg;\n });\n\n // Second pass: deduplicate large repeated blocks\n const dedupResult = deduplicateLargeBlocks(result);\n result = dedupResult.messages;\n charsSaved += dedupResult.charsSaved;\n\n return {\n messages: result,\n charsSaved,\n observationsCompressed,\n };\n}\n","/**\n * L7: Dynamic Codebook Builder\n *\n * Inspired by claw-compactor's frequency-based codebook.\n * Builds codebook from actual content being compressed,\n * rather than relying on static patterns.\n *\n * Finds phrases that appear 3+ times and replaces with short codes.\n */\n\nimport { NormalizedMessage } from \"../types\";\n\ninterface DynamicCodebookResult {\n messages: NormalizedMessage[];\n charsSaved: number;\n dynamicCodes: Record<string, string>; // code -> phrase\n substitutions: number;\n}\n\n// Config\nconst MIN_PHRASE_LENGTH = 20;\nconst MAX_PHRASE_LENGTH = 200;\nconst MIN_FREQUENCY = 3;\nconst MAX_ENTRIES = 100;\nconst CODE_PREFIX = \"$D\"; // Dynamic codes: $D01, $D02, etc.\n\n/**\n * Find repeated phrases in content.\n */\nfunction findRepeatedPhrases(allContent: string): Map<string, number> {\n const phrases = new Map<string, number>();\n\n // Split by sentence-like boundaries\n const segments = allContent.split(/(?<=[.!?\\n])\\s+/);\n\n for (const segment of segments) {\n const trimmed = segment.trim();\n if (trimmed.length >= MIN_PHRASE_LENGTH && trimmed.length <= MAX_PHRASE_LENGTH) {\n phrases.set(trimmed, (phrases.get(trimmed) || 0) + 1);\n }\n }\n\n // Also find repeated lines\n const lines = allContent.split(\"\\n\");\n for (const line of lines) {\n const trimmed = line.trim();\n if (trimmed.length >= MIN_PHRASE_LENGTH && trimmed.length <= MAX_PHRASE_LENGTH) {\n phrases.set(trimmed, (phrases.get(trimmed) || 0) + 1);\n }\n }\n\n return phrases;\n}\n\n/**\n * Build dynamic codebook from message content.\n */\nfunction buildDynamicCodebook(messages: NormalizedMessage[]): Record<string, string> {\n // Combine all content\n let allContent = \"\";\n for (const msg of messages) {\n // Only process string content (skip arrays for multimodal messages)\n if (msg.content && typeof msg.content === \"string\") {\n allContent += msg.content + \"\\n\";\n }\n }\n\n // Find repeated phrases\n const phrases = findRepeatedPhrases(allContent);\n\n // Filter by frequency and sort by savings potential\n const candidates: Array<{ phrase: string; count: number; savings: number }> = [];\n for (const [phrase, count] of phrases.entries()) {\n if (count >= MIN_FREQUENCY) {\n // Savings = (phrase length - code length) * occurrences\n const codeLength = 4; // e.g., \"$D01\"\n const savings = (phrase.length - codeLength) * count;\n if (savings > 50) {\n candidates.push({ phrase, count, savings });\n }\n }\n }\n\n // Sort by savings (descending) and take top entries\n candidates.sort((a, b) => b.savings - a.savings);\n const topCandidates = candidates.slice(0, MAX_ENTRIES);\n\n // Build codebook\n const codebook: Record<string, string> = {};\n topCandidates.forEach((c, i) => {\n const code = `${CODE_PREFIX}${String(i + 1).padStart(2, \"0\")}`;\n codebook[code] = c.phrase;\n });\n\n return codebook;\n}\n\n/**\n * Escape special regex characters.\n */\nfunction escapeRegex(str: string): string {\n // Defensive type check\n if (!str || typeof str !== \"string\") return \"\";\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/**\n * Apply dynamic codebook to messages.\n */\nexport function applyDynamicCodebook(messages: NormalizedMessage[]): DynamicCodebookResult {\n // Build codebook from content\n const codebook = buildDynamicCodebook(messages);\n\n if (Object.keys(codebook).length === 0) {\n return {\n messages,\n charsSaved: 0,\n dynamicCodes: {},\n substitutions: 0,\n };\n }\n\n // Create inverse map for replacement\n const phraseToCode: Record<string, string> = {};\n for (const [code, phrase] of Object.entries(codebook)) {\n phraseToCode[phrase] = code;\n }\n\n // Sort phrases by length (longest first) to avoid partial replacements\n const sortedPhrases = Object.keys(phraseToCode).sort((a, b) => b.length - a.length);\n\n let charsSaved = 0;\n let substitutions = 0;\n\n // Apply replacements\n const result = messages.map((msg) => {\n // Only process string content (skip arrays for multimodal messages)\n if (!msg.content || typeof msg.content !== \"string\") return msg;\n\n let content = msg.content;\n for (const phrase of sortedPhrases) {\n const code = phraseToCode[phrase];\n const regex = new RegExp(escapeRegex(phrase), \"g\");\n const matches = content.match(regex);\n if (matches) {\n content = content.replace(regex, code);\n charsSaved += (phrase.length - code.length) * matches.length;\n substitutions += matches.length;\n }\n }\n\n return { ...msg, content };\n });\n\n return {\n messages: result,\n charsSaved,\n dynamicCodes: codebook,\n substitutions,\n };\n}\n\n/**\n * Generate header for dynamic codes (to include in system message).\n */\nexport function generateDynamicCodebookHeader(codebook: Record<string, string>): string {\n if (Object.keys(codebook).length === 0) return \"\";\n\n const entries = Object.entries(codebook)\n .slice(0, 20) // Limit header size\n .map(([code, phrase]) => {\n // Truncate long phrases in header\n const displayPhrase = phrase.length > 40 ? phrase.slice(0, 37) + \"...\" : phrase;\n return `${code}=${displayPhrase}`;\n })\n .join(\", \");\n\n return `[DynDict: ${entries}]`;\n}\n","/**\n * LLM-Safe Context Compression\n *\n * Reduces token usage by 15-40% while preserving semantic meaning.\n * Implements 7 compression layers inspired by claw-compactor.\n *\n * Usage:\n * const result = await compressContext(messages);\n * // result.messages -> compressed version to send to provider\n * // result.originalMessages -> original for logging\n */\n\nimport {\n NormalizedMessage,\n CompressionConfig,\n CompressionResult,\n CompressionStats,\n DEFAULT_COMPRESSION_CONFIG,\n} from \"./types\";\nimport { deduplicateMessages } from \"./layers/deduplication\";\nimport { normalizeMessagesWhitespace } from \"./layers/whitespace\";\nimport { encodeMessages } from \"./layers/dictionary\";\nimport { shortenPaths } from \"./layers/paths\";\nimport { compactMessagesJson } from \"./layers/json-compact\";\nimport { compressObservations } from \"./layers/observation\";\nimport { applyDynamicCodebook, generateDynamicCodebookHeader } from \"./layers/dynamic-codebook\";\nimport { generateCodebookHeader, STATIC_CODEBOOK } from \"./codebook\";\n\nexport * from \"./types\";\nexport { STATIC_CODEBOOK } from \"./codebook\";\n\n/**\n * Calculate total character count for messages.\n */\nfunction calculateTotalChars(messages: NormalizedMessage[]): number {\n return messages.reduce((total, msg) => {\n let chars = 0;\n if (typeof msg.content === \"string\") {\n chars = msg.content.length;\n } else if (Array.isArray(msg.content)) {\n // For multimodal content, stringify to get approximate size\n chars = JSON.stringify(msg.content).length;\n }\n if (msg.tool_calls) {\n chars += JSON.stringify(msg.tool_calls).length;\n }\n return total + chars;\n }, 0);\n}\n\n/**\n * Deep clone messages to preserve originals.\n */\nfunction cloneMessages(messages: NormalizedMessage[]): NormalizedMessage[] {\n return JSON.parse(JSON.stringify(messages));\n}\n\n/**\n * Prepend codebook header to the first USER message (not system).\n *\n * Why not system message?\n * - Google Gemini uses systemInstruction which doesn't support codebook format\n * - The codebook header in user message is still visible to all LLMs\n * - This ensures compatibility across all providers\n */\nfunction prependCodebookHeader(\n messages: NormalizedMessage[],\n usedCodes: Set<string>,\n pathMap: Record<string, string>,\n): NormalizedMessage[] {\n const header = generateCodebookHeader(usedCodes, pathMap);\n if (!header) return messages;\n\n // Find first user message (not system - Google's systemInstruction doesn't support codebook)\n const userIndex = messages.findIndex((m) => m.role === \"user\");\n\n if (userIndex === -1) {\n // No user message, add codebook as system (fallback)\n return [{ role: \"system\", content: header }, ...messages];\n }\n\n // Prepend to first user message (only if content is a string)\n return messages.map((msg, i) => {\n if (i === userIndex) {\n // Only prepend to string content - skip arrays (multimodal messages)\n if (typeof msg.content === \"string\") {\n return {\n ...msg,\n content: `${header}\\n\\n${msg.content}`,\n };\n }\n // For non-string content, don't modify the message\n // The codebook header would corrupt array content\n }\n return msg;\n });\n}\n\n/**\n * Main compression function.\n *\n * Applies 5 layers in sequence:\n * 1. Deduplication - Remove exact duplicate messages\n * 2. Whitespace - Normalize excessive whitespace\n * 3. Dictionary - Replace common phrases with codes\n * 4. Paths - Shorten repeated file paths\n * 5. JSON - Compact JSON in tool calls\n *\n * Then prepends a codebook header for the LLM to decode in-context.\n */\nexport async function compressContext(\n messages: NormalizedMessage[],\n config: Partial<CompressionConfig> = {},\n): Promise<CompressionResult> {\n const fullConfig: CompressionConfig = {\n ...DEFAULT_COMPRESSION_CONFIG,\n ...config,\n layers: {\n ...DEFAULT_COMPRESSION_CONFIG.layers,\n ...config.layers,\n },\n dictionary: {\n ...DEFAULT_COMPRESSION_CONFIG.dictionary,\n ...config.dictionary,\n },\n };\n\n // If compression disabled, return as-is\n if (!fullConfig.enabled) {\n const originalChars = calculateTotalChars(messages);\n return {\n messages,\n originalMessages: messages,\n originalChars,\n compressedChars: originalChars,\n compressionRatio: 1,\n stats: {\n duplicatesRemoved: 0,\n whitespaceSavedChars: 0,\n dictionarySubstitutions: 0,\n pathsShortened: 0,\n jsonCompactedChars: 0,\n observationsCompressed: 0,\n observationCharsSaved: 0,\n dynamicSubstitutions: 0,\n dynamicCharsSaved: 0,\n },\n codebook: {},\n pathMap: {},\n dynamicCodes: {},\n };\n }\n\n // Preserve originals for logging\n const originalMessages = fullConfig.preserveRaw ? cloneMessages(messages) : messages;\n const originalChars = calculateTotalChars(messages);\n\n // Initialize stats\n const stats: CompressionStats = {\n duplicatesRemoved: 0,\n whitespaceSavedChars: 0,\n dictionarySubstitutions: 0,\n pathsShortened: 0,\n jsonCompactedChars: 0,\n observationsCompressed: 0,\n observationCharsSaved: 0,\n dynamicSubstitutions: 0,\n dynamicCharsSaved: 0,\n };\n\n let result = cloneMessages(messages);\n let usedCodes = new Set<string>();\n let pathMap: Record<string, string> = {};\n let dynamicCodes: Record<string, string> = {};\n\n // Layer 1: Deduplication\n if (fullConfig.layers.deduplication) {\n const dedupResult = deduplicateMessages(result);\n result = dedupResult.messages;\n stats.duplicatesRemoved = dedupResult.duplicatesRemoved;\n }\n\n // Layer 2: Whitespace normalization\n if (fullConfig.layers.whitespace) {\n const wsResult = normalizeMessagesWhitespace(result);\n result = wsResult.messages;\n stats.whitespaceSavedChars = wsResult.charsSaved;\n }\n\n // Layer 3: Dictionary encoding\n if (fullConfig.layers.dictionary) {\n const dictResult = encodeMessages(result);\n result = dictResult.messages;\n stats.dictionarySubstitutions = dictResult.substitutionCount;\n usedCodes = dictResult.usedCodes;\n }\n\n // Layer 4: Path shortening\n if (fullConfig.layers.paths) {\n const pathResult = shortenPaths(result);\n result = pathResult.messages;\n pathMap = pathResult.pathMap;\n stats.pathsShortened = Object.keys(pathMap).length;\n }\n\n // Layer 5: JSON compaction\n if (fullConfig.layers.jsonCompact) {\n const jsonResult = compactMessagesJson(result);\n result = jsonResult.messages;\n stats.jsonCompactedChars = jsonResult.charsSaved;\n }\n\n // Layer 6: Observation compression (BIG WIN - 97% on tool results)\n if (fullConfig.layers.observation) {\n const obsResult = compressObservations(result);\n result = obsResult.messages;\n stats.observationsCompressed = obsResult.observationsCompressed;\n stats.observationCharsSaved = obsResult.charsSaved;\n }\n\n // Layer 7: Dynamic codebook (learns from actual content)\n if (fullConfig.layers.dynamicCodebook) {\n const dynResult = applyDynamicCodebook(result);\n result = dynResult.messages;\n stats.dynamicSubstitutions = dynResult.substitutions;\n stats.dynamicCharsSaved = dynResult.charsSaved;\n dynamicCodes = dynResult.dynamicCodes;\n }\n\n // Add codebook header if enabled and we have codes to include\n if (\n fullConfig.dictionary.includeCodebookHeader &&\n (usedCodes.size > 0 || Object.keys(pathMap).length > 0 || Object.keys(dynamicCodes).length > 0)\n ) {\n result = prependCodebookHeader(result, usedCodes, pathMap);\n // Also add dynamic codebook header if we have dynamic codes\n if (Object.keys(dynamicCodes).length > 0) {\n const dynHeader = generateDynamicCodebookHeader(dynamicCodes);\n if (dynHeader) {\n const systemIndex = result.findIndex((m) => m.role === \"system\");\n // Only prepend to string content - skip arrays (multimodal messages)\n if (systemIndex >= 0 && typeof result[systemIndex].content === \"string\") {\n result[systemIndex] = {\n ...result[systemIndex],\n content: `${dynHeader}\\n${result[systemIndex].content}`,\n };\n }\n }\n }\n }\n\n // Calculate final stats\n const compressedChars = calculateTotalChars(result);\n const compressionRatio = compressedChars / originalChars;\n\n // Build used codebook for logging\n const usedCodebook: Record<string, string> = {};\n usedCodes.forEach((code) => {\n usedCodebook[code] = STATIC_CODEBOOK[code];\n });\n\n return {\n messages: result,\n originalMessages,\n originalChars,\n compressedChars,\n compressionRatio,\n stats,\n codebook: usedCodebook,\n pathMap,\n dynamicCodes,\n };\n}\n\n/**\n * Quick check if compression would benefit these messages.\n * Returns true if messages are large enough to warrant compression.\n */\nexport function shouldCompress(messages: NormalizedMessage[]): boolean {\n const chars = calculateTotalChars(messages);\n // Only compress if > 5000 chars (roughly 1000 tokens)\n return chars > 5000;\n}\n","/**\n * Session Persistence Store\n *\n * Tracks model selections per session to prevent model switching mid-task.\n * When a session is active, the router will continue using the same model\n * instead of re-routing each request.\n */\n\nimport { createHash } from \"node:crypto\";\n\nexport type SessionEntry = {\n model: string;\n tier: string;\n createdAt: number;\n lastUsedAt: number;\n requestCount: number;\n // --- Three-strike escalation ---\n recentHashes: string[]; // Sliding window of last 3 request content fingerprints\n strikes: number; // Consecutive similar request count\n escalated: boolean; // Whether session was already escalated via three-strike\n};\n\nexport type SessionConfig = {\n /** Enable session persistence (default: false) */\n enabled: boolean;\n /** Session timeout in ms (default: 30 minutes) */\n timeoutMs: number;\n /** Header name for session ID (default: X-Session-ID) */\n headerName: string;\n};\n\nexport const DEFAULT_SESSION_CONFIG: SessionConfig = {\n enabled: true,\n timeoutMs: 30 * 60 * 1000, // 30 minutes\n headerName: \"x-session-id\",\n};\n\n/**\n * Session persistence store for maintaining model selections.\n */\nexport class SessionStore {\n private sessions: Map<string, SessionEntry> = new Map();\n private config: SessionConfig;\n private cleanupInterval: ReturnType<typeof setInterval> | null = null;\n\n constructor(config: Partial<SessionConfig> = {}) {\n this.config = { ...DEFAULT_SESSION_CONFIG, ...config };\n\n // Start cleanup interval (every 5 minutes)\n if (this.config.enabled) {\n this.cleanupInterval = setInterval(() => this.cleanup(), 5 * 60 * 1000);\n }\n }\n\n /**\n * Get the pinned model for a session, if any.\n */\n getSession(sessionId: string): SessionEntry | undefined {\n if (!this.config.enabled || !sessionId) {\n return undefined;\n }\n\n const entry = this.sessions.get(sessionId);\n if (!entry) {\n return undefined;\n }\n\n // Check if session has expired\n const now = Date.now();\n if (now - entry.lastUsedAt > this.config.timeoutMs) {\n this.sessions.delete(sessionId);\n return undefined;\n }\n\n return entry;\n }\n\n /**\n * Pin a model to a session.\n */\n setSession(sessionId: string, model: string, tier: string): void {\n if (!this.config.enabled || !sessionId) {\n return;\n }\n\n const existing = this.sessions.get(sessionId);\n const now = Date.now();\n\n if (existing) {\n existing.lastUsedAt = now;\n existing.requestCount++;\n // Update model if different (e.g., fallback)\n if (existing.model !== model) {\n existing.model = model;\n existing.tier = tier;\n }\n } else {\n this.sessions.set(sessionId, {\n model,\n tier,\n createdAt: now,\n lastUsedAt: now,\n requestCount: 1,\n recentHashes: [],\n strikes: 0,\n escalated: false,\n });\n }\n }\n\n /**\n * Touch a session to extend its timeout.\n */\n touchSession(sessionId: string): void {\n if (!this.config.enabled || !sessionId) {\n return;\n }\n\n const entry = this.sessions.get(sessionId);\n if (entry) {\n entry.lastUsedAt = Date.now();\n entry.requestCount++;\n }\n }\n\n /**\n * Clear a specific session.\n */\n clearSession(sessionId: string): void {\n this.sessions.delete(sessionId);\n }\n\n /**\n * Clear all sessions.\n */\n clearAll(): void {\n this.sessions.clear();\n }\n\n /**\n * Get session stats for debugging.\n */\n getStats(): { count: number; sessions: Array<{ id: string; model: string; age: number }> } {\n const now = Date.now();\n const sessions = Array.from(this.sessions.entries()).map(([id, entry]) => ({\n id: id.slice(0, 8) + \"...\",\n model: entry.model,\n age: Math.round((now - entry.createdAt) / 1000),\n }));\n return { count: this.sessions.size, sessions };\n }\n\n /**\n * Clean up expired sessions.\n */\n private cleanup(): void {\n const now = Date.now();\n for (const [id, entry] of this.sessions) {\n if (now - entry.lastUsedAt > this.config.timeoutMs) {\n this.sessions.delete(id);\n }\n }\n }\n\n /**\n * Record a request content hash and detect repetitive patterns.\n * Returns true if escalation should be triggered (3+ consecutive similar requests).\n */\n recordRequestHash(sessionId: string, hash: string): boolean {\n const entry = this.sessions.get(sessionId);\n if (!entry) return false;\n\n const prev = entry.recentHashes;\n if (prev.length > 0 && prev[prev.length - 1] === hash) {\n entry.strikes++;\n } else {\n entry.strikes = 0;\n }\n\n entry.recentHashes.push(hash);\n if (entry.recentHashes.length > 3) {\n entry.recentHashes.shift();\n }\n\n return entry.strikes >= 2 && !entry.escalated;\n }\n\n /**\n * Escalate session to next tier. Returns the new model/tier or null if already at max.\n */\n escalateSession(\n sessionId: string,\n tierConfigs: Record<string, { primary: string; fallback: string[] }>,\n ): { model: string; tier: string } | null {\n const entry = this.sessions.get(sessionId);\n if (!entry) return null;\n\n const TIER_ORDER = [\"SIMPLE\", \"MEDIUM\", \"COMPLEX\", \"REASONING\"];\n const currentIdx = TIER_ORDER.indexOf(entry.tier);\n if (currentIdx < 0 || currentIdx >= TIER_ORDER.length - 1) return null;\n\n const nextTier = TIER_ORDER[currentIdx + 1];\n const nextConfig = tierConfigs[nextTier];\n if (!nextConfig) return null;\n\n entry.model = nextConfig.primary;\n entry.tier = nextTier;\n entry.strikes = 0;\n entry.escalated = true;\n\n return { model: nextConfig.primary, tier: nextTier };\n }\n\n /**\n * Stop the cleanup interval.\n */\n close(): void {\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n this.cleanupInterval = null;\n }\n }\n}\n\n/**\n * Generate a session ID from request headers or create a default.\n */\nexport function getSessionId(\n headers: Record<string, string | string[] | undefined>,\n headerName: string = DEFAULT_SESSION_CONFIG.headerName,\n): string | undefined {\n const value = headers[headerName] || headers[headerName.toLowerCase()];\n if (typeof value === \"string\" && value.length > 0) {\n return value;\n }\n if (Array.isArray(value) && value.length > 0) {\n return value[0];\n }\n return undefined;\n}\n\n/**\n * Derive a stable session ID from message content when no explicit session\n * header is provided. Uses the first user message as the conversation anchor —\n * same opening message = same session ID across all subsequent turns.\n *\n * This prevents model-switching mid-conversation even when OpenClaw doesn't\n * send an x-session-id header (which is the default OpenClaw behaviour).\n */\nexport function deriveSessionId(\n messages: Array<{ role: string; content: unknown }>,\n): string | undefined {\n const firstUser = messages.find((m) => m.role === \"user\");\n if (!firstUser) return undefined;\n\n const content =\n typeof firstUser.content === \"string\" ? firstUser.content : JSON.stringify(firstUser.content);\n\n // 8-char hex prefix of SHA-256 — short enough for logs, collision-resistant\n // enough for session tracking within a single gateway instance.\n return createHash(\"sha256\").update(content).digest(\"hex\").slice(0, 8);\n}\n\n/**\n * Generate a short hash fingerprint from request content.\n * Captures: last user message text + tool call names (if any).\n * Normalizes whitespace to avoid false negatives from minor formatting diffs.\n */\nexport function hashRequestContent(\n lastUserContent: string,\n toolCallNames?: string[],\n): string {\n const normalized = lastUserContent.replace(/\\s+/g, \" \").trim().slice(0, 500);\n const toolSuffix = toolCallNames?.length\n ? `|tools:${toolCallNames.sort().join(\",\")}`\n : \"\";\n return createHash(\"sha256\")\n .update(normalized + toolSuffix)\n .digest(\"hex\")\n .slice(0, 12);\n}\n","/**\n * Auto-update checker for ClawRouter.\n * Checks npm registry on startup and notifies user if update available.\n */\n\nimport { VERSION } from \"./version.js\";\n\nconst NPM_REGISTRY = \"https://registry.npmjs.org/@blockrun/clawrouter/latest\";\nconst UPDATE_URL = \"https://blockrun.ai/ClawRouter-update\";\nconst CHECK_TIMEOUT_MS = 5_000; // Don't block startup for more than 5s\n\n/**\n * Compare semver versions. Returns:\n * 1 if a > b\n * 0 if a === b\n * -1 if a < b\n */\nfunction compareSemver(a: string, b: string): number {\n const pa = a.split(\".\").map(Number);\n const pb = b.split(\".\").map(Number);\n for (let i = 0; i < 3; i++) {\n if ((pa[i] || 0) > (pb[i] || 0)) return 1;\n if ((pa[i] || 0) < (pb[i] || 0)) return -1;\n }\n return 0;\n}\n\n/**\n * Check npm registry for latest version.\n * Non-blocking, silent on errors.\n */\nexport async function checkForUpdates(): Promise<void> {\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS);\n\n const res = await fetch(NPM_REGISTRY, {\n signal: controller.signal,\n headers: { Accept: \"application/json\" },\n });\n clearTimeout(timeout);\n\n if (!res.ok) return;\n\n const data = (await res.json()) as { version?: string };\n const latest = data.version;\n\n if (!latest) return;\n\n if (compareSemver(latest, VERSION) > 0) {\n console.log(\"\");\n console.log(`\\x1b[33m⬆️ ClawRouter ${latest} available (you have ${VERSION})\\x1b[0m`);\n console.log(` Run: \\x1b[36mcurl -fsSL ${UPDATE_URL} | bash\\x1b[0m`);\n console.log(\"\");\n }\n } catch {\n // Silent fail - don't disrupt startup\n }\n}\n","/**\n * Configuration Module\n *\n * Reads environment variables at module load time.\n * Separated from network code to avoid security scanner false positives.\n */\n\nconst DEFAULT_PORT = 8402;\n\n/**\n * Proxy port configuration - resolved once at module load.\n * Reads BLOCKRUN_PROXY_PORT env var or defaults to 8402.\n */\nexport const PROXY_PORT = (() => {\n const envPort = process[\"env\"].BLOCKRUN_PROXY_PORT;\n if (envPort) {\n const parsed = parseInt(envPort, 10);\n if (!isNaN(parsed) && parsed > 0 && parsed < 65536) {\n return parsed;\n }\n }\n return DEFAULT_PORT;\n})();\n","/**\n * Session Journal - Memory layer for ClawRouter\n *\n * Maintains a compact record of key actions per session, enabling agents\n * to recall earlier work even when OpenClaw's sessions_history is truncated.\n *\n * How it works:\n * 1. As LLM responses flow through, extracts key actions (\"I created X\", \"I fixed Y\")\n * 2. Stores them in a compact journal per session\n * 3. When a request mentions past work (\"what did you do today?\"), injects the journal\n */\n\nexport interface JournalEntry {\n timestamp: number;\n action: string; // Compact description: \"Created login component\"\n model?: string;\n}\n\nexport interface SessionJournalConfig {\n /** Maximum entries per session (default: 100) */\n maxEntries?: number;\n /** Maximum age of entries in ms (default: 24 hours) */\n maxAgeMs?: number;\n /** Maximum events to extract per response (default: 5) */\n maxEventsPerResponse?: number;\n}\n\nconst DEFAULT_CONFIG: Required<SessionJournalConfig> = {\n maxEntries: 100,\n maxAgeMs: 24 * 60 * 60 * 1000, // 24 hours\n maxEventsPerResponse: 5,\n};\n\nexport class SessionJournal {\n private journals: Map<string, JournalEntry[]> = new Map();\n private config: Required<SessionJournalConfig>;\n\n constructor(config?: SessionJournalConfig) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n }\n\n /**\n * Extract key events from assistant response content.\n * Looks for patterns like \"I created...\", \"I fixed...\", \"Successfully...\"\n */\n extractEvents(content: string): string[] {\n if (!content || typeof content !== \"string\") {\n return [];\n }\n\n const events: string[] = [];\n const seen = new Set<string>();\n\n // Patterns for identifying key actions\n // Note: Patterns allow optional words like \"also\", \"then\", \"have\" between \"I\" and verb\n const patterns = [\n // Creation patterns\n /I (?:also |then |have |)?(?:created|implemented|added|wrote|built|generated|set up|initialized) ([^.!?\\n]{10,150})/gi,\n // Fix patterns\n /I (?:also |then |have |)?(?:fixed|resolved|solved|patched|corrected|addressed|debugged) ([^.!?\\n]{10,150})/gi,\n // Completion patterns\n /I (?:also |then |have |)?(?:completed|finished|done with|wrapped up) ([^.!?\\n]{10,150})/gi,\n // Update patterns\n /I (?:also |then |have |)?(?:updated|modified|changed|refactored|improved|enhanced|optimized) ([^.!?\\n]{10,150})/gi,\n // Success patterns\n /Successfully ([^.!?\\n]{10,150})/gi,\n // Tool usage patterns (when agent uses tools)\n /I (?:also |then |have |)?(?:ran|executed|called|invoked) ([^.!?\\n]{10,100})/gi,\n ];\n\n for (const pattern of patterns) {\n // Reset pattern lastIndex for each iteration\n pattern.lastIndex = 0;\n\n let match;\n while ((match = pattern.exec(content)) !== null) {\n const action = match[0].trim();\n\n // Skip if already seen (dedup)\n const normalized = action.toLowerCase();\n if (seen.has(normalized)) {\n continue;\n }\n\n // Validate length (not too short or too long)\n if (action.length >= 15 && action.length <= 200) {\n events.push(action);\n seen.add(normalized);\n }\n\n // Stop if we have enough events\n if (events.length >= this.config.maxEventsPerResponse) {\n break;\n }\n }\n\n if (events.length >= this.config.maxEventsPerResponse) {\n break;\n }\n }\n\n return events;\n }\n\n /**\n * Record events to the session journal.\n */\n record(sessionId: string, events: string[], model?: string): void {\n if (!sessionId || !events.length) {\n return;\n }\n\n const journal = this.journals.get(sessionId) || [];\n const now = Date.now();\n\n for (const action of events) {\n journal.push({\n timestamp: now,\n action,\n model,\n });\n }\n\n // Trim old entries and enforce max count\n const cutoff = now - this.config.maxAgeMs;\n const trimmed = journal.filter((e) => e.timestamp > cutoff).slice(-this.config.maxEntries);\n\n this.journals.set(sessionId, trimmed);\n }\n\n /**\n * Check if the user message indicates a need for historical context.\n */\n needsContext(lastUserMessage: string): boolean {\n if (!lastUserMessage || typeof lastUserMessage !== \"string\") {\n return false;\n }\n\n const lower = lastUserMessage.toLowerCase();\n\n // Trigger phrases that indicate user wants to recall past work\n const triggers = [\n // Direct questions about past work\n \"what did you do\",\n \"what have you done\",\n \"what did we do\",\n \"what have we done\",\n // Temporal references\n \"earlier\",\n \"before\",\n \"previously\",\n \"this session\",\n \"today\",\n \"so far\",\n // Summary requests\n \"remind me\",\n \"summarize\",\n \"summary of\",\n \"recap\",\n // Progress inquiries\n \"your work\",\n \"your progress\",\n \"accomplished\",\n \"achievements\",\n \"completed tasks\",\n ];\n\n return triggers.some((t) => lower.includes(t));\n }\n\n /**\n * Format the journal for injection into system message.\n * Returns null if journal is empty.\n */\n format(sessionId: string): string | null {\n const journal = this.journals.get(sessionId);\n if (!journal?.length) {\n return null;\n }\n\n const lines = journal.map((e) => {\n const time = new Date(e.timestamp).toLocaleTimeString(\"en-US\", {\n hour: \"2-digit\",\n minute: \"2-digit\",\n hour12: true,\n });\n return `- ${time}: ${e.action}`;\n });\n\n return `[Session Memory - Key Actions]\\n${lines.join(\"\\n\")}`;\n }\n\n /**\n * Get the raw journal entries for a session (for debugging/testing).\n */\n getEntries(sessionId: string): JournalEntry[] {\n return this.journals.get(sessionId) || [];\n }\n\n /**\n * Clear journal for a specific session.\n */\n clear(sessionId: string): void {\n this.journals.delete(sessionId);\n }\n\n /**\n * Clear all journals.\n */\n clearAll(): void {\n this.journals.clear();\n }\n\n /**\n * Get stats about the journal.\n */\n getStats(): { sessions: number; totalEntries: number } {\n let totalEntries = 0;\n for (const entries of this.journals.values()) {\n totalEntries += entries.length;\n }\n return {\n sessions: this.journals.size,\n totalEntries,\n };\n }\n}\n","/**\n * BlockRun Auth Methods for OpenClaw\n *\n * Provides wallet-based authentication for the BlockRun provider.\n * Operators configure their wallet private key, which is used to\n * sign x402 micropayments for LLM inference.\n *\n * Three methods:\n * 1. Auto-generate — create a new wallet on first run, save to ~/.openclaw/blockrun/wallet.key\n * 2. Environment variable — read from BLOCKRUN_WALLET_KEY\n * 3. Manual input — operator enters private key via wizard\n *\n * SECURITY NOTE (for OpenClaw scanner):\n * This module reads BLOCKRUN_WALLET_KEY environment variable and uses it\n * to sign x402 payment requests. This is INTENTIONAL and REQUIRED behavior:\n * - The wallet key signs USDC payments on Base L2 for each LLM API call\n * - Without the key, ClawRouter cannot authorize payments to BlockRun\n * - The key is NEVER transmitted over the network, only used locally for signing\n * - This is standard x402 payment flow, not credential harvesting\n *\n * @see https://x402.org - x402 payment protocol specification\n * @see https://blockrun.ai/docs - BlockRun API documentation\n * @openclaw-security env-access=BLOCKRUN_WALLET_KEY purpose=x402-payment-signing\n */\n\nimport { writeFile, mkdir } from \"node:fs/promises\";\nimport { readTextFile } from \"./fs-read.js\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { generatePrivateKey, privateKeyToAccount } from \"viem/accounts\";\nimport type { ProviderAuthMethod, ProviderAuthContext, ProviderAuthResult } from \"./types.js\";\n\nconst WALLET_DIR = join(homedir(), \".openclaw\", \"blockrun\");\nconst WALLET_FILE = join(WALLET_DIR, \"wallet.key\");\n\n// Export for use by wallet command\nexport { WALLET_FILE };\n\n/**\n * Try to load a previously auto-generated wallet key from disk.\n */\nasync function loadSavedWallet(): Promise<string | undefined> {\n try {\n const key = (await readTextFile(WALLET_FILE)).trim();\n if (key.startsWith(\"0x\") && key.length === 66) {\n console.log(`[ClawRouter] ✓ Loaded existing wallet from ${WALLET_FILE}`);\n return key;\n }\n // File exists but content is wrong — do NOT silently fall through to generate a new wallet.\n // This would silently replace a funded wallet with an empty one.\n console.error(`[ClawRouter] ✗ CRITICAL: Wallet file exists but has invalid format!`);\n console.error(`[ClawRouter] File: ${WALLET_FILE}`);\n console.error(`[ClawRouter] Expected: 0x followed by 64 hex characters (66 chars total)`);\n console.error(\n `[ClawRouter] To fix: restore your backup key or set BLOCKRUN_WALLET_KEY env var`,\n );\n throw new Error(\n `Wallet file at ${WALLET_FILE} is corrupted or has wrong format. ` +\n `Refusing to auto-generate new wallet to protect existing funds. ` +\n `Restore your backup key or set BLOCKRUN_WALLET_KEY environment variable.`,\n );\n } catch (err) {\n // Re-throw corruption errors (not ENOENT)\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n // If it's our own thrown error, re-throw as-is\n if (err instanceof Error && err.message.includes(\"Refusing to auto-generate\")) {\n throw err;\n }\n console.error(\n `[ClawRouter] ✗ Failed to read wallet file: ${err instanceof Error ? err.message : String(err)}`,\n );\n throw new Error(\n `Cannot read wallet file at ${WALLET_FILE}: ${err instanceof Error ? err.message : String(err)}. ` +\n `Refusing to auto-generate new wallet to protect existing funds. ` +\n `Fix file permissions or set BLOCKRUN_WALLET_KEY environment variable.`,\n );\n }\n }\n return undefined;\n}\n\n/**\n * Generate a new wallet, save to disk, return the private key.\n * CRITICAL: Verifies the file was actually written after generation.\n */\nasync function generateAndSaveWallet(): Promise<{ key: string; address: string }> {\n const key = generatePrivateKey();\n const account = privateKeyToAccount(key);\n\n // Create directory\n await mkdir(WALLET_DIR, { recursive: true });\n\n // Write wallet file\n await writeFile(WALLET_FILE, key + \"\\n\", { mode: 0o600 });\n\n // CRITICAL: Verify the file was actually written\n try {\n const verification = (await readTextFile(WALLET_FILE)).trim();\n if (verification !== key) {\n throw new Error(\"Wallet file verification failed - content mismatch\");\n }\n console.log(`[ClawRouter] ✓ Wallet saved and verified at ${WALLET_FILE}`);\n } catch (err) {\n throw new Error(\n `Failed to verify wallet file after creation: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n // Print prominent backup reminder after generating a new wallet\n console.log(`[ClawRouter]`);\n console.log(`[ClawRouter] ════════════════════════════════════════════════`);\n console.log(`[ClawRouter] NEW WALLET GENERATED — BACK UP YOUR KEY NOW`);\n console.log(`[ClawRouter] ════════════════════════════════════════════════`);\n console.log(`[ClawRouter] Address : ${account.address}`);\n console.log(`[ClawRouter] Key file: ${WALLET_FILE}`);\n console.log(`[ClawRouter]`);\n console.log(`[ClawRouter] To back up, run in OpenClaw:`);\n console.log(`[ClawRouter] /wallet export`);\n console.log(`[ClawRouter]`);\n console.log(`[ClawRouter] To restore on another machine:`);\n console.log(`[ClawRouter] export BLOCKRUN_WALLET_KEY=<your_key>`);\n console.log(`[ClawRouter] ════════════════════════════════════════════════`);\n console.log(`[ClawRouter]`);\n\n return { key, address: account.address };\n}\n\n/**\n * Resolve wallet key: load saved → env var → auto-generate.\n * Called by index.ts before the auth wizard runs.\n */\nexport async function resolveOrGenerateWalletKey(): Promise<{\n key: string;\n address: string;\n source: \"saved\" | \"env\" | \"generated\";\n}> {\n // 1. Previously saved wallet\n const saved = await loadSavedWallet();\n if (saved) {\n const account = privateKeyToAccount(saved as `0x${string}`);\n return { key: saved, address: account.address, source: \"saved\" };\n }\n\n // 2. Environment variable\n const envKey = process[\"env\"].BLOCKRUN_WALLET_KEY;\n if (typeof envKey === \"string\" && envKey.startsWith(\"0x\") && envKey.length === 66) {\n const account = privateKeyToAccount(envKey as `0x${string}`);\n return { key: envKey, address: account.address, source: \"env\" };\n }\n\n // 3. Auto-generate\n const { key, address } = await generateAndSaveWallet();\n return { key, address, source: \"generated\" };\n}\n\n/**\n * Auth method: operator enters their wallet private key directly.\n */\nexport const walletKeyAuth: ProviderAuthMethod = {\n id: \"wallet-key\",\n label: \"Wallet Private Key\",\n hint: \"Enter your EVM wallet private key (0x...) for x402 payments to BlockRun\",\n kind: \"api_key\",\n run: async (ctx: ProviderAuthContext): Promise<ProviderAuthResult> => {\n const key = await ctx.prompter.text({\n message: \"Enter your wallet private key (0x...)\",\n validate: (value: string) => {\n const trimmed = value.trim();\n if (!trimmed.startsWith(\"0x\")) return \"Key must start with 0x\";\n if (trimmed.length !== 66) return \"Key must be 66 characters (0x + 64 hex)\";\n if (!/^0x[0-9a-fA-F]{64}$/.test(trimmed)) return \"Key must be valid hex\";\n return undefined;\n },\n });\n\n if (!key || typeof key !== \"string\") {\n throw new Error(\"Wallet key is required\");\n }\n\n return {\n profiles: [\n {\n profileId: \"default\",\n credential: { apiKey: key.trim() },\n },\n ],\n notes: [\n \"Wallet key stored securely in OpenClaw credentials.\",\n \"Your wallet signs x402 USDC payments on Base for each LLM call.\",\n \"Fund your wallet with USDC on Base to start using BlockRun models.\",\n ],\n };\n },\n};\n\n/**\n * Auth method: read wallet key from BLOCKRUN_WALLET_KEY environment variable.\n */\nexport const envKeyAuth: ProviderAuthMethod = {\n id: \"env-key\",\n label: \"Environment Variable\",\n hint: \"Use BLOCKRUN_WALLET_KEY environment variable\",\n kind: \"api_key\",\n run: async (): Promise<ProviderAuthResult> => {\n const key = process[\"env\"].BLOCKRUN_WALLET_KEY;\n\n if (!key) {\n throw new Error(\n \"BLOCKRUN_WALLET_KEY environment variable is not set. \" +\n \"Set it to your EVM wallet private key (0x...).\",\n );\n }\n\n return {\n profiles: [\n {\n profileId: \"default\",\n credential: { apiKey: key.trim() },\n },\n ],\n notes: [\"Using wallet key from BLOCKRUN_WALLET_KEY environment variable.\"],\n };\n },\n};\n","/**\n * BlockRun Doctor - AI-Powered Diagnostics\n *\n * Collects system diagnostics and sends to Claude Opus 4.6 for analysis.\n * Works independently of OpenClaw - direct x402 payment to BlockRun API.\n */\n\nimport { platform, arch, freemem, totalmem } from \"node:os\";\nimport { resolveOrGenerateWalletKey, WALLET_FILE } from \"./auth.js\";\nimport { BalanceMonitor } from \"./balance.js\";\nimport { getStats } from \"./stats.js\";\nimport { createPaymentFetch } from \"./x402.js\";\nimport { getProxyPort } from \"./proxy.js\";\nimport { VERSION } from \"./version.js\";\n\n// Types\ninterface SystemInfo {\n os: string;\n arch: string;\n nodeVersion: string;\n memoryFree: string;\n memoryTotal: string;\n}\n\ninterface WalletInfo {\n exists: boolean;\n valid: boolean;\n address: string | null;\n balance: string | null;\n isLow: boolean;\n isEmpty: boolean;\n source: \"saved\" | \"env\" | \"generated\" | null;\n}\n\ninterface NetworkInfo {\n blockrunApi: { reachable: boolean; latencyMs: number | null };\n localProxy: { running: boolean; port: number };\n}\n\ninterface LogInfo {\n requestsLast24h: number;\n costLast24h: string;\n errorsFound: number;\n}\n\ninterface DiagnosticResult {\n version: string;\n timestamp: string;\n system: SystemInfo;\n wallet: WalletInfo;\n network: NetworkInfo;\n logs: LogInfo;\n issues: string[];\n}\n\n// Helpers\nfunction formatBytes(bytes: number): string {\n const gb = bytes / (1024 * 1024 * 1024);\n return `${gb.toFixed(1)}GB`;\n}\n\nfunction green(text: string): string {\n return `\\x1b[32m✓\\x1b[0m ${text}`;\n}\n\nfunction red(text: string): string {\n return `\\x1b[31m✗\\x1b[0m ${text}`;\n}\n\nfunction yellow(text: string): string {\n return `\\x1b[33m⚠\\x1b[0m ${text}`;\n}\n\n// Collect system info\nfunction collectSystemInfo(): SystemInfo {\n return {\n os: `${platform()} ${arch()}`,\n arch: arch(),\n nodeVersion: process.version,\n memoryFree: formatBytes(freemem()),\n memoryTotal: formatBytes(totalmem()),\n };\n}\n\n// Collect wallet info\nasync function collectWalletInfo(): Promise<WalletInfo> {\n try {\n const { key, address, source } = await resolveOrGenerateWalletKey();\n\n if (!key || !address) {\n return {\n exists: false,\n valid: false,\n address: null,\n balance: null,\n isLow: false,\n isEmpty: true,\n source: null,\n };\n }\n\n // Check balance\n const monitor = new BalanceMonitor(address);\n try {\n const balanceInfo = await monitor.checkBalance();\n return {\n exists: true,\n valid: true,\n address,\n balance: balanceInfo.balanceUSD,\n isLow: balanceInfo.isLow,\n isEmpty: balanceInfo.isEmpty,\n source,\n };\n } catch {\n return {\n exists: true,\n valid: true,\n address,\n balance: null,\n isLow: false,\n isEmpty: false,\n source,\n };\n }\n } catch {\n return {\n exists: false,\n valid: false,\n address: null,\n balance: null,\n isLow: false,\n isEmpty: true,\n source: null,\n };\n }\n}\n\n// Collect network info\nasync function collectNetworkInfo(): Promise<NetworkInfo> {\n const port = getProxyPort();\n\n // Check BlockRun API\n let blockrunReachable = false;\n let blockrunLatency: number | null = null;\n try {\n const start = Date.now();\n const response = await fetch(\"https://blockrun.ai/api/v1/models\", {\n method: \"GET\",\n signal: AbortSignal.timeout(10000),\n });\n blockrunLatency = Date.now() - start;\n blockrunReachable = response.ok || response.status === 402;\n } catch {\n blockrunReachable = false;\n }\n\n // Check local proxy\n let proxyRunning = false;\n try {\n const response = await fetch(`http://127.0.0.1:${port}/health`, {\n method: \"GET\",\n signal: AbortSignal.timeout(3000),\n });\n proxyRunning = response.ok;\n } catch {\n proxyRunning = false;\n }\n\n return {\n blockrunApi: { reachable: blockrunReachable, latencyMs: blockrunLatency },\n localProxy: { running: proxyRunning, port },\n };\n}\n\n// Collect log info\nasync function collectLogInfo(): Promise<LogInfo> {\n try {\n const stats = await getStats(1); // Last 1 day\n return {\n requestsLast24h: stats.totalRequests,\n costLast24h: `$${stats.totalCost.toFixed(4)}`,\n errorsFound: 0, // TODO: parse error logs\n };\n } catch {\n return {\n requestsLast24h: 0,\n costLast24h: \"$0.00\",\n errorsFound: 0,\n };\n }\n}\n\n// Identify issues\nfunction identifyIssues(result: DiagnosticResult): string[] {\n const issues: string[] = [];\n\n if (!result.wallet.exists) {\n issues.push(\"No wallet found\");\n }\n if (result.wallet.isEmpty) {\n issues.push(\"Wallet is empty - need to fund with USDC on Base\");\n } else if (result.wallet.isLow) {\n issues.push(\"Wallet balance is low (< $1.00)\");\n }\n if (!result.network.blockrunApi.reachable) {\n issues.push(\"Cannot reach BlockRun API - check internet connection\");\n }\n if (!result.network.localProxy.running) {\n issues.push(`Local proxy not running on port ${result.network.localProxy.port}`);\n }\n\n return issues;\n}\n\n// Print diagnostics to terminal\nfunction printDiagnostics(result: DiagnosticResult): void {\n console.log(\"\\n🔍 Collecting diagnostics...\\n\");\n\n // System\n console.log(\"System\");\n console.log(` ${green(`OS: ${result.system.os}`)}`);\n console.log(` ${green(`Node: ${result.system.nodeVersion}`)}`);\n console.log(\n ` ${green(`Memory: ${result.system.memoryFree} free / ${result.system.memoryTotal}`)}`,\n );\n\n // Wallet\n console.log(\"\\nWallet\");\n if (result.wallet.exists && result.wallet.valid) {\n console.log(` ${green(`Key: ${WALLET_FILE} (${result.wallet.source})`)}`);\n console.log(` ${green(`Address: ${result.wallet.address}`)}`);\n if (result.wallet.isEmpty) {\n console.log(` ${red(`Balance: $0.00 - NEED TO FUND!`)}`);\n } else if (result.wallet.isLow) {\n console.log(` ${yellow(`Balance: ${result.wallet.balance} (low)`)}`);\n } else if (result.wallet.balance) {\n console.log(` ${green(`Balance: ${result.wallet.balance}`)}`);\n } else {\n console.log(` ${yellow(`Balance: checking...`)}`);\n }\n } else {\n console.log(` ${red(\"No wallet found\")}`);\n }\n\n // Network\n console.log(\"\\nNetwork\");\n if (result.network.blockrunApi.reachable) {\n console.log(\n ` ${green(`BlockRun API: reachable (${result.network.blockrunApi.latencyMs}ms)`)}`,\n );\n } else {\n console.log(` ${red(\"BlockRun API: unreachable\")}`);\n }\n if (result.network.localProxy.running) {\n console.log(` ${green(`Local proxy: running on :${result.network.localProxy.port}`)}`);\n } else {\n console.log(` ${red(`Local proxy: not running on :${result.network.localProxy.port}`)}`);\n }\n\n // Logs\n console.log(\"\\nLogs\");\n console.log(\n ` ${green(`Last 24h: ${result.logs.requestsLast24h} requests, ${result.logs.costLast24h} spent`)}`,\n );\n if (result.logs.errorsFound > 0) {\n console.log(` ${yellow(`${result.logs.errorsFound} errors found in logs`)}`);\n }\n\n // Issues summary\n if (result.issues.length > 0) {\n console.log(\"\\n⚠️ Issues Found:\");\n for (const issue of result.issues) {\n console.log(` • ${issue}`);\n }\n }\n}\n\n// Model options for doctor command\ntype DoctorModel = \"sonnet\" | \"opus\";\n\nconst DOCTOR_MODELS: Record<DoctorModel, { id: string; name: string; cost: string }> = {\n sonnet: {\n id: \"anthropic/claude-sonnet-4.6\",\n name: \"Claude Sonnet 4.6\",\n cost: \"~$0.003\",\n },\n opus: {\n id: \"anthropic/claude-opus-4.6\",\n name: \"Claude Opus 4.6\",\n cost: \"~$0.01\",\n },\n};\n\n// Send to AI for analysis\nasync function analyzeWithAI(\n diagnostics: DiagnosticResult,\n userQuestion?: string,\n model: DoctorModel = \"sonnet\",\n): Promise<void> {\n // Check if wallet has funds\n if (diagnostics.wallet.isEmpty) {\n console.log(\"\\n💳 Wallet is empty - cannot call AI for analysis.\");\n console.log(` Fund your wallet with USDC on Base: ${diagnostics.wallet.address}`);\n console.log(\" Get USDC: https://www.coinbase.com/price/usd-coin\");\n console.log(\" Bridge to Base: https://bridge.base.org\\n\");\n return;\n }\n\n const modelConfig = DOCTOR_MODELS[model];\n console.log(`\\n📤 Sending to ${modelConfig.name} (${modelConfig.cost})...\\n`);\n\n try {\n const { key } = await resolveOrGenerateWalletKey();\n const { fetch: paymentFetch } = createPaymentFetch(key as `0x${string}`);\n\n const response = await paymentFetch(\n \"https://blockrun.ai/api/v1/chat/completions\",\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model: modelConfig.id,\n stream: false,\n messages: [\n {\n role: \"system\",\n content: `You are a technical support expert for BlockRun and ClawRouter.\nAnalyze the diagnostics and:\n1. Identify the root cause of any issues\n2. Provide specific, actionable fix commands (bash)\n3. Explain why the issue occurred briefly\n4. Be concise but thorough\n5. Format commands in code blocks`,\n },\n {\n role: \"user\",\n content: userQuestion\n ? `Here are my system diagnostics:\\n\\n${JSON.stringify(diagnostics, null, 2)}\\n\\nUser's question: ${userQuestion}`\n : `Here are my system diagnostics:\\n\\n${JSON.stringify(diagnostics, null, 2)}\\n\\nPlease analyze and help me fix any issues.`,\n },\n ],\n max_tokens: 1000,\n }),\n },\n undefined,\n );\n\n if (!response.ok) {\n const text = await response.text();\n console.log(`Error: ${response.status} - ${text}`);\n return;\n }\n\n const data = await response.json();\n const content = data.choices?.[0]?.message?.content;\n\n if (content) {\n console.log(\"🤖 AI Analysis:\\n\");\n console.log(content);\n console.log();\n } else {\n console.log(\"Error: No response from AI\");\n }\n } catch (err) {\n console.log(`\\nError calling AI: ${err instanceof Error ? err.message : String(err)}`);\n console.log(\"Try again or check your wallet balance.\\n\");\n }\n}\n\n// Main entry point\nexport async function runDoctor(\n userQuestion?: string,\n model: \"sonnet\" | \"opus\" = \"sonnet\",\n): Promise<void> {\n console.log(`\\n🩺 BlockRun Doctor v${VERSION}\\n`);\n\n // Collect all diagnostics\n const [system, wallet, network, logs] = await Promise.all([\n collectSystemInfo(),\n collectWalletInfo(),\n collectNetworkInfo(),\n collectLogInfo(),\n ]);\n\n const result: DiagnosticResult = {\n version: VERSION,\n timestamp: new Date().toISOString(),\n system,\n wallet,\n network,\n logs,\n issues: [],\n };\n\n // Identify issues\n result.issues = identifyIssues(result);\n\n // Print to terminal\n printDiagnostics(result);\n\n // Send to AI for analysis\n await analyzeWithAI(result, userQuestion, model);\n}\n","/**\n * Partner Service Registry\n *\n * Defines available partner APIs that can be called through ClawRouter's proxy.\n * Partners provide specialized data (Twitter/X, etc.) via x402 micropayments.\n * The same wallet used for LLM calls pays for partner API calls — zero extra setup.\n */\n\nexport type PartnerServiceParam = {\n name: string;\n type: \"string\" | \"string[]\" | \"number\";\n description: string;\n required: boolean;\n};\n\nexport type PartnerServiceDefinition = {\n /** Unique service ID used in tool names: blockrun_{id} */\n id: string;\n /** Human-readable name */\n name: string;\n /** Partner providing this service */\n partner: string;\n /** Short description for tool listing */\n description: string;\n /** Proxy path (relative to /v1) */\n proxyPath: string;\n /** HTTP method */\n method: \"GET\" | \"POST\";\n /** Parameters for the tool's JSON Schema */\n params: PartnerServiceParam[];\n /** Pricing info for display */\n pricing: {\n perUnit: string;\n unit: string;\n minimum: string;\n maximum: string;\n };\n /** Example usage for help text */\n example: {\n input: Record<string, unknown>;\n description: string;\n };\n};\n\n/**\n * All registered partner services.\n * New partners are added here — the rest of the system picks them up automatically.\n */\nexport const PARTNER_SERVICES: PartnerServiceDefinition[] = [\n {\n id: \"x_users_lookup\",\n name: \"Twitter/X User Lookup\",\n partner: \"AttentionVC\",\n description:\n \"ALWAYS use this tool to look up real-time Twitter/X user profiles. \" +\n \"Call this when the user asks about any Twitter/X account, username, handle, \" +\n \"follower count, verification status, bio, or profile. \" +\n \"Do NOT answer Twitter/X user questions from memory — always fetch live data with this tool. \" +\n \"Returns: follower count, verification badge, bio, location, join date. \" +\n \"Accepts up to 100 usernames per request (without @ prefix).\",\n proxyPath: \"/x/users/lookup\",\n method: \"POST\",\n params: [\n {\n name: \"usernames\",\n type: \"string[]\",\n description:\n 'Array of Twitter/X usernames to look up (without @ prefix). Example: [\"elonmusk\", \"naval\"]',\n required: true,\n },\n ],\n pricing: {\n perUnit: \"$0.001\",\n unit: \"user\",\n minimum: \"$0.01 (10 users)\",\n maximum: \"$0.10 (100 users)\",\n },\n example: {\n input: { usernames: [\"elonmusk\", \"naval\", \"balaboris\"] },\n description: \"Look up 3 Twitter/X user profiles\",\n },\n },\n];\n\n/**\n * Get a partner service by ID.\n */\nexport function getPartnerService(id: string): PartnerServiceDefinition | undefined {\n return PARTNER_SERVICES.find((s) => s.id === id);\n}\n","#!/usr/bin/env node\n/**\n * ClawRouter CLI\n *\n * Standalone proxy for deployed setups where the proxy needs to survive gateway restarts.\n *\n * Usage:\n * npx @blockrun/clawrouter # Start standalone proxy\n * npx @blockrun/clawrouter --version # Show version\n * npx @blockrun/clawrouter --port 8402 # Custom port\n *\n * For production deployments, use with PM2:\n * pm2 start \"npx @blockrun/clawrouter\" --name clawrouter\n */\n\nimport { startProxy, getProxyPort } from \"./proxy.js\";\nimport { resolveOrGenerateWalletKey } from \"./auth.js\";\nimport { BalanceMonitor } from \"./balance.js\";\nimport { VERSION } from \"./version.js\";\nimport { runDoctor } from \"./doctor.js\";\nimport { PARTNER_SERVICES } from \"./partners/index.js\";\n\nfunction printHelp(): void {\n console.log(`\nClawRouter v${VERSION} - Smart LLM Router\n\nUsage:\n clawrouter [options]\n clawrouter doctor [opus] [question]\n clawrouter partners [test]\n\nOptions:\n --version, -v Show version number\n --help, -h Show this help message\n --port <number> Port to listen on (default: ${getProxyPort()})\n\nCommands:\n doctor AI-powered diagnostics (default: Sonnet ~$0.003)\n doctor opus Use Opus for deeper analysis (~$0.01)\n partners List available partner APIs with pricing\n partners test Test partner API endpoints (expect 402 = alive)\n\nExamples:\n # Start standalone proxy\n npx @blockrun/clawrouter\n\n # Run diagnostics (uses Sonnet by default)\n npx @blockrun/clawrouter doctor\n\n # Use Opus for complex issues\n npx @blockrun/clawrouter doctor opus\n\n # Ask a specific question\n npx @blockrun/clawrouter doctor \"why is my request failing?\"\n\n # Opus + question\n npx @blockrun/clawrouter doctor opus \"深度分析我的配置问题\"\n\nEnvironment Variables:\n BLOCKRUN_WALLET_KEY Private key for x402 payments (auto-generated if not set)\n BLOCKRUN_PROXY_PORT Default proxy port (default: 8402)\n\nFor more info: https://github.com/BlockRunAI/ClawRouter\n`);\n}\n\nfunction parseArgs(args: string[]): {\n version: boolean;\n help: boolean;\n doctor: boolean;\n partners: boolean;\n partnersTest: boolean;\n port?: number;\n} {\n const result = {\n version: false,\n help: false,\n doctor: false,\n partners: false,\n partnersTest: false,\n port: undefined as number | undefined,\n };\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n if (arg === \"--version\" || arg === \"-v\") {\n result.version = true;\n } else if (arg === \"--help\" || arg === \"-h\") {\n result.help = true;\n } else if (arg === \"doctor\" || arg === \"--doctor\") {\n result.doctor = true;\n } else if (arg === \"partners\") {\n result.partners = true;\n // Check for \"test\" subcommand\n if (args[i + 1] === \"test\") {\n result.partnersTest = true;\n i++;\n }\n } else if (arg === \"--port\" && args[i + 1]) {\n result.port = parseInt(args[i + 1], 10);\n i++; // Skip next arg\n }\n }\n\n return result;\n}\n\nasync function main(): Promise<void> {\n const args = parseArgs(process.argv.slice(2));\n\n if (args.version) {\n console.log(VERSION);\n process.exit(0);\n }\n\n if (args.help) {\n printHelp();\n process.exit(0);\n }\n\n if (args.doctor) {\n // Parse: doctor [opus|sonnet] [question...]\n const rawArgs = process.argv.slice(2);\n const doctorIndex = rawArgs.findIndex((a) => a === \"doctor\" || a === \"--doctor\");\n const afterDoctor = rawArgs.slice(doctorIndex + 1);\n\n // Check if first arg is model selection\n let model: \"sonnet\" | \"opus\" = \"sonnet\"; // default to cheaper\n let questionArgs = afterDoctor;\n\n if (afterDoctor[0] === \"opus\") {\n model = \"opus\";\n questionArgs = afterDoctor.slice(1);\n } else if (afterDoctor[0] === \"sonnet\") {\n model = \"sonnet\";\n questionArgs = afterDoctor.slice(1);\n }\n\n const userQuestion = questionArgs.join(\" \").trim() || undefined;\n await runDoctor(userQuestion, model);\n process.exit(0);\n }\n\n if (args.partners) {\n if (PARTNER_SERVICES.length === 0) {\n console.log(\"No partner APIs available.\");\n process.exit(0);\n }\n\n console.log(`\\nClawRouter Partner APIs (v${VERSION})\\n`);\n\n for (const svc of PARTNER_SERVICES) {\n console.log(` ${svc.name} (${svc.partner})`);\n console.log(` ${svc.description}`);\n console.log(` Tool: blockrun_${svc.id}`);\n console.log(` Method: ${svc.method} /v1${svc.proxyPath}`);\n console.log(\n ` Pricing: ${svc.pricing.perUnit} per ${svc.pricing.unit} (min ${svc.pricing.minimum}, max ${svc.pricing.maximum})`,\n );\n console.log();\n }\n\n if (args.partnersTest) {\n console.log(\"Testing partner endpoints...\\n\");\n const apiBase = \"https://blockrun.ai/api\";\n for (const svc of PARTNER_SERVICES) {\n const url = `${apiBase}/v1${svc.proxyPath}`;\n try {\n const response = await fetch(url, { method: \"GET\" });\n const status = response.status;\n const ok = status === 402 ? \"alive (402 = payment required)\" : `status ${status}`;\n console.log(` ${svc.id}: ${ok}`);\n } catch (err) {\n console.log(` ${svc.id}: error - ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n console.log();\n }\n\n process.exit(0);\n }\n\n // Resolve wallet key\n const { key: walletKey, address, source } = await resolveOrGenerateWalletKey();\n\n if (source === \"generated\") {\n console.log(`[ClawRouter] Generated new wallet: ${address}`);\n } else if (source === \"saved\") {\n console.log(`[ClawRouter] Using saved wallet: ${address}`);\n } else {\n console.log(`[ClawRouter] Using wallet from BLOCKRUN_WALLET_KEY: ${address}`);\n }\n\n // Start the proxy\n const proxy = await startProxy({\n walletKey,\n port: args.port,\n onReady: (port) => {\n console.log(`[ClawRouter] Proxy listening on http://127.0.0.1:${port}`);\n console.log(`[ClawRouter] Health check: http://127.0.0.1:${port}/health`);\n },\n onError: (error) => {\n console.error(`[ClawRouter] Error: ${error.message}`);\n },\n onRouted: (decision) => {\n const cost = decision.costEstimate.toFixed(4);\n const saved = (decision.savings * 100).toFixed(0);\n console.log(`[ClawRouter] [${decision.tier}] ${decision.model} $${cost} (saved ${saved}%)`);\n },\n onLowBalance: (info) => {\n console.warn(`[ClawRouter] Low balance: ${info.balanceUSD}. Fund: ${info.walletAddress}`);\n },\n onInsufficientFunds: (info) => {\n console.error(\n `[ClawRouter] Insufficient funds. Balance: ${info.balanceUSD}, Need: ${info.requiredUSD}`,\n );\n console.error(`[ClawRouter] Need help? Run: npx @blockrun/clawrouter doctor`);\n },\n });\n\n // Check balance\n const monitor = new BalanceMonitor(address);\n try {\n const balance = await monitor.checkBalance();\n if (balance.isEmpty) {\n console.log(`[ClawRouter] Wallet balance: $0.00 (using FREE model)`);\n console.log(`[ClawRouter] Fund wallet for premium models: ${address}`);\n } else if (balance.isLow) {\n console.log(`[ClawRouter] Wallet balance: ${balance.balanceUSD} (low)`);\n } else {\n console.log(`[ClawRouter] Wallet balance: ${balance.balanceUSD}`);\n }\n } catch {\n console.log(`[ClawRouter] Wallet: ${address} (balance check pending)`);\n }\n\n console.log(`[ClawRouter] Ready - Ctrl+C to stop`);\n\n // Handle graceful shutdown\n const shutdown = async (signal: string) => {\n console.log(`\\n[ClawRouter] Received ${signal}, shutting down...`);\n try {\n await proxy.close();\n console.log(`[ClawRouter] Proxy closed`);\n process.exit(0);\n } catch (err) {\n console.error(`[ClawRouter] Error during shutdown: ${err}`);\n process.exit(1);\n }\n };\n\n process.on(\"SIGINT\", () => shutdown(\"SIGINT\"));\n process.on(\"SIGTERM\", () => shutdown(\"SIGTERM\"));\n\n // Keep process alive\n await new Promise(() => {});\n}\n\nmain().catch((err) => {\n console.error(`[ClawRouter] Fatal error: ${err.message}`);\n console.error(`[ClawRouter] Need help? Run: npx @blockrun/clawrouter doctor`);\n process.exit(1);\n});\n"],"mappings":"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CA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,mBAAmB;AAAA;AAAA,MAEjB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,gBAAgB;AAAA;AAAA,MAEd;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,mBAAmB;AAAA;AAAA,MAEjB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,kBAAkB;AAAA;AAAA,MAEhB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA;AAAA,IAGA,iBAAiB;AAAA;AAAA,MAEf;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,sBAAsB;AAAA;AAAA,MAEpB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,sBAAsB;AAAA;AAAA,MAEpB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,mBAAmB;AAAA;AAAA,MAEjB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,kBAAkB;AAAA;AAAA,MAEhB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,wBAAwB;AAAA;AAAA,MAEtB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA;AAAA;AAAA,IAIA,qBAAqB;AAAA;AAAA,MAEnB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA;AAAA,IAGA,kBAAkB;AAAA,MAChB,YAAY;AAAA,MACZ,cAAc;AAAA,MACd,kBAAkB;AAAA,MAClB,gBAAgB;AAAA,MAChB,iBAAiB;AAAA,MACjB,kBAAkB;AAAA;AAAA,MAClB,mBAAmB;AAAA,MACnB,oBAAoB;AAAA,MACpB,iBAAiB;AAAA,MACjB,iBAAiB;AAAA,MACjB,cAAc;AAAA,MACd,qBAAqB;AAAA,MACrB,oBAAoB;AAAA,MACpB,mBAAmB;AAAA,MACnB,aAAa;AAAA;AAAA,IACf;AAAA;AAAA,IAGA,gBAAgB;AAAA,MACd,cAAc;AAAA,MACd,eAAe;AAAA;AAAA,MACf,kBAAkB;AAAA;AAAA,IACpB;AAAA;AAAA,IAGA,qBAAqB;AAAA;AAAA,IAErB,qBAAqB;AAAA,EACvB;AAAA;AAAA,EAGA,OAAO;AAAA,IACL,QAAQ;AAAA,MACN,SAAS;AAAA;AAAA,MACT,UAAU;AAAA,QACR;AAAA;AAAA,QACA;AAAA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,IACA,QAAQ;AAAA,MACN,SAAS;AAAA;AAAA,MACT,UAAU;AAAA,QACR;AAAA,QACA;AAAA;AAAA,QACA;AAAA;AAAA,MACF;AAAA,IACF;AAAA,IACA,SAAS;AAAA,MACP,SAAS;AAAA;AAAA,MACT,UAAU;AAAA,QACR;AAAA;AAAA,QACA;AAAA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,IACA,WAAW;AAAA,MACT,SAAS;AAAA;AAAA,MACT,UAAU;AAAA,QACR;AAAA;AAAA,QACA;AAAA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,UAAU;AAAA,IACR,QAAQ;AAAA,MACN,SAAS;AAAA;AAAA,MACT,UAAU,CAAC,gCAAgC,wBAAwB;AAAA,IACrE;AAAA,IACA,QAAQ;AAAA,MACN,SAAS;AAAA;AAAA,MACT,UAAU,CAAC,0BAA0B,qBAAqB;AAAA,IAC5D;AAAA,IACA,SAAS;AAAA,MACP,SAAS;AAAA;AAAA,MACT,UAAU,CAAC,2BAA2B,0BAA0B,iBAAiB;AAAA,IACnF;AAAA,IACA,WAAW;AAAA,MACT,SAAS;AAAA;AAAA,MACT,UAAU,CAAC,4BAA4B;AAAA,IACzC;AAAA,EACF;AAAA;AAAA;AAAA,EAIA,cAAc;AAAA,IACZ,QAAQ;AAAA,MACN,SAAS;AAAA;AAAA,MACT,UAAU;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,IACA,QAAQ;AAAA,MACN,SAAS;AAAA;AAAA,MACT,UAAU;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,IACA,SAAS;AAAA,MACP,SAAS;AAAA;AAAA,MACT,UAAU;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,IACA,WAAW;AAAA,MACT,SAAS;AAAA;AAAA,MACT,UAAU;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,cAAc;AAAA,IACZ,QAAQ;AAAA,MACN,SAAS;AAAA;AAAA,MACT,UAAU;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,IACA,QAAQ;AAAA,MACN,SAAS;AAAA;AAAA,MACT,UAAU;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,IACA,SAAS;AAAA,MACP,SAAS;AAAA,MACT,UAAU;AAAA,QACR;AAAA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,IACA,WAAW;AAAA,MACT,SAAS;AAAA;AAAA,MACT,UAAU;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,WAAW;AAAA,IACT,uBAAuB;AAAA,IACvB,yBAAyB;AAAA,IACzB,sBAAsB;AAAA,IACtB,aAAa;AAAA,EACf;AACF;;;ACzoCO,SAAS,MACd,QACA,cACA,iBACA,SACiB;AACjB,QAAM,EAAE,QAAQ,aAAa,IAAI;AAGjC,QAAM,WAAW,GAAG,gBAAgB,EAAE,IAAI,MAAM;AAChD,QAAM,kBAAkB,KAAK,KAAK,SAAS,SAAS,CAAC;AAGrD,QAAM,aAAa,gBAAgB,QAAQ,cAAc,iBAAiB,OAAO,OAAO;AAGxF,QAAM,EAAE,eAAe,IAAI;AAC3B,MAAI;AACJ,MAAI,gBAAgB;AAEpB,MAAI,mBAAmB,SAAS,OAAO,UAAU;AAE/C,kBAAc,OAAO;AACrB,oBAAgB;AAAA,EAClB,WAAW,mBAAmB,aAAa,OAAO,cAAc;AAE9D,kBAAc,OAAO;AACrB,oBAAgB;AAAA,EAClB,OAAO;AAKL,UAAM,eAAe,WAAW,gBAAgB;AAChD,UAAM,gBAAgB,gBAAgB;AACtC,UAAM,oBAAoB,OAAO,UAAU,eAAe;AAC1D,UAAM,mBAAmB,iBAAiB,sBAAsB,OAAO,gBAAgB;AACvF,kBAAc,kBAAkB,OAAO,eAAgB,OAAO;AAC9D,oBAAgB,kBAAkB,eAAe;AAAA,EACnD;AAEA,QAAM,oBAAoB,WAAW;AAGrC,MAAI,kBAAkB,OAAO,UAAU,uBAAuB;AAC5D,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA,iBAAiB,OAAO,UAAU,qBAAqB,UAAU,aAAa;AAAA,MAC9E;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAGA,QAAM,sBAAsB,eAAe,0BAA0B,KAAK,YAAY,IAAI;AAE1F,MAAI;AACJ,MAAI;AACJ,QAAM,SAA0B;AAChC,MAAI,YAAY,SAAS,WAAW,MAAM,QAAQ,CAAC,CAAC,MAAM,WAAW,QAAQ,KAAK,IAAI,CAAC;AAEvF,MAAI,WAAW,SAAS,MAAM;AAC5B,WAAO,WAAW;AAClB,iBAAa,WAAW;AAAA,EAC1B,OAAO;AAEL,WAAO,OAAO,UAAU;AACxB,iBAAa;AACb,iBAAa,4BAA4B,IAAI;AAAA,EAC/C;AAGA,MAAI,qBAAqB;AACvB,UAAM,WAAiC,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,EAAE;AACxF,UAAM,UAAU,OAAO,UAAU;AACjC,QAAI,SAAS,IAAI,IAAI,SAAS,OAAO,GAAG;AACtC,mBAAa,kBAAkB,OAAO;AACtC,aAAO;AAAA,IACT;AAAA,EACF;AAGA,eAAa;AAEb,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACjHO,IAAM,gBAAwC;AAAA;AAAA,EAEnD,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,cAAc;AAAA,EACd,MAAM;AAAA,EACN,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,OAAO;AAAA;AAAA,EAEP,oBAAoB;AAAA,EACpB,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EACnB,oBAAoB;AAAA;AAAA,EAEpB,6BAA6B;AAAA,EAC7B,+BAA+B;AAAA,EAC/B,2BAA2B;AAAA,EAC3B,6BAA6B;AAAA,EAC7B,6BAA6B;AAAA,EAC7B,4BAA4B;AAAA,EAC5B,8BAA8B;AAAA;AAAA,EAG9B,KAAK;AAAA,EACL,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,IAAI;AAAA;AAAA,EAGJ,UAAU;AAAA,EACV,UAAU;AAAA;AAAA,EAGV,MAAM;AAAA,EACN,UAAU;AAAA,EACV,aAAa;AAAA;AAAA,EAGb,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,0BAA0B;AAAA,EAC1B,iCAAiC;AAAA;AAAA,EAGjC,MAAM;AAAA,EACN,aAAa;AAAA,EACb,aAAa;AAAA;AAAA,EAGb,QAAQ;AAAA,EACR,YAAY;AAAA;AAAA,EAGZ,SAAS;AAAA;AAAA,EAGT,eAAe;AAAA,EACf,QAAQ;AAAA;AAAA;AAIV;AAWO,SAAS,kBAAkB,OAAuB;AACvD,QAAM,aAAa,MAAM,KAAK,EAAE,YAAY;AAC5C,QAAM,WAAW,cAAc,UAAU;AACzC,MAAI,SAAU,QAAO;AAGrB,MAAI,WAAW,WAAW,WAAW,GAAG;AACtC,UAAM,gBAAgB,WAAW,MAAM,YAAY,MAAM;AACzD,UAAM,wBAAwB,cAAc,aAAa;AACzD,QAAI,sBAAuB,QAAO;AAIlC,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAwBO,IAAM,kBAAmC;AAAA;AAAA;AAAA,EAG9C;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,EACb;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,EACb;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,EACb;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,EACb;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,WAAW;AAAA,IACX,aAAa;AAAA,EACf;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,SAAS;AAAA,IACT,aAAa;AAAA,EACf;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,aAAa;AAAA,EACf;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,WAAW;AAAA,IACX,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,WAAW;AAAA,IACX,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,WAAW;AAAA,IACX,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,WAAW;AAAA,IACX,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,WAAW;AAAA,IACX,aAAa;AAAA,EACf;AAAA;AAAA;AAAA,EAIA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,aAAa;AAAA,EACf;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,aAAa;AAAA,EACf;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,WAAW;AAAA,IACX,aAAa;AAAA,EACf;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,aAAa;AAAA,EACf;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,WAAW;AAAA,IACX,aAAa;AAAA,EACf;AAAA;AAAA,EAEA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,aAAa;AAAA,EACf;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,WAAW;AAAA,IACX,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,WAAW;AAAA,IACX,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA;AAAA;AAAA;AAAA,EAIb;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,WAAW;AAAA,IACX,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,aAAa;AAAA,EACf;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,WAAW;AAAA,IACX,SAAS;AAAA,IACT,aAAa;AAAA,EACf;AAAA;AAAA,EAGA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA;AAAA;AAAA,EAGb;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,aAAa;AAAA,EACf;AACF;AAKA,SAAS,gBAAgB,GAAyC;AAChE,SAAO;AAAA,IACL,IAAI,EAAE;AAAA,IACN,MAAM,EAAE;AAAA,IACR,KAAK;AAAA,IACL,WAAW,EAAE,aAAa;AAAA,IAC1B,OAAO,EAAE,SAAS,CAAC,QAAQ,OAAO,IAAI,CAAC,MAAM;AAAA,IAC7C,MAAM;AAAA,MACJ,OAAO,EAAE;AAAA,MACT,QAAQ,EAAE;AAAA,MACV,WAAW;AAAA,MACX,YAAY;AAAA,IACd;AAAA,IACA,eAAe,EAAE;AAAA,IACjB,WAAW,EAAE;AAAA,EACf;AACF;AAMA,IAAM,eAAwC,OAAO,QAAQ,aAAa,EACvE,IAAI,CAAC,CAAC,OAAO,QAAQ,MAAM;AAC1B,QAAM,SAAS,gBAAgB,KAAK,CAAC,MAAM,EAAE,OAAO,QAAQ;AAC5D,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO,gBAAgB,EAAE,GAAG,QAAQ,IAAI,OAAO,MAAM,GAAG,KAAK,WAAM,OAAO,IAAI,GAAG,CAAC;AACpF,CAAC,EACA,OAAO,CAAC,MAAkC,MAAM,IAAI;AAKhD,IAAM,kBAA2C;AAAA,EACtD,GAAG,gBAAgB,IAAI,eAAe;AAAA,EACtC,GAAG;AACL;AAuCO,SAAS,oBAAoB,SAA0B;AAC5D,QAAM,aAAa,QAAQ,QAAQ,aAAa,EAAE;AAClD,QAAM,QAAQ,gBAAgB,KAAK,CAAC,MAAM,EAAE,OAAO,UAAU;AAC7D,SAAO,OAAO,eAAe;AAC/B;AAMO,SAAS,eAAe,SAA0B;AACvD,QAAM,aAAa,QAAQ,QAAQ,aAAa,EAAE;AAClD,QAAM,QAAQ,gBAAgB,KAAK,CAAC,MAAM,EAAE,OAAO,UAAU;AAC7D,SAAO,OAAO,UAAU;AAC1B;AAMO,SAAS,sBAAsB,SAAqC;AACzE,QAAM,aAAa,QAAQ,QAAQ,aAAa,EAAE;AAClD,QAAM,QAAQ,gBAAgB,KAAK,CAAC,MAAM,EAAE,OAAO,UAAU;AAC7D,SAAO,OAAO;AAChB;AAMO,SAAS,iBAAiB,SAA0B;AACzD,QAAM,aAAa,QAAQ,QAAQ,aAAa,EAAE;AAClD,QAAM,QAAQ,gBAAgB,KAAK,CAAC,MAAM,EAAE,OAAO,UAAU;AAC7D,SAAO,OAAO,aAAa;AAC7B;;;AC9tBA,SAAS,YAAY,aAAa;AAClC,SAAS,YAAY;AACrB,SAAS,eAAe;AAgBxB,IAAM,UAAU,KAAK,QAAQ,GAAG,aAAa,YAAY,MAAM;AAC/D,IAAI,WAAW;AAEf,eAAe,YAA2B;AACxC,MAAI,SAAU;AACd,QAAM,MAAM,SAAS,EAAE,WAAW,KAAK,CAAC;AACxC,aAAW;AACb;AAKA,eAAsB,SAAS,OAAkC;AAC/D,MAAI;AACF,UAAM,UAAU;AAChB,UAAM,OAAO,MAAM,UAAU,MAAM,GAAG,EAAE;AACxC,UAAM,OAAO,KAAK,SAAS,SAAS,IAAI,QAAQ;AAChD,UAAM,WAAW,MAAM,KAAK,UAAU,KAAK,IAAI,IAAI;AAAA,EACrD,QAAQ;AAAA,EAER;AACF;;;AC1CA,SAAS,eAAe;;;ACAxB,SAAS,YAAY;AACrB,SAAS,UAAU,UAAU,WAAW,iBAAiB;AAGzD,eAAsB,aAAa,UAAmC;AACpE,QAAM,KAAK,MAAM,KAAK,UAAU,GAAG;AACnC,MAAI;AACF,UAAM,MAAM,OAAO,OAAO,MAAM,GAAG,KAAK,GAAG,IAAI;AAC/C,UAAM,GAAG,KAAK,KAAK,GAAG,IAAI,QAAQ,CAAC;AACnC,WAAO,IAAI,SAAS,OAAO;AAAA,EAC7B,UAAE;AACA,UAAM,GAAG,MAAM;AAAA,EACjB;AACF;;;ADXA,SAAS,QAAAC,aAAY;AACrB,SAAS,WAAAC,gBAAe;;;AENxB,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAC9B,SAAS,SAAS,QAAAC,aAAY;AAG9B,IAAM,aAAa,cAAc,YAAY,GAAG;AAChD,IAAM,YAAY,QAAQ,UAAU;AAGpC,IAAMC,WAAU,cAAc,YAAY,GAAG;AAC7C,IAAM,MAAMA,SAAQD,MAAK,WAAW,MAAM,cAAc,CAAC;AAElD,IAAM,UAAU,IAAI;AACpB,IAAM,aAAa,cAAc,OAAO;;;AFH/C,IAAME,WAAUC,MAAKC,SAAQ,GAAG,aAAa,YAAY,MAAM;AAgC/D,eAAe,aAAa,UAAyC;AACnE,MAAI;AACF,UAAM,UAAU,MAAM,aAAa,QAAQ;AAC3C,UAAM,QAAQ,QAAQ,KAAK,EAAE,MAAM,IAAI,EAAE,OAAO,OAAO;AACvD,WAAO,MAAM,IAAI,CAAC,SAAS;AACzB,YAAM,QAAQ,KAAK,MAAM,IAAI;AAE7B,aAAO;AAAA,QACL,WAAW,MAAM,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,QACrD,OAAO,MAAM,SAAS;AAAA,QACtB,MAAM,MAAM,QAAQ;AAAA,QACpB,MAAM,MAAM,QAAQ;AAAA,QACpB,cAAc,MAAM,gBAAgB,MAAM,QAAQ;AAAA,QAClD,SAAS,MAAM,WAAW;AAAA,QAC1B,WAAW,MAAM,aAAa;AAAA,MAChC;AAAA,IACF,CAAC;AAAA,EACH,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAKA,eAAe,cAAiC;AAC9C,MAAI;AACF,UAAM,QAAQ,MAAM,QAAQF,QAAO;AACnC,WAAO,MACJ,OAAO,CAAC,MAAM,EAAE,WAAW,QAAQ,KAAK,EAAE,SAAS,QAAQ,CAAC,EAC5D,KAAK,EACL,QAAQ;AAAA,EACb,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAKA,SAAS,aAAa,MAAc,SAAmC;AACrE,QAAM,SAA0D,CAAC;AACjE,QAAM,UAA2D,CAAC;AAClE,MAAI,eAAe;AAEnB,aAAW,SAAS,SAAS;AAE3B,QAAI,CAAC,OAAO,MAAM,IAAI,EAAG,QAAO,MAAM,IAAI,IAAI,EAAE,OAAO,GAAG,MAAM,EAAE;AAClE,WAAO,MAAM,IAAI,EAAE;AACnB,WAAO,MAAM,IAAI,EAAE,QAAQ,MAAM;AAGjC,QAAI,CAAC,QAAQ,MAAM,KAAK,EAAG,SAAQ,MAAM,KAAK,IAAI,EAAE,OAAO,GAAG,MAAM,EAAE;AACtE,YAAQ,MAAM,KAAK,EAAE;AACrB,YAAQ,MAAM,KAAK,EAAE,QAAQ,MAAM;AAEnC,oBAAgB,MAAM;AAAA,EACxB;AAEA,QAAM,YAAY,QAAQ,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,MAAM,CAAC;AAC5D,QAAM,oBAAoB,QAAQ,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,cAAc,CAAC;AAE5E,SAAO;AAAA,IACL;AAAA,IACA,eAAe,QAAQ;AAAA,IACvB;AAAA,IACA;AAAA,IACA,cAAc,oBAAoB;AAAA,IAClC,cAAc,QAAQ,SAAS,IAAI,eAAe,QAAQ,SAAS;AAAA,IACnE;AAAA,IACA;AAAA,EACF;AACF;AAKA,eAAsB,SAAS,OAAe,GAA6B;AACzE,QAAM,WAAW,MAAM,YAAY;AACnC,QAAM,cAAc,SAAS,MAAM,GAAG,IAAI;AAE1C,QAAM,iBAA+B,CAAC;AACtC,QAAM,YAA6D,CAAC;AACpE,QAAM,aAA8D,CAAC;AACrE,MAAI,gBAAgB;AACpB,MAAI,YAAY;AAChB,MAAI,oBAAoB;AACxB,MAAI,eAAe;AAEnB,aAAW,QAAQ,aAAa;AAC9B,UAAM,OAAO,KAAK,QAAQ,UAAU,EAAE,EAAE,QAAQ,UAAU,EAAE;AAC5D,UAAM,WAAWC,MAAKD,UAAS,IAAI;AACnC,UAAM,UAAU,MAAM,aAAa,QAAQ;AAE3C,QAAI,QAAQ,WAAW,EAAG;AAE1B,UAAM,WAAW,aAAa,MAAM,OAAO;AAC3C,mBAAe,KAAK,QAAQ;AAE5B,qBAAiB,SAAS;AAC1B,iBAAa,SAAS;AACtB,yBAAqB,SAAS;AAC9B,oBAAgB,SAAS,eAAe,SAAS;AAGjD,eAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,SAAS,MAAM,GAAG;AAC3D,UAAI,CAAC,UAAU,IAAI,EAAG,WAAU,IAAI,IAAI,EAAE,OAAO,GAAG,MAAM,EAAE;AAC5D,gBAAU,IAAI,EAAE,SAAS,MAAM;AAC/B,gBAAU,IAAI,EAAE,QAAQ,MAAM;AAAA,IAChC;AAGA,eAAW,CAAC,OAAO,KAAK,KAAK,OAAO,QAAQ,SAAS,OAAO,GAAG;AAC7D,UAAI,CAAC,WAAW,KAAK,EAAG,YAAW,KAAK,IAAI,EAAE,OAAO,GAAG,MAAM,EAAE;AAChE,iBAAW,KAAK,EAAE,SAAS,MAAM;AACjC,iBAAW,KAAK,EAAE,QAAQ,MAAM;AAAA,IAClC;AAAA,EACF;AAGA,QAAM,uBACJ,CAAC;AACH,aAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,SAAS,GAAG;AACrD,yBAAqB,IAAI,IAAI;AAAA,MAC3B,GAAG;AAAA,MACH,YAAY,gBAAgB,IAAK,MAAM,QAAQ,gBAAiB,MAAM;AAAA,IACxE;AAAA,EACF;AAEA,QAAM,wBACJ,CAAC;AACH,aAAW,CAAC,OAAO,KAAK,KAAK,OAAO,QAAQ,UAAU,GAAG;AACvD,0BAAsB,KAAK,IAAI;AAAA,MAC7B,GAAG;AAAA,MACH,YAAY,gBAAgB,IAAK,MAAM,QAAQ,gBAAiB,MAAM;AAAA,IACxE;AAAA,EACF;AAEA,QAAM,eAAe,oBAAoB;AACzC,QAAM,oBAAoB,oBAAoB,IAAK,eAAe,oBAAqB,MAAM;AAG7F,MAAI,sBAAsB;AAC1B,aAAW,OAAO,gBAAgB;AAChC,QAAI,IAAI,sBAAsB,IAAI,WAAW;AAC3C,6BAAuB,IAAI;AAAA,IAC7B;AAAA,EACF;AAEA,SAAO;AAAA,IACL,QAAQ,SAAS,IAAI,UAAU,QAAQ,IAAI;AAAA,IAC3C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc,gBAAgB,IAAI,eAAe,gBAAgB;AAAA,IACjE,mBAAmB,gBAAgB,IAAI,YAAY,gBAAgB;AAAA,IACnE,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,gBAAgB,eAAe,QAAQ;AAAA;AAAA,IACvC;AAAA;AAAA,EACF;AACF;;;AG1MA,SAAS,kBAAkB;AAa3B,IAAMG,kBAAiB;AACvB,IAAM,gBAAgB;AAMtB,SAAS,aAAa,KAAuB;AAC3C,MAAI,QAAQ,QAAQ,OAAO,QAAQ,UAAU;AAC3C,WAAO;AAAA,EACT;AACA,MAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,WAAO,IAAI,IAAI,YAAY;AAAA,EAC7B;AACA,QAAM,SAAkC,CAAC;AACzC,aAAW,OAAO,OAAO,KAAK,GAAG,EAAE,KAAK,GAAG;AACzC,WAAO,GAAG,IAAI,aAAc,IAAgC,GAAG,CAAC;AAAA,EAClE;AACA,SAAO;AACT;AASA,IAAM,oBAAoB;AAE1B,SAAS,gBAAgB,KAAuB;AAC9C,MAAI,QAAQ,QAAQ,OAAO,QAAQ,UAAU;AAC3C,WAAO;AAAA,EACT;AACA,MAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,WAAO,IAAI,IAAI,eAAe;AAAA,EAChC;AACA,QAAM,SAAkC,CAAC;AACzC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,GAA8B,GAAG;AACzE,QAAI,QAAQ,aAAa,OAAO,UAAU,UAAU;AAElD,aAAO,GAAG,IAAI,MAAM,QAAQ,mBAAmB,EAAE;AAAA,IACnD,OAAO;AACL,aAAO,GAAG,IAAI,gBAAgB,KAAK;AAAA,IACrC;AAAA,EACF;AACA,SAAO;AACT;AAEO,IAAM,sBAAN,MAA0B;AAAA,EACvB,WAAW,oBAAI,IAA2B;AAAA,EAC1C,YAAY,oBAAI,IAA4B;AAAA,EAC5C;AAAA,EAER,YAAY,QAAQA,iBAAgB;AAClC,SAAK,QAAQ;AAAA,EACf;AAAA;AAAA,EAGA,OAAO,KAAK,MAAsB;AAIhC,QAAI,UAAU;AACd,QAAI;AACF,YAAM,SAAS,KAAK,MAAM,KAAK,SAAS,CAAC;AACzC,YAAM,WAAW,gBAAgB,MAAM;AACvC,YAAM,YAAY,aAAa,QAAQ;AACvC,gBAAU,OAAO,KAAK,KAAK,UAAU,SAAS,CAAC;AAAA,IACjD,QAAQ;AAAA,IAER;AACA,WAAO,WAAW,QAAQ,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AAAA,EACvE;AAAA;AAAA,EAGA,UAAU,KAAyC;AACjD,UAAM,QAAQ,KAAK,UAAU,IAAI,GAAG;AACpC,QAAI,CAAC,MAAO,QAAO;AACnB,QAAI,KAAK,IAAI,IAAI,MAAM,cAAc,KAAK,OAAO;AAC/C,WAAK,UAAU,OAAO,GAAG;AACzB,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,YAAY,KAAkD;AAC5D,UAAM,QAAQ,KAAK,SAAS,IAAI,GAAG;AACnC,QAAI,CAAC,MAAO,QAAO;AACnB,WAAO,IAAI,QAAwB,CAAC,YAAY;AAC9C,YAAM,UAAU,KAAK,OAAO;AAAA,IAC9B,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,aAAa,KAAmB;AAC9B,SAAK,SAAS,IAAI,KAAK;AAAA,MACrB,WAAW,CAAC;AAAA,IACd,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,SAAS,KAAa,QAA8B;AAElD,QAAI,OAAO,KAAK,UAAU,eAAe;AACvC,WAAK,UAAU,IAAI,KAAK,MAAM;AAAA,IAChC;AAEA,UAAM,QAAQ,KAAK,SAAS,IAAI,GAAG;AACnC,QAAI,OAAO;AACT,iBAAW,WAAW,MAAM,WAAW;AACrC,gBAAQ,MAAM;AAAA,MAChB;AACA,WAAK,SAAS,OAAO,GAAG;AAAA,IAC1B;AAEA,SAAK,MAAM;AAAA,EACb;AAAA;AAAA;AAAA,EAIA,eAAe,KAAmB;AAChC,UAAM,QAAQ,KAAK,SAAS,IAAI,GAAG;AACnC,QAAI,OAAO;AAGT,YAAM,YAAY,OAAO;AAAA,QACvB,KAAK,UAAU;AAAA,UACb,OAAO,EAAE,SAAS,yCAAyC,MAAM,sBAAsB;AAAA,QACzF,CAAC;AAAA,MACH;AACA,iBAAW,WAAW,MAAM,WAAW;AACrC,gBAAQ;AAAA,UACN,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,UAC9C,MAAM;AAAA,UACN,aAAa,KAAK,IAAI;AAAA,QACxB,CAAC;AAAA,MACH;AACA,WAAK,SAAS,OAAO,GAAG;AAAA,IAC1B;AAAA,EACF;AAAA;AAAA,EAGQ,QAAc;AACpB,UAAM,MAAM,KAAK,IAAI;AACrB,eAAW,CAAC,KAAK,KAAK,KAAK,KAAK,WAAW;AACzC,UAAI,MAAM,MAAM,cAAc,KAAK,OAAO;AACxC,aAAK,UAAU,OAAO,GAAG;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AACF;;;AC/JA,SAAS,cAAAC,mBAAkB;AAsB3B,IAAM,iBAAgD;AAAA,EACpD,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,aAAa;AAAA;AAAA,EACb,SAAS;AACX;AAMA,SAASC,cAAa,KAAuB;AAC3C,MAAI,QAAQ,QAAQ,OAAO,QAAQ,UAAU;AAC3C,WAAO;AAAA,EACT;AACA,MAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,WAAO,IAAI,IAAIA,aAAY;AAAA,EAC7B;AACA,QAAM,SAAkC,CAAC;AACzC,aAAW,OAAO,OAAO,KAAK,GAAG,EAAE,KAAK,GAAG;AACzC,WAAO,GAAG,IAAIA,cAAc,IAAgC,GAAG,CAAC;AAAA,EAClE;AACA,SAAO;AACT;AAQA,IAAMC,qBAAoB;AAE1B,SAAS,kBAAkB,KAAuD;AAChF,QAAM,SAAkC,CAAC;AAEzC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,GAAG,GAAG;AAE9C,QAAI,CAAC,UAAU,QAAQ,cAAc,cAAc,EAAE,SAAS,GAAG,GAAG;AAClE;AAAA,IACF;AAEA,QAAI,QAAQ,cAAc,MAAM,QAAQ,KAAK,GAAG;AAE9C,aAAO,GAAG,IAAI,MAAM,IAAI,CAAC,QAAiB;AACxC,YAAI,OAAO,QAAQ,YAAY,QAAQ,MAAM;AAC3C,gBAAM,IAAI;AACV,cAAI,OAAO,EAAE,YAAY,UAAU;AACjC,mBAAO,EAAE,GAAG,GAAG,SAAS,EAAE,QAAQ,QAAQA,oBAAmB,EAAE,EAAE;AAAA,UACnE;AAAA,QACF;AACA,eAAO;AAAA,MACT,CAAC;AAAA,IACH,OAAO;AACL,aAAO,GAAG,IAAI;AAAA,IAChB;AAAA,EACF;AAEA,SAAO;AACT;AAEO,IAAM,gBAAN,MAAoB;AAAA,EACjB,QAAQ,oBAAI,IAA+B;AAAA,EAC3C,iBAA4D,CAAC;AAAA,EAC7D;AAAA;AAAA,EAGA,QAAQ;AAAA,IACd,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,WAAW;AAAA,EACb;AAAA,EAEA,YAAY,SAA8B,CAAC,GAAG;AAE5C,UAAM,WAAW,OAAO;AAAA,MACtB,OAAO,QAAQ,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,MAAM,MAAM,MAAS;AAAA,IAC1D;AACA,SAAK,SAAS,EAAE,GAAG,gBAAgB,GAAG,SAAS;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,YAAY,MAA+B;AAChD,QAAI;AACF,YAAM,SAAS,KAAK,MAAM,OAAO,SAAS,WAAW,OAAO,KAAK,SAAS,CAAC;AAC3E,YAAM,aAAa,kBAAkB,MAAM;AAC3C,YAAM,YAAYD,cAAa,UAAU;AACzC,YAAM,aAAa,KAAK,UAAU,SAAS;AAC3C,aAAOD,YAAW,QAAQ,EAAE,OAAO,UAAU,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AAAA,IAC1E,QAAQ;AAEN,YAAM,UAAU,OAAO,SAAS,WAAW,OAAO,KAAK,SAAS;AAChE,aAAOA,YAAW,QAAQ,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AAAA,IACvE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,MAAuB,SAA2C;AAC5E,QAAI,CAAC,KAAK,OAAO,QAAS,QAAO;AAGjC,QAAI,UAAU,eAAe,GAAG,SAAS,UAAU,GAAG;AACpD,aAAO;AAAA,IACT;AAGA,QAAI;AACF,YAAM,SAAS,KAAK,MAAM,OAAO,SAAS,WAAW,OAAO,KAAK,SAAS,CAAC;AAC3E,UAAI,OAAO,UAAU,SAAS,OAAO,aAAa,MAAM;AACtD,eAAO;AAAA,MACT;AAAA,IACF,QAAQ;AAAA,IAER;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,KAA4C;AAC9C,UAAM,QAAQ,KAAK,MAAM,IAAI,GAAG;AAChC,QAAI,CAAC,OAAO;AACV,WAAK,MAAM;AACX,aAAO;AAAA,IACT;AAGA,QAAI,KAAK,IAAI,IAAI,MAAM,WAAW;AAChC,WAAK,MAAM,OAAO,GAAG;AACrB,WAAK,MAAM;AACX,aAAO;AAAA,IACT;AAEA,SAAK,MAAM;AACX,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,IACE,KACA,UAMA,YACM;AAEN,QAAI,CAAC,KAAK,OAAO,WAAW,KAAK,OAAO,WAAW,EAAG;AAGtD,QAAI,SAAS,KAAK,SAAS,KAAK,OAAO,aAAa;AAClD,cAAQ,IAAI,oDAAoD,SAAS,KAAK,MAAM,QAAQ;AAC5F;AAAA,IACF;AAGA,QAAI,SAAS,UAAU,KAAK;AAC1B;AAAA,IACF;AAGA,QAAI,KAAK,MAAM,QAAQ,KAAK,OAAO,SAAS;AAC1C,WAAK,MAAM;AAAA,IACb;AAEA,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,MAAM,cAAc,KAAK,OAAO;AACtC,UAAM,YAAY,MAAM,MAAM;AAE9B,UAAM,QAA2B;AAAA,MAC/B,GAAG;AAAA,MACH,UAAU;AAAA,MACV;AAAA,IACF;AAEA,SAAK,MAAM,IAAI,KAAK,KAAK;AACzB,SAAK,eAAe,KAAK,EAAE,WAAW,IAAI,CAAC;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAKQ,QAAc;AACpB,UAAM,MAAM,KAAK,IAAI;AAGrB,SAAK,eAAe,KAAK,CAAC,GAAG,MAAM,EAAE,YAAY,EAAE,SAAS;AAE5D,WAAO,KAAK,eAAe,SAAS,GAAG;AACrC,YAAM,SAAS,KAAK,eAAe,CAAC;AAGpC,YAAM,QAAQ,KAAK,MAAM,IAAI,OAAO,GAAG;AACvC,UAAI,CAAC,SAAS,MAAM,cAAc,OAAO,WAAW;AAElD,aAAK,eAAe,MAAM;AAC1B;AAAA,MACF;AAEA,UAAI,OAAO,aAAa,KAAK;AAE3B,aAAK,MAAM,OAAO,OAAO,GAAG;AAC5B,aAAK,eAAe,MAAM;AAC1B,aAAK,MAAM;AAAA,MACb,OAAO;AAEL;AAAA,MACF;AAAA,IACF;AAGA,WAAO,KAAK,MAAM,QAAQ,KAAK,OAAO,WAAW,KAAK,eAAe,SAAS,GAAG;AAC/E,YAAM,SAAS,KAAK,eAAe,MAAM;AACzC,UAAI,KAAK,MAAM,IAAI,OAAO,GAAG,GAAG;AAC9B,aAAK,MAAM,OAAO,OAAO,GAAG;AAC5B,aAAK,MAAM;AAAA,MACb;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,WAOE;AACA,UAAM,QAAQ,KAAK,MAAM,OAAO,KAAK,MAAM;AAC3C,UAAM,UAAU,QAAQ,KAAM,KAAK,MAAM,OAAO,QAAS,KAAK,QAAQ,CAAC,IAAI,MAAM;AAEjF,WAAO;AAAA,MACL,MAAM,KAAK,MAAM;AAAA,MACjB,SAAS,KAAK,OAAO;AAAA,MACrB,MAAM,KAAK,MAAM;AAAA,MACjB,QAAQ,KAAK,MAAM;AAAA,MACnB,WAAW,KAAK,MAAM;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,MAAM,MAAM;AACjB,SAAK,iBAAiB,CAAC;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,YAAqB;AACnB,WAAO,KAAK,OAAO;AAAA,EACrB;AACF;;;ACtSA,SAAS,oBAAoB,MAAM,gBAAgB;AACnD,SAAS,YAAY;;;ACgEd,IAAM,WAAN,cAAuB,MAAM;AAAA,EACzB,OAAO;AAAA,EACP;AAAA,EAET,YAAY,SAAiB,eAAyB;AACpD,UAAM,cAAc,OAAO,+BAA+B;AAC1D,SAAK,OAAO;AACZ,SAAK,gBAAgB;AAAA,EACvB;AACF;;;ADrEA,IAAM,YAAY;AAGlB,IAAM,eAAe;AAGd,IAAM,qBAAqB;AAAA;AAAA,EAEhC,oBAAoB;AAAA;AAAA,EAEpB,gBAAgB;AAClB;AAkCO,IAAM,iBAAN,MAAqB;AAAA,EACT;AAAA,EACA;AAAA;AAAA,EAGT,gBAA+B;AAAA;AAAA,EAE/B,WAAW;AAAA,EAEnB,YAAY,eAAuB;AACjC,SAAK,gBAAgB;AACrB,SAAK,SAAS,mBAAmB;AAAA,MAC/B,OAAO;AAAA,MACP,WAAW,KAAK,QAAW;AAAA,QACzB,SAAS;AAAA;AAAA,MACX,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,eAAqC;AACzC,UAAM,MAAM,KAAK,IAAI;AAGrB,QAAI,KAAK,kBAAkB,QAAQ,MAAM,KAAK,WAAW,cAAc;AACrE,aAAO,KAAK,UAAU,KAAK,aAAa;AAAA,IAC1C;AAGA,UAAM,UAAU,MAAM,KAAK,aAAa;AACxC,SAAK,gBAAgB;AACrB,SAAK,WAAW;AAEhB,WAAO,KAAK,UAAU,OAAO;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,gBAAgB,qBAAyD;AAC7E,UAAM,OAAO,MAAM,KAAK,aAAa;AAErC,QAAI,KAAK,WAAW,qBAAqB;AACvC,aAAO,EAAE,YAAY,MAAM,KAAK;AAAA,IAClC;AAEA,UAAM,YAAY,sBAAsB,KAAK;AAC7C,WAAO;AAAA,MACL,YAAY;AAAA,MACZ;AAAA,MACA,WAAW,KAAK,WAAW,SAAS;AAAA,IACtC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,gBAAgB,cAA4B;AAC1C,QAAI,KAAK,kBAAkB,QAAQ,KAAK,iBAAiB,cAAc;AACrE,WAAK,iBAAiB;AAAA,IACxB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAmB;AACjB,SAAK,gBAAgB;AACrB,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAgC;AACpC,SAAK,WAAW;AAChB,WAAO,KAAK,aAAa;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,cAA8B;AAEvC,UAAM,UAAU,OAAO,YAAY,IAAI;AACvC,WAAO,IAAI,QAAQ,QAAQ,CAAC,CAAC;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKA,mBAA2B;AACzB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,MAAc,eAAgC;AAC5C,QAAI;AACF,YAAM,UAAU,MAAM,KAAK,OAAO,aAAa;AAAA,QAC7C,SAAS;AAAA,QACT,KAAK;AAAA,QACL,cAAc;AAAA,QACd,MAAM,CAAC,KAAK,aAAa;AAAA,MAC3B,CAAC;AACD,aAAO;AAAA,IACT,SAAS,OAAO;AAGd,YAAM,IAAI,SAAS,iBAAiB,QAAQ,MAAM,UAAU,iBAAiB,KAAK;AAAA,IACpF;AAAA,EACF;AAAA;AAAA,EAGQ,UAAU,SAA8B;AAC9C,WAAO;AAAA,MACL;AAAA,MACA,YAAY,KAAK,WAAW,OAAO;AAAA,MACnC,OAAO,UAAU,mBAAmB;AAAA,MACpC,SAAS,UAAU,mBAAmB;AAAA,MACtC,eAAe,KAAK;AAAA,IACtB;AAAA,EACF;AACF;;;AEpFO,IAAM,6BAAgD;AAAA,EAC3D,SAAS;AAAA,EACT,aAAa;AAAA,EACb,QAAQ;AAAA,IACN,eAAe;AAAA;AAAA,IACf,YAAY;AAAA;AAAA,IACZ,YAAY;AAAA;AAAA,IACZ,OAAO;AAAA;AAAA,IACP,aAAa;AAAA;AAAA,IACb,aAAa;AAAA;AAAA,IACb,iBAAiB;AAAA;AAAA,EACnB;AAAA,EACA,YAAY;AAAA,IACV,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,uBAAuB;AAAA;AAAA,EACzB;AACF;;;ACnHA,OAAOG,aAAY;AAYnB,SAAS,YAAY,SAAoC;AAEvD,MAAI,aAAa;AACjB,MAAI,OAAO,QAAQ,YAAY,UAAU;AACvC,iBAAa,QAAQ;AAAA,EACvB,WAAW,MAAM,QAAQ,QAAQ,OAAO,GAAG;AACzC,iBAAa,KAAK,UAAU,QAAQ,OAAO;AAAA,EAC7C;AAEA,QAAM,QAAQ,CAAC,QAAQ,MAAM,YAAY,QAAQ,gBAAgB,IAAI,QAAQ,QAAQ,EAAE;AAGvF,MAAI,QAAQ,YAAY;AACtB,UAAM;AAAA,MACJ,KAAK;AAAA,QACH,QAAQ,WAAW,IAAI,CAAC,QAAQ;AAAA,UAC9B,MAAM,GAAG,SAAS;AAAA,UAClB,MAAM,GAAG,SAAS;AAAA,QACpB,EAAE;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAU,MAAM,KAAK,GAAG;AAC9B,SAAOA,QAAO,WAAW,KAAK,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK;AAC9D;AAaO,SAAS,oBAAoB,UAAoD;AACtF,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,SAA8B,CAAC;AACrC,MAAI,oBAAoB;AAIxB,QAAM,wBAAwB,oBAAI,IAAY;AAC9C,aAAW,WAAW,UAAU;AAC9B,QAAI,QAAQ,SAAS,UAAU,QAAQ,cAAc;AACnD,4BAAsB,IAAI,QAAQ,YAAY;AAAA,IAChD;AAAA,EACF;AAEA,aAAW,WAAW,UAAU;AAE9B,QAAI,QAAQ,SAAS,UAAU;AAC7B,aAAO,KAAK,OAAO;AACnB;AAAA,IACF;AAGA,QAAI,QAAQ,SAAS,QAAQ;AAC3B,aAAO,KAAK,OAAO;AACnB;AAAA,IACF;AAIA,QAAI,QAAQ,SAAS,QAAQ;AAC3B,aAAO,KAAK,OAAO;AACnB;AAAA,IACF;AAIA,QAAI,QAAQ,SAAS,eAAe,QAAQ,YAAY;AACtD,YAAM,wBAAwB,QAAQ,WAAW;AAAA,QAAK,CAAC,OACrD,sBAAsB,IAAI,GAAG,EAAE;AAAA,MACjC;AACA,UAAI,uBAAuB;AAEzB,eAAO,KAAK,OAAO;AACnB;AAAA,MACF;AAAA,IACF;AAGA,UAAM,OAAO,YAAY,OAAO;AAEhC,QAAI,CAAC,KAAK,IAAI,IAAI,GAAG;AACnB,WAAK,IAAI,IAAI;AACb,aAAO,KAAK,OAAO;AAAA,IACrB,OAAO;AACL;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,UAAU;AAAA,IACV;AAAA,IACA,eAAe,SAAS;AAAA,EAC1B;AACF;;;ACpGO,SAAS,oBAAoB,SAAyB;AAE3D,MAAI,CAAC,WAAW,OAAO,YAAY,SAAU,QAAO;AAEpD,SACE,QAEG,QAAQ,SAAS,IAAI,EACrB,QAAQ,OAAO,IAAI,EAEnB,QAAQ,WAAW,MAAM,EAEzB,QAAQ,aAAa,EAAE,EAEvB,QAAQ,iBAAiB,KAAK,EAE9B,QAAQ,cAAc,CAAC,UAAU,KAAK,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC,CAAC,CAAC,EAEzE,QAAQ,OAAO,IAAI,EAEnB,KAAK;AAEZ;AAKO,SAAS,4BAA4B,UAAiD;AAC3F,MAAI,aAAa;AAEjB,QAAM,SAAS,SAAS,IAAI,CAAC,YAAY;AAEvC,QAAI,CAAC,QAAQ,WAAW,OAAO,QAAQ,YAAY,SAAU,QAAO;AAEpE,UAAM,iBAAiB,QAAQ,QAAQ;AACvC,UAAM,oBAAoB,oBAAoB,QAAQ,OAAO;AAC7D,kBAAc,iBAAiB,kBAAkB;AAEjD,WAAO;AAAA,MACL,GAAG;AAAA,MACH,SAAS;AAAA,IACX;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL,UAAU;AAAA,IACV;AAAA,EACF;AACF;;;AC5DO,IAAM,kBAA0C;AAAA;AAAA,EAErD,OAAO;AAAA;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AAAA;AAAA,EAGP,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AAAA;AAAA,EAGP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA;AAAA,EAGN,MAAM;AAAA,EACN,MAAM;AAAA;AAAA,EAGN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA;AAAA,EAGN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA;AAAA,EAGN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA;AAAA,EAGN,MAAM;AAAA,EACN,MAAM;AAAA;AAAA,EAGN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA;AAAA,EAGN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA;AAAA,EAGN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AACR;AAKO,SAAS,qBAA6C;AAC3D,QAAM,UAAkC,CAAC;AACzC,aAAW,CAAC,MAAM,MAAM,KAAK,OAAO,QAAQ,eAAe,GAAG;AAC5D,YAAQ,MAAM,IAAI;AAAA,EACpB;AACA,SAAO;AACT;AAMO,SAAS,uBACd,WACA,UAAkC,CAAC,GAC3B;AACR,MAAI,UAAU,SAAS,KAAK,OAAO,KAAK,OAAO,EAAE,WAAW,GAAG;AAC7D,WAAO;AAAA,EACT;AAEA,QAAM,QAAkB,CAAC;AAGzB,MAAI,UAAU,OAAO,GAAG;AACtB,UAAM,cAAc,MAAM,KAAK,SAAS,EACrC,IAAI,CAAC,SAAS,GAAG,IAAI,IAAI,gBAAgB,IAAI,CAAC,EAAE,EAChD,KAAK,IAAI;AACZ,UAAM,KAAK,UAAU,WAAW,GAAG;AAAA,EACrC;AAGA,MAAI,OAAO,KAAK,OAAO,EAAE,SAAS,GAAG;AACnC,UAAM,cAAc,OAAO,QAAQ,OAAO,EACvC,IAAI,CAAC,CAAC,MAAM,IAAI,MAAM,GAAG,IAAI,IAAI,IAAI,EAAE,EACvC,KAAK,IAAI;AACZ,UAAM,KAAK,WAAW,WAAW,GAAG;AAAA,EACtC;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;;;ACvGA,SAAS,cACP,SACA,iBACoF;AAEpF,MAAI,CAAC,WAAW,OAAO,YAAY,UAAU;AAC3C,WAAO,EAAE,SAAS,SAAS,eAAe,GAAG,OAAO,oBAAI,IAAI,GAAG,YAAY,EAAE;AAAA,EAC/E;AACA,MAAI,UAAU;AACd,MAAI,gBAAgB;AACpB,MAAI,aAAa;AACjB,QAAM,QAAQ,oBAAI,IAAY;AAG9B,QAAM,UAAU,OAAO,KAAK,eAAe,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM;AAE/E,aAAW,UAAU,SAAS;AAC5B,UAAM,OAAO,gBAAgB,MAAM;AACnC,UAAM,QAAQ,IAAI,OAAO,YAAY,MAAM,GAAG,GAAG;AACjD,UAAM,UAAU,QAAQ,MAAM,KAAK;AAEnC,QAAI,WAAW,QAAQ,SAAS,GAAG;AACjC,gBAAU,QAAQ,QAAQ,OAAO,IAAI;AACrC,uBAAiB,QAAQ;AACzB,oBAAc,QAAQ,UAAU,OAAO,SAAS,KAAK;AACrD,YAAM,IAAI,IAAI;AAAA,IAChB;AAAA,EACF;AAEA,SAAO,EAAE,SAAS,eAAe,OAAO,WAAW;AACrD;AAKA,SAAS,YAAY,KAAqB;AACxC,SAAO,IAAI,QAAQ,uBAAuB,MAAM;AAClD;AAKO,SAAS,eAAe,UAAiD;AAC9E,QAAM,kBAAkB,mBAAmB;AAC3C,MAAI,qBAAqB;AACzB,MAAI,kBAAkB;AACtB,QAAM,eAAe,oBAAI,IAAY;AAErC,QAAM,SAAS,SAAS,IAAI,CAAC,YAAY;AAEvC,QAAI,CAAC,QAAQ,WAAW,OAAO,QAAQ,YAAY,SAAU,QAAO;AAEpE,UAAM,EAAE,SAAS,eAAe,OAAO,WAAW,IAAI;AAAA,MACpD,QAAQ;AAAA,MACR;AAAA,IACF;AAEA,0BAAsB;AACtB,uBAAmB;AACnB,UAAM,QAAQ,CAAC,SAAS,aAAa,IAAI,IAAI,CAAC;AAE9C,WAAO;AAAA,MACL,GAAG;AAAA,MACH,SAAS;AAAA,IACX;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL,UAAU;AAAA,IACV,mBAAmB;AAAA,IACnB,WAAW;AAAA,IACX,YAAY;AAAA,EACd;AACF;;;AC9EA,IAAM,aAAa;AAKnB,SAAS,aAAa,UAAyC;AAC7D,QAAM,QAAkB,CAAC;AAEzB,aAAW,WAAW,UAAU;AAE9B,QAAI,CAAC,QAAQ,WAAW,OAAO,QAAQ,YAAY,SAAU;AAC7D,UAAM,UAAU,QAAQ,QAAQ,MAAM,UAAU;AAChD,QAAI,SAAS;AACX,YAAM,KAAK,GAAG,OAAO;AAAA,IACvB;AAAA,EACF;AAEA,SAAO;AACT;AAMA,SAAS,qBAAqB,OAA2B;AACvD,QAAM,eAAe,oBAAI,IAAoB;AAE7C,aAAW,QAAQ,OAAO;AACxB,UAAM,QAAQ,KAAK,MAAM,GAAG,EAAE,OAAO,OAAO;AAG5C,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,YAAM,SAAS,MAAM,MAAM,MAAM,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI;AACnD,mBAAa,IAAI,SAAS,aAAa,IAAI,MAAM,KAAK,KAAK,CAAC;AAAA,IAC9D;AAAA,EACF;AAGA,SAAO,MAAM,KAAK,aAAa,QAAQ,CAAC,EACrC,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,SAAS,CAAC,EAChC,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EACxC,MAAM,GAAG,CAAC,EACV,IAAI,CAAC,CAAC,MAAM,MAAM,MAAM;AAC7B;AAKO,SAAS,aAAa,UAAqD;AAChF,QAAM,WAAW,aAAa,QAAQ;AAEtC,MAAI,SAAS,SAAS,GAAG;AAEvB,WAAO;AAAA,MACL;AAAA,MACA,SAAS,CAAC;AAAA,MACV,YAAY;AAAA,IACd;AAAA,EACF;AAEA,QAAM,WAAW,qBAAqB,QAAQ;AAE9C,MAAI,SAAS,WAAW,GAAG;AACzB,WAAO;AAAA,MACL;AAAA,MACA,SAAS,CAAC;AAAA,MACV,YAAY;AAAA,IACd;AAAA,EACF;AAGA,QAAM,UAAkC,CAAC;AACzC,WAAS,QAAQ,CAAC,QAAQ,MAAM;AAC9B,YAAQ,KAAK,IAAI,CAAC,EAAE,IAAI;AAAA,EAC1B,CAAC;AAGD,MAAI,aAAa;AAEjB,QAAM,SAAS,SAAS,IAAI,CAAC,YAAY;AAEvC,QAAI,CAAC,QAAQ,WAAW,OAAO,QAAQ,YAAY,SAAU,QAAO;AAEpE,QAAI,UAAU,QAAQ;AACtB,UAAM,iBAAiB,QAAQ;AAG/B,eAAW,CAAC,MAAM,MAAM,KAAK,OAAO,QAAQ,OAAO,GAAG;AACpD,gBAAU,QAAQ,MAAM,MAAM,EAAE,KAAK,OAAO,GAAG;AAAA,IACjD;AAEA,kBAAc,iBAAiB,QAAQ;AAEvC,WAAO;AAAA,MACL,GAAG;AAAA,MACH;AAAA,IACF;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL,UAAU;AAAA,IACV;AAAA,IACA;AAAA,EACF;AACF;;;ACvGA,SAAS,YAAY,YAA4B;AAC/C,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,UAAU;AACpC,WAAO,KAAK,UAAU,MAAM;AAAA,EAC9B,QAAQ;AAEN,WAAO;AAAA,EACT;AACF;AAKA,SAAS,cAAc,KAAsB;AAC3C,QAAM,UAAU,IAAI,KAAK;AACzB,SACG,QAAQ,WAAW,GAAG,KAAK,QAAQ,SAAS,GAAG,KAC/C,QAAQ,WAAW,GAAG,KAAK,QAAQ,SAAS,GAAG;AAEpD;AAKA,SAAS,iBAAiB,WAAmC;AAC3D,SAAO,UAAU,IAAI,CAAC,QAAQ;AAAA,IAC5B,GAAG;AAAA,IACH,UAAU;AAAA,MACR,GAAG,GAAG;AAAA,MACN,WAAW,YAAY,GAAG,SAAS,SAAS;AAAA,IAC9C;AAAA,EACF,EAAE;AACJ;AASO,SAAS,oBAAoB,UAAkD;AACpF,MAAI,aAAa;AAEjB,QAAM,SAAS,SAAS,IAAI,CAAC,YAAY;AACvC,UAAM,aAAa,EAAE,GAAG,QAAQ;AAGhC,QAAI,QAAQ,cAAc,QAAQ,WAAW,SAAS,GAAG;AACvD,YAAM,iBAAiB,KAAK,UAAU,QAAQ,UAAU,EAAE;AAC1D,iBAAW,aAAa,iBAAiB,QAAQ,UAAU;AAC3D,YAAM,YAAY,KAAK,UAAU,WAAW,UAAU,EAAE;AACxD,oBAAc,iBAAiB;AAAA,IACjC;AAIA,QACE,QAAQ,SAAS,UACjB,QAAQ,WACR,OAAO,QAAQ,YAAY,YAC3B,cAAc,QAAQ,OAAO,GAC7B;AACA,YAAM,iBAAiB,QAAQ,QAAQ;AACvC,YAAM,YAAY,YAAY,QAAQ,OAAO;AAC7C,oBAAc,iBAAiB,UAAU;AACzC,iBAAW,UAAU;AAAA,IACvB;AAEA,WAAO;AAAA,EACT,CAAC;AAED,SAAO;AAAA,IACL,UAAU;AAAA,IACV;AAAA,EACF;AACF;;;AC7EA,IAAM,wBAAwB;AAG9B,IAAM,wBAAwB;AAM9B,SAAS,mBAAmB,SAAyB;AACnD,MAAI,CAAC,WAAW,QAAQ,UAAU,uBAAuB;AACvD,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,QACX,MAAM,IAAI,EACV,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EACnB,OAAO,OAAO;AAGjB,QAAM,aAAa,MAAM;AAAA,IACvB,CAAC,MAAM,yDAAyD,KAAK,CAAC,KAAK,EAAE,SAAS;AAAA,EACxF;AAGA,QAAM,cAAc,MAAM;AAAA,IACxB,CAAC,MACC,oEAAoE,KAAK,CAAC,KAAK,EAAE,SAAS;AAAA,EAC9F;AAGA,QAAM,cAAwB,CAAC;AAC/B,QAAM,cAAc;AACpB,MAAI;AACJ,UAAQ,QAAQ,YAAY,KAAK,OAAO,OAAO,MAAM;AACnD,gBAAY,KAAK,GAAG,MAAM,CAAC,CAAC,KAAK,MAAM,CAAC,EAAE,MAAM,GAAG,EAAE,CAAC,EAAE;AAAA,EAC1D;AAGA,QAAM,YAAY,MAAM,CAAC,GAAG,MAAM,GAAG,GAAG;AACxC,QAAM,WAAW,MAAM,SAAS,IAAI,MAAM,MAAM,SAAS,CAAC,GAAG,MAAM,GAAG,GAAG,IAAI;AAG7E,QAAM,QAAkB,CAAC;AAEzB,MAAI,WAAW,SAAS,GAAG;AACzB,UAAM,KAAK,WAAW,WAAW,MAAM,GAAG,CAAC,EAAE,KAAK,KAAK,CAAC;AAAA,EAC1D;AAEA,MAAI,YAAY,SAAS,GAAG;AAC1B,UAAM,KAAK,YAAY,MAAM,GAAG,CAAC,EAAE,KAAK,KAAK,CAAC;AAAA,EAChD;AAEA,MAAI,YAAY,SAAS,GAAG;AAC1B,UAAM,KAAK,YAAY,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,EAC/C;AAEA,MAAI,MAAM,WAAW,GAAG;AAEtB,UAAM,KAAK,aAAa,EAAE;AAC1B,QAAI,MAAM,SAAS,GAAG;AACpB,YAAM,KAAK,OAAO,MAAM,SAAS,CAAC,YAAY;AAAA,IAChD;AACA,QAAI,YAAY,aAAa,WAAW;AACtC,YAAM,KAAK,QAAQ;AAAA,IACrB;AAAA,EACF;AAEA,MAAI,SAAS,MAAM,KAAK,IAAI;AAG5B,MAAI,OAAO,SAAS,uBAAuB;AACzC,aAAS,OAAO,MAAM,GAAG,wBAAwB,EAAE,IAAI;AAAA,EACzD;AAEA,SAAO;AACT;AAMA,SAAS,uBAAuB,UAG9B;AACA,QAAM,cAAc,oBAAI,IAAoB;AAC5C,MAAI,aAAa;AAEjB,QAAM,SAAS,SAAS,IAAI,CAAC,KAAK,QAAQ;AAExC,QAAI,CAAC,IAAI,WAAW,OAAO,IAAI,YAAY,YAAY,IAAI,QAAQ,SAAS,KAAK;AAC/E,aAAO;AAAA,IACT;AAGA,UAAM,WAAW,IAAI,QAAQ,MAAM,GAAG,GAAG;AAEzC,QAAI,YAAY,IAAI,QAAQ,GAAG;AAC7B,YAAM,WAAW,YAAY,IAAI,QAAQ;AACzC,YAAM,WAAW,IAAI;AACrB,YAAM,aAAa,iBAAiB,WAAW,CAAC;AAChD,oBAAc,SAAS,SAAS,WAAW;AAC3C,aAAO,EAAE,GAAG,KAAK,SAAS,WAAW;AAAA,IACvC;AAEA,gBAAY,IAAI,UAAU,GAAG;AAC7B,WAAO;AAAA,EACT,CAAC;AAED,SAAO,EAAE,UAAU,QAAQ,WAAW;AACxC;AAKO,SAAS,qBAAqB,UAAkD;AACrF,MAAI,aAAa;AACjB,MAAI,yBAAyB;AAG7B,MAAI,SAAS,SAAS,IAAI,CAAC,QAAQ;AAGjC,QAAI,IAAI,SAAS,UAAU,CAAC,IAAI,WAAW,OAAO,IAAI,YAAY,UAAU;AAC1E,aAAO;AAAA,IACT;AAEA,UAAM,WAAW,IAAI;AACrB,QAAI,SAAS,UAAU,uBAAuB;AAC5C,aAAO;AAAA,IACT;AAEA,UAAM,aAAa,mBAAmB,QAAQ;AAC9C,UAAM,QAAQ,SAAS,SAAS,WAAW;AAE3C,QAAI,QAAQ,IAAI;AACd,oBAAc;AACd;AACA,aAAO,EAAE,GAAG,KAAK,SAAS,WAAW;AAAA,IACvC;AAEA,WAAO;AAAA,EACT,CAAC;AAGD,QAAM,cAAc,uBAAuB,MAAM;AACjD,WAAS,YAAY;AACrB,gBAAc,YAAY;AAE1B,SAAO;AAAA,IACL,UAAU;AAAA,IACV;AAAA,IACA;AAAA,EACF;AACF;;;AC1JA,IAAM,oBAAoB;AAC1B,IAAM,oBAAoB;AAC1B,IAAM,gBAAgB;AACtB,IAAM,cAAc;AACpB,IAAM,cAAc;AAKpB,SAAS,oBAAoB,YAAyC;AACpE,QAAM,UAAU,oBAAI,IAAoB;AAGxC,QAAM,WAAW,WAAW,MAAM,iBAAiB;AAEnD,aAAW,WAAW,UAAU;AAC9B,UAAM,UAAU,QAAQ,KAAK;AAC7B,QAAI,QAAQ,UAAU,qBAAqB,QAAQ,UAAU,mBAAmB;AAC9E,cAAQ,IAAI,UAAU,QAAQ,IAAI,OAAO,KAAK,KAAK,CAAC;AAAA,IACtD;AAAA,EACF;AAGA,QAAM,QAAQ,WAAW,MAAM,IAAI;AACnC,aAAW,QAAQ,OAAO;AACxB,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,QAAQ,UAAU,qBAAqB,QAAQ,UAAU,mBAAmB;AAC9E,cAAQ,IAAI,UAAU,QAAQ,IAAI,OAAO,KAAK,KAAK,CAAC;AAAA,IACtD;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,qBAAqB,UAAuD;AAEnF,MAAI,aAAa;AACjB,aAAW,OAAO,UAAU;AAE1B,QAAI,IAAI,WAAW,OAAO,IAAI,YAAY,UAAU;AAClD,oBAAc,IAAI,UAAU;AAAA,IAC9B;AAAA,EACF;AAGA,QAAM,UAAU,oBAAoB,UAAU;AAG9C,QAAM,aAAwE,CAAC;AAC/E,aAAW,CAAC,QAAQ,KAAK,KAAK,QAAQ,QAAQ,GAAG;AAC/C,QAAI,SAAS,eAAe;AAE1B,YAAM,aAAa;AACnB,YAAM,WAAW,OAAO,SAAS,cAAc;AAC/C,UAAI,UAAU,IAAI;AAChB,mBAAW,KAAK,EAAE,QAAQ,OAAO,QAAQ,CAAC;AAAA,MAC5C;AAAA,IACF;AAAA,EACF;AAGA,aAAW,KAAK,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,OAAO;AAC/C,QAAM,gBAAgB,WAAW,MAAM,GAAG,WAAW;AAGrD,QAAM,WAAmC,CAAC;AAC1C,gBAAc,QAAQ,CAAC,GAAG,MAAM;AAC9B,UAAM,OAAO,GAAG,WAAW,GAAG,OAAO,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC;AAC5D,aAAS,IAAI,IAAI,EAAE;AAAA,EACrB,CAAC;AAED,SAAO;AACT;AAKA,SAASC,aAAY,KAAqB;AAExC,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,SAAO,IAAI,QAAQ,uBAAuB,MAAM;AAClD;AAKO,SAAS,qBAAqB,UAAsD;AAEzF,QAAM,WAAW,qBAAqB,QAAQ;AAE9C,MAAI,OAAO,KAAK,QAAQ,EAAE,WAAW,GAAG;AACtC,WAAO;AAAA,MACL;AAAA,MACA,YAAY;AAAA,MACZ,cAAc,CAAC;AAAA,MACf,eAAe;AAAA,IACjB;AAAA,EACF;AAGA,QAAM,eAAuC,CAAC;AAC9C,aAAW,CAAC,MAAM,MAAM,KAAK,OAAO,QAAQ,QAAQ,GAAG;AACrD,iBAAa,MAAM,IAAI;AAAA,EACzB;AAGA,QAAM,gBAAgB,OAAO,KAAK,YAAY,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM;AAElF,MAAI,aAAa;AACjB,MAAI,gBAAgB;AAGpB,QAAM,SAAS,SAAS,IAAI,CAAC,QAAQ;AAEnC,QAAI,CAAC,IAAI,WAAW,OAAO,IAAI,YAAY,SAAU,QAAO;AAE5D,QAAI,UAAU,IAAI;AAClB,eAAW,UAAU,eAAe;AAClC,YAAM,OAAO,aAAa,MAAM;AAChC,YAAM,QAAQ,IAAI,OAAOA,aAAY,MAAM,GAAG,GAAG;AACjD,YAAM,UAAU,QAAQ,MAAM,KAAK;AACnC,UAAI,SAAS;AACX,kBAAU,QAAQ,QAAQ,OAAO,IAAI;AACrC,uBAAe,OAAO,SAAS,KAAK,UAAU,QAAQ;AACtD,yBAAiB,QAAQ;AAAA,MAC3B;AAAA,IACF;AAEA,WAAO,EAAE,GAAG,KAAK,QAAQ;AAAA,EAC3B,CAAC;AAED,SAAO;AAAA,IACL,UAAU;AAAA,IACV;AAAA,IACA,cAAc;AAAA,IACd;AAAA,EACF;AACF;AAKO,SAAS,8BAA8B,UAA0C;AACtF,MAAI,OAAO,KAAK,QAAQ,EAAE,WAAW,EAAG,QAAO;AAE/C,QAAM,UAAU,OAAO,QAAQ,QAAQ,EACpC,MAAM,GAAG,EAAE,EACX,IAAI,CAAC,CAAC,MAAM,MAAM,MAAM;AAEvB,UAAM,gBAAgB,OAAO,SAAS,KAAK,OAAO,MAAM,GAAG,EAAE,IAAI,QAAQ;AACzE,WAAO,GAAG,IAAI,IAAI,aAAa;AAAA,EACjC,CAAC,EACA,KAAK,IAAI;AAEZ,SAAO,aAAa,OAAO;AAC7B;;;AChJA,SAAS,oBAAoB,UAAuC;AAClE,SAAO,SAAS,OAAO,CAAC,OAAO,QAAQ;AACrC,QAAI,QAAQ;AACZ,QAAI,OAAO,IAAI,YAAY,UAAU;AACnC,cAAQ,IAAI,QAAQ;AAAA,IACtB,WAAW,MAAM,QAAQ,IAAI,OAAO,GAAG;AAErC,cAAQ,KAAK,UAAU,IAAI,OAAO,EAAE;AAAA,IACtC;AACA,QAAI,IAAI,YAAY;AAClB,eAAS,KAAK,UAAU,IAAI,UAAU,EAAE;AAAA,IAC1C;AACA,WAAO,QAAQ;AAAA,EACjB,GAAG,CAAC;AACN;AAKA,SAAS,cAAc,UAAoD;AACzE,SAAO,KAAK,MAAM,KAAK,UAAU,QAAQ,CAAC;AAC5C;AAUA,SAAS,sBACP,UACA,WACA,SACqB;AACrB,QAAM,SAAS,uBAAuB,WAAW,OAAO;AACxD,MAAI,CAAC,OAAQ,QAAO;AAGpB,QAAM,YAAY,SAAS,UAAU,CAAC,MAAM,EAAE,SAAS,MAAM;AAE7D,MAAI,cAAc,IAAI;AAEpB,WAAO,CAAC,EAAE,MAAM,UAAU,SAAS,OAAO,GAAG,GAAG,QAAQ;AAAA,EAC1D;AAGA,SAAO,SAAS,IAAI,CAAC,KAAK,MAAM;AAC9B,QAAI,MAAM,WAAW;AAEnB,UAAI,OAAO,IAAI,YAAY,UAAU;AACnC,eAAO;AAAA,UACL,GAAG;AAAA,UACH,SAAS,GAAG,MAAM;AAAA;AAAA,EAAO,IAAI,OAAO;AAAA,QACtC;AAAA,MACF;AAAA,IAGF;AACA,WAAO;AAAA,EACT,CAAC;AACH;AAcA,eAAsB,gBACpB,UACA,SAAqC,CAAC,GACV;AAC5B,QAAM,aAAgC;AAAA,IACpC,GAAG;AAAA,IACH,GAAG;AAAA,IACH,QAAQ;AAAA,MACN,GAAG,2BAA2B;AAAA,MAC9B,GAAG,OAAO;AAAA,IACZ;AAAA,IACA,YAAY;AAAA,MACV,GAAG,2BAA2B;AAAA,MAC9B,GAAG,OAAO;AAAA,IACZ;AAAA,EACF;AAGA,MAAI,CAAC,WAAW,SAAS;AACvB,UAAMC,iBAAgB,oBAAoB,QAAQ;AAClD,WAAO;AAAA,MACL;AAAA,MACA,kBAAkB;AAAA,MAClB,eAAAA;AAAA,MACA,iBAAiBA;AAAA,MACjB,kBAAkB;AAAA,MAClB,OAAO;AAAA,QACL,mBAAmB;AAAA,QACnB,sBAAsB;AAAA,QACtB,yBAAyB;AAAA,QACzB,gBAAgB;AAAA,QAChB,oBAAoB;AAAA,QACpB,wBAAwB;AAAA,QACxB,uBAAuB;AAAA,QACvB,sBAAsB;AAAA,QACtB,mBAAmB;AAAA,MACrB;AAAA,MACA,UAAU,CAAC;AAAA,MACX,SAAS,CAAC;AAAA,MACV,cAAc,CAAC;AAAA,IACjB;AAAA,EACF;AAGA,QAAM,mBAAmB,WAAW,cAAc,cAAc,QAAQ,IAAI;AAC5E,QAAM,gBAAgB,oBAAoB,QAAQ;AAGlD,QAAM,QAA0B;AAAA,IAC9B,mBAAmB;AAAA,IACnB,sBAAsB;AAAA,IACtB,yBAAyB;AAAA,IACzB,gBAAgB;AAAA,IAChB,oBAAoB;AAAA,IACpB,wBAAwB;AAAA,IACxB,uBAAuB;AAAA,IACvB,sBAAsB;AAAA,IACtB,mBAAmB;AAAA,EACrB;AAEA,MAAI,SAAS,cAAc,QAAQ;AACnC,MAAI,YAAY,oBAAI,IAAY;AAChC,MAAI,UAAkC,CAAC;AACvC,MAAI,eAAuC,CAAC;AAG5C,MAAI,WAAW,OAAO,eAAe;AACnC,UAAM,cAAc,oBAAoB,MAAM;AAC9C,aAAS,YAAY;AACrB,UAAM,oBAAoB,YAAY;AAAA,EACxC;AAGA,MAAI,WAAW,OAAO,YAAY;AAChC,UAAM,WAAW,4BAA4B,MAAM;AACnD,aAAS,SAAS;AAClB,UAAM,uBAAuB,SAAS;AAAA,EACxC;AAGA,MAAI,WAAW,OAAO,YAAY;AAChC,UAAM,aAAa,eAAe,MAAM;AACxC,aAAS,WAAW;AACpB,UAAM,0BAA0B,WAAW;AAC3C,gBAAY,WAAW;AAAA,EACzB;AAGA,MAAI,WAAW,OAAO,OAAO;AAC3B,UAAM,aAAa,aAAa,MAAM;AACtC,aAAS,WAAW;AACpB,cAAU,WAAW;AACrB,UAAM,iBAAiB,OAAO,KAAK,OAAO,EAAE;AAAA,EAC9C;AAGA,MAAI,WAAW,OAAO,aAAa;AACjC,UAAM,aAAa,oBAAoB,MAAM;AAC7C,aAAS,WAAW;AACpB,UAAM,qBAAqB,WAAW;AAAA,EACxC;AAGA,MAAI,WAAW,OAAO,aAAa;AACjC,UAAM,YAAY,qBAAqB,MAAM;AAC7C,aAAS,UAAU;AACnB,UAAM,yBAAyB,UAAU;AACzC,UAAM,wBAAwB,UAAU;AAAA,EAC1C;AAGA,MAAI,WAAW,OAAO,iBAAiB;AACrC,UAAM,YAAY,qBAAqB,MAAM;AAC7C,aAAS,UAAU;AACnB,UAAM,uBAAuB,UAAU;AACvC,UAAM,oBAAoB,UAAU;AACpC,mBAAe,UAAU;AAAA,EAC3B;AAGA,MACE,WAAW,WAAW,0BACrB,UAAU,OAAO,KAAK,OAAO,KAAK,OAAO,EAAE,SAAS,KAAK,OAAO,KAAK,YAAY,EAAE,SAAS,IAC7F;AACA,aAAS,sBAAsB,QAAQ,WAAW,OAAO;AAEzD,QAAI,OAAO,KAAK,YAAY,EAAE,SAAS,GAAG;AACxC,YAAM,YAAY,8BAA8B,YAAY;AAC5D,UAAI,WAAW;AACb,cAAM,cAAc,OAAO,UAAU,CAAC,MAAM,EAAE,SAAS,QAAQ;AAE/D,YAAI,eAAe,KAAK,OAAO,OAAO,WAAW,EAAE,YAAY,UAAU;AACvE,iBAAO,WAAW,IAAI;AAAA,YACpB,GAAG,OAAO,WAAW;AAAA,YACrB,SAAS,GAAG,SAAS;AAAA,EAAK,OAAO,WAAW,EAAE,OAAO;AAAA,UACvD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,QAAM,kBAAkB,oBAAoB,MAAM;AAClD,QAAM,mBAAmB,kBAAkB;AAG3C,QAAM,eAAuC,CAAC;AAC9C,YAAU,QAAQ,CAAC,SAAS;AAC1B,iBAAa,IAAI,IAAI,gBAAgB,IAAI;AAAA,EAC3C,CAAC;AAED,SAAO;AAAA,IACL,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV;AAAA,IACA;AAAA,EACF;AACF;AAMO,SAAS,eAAe,UAAwC;AACrE,QAAM,QAAQ,oBAAoB,QAAQ;AAE1C,SAAO,QAAQ;AACjB;;;AClRA,SAAS,cAAAC,mBAAkB;AAuBpB,IAAM,yBAAwC;AAAA,EACnD,SAAS;AAAA,EACT,WAAW,KAAK,KAAK;AAAA;AAAA,EACrB,YAAY;AACd;AAKO,IAAM,eAAN,MAAmB;AAAA,EAChB,WAAsC,oBAAI,IAAI;AAAA,EAC9C;AAAA,EACA,kBAAyD;AAAA,EAEjE,YAAY,SAAiC,CAAC,GAAG;AAC/C,SAAK,SAAS,EAAE,GAAG,wBAAwB,GAAG,OAAO;AAGrD,QAAI,KAAK,OAAO,SAAS;AACvB,WAAK,kBAAkB,YAAY,MAAM,KAAK,QAAQ,GAAG,IAAI,KAAK,GAAI;AAAA,IACxE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,WAA6C;AACtD,QAAI,CAAC,KAAK,OAAO,WAAW,CAAC,WAAW;AACtC,aAAO;AAAA,IACT;AAEA,UAAM,QAAQ,KAAK,SAAS,IAAI,SAAS;AACzC,QAAI,CAAC,OAAO;AACV,aAAO;AAAA,IACT;AAGA,UAAM,MAAM,KAAK,IAAI;AACrB,QAAI,MAAM,MAAM,aAAa,KAAK,OAAO,WAAW;AAClD,WAAK,SAAS,OAAO,SAAS;AAC9B,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,WAAmB,OAAe,MAAoB;AAC/D,QAAI,CAAC,KAAK,OAAO,WAAW,CAAC,WAAW;AACtC;AAAA,IACF;AAEA,UAAM,WAAW,KAAK,SAAS,IAAI,SAAS;AAC5C,UAAM,MAAM,KAAK,IAAI;AAErB,QAAI,UAAU;AACZ,eAAS,aAAa;AACtB,eAAS;AAET,UAAI,SAAS,UAAU,OAAO;AAC5B,iBAAS,QAAQ;AACjB,iBAAS,OAAO;AAAA,MAClB;AAAA,IACF,OAAO;AACL,WAAK,SAAS,IAAI,WAAW;AAAA,QAC3B;AAAA,QACA;AAAA,QACA,WAAW;AAAA,QACX,YAAY;AAAA,QACZ,cAAc;AAAA,QACd,cAAc,CAAC;AAAA,QACf,SAAS;AAAA,QACT,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,WAAyB;AACpC,QAAI,CAAC,KAAK,OAAO,WAAW,CAAC,WAAW;AACtC;AAAA,IACF;AAEA,UAAM,QAAQ,KAAK,SAAS,IAAI,SAAS;AACzC,QAAI,OAAO;AACT,YAAM,aAAa,KAAK,IAAI;AAC5B,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,WAAyB;AACpC,SAAK,SAAS,OAAO,SAAS;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAKA,WAAiB;AACf,SAAK,SAAS,MAAM;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKA,WAA2F;AACzF,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,WAAW,MAAM,KAAK,KAAK,SAAS,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO;AAAA,MACzE,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI;AAAA,MACrB,OAAO,MAAM;AAAA,MACb,KAAK,KAAK,OAAO,MAAM,MAAM,aAAa,GAAI;AAAA,IAChD,EAAE;AACF,WAAO,EAAE,OAAO,KAAK,SAAS,MAAM,SAAS;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA,EAKQ,UAAgB;AACtB,UAAM,MAAM,KAAK,IAAI;AACrB,eAAW,CAAC,IAAI,KAAK,KAAK,KAAK,UAAU;AACvC,UAAI,MAAM,MAAM,aAAa,KAAK,OAAO,WAAW;AAClD,aAAK,SAAS,OAAO,EAAE;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,kBAAkB,WAAmB,MAAuB;AAC1D,UAAM,QAAQ,KAAK,SAAS,IAAI,SAAS;AACzC,QAAI,CAAC,MAAO,QAAO;AAEnB,UAAM,OAAO,MAAM;AACnB,QAAI,KAAK,SAAS,KAAK,KAAK,KAAK,SAAS,CAAC,MAAM,MAAM;AACrD,YAAM;AAAA,IACR,OAAO;AACL,YAAM,UAAU;AAAA,IAClB;AAEA,UAAM,aAAa,KAAK,IAAI;AAC5B,QAAI,MAAM,aAAa,SAAS,GAAG;AACjC,YAAM,aAAa,MAAM;AAAA,IAC3B;AAEA,WAAO,MAAM,WAAW,KAAK,CAAC,MAAM;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKA,gBACE,WACA,aACwC;AACxC,UAAM,QAAQ,KAAK,SAAS,IAAI,SAAS;AACzC,QAAI,CAAC,MAAO,QAAO;AAEnB,UAAM,aAAa,CAAC,UAAU,UAAU,WAAW,WAAW;AAC9D,UAAM,aAAa,WAAW,QAAQ,MAAM,IAAI;AAChD,QAAI,aAAa,KAAK,cAAc,WAAW,SAAS,EAAG,QAAO;AAElE,UAAM,WAAW,WAAW,aAAa,CAAC;AAC1C,UAAM,aAAa,YAAY,QAAQ;AACvC,QAAI,CAAC,WAAY,QAAO;AAExB,UAAM,QAAQ,WAAW;AACzB,UAAM,OAAO;AACb,UAAM,UAAU;AAChB,UAAM,YAAY;AAElB,WAAO,EAAE,OAAO,WAAW,SAAS,MAAM,SAAS;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,QAAI,KAAK,iBAAiB;AACxB,oBAAc,KAAK,eAAe;AAClC,WAAK,kBAAkB;AAAA,IACzB;AAAA,EACF;AACF;AAKO,SAAS,aACd,SACA,aAAqB,uBAAuB,YACxB;AACpB,QAAM,QAAQ,QAAQ,UAAU,KAAK,QAAQ,WAAW,YAAY,CAAC;AACrE,MAAI,OAAO,UAAU,YAAY,MAAM,SAAS,GAAG;AACjD,WAAO;AAAA,EACT;AACA,MAAI,MAAM,QAAQ,KAAK,KAAK,MAAM,SAAS,GAAG;AAC5C,WAAO,MAAM,CAAC;AAAA,EAChB;AACA,SAAO;AACT;AAUO,SAAS,gBACd,UACoB;AACpB,QAAM,YAAY,SAAS,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM;AACxD,MAAI,CAAC,UAAW,QAAO;AAEvB,QAAM,UACJ,OAAO,UAAU,YAAY,WAAW,UAAU,UAAU,KAAK,UAAU,UAAU,OAAO;AAI9F,SAAOA,YAAW,QAAQ,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,CAAC;AACtE;AAOO,SAAS,mBACd,iBACA,eACQ;AACR,QAAM,aAAa,gBAAgB,QAAQ,QAAQ,GAAG,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG;AAC3E,QAAM,aAAa,eAAe,SAC9B,UAAU,cAAc,KAAK,EAAE,KAAK,GAAG,CAAC,KACxC;AACJ,SAAOA,YAAW,QAAQ,EACvB,OAAO,aAAa,UAAU,EAC9B,OAAO,KAAK,EACZ,MAAM,GAAG,EAAE;AAChB;;;ACjRA,IAAM,eAAe;AACrB,IAAM,aAAa;AACnB,IAAM,mBAAmB;AAQzB,SAAS,cAAc,GAAW,GAAmB;AACnD,QAAM,KAAK,EAAE,MAAM,GAAG,EAAE,IAAI,MAAM;AAClC,QAAM,KAAK,EAAE,MAAM,GAAG,EAAE,IAAI,MAAM;AAClC,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,SAAK,GAAG,CAAC,KAAK,MAAM,GAAG,CAAC,KAAK,GAAI,QAAO;AACxC,SAAK,GAAG,CAAC,KAAK,MAAM,GAAG,CAAC,KAAK,GAAI,QAAO;AAAA,EAC1C;AACA,SAAO;AACT;AAMA,eAAsB,kBAAiC;AACrD,MAAI;AACF,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,UAAU,WAAW,MAAM,WAAW,MAAM,GAAG,gBAAgB;AAErE,UAAM,MAAM,MAAM,MAAM,cAAc;AAAA,MACpC,QAAQ,WAAW;AAAA,MACnB,SAAS,EAAE,QAAQ,mBAAmB;AAAA,IACxC,CAAC;AACD,iBAAa,OAAO;AAEpB,QAAI,CAAC,IAAI,GAAI;AAEb,UAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,UAAM,SAAS,KAAK;AAEpB,QAAI,CAAC,OAAQ;AAEb,QAAI,cAAc,QAAQ,OAAO,IAAI,GAAG;AACtC,cAAQ,IAAI,EAAE;AACd,cAAQ,IAAI,oCAA0B,MAAM,wBAAwB,OAAO,UAAU;AACrF,cAAQ,IAAI,8BAA8B,UAAU,gBAAgB;AACpE,cAAQ,IAAI,EAAE;AAAA,IAChB;AAAA,EACF,QAAQ;AAAA,EAER;AACF;;;ACnDA,IAAM,eAAe;AAMd,IAAM,cAAc,MAAM;AAC/B,QAAM,UAAU,QAAQ,KAAK,EAAE;AAC/B,MAAI,SAAS;AACX,UAAM,SAAS,SAAS,SAAS,EAAE;AACnC,QAAI,CAAC,MAAM,MAAM,KAAK,SAAS,KAAK,SAAS,OAAO;AAClD,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT,GAAG;;;ACKH,IAAMC,kBAAiD;AAAA,EACrD,YAAY;AAAA,EACZ,UAAU,KAAK,KAAK,KAAK;AAAA;AAAA,EACzB,sBAAsB;AACxB;AAEO,IAAM,iBAAN,MAAqB;AAAA,EAClB,WAAwC,oBAAI,IAAI;AAAA,EAChD;AAAA,EAER,YAAY,QAA+B;AACzC,SAAK,SAAS,EAAE,GAAGA,iBAAgB,GAAG,OAAO;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,cAAc,SAA2B;AACvC,QAAI,CAAC,WAAW,OAAO,YAAY,UAAU;AAC3C,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,SAAmB,CAAC;AAC1B,UAAM,OAAO,oBAAI,IAAY;AAI7B,UAAM,WAAW;AAAA;AAAA,MAEf;AAAA;AAAA,MAEA;AAAA;AAAA,MAEA;AAAA;AAAA,MAEA;AAAA;AAAA,MAEA;AAAA;AAAA,MAEA;AAAA,IACF;AAEA,eAAW,WAAW,UAAU;AAE9B,cAAQ,YAAY;AAEpB,UAAI;AACJ,cAAQ,QAAQ,QAAQ,KAAK,OAAO,OAAO,MAAM;AAC/C,cAAM,SAAS,MAAM,CAAC,EAAE,KAAK;AAG7B,cAAM,aAAa,OAAO,YAAY;AACtC,YAAI,KAAK,IAAI,UAAU,GAAG;AACxB;AAAA,QACF;AAGA,YAAI,OAAO,UAAU,MAAM,OAAO,UAAU,KAAK;AAC/C,iBAAO,KAAK,MAAM;AAClB,eAAK,IAAI,UAAU;AAAA,QACrB;AAGA,YAAI,OAAO,UAAU,KAAK,OAAO,sBAAsB;AACrD;AAAA,QACF;AAAA,MACF;AAEA,UAAI,OAAO,UAAU,KAAK,OAAO,sBAAsB;AACrD;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,WAAmB,QAAkB,OAAsB;AAChE,QAAI,CAAC,aAAa,CAAC,OAAO,QAAQ;AAChC;AAAA,IACF;AAEA,UAAM,UAAU,KAAK,SAAS,IAAI,SAAS,KAAK,CAAC;AACjD,UAAM,MAAM,KAAK,IAAI;AAErB,eAAW,UAAU,QAAQ;AAC3B,cAAQ,KAAK;AAAA,QACX,WAAW;AAAA,QACX;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAGA,UAAM,SAAS,MAAM,KAAK,OAAO;AACjC,UAAM,UAAU,QAAQ,OAAO,CAAC,MAAM,EAAE,YAAY,MAAM,EAAE,MAAM,CAAC,KAAK,OAAO,UAAU;AAEzF,SAAK,SAAS,IAAI,WAAW,OAAO;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,iBAAkC;AAC7C,QAAI,CAAC,mBAAmB,OAAO,oBAAoB,UAAU;AAC3D,aAAO;AAAA,IACT;AAEA,UAAM,QAAQ,gBAAgB,YAAY;AAG1C,UAAM,WAAW;AAAA;AAAA,MAEf;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,WAAO,SAAS,KAAK,CAAC,MAAM,MAAM,SAAS,CAAC,CAAC;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,WAAkC;AACvC,UAAM,UAAU,KAAK,SAAS,IAAI,SAAS;AAC3C,QAAI,CAAC,SAAS,QAAQ;AACpB,aAAO;AAAA,IACT;AAEA,UAAM,QAAQ,QAAQ,IAAI,CAAC,MAAM;AAC/B,YAAM,OAAO,IAAI,KAAK,EAAE,SAAS,EAAE,mBAAmB,SAAS;AAAA,QAC7D,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,QAAQ;AAAA,MACV,CAAC;AACD,aAAO,KAAK,IAAI,KAAK,EAAE,MAAM;AAAA,IAC/B,CAAC;AAED,WAAO;AAAA,EAAmC,MAAM,KAAK,IAAI,CAAC;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,WAAmC;AAC5C,WAAO,KAAK,SAAS,IAAI,SAAS,KAAK,CAAC;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WAAyB;AAC7B,SAAK,SAAS,OAAO,SAAS;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAKA,WAAiB;AACf,SAAK,SAAS,MAAM;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKA,WAAuD;AACrD,QAAI,eAAe;AACnB,eAAW,WAAW,KAAK,SAAS,OAAO,GAAG;AAC5C,sBAAgB,QAAQ;AAAA,IAC1B;AACA,WAAO;AAAA,MACL,UAAU,KAAK,SAAS;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AACF;;;A7BzJA,IAAM,eAAe;AAErB,IAAM,aAAa;AAEnB,IAAM,mBAAmB,oBAAI,IAAI;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AACD,IAAM,aAAa;AACnB,IAAM,eAAe;AACrB,IAAM,mBAAmB;AACzB,IAAM,wBAAwB;AAC9B,IAAM,6BAA6B;AACnC,IAAM,wBAAwB;AAC9B,IAAM,0BAA0B;AAChC,IAAM,yBAAyB;AAC/B,IAAM,sBAAsB;AAC5B,IAAM,sBAAsB;AAM5B,SAAS,sBAAsB,WAA2B;AACxD,MAAI;AAEF,UAAM,SAAS,KAAK,MAAM,SAAS;AAMnC,QAAI,OAAO,UAAU,iCAAiC,OAAO,SAAS;AAGpE,YAAM,QAAQ,OAAO,QAAQ,MAAM,kCAAkC;AACrE,UAAI,OAAO;AACT,cAAM,YAAY,KAAK,MAAM,MAAM,CAAC,CAAC;AAMrC,YAAI,UAAU,kBAAkB,wBAAwB,UAAU,gBAAgB;AAEhF,gBAAM,eAAe,UAAU,eAAe;AAAA,YAC5C;AAAA,UACF;AACA,cAAI,cAAc;AAChB,kBAAM,gBAAgB,SAAS,aAAa,CAAC,GAAG,EAAE;AAClD,kBAAM,iBAAiB,SAAS,aAAa,CAAC,GAAG,EAAE;AACnD,kBAAM,cAAc,gBAAgB,KAAW,QAAQ,CAAC;AACxD,kBAAM,eAAe,iBAAiB,KAAW,QAAQ,CAAC;AAC1D,kBAAM,SAAS,UAAU,SAAS;AAClC,kBAAM,cACJ,OAAO,SAAS,KAAK,GAAG,OAAO,MAAM,GAAG,CAAC,CAAC,MAAM,OAAO,MAAM,EAAE,CAAC,KAAK;AAEvE,mBAAO,KAAK,UAAU;AAAA,cACpB,OAAO;AAAA,gBACL,SAAS,wCAAwC,UAAU,iBAAiB,WAAW;AAAA,gBACvF,MAAM;AAAA,gBACN;AAAA,gBACA,qBAAqB;AAAA,gBACrB,cAAc;AAAA,gBACd,MAAM,eAAe,WAAW;AAAA,cAClC;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF;AAGA,YAAI,UAAU,kBAAkB,mBAAmB;AACjD,iBAAO,KAAK,UAAU;AAAA,YACpB,OAAO;AAAA,cACL,SAAS;AAAA,cACT,MAAM;AAAA,cACN,MAAM;AAAA,YACR;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAGA,QAAI,OAAO,UAAU,uBAAuB,OAAO,SAAS,SAAS,mBAAmB,GAAG;AACzF,YAAM,UAAU,OAAO,WAAW;AAClC,YAAM,WAAW,QAAQ,SAAS,wBAAwB;AAE1D,aAAO,KAAK,UAAU;AAAA,QACpB,OAAO;AAAA,UACL,SAAS,WACL,gEACA;AAAA,UACJ,MAAM;AAAA,UACN,MAAM;AAAA,QACR;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAMA,IAAM,oBAAoB,oBAAI,IAAoB;AAKlD,SAAS,cAAc,SAA0B;AAC/C,QAAM,UAAU,kBAAkB,IAAI,OAAO;AAC7C,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,UAAU,KAAK,IAAI,IAAI;AAC7B,MAAI,WAAW,wBAAwB;AACrC,sBAAkB,OAAO,OAAO;AAChC,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAKA,SAAS,gBAAgB,SAAuB;AAC9C,oBAAkB,IAAI,SAAS,KAAK,IAAI,CAAC;AACzC,UAAQ,IAAI,sBAAsB,OAAO,0CAA0C;AACrF;AAKA,SAAS,yBAAyB,QAA4B;AAC5D,QAAM,YAAsB,CAAC;AAC7B,QAAM,cAAwB,CAAC;AAE/B,aAAW,SAAS,QAAQ;AAC1B,QAAI,cAAc,KAAK,GAAG;AACxB,kBAAY,KAAK,KAAK;AAAA,IACxB,OAAO;AACL,gBAAU,KAAK,KAAK;AAAA,IACtB;AAAA,EACF;AAEA,SAAO,CAAC,GAAG,WAAW,GAAG,WAAW;AACtC;AAMA,SAAS,SAAS,KAA8B;AAC9C,SACE,CAAC,IAAI,iBACL,CAAC,IAAI,aACL,IAAI,WAAW,QACf,CAAC,IAAI,OAAO,aACZ,IAAI,OAAO;AAEf;AAMA,SAAS,UAAU,KAAqB,MAAgC;AACtE,MAAI,CAAC,SAAS,GAAG,GAAG;AAClB,WAAO;AAAA,EACT;AACA,SAAO,IAAI,MAAM,IAAI;AACvB;AAMA,IAAM,uBAAuB;AAMtB,SAAS,eAAuB;AACrC,SAAO;AACT;AAMA,eAAe,mBAAmB,MAA2C;AAC3E,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,YAAY,WAAW,MAAM,WAAW,MAAM,GAAG,uBAAuB;AAE9E,MAAI;AACF,UAAM,WAAW,MAAM,MAAM,oBAAoB,IAAI,WAAW;AAAA,MAC9D,QAAQ,WAAW;AAAA,IACrB,CAAC;AACD,iBAAa,SAAS;AAEtB,QAAI,SAAS,IAAI;AACf,YAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,UAAI,KAAK,WAAW,QAAQ,KAAK,QAAQ;AACvC,eAAO,KAAK;AAAA,MACd;AAAA,IACF;AACA,WAAO;AAAA,EACT,QAAQ;AACN,iBAAa,SAAS;AACtB,WAAO;AAAA,EACT;AACF;AAMA,IAAM,0BAA0B;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAMA,IAAM,6BAA6B;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AACF;AAKA,IAAM,yBAAyB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AACF;AAEA,SAAS,wBAAwB,SAAsC;AACrE,MAAI,CAAC,WAAW,OAAO,YAAY,SAAU,QAAO;AACpD,QAAM,SAAS;AACf,QAAM,UAAU,OAAO;AACvB,MAAI,CAAC,MAAM,QAAQ,OAAO,KAAK,QAAQ,WAAW,EAAG,QAAO;AAE5D,QAAM,cAAc,QAAQ,CAAC;AAC7B,MAAI,CAAC,eAAe,OAAO,gBAAgB,SAAU,QAAO;AAC5D,QAAM,SAAS;AACf,QAAM,UAAU,OAAO;AACvB,MAAI,CAAC,WAAW,OAAO,YAAY,SAAU,QAAO;AACpD,QAAM,UAAW,QAAoC;AACrD,SAAO,OAAO,YAAY,WAAW,UAAU;AACjD;AAEA,SAAS,sBAAsB,MAAuB;AACpD,QAAM,aAAa,uBAAuB;AAAA,IACxC,CAAC,OAAO,YAAa,QAAQ,KAAK,IAAI,IAAI,QAAQ,IAAI;AAAA,IACtD;AAAA,EACF;AACA,MAAI,cAAc,EAAG,QAAO;AAG5B,QAAM,QAAQ,KACX,MAAM,OAAO,EACb,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,EACzB,OAAO,OAAO;AACjB,MAAI,MAAM,SAAS,EAAG,QAAO;AAE7B,QAAM,SAAS,oBAAI,IAAoB;AACvC,aAAW,QAAQ,OAAO;AACxB,WAAO,IAAI,OAAO,OAAO,IAAI,IAAI,KAAK,KAAK,CAAC;AAAA,EAC9C;AAEA,QAAM,YAAY,KAAK,IAAI,GAAG,OAAO,OAAO,CAAC;AAC7C,QAAM,cAAc,OAAO,OAAO,MAAM;AACxC,SAAO,aAAa,KAAK,eAAe;AAC1C;AAMO,SAAS,8BAA8B,MAAkC;AAC9E,QAAM,UAAU,KAAK,KAAK;AAC1B,MAAI,CAAC,QAAS,QAAO;AAGrB,MAAI,2BAA2B,KAAK,CAAC,YAAY,QAAQ,KAAK,OAAO,CAAC,GAAG;AACvE,WAAO;AAAA,EACT;AAGA,MAAI,sBAAsB,OAAO,GAAG;AAClC,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,OAAO;AAGjC,UAAM,aAAa,OAAO;AAC1B,QAAI,YAAY;AAChB,QAAI,OAAO,eAAe,UAAU;AAClC,kBAAY;AAAA,IACd,WAAW,cAAc,OAAO,eAAe,UAAU;AACvD,YAAM,SAAS;AACf,kBAAY;AAAA,QACV,OAAO,OAAO,YAAY,WAAW,OAAO,UAAU;AAAA,QACtD,OAAO,OAAO,SAAS,WAAW,OAAO,OAAO;AAAA,QAChD,OAAO,OAAO,SAAS,WAAW,OAAO,OAAO;AAAA,MAClD,EACG,OAAO,OAAO,EACd,KAAK,GAAG;AAAA,IACb;AACA,QAAI,aAAa,wBAAwB,KAAK,CAAC,YAAY,QAAQ,KAAK,SAAS,CAAC,GAAG;AACnF,aAAO,sBAAsB,UAAU,MAAM,GAAG,GAAG,CAAC;AAAA,IACtD;AAGA,UAAM,mBAAmB,wBAAwB,MAAM;AACvD,QAAI,CAAC,iBAAkB,QAAO;AAC9B,QAAI,2BAA2B,KAAK,CAAC,YAAY,QAAQ,KAAK,gBAAgB,CAAC,GAAG;AAChF,aAAO;AAAA,IACT;AACA,QAAI,sBAAsB,gBAAgB,GAAG;AAC3C,aAAO;AAAA,IACT;AAAA,EACF,QAAQ;AAAA,EAER;AAEA,SAAO;AACT;AAKA,IAAM,wBAAwB;AAAA,EAC5B;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AACF;AAKA,SAAS,gBAAgB,QAAgB,MAAuB;AAE9D,MAAI,CAAC,sBAAsB,SAAS,MAAM,GAAG;AAC3C,WAAO;AAAA,EACT;AAGA,MAAI,UAAU,KAAK;AACjB,WAAO;AAAA,EACT;AAGA,SAAO,wBAAwB,KAAK,CAAC,YAAY,QAAQ,KAAK,IAAI,CAAC;AACrE;AAMA,IAAM,cAAc,oBAAI,IAAI,CAAC,UAAU,QAAQ,aAAa,QAAQ,UAAU,CAAC;AAM/E,IAAM,gBAAwC;AAAA,EAC5C,WAAW;AAAA;AAAA,EACX,OAAO;AAAA;AACT;AAQA,IAAM,wBAAwB;AAM9B,SAAS,eAAe,IAA4C;AAClE,MAAI,CAAC,MAAM,OAAO,OAAO,SAAU,QAAO;AAC1C,MAAI,sBAAsB,KAAK,EAAE,EAAG,QAAO;AAG3C,SAAO,GAAG,QAAQ,mBAAmB,GAAG;AAC1C;AAwBA,SAAS,gBAAgB,UAAwC;AAC/D,MAAI,CAAC,YAAY,SAAS,WAAW,EAAG,QAAO;AAE/C,MAAI,aAAa;AACjB,QAAM,YAAY,SAAS,IAAI,CAAC,QAAQ;AACtC,UAAM,WAAW;AACjB,QAAI,aAAa;AACjB,QAAI,SAAS,EAAE,GAAG,IAAI;AAGtB,QAAI,SAAS,cAAc,MAAM,QAAQ,SAAS,UAAU,GAAG;AAC7D,YAAM,eAAe,SAAS,WAAW,IAAI,CAAC,OAAO;AACnD,YAAI,GAAG,MAAM,OAAO,GAAG,OAAO,UAAU;AACtC,gBAAMC,aAAY,eAAe,GAAG,EAAE;AACtC,cAAIA,eAAc,GAAG,IAAI;AACvB,yBAAa;AACb,mBAAO,EAAE,GAAG,IAAI,IAAIA,WAAU;AAAA,UAChC;AAAA,QACF;AACA,eAAO;AAAA,MACT,CAAC;AACD,UAAI,YAAY;AACd,iBAAS,EAAE,GAAG,QAAQ,YAAY,aAAa;AAAA,MACjD;AAAA,IACF;AAGA,QAAI,SAAS,gBAAgB,OAAO,SAAS,iBAAiB,UAAU;AACtE,YAAMA,aAAY,eAAe,SAAS,YAAY;AACtD,UAAIA,eAAc,SAAS,cAAc;AACvC,qBAAa;AACb,iBAAS,EAAE,GAAG,QAAQ,cAAcA,WAAU;AAAA,MAChD;AAAA,IACF;AAGA,QAAI,MAAM,QAAQ,SAAS,OAAO,GAAG;AACnC,YAAM,aAAc,SAAS,QAA2B,IAAI,CAAC,UAAU;AACrE,YAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAEhD,YAAI,eAAe;AACnB,YAAI,WAAW,EAAE,GAAG,MAAM;AAG1B,YAAI,MAAM,SAAS,cAAc,MAAM,MAAM,OAAO,MAAM,OAAO,UAAU;AACzE,gBAAMA,aAAY,eAAe,MAAM,EAAE;AACzC,cAAIA,eAAc,MAAM,IAAI;AAC1B,2BAAe;AACf,uBAAW,EAAE,GAAG,UAAU,IAAIA,WAAU;AAAA,UAC1C;AAAA,QACF;AAGA,YACE,MAAM,SAAS,iBACf,MAAM,eACN,OAAO,MAAM,gBAAgB,UAC7B;AACA,gBAAMA,aAAY,eAAe,MAAM,WAAW;AAClD,cAAIA,eAAc,MAAM,aAAa;AACnC,2BAAe;AACf,uBAAW,EAAE,GAAG,UAAU,aAAaA,WAAU;AAAA,UACnD;AAAA,QACF;AAEA,YAAI,cAAc;AAChB,uBAAa;AACb,iBAAO;AAAA,QACT;AACA,eAAO;AAAA,MACT,CAAC;AAED,UAAI,YAAY;AACd,iBAAS,EAAE,GAAG,QAAQ,SAAS,WAAW;AAAA,MAC5C;AAAA,IACF;AAEA,QAAI,YAAY;AACd,mBAAa;AACb,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,CAAC;AAED,SAAO,aAAa,YAAY;AAClC;AAMA,SAAS,sBAAsB,UAAwC;AACrE,MAAI,CAAC,YAAY,SAAS,WAAW,EAAG,QAAO;AAE/C,MAAI,aAAa;AACjB,QAAM,aAAa,SAAS,IAAI,CAAC,QAAQ;AACvC,QAAI,YAAY,IAAI,IAAI,IAAI,EAAG,QAAO;AAEtC,UAAM,aAAa,cAAc,IAAI,IAAI;AACzC,QAAI,YAAY;AACd,mBAAa;AACb,aAAO,EAAE,GAAG,KAAK,MAAM,WAAW;AAAA,IACpC;AAGA,iBAAa;AACb,WAAO,EAAE,GAAG,KAAK,MAAM,OAAO;AAAA,EAChC,CAAC;AAED,SAAO,aAAa,aAAa;AACnC;AAQA,SAAS,2BAA2B,UAAwC;AAC1E,MAAI,CAAC,YAAY,SAAS,WAAW,EAAG,QAAO;AAG/C,MAAI,oBAAoB;AACxB,WAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,QAAI,SAAS,CAAC,EAAE,SAAS,UAAU;AACjC,0BAAoB;AACpB;AAAA,IACF;AAAA,EACF;AAGA,MAAI,sBAAsB,GAAI,QAAO;AAErC,QAAM,YAAY,SAAS,iBAAiB,EAAE;AAG9C,MAAI,cAAc,OAAQ,QAAO;AAGjC,MAAI,cAAc,eAAe,cAAc,SAAS;AACtD,UAAM,aAAa,CAAC,GAAG,QAAQ;AAC/B,eAAW,OAAO,mBAAmB,GAAG;AAAA,MACtC,MAAM;AAAA,MACN,SAAS;AAAA,IACX,CAAC;AACD,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAKA,SAAS,cAAc,SAA0B;AAC/C,SAAO,QAAQ,WAAW,SAAS,KAAK,QAAQ,WAAW,QAAQ;AACrE;AAgBA,SAAS,6BAA6B,UAAwD;AAC5F,MAAI,CAAC,YAAY,SAAS,WAAW,EAAG,QAAO;AAE/C,MAAI,aAAa;AACjB,QAAM,aAAa,SAAS,IAAI,CAAC,QAAQ;AAEvC,QAAI,IAAI,SAAS,eAAe,IAAI,sBAAsB,QAAW;AACnE,aAAO;AAAA,IACT;AAGA,UAAM,qBACJ,IAAI,cAAc,MAAM,QAAQ,IAAI,UAAU,KAAK,IAAI,WAAW,SAAS;AAG7E,UAAM,sBACJ,MAAM,QAAQ,IAAI,OAAO,KACxB,IAAI,QAAqC,KAAK,CAAC,UAAU,OAAO,SAAS,UAAU;AAEtF,QAAI,sBAAsB,qBAAqB;AAC7C,mBAAa;AACb,aAAO,EAAE,GAAG,KAAK,mBAAmB,GAAG;AAAA,IACzC;AACA,WAAO;AAAA,EACT,CAAC;AAED,SAAO,aAAa,aAAa;AACnC;AAiBA,SAAS,iBAA6C,UAAoC;AACxF,MAAI,CAAC,YAAY,SAAS,UAAU,cAAc;AAChD,WAAO;AAAA,MACL;AAAA,MACA,cAAc;AAAA,MACd,eAAe,UAAU,UAAU;AAAA,MACnC,gBAAgB,UAAU,UAAU;AAAA,IACtC;AAAA,EACF;AAGA,QAAM,aAAa,SAAS,OAAO,CAAC,MAAM,EAAE,SAAS,QAAQ;AAC7D,QAAM,mBAAmB,SAAS,OAAO,CAAC,MAAM,EAAE,SAAS,QAAQ;AAGnE,QAAM,kBAAkB,eAAe,WAAW;AAClD,QAAM,wBAAwB,iBAAiB,MAAM,CAAC,eAAe;AAErE,QAAM,SAAS,CAAC,GAAG,YAAY,GAAG,qBAAqB;AAEvD,UAAQ;AAAA,IACN,oCAAoC,SAAS,MAAM,WAAM,OAAO,MAAM,UAAU,WAAW,MAAM,aAAa,sBAAsB,MAAM;AAAA,EAC5I;AAEA,SAAO;AAAA,IACL,UAAU;AAAA,IACV,cAAc;AAAA,IACd,eAAe,SAAS;AAAA,IACxB,gBAAgB,OAAO;AAAA,EACzB;AACF;AAOA,IAAM,gBAAgB;AAGtB,IAAM,gBAAgB;AAGtB,IAAM,kBAAkB;AAGxB,IAAM,oBACJ;AASF,SAAS,oBAAoB,SAAyB;AACpD,MAAI,CAAC,QAAS,QAAO;AAErB,MAAI,UAAU,QAAQ,QAAQ,eAAe,EAAE;AAE/C,YAAU,QAAQ,QAAQ,eAAe,EAAE;AAE3C,YAAU,QAAQ,QAAQ,mBAAmB,EAAE;AAE/C,YAAU,QAAQ,QAAQ,iBAAiB,EAAE;AAC7C,SAAO;AACT;AAsEA,SAAS,oBAA+C;AACtD,QAAM,MAAM,oBAAI,IAA0B;AAC1C,aAAW,KAAK,iBAAiB;AAC/B,QAAI,EAAE,OAAO,WAAY;AACzB,QAAI,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,YAAY,aAAa,EAAE,YAAY,CAAC;AAAA,EACxE;AACA,SAAO;AACT;AAaO,SAAS,oBACd,YAAoB,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI,GAC9B;AAClB,QAAM,OAAO,oBAAI,IAAY;AAC7B,SAAO,gBAAgB,OAAO,CAAC,UAAU;AACvC,QAAI,KAAK,IAAI,MAAM,EAAE,EAAG,QAAO;AAC/B,SAAK,IAAI,MAAM,EAAE;AACjB,WAAO;AAAA,EACT,CAAC,EAAE,IAAI,CAAC,WAAW;AAAA,IACjB,IAAI,MAAM;AAAA,IACV,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,UAAU,MAAM,GAAG,SAAS,GAAG,IAAK,MAAM,GAAG,MAAM,GAAG,EAAE,CAAC,KAAK,aAAc;AAAA,EAC9E,EAAE;AACJ;AAKA,SAAS,mBAAmB,WAAmD;AAC7E,MAAI,CAAC,UAAW,QAAO;AACvB,SAAO;AAAA,IACL,GAAG;AAAA,IACH,GAAG;AAAA,IACH,YAAY,EAAE,GAAG,uBAAuB,YAAY,GAAG,UAAU,WAAW;AAAA,IAC5E,SAAS,EAAE,GAAG,uBAAuB,SAAS,GAAG,UAAU,QAAQ;AAAA,IACnE,OAAO,EAAE,GAAG,uBAAuB,OAAO,GAAG,UAAU,MAAM;AAAA,IAC7D,WAAW,EAAE,GAAG,uBAAuB,WAAW,GAAG,UAAU,UAAU;AAAA,EAC3E;AACF;AAMA,SAAS,eACP,SACA,YACA,WACoB;AACpB,QAAM,QAAQ,gBAAgB,KAAK,CAAC,MAAM,EAAE,OAAO,OAAO;AAC1D,MAAI,CAAC,MAAO,QAAO;AAGnB,QAAM,uBAAuB,KAAK,KAAK,aAAa,CAAC;AACrD,QAAM,wBAAwB,aAAa,MAAM,aAAa;AAE9D,QAAM,UACH,uBAAuB,MAAa,MAAM,aAC1C,wBAAwB,MAAa,MAAM;AAI9C,QAAM,eAAe,KAAK,IAAI,KAAM,KAAK,KAAK,UAAU,MAAM,GAAS,CAAC;AACxE,SAAO,aAAa,SAAS;AAC/B;AASA,eAAe,oBACb,KACA,KACA,SACA,UAKe;AACf,QAAM,YAAY,KAAK,IAAI;AAC3B,QAAM,cAAc,GAAG,OAAO,GAAG,IAAI,GAAG;AAGxC,QAAM,aAAuB,CAAC;AAC9B,mBAAiB,SAAS,KAAK;AAC7B,eAAW,KAAK,OAAO,SAAS,KAAK,IAAI,QAAQ,OAAO,KAAK,KAAK,CAAC;AAAA,EACrE;AACA,QAAM,OAAO,OAAO,OAAO,UAAU;AAGrC,QAAM,UAAkC,CAAC;AACzC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,OAAO,GAAG;AACtD,QACE,QAAQ,UACR,QAAQ,gBACR,QAAQ,uBACR,QAAQ;AAER;AACF,QAAI,OAAO,UAAU,SAAU,SAAQ,GAAG,IAAI;AAAA,EAChD;AACA,MAAI,CAAC,QAAQ,cAAc,EAAG,SAAQ,cAAc,IAAI;AACxD,UAAQ,YAAY,IAAI;AAExB,UAAQ,IAAI,iCAAiC,IAAI,MAAM,IAAI,IAAI,GAAG,EAAE;AAEpE,QAAM,WAAW,MAAM,SAAS,aAAa;AAAA,IAC3C,QAAQ,IAAI,UAAU;AAAA,IACtB;AAAA,IACA,MAAM,KAAK,SAAS,IAAI,IAAI,WAAW,IAAI,IAAI;AAAA,EACjD,CAAC;AAGD,QAAM,kBAA0C,CAAC;AACjD,WAAS,QAAQ,QAAQ,CAAC,OAAO,QAAQ;AACvC,QAAI,QAAQ,uBAAuB,QAAQ,gBAAgB,QAAQ,mBAAoB;AACvF,oBAAgB,GAAG,IAAI;AAAA,EACzB,CAAC;AAED,MAAI,UAAU,SAAS,QAAQ,eAAe;AAG9C,MAAI,SAAS,MAAM;AACjB,UAAM,SAAS,SAAS,KAAK,UAAU;AACvC,QAAI;AACF,aAAO,MAAM;AACX,cAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,YAAI,KAAM;AACV,kBAAU,KAAK,OAAO,KAAK,KAAK,CAAC;AAAA,MACnC;AAAA,IACF,UAAE;AACA,aAAO,YAAY;AAAA,IACrB;AAAA,EACF;AAEA,MAAI,IAAI;AAER,QAAM,YAAY,KAAK,IAAI,IAAI;AAC/B,UAAQ,IAAI,kCAAkC,SAAS,MAAM,KAAK,SAAS,KAAK;AAGhF,WAAS;AAAA,IACP,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA;AAAA,IACN,cAAc;AAAA,IACd,SAAS;AAAA,IACT;AAAA,IACA,YACG,IAAI,KAAK,MAAM,GAAG,EAAE,CAAC,KAAK,IAAI,QAAQ,WAAW,EAAE,EAAE,QAAQ,OAAO,GAAG,KAAK;AAAA,IAC/E,SAAS;AAAA,EACX,CAAC,EAAE,MAAM,MAAM;AAAA,EAAC,CAAC;AACnB;AAOA,eAAe,oBAAoB,SAAkC;AACnE,QAAM,QAAQ,QAAQ,MAAM,iCAAiC;AAC7D,MAAI,CAAC,MAAO,OAAM,IAAI,MAAM,yBAAyB;AACrD,QAAM,CAAC,EAAE,UAAU,OAAO,IAAI;AAC9B,QAAM,MAAM,aAAa,eAAe,QAAQ,SAAS,MAAM,GAAG,EAAE,CAAC,KAAK;AAE1E,QAAM,SAAS,OAAO,KAAK,SAAS,QAAQ;AAC5C,QAAM,OAAO,IAAI,KAAK,CAAC,MAAM,GAAG,EAAE,MAAM,SAAS,CAAC;AAElD,QAAM,OAAO,IAAI,SAAS;AAC1B,OAAK,OAAO,WAAW,YAAY;AACnC,OAAK,OAAO,gBAAgB,MAAM,SAAS,GAAG,EAAE;AAEhD,QAAM,OAAO,MAAM,MAAM,mCAAmC;AAAA,IAC1D,QAAQ;AAAA,IACR,MAAM;AAAA,EACR,CAAC;AAED,MAAI,CAAC,KAAK,GAAI,OAAM,IAAI,MAAM,kCAAkC,KAAK,MAAM,EAAE;AAC7E,QAAM,SAAS,MAAM,KAAK,KAAK;AAC/B,MAAI,OAAO,WAAW,UAAU,GAAG;AACjC,WAAO,OAAO,KAAK;AAAA,EACrB;AACA,QAAM,IAAI,MAAM,6BAA6B,MAAM,EAAE;AACvD;AAUA,eAAsB,WAAW,SAA6C;AAC5E,QAAM,UAAU,QAAQ,WAAW;AAGnC,QAAM,aAAa,QAAQ,QAAQ,aAAa;AAGhD,QAAM,iBAAiB,MAAM,mBAAmB,UAAU;AAC1D,MAAI,gBAAgB;AAElB,UAAMC,WAAUC,qBAAoB,QAAQ,SAA0B;AACtE,UAAMC,kBAAiB,IAAI,eAAeF,SAAQ,OAAO;AACzD,UAAMG,WAAU,oBAAoB,UAAU;AAG9C,QAAI,mBAAmBH,SAAQ,SAAS;AACtC,cAAQ;AAAA,QACN,uCAAuC,UAAU,gBAAgB,cAAc,6BAA6BA,SAAQ,OAAO;AAAA,MAC7H;AAAA,IACF;AAEA,YAAQ,UAAU,UAAU;AAE5B,WAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAAG;AAAA,MACA,eAAe;AAAA,MACf,gBAAAD;AAAA,MACA,OAAO,YAAY;AAAA,MAEnB;AAAA,IACF;AAAA,EACF;AAGA,QAAM,UAAUD,qBAAoB,QAAQ,SAA0B;AACtE,QAAM,EAAE,OAAO,SAAS,IAAI,mBAAmB,QAAQ,SAA0B;AAGjF,QAAM,iBAAiB,IAAI,eAAe,QAAQ,OAAO;AAGzD,QAAM,gBAAgB,mBAAmB,QAAQ,aAAa;AAC9D,QAAM,eAAe,kBAAkB;AACvC,QAAM,aAA4B;AAAA,IAChC,QAAQ;AAAA,IACR;AAAA,EACF;AAGA,QAAM,eAAe,IAAI,oBAAoB;AAG7C,QAAM,gBAAgB,IAAI,cAAc,QAAQ,WAAW;AAG3D,QAAM,eAAe,IAAI,aAAa,QAAQ,aAAa;AAG3D,QAAM,iBAAiB,IAAI,eAAe;AAG1C,QAAM,cAAc,oBAAI,IAA0B;AAElD,QAAM,SAAS,aAAa,OAAO,KAAsB,QAAwB;AAE/E,QAAI,GAAG,SAAS,CAAC,QAAQ;AACvB,cAAQ,MAAM,sCAAsC,IAAI,OAAO,EAAE;AAAA,IAEnE,CAAC;AAED,QAAI,GAAG,SAAS,CAAC,QAAQ;AACvB,cAAQ,MAAM,uCAAuC,IAAI,OAAO,EAAE;AAAA,IAEpE,CAAC;AAGD,aAAS,KAAK,CAAC,QAAQ;AACrB,UAAI,OAAO,IAAI,SAAS,wBAAwB;AAC9C,gBAAQ,MAAM,8CAA8C,IAAI,OAAO,EAAE;AAAA,MAC3E;AAAA,IAGF,CAAC;AAGD,aAAS,KAAK,CAAC,QAAQ;AACrB,UAAI,OAAO,IAAI,SAAS,wBAAwB;AAC9C,gBAAQ,MAAM,6CAA6C,IAAI,OAAO,EAAE;AAAA,MAC1E;AAAA,IACF,CAAC;AAGD,QAAI,IAAI,QAAQ,aAAa,IAAI,KAAK,WAAW,UAAU,GAAG;AAC5D,YAAM,MAAM,IAAI,IAAI,IAAI,KAAK,kBAAkB;AAC/C,YAAM,OAAO,IAAI,aAAa,IAAI,MAAM,MAAM;AAE9C,YAAM,WAAoC;AAAA,QACxC,QAAQ;AAAA,QACR,QAAQ,QAAQ;AAAA,MAClB;AAEA,UAAI,MAAM;AACR,YAAI;AACF,gBAAM,cAAc,MAAM,eAAe,aAAa;AACtD,mBAAS,UAAU,YAAY;AAC/B,mBAAS,QAAQ,YAAY;AAC7B,mBAAS,UAAU,YAAY;AAAA,QACjC,QAAQ;AACN,mBAAS,eAAe;AAAA,QAC1B;AAAA,MACF;AAEA,UAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,UAAI,IAAI,KAAK,UAAU,QAAQ,CAAC;AAChC;AAAA,IACF;AAGA,QAAI,IAAI,QAAQ,YAAY,IAAI,KAAK,WAAW,SAAS,GAAG;AAC1D,YAAM,QAAQ,cAAc,SAAS;AACrC,UAAI,UAAU,KAAK;AAAA,QACjB,gBAAgB;AAAA,QAChB,iBAAiB;AAAA,MACnB,CAAC;AACD,UAAI,IAAI,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AACtC;AAAA,IACF;AAGA,QAAI,IAAI,QAAQ,YAAY,IAAI,KAAK,WAAW,SAAS,GAAG;AAC1D,UAAI;AACF,cAAM,MAAM,IAAI,IAAI,IAAI,KAAK,kBAAkB;AAC/C,cAAM,OAAO,SAAS,IAAI,aAAa,IAAI,MAAM,KAAK,KAAK,EAAE;AAC7D,cAAM,QAAQ,MAAM,SAAS,KAAK,IAAI,MAAM,EAAE,CAAC;AAE/C,YAAI,UAAU,KAAK;AAAA,UACjB,gBAAgB;AAAA,UAChB,iBAAiB;AAAA,QACnB,CAAC;AACD,YAAI,IAAI,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AAAA,MACxC,SAAS,KAAK;AACZ,YAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,YAAI;AAAA,UACF,KAAK,UAAU;AAAA,YACb,OAAO,wBAAwB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,UACjF,CAAC;AAAA,QACH;AAAA,MACF;AACA;AAAA,IACF;AAGA,QAAI,IAAI,QAAQ,gBAAgB,IAAI,WAAW,OAAO;AACpD,YAAM,SAAS,oBAAoB;AACnC,UAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,UAAI,IAAI,KAAK,UAAU,EAAE,QAAQ,QAAQ,MAAM,OAAO,CAAC,CAAC;AACxD;AAAA,IACF;AAGA,QAAI,IAAI,KAAK,MAAM,wBAAwB,GAAG;AAC5C,UAAI;AACF,cAAM,oBAAoB,KAAK,KAAK,SAAS,QAAQ;AAAA,MACvD,SAAS,KAAK;AACZ,cAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAChE,gBAAQ,UAAU,KAAK;AACvB,YAAI,CAAC,IAAI,aAAa;AACpB,cAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,cAAI;AAAA,YACF,KAAK,UAAU;AAAA,cACb,OAAO,EAAE,SAAS,wBAAwB,MAAM,OAAO,IAAI,MAAM,gBAAgB;AAAA,YACnF,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AACA;AAAA,IACF;AAGA,QAAI,CAAC,IAAI,KAAK,WAAW,KAAK,GAAG;AAC/B,UAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,UAAI,IAAI,KAAK,UAAU,EAAE,OAAO,YAAY,CAAC,CAAC;AAC9C;AAAA,IACF;AAEA,QAAI;AACF,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,YAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAChE,cAAQ,UAAU,KAAK;AAEvB,UAAI,CAAC,IAAI,aAAa;AACpB,YAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,YAAI;AAAA,UACF,KAAK,UAAU;AAAA,YACb,OAAO,EAAE,SAAS,gBAAgB,MAAM,OAAO,IAAI,MAAM,cAAc;AAAA,UACzE,CAAC;AAAA,QACH;AAAA,MACF,WAAW,CAAC,IAAI,eAAe;AAE7B,YAAI;AAAA,UACF,SAAS,KAAK,UAAU,EAAE,OAAO,EAAE,SAAS,MAAM,SAAS,MAAM,cAAc,EAAE,CAAC,CAAC;AAAA;AAAA;AAAA,QACrF;AACA,YAAI,MAAM,kBAAkB;AAC5B,YAAI,IAAI;AAAA,MACV;AAAA,IACF;AAAA,EACF,CAAC;AAKD,QAAM,YAAY,CAAC,YAAmC;AACpD,WAAO,IAAI,QAAc,CAAC,gBAAgB,kBAAkB;AAC1D,YAAM,UAAU,OAAO,QAA+B;AACpD,eAAO,eAAe,SAAS,OAAO;AAEtC,YAAI,IAAI,SAAS,cAAc;AAE7B,gBAAMG,kBAAiB,MAAM,mBAAmB,UAAU;AAC1D,cAAIA,iBAAgB;AAElB,oBAAQ,IAAI,gDAAgD,UAAU,WAAW;AACjF,0BAAc,EAAE,MAAM,kBAAkB,QAAQA,gBAAe,CAAC;AAChE;AAAA,UACF;AAGA,cAAI,UAAU,qBAAqB;AACjC,oBAAQ;AAAA,cACN,qBAAqB,UAAU,8BAA8B,mBAAmB,eAAe,OAAO,IAAI,mBAAmB;AAAA,YAC/H;AACA,0BAAc,EAAE,MAAM,SAAS,QAAQ,CAAC;AACxC;AAAA,UACF;AAGA,kBAAQ;AAAA,YACN,qBAAqB,UAAU,uBAAuB,mBAAmB;AAAA,UAC3E;AACA,wBAAc,GAAG;AACjB;AAAA,QACF;AAEA,sBAAc,GAAG;AAAA,MACnB;AAEA,aAAO,KAAK,SAAS,OAAO;AAC5B,aAAO,OAAO,YAAY,aAAa,MAAM;AAC3C,eAAO,eAAe,SAAS,OAAO;AACtC,uBAAe;AAAA,MACjB,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAGA,MAAI;AACJ,WAAS,UAAU,GAAG,WAAW,qBAAqB,WAAW;AAC/D,QAAI;AACF,YAAM,UAAU,OAAO;AACvB;AAAA,IACF,SAAS,KAAc;AACrB,YAAM,QAAQ;AAEd,UAAI,MAAM,SAAS,oBAAoB,MAAM,QAAQ;AAEnD,cAAMD,WAAU,oBAAoB,UAAU;AAC9C,gBAAQ,UAAU,UAAU;AAC5B,eAAO;AAAA,UACL,MAAM;AAAA,UACN,SAAAA;AAAA,UACA,eAAe,MAAM;AAAA,UACrB;AAAA,UACA,OAAO,YAAY;AAAA,UAEnB;AAAA,QACF;AAAA,MACF;AAEA,UAAI,MAAM,SAAS,SAAS;AAE1B,cAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,mBAAmB,CAAC;AAC3D;AAAA,MACF;AAGA,kBAAY;AACZ;AAAA,IACF;AAAA,EACF;AAEA,MAAI,WAAW;AACb,UAAM;AAAA,EACR;AAGA,QAAM,OAAO,OAAO,QAAQ;AAC5B,QAAM,OAAO,KAAK;AAClB,QAAM,UAAU,oBAAoB,IAAI;AAExC,UAAQ,UAAU,IAAI;AAGtB,kBAAgB;AAIhB,SAAO,GAAG,SAAS,CAAC,QAAQ;AAC1B,YAAQ,MAAM,sCAAsC,IAAI,OAAO,EAAE;AACjE,YAAQ,UAAU,GAAG;AAAA,EAEvB,CAAC;AAGD,SAAO,GAAG,eAAe,CAAC,KAAK,WAAW;AACxC,YAAQ,MAAM,8BAA8B,IAAI,OAAO,EAAE;AAEzD,QAAI,OAAO,YAAY,CAAC,OAAO,WAAW;AACxC,aAAO,IAAI,kCAAkC;AAAA,IAC/C;AAAA,EACF,CAAC;AAGD,SAAO,GAAG,cAAc,CAAC,WAAW;AAClC,gBAAY,IAAI,MAAM;AAGtB,WAAO,WAAW,GAAO;AAEzB,WAAO,GAAG,WAAW,MAAM;AACzB,cAAQ,MAAM,oDAAoD;AAClE,aAAO,QAAQ;AAAA,IACjB,CAAC;AAED,WAAO,GAAG,OAAO,MAAM;AAAA,IAEvB,CAAC;AAED,WAAO,GAAG,SAAS,CAAC,QAAQ;AAC1B,cAAQ,MAAM,8BAA8B,IAAI,OAAO,EAAE;AAAA,IAC3D,CAAC;AAED,WAAO,GAAG,SAAS,MAAM;AACvB,kBAAY,OAAO,MAAM;AAAA,IAC3B,CAAC;AAAA,EACH,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,eAAe,QAAQ;AAAA,IACvB;AAAA,IACA,OAAO,MACL,IAAI,QAAc,CAAC,KAAK,QAAQ;AAC9B,YAAM,UAAU,WAAW,MAAM;AAC/B,YAAI,IAAI,MAAM,qCAAqC,CAAC;AAAA,MACtD,GAAG,GAAI;AAEP,mBAAa,MAAM;AAEnB,iBAAW,UAAU,aAAa;AAChC,eAAO,QAAQ;AAAA,MACjB;AACA,kBAAY,MAAM;AAClB,aAAO,MAAM,CAAC,QAAQ;AACpB,qBAAa,OAAO;AACpB,YAAI,KAAK;AACP,cAAI,GAAG;AAAA,QACT,OAAO;AACL,cAAI;AAAA,QACN;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACL;AACF;AAeA,eAAe,gBACb,aACA,QACA,SACA,MACA,SACA,WACA,UAKA,gBACA,QAC6B;AAE7B,MAAI,cAAc;AAClB,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,KAAK,SAAS,CAAC;AACzC,WAAO,QAAQ;AAGf,QAAI,MAAM,QAAQ,OAAO,QAAQ,GAAG;AAClC,aAAO,WAAW,sBAAsB,OAAO,QAAyB;AAAA,IAC1E;AAGA,QAAI,MAAM,QAAQ,OAAO,QAAQ,GAAG;AAClC,YAAM,mBAAmB,iBAAiB,OAAO,QAAyB;AAC1E,aAAO,WAAW,iBAAiB;AAAA,IACrC;AAGA,QAAI,MAAM,QAAQ,OAAO,QAAQ,GAAG;AAClC,aAAO,WAAW,gBAAgB,OAAO,QAAyB;AAAA,IACpE;AAGA,QAAI,cAAc,OAAO,KAAK,MAAM,QAAQ,OAAO,QAAQ,GAAG;AAC5D,aAAO,WAAW,2BAA2B,OAAO,QAAyB;AAAA,IAC/E;AAIA,UAAM,qBAAqB,CAAC,EAC1B,OAAO,YACP,OAAO,qBACP,iBAAiB,OAAO;AAE1B,QAAI,sBAAsB,MAAM,QAAQ,OAAO,QAAQ,GAAG;AACxD,aAAO,WAAW,6BAA6B,OAAO,QAAiC;AAAA,IACzF;AAEA,kBAAc,OAAO,KAAK,KAAK,UAAU,MAAM,CAAC;AAAA,EAClD,QAAQ;AAAA,EAER;AAGA,QAAM,YAAY,eAAe,SAAS,YAAY,QAAQ,SAAS;AACvE,QAAM,UAAqC,YAAY,EAAE,iBAAiB,UAAU,IAAI;AAExF,MAAI;AACF,UAAM,WAAW,MAAM;AAAA,MACrB;AAAA,MACA;AAAA,QACE;AAAA,QACA;AAAA,QACA,MAAM,YAAY,SAAS,IAAI,IAAI,WAAW,WAAW,IAAI;AAAA,QAC7D;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAGA,QAAI,SAAS,WAAW,KAAK;AAE3B,YAAM,YAAY,MAAM,SAAS,KAAK;AACtC,YAAM,gBAAgB,gBAAgB,SAAS,QAAQ,SAAS;AAEhE,aAAO;AAAA,QACL,SAAS;AAAA,QACT;AAAA,QACA,aAAa,SAAS;AAAA,QACtB,iBAAiB;AAAA,MACnB;AAAA,IACF;AAGA,UAAM,cAAc,SAAS,QAAQ,IAAI,cAAc,KAAK;AAC5D,QAAI,YAAY,SAAS,MAAM,KAAK,YAAY,SAAS,MAAM,GAAG;AAChE,UAAI;AACF,cAAM,eAAe,MAAM,SAAS,MAAM,EAAE,KAAK;AACjD,cAAM,iBAAiB,8BAA8B,YAAY;AACjE,YAAI,gBAAgB;AAClB,iBAAO;AAAA,YACL,SAAS;AAAA,YACT,WAAW;AAAA,YACX,aAAa;AAAA,YACb,iBAAiB;AAAA,UACnB;AAAA,QACF;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,WAAO,EAAE,SAAS,MAAM,SAAS;AAAA,EACnC,SAAS,KAAK;AACZ,UAAM,WAAW,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAChE,WAAO;AAAA,MACL,SAAS;AAAA,MACT,WAAW;AAAA,MACX,aAAa;AAAA,MACb,iBAAiB;AAAA;AAAA,IACnB;AAAA,EACF;AACF;AAYA,eAAe,aACb,KACA,KACA,SACA,UAKA,SACA,YACA,cACA,gBACA,cACA,eACA,gBACe;AACf,QAAM,YAAY,KAAK,IAAI;AAG3B,QAAM,cAAc,GAAG,OAAO,GAAG,IAAI,GAAG;AAGxC,QAAM,aAAuB,CAAC;AAC9B,mBAAiB,SAAS,KAAK;AAC7B,eAAW,KAAK,OAAO,SAAS,KAAK,IAAI,QAAQ,OAAO,KAAK,KAAK,CAAC;AAAA,EACrE;AACA,MAAI,OAAO,OAAO,OAAO,UAAU;AAGnC,QAAM,wBAAwB,KAAK,KAAK,KAAK,SAAS,IAAI;AAG1D,QAAM,YAAY,IAAI,QAAQ,oBAAoB,MAAM;AAGxD,MAAI;AACJ,MAAI,WAAW;AACf,MAAI,YAAY;AAChB,MAAI,cAAc;AAClB,MAAI,UAAU;AACd,MAAI,YAAY;AAChB,MAAI,iBAA6D;AACjE,MAAI,qBAAqB;AACzB,QAAM,mBAAmB,IAAI,KAAK,SAAS,mBAAmB;AAG9D,QAAM,YAAY,aAAa,IAAI,OAAwD;AAE3F,MAAI,qBAAyC;AAE7C,MAAI,oBAAoB,KAAK,SAAS,GAAG;AACvC,QAAI;AACF,YAAM,SAAS,KAAK,MAAM,KAAK,SAAS,CAAC;AACzC,oBAAc,OAAO,WAAW;AAChC,gBAAW,OAAO,SAAoB;AACtC,kBAAa,OAAO,cAAyB;AAC7C,UAAI,eAAe;AAGnB,YAAM,iBAAiB,MAAM,QAAQ,OAAO,QAAQ,IAC/C,OAAO,WACR,CAAC;AACL,YAAM,cAAc,CAAC,GAAG,cAAc,EAAE,QAAQ,EAAE,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM;AAC/E,YAAM,iBAAiB,aAAa;AACpC,YAAM,cACJ,OAAO,mBAAmB,WACtB,iBACA,MAAM,QAAQ,cAAc,IACzB,eACE,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM,EAC/B,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,EACvB,KAAK,GAAG,IACX;AAIR,UAAI,aAAa,eAAe,SAAS,GAAG;AAC1C,cAAM,WAAW;AAEjB,YAAI,eAAe,aAAa,WAAW,GAAG;AAC5C,gBAAM,cAAc,eAAe,OAAO,SAAS;AACnD,cAAI,aAAa;AAEf,kBAAM,SAAS,SAAS,UAAU,CAAC,MAAM,EAAE,SAAS,QAAQ;AAC5D,gBAAI,UAAU,KAAK,OAAO,SAAS,MAAM,EAAE,YAAY,UAAU;AAC/D,uBAAS,MAAM,IAAI;AAAA,gBACjB,GAAG,SAAS,MAAM;AAAA,gBAClB,SAAS,cAAc,SAAS,SAAS,MAAM,EAAE;AAAA,cACnD;AAAA,YACF,OAAO;AACL,uBAAS,QAAQ,EAAE,MAAM,UAAU,SAAS,YAAY,CAAC;AAAA,YAC3D;AACA,mBAAO,WAAW;AAClB,2BAAe;AACf,oBAAQ;AAAA,cACN,0CAA0C,YAAY,MAAM,uBAAuB,UAAU,MAAM,GAAG,CAAC,CAAC;AAAA,YAC1G;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAGA,UAAI,YAAY,WAAW,QAAQ,GAAG;AACpC,cAAM,cAAc,YAAY,MAAM,SAAS,MAAM,EAAE,KAAK,KAAK;AACjE,cAAM,WAAW,OAAO;AACxB,cAAM,YAAY,UAAU,KAAK,CAAC,MAAM,EAAE,SAAS,QAAQ;AAC3D,cAAM,eAAe,OAAO,WAAW,YAAY,WAAW,UAAU,UAAU;AAClF,cAAM,WAAW,GAAG,gBAAgB,EAAE,IAAI,WAAW;AACrD,cAAM,kBAAkB,KAAK,KAAK,SAAS,SAAS,CAAC;AAGrD,cAAME,mBACJ,OAAO,OAAO,UAAU,WAAW,OAAO,MAAM,KAAK,EAAE,YAAY,IAAI;AACzE,cAAM,cAAcA,iBAAgB,QAAQ,aAAa,EAAE;AAC3D,cAAM,eACJ,CAAC,QAAQ,OAAO,QAAQ,SAAS,EAAE,SAAS,WAAW,IAAI,cAAc;AAI3E,cAAM,UAAU;AAAA,UACd;AAAA,UACA;AAAA,UACA;AAAA,UACA,uBAAuB;AAAA,QACzB;AAGA,cAAM,eAAe,MAAM,aAAa,cAAc,WAAW;AAAA,UAC/D,GAAG;AAAA,UACH,gBAAgB;AAAA,QAClB,CAAC;AAGD,cAAM,YAAY,QAAQ,cAAc,CAAC,GACtC,IAAI,CAAC,MAAM;AACV,gBAAM,WAAW,EAAE,OAAO,KAAK,OAAO,EAAE;AACxC,gBAAM,WAAW,EAAE,MAAM,QAAQ,CAAC,EAAE,SAAS,CAAC;AAC9C,gBAAM,SAAS,EAAE,SAAS,MAAM,EAAE,MAAM,MAAM;AAC9C,iBAAO,KAAK,OAAO,GAAG,QAAQ,GAAG,MAAM;AAAA,QACzC,CAAC,EACA,KAAK,IAAI;AAGZ,cAAM,OAAO,YAAY,aAAa,WAAW,SAAS,IAAI;AAC9D,cAAM,WAAW,OACb,YAAY,UAAW,MAAM,GAAG,CAAC,CAAC,sBAAiB,KAAK,KAAK,KAAK,KAAK,YAAY,eACnF,YACE,YAAY,UAAU,MAAM,GAAG,CAAC,CAAC,+BACjC;AAEN,cAAM,EAAE,cAAc,eAAe,iBAAiB,IACpD,uBAAuB,QAAQ;AAEjC,cAAM,YAAY;AAAA,UAChB;AAAA,UACA;AAAA,UACA,YAAY,YAAY,YAAY,aAAa,IAAI,aAAa,aAAa,KAAK;AAAA,UACpF,eAAe,aAAa,WAAW,QAAQ,CAAC,CAAC,aAAa,aAAa,aAAa,QAAQ,CAAC,CAAC,gBAAgB,aAAa,UAAU,KAAK,QAAQ,CAAC,CAAC;AAAA,UACxJ,cAAc,aAAa,SAAS;AAAA,UACpC;AAAA,UACA,sBAAsB,QAAQ,MAAM,QAAQ,CAAC,CAAC;AAAA,UAC9C;AAAA,UACA;AAAA,UACA,4BAA4B,aAAa,QAAQ,CAAC,CAAC,cAAc,cAAc,QAAQ,CAAC,CAAC,eAAe,iBAAiB,QAAQ,CAAC,CAAC,kBAAkB,iBAAiB,QAAQ,CAAC,CAAC;AAAA,UAChL;AAAA,UACA;AAAA,QACF,EAAE,KAAK,IAAI;AAGX,cAAM,eAAe,kBAAkB,KAAK,IAAI,CAAC;AACjD,cAAM,YAAY,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AAC9C,cAAM,oBAAoB;AAAA,UACxB,IAAI;AAAA,UACJ,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,OAAO;AAAA,UACP,SAAS;AAAA,YACP;AAAA,cACE,OAAO;AAAA,cACP,SAAS,EAAE,MAAM,aAAa,SAAS,UAAU;AAAA,cACjD,eAAe;AAAA,YACjB;AAAA,UACF;AAAA,UACA,OAAO,EAAE,eAAe,GAAG,mBAAmB,GAAG,cAAc,EAAE;AAAA,QACnE;AAEA,YAAI,aAAa;AAEf,cAAI,UAAU,KAAK;AAAA,YACjB,gBAAgB;AAAA,YAChB,iBAAiB;AAAA,YACjB,YAAY;AAAA,UACd,CAAC;AACD,gBAAM,WAAW;AAAA,YACf,IAAI;AAAA,YACJ,QAAQ;AAAA,YACR,SAAS;AAAA,YACT,OAAO;AAAA,YACP,SAAS;AAAA,cACP;AAAA,gBACE,OAAO;AAAA,gBACP,OAAO,EAAE,MAAM,aAAa,SAAS,UAAU;AAAA,gBAC/C,eAAe;AAAA,cACjB;AAAA,YACF;AAAA,UACF;AACA,gBAAM,UAAU;AAAA,YACd,IAAI;AAAA,YACJ,QAAQ;AAAA,YACR,SAAS;AAAA,YACT,OAAO;AAAA,YACP,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,GAAG,eAAe,OAAO,CAAC;AAAA,UAC1D;AACA,cAAI,MAAM,SAAS,KAAK,UAAU,QAAQ,CAAC;AAAA;AAAA,CAAM;AACjD,cAAI,MAAM,SAAS,KAAK,UAAU,OAAO,CAAC;AAAA;AAAA,CAAM;AAChD,cAAI,MAAM,kBAAkB;AAC5B,cAAI,IAAI;AAAA,QACV,OAAO;AACL,cAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,cAAI,IAAI,KAAK,UAAU,iBAAiB,CAAC;AAAA,QAC3C;AACA,gBAAQ,IAAI,sCAAiC,aAAa,IAAI,MAAM,aAAa,KAAK,EAAE;AACxF;AAAA,MACF;AAGA,UAAI,YAAY,WAAW,WAAW,GAAG;AACvC,cAAM,YAAY,YAAY,MAAM,YAAY,MAAM,EAAE,KAAK;AAG7D,YAAI,aAAa;AACjB,YAAI,YAAY;AAChB,YAAI,cAAc;AAGlB,cAAM,aAAa,UAAU,MAAM,iBAAiB;AACpD,YAAI,YAAY;AACd,gBAAM,MAAM,WAAW,CAAC;AAExB,gBAAM,sBAA8C;AAAA,YAClD,YAAY;AAAA,YACZ,UAAU;AAAA,YACV,SAAS;AAAA,YACT,aAAa;AAAA,YACb,eAAe;AAAA,YACf,QAAQ;AAAA,YACR,YAAY;AAAA,YACZ,UAAU;AAAA,YACV,eAAe;AAAA,YACf,cAAc;AAAA,YACd,mBAAmB;AAAA,UACrB;AACA,uBAAa,oBAAoB,GAAG,KAAK;AACzC,wBAAc,YAAY,QAAQ,iBAAiB,EAAE,EAAE,KAAK;AAAA,QAC9D;AAGA,cAAM,YAAY,UAAU,MAAM,oBAAoB;AACtD,YAAI,WAAW;AACb,sBAAY,UAAU,CAAC;AACvB,wBAAc,YAAY,QAAQ,oBAAoB,EAAE,EAAE,KAAK;AAAA,QACjE;AAEA,YAAI,CAAC,aAAa;AAChB,gBAAM,YAAY;AAAA,YAChB;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF,EAAE,KAAK,IAAI;AAEX,gBAAM,eAAe,kBAAkB,KAAK,IAAI,CAAC;AACjD,gBAAM,YAAY,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AAC9C,cAAI,aAAa;AACf,gBAAI,UAAU,KAAK;AAAA,cACjB,gBAAgB;AAAA,cAChB,iBAAiB;AAAA,cACjB,YAAY;AAAA,YACd,CAAC;AACD,gBAAI,MAAM,SAAS,KAAK,UAAU,EAAE,IAAI,cAAc,QAAQ,yBAAyB,SAAS,WAAW,OAAO,oBAAoB,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,EAAE,MAAM,aAAa,SAAS,UAAU,GAAG,eAAe,KAAK,CAAC,EAAE,CAAC,CAAC;AAAA;AAAA,CAAM;AAC7O,gBAAI,MAAM,SAAS,KAAK,UAAU,EAAE,IAAI,cAAc,QAAQ,yBAAyB,SAAS,WAAW,OAAO,oBAAoB,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,GAAG,eAAe,OAAO,CAAC,EAAE,CAAC,CAAC;AAAA;AAAA,CAAM;AACxM,gBAAI,MAAM,kBAAkB;AAC5B,gBAAI,IAAI;AAAA,UACV,OAAO;AACL,gBAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,gBAAI,IAAI,KAAK,UAAU;AAAA,cACrB,IAAI;AAAA,cAAc,QAAQ;AAAA,cAAmB,SAAS;AAAA,cAAW,OAAO;AAAA,cACxE,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,EAAE,MAAM,aAAa,SAAS,UAAU,GAAG,eAAe,OAAO,CAAC;AAAA,cACjG,OAAO,EAAE,eAAe,GAAG,mBAAmB,GAAG,cAAc,EAAE;AAAA,YACnE,CAAC,CAAC;AAAA,UACJ;AACA,kBAAQ,IAAI,0DAAqD;AACjE;AAAA,QACF;AAGA,gBAAQ,IAAI,yCAAoC,UAAU,KAAK,SAAS,MAAM,YAAY,MAAM,GAAG,EAAE,CAAC,KAAK;AAC3G,YAAI;AACF,gBAAM,mBAAmB,GAAG,OAAO;AACnC,gBAAM,YAAY,KAAK,UAAU,EAAE,OAAO,YAAY,QAAQ,aAAa,MAAM,WAAW,GAAG,EAAE,CAAC;AAClG,gBAAM,gBAAgB,MAAM,SAAS,kBAAkB;AAAA,YACrD,QAAQ;AAAA,YACR,SAAS,EAAE,gBAAgB,oBAAoB,cAAc,WAAW;AAAA,YACxE,MAAM;AAAA,UACR,CAAC;AAED,gBAAM,cAAc,MAAM,cAAc,KAAK;AAM7C,cAAI;AACJ,cAAI,CAAC,cAAc,MAAM,YAAY,OAAO;AAC1C,kBAAM,SAAS,OAAO,YAAY,UAAU,WACxC,YAAY,QACX,YAAY,OAAgC,WAAW,QAAQ,cAAc,MAAM;AACxF,2BAAe,4BAA4B,MAAM;AACjD,oBAAQ,IAAI,iCAAiC,MAAM,EAAE;AAAA,UACvD,OAAO;AACL,kBAAM,SAAS,YAAY,QAAQ,CAAC;AACpC,gBAAI,OAAO,WAAW,GAAG;AACvB,6BAAe;AAAA,YACjB,OAAO;AACL,oBAAM,QAAkB,CAAC;AACzB,yBAAW,OAAO,QAAQ;AACxB,oBAAI,IAAI,KAAK;AACX,sBAAI,IAAI,IAAI,WAAW,OAAO,GAAG;AAC/B,wBAAI;AACF,4BAAM,YAAY,MAAM,oBAAoB,IAAI,GAAG;AACnD,4BAAM,KAAK,SAAS;AAAA,oBACtB,SAAS,WAAW;AAClB,8BAAQ,MAAM,sDAAsD,qBAAqB,QAAQ,UAAU,UAAU,OAAO,SAAS,CAAC,EAAE;AACxI,4BAAM,KAAK,uEAAuE;AAAA,oBACpF;AAAA,kBACF,OAAO;AACL,0BAAM,KAAK,IAAI,GAAG;AAAA,kBACpB;AAAA,gBACF;AACA,oBAAI,IAAI,eAAgB,OAAM,KAAK,mBAAmB,IAAI,cAAc,EAAE;AAAA,cAC5E;AACA,oBAAM,KAAK,IAAI,UAAU,UAAU,YAAY,SAAS,EAAE;AAC1D,6BAAe,MAAM,KAAK,IAAI;AAAA,YAChC;AACA,oBAAQ,IAAI,mCAAmC,OAAO,MAAM,qBAAqB;AAAA,UACnF;AAGA,gBAAM,eAAe,kBAAkB,KAAK,IAAI,CAAC;AACjD,gBAAM,YAAY,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AAC9C,cAAI,aAAa;AACf,gBAAI,UAAU,KAAK;AAAA,cACjB,gBAAgB;AAAA,cAChB,iBAAiB;AAAA,cACjB,YAAY;AAAA,YACd,CAAC;AACD,gBAAI,MAAM,SAAS,KAAK,UAAU,EAAE,IAAI,cAAc,QAAQ,yBAAyB,SAAS,WAAW,OAAO,oBAAoB,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,EAAE,MAAM,aAAa,SAAS,aAAa,GAAG,eAAe,KAAK,CAAC,EAAE,CAAC,CAAC;AAAA;AAAA,CAAM;AAChP,gBAAI,MAAM,SAAS,KAAK,UAAU,EAAE,IAAI,cAAc,QAAQ,yBAAyB,SAAS,WAAW,OAAO,oBAAoB,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,GAAG,eAAe,OAAO,CAAC,EAAE,CAAC,CAAC;AAAA;AAAA,CAAM;AACxM,gBAAI,MAAM,kBAAkB;AAC5B,gBAAI,IAAI;AAAA,UACV,OAAO;AACL,gBAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,gBAAI,IAAI,KAAK,UAAU;AAAA,cACrB,IAAI;AAAA,cAAc,QAAQ;AAAA,cAAmB,SAAS;AAAA,cAAW,OAAO;AAAA,cACxE,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,EAAE,MAAM,aAAa,SAAS,aAAa,GAAG,eAAe,OAAO,CAAC;AAAA,cACpG,OAAO,EAAE,eAAe,GAAG,mBAAmB,GAAG,cAAc,EAAE;AAAA,YACnE,CAAC,CAAC;AAAA,UACJ;AAAA,QACF,SAAS,KAAK;AACZ,gBAAM,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC9D,kBAAQ,MAAM,iCAAiC,MAAM,EAAE;AACvD,cAAI,CAAC,IAAI,aAAa;AACpB,gBAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,gBAAI,IAAI,KAAK,UAAU;AAAA,cACrB,OAAO,EAAE,SAAS,4BAA4B,MAAM,IAAI,MAAM,cAAc;AAAA,YAC9E,CAAC,CAAC;AAAA,UACJ;AAAA,QACF;AACA;AAAA,MACF;AAIA,UAAI,OAAO,WAAW,MAAM;AAC1B,eAAO,SAAS;AAChB,uBAAe;AAAA,MACjB;AAGA,YAAM,kBACJ,OAAO,OAAO,UAAU,WAAW,OAAO,MAAM,KAAK,EAAE,YAAY,IAAI;AAGzE,YAAM,gBAAgB,kBAAkB,eAAe;AACvD,YAAM,WAAW,kBAAkB;AAEnC,YAAM,mBAAmB,iBAAiB,IAAI,eAAe;AAG7D,UAAI,kBAAkB;AACpB,cAAM,cAAc,gBAAgB,QAAQ,aAAa,EAAE;AAC3D,yBAAiB;AAAA,MACnB;AAGA,cAAQ;AAAA,QACN,iCAAiC,OAAO,KAAK,qBAAqB,eAAe,IAAI,WAAW,eAAe,aAAa,MAAM,EAAE,GAAG,iBAAiB,cAAc,cAAc,KAAK,EAAE;AAAA,MAC7L;AAIA,UAAI,CAAC,kBAAkB;AACrB,YAAI,OAAO,UAAU,eAAe;AAClC,iBAAO,QAAQ;AACf,yBAAe;AAAA,QACjB;AACA,kBAAU;AAAA,MACZ;AAGA,UAAI,kBAAkB;AAEpB,YAAI,mBAAmB,QAAQ;AAC7B,gBAAM,YAAY;AAClB,kBAAQ,IAAI,qCAAqC,SAAS,WAAW;AACrE,iBAAO,QAAQ;AACf,oBAAU;AACV,yBAAe;AAGf,gBAAM,SAAS;AAAA,YACb,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,YAClC,OAAO;AAAA,YACP,MAAM;AAAA,YACN,MAAM;AAAA,YACN,cAAc;AAAA,YACd,SAAS;AAAA;AAAA,YACT,WAAW;AAAA,UACb,CAAC;AAAA,QACH,OAAO;AAKL,+BACE,aAAa,IAAI,OAAwD,KACzE,gBAAgB,cAAc;AAChC,gBAAM,kBAAkB,qBACpB,aAAa,WAAW,kBAAkB,IAC1C;AAGJ,gBAAM,YAAY,aAAa;AAC/B,gBAAM,SACJ,OAAO,cAAc,WACjB,YACA,MAAM,QAAQ,SAAS,IACpB,UACE,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM,EAC/B,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,EACvB,KAAK,GAAG,IACX;AACR,gBAAM,YAAY,eAAe,KAAK,CAAC,MAAM,EAAE,SAAS,QAAQ;AAChE,gBAAM,eACJ,OAAO,WAAW,YAAY,WAAW,UAAU,UAAU;AAI/D,gBAAM,QAAQ,OAAO;AACrB,qBAAW,MAAM,QAAQ,KAAK,KAAK,MAAM,SAAS;AAElD,cAAI,YAAY,OAAO;AACrB,oBAAQ,IAAI,gCAAgC,MAAM,MAAM,8BAA8B;AAAA,UACxF;AAGA,sBAAY,eAAe,KAAK,CAAC,MAAM;AACrC,gBAAI,MAAM,QAAQ,EAAE,OAAO,GAAG;AAC5B,qBAAQ,EAAE,QAAoC,KAAK,CAAC,MAAM,EAAE,SAAS,WAAW;AAAA,YAClF;AACA,mBAAO;AAAA,UACT,CAAC;AACD,cAAI,WAAW;AACb,oBAAQ,IAAI,0EAA0E;AAAA,UACxF;AAGA,4BAAkB,MAAM,QAAQ,cAAc,WAAW;AAAA,YACvD,GAAG;AAAA,YACH,gBAAgB,kBAAkB;AAAA,UACpC,CAAC;AAED,cAAI,iBAAiB;AAKnB,kBAAM,WAAmC;AAAA,cACvC,QAAQ;AAAA,cACR,QAAQ;AAAA,cACR,SAAS;AAAA,cACT,WAAW;AAAA,YACb;AACA,kBAAM,eAAe,SAAS,gBAAgB,IAAI,KAAK;AACvD,kBAAM,UAAU,SAAS,gBAAgB,IAAI,KAAK;AAElD,gBAAI,UAAU,cAAc;AAE1B,sBAAQ;AAAA,gBACN,wBAAwB,oBAAoB,MAAM,GAAG,CAAC,CAAC,kBAAkB,gBAAgB,IAAI,WAAM,gBAAgB,IAAI,KAAK,gBAAgB,KAAK;AAAA,cACnJ;AACA,qBAAO,QAAQ,gBAAgB;AAC/B,wBAAU,gBAAgB;AAC1B,6BAAe;AACf,kBAAI,oBAAoB;AACtB,6BAAa;AAAA,kBACX;AAAA,kBACA,gBAAgB;AAAA,kBAChB,gBAAgB;AAAA,gBAClB;AAAA,cACF;AAAA,YACF,OAAO;AAEL,sBAAQ;AAAA,gBACN,wBAAwB,oBAAoB,MAAM,GAAG,CAAC,CAAC,6BAA6B,gBAAgB,KAAK,KAAK,gBAAgB,IAAI,OAAO,gBAAgB,IAAI;AAAA,cAC/J;AACA,qBAAO,QAAQ,gBAAgB;AAC/B,wBAAU,gBAAgB;AAC1B,6BAAe;AACf,2BAAa,aAAa,kBAAmB;AAE7C,gCAAkB;AAAA,gBAChB,GAAG;AAAA,gBACH,OAAO,gBAAgB;AAAA,gBACvB,MAAM,gBAAgB;AAAA,cACxB;AAAA,YACF;AAGA,kBAAM,mBAAmB,CAAC,GAAG,cAAc,EACxC,QAAQ,EACR,KAAK,CAAC,MAAM,EAAE,SAAS,WAAW;AACrC,kBAAM,gBAAgB,MAAM,QAAS,kBAA0B,UAAU,IACpE,iBAAyB,WACvB,IAAI,CAAC,OAAY,GAAG,UAAU,IAAI,EAClC,OAAO,OAAO,IACjB;AACJ,kBAAM,cAAc,mBAAmB,QAAQ,aAAa;AAC5D,kBAAM,iBAAiB,aAAa;AAAA,cAClC;AAAA,cACA;AAAA,YACF;AAEA,gBAAI,gBAAgB;AAClB,oBAAM,qBAAqB,MAAM;AAC/B,oBACE,gBAAgB,WAAW,SAAS,SAAS,KAC7C,WAAW,OAAO,cAClB;AACA,yBAAO,WAAW,OAAO;AAAA,gBAC3B;AACA,oBAAI,mBAAmB,SAAS,WAAW,OAAO,UAAU;AAC1D,yBAAO,WAAW,OAAO;AAAA,gBAC3B;AACA,oBAAI,mBAAmB,aAAa,WAAW,OAAO,cAAc;AAClE,yBAAO,WAAW,OAAO;AAAA,gBAC3B;AACA,uBAAO,WAAW,OAAO;AAAA,cAC3B,GAAG;AAEH,oBAAM,aAAa,aAAa;AAAA,gBAC9B;AAAA,gBACA;AAAA,cACF;AACA,kBAAI,YAAY;AACd,wBAAQ;AAAA,kBACN,4CAAuC,gBAAgB,KAAK,WAAM,WAAW,KAAK,KAAK,gBAAgB,IAAI,WAAM,WAAW,IAAI;AAAA,gBAClI;AACA,uBAAO,QAAQ,WAAW;AAC1B,0BAAU,WAAW;AACrB,kCAAkB;AAAA,kBAChB,GAAG;AAAA,kBACH,OAAO,WAAW;AAAA,kBAClB,MAAM,WAAW;AAAA,gBACnB;AAAA,cACF;AAAA,YACF;AAAA,UACF,OAAO;AAEL,mBAAO,QAAQ,gBAAgB;AAC/B,sBAAU,gBAAgB;AAC1B,2BAAe;AACf,gBAAI,oBAAoB;AACtB,2BAAa;AAAA,gBACX;AAAA,gBACA,gBAAgB;AAAA,gBAChB,gBAAgB;AAAA,cAClB;AACA,sBAAQ;AAAA,gBACN,wBAAwB,mBAAmB,MAAM,GAAG,CAAC,CAAC,wBAAwB,gBAAgB,KAAK;AAAA,cACrG;AAAA,YACF;AAAA,UACF;AAEA,kBAAQ,WAAW,eAAe;AAAA,QACpC;AAAA,MACF;AAGA,UAAI,cAAc;AAChB,eAAO,OAAO,KAAK,KAAK,UAAU,MAAM,CAAC;AAAA,MAC3C;AAAA,IACF,SAAS,KAAK;AAEZ,YAAM,WAAW,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAChE,cAAQ,MAAM,+BAA+B,QAAQ,EAAE;AACvD,cAAQ,MAAM,8DAA8D;AAC5E,cAAQ,UAAU,IAAI,MAAM,mBAAmB,QAAQ,EAAE,CAAC;AAAA,IAC5D;AAAA,EACF;AAIA,QAAM,eAAe,QAAQ,wBAAwB;AACrD,QAAM,uBAAuB,QAAQ,0BAA0B;AAC/D,QAAM,gBAAgB,KAAK,KAAK,KAAK,SAAS,IAAI;AAElD,MAAI,gBAAgB,gBAAgB,sBAAsB;AACxD,QAAI;AACF,cAAQ;AAAA,QACN,6BAA6B,aAAa,wBAAwB,oBAAoB;AAAA,MACxF;AAGA,YAAM,SAAS,KAAK,MAAM,KAAK,SAAS,CAAC;AAKzC,UAAI,OAAO,YAAY,OAAO,SAAS,SAAS,KAAK,eAAe,OAAO,QAAQ,GAAG;AAEpF,cAAM,oBAAoB,MAAM,gBAAgB,OAAO,UAAU;AAAA,UAC/D,SAAS;AAAA,UACT,aAAa;AAAA;AAAA,UACb,QAAQ;AAAA,YACN,eAAe;AAAA;AAAA,YACf,YAAY;AAAA;AAAA,YACZ,YAAY;AAAA;AAAA,YACZ,OAAO;AAAA;AAAA,YACP,aAAa;AAAA;AAAA,YACb,aAAa;AAAA;AAAA,YACb,iBAAiB;AAAA;AAAA,UACnB;AAAA,UACA,YAAY;AAAA,YACV,YAAY;AAAA,YACZ,iBAAiB;AAAA,YACjB,uBAAuB;AAAA,UACzB;AAAA,QACF,CAAC;AAED,cAAM,mBAAmB,KAAK,KAAK,kBAAkB,kBAAkB,IAAI;AAC3E,cAAM,YAAa,gBAAgB,oBAAoB,gBAAiB,KAAK,QAAQ,CAAC;AAEtF,gBAAQ;AAAA,UACN,2BAA2B,aAAa,aAAQ,gBAAgB,OAAO,OAAO;AAAA,QAChF;AAGA,eAAO,WAAW,kBAAkB;AACpC,eAAO,OAAO,KAAK,KAAK,UAAU,MAAM,CAAC;AAAA,MAC3C;AAAA,IACF,SAAS,KAAK;AAEZ,cAAQ;AAAA,QACN,oCAAoC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MACtF;AAAA,IACF;AAAA,EACF;AAGA,QAAM,WAAW,cAAc,YAAY,IAAI;AAC/C,QAAM,aAAqC,CAAC;AAC5C,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,OAAO,GAAG;AACtD,QAAI,OAAO,UAAU,SAAU,YAAW,GAAG,IAAI;AAAA,EACnD;AACA,MAAI,cAAc,YAAY,MAAM,UAAU,GAAG;AAC/C,UAAM,iBAAiB,cAAc,IAAI,QAAQ;AACjD,QAAI,gBAAgB;AAClB,cAAQ,IAAI,8BAA8B,eAAe,KAAK,mBAAmB;AACjF,UAAI,UAAU,eAAe,QAAQ,eAAe,OAAO;AAC3D,UAAI,IAAI,eAAe,IAAI;AAC3B;AAAA,IACF;AAAA,EACF;AAGA,QAAM,WAAW,oBAAoB,KAAK,IAAI;AAG9C,QAAM,SAAS,aAAa,UAAU,QAAQ;AAC9C,MAAI,QAAQ;AACV,QAAI,UAAU,OAAO,QAAQ,OAAO,OAAO;AAC3C,QAAI,IAAI,OAAO,IAAI;AACnB;AAAA,EACF;AAGA,QAAM,WAAW,aAAa,YAAY,QAAQ;AAClD,MAAI,UAAU;AACZ,UAAM,SAAS,MAAM;AACrB,QAAI,UAAU,OAAO,QAAQ,OAAO,OAAO;AAC3C,QAAI,IAAI,OAAO,IAAI;AACnB;AAAA,EACF;AAGA,eAAa,aAAa,QAAQ;AAKlC,MAAI;AACJ,QAAM,cAAc,YAAY;AAEhC,MAAI,WAAW,CAAC,QAAQ,oBAAoB,CAAC,aAAa;AACxD,UAAM,YAAY,eAAe,SAAS,KAAK,QAAQ,SAAS;AAChE,QAAI,WAAW;AACb,4BAAsB,OAAO,SAAS;AAItC,YAAM,qBACH,sBAAsB,OAAO,KAAK,KAAK,uBAAuB,GAAG,CAAC,IAAK;AAG1E,YAAM,cAAc,MAAM,eAAe,gBAAgB,kBAAkB;AAE3E,UAAI,YAAY,KAAK,WAAW,CAAC,YAAY,YAAY;AAGvD,cAAM,gBAAgB;AACtB,gBAAQ;AAAA,UACN,uBAAuB,YAAY,KAAK,UAAU,UAAU,cAAc,MAAM,YAAY,KAAK,UAAU,kCAAkC,UAAU,gBAAgB,aAAa;AAAA,QACtL;AACA,kBAAU;AAEV,cAAM,SAAS,KAAK,MAAM,KAAK,SAAS,CAAC;AACzC,eAAO,QAAQ;AACf,eAAO,OAAO,KAAK,KAAK,UAAU,MAAM,CAAC;AAGzC,gBAAQ,eAAe;AAAA,UACrB,YAAY,YAAY,KAAK;AAAA,UAC7B,eAAe,YAAY,KAAK;AAAA,QAClC,CAAC;AAAA,MACH,WAAW,YAAY,KAAK,OAAO;AAEjC,gBAAQ,eAAe;AAAA,UACrB,YAAY,YAAY,KAAK;AAAA,UAC7B,eAAe,YAAY,KAAK;AAAA,QAClC,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAGA,MAAI;AACJ,MAAI,mBAAmB;AAEvB,MAAI,aAAa;AAEf,QAAI,UAAU,KAAK;AAAA,MACjB,gBAAgB;AAAA,MAChB,iBAAiB;AAAA,MACjB,YAAY;AAAA,MACZ,qBAAqB,OAAO,qBAAqB;AAAA,MACjD,sBAAsB,OAAO,gBAAgB;AAAA,IAC/C,CAAC;AACD,uBAAmB;AAGnB,cAAU,KAAK,iBAAiB;AAGhC,wBAAoB,YAAY,MAAM;AACpC,UAAI,SAAS,GAAG,GAAG;AACjB,kBAAU,KAAK,iBAAiB;AAAA,MAClC,OAAO;AAEL,sBAAc,iBAAiB;AAC/B,4BAAoB;AAAA,MACtB;AAAA,IACF,GAAG,qBAAqB;AAAA,EAC1B;AAGA,QAAM,UAAkC,CAAC;AACzC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,OAAO,GAAG;AACtD,QACE,QAAQ,UACR,QAAQ,gBACR,QAAQ,uBACR,QAAQ;AAER;AACF,QAAI,OAAO,UAAU,UAAU;AAC7B,cAAQ,GAAG,IAAI;AAAA,IACjB;AAAA,EACF;AACA,MAAI,CAAC,QAAQ,cAAc,GAAG;AAC5B,YAAQ,cAAc,IAAI;AAAA,EAC5B;AACA,UAAQ,YAAY,IAAI;AAGxB,MAAI,YAAY;AAChB,MAAI,GAAG,SAAS,MAAM;AACpB,QAAI,mBAAmB;AACrB,oBAAc,iBAAiB;AAC/B,0BAAoB;AAAA,IACtB;AAEA,QAAI,CAAC,WAAW;AACd,mBAAa,eAAe,QAAQ;AAAA,IACtC;AAAA,EACF,CAAC;AAGD,QAAM,YAAY,QAAQ,oBAAoB;AAC9C,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,YAAY,WAAW,MAAM,WAAW,MAAM,GAAG,SAAS;AAEhE,MAAI;AAIF,QAAI;AACJ,QAAI,iBAAiB;AAEnB,YAAM,uBAAuB,KAAK,KAAK,KAAK,SAAS,CAAC;AACtD,YAAM,uBAAuB,uBAAuB;AAIpD,YAAM,eAAe,MAAM;AACzB,YAAI,gBAAgB,WAAW,SAAS,SAAS,KAAK,WAAW,OAAO,cAAc;AACpF,iBAAO,WAAW,OAAO;AAAA,QAC3B;AACA,YAAI,mBAAmB,SAAS,WAAW,OAAO,UAAU;AAC1D,iBAAO,WAAW,OAAO;AAAA,QAC3B;AACA,YAAI,mBAAmB,aAAa,WAAW,OAAO,cAAc;AAClE,iBAAO,WAAW,OAAO;AAAA,QAC3B;AACA,eAAO,WAAW,OAAO;AAAA,MAC3B,GAAG;AAGH,YAAM,YAAY,iBAAiB,gBAAgB,MAAM,WAAW;AACpE,YAAM,kBAAkB;AAAA,QACtB,gBAAgB;AAAA,QAChB;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAGA,YAAM,kBAAkB,UAAU,OAAO,CAAC,MAAM,CAAC,gBAAgB,SAAS,CAAC,CAAC;AAC5E,UAAI,gBAAgB,SAAS,GAAG;AAC9B,gBAAQ;AAAA,UACN,iCAAiC,oBAAoB,sBAAsB,gBAAgB,KAAK,IAAI,CAAC;AAAA,QACvG;AAAA,MACF;AAKA,YAAM,eAAe,oBAAoB,iBAAiB,UAAU,mBAAmB;AACvF,YAAM,eAAe,gBAAgB,OAAO,CAAC,MAAM,CAAC,aAAa,SAAS,CAAC,CAAC;AAC5E,UAAI,aAAa,SAAS,GAAG;AAC3B,gBAAQ;AAAA,UACN,8CAA8C,aAAa,KAAK,IAAI,CAAC;AAAA,QACvE;AAAA,MACF;AAGA,YAAM,iBAAiB,eAAe,cAAc,WAAW,cAAc;AAC7E,YAAM,iBAAiB,aAAa,OAAO,CAAC,MAAM,CAAC,eAAe,SAAS,CAAC,CAAC;AAC7E,UAAI,eAAe,SAAS,GAAG;AAC7B,gBAAQ;AAAA,UACN,wCAAwC,eAAe,KAAK,IAAI,CAAC;AAAA,QACnE;AAAA,MACF;AAGA,oBAAc,eAAe,MAAM,GAAG,qBAAqB;AAG3D,oBAAc,yBAAyB,WAAW;AAAA,IACpD,OAAO;AAEL,oBAAc,UAAU,CAAC,OAAO,IAAI,CAAC;AAAA,IACvC;AAKA,QAAI,CAAC,YAAY,SAAS,UAAU,GAAG;AACrC,kBAAY,KAAK,UAAU;AAAA,IAC7B;AAGA,QAAI;AACJ,QAAI;AACJ,QAAI,kBAAkB;AAEtB,aAAS,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK;AAC3C,YAAM,WAAW,YAAY,CAAC;AAC9B,YAAM,gBAAgB,MAAM,YAAY,SAAS;AAEjD,cAAQ,IAAI,6BAA6B,IAAI,CAAC,IAAI,YAAY,MAAM,KAAK,QAAQ,EAAE;AAEnF,YAAM,SAAS,MAAM;AAAA,QACnB;AAAA,QACA,IAAI,UAAU;AAAA,QACd;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,WAAW;AAAA,MACb;AAEA,UAAI,OAAO,WAAW,OAAO,UAAU;AACrC,mBAAW,OAAO;AAClB,0BAAkB;AAClB,gBAAQ,IAAI,oCAAoC,QAAQ,EAAE;AAC1D;AAAA,MACF;AAGA,kBAAY;AAAA,QACV,MAAM,OAAO,aAAa;AAAA,QAC1B,QAAQ,OAAO,eAAe;AAAA,MAChC;AAGA,UAAI,OAAO,mBAAmB,CAAC,eAAe;AAE5C,YAAI,OAAO,gBAAgB,KAAK;AAC9B,0BAAgB,QAAQ;AAAA,QAC1B;AAKA,cAAM,eAAe,qDAAqD;AAAA,UACxE,OAAO,aAAa;AAAA,QACtB;AACA,YAAI,gBAAgB,aAAa,YAAY;AAC3C,gBAAM,UAAU,YAAY,QAAQ,UAAU;AAC9C,cAAI,UAAU,IAAI,GAAG;AACnB,oBAAQ,IAAI,6DAAwD,UAAU,EAAE;AAChF,gBAAI,UAAU;AACd;AAAA,UACF;AAAA,QACF;AAEA,gBAAQ;AAAA,UACN,oCAAoC,QAAQ,sBAAsB,OAAO,WAAW,MAAM,GAAG,GAAG,CAAC;AAAA,QACnG;AACA;AAAA,MACF;AAGA,UAAI,CAAC,OAAO,iBAAiB;AAC3B,gBAAQ;AAAA,UACN,wCAAwC,QAAQ,mBAAmB,OAAO,WAAW,MAAM,GAAG,GAAG,CAAC;AAAA,QACpG;AAAA,MACF;AACA;AAAA,IACF;AAGA,iBAAa,SAAS;AAGtB,QAAI,mBAAmB;AACrB,oBAAc,iBAAiB;AAC/B,0BAAoB;AAAA,IACtB;AAKA,QAAI,aAAa,oBAAoB,iBAAiB;AACpD,YAAM,eAAe,gCAAgC,kBAAkB,MAAM,SAAS,gBAAgB,IAAI,UAAU,eAAe,YAAY,gBAAgB,cAAc,QAAQ,CAAC,KAAK,KAAK,eAAe,gBAAgB,WAAW,QAAQ,CAAC,CAAC,cAAc,gBAAgB,SAAS;AAAA;AAAA;AAC3R,gBAAU,KAAK,YAAY;AAAA,IAC7B;AAIA,QAAI,mBAAmB,oBAAoB,gBAAgB,OAAO;AAChE,YAAM,uBAAuB,KAAK,KAAK,KAAK,SAAS,CAAC;AACtD,YAAM,WAAW;AAAA,QACf;AAAA,QACA,WAAW;AAAA,QACX;AAAA,QACA;AAAA,QACA,kBAAkB;AAAA,MACpB;AACA,wBAAkB;AAAA,QAChB,GAAG;AAAA,QACH,OAAO;AAAA,QACP,WAAW,GAAG,gBAAgB,SAAS,kBAAkB,eAAe;AAAA,QACxE,cAAc,SAAS;AAAA,QACvB,cAAc,SAAS;AAAA,QACvB,SAAS,SAAS;AAAA,MACpB;AACA,cAAQ,WAAW,eAAe;AAKlC,UAAI,oBAAoB;AACtB,qBAAa,WAAW,oBAAoB,iBAAiB,gBAAgB,IAAI;AACjF,gBAAQ;AAAA,UACN,wBAAwB,mBAAmB,MAAM,GAAG,CAAC,CAAC,gCAAgC,eAAe;AAAA,QACvG;AAAA,MACF;AAAA,IACF;AAGA,QAAI,CAAC,UAAU;AACb,YAAM,aAAa,WAAW,QAAQ;AACtC,YAAM,YAAY,WAAW,UAAU;AAGvC,YAAM,iBAAiB,sBAAsB,UAAU;AAEvD,UAAI,kBAAkB;AAGpB,YAAI;AACJ,YAAI;AACF,gBAAM,SAAS,KAAK,MAAM,cAAc;AACxC,uBAAa,KAAK,UAAU,MAAM;AAAA,QACpC,QAAQ;AACN,uBAAa,KAAK,UAAU;AAAA,YAC1B,OAAO,EAAE,SAAS,YAAY,MAAM,kBAAkB,QAAQ,UAAU;AAAA,UAC1E,CAAC;AAAA,QACH;AACA,cAAM,WAAW,SAAS,UAAU;AAAA;AAAA;AACpC,kBAAU,KAAK,QAAQ;AACvB,kBAAU,KAAK,kBAAkB;AACjC,YAAI,IAAI;AAER,cAAM,SAAS,OAAO,KAAK,WAAW,kBAAkB;AACxD,qBAAa,SAAS,UAAU;AAAA,UAC9B,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,oBAAoB;AAAA,UAC/C,MAAM;AAAA,UACN,aAAa,KAAK,IAAI;AAAA,QACxB,CAAC;AAAA,MACH,OAAO;AAEL,YAAI,UAAU,WAAW;AAAA,UACvB,gBAAgB;AAAA,UAChB,qBAAqB,OAAO,qBAAqB;AAAA,UACjD,sBAAsB,OAAO,gBAAgB;AAAA,QAC/C,CAAC;AACD,YAAI,IAAI,cAAc;AAEtB,qBAAa,SAAS,UAAU;AAAA,UAC9B,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,UAC9C,MAAM,OAAO,KAAK,cAAc;AAAA,UAChC,aAAa,KAAK,IAAI;AAAA,QACxB,CAAC;AAAA,MACH;AACA;AAAA,IACF;AAGA,UAAM,iBAA2B,CAAC;AAElC,QAAI,kBAAkB;AAQpB,UAAI,SAAS,MAAM;AACjB,cAAM,SAAS,SAAS,KAAK,UAAU;AACvC,cAAM,SAAuB,CAAC;AAC9B,YAAI;AACF,iBAAO,MAAM;AACX,kBAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,gBAAI,KAAM;AACV,mBAAO,KAAK,KAAK;AAAA,UACnB;AAAA,QACF,UAAE;AACA,iBAAO,YAAY;AAAA,QACrB;AAGA,cAAM,WAAW,OAAO,OAAO,MAAM;AACrC,cAAM,UAAU,SAAS,SAAS;AAClC,YAAI;AACF,gBAAM,MAAM,KAAK,MAAM,OAAO;AAgC9B,gBAAM,YAAY;AAAA,YAChB,IAAI,IAAI,MAAM,YAAY,KAAK,IAAI,CAAC;AAAA,YACpC,QAAQ;AAAA,YACR,SAAS,IAAI,WAAW,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AAAA,YACpD,OAAO,IAAI,SAAS;AAAA,YACpB,oBAAoB;AAAA,UACtB;AAGA,cAAI,IAAI,WAAW,MAAM,QAAQ,IAAI,OAAO,GAAG;AAC7C,uBAAW,UAAU,IAAI,SAAS;AAEhC,oBAAM,aAAa,OAAO,SAAS,WAAW,OAAO,OAAO,WAAW;AACvE,oBAAM,UAAU,oBAAoB,UAAU;AAC9C,oBAAM,OAAO,OAAO,SAAS,QAAQ,OAAO,OAAO,QAAQ;AAC3D,oBAAM,QAAQ,OAAO,SAAS;AAG9B,kBAAI,SAAS;AACX,sCAAsB;AAAA,cACxB;AAGA,oBAAM,YAAY;AAAA,gBAChB,GAAG;AAAA,gBACH,SAAS,CAAC,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,UAAU,MAAM,eAAe,KAAK,CAAC;AAAA,cAC3E;AACA,oBAAM,WAAW,SAAS,KAAK,UAAU,SAAS,CAAC;AAAA;AAAA;AACnD,wBAAU,KAAK,QAAQ;AACvB,6BAAe,KAAK,OAAO,KAAK,QAAQ,CAAC;AAGzC,kBAAI,SAAS;AACX,sBAAM,eAAe;AAAA,kBACnB,GAAG;AAAA,kBACH,SAAS,CAAC,EAAE,OAAO,OAAO,EAAE,QAAQ,GAAG,UAAU,MAAM,eAAe,KAAK,CAAC;AAAA,gBAC9E;AACA,sBAAM,cAAc,SAAS,KAAK,UAAU,YAAY,CAAC;AAAA;AAAA;AACzD,0BAAU,KAAK,WAAW;AAC1B,+BAAe,KAAK,OAAO,KAAK,WAAW,CAAC;AAAA,cAC9C;AAGA,oBAAM,YAAY,OAAO,SAAS,cAAc,OAAO,OAAO;AAC9D,kBAAI,aAAa,UAAU,SAAS,GAAG;AACrC,sBAAM,gBAAgB;AAAA,kBACpB,GAAG;AAAA,kBACH,SAAS;AAAA,oBACP;AAAA,sBACE;AAAA,sBACA,OAAO,EAAE,YAAY,UAAU;AAAA,sBAC/B,UAAU;AAAA,sBACV,eAAe;AAAA,oBACjB;AAAA,kBACF;AAAA,gBACF;AACA,sBAAM,eAAe,SAAS,KAAK,UAAU,aAAa,CAAC;AAAA;AAAA;AAC3D,0BAAU,KAAK,YAAY;AAC3B,+BAAe,KAAK,OAAO,KAAK,YAAY,CAAC;AAAA,cAC/C;AAGA,oBAAM,cAAc;AAAA,gBAClB,GAAG;AAAA,gBACH,SAAS;AAAA,kBACP;AAAA,oBACE;AAAA,oBACA,OAAO,CAAC;AAAA,oBACR,UAAU;AAAA,oBACV,eACE,aAAa,UAAU,SAAS,IAC5B,eACC,OAAO,iBAAiB;AAAA,kBACjC;AAAA,gBACF;AAAA,cACF;AACA,oBAAM,aAAa,SAAS,KAAK,UAAU,WAAW,CAAC;AAAA;AAAA;AACvD,wBAAU,KAAK,UAAU;AACzB,6BAAe,KAAK,OAAO,KAAK,UAAU,CAAC;AAAA,YAC7C;AAAA,UACF;AAAA,QACF,QAAQ;AAEN,gBAAM,UAAU,SAAS,OAAO;AAAA;AAAA;AAChC,oBAAU,KAAK,OAAO;AACtB,yBAAe,KAAK,OAAO,KAAK,OAAO,CAAC;AAAA,QAC1C;AAAA,MACF;AAGA,gBAAU,KAAK,kBAAkB;AACjC,qBAAe,KAAK,OAAO,KAAK,kBAAkB,CAAC;AACnD,UAAI,IAAI;AAGR,mBAAa,SAAS,UAAU;AAAA,QAC9B,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,oBAAoB;AAAA,QAC/C,MAAM,OAAO,OAAO,cAAc;AAAA,QAClC,aAAa,KAAK,IAAI;AAAA,MACxB,CAAC;AAAA,IACH,OAAO;AAEL,YAAM,kBAA0C,CAAC;AACjD,eAAS,QAAQ,QAAQ,CAAC,OAAO,QAAQ;AAEvC,YAAI,QAAQ,uBAAuB,QAAQ,gBAAgB,QAAQ;AACjE;AACF,wBAAgB,GAAG,IAAI;AAAA,MACzB,CAAC;AAGD,sBAAgB,mBAAmB,IAAI,OAAO,qBAAqB;AACnE,sBAAgB,oBAAoB,IAAI,OAAO,gBAAgB;AAG/D,UAAI,aAAa,iBAAiB;AAChC,wBAAgB,sBAAsB,IAAI,kBAAkB;AAC5D,wBAAgB,mBAAmB,IAAI,gBAAgB;AACvD,wBAAgB,oBAAoB,IAAI;AACxC,wBAAgB,yBAAyB,IAAI,gBAAgB,WAAW,QAAQ,CAAC;AACjF,wBAAgB,wBAAwB,IAAI,gBAAgB;AAC5D,YAAI,gBAAgB,iBAAiB,QAAW;AAC9C,0BAAgB,4BAA4B,IAAI,gBAAgB,aAAa,QAAQ,CAAC;AAAA,QACxF;AAAA,MACF;AAEA,UAAI,UAAU,SAAS,QAAQ,eAAe;AAE9C,UAAI,SAAS,MAAM;AACjB,cAAM,SAAS,SAAS,KAAK,UAAU;AACvC,YAAI;AACF,iBAAO,MAAM;AACX,kBAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,gBAAI,KAAM;AACV,kBAAM,QAAQ,OAAO,KAAK,KAAK;AAC/B,sBAAU,KAAK,KAAK;AACpB,2BAAe,KAAK,KAAK;AAAA,UAC3B;AAAA,QACF,UAAE;AACA,iBAAO,YAAY;AAAA,QACrB;AAAA,MACF;AAEA,UAAI,IAAI;AAER,YAAM,eAAe,OAAO,OAAO,cAAc;AAGjD,mBAAa,SAAS,UAAU;AAAA,QAC9B,QAAQ,SAAS;AAAA,QACjB,SAAS;AAAA,QACT,MAAM;AAAA,QACN,aAAa,KAAK,IAAI;AAAA,MACxB,CAAC;AAGD,UAAI,SAAS,WAAW,OAAO,cAAc,YAAY,IAAI,GAAG;AAC9D,sBAAc,IAAI,UAAU;AAAA,UAC1B,MAAM;AAAA,UACN,QAAQ,SAAS;AAAA,UACjB,SAAS;AAAA,UACT,OAAO;AAAA,QACT,CAAC;AACD,gBAAQ;AAAA,UACN,oCAAoC,eAAe,KAAK,aAAa,MAAM;AAAA,QAC7E;AAAA,MACF;AAGA,UAAI;AACF,cAAM,UAAU,KAAK,MAAM,aAAa,SAAS,CAAC;AAGlD,YAAI,QAAQ,UAAU,CAAC,GAAG,SAAS,SAAS;AAC1C,+BAAqB,QAAQ,QAAQ,CAAC,EAAE,QAAQ;AAAA,QAClD;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAGA,QAAI,aAAa,oBAAoB;AACnC,YAAM,SAAS,eAAe,cAAc,kBAAkB;AAC9D,UAAI,OAAO,SAAS,GAAG;AACrB,uBAAe,OAAO,WAAW,QAAQ,eAAe;AACxD,gBAAQ;AAAA,UACN,yBAAyB,OAAO,MAAM,0CAA0C,UAAU,MAAM,GAAG,CAAC,CAAC;AAAA,QACvG;AAAA,MACF;AAAA,IACF;AAGA,QAAI,wBAAwB,QAAW;AACrC,qBAAe,gBAAgB,mBAAmB;AAAA,IACpD;AAGA,gBAAY;AAAA,EACd,SAAS,KAAK;AAEZ,iBAAa,SAAS;AAGtB,QAAI,mBAAmB;AACrB,oBAAc,iBAAiB;AAC/B,0BAAoB;AAAA,IACtB;AAGA,iBAAa,eAAe,QAAQ;AAGpC,mBAAe,WAAW;AAG1B,QAAI,eAAe,SAAS,IAAI,SAAS,cAAc;AACrD,YAAM,IAAI,MAAM,2BAA2B,SAAS,IAAI;AAAA,IAC1D;AAEA,UAAM;AAAA,EACR;AAMA,QAAM,WAAW,iBAAiB,SAAS;AAC3C,MAAI,UAAU;AAEZ,UAAM,uBAAuB,KAAK,KAAK,KAAK,SAAS,CAAC;AACtD,UAAM,gBAAgB;AAAA,MACpB;AAAA,MACA,WAAW;AAAA,MACX;AAAA,MACA;AAAA,MACA,kBAAkB;AAAA,IACpB;AAEA,UAAM,iBAAiB,cAAc,eAAe;AACpD,UAAM,qBAAqB,cAAc,eAAe;AACxD,UAAM,QAAoB;AAAA,MACxB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,OAAO;AAAA,MACP,MAAM,iBAAiB,QAAQ;AAAA,MAC/B,MAAM;AAAA,MACN,cAAc;AAAA,MACd,SAAS,cAAc;AAAA,MACvB,WAAW,KAAK,IAAI,IAAI;AAAA,IAC1B;AACA,aAAS,KAAK,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EAChC;AACF;;;A8B97FA,SAAS,WAAW,SAAAC,cAAa;AAEjC,SAAS,QAAAC,aAAY;AACrB,SAAS,WAAAC,gBAAe;AACxB,SAAS,oBAAoB,uBAAAC,4BAA2B;AAGxD,IAAM,aAAaF,MAAKC,SAAQ,GAAG,aAAa,UAAU;AAC1D,IAAM,cAAcD,MAAK,YAAY,YAAY;AAQjD,eAAe,kBAA+C;AAC5D,MAAI;AACF,UAAM,OAAO,MAAM,aAAa,WAAW,GAAG,KAAK;AACnD,QAAI,IAAI,WAAW,IAAI,KAAK,IAAI,WAAW,IAAI;AAC7C,cAAQ,IAAI,mDAA8C,WAAW,EAAE;AACvE,aAAO;AAAA,IACT;AAGA,YAAQ,MAAM,0EAAqE;AACnF,YAAQ,MAAM,wBAAwB,WAAW,EAAE;AACnD,YAAQ,MAAM,4EAA4E;AAC1F,YAAQ;AAAA,MACN;AAAA,IACF;AACA,UAAM,IAAI;AAAA,MACR,kBAAkB,WAAW;AAAA,IAG/B;AAAA,EACF,SAAS,KAAK;AAEZ,QAAK,IAA8B,SAAS,UAAU;AAEpD,UAAI,eAAe,SAAS,IAAI,QAAQ,SAAS,2BAA2B,GAAG;AAC7E,cAAM;AAAA,MACR;AACA,cAAQ;AAAA,QACN,mDAA8C,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MAChG;AACA,YAAM,IAAI;AAAA,QACR,8BAA8B,WAAW,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MAGhG;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAMA,eAAe,wBAAmE;AAChF,QAAM,MAAM,mBAAmB;AAC/B,QAAM,UAAUG,qBAAoB,GAAG;AAGvC,QAAMC,OAAM,YAAY,EAAE,WAAW,KAAK,CAAC;AAG3C,QAAM,UAAU,aAAa,MAAM,MAAM,EAAE,MAAM,IAAM,CAAC;AAGxD,MAAI;AACF,UAAM,gBAAgB,MAAM,aAAa,WAAW,GAAG,KAAK;AAC5D,QAAI,iBAAiB,KAAK;AACxB,YAAM,IAAI,MAAM,oDAAoD;AAAA,IACtE;AACA,YAAQ,IAAI,oDAA+C,WAAW,EAAE;AAAA,EAC1E,SAAS,KAAK;AACZ,UAAM,IAAI;AAAA,MACR,gDAAgD,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IAClG;AAAA,EACF;AAGA,UAAQ,IAAI,cAAc;AAC1B,UAAQ,IAAI,+SAA+D;AAC3E,UAAQ,IAAI,iEAA4D;AACxE,UAAQ,IAAI,+SAA+D;AAC3E,UAAQ,IAAI,4BAA4B,QAAQ,OAAO,EAAE;AACzD,UAAQ,IAAI,4BAA4B,WAAW,EAAE;AACrD,UAAQ,IAAI,cAAc;AAC1B,UAAQ,IAAI,6CAA6C;AACzD,UAAQ,IAAI,iCAAiC;AAC7C,UAAQ,IAAI,cAAc;AAC1B,UAAQ,IAAI,+CAA+C;AAC3D,UAAQ,IAAI,wDAAwD;AACpE,UAAQ,IAAI,+SAA+D;AAC3E,UAAQ,IAAI,cAAc;AAE1B,SAAO,EAAE,KAAK,SAAS,QAAQ,QAAQ;AACzC;AAMA,eAAsB,6BAInB;AAED,QAAM,QAAQ,MAAM,gBAAgB;AACpC,MAAI,OAAO;AACT,UAAM,UAAUD,qBAAoB,KAAsB;AAC1D,WAAO,EAAE,KAAK,OAAO,SAAS,QAAQ,SAAS,QAAQ,QAAQ;AAAA,EACjE;AAGA,QAAM,SAAS,QAAQ,KAAK,EAAE;AAC9B,MAAI,OAAO,WAAW,YAAY,OAAO,WAAW,IAAI,KAAK,OAAO,WAAW,IAAI;AACjF,UAAM,UAAUA,qBAAoB,MAAuB;AAC3D,WAAO,EAAE,KAAK,QAAQ,SAAS,QAAQ,SAAS,QAAQ,MAAM;AAAA,EAChE;AAGA,QAAM,EAAE,KAAK,QAAQ,IAAI,MAAM,sBAAsB;AACrD,SAAO,EAAE,KAAK,SAAS,QAAQ,YAAY;AAC7C;;;AClJA,SAAS,UAAU,MAAM,SAAS,gBAAgB;AAiDlD,SAAS,YAAY,OAAuB;AAC1C,QAAM,KAAK,SAAS,OAAO,OAAO;AAClC,SAAO,GAAG,GAAG,QAAQ,CAAC,CAAC;AACzB;AAEA,SAAS,MAAM,MAAsB;AACnC,SAAO,yBAAoB,IAAI;AACjC;AAEA,SAAS,IAAI,MAAsB;AACjC,SAAO,yBAAoB,IAAI;AACjC;AAEA,SAAS,OAAO,MAAsB;AACpC,SAAO,yBAAoB,IAAI;AACjC;AAGA,SAAS,oBAAgC;AACvC,SAAO;AAAA,IACL,IAAI,GAAG,SAAS,CAAC,IAAI,KAAK,CAAC;AAAA,IAC3B,MAAM,KAAK;AAAA,IACX,aAAa,QAAQ;AAAA,IACrB,YAAY,YAAY,QAAQ,CAAC;AAAA,IACjC,aAAa,YAAY,SAAS,CAAC;AAAA,EACrC;AACF;AAGA,eAAe,oBAAyC;AACtD,MAAI;AACF,UAAM,EAAE,KAAK,SAAS,OAAO,IAAI,MAAM,2BAA2B;AAElE,QAAI,CAAC,OAAO,CAAC,SAAS;AACpB,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,SAAS;AAAA,QACT,SAAS;AAAA,QACT,OAAO;AAAA,QACP,SAAS;AAAA,QACT,QAAQ;AAAA,MACV;AAAA,IACF;AAGA,UAAM,UAAU,IAAI,eAAe,OAAO;AAC1C,QAAI;AACF,YAAM,cAAc,MAAM,QAAQ,aAAa;AAC/C,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,OAAO;AAAA,QACP;AAAA,QACA,SAAS,YAAY;AAAA,QACrB,OAAO,YAAY;AAAA,QACnB,SAAS,YAAY;AAAA,QACrB;AAAA,MACF;AAAA,IACF,QAAQ;AACN,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,OAAO;AAAA,QACP;AAAA,QACA,SAAS;AAAA,QACT,OAAO;AAAA,QACP,SAAS;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,SAAS;AAAA,MACT,SAAS;AAAA,MACT,OAAO;AAAA,MACP,SAAS;AAAA,MACT,QAAQ;AAAA,IACV;AAAA,EACF;AACF;AAGA,eAAe,qBAA2C;AACxD,QAAM,OAAO,aAAa;AAG1B,MAAI,oBAAoB;AACxB,MAAI,kBAAiC;AACrC,MAAI;AACF,UAAM,QAAQ,KAAK,IAAI;AACvB,UAAM,WAAW,MAAM,MAAM,qCAAqC;AAAA,MAChE,QAAQ;AAAA,MACR,QAAQ,YAAY,QAAQ,GAAK;AAAA,IACnC,CAAC;AACD,sBAAkB,KAAK,IAAI,IAAI;AAC/B,wBAAoB,SAAS,MAAM,SAAS,WAAW;AAAA,EACzD,QAAQ;AACN,wBAAoB;AAAA,EACtB;AAGA,MAAI,eAAe;AACnB,MAAI;AACF,UAAM,WAAW,MAAM,MAAM,oBAAoB,IAAI,WAAW;AAAA,MAC9D,QAAQ;AAAA,MACR,QAAQ,YAAY,QAAQ,GAAI;AAAA,IAClC,CAAC;AACD,mBAAe,SAAS;AAAA,EAC1B,QAAQ;AACN,mBAAe;AAAA,EACjB;AAEA,SAAO;AAAA,IACL,aAAa,EAAE,WAAW,mBAAmB,WAAW,gBAAgB;AAAA,IACxE,YAAY,EAAE,SAAS,cAAc,KAAK;AAAA,EAC5C;AACF;AAGA,eAAe,iBAAmC;AAChD,MAAI;AACF,UAAM,QAAQ,MAAM,SAAS,CAAC;AAC9B,WAAO;AAAA,MACL,iBAAiB,MAAM;AAAA,MACvB,aAAa,IAAI,MAAM,UAAU,QAAQ,CAAC,CAAC;AAAA,MAC3C,aAAa;AAAA;AAAA,IACf;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,MACL,iBAAiB;AAAA,MACjB,aAAa;AAAA,MACb,aAAa;AAAA,IACf;AAAA,EACF;AACF;AAGA,SAAS,eAAe,QAAoC;AAC1D,QAAM,SAAmB,CAAC;AAE1B,MAAI,CAAC,OAAO,OAAO,QAAQ;AACzB,WAAO,KAAK,iBAAiB;AAAA,EAC/B;AACA,MAAI,OAAO,OAAO,SAAS;AACzB,WAAO,KAAK,kDAAkD;AAAA,EAChE,WAAW,OAAO,OAAO,OAAO;AAC9B,WAAO,KAAK,iCAAiC;AAAA,EAC/C;AACA,MAAI,CAAC,OAAO,QAAQ,YAAY,WAAW;AACzC,WAAO,KAAK,uDAAuD;AAAA,EACrE;AACA,MAAI,CAAC,OAAO,QAAQ,WAAW,SAAS;AACtC,WAAO,KAAK,mCAAmC,OAAO,QAAQ,WAAW,IAAI,EAAE;AAAA,EACjF;AAEA,SAAO;AACT;AAGA,SAAS,iBAAiB,QAAgC;AACxD,UAAQ,IAAI,yCAAkC;AAG9C,UAAQ,IAAI,QAAQ;AACpB,UAAQ,IAAI,KAAK,MAAM,OAAO,OAAO,OAAO,EAAE,EAAE,CAAC,EAAE;AACnD,UAAQ,IAAI,KAAK,MAAM,SAAS,OAAO,OAAO,WAAW,EAAE,CAAC,EAAE;AAC9D,UAAQ;AAAA,IACN,KAAK,MAAM,WAAW,OAAO,OAAO,UAAU,WAAW,OAAO,OAAO,WAAW,EAAE,CAAC;AAAA,EACvF;AAGA,UAAQ,IAAI,UAAU;AACtB,MAAI,OAAO,OAAO,UAAU,OAAO,OAAO,OAAO;AAC/C,YAAQ,IAAI,KAAK,MAAM,QAAQ,WAAW,KAAK,OAAO,OAAO,MAAM,GAAG,CAAC,EAAE;AACzE,YAAQ,IAAI,KAAK,MAAM,YAAY,OAAO,OAAO,OAAO,EAAE,CAAC,EAAE;AAC7D,QAAI,OAAO,OAAO,SAAS;AACzB,cAAQ,IAAI,KAAK,IAAI,gCAAgC,CAAC,EAAE;AAAA,IAC1D,WAAW,OAAO,OAAO,OAAO;AAC9B,cAAQ,IAAI,KAAK,OAAO,YAAY,OAAO,OAAO,OAAO,QAAQ,CAAC,EAAE;AAAA,IACtE,WAAW,OAAO,OAAO,SAAS;AAChC,cAAQ,IAAI,KAAK,MAAM,YAAY,OAAO,OAAO,OAAO,EAAE,CAAC,EAAE;AAAA,IAC/D,OAAO;AACL,cAAQ,IAAI,KAAK,OAAO,sBAAsB,CAAC,EAAE;AAAA,IACnD;AAAA,EACF,OAAO;AACL,YAAQ,IAAI,KAAK,IAAI,iBAAiB,CAAC,EAAE;AAAA,EAC3C;AAGA,UAAQ,IAAI,WAAW;AACvB,MAAI,OAAO,QAAQ,YAAY,WAAW;AACxC,YAAQ;AAAA,MACN,KAAK,MAAM,4BAA4B,OAAO,QAAQ,YAAY,SAAS,KAAK,CAAC;AAAA,IACnF;AAAA,EACF,OAAO;AACL,YAAQ,IAAI,KAAK,IAAI,2BAA2B,CAAC,EAAE;AAAA,EACrD;AACA,MAAI,OAAO,QAAQ,WAAW,SAAS;AACrC,YAAQ,IAAI,KAAK,MAAM,4BAA4B,OAAO,QAAQ,WAAW,IAAI,EAAE,CAAC,EAAE;AAAA,EACxF,OAAO;AACL,YAAQ,IAAI,KAAK,IAAI,gCAAgC,OAAO,QAAQ,WAAW,IAAI,EAAE,CAAC,EAAE;AAAA,EAC1F;AAGA,UAAQ,IAAI,QAAQ;AACpB,UAAQ;AAAA,IACN,KAAK,MAAM,aAAa,OAAO,KAAK,eAAe,cAAc,OAAO,KAAK,WAAW,QAAQ,CAAC;AAAA,EACnG;AACA,MAAI,OAAO,KAAK,cAAc,GAAG;AAC/B,YAAQ,IAAI,KAAK,OAAO,GAAG,OAAO,KAAK,WAAW,uBAAuB,CAAC,EAAE;AAAA,EAC9E;AAGA,MAAI,OAAO,OAAO,SAAS,GAAG;AAC5B,YAAQ,IAAI,+BAAqB;AACjC,eAAW,SAAS,OAAO,QAAQ;AACjC,cAAQ,IAAI,YAAO,KAAK,EAAE;AAAA,IAC5B;AAAA,EACF;AACF;AAKA,IAAM,gBAAiF;AAAA,EACrF,QAAQ;AAAA,IACN,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,MAAM;AAAA,IACJ,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AACF;AAGA,eAAe,cACb,aACA,cACA,QAAqB,UACN;AAEf,MAAI,YAAY,OAAO,SAAS;AAC9B,YAAQ,IAAI,4DAAqD;AACjE,YAAQ,IAAI,0CAA0C,YAAY,OAAO,OAAO,EAAE;AAClF,YAAQ,IAAI,sDAAsD;AAClE,YAAQ,IAAI,8CAA8C;AAC1D;AAAA,EACF;AAEA,QAAM,cAAc,cAAc,KAAK;AACvC,UAAQ,IAAI;AAAA,uBAAmB,YAAY,IAAI,KAAK,YAAY,IAAI;AAAA,CAAQ;AAE5E,MAAI;AACF,UAAM,EAAE,IAAI,IAAI,MAAM,2BAA2B;AACjD,UAAM,EAAE,OAAO,aAAa,IAAI,mBAAmB,GAAoB;AAEvE,UAAM,WAAW,MAAM;AAAA,MACrB;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU;AAAA,UACnB,OAAO,YAAY;AAAA,UACnB,QAAQ;AAAA,UACR,UAAU;AAAA,YACR;AAAA,cACE,MAAM;AAAA,cACN,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAOX;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,SAAS,eACL;AAAA;AAAA,EAAsC,KAAK,UAAU,aAAa,MAAM,CAAC,CAAC;AAAA;AAAA,mBAAwB,YAAY,KAC9G;AAAA;AAAA,EAAsC,KAAK,UAAU,aAAa,MAAM,CAAC,CAAC;AAAA;AAAA;AAAA,YAChF;AAAA,UACF;AAAA,UACA,YAAY;AAAA,QACd,CAAC;AAAA,MACH;AAAA,MACA;AAAA,IACF;AAEA,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,OAAO,MAAM,SAAS,KAAK;AACjC,cAAQ,IAAI,UAAU,SAAS,MAAM,MAAM,IAAI,EAAE;AACjD;AAAA,IACF;AAEA,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,UAAM,UAAU,KAAK,UAAU,CAAC,GAAG,SAAS;AAE5C,QAAI,SAAS;AACX,cAAQ,IAAI,0BAAmB;AAC/B,cAAQ,IAAI,OAAO;AACnB,cAAQ,IAAI;AAAA,IACd,OAAO;AACL,cAAQ,IAAI,4BAA4B;AAAA,IAC1C;AAAA,EACF,SAAS,KAAK;AACZ,YAAQ,IAAI;AAAA,oBAAuB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AACrF,YAAQ,IAAI,2CAA2C;AAAA,EACzD;AACF;AAGA,eAAsB,UACpB,cACA,QAA2B,UACZ;AACf,UAAQ,IAAI;AAAA,6BAAyB,OAAO;AAAA,CAAI;AAGhD,QAAM,CAAC,QAAQ,QAAQ,SAAS,IAAI,IAAI,MAAM,QAAQ,IAAI;AAAA,IACxD,kBAAkB;AAAA,IAClB,kBAAkB;AAAA,IAClB,mBAAmB;AAAA,IACnB,eAAe;AAAA,EACjB,CAAC;AAED,QAAM,SAA2B;AAAA,IAC/B,SAAS;AAAA,IACT,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ,CAAC;AAAA,EACX;AAGA,SAAO,SAAS,eAAe,MAAM;AAGrC,mBAAiB,MAAM;AAGvB,QAAM,cAAc,QAAQ,cAAc,KAAK;AACjD;;;ACnWO,IAAM,mBAA+C;AAAA,EAC1D;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,aACE;AAAA,IAMF,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,QAAQ;AAAA,MACN;AAAA,QACE,MAAM;AAAA,QACN,MAAM;AAAA,QACN,aACE;AAAA,QACF,UAAU;AAAA,MACZ;AAAA,IACF;AAAA,IACA,SAAS;AAAA,MACP,SAAS;AAAA,MACT,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS;AAAA,IACX;AAAA,IACA,SAAS;AAAA,MACP,OAAO,EAAE,WAAW,CAAC,YAAY,SAAS,WAAW,EAAE;AAAA,MACvD,aAAa;AAAA,IACf;AAAA,EACF;AACF;;;AC5DA,SAAS,YAAkB;AACzB,UAAQ,IAAI;AAAA,cACA,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kDAU6B,aAAa,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CA6B/D;AACD;AAEA,SAAS,UAAU,MAOjB;AACA,QAAM,SAAS;AAAA,IACb,SAAS;AAAA,IACT,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,cAAc;AAAA,IACd,MAAM;AAAA,EACR;AAEA,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,MAAM,KAAK,CAAC;AAClB,QAAI,QAAQ,eAAe,QAAQ,MAAM;AACvC,aAAO,UAAU;AAAA,IACnB,WAAW,QAAQ,YAAY,QAAQ,MAAM;AAC3C,aAAO,OAAO;AAAA,IAChB,WAAW,QAAQ,YAAY,QAAQ,YAAY;AACjD,aAAO,SAAS;AAAA,IAClB,WAAW,QAAQ,YAAY;AAC7B,aAAO,WAAW;AAElB,UAAI,KAAK,IAAI,CAAC,MAAM,QAAQ;AAC1B,eAAO,eAAe;AACtB;AAAA,MACF;AAAA,IACF,WAAW,QAAQ,YAAY,KAAK,IAAI,CAAC,GAAG;AAC1C,aAAO,OAAO,SAAS,KAAK,IAAI,CAAC,GAAG,EAAE;AACtC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEA,eAAe,OAAsB;AACnC,QAAM,OAAO,UAAU,QAAQ,KAAK,MAAM,CAAC,CAAC;AAE5C,MAAI,KAAK,SAAS;AAChB,YAAQ,IAAI,OAAO;AACnB,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI,KAAK,MAAM;AACb,cAAU;AACV,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI,KAAK,QAAQ;AAEf,UAAM,UAAU,QAAQ,KAAK,MAAM,CAAC;AACpC,UAAM,cAAc,QAAQ,UAAU,CAAC,MAAM,MAAM,YAAY,MAAM,UAAU;AAC/E,UAAM,cAAc,QAAQ,MAAM,cAAc,CAAC;AAGjD,QAAI,QAA2B;AAC/B,QAAI,eAAe;AAEnB,QAAI,YAAY,CAAC,MAAM,QAAQ;AAC7B,cAAQ;AACR,qBAAe,YAAY,MAAM,CAAC;AAAA,IACpC,WAAW,YAAY,CAAC,MAAM,UAAU;AACtC,cAAQ;AACR,qBAAe,YAAY,MAAM,CAAC;AAAA,IACpC;AAEA,UAAM,eAAe,aAAa,KAAK,GAAG,EAAE,KAAK,KAAK;AACtD,UAAM,UAAU,cAAc,KAAK;AACnC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI,KAAK,UAAU;AACjB,QAAI,iBAAiB,WAAW,GAAG;AACjC,cAAQ,IAAI,4BAA4B;AACxC,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,YAAQ,IAAI;AAAA,4BAA+B,OAAO;AAAA,CAAK;AAEvD,eAAW,OAAO,kBAAkB;AAClC,cAAQ,IAAI,KAAK,IAAI,IAAI,KAAK,IAAI,OAAO,GAAG;AAC5C,cAAQ,IAAI,OAAO,IAAI,WAAW,EAAE;AACpC,cAAQ,IAAI,yBAAyB,IAAI,EAAE,EAAE;AAC7C,cAAQ,IAAI,gBAAgB,IAAI,MAAM,OAAO,IAAI,SAAS,EAAE;AAC5D,cAAQ;AAAA,QACN,gBAAgB,IAAI,QAAQ,OAAO,QAAQ,IAAI,QAAQ,IAAI,SAAS,IAAI,QAAQ,OAAO,SAAS,IAAI,QAAQ,OAAO;AAAA,MACrH;AACA,cAAQ,IAAI;AAAA,IACd;AAEA,QAAI,KAAK,cAAc;AACrB,cAAQ,IAAI,gCAAgC;AAC5C,YAAM,UAAU;AAChB,iBAAW,OAAO,kBAAkB;AAClC,cAAM,MAAM,GAAG,OAAO,MAAM,IAAI,SAAS;AACzC,YAAI;AACF,gBAAM,WAAW,MAAM,MAAM,KAAK,EAAE,QAAQ,MAAM,CAAC;AACnD,gBAAM,SAAS,SAAS;AACxB,gBAAM,KAAK,WAAW,MAAM,mCAAmC,UAAU,MAAM;AAC/E,kBAAQ,IAAI,KAAK,IAAI,EAAE,KAAK,EAAE,EAAE;AAAA,QAClC,SAAS,KAAK;AACZ,kBAAQ,IAAI,KAAK,IAAI,EAAE,aAAa,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAAA,QACxF;AAAA,MACF;AACA,cAAQ,IAAI;AAAA,IACd;AAEA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,EAAE,KAAK,WAAW,SAAS,OAAO,IAAI,MAAM,2BAA2B;AAE7E,MAAI,WAAW,aAAa;AAC1B,YAAQ,IAAI,sCAAsC,OAAO,EAAE;AAAA,EAC7D,WAAW,WAAW,SAAS;AAC7B,YAAQ,IAAI,oCAAoC,OAAO,EAAE;AAAA,EAC3D,OAAO;AACL,YAAQ,IAAI,uDAAuD,OAAO,EAAE;AAAA,EAC9E;AAGA,QAAM,QAAQ,MAAM,WAAW;AAAA,IAC7B;AAAA,IACA,MAAM,KAAK;AAAA,IACX,SAAS,CAAC,SAAS;AACjB,cAAQ,IAAI,oDAAoD,IAAI,EAAE;AACtE,cAAQ,IAAI,+CAA+C,IAAI,SAAS;AAAA,IAC1E;AAAA,IACA,SAAS,CAAC,UAAU;AAClB,cAAQ,MAAM,uBAAuB,MAAM,OAAO,EAAE;AAAA,IACtD;AAAA,IACA,UAAU,CAAC,aAAa;AACtB,YAAM,OAAO,SAAS,aAAa,QAAQ,CAAC;AAC5C,YAAM,SAAS,SAAS,UAAU,KAAK,QAAQ,CAAC;AAChD,cAAQ,IAAI,iBAAiB,SAAS,IAAI,KAAK,SAAS,KAAK,KAAK,IAAI,WAAW,KAAK,IAAI;AAAA,IAC5F;AAAA,IACA,cAAc,CAAC,SAAS;AACtB,cAAQ,KAAK,6BAA6B,KAAK,UAAU,WAAW,KAAK,aAAa,EAAE;AAAA,IAC1F;AAAA,IACA,qBAAqB,CAAC,SAAS;AAC7B,cAAQ;AAAA,QACN,6CAA6C,KAAK,UAAU,WAAW,KAAK,WAAW;AAAA,MACzF;AACA,cAAQ,MAAM,8DAA8D;AAAA,IAC9E;AAAA,EACF,CAAC;AAGD,QAAM,UAAU,IAAI,eAAe,OAAO;AAC1C,MAAI;AACF,UAAM,UAAU,MAAM,QAAQ,aAAa;AAC3C,QAAI,QAAQ,SAAS;AACnB,cAAQ,IAAI,uDAAuD;AACnE,cAAQ,IAAI,gDAAgD,OAAO,EAAE;AAAA,IACvE,WAAW,QAAQ,OAAO;AACxB,cAAQ,IAAI,gCAAgC,QAAQ,UAAU,QAAQ;AAAA,IACxE,OAAO;AACL,cAAQ,IAAI,gCAAgC,QAAQ,UAAU,EAAE;AAAA,IAClE;AAAA,EACF,QAAQ;AACN,YAAQ,IAAI,wBAAwB,OAAO,0BAA0B;AAAA,EACvE;AAEA,UAAQ,IAAI,qCAAqC;AAGjD,QAAM,WAAW,OAAO,WAAmB;AACzC,YAAQ,IAAI;AAAA,wBAA2B,MAAM,oBAAoB;AACjE,QAAI;AACF,YAAM,MAAM,MAAM;AAClB,cAAQ,IAAI,2BAA2B;AACvC,cAAQ,KAAK,CAAC;AAAA,IAChB,SAAS,KAAK;AACZ,cAAQ,MAAM,uCAAuC,GAAG,EAAE;AAC1D,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AAEA,UAAQ,GAAG,UAAU,MAAM,SAAS,QAAQ,CAAC;AAC7C,UAAQ,GAAG,WAAW,MAAM,SAAS,SAAS,CAAC;AAG/C,QAAM,IAAI,QAAQ,MAAM;AAAA,EAAC,CAAC;AAC5B;AAEA,KAAK,EAAE,MAAM,CAAC,QAAQ;AACpB,UAAQ,MAAM,6BAA6B,IAAI,OAAO,EAAE;AACxD,UAAQ,MAAM,8DAA8D;AAC5E,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["privateKeyToAccount","response","paymentHeader","confidence","supportsToolCalling","supportsVision","join","homedir","join","require","LOG_DIR","join","homedir","DEFAULT_TTL_MS","createHash","canonicalize","TIMESTAMP_PATTERN","crypto","escapeRegex","originalChars","createHash","DEFAULT_CONFIG","sanitized","account","privateKeyToAccount","balanceMonitor","baseUrl","existingWallet","normalizedModel","mkdir","join","homedir","privateKeyToAccount","privateKeyToAccount","mkdir"]}