{"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();\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();\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 {\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();\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();\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 {\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"}}}}