Files
OpenCode 68a9071cf1 feat: reconcile local master with origin (exa/hot-platform hunters, leaks ledger, latest results)
Local branch had diverged from origin/master (sibling commits on the same base). Rewrote local history linearly on top of origin/master, folding in all local content: exa/hot-platform discovery hunters, leaks ledger, nightly sweep orchestrator, updated .gitignore and skill docs, plus the latest hunt output and vault state. Remote-only files (vault keys, channel scripts) were restored rather than dropped, so the resulting tree is a full union of both sides.
2026-08-07 12:53:47 +08:00

1 line
23 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"repo": "asi-integration/asi-landing", "files": {"src/lib/communication/llm-router/provider.ts": {"6c6af6421aa8ae28857f6fb54011bf59faa1e04a": {"t": 1786067414.9725356, "n": 11046, "h": "ef8ea1f57264f0d0", "c": "import {\n createChatCompletionsLlmRouterProvider,\n createDeepSeekLlmRouterProvider,\n} from './deepseek-provider';\nimport { validateLlmRouterDecision } from './validate-llm-router-decision';\nimport type {\n LlmRouterAttemptAudit,\n LlmRouterChainResult,\n LlmRouterDecision,\n LlmRouterInput,\n LlmRouterProvider,\n LlmRouterProviderName,\n} from './types';\n\ntype ProviderRole = 'primary' | 'secondary' | 'premium' | 'fixed';\n\ntype StickyProvider = {\n provider: LlmRouterProviderName;\n expiresAt: number;\n remainingMessages: number;\n};\n\nconst stickyProviders = new Map<string, StickyProvider>();\n\nfunction cleanKeyPart(value: string | undefined): string | undefined {\n const trimmed = value?.trim();\n return trimmed ? trimmed.slice(0, 160) : undefined;\n}\n\nfunction stickyProviderKey(input: LlmRouterInput): string | undefined {\n const bookingId = cleanKeyPart(input.bookingId);\n if (bookingId) return `booking:${bookingId}`;\n\n const conversationId = cleanKeyPart(input.conversationId);\n if (conversationId) return `conversation:${conversationId}`;\n\n const sessionId = cleanKeyPart(input.sessionId);\n if (sessionId) return `session:${sessionId}`;\n\n const chatId = cleanKeyPart(input.chatId);\n if (chatId) return `chat:${chatId}`;\n\n return undefined;\n}\n\nexport function createDisabledLlmRouterProvider(): LlmRouterProvider {\n return {\n name: 'disabled',\n modelName: 'disabled',\n async classifyGuestMessage(_input: LlmRouterInput) {\n throw new Error('llm_router_disabled');\n },\n };\n}\n\nfunction num(value: string | undefined, fallback: number): number {\n const parsed = Number(value);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;\n}\n\nfunction nonNegativeNum(value: string | undefined, fallback: number): number {\n const parsed = Number(value);\n return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback;\n}\n\nfunction bool(value: string | undefined, fallback: boolean): boolean {\n if (value === undefined) return fallback;\n return value === 'true' || value === '1';\n}\n\nfunction providerFromName(name: LlmRouterProviderName, role: ProviderRole): LlmRouterProvider {\n if (name === 'deepseek') {\n const apiKey = process.env.DEEPSEEK_API_KEY;\n if (!apiKey) return createDisabledLlmRouterProvider();\n return createDeepSeekLlmRouterProvider({\n apiKey,\n baseUrl: process.env.DEEPSEEK_BASE_URL || 'https://api.deepseek.com',\n model: process.env.DEEPSEEK_MODEL || 'deepseek-v4-flash',\n timeoutMs: num(\n role === 'primary' ? process.env.LLM_ROUTER_PRIMARY_TIMEOUT_MS : process.env.LLM_ROUTER_TIMEOUT_MS,\n role === 'primary' ? 5000 : 6000,\n ),\n maxRetries: nonNegativeNum(process.env.LLM_ROUTER_MAX_RETRIES, 1),\n });\n }\n\n if (name === 'openai' || name === 'openai-premium') {\n const apiKey = process.env.OPENAI_API_KEY ?? process.env.LLM_API_KEY;\n if (!apiKey) return createDisabledLlmRouterProvider();\n return createChatCompletionsLlmRouterProvider({\n providerName: name,\n apiKey,\n baseUrl: process.env.OPENAI_BASE_URL || process.env.LLM_BASE_URL || 'https://api.openai.com/v1',\n model:\n name === 'openai-premium'\n ? process.env.OPENAI_PREMIUM_MODEL || 'gpt-5-mini'\n : process.env.OPENAI_MODEL || 'gpt-5-nano',\n timeoutMs: num(\n role === 'primary' ? process.env.LLM_ROUTER_PRIMARY_TIMEOUT_MS : process.env.LLM_ROUTER_SECONDARY_TIMEOUT_MS,\n role === 'primary' ? 5000 : 6000,\n ),\n maxRetries: nonNegativeNum(process.env.LLM_ROUTER_MAX_RETRIES, 1),\n });\n }\n\n return createDisabledLlmRouterProvider();\n}\n\nexport function getConfiguredLlmRouterProvider(): LlmRouterProvider {\n const legacy = process.env.LLM_ROUTER_PROVIDER as LlmRouterProviderName | undefined;\n const configured = (legacy ?? process.env.LLM_ROUTER_PRIMARY_PROVIDER ?? 'disabled').toLowerCase() as LlmRouterProviderName;\n return providerFromName(configured, 'fixed');\n}\n\nexport function getConfiguredLlmRouterProviderChain(input: LlmRouterInput): Array<{\n role: ProviderRole;\n provider: LlmRouterProvider;\n}> {\n const mode = String(process.env.LLM_ROUTER_MODE ?? 'fixed').toLowerCase();\n if (mode !== 'auto' || !bool(process.env.LLM_ROUTER_AUTO_FALLBACK_ENABLED, true)) {\n return [{ role: 'fixed', provider: getConfiguredLlmRouterProvider() }];\n }\n\n const primaryName = (process.env.LLM_ROUTER_PRIMARY_PROVIDER ?? process.env.LLM_ROUTER_PROVIDER ?? 'deepseek').toLowerCase() as LlmRouterProviderName;\n const secondaryName = (process.env.LLM_ROUTER_SECONDARY_PROVIDER ?? 'openai').toLowerCase() as LlmRouterProviderName;\n const premiumName = (process.env.LLM_ROUTER_TERTIARY_PROVIDER ?? 'openai-premium').toLowerCase() as LlmRouterProviderName;\n const chain: Array<{ role: ProviderRole; provider: LlmRouterProvider }> = [];\n\n const stickyKey = stickyProviderKey(input);\n const sticky = stickyKey ? stickyProviders.get(stickyKey) : undefined;\n if (sticky && sticky.expiresAt > Date.now() && sticky.remainingMessages > 0) {\n sticky.remainingMessages -= 1;\n chain.push({ role: 'secondary', provider: providerFromName(sticky.provider, 'secondary') });\n } else {\n if (stickyKey && sticky) stickyProviders.delete(stickyKey);\n chain.push({ role: 'primary', provider: providerFromName(primaryName, 'primary') });\n }\n\n if (input.forceStrongerProvider && chain[0]?.provider.name === 'deepseek') {\n chain.unshift({ role: 'secondary', provider: providerFromName(secondaryName, 'secondary') });\n }\n\n chain.push({ role: 'secondary', provider: providerFromName(secondaryName, 'secondary') });\n chain.push({ role: 'premium', provider: providerFromName(premiumName, 'premium') });\n\n const seen = new Set<string>();\n return chain.filter(({ provider }) => {\n const key = `${provider.name}:${provider.modelName ?? ''}`;\n if (provider.name === 'disabled' || seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n\nexport async function classifyWithConfiguredLlmRouter(input: LlmRouterInput): Promise<LlmRouterChainResult> {\n const chain = getConfiguredLlmRouterProviderChain(input);\n const maxAttempts =\n String(process.env.LLM_ROUTER_MODE ?? 'fixed').toLowerCase() === 'auto'\n ? num(process.env.LLM_ROUTER_MAX_PROVIDER_ATTEMPTS, 2)\n : 1;\n const attempts: LlmRouterAttemptAudit[] = [];\n\n const stickyKey = stickyProviderKey(input);\n const sticky = stickyKey ? stickyProviders.get(stickyKey) : undefined;\n if (sticky && sticky.expiresAt > Date.now() && sticky.remainingMessages >= 0) {\n attempts.push({\n marker: 'LLM_ROUTER_STICKY_PROVIDER_USED',\n provider: sticky.provider,\n validation: 'skipped',\n fallbackPath: 'sticky_provider',\n });\n }\n\n for (const { role, provider } of chain.slice(0, maxAttempts)) {\n const usedMarker: LlmRouterAttemptAudit['marker'] =\n role === 'primary'\n ? 'LLM_ROUTER_PRIMARY_USED'\n : role === 'premium'\n ? 'LLM_ROUTER_PREMIUM_USED'\n : 'LLM_ROUTER_SECONDARY_USED';\n const started = Date.now();\n const usedAttempt: LlmRouterAttemptAudit = {\n marker: usedMarker,\n provider: provider.name,\n modelName: provider.modelName,\n validation: 'skipped',\n fallbackPath: role,\n };\n attempts.push(usedAttempt);\n\n try {\n const decision = await provider.classifyGuestMessage(input);\n const validation = validateRouterQuality(input, decision);\n const latencyMs = Date.now() - started;\n if (validation.ok) {\n Object.assign(usedAttempt, {\n provider: provider.name,\n modelName: provider.modelName,\n latencyMs,\n normalizedIntent: decision.intent,\n confidence: decision.confidence,\n validation: 'accepted',\n fallbackPath: role,\n finalActionType: decision.actionType,\n finalShouldEscalate: decision.shouldEscalate,\n });\n setStickyProvider(input, provider, role, attempts);\n return { ok: true, decision, provider: provider.name, modelName: provider.modelName, attempts };\n }\n\n attempts.push({\n marker: role === 'primary' ? 'LLM_ROUTER_PRIMARY_FAILED' : 'LLM_ROUTER_VALIDATION_FAILED',\n provider: provider.name,\n modelName: provider.modelName,\n latencyMs,\n failureReason: validation.reason,\n normalizedIntent: decision.intent,\n confidence: decision.confidence,\n validation: validation.reason === 'low_confidence' ? 'low_confidence' : 'rejected',\n fallbackPath: role,\n finalActionType: decision.actionType,\n finalShouldEscalate: decision.shouldEscalate,\n });\n } catch (error) {\n attempts.push({\n marker: role === 'primary' ? 'LLM_ROUTER_PRIMARY_FAILED' : 'LLM_ROUTER_VALIDATION_FAILED',\n provider: provider.name,\n modelName: provider.modelName,\n latencyMs: Date.now() - started,\n failureReason: error instanceof Error ? error.message.slice(0, 80) : 'provider_failed',\n validation: 'provider_failed',\n fallbackPath: role,\n });\n }\n }\n\n attempts.push({\n marker: 'LLM_ROUTER_SAFE_FALLBACK_USED',\n provider: 'disabled',\n validation: 'skipped',\n fallbackPath: 'safe_fallback',\n });\n return { ok: false, reason: 'all_providers_failed', attempts };\n}\n\nfunction validateRouterQuality(\n input: LlmRouterInput,\n decision: LlmRouterDecision,\n): { ok: true } | { ok: false; reason: string } {\n const strict = validateLlmRouterDecision(decision);\n if (!strict.ok) return { ok: false, reason: strict.reason };\n if (decision.confidence < 0.7) return { ok: false, reason: 'low_confidence' };\n if (isUrgentAccessText(input.messageText) && !(decision.intent === 'access_problem' && decision.shouldEscalate)) {\n return { ok: false, reason: 'urgent_access_not_escalated' };\n }\n if (input.forceStrongerProvider && decision.intent === 'unknown') {\n return { ok: false, reason: 'misunderstanding_loop_unknown' };\n }\n return { ok: true };\n}\n\nfunction isUrgentAccessText(text: string): boolean {\n const normalized = text.toLocaleLowerCase('ru-RU');\n return /(стою|у\\s+двери|снаружи|не\\s+могу\\s+(попасть|войти|зайти)|код\\s+не\\s+работает|дверь\\s+не\\s+открывается|замок\\s+не\\s+открывается)/i.test(\n normalized,\n );\n}\n\nfunction setStickyProvider(\n input: LlmRouterInput,\n provider: LlmRouterProvider,\n role: ProviderRole,\n attempts: LlmRouterAttemptAudit[],\n): void {\n const stickyKey = stickyProviderKey(input);\n if (!stickyKey || role === 'primary' || provider.name === 'disabled' || provider.name === 'deepseek') return;\n stickyProviders.set(stickyKey, {\n provider: provider.name,\n expiresAt: Date.now() + num(process.env.LLM_ROUTER_STICKY_PROVIDER_TTL_MINUTES, 15) * 60_000,\n remainingMessages: 5,\n });\n attempts.push({\n marker: 'LLM_ROUTER_STICKY_PROVIDER_SET',\n provider: provider.name,\n modelName: provider.modelName,\n validation: 'accepted',\n fallbackPath: 'sticky_provider',\n });\n}\n\nexport function __resetLlmRouterStickyProvidersForTests(): void {\n stickyProviders.clear();\n}\n"}, "5c944cc88e5668f6d74c31b8de58f01d5dcfd6a6": {"t": 1786068276.4410396, "n": 11046, "h": "ef8ea1f57264f0d0", "c": "import {\n createChatCompletionsLlmRouterProvider,\n createDeepSeekLlmRouterProvider,\n} from './deepseek-provider';\nimport { validateLlmRouterDecision } from './validate-llm-router-decision';\nimport type {\n LlmRouterAttemptAudit,\n LlmRouterChainResult,\n LlmRouterDecision,\n LlmRouterInput,\n LlmRouterProvider,\n LlmRouterProviderName,\n} from './types';\n\ntype ProviderRole = 'primary' | 'secondary' | 'premium' | 'fixed';\n\ntype StickyProvider = {\n provider: LlmRouterProviderName;\n expiresAt: number;\n remainingMessages: number;\n};\n\nconst stickyProviders = new Map<string, StickyProvider>();\n\nfunction cleanKeyPart(value: string | undefined): string | undefined {\n const trimmed = value?.trim();\n return trimmed ? trimmed.slice(0, 160) : undefined;\n}\n\nfunction stickyProviderKey(input: LlmRouterInput): string | undefined {\n const bookingId = cleanKeyPart(input.bookingId);\n if (bookingId) return `booking:${bookingId}`;\n\n const conversationId = cleanKeyPart(input.conversationId);\n if (conversationId) return `conversation:${conversationId}`;\n\n const sessionId = cleanKeyPart(input.sessionId);\n if (sessionId) return `session:${sessionId}`;\n\n const chatId = cleanKeyPart(input.chatId);\n if (chatId) return `chat:${chatId}`;\n\n return undefined;\n}\n\nexport function createDisabledLlmRouterProvider(): LlmRouterProvider {\n return {\n name: 'disabled',\n modelName: 'disabled',\n async classifyGuestMessage(_input: LlmRouterInput) {\n throw new Error('llm_router_disabled');\n },\n };\n}\n\nfunction num(value: string | undefined, fallback: number): number {\n const parsed = Number(value);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;\n}\n\nfunction nonNegativeNum(value: string | undefined, fallback: number): number {\n const parsed = Number(value);\n return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback;\n}\n\nfunction bool(value: string | undefined, fallback: boolean): boolean {\n if (value === undefined) return fallback;\n return value === 'true' || value === '1';\n}\n\nfunction providerFromName(name: LlmRouterProviderName, role: ProviderRole): LlmRouterProvider {\n if (name === 'deepseek') {\n const apiKey = process.env.DEEPSEEK_API_KEY;\n if (!apiKey) return createDisabledLlmRouterProvider();\n return createDeepSeekLlmRouterProvider({\n apiKey,\n baseUrl: process.env.DEEPSEEK_BASE_URL || 'https://api.deepseek.com',\n model: process.env.DEEPSEEK_MODEL || 'deepseek-v4-flash',\n timeoutMs: num(\n role === 'primary' ? process.env.LLM_ROUTER_PRIMARY_TIMEOUT_MS : process.env.LLM_ROUTER_TIMEOUT_MS,\n role === 'primary' ? 5000 : 6000,\n ),\n maxRetries: nonNegativeNum(process.env.LLM_ROUTER_MAX_RETRIES, 1),\n });\n }\n\n if (name === 'openai' || name === 'openai-premium') {\n const apiKey = process.env.OPENAI_API_KEY ?? process.env.LLM_API_KEY;\n if (!apiKey) return createDisabledLlmRouterProvider();\n return createChatCompletionsLlmRouterProvider({\n providerName: name,\n apiKey,\n baseUrl: process.env.OPENAI_BASE_URL || process.env.LLM_BASE_URL || 'https://api.openai.com/v1',\n model:\n name === 'openai-premium'\n ? process.env.OPENAI_PREMIUM_MODEL || 'gpt-5-mini'\n : process.env.OPENAI_MODEL || 'gpt-5-nano',\n timeoutMs: num(\n role === 'primary' ? process.env.LLM_ROUTER_PRIMARY_TIMEOUT_MS : process.env.LLM_ROUTER_SECONDARY_TIMEOUT_MS,\n role === 'primary' ? 5000 : 6000,\n ),\n maxRetries: nonNegativeNum(process.env.LLM_ROUTER_MAX_RETRIES, 1),\n });\n }\n\n return createDisabledLlmRouterProvider();\n}\n\nexport function getConfiguredLlmRouterProvider(): LlmRouterProvider {\n const legacy = process.env.LLM_ROUTER_PROVIDER as LlmRouterProviderName | undefined;\n const configured = (legacy ?? process.env.LLM_ROUTER_PRIMARY_PROVIDER ?? 'disabled').toLowerCase() as LlmRouterProviderName;\n return providerFromName(configured, 'fixed');\n}\n\nexport function getConfiguredLlmRouterProviderChain(input: LlmRouterInput): Array<{\n role: ProviderRole;\n provider: LlmRouterProvider;\n}> {\n const mode = String(process.env.LLM_ROUTER_MODE ?? 'fixed').toLowerCase();\n if (mode !== 'auto' || !bool(process.env.LLM_ROUTER_AUTO_FALLBACK_ENABLED, true)) {\n return [{ role: 'fixed', provider: getConfiguredLlmRouterProvider() }];\n }\n\n const primaryName = (process.env.LLM_ROUTER_PRIMARY_PROVIDER ?? process.env.LLM_ROUTER_PROVIDER ?? 'deepseek').toLowerCase() as LlmRouterProviderName;\n const secondaryName = (process.env.LLM_ROUTER_SECONDARY_PROVIDER ?? 'openai').toLowerCase() as LlmRouterProviderName;\n const premiumName = (process.env.LLM_ROUTER_TERTIARY_PROVIDER ?? 'openai-premium').toLowerCase() as LlmRouterProviderName;\n const chain: Array<{ role: ProviderRole; provider: LlmRouterProvider }> = [];\n\n const stickyKey = stickyProviderKey(input);\n const sticky = stickyKey ? stickyProviders.get(stickyKey) : undefined;\n if (sticky && sticky.expiresAt > Date.now() && sticky.remainingMessages > 0) {\n sticky.remainingMessages -= 1;\n chain.push({ role: 'secondary', provider: providerFromName(sticky.provider, 'secondary') });\n } else {\n if (stickyKey && sticky) stickyProviders.delete(stickyKey);\n chain.push({ role: 'primary', provider: providerFromName(primaryName, 'primary') });\n }\n\n if (input.forceStrongerProvider && chain[0]?.provider.name === 'deepseek') {\n chain.unshift({ role: 'secondary', provider: providerFromName(secondaryName, 'secondary') });\n }\n\n chain.push({ role: 'secondary', provider: providerFromName(secondaryName, 'secondary') });\n chain.push({ role: 'premium', provider: providerFromName(premiumName, 'premium') });\n\n const seen = new Set<string>();\n return chain.filter(({ provider }) => {\n const key = `${provider.name}:${provider.modelName ?? ''}`;\n if (provider.name === 'disabled' || seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n\nexport async function classifyWithConfiguredLlmRouter(input: LlmRouterInput): Promise<LlmRouterChainResult> {\n const chain = getConfiguredLlmRouterProviderChain(input);\n const maxAttempts =\n String(process.env.LLM_ROUTER_MODE ?? 'fixed').toLowerCase() === 'auto'\n ? num(process.env.LLM_ROUTER_MAX_PROVIDER_ATTEMPTS, 2)\n : 1;\n const attempts: LlmRouterAttemptAudit[] = [];\n\n const stickyKey = stickyProviderKey(input);\n const sticky = stickyKey ? stickyProviders.get(stickyKey) : undefined;\n if (sticky && sticky.expiresAt > Date.now() && sticky.remainingMessages >= 0) {\n attempts.push({\n marker: 'LLM_ROUTER_STICKY_PROVIDER_USED',\n provider: sticky.provider,\n validation: 'skipped',\n fallbackPath: 'sticky_provider',\n });\n }\n\n for (const { role, provider } of chain.slice(0, maxAttempts)) {\n const usedMarker: LlmRouterAttemptAudit['marker'] =\n role === 'primary'\n ? 'LLM_ROUTER_PRIMARY_USED'\n : role === 'premium'\n ? 'LLM_ROUTER_PREMIUM_USED'\n : 'LLM_ROUTER_SECONDARY_USED';\n const started = Date.now();\n const usedAttempt: LlmRouterAttemptAudit = {\n marker: usedMarker,\n provider: provider.name,\n modelName: provider.modelName,\n validation: 'skipped',\n fallbackPath: role,\n };\n attempts.push(usedAttempt);\n\n try {\n const decision = await provider.classifyGuestMessage(input);\n const validation = validateRouterQuality(input, decision);\n const latencyMs = Date.now() - started;\n if (validation.ok) {\n Object.assign(usedAttempt, {\n provider: provider.name,\n modelName: provider.modelName,\n latencyMs,\n normalizedIntent: decision.intent,\n confidence: decision.confidence,\n validation: 'accepted',\n fallbackPath: role,\n finalActionType: decision.actionType,\n finalShouldEscalate: decision.shouldEscalate,\n });\n setStickyProvider(input, provider, role, attempts);\n return { ok: true, decision, provider: provider.name, modelName: provider.modelName, attempts };\n }\n\n attempts.push({\n marker: role === 'primary' ? 'LLM_ROUTER_PRIMARY_FAILED' : 'LLM_ROUTER_VALIDATION_FAILED',\n provider: provider.name,\n modelName: provider.modelName,\n latencyMs,\n failureReason: validation.reason,\n normalizedIntent: decision.intent,\n confidence: decision.confidence,\n validation: validation.reason === 'low_confidence' ? 'low_confidence' : 'rejected',\n fallbackPath: role,\n finalActionType: decision.actionType,\n finalShouldEscalate: decision.shouldEscalate,\n });\n } catch (error) {\n attempts.push({\n marker: role === 'primary' ? 'LLM_ROUTER_PRIMARY_FAILED' : 'LLM_ROUTER_VALIDATION_FAILED',\n provider: provider.name,\n modelName: provider.modelName,\n latencyMs: Date.now() - started,\n failureReason: error instanceof Error ? error.message.slice(0, 80) : 'provider_failed',\n validation: 'provider_failed',\n fallbackPath: role,\n });\n }\n }\n\n attempts.push({\n marker: 'LLM_ROUTER_SAFE_FALLBACK_USED',\n provider: 'disabled',\n validation: 'skipped',\n fallbackPath: 'safe_fallback',\n });\n return { ok: false, reason: 'all_providers_failed', attempts };\n}\n\nfunction validateRouterQuality(\n input: LlmRouterInput,\n decision: LlmRouterDecision,\n): { ok: true } | { ok: false; reason: string } {\n const strict = validateLlmRouterDecision(decision);\n if (!strict.ok) return { ok: false, reason: strict.reason };\n if (decision.confidence < 0.7) return { ok: false, reason: 'low_confidence' };\n if (isUrgentAccessText(input.messageText) && !(decision.intent === 'access_problem' && decision.shouldEscalate)) {\n return { ok: false, reason: 'urgent_access_not_escalated' };\n }\n if (input.forceStrongerProvider && decision.intent === 'unknown') {\n return { ok: false, reason: 'misunderstanding_loop_unknown' };\n }\n return { ok: true };\n}\n\nfunction isUrgentAccessText(text: string): boolean {\n const normalized = text.toLocaleLowerCase('ru-RU');\n return /(стою|у\\s+двери|снаружи|не\\s+могу\\s+(попасть|войти|зайти)|код\\s+не\\s+работает|дверь\\s+не\\s+открывается|замок\\s+не\\s+открывается)/i.test(\n normalized,\n );\n}\n\nfunction setStickyProvider(\n input: LlmRouterInput,\n provider: LlmRouterProvider,\n role: ProviderRole,\n attempts: LlmRouterAttemptAudit[],\n): void {\n const stickyKey = stickyProviderKey(input);\n if (!stickyKey || role === 'primary' || provider.name === 'disabled' || provider.name === 'deepseek') return;\n stickyProviders.set(stickyKey, {\n provider: provider.name,\n expiresAt: Date.now() + num(process.env.LLM_ROUTER_STICKY_PROVIDER_TTL_MINUTES, 15) * 60_000,\n remainingMessages: 5,\n });\n attempts.push({\n marker: 'LLM_ROUTER_STICKY_PROVIDER_SET',\n provider: provider.name,\n modelName: provider.modelName,\n validation: 'accepted',\n fallbackPath: 'sticky_provider',\n });\n}\n\nexport function __resetLlmRouterStickyProvidersForTests(): void {\n stickyProviders.clear();\n}\n"}}}}