@loreai/gateway 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +3548 -0
- package/dist/index.js.map +7 -0
- package/package.json +53 -0
- package/src/auth.ts +133 -0
- package/src/batch-queue.ts +555 -0
- package/src/compaction.ts +195 -0
- package/src/config.ts +199 -0
- package/src/idle.ts +246 -0
- package/src/index.ts +41 -0
- package/src/llm-adapter.ts +110 -0
- package/src/pipeline.ts +1604 -0
- package/src/recall.ts +301 -0
- package/src/recorder.ts +192 -0
- package/src/server.ts +250 -0
- package/src/session.ts +207 -0
- package/src/stream/anthropic.ts +708 -0
- package/src/temporal-adapter.ts +307 -0
- package/src/translate/anthropic.ts +425 -0
- package/src/translate/openai.ts +536 -0
- package/src/translate/types.ts +177 -0
- package/src/worker-model.ts +408 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../package.json", "../src/config.ts", "../src/auth.ts", "../src/translate/anthropic.ts", "../src/translate/openai.ts", "../src/stream/anthropic.ts", "../src/pipeline.ts", "../src/session.ts", "../src/compaction.ts", "../src/temporal-adapter.ts", "../src/llm-adapter.ts", "../src/batch-queue.ts", "../src/idle.ts", "../src/worker-model.ts", "../src/recall.ts", "../src/server.ts", "../src/index.ts"],
|
|
4
|
+
"sourcesContent": ["{\n \"name\": \"@loreai/gateway\",\n \"version\": \"0.12.0\",\n \"type\": \"module\",\n \"license\": \"FSL-1.1-Apache-2.0\",\n \"description\": \"Lore as a transparent LLM proxy \u2014 context management for any AI coding client\",\n \"main\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"bun\": \"./src/index.ts\",\n \"default\": \"./dist/index.js\"\n }\n },\n \"bin\": {\n \"lore-gateway\": \"./dist/index.js\"\n },\n \"scripts\": {\n \"typecheck\": \"tsc --noEmit\",\n \"build\": \"bun run script/build.ts\",\n \"start\": \"bun run src/index.ts\"\n },\n \"dependencies\": {\n \"@loreai/core\": \"workspace:*\"\n },\n \"files\": [\n \"src/\",\n \"dist/\",\n \"README.md\",\n \"LICENSE\"\n ],\n \"engines\": {\n \"bun\": \">=1.2.0\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/BYK/loreai.git\",\n \"directory\": \"packages/gateway\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"keywords\": [\n \"lore\",\n \"gateway\",\n \"proxy\",\n \"llm\",\n \"context-management\",\n \"anthropic\",\n \"openai\"\n ],\n \"author\": \"BYK\"\n}\n", "/**\n * Gateway configuration \u2014 loaded from environment variables with sensible\n * defaults. No Zod, no file-based config, no @loreai/core dependency.\n */\n\n// ---------------------------------------------------------------------------\n// Config shape\n// ---------------------------------------------------------------------------\n\nexport interface GatewayConfig {\n /** Port to listen on. Default: 6969. Env: LORE_LISTEN_PORT */\n port: number;\n /** Host to bind to. Default: \"127.0.0.1\". Env: LORE_LISTEN_HOST */\n host: string;\n /** Upstream Anthropic API URL. Default: \"https://api.anthropic.com\". Env: LORE_UPSTREAM_ANTHROPIC */\n upstreamAnthropic: string;\n /** Upstream OpenAI API URL. Default: \"https://api.openai.com\". Env: LORE_UPSTREAM_OPENAI */\n upstreamOpenAI: string;\n /** Idle timeout in seconds before triggering background work. Default: 60 */\n idleTimeoutSeconds: number;\n /** Whether to log requests. Default: false. Env: LORE_DEBUG */\n debug: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// loadConfig\n// ---------------------------------------------------------------------------\n\n/** Load gateway configuration from environment variables with defaults. */\nexport function loadConfig(): GatewayConfig {\n const env = process.env;\n return {\n port: parsePort(env.LORE_LISTEN_PORT, 6969),\n host: env.LORE_LISTEN_HOST || \"127.0.0.1\",\n upstreamAnthropic: trimTrailingSlash(\n env.LORE_UPSTREAM_ANTHROPIC || \"https://api.anthropic.com\",\n ),\n upstreamOpenAI: trimTrailingSlash(\n env.LORE_UPSTREAM_OPENAI || \"https://api.openai.com\",\n ),\n idleTimeoutSeconds: parsePositiveInt(env.LORE_IDLE_TIMEOUT, 60),\n debug: isTruthy(env.LORE_DEBUG),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Upstream routing \u2014 model name \u2192 provider URL + protocol\n// ---------------------------------------------------------------------------\n\nexport type UpstreamRoute = {\n url: string;\n protocol: \"anthropic\" | \"openai\";\n};\n\n/**\n * Model prefix \u2192 upstream provider routing table.\n *\n * Ordered from most-specific to most-general so that e.g. `claude-3-5-haiku`\n * matches `claude-` before any catch-all. Unknown models fall back to the\n * env-var-configured defaults.\n */\nconst UPSTREAM_ROUTES: Array<{ prefix: string; url: string; protocol: \"anthropic\" | \"openai\" }> = [\n // Anthropic\n { prefix: \"claude-\", url: \"https://api.anthropic.com\", protocol: \"anthropic\" },\n // Nvidia NIM\n { prefix: \"nvidia/\", url: \"https://integrate.api.nvidia.com\", protocol: \"openai\" },\n { prefix: \"meta/\", url: \"https://integrate.api.nvidia.com\", protocol: \"openai\" },\n { prefix: \"mistralai/\", url: \"https://integrate.api.nvidia.com\", protocol: \"openai\" },\n { prefix: \"google/\", url: \"https://integrate.api.nvidia.com\", protocol: \"openai\" },\n { prefix: \"qwen/\", url: \"https://integrate.api.nvidia.com\", protocol: \"openai\" },\n { prefix: \"deepseek/\", url: \"https://integrate.api.nvidia.com\", protocol: \"openai\" },\n // OpenAI\n { prefix: \"gpt-\", url: \"https://api.openai.com\", protocol: \"openai\" },\n { prefix: \"o1-\", url: \"https://api.openai.com\", protocol: \"openai\" },\n { prefix: \"o3-\", url: \"https://api.openai.com\", protocol: \"openai\" },\n { prefix: \"o4-\", url: \"https://api.openai.com\", protocol: \"openai\" },\n // xAI\n { prefix: \"grok-\", url: \"https://api.x.ai\", protocol: \"openai\" },\n // Mistral (direct)\n { prefix: \"mistral-\", url: \"https://api.mistral.ai\", protocol: \"openai\" },\n { prefix: \"codestral-\", url: \"https://api.mistral.ai\", protocol: \"openai\" },\n // Google (direct)\n { prefix: \"gemini-\", url: \"https://generativelanguage.googleapis.com\", protocol: \"openai\" },\n];\n\n/**\n * Resolve which upstream to use for a given model name.\n *\n * Returns the inferred route, or null if the model doesn't match any known\n * prefix (caller should fall back to env-var-configured defaults).\n */\nexport function resolveUpstreamRoute(model: string): UpstreamRoute | null {\n for (const route of UPSTREAM_ROUTES) {\n if (model.startsWith(route.prefix)) {\n return { url: route.url, protocol: route.protocol };\n }\n }\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Project path inference\n// ---------------------------------------------------------------------------\n\n/**\n * Regex patterns to extract an absolute project path from a system prompt.\n *\n * Claude Code embeds absolute paths in several places:\n * - CLAUDE.md content references (`/home/user/project/CLAUDE.md`)\n * - Tool definitions mention cwd (`\"cwd\": \"/home/user/project\"`)\n * - Working directory lines (`Working directory: /Users/\u2026/project`)\n *\n * Each pattern captures the directory portion (no trailing filename when\n * possible). Ordered from most-specific to most-general.\n */\nconst PROJECT_PATH_PATTERNS: RegExp[] = [\n // \"cwd\": \"/home/\u2026/project\" or \"cwd\":\"/Users/\u2026/project\" (JSON-style)\n /[\"']?cwd[\"']?\\s*[:=]\\s*[\"']?(\\/(?:home|Users)\\/[^\\s\"',}]+)/,\n // Working directory: /home/user/project\n /[Ww]orking\\s+directory[:=]\\s*(\\/(?:home|Users)\\/[^\\s\"',]+)/,\n // CLAUDE.md / AGENTS.md / .lore.md file path \u2192 take the directory\n /(\\/(?:home|Users)\\/[^\\s\"',]+)\\/(?:CLAUDE|AGENTS|\\.lore)\\.md/,\n // Generic absolute path starting with /home/ or /Users/ \u2014 first occurrence\n // Captures until whitespace, quote, comma, or bracket.\n /(\\/(?:home|Users)\\/[\\w./-]+)/,\n];\n\n/**\n * Try to extract a project path from the system prompt content.\n *\n * Claude Code includes absolute paths in its system prompt (CLAUDE.md\n * content, tool definitions, working directory references). Returns the\n * extracted path or `null` if nothing looks like a project directory.\n */\nexport function inferProjectPath(systemPrompt: string): string | null {\n for (const pattern of PROJECT_PATH_PATTERNS) {\n const match = pattern.exec(systemPrompt);\n if (match?.[1]) {\n // Strip trailing slashes for consistency\n return match[1].replace(/\\/+$/, \"\") || null;\n }\n }\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// getProjectPath\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve the project path for a request. Checks in order:\n * 1. `X-Lore-Project` header (explicit override)\n * 2. `inferProjectPath(systemPrompt)` (zero-config extraction)\n * 3. `process.cwd()` (last resort fallback)\n */\nexport function getProjectPath(\n systemPrompt: string,\n headers: Record<string, string>,\n): string {\n // 1. Explicit header override\n const headerPath = headers[\"x-lore-project\"];\n if (headerPath) return headerPath;\n\n // 2. Infer from system prompt content\n const inferred = inferProjectPath(systemPrompt);\n if (inferred) return inferred;\n\n // 3. Fall back to gateway's own cwd\n return process.cwd();\n}\n\n// ---------------------------------------------------------------------------\n// Helpers (not exported \u2014 internal only)\n// ---------------------------------------------------------------------------\n\nfunction parsePort(value: string | undefined, fallback: number): number {\n if (!value) return fallback;\n const n = Number.parseInt(value, 10);\n if (Number.isNaN(n) || n < 0 || n > 65535) return fallback;\n return n;\n}\n\nfunction parsePositiveInt(\n value: string | undefined,\n fallback: number,\n): number {\n if (!value) return fallback;\n const n = Number.parseInt(value, 10);\n if (Number.isNaN(n) || n <= 0) return fallback;\n return n;\n}\n\nfunction isTruthy(value: string | undefined): boolean {\n return value === \"1\" || value?.toLowerCase() === \"true\";\n}\n\nfunction trimTrailingSlash(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n", "/**\n * Gateway authentication: typed credentials, per-session registry, and\n * two-level lookup for background workers.\n *\n * Replaces the bare `lastSeenApiKey` string with a typed `AuthCredential`\n * that supports both API-key (`x-api-key`) and OAuth Bearer token\n * (`Authorization: Bearer`) authentication schemes.\n *\n * The per-session registry ensures background workers (distillation,\n * curation, batch queue) use the correct credential for their session\n * even when multiple clients are connected simultaneously.\n */\n\n// ---------------------------------------------------------------------------\n// AuthCredential type\n// ---------------------------------------------------------------------------\n\n/** Auth credential \u2014 either an API key or an OAuth bearer token. */\nexport type AuthCredential =\n | { scheme: \"api-key\"; value: string }\n | { scheme: \"bearer\"; value: string };\n\n// ---------------------------------------------------------------------------\n// Header extraction / formatting\n// ---------------------------------------------------------------------------\n\n/**\n * Extract auth from request headers.\n *\n * Prefers `x-api-key` (Anthropic SDK default), falls back to\n * `Authorization: Bearer` (OAuth / Claude Code subscriptions).\n * Returns `null` if neither is present.\n */\nexport function extractAuth(\n headers: Record<string, string>,\n): AuthCredential | null {\n const apiKey = headers[\"x-api-key\"] || headers[\"X-Api-Key\"];\n if (apiKey) return { scheme: \"api-key\", value: apiKey };\n\n const authHeader =\n headers[\"authorization\"] || headers[\"Authorization\"];\n if (authHeader) {\n const match = /^Bearer\\s+(\\S+)$/i.exec(authHeader);\n if (match) return { scheme: \"bearer\", value: match[1] };\n }\n\n return null;\n}\n\n/**\n * Format credential as the appropriate HTTP header(s).\n *\n * - `api-key` \u2192 `{ \"x-api-key\": value }`\n * - `bearer` \u2192 `{ \"Authorization\": \"Bearer <value>\" }`\n */\nexport function authHeaders(cred: AuthCredential): Record<string, string> {\n switch (cred.scheme) {\n case \"api-key\":\n return { \"x-api-key\": cred.value };\n case \"bearer\":\n return { Authorization: `Bearer ${cred.value}` };\n }\n}\n\n/**\n * Non-sensitive suffix for fingerprinting \u2014 last 8 chars of credential value.\n *\n * Used to differentiate sessions that share the same first message but use\n * different API keys or OAuth tokens. The suffix alone cannot reconstruct\n * the full credential.\n */\nexport function authFingerprint(cred: AuthCredential): string {\n return cred.value.slice(-8);\n}\n\n// ---------------------------------------------------------------------------\n// Per-session registry\n// ---------------------------------------------------------------------------\n\nconst sessionAuth = new Map<string, AuthCredential>();\n\nexport function setSessionAuth(\n sessionID: string,\n cred: AuthCredential,\n): void {\n sessionAuth.set(sessionID, cred);\n}\n\nexport function getSessionAuth(\n sessionID: string,\n): AuthCredential | null {\n return sessionAuth.get(sessionID) ?? null;\n}\n\n/** Delete a session's credential (for future eviction). */\nexport function deleteSessionAuth(sessionID: string): void {\n sessionAuth.delete(sessionID);\n}\n\n// ---------------------------------------------------------------------------\n// Global fallback (replaces lastSeenApiKey)\n// ---------------------------------------------------------------------------\n\nlet lastSeenAuth: AuthCredential | null = null;\n\nexport function setLastSeenAuth(cred: AuthCredential): void {\n lastSeenAuth = cred;\n}\n\nexport function getLastSeenAuth(): AuthCredential | null {\n return lastSeenAuth;\n}\n\n// ---------------------------------------------------------------------------\n// Two-level lookup\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve auth credentials for a given session.\n *\n * 1. If `sessionID` is provided, check the per-session registry first.\n * 2. Fall back to the global `lastSeenAuth` (for cold-start or callers\n * that don't pass a session ID).\n */\nexport function resolveAuth(\n sessionID?: string,\n): AuthCredential | null {\n if (sessionID) {\n const cred = getSessionAuth(sessionID);\n if (cred) return cred;\n }\n return getLastSeenAuth();\n}\n", "/**\n * Anthropic \u2194 Gateway translation layer.\n *\n * Converts between Anthropic's `/v1/messages` API format and the gateway's\n * internal `GatewayRequest`/`GatewayResponse` types. The parser is lenient \u2014\n * unknown fields pass through in `metadata` rather than causing errors.\n */\nimport type {\n GatewayContentBlock,\n GatewayMessage,\n GatewayRequest,\n GatewayResponse,\n GatewayTool,\n} from \"./types\";\nimport { extractAuth, authHeaders } from \"../auth\";\n\n// ---------------------------------------------------------------------------\n// Anthropic API version \u2014 used in all outgoing requests\n// ---------------------------------------------------------------------------\n\nconst ANTHROPIC_VERSION = \"2023-06-01\";\n\n// ---------------------------------------------------------------------------\n// Fields the gateway reads/writes \u2014 everything else goes into `metadata`\n// ---------------------------------------------------------------------------\n\n/** Top-level body fields that are extracted into `GatewayRequest` fields. */\nconst KNOWN_BODY_FIELDS = new Set([\n \"model\",\n \"system\",\n \"messages\",\n \"tools\",\n \"max_tokens\",\n \"stream\",\n]);\n\n// ---------------------------------------------------------------------------\n// Helpers \u2014 content block translation\n// ---------------------------------------------------------------------------\n\n/**\n * Normalize an Anthropic content block (from a message's `content` array)\n * into a `GatewayContentBlock`. Unknown block types are preserved as text\n * blocks with a JSON dump so no information is lost.\n */\nfunction toGatewayBlock(block: Record<string, unknown>): GatewayContentBlock {\n switch (block.type) {\n case \"text\":\n return { type: \"text\", text: String(block.text ?? \"\") };\n\n case \"thinking\":\n return {\n type: \"thinking\",\n thinking: String(block.thinking ?? \"\"),\n ...(block.signature != null\n ? { signature: String(block.signature) }\n : undefined),\n };\n\n case \"tool_use\":\n return {\n type: \"tool_use\",\n id: String(block.id ?? \"\"),\n name: String(block.name ?? \"\"),\n input: block.input,\n };\n\n case \"tool_result\": {\n // Anthropic `tool_result` content can be a string or array of blocks.\n let content = \"\";\n if (typeof block.content === \"string\") {\n content = block.content;\n } else if (Array.isArray(block.content)) {\n content = (block.content as Array<Record<string, unknown>>)\n .filter((b) => b.type === \"text\")\n .map((b) => String(b.text ?? \"\"))\n .join(\"\\n\");\n }\n return {\n type: \"tool_result\",\n toolUseId: String(block.tool_use_id ?? \"\"),\n content,\n ...(block.is_error ? { isError: true } : undefined),\n };\n }\n\n default:\n // Unknown block type \u2014 preserve as text so nothing is silently dropped\n return { type: \"text\", text: JSON.stringify(block) };\n }\n}\n\n/**\n * Normalize Anthropic message content (string or array of blocks) into\n * a `GatewayContentBlock[]`.\n */\nfunction normalizeContent(content: unknown): GatewayContentBlock[] {\n if (typeof content === \"string\") {\n return [{ type: \"text\", text: content }];\n }\n\n if (Array.isArray(content)) {\n return content.map((block) =>\n toGatewayBlock(block as Record<string, unknown>),\n );\n }\n\n // Null / undefined / unexpected \u2192 empty\n return [];\n}\n\n/**\n * Normalize Anthropic's `system` field. Can be:\n * - `undefined` / `null` \u2192 `\"\"`\n * - a plain string \u2192 used directly\n * - an array of content blocks (e.g. with `cache_control`) \u2192 join text blocks\n */\nfunction normalizeSystem(system: unknown): string {\n if (system == null) return \"\";\n if (typeof system === \"string\") return system;\n\n if (Array.isArray(system)) {\n return (system as Array<Record<string, unknown>>)\n .filter((block) => block.type === \"text\")\n .map((block) => String(block.text ?? \"\"))\n .join(\"\\n\");\n }\n\n return String(system);\n}\n\n// ---------------------------------------------------------------------------\n// Reverse helpers \u2014 gateway blocks \u2192 Anthropic format\n// ---------------------------------------------------------------------------\n\n/**\n * Convert a `GatewayContentBlock` back to Anthropic's wire format.\n */\nfunction toAnthropicBlock(\n block: GatewayContentBlock,\n): Record<string, unknown> {\n switch (block.type) {\n case \"text\":\n return { type: \"text\", text: block.text };\n\n case \"thinking\":\n return {\n type: \"thinking\",\n thinking: block.thinking,\n ...(block.signature != null ? { signature: block.signature } : undefined),\n };\n\n case \"tool_use\":\n return {\n type: \"tool_use\",\n id: block.id,\n name: block.name,\n input: block.input,\n };\n\n case \"tool_result\": {\n const result: Record<string, unknown> = {\n type: \"tool_result\",\n tool_use_id: block.toolUseId,\n content: block.content,\n };\n if (block.isError) result.is_error = true;\n return result;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// parseAnthropicRequest\n// ---------------------------------------------------------------------------\n\n/**\n * Parse a raw Anthropic `/v1/messages` request body into a `GatewayRequest`.\n *\n * Lenient: unknown top-level fields are preserved in `metadata` for\n * faithful upstream forwarding. Content normalization handles both\n * string and array forms.\n */\nexport function parseAnthropicRequest(\n body: unknown,\n headers: Record<string, string>,\n): GatewayRequest {\n const raw = (body ?? {}) as Record<string, unknown>;\n\n // --- Extract known fields ---\n const model = String(raw.model ?? \"\");\n const system = normalizeSystem(raw.system);\n const stream = raw.stream === true;\n const maxTokens =\n typeof raw.max_tokens === \"number\" ? raw.max_tokens : 4096;\n\n // --- Messages ---\n const rawMessages = Array.isArray(raw.messages) ? raw.messages : [];\n const messages: GatewayMessage[] = rawMessages.map(\n (msg: Record<string, unknown>) => ({\n role: msg.role === \"assistant\" ? \"assistant\" : \"user\",\n content: normalizeContent(msg.content),\n }),\n );\n\n // --- Tools ---\n const rawTools = Array.isArray(raw.tools) ? raw.tools : [];\n const tools: GatewayTool[] = rawTools.map(\n (t: Record<string, unknown>) => ({\n name: String(t.name ?? \"\"),\n description: String(t.description ?? \"\"),\n inputSchema: (t.input_schema as Record<string, unknown>) ?? {},\n }),\n );\n\n // --- Metadata: everything the gateway doesn't explicitly process ---\n const metadata: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(raw)) {\n if (!KNOWN_BODY_FIELDS.has(key)) {\n metadata[key] = value;\n }\n }\n\n return {\n protocol: \"anthropic\",\n model,\n system,\n messages,\n tools,\n stream,\n maxTokens,\n metadata,\n rawHeaders: headers,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Caching options\n// ---------------------------------------------------------------------------\n\n/**\n * Options controlling Anthropic prompt caching behavior.\n *\n * Two independent mechanisms:\n * 1. **System prompt caching**: sends `system` as a block array with an\n * explicit `cache_control` breakpoint. This is the highest-stability\n * cache slot \u2014 the system prompt rarely changes within a session.\n * 2. **Conversation caching**: places an explicit `cache_control` breakpoint\n * on the last message block, enabling Anthropic to cache the conversation\n * prefix up to that point. Between consecutive stable turns (same gradient\n * layer, no distillation arrival, no window eviction), the prefix is\n * byte-identical \u2192 cache reads at 0.1\u00D7 base cost vs 1\u00D7 uncached.\n *\n * Title/summary passthrough requests should NEVER enable caching \u2014 their\n * content varies every call, producing 1.25\u00D7 write cost with zero reads.\n */\nexport type AnthropicCacheOptions = {\n /**\n * Cache the system prompt with an explicit breakpoint.\n * - `\"5m\"` \u2014 default 5-minute TTL (conversation turns, frequent enough\n * for 5m refresh)\n * - `\"1h\"` \u2014 extended 1-hour TTL (worker calls that come in bursts\n * separated by minutes of user thinking)\n * - `false` \u2014 no system caching\n */\n systemTTL?: \"5m\" | \"1h\" | false;\n\n /**\n * Place an explicit `cache_control` breakpoint on the last block of the\n * last message, enabling Anthropic to cache the conversation prefix.\n *\n * When `true`, the gateway adds `cache_control: { type: \"ephemeral\" }`\n * to the final content block. On the next turn, Anthropic's lookback\n * window finds the prior breakpoint, reads the cached prefix (0.1\u00D7\n * cost), and writes only the new tail (1.25\u00D7).\n */\n cacheConversation?: boolean;\n};\n\n// ---------------------------------------------------------------------------\n// buildAnthropicRequest\n// ---------------------------------------------------------------------------\n\n/**\n * Convert a `GatewayRequest` back to Anthropic API format for upstream\n * forwarding.\n *\n * Returns the relative path, headers, and JSON body. The caller prepends\n * the upstream base URL.\n *\n * @param req The normalized gateway request\n * @param cache Optional caching configuration. When omitted, no\n * `cache_control` annotations are added (passthrough behavior).\n */\nexport function buildAnthropicRequest(\n req: GatewayRequest,\n cache?: AnthropicCacheOptions,\n): {\n url: string;\n headers: Record<string, string>;\n body: unknown;\n} {\n // --- Headers ---\n const headers: Record<string, string> = {\n \"content-type\": \"application/json\",\n \"anthropic-version\": ANTHROPIC_VERSION,\n };\n\n // Forward auth from the original request (API key or OAuth Bearer)\n const cred = extractAuth(req.rawHeaders);\n if (cred) {\n Object.assign(headers, authHeaders(cred));\n }\n\n // Forward anthropic-beta if present (enables features like extended thinking)\n const beta =\n req.rawHeaders[\"anthropic-beta\"] || req.rawHeaders[\"Anthropic-Beta\"] || \"\";\n if (beta) {\n headers[\"anthropic-beta\"] = beta;\n }\n\n // --- Body ---\n const body: Record<string, unknown> = {\n model: req.model,\n max_tokens: req.maxTokens,\n stream: req.stream,\n };\n\n // System \u2014 only include if non-empty\n if (req.system) {\n const systemTTL = cache?.systemTTL;\n if (systemTTL) {\n // Send as block array with explicit cache_control breakpoint.\n // This creates a stable cache slot for the system prompt \u2014 it changes\n // only when LTM entries are added/removed or AGENTS.md is updated.\n const cacheControl: Record<string, string> =\n systemTTL === \"1h\"\n ? { type: \"ephemeral\", ttl: \"1h\" }\n : { type: \"ephemeral\" };\n body.system = [\n { type: \"text\", text: req.system, cache_control: cacheControl },\n ];\n } else {\n body.system = req.system;\n }\n }\n\n // Messages\n const messages = req.messages.map((msg) => ({\n role: msg.role,\n content: msg.content.map(toAnthropicBlock),\n }));\n\n // Conversation caching: place a breakpoint on the final content block of\n // the last message. Anthropic's 20-block lookback finds the prior turn's\n // breakpoint, reads the cached prefix, and writes only the new tail.\n if (cache?.cacheConversation && messages.length > 0) {\n const lastMsg = messages[messages.length - 1]!;\n if (lastMsg.content.length > 0) {\n const lastBlock = lastMsg.content[lastMsg.content.length - 1]!;\n (lastBlock as Record<string, unknown>).cache_control = {\n type: \"ephemeral\",\n };\n }\n }\n\n body.messages = messages;\n\n // Tools \u2014 only include if present\n if (req.tools.length > 0) {\n body.tools = req.tools.map((t) => ({\n name: t.name,\n description: t.description,\n input_schema: t.inputSchema,\n }));\n }\n\n // Restore all metadata params (temperature, top_p, stop_sequences, etc.)\n for (const [key, value] of Object.entries(req.metadata)) {\n body[key] = value;\n }\n\n return {\n url: \"/v1/messages\",\n headers,\n body,\n };\n}\n\n// ---------------------------------------------------------------------------\n// buildAnthropicNonStreamResponse\n// ---------------------------------------------------------------------------\n\n/**\n * Build a non-streaming Anthropic response JSON from a `GatewayResponse`.\n *\n * Produces the standard Anthropic `/v1/messages` response shape with\n * `type: \"message\"`, `role: \"assistant\"`, content blocks, and usage.\n */\nexport function buildAnthropicNonStreamResponse(\n resp: GatewayResponse,\n): unknown {\n const usage: Record<string, number> = {\n input_tokens: resp.usage.inputTokens,\n output_tokens: resp.usage.outputTokens,\n };\n\n if (resp.usage.cacheReadInputTokens != null) {\n usage.cache_read_input_tokens = resp.usage.cacheReadInputTokens;\n }\n if (resp.usage.cacheCreationInputTokens != null) {\n usage.cache_creation_input_tokens = resp.usage.cacheCreationInputTokens;\n }\n\n return {\n id: resp.id,\n type: \"message\",\n role: \"assistant\",\n model: resp.model,\n content: resp.content.map(toAnthropicBlock),\n stop_reason: resp.stopReason,\n stop_sequence: null,\n usage,\n };\n}\n", "/**\n * OpenAI \u2194 Gateway translation layer.\n *\n * Converts between OpenAI's `/v1/chat/completions` API format and the gateway's\n * internal `GatewayRequest`/`GatewayResponse` types.\n */\nimport type {\n GatewayContentBlock,\n GatewayMessage,\n GatewayRequest,\n GatewayResponse,\n GatewayTool,\n} from \"./types\";\nimport { extractAuth } from \"../auth\";\n\n// ---------------------------------------------------------------------------\n// OpenAI \u2192 GatewayRequest\n// ---------------------------------------------------------------------------\n\nexport function parseOpenAIRequest(\n body: unknown,\n headers: Record<string, string>,\n): GatewayRequest {\n const raw = (body ?? {}) as Record<string, unknown>;\n\n // Extract known fields\n const model = String(raw.model ?? \"\");\n const stream = raw.stream === true;\n\n // max_tokens defaults to 4096 if not specified\n const maxTokens =\n typeof raw.max_tokens === \"number\" ? raw.max_tokens : 4096;\n\n // Extract extras (temperature, top_p, etc.) for later forwarding\n const extras: GatewayRequest[\"extras\"] = {};\n if (typeof raw.temperature === \"number\") {\n extras.temperature = raw.temperature;\n }\n if (typeof raw.top_p === \"number\") {\n extras.top_p = raw.top_p;\n }\n if (typeof raw.frequency_penalty === \"number\") {\n extras.frequency_penalty = raw.frequency_penalty;\n }\n if (typeof raw.presence_penalty === \"number\") {\n extras.presence_penalty = raw.presence_penalty;\n }\n if (typeof raw.user === \"string\") {\n extras.user = raw.user;\n }\n if (raw.logprobs === true || raw.logprobs === false) {\n extras.logprobs = raw.logprobs;\n }\n if (typeof raw.top_logprobs === \"number\") {\n extras.top_logprobs = raw.top_logprobs;\n }\n\n // Parse messages and extract system prompt\n const rawMessages = Array.isArray(raw.messages) ? raw.messages : [];\n let system = \"\";\n const messages: GatewayMessage[] = [];\n\n for (const msg of rawMessages as Array<Record<string, unknown>>) {\n const role = msg.role as string;\n const content = msg.content;\n\n if (role === \"system\") {\n // Concatenate multiple system messages with double newline\n const text = typeof content === \"string\" ? content : \"\";\n if (system) {\n system += \"\\n\\n\" + text;\n } else {\n system = text;\n }\n continue;\n }\n\n if (role === \"user\") {\n const blocks = parseUserContent(content, msg.tool_calls as Array<Record<string, unknown>> | undefined);\n messages.push({ role: \"user\", content: blocks });\n continue;\n }\n\n if (role === \"assistant\") {\n const blocks = parseAssistantContent(\n content,\n msg.tool_calls as Array<Record<string, unknown>> | undefined,\n );\n messages.push({ role: \"assistant\", content: blocks });\n continue;\n }\n\n if (role === \"tool\") {\n // Tool results are already represented in the content of the user message\n // that follows them in OpenAI. We process them when we encounter the\n // assistant message that generated the tool call.\n const toolResultBlocks = parseToolResult(msg);\n if (toolResultBlocks.length > 0) {\n messages.push({ role: \"user\", content: toolResultBlocks });\n }\n continue;\n }\n }\n\n // Parse tools\n const rawTools = Array.isArray(raw.tools) ? raw.tools : [];\n const tools: GatewayTool[] = rawTools.map(\n (t: Record<string, unknown>) => {\n const func = t.function as Record<string, unknown> | undefined;\n return {\n name: String(func?.name ?? t.name ?? \"\"),\n description: String(func?.description ?? \"\"),\n inputSchema: (func?.parameters as Record<string, unknown>) ?? {},\n };\n },\n );\n\n return {\n protocol: \"openai\",\n model,\n system,\n messages,\n tools,\n stream,\n maxTokens,\n metadata: {},\n rawHeaders: {\n ...headers,\n \"x-api-key\": headers[\"x-api-key\"] ?? \"\",\n },\n extras,\n };\n}\n\nfunction parseUserContent(\n content: unknown,\n toolCalls?: Array<Record<string, unknown>>,\n): GatewayContentBlock[] {\n const blocks: GatewayContentBlock[] = [];\n\n if (typeof content === \"string\" && content) {\n blocks.push({ type: \"text\", text: content });\n } else if (Array.isArray(content)) {\n for (const item of content as Array<Record<string, unknown>>) {\n if (item.type === \"text\") {\n blocks.push({ type: \"text\", text: String(item.text ?? \"\") });\n } else if (item.type === \"tool_use\") {\n blocks.push({\n type: \"tool_use\",\n id: String(item.id ?? \"\"),\n name: String(item.name ?? \"\"),\n input: item.input ?? {},\n });\n }\n }\n }\n\n // Add tool_use blocks from tool_calls field\n if (toolCalls) {\n for (const tc of toolCalls) {\n const fn = tc.function as Record<string, unknown> | undefined;\n blocks.push({\n type: \"tool_use\",\n id: String(tc.id ?? \"\"),\n name: String(fn?.name ?? \"\"),\n input: fn?.arguments ? JSON.parse(fn.arguments as string) : {},\n });\n }\n }\n\n return blocks;\n}\n\nfunction parseAssistantContent(\n content: unknown,\n toolCalls?: Array<Record<string, unknown>>,\n): GatewayContentBlock[] {\n const blocks: GatewayContentBlock[] = [];\n\n if (typeof content === \"string\" && content) {\n blocks.push({ type: \"text\", text: content });\n } else if (Array.isArray(content)) {\n for (const item of content as Array<Record<string, unknown>>) {\n if (item.type === \"text\") {\n blocks.push({ type: \"text\", text: String(item.text ?? \"\") });\n } else if (item.type === \"tool_use\") {\n blocks.push({\n type: \"tool_use\",\n id: String(item.id ?? \"\"),\n name: String(item.name ?? \"\"),\n input: item.input ?? {},\n });\n }\n }\n }\n\n // Add tool_use blocks from tool_calls field\n if (toolCalls) {\n for (const tc of toolCalls) {\n const fn = tc.function as Record<string, unknown> | undefined;\n blocks.push({\n type: \"tool_use\",\n id: String(tc.id ?? \"\"),\n name: String(fn?.name ?? \"\"),\n input: fn?.arguments ? JSON.parse(fn.arguments as string) : {},\n });\n }\n }\n\n return blocks;\n}\n\nfunction parseToolResult(msg: Record<string, unknown>): GatewayContentBlock[] {\n const blocks: GatewayContentBlock[] = [];\n const toolCallId = String(msg.tool_call_id ?? \"\");\n const content = msg.content;\n\n if (typeof content === \"string\" && content) {\n blocks.push({\n type: \"tool_result\",\n toolUseId: toolCallId,\n content,\n });\n } else if (Array.isArray(content)) {\n for (const item of content as Array<Record<string, unknown>>) {\n if (item.type === \"text\") {\n blocks.push({\n type: \"tool_result\",\n toolUseId: toolCallId,\n content: String(item.text ?? \"\"),\n });\n }\n }\n }\n\n return blocks;\n}\n\n// ---------------------------------------------------------------------------\n// GatewayResponse \u2192 OpenAI response\n// ---------------------------------------------------------------------------\n\nexport function buildOpenAIResponse(\n resp: GatewayResponse,\n wasStreaming: boolean,\n): Response {\n if (wasStreaming) {\n return buildOpenAIStreamResponse(resp);\n }\n return buildOpenAINonStreamResponse(resp);\n}\n\nfunction buildOpenAINonStreamResponse(resp: GatewayResponse): Response {\n const chunks: unknown[] = [];\n let content = \"\";\n const toolCalls: Array<Record<string, unknown>> = [];\n\n for (const block of resp.content) {\n if (block.type === \"text\") {\n content += block.text;\n } else if (block.type === \"tool_use\") {\n toolCalls.push({\n id: block.id,\n type: \"function\",\n function: {\n name: block.name,\n arguments: JSON.stringify(block.input),\n },\n });\n }\n }\n\n const message: Record<string, unknown> = {\n role: \"assistant\",\n content: content || null,\n };\n\n if (toolCalls.length > 0) {\n message.tool_calls = toolCalls;\n }\n\n const response = {\n id: resp.id.startsWith(\"chatcmpl-\") ? resp.id : `chatcmpl-${resp.id}`,\n object: \"chat.completion\",\n created: Math.floor(Date.now() / 1000),\n model: resp.model,\n choices: [\n {\n index: 0,\n message,\n finish_reason: mapStopReason(resp.stopReason),\n logprobs: null,\n },\n ],\n usage: {\n prompt_tokens: resp.usage.inputTokens,\n completion_tokens: resp.usage.outputTokens,\n total_tokens:\n resp.usage.inputTokens + resp.usage.outputTokens,\n },\n };\n\n return new Response(JSON.stringify(response), {\n status: 200,\n headers: { \"content-type\": \"application/json\" },\n });\n}\n\nfunction mapStopReason(reason: string): string {\n switch (reason) {\n case \"end_turn\":\n case \"stop\":\n case \"stop_sequence\":\n return \"stop\";\n case \"max_tokens\":\n case \"length\":\n return \"length\";\n case \"tool_use\":\n return \"tool_calls\";\n default:\n return \"stop\";\n }\n}\n\nfunction buildOpenAIStreamResponse(resp: GatewayResponse): Response {\n const encoder = new TextEncoder();\n let offset = 0;\n\n const stream = new ReadableStream({\n start(controller) {\n const baseId = resp.id.startsWith(\"chatcmpl-\")\n ? resp.id\n : `chatcmpl-${resp.id}`;\n const created = Math.floor(Date.now() / 1000);\n\n function emitChunk(\n delta: Record<string, unknown>,\n finishReason: string | null,\n ) {\n const chunk = {\n id: baseId,\n object: \"chat.completion.chunk\",\n created,\n model: resp.model,\n choices: [\n {\n index: 0,\n delta,\n finish_reason: finishReason,\n },\n ],\n };\n controller.enqueue(\n encoder.encode(`data: ${JSON.stringify(chunk)}\\n\\n`),\n );\n }\n\n // Emit role in first chunk\n emitChunk({ role: \"assistant\" }, null);\n\n // Process content blocks\n for (const block of resp.content) {\n if (block.type === \"text\") {\n // Split text into small chunks to simulate streaming\n const text = block.text;\n let pos = 0;\n while (pos < text.length) {\n const chunk = text.slice(pos, pos + 10);\n emitChunk({ content: chunk }, null);\n pos += 10;\n }\n } else if (block.type === \"tool_use\") {\n emitChunk(\n {\n tool_calls: [\n {\n index: offset,\n id: block.id,\n type: \"function\",\n function: {\n name: block.name,\n arguments: JSON.stringify(block.input),\n },\n },\n ],\n },\n null,\n );\n offset++;\n }\n }\n\n // Emit final chunk with finish reason\n emitChunk({}, mapStopReason(resp.stopReason));\n\n // Send [DONE] marker\n controller.enqueue(encoder.encode(\"data: [DONE]\\n\\n\"));\n controller.close();\n },\n });\n\n return new Response(stream, {\n status: 200,\n headers: {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-cache\",\n connection: \"keep-alive\",\n },\n });\n}\n\n// ---------------------------------------------------------------------------\n// GatewayRequest \u2192 OpenAI upstream request\n// ---------------------------------------------------------------------------\n\nexport function buildOpenAIUpstreamRequest(\n req: GatewayRequest,\n upstreamBase: string,\n): { url: string; headers: Record<string, string>; body: unknown } {\n const headers: Record<string, string> = {\n \"content-type\": \"application/json\",\n };\n\n // Forward auth from the original request \u2014 OpenAI-protocol upstreams\n // always use Bearer regardless of the incoming auth scheme.\n const cred = extractAuth(req.rawHeaders);\n if (cred) {\n headers[\"Authorization\"] = `Bearer ${cred.value}`;\n }\n\n const body: Record<string, unknown> = {\n model: req.model,\n messages: buildOpenAIMessages(req.messages, req.system),\n stream: req.stream,\n };\n\n if (req.maxTokens) {\n body.max_tokens = req.maxTokens;\n }\n\n // Add tools in OpenAI format\n if (req.tools.length > 0) {\n body.tools = req.tools.map((t) => ({\n type: \"function\",\n function: {\n name: t.name,\n description: t.description,\n parameters: t.inputSchema,\n },\n }));\n }\n\n // Forward extras\n if (req.extras) {\n if (req.extras.temperature !== undefined) {\n body.temperature = req.extras.temperature;\n }\n if (req.extras.top_p !== undefined) {\n body.top_p = req.extras.top_p;\n }\n if (req.extras.frequency_penalty !== undefined) {\n body.frequency_penalty = req.extras.frequency_penalty;\n }\n if (req.extras.presence_penalty !== undefined) {\n body.presence_penalty = req.extras.presence_penalty;\n }\n if (req.extras.user !== undefined) {\n body.user = req.extras.user;\n }\n if (req.extras.logprobs !== undefined) {\n body.logprobs = req.extras.logprobs;\n }\n if (req.extras.top_logprobs !== undefined) {\n body.top_logprobs = req.extras.top_logprobs;\n }\n }\n\n return {\n url: `${upstreamBase}/v1/chat/completions`,\n headers,\n body,\n };\n}\n\nfunction buildOpenAIMessages(\n messages: GatewayMessage[],\n system: string,\n): Array<Record<string, unknown>> {\n const result: Array<Record<string, unknown>> = [];\n\n // Add system prompt if present\n if (system) {\n result.push({ role: \"system\", content: system });\n }\n\n for (const msg of messages) {\n const blocks = msg.content;\n const role = msg.role;\n\n // Find text content and tool_use blocks\n const textParts: string[] = [];\n const toolUses: Array<Record<string, unknown>> = [];\n\n for (const block of blocks) {\n if (block.type === \"text\") {\n textParts.push(block.text);\n } else if (block.type === \"tool_use\") {\n toolUses.push({\n id: block.id,\n type: \"function\",\n function: {\n name: block.name,\n arguments: JSON.stringify(block.input),\n },\n });\n } else if (block.type === \"tool_result\") {\n // tool_result comes from previous assistant tool_use calls\n // It's typically attached to the user message as a tool result\n }\n }\n\n const msgRecord: Record<string, unknown> = { role };\n\n if (textParts.length > 0) {\n msgRecord.content = textParts.join(\"\");\n }\n\n if (toolUses.length > 0) {\n msgRecord.tool_calls = toolUses;\n }\n\n result.push(msgRecord);\n }\n\n return result;\n}", "/**\n * Anthropic SSE stream handling.\n *\n * Parses upstream Anthropic streaming responses (named SSE events), accumulates\n * the full response into a `GatewayResponse`, and provides helpers for\n * generating synthetic SSE event sequences (e.g. for compaction interception).\n *\n * Anthropic uses named SSE events with a lifecycle:\n * message_start -> content_block_start/delta/stop (repeated) -> message_delta -> message_stop\n *\n * All functions are pure (no side effects) except `parseSSEStream` which is\n * an async generator consuming a byte stream.\n */\nimport type {\n GatewayContentBlock,\n GatewayResponse,\n GatewayUsage,\n} from \"../translate/types\";\n\n// ---------------------------------------------------------------------------\n// SSE formatting\n// ---------------------------------------------------------------------------\n\n/** Format a single named SSE event for sending to the client. */\nexport function formatSSEEvent(eventType: string, data: string): string {\n return `event: ${eventType}\\ndata: ${data}\\n\\n`;\n}\n\n// ---------------------------------------------------------------------------\n// SSE parsing\n// ---------------------------------------------------------------------------\n\n/**\n * Parse an SSE byte stream into typed events.\n *\n * Handles:\n * - `event: <type>` followed by `data: <json>`\n * - Multiple `data:` lines (joined with `\\n`)\n * - Blank lines as event delimiters\n * - Default event type `\"message\"` when no `event:` line precedes data\n */\nexport async function* parseSSEStream(\n reader: ReadableStreamDefaultReader<Uint8Array>,\n): AsyncGenerator<{ event: string; data: string }> {\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n for (;;) {\n const { done, value } = await reader.read();\n if (value) {\n buffer += decoder.decode(value, { stream: true });\n }\n\n // Process complete events (delimited by blank lines: \\n\\n)\n let boundary: number;\n while ((boundary = buffer.indexOf(\"\\n\\n\")) !== -1) {\n const block = buffer.slice(0, boundary);\n buffer = buffer.slice(boundary + 2);\n\n // Skip empty blocks\n if (block.trim() === \"\") continue;\n\n let eventType = \"message\";\n const dataLines: string[] = [];\n\n for (const line of block.split(\"\\n\")) {\n if (line.startsWith(\"event:\")) {\n eventType = line.slice(6).trim();\n } else if (line.startsWith(\"data:\")) {\n dataLines.push(line.slice(5).trimStart());\n }\n // Lines starting with ':' are comments \u2014 ignore\n // Other lines without known prefix \u2014 ignore per SSE spec\n }\n\n if (dataLines.length > 0) {\n yield { event: eventType, data: dataLines.join(\"\\n\") };\n }\n }\n\n if (done) {\n // Flush any remaining partial block (shouldn't happen with well-formed SSE)\n if (buffer.trim()) {\n let eventType = \"message\";\n const dataLines: string[] = [];\n for (const line of buffer.split(\"\\n\")) {\n if (line.startsWith(\"event:\")) {\n eventType = line.slice(6).trim();\n } else if (line.startsWith(\"data:\")) {\n dataLines.push(line.slice(5).trimStart());\n }\n }\n if (dataLines.length > 0) {\n yield { event: eventType, data: dataLines.join(\"\\n\") };\n }\n }\n break;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Stream accumulator\n// ---------------------------------------------------------------------------\n\n/** Intermediate block state during streaming. */\ntype AccumulatingBlock =\n | { type: \"text\"; text: string }\n | { type: \"thinking\"; thinking: string; signature: string }\n | { type: \"tool_use\"; id: string; name: string; partialJson: string };\n\n/** State machine that processes Anthropic SSE events and builds a GatewayResponse. */\nexport interface StreamAccumulator {\n /** Process a single SSE event. Returns the event line(s) to forward to client. */\n processEvent(eventType: string, data: string): string;\n /** Get the accumulated response after stream ends. */\n getResponse(): GatewayResponse;\n /** Whether the stream has completed (message_stop received). */\n isDone(): boolean;\n}\n\nexport function createStreamAccumulator(): StreamAccumulator {\n let id = \"\";\n let model = \"\";\n let stopReason = \"\";\n let done = false;\n\n const usage: GatewayUsage = {\n inputTokens: 0,\n outputTokens: 0,\n };\n\n /** Blocks indexed by their stream index. */\n const blocks = new Map<number, AccumulatingBlock>();\n /** Finalized content blocks in order. */\n const content: GatewayContentBlock[] = [];\n /** Track which indices have been finalized. */\n const finalized = new Set<number>();\n\n function processEvent(eventType: string, data: string): string {\n // Forward the event as-is regardless of processing outcome\n const forwarded = formatSSEEvent(eventType, data);\n\n // Parse the data payload \u2014 if it's not valid JSON, just forward\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(data) as Record<string, unknown>;\n } catch {\n return forwarded;\n }\n\n switch (eventType) {\n case \"message_start\":\n handleMessageStart(parsed);\n break;\n case \"content_block_start\":\n handleContentBlockStart(parsed);\n break;\n case \"content_block_delta\":\n handleContentBlockDelta(parsed);\n break;\n case \"content_block_stop\":\n handleContentBlockStop(parsed);\n break;\n case \"message_delta\":\n handleMessageDelta(parsed);\n break;\n case \"message_stop\":\n done = true;\n break;\n // \"ping\" and unknown events \u2014 just forward\n }\n\n return forwarded;\n }\n\n function handleMessageStart(parsed: Record<string, unknown>): void {\n const message = parsed.message as Record<string, unknown> | undefined;\n if (!message) return;\n\n if (typeof message.id === \"string\") id = message.id;\n if (typeof message.model === \"string\") model = message.model;\n\n const msgUsage = message.usage as Record<string, number> | undefined;\n if (msgUsage) {\n if (typeof msgUsage.input_tokens === \"number\") {\n usage.inputTokens = msgUsage.input_tokens;\n }\n if (typeof msgUsage.output_tokens === \"number\") {\n usage.outputTokens = msgUsage.output_tokens;\n }\n if (typeof msgUsage.cache_read_input_tokens === \"number\") {\n usage.cacheReadInputTokens = msgUsage.cache_read_input_tokens;\n }\n if (typeof msgUsage.cache_creation_input_tokens === \"number\") {\n usage.cacheCreationInputTokens = msgUsage.cache_creation_input_tokens;\n }\n }\n }\n\n function handleContentBlockStart(parsed: Record<string, unknown>): void {\n const index = parsed.index as number;\n if (typeof index !== \"number\") return;\n\n const block = parsed.content_block as Record<string, unknown> | undefined;\n if (!block || typeof block.type !== \"string\") return;\n\n switch (block.type) {\n case \"text\":\n blocks.set(index, {\n type: \"text\",\n text: typeof block.text === \"string\" ? block.text : \"\",\n });\n break;\n case \"thinking\":\n blocks.set(index, {\n type: \"thinking\",\n thinking:\n typeof block.thinking === \"string\" ? block.thinking : \"\",\n signature: \"\",\n });\n break;\n case \"tool_use\":\n blocks.set(index, {\n type: \"tool_use\",\n id: typeof block.id === \"string\" ? block.id : \"\",\n name: typeof block.name === \"string\" ? block.name : \"\",\n partialJson: \"\",\n });\n break;\n }\n }\n\n function handleContentBlockDelta(parsed: Record<string, unknown>): void {\n const index = parsed.index as number;\n if (typeof index !== \"number\") return;\n\n const delta = parsed.delta as Record<string, unknown> | undefined;\n if (!delta || typeof delta.type !== \"string\") return;\n\n const block = blocks.get(index);\n if (!block) return;\n\n switch (delta.type) {\n case \"text_delta\":\n if (block.type === \"text\" && typeof delta.text === \"string\") {\n block.text += delta.text;\n }\n break;\n case \"thinking_delta\":\n if (\n block.type === \"thinking\" &&\n typeof delta.thinking === \"string\"\n ) {\n block.thinking += delta.thinking;\n }\n break;\n case \"signature_delta\":\n if (\n block.type === \"thinking\" &&\n typeof delta.signature === \"string\"\n ) {\n block.signature += delta.signature;\n }\n break;\n case \"input_json_delta\":\n if (\n block.type === \"tool_use\" &&\n typeof delta.partial_json === \"string\"\n ) {\n block.partialJson += delta.partial_json;\n }\n break;\n }\n }\n\n function handleContentBlockStop(parsed: Record<string, unknown>): void {\n const index = parsed.index as number;\n if (typeof index !== \"number\") return;\n\n const block = blocks.get(index);\n if (!block || finalized.has(index)) return;\n\n finalized.add(index);\n\n switch (block.type) {\n case \"text\":\n content.push({ type: \"text\", text: block.text });\n break;\n case \"thinking\": {\n const thinkingBlock: GatewayContentBlock = {\n type: \"thinking\",\n thinking: block.thinking,\n };\n if (block.signature) {\n (thinkingBlock as { signature?: string }).signature =\n block.signature;\n }\n content.push(thinkingBlock);\n break;\n }\n case \"tool_use\": {\n let input: unknown = {};\n if (block.partialJson) {\n try {\n input = JSON.parse(block.partialJson);\n } catch {\n // Malformed JSON \u2014 store as raw string\n input = block.partialJson;\n }\n }\n content.push({\n type: \"tool_use\",\n id: block.id,\n name: block.name,\n input,\n });\n break;\n }\n }\n }\n\n function handleMessageDelta(parsed: Record<string, unknown>): void {\n const delta = parsed.delta as Record<string, unknown> | undefined;\n if (delta && typeof delta.stop_reason === \"string\") {\n stopReason = delta.stop_reason;\n }\n\n // message_delta usage is cumulative output tokens\n const deltaUsage = parsed.usage as Record<string, number> | undefined;\n if (deltaUsage) {\n if (typeof deltaUsage.output_tokens === \"number\") {\n usage.outputTokens = deltaUsage.output_tokens;\n }\n }\n }\n\n function getResponse(): GatewayResponse {\n // Finalize any blocks that weren't explicitly stopped (shouldn't happen\n // with well-formed streams, but be defensive)\n for (const [index, block] of blocks) {\n if (!finalized.has(index)) {\n finalized.add(index);\n switch (block.type) {\n case \"text\":\n content.push({ type: \"text\", text: block.text });\n break;\n case \"thinking\":\n content.push({\n type: \"thinking\",\n thinking: block.thinking,\n ...(block.signature ? { signature: block.signature } : {}),\n });\n break;\n case \"tool_use\": {\n let input: unknown = {};\n if (block.partialJson) {\n try {\n input = JSON.parse(block.partialJson);\n } catch {\n input = block.partialJson;\n }\n }\n content.push({\n type: \"tool_use\",\n id: block.id,\n name: block.name,\n input,\n });\n break;\n }\n }\n }\n }\n\n return {\n id,\n model,\n content,\n stopReason,\n usage: { ...usage },\n };\n }\n\n return {\n processEvent,\n getResponse,\n isDone: () => done,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Synthetic SSE builders\n// ---------------------------------------------------------------------------\n\n/**\n * Build a synthetic `message_start` SSE event from a GatewayResponse.\n *\n * Used when the gateway generates its own response (e.g. compaction\n * interception) and needs to emit a well-formed Anthropic stream.\n */\nexport function buildSSEMessageStart(response: GatewayResponse): string {\n const message = {\n type: \"message_start\",\n message: {\n id: response.id,\n type: \"message\",\n role: \"assistant\",\n content: [],\n model: response.model,\n stop_reason: null,\n stop_sequence: null,\n usage: {\n input_tokens: response.usage.inputTokens,\n output_tokens: 1,\n ...(response.usage.cacheReadInputTokens != null\n ? { cache_read_input_tokens: response.usage.cacheReadInputTokens }\n : {}),\n ...(response.usage.cacheCreationInputTokens != null\n ? {\n cache_creation_input_tokens:\n response.usage.cacheCreationInputTokens,\n }\n : {}),\n },\n },\n };\n\n return formatSSEEvent(\"message_start\", JSON.stringify(message));\n}\n\n/**\n * Build a complete SSE event sequence for a simple text-only response.\n *\n * Generates the full Anthropic streaming lifecycle:\n * message_start -> content_block_start -> content_block_delta ->\n * content_block_stop -> message_delta -> message_stop\n *\n * Used for compaction interception where Lore generates a synthetic\n * response instead of forwarding to upstream.\n */\nexport function buildSSETextResponse(\n id: string,\n model: string,\n text: string,\n usage: { inputTokens: number; outputTokens: number },\n): string {\n const events: string[] = [];\n\n // message_start\n events.push(\n formatSSEEvent(\n \"message_start\",\n JSON.stringify({\n type: \"message_start\",\n message: {\n id,\n type: \"message\",\n role: \"assistant\",\n content: [],\n model,\n stop_reason: null,\n stop_sequence: null,\n usage: {\n input_tokens: usage.inputTokens,\n output_tokens: 1,\n },\n },\n }),\n ),\n );\n\n // content_block_start\n events.push(\n formatSSEEvent(\n \"content_block_start\",\n JSON.stringify({\n type: \"content_block_start\",\n index: 0,\n content_block: { type: \"text\", text: \"\" },\n }),\n ),\n );\n\n // content_block_delta \u2014 full text in one delta\n events.push(\n formatSSEEvent(\n \"content_block_delta\",\n JSON.stringify({\n type: \"content_block_delta\",\n index: 0,\n delta: { type: \"text_delta\", text },\n }),\n ),\n );\n\n // content_block_stop\n events.push(\n formatSSEEvent(\n \"content_block_stop\",\n JSON.stringify({\n type: \"content_block_stop\",\n index: 0,\n }),\n ),\n );\n\n // message_delta\n events.push(\n formatSSEEvent(\n \"message_delta\",\n JSON.stringify({\n type: \"message_delta\",\n delta: { stop_reason: \"end_turn\", stop_sequence: null },\n usage: { output_tokens: usage.outputTokens },\n }),\n ),\n );\n\n // message_stop\n events.push(\n formatSSEEvent(\n \"message_stop\",\n JSON.stringify({ type: \"message_stop\" }),\n ),\n );\n\n return events.join(\"\");\n}\n\n// ---------------------------------------------------------------------------\n// Recall-aware stream accumulator\n// ---------------------------------------------------------------------------\n\n/**\n * Extended accumulator interface with recall-aware filtering.\n *\n * Wraps the standard `StreamAccumulator` and adds:\n * - Suppression of recall tool_use blocks (not forwarded to client)\n * - Re-indexing of subsequent blocks to maintain contiguity\n * - Detection of which recall case (only vs mixed) applies\n * - Access to the suppressed recall block data\n *\n * For events targeting a suppressed (recall) block, `processEvent` returns\n * an empty string (nothing to forward). For all other events, it returns\n * the SSE text to forward \u2014 with adjusted block indices if needed.\n *\n * Also holds back `message_delta` and `message_stop` events when recall is\n * detected, so the caller can decide whether to forward them (Case 2) or\n * replace them with the continuation stream (Case 1).\n */\nexport interface RecallAwareAccumulator extends StreamAccumulator {\n /** Whether a recall tool_use block was detected in the stream. */\n hasRecall(): boolean;\n /** Whether non-recall tool_use blocks exist in the stream. */\n hasOtherTools(): boolean;\n /** The upstream block index at which recall was first detected. */\n recallBlockIndex(): number;\n /** Number of non-suppressed content blocks forwarded to the client. */\n clientBlockCount(): number;\n /** The held-back message_delta + message_stop events (SSE text). */\n heldBackEvents(): string;\n}\n\n/**\n * Create a recall-aware stream accumulator.\n *\n * @param recallToolName - The name of the recall tool to intercept (default: \"recall\")\n */\nexport function createRecallAwareAccumulator(\n recallToolName = \"recall\",\n): RecallAwareAccumulator {\n // Delegate to the standard accumulator for actual accumulation\n const inner = createStreamAccumulator();\n\n /** Set of upstream block indices that are suppressed (recall). */\n const suppressedIndices = new Set<number>();\n /** Tracks other tool_use block indices (non-recall). */\n const otherToolIndices = new Set<number>();\n /** Number of suppressed blocks seen so far (for re-indexing). */\n let suppressedCount = 0;\n /** First suppressed block index (for continuation re-indexing). */\n let firstSuppressedIndex = -1;\n /** Total client-visible blocks forwarded. */\n let clientBlocks = 0;\n /** Held-back message_delta + message_stop SSE text. */\n let heldBack = \"\";\n /** Whether we've detected recall in this stream. */\n let recallDetected = false;\n\n function processEvent(eventType: string, data: string): string {\n // Always feed the inner accumulator (it tracks full state)\n inner.processEvent(eventType, data);\n\n // Parse the data payload\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(data) as Record<string, unknown>;\n } catch {\n // Non-JSON events (pings, etc.) \u2014 forward as-is\n return formatSSEEvent(eventType, data);\n }\n\n switch (eventType) {\n case \"content_block_start\": {\n const index = parsed.index as number;\n if (typeof index !== \"number\") break;\n\n const block = parsed.content_block as Record<string, unknown> | undefined;\n if (\n block?.type === \"tool_use\" &&\n block.name === recallToolName\n ) {\n // Suppress this block\n suppressedIndices.add(index);\n suppressedCount++;\n recallDetected = true;\n if (firstSuppressedIndex < 0) firstSuppressedIndex = index;\n return \"\"; // Don't forward\n }\n\n if (block?.type === \"tool_use\") {\n otherToolIndices.add(index);\n }\n\n clientBlocks++;\n // Re-index if needed\n if (suppressedCount > 0) {\n const adjusted = { ...parsed, index: index - suppressedCount };\n return formatSSEEvent(eventType, JSON.stringify(adjusted));\n }\n break;\n }\n\n case \"content_block_delta\":\n case \"content_block_stop\": {\n const index = parsed.index as number;\n if (typeof index === \"number\" && suppressedIndices.has(index)) {\n return \"\"; // Don't forward recall block events\n }\n // Re-index if needed\n if (suppressedCount > 0 && typeof (parsed.index) === \"number\") {\n const adjusted = {\n ...parsed,\n index: (parsed.index as number) - suppressedCount,\n };\n return formatSSEEvent(eventType, JSON.stringify(adjusted));\n }\n break;\n }\n\n case \"message_delta\":\n case \"message_stop\": {\n if (recallDetected) {\n // Hold back \u2014 caller decides whether to forward or replace\n heldBack += formatSSEEvent(eventType, data);\n return \"\";\n }\n break;\n }\n\n // message_start, ping, etc. \u2014 forward unchanged\n }\n\n return formatSSEEvent(eventType, data);\n }\n\n return {\n processEvent,\n getResponse: () => inner.getResponse(),\n isDone: () => inner.isDone(),\n hasRecall: () => recallDetected,\n hasOtherTools: () => otherToolIndices.size > 0,\n recallBlockIndex: () => firstSuppressedIndex,\n clientBlockCount: () => clientBlocks,\n heldBackEvents: () => heldBack,\n };\n}\n\n/**\n * Consume an Anthropic SSE streaming Response and return the accumulated\n * GatewayResponse. Useful when the response needs to be translated to another\n * protocol format (e.g. OpenAI) after the pipeline produces Anthropic SSE.\n */\nexport async function accumulateSSEResponse(\n response: Response,\n): Promise<GatewayResponse> {\n const accumulator = createStreamAccumulator();\n const text = await response.text();\n\n for (const block of text.split(\"\\n\\n\")) {\n if (!block.trim()) continue;\n let eventType = \"message\";\n const dataLines: string[] = [];\n for (const line of block.split(\"\\n\")) {\n if (line.startsWith(\"event:\")) {\n eventType = line.slice(6).trim();\n } else if (line.startsWith(\"data:\")) {\n dataLines.push(line.slice(5).trimStart());\n }\n }\n if (dataLines.length > 0) {\n accumulator.processEvent(eventType, dataLines.join(\"\\n\"));\n }\n }\n\n return accumulator.getResponse();\n}\n", "/**\n * Core request processing pipeline for the Lore gateway.\n *\n * Orchestrates the full flow for every request:\n * session identification \u2192 LTM injection \u2192 gradient transform \u2192\n * upstream forwarding \u2192 response accumulation \u2192 calibration \u2192\n * temporal storage \u2192 background work scheduling.\n *\n * Three request classes are handled:\n * 1. Compaction requests \u2192 intercepted, never forwarded upstream.\n * 2. Title/summary requests \u2192 forwarded transparently, no Lore processing.\n * 3. Normal conversation turns \u2192 full pipeline.\n */\nimport type { LoreMessageWithParts, LLMClient } from \"@loreai/core\";\nimport {\n load,\n config as loreConfig,\n ensureProject,\n isFirstRun,\n temporal,\n ltm,\n distillation,\n curator,\n log,\n transform,\n setModelLimits,\n setLtmTokens,\n getLtmBudget,\n setMaxLayer0Tokens,\n computeLayer0Cap,\n calibrate,\n getLastTransformedCount,\n onIdleResume,\n consumeCameOutOfIdle,\n needsUrgentDistillation,\n formatKnowledge,\n buildCompactPrompt,\n} from \"@loreai/core\";\n\nimport type {\n GatewayRequest,\n GatewayResponse,\n GatewayContentBlock,\n GatewayToolUseBlock,\n GatewayToolResultBlock,\n SessionState,\n} from \"./translate/types\";\nimport type { GatewayConfig } from \"./config\";\nimport { getProjectPath, resolveUpstreamRoute } from \"./config\";\nimport {\n generateSessionID,\n fingerprintMessages,\n MESSAGE_COUNT_PROXIMITY_THRESHOLD,\n} from \"./session\";\nimport {\n isCompactionRequest,\n isTitleOrSummaryRequest,\n extractPreviousSummary,\n buildCompactionResponse,\n} from \"./compaction\";\nimport {\n buildAnthropicRequest,\n buildAnthropicNonStreamResponse,\n type AnthropicCacheOptions,\n} from \"./translate/anthropic\";\nimport {\n buildOpenAIUpstreamRequest,\n buildOpenAIResponse,\n} from \"./translate/openai\";\nimport {\n createStreamAccumulator,\n createRecallAwareAccumulator,\n parseSSEStream,\n buildSSETextResponse,\n formatSSEEvent,\n type StreamAccumulator,\n} from \"./stream/anthropic\";\nimport {\n gatewayMessagesToLore,\n updateAssistantMessageTokens,\n resolveToolResults,\n} from \"./temporal-adapter\";\nimport { createGatewayLLMClient } from \"./llm-adapter\";\nimport { createBatchLLMClient } from \"./batch-queue\";\nimport {\n extractAuth,\n authFingerprint,\n setLastSeenAuth,\n setSessionAuth,\n resolveAuth,\n} from \"./auth\";\nimport type { UpstreamInterceptor } from \"./recorder\";\nimport { startIdleScheduler, buildIdleWorkHandler } from \"./idle\";\nimport { getWorkerModel, resetWorkerModelState } from \"./worker-model\";\nimport {\n RECALL_GATEWAY_TOOL,\n RECALL_TOOL_NAME,\n executeRecall,\n findRecallToolUse,\n hasRecallToolUse,\n hasOtherToolUse,\n clientHasRecallTool,\n isPendingRecallValid,\n injectPendingRecall,\n buildRecallFollowUp,\n stripRecallFromResponse,\n} from \"./recall\";\n\n// ---------------------------------------------------------------------------\n// Module state\n// ---------------------------------------------------------------------------\n\n/** One-time initialization flag. */\nlet initialized = false;\n\n/** Active upstream interceptor \u2014 used for recording/replay. */\nlet activeInterceptor: UpstreamInterceptor | undefined;\n\n/**\n * Set (or clear) the module-level upstream interceptor.\n *\n * When set, every call to `forwardToUpstream` passes through the interceptor\n * instead of calling `fetch` directly. Used by the recording and replay\n * scripts to capture or replay upstream traffic without modifying individual\n * call sites.\n */\nexport function setUpstreamInterceptor(\n interceptor: UpstreamInterceptor | undefined,\n): void {\n activeInterceptor = interceptor;\n}\n\n/**\n * Reset all module-level singleton state.\n *\n * Intended for test harnesses only \u2014 allows multiple independent gateway\n * instances to run sequentially in the same Bun process without leaking\n * session state, initialization flags, or cached project paths across test\n * suites.\n */\nexport async function resetPipelineState(): Promise<void> {\n initialized = false;\n cachedProjectPath = null;\n sessions.clear();\n ltmSessionCache.clear();\n // Shut down batch queue gracefully before clearing the client\n if (llmClient && \"shutdown\" in llmClient) {\n await (llmClient as LLMClient & { shutdown: () => Promise<void> }).shutdown();\n }\n llmClient = null;\n activeInterceptor = undefined;\n if (stopIdleScheduler) {\n stopIdleScheduler();\n stopIdleScheduler = null;\n }\n lastSeenSessionModel = null;\n resetWorkerModelState();\n}\n\n/** Cached project path from the first request that carried a system prompt. */\nlet cachedProjectPath: string | null = null;\n\n/** Per-session state tracked across requests. */\nconst sessions = new Map<string, SessionState>();\n\n/**\n * Per-session LTM cache for byte-stability.\n *\n * Without caching, `ltm.forSession()` re-scores entries against evolving\n * session context every turn, producing different formatted text \u2192 system\n * prompt changes at byte 0 \u2192 total cache invalidation on every turn.\n */\nconst ltmSessionCache = new Map<\n string,\n { formatted: string; tokenCount: number }\n>();\n\n/** Cached LLM client for background workers. */\nlet llmClient: LLMClient | null = null;\n\n/** Cleanup function for the idle scheduler timer. */\nlet stopIdleScheduler: (() => void) | null = null;\n\n/** Last seen session model ID \u2014 used for worker model discovery context. */\nlet lastSeenSessionModel: string | null = null;\n\n// ---------------------------------------------------------------------------\n// Model limits \u2014 hardcoded for known models, fallback for unknown\n// ---------------------------------------------------------------------------\n\ntype ModelSpec = {\n context: number;\n output: number;\n /** Cache-read cost per token in USD (Anthropic: 10% of input price). */\n cacheReadCost?: number;\n};\n\nconst MODEL_SPECS: Record<string, ModelSpec> = {\n // Pricing: https://docs.anthropic.com/en/docs/about-claude/models\n // Cache-read = input_price / 1_000_000 * 0.1 (10% of input for Anthropic)\n \"claude-opus-4\": { context: 200_000, output: 32_000, cacheReadCost: 15 / 1_000_000 * 0.1 },\n \"claude-sonnet-4\": { context: 200_000, output: 16_000, cacheReadCost: 3 / 1_000_000 * 0.1 },\n \"claude-sonnet-3-5\": { context: 200_000, output: 8_192, cacheReadCost: 3 / 1_000_000 * 0.1 },\n \"claude-haiku-3-5\": { context: 200_000, output: 8_192, cacheReadCost: 0.80 / 1_000_000 * 0.1 },\n};\n\nconst DEFAULT_MODEL_SPEC: ModelSpec = { context: 200_000, output: 8_192 };\n\nfunction getModelSpec(model: string): ModelSpec {\n // Check for prefix matches: \"claude-opus-4-20250514\" \u2192 \"claude-opus-4\"\n for (const [prefix, spec] of Object.entries(MODEL_SPECS)) {\n if (model.startsWith(prefix)) return spec;\n }\n return DEFAULT_MODEL_SPEC;\n}\n\n// ---------------------------------------------------------------------------\n// Initialization\n// ---------------------------------------------------------------------------\n\n/**\n * One-time init: load Lore config, ensure project exists in DB, start idle scheduler.\n * Safe to call multiple times \u2014 only the first call does work.\n */\nasync function initIfNeeded(projectPath: string, config?: GatewayConfig): Promise<void> {\n if (initialized) return;\n\n await load(projectPath);\n ensureProject(projectPath);\n initialized = true;\n cachedProjectPath = projectPath;\n\n // Start the idle scheduler for background work (distillation, curation,\n // pruning, AGENTS.md export). Uses a 30s poll interval and fires for any\n // session whose lastRequestTime exceeds the idle timeout.\n if (config && !stopIdleScheduler) {\n const llm = getLLMClient(config);\n const sessionModelID = lastSeenSessionModel ?? (loreConfig().model?.modelID ?? \"claude-sonnet-4-20250514\");\n const idleHandler = buildIdleWorkHandler(\n projectPath,\n llm,\n config.upstreamAnthropic,\n () => resolveAuth(),\n sessionModelID,\n // onLtmInvalidated: clear the LTM session cache\n () => ltmSessionCache.clear(),\n );\n stopIdleScheduler = startIdleScheduler(config, sessions, idleHandler);\n }\n\n log.info(`gateway pipeline initialized: ${projectPath}`);\n}\n\nfunction getLLMClient(config: GatewayConfig): LLMClient {\n if (!llmClient) {\n const cfg = loreConfig();\n const defaultModel = cfg.model ?? {\n providerID: \"anthropic\",\n modelID: \"claude-sonnet-4-20250514\",\n };\n const inner = createGatewayLLMClient(\n config.upstreamAnthropic,\n resolveAuth,\n defaultModel,\n );\n\n // Wrap with batch queue for 50% cost savings on non-urgent worker calls.\n // Enabled by default \u2014 disable via LORE_BATCH_DISABLED=1.\n const batchDisabled = process.env.LORE_BATCH_DISABLED === \"1\";\n if (batchDisabled) {\n llmClient = inner;\n } else {\n llmClient = createBatchLLMClient(\n inner,\n config.upstreamAnthropic,\n resolveAuth,\n defaultModel,\n );\n }\n }\n return llmClient;\n}\n\n// ---------------------------------------------------------------------------\n// Session management helpers\n// ---------------------------------------------------------------------------\n\nfunction getOrCreateSession(\n sessionID: string,\n projectPath: string,\n): SessionState {\n let state = sessions.get(sessionID);\n if (!state) {\n state = {\n sessionID,\n projectPath,\n fingerprint: \"\",\n lastRequestTime: Date.now(),\n messageCount: 0,\n turnsSinceCuration: 0,\n };\n sessions.set(sessionID, state);\n }\n state.lastRequestTime = Date.now();\n\n // Lazy cleanup: discard expired pending recall on access\n if (state.pendingRecall && !isPendingRecallValid(state.pendingRecall)) {\n log.warn(\n `lazy cleanup: discarding expired pending recall for session ${sessionID.slice(0, 16)}`,\n );\n state.pendingRecall = undefined;\n }\n\n return state;\n}\n\n/**\n * Identify or create a session from the incoming request messages.\n *\n * Uses a fingerprint of the first user message combined with\n * message-count proximity to correlate requests to sessions.\n * Forked sessions (which share the same first message) are\n * disambiguated by a significant drop in message count.\n */\nasync function identifySession(\n req: GatewayRequest,\n _projectPath: string,\n): Promise<{ sessionID: string; isNew: boolean }> {\n const rawMessages = req.messages.map((m) => ({\n role: m.role,\n content: m.content,\n }));\n const cred = extractAuth(req.rawHeaders);\n const fingerprint = await fingerprintMessages(rawMessages, {\n model: req.model,\n authSuffix: cred ? authFingerprint(cred) : \"\",\n });\n const msgCount = req.messages.length;\n\n // Find the best matching session: same fingerprint + closest message count\n let bestMatch: { sid: string; countDiff: number } | null = null;\n\n for (const [sid, state] of sessions) {\n if (state.fingerprint !== fingerprint) continue;\n\n const diff = msgCount - state.messageCount;\n\n // Normal session: count grows by 2\u20136 per turn.\n // Fork: count drops significantly (parent at 600, fork at 300).\n // Reject if the count dropped too far (likely a fork).\n if (diff < -MESSAGE_COUNT_PROXIMITY_THRESHOLD) continue;\n\n const absDiff = Math.abs(diff);\n if (!bestMatch || absDiff < bestMatch.countDiff) {\n bestMatch = { sid, countDiff: absDiff };\n }\n }\n\n if (bestMatch) {\n return { sessionID: bestMatch.sid, isNew: false };\n }\n\n // No matching session \u2192 create new\n const sessionID = generateSessionID();\n return { sessionID, isNew: true };\n}\n\n// ---------------------------------------------------------------------------\n// Upstream forwarding\n// ---------------------------------------------------------------------------\n\n/**\n * Forward a request to the upstream provider (Anthropic or OpenAI).\n *\n * When an interceptor is provided (or a module-level one is active), the\n * interceptor is called instead of `fetch` directly. This enables recording\n * and replay without modifying individual call sites.\n *\n * Returns the raw fetch Response (may be streaming or non-streaming).\n */\nasync function forwardToUpstream(\n req: GatewayRequest,\n config: GatewayConfig,\n interceptor?: UpstreamInterceptor,\n cache?: AnthropicCacheOptions,\n): Promise<Response> {\n let url: string;\n let headers: Record<string, string>;\n let body: unknown;\n\n // Infer upstream from model name; fall back to protocol + env-var defaults.\n const route = resolveUpstreamRoute(req.model);\n const effectiveProtocol = route?.protocol ?? req.protocol;\n const effectiveUpstreamBase = route?.url ?? (effectiveProtocol === \"openai\" ? config.upstreamOpenAI : config.upstreamAnthropic);\n\n if (effectiveProtocol === \"openai\") {\n const result = buildOpenAIUpstreamRequest(req, effectiveUpstreamBase);\n url = result.url;\n headers = result.headers;\n body = result.body;\n } else {\n const result = buildAnthropicRequest(req, cache);\n url = `${effectiveUpstreamBase}${result.url}`;\n headers = result.headers;\n body = result.body;\n }\n\n const effectiveInterceptor = interceptor ?? activeInterceptor;\n\n if (effectiveInterceptor) {\n return effectiveInterceptor(\n body,\n req.model,\n req.stream,\n () =>\n fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n }),\n );\n }\n\n return fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n });\n}\n\n// ---------------------------------------------------------------------------\n// Response builders\n// ---------------------------------------------------------------------------\n\n/**\n * Create a streaming SSE response from upstream with parallel accumulation.\n *\n * When `recallContext` is provided, uses a recall-aware accumulator that\n * transparently intercepts recall tool_use blocks:\n * - **Case 1 (recall-only)**: pauses client stream, executes recall, sends\n * a follow-up request, and pipes the continuation into the same HTTP\n * response stream.\n * - **Case 2 (mixed tools)**: suppresses recall blocks, stores the pending\n * result for injection into the next request.\n */\nfunction buildStreamingResponse(\n upstreamResponse: Response,\n onComplete: (response: GatewayResponse) => void,\n recallContext?: {\n modifiedReq: GatewayRequest;\n config: GatewayConfig;\n sessionState: SessionState;\n cacheOptions: AnthropicCacheOptions;\n },\n): Response {\n const recallAccum = recallContext\n ? createRecallAwareAccumulator(RECALL_TOOL_NAME)\n : null;\n const accumulator: StreamAccumulator = recallAccum ?? createStreamAccumulator();\n const encoder = new TextEncoder();\n\n const stream = new ReadableStream({\n async start(controller) {\n try {\n // Parse and forward upstream SSE events\n const reader = upstreamResponse.body!.getReader();\n for await (const { event, data } of parseSSEStream(reader)) {\n const forwarded = accumulator.processEvent(event, data);\n if (forwarded) {\n controller.enqueue(encoder.encode(forwarded));\n }\n }\n\n // --- Recall interception (streaming) ---\n if (recallAccum?.hasRecall()) {\n const resp = recallAccum.getResponse();\n const recallBlock = findRecallToolUse(resp);\n\n if (recallBlock && recallContext) {\n const { result, input } = await executeRecall(\n recallBlock,\n recallContext.sessionState.projectPath,\n recallContext.sessionState.sessionID,\n );\n\n if (recallAccum.hasOtherTools()) {\n // Case 2: mixed tools \u2014 store pending, forward held-back events\n const position = resp.content.indexOf(recallBlock);\n recallContext.sessionState.pendingRecall = {\n toolUseId: recallBlock.id,\n input,\n position,\n result,\n timestamp: Date.now(),\n };\n log.info(\n `recall (stream, mixed): stored pending result for session ` +\n `${recallContext.sessionState.sessionID.slice(0, 16)}`,\n );\n\n // Emit a synthetic \"[Searching memory...]\" text block after all\n // other tool blocks. The accumulator already re-indexed other\n // tools to fill the gap, so this goes at clientBlockCount.\n const searchingIdx = recallAccum.clientBlockCount();\n const syntheticCase2 = [\n formatSSEEvent(\"content_block_start\", JSON.stringify({\n type: \"content_block_start\",\n index: searchingIdx,\n content_block: { type: \"text\", text: \"\" },\n })),\n formatSSEEvent(\"content_block_delta\", JSON.stringify({\n type: \"content_block_delta\",\n index: searchingIdx,\n delta: { type: \"text_delta\", text: \"\\n\\n[Searching memory...]\" },\n })),\n formatSSEEvent(\"content_block_stop\", JSON.stringify({\n type: \"content_block_stop\",\n index: searchingIdx,\n })),\n ].join(\"\");\n controller.enqueue(encoder.encode(syntheticCase2));\n\n // Forward the held-back message_delta + message_stop\n const heldBack = recallAccum.heldBackEvents();\n if (heldBack) {\n controller.enqueue(encoder.encode(heldBack));\n }\n\n controller.close();\n\n // Post-stream: use stripped response for temporal storage\n const cleanResp = stripRecallFromResponse(resp);\n onComplete(cleanResp);\n return;\n }\n\n // Case 1: recall-only \u2014 send follow-up, pipe continuation\n log.info(\n `recall (stream, only): executing follow-up for session ` +\n `${recallContext.sessionState.sessionID.slice(0, 16)}`,\n );\n\n // Emit a synthetic \"[Searching memory...]\" text block at the\n // suppressed recall index so the client sees a natural indicator\n // during the pause while the recall executes.\n const searchingIndex = recallAccum.clientBlockCount();\n const syntheticBlock = [\n formatSSEEvent(\"content_block_start\", JSON.stringify({\n type: \"content_block_start\",\n index: searchingIndex,\n content_block: { type: \"text\", text: \"\" },\n })),\n formatSSEEvent(\"content_block_delta\", JSON.stringify({\n type: \"content_block_delta\",\n index: searchingIndex,\n delta: { type: \"text_delta\", text: \"\\n\\n[Searching memory...]\" },\n })),\n formatSSEEvent(\"content_block_stop\", JSON.stringify({\n type: \"content_block_stop\",\n index: searchingIndex,\n })),\n ].join(\"\");\n controller.enqueue(encoder.encode(syntheticBlock));\n\n const followUp = buildRecallFollowUp(\n recallContext.modifiedReq,\n resp,\n result,\n recallBlock,\n );\n const followUpResponse = await forwardToUpstream(\n followUp,\n recallContext.config,\n undefined,\n recallContext.cacheOptions,\n );\n\n if (!followUpResponse.ok) {\n const errorBody = await followUpResponse.text();\n log.error(\n `recall follow-up upstream error: ${followUpResponse.status} ${errorBody.slice(0, 500)}`,\n );\n // Forward the held-back events to close the stream gracefully\n const heldBack = recallAccum.heldBackEvents();\n if (heldBack) {\n controller.enqueue(encoder.encode(heldBack));\n }\n controller.close();\n const cleanResp = stripRecallFromResponse(resp);\n onComplete(cleanResp);\n return;\n }\n\n // Pipe the continuation stream into the same HTTP response.\n // Suppress message_start (client already has one) and re-index\n // content blocks to continue from where the client left off.\n // +1 accounts for the synthetic \"[Searching memory...]\" block.\n // Use clientBlockCount (not recallBlockIndex) \u2014 this is the number\n // of blocks the client has already seen, so continuation blocks\n // start at clientBlockCount + 1 (for the synthetic block).\n const blockOffset = recallAccum.clientBlockCount() + 1;\n const contReader = followUpResponse.body!.getReader();\n\n for await (const { event: contEvent, data: contData } of parseSSEStream(contReader)) {\n if (contEvent === \"message_start\") {\n // Suppress \u2014 client already received one\n continue;\n }\n\n // Re-index content block events\n if (\n contEvent === \"content_block_start\" ||\n contEvent === \"content_block_delta\" ||\n contEvent === \"content_block_stop\"\n ) {\n try {\n const parsed = JSON.parse(contData) as Record<string, unknown>;\n if (typeof parsed.index === \"number\") {\n parsed.index = (parsed.index as number) + blockOffset;\n const adjusted = formatSSEEvent(\n contEvent,\n JSON.stringify(parsed),\n );\n controller.enqueue(encoder.encode(adjusted));\n continue;\n }\n } catch {\n // Fall through to forward as-is\n }\n }\n\n // Forward message_delta, message_stop, and other events as-is\n const forwarded = formatSSEEvent(contEvent, contData);\n controller.enqueue(encoder.encode(forwarded));\n }\n\n controller.close();\n\n // Post-stream: accumulate the continuation for temporal storage.\n // We use resp (original) + continuation for a complete picture,\n // but for simplicity just store the continuation response since\n // it's what the model actually produced for the client.\n // The continuation accumulator was not wired \u2014 use the original\n // response's pre-recall content + continuation's content.\n // For now, call onComplete with the original response so at least\n // the pre-recall content is stored. The continuation's text is\n // visible to the client but not separately stored \u2014 acceptable\n // since temporal storage captures the full conversation on next turn.\n onComplete(resp);\n return;\n }\n }\n\n // No recall \u2014 normal path\n controller.close();\n const response = accumulator.getResponse();\n onComplete(response);\n } catch (err) {\n log.error(\"streaming pipeline error:\", err);\n controller.error(err);\n }\n },\n });\n\n return new Response(stream, {\n status: 200,\n headers: {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-cache\",\n connection: \"keep-alive\",\n },\n });\n}\n\n/**\n * Accumulate a non-streaming upstream response into a GatewayResponse.\n */\nasync function accumulateNonStreamResponse(\n upstreamResponse: Response,\n): Promise<GatewayResponse> {\n const json = (await upstreamResponse.json()) as Record<string, unknown>;\n\n const content: GatewayContentBlock[] = [];\n const rawContent = json.content as Array<Record<string, unknown>> | undefined;\n if (rawContent) {\n for (const block of rawContent) {\n switch (block.type) {\n case \"text\":\n content.push({ type: \"text\", text: String(block.text ?? \"\") });\n break;\n case \"thinking\":\n content.push({\n type: \"thinking\",\n thinking: String(block.thinking ?? \"\"),\n ...(block.signature\n ? { signature: String(block.signature) }\n : undefined),\n });\n break;\n case \"tool_use\":\n content.push({\n type: \"tool_use\",\n id: String(block.id ?? \"\"),\n name: String(block.name ?? \"\"),\n input: block.input,\n });\n break;\n }\n }\n }\n\n const usage = json.usage as Record<string, number> | undefined;\n\n return {\n id: String(json.id ?? \"\"),\n model: String(json.model ?? \"\"),\n content,\n stopReason: String(\n (json.stop_reason as string) ?? \"end_turn\",\n ),\n usage: {\n inputTokens: usage?.input_tokens ?? 0,\n outputTokens: usage?.output_tokens ?? 0,\n cacheReadInputTokens: usage?.cache_read_input_tokens,\n cacheCreationInputTokens: usage?.cache_creation_input_tokens,\n },\n };\n}\n\n/**\n * Accumulate a streaming upstream SSE response into a GatewayResponse.\n *\n * Used for OpenAI requests where we need to convert the accumulated\n * response to OpenAI format before returning to the client.\n */\nasync function accumulateStreamResponse(\n upstreamResponse: Response,\n): Promise<GatewayResponse> {\n const accumulator = createStreamAccumulator();\n const reader = upstreamResponse.body!.getReader();\n\n for await (const { event, data } of parseSSEStream(reader)) {\n accumulator.processEvent(event, data);\n }\n\n return accumulator.getResponse();\n}\n\n/**\n * Convert a GatewayResponse to a non-streaming HTTP Response.\n */\nfunction nonStreamHttpResponse(resp: GatewayResponse): Response {\n const body = buildAnthropicNonStreamResponse(resp);\n return new Response(JSON.stringify(body), {\n status: 200,\n headers: { \"content-type\": \"application/json\" },\n });\n}\n\n/**\n * Convert a GatewayResponse to a streaming SSE HTTP Response.\n */\nfunction streamHttpResponse(resp: GatewayResponse): Response {\n // Build the full SSE text for a text-only response\n const textBlocks = resp.content.filter(\n (b): b is { type: \"text\"; text: string } => b.type === \"text\",\n );\n const fullText = textBlocks.map((b) => b.text).join(\"\");\n\n const sseBody = buildSSETextResponse(resp.id, resp.model, fullText, {\n inputTokens: resp.usage.inputTokens,\n outputTokens: resp.usage.outputTokens,\n });\n\n return new Response(sseBody, {\n status: 200,\n headers: {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-cache\",\n connection: \"keep-alive\",\n },\n });\n}\n\n// ---------------------------------------------------------------------------\n// Post-response processing\n// ---------------------------------------------------------------------------\n\n/**\n * Run after a successful response: calibrate, store temporal messages,\n * and schedule background work (distillation, curation).\n */\nfunction postResponse(\n req: GatewayRequest,\n resp: GatewayResponse,\n sessionState: SessionState,\n config: GatewayConfig,\n): void {\n const { sessionID, projectPath } = sessionState;\n\n try {\n // --- Calibrate overhead from real token counts ---\n const actualInput =\n (resp.usage.inputTokens ?? 0) +\n (resp.usage.cacheReadInputTokens ?? 0) +\n (resp.usage.cacheCreationInputTokens ?? 0);\n calibrate(\n actualInput,\n sessionID,\n getLastTransformedCount(sessionID),\n );\n\n // --- Temporal storage ---\n // Store all messages (user + assistant) from this turn.\n // Convert gateway messages to Lore format.\n const loreMessages = gatewayMessagesToLore(req.messages, sessionID);\n resolveToolResults(loreMessages);\n\n // Store the latest user message (last user message in the array)\n for (let i = loreMessages.length - 1; i >= 0; i--) {\n if (loreMessages[i].info.role === \"user\") {\n temporal.store({\n projectPath,\n info: loreMessages[i].info,\n parts: loreMessages[i].parts,\n });\n break;\n }\n }\n\n // Build and store the assistant response message\n const assistantMsg = gatewayMessagesToLore(\n [{ role: \"assistant\", content: resp.content }],\n sessionID,\n )[0];\n updateAssistantMessageTokens(assistantMsg, resp.usage, resp.model);\n temporal.store({\n projectPath,\n info: assistantMsg.info,\n parts: assistantMsg.parts,\n });\n\n // Update session state\n sessionState.turnsSinceCuration =\n (sessionState.turnsSinceCuration ?? 0) + 1;\n\n // --- Schedule background work (fire-and-forget) ---\n scheduleBackgroundWork(sessionState, config);\n } catch (e) {\n log.error(\"post-response processing failed:\", e);\n }\n}\n\n/**\n * Schedule background distillation and curation (fire-and-forget).\n */\nfunction scheduleBackgroundWork(\n sessionState: SessionState,\n config: GatewayConfig,\n): void {\n const { sessionID, projectPath } = sessionState;\n const llm = getLLMClient(config);\n const cfg = loreConfig();\n const model = getWorkerModel();\n\n // Check if urgent distillation is needed (gradient flagged it).\n // Mark urgent: true so these bypass the batch queue \u2014 the gradient is\n // in overflow and needs the result before the next user turn.\n if (needsUrgentDistillation()) {\n distillation\n .run({\n llm,\n projectPath,\n sessionID,\n model,\n force: true,\n urgent: true,\n })\n .catch((e) => log.error(\"background distillation failed:\", e));\n }\n\n // Check if pending messages exceed maxSegment threshold\n const pending = temporal.undistilledCount(projectPath, sessionID);\n if (pending >= cfg.distillation.maxSegment) {\n log.info(\n `incremental distillation: ${pending} undistilled messages in ${sessionID.slice(0, 16)}`,\n );\n distillation\n .run({ llm, projectPath, sessionID, model })\n .catch((e) => log.error(\"background distillation failed:\", e));\n }\n\n // Curation: run periodically when the knowledge system is enabled\n if (\n cfg.knowledge.enabled &&\n cfg.curator.onIdle &&\n sessionState.turnsSinceCuration >= cfg.curator.afterTurns\n ) {\n curator\n .run({ llm, projectPath, sessionID, model })\n .then(() => {\n sessionState.turnsSinceCuration = 0;\n // Invalidate LTM cache after curation changes knowledge entries\n ltmSessionCache.delete(sessionID);\n })\n .catch((e) => log.error(\"background curation failed:\", e));\n }\n}\n\n// ---------------------------------------------------------------------------\n// Case 1: Compaction interception\n// ---------------------------------------------------------------------------\n\nasync function handleCompaction(\n req: GatewayRequest,\n config: GatewayConfig,\n): Promise<Response> {\n // Identify session\n const projectPath = cachedProjectPath ?? getProjectPath(req.system, req.rawHeaders);\n await initIfNeeded(projectPath, config);\n\n const { sessionID } = await identifySession(req, projectPath);\n const sessionState = getOrCreateSession(sessionID, projectPath);\n const llm = getLLMClient(config);\n\n log.info(`compaction intercepted for session ${sessionID.slice(0, 16)}`);\n\n // 1. Force-distill all undistilled messages.\n // Mark urgent: true \u2014 client is blocking on the compaction response.\n const model = getWorkerModel();\n await distillation.run({\n llm,\n projectPath,\n sessionID,\n model,\n force: true,\n urgent: true,\n });\n\n // 2. Load distillation summaries\n const distillations = distillation.loadForSession(projectPath, sessionID);\n\n // 3. Extract previous summary from the request (if any)\n const previousSummary = extractPreviousSummary(req);\n\n // 4. Build knowledge block\n const cfg = loreConfig();\n const entries = cfg.knowledge.enabled\n ? ltm.forProject(projectPath, cfg.crossProject)\n : [];\n const knowledge = entries.length\n ? formatKnowledge(\n entries.map((e) => ({\n category: e.category,\n title: e.title,\n content: e.content,\n })),\n )\n : \"\";\n\n // 5. Build the compact prompt\n const compactPrompt = buildCompactPrompt({\n hasDistillations: distillations.length > 0,\n knowledge,\n previousSummary,\n });\n\n // 6. Build context with distillation summaries\n let context = \"\";\n if (distillations.length > 0) {\n context =\n `## Lore Pre-computed Session Summaries\\n\\n` +\n `The following ${distillations.length} summary chunk(s) were pre-computed ` +\n `from the conversation history. Use these as the authoritative source.\\n\\n` +\n distillations\n .map(\n (d, i) =>\n `### Chunk ${i + 1}${d.generation > 0 ? \" (consolidated)\" : \"\"}\\n${d.observations}`,\n )\n .join(\"\\n\\n\");\n }\n\n // 7. Generate the compaction summary via LLM\n const userContent = context\n ? `${context}\\n\\n---\\n\\n${compactPrompt}`\n : compactPrompt;\n\n const summaryText = await llm.prompt(compactPrompt, userContent, {\n model: cfg.model,\n workerID: \"lore-compact\",\n urgent: true, // Client is blocking on this response\n });\n\n const summary = summaryText ?? \"(Compaction failed \u2014 no summary generated.)\";\n\n // 8. Build and return the response\n const resp = buildCompactionResponse(sessionID, summary, req.model);\n\n if (req.stream) {\n return streamHttpResponse(resp);\n }\n return nonStreamHttpResponse(resp);\n}\n\n// ---------------------------------------------------------------------------\n// Case 2: Title/summary passthrough\n// ---------------------------------------------------------------------------\n\nasync function handlePassthrough(\n req: GatewayRequest,\n config: GatewayConfig,\n): Promise<Response> {\n const upstreamResponse = await forwardToUpstream(req, config);\n\n // For streaming, pipe through unchanged\n if (req.stream && upstreamResponse.body) {\n return new Response(upstreamResponse.body, {\n status: upstreamResponse.status,\n headers: {\n \"content-type\":\n upstreamResponse.headers.get(\"content-type\") ??\n \"text/event-stream\",\n },\n });\n }\n\n // For non-streaming, pass through the JSON response as-is\n const body = await upstreamResponse.text();\n return new Response(body, {\n status: upstreamResponse.status,\n headers: {\n \"content-type\": \"application/json\",\n },\n });\n}\n\n// ---------------------------------------------------------------------------\n// Case 3: Normal conversation turn \u2014 full pipeline\n// ---------------------------------------------------------------------------\n\nasync function handleConversationTurn(\n req: GatewayRequest,\n config: GatewayConfig,\n): Promise<Response> {\n // --- 1. Project path & init ---\n const projectPath = getProjectPath(req.system, req.rawHeaders);\n await initIfNeeded(projectPath, config);\n\n // --- 2. Capture auth credentials for background workers ---\n const cred = extractAuth(req.rawHeaders);\n if (cred) {\n setLastSeenAuth(cred);\n }\n\n // --- 3. Session identification ---\n const { sessionID, isNew } = await identifySession(req, projectPath);\n const sessionState = getOrCreateSession(sessionID, projectPath);\n\n // Bind auth credential to this session for background workers\n if (cred) {\n setSessionAuth(sessionID, cred);\n }\n\n // Track fingerprint for future correlation\n if (isNew) {\n const fingerprint = await fingerprintMessages(\n req.messages.map((m) => ({ role: m.role, content: m.content })),\n {\n model: req.model,\n authSuffix: cred ? authFingerprint(cred) : \"\",\n },\n );\n sessionState.fingerprint = fingerprint;\n }\n\n // Always update message count for proximity matching\n sessionState.messageCount = req.messages.length;\n\n // Track session model for worker model discovery\n lastSeenSessionModel = req.model;\n\n // --- Inject pending recall from previous turn (Case 2: mixed tools) ---\n if (sessionState.pendingRecall) {\n if (isPendingRecallValid(sessionState.pendingRecall)) {\n const injected = injectPendingRecall(req, sessionState.pendingRecall);\n if (injected) {\n log.info(\n `injected pending recall result into request for session ${sessionID.slice(0, 16)}`,\n );\n } else {\n log.warn(\n `failed to inject pending recall \u2014 conversation structure mismatch`,\n );\n }\n } else {\n log.warn(\n `discarding expired pending recall for session ${sessionID.slice(0, 16)}`,\n );\n }\n sessionState.pendingRecall = undefined;\n }\n\n log.info(\n `turn: session=${sessionID.slice(0, 16)} messages=${req.messages.length} ` +\n `model=${req.model} stream=${req.stream} new=${isNew}`,\n );\n\n // --- 4. Set model limits ---\n const modelSpec = getModelSpec(req.model);\n setModelLimits({ context: modelSpec.context, output: modelSpec.output });\n\n // Cost-aware layer-0 cap: explicit config wins > cost formula > disabled.\n const cfg = loreConfig();\n if (cfg.budget.maxLayer0Tokens !== undefined) {\n setMaxLayer0Tokens(cfg.budget.maxLayer0Tokens);\n } else if (modelSpec.cacheReadCost && cfg.budget.targetCacheReadCostPerTurn > 0) {\n setMaxLayer0Tokens(computeLayer0Cap(\n cfg.budget.targetCacheReadCostPerTurn,\n modelSpec.cacheReadCost,\n ));\n }\n\n // --- 5. Cold-cache idle-resume ---\n const thresholdMs = cfg.idleResumeMinutes * 60_000;\n const idleResult = onIdleResume(sessionID, thresholdMs);\n if (idleResult.triggered) {\n ltmSessionCache.delete(sessionID);\n log.info(\n `session idle ${Math.round(idleResult.idleMs / 60_000)}min \u2014 refreshing caches`,\n );\n }\n\n // --- 6. LTM injection into system prompt ---\n let modifiedSystem = req.system;\n if (cfg.knowledge.enabled) {\n try {\n let cached = ltmSessionCache.get(sessionID);\n\n if (!cached) {\n const ltmFraction = cfg.budget.ltm;\n const ltmBudget = getLtmBudget(ltmFraction);\n const entries = ltm.forSession(projectPath, sessionID, ltmBudget);\n if (entries.length) {\n const formatted = formatKnowledge(\n entries.map((e) => ({\n category: e.category,\n title: e.title,\n content: e.content,\n })),\n ltmBudget,\n );\n\n if (formatted) {\n const tokenCount = Math.ceil(formatted.length / 3);\n cached = { formatted, tokenCount };\n ltmSessionCache.set(sessionID, cached);\n }\n }\n }\n\n if (cached) {\n setLtmTokens(cached.tokenCount, sessionID);\n modifiedSystem = `${req.system}\\n\\n${cached.formatted}`;\n } else {\n setLtmTokens(0, sessionID);\n }\n } catch (e) {\n log.error(\"LTM injection failed:\", e);\n setLtmTokens(0, sessionID);\n } finally {\n consumeCameOutOfIdle(sessionID);\n }\n } else {\n setLtmTokens(0, sessionID);\n consumeCameOutOfIdle(sessionID);\n }\n\n // First-run greeting\n if (isFirstRun()) {\n modifiedSystem +=\n \"\\n\\n[Lore plugin] This is the first time Lore has been activated. \" +\n \"Briefly let the user know that Lore is now active and their \" +\n \"coding agent will get progressively smarter on this codebase \" +\n \"over time as knowledge accumulates across sessions.\";\n }\n\n // Lore knowledge file commit reminder\n if (cfg.knowledge.enabled) {\n const filesToTrack = [\".lore.md\"];\n if (cfg.agentsFile.enabled) filesToTrack.push(cfg.agentsFile.path);\n modifiedSystem +=\n `\\n\\nWhen making git commits, always check if ${filesToTrack.join(\" and \")} ` +\n `have unstaged changes and include them in the commit. These files contain ` +\n `shared project knowledge managed by lore and must be version-controlled.`;\n }\n\n // --- 7. Gradient transform on messages ---\n const loreMessages = gatewayMessagesToLore(req.messages, sessionID);\n resolveToolResults(loreMessages);\n\n const result = transform({\n messages: loreMessages,\n projectPath,\n sessionID,\n });\n\n // Drop trailing pure-text assistant messages to prevent prefill errors\n while (\n result.messages.length > 0 &&\n result.messages.at(-1)!.info.role !== \"user\"\n ) {\n const last = result.messages.at(-1)!;\n const hasToolParts = last.parts.some((p) => p.type === \"tool\");\n if (hasToolParts) break;\n result.messages.pop();\n }\n\n // --- 8. Build the modified request ---\n // Reconstruct GatewayMessages from the transformed Lore messages.\n // loreMessagesToGateway reconstructs tool_result blocks from assistant's\n // completed/error tool parts; removeOrphanedToolResults is a safety net\n // that catches any remaining orphaned tool_result references.\n const transformedMessages = loreMessagesToGateway(result.messages);\n removeOrphanedToolResults(transformedMessages);\n\n const modifiedReq: GatewayRequest = {\n ...req,\n system: modifiedSystem,\n messages: transformedMessages,\n };\n\n // --- 8b. Inject recall tool ---\n // Only inject if the client doesn't already have a recall tool (e.g. from\n // a host plugin like OpenCode) and the request has other tools (so it's a\n // coding agent, not a bare chat).\n if (modifiedReq.tools.length > 0 && !clientHasRecallTool(modifiedReq.tools)) {\n modifiedReq.tools = [...modifiedReq.tools, RECALL_GATEWAY_TOOL];\n }\n\n // --- 9. Forward to upstream ---\n // Enable prompt caching for conversation turns:\n // - System prompt: explicit breakpoint with 5m TTL (frequent turns)\n // - Conversation: breakpoint on last block so Anthropic caches the prefix\n // Title/summary passthrough (handlePassthrough) never reaches here \u2014 it\n // forwards the raw request without buildAnthropicRequest, so no caching.\n const cacheOptions: AnthropicCacheOptions = {\n systemTTL: \"5m\",\n cacheConversation: true,\n };\n const upstreamResponse = await forwardToUpstream(\n modifiedReq,\n config,\n undefined,\n cacheOptions,\n );\n\n if (!upstreamResponse.ok) {\n const errorBody = await upstreamResponse.text();\n log.error(\n `upstream error: ${upstreamResponse.status} ${errorBody.slice(0, 500)}`,\n );\n return new Response(errorBody, {\n status: upstreamResponse.status,\n headers: { \"content-type\": \"application/json\" },\n });\n }\n\n if (req.stream && upstreamResponse.body) {\n // Streaming: forward events and accumulate in parallel.\n // Pass recall context so the accumulator can intercept recall tool_use.\n const hasRecallTool = modifiedReq.tools.some(\n (t) => t.name === RECALL_TOOL_NAME,\n );\n return buildStreamingResponse(\n upstreamResponse,\n (resp) => postResponse(req, resp, sessionState, config),\n hasRecallTool\n ? { modifiedReq, config, sessionState, cacheOptions }\n : undefined,\n );\n }\n\n // Non-streaming (also used for OpenAI protocol via accumulateStreamResponse)\n const resp = await accumulateNonStreamResponse(upstreamResponse);\n\n // --- Recall interception (non-streaming) ---\n if (hasRecallToolUse(resp)) {\n const recallBlock = findRecallToolUse(resp)!;\n const { result, input } = await executeRecall(\n recallBlock,\n sessionState.projectPath,\n sessionState.sessionID,\n );\n\n if (hasOtherToolUse(resp)) {\n // Case 2: recall + other tools \u2014 store pending, strip recall from response\n const position = resp.content.indexOf(recallBlock);\n sessionState.pendingRecall = {\n toolUseId: recallBlock.id,\n input,\n position,\n result,\n timestamp: Date.now(),\n };\n log.info(\n `recall (non-stream, mixed): stored pending result for session ${sessionState.sessionID.slice(0, 16)}`,\n );\n const cleanResp = stripRecallFromResponse(resp);\n postResponse(req, cleanResp, sessionState, config);\n return nonStreamHttpResponse(cleanResp);\n }\n\n // Case 1: recall-only \u2014 send follow-up request\n log.info(\n `recall (non-stream, only): executing follow-up for session ${sessionState.sessionID.slice(0, 16)}`,\n );\n const followUp = buildRecallFollowUp(modifiedReq, resp, result, recallBlock);\n // Strip recall from the follow-up tools (already done by buildRecallFollowUp)\n const followUpResponse = await forwardToUpstream(\n followUp,\n config,\n undefined,\n cacheOptions,\n );\n\n if (!followUpResponse.ok) {\n const errorBody = await followUpResponse.text();\n log.error(\n `recall follow-up upstream error: ${followUpResponse.status} ${errorBody.slice(0, 500)}`,\n );\n // Fall back to the original response without recall\n const cleanResp = stripRecallFromResponse(resp);\n postResponse(req, cleanResp, sessionState, config);\n return nonStreamHttpResponse(cleanResp);\n }\n\n const continuationResp = await accumulateNonStreamResponse(followUpResponse);\n\n // Merge usage from both requests\n continuationResp.usage.inputTokens += resp.usage.inputTokens;\n continuationResp.usage.outputTokens += resp.usage.outputTokens;\n if (resp.usage.cacheReadInputTokens) {\n continuationResp.usage.cacheReadInputTokens =\n (continuationResp.usage.cacheReadInputTokens ?? 0) +\n resp.usage.cacheReadInputTokens;\n }\n if (resp.usage.cacheCreationInputTokens) {\n continuationResp.usage.cacheCreationInputTokens =\n (continuationResp.usage.cacheCreationInputTokens ?? 0) +\n resp.usage.cacheCreationInputTokens;\n }\n\n postResponse(req, continuationResp, sessionState, config);\n return nonStreamHttpResponse(continuationResp);\n }\n\n postResponse(req, resp, sessionState, config);\n return nonStreamHttpResponse(resp);\n}\n\n// ---------------------------------------------------------------------------\n// Lore message \u2192 Gateway message conversion\n// ---------------------------------------------------------------------------\n\n/**\n * Convert transformed Lore messages back to gateway message format.\n *\n * This reverses `gatewayMessagesToLore` after gradient transform has\n * potentially trimmed/reordered messages.\n *\n * Completed/error tool parts on assistant messages produce BOTH a `tool_use`\n * block on the assistant AND a corresponding `tool_result` block injected at\n * the start of the following user message. This makes the conversion\n * self-contained: tool pairing is reconstructed from whatever messages\n * survived gradient eviction, without depending on cross-message `tool_result`\n * parts that can become orphaned when the assistant message is evicted.\n *\n * `resolveToolResults()` strips `tool: \"result\"` parts from user messages\n * after pairing, so under normal operation those parts are gone. The fallback\n * handling for residual `tool: \"result\"` parts is kept for robustness.\n */\n/** @internal Exported for tests. */\nexport function loreMessagesToGateway(\n messages: LoreMessageWithParts[],\n): Array<{ role: \"user\" | \"assistant\"; content: GatewayContentBlock[] }> {\n const out: Array<{\n role: \"user\" | \"assistant\";\n content: GatewayContentBlock[];\n }> = [];\n\n // tool_result blocks reconstructed from the preceding assistant message's\n // completed/error tool parts. Injected at the start of the next user message.\n let pendingToolResults: GatewayContentBlock[] = [];\n\n for (const msg of messages) {\n const content: GatewayContentBlock[] = [];\n\n if (msg.info.role === \"user\") {\n // Inject reconstructed tool_result blocks from preceding assistant\n content.push(...pendingToolResults);\n pendingToolResults = [];\n } else {\n // New assistant message \u2014 reset pending results (shouldn't have any\n // in well-formed conversations, but handles back-to-back assistants)\n pendingToolResults = [];\n }\n\n for (const part of msg.parts) {\n switch (part.type) {\n case \"text\":\n content.push({\n type: \"text\",\n text: (part as { text: string }).text,\n });\n break;\n case \"reasoning\":\n content.push({\n type: \"thinking\",\n thinking: (part as { text: string }).text ?? \"\",\n });\n break;\n case \"tool\": {\n const toolPart = part as {\n type: \"tool\";\n tool: string;\n callID: string;\n state: {\n status: string;\n input?: unknown;\n output?: string;\n error?: string;\n };\n };\n if (toolPart.tool === \"result\") {\n // Residual tool_result part (should have been stripped by\n // resolveToolResults, but handle gracefully for robustness)\n content.push({\n type: \"tool_result\",\n toolUseId: toolPart.callID,\n content: toolPart.state.output ?? \"\",\n });\n } else {\n // Emit tool_use on this assistant message\n content.push({\n type: \"tool_use\",\n id: toolPart.callID,\n name: toolPart.tool,\n input: toolPart.state.input ?? {},\n });\n // Completed/error tool parts: queue a tool_result for the next\n // user message. This reconstructs the Anthropic API's split-\n // message format from Lore's single-message representation.\n if (toolPart.state.status === \"completed\") {\n pendingToolResults.push({\n type: \"tool_result\",\n toolUseId: toolPart.callID,\n content: toolPart.state.output ?? \"\",\n });\n } else if (toolPart.state.status === \"error\") {\n pendingToolResults.push({\n type: \"tool_result\",\n toolUseId: toolPart.callID,\n content: toolPart.state.error ?? \"[error]\",\n isError: true,\n });\n }\n // Pending tool parts (not yet resolved) only emit tool_use \u2014\n // the model will see an unresolved tool call. sanitizeToolParts\n // in gradient.ts converts these to error state before this point.\n }\n break;\n }\n // Generic / unknown parts \u2014 skip or represent as text\n default:\n if (\"text\" in part && typeof part.text === \"string\") {\n content.push({ type: \"text\", text: part.text });\n }\n break;\n }\n }\n\n out.push({ role: msg.info.role as \"user\" | \"assistant\", content });\n }\n\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Post-conversion validation: remove orphaned tool_result blocks\n// ---------------------------------------------------------------------------\n\n/**\n * Belt-and-suspenders safety net: ensures every `tool_result` block on a user\n * message references a `tool_use` block on the immediately preceding assistant\n * message. Removes orphans and logs a warning.\n *\n * This should never fire under normal operation (resolveToolResults strips\n * redundant tool_result parts, and loreMessagesToGateway reconstructs them\n * from the assistant's completed tool parts). But if a future code path\n * introduces orphaned references, this catches them before they reach the API.\n */\n/** @internal Exported for tests. */\nexport function removeOrphanedToolResults(\n messages: Array<{\n role: \"user\" | \"assistant\";\n content: GatewayContentBlock[];\n }>,\n): void {\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i]!;\n if (msg.role !== \"user\") continue;\n if (!msg.content.some((b) => b.type === \"tool_result\")) continue;\n\n // Collect tool_use IDs from the preceding assistant message\n const prev =\n i > 0 && messages[i - 1]!.role === \"assistant\"\n ? messages[i - 1]!\n : null;\n const toolUseIds = new Set(\n (prev?.content ?? [])\n .filter((b): b is GatewayToolUseBlock => b.type === \"tool_use\")\n .map((b) => b.id),\n );\n\n // Remove tool_result blocks that reference missing tool_use IDs\n const before = msg.content.length;\n msg.content = msg.content.filter(\n (b) =>\n b.type !== \"tool_result\" ||\n toolUseIds.has((b as GatewayToolResultBlock).toolUseId),\n );\n if (msg.content.length < before) {\n log.warn(\n `removed ${before - msg.content.length} orphaned tool_result block(s) from message ${i}`,\n );\n }\n // If the user message is now empty, add placeholder text so the API\n // doesn't reject an empty content array.\n if (msg.content.length === 0) {\n msg.content = [{ type: \"text\", text: \"[tool results provided]\" }];\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Error response builder\n// ---------------------------------------------------------------------------\n\nfunction errorResponse(status: number, message: string): Response {\n return new Response(\n JSON.stringify({\n type: \"error\",\n error: {\n type: \"server_error\",\n message,\n },\n }),\n {\n status,\n headers: { \"content-type\": \"application/json\" },\n },\n );\n}\n\n// ---------------------------------------------------------------------------\n// Main entry point\n// ---------------------------------------------------------------------------\n\n/**\n * Process an incoming gateway request through the full Lore pipeline.\n *\n * Returns a standard `Response` object \u2014 either a streaming SSE response\n * or a JSON response, depending on the client's `stream` setting.\n */\nexport async function handleRequest(\n req: GatewayRequest,\n config: GatewayConfig,\n): Promise<Response> {\n try {\n // Capture auth credentials early for background workers\n const earlyAuth = extractAuth(req.rawHeaders);\n if (earlyAuth) {\n setLastSeenAuth(earlyAuth);\n }\n\n // --- Case 1: Compaction request \u2192 intercept ---\n if (isCompactionRequest(req)) {\n return await handleCompaction(req, config);\n }\n\n // --- Case 2: Title/summary request \u2192 passthrough ---\n if (isTitleOrSummaryRequest(req)) {\n return await handlePassthrough(req, config);\n }\n\n // --- Case 3: Normal conversation turn \u2192 full pipeline ---\n return await handleConversationTurn(req, config);\n } catch (err) {\n const message =\n err instanceof Error ? err.message : \"Unknown gateway error\";\n log.error(\"pipeline error:\", err);\n return errorResponse(502, message);\n }\n}\n", "/**\n * Session identification for the Lore gateway proxy.\n *\n * Raw LLM API requests carry no session ID, so the gateway injects a\n * text-block marker `[lore:<base62>]` into the first response of a new\n * session. Subsequent requests from the same session echo it back in\n * the message history, allowing the gateway to correlate turns.\n *\n * The session ID packs 8 random bytes + 4 bytes of unix timestamp\n * (seconds, big-endian) into 12 bytes, then base62-encodes them to a\n * compact alphanumeric string (~17 chars).\n *\n * A SHA-256 fingerprint of the first user message serves as a\n * belt-and-suspenders fallback for sessions that haven't received their\n * marker yet (e.g. the very first request before any response).\n *\n * This module has zero dependencies on `@loreai/core` \u2014 pure utility.\n */\n\n// ---------------------------------------------------------------------------\n// Base62 encoding\n// ---------------------------------------------------------------------------\n\nconst BASE62_ALPHABET =\n \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\";\nconst BASE = 62n;\n\n/**\n * Encode a byte array to a base62 string.\n *\n * Interprets `bytes` as an unsigned big-endian integer, then repeatedly\n * divmods by 62, mapping each remainder to `BASE62_ALPHABET`. The result\n * is reversed so the most-significant digit comes first and zero-padded\n * to `minLength` for consistent output width.\n */\nexport function base62Encode(bytes: Uint8Array, minLength = 0): string {\n let n = 0n;\n for (const b of bytes) {\n n = (n << 8n) | BigInt(b);\n }\n\n if (n === 0n) return BASE62_ALPHABET[0].repeat(Math.max(1, minLength));\n\n const chars: string[] = [];\n while (n > 0n) {\n chars.push(BASE62_ALPHABET[Number(n % BASE)]);\n n /= BASE;\n }\n\n chars.reverse();\n\n // Pad to minLength for consistent width\n while (chars.length < minLength) {\n chars.unshift(BASE62_ALPHABET[0]);\n }\n\n return chars.join(\"\");\n}\n\n// ---------------------------------------------------------------------------\n// Session ID generation\n// ---------------------------------------------------------------------------\n\n/** 12 bytes \u2192 base62 \u2192 at most 17 alphanumeric characters. */\nconst SESSION_ID_MIN_LENGTH = 17;\n\n/**\n * Generate a new session ID.\n *\n * Layout (12 bytes):\n * [0..7] \u2014 8 random bytes (session hash)\n * [8..11] \u2014 4 bytes unix timestamp (seconds, big-endian)\n */\nexport function generateSessionID(): string {\n const buf = new Uint8Array(12);\n crypto.getRandomValues(buf.subarray(0, 8));\n\n const ts = Math.floor(Date.now() / 1000);\n const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);\n view.setUint32(8, ts >>> 0, false); // big-endian\n\n return base62Encode(buf, SESSION_ID_MIN_LENGTH);\n}\n\n// ---------------------------------------------------------------------------\n// Marker formatting / parsing\n// ---------------------------------------------------------------------------\n\nconst MARKER_RE = /\\[lore:([a-zA-Z0-9]+)\\]/;\n\n/** Format a session ID as the injectable text marker. */\nexport function formatMarker(sessionID: string): string {\n return `[lore:${sessionID}]`;\n}\n\n/**\n * Extract a session ID from a marker string, or `null` if the text\n * does not contain a valid marker.\n */\nexport function parseMarker(text: string): string | null {\n const m = MARKER_RE.exec(text);\n return m ? m[1] : null;\n}\n\n// ---------------------------------------------------------------------------\n// Message scanning\n// ---------------------------------------------------------------------------\n\n/**\n * Extract text from a single message's content field.\n *\n * Handles both Anthropic-style content (array of `{type:\"text\", text}` blocks)\n * and OpenAI-style content (plain string).\n */\nfunction extractTextParts(content: unknown): string[] {\n if (typeof content === \"string\") return [content];\n\n if (Array.isArray(content)) {\n const texts: string[] = [];\n for (const block of content) {\n if (\n block &&\n typeof block === \"object\" &&\n \"type\" in block &&\n block.type === \"text\" &&\n \"text\" in block &&\n typeof block.text === \"string\"\n ) {\n texts.push(block.text);\n }\n }\n return texts;\n }\n\n return [];\n}\n\n/**\n * Scan a message array for a `[lore:<sessionID>]` marker inside any\n * text content block. Returns the extracted session ID or `null`.\n */\nexport function scanForMarker(\n messages: Array<{ role: string; content: unknown }>,\n): string | null {\n for (const msg of messages) {\n for (const text of extractTextParts(msg.content)) {\n const id = parseMarker(text);\n if (id) return id;\n }\n }\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Fingerprinting (fallback)\n// ---------------------------------------------------------------------------\n\n/**\n * Compute a SHA-256 fingerprint from the first user message's content,\n * optionally incorporating the model name and an auth credential suffix.\n *\n * Returns the first 16 hex characters of the hash. Used as the primary\n * session correlator \u2014 combined with message-count proximity to\n * disambiguate forked sessions that share the same first message.\n *\n * Including `model` and `authSuffix` ensures that a key change or model\n * switch creates a new session rather than reusing an existing one.\n */\nexport async function fingerprintMessages(\n messages: Array<{ role: string; content: unknown }>,\n extras?: { model?: string; authSuffix?: string },\n): Promise<string> {\n let firstUserContent = \"\";\n for (const msg of messages) {\n if (msg.role === \"user\") {\n const texts = extractTextParts(msg.content);\n firstUserContent = texts.join(\"\");\n break;\n }\n }\n\n const material =\n firstUserContent + (extras?.model ?? \"\") + (extras?.authSuffix ?? \"\");\n const encoded = new TextEncoder().encode(material);\n const hash = await crypto.subtle.digest(\"SHA-256\", encoded);\n const bytes = new Uint8Array(hash);\n\n // First 16 hex chars (8 bytes)\n let hex = \"\";\n for (let i = 0; i < 8; i++) {\n hex += bytes[i].toString(16).padStart(2, \"0\");\n }\n return hex;\n}\n\n// ---------------------------------------------------------------------------\n// Message-count proximity matching\n// ---------------------------------------------------------------------------\n\n/**\n * Maximum message count difference for two requests to be considered\n * part of the same session. Normal turns add 2\u20136 messages (user +\n * assistant + tool calls); a forked session drops to the fork point.\n * A threshold of 20 accommodates bursts of tool-call messages while\n * reliably distinguishing forks (which typically differ by 50+).\n */\nexport const MESSAGE_COUNT_PROXIMITY_THRESHOLD = 20;\n", "/**\n * Compaction request detection and interception for the Lore gateway.\n *\n * Claude Code (and other clients using the same pattern) sends compaction\n * requests with a distinct system prompt and message structure. The gateway\n * detects these and runs Lore's own distillation instead of forwarding to\n * the upstream API.\n *\n * Detection mirrors the patterns documented in the upstream\n * `packages/opencode/src/agent/prompt/compaction.txt` and the\n * `experimental.session.compacting` hook.\n *\n * This module has zero dependencies on `@loreai/core` \u2014 pure detection logic.\n */\nimport type { GatewayRequest, GatewayResponse } from \"./translate/types\";\n\n// ---------------------------------------------------------------------------\n// Detection patterns \u2014 exported so tests can reference them\n// ---------------------------------------------------------------------------\n\n/** System prompt substrings that identify a compaction agent. */\nexport const COMPACTION_SYSTEM_PATTERNS = [\n \"anchored context summarization assistant\",\n] as const;\n\n/** Last user message substrings that indicate a compaction request. */\nexport const COMPACTION_USER_PATTERNS = [\n \"anchored summary from the conversation history above\",\n \"Update the anchored summary below\",\n \"<previous-summary>\",\n] as const;\n\n/**\n * Template section headers found in the `<template>` block of a compaction\n * request. A request matching \u22654 of these (with a `<template>` tag) is\n * considered a compaction request.\n */\nexport const COMPACTION_TEMPLATE_SECTIONS = [\n \"## Goal\",\n \"## Progress\",\n \"## Key Decisions\",\n \"## Next Steps\",\n \"## Critical Context\",\n \"## Relevant Files\",\n] as const;\n\n/** Minimum number of template sections that must match (with `<template>` tag). */\nconst MIN_TEMPLATE_SECTION_MATCHES = 4;\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Extract the concatenated text content from the last user message.\n * Returns an empty string if there are no user messages or no text blocks.\n */\nfunction lastUserText(req: GatewayRequest): string {\n for (let i = req.messages.length - 1; i >= 0; i--) {\n const msg = req.messages[i];\n if (msg.role === \"user\") {\n return msg.content\n .filter((b) => b.type === \"text\")\n .map((b) => (b as { type: \"text\"; text: string }).text)\n .join(\"\\n\");\n }\n }\n return \"\";\n}\n\n/** Rough token estimate: ~4 characters per token. */\nfunction estimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\n}\n\n// ---------------------------------------------------------------------------\n// isCompactionRequest\n// ---------------------------------------------------------------------------\n\n/**\n * Returns `true` if the request looks like a compaction request.\n *\n * Checks in order:\n * 1. System prompt contains any `COMPACTION_SYSTEM_PATTERNS` \u2192 true\n * 2. Tools empty AND last user message contains any `COMPACTION_USER_PATTERNS` \u2192 true\n * 3. Last user message has `<template>` tag AND \u22654 template sections \u2192 true\n * 4. Otherwise \u2192 false\n */\nexport function isCompactionRequest(req: GatewayRequest): boolean {\n // 1. System prompt check \u2014 strongest signal, sufficient alone\n const systemLower = req.system.toLowerCase();\n for (const pattern of COMPACTION_SYSTEM_PATTERNS) {\n if (systemLower.includes(pattern.toLowerCase())) return true;\n }\n\n const userText = lastUserText(req);\n\n // 2. No tools + user message contains compaction keywords\n if (req.tools.length === 0 && userText) {\n for (const pattern of COMPACTION_USER_PATTERNS) {\n if (userText.includes(pattern)) return true;\n }\n }\n\n // 3. <template> tag + \u22654 section headers\n if (userText.includes(\"<template>\")) {\n let matches = 0;\n for (const section of COMPACTION_TEMPLATE_SECTIONS) {\n if (userText.includes(section)) matches++;\n }\n if (matches >= MIN_TEMPLATE_SECTION_MATCHES) return true;\n }\n\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// extractPreviousSummary\n// ---------------------------------------------------------------------------\n\n/** Regex to extract content from `<previous-summary>` block (dotAll). */\nconst PREVIOUS_SUMMARY_RE =\n /<previous-summary>\\n(.*?)\\n<\\/previous-summary>/s;\n\n/**\n * Extract the content of a `<previous-summary>` block from the last user\n * message, or `undefined` if no such block exists.\n */\nexport function extractPreviousSummary(\n req: GatewayRequest,\n): string | undefined {\n const userText = lastUserText(req);\n const match = PREVIOUS_SUMMARY_RE.exec(userText);\n return match?.[1] ?? undefined;\n}\n\n// ---------------------------------------------------------------------------\n// isTitleOrSummaryRequest\n// ---------------------------------------------------------------------------\n\n/** Max system prompt length for title/summary agents (chars). */\nconst TITLE_SUMMARY_MAX_SYSTEM_LENGTH = 500;\n\n/** Max number of tools for a title/summary agent (0 or very few). */\nconst TITLE_SUMMARY_MAX_TOOLS = 2;\n\n/** Max message count for a title/summary agent (system extracted, so 1\u20132). */\nconst TITLE_SUMMARY_MAX_MESSAGES = 2;\n\n/**\n * Detect non-conversation requests that should be forwarded without Lore\n * pipeline processing (title generation, summary agents, etc.).\n *\n * These have:\n * - Empty or very few tools (\u22642)\n * - Only 1\u20132 messages (system already extracted to `req.system`)\n * - Short system prompt (< 500 chars)\n * - NOT a compaction request (handled separately)\n */\nexport function isTitleOrSummaryRequest(req: GatewayRequest): boolean {\n // Compaction requests are handled separately \u2014 don't classify as title/summary\n if (isCompactionRequest(req)) return false;\n\n return (\n req.tools.length <= TITLE_SUMMARY_MAX_TOOLS &&\n req.messages.length <= TITLE_SUMMARY_MAX_MESSAGES &&\n req.system.length < TITLE_SUMMARY_MAX_SYSTEM_LENGTH\n );\n}\n\n// ---------------------------------------------------------------------------\n// buildCompactionResponse\n// ---------------------------------------------------------------------------\n\n/**\n * Build a `GatewayResponse` wrapping a compaction summary as if it were a\n * normal assistant response. The gateway translates this back to the\n * client's protocol (Anthropic/OpenAI) before sending.\n */\nexport function buildCompactionResponse(\n _sessionID: string,\n summary: string,\n model: string,\n): GatewayResponse {\n return {\n id: `msg_lore_compact_${crypto.randomUUID().slice(0, 8)}`,\n model,\n content: [{ type: \"text\", text: summary }],\n stopReason: \"end_turn\",\n usage: {\n inputTokens: 0,\n outputTokens: estimateTokens(summary),\n },\n };\n}\n", "/**\n * Converts raw Anthropic API messages (as they appear in request/response\n * bodies) into `@loreai/core`'s `LoreMessageWithParts` shape for temporal\n * storage and gradient transform.\n *\n * Follows the same tool-pairing pattern used by the Pi adapter\n * (`packages/pi/src/adapter.ts`): tool_use blocks on assistant messages are\n * initially stored as \"pending\", then `resolveToolResults` walks the\n * conversation to merge matching tool_result blocks from subsequent user\n * messages into \"completed\" state.\n */\nimport { createHash, randomUUID } from \"crypto\";\nimport { isToolPart } from \"@loreai/core\";\nimport type {\n LoreAssistantMessage,\n LoreMessageWithParts,\n LorePart,\n LoreReasoningPart,\n LoreTextPart,\n LoreToolPart,\n LoreUserMessage,\n} from \"@loreai/core\";\nimport type {\n GatewayContentBlock,\n GatewayMessage,\n GatewayUsage,\n} from \"./translate/types\";\n\n// ---------------------------------------------------------------------------\n// Deterministic ID generation\n// ---------------------------------------------------------------------------\n\n/**\n * Generate a deterministic UUID-like ID from message content.\n * Same message at the same position produces the same ID across requests,\n * which is critical for gradient prefix fingerprinting and cache-bust detection.\n */\nfunction deterministicID(role: string, index: number, content: GatewayContentBlock[]): string {\n const h = createHash(\"sha256\");\n h.update(`${role}:${index}:`);\n for (const block of content) {\n switch (block.type) {\n case \"text\":\n h.update(`text:${block.text}`);\n break;\n case \"thinking\":\n h.update(`thinking:${block.thinking}`);\n break;\n case \"tool_use\":\n h.update(`tool_use:${block.id}:${block.name}:${JSON.stringify(block.input)}`);\n break;\n case \"tool_result\":\n h.update(`tool_result:${block.toolUseId}:${block.content}`);\n break;\n }\n }\n return h.digest(\"hex\").slice(0, 32);\n}\n\n/**\n * Generate a deterministic ID for a part within a message.\n * Uses the message ID + part index for stability.\n */\nfunction deterministicPartID(messageID: string, partIndex: number): string {\n const h = createHash(\"sha256\");\n h.update(`${messageID}:part:${partIndex}`);\n return h.digest(\"hex\").slice(0, 32);\n}\n\n// ---------------------------------------------------------------------------\n// Part conversion helpers\n// ---------------------------------------------------------------------------\n\nfunction contentBlockToPart(\n block: GatewayContentBlock,\n sessionID: string,\n messageID: string,\n partIndex: number,\n): LorePart {\n const now = Date.now();\n const id = deterministicPartID(messageID, partIndex);\n switch (block.type) {\n case \"text\":\n return {\n id,\n sessionID,\n messageID,\n type: \"text\",\n text: block.text,\n time: { start: now, end: now },\n } satisfies LoreTextPart;\n\n case \"thinking\":\n return {\n id,\n sessionID,\n messageID,\n type: \"reasoning\",\n text: block.thinking,\n } satisfies LoreReasoningPart;\n\n case \"tool_use\":\n return {\n id,\n sessionID,\n messageID,\n type: \"tool\",\n tool: block.name,\n callID: block.id,\n state: { status: \"pending\", input: block.input },\n } satisfies LoreToolPart;\n\n case \"tool_result\":\n return {\n id,\n sessionID,\n messageID,\n type: \"tool\",\n tool: \"result\",\n callID: block.toolUseId,\n state: {\n status: \"completed\",\n input: null,\n output: block.content,\n time: { start: now, end: now },\n },\n } satisfies LoreToolPart;\n }\n}\n\n// ---------------------------------------------------------------------------\n// 1. gatewayMessagesToLore\n// ---------------------------------------------------------------------------\n\n/**\n * Convert an array of gateway messages to Lore's message-with-parts format.\n *\n * User messages get minimal metadata (we don't know the model at message\n * level). Assistant messages get zeroed-out token counts \u2014 call\n * `updateAssistantMessageTokens` after accumulating the API response to\n * fill them in.\n */\nexport function gatewayMessagesToLore(\n messages: GatewayMessage[],\n sessionID: string,\n): LoreMessageWithParts[] {\n const out: LoreMessageWithParts[] = [];\n const now = Date.now();\n\n for (let i = 0; i < messages.length; i++) {\n const m = messages[i];\n const id = deterministicID(m.role, i, m.content);\n const parts: LorePart[] = m.content.map((block, pi) =>\n contentBlockToPart(block, sessionID, id, pi),\n );\n\n if (m.role === \"user\") {\n const info: LoreUserMessage = {\n id,\n sessionID,\n role: \"user\",\n time: { created: now },\n agent: \"gateway\",\n model: { providerID: \"anthropic\", modelID: \"unknown\" },\n };\n out.push({ info, parts });\n } else {\n const info: LoreAssistantMessage = {\n id,\n sessionID,\n role: \"assistant\",\n time: { created: now },\n parentID: \"\",\n modelID: \"unknown\",\n providerID: \"anthropic\",\n mode: \"gateway\",\n path: { cwd: \"\", root: \"\" },\n cost: 0,\n tokens: {\n input: 0,\n output: 0,\n reasoning: 0,\n cache: { read: 0, write: 0 },\n },\n };\n out.push({ info, parts });\n }\n }\n\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// 2. updateAssistantMessageTokens\n// ---------------------------------------------------------------------------\n\n/**\n * Update an assistant message's token counts from the API response usage data.\n * Mutates in place \u2014 call after the upstream response is fully accumulated.\n */\nexport function updateAssistantMessageTokens(\n msg: LoreMessageWithParts,\n usage: GatewayUsage,\n model: string,\n): void {\n const info = msg.info;\n if (info.role !== \"assistant\") return;\n\n info.tokens.input = usage.inputTokens;\n info.tokens.output = usage.outputTokens;\n info.tokens.cache.read = usage.cacheReadInputTokens ?? 0;\n info.tokens.cache.write = usage.cacheCreationInputTokens ?? 0;\n info.modelID = model;\n}\n\n// ---------------------------------------------------------------------------\n// 3. resolveToolResults\n// ---------------------------------------------------------------------------\n\n/**\n * Walk through the messages and match tool_result blocks (on user messages)\n * with their corresponding tool_use blocks (on preceding assistant messages).\n *\n * When a tool_use was initially stored as \"pending\", update it to \"completed\"\n * with the output from the matching tool_result. This mirrors the tool-pairing\n * pattern used in the Pi adapter (`piMessagesToLore`).\n *\n * After resolving, strips all `tool: \"result\"` parts from user messages.\n * Their data is now redundant (merged into the assistant's completed tool part).\n * This prevents orphaned `tool_result` blocks when gradient evicts the assistant\n * message but keeps the following user message \u2014 the Anthropic API requires every\n * `tool_result` to reference a `tool_use` on the immediately preceding assistant.\n *\n * Mutates messages in place.\n */\nexport function resolveToolResults(messages: LoreMessageWithParts[]): void {\n // --- Pass 1: Index all tool_result parts by callID ---\n const resultsByCallID = new Map<\n string,\n { output: string; isError: boolean }\n >();\n\n for (const msg of messages) {\n for (const part of msg.parts) {\n if (\n isToolPart(part) &&\n part.tool === \"result\" &&\n part.state.status === \"completed\"\n ) {\n resultsByCallID.set(part.callID, {\n output: part.state.output,\n isError: false,\n });\n }\n }\n }\n\n // --- Pass 2: Resolve pending tool_use \u2192 completed where a result exists ---\n const now = Date.now();\n for (const msg of messages) {\n for (const part of msg.parts) {\n if (\n isToolPart(part) &&\n part.tool !== \"result\" &&\n part.state.status === \"pending\"\n ) {\n const result = resultsByCallID.get(part.callID);\n if (result) {\n part.state = {\n status: \"completed\",\n input: part.state.input,\n output: result.output,\n time: { start: now, end: now },\n };\n }\n }\n }\n }\n\n // --- Pass 3: Strip redundant tool_result parts from user messages ---\n // After resolving, tool_result data lives on the assistant's completed\n // tool part. Keeping it on user messages creates orphaned tool_result\n // blocks when gradient evicts the assistant but keeps the user.\n // loreMessagesToGateway() reconstructs tool_result blocks from the\n // assistant's completed/error tool parts, so no data is lost.\n for (const msg of messages) {\n if (msg.info.role !== \"user\") continue;\n const before = msg.parts.length;\n msg.parts = msg.parts.filter(\n (p) => !(isToolPart(p) && p.tool === \"result\"),\n );\n // If stripping left the user message with no content parts,\n // add a placeholder text part so the message survives API conversion.\n if (msg.parts.length === 0 && before > 0) {\n msg.parts = [\n {\n id: randomUUID(),\n sessionID: \"\",\n messageID: msg.info.id,\n type: \"text\" as const,\n text: \"[tool results provided]\",\n time: { start: 0, end: 0 },\n } satisfies LoreTextPart,\n ];\n }\n }\n}\n", "/**\n * Gateway LLM adapter: implements LLMClient via direct Anthropic API calls.\n * Used by Lore's background workers (distillation, curation, query expansion)\n * running inside the gateway process.\n */\n\nimport type { LLMClient } from \"@loreai/core\";\nimport { log } from \"@loreai/core\";\nimport type { AuthCredential } from \"./auth\";\nimport { authHeaders } from \"./auth\";\n\n// ---------------------------------------------------------------------------\n// Worker call tracking\n// ---------------------------------------------------------------------------\n\n/** Tracks worker session IDs so temporal capture can skip them. */\nexport const activeWorkerCalls = new Set<string>();\n\n// ---------------------------------------------------------------------------\n// LLMClient factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create an LLMClient that sends single-turn prompts directly to Anthropic.\n *\n * @param upstreamUrl Base URL of the upstream Anthropic endpoint\n * @param getAuth Callback to resolve auth credentials (per-session \u2192 global fallback)\n * @param defaultModel Default model to use when no override is specified\n */\nexport function createGatewayLLMClient(\n upstreamUrl: string,\n getAuth: (sessionID?: string) => AuthCredential | null,\n defaultModel: { providerID: string; modelID: string },\n): LLMClient {\n return {\n async prompt(system, user, opts) {\n const cred = getAuth(opts?.sessionID);\n if (!cred) {\n log.warn(\"no auth credentials available for worker call\");\n return null;\n }\n\n const model = opts?.model ?? defaultModel;\n const url = `${upstreamUrl.replace(/\\/$/, \"\")}/v1/messages`;\n\n // Track this call so temporal capture can skip it\n const callID = `gw-worker-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n activeWorkerCalls.add(callID);\n\n try {\n // System prompt caching for workers: send as block array with 1h TTL.\n // Worker calls come in bursts (distillation, curation) separated by\n // minutes of user thinking \u2014 5m TTL expires between bursts, but 1h\n // survives. The system prompt (DISTILLATION_SYSTEM, etc.) is static\n // across all calls \u2192 near-100% cache hit rate after the first write.\n // Cost: 1.25\u00D7 base for the initial write, 0.1\u00D7 for subsequent reads.\n const systemPayload = system\n ? [\n {\n type: \"text\",\n text: system,\n cache_control: { type: \"ephemeral\", ttl: \"1h\" },\n },\n ]\n : undefined;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"anthropic-version\": \"2023-06-01\",\n ...authHeaders(cred),\n },\n // opts.thinking is intentionally not forwarded \u2014 this bare API\n // call never includes the `thinking` parameter so Anthropic\n // models won't produce thinking tokens regardless.\n body: JSON.stringify({\n model: model.modelID,\n max_tokens: 8192,\n system: systemPayload ?? system,\n messages: [{ role: \"user\", content: user }],\n }),\n });\n\n if (!response.ok) {\n const text = await response.text().catch(() => \"(no body)\");\n log.error(\n `worker upstream request failed: ${response.status} ${response.statusText} \u2014 ${text}`,\n );\n return null;\n }\n\n const data = (await response.json()) as {\n content?: Array<{ type: string; text?: string }>;\n };\n\n const textBlock = data.content?.find(\n (b) => b.type === \"text\" && typeof b.text === \"string\",\n );\n\n return textBlock?.text ?? null;\n } catch (e) {\n log.error(\"worker prompt failed:\", e);\n return null;\n } finally {\n activeWorkerCalls.delete(callID);\n }\n },\n };\n}\n", "/**\n * Batch queue for Anthropic Message Batches API.\n *\n * Wraps a synchronous LLMClient and intercepts non-urgent `prompt()` calls,\n * accumulating them in a queue. A flush timer periodically sends the queue\n * to Anthropic's `/v1/messages/batches` endpoint for 50% cost savings.\n * A poll timer checks for results and resolves the pending promises.\n *\n * Urgent calls (compaction, overflow recovery, query expansion) bypass\n * the queue entirely and delegate to the inner synchronous client.\n *\n * Auth credentials are snapshotted per-item at enqueue time and grouped\n * by credential at flush time \u2014 this ensures multi-session isolation when\n * multiple clients with different API keys are connected simultaneously.\n *\n * This is a gateway-only enhancement \u2014 the OpenCode and Pi adapters\n * always process immediately regardless of the `urgent` flag.\n */\n\nimport type { LLMClient } from \"@loreai/core\";\nimport { log } from \"@loreai/core\";\nimport type { AuthCredential } from \"./auth\";\nimport { authHeaders } from \"./auth\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** A single pending request waiting to be batched. */\ninterface PendingRequest {\n /** Unique ID for correlating batch results (alphanumeric + hyphens). */\n customId: string;\n /** Standard Messages API params. */\n params: {\n model: string;\n max_tokens: number;\n system:\n | string\n | Array<{ type: string; text: string; cache_control?: { type: string; ttl?: string } }>;\n messages: Array<{ role: string; content: string }>;\n };\n /** Resolve the caller's promise with the text response. */\n resolve: (value: string | null) => void;\n /** Reject the caller's promise on error. */\n reject: (error: Error) => void;\n /** Timestamp when the request was enqueued. */\n enqueuedAt: number;\n /** Auth credential snapshotted at enqueue time for per-session isolation. */\n auth: AuthCredential;\n}\n\n/** A batch that has been submitted and is being polled for results. */\ninterface InflightBatch {\n /** Anthropic batch ID returned by the create endpoint. */\n batchId: string;\n /** Map from custom_id \u2192 pending request (for resolving on completion). */\n requests: Map<string, PendingRequest>;\n /** Timestamp when the batch was submitted. */\n submittedAt: number;\n /** Poll timer handle. */\n pollTimer: ReturnType<typeof setInterval>;\n /** Auth credential for this batch (used for poll/retrieve calls). */\n auth: AuthCredential;\n}\n\nexport interface BatchQueueConfig {\n /** How often to flush the queue (ms). Default: 30000 (30s). */\n flushIntervalMs?: number;\n /** Max items before auto-flush. Default: 50. */\n maxQueueSize?: number;\n /** How often to poll for batch results (ms). Default: 60000 (60s). */\n pollIntervalMs?: number;\n /** Max age of a batch before giving up and falling back (ms). Default: 3600000 (1h). */\n maxBatchAgeMs?: number;\n}\n\nconst DEFAULT_FLUSH_INTERVAL_MS = 30_000;\nconst DEFAULT_MAX_QUEUE_SIZE = 50;\nconst DEFAULT_POLL_INTERVAL_MS = 60_000;\nconst DEFAULT_MAX_BATCH_AGE_MS = 3_600_000; // 1 hour\n\n// ---------------------------------------------------------------------------\n// ID generation\n// ---------------------------------------------------------------------------\n\nlet idCounter = 0;\n\n/** Generate a batch-API-compatible custom_id (alphanumeric + hyphens, 1-64 chars). */\nfunction generateCustomId(): string {\n const ts = Date.now().toString(36);\n const seq = (idCounter++).toString(36);\n const rand = Math.random().toString(36).slice(2, 8);\n return `lore-${ts}-${seq}-${rand}`;\n}\n\n/** Produce a grouping key for an auth credential. */\nfunction authKey(cred: AuthCredential): string {\n return `${cred.scheme}:${cred.value}`;\n}\n\n// ---------------------------------------------------------------------------\n// BatchLLMClient\n// ---------------------------------------------------------------------------\n\n/**\n * Create a batch-aware LLMClient that wraps a synchronous inner client.\n *\n * - `urgent: true` calls \u2192 immediate delegation to `inner.prompt()`\n * - `urgent: false/undefined` calls \u2192 queued for batch processing\n * - On flush timer or queue full \u2192 POST /v1/messages/batches\n * - On poll timer \u2192 GET /v1/messages/batches/{id}, resolve promises\n * - On error \u2192 fallback to synchronous calls for the failed batch\n *\n * @param inner The synchronous LLMClient (gateway's direct adapter)\n * @param upstreamUrl Base Anthropic API URL (e.g. \"https://api.anthropic.com\")\n * @param getAuth Callback to resolve auth credentials (per-session \u2192 global fallback)\n * @param defaultModel Default model for requests without explicit model\n * @param batchConfig Optional tuning parameters\n */\nexport function createBatchLLMClient(\n inner: LLMClient,\n upstreamUrl: string,\n getAuth: (sessionID?: string) => AuthCredential | null,\n defaultModel: { providerID: string; modelID: string },\n batchConfig?: BatchQueueConfig,\n): LLMClient & { shutdown: () => Promise<void>; stats: () => BatchStats } {\n const flushIntervalMs = batchConfig?.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS;\n const maxQueueSize = batchConfig?.maxQueueSize ?? DEFAULT_MAX_QUEUE_SIZE;\n const pollIntervalMs = batchConfig?.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;\n const maxBatchAgeMs = batchConfig?.maxBatchAgeMs ?? DEFAULT_MAX_BATCH_AGE_MS;\n\n // State\n const queue: PendingRequest[] = [];\n const inflight = new Map<string, InflightBatch>();\n let flushTimer: ReturnType<typeof setInterval> | null = null;\n let shuttingDown = false;\n\n // Stats\n let totalQueued = 0;\n let totalBatched = 0;\n let totalUrgent = 0;\n let totalFallback = 0;\n let totalResolved = 0;\n let totalFailed = 0;\n\n // -------------------------------------------------------------------------\n // Submit a single batch for one credential group\n // -------------------------------------------------------------------------\n\n async function submitBatch(auth: AuthCredential, items: PendingRequest[]): Promise<void> {\n const requests = items.map((item) => ({\n custom_id: item.customId,\n params: item.params,\n }));\n\n log.info(`batch flush: submitting ${items.length} requests`);\n\n try {\n const url = `${upstreamUrl.replace(/\\/$/, \"\")}/v1/messages/batches`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"anthropic-version\": \"2023-06-01\",\n ...authHeaders(auth),\n },\n body: JSON.stringify({ requests }),\n });\n\n if (!response.ok) {\n const text = await response.text().catch(() => \"(no body)\");\n log.error(`batch create failed: ${response.status} ${response.statusText} \u2014 ${text}`);\n // Fall back to synchronous for all items\n await fallbackAll(items);\n return;\n }\n\n const data = (await response.json()) as {\n id: string;\n processing_status: string;\n };\n\n totalBatched += items.length;\n\n // Track inflight batch\n const requestMap = new Map<string, PendingRequest>();\n for (const item of items) {\n requestMap.set(item.customId, item);\n }\n\n const pollTimer = setInterval(\n () => pollBatch(data.id).catch((e) => log.error(\"batch poll error:\", e)),\n pollIntervalMs,\n );\n\n inflight.set(data.id, {\n batchId: data.id,\n requests: requestMap,\n submittedAt: Date.now(),\n pollTimer,\n auth,\n });\n\n log.info(`batch created: ${data.id} with ${items.length} requests`);\n } catch (e) {\n log.error(\"batch create error:\", e);\n await fallbackAll(items);\n }\n }\n\n // -------------------------------------------------------------------------\n // Flush: group queued items by credential, submit one batch per group\n // -------------------------------------------------------------------------\n\n async function flush(): Promise<void> {\n if (queue.length === 0) return;\n\n // Take all items from the queue\n const batch = queue.splice(0);\n\n // Group by auth credential \u2014 each credential gets its own batch\n const byAuth = new Map<string, { auth: AuthCredential; items: PendingRequest[] }>();\n for (const item of batch) {\n const key = authKey(item.auth);\n let group = byAuth.get(key);\n if (!group) {\n group = { auth: item.auth, items: [] };\n byAuth.set(key, group);\n }\n group.items.push(item);\n }\n\n for (const { auth, items } of byAuth.values()) {\n await submitBatch(auth, items);\n }\n }\n\n // -------------------------------------------------------------------------\n // Poll: check batch status and resolve promises\n // -------------------------------------------------------------------------\n\n async function pollBatch(batchId: string): Promise<void> {\n const batch = inflight.get(batchId);\n if (!batch) return;\n\n // Check max age \u2014 give up and fallback if too old\n if (Date.now() - batch.submittedAt > maxBatchAgeMs) {\n log.warn(`batch ${batchId} exceeded max age \u2014 falling back to synchronous`);\n clearInterval(batch.pollTimer);\n inflight.delete(batchId);\n await fallbackAll([...batch.requests.values()]);\n return;\n }\n\n try {\n const url = `${upstreamUrl.replace(/\\/$/, \"\")}/v1/messages/batches/${batchId}`;\n const response = await fetch(url, {\n headers: {\n \"anthropic-version\": \"2023-06-01\",\n ...authHeaders(batch.auth),\n },\n });\n\n if (!response.ok) {\n log.error(`batch poll failed for ${batchId}: ${response.status}`);\n return; // Retry on next poll\n }\n\n const data = (await response.json()) as {\n processing_status: string;\n results_url: string | null;\n };\n\n if (data.processing_status !== \"ended\") return;\n\n // Batch is done \u2014 stream results\n log.info(`batch ${batchId} ended \u2014 retrieving results`);\n\n if (data.results_url) {\n await retrieveResults(batchId, data.results_url);\n } else {\n // No results URL \u2014 try the standard endpoint\n await retrieveResults(\n batchId,\n `${upstreamUrl.replace(/\\/$/, \"\")}/v1/messages/batches/${batchId}/results`,\n );\n }\n } catch (e) {\n log.error(`batch poll error for ${batchId}:`, e);\n }\n }\n\n async function retrieveResults(batchId: string, resultsUrl: string): Promise<void> {\n const batch = inflight.get(batchId);\n if (!batch) return;\n\n try {\n const response = await fetch(resultsUrl, {\n headers: {\n \"anthropic-version\": \"2023-06-01\",\n ...authHeaders(batch.auth),\n },\n });\n\n if (!response.ok) {\n log.error(`batch results fetch failed for ${batchId}: ${response.status}`);\n return;\n }\n\n const text = await response.text();\n // Results are JSONL \u2014 one JSON object per line\n const lines = text.split(\"\\n\").filter((l) => l.trim());\n\n for (const line of lines) {\n try {\n const result = JSON.parse(line) as {\n custom_id: string;\n result: {\n type: \"succeeded\" | \"errored\" | \"canceled\" | \"expired\";\n message?: {\n content?: Array<{ type: string; text?: string }>;\n };\n error?: { type: string; message: string };\n };\n };\n\n const pending = batch.requests.get(result.custom_id);\n if (!pending) continue;\n\n switch (result.result.type) {\n case \"succeeded\": {\n const textBlock = result.result.message?.content?.find(\n (b) => b.type === \"text\" && typeof b.text === \"string\",\n );\n pending.resolve(textBlock?.text ?? null);\n totalResolved++;\n break;\n }\n case \"errored\":\n pending.resolve(null); // Match inner client behavior (null on error)\n totalFailed++;\n log.error(\n `batch item ${result.custom_id} errored: ${result.result.error?.type ?? \"unknown\"} \u2014 ${result.result.error?.message ?? JSON.stringify(result.result.error)}`,\n );\n break;\n case \"canceled\":\n case \"expired\":\n pending.resolve(null);\n totalFailed++;\n log.warn(`batch item ${result.custom_id} ${result.result.type}`);\n break;\n }\n\n batch.requests.delete(result.custom_id);\n } catch {\n log.error(`failed to parse batch result line: ${line.slice(0, 200)}`);\n }\n }\n\n // Resolve any remaining items that weren't in the results (shouldn't happen)\n for (const [, pending] of batch.requests) {\n pending.resolve(null);\n totalFailed++;\n }\n\n // Clean up\n clearInterval(batch.pollTimer);\n inflight.delete(batchId);\n log.info(\n `batch ${batchId} fully resolved (${totalResolved} ok, ${totalFailed} failed total)`,\n );\n } catch (e) {\n log.error(`batch results retrieval error for ${batchId}:`, e);\n }\n }\n\n // -------------------------------------------------------------------------\n // Fallback: process items synchronously via inner client\n // -------------------------------------------------------------------------\n\n async function fallbackAll(items: PendingRequest[]): Promise<void> {\n totalFallback += items.length;\n log.info(`batch fallback: processing ${items.length} items synchronously`);\n\n // Process in parallel with concurrency limit of 5\n const CONCURRENCY = 5;\n for (let i = 0; i < items.length; i += CONCURRENCY) {\n const chunk = items.slice(i, i + CONCURRENCY);\n await Promise.all(\n chunk.map(async (item) => {\n try {\n const system =\n typeof item.params.system === \"string\"\n ? item.params.system\n : item.params.system\n .map((b) => b.text)\n .join(\"\\n\");\n const user = item.params.messages[0]?.content ?? \"\";\n const result = await inner.prompt(system, user, { urgent: true });\n item.resolve(result);\n } catch (e) {\n log.error(`batch fallback error for ${item.customId}:`, e);\n item.resolve(null);\n }\n }),\n );\n }\n }\n\n // -------------------------------------------------------------------------\n // Start flush timer\n // -------------------------------------------------------------------------\n\n flushTimer = setInterval(() => {\n flush().catch((e) => log.error(\"batch flush timer error:\", e));\n }, flushIntervalMs);\n\n // -------------------------------------------------------------------------\n // LLMClient implementation\n // -------------------------------------------------------------------------\n\n return {\n async prompt(system, user, opts) {\n // Urgent calls bypass the queue entirely\n if (opts?.urgent || shuttingDown) {\n totalUrgent++;\n return inner.prompt(system, user, opts);\n }\n\n // Snapshot auth credential at enqueue time for session isolation.\n // If no credential is available, fall back to synchronous processing\n // (which will also attempt to resolve auth \u2014 matches prior behavior).\n const cred = getAuth(opts?.sessionID);\n if (!cred) {\n totalUrgent++;\n return inner.prompt(system, user, opts);\n }\n\n totalQueued++;\n\n const model = opts?.model ?? defaultModel;\n\n // Build system payload with 1h cache (same as direct adapter)\n const systemPayload = system\n ? [\n {\n type: \"text\" as const,\n text: system,\n cache_control: { type: \"ephemeral\" as const, ttl: \"1h\" },\n },\n ]\n : system;\n\n const customId = generateCustomId();\n\n const promise = new Promise<string | null>((resolve, reject) => {\n queue.push({\n customId,\n params: {\n model: model.modelID,\n max_tokens: 8192,\n system: systemPayload ?? system,\n messages: [{ role: \"user\", content: user }],\n },\n resolve,\n reject,\n enqueuedAt: Date.now(),\n auth: cred,\n });\n });\n\n // Auto-flush if queue is full\n if (queue.length >= maxQueueSize) {\n flush().catch((e) => log.error(\"batch auto-flush error:\", e));\n }\n\n return promise;\n },\n\n /**\n * Gracefully shut down the batch queue:\n * 1. Stop the flush timer\n * 2. Flush any remaining queued items (as a batch if possible, fallback sync)\n * 3. Switch to synchronous mode for future calls\n * 4. DON'T wait for inflight batches \u2014 they resolve eventually or expire\n */\n async shutdown(): Promise<void> {\n shuttingDown = true;\n if (flushTimer) {\n clearInterval(flushTimer);\n flushTimer = null;\n }\n\n // Flush remaining items synchronously (batch API might not finish before process exits)\n if (queue.length > 0) {\n log.info(`batch shutdown: processing ${queue.length} remaining items synchronously`);\n await fallbackAll(queue.splice(0));\n }\n\n // Clean up inflight poll timers (batches will expire naturally)\n for (const [batchId, batch] of inflight) {\n clearInterval(batch.pollTimer);\n // Resolve all pending promises with null (callers handle null gracefully)\n for (const [, pending] of batch.requests) {\n pending.resolve(null);\n }\n log.warn(`batch shutdown: abandoned inflight batch ${batchId}`);\n }\n inflight.clear();\n },\n\n /** Return current batch queue statistics. */\n stats(): BatchStats {\n return {\n queued: queue.length,\n inflightBatches: inflight.size,\n inflightRequests: [...inflight.values()].reduce(\n (sum, b) => sum + b.requests.size,\n 0,\n ),\n totalQueued,\n totalBatched,\n totalUrgent,\n totalFallback,\n totalResolved,\n totalFailed,\n };\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Stats type\n// ---------------------------------------------------------------------------\n\nexport interface BatchStats {\n /** Items currently in the queue waiting for next flush. */\n queued: number;\n /** Number of batches currently being polled. */\n inflightBatches: number;\n /** Total requests across all inflight batches. */\n inflightRequests: number;\n /** Total requests that entered the queue. */\n totalQueued: number;\n /** Total requests successfully submitted to the Batch API. */\n totalBatched: number;\n /** Total requests that bypassed the queue (urgent). */\n totalUrgent: number;\n /** Total requests that fell back to synchronous processing. */\n totalFallback: number;\n /** Total batch results successfully resolved. */\n totalResolved: number;\n /** Total batch results that failed/expired/canceled. */\n totalFailed: number;\n}\n", "/**\n * Idle detection and background work scheduling for the Lore gateway.\n *\n * Since the gateway doesn't have host lifecycle hooks (like OpenCode's\n * `session.idle` event), it uses a timer-based approach to detect when\n * sessions go idle and trigger background work (distillation, curation,\n * pruning, AGENTS.md export, etc.).\n */\n\nimport { join } from \"node:path\";\nimport {\n temporal,\n distillation,\n curator,\n ltm,\n latReader,\n log,\n config as loreConfig,\n getLastTurnAt,\n exportToFile,\n exportLoreFile,\n} from \"@loreai/core\";\nimport type { LLMClient } from \"@loreai/core\";\nimport type { GatewayConfig } from \"./config\";\nimport type { SessionState } from \"./translate/types\";\nimport type { AuthCredential } from \"./auth\";\nimport { maybeValidateWorkerModel, getWorkerModel } from \"./worker-model\";\n\nconst POLL_INTERVAL_MS = 30_000;\n\n// ---------------------------------------------------------------------------\n// startIdleScheduler\n// ---------------------------------------------------------------------------\n\n/**\n * Start a periodic timer that checks each active session for idle timeout.\n *\n * Every 30 seconds, walks the sessions map and fires `doIdleWork` for any\n * session whose `lastRequestTime` is older than `config.idleTimeoutSeconds`.\n * Tracks in-progress sessions to avoid double-triggering.\n *\n * @returns A cleanup function that clears the interval timer.\n */\nexport function startIdleScheduler(\n config: GatewayConfig,\n sessions: Map<string, SessionState>,\n doIdleWork: (sessionID: string, state: SessionState) => Promise<void>,\n): () => void {\n const inProgress = new Set<string>();\n\n const timer = setInterval(() => {\n const now = Date.now();\n const timeoutMs = config.idleTimeoutSeconds * 1000;\n\n for (const [sessionID, state] of sessions) {\n if (inProgress.has(sessionID)) continue;\n if (now - state.lastRequestTime < timeoutMs) continue;\n\n inProgress.add(sessionID);\n doIdleWork(sessionID, state)\n .catch((e) => log.error(`idle work failed for session ${sessionID}:`, e))\n .finally(() => inProgress.delete(sessionID));\n }\n }, POLL_INTERVAL_MS);\n\n return () => clearInterval(timer);\n}\n\n// ---------------------------------------------------------------------------\n// touchSession\n// ---------------------------------------------------------------------------\n\n/**\n * Update a session's `lastRequestTime` to now. Called on every request.\n */\nexport function touchSession(\n sessions: Map<string, SessionState>,\n sessionID: string,\n): void {\n const state = sessions.get(sessionID);\n if (state) {\n state.lastRequestTime = Date.now();\n }\n}\n\n// ---------------------------------------------------------------------------\n// buildIdleWorkHandler\n// ---------------------------------------------------------------------------\n\n/**\n * Build the idle work handler that runs the same background tasks as\n * OpenCode/Pi adapters on session idle:\n *\n * 1. Distillation (if enough undistilled messages)\n * 2. Curation (if enough turns since last curation)\n * 3. Consolidation (if entries exceed max)\n * 4. Temporal pruning\n * 5. AGENTS.md export\n * 6. Dead reference cleanup\n * 7. lat.md refresh\n *\n * Each step is independently try/catch'd \u2014 one failure won't block the rest.\n *\n * @param projectPath - Resolved project directory path\n * @param llm - LLM client for worker calls (distillation, curation)\n * @param upstreamUrl - Anthropic API base URL (for model discovery)\n * @param getAuth - Callback to resolve auth credentials\n * @param sessionModel - Model ID used for conversation (frontier model)\n * @param onLtmInvalidated - Callback to clear LTM session cache when curation\n * creates/updates/deletes knowledge entries\n */\nexport function buildIdleWorkHandler(\n projectPath: string,\n llm: LLMClient,\n upstreamUrl: string,\n getAuth: () => AuthCredential | null,\n sessionModel: string,\n onLtmInvalidated?: () => void,\n): (sessionID: string, state: SessionState) => Promise<void> {\n return async (sessionID: string, state: SessionState) => {\n const cfg = loreConfig();\n\n // 0. Worker model validation \u2014 discover cheaper models for background work.\n // Runs before distillation/curation so the resolved model is up-to-date.\n try {\n const cred = getAuth();\n if (cred) {\n await maybeValidateWorkerModel(\n sessionModel,\n upstreamUrl,\n cred,\n llm,\n projectPath,\n sessionID,\n );\n }\n } catch (e) {\n log.error(\"idle worker model validation error:\", e);\n }\n\n const model = getWorkerModel();\n\n // 1. Distillation \u2014 force-distill ALL pending messages on idle, even\n // below minMessages. The cache is going cold; aggressive distillation\n // now means a smaller context on the next turn via post-idle compact.\n // Meta-distillation is always allowed on idle (cache is cold anyway).\n try {\n const pending = temporal.undistilledCount(projectPath, sessionID);\n if (pending > 0) {\n await distillation.run({ llm, projectPath, sessionID, model, force: true });\n }\n } catch (e) {\n log.error(\"idle distillation error:\", e);\n }\n\n // 2. Curation\n if (cfg.knowledge.enabled && cfg.curator.onIdle) {\n try {\n if (state.turnsSinceCuration >= cfg.curator.afterTurns) {\n await curator.run({ llm, projectPath, sessionID, model });\n state.turnsSinceCuration = 0;\n onLtmInvalidated?.();\n }\n } catch (e) {\n log.error(\"idle curation error:\", e);\n }\n }\n\n // 3. Consolidation \u2014 runs after curation so new entries are counted\n if (cfg.knowledge.enabled) {\n try {\n const entries = ltm.forProject(projectPath, false);\n if (entries.length > cfg.curator.maxEntries) {\n log.info(\n `entry count ${entries.length} exceeds maxEntries ${cfg.curator.maxEntries} \u2014 running consolidation`,\n );\n const { updated, deleted } = await curator.consolidate({\n llm,\n projectPath,\n sessionID,\n model,\n });\n if (updated > 0 || deleted > 0) {\n log.info(`consolidation: ${updated} updated, ${deleted} deleted`);\n onLtmInvalidated?.();\n }\n }\n } catch (e) {\n log.error(\"idle consolidation error:\", e);\n }\n }\n\n // 4. Temporal pruning\n try {\n const { ttlDeleted, capDeleted } = temporal.prune({\n projectPath,\n retentionDays: cfg.pruning.retention,\n maxStorageMB: cfg.pruning.maxStorage,\n });\n if (ttlDeleted > 0 || capDeleted > 0) {\n log.info(\n `pruned temporal messages: ${ttlDeleted} by TTL, ${capDeleted} by size cap`,\n );\n }\n } catch (e) {\n log.error(\"idle pruning error:\", e);\n }\n\n // 5. Knowledge export (.lore.md + optional agents file pointer)\n if (cfg.knowledge.enabled) {\n try {\n const entries = ltm.forProject(projectPath, false);\n if (entries.length > 0) {\n if (cfg.agentsFile.enabled) {\n const filePath = join(projectPath, cfg.agentsFile.path);\n exportToFile({ projectPath, filePath });\n } else {\n exportLoreFile(projectPath);\n }\n }\n } catch (e) {\n log.error(\"idle knowledge export error:\", e);\n }\n }\n\n // 6. Dead reference cleanup\n if (cfg.knowledge.enabled) {\n try {\n const cleaned = ltm.cleanDeadRefs();\n if (cleaned > 0) {\n log.info(`cleaned ${cleaned} dead knowledge cross-references`);\n onLtmInvalidated?.();\n }\n } catch (e) {\n log.error(\"idle dead-ref cleanup error:\", e);\n }\n }\n\n // 7. lat.md refresh\n try {\n latReader.refresh(projectPath);\n } catch (e) {\n log.error(\"idle lat-reader refresh error:\", e);\n }\n };\n}\n", "/**\n * Gateway worker model discovery and resolution.\n *\n * Discovers available models from the upstream Anthropic `/v1/models` API,\n * fetches per-model pricing from models.dev (open-source model database),\n * and integrates with core's worker model validation/resolution pipeline.\n *\n * This replaces the OpenCode adapter's `getProviderModels()` +\n * `maybeValidateWorkerModel()` \u2014 the gateway is the universal path and\n * doesn't depend on the OpenCode SDK's model listing (which can report\n * deprecated models as \"active\").\n */\n\nimport {\n workerModel,\n temporal,\n distillation as distillationMod,\n config as loreConfig,\n log,\n} from \"@loreai/core\";\nimport type { LLMClient } from \"@loreai/core\";\nimport type { AuthCredential } from \"./auth\";\nimport { authHeaders } from \"./auth\";\n\n// ---------------------------------------------------------------------------\n// Cost lookup \u2014 models.dev with hardcoded fallback\n// ---------------------------------------------------------------------------\n\n/**\n * models.dev JSON API endpoint \u2014 returns all providers/models with pricing.\n *\n * Single request replaces N individual TOML fetches. Response shape:\n * { anthropic: { models: { \"claude-sonnet-4-20250514\": { cost: { input: 3 }, ... }, ... } } }\n * Cost values are per-million-token USD.\n */\nconst MODELS_DEV_API = \"https://models.dev/api.json\";\n\n/** Cached models.dev cost data: modelID \u2192 per-million-token input cost. */\nlet cachedCostMap: Map<string, number> | null = null;\nlet cachedCostMapAt = 0;\nconst COST_CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour\n\n/**\n * Hardcoded fallback costs (per-input-token, USD) used when models.dev\n * API is unreachable. Prefix-matched against model IDs.\n *\n * These only serve as a safety net \u2014 runtime pricing from models.dev is\n * preferred and fetched on every discovery cycle (cached 1h).\n */\nconst FALLBACK_COSTS: Array<{ prefix: string; inputCostPerToken: number }> = [\n { prefix: \"claude-opus-4\", inputCostPerToken: 15 / 1_000_000 },\n { prefix: \"claude-sonnet-4\", inputCostPerToken: 3 / 1_000_000 },\n { prefix: \"claude-haiku-4\", inputCostPerToken: 1 / 1_000_000 },\n { prefix: \"claude-haiku-3-5\", inputCostPerToken: 0.8 / 1_000_000 },\n { prefix: \"claude-sonnet-3-5\", inputCostPerToken: 3 / 1_000_000 },\n { prefix: \"claude-3-haiku\", inputCostPerToken: 0.25 / 1_000_000 },\n { prefix: \"claude-3-sonnet\", inputCostPerToken: 3 / 1_000_000 },\n { prefix: \"claude-3-opus\", inputCostPerToken: 15 / 1_000_000 },\n];\n\nfunction fallbackCost(modelID: string): number {\n for (const { prefix, inputCostPerToken } of FALLBACK_COSTS) {\n if (modelID.startsWith(prefix)) return inputCostPerToken;\n }\n // Unknown model \u2014 assume expensive so it doesn't get picked as a worker\n return 100 / 1_000_000;\n}\n\n/** Shape of a model entry in the models.dev JSON API. */\ntype ModelsDevEntry = {\n id: string;\n cost?: { input?: number };\n};\n\n/** Shape of the models.dev JSON API response (subset we care about). */\ntype ModelsDevResponse = {\n [provider: string]: {\n models?: { [modelId: string]: ModelsDevEntry };\n };\n};\n\n/**\n * Fetch the models.dev cost map for Anthropic models.\n *\n * Single HTTP request to the JSON API, cached for 1 hour.\n * Returns a map of modelID \u2192 per-million-token input cost.\n */\nexport async function fetchCostMap(): Promise<Map<string, number>> {\n // Return cache if fresh\n if (cachedCostMap && Date.now() - cachedCostMapAt < COST_CACHE_TTL_MS) {\n return cachedCostMap;\n }\n\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 10_000);\n\n const response = await fetch(MODELS_DEV_API, { signal: controller.signal });\n clearTimeout(timeout);\n\n if (!response.ok) {\n log.warn(`models.dev API failed: ${response.status} ${response.statusText}`);\n return cachedCostMap ?? new Map();\n }\n\n const data = (await response.json()) as ModelsDevResponse;\n const anthropic = data.anthropic?.models;\n if (!anthropic) {\n log.warn(\"models.dev API: no anthropic provider found\");\n return cachedCostMap ?? new Map();\n }\n\n const costMap = new Map<string, number>();\n for (const [modelId, entry] of Object.entries(anthropic)) {\n if (entry.cost?.input != null) {\n costMap.set(modelId, entry.cost.input);\n }\n }\n\n cachedCostMap = costMap;\n cachedCostMapAt = Date.now();\n\n log.info(`models.dev: loaded costs for ${costMap.size} anthropic models`);\n return costMap;\n } catch (e) {\n log.warn(\"models.dev API error:\", e);\n return cachedCostMap ?? new Map();\n }\n}\n\n/** Clear the cached cost map (for testing). */\nexport function clearCostCache(): void {\n cachedCostMap = null;\n cachedCostMapAt = 0;\n}\n\n/**\n * Fetch per-model input cost from models.dev JSON API.\n *\n * Single HTTP request fetches all Anthropic model costs. Returns a map of\n * modelID \u2192 per-token cost. Models not found in models.dev get fallback costs.\n */\nexport async function fetchModelCosts(\n modelIDs: string[],\n): Promise<Map<string, number>> {\n const costMap = await fetchCostMap();\n const costs = new Map<string, number>();\n\n for (const id of modelIDs) {\n const costPerMillion = costMap.get(id);\n if (costPerMillion != null) {\n costs.set(id, costPerMillion / 1_000_000);\n } else {\n costs.set(id, fallbackCost(id));\n }\n }\n\n return costs;\n}\n\n// ---------------------------------------------------------------------------\n// Anthropic /v1/models API types (subset we care about)\n// ---------------------------------------------------------------------------\n\ntype AnthropicModelEntry = {\n id: string;\n display_name: string;\n created_at: string;\n capabilities?: {\n thinking?: { supported: boolean };\n };\n};\n\ntype AnthropicModelsResponse = {\n data: AnthropicModelEntry[];\n has_more: boolean;\n last_id?: string;\n};\n\n// ---------------------------------------------------------------------------\n// Model discovery \u2014 fetch from upstream /v1/models\n// ---------------------------------------------------------------------------\n\n/** Cached model list with TTL. */\nlet cachedModels: workerModel.ModelInfo[] | null = null;\nlet cachedModelsAt = 0;\nconst MODEL_CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour\n\n/**\n * Fetch available Anthropic models from the upstream API.\n *\n * Results are cached for 1 hour \u2014 model listings change rarely and we\n * don't want to hit the API on every idle cycle.\n *\n * Unlike the OpenCode SDK's `provider.list()`, the Anthropic `/v1/models`\n * API only returns models that actually exist \u2014 deprecated models are\n * removed, so we never get stale entries like `claude-3-haiku-20240307`.\n */\nexport async function discoverModels(\n upstreamUrl: string,\n cred: AuthCredential,\n): Promise<workerModel.ModelInfo[]> {\n // Return cache if fresh\n if (cachedModels && Date.now() - cachedModelsAt < MODEL_CACHE_TTL_MS) {\n return cachedModels;\n }\n\n try {\n const entries: AnthropicModelEntry[] = [];\n let afterId: string | undefined;\n\n // Paginate through all models\n do {\n const url = new URL(`${upstreamUrl}/v1/models`);\n url.searchParams.set(\"limit\", \"1000\");\n if (afterId) url.searchParams.set(\"after_id\", afterId);\n\n const response = await fetch(url.toString(), {\n headers: {\n \"content-type\": \"application/json\",\n \"anthropic-version\": \"2023-06-01\",\n ...authHeaders(cred),\n },\n });\n\n if (!response.ok) {\n const text = await response.text().catch(() => \"(no body)\");\n log.warn(\n `model discovery failed: ${response.status} ${response.statusText} \u2014 ${text}`,\n );\n return cachedModels ?? [];\n }\n\n const data = (await response.json()) as AnthropicModelsResponse;\n\n for (const entry of data.data) {\n entries.push(entry);\n }\n\n afterId = data.has_more ? data.last_id : undefined;\n } while (afterId);\n\n // Fetch costs from models.dev in parallel (with fallback to hardcoded)\n const modelIDs = entries.map((e) => e.id);\n const costs = await fetchModelCosts(modelIDs);\n\n const models: workerModel.ModelInfo[] = entries.map((entry) => ({\n id: entry.id,\n providerID: \"anthropic\",\n cost: { input: costs.get(entry.id) ?? fallbackCost(entry.id) },\n status: \"active\", // Only active models are returned by the API\n capabilities: {\n input: { text: true }, // All Anthropic models accept text\n reasoning: entry.capabilities?.thinking?.supported ?? false,\n },\n }));\n\n cachedModels = models;\n cachedModelsAt = Date.now();\n\n log.info(\n `model discovery: found ${models.length} models (${models.map((m) => m.id).join(\", \")})`,\n );\n\n return models;\n } catch (e) {\n log.warn(\"model discovery error:\", e);\n return cachedModels ?? [];\n }\n}\n\n/** Clear the cached model list (for testing). */\nexport function clearModelCache(): void {\n cachedModels = null;\n cachedModelsAt = 0;\n}\n\n// ---------------------------------------------------------------------------\n// Worker model validation \u2014 gateway version of maybeValidateWorkerModel\n// ---------------------------------------------------------------------------\n\n/** Guard against concurrent validation runs. */\nlet validating = false;\n\n/**\n * Run worker model validation if needed.\n *\n * Called on session idle \u2014 discovers available models, selects candidates,\n * checks if the stored validation is stale, and runs the two-phase\n * comparison (structural check + LLM judge) if needed.\n *\n * @param sessionModel The model ID being used for conversation (frontier)\n * @param upstreamUrl Anthropic API base URL\n * @param cred Auth credential for API calls\n * @param llm LLM client for validation prompts\n * @param projectPath Project directory path\n * @param sessionID Session ID for loading reference distillation data\n */\nexport async function maybeValidateWorkerModel(\n sessionModel: string,\n upstreamUrl: string,\n cred: AuthCredential,\n llm: LLMClient,\n projectPath: string,\n sessionID: string,\n): Promise<void> {\n if (validating) return;\n\n const cfg = loreConfig();\n if (cfg.workerModel) return; // explicit override \u2014 skip auto-selection\n\n const models = await discoverModels(upstreamUrl, cred);\n if (models.length === 0) return;\n\n // Build the session model info for candidate selection.\n // Use cost from discovered models if available, otherwise fallback.\n const discoveredModel = models.find((m) => m.id === sessionModel);\n const sessionModelInfo: Parameters<typeof workerModel.selectWorkerCandidates>[0] = {\n id: sessionModel,\n providerID: \"anthropic\",\n cost: { input: discoveredModel?.cost.input ?? fallbackCost(sessionModel) },\n };\n\n const candidates = workerModel.selectWorkerCandidates(sessionModelInfo, models);\n if (candidates.length === 0) return;\n // If session model is already the cheapest, no comparison needed\n if (candidates.length === 1 && candidates[0].id === sessionModel) return;\n\n const fingerprint = workerModel.computeModelFingerprint(\n \"anthropic\",\n sessionModel,\n models.filter((m) => m.providerID === \"anthropic\").map((m) => m.id),\n );\n\n const stored = workerModel.getValidatedWorkerModel(\"anthropic\");\n if (!workerModel.isValidationStale(stored, fingerprint)) return;\n\n // Need reference distillation data\n const distillations = distillationMod.loadForSession(projectPath, sessionID, true);\n const gen0 = distillations.filter((d) => d.generation === 0);\n if (gen0.length === 0) return;\n\n const reference = gen0[gen0.length - 1]; // most recent gen-0\n const sourceIds = reference.source_ids;\n if (sourceIds.length === 0) return;\n\n // Load source temporal messages\n const allMessages = temporal.bySession(projectPath, sessionID);\n const sourceSet = new Set(sourceIds);\n const sourceMessages = allMessages.filter((m) => sourceSet.has(m.id));\n if (sourceMessages.length === 0) return;\n\n const messagesText = sourceMessages.map((m) => m.content).join(\"\\n\");\n const date = new Date(sourceMessages[0].created_at).toLocaleDateString(\n \"en-US\",\n { year: \"numeric\", month: \"long\", day: \"numeric\" },\n );\n\n validating = true;\n try {\n const result = await workerModel.runValidation({\n llm,\n providerID: \"anthropic\",\n sessionModelID: sessionModel,\n candidates,\n referenceObservations: reference.observations,\n sourceMessagesText: messagesText,\n date,\n });\n if (result) {\n log.info(\n `worker model validated: ${result.modelID} (judge=${result.judgeScore}) \u2014 saving 50%+ on worker calls`,\n );\n }\n } catch (e) {\n log.error(\"worker model validation error:\", e);\n } finally {\n validating = false;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Resolution \u2014 wrapper around core's resolveWorkerModel\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve the effective worker model for background calls.\n *\n * Checks (in order):\n * 1. Explicit config override (`workerModel` in lore config)\n * 2. Validated auto-selection from kv_meta (with 24h TTL)\n * 3. Config model fallback (frontier model)\n */\nexport function getWorkerModel(): { providerID: string; modelID: string } | undefined {\n const cfg = loreConfig();\n return workerModel.resolveWorkerModel(\n \"anthropic\",\n cfg.workerModel,\n cfg.model,\n );\n}\n\n/** Reset module state (for testing). */\nexport function resetWorkerModelState(): void {\n clearModelCache();\n clearCostCache();\n validating = false;\n}\n", "/**\n * Gateway recall interception \u2014 transparent memory search for any client.\n *\n * Injects a `recall` tool into upstream requests and handles the response\n * transparently. Two strategies based on whether recall is the only tool:\n *\n * - **Case 1 (recall-only)**: \"Pause and Continue\" \u2014 pause client stream,\n * execute recall, send follow-up request, resume streaming in the same\n * HTTP response.\n * - **Case 2 (mixed tools)**: \"Strip and Inject\" \u2014 suppress recall blocks\n * from the client stream, execute recall in background, inject the result\n * into the next request from the client.\n *\n * All recall execution delegates to `runRecall()` from `@loreai/core`.\n */\nimport {\n runRecall,\n RECALL_TOOL_DESCRIPTION,\n RECALL_PARAM_DESCRIPTIONS,\n log,\n config as loreConfig,\n type RecallScope,\n} from \"@loreai/core\";\n\nimport type {\n GatewayTool,\n GatewayRequest,\n GatewayResponse,\n GatewayToolUseBlock,\n GatewayMessage,\n PendingRecall,\n} from \"./translate/types\";\n\n// ---------------------------------------------------------------------------\n// Tool definition\n// ---------------------------------------------------------------------------\n\n/** Recall tool definition for injection into upstream requests. */\nexport const RECALL_GATEWAY_TOOL: GatewayTool = {\n name: \"recall\",\n description: RECALL_TOOL_DESCRIPTION,\n inputSchema: {\n type: \"object\",\n properties: {\n query: {\n type: \"string\",\n description: RECALL_PARAM_DESCRIPTIONS.query,\n },\n scope: {\n type: \"string\",\n enum: [\"all\", \"session\", \"project\", \"knowledge\"],\n description: RECALL_PARAM_DESCRIPTIONS.scope,\n },\n },\n required: [\"query\"],\n },\n};\n\nexport const RECALL_TOOL_NAME = \"recall\";\n\n// ---------------------------------------------------------------------------\n// Pending recall state (cross-request, Case 2)\n// ---------------------------------------------------------------------------\n\n/** TTL for pending recall results \u2014 discard after 60 seconds. */\nconst PENDING_RECALL_TTL_MS = 60_000;\n\n/** Check whether a pending recall is still valid (within TTL). */\nexport function isPendingRecallValid(pending: PendingRecall): boolean {\n return Date.now() - pending.timestamp < PENDING_RECALL_TTL_MS;\n}\n\n// ---------------------------------------------------------------------------\n// Detection helpers\n// ---------------------------------------------------------------------------\n\n/** Find the recall tool_use block in a GatewayResponse, if any. */\nexport function findRecallToolUse(\n resp: GatewayResponse,\n): GatewayToolUseBlock | undefined {\n return resp.content.find(\n (b): b is GatewayToolUseBlock =>\n b.type === \"tool_use\" && b.name === RECALL_TOOL_NAME,\n );\n}\n\n/** Check whether a response contains a recall tool_use. */\nexport function hasRecallToolUse(resp: GatewayResponse): boolean {\n return findRecallToolUse(resp) !== undefined;\n}\n\n/** Check whether the response contains non-recall tool_use blocks. */\nexport function hasOtherToolUse(resp: GatewayResponse): boolean {\n return resp.content.some(\n (b) => b.type === \"tool_use\" && b.name !== RECALL_TOOL_NAME,\n );\n}\n\n/** Check whether the client's tools list already includes a recall tool. */\nexport function clientHasRecallTool(tools: GatewayTool[]): boolean {\n return tools.some((t) => t.name === RECALL_TOOL_NAME);\n}\n\n// ---------------------------------------------------------------------------\n// Recall execution\n// ---------------------------------------------------------------------------\n\n/** Parse recall input from the tool_use block. */\nfunction parseRecallInput(block: GatewayToolUseBlock): {\n query: string;\n scope: RecallScope;\n} {\n const input = block.input as Record<string, unknown>;\n return {\n query: typeof input.query === \"string\" ? input.query : \"\",\n scope: (input.scope as RecallScope) ?? \"all\",\n };\n}\n\n/**\n * Execute the recall tool and return formatted results.\n *\n * Wraps `runRecall()` with error handling \u2014 on failure returns a\n * user-friendly error string rather than throwing.\n */\nexport async function executeRecall(\n block: GatewayToolUseBlock,\n projectPath: string,\n sessionID: string,\n): Promise<{ result: string; input: { query: string; scope?: RecallScope } }> {\n const { query, scope } = parseRecallInput(block);\n const cfg = loreConfig();\n\n try {\n const result = await runRecall({\n query,\n scope,\n projectPath,\n sessionID,\n knowledgeEnabled: cfg.knowledge?.enabled ?? true,\n searchConfig: cfg.search,\n });\n\n return { result, input: { query, scope } };\n } catch (e) {\n log.error(\"gateway recall execution failed:\", e);\n return {\n result: \"Recall search failed. The memory system encountered an error.\",\n input: { query, scope },\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Follow-up request builder (Case 1: recall-only)\n// ---------------------------------------------------------------------------\n\n/**\n * Build a follow-up request after recall execution.\n *\n * The follow-up includes:\n * - All original messages\n * - The assistant's full response (including the recall tool_use)\n * - A user message with the recall tool_result\n * - Tools list WITHOUT recall (so the model won't call it again)\n *\n * The model continues from where it left off, now with recall results\n * in context. Its new response streams directly to the client.\n */\nexport function buildRecallFollowUp(\n originalReq: GatewayRequest,\n resp: GatewayResponse,\n recallResult: string,\n recallToolUseBlock: GatewayToolUseBlock,\n): GatewayRequest {\n // Build assistant message with ONLY the recall tool_use block.\n // Exclude any pre-recall text/thinking blocks \u2014 those were already streamed\n // to the client. By presenting only the tool_use, the model understands it\n // called recall and hasn't yet produced a substantive response, so it will\n // generate new content after receiving the tool_result.\n const assistantMessage: GatewayMessage = {\n role: \"assistant\",\n content: [recallToolUseBlock],\n };\n\n // Build user message with tool_result\n const toolResultMessage: GatewayMessage = {\n role: \"user\",\n content: [\n {\n type: \"tool_result\",\n toolUseId: recallToolUseBlock.id,\n content: recallResult || \"[No results found.]\",\n },\n ],\n };\n\n // Strip recall from tools list\n const toolsWithoutRecall = originalReq.tools.filter(\n (t) => t.name !== RECALL_TOOL_NAME,\n );\n\n return {\n ...originalReq,\n messages: [\n ...originalReq.messages,\n assistantMessage,\n toolResultMessage,\n ],\n tools: toolsWithoutRecall,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Pending recall injection (Case 2: next request enrichment)\n// ---------------------------------------------------------------------------\n\n/**\n * Inject a pending recall result into the current request.\n *\n * Finds the last assistant message in `req.messages`, inserts the recall\n * tool_use block at the recorded position, and inserts a tool_result block\n * into the following user message.\n *\n * Mutates the request in-place for efficiency. Returns true if injection\n * was performed, false if the conversation structure didn't match\n * (e.g., no trailing assistant\u2192user pair).\n */\nexport function injectPendingRecall(\n req: GatewayRequest,\n pending: PendingRecall,\n): boolean {\n const messages = req.messages;\n if (messages.length < 2) return false;\n\n // Find the last assistant message followed by a user message.\n // The pending recall was from the previous turn's assistant response.\n let assistantIdx = -1;\n for (let i = messages.length - 2; i >= 0; i--) {\n if (\n messages[i].role === \"assistant\" &&\n messages[i + 1]?.role === \"user\"\n ) {\n assistantIdx = i;\n break;\n }\n }\n\n if (assistantIdx < 0) {\n log.warn(\"injectPendingRecall: no assistant\u2192user pair found\");\n return false;\n }\n\n const assistantMsg = messages[assistantIdx];\n const userMsg = messages[assistantIdx + 1];\n\n // Insert recall tool_use into assistant message at the recorded position.\n // Clamp to content length in case the message was modified by gradient.\n const insertPos = Math.min(pending.position, assistantMsg.content.length);\n const recallToolUse: GatewayToolUseBlock = {\n type: \"tool_use\",\n id: pending.toolUseId,\n name: RECALL_TOOL_NAME,\n input: pending.input,\n };\n assistantMsg.content.splice(insertPos, 0, recallToolUse);\n\n // Insert recall tool_result into the user message.\n // Add it at the beginning alongside any other tool_results.\n userMsg.content.unshift({\n type: \"tool_result\",\n toolUseId: pending.toolUseId,\n content: pending.result,\n });\n\n // Strip recall from tools list for this request\n req.tools = req.tools.filter((t) => t.name !== RECALL_TOOL_NAME);\n\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// Response content stripping (Case 2: remove recall from response)\n// ---------------------------------------------------------------------------\n\n/**\n * Build a GatewayResponse with recall tool_use blocks removed.\n *\n * Used for Case 2 to produce a clean response for `postResponse` storage\n * that excludes the gateway-internal recall blocks.\n */\nexport function stripRecallFromResponse(\n resp: GatewayResponse,\n): GatewayResponse {\n return {\n ...resp,\n content: resp.content.filter(\n (b) => !(b.type === \"tool_use\" && b.name === RECALL_TOOL_NAME),\n ),\n };\n}\n", "/**\n * HTTP server for the Lore gateway proxy.\n *\n * Routes:\n * POST /v1/messages \u2192 Anthropic protocol (Phase 1)\n * POST /v1/chat/completions \u2192 OpenAI protocol (Phase 2 stub)\n * GET /v1/models \u2192 Passthrough to upstream\n * GET /health \u2192 Health check\n *\n * Uses `Bun.serve()` \u2014 this package targets Bun exclusively.\n */\nimport type { GatewayConfig } from \"./config\";\nimport type { GatewayRequest } from \"./translate/types\";\nimport { parseAnthropicRequest } from \"./translate/anthropic\";\nimport { parseOpenAIRequest, buildOpenAIResponse } from \"./translate/openai\";\nimport { accumulateSSEResponse } from \"./stream/anthropic\";\nimport { handleRequest } from \"./pipeline\";\n\n// ---------------------------------------------------------------------------\n// Version \u2014 best-effort from package.json, falls back gracefully\n// ---------------------------------------------------------------------------\n\nlet version = \"unknown\";\ntry {\n // Bun resolves JSON imports; use require for sync + no top-level await\n const pkg = require(\"../package.json\") as { version?: string };\n if (pkg.version) version = pkg.version;\n} catch {\n // Not critical \u2014 health endpoint will report \"unknown\"\n}\n\n// ---------------------------------------------------------------------------\n// CORS headers \u2014 permissive for localhost development\n// ---------------------------------------------------------------------------\n\nconst CORS_HEADERS: Record<string, string> = {\n \"access-control-allow-origin\": \"*\",\n \"access-control-allow-methods\": \"GET, POST, OPTIONS\",\n \"access-control-allow-headers\": \"*\",\n \"access-control-max-age\": \"86400\",\n};\n\nfunction withCors(response: Response): Response {\n for (const [key, value] of Object.entries(CORS_HEADERS)) {\n response.headers.set(key, value);\n }\n return response;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Convert Bun's Headers object to a plain Record<string, string>. */\nfunction headersToRecord(headers: Headers): Record<string, string> {\n const record: Record<string, string> = {};\n headers.forEach((value, key) => {\n record[key] = value;\n });\n return record;\n}\n\nfunction jsonResponse(body: unknown, status = 200): Response {\n return withCors(\n new Response(JSON.stringify(body), {\n status,\n headers: { \"content-type\": \"application/json\" },\n }),\n );\n}\n\nfunction errorResponse(\n status: number,\n type: string,\n message: string,\n): Response {\n return jsonResponse(\n {\n type: \"error\",\n error: { type, message },\n },\n status,\n );\n}\n\n// ---------------------------------------------------------------------------\n// Route handlers\n// ---------------------------------------------------------------------------\n\nasync function handleAnthropicMessages(\n req: Request,\n config: GatewayConfig,\n): Promise<Response> {\n let body: unknown;\n try {\n body = await req.json();\n } catch {\n return errorResponse(400, \"invalid_request_error\", \"Invalid JSON body\");\n }\n\n let gatewayReq: GatewayRequest;\n try {\n gatewayReq = parseAnthropicRequest(body, headersToRecord(req.headers));\n } catch (e) {\n const msg = e instanceof Error ? e.message : \"Failed to parse request\";\n return errorResponse(400, \"invalid_request_error\", msg);\n }\n\n try {\n const result = await handleRequest(gatewayReq, config);\n // Pipeline returns a Response directly (streaming or non-streaming)\n return withCors(result);\n } catch (e) {\n const msg = e instanceof Error ? e.message : \"Pipeline error\";\n console.error(`[lore] pipeline error: ${msg}`);\n return errorResponse(502, \"api_error\", `Gateway pipeline error: ${msg}`);\n }\n}\n\nasync function handleModelsPassthrough(config: GatewayConfig): Promise<Response> {\n try {\n const upstream = await fetch(`${config.upstreamAnthropic}/v1/models`, {\n headers: { \"content-type\": \"application/json\" },\n });\n // Clone to a new Response so we can append CORS headers\n const response = new Response(upstream.body, {\n status: upstream.status,\n statusText: upstream.statusText,\n headers: new Headers(upstream.headers),\n });\n return withCors(response);\n } catch (e) {\n const msg = e instanceof Error ? e.message : \"Upstream unreachable\";\n return errorResponse(502, \"api_error\", `Failed to fetch models: ${msg}`);\n }\n}\n\nfunction handleHealth(): Response {\n return jsonResponse({ status: \"ok\", version });\n}\n\nasync function handleOpenAIChatCompletions(\n req: Request,\n config: GatewayConfig,\n): Promise<Response> {\n let body: unknown;\n try {\n body = await req.json();\n } catch {\n return errorResponse(400, \"invalid_request_error\", \"Invalid JSON body\");\n }\n\n let gatewayReq: GatewayRequest;\n try {\n gatewayReq = parseOpenAIRequest(body, headersToRecord(req.headers));\n } catch (e) {\n const msg = e instanceof Error ? e.message : \"Failed to parse request\";\n return errorResponse(400, \"invalid_request_error\", msg);\n }\n\n let pipelineResp: Response;\n try {\n pipelineResp = await handleRequest(gatewayReq, config);\n } catch (e) {\n const msg = e instanceof Error ? e.message : \"Pipeline error\";\n console.error(`[lore] pipeline error: ${msg}`);\n return errorResponse(502, \"api_error\", `Gateway pipeline error: ${msg}`);\n }\n\n // Pipeline always returns internal Anthropic-format response.\n // Translate back to OpenAI format before returning to the client.\n if (!pipelineResp.ok) {\n // Upstream or pipeline error \u2014 forward as-is\n return withCors(pipelineResp);\n }\n\n const contentType = pipelineResp.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"text/event-stream\")) {\n // Streaming: accumulate the internal SSE then re-emit as OpenAI SSE\n const accumulated = await accumulateSSEResponse(pipelineResp);\n return withCors(buildOpenAIResponse(accumulated, true));\n }\n\n // Non-streaming: translate JSON body\n const respBody = await pipelineResp.json();\n return withCors(buildOpenAIResponse(respBody, false));\n}\n\n// ---------------------------------------------------------------------------\n// Server\n// ---------------------------------------------------------------------------\n\nexport function startServer(config: GatewayConfig): {\n stop: () => void;\n port: number;\n} {\n const server = Bun.serve({\n port: config.port,\n hostname: config.host,\n\n async fetch(req: Request): Promise<Response> {\n const url = new URL(req.url);\n const { pathname } = url;\n const method = req.method;\n\n // CORS preflight\n if (method === \"OPTIONS\") {\n return withCors(new Response(null, { status: 204 }));\n }\n\n if (config.debug) {\n console.error(`[lore] ${method} ${pathname}`);\n }\n\n try {\n // POST /v1/messages \u2014 Anthropic protocol\n if (method === \"POST\" && pathname === \"/v1/messages\") {\n return await handleAnthropicMessages(req, config);\n }\n\n // POST /v1/chat/completions \u2014 OpenAI protocol\n if (method === \"POST\" && pathname === \"/v1/chat/completions\") {\n return await handleOpenAIChatCompletions(req, config);\n }\n\n // GET /v1/models \u2014 passthrough\n if (method === \"GET\" && pathname === \"/v1/models\") {\n return await handleModelsPassthrough(config);\n }\n\n // GET /health \u2014 health check\n if (method === \"GET\" && pathname === \"/health\") {\n return handleHealth();\n }\n\n // 404 for everything else\n return errorResponse(404, \"not_found\", `No route for ${method} ${pathname}`);\n } catch (e) {\n const msg = e instanceof Error ? e.message : \"Internal server error\";\n console.error(`[lore] uncaught error: ${msg}`);\n return errorResponse(500, \"api_error\", msg);\n }\n },\n });\n\n return {\n stop: () => server.stop(),\n port: server.port ?? config.port,\n };\n}\n", "/**\n * Lore Gateway \u2014 entry point.\n *\n * Starts the HTTP proxy server that applies Lore's context management\n * pipeline to any AI coding client speaking the Anthropic or OpenAI\n * protocol.\n *\n * Usage:\n * bun run packages/gateway/src/index.ts\n * ANTHROPIC_BASE_URL=http://127.0.0.1:6969 claude\n */\nimport { loadConfig } from \"./config\";\nimport { startServer } from \"./server\";\nimport { resetPipelineState } from \"./pipeline\";\n\n// ---------------------------------------------------------------------------\n// Boot\n// ---------------------------------------------------------------------------\n\nconst config = loadConfig();\nconst server = startServer(config);\n\nconst addr = `http://${config.host}:${server.port}`;\nconsole.error(`[lore] Gateway listening on ${addr}`);\nconsole.error(`[lore] Model routing: claude-* \u2192 Anthropic, nvidia/* \u2192 Nvidia NIM, gpt-* \u2192 OpenAI, \u2026`);\nconsole.error(`[lore] Plugin auto-detects gateway \u2014 just start OpenCode normally`);\n\n// ---------------------------------------------------------------------------\n// Graceful shutdown\n// ---------------------------------------------------------------------------\n\nasync function shutdown() {\n console.error(\"[lore] Shutting down\u2026\");\n server.stop();\n // Gracefully shut down the batch queue (flushes pending items synchronously)\n await resetPipelineState();\n process.exit(0);\n}\n\nprocess.on(\"SIGINT\", () => shutdown());\nprocess.on(\"SIGTERM\", () => shutdown());\n"],
|
|
5
|
+
"mappings": ";;;;;;AAAA;AAAA;AAAA;AAAA,MACE,MAAQ;AAAA,MACR,SAAW;AAAA,MACX,MAAQ;AAAA,MACR,SAAW;AAAA,MACX,aAAe;AAAA,MACf,MAAQ;AAAA,MACR,OAAS;AAAA,MACT,SAAW;AAAA,QACT,KAAK;AAAA,UACH,KAAO;AAAA,UACP,SAAW;AAAA,QACb;AAAA,MACF;AAAA,MACA,KAAO;AAAA,QACL,gBAAgB;AAAA,MAClB;AAAA,MACA,SAAW;AAAA,QACT,WAAa;AAAA,QACb,OAAS;AAAA,QACT,OAAS;AAAA,MACX;AAAA,MACA,cAAgB;AAAA,QACd,gBAAgB;AAAA,MAClB;AAAA,MACA,OAAS;AAAA,QACP;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,SAAW;AAAA,QACT,KAAO;AAAA,MACT;AAAA,MACA,YAAc;AAAA,QACZ,MAAQ;AAAA,QACR,KAAO;AAAA,QACP,WAAa;AAAA,MACf;AAAA,MACA,eAAiB;AAAA,QACf,QAAU;AAAA,MACZ;AAAA,MACA,UAAY;AAAA,QACV;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,QAAU;AAAA,IACZ;AAAA;AAAA;;;ACvBO,SAAS,aAA4B;AAC1C,QAAM,MAAM,QAAQ;AACpB,SAAO;AAAA,IACL,MAAM,UAAU,IAAI,kBAAkB,IAAI;AAAA,IAC1C,MAAM,IAAI,oBAAoB;AAAA,IAC9B,mBAAmB;AAAA,MACjB,IAAI,2BAA2B;AAAA,IACjC;AAAA,IACA,gBAAgB;AAAA,MACd,IAAI,wBAAwB;AAAA,IAC9B;AAAA,IACA,oBAAoB,iBAAiB,IAAI,mBAAmB,EAAE;AAAA,IAC9D,OAAO,SAAS,IAAI,UAAU;AAAA,EAChC;AACF;AAkBA,IAAM,kBAA4F;AAAA;AAAA,EAEhG,EAAE,QAAQ,WAAkB,KAAK,6BAAsC,UAAU,YAAY;AAAA;AAAA,EAE7F,EAAE,QAAQ,WAAkB,KAAK,oCAAsC,UAAU,SAAS;AAAA,EAC1F,EAAE,QAAQ,SAAkB,KAAK,oCAAsC,UAAU,SAAS;AAAA,EAC1F,EAAE,QAAQ,cAAkB,KAAK,oCAAsC,UAAU,SAAS;AAAA,EAC1F,EAAE,QAAQ,WAAkB,KAAK,oCAAsC,UAAU,SAAS;AAAA,EAC1F,EAAE,QAAQ,SAAkB,KAAK,oCAAsC,UAAU,SAAS;AAAA,EAC1F,EAAE,QAAQ,aAAkB,KAAK,oCAAsC,UAAU,SAAS;AAAA;AAAA,EAE1F,EAAE,QAAQ,QAAkB,KAAK,0BAAsC,UAAU,SAAS;AAAA,EAC1F,EAAE,QAAQ,OAAkB,KAAK,0BAAsC,UAAU,SAAS;AAAA,EAC1F,EAAE,QAAQ,OAAkB,KAAK,0BAAsC,UAAU,SAAS;AAAA,EAC1F,EAAE,QAAQ,OAAkB,KAAK,0BAAsC,UAAU,SAAS;AAAA;AAAA,EAE1F,EAAE,QAAQ,SAAkB,KAAK,oBAAsC,UAAU,SAAS;AAAA;AAAA,EAE1F,EAAE,QAAQ,YAAkB,KAAK,0BAAsC,UAAU,SAAS;AAAA,EAC1F,EAAE,QAAQ,cAAkB,KAAK,0BAAsC,UAAU,SAAS;AAAA;AAAA,EAE1F,EAAE,QAAQ,WAAkB,KAAK,6CAA6C,UAAU,SAAS;AACnG;AAQO,SAAS,qBAAqB,OAAqC;AACxE,aAAW,SAAS,iBAAiB;AACnC,QAAI,MAAM,WAAW,MAAM,MAAM,GAAG;AAClC,aAAO,EAAE,KAAK,MAAM,KAAK,UAAU,MAAM,SAAS;AAAA,IACpD;AAAA,EACF;AACA,SAAO;AACT;AAiBA,IAAM,wBAAkC;AAAA;AAAA,EAEtC;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA;AAAA,EAGA;AACF;AASO,SAAS,iBAAiB,cAAqC;AACpE,aAAW,WAAW,uBAAuB;AAC3C,UAAM,QAAQ,QAAQ,KAAK,YAAY;AACvC,QAAI,QAAQ,CAAC,GAAG;AAEd,aAAO,MAAM,CAAC,EAAE,QAAQ,QAAQ,EAAE,KAAK;AAAA,IACzC;AAAA,EACF;AACA,SAAO;AACT;AAYO,SAAS,eACd,cACA,SACQ;AAER,QAAM,aAAa,QAAQ,gBAAgB;AAC3C,MAAI,WAAY,QAAO;AAGvB,QAAM,WAAW,iBAAiB,YAAY;AAC9C,MAAI,SAAU,QAAO;AAGrB,SAAO,QAAQ,IAAI;AACrB;AAMA,SAAS,UAAU,OAA2B,UAA0B;AACtE,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,IAAI,OAAO,SAAS,OAAO,EAAE;AACnC,MAAI,OAAO,MAAM,CAAC,KAAK,IAAI,KAAK,IAAI,MAAO,QAAO;AAClD,SAAO;AACT;AAEA,SAAS,iBACP,OACA,UACQ;AACR,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,IAAI,OAAO,SAAS,OAAO,EAAE;AACnC,MAAI,OAAO,MAAM,CAAC,KAAK,KAAK,EAAG,QAAO;AACtC,SAAO;AACT;AAEA,SAAS,SAAS,OAAoC;AACpD,SAAO,UAAU,OAAO,OAAO,YAAY,MAAM;AACnD;AAEA,SAAS,kBAAkB,KAAqB;AAC9C,SAAO,IAAI,QAAQ,QAAQ,EAAE;AAC/B;;;ACrKO,SAAS,YACd,SACuB;AACvB,QAAM,SAAS,QAAQ,WAAW,KAAK,QAAQ,WAAW;AAC1D,MAAI,OAAQ,QAAO,EAAE,QAAQ,WAAW,OAAO,OAAO;AAEtD,QAAM,aACJ,QAAQ,eAAe,KAAK,QAAQ,eAAe;AACrD,MAAI,YAAY;AACd,UAAM,QAAQ,oBAAoB,KAAK,UAAU;AACjD,QAAI,MAAO,QAAO,EAAE,QAAQ,UAAU,OAAO,MAAM,CAAC,EAAE;AAAA,EACxD;AAEA,SAAO;AACT;AAQO,SAAS,YAAY,MAA8C;AACxE,UAAQ,KAAK,QAAQ;AAAA,IACnB,KAAK;AACH,aAAO,EAAE,aAAa,KAAK,MAAM;AAAA,IACnC,KAAK;AACH,aAAO,EAAE,eAAe,UAAU,KAAK,KAAK,GAAG;AAAA,EACnD;AACF;AASO,SAAS,gBAAgB,MAA8B;AAC5D,SAAO,KAAK,MAAM,MAAM,EAAE;AAC5B;AAMA,IAAM,cAAc,oBAAI,IAA4B;AAE7C,SAAS,eACd,WACA,MACM;AACN,cAAY,IAAI,WAAW,IAAI;AACjC;AAEO,SAAS,eACd,WACuB;AACvB,SAAO,YAAY,IAAI,SAAS,KAAK;AACvC;AAWA,IAAI,eAAsC;AAEnC,SAAS,gBAAgB,MAA4B;AAC1D,iBAAe;AACjB;AAEO,SAAS,kBAAyC;AACvD,SAAO;AACT;AAaO,SAAS,YACd,WACuB;AACvB,MAAI,WAAW;AACb,UAAM,OAAO,eAAe,SAAS;AACrC,QAAI,KAAM,QAAO;AAAA,EACnB;AACA,SAAO,gBAAgB;AACzB;;;AChHA,IAAM,oBAAoB;AAO1B,IAAM,oBAAoB,oBAAI,IAAI;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAWD,SAAS,eAAe,OAAqD;AAC3E,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,aAAO,EAAE,MAAM,QAAQ,MAAM,OAAO,MAAM,QAAQ,EAAE,EAAE;AAAA,IAExD,KAAK;AACH,aAAO;AAAA,QACL,MAAM;AAAA,QACN,UAAU,OAAO,MAAM,YAAY,EAAE;AAAA,QACrC,GAAI,MAAM,aAAa,OACnB,EAAE,WAAW,OAAO,MAAM,SAAS,EAAE,IACrC;AAAA,MACN;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,MAAM;AAAA,QACN,IAAI,OAAO,MAAM,MAAM,EAAE;AAAA,QACzB,MAAM,OAAO,MAAM,QAAQ,EAAE;AAAA,QAC7B,OAAO,MAAM;AAAA,MACf;AAAA,IAEF,KAAK,eAAe;AAElB,UAAI,UAAU;AACd,UAAI,OAAO,MAAM,YAAY,UAAU;AACrC,kBAAU,MAAM;AAAA,MAClB,WAAW,MAAM,QAAQ,MAAM,OAAO,GAAG;AACvC,kBAAW,MAAM,QACd,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM,EAC/B,IAAI,CAAC,MAAM,OAAO,EAAE,QAAQ,EAAE,CAAC,EAC/B,KAAK,IAAI;AAAA,MACd;AACA,aAAO;AAAA,QACL,MAAM;AAAA,QACN,WAAW,OAAO,MAAM,eAAe,EAAE;AAAA,QACzC;AAAA,QACA,GAAI,MAAM,WAAW,EAAE,SAAS,KAAK,IAAI;AAAA,MAC3C;AAAA,IACF;AAAA,IAEA;AAEE,aAAO,EAAE,MAAM,QAAQ,MAAM,KAAK,UAAU,KAAK,EAAE;AAAA,EACvD;AACF;AAMA,SAAS,iBAAiB,SAAyC;AACjE,MAAI,OAAO,YAAY,UAAU;AAC/B,WAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,QAAQ,CAAC;AAAA,EACzC;AAEA,MAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,WAAO,QAAQ;AAAA,MAAI,CAAC,UAClB,eAAe,KAAgC;AAAA,IACjD;AAAA,EACF;AAGA,SAAO,CAAC;AACV;AAQA,SAAS,gBAAgB,QAAyB;AAChD,MAAI,UAAU,KAAM,QAAO;AAC3B,MAAI,OAAO,WAAW,SAAU,QAAO;AAEvC,MAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,WAAQ,OACL,OAAO,CAAC,UAAU,MAAM,SAAS,MAAM,EACvC,IAAI,CAAC,UAAU,OAAO,MAAM,QAAQ,EAAE,CAAC,EACvC,KAAK,IAAI;AAAA,EACd;AAEA,SAAO,OAAO,MAAM;AACtB;AASA,SAAS,iBACP,OACyB;AACzB,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,aAAO,EAAE,MAAM,QAAQ,MAAM,MAAM,KAAK;AAAA,IAE1C,KAAK;AACH,aAAO;AAAA,QACL,MAAM;AAAA,QACN,UAAU,MAAM;AAAA,QAChB,GAAI,MAAM,aAAa,OAAO,EAAE,WAAW,MAAM,UAAU,IAAI;AAAA,MACjE;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,MAAM;AAAA,QACN,IAAI,MAAM;AAAA,QACV,MAAM,MAAM;AAAA,QACZ,OAAO,MAAM;AAAA,MACf;AAAA,IAEF,KAAK,eAAe;AAClB,YAAM,SAAkC;AAAA,QACtC,MAAM;AAAA,QACN,aAAa,MAAM;AAAA,QACnB,SAAS,MAAM;AAAA,MACjB;AACA,UAAI,MAAM,QAAS,QAAO,WAAW;AACrC,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAaO,SAAS,sBACd,MACA,SACgB;AAChB,QAAM,MAAO,QAAQ,CAAC;AAGtB,QAAM,QAAQ,OAAO,IAAI,SAAS,EAAE;AACpC,QAAM,SAAS,gBAAgB,IAAI,MAAM;AACzC,QAAM,SAAS,IAAI,WAAW;AAC9B,QAAM,YACJ,OAAO,IAAI,eAAe,WAAW,IAAI,aAAa;AAGxD,QAAM,cAAc,MAAM,QAAQ,IAAI,QAAQ,IAAI,IAAI,WAAW,CAAC;AAClE,QAAM,WAA6B,YAAY;AAAA,IAC7C,CAAC,SAAkC;AAAA,MACjC,MAAM,IAAI,SAAS,cAAc,cAAc;AAAA,MAC/C,SAAS,iBAAiB,IAAI,OAAO;AAAA,IACvC;AAAA,EACF;AAGA,QAAM,WAAW,MAAM,QAAQ,IAAI,KAAK,IAAI,IAAI,QAAQ,CAAC;AACzD,QAAM,QAAuB,SAAS;AAAA,IACpC,CAAC,OAAgC;AAAA,MAC/B,MAAM,OAAO,EAAE,QAAQ,EAAE;AAAA,MACzB,aAAa,OAAO,EAAE,eAAe,EAAE;AAAA,MACvC,aAAc,EAAE,gBAA4C,CAAC;AAAA,IAC/D;AAAA,EACF;AAGA,QAAM,WAAoC,CAAC;AAC3C,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,GAAG,GAAG;AAC9C,QAAI,CAAC,kBAAkB,IAAI,GAAG,GAAG;AAC/B,eAAS,GAAG,IAAI;AAAA,IAClB;AAAA,EACF;AAEA,SAAO;AAAA,IACL,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY;AAAA,EACd;AACF;AA4DO,SAAS,sBACd,KACA,OAKA;AAEA,QAAM,UAAkC;AAAA,IACtC,gBAAgB;AAAA,IAChB,qBAAqB;AAAA,EACvB;AAGA,QAAM,OAAO,YAAY,IAAI,UAAU;AACvC,MAAI,MAAM;AACR,WAAO,OAAO,SAAS,YAAY,IAAI,CAAC;AAAA,EAC1C;AAGA,QAAM,OACJ,IAAI,WAAW,gBAAgB,KAAK,IAAI,WAAW,gBAAgB,KAAK;AAC1E,MAAI,MAAM;AACR,YAAQ,gBAAgB,IAAI;AAAA,EAC9B;AAGA,QAAM,OAAgC;AAAA,IACpC,OAAO,IAAI;AAAA,IACX,YAAY,IAAI;AAAA,IAChB,QAAQ,IAAI;AAAA,EACd;AAGA,MAAI,IAAI,QAAQ;AACd,UAAM,YAAY,OAAO;AACzB,QAAI,WAAW;AAIb,YAAM,eACJ,cAAc,OACV,EAAE,MAAM,aAAa,KAAK,KAAK,IAC/B,EAAE,MAAM,YAAY;AAC1B,WAAK,SAAS;AAAA,QACZ,EAAE,MAAM,QAAQ,MAAM,IAAI,QAAQ,eAAe,aAAa;AAAA,MAChE;AAAA,IACF,OAAO;AACL,WAAK,SAAS,IAAI;AAAA,IACpB;AAAA,EACF;AAGA,QAAM,WAAW,IAAI,SAAS,IAAI,CAAC,SAAS;AAAA,IAC1C,MAAM,IAAI;AAAA,IACV,SAAS,IAAI,QAAQ,IAAI,gBAAgB;AAAA,EAC3C,EAAE;AAKF,MAAI,OAAO,qBAAqB,SAAS,SAAS,GAAG;AACnD,UAAM,UAAU,SAAS,SAAS,SAAS,CAAC;AAC5C,QAAI,QAAQ,QAAQ,SAAS,GAAG;AAC9B,YAAM,YAAY,QAAQ,QAAQ,QAAQ,QAAQ,SAAS,CAAC;AAC5D,MAAC,UAAsC,gBAAgB;AAAA,QACrD,MAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,OAAK,WAAW;AAGhB,MAAI,IAAI,MAAM,SAAS,GAAG;AACxB,SAAK,QAAQ,IAAI,MAAM,IAAI,CAAC,OAAO;AAAA,MACjC,MAAM,EAAE;AAAA,MACR,aAAa,EAAE;AAAA,MACf,cAAc,EAAE;AAAA,IAClB,EAAE;AAAA,EACJ;AAGA,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,QAAQ,GAAG;AACvD,SAAK,GAAG,IAAI;AAAA,EACd;AAEA,SAAO;AAAA,IACL,KAAK;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;AAYO,SAAS,gCACd,MACS;AACT,QAAM,QAAgC;AAAA,IACpC,cAAc,KAAK,MAAM;AAAA,IACzB,eAAe,KAAK,MAAM;AAAA,EAC5B;AAEA,MAAI,KAAK,MAAM,wBAAwB,MAAM;AAC3C,UAAM,0BAA0B,KAAK,MAAM;AAAA,EAC7C;AACA,MAAI,KAAK,MAAM,4BAA4B,MAAM;AAC/C,UAAM,8BAA8B,KAAK,MAAM;AAAA,EACjD;AAEA,SAAO;AAAA,IACL,IAAI,KAAK;AAAA,IACT,MAAM;AAAA,IACN,MAAM;AAAA,IACN,OAAO,KAAK;AAAA,IACZ,SAAS,KAAK,QAAQ,IAAI,gBAAgB;AAAA,IAC1C,aAAa,KAAK;AAAA,IAClB,eAAe;AAAA,IACf;AAAA,EACF;AACF;;;ACrZO,SAAS,mBACd,MACA,SACgB;AAChB,QAAM,MAAO,QAAQ,CAAC;AAGtB,QAAM,QAAQ,OAAO,IAAI,SAAS,EAAE;AACpC,QAAM,SAAS,IAAI,WAAW;AAG9B,QAAM,YACJ,OAAO,IAAI,eAAe,WAAW,IAAI,aAAa;AAGxD,QAAM,SAAmC,CAAC;AAC1C,MAAI,OAAO,IAAI,gBAAgB,UAAU;AACvC,WAAO,cAAc,IAAI;AAAA,EAC3B;AACA,MAAI,OAAO,IAAI,UAAU,UAAU;AACjC,WAAO,QAAQ,IAAI;AAAA,EACrB;AACA,MAAI,OAAO,IAAI,sBAAsB,UAAU;AAC7C,WAAO,oBAAoB,IAAI;AAAA,EACjC;AACA,MAAI,OAAO,IAAI,qBAAqB,UAAU;AAC5C,WAAO,mBAAmB,IAAI;AAAA,EAChC;AACA,MAAI,OAAO,IAAI,SAAS,UAAU;AAChC,WAAO,OAAO,IAAI;AAAA,EACpB;AACA,MAAI,IAAI,aAAa,QAAQ,IAAI,aAAa,OAAO;AACnD,WAAO,WAAW,IAAI;AAAA,EACxB;AACA,MAAI,OAAO,IAAI,iBAAiB,UAAU;AACxC,WAAO,eAAe,IAAI;AAAA,EAC5B;AAGA,QAAM,cAAc,MAAM,QAAQ,IAAI,QAAQ,IAAI,IAAI,WAAW,CAAC;AAClE,MAAI,SAAS;AACb,QAAM,WAA6B,CAAC;AAEpC,aAAW,OAAO,aAA+C;AAC/D,UAAM,OAAO,IAAI;AACjB,UAAM,UAAU,IAAI;AAEpB,QAAI,SAAS,UAAU;AAErB,YAAM,OAAO,OAAO,YAAY,WAAW,UAAU;AACrD,UAAI,QAAQ;AACV,kBAAU,SAAS;AAAA,MACrB,OAAO;AACL,iBAAS;AAAA,MACX;AACA;AAAA,IACF;AAEA,QAAI,SAAS,QAAQ;AACnB,YAAM,SAAS,iBAAiB,SAAS,IAAI,UAAwD;AACrG,eAAS,KAAK,EAAE,MAAM,QAAQ,SAAS,OAAO,CAAC;AAC/C;AAAA,IACF;AAEA,QAAI,SAAS,aAAa;AACxB,YAAM,SAAS;AAAA,QACb;AAAA,QACA,IAAI;AAAA,MACN;AACA,eAAS,KAAK,EAAE,MAAM,aAAa,SAAS,OAAO,CAAC;AACpD;AAAA,IACF;AAEA,QAAI,SAAS,QAAQ;AAInB,YAAM,mBAAmB,gBAAgB,GAAG;AAC5C,UAAI,iBAAiB,SAAS,GAAG;AAC/B,iBAAS,KAAK,EAAE,MAAM,QAAQ,SAAS,iBAAiB,CAAC;AAAA,MAC3D;AACA;AAAA,IACF;AAAA,EACF;AAGA,QAAM,WAAW,MAAM,QAAQ,IAAI,KAAK,IAAI,IAAI,QAAQ,CAAC;AACzD,QAAM,QAAuB,SAAS;AAAA,IACpC,CAAC,MAA+B;AAC9B,YAAM,OAAO,EAAE;AACf,aAAO;AAAA,QACL,MAAM,OAAO,MAAM,QAAQ,EAAE,QAAQ,EAAE;AAAA,QACvC,aAAa,OAAO,MAAM,eAAe,EAAE;AAAA,QAC3C,aAAc,MAAM,cAA0C,CAAC;AAAA,MACjE;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU,CAAC;AAAA,IACX,YAAY;AAAA,MACV,GAAG;AAAA,MACH,aAAa,QAAQ,WAAW,KAAK;AAAA,IACvC;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,iBACP,SACA,WACuB;AACvB,QAAM,SAAgC,CAAC;AAEvC,MAAI,OAAO,YAAY,YAAY,SAAS;AAC1C,WAAO,KAAK,EAAE,MAAM,QAAQ,MAAM,QAAQ,CAAC;AAAA,EAC7C,WAAW,MAAM,QAAQ,OAAO,GAAG;AACjC,eAAW,QAAQ,SAA2C;AAC5D,UAAI,KAAK,SAAS,QAAQ;AACxB,eAAO,KAAK,EAAE,MAAM,QAAQ,MAAM,OAAO,KAAK,QAAQ,EAAE,EAAE,CAAC;AAAA,MAC7D,WAAW,KAAK,SAAS,YAAY;AACnC,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,IAAI,OAAO,KAAK,MAAM,EAAE;AAAA,UACxB,MAAM,OAAO,KAAK,QAAQ,EAAE;AAAA,UAC5B,OAAO,KAAK,SAAS,CAAC;AAAA,QACxB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAGA,MAAI,WAAW;AACb,eAAW,MAAM,WAAW;AAC1B,YAAM,KAAK,GAAG;AACd,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN,IAAI,OAAO,GAAG,MAAM,EAAE;AAAA,QACtB,MAAM,OAAO,IAAI,QAAQ,EAAE;AAAA,QAC3B,OAAO,IAAI,YAAY,KAAK,MAAM,GAAG,SAAmB,IAAI,CAAC;AAAA,MAC/D,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,sBACP,SACA,WACuB;AACvB,QAAM,SAAgC,CAAC;AAEvC,MAAI,OAAO,YAAY,YAAY,SAAS;AAC1C,WAAO,KAAK,EAAE,MAAM,QAAQ,MAAM,QAAQ,CAAC;AAAA,EAC7C,WAAW,MAAM,QAAQ,OAAO,GAAG;AACjC,eAAW,QAAQ,SAA2C;AAC5D,UAAI,KAAK,SAAS,QAAQ;AACxB,eAAO,KAAK,EAAE,MAAM,QAAQ,MAAM,OAAO,KAAK,QAAQ,EAAE,EAAE,CAAC;AAAA,MAC7D,WAAW,KAAK,SAAS,YAAY;AACnC,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,IAAI,OAAO,KAAK,MAAM,EAAE;AAAA,UACxB,MAAM,OAAO,KAAK,QAAQ,EAAE;AAAA,UAC5B,OAAO,KAAK,SAAS,CAAC;AAAA,QACxB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAGA,MAAI,WAAW;AACb,eAAW,MAAM,WAAW;AAC1B,YAAM,KAAK,GAAG;AACd,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN,IAAI,OAAO,GAAG,MAAM,EAAE;AAAA,QACtB,MAAM,OAAO,IAAI,QAAQ,EAAE;AAAA,QAC3B,OAAO,IAAI,YAAY,KAAK,MAAM,GAAG,SAAmB,IAAI,CAAC;AAAA,MAC/D,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,gBAAgB,KAAqD;AAC5E,QAAM,SAAgC,CAAC;AACvC,QAAM,aAAa,OAAO,IAAI,gBAAgB,EAAE;AAChD,QAAM,UAAU,IAAI;AAEpB,MAAI,OAAO,YAAY,YAAY,SAAS;AAC1C,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN,WAAW;AAAA,MACX;AAAA,IACF,CAAC;AAAA,EACH,WAAW,MAAM,QAAQ,OAAO,GAAG;AACjC,eAAW,QAAQ,SAA2C;AAC5D,UAAI,KAAK,SAAS,QAAQ;AACxB,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,WAAW;AAAA,UACX,SAAS,OAAO,KAAK,QAAQ,EAAE;AAAA,QACjC,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAMO,SAAS,oBACd,MACA,cACU;AACV,MAAI,cAAc;AAChB,WAAO,0BAA0B,IAAI;AAAA,EACvC;AACA,SAAO,6BAA6B,IAAI;AAC1C;AAEA,SAAS,6BAA6B,MAAiC;AACrE,QAAM,SAAoB,CAAC;AAC3B,MAAI,UAAU;AACd,QAAM,YAA4C,CAAC;AAEnD,aAAW,SAAS,KAAK,SAAS;AAChC,QAAI,MAAM,SAAS,QAAQ;AACzB,iBAAW,MAAM;AAAA,IACnB,WAAW,MAAM,SAAS,YAAY;AACpC,gBAAU,KAAK;AAAA,QACb,IAAI,MAAM;AAAA,QACV,MAAM;AAAA,QACN,UAAU;AAAA,UACR,MAAM,MAAM;AAAA,UACZ,WAAW,KAAK,UAAU,MAAM,KAAK;AAAA,QACvC;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,UAAmC;AAAA,IACvC,MAAM;AAAA,IACN,SAAS,WAAW;AAAA,EACtB;AAEA,MAAI,UAAU,SAAS,GAAG;AACxB,YAAQ,aAAa;AAAA,EACvB;AAEA,QAAM,WAAW;AAAA,IACf,IAAI,KAAK,GAAG,WAAW,WAAW,IAAI,KAAK,KAAK,YAAY,KAAK,EAAE;AAAA,IACnE,QAAQ;AAAA,IACR,SAAS,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AAAA,IACrC,OAAO,KAAK;AAAA,IACZ,SAAS;AAAA,MACP;AAAA,QACE,OAAO;AAAA,QACP;AAAA,QACA,eAAe,cAAc,KAAK,UAAU;AAAA,QAC5C,UAAU;AAAA,MACZ;AAAA,IACF;AAAA,IACA,OAAO;AAAA,MACL,eAAe,KAAK,MAAM;AAAA,MAC1B,mBAAmB,KAAK,MAAM;AAAA,MAC9B,cACE,KAAK,MAAM,cAAc,KAAK,MAAM;AAAA,IACxC;AAAA,EACF;AAEA,SAAO,IAAI,SAAS,KAAK,UAAU,QAAQ,GAAG;AAAA,IAC5C,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,EAChD,CAAC;AACH;AAEA,SAAS,cAAc,QAAwB;AAC7C,UAAQ,QAAQ;AAAA,IACd,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAEA,SAAS,0BAA0B,MAAiC;AAClE,QAAM,UAAU,IAAI,YAAY;AAChC,MAAI,SAAS;AAEb,QAAM,SAAS,IAAI,eAAe;AAAA,IAChC,MAAM,YAAY;AAChB,YAAM,SAAS,KAAK,GAAG,WAAW,WAAW,IACzC,KAAK,KACL,YAAY,KAAK,EAAE;AACvB,YAAM,UAAU,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AAE5C,eAAS,UACP,OACA,cACA;AACA,cAAM,QAAQ;AAAA,UACZ,IAAI;AAAA,UACJ,QAAQ;AAAA,UACR;AAAA,UACA,OAAO,KAAK;AAAA,UACZ,SAAS;AAAA,YACP;AAAA,cACE,OAAO;AAAA,cACP;AAAA,cACA,eAAe;AAAA,YACjB;AAAA,UACF;AAAA,QACF;AACA,mBAAW;AAAA,UACT,QAAQ,OAAO,SAAS,KAAK,UAAU,KAAK,CAAC;AAAA;AAAA,CAAM;AAAA,QACrD;AAAA,MACF;AAGA,gBAAU,EAAE,MAAM,YAAY,GAAG,IAAI;AAGrC,iBAAW,SAAS,KAAK,SAAS;AAChC,YAAI,MAAM,SAAS,QAAQ;AAEzB,gBAAM,OAAO,MAAM;AACnB,cAAI,MAAM;AACV,iBAAO,MAAM,KAAK,QAAQ;AACxB,kBAAM,QAAQ,KAAK,MAAM,KAAK,MAAM,EAAE;AACtC,sBAAU,EAAE,SAAS,MAAM,GAAG,IAAI;AAClC,mBAAO;AAAA,UACT;AAAA,QACF,WAAW,MAAM,SAAS,YAAY;AACpC;AAAA,YACE;AAAA,cACE,YAAY;AAAA,gBACV;AAAA,kBACE,OAAO;AAAA,kBACP,IAAI,MAAM;AAAA,kBACV,MAAM;AAAA,kBACN,UAAU;AAAA,oBACR,MAAM,MAAM;AAAA,oBACZ,WAAW,KAAK,UAAU,MAAM,KAAK;AAAA,kBACvC;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,YACA;AAAA,UACF;AACA;AAAA,QACF;AAAA,MACF;AAGA,gBAAU,CAAC,GAAG,cAAc,KAAK,UAAU,CAAC;AAG5C,iBAAW,QAAQ,QAAQ,OAAO,kBAAkB,CAAC;AACrD,iBAAW,MAAM;AAAA,IACnB;AAAA,EACF,CAAC;AAED,SAAO,IAAI,SAAS,QAAQ;AAAA,IAC1B,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,gBAAgB;AAAA,MAChB,iBAAiB;AAAA,MACjB,YAAY;AAAA,IACd;AAAA,EACF,CAAC;AACH;AAMO,SAAS,2BACd,KACA,cACiE;AACjE,QAAM,UAAkC;AAAA,IACtC,gBAAgB;AAAA,EAClB;AAIA,QAAM,OAAO,YAAY,IAAI,UAAU;AACvC,MAAI,MAAM;AACR,YAAQ,eAAe,IAAI,UAAU,KAAK,KAAK;AAAA,EACjD;AAEA,QAAM,OAAgC;AAAA,IACpC,OAAO,IAAI;AAAA,IACX,UAAU,oBAAoB,IAAI,UAAU,IAAI,MAAM;AAAA,IACtD,QAAQ,IAAI;AAAA,EACd;AAEA,MAAI,IAAI,WAAW;AACjB,SAAK,aAAa,IAAI;AAAA,EACxB;AAGA,MAAI,IAAI,MAAM,SAAS,GAAG;AACxB,SAAK,QAAQ,IAAI,MAAM,IAAI,CAAC,OAAO;AAAA,MACjC,MAAM;AAAA,MACN,UAAU;AAAA,QACR,MAAM,EAAE;AAAA,QACR,aAAa,EAAE;AAAA,QACf,YAAY,EAAE;AAAA,MAChB;AAAA,IACF,EAAE;AAAA,EACJ;AAGA,MAAI,IAAI,QAAQ;AACd,QAAI,IAAI,OAAO,gBAAgB,QAAW;AACxC,WAAK,cAAc,IAAI,OAAO;AAAA,IAChC;AACA,QAAI,IAAI,OAAO,UAAU,QAAW;AAClC,WAAK,QAAQ,IAAI,OAAO;AAAA,IAC1B;AACA,QAAI,IAAI,OAAO,sBAAsB,QAAW;AAC9C,WAAK,oBAAoB,IAAI,OAAO;AAAA,IACtC;AACA,QAAI,IAAI,OAAO,qBAAqB,QAAW;AAC7C,WAAK,mBAAmB,IAAI,OAAO;AAAA,IACrC;AACA,QAAI,IAAI,OAAO,SAAS,QAAW;AACjC,WAAK,OAAO,IAAI,OAAO;AAAA,IACzB;AACA,QAAI,IAAI,OAAO,aAAa,QAAW;AACrC,WAAK,WAAW,IAAI,OAAO;AAAA,IAC7B;AACA,QAAI,IAAI,OAAO,iBAAiB,QAAW;AACzC,WAAK,eAAe,IAAI,OAAO;AAAA,IACjC;AAAA,EACF;AAEA,SAAO;AAAA,IACL,KAAK,GAAG,YAAY;AAAA,IACpB;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,oBACP,UACA,QACgC;AAChC,QAAM,SAAyC,CAAC;AAGhD,MAAI,QAAQ;AACV,WAAO,KAAK,EAAE,MAAM,UAAU,SAAS,OAAO,CAAC;AAAA,EACjD;AAEA,aAAW,OAAO,UAAU;AAC1B,UAAM,SAAS,IAAI;AACnB,UAAM,OAAO,IAAI;AAGjB,UAAM,YAAsB,CAAC;AAC7B,UAAM,WAA2C,CAAC;AAElD,eAAW,SAAS,QAAQ;AAC1B,UAAI,MAAM,SAAS,QAAQ;AACzB,kBAAU,KAAK,MAAM,IAAI;AAAA,MAC3B,WAAW,MAAM,SAAS,YAAY;AACpC,iBAAS,KAAK;AAAA,UACZ,IAAI,MAAM;AAAA,UACV,MAAM;AAAA,UACN,UAAU;AAAA,YACR,MAAM,MAAM;AAAA,YACZ,WAAW,KAAK,UAAU,MAAM,KAAK;AAAA,UACvC;AAAA,QACF,CAAC;AAAA,MACH,WAAW,MAAM,SAAS,eAAe;AAAA,MAGzC;AAAA,IACF;AAEA,UAAM,YAAqC,EAAE,KAAK;AAElD,QAAI,UAAU,SAAS,GAAG;AACxB,gBAAU,UAAU,UAAU,KAAK,EAAE;AAAA,IACvC;AAEA,QAAI,SAAS,SAAS,GAAG;AACvB,gBAAU,aAAa;AAAA,IACzB;AAEA,WAAO,KAAK,SAAS;AAAA,EACvB;AAEA,SAAO;AACT;;;AC/fO,SAAS,eAAe,WAAmB,MAAsB;AACtE,SAAO,UAAU,SAAS;AAAA,QAAW,IAAI;AAAA;AAAA;AAC3C;AAeA,gBAAuB,eACrB,QACiD;AACjD,QAAM,UAAU,IAAI,YAAY;AAChC,MAAI,SAAS;AAEb,aAAS;AACP,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,QAAI,OAAO;AACT,gBAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAAA,IAClD;AAGA,QAAI;AACJ,YAAQ,WAAW,OAAO,QAAQ,MAAM,OAAO,IAAI;AACjD,YAAM,QAAQ,OAAO,MAAM,GAAG,QAAQ;AACtC,eAAS,OAAO,MAAM,WAAW,CAAC;AAGlC,UAAI,MAAM,KAAK,MAAM,GAAI;AAEzB,UAAI,YAAY;AAChB,YAAM,YAAsB,CAAC;AAE7B,iBAAW,QAAQ,MAAM,MAAM,IAAI,GAAG;AACpC,YAAI,KAAK,WAAW,QAAQ,GAAG;AAC7B,sBAAY,KAAK,MAAM,CAAC,EAAE,KAAK;AAAA,QACjC,WAAW,KAAK,WAAW,OAAO,GAAG;AACnC,oBAAU,KAAK,KAAK,MAAM,CAAC,EAAE,UAAU,CAAC;AAAA,QAC1C;AAAA,MAGF;AAEA,UAAI,UAAU,SAAS,GAAG;AACxB,cAAM,EAAE,OAAO,WAAW,MAAM,UAAU,KAAK,IAAI,EAAE;AAAA,MACvD;AAAA,IACF;AAEA,QAAI,MAAM;AAER,UAAI,OAAO,KAAK,GAAG;AACjB,YAAI,YAAY;AAChB,cAAM,YAAsB,CAAC;AAC7B,mBAAW,QAAQ,OAAO,MAAM,IAAI,GAAG;AACrC,cAAI,KAAK,WAAW,QAAQ,GAAG;AAC7B,wBAAY,KAAK,MAAM,CAAC,EAAE,KAAK;AAAA,UACjC,WAAW,KAAK,WAAW,OAAO,GAAG;AACnC,sBAAU,KAAK,KAAK,MAAM,CAAC,EAAE,UAAU,CAAC;AAAA,UAC1C;AAAA,QACF;AACA,YAAI,UAAU,SAAS,GAAG;AACxB,gBAAM,EAAE,OAAO,WAAW,MAAM,UAAU,KAAK,IAAI,EAAE;AAAA,QACvD;AAAA,MACF;AACA;AAAA,IACF;AAAA,EACF;AACF;AAsBO,SAAS,0BAA6C;AAC3D,MAAI,KAAK;AACT,MAAI,QAAQ;AACZ,MAAI,aAAa;AACjB,MAAI,OAAO;AAEX,QAAM,QAAsB;AAAA,IAC1B,aAAa;AAAA,IACb,cAAc;AAAA,EAChB;AAGA,QAAM,SAAS,oBAAI,IAA+B;AAElD,QAAM,UAAiC,CAAC;AAExC,QAAM,YAAY,oBAAI,IAAY;AAElC,WAAS,aAAa,WAAmB,MAAsB;AAE7D,UAAM,YAAY,eAAe,WAAW,IAAI;AAGhD,QAAI;AACJ,QAAI;AACF,eAAS,KAAK,MAAM,IAAI;AAAA,IAC1B,QAAQ;AACN,aAAO;AAAA,IACT;AAEA,YAAQ,WAAW;AAAA,MACjB,KAAK;AACH,2BAAmB,MAAM;AACzB;AAAA,MACF,KAAK;AACH,gCAAwB,MAAM;AAC9B;AAAA,MACF,KAAK;AACH,gCAAwB,MAAM;AAC9B;AAAA,MACF,KAAK;AACH,+BAAuB,MAAM;AAC7B;AAAA,MACF,KAAK;AACH,2BAAmB,MAAM;AACzB;AAAA,MACF,KAAK;AACH,eAAO;AACP;AAAA,IAEJ;AAEA,WAAO;AAAA,EACT;AAEA,WAAS,mBAAmB,QAAuC;AACjE,UAAM,UAAU,OAAO;AACvB,QAAI,CAAC,QAAS;AAEd,QAAI,OAAO,QAAQ,OAAO,SAAU,MAAK,QAAQ;AACjD,QAAI,OAAO,QAAQ,UAAU,SAAU,SAAQ,QAAQ;AAEvD,UAAM,WAAW,QAAQ;AACzB,QAAI,UAAU;AACZ,UAAI,OAAO,SAAS,iBAAiB,UAAU;AAC7C,cAAM,cAAc,SAAS;AAAA,MAC/B;AACA,UAAI,OAAO,SAAS,kBAAkB,UAAU;AAC9C,cAAM,eAAe,SAAS;AAAA,MAChC;AACA,UAAI,OAAO,SAAS,4BAA4B,UAAU;AACxD,cAAM,uBAAuB,SAAS;AAAA,MACxC;AACA,UAAI,OAAO,SAAS,gCAAgC,UAAU;AAC5D,cAAM,2BAA2B,SAAS;AAAA,MAC5C;AAAA,IACF;AAAA,EACF;AAEA,WAAS,wBAAwB,QAAuC;AACtE,UAAM,QAAQ,OAAO;AACrB,QAAI,OAAO,UAAU,SAAU;AAE/B,UAAM,QAAQ,OAAO;AACrB,QAAI,CAAC,SAAS,OAAO,MAAM,SAAS,SAAU;AAE9C,YAAQ,MAAM,MAAM;AAAA,MAClB,KAAK;AACH,eAAO,IAAI,OAAO;AAAA,UAChB,MAAM;AAAA,UACN,MAAM,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO;AAAA,QACtD,CAAC;AACD;AAAA,MACF,KAAK;AACH,eAAO,IAAI,OAAO;AAAA,UAChB,MAAM;AAAA,UACN,UACE,OAAO,MAAM,aAAa,WAAW,MAAM,WAAW;AAAA,UACxD,WAAW;AAAA,QACb,CAAC;AACD;AAAA,MACF,KAAK;AACH,eAAO,IAAI,OAAO;AAAA,UAChB,MAAM;AAAA,UACN,IAAI,OAAO,MAAM,OAAO,WAAW,MAAM,KAAK;AAAA,UAC9C,MAAM,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO;AAAA,UACpD,aAAa;AAAA,QACf,CAAC;AACD;AAAA,IACJ;AAAA,EACF;AAEA,WAAS,wBAAwB,QAAuC;AACtE,UAAM,QAAQ,OAAO;AACrB,QAAI,OAAO,UAAU,SAAU;AAE/B,UAAM,QAAQ,OAAO;AACrB,QAAI,CAAC,SAAS,OAAO,MAAM,SAAS,SAAU;AAE9C,UAAM,QAAQ,OAAO,IAAI,KAAK;AAC9B,QAAI,CAAC,MAAO;AAEZ,YAAQ,MAAM,MAAM;AAAA,MAClB,KAAK;AACH,YAAI,MAAM,SAAS,UAAU,OAAO,MAAM,SAAS,UAAU;AAC3D,gBAAM,QAAQ,MAAM;AAAA,QACtB;AACA;AAAA,MACF,KAAK;AACH,YACE,MAAM,SAAS,cACf,OAAO,MAAM,aAAa,UAC1B;AACA,gBAAM,YAAY,MAAM;AAAA,QAC1B;AACA;AAAA,MACF,KAAK;AACH,YACE,MAAM,SAAS,cACf,OAAO,MAAM,cAAc,UAC3B;AACA,gBAAM,aAAa,MAAM;AAAA,QAC3B;AACA;AAAA,MACF,KAAK;AACH,YACE,MAAM,SAAS,cACf,OAAO,MAAM,iBAAiB,UAC9B;AACA,gBAAM,eAAe,MAAM;AAAA,QAC7B;AACA;AAAA,IACJ;AAAA,EACF;AAEA,WAAS,uBAAuB,QAAuC;AACrE,UAAM,QAAQ,OAAO;AACrB,QAAI,OAAO,UAAU,SAAU;AAE/B,UAAM,QAAQ,OAAO,IAAI,KAAK;AAC9B,QAAI,CAAC,SAAS,UAAU,IAAI,KAAK,EAAG;AAEpC,cAAU,IAAI,KAAK;AAEnB,YAAQ,MAAM,MAAM;AAAA,MAClB,KAAK;AACH,gBAAQ,KAAK,EAAE,MAAM,QAAQ,MAAM,MAAM,KAAK,CAAC;AAC/C;AAAA,MACF,KAAK,YAAY;AACf,cAAM,gBAAqC;AAAA,UACzC,MAAM;AAAA,UACN,UAAU,MAAM;AAAA,QAClB;AACA,YAAI,MAAM,WAAW;AACnB,UAAC,cAAyC,YACxC,MAAM;AAAA,QACV;AACA,gBAAQ,KAAK,aAAa;AAC1B;AAAA,MACF;AAAA,MACA,KAAK,YAAY;AACf,YAAI,QAAiB,CAAC;AACtB,YAAI,MAAM,aAAa;AACrB,cAAI;AACF,oBAAQ,KAAK,MAAM,MAAM,WAAW;AAAA,UACtC,QAAQ;AAEN,oBAAQ,MAAM;AAAA,UAChB;AAAA,QACF;AACA,gBAAQ,KAAK;AAAA,UACX,MAAM;AAAA,UACN,IAAI,MAAM;AAAA,UACV,MAAM,MAAM;AAAA,UACZ;AAAA,QACF,CAAC;AACD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,WAAS,mBAAmB,QAAuC;AACjE,UAAM,QAAQ,OAAO;AACrB,QAAI,SAAS,OAAO,MAAM,gBAAgB,UAAU;AAClD,mBAAa,MAAM;AAAA,IACrB;AAGA,UAAM,aAAa,OAAO;AAC1B,QAAI,YAAY;AACd,UAAI,OAAO,WAAW,kBAAkB,UAAU;AAChD,cAAM,eAAe,WAAW;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AAEA,WAAS,cAA+B;AAGtC,eAAW,CAAC,OAAO,KAAK,KAAK,QAAQ;AACnC,UAAI,CAAC,UAAU,IAAI,KAAK,GAAG;AACzB,kBAAU,IAAI,KAAK;AACnB,gBAAQ,MAAM,MAAM;AAAA,UAClB,KAAK;AACH,oBAAQ,KAAK,EAAE,MAAM,QAAQ,MAAM,MAAM,KAAK,CAAC;AAC/C;AAAA,UACF,KAAK;AACH,oBAAQ,KAAK;AAAA,cACX,MAAM;AAAA,cACN,UAAU,MAAM;AAAA,cAChB,GAAI,MAAM,YAAY,EAAE,WAAW,MAAM,UAAU,IAAI,CAAC;AAAA,YAC1D,CAAC;AACD;AAAA,UACF,KAAK,YAAY;AACf,gBAAI,QAAiB,CAAC;AACtB,gBAAI,MAAM,aAAa;AACrB,kBAAI;AACF,wBAAQ,KAAK,MAAM,MAAM,WAAW;AAAA,cACtC,QAAQ;AACN,wBAAQ,MAAM;AAAA,cAChB;AAAA,YACF;AACA,oBAAQ,KAAK;AAAA,cACX,MAAM;AAAA,cACN,IAAI,MAAM;AAAA,cACV,MAAM,MAAM;AAAA,cACZ;AAAA,YACF,CAAC;AACD;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,EAAE,GAAG,MAAM;AAAA,IACpB;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,QAAQ,MAAM;AAAA,EAChB;AACF;AAoDO,SAAS,qBACd,IACA,OACA,MACA,OACQ;AACR,QAAM,SAAmB,CAAC;AAG1B,SAAO;AAAA,IACL;AAAA,MACE;AAAA,MACA,KAAK,UAAU;AAAA,QACb,MAAM;AAAA,QACN,SAAS;AAAA,UACP;AAAA,UACA,MAAM;AAAA,UACN,MAAM;AAAA,UACN,SAAS,CAAC;AAAA,UACV;AAAA,UACA,aAAa;AAAA,UACb,eAAe;AAAA,UACf,OAAO;AAAA,YACL,cAAc,MAAM;AAAA,YACpB,eAAe;AAAA,UACjB;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAGA,SAAO;AAAA,IACL;AAAA,MACE;AAAA,MACA,KAAK,UAAU;AAAA,QACb,MAAM;AAAA,QACN,OAAO;AAAA,QACP,eAAe,EAAE,MAAM,QAAQ,MAAM,GAAG;AAAA,MAC1C,CAAC;AAAA,IACH;AAAA,EACF;AAGA,SAAO;AAAA,IACL;AAAA,MACE;AAAA,MACA,KAAK,UAAU;AAAA,QACb,MAAM;AAAA,QACN,OAAO;AAAA,QACP,OAAO,EAAE,MAAM,cAAc,KAAK;AAAA,MACpC,CAAC;AAAA,IACH;AAAA,EACF;AAGA,SAAO;AAAA,IACL;AAAA,MACE;AAAA,MACA,KAAK,UAAU;AAAA,QACb,MAAM;AAAA,QACN,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF;AAGA,SAAO;AAAA,IACL;AAAA,MACE;AAAA,MACA,KAAK,UAAU;AAAA,QACb,MAAM;AAAA,QACN,OAAO,EAAE,aAAa,YAAY,eAAe,KAAK;AAAA,QACtD,OAAO,EAAE,eAAe,MAAM,aAAa;AAAA,MAC7C,CAAC;AAAA,IACH;AAAA,EACF;AAGA,SAAO;AAAA,IACL;AAAA,MACE;AAAA,MACA,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAAA,IACzC;AAAA,EACF;AAEA,SAAO,OAAO,KAAK,EAAE;AACvB;AAyCO,SAAS,6BACd,iBAAiB,UACO;AAExB,QAAM,QAAQ,wBAAwB;AAGtC,QAAM,oBAAoB,oBAAI,IAAY;AAE1C,QAAM,mBAAmB,oBAAI,IAAY;AAEzC,MAAI,kBAAkB;AAEtB,MAAI,uBAAuB;AAE3B,MAAI,eAAe;AAEnB,MAAI,WAAW;AAEf,MAAI,iBAAiB;AAErB,WAAS,aAAa,WAAmB,MAAsB;AAE7D,UAAM,aAAa,WAAW,IAAI;AAGlC,QAAI;AACJ,QAAI;AACF,eAAS,KAAK,MAAM,IAAI;AAAA,IAC1B,QAAQ;AAEN,aAAO,eAAe,WAAW,IAAI;AAAA,IACvC;AAEA,YAAQ,WAAW;AAAA,MACjB,KAAK,uBAAuB;AAC1B,cAAM,QAAQ,OAAO;AACrB,YAAI,OAAO,UAAU,SAAU;AAE/B,cAAM,QAAQ,OAAO;AACrB,YACE,OAAO,SAAS,cAChB,MAAM,SAAS,gBACf;AAEA,4BAAkB,IAAI,KAAK;AAC3B;AACA,2BAAiB;AACjB,cAAI,uBAAuB,EAAG,wBAAuB;AACrD,iBAAO;AAAA,QACT;AAEA,YAAI,OAAO,SAAS,YAAY;AAC9B,2BAAiB,IAAI,KAAK;AAAA,QAC5B;AAEA;AAEA,YAAI,kBAAkB,GAAG;AACvB,gBAAM,WAAW,EAAE,GAAG,QAAQ,OAAO,QAAQ,gBAAgB;AAC7D,iBAAO,eAAe,WAAW,KAAK,UAAU,QAAQ,CAAC;AAAA,QAC3D;AACA;AAAA,MACF;AAAA,MAEA,KAAK;AAAA,MACL,KAAK,sBAAsB;AACzB,cAAM,QAAQ,OAAO;AACrB,YAAI,OAAO,UAAU,YAAY,kBAAkB,IAAI,KAAK,GAAG;AAC7D,iBAAO;AAAA,QACT;AAEA,YAAI,kBAAkB,KAAK,OAAQ,OAAO,UAAW,UAAU;AAC7D,gBAAM,WAAW;AAAA,YACf,GAAG;AAAA,YACH,OAAQ,OAAO,QAAmB;AAAA,UACpC;AACA,iBAAO,eAAe,WAAW,KAAK,UAAU,QAAQ,CAAC;AAAA,QAC3D;AACA;AAAA,MACF;AAAA,MAEA,KAAK;AAAA,MACL,KAAK,gBAAgB;AACnB,YAAI,gBAAgB;AAElB,sBAAY,eAAe,WAAW,IAAI;AAC1C,iBAAO;AAAA,QACT;AACA;AAAA,MACF;AAAA,IAGF;AAEA,WAAO,eAAe,WAAW,IAAI;AAAA,EACvC;AAEA,SAAO;AAAA,IACL;AAAA,IACA,aAAa,MAAM,MAAM,YAAY;AAAA,IACrC,QAAQ,MAAM,MAAM,OAAO;AAAA,IAC3B,WAAW,MAAM;AAAA,IACjB,eAAe,MAAM,iBAAiB,OAAO;AAAA,IAC7C,kBAAkB,MAAM;AAAA,IACxB,kBAAkB,MAAM;AAAA,IACxB,gBAAgB,MAAM;AAAA,EACxB;AACF;AAOA,eAAsB,sBACpB,UAC0B;AAC1B,QAAM,cAAc,wBAAwB;AAC5C,QAAM,OAAO,MAAM,SAAS,KAAK;AAEjC,aAAW,SAAS,KAAK,MAAM,MAAM,GAAG;AACtC,QAAI,CAAC,MAAM,KAAK,EAAG;AACnB,QAAI,YAAY;AAChB,UAAM,YAAsB,CAAC;AAC7B,eAAW,QAAQ,MAAM,MAAM,IAAI,GAAG;AACpC,UAAI,KAAK,WAAW,QAAQ,GAAG;AAC7B,oBAAY,KAAK,MAAM,CAAC,EAAE,KAAK;AAAA,MACjC,WAAW,KAAK,WAAW,OAAO,GAAG;AACnC,kBAAU,KAAK,KAAK,MAAM,CAAC,EAAE,UAAU,CAAC;AAAA,MAC1C;AAAA,IACF;AACA,QAAI,UAAU,SAAS,GAAG;AACxB,kBAAY,aAAa,WAAW,UAAU,KAAK,IAAI,CAAC;AAAA,IAC1D;AAAA,EACF;AAEA,SAAO,YAAY,YAAY;AACjC;;;ACrrBA;AAAA,EACE;AAAA,EACA,UAAUA;AAAA,EACV;AAAA,EACA;AAAA,EACA,YAAAC;AAAA,EACA,OAAAC;AAAA,EACA,gBAAAC;AAAA,EACA,WAAAC;AAAA,EACA,OAAAC;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,OACK;;;ACdP,IAAM,kBACJ;AACF,IAAM,OAAO;AAUN,SAAS,aAAa,OAAmB,YAAY,GAAW;AACrE,MAAI,IAAI;AACR,aAAW,KAAK,OAAO;AACrB,QAAK,KAAK,KAAM,OAAO,CAAC;AAAA,EAC1B;AAEA,MAAI,MAAM,GAAI,QAAO,gBAAgB,CAAC,EAAE,OAAO,KAAK,IAAI,GAAG,SAAS,CAAC;AAErE,QAAM,QAAkB,CAAC;AACzB,SAAO,IAAI,IAAI;AACb,UAAM,KAAK,gBAAgB,OAAO,IAAI,IAAI,CAAC,CAAC;AAC5C,SAAK;AAAA,EACP;AAEA,QAAM,QAAQ;AAGd,SAAO,MAAM,SAAS,WAAW;AAC/B,UAAM,QAAQ,gBAAgB,CAAC,CAAC;AAAA,EAClC;AAEA,SAAO,MAAM,KAAK,EAAE;AACtB;AAOA,IAAM,wBAAwB;AASvB,SAAS,oBAA4B;AAC1C,QAAM,MAAM,IAAI,WAAW,EAAE;AAC7B,SAAO,gBAAgB,IAAI,SAAS,GAAG,CAAC,CAAC;AAEzC,QAAM,KAAK,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACvC,QAAM,OAAO,IAAI,SAAS,IAAI,QAAQ,IAAI,YAAY,IAAI,UAAU;AACpE,OAAK,UAAU,GAAG,OAAO,GAAG,KAAK;AAEjC,SAAO,aAAa,KAAK,qBAAqB;AAChD;AAgCA,SAAS,iBAAiB,SAA4B;AACpD,MAAI,OAAO,YAAY,SAAU,QAAO,CAAC,OAAO;AAEhD,MAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,UAAM,QAAkB,CAAC;AACzB,eAAW,SAAS,SAAS;AAC3B,UACE,SACA,OAAO,UAAU,YACjB,UAAU,SACV,MAAM,SAAS,UACf,UAAU,SACV,OAAO,MAAM,SAAS,UACtB;AACA,cAAM,KAAK,MAAM,IAAI;AAAA,MACvB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,SAAO,CAAC;AACV;AAiCA,eAAsB,oBACpB,UACA,QACiB;AACjB,MAAI,mBAAmB;AACvB,aAAW,OAAO,UAAU;AAC1B,QAAI,IAAI,SAAS,QAAQ;AACvB,YAAM,QAAQ,iBAAiB,IAAI,OAAO;AAC1C,yBAAmB,MAAM,KAAK,EAAE;AAChC;AAAA,IACF;AAAA,EACF;AAEA,QAAM,WACJ,oBAAoB,QAAQ,SAAS,OAAO,QAAQ,cAAc;AACpE,QAAM,UAAU,IAAI,YAAY,EAAE,OAAO,QAAQ;AACjD,QAAM,OAAO,MAAM,OAAO,OAAO,OAAO,WAAW,OAAO;AAC1D,QAAM,QAAQ,IAAI,WAAW,IAAI;AAGjC,MAAI,MAAM;AACV,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,WAAO,MAAM,CAAC,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AAAA,EAC9C;AACA,SAAO;AACT;AAaO,IAAM,oCAAoC;;;ACzL1C,IAAM,6BAA6B;AAAA,EACxC;AACF;AAGO,IAAM,2BAA2B;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AACF;AAOO,IAAM,+BAA+B;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGA,IAAM,+BAA+B;AAUrC,SAAS,aAAa,KAA6B;AACjD,WAAS,IAAI,IAAI,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;AACjD,UAAM,MAAM,IAAI,SAAS,CAAC;AAC1B,QAAI,IAAI,SAAS,QAAQ;AACvB,aAAO,IAAI,QACR,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM,EAC/B,IAAI,CAAC,MAAO,EAAqC,IAAI,EACrD,KAAK,IAAI;AAAA,IACd;AAAA,EACF;AACA,SAAO;AACT;AAGA,SAAS,eAAe,MAAsB;AAC5C,SAAO,KAAK,KAAK,KAAK,SAAS,CAAC;AAClC;AAeO,SAAS,oBAAoB,KAA8B;AAEhE,QAAM,cAAc,IAAI,OAAO,YAAY;AAC3C,aAAW,WAAW,4BAA4B;AAChD,QAAI,YAAY,SAAS,QAAQ,YAAY,CAAC,EAAG,QAAO;AAAA,EAC1D;AAEA,QAAM,WAAW,aAAa,GAAG;AAGjC,MAAI,IAAI,MAAM,WAAW,KAAK,UAAU;AACtC,eAAW,WAAW,0BAA0B;AAC9C,UAAI,SAAS,SAAS,OAAO,EAAG,QAAO;AAAA,IACzC;AAAA,EACF;AAGA,MAAI,SAAS,SAAS,YAAY,GAAG;AACnC,QAAI,UAAU;AACd,eAAW,WAAW,8BAA8B;AAClD,UAAI,SAAS,SAAS,OAAO,EAAG;AAAA,IAClC;AACA,QAAI,WAAW,6BAA8B,QAAO;AAAA,EACtD;AAEA,SAAO;AACT;AAOA,IAAM,sBACJ;AAMK,SAAS,uBACd,KACoB;AACpB,QAAM,WAAW,aAAa,GAAG;AACjC,QAAM,QAAQ,oBAAoB,KAAK,QAAQ;AAC/C,SAAO,QAAQ,CAAC,KAAK;AACvB;AAOA,IAAM,kCAAkC;AAGxC,IAAM,0BAA0B;AAGhC,IAAM,6BAA6B;AAY5B,SAAS,wBAAwB,KAA8B;AAEpE,MAAI,oBAAoB,GAAG,EAAG,QAAO;AAErC,SACE,IAAI,MAAM,UAAU,2BACpB,IAAI,SAAS,UAAU,8BACvB,IAAI,OAAO,SAAS;AAExB;AAWO,SAAS,wBACd,YACA,SACA,OACiB;AACjB,SAAO;AAAA,IACL,IAAI,oBAAoB,OAAO,WAAW,EAAE,MAAM,GAAG,CAAC,CAAC;AAAA,IACvD;AAAA,IACA,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,QAAQ,CAAC;AAAA,IACzC,YAAY;AAAA,IACZ,OAAO;AAAA,MACL,aAAa;AAAA,MACb,cAAc,eAAe,OAAO;AAAA,IACtC;AAAA,EACF;AACF;;;ACvLA,SAAS,YAAY,kBAAkB;AACvC,SAAS,kBAAkB;AAyB3B,SAAS,gBAAgB,MAAc,OAAe,SAAwC;AAC5F,QAAM,IAAI,WAAW,QAAQ;AAC7B,IAAE,OAAO,GAAG,IAAI,IAAI,KAAK,GAAG;AAC5B,aAAW,SAAS,SAAS;AAC3B,YAAQ,MAAM,MAAM;AAAA,MAClB,KAAK;AACH,UAAE,OAAO,QAAQ,MAAM,IAAI,EAAE;AAC7B;AAAA,MACF,KAAK;AACH,UAAE,OAAO,YAAY,MAAM,QAAQ,EAAE;AACrC;AAAA,MACF,KAAK;AACH,UAAE,OAAO,YAAY,MAAM,EAAE,IAAI,MAAM,IAAI,IAAI,KAAK,UAAU,MAAM,KAAK,CAAC,EAAE;AAC5E;AAAA,MACF,KAAK;AACH,UAAE,OAAO,eAAe,MAAM,SAAS,IAAI,MAAM,OAAO,EAAE;AAC1D;AAAA,IACJ;AAAA,EACF;AACA,SAAO,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AACpC;AAMA,SAAS,oBAAoB,WAAmB,WAA2B;AACzE,QAAM,IAAI,WAAW,QAAQ;AAC7B,IAAE,OAAO,GAAG,SAAS,SAAS,SAAS,EAAE;AACzC,SAAO,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AACpC;AAMA,SAAS,mBACP,OACA,WACA,WACA,WACU;AACV,QAAM,MAAM,KAAK,IAAI;AACrB,QAAM,KAAK,oBAAoB,WAAW,SAAS;AACnD,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA,MAAM;AAAA,QACN,MAAM,MAAM;AAAA,QACZ,MAAM,EAAE,OAAO,KAAK,KAAK,IAAI;AAAA,MAC/B;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA,MAAM;AAAA,QACN,MAAM,MAAM;AAAA,MACd;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA,MAAM;AAAA,QACN,MAAM,MAAM;AAAA,QACZ,QAAQ,MAAM;AAAA,QACd,OAAO,EAAE,QAAQ,WAAW,OAAO,MAAM,MAAM;AAAA,MACjD;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA,MAAM;AAAA,QACN,MAAM;AAAA,QACN,QAAQ,MAAM;AAAA,QACd,OAAO;AAAA,UACL,QAAQ;AAAA,UACR,OAAO;AAAA,UACP,QAAQ,MAAM;AAAA,UACd,MAAM,EAAE,OAAO,KAAK,KAAK,IAAI;AAAA,QAC/B;AAAA,MACF;AAAA,EACJ;AACF;AAcO,SAAS,sBACd,UACA,WACwB;AACxB,QAAM,MAA8B,CAAC;AACrC,QAAM,MAAM,KAAK,IAAI;AAErB,WAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,UAAM,IAAI,SAAS,CAAC;AACpB,UAAM,KAAK,gBAAgB,EAAE,MAAM,GAAG,EAAE,OAAO;AAC/C,UAAM,QAAoB,EAAE,QAAQ;AAAA,MAAI,CAAC,OAAO,OAC9C,mBAAmB,OAAO,WAAW,IAAI,EAAE;AAAA,IAC7C;AAEA,QAAI,EAAE,SAAS,QAAQ;AACrB,YAAM,OAAwB;AAAA,QAC5B;AAAA,QACA;AAAA,QACA,MAAM;AAAA,QACN,MAAM,EAAE,SAAS,IAAI;AAAA,QACrB,OAAO;AAAA,QACP,OAAO,EAAE,YAAY,aAAa,SAAS,UAAU;AAAA,MACvD;AACA,UAAI,KAAK,EAAE,MAAM,MAAM,CAAC;AAAA,IAC1B,OAAO;AACL,YAAM,OAA6B;AAAA,QACjC;AAAA,QACA;AAAA,QACA,MAAM;AAAA,QACN,MAAM,EAAE,SAAS,IAAI;AAAA,QACrB,UAAU;AAAA,QACV,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,MAAM;AAAA,QACN,MAAM,EAAE,KAAK,IAAI,MAAM,GAAG;AAAA,QAC1B,MAAM;AAAA,QACN,QAAQ;AAAA,UACN,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,WAAW;AAAA,UACX,OAAO,EAAE,MAAM,GAAG,OAAO,EAAE;AAAA,QAC7B;AAAA,MACF;AACA,UAAI,KAAK,EAAE,MAAM,MAAM,CAAC;AAAA,IAC1B;AAAA,EACF;AAEA,SAAO;AACT;AAUO,SAAS,6BACd,KACA,OACA,OACM;AACN,QAAM,OAAO,IAAI;AACjB,MAAI,KAAK,SAAS,YAAa;AAE/B,OAAK,OAAO,QAAQ,MAAM;AAC1B,OAAK,OAAO,SAAS,MAAM;AAC3B,OAAK,OAAO,MAAM,OAAO,MAAM,wBAAwB;AACvD,OAAK,OAAO,MAAM,QAAQ,MAAM,4BAA4B;AAC5D,OAAK,UAAU;AACjB;AAsBO,SAAS,mBAAmB,UAAwC;AAEzE,QAAM,kBAAkB,oBAAI,IAG1B;AAEF,aAAW,OAAO,UAAU;AAC1B,eAAW,QAAQ,IAAI,OAAO;AAC5B,UACE,WAAW,IAAI,KACf,KAAK,SAAS,YACd,KAAK,MAAM,WAAW,aACtB;AACA,wBAAgB,IAAI,KAAK,QAAQ;AAAA,UAC/B,QAAQ,KAAK,MAAM;AAAA,UACnB,SAAS;AAAA,QACX,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAGA,QAAM,MAAM,KAAK,IAAI;AACrB,aAAW,OAAO,UAAU;AAC1B,eAAW,QAAQ,IAAI,OAAO;AAC5B,UACE,WAAW,IAAI,KACf,KAAK,SAAS,YACd,KAAK,MAAM,WAAW,WACtB;AACA,cAAM,SAAS,gBAAgB,IAAI,KAAK,MAAM;AAC9C,YAAI,QAAQ;AACV,eAAK,QAAQ;AAAA,YACX,QAAQ;AAAA,YACR,OAAO,KAAK,MAAM;AAAA,YAClB,QAAQ,OAAO;AAAA,YACf,MAAM,EAAE,OAAO,KAAK,KAAK,IAAI;AAAA,UAC/B;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAQA,aAAW,OAAO,UAAU;AAC1B,QAAI,IAAI,KAAK,SAAS,OAAQ;AAC9B,UAAM,SAAS,IAAI,MAAM;AACzB,QAAI,QAAQ,IAAI,MAAM;AAAA,MACpB,CAAC,MAAM,EAAE,WAAW,CAAC,KAAK,EAAE,SAAS;AAAA,IACvC;AAGA,QAAI,IAAI,MAAM,WAAW,KAAK,SAAS,GAAG;AACxC,UAAI,QAAQ;AAAA,QACV;AAAA,UACE,IAAI,WAAW;AAAA,UACf,WAAW;AAAA,UACX,WAAW,IAAI,KAAK;AAAA,UACpB,MAAM;AAAA,UACN,MAAM;AAAA,UACN,MAAM,EAAE,OAAO,GAAG,KAAK,EAAE;AAAA,QAC3B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;AC3SA,SAAS,WAAW;AASb,IAAM,oBAAoB,oBAAI,IAAY;AAa1C,SAAS,uBACd,aACA,SACA,cACW;AACX,SAAO;AAAA,IACL,MAAM,OAAO,QAAQ,MAAM,MAAM;AAC/B,YAAM,OAAO,QAAQ,MAAM,SAAS;AACpC,UAAI,CAAC,MAAM;AACT,YAAI,KAAK,+CAA+C;AACxD,eAAO;AAAA,MACT;AAEA,YAAM,QAAQ,MAAM,SAAS;AAC7B,YAAM,MAAM,GAAG,YAAY,QAAQ,OAAO,EAAE,CAAC;AAG7C,YAAM,SAAS,aAAa,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAChF,wBAAkB,IAAI,MAAM;AAE5B,UAAI;AAOF,cAAM,gBAAgB,SAClB;AAAA,UACE;AAAA,YACE,MAAM;AAAA,YACN,MAAM;AAAA,YACN,eAAe,EAAE,MAAM,aAAa,KAAK,KAAK;AAAA,UAChD;AAAA,QACF,IACA;AAEJ,cAAM,WAAW,MAAM,MAAM,KAAK;AAAA,UAChC,QAAQ;AAAA,UACR,SAAS;AAAA,YACP,gBAAgB;AAAA,YAChB,qBAAqB;AAAA,YACrB,GAAG,YAAY,IAAI;AAAA,UACrB;AAAA;AAAA;AAAA;AAAA,UAIA,MAAM,KAAK,UAAU;AAAA,YACnB,OAAO,MAAM;AAAA,YACb,YAAY;AAAA,YACZ,QAAQ,iBAAiB;AAAA,YACzB,UAAU,CAAC,EAAE,MAAM,QAAQ,SAAS,KAAK,CAAC;AAAA,UAC5C,CAAC;AAAA,QACH,CAAC;AAED,YAAI,CAAC,SAAS,IAAI;AAChB,gBAAM,OAAO,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,WAAW;AAC1D,cAAI;AAAA,YACF,mCAAmC,SAAS,MAAM,IAAI,SAAS,UAAU,WAAM,IAAI;AAAA,UACrF;AACA,iBAAO;AAAA,QACT;AAEA,cAAM,OAAQ,MAAM,SAAS,KAAK;AAIlC,cAAM,YAAY,KAAK,SAAS;AAAA,UAC9B,CAAC,MAAM,EAAE,SAAS,UAAU,OAAO,EAAE,SAAS;AAAA,QAChD;AAEA,eAAO,WAAW,QAAQ;AAAA,MAC5B,SAAS,GAAG;AACV,YAAI,MAAM,yBAAyB,CAAC;AACpC,eAAO;AAAA,MACT,UAAE;AACA,0BAAkB,OAAO,MAAM;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AACF;;;ACzFA,SAAS,OAAAC,YAAW;AAwDpB,IAAM,4BAA4B;AAClC,IAAM,yBAAyB;AAC/B,IAAM,2BAA2B;AACjC,IAAM,2BAA2B;AAMjC,IAAI,YAAY;AAGhB,SAAS,mBAA2B;AAClC,QAAM,KAAK,KAAK,IAAI,EAAE,SAAS,EAAE;AACjC,QAAM,OAAO,aAAa,SAAS,EAAE;AACrC,QAAM,OAAO,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC;AAClD,SAAO,QAAQ,EAAE,IAAI,GAAG,IAAI,IAAI;AAClC;AAGA,SAAS,QAAQ,MAA8B;AAC7C,SAAO,GAAG,KAAK,MAAM,IAAI,KAAK,KAAK;AACrC;AAqBO,SAAS,qBACd,OACA,aACA,SACA,cACA,aACwE;AACxE,QAAM,kBAAkB,aAAa,mBAAmB;AACxD,QAAM,eAAe,aAAa,gBAAgB;AAClD,QAAM,iBAAiB,aAAa,kBAAkB;AACtD,QAAM,gBAAgB,aAAa,iBAAiB;AAGpD,QAAM,QAA0B,CAAC;AACjC,QAAM,WAAW,oBAAI,IAA2B;AAChD,MAAI,aAAoD;AACxD,MAAI,eAAe;AAGnB,MAAI,cAAc;AAClB,MAAI,eAAe;AACnB,MAAI,cAAc;AAClB,MAAI,gBAAgB;AACpB,MAAI,gBAAgB;AACpB,MAAI,cAAc;AAMlB,iBAAe,YAAY,MAAsB,OAAwC;AACvF,UAAM,WAAW,MAAM,IAAI,CAAC,UAAU;AAAA,MACpC,WAAW,KAAK;AAAA,MAChB,QAAQ,KAAK;AAAA,IACf,EAAE;AAEF,IAAAC,KAAI,KAAK,2BAA2B,MAAM,MAAM,WAAW;AAE3D,QAAI;AACF,YAAM,MAAM,GAAG,YAAY,QAAQ,OAAO,EAAE,CAAC;AAC7C,YAAM,WAAW,MAAM,MAAM,KAAK;AAAA,QAChC,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,qBAAqB;AAAA,UACrB,GAAG,YAAY,IAAI;AAAA,QACrB;AAAA,QACA,MAAM,KAAK,UAAU,EAAE,SAAS,CAAC;AAAA,MACnC,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,OAAO,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,WAAW;AAC1D,QAAAA,KAAI,MAAM,wBAAwB,SAAS,MAAM,IAAI,SAAS,UAAU,WAAM,IAAI,EAAE;AAEpF,cAAM,YAAY,KAAK;AACvB;AAAA,MACF;AAEA,YAAM,OAAQ,MAAM,SAAS,KAAK;AAKlC,sBAAgB,MAAM;AAGtB,YAAM,aAAa,oBAAI,IAA4B;AACnD,iBAAW,QAAQ,OAAO;AACxB,mBAAW,IAAI,KAAK,UAAU,IAAI;AAAA,MACpC;AAEA,YAAM,YAAY;AAAA,QAChB,MAAM,UAAU,KAAK,EAAE,EAAE,MAAM,CAAC,MAAMA,KAAI,MAAM,qBAAqB,CAAC,CAAC;AAAA,QACvE;AAAA,MACF;AAEA,eAAS,IAAI,KAAK,IAAI;AAAA,QACpB,SAAS,KAAK;AAAA,QACd,UAAU;AAAA,QACV,aAAa,KAAK,IAAI;AAAA,QACtB;AAAA,QACA;AAAA,MACF,CAAC;AAED,MAAAA,KAAI,KAAK,kBAAkB,KAAK,EAAE,SAAS,MAAM,MAAM,WAAW;AAAA,IACpE,SAAS,GAAG;AACV,MAAAA,KAAI,MAAM,uBAAuB,CAAC;AAClC,YAAM,YAAY,KAAK;AAAA,IACzB;AAAA,EACF;AAMA,iBAAe,QAAuB;AACpC,QAAI,MAAM,WAAW,EAAG;AAGxB,UAAM,QAAQ,MAAM,OAAO,CAAC;AAG5B,UAAM,SAAS,oBAAI,IAA+D;AAClF,eAAW,QAAQ,OAAO;AACxB,YAAM,MAAM,QAAQ,KAAK,IAAI;AAC7B,UAAI,QAAQ,OAAO,IAAI,GAAG;AAC1B,UAAI,CAAC,OAAO;AACV,gBAAQ,EAAE,MAAM,KAAK,MAAM,OAAO,CAAC,EAAE;AACrC,eAAO,IAAI,KAAK,KAAK;AAAA,MACvB;AACA,YAAM,MAAM,KAAK,IAAI;AAAA,IACvB;AAEA,eAAW,EAAE,MAAM,MAAM,KAAK,OAAO,OAAO,GAAG;AAC7C,YAAM,YAAY,MAAM,KAAK;AAAA,IAC/B;AAAA,EACF;AAMA,iBAAe,UAAU,SAAgC;AACvD,UAAM,QAAQ,SAAS,IAAI,OAAO;AAClC,QAAI,CAAC,MAAO;AAGZ,QAAI,KAAK,IAAI,IAAI,MAAM,cAAc,eAAe;AAClD,MAAAA,KAAI,KAAK,SAAS,OAAO,sDAAiD;AAC1E,oBAAc,MAAM,SAAS;AAC7B,eAAS,OAAO,OAAO;AACvB,YAAM,YAAY,CAAC,GAAG,MAAM,SAAS,OAAO,CAAC,CAAC;AAC9C;AAAA,IACF;AAEA,QAAI;AACF,YAAM,MAAM,GAAG,YAAY,QAAQ,OAAO,EAAE,CAAC,wBAAwB,OAAO;AAC5E,YAAM,WAAW,MAAM,MAAM,KAAK;AAAA,QAChC,SAAS;AAAA,UACP,qBAAqB;AAAA,UACrB,GAAG,YAAY,MAAM,IAAI;AAAA,QAC3B;AAAA,MACF,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,QAAAA,KAAI,MAAM,yBAAyB,OAAO,KAAK,SAAS,MAAM,EAAE;AAChE;AAAA,MACF;AAEA,YAAM,OAAQ,MAAM,SAAS,KAAK;AAKlC,UAAI,KAAK,sBAAsB,QAAS;AAGxC,MAAAA,KAAI,KAAK,SAAS,OAAO,kCAA6B;AAEtD,UAAI,KAAK,aAAa;AACpB,cAAM,gBAAgB,SAAS,KAAK,WAAW;AAAA,MACjD,OAAO;AAEL,cAAM;AAAA,UACJ;AAAA,UACA,GAAG,YAAY,QAAQ,OAAO,EAAE,CAAC,wBAAwB,OAAO;AAAA,QAClE;AAAA,MACF;AAAA,IACF,SAAS,GAAG;AACV,MAAAA,KAAI,MAAM,wBAAwB,OAAO,KAAK,CAAC;AAAA,IACjD;AAAA,EACF;AAEA,iBAAe,gBAAgB,SAAiB,YAAmC;AACjF,UAAM,QAAQ,SAAS,IAAI,OAAO;AAClC,QAAI,CAAC,MAAO;AAEZ,QAAI;AACF,YAAM,WAAW,MAAM,MAAM,YAAY;AAAA,QACvC,SAAS;AAAA,UACP,qBAAqB;AAAA,UACrB,GAAG,YAAY,MAAM,IAAI;AAAA,QAC3B;AAAA,MACF,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,QAAAA,KAAI,MAAM,kCAAkC,OAAO,KAAK,SAAS,MAAM,EAAE;AACzE;AAAA,MACF;AAEA,YAAM,OAAO,MAAM,SAAS,KAAK;AAEjC,YAAM,QAAQ,KAAK,MAAM,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC;AAErD,iBAAW,QAAQ,OAAO;AACxB,YAAI;AACF,gBAAM,SAAS,KAAK,MAAM,IAAI;AAW9B,gBAAM,UAAU,MAAM,SAAS,IAAI,OAAO,SAAS;AACnD,cAAI,CAAC,QAAS;AAEd,kBAAQ,OAAO,OAAO,MAAM;AAAA,YAC1B,KAAK,aAAa;AAChB,oBAAM,YAAY,OAAO,OAAO,SAAS,SAAS;AAAA,gBAChD,CAAC,MAAM,EAAE,SAAS,UAAU,OAAO,EAAE,SAAS;AAAA,cAChD;AACA,sBAAQ,QAAQ,WAAW,QAAQ,IAAI;AACvC;AACA;AAAA,YACF;AAAA,YACA,KAAK;AACH,sBAAQ,QAAQ,IAAI;AACpB;AACA,cAAAA,KAAI;AAAA,gBACF,cAAc,OAAO,SAAS,aAAa,OAAO,OAAO,OAAO,QAAQ,SAAS,WAAM,OAAO,OAAO,OAAO,WAAW,KAAK,UAAU,OAAO,OAAO,KAAK,CAAC;AAAA,cAC5J;AACA;AAAA,YACF,KAAK;AAAA,YACL,KAAK;AACH,sBAAQ,QAAQ,IAAI;AACpB;AACA,cAAAA,KAAI,KAAK,cAAc,OAAO,SAAS,IAAI,OAAO,OAAO,IAAI,EAAE;AAC/D;AAAA,UACJ;AAEA,gBAAM,SAAS,OAAO,OAAO,SAAS;AAAA,QACxC,QAAQ;AACN,UAAAA,KAAI,MAAM,sCAAsC,KAAK,MAAM,GAAG,GAAG,CAAC,EAAE;AAAA,QACtE;AAAA,MACF;AAGA,iBAAW,CAAC,EAAE,OAAO,KAAK,MAAM,UAAU;AACxC,gBAAQ,QAAQ,IAAI;AACpB;AAAA,MACF;AAGA,oBAAc,MAAM,SAAS;AAC7B,eAAS,OAAO,OAAO;AACvB,MAAAA,KAAI;AAAA,QACF,SAAS,OAAO,oBAAoB,aAAa,QAAQ,WAAW;AAAA,MACtE;AAAA,IACF,SAAS,GAAG;AACV,MAAAA,KAAI,MAAM,qCAAqC,OAAO,KAAK,CAAC;AAAA,IAC9D;AAAA,EACF;AAMA,iBAAe,YAAY,OAAwC;AACjE,qBAAiB,MAAM;AACvB,IAAAA,KAAI,KAAK,8BAA8B,MAAM,MAAM,sBAAsB;AAGzE,UAAM,cAAc;AACpB,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,aAAa;AAClD,YAAM,QAAQ,MAAM,MAAM,GAAG,IAAI,WAAW;AAC5C,YAAM,QAAQ;AAAA,QACZ,MAAM,IAAI,OAAO,SAAS;AACxB,cAAI;AACF,kBAAM,SACJ,OAAO,KAAK,OAAO,WAAW,WAC1B,KAAK,OAAO,SACZ,KAAK,OAAO,OACT,IAAI,CAAC,MAAM,EAAE,IAAI,EACjB,KAAK,IAAI;AAClB,kBAAM,OAAO,KAAK,OAAO,SAAS,CAAC,GAAG,WAAW;AACjD,kBAAM,SAAS,MAAM,MAAM,OAAO,QAAQ,MAAM,EAAE,QAAQ,KAAK,CAAC;AAChE,iBAAK,QAAQ,MAAM;AAAA,UACrB,SAAS,GAAG;AACV,YAAAA,KAAI,MAAM,4BAA4B,KAAK,QAAQ,KAAK,CAAC;AACzD,iBAAK,QAAQ,IAAI;AAAA,UACnB;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAMA,eAAa,YAAY,MAAM;AAC7B,UAAM,EAAE,MAAM,CAAC,MAAMA,KAAI,MAAM,4BAA4B,CAAC,CAAC;AAAA,EAC/D,GAAG,eAAe;AAMlB,SAAO;AAAA,IACL,MAAM,OAAO,QAAQ,MAAM,MAAM;AAE/B,UAAI,MAAM,UAAU,cAAc;AAChC;AACA,eAAO,MAAM,OAAO,QAAQ,MAAM,IAAI;AAAA,MACxC;AAKA,YAAM,OAAO,QAAQ,MAAM,SAAS;AACpC,UAAI,CAAC,MAAM;AACT;AACA,eAAO,MAAM,OAAO,QAAQ,MAAM,IAAI;AAAA,MACxC;AAEA;AAEA,YAAM,QAAQ,MAAM,SAAS;AAG7B,YAAM,gBAAgB,SAClB;AAAA,QACE;AAAA,UACE,MAAM;AAAA,UACN,MAAM;AAAA,UACN,eAAe,EAAE,MAAM,aAAsB,KAAK,KAAK;AAAA,QACzD;AAAA,MACF,IACA;AAEJ,YAAM,WAAW,iBAAiB;AAElC,YAAM,UAAU,IAAI,QAAuB,CAAC,SAAS,WAAW;AAC9D,cAAM,KAAK;AAAA,UACT;AAAA,UACA,QAAQ;AAAA,YACN,OAAO,MAAM;AAAA,YACb,YAAY;AAAA,YACZ,QAAQ,iBAAiB;AAAA,YACzB,UAAU,CAAC,EAAE,MAAM,QAAQ,SAAS,KAAK,CAAC;AAAA,UAC5C;AAAA,UACA;AAAA,UACA;AAAA,UACA,YAAY,KAAK,IAAI;AAAA,UACrB,MAAM;AAAA,QACR,CAAC;AAAA,MACH,CAAC;AAGD,UAAI,MAAM,UAAU,cAAc;AAChC,cAAM,EAAE,MAAM,CAAC,MAAMA,KAAI,MAAM,2BAA2B,CAAC,CAAC;AAAA,MAC9D;AAEA,aAAO;AAAA,IACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IASA,MAAM,WAA0B;AAC9B,qBAAe;AACf,UAAI,YAAY;AACd,sBAAc,UAAU;AACxB,qBAAa;AAAA,MACf;AAGA,UAAI,MAAM,SAAS,GAAG;AACpB,QAAAA,KAAI,KAAK,8BAA8B,MAAM,MAAM,gCAAgC;AACnF,cAAM,YAAY,MAAM,OAAO,CAAC,CAAC;AAAA,MACnC;AAGA,iBAAW,CAAC,SAAS,KAAK,KAAK,UAAU;AACvC,sBAAc,MAAM,SAAS;AAE7B,mBAAW,CAAC,EAAE,OAAO,KAAK,MAAM,UAAU;AACxC,kBAAQ,QAAQ,IAAI;AAAA,QACtB;AACA,QAAAA,KAAI,KAAK,4CAA4C,OAAO,EAAE;AAAA,MAChE;AACA,eAAS,MAAM;AAAA,IACjB;AAAA;AAAA,IAGA,QAAoB;AAClB,aAAO;AAAA,QACL,QAAQ,MAAM;AAAA,QACd,iBAAiB,SAAS;AAAA,QAC1B,kBAAkB,CAAC,GAAG,SAAS,OAAO,CAAC,EAAE;AAAA,UACvC,CAAC,KAAK,MAAM,MAAM,EAAE,SAAS;AAAA,UAC7B;AAAA,QACF;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;ACxgBA,SAAS,YAAY;AACrB;AAAA,EACE,YAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAAC;AAAA,EACA,UAAUC;AAAA,EAEV;AAAA,EACA;AAAA,OACK;;;ACRP;AAAA,EACE;AAAA,EACA;AAAA,EACA,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,OAAAC;AAAA,OACK;AAgBP,IAAM,iBAAiB;AAGvB,IAAI,gBAA4C;AAChD,IAAI,kBAAkB;AACtB,IAAM,oBAAoB,KAAK,KAAK;AASpC,IAAM,iBAAuE;AAAA,EAC3E,EAAE,QAAQ,iBAAiB,mBAAmB,KAAK,IAAU;AAAA,EAC7D,EAAE,QAAQ,mBAAmB,mBAAmB,IAAI,IAAU;AAAA,EAC9D,EAAE,QAAQ,kBAAkB,mBAAmB,IAAI,IAAU;AAAA,EAC7D,EAAE,QAAQ,oBAAoB,mBAAmB,MAAM,IAAU;AAAA,EACjE,EAAE,QAAQ,qBAAqB,mBAAmB,IAAI,IAAU;AAAA,EAChE,EAAE,QAAQ,kBAAkB,mBAAmB,OAAO,IAAU;AAAA,EAChE,EAAE,QAAQ,mBAAmB,mBAAmB,IAAI,IAAU;AAAA,EAC9D,EAAE,QAAQ,iBAAiB,mBAAmB,KAAK,IAAU;AAC/D;AAEA,SAAS,aAAa,SAAyB;AAC7C,aAAW,EAAE,QAAQ,kBAAkB,KAAK,gBAAgB;AAC1D,QAAI,QAAQ,WAAW,MAAM,EAAG,QAAO;AAAA,EACzC;AAEA,SAAO,MAAM;AACf;AAqBA,eAAsB,eAA6C;AAEjE,MAAI,iBAAiB,KAAK,IAAI,IAAI,kBAAkB,mBAAmB;AACrE,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,UAAU,WAAW,MAAM,WAAW,MAAM,GAAG,GAAM;AAE3D,UAAM,WAAW,MAAM,MAAM,gBAAgB,EAAE,QAAQ,WAAW,OAAO,CAAC;AAC1E,iBAAa,OAAO;AAEpB,QAAI,CAAC,SAAS,IAAI;AAChB,MAAAC,KAAI,KAAK,0BAA0B,SAAS,MAAM,IAAI,SAAS,UAAU,EAAE;AAC3E,aAAO,iBAAiB,oBAAI,IAAI;AAAA,IAClC;AAEA,UAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,UAAM,YAAY,KAAK,WAAW;AAClC,QAAI,CAAC,WAAW;AACd,MAAAA,KAAI,KAAK,6CAA6C;AACtD,aAAO,iBAAiB,oBAAI,IAAI;AAAA,IAClC;AAEA,UAAM,UAAU,oBAAI,IAAoB;AACxC,eAAW,CAAC,SAAS,KAAK,KAAK,OAAO,QAAQ,SAAS,GAAG;AACxD,UAAI,MAAM,MAAM,SAAS,MAAM;AAC7B,gBAAQ,IAAI,SAAS,MAAM,KAAK,KAAK;AAAA,MACvC;AAAA,IACF;AAEA,oBAAgB;AAChB,sBAAkB,KAAK,IAAI;AAE3B,IAAAA,KAAI,KAAK,gCAAgC,QAAQ,IAAI,mBAAmB;AACxE,WAAO;AAAA,EACT,SAAS,GAAG;AACV,IAAAA,KAAI,KAAK,yBAAyB,CAAC;AACnC,WAAO,iBAAiB,oBAAI,IAAI;AAAA,EAClC;AACF;AAGO,SAAS,iBAAuB;AACrC,kBAAgB;AAChB,oBAAkB;AACpB;AAQA,eAAsB,gBACpB,UAC8B;AAC9B,QAAM,UAAU,MAAM,aAAa;AACnC,QAAM,QAAQ,oBAAI,IAAoB;AAEtC,aAAW,MAAM,UAAU;AACzB,UAAM,iBAAiB,QAAQ,IAAI,EAAE;AACrC,QAAI,kBAAkB,MAAM;AAC1B,YAAM,IAAI,IAAI,iBAAiB,GAAS;AAAA,IAC1C,OAAO;AACL,YAAM,IAAI,IAAI,aAAa,EAAE,CAAC;AAAA,IAChC;AAAA,EACF;AAEA,SAAO;AACT;AA0BA,IAAI,eAA+C;AACnD,IAAI,iBAAiB;AACrB,IAAM,qBAAqB,KAAK,KAAK;AAYrC,eAAsB,eACpB,aACA,MACkC;AAElC,MAAI,gBAAgB,KAAK,IAAI,IAAI,iBAAiB,oBAAoB;AACpE,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,UAAiC,CAAC;AACxC,QAAI;AAGJ,OAAG;AACD,YAAM,MAAM,IAAI,IAAI,GAAG,WAAW,YAAY;AAC9C,UAAI,aAAa,IAAI,SAAS,MAAM;AACpC,UAAI,QAAS,KAAI,aAAa,IAAI,YAAY,OAAO;AAErD,YAAM,WAAW,MAAM,MAAM,IAAI,SAAS,GAAG;AAAA,QAC3C,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,qBAAqB;AAAA,UACrB,GAAG,YAAY,IAAI;AAAA,QACrB;AAAA,MACF,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,OAAO,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,WAAW;AAC1D,QAAAA,KAAI;AAAA,UACF,2BAA2B,SAAS,MAAM,IAAI,SAAS,UAAU,WAAM,IAAI;AAAA,QAC7E;AACA,eAAO,gBAAgB,CAAC;AAAA,MAC1B;AAEA,YAAM,OAAQ,MAAM,SAAS,KAAK;AAElC,iBAAW,SAAS,KAAK,MAAM;AAC7B,gBAAQ,KAAK,KAAK;AAAA,MACpB;AAEA,gBAAU,KAAK,WAAW,KAAK,UAAU;AAAA,IAC3C,SAAS;AAGT,UAAM,WAAW,QAAQ,IAAI,CAAC,MAAM,EAAE,EAAE;AACxC,UAAM,QAAQ,MAAM,gBAAgB,QAAQ;AAE5C,UAAM,SAAkC,QAAQ,IAAI,CAAC,WAAW;AAAA,MAC9D,IAAI,MAAM;AAAA,MACV,YAAY;AAAA,MACZ,MAAM,EAAE,OAAO,MAAM,IAAI,MAAM,EAAE,KAAK,aAAa,MAAM,EAAE,EAAE;AAAA,MAC7D,QAAQ;AAAA;AAAA,MACR,cAAc;AAAA,QACZ,OAAO,EAAE,MAAM,KAAK;AAAA;AAAA,QACpB,WAAW,MAAM,cAAc,UAAU,aAAa;AAAA,MACxD;AAAA,IACF,EAAE;AAEF,mBAAe;AACf,qBAAiB,KAAK,IAAI;AAE1B,IAAAA,KAAI;AAAA,MACF,0BAA0B,OAAO,MAAM,YAAY,OAAO,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,KAAK,IAAI,CAAC;AAAA,IACvF;AAEA,WAAO;AAAA,EACT,SAAS,GAAG;AACV,IAAAA,KAAI,KAAK,0BAA0B,CAAC;AACpC,WAAO,gBAAgB,CAAC;AAAA,EAC1B;AACF;AAGO,SAAS,kBAAwB;AACtC,iBAAe;AACf,mBAAiB;AACnB;AAOA,IAAI,aAAa;AAgBjB,eAAsB,yBACpB,cACA,aACA,MACA,KACA,aACA,WACe;AACf,MAAI,WAAY;AAEhB,QAAM,MAAM,WAAW;AACvB,MAAI,IAAI,YAAa;AAErB,QAAM,SAAS,MAAM,eAAe,aAAa,IAAI;AACrD,MAAI,OAAO,WAAW,EAAG;AAIzB,QAAM,kBAAkB,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,YAAY;AAChE,QAAM,mBAA6E;AAAA,IACjF,IAAI;AAAA,IACJ,YAAY;AAAA,IACZ,MAAM,EAAE,OAAO,iBAAiB,KAAK,SAAS,aAAa,YAAY,EAAE;AAAA,EAC3E;AAEA,QAAM,aAAa,YAAY,uBAAuB,kBAAkB,MAAM;AAC9E,MAAI,WAAW,WAAW,EAAG;AAE7B,MAAI,WAAW,WAAW,KAAK,WAAW,CAAC,EAAE,OAAO,aAAc;AAElE,QAAM,cAAc,YAAY;AAAA,IAC9B;AAAA,IACA;AAAA,IACA,OAAO,OAAO,CAAC,MAAM,EAAE,eAAe,WAAW,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE;AAAA,EACpE;AAEA,QAAM,SAAS,YAAY,wBAAwB,WAAW;AAC9D,MAAI,CAAC,YAAY,kBAAkB,QAAQ,WAAW,EAAG;AAGzD,QAAM,gBAAgB,gBAAgB,eAAe,aAAa,WAAW,IAAI;AACjF,QAAM,OAAO,cAAc,OAAO,CAAC,MAAM,EAAE,eAAe,CAAC;AAC3D,MAAI,KAAK,WAAW,EAAG;AAEvB,QAAM,YAAY,KAAK,KAAK,SAAS,CAAC;AACtC,QAAM,YAAY,UAAU;AAC5B,MAAI,UAAU,WAAW,EAAG;AAG5B,QAAM,cAAc,SAAS,UAAU,aAAa,SAAS;AAC7D,QAAM,YAAY,IAAI,IAAI,SAAS;AACnC,QAAM,iBAAiB,YAAY,OAAO,CAAC,MAAM,UAAU,IAAI,EAAE,EAAE,CAAC;AACpE,MAAI,eAAe,WAAW,EAAG;AAEjC,QAAM,eAAe,eAAe,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,IAAI;AACnE,QAAM,OAAO,IAAI,KAAK,eAAe,CAAC,EAAE,UAAU,EAAE;AAAA,IAClD;AAAA,IACA,EAAE,MAAM,WAAW,OAAO,QAAQ,KAAK,UAAU;AAAA,EACnD;AAEA,eAAa;AACb,MAAI;AACF,UAAM,SAAS,MAAM,YAAY,cAAc;AAAA,MAC7C;AAAA,MACA,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB;AAAA,MACA,uBAAuB,UAAU;AAAA,MACjC,oBAAoB;AAAA,MACpB;AAAA,IACF,CAAC;AACD,QAAI,QAAQ;AACV,MAAAA,KAAI;AAAA,QACF,2BAA2B,OAAO,OAAO,WAAW,OAAO,UAAU;AAAA,MACvE;AAAA,IACF;AAAA,EACF,SAAS,GAAG;AACV,IAAAA,KAAI,MAAM,kCAAkC,CAAC;AAAA,EAC/C,UAAE;AACA,iBAAa;AAAA,EACf;AACF;AAcO,SAAS,iBAAsE;AACpF,QAAM,MAAM,WAAW;AACvB,SAAO,YAAY;AAAA,IACjB;AAAA,IACA,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AACF;AAGO,SAAS,wBAA8B;AAC5C,kBAAgB;AAChB,iBAAe;AACf,eAAa;AACf;;;AD3XA,IAAM,mBAAmB;AAelB,SAAS,mBACdC,SACAC,WACA,YACY;AACZ,QAAM,aAAa,oBAAI,IAAY;AAEnC,QAAM,QAAQ,YAAY,MAAM;AAC9B,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,YAAYD,QAAO,qBAAqB;AAE9C,eAAW,CAAC,WAAW,KAAK,KAAKC,WAAU;AACzC,UAAI,WAAW,IAAI,SAAS,EAAG;AAC/B,UAAI,MAAM,MAAM,kBAAkB,UAAW;AAE7C,iBAAW,IAAI,SAAS;AACxB,iBAAW,WAAW,KAAK,EACxB,MAAM,CAAC,MAAMC,KAAI,MAAM,gCAAgC,SAAS,KAAK,CAAC,CAAC,EACvE,QAAQ,MAAM,WAAW,OAAO,SAAS,CAAC;AAAA,IAC/C;AAAA,EACF,GAAG,gBAAgB;AAEnB,SAAO,MAAM,cAAc,KAAK;AAClC;AA6CO,SAAS,qBACd,aACA,KACA,aACA,SACA,cACA,kBAC2D;AAC3D,SAAO,OAAO,WAAmB,UAAwB;AACvD,UAAM,MAAMC,YAAW;AAIvB,QAAI;AACF,YAAM,OAAO,QAAQ;AACrB,UAAI,MAAM;AACR,cAAM;AAAA,UACJ;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,GAAG;AACV,MAAAC,KAAI,MAAM,uCAAuC,CAAC;AAAA,IACpD;AAEA,UAAM,QAAQ,eAAe;AAM7B,QAAI;AACF,YAAM,UAAUC,UAAS,iBAAiB,aAAa,SAAS;AAChE,UAAI,UAAU,GAAG;AACf,cAAM,aAAa,IAAI,EAAE,KAAK,aAAa,WAAW,OAAO,OAAO,KAAK,CAAC;AAAA,MAC5E;AAAA,IACF,SAAS,GAAG;AACV,MAAAD,KAAI,MAAM,4BAA4B,CAAC;AAAA,IACzC;AAGA,QAAI,IAAI,UAAU,WAAW,IAAI,QAAQ,QAAQ;AAC/C,UAAI;AACF,YAAI,MAAM,sBAAsB,IAAI,QAAQ,YAAY;AACtD,gBAAM,QAAQ,IAAI,EAAE,KAAK,aAAa,WAAW,MAAM,CAAC;AACxD,gBAAM,qBAAqB;AAC3B,6BAAmB;AAAA,QACrB;AAAA,MACF,SAAS,GAAG;AACV,QAAAA,KAAI,MAAM,wBAAwB,CAAC;AAAA,MACrC;AAAA,IACF;AAGA,QAAI,IAAI,UAAU,SAAS;AACzB,UAAI;AACF,cAAM,UAAU,IAAI,WAAW,aAAa,KAAK;AACjD,YAAI,QAAQ,SAAS,IAAI,QAAQ,YAAY;AAC3C,UAAAA,KAAI;AAAA,YACF,eAAe,QAAQ,MAAM,uBAAuB,IAAI,QAAQ,UAAU;AAAA,UAC5E;AACA,gBAAM,EAAE,SAAS,QAAQ,IAAI,MAAM,QAAQ,YAAY;AAAA,YACrD;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF,CAAC;AACD,cAAI,UAAU,KAAK,UAAU,GAAG;AAC9B,YAAAA,KAAI,KAAK,kBAAkB,OAAO,aAAa,OAAO,UAAU;AAChE,+BAAmB;AAAA,UACrB;AAAA,QACF;AAAA,MACF,SAAS,GAAG;AACV,QAAAA,KAAI,MAAM,6BAA6B,CAAC;AAAA,MAC1C;AAAA,IACF;AAGA,QAAI;AACF,YAAM,EAAE,YAAY,WAAW,IAAIC,UAAS,MAAM;AAAA,QAChD;AAAA,QACA,eAAe,IAAI,QAAQ;AAAA,QAC3B,cAAc,IAAI,QAAQ;AAAA,MAC5B,CAAC;AACD,UAAI,aAAa,KAAK,aAAa,GAAG;AACpC,QAAAD,KAAI;AAAA,UACF,6BAA6B,UAAU,YAAY,UAAU;AAAA,QAC/D;AAAA,MACF;AAAA,IACF,SAAS,GAAG;AACV,MAAAA,KAAI,MAAM,uBAAuB,CAAC;AAAA,IACpC;AAGA,QAAI,IAAI,UAAU,SAAS;AACzB,UAAI;AACF,cAAM,UAAU,IAAI,WAAW,aAAa,KAAK;AACjD,YAAI,QAAQ,SAAS,GAAG;AACtB,cAAI,IAAI,WAAW,SAAS;AAC1B,kBAAM,WAAW,KAAK,aAAa,IAAI,WAAW,IAAI;AACtD,yBAAa,EAAE,aAAa,SAAS,CAAC;AAAA,UACxC,OAAO;AACL,2BAAe,WAAW;AAAA,UAC5B;AAAA,QACF;AAAA,MACF,SAAS,GAAG;AACV,QAAAA,KAAI,MAAM,gCAAgC,CAAC;AAAA,MAC7C;AAAA,IACF;AAGA,QAAI,IAAI,UAAU,SAAS;AACzB,UAAI;AACF,cAAM,UAAU,IAAI,cAAc;AAClC,YAAI,UAAU,GAAG;AACf,UAAAA,KAAI,KAAK,WAAW,OAAO,kCAAkC;AAC7D,6BAAmB;AAAA,QACrB;AAAA,MACF,SAAS,GAAG;AACV,QAAAA,KAAI,MAAM,gCAAgC,CAAC;AAAA,MAC7C;AAAA,IACF;AAGA,QAAI;AACF,gBAAU,QAAQ,WAAW;AAAA,IAC/B,SAAS,GAAG;AACV,MAAAA,KAAI,MAAM,kCAAkC,CAAC;AAAA,IAC/C;AAAA,EACF;AACF;;;AEtOA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAAE;AAAA,EACA,UAAUC;AAAA,OAEL;AAgBA,IAAM,sBAAmC;AAAA,EAC9C,MAAM;AAAA,EACN,aAAa;AAAA,EACb,aAAa;AAAA,IACX,MAAM;AAAA,IACN,YAAY;AAAA,MACV,OAAO;AAAA,QACL,MAAM;AAAA,QACN,aAAa,0BAA0B;AAAA,MACzC;AAAA,MACA,OAAO;AAAA,QACL,MAAM;AAAA,QACN,MAAM,CAAC,OAAO,WAAW,WAAW,WAAW;AAAA,QAC/C,aAAa,0BAA0B;AAAA,MACzC;AAAA,IACF;AAAA,IACA,UAAU,CAAC,OAAO;AAAA,EACpB;AACF;AAEO,IAAM,mBAAmB;AAOhC,IAAM,wBAAwB;AAGvB,SAAS,qBAAqB,SAAiC;AACpE,SAAO,KAAK,IAAI,IAAI,QAAQ,YAAY;AAC1C;AAOO,SAAS,kBACd,MACiC;AACjC,SAAO,KAAK,QAAQ;AAAA,IAClB,CAAC,MACC,EAAE,SAAS,cAAc,EAAE,SAAS;AAAA,EACxC;AACF;AAGO,SAAS,iBAAiB,MAAgC;AAC/D,SAAO,kBAAkB,IAAI,MAAM;AACrC;AAGO,SAAS,gBAAgB,MAAgC;AAC9D,SAAO,KAAK,QAAQ;AAAA,IAClB,CAAC,MAAM,EAAE,SAAS,cAAc,EAAE,SAAS;AAAA,EAC7C;AACF;AAGO,SAAS,oBAAoB,OAA+B;AACjE,SAAO,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,gBAAgB;AACtD;AAOA,SAAS,iBAAiB,OAGxB;AACA,QAAM,QAAQ,MAAM;AACpB,SAAO;AAAA,IACL,OAAO,OAAO,MAAM,UAAU,WAAW,MAAM,QAAQ;AAAA,IACvD,OAAQ,MAAM,SAAyB;AAAA,EACzC;AACF;AAQA,eAAsB,cACpB,OACA,aACA,WAC4E;AAC5E,QAAM,EAAE,OAAO,MAAM,IAAI,iBAAiB,KAAK;AAC/C,QAAM,MAAMA,YAAW;AAEvB,MAAI;AACF,UAAM,SAAS,MAAM,UAAU;AAAA,MAC7B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,kBAAkB,IAAI,WAAW,WAAW;AAAA,MAC5C,cAAc,IAAI;AAAA,IACpB,CAAC;AAED,WAAO,EAAE,QAAQ,OAAO,EAAE,OAAO,MAAM,EAAE;AAAA,EAC3C,SAAS,GAAG;AACV,IAAAD,KAAI,MAAM,oCAAoC,CAAC;AAC/C,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,OAAO,EAAE,OAAO,MAAM;AAAA,IACxB;AAAA,EACF;AACF;AAkBO,SAAS,oBACd,aACA,MACA,cACA,oBACgB;AAMhB,QAAM,mBAAmC;AAAA,IACvC,MAAM;AAAA,IACN,SAAS,CAAC,kBAAkB;AAAA,EAC9B;AAGA,QAAM,oBAAoC;AAAA,IACxC,MAAM;AAAA,IACN,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,WAAW,mBAAmB;AAAA,QAC9B,SAAS,gBAAgB;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AAGA,QAAM,qBAAqB,YAAY,MAAM;AAAA,IAC3C,CAAC,MAAM,EAAE,SAAS;AAAA,EACpB;AAEA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,UAAU;AAAA,MACR,GAAG,YAAY;AAAA,MACf;AAAA,MACA;AAAA,IACF;AAAA,IACA,OAAO;AAAA,EACT;AACF;AAiBO,SAAS,oBACd,KACA,SACS;AACT,QAAM,WAAW,IAAI;AACrB,MAAI,SAAS,SAAS,EAAG,QAAO;AAIhC,MAAI,eAAe;AACnB,WAAS,IAAI,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;AAC7C,QACE,SAAS,CAAC,EAAE,SAAS,eACrB,SAAS,IAAI,CAAC,GAAG,SAAS,QAC1B;AACA,qBAAe;AACf;AAAA,IACF;AAAA,EACF;AAEA,MAAI,eAAe,GAAG;AACpB,IAAAA,KAAI,KAAK,wDAAmD;AAC5D,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,SAAS,YAAY;AAC1C,QAAM,UAAU,SAAS,eAAe,CAAC;AAIzC,QAAM,YAAY,KAAK,IAAI,QAAQ,UAAU,aAAa,QAAQ,MAAM;AACxE,QAAM,gBAAqC;AAAA,IACzC,MAAM;AAAA,IACN,IAAI,QAAQ;AAAA,IACZ,MAAM;AAAA,IACN,OAAO,QAAQ;AAAA,EACjB;AACA,eAAa,QAAQ,OAAO,WAAW,GAAG,aAAa;AAIvD,UAAQ,QAAQ,QAAQ;AAAA,IACtB,MAAM;AAAA,IACN,WAAW,QAAQ;AAAA,IACnB,SAAS,QAAQ;AAAA,EACnB,CAAC;AAGD,MAAI,QAAQ,IAAI,MAAM,OAAO,CAAC,MAAM,EAAE,SAAS,gBAAgB;AAE/D,SAAO;AACT;AAYO,SAAS,wBACd,MACiB;AACjB,SAAO;AAAA,IACL,GAAG;AAAA,IACH,SAAS,KAAK,QAAQ;AAAA,MACpB,CAAC,MAAM,EAAE,EAAE,SAAS,cAAc,EAAE,SAAS;AAAA,IAC/C;AAAA,EACF;AACF;;;AR3LA,IAAI,cAAc;AAGlB,IAAI;AAwBJ,eAAsB,qBAAoC;AACxD,gBAAc;AACd,sBAAoB;AACpB,WAAS,MAAM;AACf,kBAAgB,MAAM;AAEtB,MAAI,aAAa,cAAc,WAAW;AACxC,UAAO,UAA4D,SAAS;AAAA,EAC9E;AACA,cAAY;AACZ,sBAAoB;AACpB,MAAI,mBAAmB;AACrB,sBAAkB;AAClB,wBAAoB;AAAA,EACtB;AACA,yBAAuB;AACvB,wBAAsB;AACxB;AAGA,IAAI,oBAAmC;AAGvC,IAAM,WAAW,oBAAI,IAA0B;AAS/C,IAAM,kBAAkB,oBAAI,IAG1B;AAGF,IAAI,YAA8B;AAGlC,IAAI,oBAAyC;AAG7C,IAAI,uBAAsC;AAa1C,IAAM,cAAyC;AAAA;AAAA;AAAA,EAG7C,iBAAqB,EAAE,SAAS,KAAS,QAAQ,MAAQ,eAAe,KAAK,MAAY,IAAI;AAAA,EAC7F,mBAAqB,EAAE,SAAS,KAAS,QAAQ,MAAQ,eAAe,IAAI,MAAY,IAAI;AAAA,EAC5F,qBAAqB,EAAE,SAAS,KAAS,QAAQ,MAAQ,eAAe,IAAI,MAAY,IAAI;AAAA,EAC5F,oBAAqB,EAAE,SAAS,KAAS,QAAQ,MAAQ,eAAe,MAAO,MAAY,IAAI;AACjG;AAEA,IAAM,qBAAgC,EAAE,SAAS,KAAS,QAAQ,KAAM;AAExE,SAAS,aAAa,OAA0B;AAE9C,aAAW,CAAC,QAAQ,IAAI,KAAK,OAAO,QAAQ,WAAW,GAAG;AACxD,QAAI,MAAM,WAAW,MAAM,EAAG,QAAO;AAAA,EACvC;AACA,SAAO;AACT;AAUA,eAAe,aAAa,aAAqBE,SAAuC;AACtF,MAAI,YAAa;AAEjB,QAAM,KAAK,WAAW;AACtB,gBAAc,WAAW;AACzB,gBAAc;AACd,sBAAoB;AAKpB,MAAIA,WAAU,CAAC,mBAAmB;AAChC,UAAM,MAAM,aAAaA,OAAM;AAC/B,UAAM,iBAAiB,yBAAyBC,YAAW,EAAE,OAAO,WAAW;AAC/E,UAAM,cAAc;AAAA,MAClB;AAAA,MACA;AAAA,MACAD,QAAO;AAAA,MACP,MAAM,YAAY;AAAA,MAClB;AAAA;AAAA,MAEA,MAAM,gBAAgB,MAAM;AAAA,IAC9B;AACA,wBAAoB,mBAAmBA,SAAQ,UAAU,WAAW;AAAA,EACtE;AAEA,EAAAE,KAAI,KAAK,iCAAiC,WAAW,EAAE;AACzD;AAEA,SAAS,aAAaF,SAAkC;AACtD,MAAI,CAAC,WAAW;AACd,UAAM,MAAMC,YAAW;AACvB,UAAM,eAAe,IAAI,SAAS;AAAA,MAChC,YAAY;AAAA,MACZ,SAAS;AAAA,IACX;AACA,UAAM,QAAQ;AAAA,MACZD,QAAO;AAAA,MACP;AAAA,MACA;AAAA,IACF;AAIA,UAAM,gBAAgB,QAAQ,IAAI,wBAAwB;AAC1D,QAAI,eAAe;AACjB,kBAAY;AAAA,IACd,OAAO;AACL,kBAAY;AAAA,QACV;AAAA,QACAA,QAAO;AAAA,QACP;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAMA,SAAS,mBACP,WACA,aACc;AACd,MAAI,QAAQ,SAAS,IAAI,SAAS;AAClC,MAAI,CAAC,OAAO;AACV,YAAQ;AAAA,MACN;AAAA,MACA;AAAA,MACA,aAAa;AAAA,MACb,iBAAiB,KAAK,IAAI;AAAA,MAC1B,cAAc;AAAA,MACd,oBAAoB;AAAA,IACtB;AACA,aAAS,IAAI,WAAW,KAAK;AAAA,EAC/B;AACA,QAAM,kBAAkB,KAAK,IAAI;AAGjC,MAAI,MAAM,iBAAiB,CAAC,qBAAqB,MAAM,aAAa,GAAG;AACrE,IAAAE,KAAI;AAAA,MACF,+DAA+D,UAAU,MAAM,GAAG,EAAE,CAAC;AAAA,IACvF;AACA,UAAM,gBAAgB;AAAA,EACxB;AAEA,SAAO;AACT;AAUA,eAAe,gBACb,KACA,cACgD;AAChD,QAAM,cAAc,IAAI,SAAS,IAAI,CAAC,OAAO;AAAA,IAC3C,MAAM,EAAE;AAAA,IACR,SAAS,EAAE;AAAA,EACb,EAAE;AACF,QAAM,OAAO,YAAY,IAAI,UAAU;AACvC,QAAM,cAAc,MAAM,oBAAoB,aAAa;AAAA,IACzD,OAAO,IAAI;AAAA,IACX,YAAY,OAAO,gBAAgB,IAAI,IAAI;AAAA,EAC7C,CAAC;AACD,QAAM,WAAW,IAAI,SAAS;AAG9B,MAAI,YAAuD;AAE3D,aAAW,CAAC,KAAK,KAAK,KAAK,UAAU;AACnC,QAAI,MAAM,gBAAgB,YAAa;AAEvC,UAAM,OAAO,WAAW,MAAM;AAK9B,QAAI,OAAO,CAAC,kCAAmC;AAE/C,UAAM,UAAU,KAAK,IAAI,IAAI;AAC7B,QAAI,CAAC,aAAa,UAAU,UAAU,WAAW;AAC/C,kBAAY,EAAE,KAAK,WAAW,QAAQ;AAAA,IACxC;AAAA,EACF;AAEA,MAAI,WAAW;AACb,WAAO,EAAE,WAAW,UAAU,KAAK,OAAO,MAAM;AAAA,EAClD;AAGA,QAAM,YAAY,kBAAkB;AACpC,SAAO,EAAE,WAAW,OAAO,KAAK;AAClC;AAeA,eAAe,kBACb,KACAF,SACA,aACA,OACmB;AACnB,MAAI;AACJ,MAAI;AACJ,MAAI;AAGJ,QAAM,QAAQ,qBAAqB,IAAI,KAAK;AAC5C,QAAM,oBAAoB,OAAO,YAAY,IAAI;AACjD,QAAM,wBAAwB,OAAO,QAAQ,sBAAsB,WAAWA,QAAO,iBAAiBA,QAAO;AAE7G,MAAI,sBAAsB,UAAU;AAClC,UAAM,SAAS,2BAA2B,KAAK,qBAAqB;AACpE,UAAM,OAAO;AACb,cAAU,OAAO;AACjB,WAAO,OAAO;AAAA,EAChB,OAAO;AACL,UAAM,SAAS,sBAAsB,KAAK,KAAK;AAC/C,UAAM,GAAG,qBAAqB,GAAG,OAAO,GAAG;AAC3C,cAAU,OAAO;AACjB,WAAO,OAAO;AAAA,EAChB;AAEA,QAAM,uBAAuB,eAAe;AAE5C,MAAI,sBAAsB;AACxB,WAAO;AAAA,MACL;AAAA,MACA,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,MACE,MAAM,KAAK;AAAA,QACT,QAAQ;AAAA,QACR;AAAA,QACA,MAAM,KAAK,UAAU,IAAI;AAAA,MAC3B,CAAC;AAAA,IACL;AAAA,EACF;AAEA,SAAO,MAAM,KAAK;AAAA,IAChB,QAAQ;AAAA,IACR;AAAA,IACA,MAAM,KAAK,UAAU,IAAI;AAAA,EAC3B,CAAC;AACH;AAiBA,SAAS,uBACP,kBACA,YACA,eAMU;AACV,QAAM,cAAc,gBAChB,6BAA6B,gBAAgB,IAC7C;AACJ,QAAM,cAAiC,eAAe,wBAAwB;AAC9E,QAAM,UAAU,IAAI,YAAY;AAEhC,QAAM,SAAS,IAAI,eAAe;AAAA,IAChC,MAAM,MAAM,YAAY;AACtB,UAAI;AAEF,cAAM,SAAS,iBAAiB,KAAM,UAAU;AAChD,yBAAiB,EAAE,OAAO,KAAK,KAAK,eAAe,MAAM,GAAG;AAC1D,gBAAM,YAAY,YAAY,aAAa,OAAO,IAAI;AACtD,cAAI,WAAW;AACb,uBAAW,QAAQ,QAAQ,OAAO,SAAS,CAAC;AAAA,UAC9C;AAAA,QACF;AAGA,YAAI,aAAa,UAAU,GAAG;AAC5B,gBAAM,OAAO,YAAY,YAAY;AACrC,gBAAM,cAAc,kBAAkB,IAAI;AAE1C,cAAI,eAAe,eAAe;AAChC,kBAAM,EAAE,QAAQ,MAAM,IAAI,MAAM;AAAA,cAC9B;AAAA,cACA,cAAc,aAAa;AAAA,cAC3B,cAAc,aAAa;AAAA,YAC7B;AAEA,gBAAI,YAAY,cAAc,GAAG;AAE/B,oBAAM,WAAW,KAAK,QAAQ,QAAQ,WAAW;AACjD,4BAAc,aAAa,gBAAgB;AAAA,gBACzC,WAAW,YAAY;AAAA,gBACvB;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA,WAAW,KAAK,IAAI;AAAA,cACtB;AACA,cAAAE,KAAI;AAAA,gBACF,6DACK,cAAc,aAAa,UAAU,MAAM,GAAG,EAAE,CAAC;AAAA,cACxD;AAKA,oBAAM,eAAe,YAAY,iBAAiB;AAClD,oBAAM,iBAAiB;AAAA,gBACrB,eAAe,uBAAuB,KAAK,UAAU;AAAA,kBACnD,MAAM;AAAA,kBACN,OAAO;AAAA,kBACP,eAAe,EAAE,MAAM,QAAQ,MAAM,GAAG;AAAA,gBAC1C,CAAC,CAAC;AAAA,gBACF,eAAe,uBAAuB,KAAK,UAAU;AAAA,kBACnD,MAAM;AAAA,kBACN,OAAO;AAAA,kBACP,OAAO,EAAE,MAAM,cAAc,MAAM,4BAA4B;AAAA,gBACjE,CAAC,CAAC;AAAA,gBACF,eAAe,sBAAsB,KAAK,UAAU;AAAA,kBAClD,MAAM;AAAA,kBACN,OAAO;AAAA,gBACT,CAAC,CAAC;AAAA,cACJ,EAAE,KAAK,EAAE;AACT,yBAAW,QAAQ,QAAQ,OAAO,cAAc,CAAC;AAGjD,oBAAM,WAAW,YAAY,eAAe;AAC5C,kBAAI,UAAU;AACZ,2BAAW,QAAQ,QAAQ,OAAO,QAAQ,CAAC;AAAA,cAC7C;AAEA,yBAAW,MAAM;AAGjB,oBAAM,YAAY,wBAAwB,IAAI;AAC9C,yBAAW,SAAS;AACpB;AAAA,YACF;AAGA,YAAAA,KAAI;AAAA,cACF,0DACK,cAAc,aAAa,UAAU,MAAM,GAAG,EAAE,CAAC;AAAA,YACxD;AAKA,kBAAM,iBAAiB,YAAY,iBAAiB;AACpD,kBAAM,iBAAiB;AAAA,cACrB,eAAe,uBAAuB,KAAK,UAAU;AAAA,gBACnD,MAAM;AAAA,gBACN,OAAO;AAAA,gBACP,eAAe,EAAE,MAAM,QAAQ,MAAM,GAAG;AAAA,cAC1C,CAAC,CAAC;AAAA,cACF,eAAe,uBAAuB,KAAK,UAAU;AAAA,gBACnD,MAAM;AAAA,gBACN,OAAO;AAAA,gBACP,OAAO,EAAE,MAAM,cAAc,MAAM,4BAA4B;AAAA,cACjE,CAAC,CAAC;AAAA,cACF,eAAe,sBAAsB,KAAK,UAAU;AAAA,gBAClD,MAAM;AAAA,gBACN,OAAO;AAAA,cACT,CAAC,CAAC;AAAA,YACJ,EAAE,KAAK,EAAE;AACT,uBAAW,QAAQ,QAAQ,OAAO,cAAc,CAAC;AAEjD,kBAAM,WAAW;AAAA,cACf,cAAc;AAAA,cACd;AAAA,cACA;AAAA,cACA;AAAA,YACF;AACA,kBAAM,mBAAmB,MAAM;AAAA,cAC7B;AAAA,cACA,cAAc;AAAA,cACd;AAAA,cACA,cAAc;AAAA,YAChB;AAEA,gBAAI,CAAC,iBAAiB,IAAI;AACxB,oBAAM,YAAY,MAAM,iBAAiB,KAAK;AAC9C,cAAAA,KAAI;AAAA,gBACF,oCAAoC,iBAAiB,MAAM,IAAI,UAAU,MAAM,GAAG,GAAG,CAAC;AAAA,cACxF;AAEA,oBAAM,WAAW,YAAY,eAAe;AAC5C,kBAAI,UAAU;AACZ,2BAAW,QAAQ,QAAQ,OAAO,QAAQ,CAAC;AAAA,cAC7C;AACA,yBAAW,MAAM;AACjB,oBAAM,YAAY,wBAAwB,IAAI;AAC9C,yBAAW,SAAS;AACpB;AAAA,YACF;AASA,kBAAM,cAAc,YAAY,iBAAiB,IAAI;AACrD,kBAAM,aAAa,iBAAiB,KAAM,UAAU;AAEpD,6BAAiB,EAAE,OAAO,WAAW,MAAM,SAAS,KAAK,eAAe,UAAU,GAAG;AACnF,kBAAI,cAAc,iBAAiB;AAEjC;AAAA,cACF;AAGA,kBACE,cAAc,yBACd,cAAc,yBACd,cAAc,sBACd;AACA,oBAAI;AACF,wBAAM,SAAS,KAAK,MAAM,QAAQ;AAClC,sBAAI,OAAO,OAAO,UAAU,UAAU;AACpC,2BAAO,QAAS,OAAO,QAAmB;AAC1C,0BAAM,WAAW;AAAA,sBACf;AAAA,sBACA,KAAK,UAAU,MAAM;AAAA,oBACvB;AACA,+BAAW,QAAQ,QAAQ,OAAO,QAAQ,CAAC;AAC3C;AAAA,kBACF;AAAA,gBACF,QAAQ;AAAA,gBAER;AAAA,cACF;AAGA,oBAAM,YAAY,eAAe,WAAW,QAAQ;AACpD,yBAAW,QAAQ,QAAQ,OAAO,SAAS,CAAC;AAAA,YAC9C;AAEA,uBAAW,MAAM;AAYjB,uBAAW,IAAI;AACf;AAAA,UACF;AAAA,QACF;AAGA,mBAAW,MAAM;AACjB,cAAM,WAAW,YAAY,YAAY;AACzC,mBAAW,QAAQ;AAAA,MACrB,SAAS,KAAK;AACZ,QAAAA,KAAI,MAAM,6BAA6B,GAAG;AAC1C,mBAAW,MAAM,GAAG;AAAA,MACtB;AAAA,IACF;AAAA,EACF,CAAC;AAED,SAAO,IAAI,SAAS,QAAQ;AAAA,IAC1B,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,gBAAgB;AAAA,MAChB,iBAAiB;AAAA,MACjB,YAAY;AAAA,IACd;AAAA,EACF,CAAC;AACH;AAKA,eAAe,4BACb,kBAC0B;AAC1B,QAAM,OAAQ,MAAM,iBAAiB,KAAK;AAE1C,QAAM,UAAiC,CAAC;AACxC,QAAM,aAAa,KAAK;AACxB,MAAI,YAAY;AACd,eAAW,SAAS,YAAY;AAC9B,cAAQ,MAAM,MAAM;AAAA,QAClB,KAAK;AACH,kBAAQ,KAAK,EAAE,MAAM,QAAQ,MAAM,OAAO,MAAM,QAAQ,EAAE,EAAE,CAAC;AAC7D;AAAA,QACF,KAAK;AACH,kBAAQ,KAAK;AAAA,YACX,MAAM;AAAA,YACN,UAAU,OAAO,MAAM,YAAY,EAAE;AAAA,YACrC,GAAI,MAAM,YACN,EAAE,WAAW,OAAO,MAAM,SAAS,EAAE,IACrC;AAAA,UACN,CAAC;AACD;AAAA,QACF,KAAK;AACH,kBAAQ,KAAK;AAAA,YACX,MAAM;AAAA,YACN,IAAI,OAAO,MAAM,MAAM,EAAE;AAAA,YACzB,MAAM,OAAO,MAAM,QAAQ,EAAE;AAAA,YAC7B,OAAO,MAAM;AAAA,UACf,CAAC;AACD;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AAEA,QAAM,QAAQ,KAAK;AAEnB,SAAO;AAAA,IACL,IAAI,OAAO,KAAK,MAAM,EAAE;AAAA,IACxB,OAAO,OAAO,KAAK,SAAS,EAAE;AAAA,IAC9B;AAAA,IACA,YAAY;AAAA,MACT,KAAK,eAA0B;AAAA,IAClC;AAAA,IACA,OAAO;AAAA,MACL,aAAa,OAAO,gBAAgB;AAAA,MACpC,cAAc,OAAO,iBAAiB;AAAA,MACtC,sBAAsB,OAAO;AAAA,MAC7B,0BAA0B,OAAO;AAAA,IACnC;AAAA,EACF;AACF;AAwBA,SAAS,sBAAsB,MAAiC;AAC9D,QAAM,OAAO,gCAAgC,IAAI;AACjD,SAAO,IAAI,SAAS,KAAK,UAAU,IAAI,GAAG;AAAA,IACxC,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,EAChD,CAAC;AACH;AAKA,SAAS,mBAAmB,MAAiC;AAE3D,QAAM,aAAa,KAAK,QAAQ;AAAA,IAC9B,CAAC,MAA2C,EAAE,SAAS;AAAA,EACzD;AACA,QAAM,WAAW,WAAW,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE;AAEtD,QAAM,UAAU,qBAAqB,KAAK,IAAI,KAAK,OAAO,UAAU;AAAA,IAClE,aAAa,KAAK,MAAM;AAAA,IACxB,cAAc,KAAK,MAAM;AAAA,EAC3B,CAAC;AAED,SAAO,IAAI,SAAS,SAAS;AAAA,IAC3B,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,gBAAgB;AAAA,MAChB,iBAAiB;AAAA,MACjB,YAAY;AAAA,IACd;AAAA,EACF,CAAC;AACH;AAUA,SAAS,aACP,KACA,MACA,cACAC,SACM;AACN,QAAM,EAAE,WAAW,YAAY,IAAI;AAEnC,MAAI;AAEF,UAAM,eACH,KAAK,MAAM,eAAe,MAC1B,KAAK,MAAM,wBAAwB,MACnC,KAAK,MAAM,4BAA4B;AAC1C;AAAA,MACE;AAAA,MACA;AAAA,MACA,wBAAwB,SAAS;AAAA,IACnC;AAKA,UAAM,eAAe,sBAAsB,IAAI,UAAU,SAAS;AAClE,uBAAmB,YAAY;AAG/B,aAAS,IAAI,aAAa,SAAS,GAAG,KAAK,GAAG,KAAK;AACjD,UAAI,aAAa,CAAC,EAAE,KAAK,SAAS,QAAQ;AACxC,QAAAC,UAAS,MAAM;AAAA,UACb;AAAA,UACA,MAAM,aAAa,CAAC,EAAE;AAAA,UACtB,OAAO,aAAa,CAAC,EAAE;AAAA,QACzB,CAAC;AACD;AAAA,MACF;AAAA,IACF;AAGA,UAAM,eAAe;AAAA,MACnB,CAAC,EAAE,MAAM,aAAa,SAAS,KAAK,QAAQ,CAAC;AAAA,MAC7C;AAAA,IACF,EAAE,CAAC;AACH,iCAA6B,cAAc,KAAK,OAAO,KAAK,KAAK;AACjE,IAAAA,UAAS,MAAM;AAAA,MACb;AAAA,MACA,MAAM,aAAa;AAAA,MACnB,OAAO,aAAa;AAAA,IACtB,CAAC;AAGD,iBAAa,sBACV,aAAa,sBAAsB,KAAK;AAG3C,2BAAuB,cAAcD,OAAM;AAAA,EAC7C,SAAS,GAAG;AACV,IAAAE,KAAI,MAAM,oCAAoC,CAAC;AAAA,EACjD;AACF;AAKA,SAAS,uBACP,cACAF,SACM;AACN,QAAM,EAAE,WAAW,YAAY,IAAI;AACnC,QAAM,MAAM,aAAaA,OAAM;AAC/B,QAAM,MAAMG,YAAW;AACvB,QAAM,QAAQ,eAAe;AAK7B,MAAI,wBAAwB,GAAG;AAC7B,IAAAC,cACG,IAAI;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO;AAAA,MACP,QAAQ;AAAA,IACV,CAAC,EACA,MAAM,CAAC,MAAMF,KAAI,MAAM,mCAAmC,CAAC,CAAC;AAAA,EACjE;AAGA,QAAM,UAAUD,UAAS,iBAAiB,aAAa,SAAS;AAChE,MAAI,WAAW,IAAI,aAAa,YAAY;AAC1C,IAAAC,KAAI;AAAA,MACF,6BAA6B,OAAO,4BAA4B,UAAU,MAAM,GAAG,EAAE,CAAC;AAAA,IACxF;AACA,IAAAE,cACG,IAAI,EAAE,KAAK,aAAa,WAAW,MAAM,CAAC,EAC1C,MAAM,CAAC,MAAMF,KAAI,MAAM,mCAAmC,CAAC,CAAC;AAAA,EACjE;AAGA,MACE,IAAI,UAAU,WACd,IAAI,QAAQ,UACZ,aAAa,sBAAsB,IAAI,QAAQ,YAC/C;AACA,IAAAG,SACG,IAAI,EAAE,KAAK,aAAa,WAAW,MAAM,CAAC,EAC1C,KAAK,MAAM;AACV,mBAAa,qBAAqB;AAElC,sBAAgB,OAAO,SAAS;AAAA,IAClC,CAAC,EACA,MAAM,CAAC,MAAMH,KAAI,MAAM,+BAA+B,CAAC,CAAC;AAAA,EAC7D;AACF;AAMA,eAAe,iBACb,KACAF,SACmB;AAEnB,QAAM,cAAc,qBAAqB,eAAe,IAAI,QAAQ,IAAI,UAAU;AAClF,QAAM,aAAa,aAAaA,OAAM;AAEtC,QAAM,EAAE,UAAU,IAAI,MAAM,gBAAgB,KAAK,WAAW;AAC5D,QAAM,eAAe,mBAAmB,WAAW,WAAW;AAC9D,QAAM,MAAM,aAAaA,OAAM;AAE/B,EAAAE,KAAI,KAAK,sCAAsC,UAAU,MAAM,GAAG,EAAE,CAAC,EAAE;AAIvE,QAAM,QAAQ,eAAe;AAC7B,QAAME,cAAa,IAAI;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO;AAAA,IACP,QAAQ;AAAA,EACV,CAAC;AAGD,QAAM,gBAAgBA,cAAa,eAAe,aAAa,SAAS;AAGxE,QAAM,kBAAkB,uBAAuB,GAAG;AAGlD,QAAM,MAAMD,YAAW;AACvB,QAAM,UAAU,IAAI,UAAU,UAC1BG,KAAI,WAAW,aAAa,IAAI,YAAY,IAC5C,CAAC;AACL,QAAM,YAAY,QAAQ,SACtB;AAAA,IACE,QAAQ,IAAI,CAAC,OAAO;AAAA,MAClB,UAAU,EAAE;AAAA,MACZ,OAAO,EAAE;AAAA,MACT,SAAS,EAAE;AAAA,IACb,EAAE;AAAA,EACJ,IACA;AAGJ,QAAM,gBAAgB,mBAAmB;AAAA,IACvC,kBAAkB,cAAc,SAAS;AAAA,IACzC;AAAA,IACA;AAAA,EACF,CAAC;AAGD,MAAI,UAAU;AACd,MAAI,cAAc,SAAS,GAAG;AAC5B,cACE;AAAA;AAAA,gBACiB,cAAc,MAAM;AAAA;AAAA,IAErC,cACG;AAAA,MACC,CAAC,GAAG,MACF,aAAa,IAAI,CAAC,GAAG,EAAE,aAAa,IAAI,oBAAoB,EAAE;AAAA,EAAK,EAAE,YAAY;AAAA,IACrF,EACC,KAAK,MAAM;AAAA,EAClB;AAGA,QAAM,cAAc,UAChB,GAAG,OAAO;AAAA;AAAA;AAAA;AAAA,EAAc,aAAa,KACrC;AAEJ,QAAM,cAAc,MAAM,IAAI,OAAO,eAAe,aAAa;AAAA,IAC/D,OAAO,IAAI;AAAA,IACX,UAAU;AAAA,IACV,QAAQ;AAAA;AAAA,EACV,CAAC;AAED,QAAM,UAAU,eAAe;AAG/B,QAAM,OAAO,wBAAwB,WAAW,SAAS,IAAI,KAAK;AAElE,MAAI,IAAI,QAAQ;AACd,WAAO,mBAAmB,IAAI;AAAA,EAChC;AACA,SAAO,sBAAsB,IAAI;AACnC;AAMA,eAAe,kBACb,KACAN,SACmB;AACnB,QAAM,mBAAmB,MAAM,kBAAkB,KAAKA,OAAM;AAG5D,MAAI,IAAI,UAAU,iBAAiB,MAAM;AACvC,WAAO,IAAI,SAAS,iBAAiB,MAAM;AAAA,MACzC,QAAQ,iBAAiB;AAAA,MACzB,SAAS;AAAA,QACP,gBACE,iBAAiB,QAAQ,IAAI,cAAc,KAC3C;AAAA,MACJ;AAAA,IACF,CAAC;AAAA,EACH;AAGA,QAAM,OAAO,MAAM,iBAAiB,KAAK;AACzC,SAAO,IAAI,SAAS,MAAM;AAAA,IACxB,QAAQ,iBAAiB;AAAA,IACzB,SAAS;AAAA,MACP,gBAAgB;AAAA,IAClB;AAAA,EACF,CAAC;AACH;AAMA,eAAe,uBACb,KACAA,SACmB;AAEnB,QAAM,cAAc,eAAe,IAAI,QAAQ,IAAI,UAAU;AAC7D,QAAM,aAAa,aAAaA,OAAM;AAGtC,QAAM,OAAO,YAAY,IAAI,UAAU;AACvC,MAAI,MAAM;AACR,oBAAgB,IAAI;AAAA,EACtB;AAGA,QAAM,EAAE,WAAW,MAAM,IAAI,MAAM,gBAAgB,KAAK,WAAW;AACnE,QAAM,eAAe,mBAAmB,WAAW,WAAW;AAG9D,MAAI,MAAM;AACR,mBAAe,WAAW,IAAI;AAAA,EAChC;AAGA,MAAI,OAAO;AACT,UAAM,cAAc,MAAM;AAAA,MACxB,IAAI,SAAS,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,EAAE,QAAQ,EAAE;AAAA,MAC9D;AAAA,QACE,OAAO,IAAI;AAAA,QACX,YAAY,OAAO,gBAAgB,IAAI,IAAI;AAAA,MAC7C;AAAA,IACF;AACA,iBAAa,cAAc;AAAA,EAC7B;AAGA,eAAa,eAAe,IAAI,SAAS;AAGzC,yBAAuB,IAAI;AAG3B,MAAI,aAAa,eAAe;AAC9B,QAAI,qBAAqB,aAAa,aAAa,GAAG;AACpD,YAAM,WAAW,oBAAoB,KAAK,aAAa,aAAa;AACpE,UAAI,UAAU;AACZ,QAAAE,KAAI;AAAA,UACF,2DAA2D,UAAU,MAAM,GAAG,EAAE,CAAC;AAAA,QACnF;AAAA,MACF,OAAO;AACL,QAAAA,KAAI;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF,OAAO;AACL,MAAAA,KAAI;AAAA,QACF,iDAAiD,UAAU,MAAM,GAAG,EAAE,CAAC;AAAA,MACzE;AAAA,IACF;AACA,iBAAa,gBAAgB;AAAA,EAC/B;AAEA,EAAAA,KAAI;AAAA,IACF,iBAAiB,UAAU,MAAM,GAAG,EAAE,CAAC,aAAa,IAAI,SAAS,MAAM,UAC5D,IAAI,KAAK,WAAW,IAAI,MAAM,QAAQ,KAAK;AAAA,EACxD;AAGA,QAAM,YAAY,aAAa,IAAI,KAAK;AACxC,iBAAe,EAAE,SAAS,UAAU,SAAS,QAAQ,UAAU,OAAO,CAAC;AAGvE,QAAM,MAAMC,YAAW;AACvB,MAAI,IAAI,OAAO,oBAAoB,QAAW;AAC5C,uBAAmB,IAAI,OAAO,eAAe;AAAA,EAC/C,WAAW,UAAU,iBAAiB,IAAI,OAAO,6BAA6B,GAAG;AAC/E,uBAAmB;AAAA,MACjB,IAAI,OAAO;AAAA,MACX,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAGA,QAAM,cAAc,IAAI,oBAAoB;AAC5C,QAAM,aAAa,aAAa,WAAW,WAAW;AACtD,MAAI,WAAW,WAAW;AACxB,oBAAgB,OAAO,SAAS;AAChC,IAAAD,KAAI;AAAA,MACF,gBAAgB,KAAK,MAAM,WAAW,SAAS,GAAM,CAAC;AAAA,IACxD;AAAA,EACF;AAGA,MAAI,iBAAiB,IAAI;AACzB,MAAI,IAAI,UAAU,SAAS;AACzB,QAAI;AACF,UAAI,SAAS,gBAAgB,IAAI,SAAS;AAE1C,UAAI,CAAC,QAAQ;AACX,cAAM,cAAc,IAAI,OAAO;AAC/B,cAAM,YAAY,aAAa,WAAW;AAC1C,cAAM,UAAUI,KAAI,WAAW,aAAa,WAAW,SAAS;AAChE,YAAI,QAAQ,QAAQ;AAClB,gBAAM,YAAY;AAAA,YAChB,QAAQ,IAAI,CAAC,OAAO;AAAA,cAClB,UAAU,EAAE;AAAA,cACZ,OAAO,EAAE;AAAA,cACT,SAAS,EAAE;AAAA,YACb,EAAE;AAAA,YACF;AAAA,UACF;AAEA,cAAI,WAAW;AACb,kBAAM,aAAa,KAAK,KAAK,UAAU,SAAS,CAAC;AACjD,qBAAS,EAAE,WAAW,WAAW;AACjC,4BAAgB,IAAI,WAAW,MAAM;AAAA,UACvC;AAAA,QACF;AAAA,MACF;AAEA,UAAI,QAAQ;AACV,qBAAa,OAAO,YAAY,SAAS;AACzC,yBAAiB,GAAG,IAAI,MAAM;AAAA;AAAA,EAAO,OAAO,SAAS;AAAA,MACvD,OAAO;AACL,qBAAa,GAAG,SAAS;AAAA,MAC3B;AAAA,IACF,SAAS,GAAG;AACV,MAAAJ,KAAI,MAAM,yBAAyB,CAAC;AACpC,mBAAa,GAAG,SAAS;AAAA,IAC3B,UAAE;AACA,2BAAqB,SAAS;AAAA,IAChC;AAAA,EACF,OAAO;AACL,iBAAa,GAAG,SAAS;AACzB,yBAAqB,SAAS;AAAA,EAChC;AAGA,MAAI,WAAW,GAAG;AAChB,sBACE;AAAA,EAIJ;AAGA,MAAI,IAAI,UAAU,SAAS;AACzB,UAAM,eAAe,CAAC,UAAU;AAChC,QAAI,IAAI,WAAW,QAAS,cAAa,KAAK,IAAI,WAAW,IAAI;AACjE,sBACE;AAAA;AAAA,2CAAgD,aAAa,KAAK,OAAO,CAAC;AAAA,EAG9E;AAGA,QAAM,eAAe,sBAAsB,IAAI,UAAU,SAAS;AAClE,qBAAmB,YAAY;AAE/B,QAAM,SAAS,UAAU;AAAA,IACvB,UAAU;AAAA,IACV;AAAA,IACA;AAAA,EACF,CAAC;AAGD,SACE,OAAO,SAAS,SAAS,KACzB,OAAO,SAAS,GAAG,EAAE,EAAG,KAAK,SAAS,QACtC;AACA,UAAM,OAAO,OAAO,SAAS,GAAG,EAAE;AAClC,UAAM,eAAe,KAAK,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM;AAC7D,QAAI,aAAc;AAClB,WAAO,SAAS,IAAI;AAAA,EACtB;AAOA,QAAM,sBAAsB,sBAAsB,OAAO,QAAQ;AACjE,4BAA0B,mBAAmB;AAE7C,QAAM,cAA8B;AAAA,IAClC,GAAG;AAAA,IACH,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ;AAMA,MAAI,YAAY,MAAM,SAAS,KAAK,CAAC,oBAAoB,YAAY,KAAK,GAAG;AAC3E,gBAAY,QAAQ,CAAC,GAAG,YAAY,OAAO,mBAAmB;AAAA,EAChE;AAQA,QAAM,eAAsC;AAAA,IAC1C,WAAW;AAAA,IACX,mBAAmB;AAAA,EACrB;AACA,QAAM,mBAAmB,MAAM;AAAA,IAC7B;AAAA,IACAF;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,MAAI,CAAC,iBAAiB,IAAI;AACxB,UAAM,YAAY,MAAM,iBAAiB,KAAK;AAC9C,IAAAE,KAAI;AAAA,MACF,mBAAmB,iBAAiB,MAAM,IAAI,UAAU,MAAM,GAAG,GAAG,CAAC;AAAA,IACvE;AACA,WAAO,IAAI,SAAS,WAAW;AAAA,MAC7B,QAAQ,iBAAiB;AAAA,MACzB,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAChD,CAAC;AAAA,EACH;AAEA,MAAI,IAAI,UAAU,iBAAiB,MAAM;AAGvC,UAAM,gBAAgB,YAAY,MAAM;AAAA,MACtC,CAAC,MAAM,EAAE,SAAS;AAAA,IACpB;AACA,WAAO;AAAA,MACL;AAAA,MACA,CAACK,UAAS,aAAa,KAAKA,OAAM,cAAcP,OAAM;AAAA,MACtD,gBACI,EAAE,aAAa,QAAAA,SAAQ,cAAc,aAAa,IAClD;AAAA,IACN;AAAA,EACF;AAGA,QAAM,OAAO,MAAM,4BAA4B,gBAAgB;AAG/D,MAAI,iBAAiB,IAAI,GAAG;AAC1B,UAAM,cAAc,kBAAkB,IAAI;AAC1C,UAAM,EAAE,QAAAQ,SAAQ,MAAM,IAAI,MAAM;AAAA,MAC9B;AAAA,MACA,aAAa;AAAA,MACb,aAAa;AAAA,IACf;AAEA,QAAI,gBAAgB,IAAI,GAAG;AAEzB,YAAM,WAAW,KAAK,QAAQ,QAAQ,WAAW;AACjD,mBAAa,gBAAgB;AAAA,QAC3B,WAAW,YAAY;AAAA,QACvB;AAAA,QACA;AAAA,QACA,QAAAA;AAAA,QACA,WAAW,KAAK,IAAI;AAAA,MACtB;AACA,MAAAN,KAAI;AAAA,QACF,iEAAiE,aAAa,UAAU,MAAM,GAAG,EAAE,CAAC;AAAA,MACtG;AACA,YAAM,YAAY,wBAAwB,IAAI;AAC9C,mBAAa,KAAK,WAAW,cAAcF,OAAM;AACjD,aAAO,sBAAsB,SAAS;AAAA,IACxC;AAGA,IAAAE,KAAI;AAAA,MACF,8DAA8D,aAAa,UAAU,MAAM,GAAG,EAAE,CAAC;AAAA,IACnG;AACA,UAAM,WAAW,oBAAoB,aAAa,MAAMM,SAAQ,WAAW;AAE3E,UAAM,mBAAmB,MAAM;AAAA,MAC7B;AAAA,MACAR;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,QAAI,CAAC,iBAAiB,IAAI;AACxB,YAAM,YAAY,MAAM,iBAAiB,KAAK;AAC9C,MAAAE,KAAI;AAAA,QACF,oCAAoC,iBAAiB,MAAM,IAAI,UAAU,MAAM,GAAG,GAAG,CAAC;AAAA,MACxF;AAEA,YAAM,YAAY,wBAAwB,IAAI;AAC9C,mBAAa,KAAK,WAAW,cAAcF,OAAM;AACjD,aAAO,sBAAsB,SAAS;AAAA,IACxC;AAEA,UAAM,mBAAmB,MAAM,4BAA4B,gBAAgB;AAG3E,qBAAiB,MAAM,eAAe,KAAK,MAAM;AACjD,qBAAiB,MAAM,gBAAgB,KAAK,MAAM;AAClD,QAAI,KAAK,MAAM,sBAAsB;AACnC,uBAAiB,MAAM,wBACpB,iBAAiB,MAAM,wBAAwB,KAChD,KAAK,MAAM;AAAA,IACf;AACA,QAAI,KAAK,MAAM,0BAA0B;AACvC,uBAAiB,MAAM,4BACpB,iBAAiB,MAAM,4BAA4B,KACpD,KAAK,MAAM;AAAA,IACf;AAEA,iBAAa,KAAK,kBAAkB,cAAcA,OAAM;AACxD,WAAO,sBAAsB,gBAAgB;AAAA,EAC/C;AAEA,eAAa,KAAK,MAAM,cAAcA,OAAM;AAC5C,SAAO,sBAAsB,IAAI;AACnC;AAwBO,SAAS,sBACd,UACuE;AACvE,QAAM,MAGD,CAAC;AAIN,MAAI,qBAA4C,CAAC;AAEjD,aAAW,OAAO,UAAU;AAC1B,UAAM,UAAiC,CAAC;AAExC,QAAI,IAAI,KAAK,SAAS,QAAQ;AAE5B,cAAQ,KAAK,GAAG,kBAAkB;AAClC,2BAAqB,CAAC;AAAA,IACxB,OAAO;AAGL,2BAAqB,CAAC;AAAA,IACxB;AAEA,eAAW,QAAQ,IAAI,OAAO;AAC5B,cAAQ,KAAK,MAAM;AAAA,QACjB,KAAK;AACH,kBAAQ,KAAK;AAAA,YACX,MAAM;AAAA,YACN,MAAO,KAA0B;AAAA,UACnC,CAAC;AACD;AAAA,QACF,KAAK;AACH,kBAAQ,KAAK;AAAA,YACX,MAAM;AAAA,YACN,UAAW,KAA0B,QAAQ;AAAA,UAC/C,CAAC;AACD;AAAA,QACF,KAAK,QAAQ;AACX,gBAAM,WAAW;AAWjB,cAAI,SAAS,SAAS,UAAU;AAG9B,oBAAQ,KAAK;AAAA,cACX,MAAM;AAAA,cACN,WAAW,SAAS;AAAA,cACpB,SAAS,SAAS,MAAM,UAAU;AAAA,YACpC,CAAC;AAAA,UACH,OAAO;AAEL,oBAAQ,KAAK;AAAA,cACX,MAAM;AAAA,cACN,IAAI,SAAS;AAAA,cACb,MAAM,SAAS;AAAA,cACf,OAAO,SAAS,MAAM,SAAS,CAAC;AAAA,YAClC,CAAC;AAID,gBAAI,SAAS,MAAM,WAAW,aAAa;AACzC,iCAAmB,KAAK;AAAA,gBACtB,MAAM;AAAA,gBACN,WAAW,SAAS;AAAA,gBACpB,SAAS,SAAS,MAAM,UAAU;AAAA,cACpC,CAAC;AAAA,YACH,WAAW,SAAS,MAAM,WAAW,SAAS;AAC5C,iCAAmB,KAAK;AAAA,gBACtB,MAAM;AAAA,gBACN,WAAW,SAAS;AAAA,gBACpB,SAAS,SAAS,MAAM,SAAS;AAAA,gBACjC,SAAS;AAAA,cACX,CAAC;AAAA,YACH;AAAA,UAIF;AACA;AAAA,QACF;AAAA;AAAA,QAEA;AACE,cAAI,UAAU,QAAQ,OAAO,KAAK,SAAS,UAAU;AACnD,oBAAQ,KAAK,EAAE,MAAM,QAAQ,MAAM,KAAK,KAAK,CAAC;AAAA,UAChD;AACA;AAAA,MACJ;AAAA,IACF;AAEA,QAAI,KAAK,EAAE,MAAM,IAAI,KAAK,MAA8B,QAAQ,CAAC;AAAA,EACnE;AAEA,SAAO;AACT;AAiBO,SAAS,0BACd,UAIM;AACN,WAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,UAAM,MAAM,SAAS,CAAC;AACtB,QAAI,IAAI,SAAS,OAAQ;AACzB,QAAI,CAAC,IAAI,QAAQ,KAAK,CAAC,MAAM,EAAE,SAAS,aAAa,EAAG;AAGxD,UAAM,OACJ,IAAI,KAAK,SAAS,IAAI,CAAC,EAAG,SAAS,cAC/B,SAAS,IAAI,CAAC,IACd;AACN,UAAM,aAAa,IAAI;AAAA,OACpB,MAAM,WAAW,CAAC,GAChB,OAAO,CAAC,MAAgC,EAAE,SAAS,UAAU,EAC7D,IAAI,CAAC,MAAM,EAAE,EAAE;AAAA,IACpB;AAGA,UAAM,SAAS,IAAI,QAAQ;AAC3B,QAAI,UAAU,IAAI,QAAQ;AAAA,MACxB,CAAC,MACC,EAAE,SAAS,iBACX,WAAW,IAAK,EAA6B,SAAS;AAAA,IAC1D;AACA,QAAI,IAAI,QAAQ,SAAS,QAAQ;AAC/B,MAAAE,KAAI;AAAA,QACF,WAAW,SAAS,IAAI,QAAQ,MAAM,+CAA+C,CAAC;AAAA,MACxF;AAAA,IACF;AAGA,QAAI,IAAI,QAAQ,WAAW,GAAG;AAC5B,UAAI,UAAU,CAAC,EAAE,MAAM,QAAQ,MAAM,0BAA0B,CAAC;AAAA,IAClE;AAAA,EACF;AACF;AAMA,SAAS,cAAc,QAAgB,SAA2B;AAChE,SAAO,IAAI;AAAA,IACT,KAAK,UAAU;AAAA,MACb,MAAM;AAAA,MACN,OAAO;AAAA,QACL,MAAM;AAAA,QACN;AAAA,MACF;AAAA,IACF,CAAC;AAAA,IACD;AAAA,MACE;AAAA,MACA,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAChD;AAAA,EACF;AACF;AAYA,eAAsB,cACpB,KACAF,SACmB;AACnB,MAAI;AAEF,UAAM,YAAY,YAAY,IAAI,UAAU;AAC5C,QAAI,WAAW;AACb,sBAAgB,SAAS;AAAA,IAC3B;AAGA,QAAI,oBAAoB,GAAG,GAAG;AAC5B,aAAO,MAAM,iBAAiB,KAAKA,OAAM;AAAA,IAC3C;AAGA,QAAI,wBAAwB,GAAG,GAAG;AAChC,aAAO,MAAM,kBAAkB,KAAKA,OAAM;AAAA,IAC5C;AAGA,WAAO,MAAM,uBAAuB,KAAKA,OAAM;AAAA,EACjD,SAAS,KAAK;AACZ,UAAM,UACJ,eAAe,QAAQ,IAAI,UAAU;AACvC,IAAAE,KAAI,MAAM,mBAAmB,GAAG;AAChC,WAAO,cAAc,KAAK,OAAO;AAAA,EACnC;AACF;;;AS7iDA,IAAI,UAAU;AACd,IAAI;AAEF,QAAM,MAAM;AACZ,MAAI,IAAI,QAAS,WAAU,IAAI;AACjC,QAAQ;AAER;AAMA,IAAM,eAAuC;AAAA,EAC3C,+BAA+B;AAAA,EAC/B,gCAAgC;AAAA,EAChC,gCAAgC;AAAA,EAChC,0BAA0B;AAC5B;AAEA,SAAS,SAAS,UAA8B;AAC9C,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,YAAY,GAAG;AACvD,aAAS,QAAQ,IAAI,KAAK,KAAK;AAAA,EACjC;AACA,SAAO;AACT;AAOA,SAAS,gBAAgB,SAA0C;AACjE,QAAM,SAAiC,CAAC;AACxC,UAAQ,QAAQ,CAAC,OAAO,QAAQ;AAC9B,WAAO,GAAG,IAAI;AAAA,EAChB,CAAC;AACD,SAAO;AACT;AAEA,SAAS,aAAa,MAAe,SAAS,KAAe;AAC3D,SAAO;AAAA,IACL,IAAI,SAAS,KAAK,UAAU,IAAI,GAAG;AAAA,MACjC;AAAA,MACA,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAChD,CAAC;AAAA,EACH;AACF;AAEA,SAASO,eACP,QACA,MACA,SACU;AACV,SAAO;AAAA,IACL;AAAA,MACE,MAAM;AAAA,MACN,OAAO,EAAE,MAAM,QAAQ;AAAA,IACzB;AAAA,IACA;AAAA,EACF;AACF;AAMA,eAAe,wBACb,KACAC,SACmB;AACnB,MAAI;AACJ,MAAI;AACF,WAAO,MAAM,IAAI,KAAK;AAAA,EACxB,QAAQ;AACN,WAAOD,eAAc,KAAK,yBAAyB,mBAAmB;AAAA,EACxE;AAEA,MAAI;AACJ,MAAI;AACF,iBAAa,sBAAsB,MAAM,gBAAgB,IAAI,OAAO,CAAC;AAAA,EACvE,SAAS,GAAG;AACV,UAAM,MAAM,aAAa,QAAQ,EAAE,UAAU;AAC7C,WAAOA,eAAc,KAAK,yBAAyB,GAAG;AAAA,EACxD;AAEA,MAAI;AACF,UAAM,SAAS,MAAM,cAAc,YAAYC,OAAM;AAErD,WAAO,SAAS,MAAM;AAAA,EACxB,SAAS,GAAG;AACV,UAAM,MAAM,aAAa,QAAQ,EAAE,UAAU;AAC7C,YAAQ,MAAM,0BAA0B,GAAG,EAAE;AAC7C,WAAOD,eAAc,KAAK,aAAa,2BAA2B,GAAG,EAAE;AAAA,EACzE;AACF;AAEA,eAAe,wBAAwBC,SAA0C;AAC/E,MAAI;AACF,UAAM,WAAW,MAAM,MAAM,GAAGA,QAAO,iBAAiB,cAAc;AAAA,MACpE,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAChD,CAAC;AAED,UAAM,WAAW,IAAI,SAAS,SAAS,MAAM;AAAA,MAC3C,QAAQ,SAAS;AAAA,MACjB,YAAY,SAAS;AAAA,MACrB,SAAS,IAAI,QAAQ,SAAS,OAAO;AAAA,IACvC,CAAC;AACD,WAAO,SAAS,QAAQ;AAAA,EAC1B,SAAS,GAAG;AACV,UAAM,MAAM,aAAa,QAAQ,EAAE,UAAU;AAC7C,WAAOD,eAAc,KAAK,aAAa,2BAA2B,GAAG,EAAE;AAAA,EACzE;AACF;AAEA,SAAS,eAAyB;AAChC,SAAO,aAAa,EAAE,QAAQ,MAAM,QAAQ,CAAC;AAC/C;AAEA,eAAe,4BACb,KACAC,SACmB;AACnB,MAAI;AACJ,MAAI;AACF,WAAO,MAAM,IAAI,KAAK;AAAA,EACxB,QAAQ;AACN,WAAOD,eAAc,KAAK,yBAAyB,mBAAmB;AAAA,EACxE;AAEA,MAAI;AACJ,MAAI;AACF,iBAAa,mBAAmB,MAAM,gBAAgB,IAAI,OAAO,CAAC;AAAA,EACpE,SAAS,GAAG;AACV,UAAM,MAAM,aAAa,QAAQ,EAAE,UAAU;AAC7C,WAAOA,eAAc,KAAK,yBAAyB,GAAG;AAAA,EACxD;AAEA,MAAI;AACJ,MAAI;AACF,mBAAe,MAAM,cAAc,YAAYC,OAAM;AAAA,EACvD,SAAS,GAAG;AACV,UAAM,MAAM,aAAa,QAAQ,EAAE,UAAU;AAC7C,YAAQ,MAAM,0BAA0B,GAAG,EAAE;AAC7C,WAAOD,eAAc,KAAK,aAAa,2BAA2B,GAAG,EAAE;AAAA,EACzE;AAIA,MAAI,CAAC,aAAa,IAAI;AAEpB,WAAO,SAAS,YAAY;AAAA,EAC9B;AAEA,QAAM,cAAc,aAAa,QAAQ,IAAI,cAAc,KAAK;AAChE,MAAI,YAAY,SAAS,mBAAmB,GAAG;AAE7C,UAAM,cAAc,MAAM,sBAAsB,YAAY;AAC5D,WAAO,SAAS,oBAAoB,aAAa,IAAI,CAAC;AAAA,EACxD;AAGA,QAAM,WAAW,MAAM,aAAa,KAAK;AACzC,SAAO,SAAS,oBAAoB,UAAU,KAAK,CAAC;AACtD;AAMO,SAAS,YAAYC,SAG1B;AACA,QAAMC,UAAS,IAAI,MAAM;AAAA,IACvB,MAAMD,QAAO;AAAA,IACb,UAAUA,QAAO;AAAA,IAEjB,MAAM,MAAM,KAAiC;AAC3C,YAAM,MAAM,IAAI,IAAI,IAAI,GAAG;AAC3B,YAAM,EAAE,SAAS,IAAI;AACrB,YAAM,SAAS,IAAI;AAGnB,UAAI,WAAW,WAAW;AACxB,eAAO,SAAS,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC,CAAC;AAAA,MACrD;AAEA,UAAIA,QAAO,OAAO;AAChB,gBAAQ,MAAM,UAAU,MAAM,IAAI,QAAQ,EAAE;AAAA,MAC9C;AAEA,UAAI;AAEF,YAAI,WAAW,UAAU,aAAa,gBAAgB;AACpD,iBAAO,MAAM,wBAAwB,KAAKA,OAAM;AAAA,QAClD;AAGA,YAAI,WAAW,UAAU,aAAa,wBAAwB;AAC5D,iBAAO,MAAM,4BAA4B,KAAKA,OAAM;AAAA,QACtD;AAGA,YAAI,WAAW,SAAS,aAAa,cAAc;AACjD,iBAAO,MAAM,wBAAwBA,OAAM;AAAA,QAC7C;AAGA,YAAI,WAAW,SAAS,aAAa,WAAW;AAC9C,iBAAO,aAAa;AAAA,QACtB;AAGA,eAAOD,eAAc,KAAK,aAAa,gBAAgB,MAAM,IAAI,QAAQ,EAAE;AAAA,MAC7E,SAAS,GAAG;AACV,cAAM,MAAM,aAAa,QAAQ,EAAE,UAAU;AAC7C,gBAAQ,MAAM,0BAA0B,GAAG,EAAE;AAC7C,eAAOA,eAAc,KAAK,aAAa,GAAG;AAAA,MAC5C;AAAA,IACF;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL,MAAM,MAAME,QAAO,KAAK;AAAA,IACxB,MAAMA,QAAO,QAAQD,QAAO;AAAA,EAC9B;AACF;;;ACtOA,IAAM,SAAS,WAAW;AAC1B,IAAM,SAAS,YAAY,MAAM;AAEjC,IAAM,OAAO,UAAU,OAAO,IAAI,IAAI,OAAO,IAAI;AACjD,QAAQ,MAAM,+BAA+B,IAAI,EAAE;AACnD,QAAQ,MAAM,0GAAsF;AACpG,QAAQ,MAAM,wEAAmE;AAMjF,eAAe,WAAW;AACxB,UAAQ,MAAM,4BAAuB;AACrC,SAAO,KAAK;AAEZ,QAAM,mBAAmB;AACzB,UAAQ,KAAK,CAAC;AAChB;AAEA,QAAQ,GAAG,UAAU,MAAM,SAAS,CAAC;AACrC,QAAQ,GAAG,WAAW,MAAM,SAAS,CAAC;",
|
|
6
|
+
"names": ["loreConfig", "temporal", "ltm", "distillation", "curator", "log", "log", "log", "temporal", "log", "loreConfig", "log", "log", "config", "sessions", "log", "loreConfig", "log", "temporal", "log", "loreConfig", "config", "loreConfig", "log", "config", "temporal", "log", "loreConfig", "distillation", "curator", "ltm", "resp", "result", "errorResponse", "config", "server"]
|
|
7
|
+
}
|