@nick3/copilot-api 1.7.1 → 1.9.2
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/README.md +4 -3
- package/README.zh-CN.md +4 -3
- package/dist/{account-B4EBsn8H.js → account-MllYSdRC.js} +2 -2
- package/dist/{account-B4EBsn8H.js.map → account-MllYSdRC.js.map} +1 -1
- package/dist/{accounts-manager-Ca9IG0Fv.js → accounts-manager-BM66oT38.js} +4 -4
- package/dist/{accounts-manager-Ca9IG0Fv.js.map → accounts-manager-BM66oT38.js.map} +1 -1
- package/dist/{auth-xiepl3lk.js → auth-DZoQA-kn.js} +3 -3
- package/dist/{auth-xiepl3lk.js.map → auth-DZoQA-kn.js.map} +1 -1
- package/dist/{check-usage-3sFXqP0F.js → check-usage-DEbsehjH.js} +3 -3
- package/dist/{check-usage-3sFXqP0F.js.map → check-usage-DEbsehjH.js.map} +1 -1
- package/dist/{get-copilot-token-COIPGosP.js → get-copilot-token-4mCKt94e.js} +8 -3
- package/dist/get-copilot-token-4mCKt94e.js.map +1 -0
- package/dist/main.js +3 -3
- package/dist/{poll-access-token-c2IYJJHM.js → poll-access-token-Dvk6Ho0R.js} +6 -6
- package/dist/poll-access-token-Dvk6Ho0R.js.map +1 -0
- package/dist/{server-DT8b_Z5j.js → server-DR9ZR_MN.js} +5 -5
- package/dist/{server-DT8b_Z5j.js.map → server-DR9ZR_MN.js.map} +1 -1
- package/dist/{start-Dayo0B2n.js → start-DDhYUFQR.js} +7 -6
- package/dist/start-DDhYUFQR.js.map +1 -0
- package/package.json +1 -1
- package/dist/get-copilot-token-COIPGosP.js.map +0 -1
- package/dist/poll-access-token-c2IYJJHM.js.map +0 -1
- package/dist/start-Dayo0B2n.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"accounts-manager-Ca9IG0Fv.js","names":["defaultConfig: AppConfig","cachedConfig: AppConfig | null","fs","normalizedTarget","normalized: ModelAliasInfoMap","normalized: ModelAliasMap","DEFAULT_MAX_ENTRIES","DEFAULT_TTL_MS","out: Record<string, string>","out","requestSnapshot: RequestSnapshot","responseHeaders: Record<string, string>","chunks: Array<Uint8Array>","responseBodyKind: \"json\" | \"sse\" | \"text\"","args: Array<string | number>","dailyArgs: Array<string | number>","byAccountArgs: Array<string | number>","daily: Array<DailyStats>","where: Array<string>","values: Array<SQLQueryBindings>","map: Record<string, AccountStatsRow | undefined>","disabledStore: RequestHistoryStoreApi","sharedStore: RequestHistoryStoreApi | null","sharedStatsStore: StatsStore | null","row: { account_id?: string } | null","sharedSessionAffinityStore: SessionAffinityStore | null","sharedCleanupInterval: ReturnType<typeof setInterval> | undefined","runtime: AccountRuntime","accounts: Array<AccountRuntime>","overageFallback:\n | {\n account: AccountRuntime\n model: Model\n endpoint: string\n costUnits: number\n }\n | undefined","unknownQuotaAccounts","unlimitedAccounts","shuffled: Array<ScoredAccountRuntime>","statuses: Array<AccountStatusEntry>","allAccounts: Array<AccountRuntime>","fs","added: Array<string>","removed: Array<string>","updated: Array<string>","changes: Array<string>"],"sources":["../src/lib/config.ts","../src/lib/account-affinity.ts","../src/lib/dev-mode.ts","../src/services/copilot/copilot-fetch.ts","../src/services/copilot/get-models.ts","../src/lib/accounts-manager-auth.ts","../src/lib/accounts-manager-quota.ts","../src/lib/stats-store.ts","../src/lib/request-history.ts","../src/lib/session-affinity-store.ts","../src/lib/session-ownership.ts","../src/lib/accounts-manager.ts"],"sourcesContent":["import consola from \"consola\"\nimport fs from \"node:fs\"\n\nimport { PATHS } from \"./paths\"\n\nexport type LogLevel = \"error\" | \"warn\" | \"info\" | \"debug\"\n\nexport interface DevModeConfig {\n enabled: boolean\n capture4xx: boolean\n capture5xx: boolean\n captureOther: boolean\n}\n\nexport interface AppConfig {\n auth?: {\n apiKeys?: Array<string>\n }\n providers?: Record<string, ProviderConfig>\n extraPrompts?: Record<string, string>\n smallModel?: string\n accountAffinity?: boolean\n /** @deprecated */\n apiKey?: string\n responsesApiContextManagementModels?: Array<string>\n modelReasoningEfforts?: Record<\n string,\n \"none\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\"\n >\n modelAliases?: Record<string, { target: string; allowOriginal?: boolean }>\n allowOriginalModelNamesForAliases?: boolean\n useFunctionApplyPatch?: boolean\n forceAgent?: boolean\n compactUseSmallModel?: boolean\n messageStartInputTokensFallback?: boolean\n modelRefreshIntervalHours?: number\n sessionAffinityRetentionDays?: number\n useMessagesApi?: boolean\n anthropicApiKey?: string\n useResponsesApiWebSearch?: boolean\n claudeTokenMultiplier?: number\n logLevel?: LogLevel\n devMode?: DevModeConfig\n}\n\nexport interface ModelConfig {\n temperature?: number\n topP?: number\n topK?: number\n}\n\nexport const PROVIDER_TYPE_ANTHROPIC = \"anthropic\" as const\n\nexport type ProviderType = typeof PROVIDER_TYPE_ANTHROPIC\n\nexport type ProviderAuthType = \"authorization\" | \"x-api-key\"\n\nexport interface ProviderConfig {\n type?: string\n enabled?: boolean\n baseUrl?: string\n apiKey?: string\n authType?: ProviderAuthType\n models?: Record<string, ModelConfig>\n adjustInputTokens?: boolean\n}\n\nexport interface ResolvedProviderConfig {\n name: string\n type: ProviderType\n baseUrl: string\n apiKey: string\n authType: ProviderAuthType\n models?: Record<string, ModelConfig>\n adjustInputTokens?: boolean\n}\n\nconst gpt5ExplorationPrompt = `## Exploration and reading files\n- **Think first.** Before any tool call, decide ALL files/resources you will need.\n- **Batch everything.** If you need multiple files (even from different places), read them together.\n- **multi_tool_use.parallel** Use multi_tool_use.parallel to parallelize tool calls and only this.\n- **Only make sequential calls if you truly cannot know the next file without seeing a result first.**\n- **Workflow:** (a) plan all needed reads → (b) issue one parallel batch → (c) analyze results → (d) repeat if new, unpredictable reads arise.`\n\nconst gpt5CommentaryPrompt = `# Working with the user\n\nYou interact with the user through a terminal. You have 2 ways of communicating with the users: \n- Share intermediary updates in \\`commentary\\` channel. \n- After you have completed all your work, send a message to the \\`final\\` channel. \n\n## Intermediary updates\n\n- Intermediary updates go to the \\`commentary\\` channel.\n- User updates are short updates while you are working, they are NOT final answers.\n- You use 1-2 sentence user updates to communicate progress and new information to the user as you are doing work.\n- Do not begin responses with conversational interjections or meta commentary. Avoid openers such as acknowledgements (“Done —”, “Got it”, “Great question, ”) or framing phrases.\n- You provide user updates frequently, every 20s.\n- Before exploring or doing substantial work, you start with a user update acknowledging the request and explaining your first step. You should include your understanding of the user request and explain what you will do. Avoid commenting on the request or using starters such as \"Got it -\" or \"Understood -\" etc.\n- When exploring, e.g. searching, reading files, you provide user updates as you go, every 20s, explaining what context you are gathering and what you've learned. Vary your sentence structure when providing these updates to avoid sounding repetitive - in particular, don't start each sentence the same way.\n- After you have sufficient context, and the work is substantial, you provide a longer plan (this is the only user update that may be longer than 2 sentences and can contain formatting).\n- Before performing file edits of any kind, you provide updates explaining what edits you are making.\n- As you are thinking, you very frequently provide updates even if not taking any actions, informing the user of your progress. You interrupt your thinking and send multiple updates in a row if thinking for more than 100 words.\n- Tone of your updates MUST match your personality.`\n\nconst defaultConfig: AppConfig = {\n auth: {\n apiKeys: [],\n },\n providers: {},\n extraPrompts: {\n \"gpt-5-mini\": gpt5ExplorationPrompt,\n \"gpt-5.3-codex\": gpt5CommentaryPrompt,\n \"gpt-5.4-mini\": gpt5CommentaryPrompt,\n \"gpt-5.4\": gpt5CommentaryPrompt,\n \"gpt-5.5\": gpt5CommentaryPrompt,\n },\n smallModel: \"gpt-5-mini\",\n accountAffinity: true,\n responsesApiContextManagementModels: [],\n modelReasoningEfforts: {\n \"gpt-5-mini\": \"low\",\n \"gpt-5.3-codex\": \"xhigh\",\n \"gpt-5.4-mini\": \"xhigh\",\n \"gpt-5.4\": \"xhigh\",\n \"gpt-5.5\": \"xhigh\",\n },\n allowOriginalModelNamesForAliases: false,\n useFunctionApplyPatch: true,\n forceAgent: false,\n compactUseSmallModel: true,\n messageStartInputTokensFallback: false,\n modelRefreshIntervalHours: 24,\n sessionAffinityRetentionDays: 7,\n useMessagesApi: true,\n useResponsesApiWebSearch: true,\n logLevel: \"info\",\n devMode: {\n enabled: false,\n capture4xx: false,\n capture5xx: false,\n captureOther: false,\n },\n}\n\nlet cachedConfig: AppConfig | null = null\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\n\nfunction normalizeAuthApiKeys(value: unknown): Array<string> {\n if (!Array.isArray(value)) return []\n\n return [\n ...new Set(\n value\n .filter((item): item is string => typeof item === \"string\")\n .map((item) => item.trim())\n .filter((item) => item.length > 0),\n ),\n ]\n}\n\nfunction normalizeNonNegativeNumber(value: unknown): number | undefined {\n if (typeof value !== \"number\") return undefined\n if (!Number.isFinite(value)) return undefined\n if (value < 0) return undefined\n return value\n}\n\nconst LOG_LEVELS = new Set<LogLevel>([\"error\", \"warn\", \"info\", \"debug\"])\n\nfunction normalizeLogLevel(value: unknown): LogLevel | undefined {\n if (typeof value !== \"string\") return undefined\n return LOG_LEVELS.has(value as LogLevel) ? (value as LogLevel) : undefined\n}\n\nfunction ensureConfigFile(): void {\n try {\n fs.accessSync(PATHS.CONFIG_PATH, fs.constants.R_OK)\n return\n } catch {\n // Fall through to try creating the default config file.\n }\n\n try {\n fs.mkdirSync(PATHS.APP_DIR, { recursive: true })\n fs.writeFileSync(\n PATHS.CONFIG_PATH,\n `${JSON.stringify(defaultConfig, null, 2)}\\n`,\n \"utf8\",\n )\n try {\n fs.chmodSync(PATHS.CONFIG_PATH, 0o600)\n } catch {\n // Ignore chmod errors (e.g. unsupported filesystem).\n }\n } catch {\n // Best-effort only: if we can't create the file, reads will fall back to defaults.\n }\n}\n\nfunction readConfigFromDisk(): AppConfig {\n ensureConfigFile()\n try {\n const raw = fs.readFileSync(PATHS.CONFIG_PATH, \"utf8\")\n if (!raw.trim()) {\n fs.writeFileSync(\n PATHS.CONFIG_PATH,\n `${JSON.stringify(defaultConfig, null, 2)}\\n`,\n \"utf8\",\n )\n return defaultConfig\n }\n return JSON.parse(raw) as AppConfig\n } catch (error) {\n consola.error(\"Failed to read config file, using default config\", error)\n return defaultConfig\n }\n}\n\nfunction mergeDefaultConfig(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n const extraPrompts = config.extraPrompts ?? {}\n const defaultExtraPrompts = defaultConfig.extraPrompts ?? {}\n const modelReasoningEfforts = config.modelReasoningEfforts ?? {}\n const defaultModelReasoningEfforts = defaultConfig.modelReasoningEfforts ?? {}\n const hasForceAgent = typeof config.forceAgent === \"boolean\"\n const defaultForceAgent = defaultConfig.forceAgent ?? false\n\n const missingExtraPromptModels = Object.keys(defaultExtraPrompts).filter(\n (model) => !Object.hasOwn(extraPrompts, model),\n )\n\n const missingReasoningEffortModels = Object.keys(\n defaultModelReasoningEfforts,\n ).filter((model) => !Object.hasOwn(modelReasoningEfforts, model))\n\n const hasExtraPromptChanges = missingExtraPromptModels.length > 0\n const hasReasoningEffortChanges = missingReasoningEffortModels.length > 0\n const hasForceAgentChanges = !hasForceAgent\n\n if (\n !hasExtraPromptChanges\n && !hasReasoningEffortChanges\n && !hasForceAgentChanges\n ) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n extraPrompts: {\n ...defaultExtraPrompts,\n ...extraPrompts,\n },\n modelReasoningEfforts: {\n ...defaultModelReasoningEfforts,\n ...modelReasoningEfforts,\n },\n forceAgent: hasForceAgent ? config.forceAgent : defaultForceAgent,\n },\n changed: true,\n }\n}\n\nfunction mergeDefaultAuth(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n const authConfig = isPlainObject(config.auth) ? config.auth : undefined\n const rawApiKeys =\n Array.isArray(authConfig?.apiKeys) ? authConfig.apiKeys : undefined\n const normalizedApiKeys = normalizeAuthApiKeys(rawApiKeys)\n const nextAuth = { apiKeys: normalizedApiKeys }\n\n if (authConfig && JSON.stringify(authConfig) === JSON.stringify(nextAuth)) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n auth: nextAuth,\n },\n changed: true,\n }\n}\n\nfunction mergeDefaultAccountAffinity(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n // Migration: map old freeModelLoadBalancing to accountAffinity\n const raw = config as Record<string, unknown>\n const hasOld = typeof raw.freeModelLoadBalancing === \"boolean\"\n const hasNew = typeof config.accountAffinity === \"boolean\"\n\n if (hasOld) {\n const next = { ...config } as Record<string, unknown>\n if (!hasNew) {\n next.accountAffinity = raw.freeModelLoadBalancing\n }\n delete next.freeModelLoadBalancing\n return { mergedConfig: next as AppConfig, changed: true }\n }\n\n if (hasNew) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n accountAffinity: defaultConfig.accountAffinity ?? true,\n },\n changed: true,\n }\n}\n\nfunction mergeDefaultModelRefreshInterval(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n const normalized = normalizeNonNegativeNumber(\n config.modelRefreshIntervalHours,\n )\n\n if (normalized !== undefined) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n modelRefreshIntervalHours: defaultConfig.modelRefreshIntervalHours ?? 24,\n },\n changed: true,\n }\n}\n\nfunction mergeDefaultSessionAffinityRetention(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n const normalized = normalizeNonNegativeNumber(\n config.sessionAffinityRetentionDays,\n )\n\n if (normalized !== undefined) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n sessionAffinityRetentionDays:\n defaultConfig.sessionAffinityRetentionDays ?? 7,\n },\n changed: true,\n }\n}\n\nfunction mergeDefaultLogLevel(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n const normalized = normalizeLogLevel(config.logLevel)\n\n if (normalized !== undefined) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n logLevel: defaultConfig.logLevel ?? \"info\",\n },\n changed: true,\n }\n}\n\nfunction mergeDefaultDevMode(config: AppConfig): ConfigMergeResult {\n const current = config.devMode\n if (\n current\n && typeof current.enabled === \"boolean\"\n && typeof current.capture4xx === \"boolean\"\n && typeof current.capture5xx === \"boolean\"\n && typeof current.captureOther === \"boolean\"\n ) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n devMode: {\n enabled: current?.enabled === true,\n capture4xx: current?.capture4xx === true,\n capture5xx: current?.capture5xx === true,\n captureOther: current?.captureOther === true,\n },\n },\n changed: true,\n }\n}\n\ntype ConfigMergeResult = {\n mergedConfig: AppConfig\n changed: boolean\n}\n\ntype ConfigMergeFn = (config: AppConfig) => ConfigMergeResult\n\nfunction applyConfigMerges(\n config: AppConfig,\n mergeFns: ReadonlyArray<ConfigMergeFn>,\n): ConfigMergeResult {\n return mergeFns.reduce<ConfigMergeResult>(\n (acc, mergeFn) => {\n const result = mergeFn(acc.mergedConfig)\n return {\n mergedConfig: result.mergedConfig,\n changed: acc.changed || result.changed,\n }\n },\n { mergedConfig: config, changed: false },\n )\n}\n\nexport function mergeConfigWithDefaults(): AppConfig {\n const config = readConfigFromDisk()\n\n const { mergedConfig, changed } = applyConfigMerges(config, [\n mergeDefaultAuth,\n mergeDefaultConfig,\n mergeDefaultAccountAffinity,\n mergeDefaultModelRefreshInterval,\n mergeDefaultSessionAffinityRetention,\n mergeDefaultLogLevel,\n mergeDefaultDevMode,\n ])\n\n if (changed) {\n try {\n fs.writeFileSync(\n PATHS.CONFIG_PATH,\n `${JSON.stringify(mergedConfig, null, 2)}\\n`,\n \"utf8\",\n )\n } catch (writeError) {\n consola.warn(\"Failed to write merged config defaults\", writeError)\n }\n }\n\n cachedConfig = mergedConfig\n return mergedConfig\n}\n\nexport function getConfig(): AppConfig {\n cachedConfig ??= readConfigFromDisk()\n return cachedConfig\n}\n\ntype ModelAliasSpec = {\n target: string\n allowOriginal?: boolean\n}\n\ntype ModelAliasMap = Record<string, string>\n\ntype ModelAliasInfoMap = Record<string, ModelAliasSpec>\n\ntype ModelAliasRawMap = Record<string, unknown>\n\nfunction normalizeAliasKey(value: string): string | null {\n const trimmed = value.trim().toLowerCase()\n return trimmed.length > 0 ? trimmed : null\n}\n\nfunction normalizeAliasTarget(value: string): string | null {\n const trimmed = value.trim()\n return trimmed.length > 0 ? trimmed : null\n}\n\nfunction normalizeAliasSpec(value: unknown): ModelAliasSpec | null {\n if (typeof value === \"string\") {\n const normalizedTarget = normalizeAliasTarget(value)\n return normalizedTarget ? { target: normalizedTarget } : null\n }\n if (!value || typeof value !== \"object\") {\n return null\n }\n\n const targetValue = (value as { target?: unknown }).target\n if (typeof targetValue !== \"string\") {\n return null\n }\n\n const normalizedTarget = normalizeAliasTarget(targetValue)\n if (!normalizedTarget) {\n return null\n }\n\n const allowOriginalValue = (value as { allowOriginal?: unknown })\n .allowOriginal\n const allowOriginal =\n typeof allowOriginalValue === \"boolean\" ? allowOriginalValue : undefined\n return { target: normalizedTarget, allowOriginal }\n}\n\nexport function getModelAliasesInfo(): ModelAliasInfoMap {\n const config = getConfig()\n const raw = (config.modelAliases ?? {}) as ModelAliasRawMap\n const normalized: ModelAliasInfoMap = {}\n\n for (const [alias, rawSpec] of Object.entries(raw)) {\n const normalizedAlias = normalizeAliasKey(alias)\n const normalizedSpec = normalizeAliasSpec(rawSpec)\n if (!normalizedAlias || !normalizedSpec) {\n continue\n }\n if (!Object.hasOwn(normalized, normalizedAlias)) {\n normalized[normalizedAlias] = normalizedSpec\n }\n }\n\n return normalized\n}\n\nexport function getModelAliases(): ModelAliasMap {\n const info = getModelAliasesInfo()\n const normalized: ModelAliasMap = {}\n\n for (const [alias, spec] of Object.entries(info)) {\n normalized[alias] = spec.target\n }\n\n return normalized\n}\n\nexport function resolveModelAlias(modelId: string): string {\n const normalized = normalizeAliasKey(modelId)\n if (!normalized) return modelId\n const aliases = getModelAliases()\n return aliases[normalized] ?? modelId\n}\n\nexport function isOriginalModelNameAllowedForAliases(): boolean {\n const config = getConfig()\n return config.allowOriginalModelNamesForAliases ?? false\n}\n\nexport function getAliasTargetSet(): Set<string> {\n const aliases = getModelAliasesInfo()\n const allowOriginalDefault = isOriginalModelNameAllowedForAliases()\n const targetAllowMap = new Map<string, boolean>()\n\n for (const { target, allowOriginal } of Object.values(aliases)) {\n const normalizedTarget = target.toLowerCase()\n const effectiveAllow = allowOriginal ?? allowOriginalDefault\n const currentAllow = targetAllowMap.get(normalizedTarget)\n if (currentAllow === true) {\n continue\n }\n if (effectiveAllow) {\n targetAllowMap.set(normalizedTarget, true)\n } else if (currentAllow === undefined) {\n targetAllowMap.set(normalizedTarget, false)\n }\n }\n\n const blockedTargets = new Set<string>()\n for (const [target, allowed] of targetAllowMap.entries()) {\n if (!allowed) {\n blockedTargets.add(target)\n }\n }\n\n return blockedTargets\n}\n\nexport function isOriginalModelNameAllowedForTarget(modelId: string): boolean {\n const normalized = normalizeAliasKey(modelId)\n if (!normalized) return true\n const blockedTargets = getAliasTargetSet()\n return !blockedTargets.has(normalized)\n}\n\nexport function getPreferredAliasForTarget(modelId: string): string | null {\n const aliases = getModelAliases()\n const aliasKeys = getAliasKeysForTarget(modelId, aliases)\n return aliasKeys[0] ?? null\n}\n\nfunction getAliasKeysForTarget(\n target: string,\n aliases: ModelAliasMap,\n): Array<string> {\n const normalizedTarget = target.toLowerCase()\n return Object.entries(aliases)\n .filter(([, model]) => model.toLowerCase() === normalizedTarget)\n .map(([alias]) => alias)\n .sort()\n}\n\nfunction getAliasFallbackValue<T extends string>(\n record: Record<string, T> | undefined,\n modelId: string,\n aliases: ModelAliasMap,\n): T | undefined {\n if (!record) return undefined\n\n const aliasKeys = getAliasKeysForTarget(modelId, aliases)\n if (aliasKeys.length === 0) return undefined\n\n const recordByAlias = new Map<string, T>()\n for (const [key, value] of Object.entries(record)) {\n const normalized = normalizeAliasKey(key)\n if (normalized) {\n recordByAlias.set(normalized, value)\n }\n }\n\n for (const alias of aliasKeys) {\n const value = recordByAlias.get(alias)\n if (value !== undefined) {\n return value\n }\n }\n\n return undefined\n}\n\nexport function getExtraPromptForModel(model: string): string {\n const config = getConfig()\n const direct = config.extraPrompts?.[model]\n if (direct !== undefined) return direct\n\n const aliases = getModelAliases()\n const fallback = getAliasFallbackValue(config.extraPrompts, model, aliases)\n return fallback ?? \"\"\n}\n\nexport function getSmallModel(): string {\n const config = getConfig()\n const model = config.smallModel ?? \"gpt-5-mini\"\n if (isOriginalModelNameAllowedForTarget(model)) {\n return model\n }\n\n return getPreferredAliasForTarget(model) ?? model\n}\n\nexport function getLogLevel(): LogLevel {\n const config = getConfig()\n const normalized = normalizeLogLevel(config.logLevel)\n return normalized ?? defaultConfig.logLevel ?? \"info\"\n}\n\nexport function isAccountAffinityEnabled(): boolean {\n const config = getConfig()\n return config.accountAffinity ?? true\n}\n\nexport function getModelRefreshIntervalHours(): number {\n const config = getConfig()\n const normalized = normalizeNonNegativeNumber(\n config.modelRefreshIntervalHours,\n )\n return normalized ?? defaultConfig.modelRefreshIntervalHours ?? 24\n}\n\nexport function getModelRefreshIntervalMs(): number {\n const hours = getModelRefreshIntervalHours()\n if (!Number.isFinite(hours) || hours <= 0) return 0\n return hours * 60 * 60 * 1000\n}\n\nexport function getSessionAffinityRetentionDays(): number {\n const config = getConfig()\n const normalized = normalizeNonNegativeNumber(\n config.sessionAffinityRetentionDays,\n )\n return normalized ?? defaultConfig.sessionAffinityRetentionDays ?? 7\n}\n\nexport function getSessionAffinityRetentionMs(): number {\n const days = getSessionAffinityRetentionDays()\n if (!Number.isFinite(days) || days <= 0) return 0\n return days * 24 * 60 * 60 * 1000\n}\n\nexport function isMessageStartInputTokensFallbackEnabled(): boolean {\n const config = getConfig()\n return config.messageStartInputTokensFallback ?? false\n}\n\nexport function shouldCompactUseSmallModel(): boolean {\n const config = getConfig()\n return config.compactUseSmallModel ?? true\n}\n\nexport function getResponsesApiContextManagementModels(): Array<string> {\n const config = getConfig()\n return (\n config.responsesApiContextManagementModels\n ?? defaultConfig.responsesApiContextManagementModels\n ?? []\n )\n}\n\nexport function isResponsesApiContextManagementModel(model: string): boolean {\n return getResponsesApiContextManagementModels().includes(model)\n}\n\nexport function getReasoningEffortForModel(\n model: string,\n): \"none\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" {\n const config = getConfig()\n const direct = config.modelReasoningEfforts?.[model]\n if (direct !== undefined) return direct\n\n const aliases = getModelAliases()\n const fallback = getAliasFallbackValue(\n config.modelReasoningEfforts,\n model,\n aliases,\n )\n return fallback ?? \"high\"\n}\n\nexport function isForceAgentEnabled(): boolean {\n const config = getConfig()\n return config.forceAgent ?? false\n}\n\nexport function normalizeProviderBaseUrl(url: string): string {\n return url.trim().replace(/\\/+$/u, \"\")\n}\n\nfunction resolveProviderAuthType(\n providerName: string,\n authType?: string,\n): ProviderAuthType | null {\n if (authType === undefined || authType === \"x-api-key\") {\n return \"x-api-key\"\n }\n\n if (authType === \"authorization\") {\n return authType\n }\n\n consola.warn(\n `Provider ${providerName} has invalid authType '${authType}', ignoring provider`,\n )\n return null\n}\n\nexport function getProviderConfig(name: string): ResolvedProviderConfig | null {\n const providerName = name.trim()\n if (!providerName) {\n return null\n }\n\n const config = getConfig()\n const provider = config.providers?.[providerName]\n if (!provider) {\n return null\n }\n\n if (provider.enabled === false) {\n return null\n }\n\n const type = provider.type ?? PROVIDER_TYPE_ANTHROPIC\n if (type !== PROVIDER_TYPE_ANTHROPIC) {\n consola.warn(\n `Provider ${providerName} is ignored because only anthropic type is supported`,\n )\n return null\n }\n\n const baseUrl = normalizeProviderBaseUrl(provider.baseUrl ?? \"\")\n const apiKey = (provider.apiKey ?? \"\").trim()\n const authType = resolveProviderAuthType(providerName, provider.authType)\n if (!authType) {\n return null\n }\n if (!baseUrl || !apiKey) {\n consola.warn(\n `Provider ${providerName} is enabled but missing baseUrl or apiKey`,\n )\n return null\n }\n\n return {\n name: providerName,\n type: PROVIDER_TYPE_ANTHROPIC,\n baseUrl,\n apiKey,\n authType,\n models: provider.models,\n adjustInputTokens: provider.adjustInputTokens,\n }\n}\n\nexport function listEnabledProviders(): Array<string> {\n const config = getConfig()\n const providerNames = Object.keys(config.providers ?? {})\n return providerNames.filter((name) => getProviderConfig(name) !== null)\n}\n\nexport function isMessagesApiEnabled(): boolean {\n const config = getConfig()\n return config.useMessagesApi ?? true\n}\n\nexport function getAnthropicApiKey(): string | undefined {\n const config = getConfig()\n return config.anthropicApiKey ?? process.env.ANTHROPIC_API_KEY ?? undefined\n}\n\nexport function isResponsesApiWebSearchEnabled(): boolean {\n const config = getConfig()\n return config.useResponsesApiWebSearch ?? true\n}\n\nexport function getClaudeTokenMultiplier(): number {\n const config = getConfig()\n return config.claudeTokenMultiplier ?? 1.15\n}\n","import consola from \"consola\"\n\nimport type { AccountRuntime } from \"~/lib/types/account\"\n\nexport interface AffinityContext {\n requestId?: string\n affinityModelId?: string\n}\n\nexport interface AffinityPersistenceStore {\n get(key: string): string | undefined\n set(key: string, accountId: string): void\n delete(key: string): void\n clear(): void\n}\n\nexport type AffinityPersistenceStoreProvider =\n | AffinityPersistenceStore\n | (() => AffinityPersistenceStore | undefined)\n\ninterface AffinityCacheEntry {\n accountId: string\n expiresAt: number\n}\n\nconst DEFAULT_MAX_ENTRIES = 10_000\nconst DEFAULT_TTL_MS = 60 * 60 * 1000 // 1 hour\n\n/**\n * In-memory LRU cache with TTL for account affinity mappings.\n *\n * Uses Map insertion order for LRU eviction: updated or rehydrated entries are\n * deleted and re-inserted so they move to the \"newest\" end.\n */\nexport class AccountAffinityCache {\n private readonly cache = new Map<string, AffinityCacheEntry>()\n private readonly maxEntries: number\n private readonly ttlMs: number\n private persistentStore?: AffinityPersistenceStore\n private persistentStoreProvider?: () => AffinityPersistenceStore | undefined\n\n constructor(\n maxEntries = DEFAULT_MAX_ENTRIES,\n ttlMs = DEFAULT_TTL_MS,\n persistentStore?: AffinityPersistenceStoreProvider,\n ) {\n this.maxEntries = maxEntries\n this.ttlMs = ttlMs\n\n if (typeof persistentStore === \"function\") {\n this.persistentStoreProvider = persistentStore\n } else {\n this.persistentStore = persistentStore\n }\n }\n\n /** Look up the preferred account ID for a cache key. Returns undefined if not found or expired. */\n get(key: string): string | undefined {\n const entry = this.cache.get(key)\n if (entry) {\n if (Date.now() >= entry.expiresAt) {\n this.cache.delete(key)\n } else {\n return entry.accountId\n }\n }\n\n const accountId = this.readPersistentEntry(key)\n if (!accountId) {\n return undefined\n }\n\n this.setMemory(key, accountId)\n return accountId\n }\n\n /** Record a successful account mapping. Refreshes TTL and moves the entry to the newest position. */\n set(key: string, accountId: string): void {\n this.setMemory(key, accountId)\n this.writePersistentEntry(key, accountId)\n }\n\n /** Remove a specific entry. */\n delete(key: string): boolean {\n const deleted = this.cache.delete(key)\n this.deletePersistentEntry(key)\n return deleted\n }\n\n /** Remove all in-memory entries. */\n clearMemory(): void {\n this.cache.clear()\n }\n\n /** Remove all entries. */\n clear(): void {\n this.clearMemory()\n this.clearPersistentEntries()\n }\n\n /** Current number of entries (including potentially expired ones). */\n get size(): number {\n return this.cache.size\n }\n\n private getPersistentStore(): AffinityPersistenceStore | undefined {\n if (this.persistentStore) {\n return this.persistentStore\n }\n if (!this.persistentStoreProvider) {\n return undefined\n }\n\n try {\n const store = this.persistentStoreProvider()\n if (store) {\n this.persistentStore = store\n }\n return store\n } catch (error) {\n this.persistentStoreProvider = undefined\n consola.warn(\"Failed to resolve affinity persistence store:\", error)\n return undefined\n }\n }\n\n private readPersistentEntry(key: string): string | undefined {\n const store = this.getPersistentStore()\n if (!store) {\n return undefined\n }\n\n try {\n return store.get(key)\n } catch (error) {\n consola.warn(\n \"Failed to read affinity mapping from persistent store:\",\n error,\n )\n return undefined\n }\n }\n\n private writePersistentEntry(key: string, accountId: string): void {\n const store = this.getPersistentStore()\n if (!store) {\n return\n }\n\n try {\n store.set(key, accountId)\n } catch (error) {\n consola.warn(\"Failed to persist affinity mapping:\", error)\n }\n }\n\n private deletePersistentEntry(key: string): void {\n const store = this.getPersistentStore()\n if (!store) {\n return\n }\n\n try {\n store.delete(key)\n } catch (error) {\n consola.warn(\"Failed to delete affinity mapping:\", error)\n }\n }\n\n private clearPersistentEntries(): void {\n const store = this.getPersistentStore()\n if (!store) {\n return\n }\n\n try {\n store.clear()\n } catch (error) {\n consola.warn(\"Failed to clear persistent affinity mappings:\", error)\n }\n }\n\n private setMemory(key: string, accountId: string): void {\n // Delete first so re-insertion moves it to the newest position (LRU).\n this.cache.delete(key)\n\n // Evict oldest entries if at capacity.\n while (this.cache.size >= this.maxEntries) {\n const oldest = this.cache.keys().next()\n if (oldest.done) break\n this.cache.delete(oldest.value)\n }\n\n this.cache.set(key, {\n accountId,\n expiresAt: Date.now() + this.ttlMs,\n })\n }\n}\n\n/**\n * Extract the affinity key from the request context.\n * Uses the upstream request ID which is deterministic for the same user message.\n */\nexport function extractAffinityKey(\n context: AffinityContext,\n): string | undefined {\n return context.requestId?.trim() || undefined\n}\n\n/**\n * Build the full cache key by combining the affinity key with the model ID.\n * This prevents cross-model pollution (same session requesting different models\n * can be routed to different accounts).\n */\nexport function buildAffinityCacheKey(\n affinityKey: string,\n modelId: string,\n): string {\n return `${affinityKey}:${modelId}`\n}\n\n/**\n * Check whether an account is a valid affinity candidate.\n * An account is valid if it is not failed and is present in the provided\n * runtime list.\n */\nexport function isAffinityAccountUsable(\n accountId: string,\n accounts: ReadonlyArray<AccountRuntime>,\n): AccountRuntime | undefined {\n const account = accounts.find((a) => a.id === accountId)\n if (!account) return undefined\n if (account.failed) return undefined\n return account\n}\n","import { getConfig } from \"./config\"\n\nexport function isDevModeEnabled(): boolean {\n return getConfig().devMode?.enabled === true\n}\n\nexport function isCapture4xxEnabled(): boolean {\n return getConfig().devMode?.capture4xx === true\n}\n\nexport function isCapture5xxEnabled(): boolean {\n return getConfig().devMode?.capture5xx === true\n}\n\nexport function isCaptureOtherEnabled(): boolean {\n return getConfig().devMode?.captureOther === true\n}\n","import consola from \"consola\"\n\nimport {\n isCapture4xxEnabled,\n isCapture5xxEnabled,\n isCaptureOtherEnabled,\n} from \"~/lib/dev-mode\"\nimport { getRequestOutboundStore } from \"~/lib/request-outbound\"\n\nexport type CopilotFetchCtx = {\n requestId?: string\n capturable?: boolean\n callSite: string\n}\n\nconst pendingCaptures = new Map<string, PersistInput>()\nconst pendingCapturePromises = new Map<string, Promise<void>>()\n\nexport async function flushPendingCapture(requestId: string): Promise<void> {\n const pending = pendingCaptures.get(requestId)\n if (pending) {\n pendingCaptures.delete(requestId)\n pendingCapturePromises.delete(requestId)\n persistNow(pending)\n return\n }\n const promise = pendingCapturePromises.get(requestId)\n if (promise) {\n await promise\n const deferred = pendingCaptures.get(requestId)\n if (deferred) {\n pendingCaptures.delete(requestId)\n persistNow(deferred)\n }\n pendingCapturePromises.delete(requestId)\n }\n}\n\ntype RequestSnapshot = {\n url: string\n method: string\n headers: Record<string, string>\n body: string | null\n bodyKind: \"json\" | \"text\" | \"binary\"\n}\n\nfunction snapshotHeaders(init: RequestInit): Record<string, string> {\n const headers = init.headers\n if (headers instanceof Headers) {\n const out: Record<string, string> = {}\n for (const [key, value] of headers.entries()) {\n out[key] = value\n }\n return out\n }\n\n if (Array.isArray(headers)) {\n const out: Record<string, string> = {}\n for (const [key, value] of headers) {\n out[key] = value\n }\n return out\n }\n\n const out: Record<string, string> = {}\n for (const [key, value] of Object.entries(\n (headers ?? {}) as Record<string, string>,\n )) {\n out[key] = value\n }\n return out\n}\n\nfunction snapshotBody(init: RequestInit): {\n body: string | null\n bodyKind: \"json\" | \"text\" | \"binary\"\n} {\n const body = init.body\n if (body === null || body === undefined) {\n return { body: null, bodyKind: \"text\" }\n }\n\n if (typeof body === \"string\") {\n try {\n JSON.parse(body)\n return { body, bodyKind: \"json\" }\n } catch {\n return { body, bodyKind: \"text\" }\n }\n }\n\n if (body instanceof Uint8Array) {\n return { body: Buffer.from(body).toString(\"base64\"), bodyKind: \"binary\" }\n }\n\n if (body instanceof ArrayBuffer) {\n return {\n body: Buffer.from(new Uint8Array(body)).toString(\"base64\"),\n bodyKind: \"binary\",\n }\n }\n\n return { body: null, bodyKind: \"text\" }\n}\n\nfunction shouldCaptureStatus(status: number): boolean {\n if (status >= 400 && status < 500) return isCapture4xxEnabled()\n if (status >= 500) return isCapture5xxEnabled()\n return isCaptureOtherEnabled()\n}\n\nexport async function copilotFetch(\n input: string | URL,\n init: RequestInit,\n ctx: CopilotFetchCtx,\n): Promise<Response> {\n const urlString = typeof input === \"string\" ? input : input.toString()\n\n const requestSnapshot: RequestSnapshot = {\n url: urlString,\n method: (init.method ?? \"GET\").toUpperCase(),\n headers: snapshotHeaders(init),\n ...snapshotBody(init),\n }\n\n const response = await fetch(input, init)\n\n const shouldCapture =\n ctx.requestId !== undefined\n && ctx.capturable !== false\n && shouldCaptureStatus(response.status)\n\n if (!shouldCapture) {\n return response\n }\n\n const contentType = response.headers.get(\"content-type\") ?? \"\"\n const isSSE = contentType.includes(\"text/event-stream\")\n const responseHeaders: Record<string, string> = {}\n for (const [key, value] of response.headers.entries()) {\n responseHeaders[key] = value\n }\n\n if (!response.body) {\n storePending({\n requestSnapshot,\n status: response.status,\n responseBody: \"\",\n responseBodyKind: isSSE ? \"sse\" : \"json\",\n responseHeaders,\n ctx,\n })\n return response\n }\n\n const [forClient, forCapture] = response.body.tee()\n\n const capturePromise = (async () => {\n const chunks: Array<Uint8Array> = []\n const reader =\n forCapture.getReader() as ReadableStreamDefaultReader<Uint8Array>\n\n try {\n for (;;) {\n const result = await reader.read()\n if (result.done) {\n break\n }\n\n const value = result.value\n if (value instanceof Uint8Array) {\n chunks.push(value)\n }\n }\n\n const buffer = Buffer.concat(chunks.map((chunk) => Buffer.from(chunk)))\n const text = buffer.toString(\"utf8\")\n let responseBodyKind: \"json\" | \"sse\" | \"text\" = \"text\"\n\n if (isSSE) {\n responseBodyKind = \"sse\"\n } else if (contentType.includes(\"application/json\")) {\n responseBodyKind = \"json\"\n }\n\n storePending({\n requestSnapshot,\n status: response.status,\n responseBody: text,\n responseBodyKind,\n responseHeaders,\n ctx,\n })\n } catch (error) {\n consola.debug(\"copilotFetch capture stream failed\", error)\n }\n })()\n\n if (ctx.requestId) {\n pendingCapturePromises.set(ctx.requestId, capturePromise)\n }\n\n return new Response(forClient, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n })\n}\n\ntype PersistInput = {\n requestSnapshot: RequestSnapshot\n status: number\n responseBody: string\n responseBodyKind: \"json\" | \"sse\" | \"text\"\n responseHeaders: Record<string, string>\n ctx: CopilotFetchCtx\n}\n\nfunction storePending(input: PersistInput): void {\n const id = input.ctx.requestId\n if (!id) return\n pendingCaptures.set(id, input)\n}\n\nfunction persistNow({\n requestSnapshot,\n status,\n responseBody,\n responseBodyKind,\n responseHeaders,\n ctx,\n}: PersistInput): void {\n if (!ctx.requestId) {\n return\n }\n\n try {\n getRequestOutboundStore().insert({\n requestId: ctx.requestId,\n httpStatus: status,\n upstreamUrl: requestSnapshot.url,\n upstreamMethod: requestSnapshot.method,\n requestHeaders: requestSnapshot.headers,\n requestBody: requestSnapshot.body,\n requestBodyKind: requestSnapshot.bodyKind,\n responseStatus: status,\n responseHeaders,\n responseBody,\n responseBodyKind,\n })\n } catch (error) {\n consola.debug(\"copilotFetch persist failed\", error)\n }\n}\n","import consola from \"consola\"\nimport fs from \"node:fs/promises\"\n\nimport type { AccountContext } from \"~/lib/types/account\"\n\nimport { copilotBaseUrl, copilotModelsHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { PATHS } from \"~/lib/paths\"\nimport { accountFromState } from \"~/lib/state\"\n\nimport { copilotFetch } from \"./copilot-fetch\"\n\nexport const getModels = async (\n account?: AccountContext,\n options?: {\n requestId?: string\n },\n) => {\n const ctx = account ?? accountFromState()\n const response = await copilotFetch(\n `${copilotBaseUrl(ctx)}/models`,\n {\n headers: copilotModelsHeaders(ctx),\n },\n {\n requestId: options?.requestId,\n callSite: \"models\",\n capturable: false,\n },\n )\n\n if (!response.ok) {\n const errorText = await response.clone().text()\n\n consola.error(\"Failed to get models response body\", errorText)\n\n throw new HTTPError(\"Failed to get models\", response)\n }\n\n const models = (await response.json()) as ModelsResponse\n\n // Persist models response for debugging/inspection.\n // Best effort: do not fail startup if the local write fails.\n try {\n await fs.mkdir(PATHS.APP_DIR, { recursive: true })\n await fs.writeFile(\n PATHS.MODELS_PATH,\n `${JSON.stringify(models, null, 2)}\\n`,\n {\n encoding: \"utf8\",\n mode: 0o600,\n },\n )\n } catch {\n // ignore\n }\n\n return models\n}\n\nexport interface ModelsResponse {\n data: Array<Model>\n object: string\n}\n\ninterface ModelLimits {\n max_context_window_tokens?: number\n max_output_tokens?: number\n max_prompt_tokens?: number\n max_inputs?: number\n}\n\ninterface ModelSupports {\n max_thinking_budget?: number\n min_thinking_budget?: number\n tool_calls?: boolean\n parallel_tool_calls?: boolean\n dimensions?: boolean\n streaming?: boolean\n structured_outputs?: boolean\n vision?: boolean\n adaptive_thinking?: boolean\n reasoning_effort?: Array<string>\n}\n\ninterface ModelCapabilities {\n family: string\n limits: ModelLimits\n object: string\n supports: ModelSupports\n tokenizer: string\n type: string\n}\n\ninterface ModelBilling {\n is_premium?: boolean\n multiplier?: number\n}\n\nexport interface Model {\n billing?: ModelBilling\n capabilities: ModelCapabilities\n id: string\n model_picker_enabled: boolean\n name: string\n object: string\n preview: boolean\n vendor: string\n version: string\n policy?: {\n state: string\n terms: string\n }\n supported_endpoints?: Array<string>\n}\n","import consola from \"consola\"\n\nimport type {\n AccountContext,\n AccountRuntime,\n AccountType,\n} from \"~/lib/types/account\"\nimport type { QuotaDetail } from \"~/services/github/get-copilot-usage\"\n\nexport type AuthSnapshot = Readonly<{\n githubToken: string\n accountType: AccountType\n}>\n\nexport const takeAuthSnapshot = (account: AccountRuntime): AuthSnapshot => ({\n githubToken: account.githubToken,\n accountType: account.accountType,\n})\n\nexport const isAuthSnapshotCurrent = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n): boolean =>\n account.githubToken === snapshot.githubToken\n && account.accountType === snapshot.accountType\n\nexport const isSameAuthSnapshot = (\n a: AuthSnapshot | undefined,\n b: AuthSnapshot,\n): boolean => {\n if (!a) return false\n return a.githubToken === b.githubToken && a.accountType === b.accountType\n}\n\nexport const toAccountContextFromSnapshot = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n copilotToken?: string,\n): AccountContext => ({\n accountLogin: account.accountLogin,\n githubToken: snapshot.githubToken,\n copilotToken,\n ...(account.copilotApiUrl !== undefined ?\n { copilotApiUrl: account.copilotApiUrl }\n : {}),\n accountType: snapshot.accountType,\n vsCodeVersion: account.vsCodeVersion,\n clientDeviceId: account.clientDeviceId,\n clientMachineId: account.clientMachineId,\n clientSessionId: account.clientSessionId,\n})\n\nexport const applyCopilotTokenIfCurrent = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n copilotToken: string,\n): boolean => {\n if (!isAuthSnapshotCurrent(account, snapshot)) {\n return false\n }\n\n account.copilotToken = copilotToken\n return true\n}\n\nexport const applyModelsIfCurrent = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n models: AccountRuntime[\"models\"],\n): boolean => {\n if (!isAuthSnapshotCurrent(account, snapshot)) {\n return false\n }\n\n account.models = models\n return true\n}\n\nexport const applyTokenRefreshSuccessIfCurrent = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n token: string,\n): boolean => {\n if (!isAuthSnapshotCurrent(account, snapshot)) {\n return false\n }\n\n account.copilotToken = token\n account.failed = false\n account.failureReason = undefined\n return true\n}\n\nexport const applyTokenRefreshFailureIfCurrent = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n error: unknown,\n): boolean => {\n if (!isAuthSnapshotCurrent(account, snapshot)) {\n return false\n }\n\n account.failed = true\n account.failureReason = String(error)\n return true\n}\n\nexport const applyQuotaRefreshSuccessIfCurrent = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n result: {\n premium: QuotaDetail\n copilotApiUrl?: string\n },\n): boolean => {\n if (!isAuthSnapshotCurrent(account, snapshot)) {\n return false\n }\n\n const { premium, copilotApiUrl } = result\n\n account.premiumEntitlement = premium.entitlement\n account.premiumRemaining = premium.remaining\n account.unlimited = premium.unlimited\n account.overagePermitted = premium.overage_permitted\n if (copilotApiUrl) {\n account.copilotApiUrl = copilotApiUrl\n }\n account.lastQuotaFetch = Date.now()\n account.failed = false\n account.failureReason = undefined\n return true\n}\n\nexport const setAccountFailedState = (\n account: AccountRuntime,\n reason: string,\n): void => {\n account.failed = true\n account.failureReason = reason\n consola.warn(`Account ${account.id} marked as failed: ${reason}`)\n}\n\nexport const applyUnauthorizedIfCurrent = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n reason: string,\n): boolean => {\n if (!isAuthSnapshotCurrent(account, snapshot)) {\n return false\n }\n\n setAccountFailedState(account, reason)\n return true\n}\n","import type { AccountRuntime } from \"~/lib/types/account\"\nimport type { Model } from \"~/services/copilot/get-models\"\n\nexport type QuotaReservation = Readonly<{ id: symbol }>\n\nexport const getCostUnits = (model: Model): number => {\n // Per user decision: missing billing => treat as free (costUnits = 0)\n const billing = model.billing\n if (!billing) {\n return 0\n }\n\n if (billing.is_premium !== true) {\n return 0\n }\n\n const multiplier = billing.multiplier\n if (\n typeof multiplier !== \"number\"\n || !Number.isFinite(multiplier)\n || multiplier <= 0\n ) {\n return 1\n }\n\n return multiplier\n}\n\nexport const getEffectivePremiumRemaining = (\n account: AccountRuntime,\n): number | undefined => {\n if (account.premiumRemaining === undefined) {\n return undefined\n }\n\n const reserved = account.premiumReserved ?? 0\n return account.premiumRemaining - reserved\n}\n\nexport const reservePremiumUnits = (\n account: AccountRuntime,\n units: number,\n): QuotaReservation | undefined => {\n if (units <= 0) {\n return undefined\n }\n\n const id = Symbol(\"quotaReservation\")\n\n if (!account.premiumReservations) {\n account.premiumReservations = new Map()\n }\n\n account.premiumReservations.set(id, units)\n account.premiumReserved = (account.premiumReserved ?? 0) + units\n\n return { id }\n}\n\nexport const releasePremiumReservation = (\n account: AccountRuntime,\n reservation?: QuotaReservation,\n): void => {\n if (!reservation) {\n return\n }\n\n const reservations = account.premiumReservations\n if (!reservations) {\n return\n }\n\n const reservedUnits = reservations.get(reservation.id)\n if (reservedUnits === undefined) {\n return\n }\n\n reservations.delete(reservation.id)\n\n const nextReserved = (account.premiumReserved ?? 0) - reservedUnits\n account.premiumReserved = Math.max(0, nextReserved)\n\n if (reservations.size === 0) {\n account.premiumReservations = undefined\n }\n}\n","import type { Database } from \"bun:sqlite\"\n\nimport { consola } from \"consola\"\n\nexport interface DailyStats {\n date: string\n request_count: number\n premium_consumed: number\n tokens_total: number\n error_count: number\n}\n\nexport interface DailyAccountStats extends DailyStats {\n account_id: string\n}\n\nexport interface PremiumStatsResponse {\n daily: Array<DailyStats>\n by_account: Array<DailyAccountStats>\n range: { from: string; to: string; granularity: \"day\" | \"hour\" }\n}\n\nexport const DEFAULT_STATS_RETENTION_DAYS = 180\n\nexport function toLocalDateString(ms: number): string {\n const d = new Date(ms)\n return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, \"0\")}-${String(d.getDate()).padStart(2, \"0\")}`\n}\n\nexport class StatsStore {\n private readonly db: Database\n private readonly upsertStmt: ReturnType<Database[\"query\"]>\n private readonly insertSnapshotStmt: ReturnType<Database[\"query\"]>\n\n constructor(db: Database) {\n this.db = db\n this.upsertStmt = db.query(`\n INSERT INTO daily_premium_stats\n (date, account_id, request_count, cost_units_sum, tokens_total, error_count, updated_at_ms)\n VALUES (?, ?, 1, ?, ?, ?, ?)\n ON CONFLICT(date, account_id) DO UPDATE SET\n request_count = request_count + 1,\n cost_units_sum = cost_units_sum + excluded.cost_units_sum,\n tokens_total = tokens_total + excluded.tokens_total,\n error_count = error_count + excluded.error_count,\n updated_at_ms = excluded.updated_at_ms\n `)\n this.insertSnapshotStmt = db.query(`\n INSERT INTO quota_snapshots\n (account_id, snapshot_at_ms, remaining, entitlement, unlimited, source)\n VALUES (?, ?, ?, ?, ?, ?)\n `)\n }\n\n upsertDailyStats(record: {\n startedAtMs: number\n accountId: string\n costUnits: number\n tokensTotal: number\n hasError: boolean\n }): void {\n const date = toLocalDateString(record.startedAtMs)\n this.upsertStmt.run(\n date,\n record.accountId,\n record.costUnits,\n record.tokensTotal,\n record.hasError ? 1 : 0,\n Date.now(),\n )\n }\n\n insertQuotaSnapshot(record: {\n accountId: string\n snapshotAtMs: number\n remaining: number\n entitlement: number\n unlimited: boolean\n source: string\n }): void {\n this.insertSnapshotStmt.run(\n record.accountId,\n record.snapshotAtMs,\n record.remaining,\n record.entitlement,\n record.unlimited ? 1 : 0,\n record.source,\n )\n }\n\n getConsumptionFromSnapshots(params: {\n fromMs: number\n toMs: number\n granularity: \"day\" | \"hour\"\n accountId?: string\n }): Array<{ date: string; account_id: string; premium_consumed: number }> {\n const dateExpr =\n params.granularity === \"hour\" ?\n \"strftime('%Y-%m-%dT%H:00:00Z', snapshot_at_ms / 1000, 'unixepoch')\"\n : \"date(snapshot_at_ms / 1000, 'unixepoch', 'localtime')\"\n\n const accountFilter = params.accountId ? \" AND account_id = ?\" : \"\"\n const args: Array<string | number> = []\n\n // baseline CTE: WHERE snapshot_at_ms < ?\n args.push(params.fromMs)\n // baseline CTE: AND account_id = ? (if filtered)\n if (params.accountId) args.push(params.accountId)\n\n // all_snaps CTE: WHERE snapshot_at_ms >= ? AND snapshot_at_ms <= ?\n args.push(params.fromMs, params.toMs)\n // all_snaps CTE: AND account_id = ? (if filtered)\n if (params.accountId) args.push(params.accountId)\n\n // outer WHERE: snapshot_at_ms >= ?\n args.push(params.fromMs)\n\n return this.db\n .query(\n `WITH baseline AS (\n SELECT qs.account_id, qs.snapshot_at_ms, qs.remaining, qs.id\n FROM quota_snapshots qs\n INNER JOIN (\n SELECT account_id, MAX(snapshot_at_ms) AS max_ts\n FROM quota_snapshots\n WHERE snapshot_at_ms < ?\n AND unlimited = 0${accountFilter}\n GROUP BY account_id\n ) latest ON qs.account_id = latest.account_id\n AND qs.snapshot_at_ms = latest.max_ts\n ),\n all_snaps AS (\n SELECT account_id, snapshot_at_ms, remaining, id\n FROM baseline\n UNION ALL\n SELECT account_id, snapshot_at_ms, remaining, id\n FROM quota_snapshots\n WHERE snapshot_at_ms >= ? AND snapshot_at_ms <= ?\n AND unlimited = 0${accountFilter}\n ),\n with_prev AS (\n SELECT\n account_id,\n snapshot_at_ms,\n remaining,\n LAG(remaining) OVER (\n PARTITION BY account_id ORDER BY snapshot_at_ms, id\n ) AS prev_remaining\n FROM all_snaps\n )\n SELECT\n ${dateExpr} AS date,\n account_id,\n SUM(\n CASE WHEN prev_remaining IS NOT NULL AND prev_remaining > remaining\n THEN prev_remaining - remaining\n ELSE 0\n END\n ) AS premium_consumed\n FROM with_prev\n WHERE snapshot_at_ms >= ?\n GROUP BY 1, 2\n ORDER BY 1, 2`,\n )\n .all(...args) as Array<{\n date: string\n account_id: string\n premium_consumed: number\n }>\n }\n\n getDailyPremiumStats(params: {\n from: string\n to: string\n accountId?: string\n }): { daily: Array<DailyStats>; byAccount: Array<DailyAccountStats> } {\n const accountFilter = params.accountId ? \" AND account_id = ?\" : \"\"\n const args: Array<string | number> = [params.from, params.to]\n if (params.accountId) args.push(params.accountId)\n\n const dailyMetrics = this.db\n .query(\n `SELECT date,\n SUM(request_count) AS request_count,\n SUM(tokens_total) AS tokens_total,\n SUM(error_count) AS error_count\n FROM daily_premium_stats\n WHERE date >= ? AND date <= ?${accountFilter}\n GROUP BY date\n ORDER BY date`,\n )\n .all(...args) as Array<{\n date: string\n request_count: number\n tokens_total: number\n error_count: number\n }>\n\n const byAccountMetrics = this.db\n .query(\n `SELECT date, account_id, request_count, tokens_total, error_count\n FROM daily_premium_stats\n WHERE date >= ? AND date <= ?${accountFilter}\n ORDER BY date, account_id`,\n )\n .all(...args) as Array<{\n date: string\n account_id: string\n request_count: number\n tokens_total: number\n error_count: number\n }>\n\n const fromMs = this.localDateToMs(params.from)\n const toMs = this.localDateEndMs(params.to)\n\n const consumption = this.getConsumptionFromSnapshots({\n fromMs,\n toMs,\n granularity: \"day\",\n accountId: params.accountId,\n })\n\n return this.mergeMetricsAndConsumption(\n dailyMetrics,\n byAccountMetrics,\n consumption,\n )\n }\n\n getHourlyPremiumStats(params: {\n fromMs: number\n toMs: number\n accountId?: string\n }): { daily: Array<DailyStats>; byAccount: Array<DailyAccountStats> } {\n const accountFilter = params.accountId ? \" AND account_id = ?\" : \"\"\n const dailyArgs: Array<string | number> = [params.fromMs, params.toMs]\n if (params.accountId) dailyArgs.push(params.accountId)\n\n const dailyMetrics = this.db\n .query(\n `SELECT strftime('%Y-%m-%dT%H:00:00Z', started_at_ms / 1000, 'unixepoch') AS date,\n COUNT(*) AS request_count,\n COALESCE(SUM(tokens_total), 0) AS tokens_total,\n SUM(CASE WHEN error_name IS NOT NULL THEN 1 ELSE 0 END) AS error_count\n FROM request_log\n WHERE cost_units > 0\n AND started_at_ms >= ? AND started_at_ms <= ?${accountFilter}\n GROUP BY 1\n ORDER BY 1`,\n )\n .all(...dailyArgs) as Array<{\n date: string\n request_count: number\n tokens_total: number\n error_count: number\n }>\n\n const byAccountFilter =\n params.accountId ? \" AND account_id = ?\" : \" AND account_id IS NOT NULL\"\n const byAccountArgs: Array<string | number> = [params.fromMs, params.toMs]\n if (params.accountId) byAccountArgs.push(params.accountId)\n\n const byAccountMetrics = this.db\n .query(\n `SELECT strftime('%Y-%m-%dT%H:00:00Z', started_at_ms / 1000, 'unixepoch') AS date,\n account_id,\n COUNT(*) AS request_count,\n COALESCE(SUM(tokens_total), 0) AS tokens_total,\n SUM(CASE WHEN error_name IS NOT NULL THEN 1 ELSE 0 END) AS error_count\n FROM request_log\n WHERE cost_units > 0\n AND started_at_ms >= ? AND started_at_ms <= ?${byAccountFilter}\n GROUP BY 1, 2\n ORDER BY 1, 2`,\n )\n .all(...byAccountArgs) as Array<{\n date: string\n account_id: string\n request_count: number\n tokens_total: number\n error_count: number\n }>\n\n const consumption = this.getConsumptionFromSnapshots({\n fromMs: params.fromMs,\n toMs: params.toMs,\n granularity: \"hour\",\n accountId: params.accountId,\n })\n\n return this.mergeMetricsAndConsumption(\n dailyMetrics,\n byAccountMetrics,\n consumption,\n )\n }\n\n cleanupStatsRetention(\n retentionDays: number = DEFAULT_STATS_RETENTION_DAYS,\n ): void {\n try {\n const nowMs = Date.now()\n const cutoffMs = nowMs - retentionDays * 24 * 60 * 60 * 1000\n const cutoffDate = toLocalDateString(cutoffMs)\n this.db\n .query(\"DELETE FROM daily_premium_stats WHERE date < ?;\")\n .run(cutoffDate)\n\n // Keep the latest snapshot per account before the cutoff as baseline\n // for getConsumptionFromSnapshots() which needs a pre-range reference.\n this.db\n .query(\n `DELETE FROM quota_snapshots\n WHERE snapshot_at_ms < ?\n AND id NOT IN (\n SELECT qs.id\n FROM quota_snapshots qs\n INNER JOIN (\n SELECT account_id, MAX(snapshot_at_ms) AS max_ts\n FROM quota_snapshots\n WHERE snapshot_at_ms < ?\n GROUP BY account_id\n ) latest ON qs.account_id = latest.account_id\n AND qs.snapshot_at_ms = latest.max_ts\n );`,\n )\n .run(cutoffMs, cutoffMs)\n } catch (error) {\n consola.debug(\"Failed to cleanup stats retention\", error)\n }\n }\n\n private localDateToMs(dateStr: string): number {\n const [y, m, d] = dateStr.split(\"-\").map(Number)\n return new Date(y, m - 1, d).getTime()\n }\n\n /** End-of-day ms (next local midnight - 1ms), DST-safe. */\n private localDateEndMs(dateStr: string): number {\n const [y, m, d] = dateStr.split(\"-\").map(Number)\n return new Date(y, m - 1, d + 1).getTime() - 1\n }\n\n private mergeMetricsAndConsumption(\n dailyMetrics: Array<{\n date: string\n request_count: number\n tokens_total: number\n error_count: number\n }>,\n byAccountMetrics: Array<{\n date: string\n account_id: string\n request_count: number\n tokens_total: number\n error_count: number\n }>,\n consumption: Array<{\n date: string\n account_id: string\n premium_consumed: number\n }>,\n ): { daily: Array<DailyStats>; byAccount: Array<DailyAccountStats> } {\n const consumptionMap = new Map<string, number>()\n const dateConsumptionMap = new Map<string, number>()\n for (const c of consumption) {\n consumptionMap.set(`${c.date}|${c.account_id}`, c.premium_consumed)\n dateConsumptionMap.set(\n c.date,\n (dateConsumptionMap.get(c.date) ?? 0) + c.premium_consumed,\n )\n }\n\n const allDates = new Set([\n ...dailyMetrics.map((m) => m.date),\n ...consumption.map((c) => c.date),\n ])\n const metricsMap = new Map(dailyMetrics.map((m) => [m.date, m]))\n\n const daily: Array<DailyStats> = [...allDates].sort().map((date) => {\n const m = metricsMap.get(date)\n return {\n date,\n request_count: m?.request_count ?? 0,\n premium_consumed: dateConsumptionMap.get(date) ?? 0,\n tokens_total: m?.tokens_total ?? 0,\n error_count: m?.error_count ?? 0,\n }\n })\n\n const allAccountDateKeys = new Set([\n ...byAccountMetrics.map((m) => `${m.date}|${m.account_id}`),\n ...consumption.map((c) => `${c.date}|${c.account_id}`),\n ])\n const byAccountMetricsMap = new Map(\n byAccountMetrics.map((m) => [`${m.date}|${m.account_id}`, m]),\n )\n\n const byAccount: Array<DailyAccountStats> = [...allAccountDateKeys]\n .sort()\n .map((key) => {\n const [date, account_id] = key.split(\"|\")\n const m = byAccountMetricsMap.get(key)\n return {\n date,\n account_id,\n request_count: m?.request_count ?? 0,\n premium_consumed: consumptionMap.get(key) ?? 0,\n tokens_total: m?.tokens_total ?? 0,\n error_count: m?.error_count ?? 0,\n }\n })\n\n return { daily, byAccount }\n }\n}\n","import type { Database, SQLQueryBindings } from \"bun:sqlite\"\nimport type { Context } from \"hono\"\n\nimport consola from \"consola\"\n\nimport type {\n ChatCompletionChunk,\n ChatCompletionResponse,\n} from \"~/services/copilot/create-chat-completions\"\nimport type { EmbeddingResponse } from \"~/services/copilot/create-embeddings\"\nimport type {\n ResponseStreamEvent,\n ResponsesResult,\n ResponseUsage,\n} from \"~/services/copilot/create-responses\"\n\nimport type { AccountSelectionReason } from \"./accounts-manager\"\nimport type { AffinityKeySource } from \"./utils\"\n\nimport { getAdminDb, getAdminDbPath, getAdminDbUserVersion } from \"./admin-db\"\nimport { consumeOutboundHeadersSnapshot } from \"./request-context\"\nimport { StatsStore } from \"./stats-store\"\n\nconst DEFAULT_RETENTION_DAYS = 35\nconst DEFAULT_MAX_ROWS = 200_000\n\nconst INSERT_WARN_THROTTLE_MS = 30_000\n\nlet lastInsertWarnAtMs = 0\nlet suppressedInsertWarnCount = 0\n\nfunction warnInsertFailure(error: unknown): void {\n const now = Date.now()\n\n if (now - lastInsertWarnAtMs < INSERT_WARN_THROTTLE_MS) {\n suppressedInsertWarnCount++\n return\n }\n\n const suppressed = suppressedInsertWarnCount\n suppressedInsertWarnCount = 0\n lastInsertWarnAtMs = now\n\n const suffix =\n suppressed > 0 ? ` (suppressed ${suppressed} similar errors)` : \"\"\n consola.warn(`Failed to insert request log${suffix}`, error)\n}\n\nfunction toDbNull<T>(value: T | null | undefined): T | null {\n return value === undefined ? null : value\n}\n\nfunction toDbBool(value: boolean | undefined): 0 | 1 | null {\n if (value === true) return 1\n if (value === false) return 0\n return null\n}\n\nexport type ClientIpInfo = {\n ip?: string\n source?: string\n}\n\nexport function getClientIpInfo(c: Context): ClientIpInfo {\n const cf = c.req.header(\"cf-connecting-ip\")\n if (cf) return { ip: cf.trim(), source: \"cf-connecting-ip\" }\n\n const xff = c.req.header(\"x-forwarded-for\")\n if (xff) {\n const first = xff.split(\",\")[0]?.trim()\n if (first) return { ip: first, source: \"x-forwarded-for\" }\n }\n\n const xri = c.req.header(\"x-real-ip\")\n if (xri) return { ip: xri.trim(), source: \"x-real-ip\" }\n\n return {}\n}\n\nexport type NormalizedUsage = {\n tokensInput?: number\n tokensOutput?: number\n tokensTotal?: number\n tokensCachedInput?: number\n usageJson?: string\n}\n\nexport function normalizeChatCompletionsUsage(\n usage?: ChatCompletionResponse[\"usage\"] | ChatCompletionChunk[\"usage\"],\n): NormalizedUsage {\n if (!usage) return {}\n\n const cached = usage.prompt_tokens_details?.cached_tokens ?? 0\n const prompt = usage.prompt_tokens\n const completion = usage.completion_tokens\n const total = usage.total_tokens\n\n return {\n tokensCachedInput: cached,\n tokensInput: Math.max(0, prompt - cached),\n tokensOutput: completion,\n tokensTotal: total,\n usageJson: JSON.stringify(usage),\n }\n}\n\nexport function normalizeResponsesUsage(\n usage?: ResponseUsage | null,\n): NormalizedUsage {\n if (!usage) return {}\n\n const cached = usage.input_tokens_details?.cached_tokens ?? 0\n const input = usage.input_tokens\n const output = usage.output_tokens ?? 0\n const total = usage.total_tokens\n\n return {\n tokensCachedInput: cached,\n tokensInput: Math.max(0, input - cached),\n tokensOutput: output,\n tokensTotal: total,\n usageJson: JSON.stringify(usage),\n }\n}\n\ntype AnthropicUsage = {\n input_tokens?: number\n output_tokens?: number\n cache_creation_input_tokens?: number\n cache_read_input_tokens?: number\n service_tier?: \"standard\" | \"priority\" | \"batch\"\n}\n\nexport function normalizeMessagesUsage(\n usage?: AnthropicUsage | null,\n): NormalizedUsage {\n if (!usage) return {}\n\n const cached = usage.cache_read_input_tokens ?? 0\n const input = usage.input_tokens\n const output = usage.output_tokens\n const hasInput = typeof input === \"number\"\n const hasOutput = typeof output === \"number\"\n const tokensInput = hasInput ? Math.max(0, input - cached) : undefined\n const tokensOutput = hasOutput ? output : undefined\n const tokensTotal =\n hasInput || hasOutput ? (input ?? 0) + (output ?? 0) : undefined\n\n return {\n tokensCachedInput: cached,\n tokensInput,\n tokensOutput,\n tokensTotal,\n usageJson: JSON.stringify(usage),\n }\n}\n\nexport function normalizeEmbeddingsUsage(\n usage?: EmbeddingResponse[\"usage\"],\n): NormalizedUsage {\n if (!usage) return {}\n\n return {\n tokensCachedInput: 0,\n tokensInput: usage.prompt_tokens,\n tokensOutput: 0,\n tokensTotal: usage.total_tokens,\n usageJson: JSON.stringify(usage),\n }\n}\n\nexport type RequestLogInsert = {\n requestId: string\n startedAtMs: number\n finishedAtMs?: number\n durationMs?: number\n ttfbMs?: number\n\n method: string\n path: string\n upstreamEndpoint?: string\n stream: boolean\n\n accountId?: string\n accountType?: string\n costUnits?: number\n clientModel?: string\n upstreamModel?: string\n\n clientIp?: string\n clientIpSource?: string\n userAgent?: string\n\n userId?: string\n safetyIdentifier?: string\n promptCacheKey?: string\n initiator?: \"agent\" | \"user\"\n isSubagent?: boolean\n upstreamRequestId?: string\n outboundXRequestId?: string\n outboundXAgentTaskId?: string\n outboundXInteractionId?: string\n outboundXInteractionType?: string\n outboundOpenaiIntent?: string\n outboundUserAgent?: string\n affinityKeyUsed?: string\n affinityKeySource?: AffinityKeySource\n selectionReason?: AccountSelectionReason\n\n tokensInput?: number\n tokensOutput?: number\n tokensTotal?: number\n tokensCachedInput?: number\n usageJson?: string\n\n premiumRemainingBefore?: number\n premiumRemainingAfter?: number\n premiumRemainingDiff?: number\n premiumUnlimitedBefore?: boolean\n premiumUnlimitedAfter?: boolean\n\n httpStatus?: number\n errorName?: string\n errorStatus?: number\n errorMessage?: string\n upstreamErrorMessageRaw?: string\n selectionFailureReason?: string\n\n affinityHit?: boolean\n affinityCacheKey?: string\n}\n\nexport type RequestLogRow = {\n id: number\n request_id: string\n started_at_ms: number\n finished_at_ms: number | null\n duration_ms: number | null\n ttfb_ms: number | null\n\n method: string\n path: string\n upstream_endpoint: string | null\n stream: number\n\n account_id: string | null\n account_type: string | null\n cost_units: number | null\n client_model: string | null\n upstream_model: string | null\n\n client_ip: string | null\n client_ip_source: string | null\n user_agent: string | null\n\n user_id: string | null\n safety_identifier: string | null\n prompt_cache_key: string | null\n initiator: string | null\n is_subagent: number | null\n upstream_request_id: string | null\n outbound_x_request_id: string | null\n outbound_x_agent_task_id: string | null\n outbound_x_interaction_id: string | null\n outbound_x_interaction_type: string | null\n outbound_openai_intent: string | null\n outbound_user_agent: string | null\n affinity_key_used: string | null\n affinity_key_source: string | null\n selection_reason: string | null\n\n tokens_input: number | null\n tokens_output: number | null\n tokens_total: number | null\n tokens_cached_input: number | null\n usage_json: string | null\n\n premium_remaining_before: number | null\n premium_remaining_after: number | null\n premium_remaining_diff: number | null\n premium_unlimited_before: number | null\n premium_unlimited_after: number | null\n\n http_status: number | null\n error_name: string | null\n error_status: number | null\n error_message: string | null\n upstream_error_message_raw: string | null\n selection_failure_reason: string | null\n\n affinity_hit: number | null\n affinity_cache_key: string | null\n}\n\nexport type RequestLogQuery = {\n limit: number\n cursorId?: number\n\n accountId?: string\n upstreamModel?: string\n clientModel?: string\n upstreamEndpoint?: string\n path?: string\n status?: number\n hasError?: boolean\n fromMs?: number\n toMs?: number\n}\n\nexport type SessionUsageKey = {\n promptCacheKey: string\n safetyIdentifier: string\n clientModel: string\n}\n\nexport type RequestLogQueryResult = {\n items: Array<RequestLogRow>\n nextCursorId?: number\n hasMore: boolean\n}\n\nexport type AccountStatsRow = {\n account_id: string\n request_count: number\n error_count: number\n tokens_total: number\n avg_duration_ms: number\n last_request_at_ms: number\n}\n\nfunction pickRecordedHeader(\n explicitValue: string | undefined,\n snapshotValue: string | undefined,\n): string | undefined {\n return explicitValue ?? snapshotValue\n}\n\nfunction buildInsertArgs(record: RequestLogInsert) {\n const outboundHeadersSnapshot = consumeOutboundHeadersSnapshot()\n const recordedOutboundHeaders = {\n xRequestId: pickRecordedHeader(\n record.outboundXRequestId,\n outboundHeadersSnapshot?.xRequestId,\n ),\n xAgentTaskId: pickRecordedHeader(\n record.outboundXAgentTaskId,\n outboundHeadersSnapshot?.xAgentTaskId,\n ),\n xInteractionId: pickRecordedHeader(\n record.outboundXInteractionId,\n outboundHeadersSnapshot?.xInteractionId,\n ),\n xInteractionType: pickRecordedHeader(\n record.outboundXInteractionType,\n outboundHeadersSnapshot?.xInteractionType,\n ),\n openaiIntent: pickRecordedHeader(\n record.outboundOpenaiIntent,\n outboundHeadersSnapshot?.openaiIntent,\n ),\n userAgent: pickRecordedHeader(\n record.outboundUserAgent,\n outboundHeadersSnapshot?.userAgent,\n ),\n }\n\n return [\n record.requestId,\n record.startedAtMs,\n toDbNull(record.finishedAtMs),\n toDbNull(record.durationMs),\n toDbNull(record.ttfbMs),\n\n record.method,\n record.path,\n toDbNull(record.upstreamEndpoint),\n record.stream ? 1 : 0,\n\n toDbNull(record.accountId),\n toDbNull(record.accountType),\n toDbNull(record.costUnits),\n toDbNull(record.clientModel),\n toDbNull(record.upstreamModel),\n\n toDbNull(record.clientIp),\n toDbNull(record.clientIpSource),\n toDbNull(record.userAgent),\n toDbNull(record.userId),\n toDbNull(record.safetyIdentifier),\n toDbNull(record.promptCacheKey),\n toDbNull(record.initiator),\n toDbBool(record.isSubagent),\n toDbNull(record.upstreamRequestId),\n toDbNull(recordedOutboundHeaders.xRequestId),\n toDbNull(recordedOutboundHeaders.xAgentTaskId),\n toDbNull(recordedOutboundHeaders.xInteractionId),\n toDbNull(recordedOutboundHeaders.xInteractionType),\n toDbNull(recordedOutboundHeaders.openaiIntent),\n toDbNull(recordedOutboundHeaders.userAgent),\n toDbNull(record.affinityKeyUsed),\n toDbNull(record.affinityKeySource),\n toDbNull(record.selectionReason),\n\n toDbNull(record.tokensInput),\n toDbNull(record.tokensOutput),\n toDbNull(record.tokensTotal),\n toDbNull(record.tokensCachedInput),\n toDbNull(record.usageJson),\n\n toDbNull(record.premiumRemainingBefore),\n toDbNull(record.premiumRemainingAfter),\n toDbNull(record.premiumRemainingDiff),\n toDbBool(record.premiumUnlimitedBefore),\n toDbBool(record.premiumUnlimitedAfter),\n\n toDbNull(record.httpStatus),\n toDbNull(record.errorName),\n toDbNull(record.errorStatus),\n toDbNull(record.errorMessage),\n toDbNull(record.upstreamErrorMessageRaw),\n toDbNull(record.selectionFailureReason),\n\n toDbBool(record.affinityHit),\n toDbNull(record.affinityCacheKey),\n ] as const\n}\n\nexport class RequestHistoryStore {\n private readonly db: Database\n private readonly insertStmt: ReturnType<Database[\"query\"]>\n\n private readonly getByRequestIdStmt: ReturnType<Database[\"query\"]>\n private readonly getLastCompletedUsageBySessionStmt: ReturnType<\n Database[\"query\"]\n >\n\n constructor(db: Database) {\n this.db = db\n\n const insertColumns = [\n \"request_id\",\n \"started_at_ms\",\n \"finished_at_ms\",\n \"duration_ms\",\n \"ttfb_ms\",\n \"method\",\n \"path\",\n \"upstream_endpoint\",\n \"stream\",\n \"account_id\",\n \"account_type\",\n \"cost_units\",\n \"client_model\",\n \"upstream_model\",\n \"client_ip\",\n \"client_ip_source\",\n \"user_agent\",\n \"user_id\",\n \"safety_identifier\",\n \"prompt_cache_key\",\n \"initiator\",\n \"is_subagent\",\n \"upstream_request_id\",\n \"outbound_x_request_id\",\n \"outbound_x_agent_task_id\",\n \"outbound_x_interaction_id\",\n \"outbound_x_interaction_type\",\n \"outbound_openai_intent\",\n \"outbound_user_agent\",\n \"affinity_key_used\",\n \"affinity_key_source\",\n \"selection_reason\",\n \"tokens_input\",\n \"tokens_output\",\n \"tokens_total\",\n \"tokens_cached_input\",\n \"usage_json\",\n \"premium_remaining_before\",\n \"premium_remaining_after\",\n \"premium_remaining_diff\",\n \"premium_unlimited_before\",\n \"premium_unlimited_after\",\n \"http_status\",\n \"error_name\",\n \"error_status\",\n \"error_message\",\n \"upstream_error_message_raw\",\n \"selection_failure_reason\",\n \"affinity_hit\",\n \"affinity_cache_key\",\n ]\n\n this.insertStmt = db.query(`\n INSERT INTO request_log (${insertColumns.join(\", \")})\n VALUES (${insertColumns.map(() => \"?\").join(\", \")});\n `)\n\n this.getByRequestIdStmt = db.query(\n \"SELECT * FROM request_log WHERE request_id = ? LIMIT 1;\",\n )\n\n this.getLastCompletedUsageBySessionStmt = db.query(`\n SELECT\n tokens_input,\n tokens_output,\n tokens_total,\n tokens_cached_input\n FROM request_log\n WHERE prompt_cache_key = ?\n AND safety_identifier = ?\n AND client_model = ?\n AND finished_at_ms IS NOT NULL\n AND tokens_input IS NOT NULL\n ORDER BY finished_at_ms DESC\n LIMIT 1;\n `)\n }\n\n insert(record: RequestLogInsert): void {\n try {\n const args = buildInsertArgs(record)\n\n this.insertStmt.run(...args)\n\n // Write-time aggregation for premium stats\n if (\n record.costUnits !== undefined\n && record.costUnits > 0\n && record.accountId\n ) {\n try {\n getStatsStoreInstance()?.upsertDailyStats({\n startedAtMs: record.startedAtMs,\n accountId: record.accountId,\n costUnits: record.costUnits,\n tokensTotal: record.tokensTotal ?? 0,\n hasError: record.errorName !== undefined,\n })\n } catch {\n // Stats aggregation is best-effort; never break request logging\n }\n }\n } catch (error) {\n warnInsertFailure(error)\n }\n }\n\n getByRequestId(requestId: string): RequestLogRow | null {\n try {\n const row = this.getByRequestIdStmt.get(requestId) as\n | RequestLogRow\n | null\n | undefined\n return row ?? null\n } catch (error) {\n consola.debug(\"Failed to fetch request log by request_id\", error)\n return null\n }\n }\n\n getLastCompletedUsageBySession(\n session: SessionUsageKey,\n ): NormalizedUsage | null {\n if (\n !session.promptCacheKey\n || !session.safetyIdentifier\n || !session.clientModel\n ) {\n return null\n }\n\n try {\n const row = this.getLastCompletedUsageBySessionStmt.get(\n session.promptCacheKey,\n session.safetyIdentifier,\n session.clientModel,\n ) as\n | {\n tokens_input: number | null\n tokens_output: number | null\n tokens_total: number | null\n tokens_cached_input: number | null\n }\n | null\n | undefined\n\n if (!row || row.tokens_input === null) {\n return null\n }\n\n const tokensOutput =\n row.tokens_output === null ? undefined : row.tokens_output\n const tokensTotal =\n row.tokens_total === null ? undefined : row.tokens_total\n const tokensCachedInput =\n row.tokens_cached_input === null ? undefined : row.tokens_cached_input\n\n return {\n tokensInput: row.tokens_input,\n tokensOutput,\n tokensTotal,\n tokensCachedInput,\n }\n } catch (error) {\n consola.debug(\"Failed to fetch last completed usage by session\", error)\n return null\n }\n }\n\n query(params: RequestLogQuery): RequestLogQueryResult {\n const limit = Math.max(1, Math.min(params.limit, 200))\n\n const where: Array<string> = []\n const values: Array<SQLQueryBindings> = []\n\n if (params.cursorId !== undefined) {\n where.push(\"id < ?\")\n values.push(params.cursorId)\n }\n\n if (params.accountId) {\n where.push(\"account_id = ?\")\n values.push(params.accountId)\n }\n\n if (params.upstreamModel) {\n where.push(\"upstream_model = ?\")\n values.push(params.upstreamModel)\n }\n\n if (params.clientModel) {\n where.push(\"client_model = ?\")\n values.push(params.clientModel)\n }\n\n if (params.upstreamEndpoint) {\n where.push(\"upstream_endpoint = ?\")\n values.push(params.upstreamEndpoint)\n }\n\n if (params.path) {\n where.push(\"path = ?\")\n values.push(params.path)\n }\n\n if (params.status !== undefined) {\n where.push(\"http_status = ?\")\n values.push(params.status)\n }\n\n if (params.hasError === true) {\n where.push(\"http_status >= 400\")\n }\n if (params.hasError === false) {\n where.push(\"http_status < 400\")\n }\n\n if (params.fromMs !== undefined) {\n where.push(\"started_at_ms >= ?\")\n values.push(params.fromMs)\n }\n\n if (params.toMs !== undefined) {\n where.push(\"started_at_ms <= ?\")\n values.push(params.toMs)\n }\n\n const whereSql = where.length > 0 ? `WHERE ${where.join(\" AND \")}` : \"\"\n\n const sql = `\n SELECT *\n FROM request_log\n ${whereSql}\n ORDER BY id DESC\n LIMIT ?;\n `\n\n const rows = this.db\n .query(sql)\n .all(...values, limit + 1) as Array<RequestLogRow>\n\n const items = rows.slice(0, limit)\n const hasMore = rows.length > limit\n const nextCursorId = hasMore ? items.at(-1)?.id : undefined\n\n return {\n items,\n nextCursorId,\n hasMore,\n }\n }\n\n getAccountStatsSince(\n sinceMs: number,\n ): Record<string, AccountStatsRow | undefined> {\n try {\n const sql = `\n SELECT\n account_id,\n COUNT(*) AS request_count,\n SUM(CASE WHEN http_status >= 400 THEN 1 ELSE 0 END) AS error_count,\n COALESCE(SUM(tokens_total), 0) AS tokens_total,\n COALESCE(AVG(duration_ms), 0) AS avg_duration_ms,\n COALESCE(MAX(started_at_ms), 0) AS last_request_at_ms\n FROM request_log\n WHERE started_at_ms >= ? AND account_id IS NOT NULL\n GROUP BY account_id;\n `\n\n const rows = this.db.query(sql).all(sinceMs) as Array<AccountStatsRow>\n const map: Record<string, AccountStatsRow | undefined> = {}\n for (const row of rows) {\n map[row.account_id] = row\n }\n return map\n } catch (error) {\n consola.debug(\"Failed to fetch account stats\", error)\n return {}\n }\n }\n\n cleanupRetention(\n retentionDays: number = DEFAULT_RETENTION_DAYS,\n maxRows: number = DEFAULT_MAX_ROWS,\n ): void {\n try {\n const cutoffMs = Date.now() - retentionDays * 24 * 60 * 60 * 1000\n this.db\n .query(\"DELETE FROM request_log WHERE started_at_ms < ?;\")\n .run(cutoffMs)\n\n const countRow = this.db\n .query(\"SELECT COUNT(*) AS c FROM request_log;\")\n .get() as { c: number }\n\n const count = countRow.c\n if (count <= maxRows) {\n return\n }\n\n const offset = maxRows - 1\n const threshold = this.db\n .query(\"SELECT id FROM request_log ORDER BY id DESC LIMIT 1 OFFSET ?;\")\n .get(offset) as { id?: number } | null\n\n const thresholdId = threshold?.id\n if (!thresholdId) {\n return\n }\n\n this.db.query(\"DELETE FROM request_log WHERE id < ?;\").run(thresholdId)\n } catch (error) {\n consola.debug(\"Failed to cleanup request_log retention\", error)\n }\n\n import(\"./request-outbound\")\n .then((m) => m.getRequestOutboundStore().cleanupOrphans())\n .catch(() => {})\n }\n\n meta(): {\n dbPath: string\n userVersion: number\n retentionDays: number\n maxRows: number\n } {\n return {\n dbPath: getAdminDbPath(),\n userVersion: getAdminDbUserVersion(this.db),\n retentionDays: DEFAULT_RETENTION_DAYS,\n maxRows: DEFAULT_MAX_ROWS,\n }\n }\n}\n\nexport type RequestHistoryStoreApi = {\n insert(record: RequestLogInsert): void\n getByRequestId(requestId: string): RequestLogRow | null\n getLastCompletedUsageBySession(\n session: SessionUsageKey,\n ): NormalizedUsage | null\n query(params: RequestLogQuery): RequestLogQueryResult\n getAccountStatsSince(\n sinceMs: number,\n ): Record<string, AccountStatsRow | undefined>\n cleanupRetention(retentionDays?: number, maxRows?: number): void\n meta(): {\n dbPath: string\n userVersion: number\n retentionDays: number\n maxRows: number\n }\n}\n\nconst STORE_INIT_WARN_THROTTLE_MS = 30_000\nconst STORE_INIT_RETRY_DELAY_MS = 30_000\n\nlet lastStoreInitWarnAtMs = 0\nlet suppressedStoreInitWarnCount = 0\nlet nextStoreRetryAtMs = 0\n\nfunction warnStoreInitFailure(error: unknown): void {\n const now = Date.now()\n\n if (now - lastStoreInitWarnAtMs < STORE_INIT_WARN_THROTTLE_MS) {\n suppressedStoreInitWarnCount++\n return\n }\n\n const suppressed = suppressedStoreInitWarnCount\n suppressedStoreInitWarnCount = 0\n lastStoreInitWarnAtMs = now\n\n const suffix =\n suppressed > 0 ? ` (suppressed ${suppressed} similar errors)` : \"\"\n consola.warn(`Request history store is disabled${suffix}`, error)\n}\n\nconst disabledStore: RequestHistoryStoreApi = {\n insert: () => {},\n getByRequestId: () => null,\n getLastCompletedUsageBySession: () => null,\n query: () => ({ items: [], hasMore: false }),\n getAccountStatsSince: () => ({}),\n cleanupRetention: () => {},\n meta: () => ({\n dbPath: getAdminDbPath(),\n userVersion: 0,\n retentionDays: DEFAULT_RETENTION_DAYS,\n maxRows: DEFAULT_MAX_ROWS,\n }),\n}\n\nlet sharedStore: RequestHistoryStoreApi | null = null\nlet maintenanceStarted = false\n\nlet sharedStatsStore: StatsStore | null = null\n\nfunction getStatsStoreInstance(): StatsStore | null {\n if (sharedStatsStore) return sharedStatsStore\n try {\n sharedStatsStore = new StatsStore(getAdminDb())\n return sharedStatsStore\n } catch {\n return null\n }\n}\n\nexport function getRequestHistoryStore(): RequestHistoryStoreApi {\n if (sharedStore) {\n return sharedStore\n }\n\n const now = Date.now()\n if (now < nextStoreRetryAtMs) {\n return disabledStore\n }\n\n try {\n sharedStore = new RequestHistoryStore(getAdminDb())\n\n if (!maintenanceStarted) {\n maintenanceStarted = true\n\n // Run once at startup.\n sharedStore.cleanupRetention()\n getStatsStoreInstance()?.cleanupStatsRetention()\n\n // Then daily.\n setInterval(\n () => {\n sharedStore?.cleanupRetention()\n try {\n getStatsStoreInstance()?.cleanupStatsRetention()\n } catch {\n // Stats cleanup is best-effort\n }\n },\n 24 * 60 * 60 * 1000,\n )\n }\n\n return sharedStore\n } catch (error) {\n nextStoreRetryAtMs = now + STORE_INIT_RETRY_DELAY_MS\n warnStoreInitFailure(error)\n return disabledStore\n }\n}\n\nexport function extractResponsesUsageFromStreamEvent(\n event: ResponseStreamEvent,\n): NormalizedUsage {\n if (\n event.type === \"response.completed\"\n || event.type === \"response.incomplete\"\n ) {\n return normalizeResponsesUsage(event.response.usage)\n }\n\n if (event.type === \"response.failed\") {\n return normalizeResponsesUsage(event.response.usage)\n }\n\n return {}\n}\n\nexport function extractResponsesUsageFromResult(\n result: ResponsesResult,\n): NormalizedUsage {\n return normalizeResponsesUsage(result.usage)\n}\n\nexport function getStatsStore(): StatsStore | null {\n return getStatsStoreInstance()\n}\n","import type { Database } from \"bun:sqlite\"\n\nimport consola from \"consola\"\n\nimport { getAdminDb } from \"./admin-db\"\nimport { getSessionAffinityRetentionMs } from \"./config\"\n\nconst DAY_MS = 24 * 60 * 60 * 1000\nconst DEFAULT_MAX_AGE_MS = 7 * DAY_MS\nconst CLEANUP_INTERVAL_MS = DAY_MS\n\nconst maybeUnref = (timer: ReturnType<typeof setInterval>) => {\n timer.unref()\n}\n\nexport class SessionAffinityStore {\n private readonly db: Database\n\n constructor(db: Database) {\n this.db = db\n }\n\n get(cacheKey: string): string | undefined {\n let row: { account_id?: string } | null\n\n try {\n row = this.db\n .query(\n \"SELECT account_id FROM session_affinity WHERE cache_key = ? LIMIT 1;\",\n )\n .get(cacheKey) as { account_id?: string } | null\n } catch (error) {\n consola.warn(\"Failed to read session affinity mapping:\", error)\n return undefined\n }\n\n if (!row?.account_id) {\n return undefined\n }\n\n try {\n this.db\n .query(\n \"UPDATE session_affinity SET last_used_at_ms = ? WHERE cache_key = ?;\",\n )\n .run(Date.now(), cacheKey)\n } catch (error) {\n consola.warn(\"Failed to update session affinity last_used_at_ms:\", error)\n }\n\n return row.account_id\n }\n\n set(cacheKey: string, accountId: string): void {\n const now = Date.now()\n\n try {\n this.db\n .query(\n `\n INSERT INTO session_affinity (\n cache_key,\n account_id,\n created_at_ms,\n last_confirmed_at_ms,\n last_used_at_ms\n ) VALUES (?, ?, ?, ?, ?)\n ON CONFLICT(cache_key) DO UPDATE SET\n account_id = excluded.account_id,\n last_confirmed_at_ms = excluded.last_confirmed_at_ms,\n last_used_at_ms = excluded.last_used_at_ms;\n `,\n )\n .run(cacheKey, accountId, now, now, now)\n } catch (error) {\n consola.warn(\"Failed to persist session affinity mapping:\", error)\n }\n }\n\n delete(cacheKey: string): void {\n try {\n this.db\n .query(\"DELETE FROM session_affinity WHERE cache_key = ?;\")\n .run(cacheKey)\n } catch (error) {\n consola.warn(\"Failed to delete session affinity mapping:\", error)\n }\n }\n\n clear(): void {\n try {\n this.db.query(\"DELETE FROM session_affinity;\").run()\n } catch (error) {\n consola.warn(\"Failed to clear session affinity mappings:\", error)\n }\n }\n\n cleanup(maxAgeMs: number = DEFAULT_MAX_AGE_MS): void {\n try {\n this.db\n .query(\"DELETE FROM session_affinity WHERE last_used_at_ms < ?;\")\n .run(Date.now() - maxAgeMs)\n } catch (error) {\n consola.warn(\"Failed to cleanup session affinity mappings:\", error)\n }\n }\n}\n\nlet sharedSessionAffinityStore: SessionAffinityStore | null = null\nlet sharedCleanupInterval: ReturnType<typeof setInterval> | undefined\n\nfunction clearSharedSessionAffinityCleanup(): void {\n if (!sharedCleanupInterval) {\n return\n }\n\n clearInterval(sharedCleanupInterval)\n sharedCleanupInterval = undefined\n}\n\nexport function getSharedSessionAffinityStore(): SessionAffinityStore {\n if (!sharedSessionAffinityStore) {\n sharedSessionAffinityStore = new SessionAffinityStore(getAdminDb())\n }\n\n return sharedSessionAffinityStore\n}\n\nexport function applySharedSessionAffinityRetention(\n retentionMs: number = getSessionAffinityRetentionMs(),\n): void {\n clearSharedSessionAffinityCleanup()\n\n if (!Number.isFinite(retentionMs) || retentionMs <= 0) {\n return\n }\n\n try {\n const store = getSharedSessionAffinityStore()\n store.cleanup(retentionMs)\n\n sharedCleanupInterval = setInterval(() => {\n store.cleanup(retentionMs)\n }, CLEANUP_INTERVAL_MS)\n maybeUnref(sharedCleanupInterval)\n } catch (error) {\n consola.warn(\"Failed to apply session affinity retention:\", error)\n }\n}\n","interface SessionOwnershipCacheEntry {\n accountId: string\n expiresAt: number\n}\n\nconst DEFAULT_MAX_ENTRIES = 10_000\nconst DEFAULT_TTL_MS = 60 * 60 * 1000\n\n/**\n * In-memory TTL/LRU cache for root-session ownership.\n *\n * Uses Map insertion order for eviction: read/write hits move an entry to the\n * newest position, and writes refresh TTL.\n */\nexport class SessionOwnershipCache {\n private readonly cache = new Map<string, SessionOwnershipCacheEntry>()\n private readonly maxEntries: number\n private readonly ttlMs: number\n\n constructor(maxEntries = DEFAULT_MAX_ENTRIES, ttlMs = DEFAULT_TTL_MS) {\n this.maxEntries = maxEntries\n this.ttlMs = ttlMs\n }\n\n get(rootSessionId: string): string | undefined {\n const entry = this.cache.get(rootSessionId)\n if (!entry) {\n return undefined\n }\n\n if (Date.now() >= entry.expiresAt) {\n this.cache.delete(rootSessionId)\n return undefined\n }\n\n this.cache.delete(rootSessionId)\n this.cache.set(rootSessionId, entry)\n return entry.accountId\n }\n\n set(rootSessionId: string, accountId: string): void {\n this.cache.delete(rootSessionId)\n\n while (this.cache.size >= this.maxEntries) {\n const oldest = this.cache.keys().next()\n if (oldest.done) {\n break\n }\n this.cache.delete(oldest.value)\n }\n\n this.cache.set(rootSessionId, {\n accountId,\n expiresAt: Date.now() + this.ttlMs,\n })\n }\n\n clear(): void {\n this.cache.clear()\n }\n}\n","/* eslint-disable max-lines */\nimport consola from \"consola\"\nimport fs from \"node:fs\"\n\nimport type {\n AccountContext,\n AccountMeta,\n AccountRuntime,\n AccountType,\n} from \"~/lib/types/account\"\n\nimport {\n AccountAffinityCache,\n buildAffinityCacheKey,\n extractAffinityKey,\n isAffinityAccountUsable,\n type AffinityContext,\n type AffinityPersistenceStoreProvider,\n} from \"~/lib/account-affinity\"\nimport { resolveModelAlias } from \"~/lib/config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { getModels, type Model } from \"~/services/copilot/get-models\"\nimport { getCopilotToken } from \"~/services/github/get-copilot-token\"\nimport { getCopilotUsage } from \"~/services/github/get-copilot-usage\"\nimport { getGitHubUser } from \"~/services/github/get-user\"\n\nimport {\n buildIdentityKey,\n createAccountSessionId,\n getCurrentIdentityEnvironment,\n} from \"./account-client-identity\"\nimport {\n applyCopilotTokenIfCurrent,\n applyModelsIfCurrent,\n applyQuotaRefreshSuccessIfCurrent,\n applyTokenRefreshFailureIfCurrent,\n applyTokenRefreshSuccessIfCurrent,\n applyUnauthorizedIfCurrent,\n isAuthSnapshotCurrent,\n isSameAuthSnapshot,\n setAccountFailedState,\n takeAuthSnapshot,\n toAccountContextFromSnapshot,\n type AuthSnapshot,\n} from \"./accounts-manager-auth\"\nimport {\n getCostUnits,\n getEffectivePremiumRemaining,\n releasePremiumReservation,\n reservePremiumUnits,\n type QuotaReservation,\n} from \"./accounts-manager-quota\"\nimport {\n hasLegacyToken,\n hasRegistry,\n ensureAccountClientIdentity,\n isAccountEnabled,\n listAccountsFromRegistry,\n loadAccountToken,\n readLegacyToken,\n saveAccountToken,\n addAccountToRegistry,\n} from \"./accounts-registry\"\nimport { PATHS } from \"./paths\"\nimport { getStatsStore } from \"./request-history\"\nimport { getSharedSessionAffinityStore } from \"./session-affinity-store\"\nimport { SessionOwnershipCache } from \"./session-ownership\"\n\n/** Quota cache TTL in milliseconds (45 seconds) for pre-request selection. */\nconst QUOTA_CACHE_TTL = 45 * 1000\n\n/** Debounce delay for registry reload in milliseconds */\nconst RELOAD_DEBOUNCE_MS = 500\n\n/** Registry watcher restart initial delay in milliseconds */\nconst WATCHER_RESTART_INITIAL_DELAY_MS = 1000\n/** Registry watcher restart max delay in milliseconds */\nconst WATCHER_RESTART_MAX_DELAY_MS = 60 * 1000\n/** Session refresh base interval in milliseconds. */\nconst SESSION_REFRESH_BASE_MS = 60 * 60 * 1000\n/** Session refresh jitter window in milliseconds. */\nconst SESSION_REFRESH_JITTER_MS = 20 * 60 * 1000\n\n/** Minimum delay between account initializations in milliseconds. */\nconst INIT_STAGGER_MIN_MS = 2000\n/** Maximum delay between account initializations in milliseconds. */\nconst INIT_STAGGER_MAX_MS = 5000\n/** Random jitter window added to token refresh delay in milliseconds. */\nconst TOKEN_REFRESH_JITTER_MS = 30_000\n\nexport interface AccountRequestCandidate {\n modelId: string\n endpoint: string\n}\n\nexport type { QuotaReservation } from \"./accounts-manager-quota\"\nexport type { AffinityContext } from \"~/lib/account-affinity\"\n\nexport type AccountSelectionContext = AffinityContext & {\n ownershipLookupSessionId?: string\n ownershipWriteSessionId?: string\n}\n\nexport type SelectAccountForRequestFailureReason =\n | \"NO_ACCOUNTS\"\n | \"MODEL_NOT_SUPPORTED\"\n | \"NO_QUOTA\"\n\nexport type AccountSelectionReason =\n | \"affinity_hit\"\n | \"affinity_miss\"\n | \"preferred_account_unavailable\"\n | \"no_session_key\"\n | \"rotated_after_miss\"\n | \"subagent_owner_hit\"\n | \"subagent_owner_miss\"\n | \"subagent_owner_unusable_fallback\"\n | \"subagent_marker_invalid_fallback\"\n\ntype SelectAccountForRequestSuccess = {\n ok: true\n account: AccountRuntime\n selectedModel: Model\n endpoint: string\n costUnits: number\n reservation?: QuotaReservation\n /** Call after a successful upstream response to persist the affinity mapping. */\n confirmAffinity?: () => void\n /** Call after a successful upstream response to persist the ownership mapping. */\n confirmOwnership?: () => void\n /** Whether this selection was served from the affinity cache. */\n affinityHit?: boolean\n /** The cache key used for affinity lookup (e.g. `\"session-1:claude-sonnet-4\"`). */\n affinityCacheKey?: string\n /** High-level reason for why this account was selected. */\n selectionReason?: AccountSelectionReason\n}\n\nexport type SelectAccountForRequestResult =\n | SelectAccountForRequestSuccess\n | {\n ok: false\n reason: SelectAccountForRequestFailureReason\n selectionReason?: AccountSelectionReason\n }\n\nexport type AccountStatusEntry = {\n id: string\n entitlement?: number\n remaining?: number\n unlimited?: boolean\n overagePermitted?: boolean\n failed?: boolean\n failureReason?: string\n enabled?: boolean\n}\n\nfunction getInitialSelectionReason(\n cacheKey: string | undefined,\n rotationStart: number,\n): AccountSelectionReason {\n if (!cacheKey) {\n return \"no_session_key\"\n }\n\n return rotationStart > 0 ? \"rotated_after_miss\" : \"affinity_miss\"\n}\n\nfunction preserveSubagentSelectionReason(\n initialSelectionReason: AccountSelectionReason,\n nextSelectionReason: AccountSelectionReason,\n): AccountSelectionReason {\n return initialSelectionReason.startsWith(\"subagent_\") ?\n initialSelectionReason\n : nextSelectionReason\n}\n\ntype ScoredAccountRuntime = {\n account: AccountRuntime\n effectiveRemaining: number\n}\n\nexport interface AccountsManagerOptions {\n persistentAffinityStore?: AffinityPersistenceStoreProvider\n}\n\n/** Manages multiple GitHub Copilot accounts at runtime. */\nexport class AccountsManager {\n private accounts: Map<string, AccountRuntime> = new Map()\n private accountOrder: Array<string> = []\n private temporaryAccount?: AccountRuntime\n private vsCodeVersion?: string\n private accountAffinityEnabled = true\n private affinityCache: AccountAffinityCache\n private sessionOwnership = new SessionOwnershipCache()\n private sessionOwnershipGeneration = 0\n private loadBalanceCursor = 0\n\n constructor(options: AccountsManagerOptions = {}) {\n const { persistentAffinityStore } = options\n\n this.affinityCache = new AccountAffinityCache(\n undefined,\n undefined,\n persistentAffinityStore,\n )\n }\n\n private quotaRefreshSnapshotByAccount = new WeakMap<\n AccountRuntime,\n AuthSnapshot\n >()\n private modelsRefreshSnapshotByAccount = new WeakMap<\n AccountRuntime,\n AuthSnapshot\n >()\n private tokenRefreshEnabledAccounts = new WeakSet<AccountRuntime>()\n private modelsRefreshTimer?: ReturnType<typeof setTimeout>\n private modelsRefreshIntervalMs = 0\n\n // Registry file watcher for hot reload\n private registryWatcher?: fs.FSWatcher\n private reloadDebounceTimer?: ReturnType<typeof setTimeout>\n private registryWatcherRestartTimer?: ReturnType<typeof setTimeout>\n private registryWatcherRestartDelayMs = WATCHER_RESTART_INITIAL_DELAY_MS\n private isReloading = false\n private currentReloadPromise?: Promise<void>\n\n /** Initialize accounts manager (load registry, migrate legacy token). */\n async initialize(vsCodeVersion?: string): Promise<void> {\n this.vsCodeVersion = vsCodeVersion\n\n // Check if we need to migrate legacy token\n const hasReg = await hasRegistry()\n const hasLegacy = await hasLegacyToken()\n\n if (!hasReg && hasLegacy) {\n await this.migrateLegacyToken()\n }\n\n // Load accounts from registry\n const accountMetas = await listAccountsFromRegistry()\n\n for (const meta of accountMetas) {\n const token = await loadAccountToken(meta.id)\n if (!token) {\n consola.warn(`No token found for account ${meta.id}, skipping`)\n continue\n }\n\n const runtime: AccountRuntime = {\n ...meta,\n accountLogin: meta.id,\n githubToken: token,\n vsCodeVersion: this.vsCodeVersion,\n }\n\n this.accounts.set(meta.id, runtime)\n this.accountOrder.push(meta.id)\n }\n\n // Initialize Copilot tokens for all accounts (staggered to avoid burst traffic)\n let isFirstAccount = true\n for (const account of this.accounts.values()) {\n if (!isFirstAccount) {\n const staggerDelay =\n INIT_STAGGER_MIN_MS\n + Math.floor(\n Math.random() * (INIT_STAGGER_MAX_MS - INIT_STAGGER_MIN_MS),\n )\n consola.debug(\n `Staggering initialization of account ${account.id} by ${staggerDelay}ms`,\n )\n await new Promise((resolve) => setTimeout(resolve, staggerDelay))\n }\n isFirstAccount = false\n\n try {\n await this.initializeAccount(account)\n } catch (error) {\n consola.error(`Failed to initialize account ${account.id}:`, error)\n account.failed = true\n account.failureReason = String(error)\n }\n }\n\n consola.info(`Loaded ${this.accounts.size} account(s)`)\n\n // Start watching the registry file for hot reload\n this.startRegistryWatcher()\n }\n\n setAccountAffinityEnabled(enabled: boolean): void {\n this.accountAffinityEnabled = enabled\n if (!enabled) {\n this.affinityCache.clearMemory()\n }\n }\n\n setModelsRefreshIntervalMs(intervalMs: number): void {\n this.modelsRefreshIntervalMs =\n Number.isFinite(intervalMs) && intervalMs > 0 ? intervalMs : 0\n this.scheduleModelsRefresh()\n }\n\n private computeTokenRefreshDelayMs(refreshInSeconds: number): number {\n const baseDelay = Math.max((refreshInSeconds - 60) * 1000, 1000)\n const jitter = Math.floor(Math.random() * TOKEN_REFRESH_JITTER_MS)\n // Ensure the jittered delay doesn't exceed the token's validity window\n const maxSafeDelay = Math.max(refreshInSeconds * 1000 - 1000, 1000)\n return Math.min(baseDelay + jitter, maxSafeDelay)\n }\n\n private computeSessionRefreshDelayMs(): number {\n const randomDelay = Math.floor(Math.random() * SESSION_REFRESH_JITTER_MS)\n return SESSION_REFRESH_BASE_MS + randomDelay\n }\n\n private resolveAccountLogin(account: AccountRuntime): string {\n return account.accountLogin ?? account.id\n }\n\n private commitAccountIdentity(\n account: AccountRuntime,\n {\n identityKey,\n login,\n deviceId,\n machineId,\n }: {\n identityKey: string\n login: string\n deviceId: string\n machineId: string\n },\n ): void {\n account.accountLogin = login\n account.identityKey = identityKey\n account.clientDeviceId = deviceId\n account.clientMachineId = machineId\n }\n\n private async applyAccountIdentity(account: AccountRuntime): Promise<void> {\n const login = this.resolveAccountLogin(account)\n const { oauthApp, enterpriseDomain } = getCurrentIdentityEnvironment()\n const identityKey = buildIdentityKey({\n login,\n oauthApp,\n enterpriseDomain,\n })\n const identity = await ensureAccountClientIdentity({\n login,\n oauthApp,\n enterpriseDomain,\n })\n\n this.commitAccountIdentity(account, {\n identityKey,\n login,\n deviceId: identity.deviceId,\n machineId: identity.machineId,\n })\n\n if (!account.clientSessionId) {\n account.clientSessionId = createAccountSessionId()\n consola.debug(\n `Generated VSCode session ID for account ${account.id}: ${account.clientSessionId}`,\n )\n }\n\n this.startSessionRefresh(account)\n }\n\n private shouldContinueTokenRefresh(\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n ): boolean {\n return (\n this.tokenRefreshEnabledAccounts.has(account)\n && isAuthSnapshotCurrent(account, snapshot)\n )\n }\n\n private async runTokenRefreshTick(\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n refreshInSeconds: number,\n ): Promise<void> {\n if (!this.shouldContinueTokenRefresh(account, snapshot)) {\n return\n }\n\n try {\n const ctx = toAccountContextFromSnapshot(account, snapshot)\n const { token, refresh_in } = await getCopilotToken(ctx)\n\n if (!this.shouldContinueTokenRefresh(account, snapshot)) {\n return\n }\n\n const applied = applyTokenRefreshSuccessIfCurrent(\n account,\n snapshot,\n token,\n )\n if (!applied) {\n return\n }\n\n consola.debug(`Refreshed token for account ${account.id}`)\n\n // Schedule next refresh using the new refresh interval.\n if (!this.shouldContinueTokenRefresh(account, snapshot)) {\n return\n }\n this.startTokenRefresh(account, refresh_in)\n } catch (error) {\n consola.error(`Failed to refresh token for ${account.id}:`, error)\n\n if (!this.shouldContinueTokenRefresh(account, snapshot)) {\n return\n }\n\n applyTokenRefreshFailureIfCurrent(account, snapshot, error)\n\n // Retry using the previous refresh interval (best effort).\n if (!this.shouldContinueTokenRefresh(account, snapshot)) {\n return\n }\n this.startTokenRefresh(account, refreshInSeconds)\n }\n }\n\n private finalizeQuotaRefreshPromise(\n account: AccountRuntime,\n promise: Promise<void>,\n ): void {\n if (account.quotaRefreshPromise !== promise) {\n return\n }\n\n account.isRefreshingQuota = false\n account.quotaRefreshPromise = undefined\n this.quotaRefreshSnapshotByAccount.delete(account)\n }\n\n /** Initialize a single account. */\n private async initializeAccount(account: AccountRuntime): Promise<void> {\n await this.applyAccountIdentity(account)\n const snapshot = takeAuthSnapshot(account)\n\n try {\n // Get Copilot token\n const tokenCtx = toAccountContextFromSnapshot(account, snapshot)\n const { token, refresh_in } = await getCopilotToken(tokenCtx)\n\n if (!applyCopilotTokenIfCurrent(account, snapshot, token)) {\n return\n }\n\n // Resolve the account-specific Copilot endpoint before the first models fetch.\n await this.refreshQuota(account)\n\n // Start token refresh timer\n this.startTokenRefresh(account, refresh_in)\n\n // Get models\n const modelsCtx = toAccountContextFromSnapshot(account, snapshot, token)\n const models = await getModels(modelsCtx)\n\n if (!applyModelsIfCurrent(account, snapshot, models)) {\n return\n }\n account.lastModelsFetch = Date.now()\n\n consola.debug(`Account ${account.id} initialized`)\n } catch (error) {\n // Ignore stale results if registry hot reload changed auth.\n if (!isAuthSnapshotCurrent(account, snapshot)) {\n return\n }\n\n throw error\n }\n }\n\n /** Migrate legacy github_token to the new multi-account system. */\n private async migrateLegacyToken(): Promise<void> {\n const token = await readLegacyToken()\n if (!token) return\n\n try {\n // Get user info to determine the account ID\n const user = await getGitHubUser({\n githubToken: token,\n accountType: \"individual\",\n })\n const id = user.login\n\n // Save token to new location\n await saveAccountToken(id, token)\n\n // Add to registry\n await addAccountToRegistry({\n id,\n accountType: \"individual\",\n addedAt: Date.now(),\n })\n\n consola.info(`Migrated legacy token to account: ${id}`)\n } catch (error) {\n consola.error(\"Failed to migrate legacy token:\", error)\n }\n }\n\n /** Start token refresh timer for an account. */\n private startTokenRefresh(\n account: AccountRuntime,\n refreshInSeconds: number,\n ): void {\n // Stop existing timer if any\n this.stopTokenRefresh(account)\n\n this.tokenRefreshEnabledAccounts.add(account)\n\n const snapshot = takeAuthSnapshot(account)\n const delayMs = this.computeTokenRefreshDelayMs(refreshInSeconds)\n\n account.refreshTimer = setTimeout(() => {\n void this.runTokenRefreshTick(account, snapshot, refreshInSeconds)\n }, delayMs)\n }\n\n /** Stop token refresh timer for an account. */\n private stopTokenRefresh(account: AccountRuntime): void {\n this.tokenRefreshEnabledAccounts.delete(account)\n\n if (account.refreshTimer) {\n clearTimeout(account.refreshTimer)\n account.refreshTimer = undefined\n }\n }\n\n /** Stop all token refresh timers. */\n private stopAllTokenRefresh(): void {\n for (const account of this.accounts.values()) {\n this.stopTokenRefresh(account)\n }\n if (this.temporaryAccount) {\n this.stopTokenRefresh(this.temporaryAccount)\n }\n }\n\n private startSessionRefresh(account: AccountRuntime): void {\n this.stopSessionRefresh(account)\n\n const delayMs = this.computeSessionRefreshDelayMs()\n consola.debug(\n `Scheduling next VSCode session ID refresh for ${account.id} in ${Math.round(\n delayMs / 1000,\n )} seconds`,\n )\n\n account.sessionRefreshTimer = setTimeout(() => {\n try {\n account.clientSessionId = createAccountSessionId()\n consola.debug(\n `Refreshed VSCode session ID for account ${account.id}: ${account.clientSessionId}`,\n )\n } catch (error) {\n consola.error(\n `Failed to refresh VSCode session ID for ${account.id}, rescheduling...`,\n error,\n )\n } finally {\n this.startSessionRefresh(account)\n }\n }, delayMs)\n }\n\n private stopSessionRefresh(account: AccountRuntime): void {\n if (account.sessionRefreshTimer) {\n clearTimeout(account.sessionRefreshTimer)\n account.sessionRefreshTimer = undefined\n }\n }\n\n private stopAllSessionRefresh(): void {\n for (const account of this.accounts.values()) {\n this.stopSessionRefresh(account)\n }\n\n if (this.temporaryAccount) {\n this.stopSessionRefresh(this.temporaryAccount)\n }\n }\n\n private scheduleModelsRefresh(): void {\n this.stopModelsRefresh()\n\n if (!this.modelsRefreshIntervalMs || this.modelsRefreshIntervalMs <= 0) {\n return\n }\n\n this.modelsRefreshTimer = setTimeout(() => {\n void this.runModelsRefreshTick()\n }, this.modelsRefreshIntervalMs)\n }\n\n private stopModelsRefresh(): void {\n if (this.modelsRefreshTimer) {\n clearTimeout(this.modelsRefreshTimer)\n this.modelsRefreshTimer = undefined\n }\n }\n\n private async runModelsRefreshTick(): Promise<void> {\n try {\n await this.refreshAllModels()\n } catch (error) {\n consola.error(\"Failed to refresh models:\", error)\n } finally {\n this.scheduleModelsRefresh()\n }\n }\n\n private finalizeModelsRefreshPromise(\n account: AccountRuntime,\n promise: Promise<void>,\n ): void {\n if (account.modelsRefreshPromise !== promise) {\n return\n }\n\n account.isRefreshingModels = false\n account.modelsRefreshPromise = undefined\n this.modelsRefreshSnapshotByAccount.delete(account)\n }\n\n private async refreshModels(account: AccountRuntime): Promise<void> {\n if (!account.copilotToken) {\n consola.debug(\n `Skip model refresh for ${account.id}: missing Copilot token`,\n )\n return\n }\n\n const snapshot = takeAuthSnapshot(account)\n\n if (account.modelsRefreshPromise) {\n const existingSnapshot = this.modelsRefreshSnapshotByAccount.get(account)\n if (isSameAuthSnapshot(existingSnapshot, snapshot)) {\n await account.modelsRefreshPromise\n return\n }\n }\n\n account.isRefreshingModels = true\n\n const ctx = toAccountContextFromSnapshot(\n account,\n snapshot,\n account.copilotToken,\n )\n\n const promise = (async () => {\n try {\n const models = await getModels(ctx)\n const applied = applyModelsIfCurrent(account, snapshot, models)\n if (applied) {\n account.lastModelsFetch = Date.now()\n }\n } catch (error) {\n if (error instanceof HTTPError && error.response.status === 401) {\n applyUnauthorizedIfCurrent(account, snapshot, \"Unauthorized (401)\")\n return\n }\n\n consola.error(`Failed to refresh models for ${account.id}:`, error)\n }\n })()\n\n account.modelsRefreshPromise = promise\n this.modelsRefreshSnapshotByAccount.set(account, snapshot)\n\n void promise.finally(() => {\n this.finalizeModelsRefreshPromise(account, promise)\n })\n\n await promise\n }\n\n private async refreshAllModels(): Promise<void> {\n const accounts: Array<AccountRuntime> = []\n\n if (this.temporaryAccount) {\n accounts.push(this.temporaryAccount)\n }\n\n for (const id of this.accountOrder) {\n const account = this.accounts.get(id)\n if (account) {\n accounts.push(account)\n }\n }\n\n if (accounts.length === 0) {\n return\n }\n\n await Promise.allSettled(\n accounts.map((account) => this.refreshModels(account)),\n )\n }\n\n /** Refresh quota information for an account. */\n async refreshQuota(account: AccountRuntime): Promise<void> {\n const snapshot = takeAuthSnapshot(account)\n\n if (account.quotaRefreshPromise) {\n const existingSnapshot = this.quotaRefreshSnapshotByAccount.get(account)\n if (isSameAuthSnapshot(existingSnapshot, snapshot)) {\n await account.quotaRefreshPromise\n return\n }\n }\n\n account.isRefreshingQuota = true\n\n const ctx = toAccountContextFromSnapshot(account, snapshot)\n const promise = (async () => {\n try {\n const usage = await getCopilotUsage(ctx)\n const premium = usage.quota_snapshots.premium_interactions\n const applied = applyQuotaRefreshSuccessIfCurrent(account, snapshot, {\n premium,\n copilotApiUrl: usage.endpoints.api,\n })\n\n if (applied) {\n try {\n getStatsStore()?.insertQuotaSnapshot({\n accountId: account.id,\n snapshotAtMs: Date.now(),\n remaining: premium.remaining,\n entitlement: premium.entitlement,\n unlimited: premium.unlimited,\n source: \"refresh\",\n })\n } catch {\n // Best-effort: don't fail the quota refresh if snapshot insert fails\n }\n }\n } catch (error) {\n if (error instanceof HTTPError && error.response.status === 401) {\n applyUnauthorizedIfCurrent(account, snapshot, \"Unauthorized (401)\")\n return\n }\n\n consola.error(`Failed to refresh quota for ${account.id}:`, error)\n // Don't mark as failed for non-401 quota refresh errors\n }\n })()\n\n account.quotaRefreshPromise = promise\n this.quotaRefreshSnapshotByAccount.set(account, snapshot)\n\n void promise.finally(() => {\n this.finalizeQuotaRefreshPromise(account, promise)\n })\n\n await promise\n }\n\n /** Check if quota cache is expired. */\n private isQuotaCacheExpired(account: AccountRuntime): boolean {\n if (!account.lastQuotaFetch) return true\n return Date.now() - account.lastQuotaFetch > QUOTA_CACHE_TTL\n }\n\n private isAccountFailed(account: AccountRuntime): boolean {\n return account.failed === true\n }\n\n private useOverageFallback(fallback: {\n account: AccountRuntime\n model: Model\n endpoint: string\n costUnits: number\n }): SelectAccountForRequestSuccess {\n const reservation = reservePremiumUnits(\n fallback.account,\n fallback.costUnits,\n )\n return {\n ok: true,\n account: fallback.account,\n selectedModel: fallback.model,\n endpoint: fallback.endpoint,\n costUnits: fallback.costUnits,\n reservation,\n }\n }\n\n private isModelSupportedForEndpoint(model: Model, endpoint: string): boolean {\n if (endpoint === \"/responses\") {\n return model.supported_endpoints?.includes(endpoint) ?? false\n }\n\n const supported = model.supported_endpoints\n if (!supported) {\n return true\n }\n\n return supported.includes(endpoint)\n }\n\n private pickSupportedCandidate(\n account: AccountRuntime,\n candidates: Array<AccountRequestCandidate>,\n ): { candidate: AccountRequestCandidate; model: Model } | null {\n const models = account.models?.data\n if (!models) {\n return null\n }\n\n for (const candidate of candidates) {\n const model = models.find((m) => m.id === candidate.modelId)\n if (!model) {\n continue\n }\n\n if (!this.isModelSupportedForEndpoint(model, candidate.endpoint)) {\n continue\n }\n\n return { candidate, model }\n }\n\n return null\n }\n\n private async selectAccountForCandidates(\n orderedAccounts: Array<AccountRuntime>,\n candidates: Array<AccountRequestCandidate>,\n ): Promise<SelectAccountForRequestResult> {\n if (orderedAccounts.length === 0) {\n return { ok: false, reason: \"NO_ACCOUNTS\" }\n }\n\n let supportedCandidateFound = false\n let overageFallback:\n | {\n account: AccountRuntime\n model: Model\n endpoint: string\n costUnits: number\n }\n | undefined\n\n for (const account of orderedAccounts) {\n if (this.isAccountFailed(account)) {\n continue\n }\n\n const supported = this.pickSupportedCandidate(account, candidates)\n if (!supported) {\n continue\n }\n\n supportedCandidateFound = true\n\n const { candidate, model } = supported\n const costUnits = getCostUnits(model)\n\n if (costUnits <= 0) {\n // Free model: sequential routing (first available account).\n // When account affinity is enabled, the caller (selectAccountForRequest)\n // handles cache lookup/write-back; this path only runs on cache miss.\n return {\n ok: true,\n account,\n selectedModel: model,\n endpoint: candidate.endpoint,\n costUnits,\n }\n }\n\n if (!account.unlimited && this.isQuotaCacheExpired(account)) {\n await this.refreshQuota(account)\n }\n\n if (this.isAccountFailed(account)) {\n continue\n }\n\n if (account.unlimited) {\n return {\n ok: true,\n account,\n selectedModel: model,\n endpoint: candidate.endpoint,\n costUnits,\n }\n }\n\n // Check if account has sufficient quota.\n const effectiveRemaining = getEffectivePremiumRemaining(account)\n if (effectiveRemaining !== undefined && effectiveRemaining < costUnits) {\n // Insufficient quota - store as overage fallback if permitted, but keep\n // looking for accounts with quota to avoid unnecessary overage charges.\n if (account.overagePermitted && !overageFallback) {\n overageFallback = {\n account,\n model,\n endpoint: candidate.endpoint,\n costUnits,\n }\n }\n continue\n }\n\n const reservation = reservePremiumUnits(account, costUnits)\n\n return {\n ok: true,\n account,\n selectedModel: model,\n endpoint: candidate.endpoint,\n costUnits,\n reservation,\n }\n }\n\n if (!supportedCandidateFound) {\n return { ok: false, reason: \"MODEL_NOT_SUPPORTED\" }\n }\n\n // No account with quota found - use overage fallback if available.\n return overageFallback ?\n this.useOverageFallback(overageFallback)\n : { ok: false, reason: \"NO_QUOTA\" }\n }\n\n /**\n * Try to use a preferred (affinity) account for the request.\n * Returns a successful selection if the account is usable; null otherwise.\n */\n\n private async tryAffinityAccount(\n preferredAccountId: string,\n orderedAccounts: Array<AccountRuntime>,\n candidates: Array<AccountRequestCandidate>,\n ): Promise<SelectAccountForRequestSuccess | null> {\n const account = isAffinityAccountUsable(preferredAccountId, orderedAccounts)\n if (!account) {\n return null\n }\n\n // Try original candidates first, then alias-resolved candidates.\n const supported =\n this.pickSupportedCandidate(account, candidates)\n ?? this.pickAliasFallbackCandidate(account, candidates)\n if (!supported) {\n return null\n }\n\n return this.validateAffinityQuota(account, supported)\n }\n\n /**\n * Resolve model aliases and try to pick a supported candidate.\n * Returns null if no alias differs or the account doesn't support the alias.\n */\n private pickAliasFallbackCandidate(\n account: AccountRuntime,\n candidates: Array<AccountRequestCandidate>,\n ): { candidate: AccountRequestCandidate; model: Model } | null {\n const aliasCandidates = candidates.map((candidate) => {\n const modelId = resolveModelAlias(candidate.modelId)\n if (modelId === candidate.modelId) return candidate\n return { ...candidate, modelId }\n })\n const aliasChanged = aliasCandidates.some(\n (candidate, index) => candidate.modelId !== candidates[index].modelId,\n )\n if (!aliasChanged) return null\n\n return this.pickSupportedCandidate(account, aliasCandidates)\n }\n\n /**\n * Validate quota for an affinity candidate. Free models pass immediately;\n * premium models go through quota refresh / reservation.\n */\n private async validateAffinityQuota(\n account: AccountRuntime,\n supported: { candidate: AccountRequestCandidate; model: Model },\n ): Promise<SelectAccountForRequestSuccess | null> {\n const { candidate, model } = supported\n const costUnits = getCostUnits(model)\n\n // Free model — no quota checks needed.\n if (costUnits <= 0) {\n return {\n ok: true,\n account,\n selectedModel: model,\n endpoint: candidate.endpoint,\n costUnits,\n }\n }\n\n // Premium model — validate quota.\n if (!account.unlimited && this.isQuotaCacheExpired(account)) {\n await this.refreshQuota(account)\n }\n\n if (this.isAccountFailed(account)) {\n return null\n }\n\n if (account.unlimited) {\n return {\n ok: true,\n account,\n selectedModel: model,\n endpoint: candidate.endpoint,\n costUnits,\n }\n }\n\n const effectiveRemaining = getEffectivePremiumRemaining(account)\n if (effectiveRemaining !== undefined && effectiveRemaining < costUnits) {\n return null\n }\n\n const reservation = reservePremiumUnits(account, costUnits)\n\n return {\n ok: true,\n account,\n selectedModel: model,\n endpoint: candidate.endpoint,\n costUnits,\n reservation,\n }\n }\n\n /**\n * Select an available account for a specific request (model + endpoint).\n * When account affinity is enabled, routes to the previously successful account\n * for the same affinity key + model combination.\n * Uses reservation to avoid oversubscribing premium quota under concurrency.\n */\n async selectAccountForRequest(\n candidates: Array<AccountRequestCandidate>,\n context?: AccountSelectionContext,\n ): Promise<SelectAccountForRequestResult> {\n if (candidates.length === 0) {\n throw new Error(\"selectAccountForRequest requires at least one candidate\")\n }\n\n const orderedAccounts = this.getOrderedEnabledAccounts()\n const ownerSelection = await this.selectPreferredSessionOwner({\n lookupSessionId: context?.ownershipLookupSessionId,\n orderedAccounts,\n candidates,\n })\n if (ownerSelection.result) {\n this.attachConfirmOwnership(\n ownerSelection.result,\n context?.ownershipWriteSessionId,\n )\n return ownerSelection.result\n }\n\n const affinityPlan = this.buildAffinitySelectionPlan({\n orderedAccounts,\n candidates,\n context,\n ownerSelectionReason: ownerSelection.selectionReason,\n })\n const preferredSelection = await this.selectPreferredAffinityAccount({\n cacheKey: affinityPlan.cacheKey,\n orderedAccounts,\n candidates,\n initialSelectionReason: affinityPlan.initialSelectionReason,\n })\n if (preferredSelection.result) {\n this.attachConfirmOwnership(\n preferredSelection.result,\n context?.ownershipWriteSessionId,\n )\n return preferredSelection.result\n }\n\n let accountsForSelection = affinityPlan.defaultAccountsForSelection\n let premiumRemainingOrderedAccountIds = new Set<string>()\n let selectionReason = preferredSelection.selectionReason\n\n if (\n affinityPlan.canReorderOnAffinityCacheMiss\n && preferredSelection.affinityCacheMiss\n ) {\n const affinityMissOrder =\n this.orderAccountsForAffinityCacheMiss(orderedAccounts)\n accountsForSelection = affinityMissOrder.accounts\n premiumRemainingOrderedAccountIds =\n affinityMissOrder.premiumRemainingOrderedAccountIds\n }\n\n const result = await this.selectWithAliasFallback(\n accountsForSelection,\n candidates,\n )\n if (result.ok && premiumRemainingOrderedAccountIds.has(result.account.id)) {\n selectionReason = \"affinity_miss\"\n }\n\n return this.finalizeSelectedAccount({\n result,\n cacheKey: affinityPlan.cacheKey,\n selectionReason,\n ownershipWriteSessionId: context?.ownershipWriteSessionId,\n })\n }\n\n private getOrderedEnabledAccounts(): Array<AccountRuntime> {\n return [\n ...(this.temporaryAccount ? [this.temporaryAccount] : []),\n ...this.accountOrder\n .map((id) => this.accounts.get(id))\n .filter((account): account is AccountRuntime => account !== undefined),\n ].filter((account) => isAccountEnabled(account))\n }\n\n private buildAffinitySelectionPlan(params: {\n orderedAccounts: Array<AccountRuntime>\n candidates: Array<AccountRequestCandidate>\n context?: AccountSelectionContext\n ownerSelectionReason?: AccountSelectionReason\n }): {\n cacheKey: string | undefined\n defaultAccountsForSelection: Array<AccountRuntime>\n initialSelectionReason: AccountSelectionReason\n canReorderOnAffinityCacheMiss: boolean\n } {\n const { orderedAccounts, candidates, context, ownerSelectionReason } =\n params\n const affinityKey =\n this.accountAffinityEnabled && context ?\n extractAffinityKey(context)\n : undefined\n const modelKey = context?.affinityModelId ?? candidates[0].modelId\n const cacheKey =\n affinityKey ? buildAffinityCacheKey(affinityKey, modelKey) : undefined\n const shouldRotate =\n this.accountAffinityEnabled && orderedAccounts.length > 1\n const rotationStart =\n shouldRotate ? this.loadBalanceCursor % orderedAccounts.length : 0\n\n return {\n cacheKey,\n defaultAccountsForSelection:\n shouldRotate ? this.rotateAccounts(orderedAccounts) : orderedAccounts,\n initialSelectionReason:\n ownerSelectionReason\n ?? getInitialSelectionReason(cacheKey, rotationStart),\n canReorderOnAffinityCacheMiss:\n ownerSelectionReason === undefined && cacheKey !== undefined,\n }\n }\n\n private finalizeSelectedAccount(params: {\n result: SelectAccountForRequestResult\n cacheKey: string | undefined\n selectionReason: AccountSelectionReason\n ownershipWriteSessionId: string | undefined\n }): SelectAccountForRequestResult {\n const { result, cacheKey, selectionReason, ownershipWriteSessionId } =\n params\n if (!result.ok) {\n return {\n ...result,\n selectionReason,\n }\n }\n\n this.loadBalanceCursor++\n result.selectionReason = selectionReason\n result.affinityCacheKey = cacheKey\n\n if (cacheKey) {\n result.confirmAffinity = () => {\n if (!this.accountAffinityEnabled) return\n this.affinityCache.set(cacheKey, result.account.id)\n }\n }\n\n this.attachConfirmOwnership(result, ownershipWriteSessionId)\n return result\n }\n\n invalidateAffinity(cacheKey: string): void {\n const normalizedCacheKey = cacheKey.trim()\n if (!normalizedCacheKey) {\n return\n }\n\n this.affinityCache.delete(normalizedCacheKey)\n }\n\n private attachConfirmOwnership(\n result: SelectAccountForRequestSuccess,\n ownershipWriteSessionId: string | undefined,\n ): void {\n const rootSessionId = ownershipWriteSessionId?.trim()\n if (!rootSessionId) {\n return\n }\n\n const generation = this.sessionOwnershipGeneration\n result.confirmOwnership = () => {\n if (generation !== this.sessionOwnershipGeneration) {\n return\n }\n this.sessionOwnership.set(rootSessionId, result.account.id)\n }\n }\n\n private async selectPreferredSessionOwner(params: {\n lookupSessionId: string | undefined\n orderedAccounts: Array<AccountRuntime>\n candidates: Array<AccountRequestCandidate>\n }): Promise<{\n result?: SelectAccountForRequestSuccess\n selectionReason?: AccountSelectionReason\n }> {\n const { lookupSessionId, orderedAccounts, candidates } = params\n\n if (lookupSessionId === undefined) {\n return {}\n }\n\n const rootSessionId = lookupSessionId.trim()\n if (!rootSessionId) {\n return { selectionReason: \"subagent_marker_invalid_fallback\" }\n }\n\n const preferredAccountId = this.sessionOwnership.get(rootSessionId)\n if (!preferredAccountId) {\n return { selectionReason: \"subagent_owner_miss\" }\n }\n\n const ownerResult = await this.tryAffinityAccount(\n preferredAccountId,\n orderedAccounts,\n candidates,\n )\n if (!ownerResult) {\n return { selectionReason: \"subagent_owner_unusable_fallback\" }\n }\n\n ownerResult.selectionReason = \"subagent_owner_hit\"\n\n return {\n result: ownerResult,\n }\n }\n\n /**\n * Try the preferred account from the affinity cache before normal selection.\n */\n private async selectPreferredAffinityAccount(params: {\n cacheKey: string | undefined\n orderedAccounts: Array<AccountRuntime>\n candidates: Array<AccountRequestCandidate>\n initialSelectionReason: AccountSelectionReason\n }): Promise<{\n result?: SelectAccountForRequestSuccess\n selectionReason: AccountSelectionReason\n affinityCacheMiss: boolean\n }> {\n const { cacheKey, orderedAccounts, candidates, initialSelectionReason } =\n params\n\n if (!cacheKey) {\n return {\n selectionReason: initialSelectionReason,\n affinityCacheMiss: false,\n }\n }\n\n const preferredId = this.affinityCache.get(cacheKey)\n if (!preferredId) {\n return {\n selectionReason: initialSelectionReason,\n affinityCacheMiss: true,\n }\n }\n\n const affinityResult = await this.tryAffinityAccount(\n preferredId,\n orderedAccounts,\n candidates,\n )\n if (!affinityResult) {\n this.affinityCache.delete(cacheKey)\n return {\n selectionReason: preserveSubagentSelectionReason(\n initialSelectionReason,\n \"preferred_account_unavailable\",\n ),\n affinityCacheMiss: false,\n }\n }\n\n const selectionReason = preserveSubagentSelectionReason(\n initialSelectionReason,\n \"affinity_hit\",\n )\n affinityResult.affinityHit = true\n affinityResult.affinityCacheKey = cacheKey\n affinityResult.selectionReason = selectionReason\n affinityResult.confirmAffinity = () => {\n if (!this.accountAffinityEnabled) return\n this.affinityCache.set(cacheKey, affinityResult.account.id)\n }\n\n return {\n result: affinityResult,\n selectionReason,\n affinityCacheMiss: false,\n }\n }\n\n /**\n * Rotate the accounts array by the current load-balance cursor for round-robin distribution.\n * This ensures cache-miss requests are spread across accounts instead of always hitting the first.\n */\n private rotateAccounts(\n accounts: Array<AccountRuntime>,\n ): Array<AccountRuntime> {\n const start = this.loadBalanceCursor % accounts.length\n if (start === 0) return accounts\n return [...accounts.slice(start), ...accounts.slice(0, start)]\n }\n\n private orderAccountsForAffinityCacheMiss(\n orderedAccounts: Array<AccountRuntime>,\n ): {\n accounts: Array<AccountRuntime>\n premiumRemainingOrderedAccountIds: Set<string>\n } {\n const scoredAccounts = orderedAccounts\n .map((account) => ({\n account,\n effectiveRemaining: getEffectivePremiumRemaining(account),\n }))\n .filter(\n (entry): entry is ScoredAccountRuntime =>\n entry.effectiveRemaining !== undefined,\n )\n .sort((left, right) => right.effectiveRemaining - left.effectiveRemaining)\n\n if (scoredAccounts.length > 0) {\n const scoredAccountsInSelectionOrder =\n this.shuffleWithinEqualRemainingBuckets(scoredAccounts).map(\n ({ account }) => account,\n )\n const scoredAccountSet = new Set(scoredAccountsInSelectionOrder)\n const unknownQuotaAccounts = orderedAccounts.filter(\n (account) => !scoredAccountSet.has(account) && !account.unlimited,\n )\n const unlimitedAccounts = orderedAccounts.filter(\n (account) => !scoredAccountSet.has(account) && account.unlimited,\n )\n return {\n accounts: [\n ...scoredAccountsInSelectionOrder,\n ...unknownQuotaAccounts,\n ...unlimitedAccounts,\n ],\n premiumRemainingOrderedAccountIds: new Set(\n scoredAccountsInSelectionOrder.map((account) => account.id),\n ),\n }\n }\n\n const premiumRemainingOrderedAccountIds = new Set<string>()\n const unlimitedAccounts = orderedAccounts.filter(\n (account) => account.unlimited,\n )\n if (unlimitedAccounts.length === 0) {\n return {\n accounts: orderedAccounts,\n premiumRemainingOrderedAccountIds,\n }\n }\n\n const unknownQuotaAccounts = orderedAccounts.filter(\n (account) => !account.unlimited,\n )\n return {\n accounts: [\n ...this.shuffleArray(unlimitedAccounts),\n ...unknownQuotaAccounts,\n ],\n premiumRemainingOrderedAccountIds,\n }\n }\n\n private shuffleWithinEqualRemainingBuckets(\n scoredAccounts: Array<ScoredAccountRuntime>,\n ): Array<ScoredAccountRuntime> {\n const shuffled: Array<ScoredAccountRuntime> = []\n\n let index = 0\n while (index < scoredAccounts.length) {\n const currentRemaining = scoredAccounts[index].effectiveRemaining\n let bucketEnd = index + 1\n while (\n bucketEnd < scoredAccounts.length\n && scoredAccounts[bucketEnd].effectiveRemaining === currentRemaining\n ) {\n bucketEnd++\n }\n\n shuffled.push(\n ...this.shuffleArray(scoredAccounts.slice(index, bucketEnd)),\n )\n index = bucketEnd\n }\n\n return shuffled\n }\n\n private shuffleArray<T>(items: Array<T>): Array<T> {\n if (items.length <= 1) {\n return items\n }\n\n const shuffled = [...items]\n for (let index = shuffled.length - 1; index > 0; index--) {\n const randomIndex = Math.floor(Math.random() * (index + 1))\n ;[shuffled[index], shuffled[randomIndex]] = [\n shuffled[randomIndex],\n shuffled[index],\n ]\n }\n\n return shuffled\n }\n\n /**\n * Normal account selection with alias fallback.\n * Extracted to keep selectAccountForRequest readable after adding affinity logic.\n */\n private async selectWithAliasFallback(\n orderedAccounts: Array<AccountRuntime>,\n candidates: Array<AccountRequestCandidate>,\n ): Promise<SelectAccountForRequestResult> {\n const primary = await this.selectAccountForCandidates(\n orderedAccounts,\n candidates,\n )\n if (primary.ok || primary.reason !== \"MODEL_NOT_SUPPORTED\") {\n return primary\n }\n\n const aliasCandidates = candidates.map((candidate) => {\n const modelId = resolveModelAlias(candidate.modelId)\n if (modelId === candidate.modelId) return candidate\n return { ...candidate, modelId }\n })\n const aliasChanged = aliasCandidates.some(\n (candidate, index) => candidate.modelId !== candidates[index].modelId,\n )\n if (!aliasChanged) {\n return primary\n }\n\n return this.selectAccountForCandidates(orderedAccounts, aliasCandidates)\n }\n\n /**\n * Finalize quota after a request completes.\n * This releases any in-flight reservation and refreshes the actual quota from the API.\n */\n async finalizeQuota(\n account: AccountRuntime,\n reservation?: QuotaReservation,\n ): Promise<void> {\n releasePremiumReservation(account, reservation)\n\n try {\n await this.refreshQuota(account)\n } catch (error) {\n consola.debug(`Failed to finalize quota for ${account.id}:`, error)\n }\n }\n\n /**\n * Mark an account as failed.\n */\n markAccountFailed(id: string, reason: string): void {\n const account = this.accounts.get(id)\n if (account) {\n setAccountFailedState(account, reason)\n return\n }\n\n if (this.temporaryAccount && this.temporaryAccount.id === id) {\n setAccountFailedState(this.temporaryAccount, reason)\n }\n }\n\n /**\n * Get status of all accounts.\n */\n getAccountStatus(): Array<AccountStatusEntry> {\n const statuses: Array<AccountStatusEntry> = []\n\n if (this.temporaryAccount) {\n statuses.push({\n id: \"(temporary)\",\n entitlement: this.temporaryAccount.premiumEntitlement,\n remaining: this.temporaryAccount.premiumRemaining,\n unlimited: this.temporaryAccount.unlimited,\n overagePermitted: this.temporaryAccount.overagePermitted,\n failed: this.temporaryAccount.failed,\n failureReason: this.temporaryAccount.failureReason,\n })\n }\n\n for (const id of this.accountOrder) {\n const account = this.accounts.get(id)\n if (account) {\n statuses.push({\n id: account.id,\n entitlement: account.premiumEntitlement,\n remaining: account.premiumRemaining,\n unlimited: account.unlimited,\n overagePermitted: account.overagePermitted,\n failed: account.failed,\n failureReason: account.failureReason,\n enabled: account.enabled,\n })\n }\n }\n\n return statuses\n }\n\n /**\n * Set a temporary account from a GitHub token (--github-token).\n * This account takes priority over registered accounts.\n */\n async setTemporaryAccount(\n githubToken: string,\n accountType: AccountType,\n ): Promise<void> {\n const user = await getGitHubUser({ githubToken, accountType })\n\n if (this.temporaryAccount) {\n this.stopTokenRefresh(this.temporaryAccount)\n this.stopSessionRefresh(this.temporaryAccount)\n }\n\n const runtime: AccountRuntime = {\n id: \"(temporary)\",\n accountLogin: user.login,\n accountType,\n addedAt: Date.now(),\n githubToken,\n vsCodeVersion: this.vsCodeVersion,\n }\n\n try {\n await this.initializeAccount(runtime)\n this.temporaryAccount = runtime\n consola.info(\"Temporary account initialized\")\n } catch (error) {\n consola.error(\"Failed to initialize temporary account:\", error)\n throw error\n }\n }\n\n /**\n * Check if any accounts are available.\n */\n hasAccounts(): boolean {\n return this.accounts.size > 0 || this.temporaryAccount !== undefined\n }\n\n /**\n * Get the first available account's models.\n * Used for caching models in legacy compatibility mode.\n */\n getFirstAccountModels(): AccountRuntime[\"models\"] {\n if (this.temporaryAccount?.models) {\n return this.temporaryAccount.models\n }\n\n for (const id of this.accountOrder) {\n const account = this.accounts.get(id)\n if (account?.models) {\n return account.models\n }\n }\n\n return undefined\n }\n\n /**\n * Get account context by account ID.\n * Returns null if no account with the given ID exists.\n */\n getAccountContextById(id: string): AccountContext | null {\n if (this.temporaryAccount && this.temporaryAccount.id === id) {\n return this.toAccountContext(this.temporaryAccount)\n }\n\n const account = this.accounts.get(id)\n if (account) {\n return this.toAccountContext(account)\n }\n\n return null\n }\n\n /**\n * Get account context by index.\n * Index 0 is the temporary account (if exists), otherwise the first registered account.\n * Returns null if index is out of bounds.\n */\n getAccountContextByIndex(index: number): AccountContext | null {\n // Build the same order as getAccountStatus()\n const allAccounts: Array<AccountRuntime> = []\n\n if (this.temporaryAccount) {\n allAccounts.push(this.temporaryAccount)\n }\n\n for (const id of this.accountOrder) {\n const account = this.accounts.get(id)\n if (account) {\n allAccounts.push(account)\n }\n }\n\n if (index < 0 || index >= allAccounts.length) {\n return null\n }\n\n return this.toAccountContext(allAccounts[index])\n }\n\n /**\n * Get the total number of accounts (including temporary).\n */\n getAccountCount(): number {\n return (this.temporaryAccount ? 1 : 0) + this.accountOrder.length\n }\n\n /**\n * Convert AccountRuntime to AccountContext for service calls.\n */\n private toAccountContext(account: AccountRuntime): AccountContext {\n return {\n accountLogin: account.accountLogin,\n githubToken: account.githubToken,\n copilotToken: account.copilotToken,\n ...(account.copilotApiUrl !== undefined ?\n { copilotApiUrl: account.copilotApiUrl }\n : {}),\n accountType: account.accountType,\n vsCodeVersion: account.vsCodeVersion,\n clientDeviceId: account.clientDeviceId,\n clientMachineId: account.clientMachineId,\n clientSessionId: account.clientSessionId,\n }\n }\n\n /**\n * Start watching the registry file for changes.\n * Enables hot reload of accounts when the file is modified.\n */\n private startRegistryWatcher(): void {\n // Stop existing watcher if any\n this.stopRegistryWatcher()\n\n try {\n this.registryWatcher = fs.watch(\n PATHS.ACCOUNTS_REGISTRY_PATH,\n (eventType) => {\n // Only react to 'change' events (file content modified)\n if (eventType === \"change\") {\n this.scheduleReload()\n }\n },\n )\n\n // Successful start: reset restart backoff.\n this.registryWatcherRestartDelayMs = WATCHER_RESTART_INITIAL_DELAY_MS\n if (this.registryWatcherRestartTimer) {\n clearTimeout(this.registryWatcherRestartTimer)\n this.registryWatcherRestartTimer = undefined\n }\n\n // Handle watcher errors (e.g., file deleted)\n this.registryWatcher.on(\"error\", (error) => {\n consola.debug(\"Registry watcher error:\", error)\n\n const delayMs = this.registryWatcherRestartDelayMs\n this.registryWatcherRestartDelayMs = Math.min(\n this.registryWatcherRestartDelayMs * 2,\n WATCHER_RESTART_MAX_DELAY_MS,\n )\n\n // Close broken watcher to avoid repeated error events.\n this.stopRegistryWatcher()\n\n // Try to restart the watcher after a delay (with backoff)\n this.registryWatcherRestartTimer = setTimeout(() => {\n this.registryWatcherRestartTimer = undefined\n this.startRegistryWatcher()\n }, delayMs)\n\n consola.debug(`Restarting registry watcher in ${delayMs}ms`)\n })\n\n consola.debug(\"Started registry file watcher\")\n } catch (error) {\n consola.warn(\"Failed to start registry watcher:\", error)\n }\n }\n\n /**\n * Immediately reload the registry, bypassing the debounce delay.\n * If a reload is already running, waits for it to complete and then\n * runs another reload to ensure the latest changes are captured.\n */\n async reloadRegistryNow(): Promise<void> {\n if (this.reloadDebounceTimer) {\n clearTimeout(this.reloadDebounceTimer)\n this.reloadDebounceTimer = undefined\n }\n // Wait for any in-progress reload before starting a fresh one\n if (this.currentReloadPromise) {\n await this.currentReloadPromise\n }\n await this.reloadRegistry()\n }\n\n /**\n * Schedule a registry reload with debouncing.\n */\n private scheduleReload(): void {\n // Clear existing timer\n if (this.reloadDebounceTimer) {\n clearTimeout(this.reloadDebounceTimer)\n }\n\n // Schedule reload after debounce delay\n this.reloadDebounceTimer = setTimeout(() => {\n void this.reloadRegistry()\n }, RELOAD_DEBOUNCE_MS)\n }\n\n /**\n * Reload the registry and perform incremental updates.\n * Adds new accounts, removes deleted ones, and reinitializes existing accounts\n * when token/accountType changes.\n */\n private async reloadRegistry(): Promise<void> {\n // Prevent concurrent reloads\n if (this.isReloading) {\n return\n }\n this.isReloading = true\n\n this.currentReloadPromise = (async () => {\n try {\n const newMetas = await listAccountsFromRegistry()\n const newIds = new Set(newMetas.map((m) => m.id))\n const currentIds = new Set(this.accountOrder)\n\n // Track changes for logging\n const added: Array<string> = []\n const removed: Array<string> = []\n const updated: Array<string> = []\n\n this.removeDeletedAccounts(currentIds, newIds, removed)\n\n // Add new accounts (newIds - currentIds)\n for (const meta of newMetas) {\n if (!currentIds.has(meta.id)) {\n await this.addNewAccount(meta, added)\n }\n }\n\n // Update existing accounts when meta/token changed\n await this.reinitializeUpdatedAccounts(newMetas, currentIds, updated)\n\n // Update accountOrder to reflect new order\n this.accountOrder = newMetas\n .map((m) => m.id)\n .filter((id) => this.accounts.has(id))\n\n // Reset load-balance cursor on account list/order changes.\n this.loadBalanceCursor = 0\n\n this.logRegistryReloadChanges(added, removed, updated)\n } catch (error) {\n consola.error(\"Failed to reload registry:\", error)\n this.shutdown()\n process.exit(1)\n } finally {\n this.isReloading = false\n this.currentReloadPromise = undefined\n }\n })()\n\n await this.currentReloadPromise\n }\n\n private removeDeletedAccounts(\n currentIds: Set<string>,\n newIds: Set<string>,\n removed: Array<string>,\n ): void {\n for (const id of currentIds) {\n if (!newIds.has(id)) {\n const account = this.accounts.get(id)\n if (!account) {\n continue\n }\n\n this.stopTokenRefresh(account)\n this.stopSessionRefresh(account)\n this.accounts.delete(id)\n removed.push(id)\n }\n }\n }\n\n private async reinitializeUpdatedAccounts(\n newMetas: Array<AccountMeta>,\n currentIds: Set<string>,\n updated: Array<string>,\n ): Promise<void> {\n for (const meta of newMetas) {\n if (!currentIds.has(meta.id)) {\n continue\n }\n\n const account = this.accounts.get(meta.id)\n if (!account) {\n continue\n }\n\n const token = await loadAccountToken(meta.id)\n if (!token) {\n consola.warn(`No token found for account ${meta.id}, skipping update`)\n continue\n }\n\n const accountTypeChanged = account.accountType !== meta.accountType\n const tokenChanged = account.githubToken !== token\n const addedAtChanged = account.addedAt !== meta.addedAt\n\n // Keep runtime metadata in sync with the registry.\n if (accountTypeChanged) {\n account.accountType = meta.accountType\n }\n if (addedAtChanged) {\n account.addedAt = meta.addedAt\n }\n // Always sync the enabled flag so toggle takes effect immediately.\n account.enabled = meta.enabled\n account.accountLogin = meta.id\n if (tokenChanged) {\n account.githubToken = token\n }\n\n if (!accountTypeChanged && !tokenChanged) {\n continue\n }\n\n try {\n await this.initializeAccount(account)\n updated.push(meta.id)\n } catch (error) {\n consola.error(\n `Failed to reinitialize account ${meta.id} after update:`,\n error,\n )\n account.failed = true\n account.failureReason = String(error)\n updated.push(`${meta.id} (failed)`)\n }\n }\n }\n\n private logRegistryReloadChanges(\n added: Array<string>,\n removed: Array<string>,\n updated: Array<string>,\n ): void {\n if (added.length === 0 && removed.length === 0 && updated.length === 0) {\n return\n }\n\n const changes: Array<string> = []\n if (added.length > 0) {\n changes.push(`added: ${added.join(\", \")}`)\n }\n if (removed.length > 0) {\n changes.push(`removed: ${removed.join(\", \")}`)\n }\n if (updated.length > 0) {\n changes.push(`updated: ${updated.join(\", \")}`)\n }\n\n consola.info(\n `Registry reloaded (${changes.join(\"; \")}). Total: ${this.accounts.size} account(s)`,\n )\n }\n\n /**\n * Helper to add a new account during reload.\n */\n private async addNewAccount(\n meta: { id: string; accountType: AccountType; addedAt: number },\n added: Array<string>,\n ): Promise<void> {\n const token = await loadAccountToken(meta.id)\n if (!token) {\n consola.warn(`No token found for new account ${meta.id}, skipping`)\n return\n }\n\n const runtime: AccountRuntime = {\n ...meta,\n accountLogin: meta.id,\n githubToken: token,\n vsCodeVersion: this.vsCodeVersion,\n }\n\n try {\n await this.initializeAccount(runtime)\n this.accounts.set(meta.id, runtime)\n added.push(meta.id)\n } catch (error) {\n consola.error(`Failed to initialize new account ${meta.id}:`, error)\n runtime.failed = true\n runtime.failureReason = String(error)\n this.accounts.set(meta.id, runtime)\n added.push(`${meta.id} (failed)`)\n }\n }\n\n /**\n * Stop the registry file watcher.\n */\n private stopRegistryWatcher(): void {\n if (this.reloadDebounceTimer) {\n clearTimeout(this.reloadDebounceTimer)\n this.reloadDebounceTimer = undefined\n }\n if (this.registryWatcherRestartTimer) {\n clearTimeout(this.registryWatcherRestartTimer)\n this.registryWatcherRestartTimer = undefined\n }\n if (this.registryWatcher) {\n this.registryWatcher.close()\n this.registryWatcher = undefined\n }\n }\n\n /**\n * Shutdown the manager and clean up resources.\n */\n shutdown(): void {\n this.sessionOwnershipGeneration++\n this.stopRegistryWatcher()\n this.stopAllTokenRefresh()\n this.stopAllSessionRefresh()\n this.stopModelsRefresh()\n this.affinityCache.clearMemory()\n this.sessionOwnership.clear()\n this.loadBalanceCursor = 0\n this.accounts.clear()\n this.accountOrder = []\n this.temporaryAccount = undefined\n }\n}\n\n/** Singleton instance of AccountsManager */\nexport const accountsManager = new AccountsManager({\n persistentAffinityStore: getSharedSessionAffinityStore,\n})\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"accounts-manager-BM66oT38.js","names":["defaultConfig: AppConfig","cachedConfig: AppConfig | null","fs","normalizedTarget","normalized: ModelAliasInfoMap","normalized: ModelAliasMap","DEFAULT_MAX_ENTRIES","DEFAULT_TTL_MS","out: Record<string, string>","out","requestSnapshot: RequestSnapshot","responseHeaders: Record<string, string>","chunks: Array<Uint8Array>","responseBodyKind: \"json\" | \"sse\" | \"text\"","args: Array<string | number>","dailyArgs: Array<string | number>","byAccountArgs: Array<string | number>","daily: Array<DailyStats>","where: Array<string>","values: Array<SQLQueryBindings>","map: Record<string, AccountStatsRow | undefined>","disabledStore: RequestHistoryStoreApi","sharedStore: RequestHistoryStoreApi | null","sharedStatsStore: StatsStore | null","row: { account_id?: string } | null","sharedSessionAffinityStore: SessionAffinityStore | null","sharedCleanupInterval: ReturnType<typeof setInterval> | undefined","runtime: AccountRuntime","accounts: Array<AccountRuntime>","overageFallback:\n | {\n account: AccountRuntime\n model: Model\n endpoint: string\n costUnits: number\n }\n | undefined","unknownQuotaAccounts","unlimitedAccounts","shuffled: Array<ScoredAccountRuntime>","statuses: Array<AccountStatusEntry>","allAccounts: Array<AccountRuntime>","fs","added: Array<string>","removed: Array<string>","updated: Array<string>","changes: Array<string>"],"sources":["../src/lib/config.ts","../src/lib/account-affinity.ts","../src/lib/dev-mode.ts","../src/services/copilot/copilot-fetch.ts","../src/services/copilot/get-models.ts","../src/lib/accounts-manager-auth.ts","../src/lib/accounts-manager-quota.ts","../src/lib/stats-store.ts","../src/lib/request-history.ts","../src/lib/session-affinity-store.ts","../src/lib/session-ownership.ts","../src/lib/accounts-manager.ts"],"sourcesContent":["import consola from \"consola\"\nimport fs from \"node:fs\"\n\nimport { PATHS } from \"./paths\"\n\nexport type LogLevel = \"error\" | \"warn\" | \"info\" | \"debug\"\n\nexport interface DevModeConfig {\n enabled: boolean\n capture4xx: boolean\n capture5xx: boolean\n captureOther: boolean\n}\n\nexport interface AppConfig {\n auth?: {\n apiKeys?: Array<string>\n }\n providers?: Record<string, ProviderConfig>\n extraPrompts?: Record<string, string>\n smallModel?: string\n accountAffinity?: boolean\n /** @deprecated */\n apiKey?: string\n responsesApiContextManagementModels?: Array<string>\n modelReasoningEfforts?: Record<\n string,\n \"none\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\"\n >\n modelAliases?: Record<string, { target: string; allowOriginal?: boolean }>\n allowOriginalModelNamesForAliases?: boolean\n useFunctionApplyPatch?: boolean\n forceAgent?: boolean\n compactUseSmallModel?: boolean\n messageStartInputTokensFallback?: boolean\n modelRefreshIntervalHours?: number\n sessionAffinityRetentionDays?: number\n useMessagesApi?: boolean\n anthropicApiKey?: string\n useResponsesApiWebSearch?: boolean\n claudeTokenMultiplier?: number\n logLevel?: LogLevel\n devMode?: DevModeConfig\n}\n\nexport interface ModelConfig {\n temperature?: number\n topP?: number\n topK?: number\n}\n\nexport const PROVIDER_TYPE_ANTHROPIC = \"anthropic\" as const\n\nexport type ProviderType = typeof PROVIDER_TYPE_ANTHROPIC\n\nexport type ProviderAuthType = \"authorization\" | \"x-api-key\"\n\nexport interface ProviderConfig {\n type?: string\n enabled?: boolean\n baseUrl?: string\n apiKey?: string\n authType?: ProviderAuthType\n models?: Record<string, ModelConfig>\n adjustInputTokens?: boolean\n}\n\nexport interface ResolvedProviderConfig {\n name: string\n type: ProviderType\n baseUrl: string\n apiKey: string\n authType: ProviderAuthType\n models?: Record<string, ModelConfig>\n adjustInputTokens?: boolean\n}\n\nconst gpt5ExplorationPrompt = `## Exploration and reading files\n- **Think first.** Before any tool call, decide ALL files/resources you will need.\n- **Batch everything.** If you need multiple files (even from different places), read them together.\n- **multi_tool_use.parallel** Use multi_tool_use.parallel to parallelize tool calls and only this.\n- **Only make sequential calls if you truly cannot know the next file without seeing a result first.**\n- **Workflow:** (a) plan all needed reads → (b) issue one parallel batch → (c) analyze results → (d) repeat if new, unpredictable reads arise.`\n\nconst gpt5CommentaryPrompt = `# Working with the user\n\nYou interact with the user through a terminal. You have 2 ways of communicating with the users: \n- Share intermediary updates in \\`commentary\\` channel. \n- After you have completed all your work, send a message to the \\`final\\` channel. \n\n## Intermediary updates\n\n- Intermediary updates go to the \\`commentary\\` channel.\n- User updates are short updates while you are working, they are NOT final answers.\n- You use 1-2 sentence user updates to communicate progress and new information to the user as you are doing work.\n- Do not begin responses with conversational interjections or meta commentary. Avoid openers such as acknowledgements (“Done —”, “Got it”, “Great question, ”) or framing phrases.\n- You provide user updates frequently, every 20s.\n- Before exploring or doing substantial work, you start with a user update acknowledging the request and explaining your first step. You should include your understanding of the user request and explain what you will do. Avoid commenting on the request or using starters such as \"Got it -\" or \"Understood -\" etc.\n- When exploring, e.g. searching, reading files, you provide user updates as you go, every 20s, explaining what context you are gathering and what you've learned. Vary your sentence structure when providing these updates to avoid sounding repetitive - in particular, don't start each sentence the same way.\n- After you have sufficient context, and the work is substantial, you provide a longer plan (this is the only user update that may be longer than 2 sentences and can contain formatting).\n- Before performing file edits of any kind, you provide updates explaining what edits you are making.\n- As you are thinking, you very frequently provide updates even if not taking any actions, informing the user of your progress. You interrupt your thinking and send multiple updates in a row if thinking for more than 100 words.\n- Tone of your updates MUST match your personality.`\n\nconst defaultConfig: AppConfig = {\n auth: {\n apiKeys: [],\n },\n providers: {},\n extraPrompts: {\n \"gpt-5-mini\": gpt5ExplorationPrompt,\n \"gpt-5.3-codex\": gpt5CommentaryPrompt,\n \"gpt-5.4-mini\": gpt5CommentaryPrompt,\n \"gpt-5.4\": gpt5CommentaryPrompt,\n \"gpt-5.5\": gpt5CommentaryPrompt,\n },\n smallModel: \"gpt-5-mini\",\n accountAffinity: true,\n responsesApiContextManagementModels: [],\n modelReasoningEfforts: {\n \"gpt-5-mini\": \"low\",\n \"gpt-5.3-codex\": \"xhigh\",\n \"gpt-5.4-mini\": \"xhigh\",\n \"gpt-5.4\": \"xhigh\",\n \"gpt-5.5\": \"xhigh\",\n },\n allowOriginalModelNamesForAliases: false,\n useFunctionApplyPatch: true,\n forceAgent: false,\n compactUseSmallModel: true,\n messageStartInputTokensFallback: false,\n modelRefreshIntervalHours: 24,\n sessionAffinityRetentionDays: 7,\n useMessagesApi: true,\n useResponsesApiWebSearch: true,\n logLevel: \"info\",\n devMode: {\n enabled: false,\n capture4xx: false,\n capture5xx: false,\n captureOther: false,\n },\n}\n\nlet cachedConfig: AppConfig | null = null\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\n\nfunction normalizeAuthApiKeys(value: unknown): Array<string> {\n if (!Array.isArray(value)) return []\n\n return [\n ...new Set(\n value\n .filter((item): item is string => typeof item === \"string\")\n .map((item) => item.trim())\n .filter((item) => item.length > 0),\n ),\n ]\n}\n\nfunction normalizeNonNegativeNumber(value: unknown): number | undefined {\n if (typeof value !== \"number\") return undefined\n if (!Number.isFinite(value)) return undefined\n if (value < 0) return undefined\n return value\n}\n\nconst LOG_LEVELS = new Set<LogLevel>([\"error\", \"warn\", \"info\", \"debug\"])\n\nfunction normalizeLogLevel(value: unknown): LogLevel | undefined {\n if (typeof value !== \"string\") return undefined\n return LOG_LEVELS.has(value as LogLevel) ? (value as LogLevel) : undefined\n}\n\nfunction ensureConfigFile(): void {\n try {\n fs.accessSync(PATHS.CONFIG_PATH, fs.constants.R_OK)\n return\n } catch {\n // Fall through to try creating the default config file.\n }\n\n try {\n fs.mkdirSync(PATHS.APP_DIR, { recursive: true })\n fs.writeFileSync(\n PATHS.CONFIG_PATH,\n `${JSON.stringify(defaultConfig, null, 2)}\\n`,\n \"utf8\",\n )\n try {\n fs.chmodSync(PATHS.CONFIG_PATH, 0o600)\n } catch {\n // Ignore chmod errors (e.g. unsupported filesystem).\n }\n } catch {\n // Best-effort only: if we can't create the file, reads will fall back to defaults.\n }\n}\n\nfunction readConfigFromDisk(): AppConfig {\n ensureConfigFile()\n try {\n const raw = fs.readFileSync(PATHS.CONFIG_PATH, \"utf8\")\n if (!raw.trim()) {\n fs.writeFileSync(\n PATHS.CONFIG_PATH,\n `${JSON.stringify(defaultConfig, null, 2)}\\n`,\n \"utf8\",\n )\n return defaultConfig\n }\n return JSON.parse(raw) as AppConfig\n } catch (error) {\n consola.error(\"Failed to read config file, using default config\", error)\n return defaultConfig\n }\n}\n\nfunction mergeDefaultConfig(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n const extraPrompts = config.extraPrompts ?? {}\n const defaultExtraPrompts = defaultConfig.extraPrompts ?? {}\n const modelReasoningEfforts = config.modelReasoningEfforts ?? {}\n const defaultModelReasoningEfforts = defaultConfig.modelReasoningEfforts ?? {}\n const hasForceAgent = typeof config.forceAgent === \"boolean\"\n const defaultForceAgent = defaultConfig.forceAgent ?? false\n\n const missingExtraPromptModels = Object.keys(defaultExtraPrompts).filter(\n (model) => !Object.hasOwn(extraPrompts, model),\n )\n\n const missingReasoningEffortModels = Object.keys(\n defaultModelReasoningEfforts,\n ).filter((model) => !Object.hasOwn(modelReasoningEfforts, model))\n\n const hasExtraPromptChanges = missingExtraPromptModels.length > 0\n const hasReasoningEffortChanges = missingReasoningEffortModels.length > 0\n const hasForceAgentChanges = !hasForceAgent\n\n if (\n !hasExtraPromptChanges\n && !hasReasoningEffortChanges\n && !hasForceAgentChanges\n ) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n extraPrompts: {\n ...defaultExtraPrompts,\n ...extraPrompts,\n },\n modelReasoningEfforts: {\n ...defaultModelReasoningEfforts,\n ...modelReasoningEfforts,\n },\n forceAgent: hasForceAgent ? config.forceAgent : defaultForceAgent,\n },\n changed: true,\n }\n}\n\nfunction mergeDefaultAuth(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n const authConfig = isPlainObject(config.auth) ? config.auth : undefined\n const rawApiKeys =\n Array.isArray(authConfig?.apiKeys) ? authConfig.apiKeys : undefined\n const normalizedApiKeys = normalizeAuthApiKeys(rawApiKeys)\n const nextAuth = { apiKeys: normalizedApiKeys }\n\n if (authConfig && JSON.stringify(authConfig) === JSON.stringify(nextAuth)) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n auth: nextAuth,\n },\n changed: true,\n }\n}\n\nfunction mergeDefaultAccountAffinity(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n // Migration: map old freeModelLoadBalancing to accountAffinity\n const raw = config as Record<string, unknown>\n const hasOld = typeof raw.freeModelLoadBalancing === \"boolean\"\n const hasNew = typeof config.accountAffinity === \"boolean\"\n\n if (hasOld) {\n const next = { ...config } as Record<string, unknown>\n if (!hasNew) {\n next.accountAffinity = raw.freeModelLoadBalancing\n }\n delete next.freeModelLoadBalancing\n return { mergedConfig: next as AppConfig, changed: true }\n }\n\n if (hasNew) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n accountAffinity: defaultConfig.accountAffinity ?? true,\n },\n changed: true,\n }\n}\n\nfunction mergeDefaultModelRefreshInterval(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n const normalized = normalizeNonNegativeNumber(\n config.modelRefreshIntervalHours,\n )\n\n if (normalized !== undefined) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n modelRefreshIntervalHours: defaultConfig.modelRefreshIntervalHours ?? 24,\n },\n changed: true,\n }\n}\n\nfunction mergeDefaultSessionAffinityRetention(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n const normalized = normalizeNonNegativeNumber(\n config.sessionAffinityRetentionDays,\n )\n\n if (normalized !== undefined) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n sessionAffinityRetentionDays:\n defaultConfig.sessionAffinityRetentionDays ?? 7,\n },\n changed: true,\n }\n}\n\nfunction mergeDefaultLogLevel(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n const normalized = normalizeLogLevel(config.logLevel)\n\n if (normalized !== undefined) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n logLevel: defaultConfig.logLevel ?? \"info\",\n },\n changed: true,\n }\n}\n\nfunction mergeDefaultDevMode(config: AppConfig): ConfigMergeResult {\n const current = config.devMode\n if (\n current\n && typeof current.enabled === \"boolean\"\n && typeof current.capture4xx === \"boolean\"\n && typeof current.capture5xx === \"boolean\"\n && typeof current.captureOther === \"boolean\"\n ) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n devMode: {\n enabled: current?.enabled === true,\n capture4xx: current?.capture4xx === true,\n capture5xx: current?.capture5xx === true,\n captureOther: current?.captureOther === true,\n },\n },\n changed: true,\n }\n}\n\ntype ConfigMergeResult = {\n mergedConfig: AppConfig\n changed: boolean\n}\n\ntype ConfigMergeFn = (config: AppConfig) => ConfigMergeResult\n\nfunction applyConfigMerges(\n config: AppConfig,\n mergeFns: ReadonlyArray<ConfigMergeFn>,\n): ConfigMergeResult {\n return mergeFns.reduce<ConfigMergeResult>(\n (acc, mergeFn) => {\n const result = mergeFn(acc.mergedConfig)\n return {\n mergedConfig: result.mergedConfig,\n changed: acc.changed || result.changed,\n }\n },\n { mergedConfig: config, changed: false },\n )\n}\n\nexport function mergeConfigWithDefaults(): AppConfig {\n const config = readConfigFromDisk()\n\n const { mergedConfig, changed } = applyConfigMerges(config, [\n mergeDefaultAuth,\n mergeDefaultConfig,\n mergeDefaultAccountAffinity,\n mergeDefaultModelRefreshInterval,\n mergeDefaultSessionAffinityRetention,\n mergeDefaultLogLevel,\n mergeDefaultDevMode,\n ])\n\n if (changed) {\n try {\n fs.writeFileSync(\n PATHS.CONFIG_PATH,\n `${JSON.stringify(mergedConfig, null, 2)}\\n`,\n \"utf8\",\n )\n } catch (writeError) {\n consola.warn(\"Failed to write merged config defaults\", writeError)\n }\n }\n\n cachedConfig = mergedConfig\n return mergedConfig\n}\n\nexport function getConfig(): AppConfig {\n cachedConfig ??= readConfigFromDisk()\n return cachedConfig\n}\n\ntype ModelAliasSpec = {\n target: string\n allowOriginal?: boolean\n}\n\ntype ModelAliasMap = Record<string, string>\n\ntype ModelAliasInfoMap = Record<string, ModelAliasSpec>\n\ntype ModelAliasRawMap = Record<string, unknown>\n\nfunction normalizeAliasKey(value: string): string | null {\n const trimmed = value.trim().toLowerCase()\n return trimmed.length > 0 ? trimmed : null\n}\n\nfunction normalizeAliasTarget(value: string): string | null {\n const trimmed = value.trim()\n return trimmed.length > 0 ? trimmed : null\n}\n\nfunction normalizeAliasSpec(value: unknown): ModelAliasSpec | null {\n if (typeof value === \"string\") {\n const normalizedTarget = normalizeAliasTarget(value)\n return normalizedTarget ? { target: normalizedTarget } : null\n }\n if (!value || typeof value !== \"object\") {\n return null\n }\n\n const targetValue = (value as { target?: unknown }).target\n if (typeof targetValue !== \"string\") {\n return null\n }\n\n const normalizedTarget = normalizeAliasTarget(targetValue)\n if (!normalizedTarget) {\n return null\n }\n\n const allowOriginalValue = (value as { allowOriginal?: unknown })\n .allowOriginal\n const allowOriginal =\n typeof allowOriginalValue === \"boolean\" ? allowOriginalValue : undefined\n return { target: normalizedTarget, allowOriginal }\n}\n\nexport function getModelAliasesInfo(): ModelAliasInfoMap {\n const config = getConfig()\n const raw = (config.modelAliases ?? {}) as ModelAliasRawMap\n const normalized: ModelAliasInfoMap = {}\n\n for (const [alias, rawSpec] of Object.entries(raw)) {\n const normalizedAlias = normalizeAliasKey(alias)\n const normalizedSpec = normalizeAliasSpec(rawSpec)\n if (!normalizedAlias || !normalizedSpec) {\n continue\n }\n if (!Object.hasOwn(normalized, normalizedAlias)) {\n normalized[normalizedAlias] = normalizedSpec\n }\n }\n\n return normalized\n}\n\nexport function getModelAliases(): ModelAliasMap {\n const info = getModelAliasesInfo()\n const normalized: ModelAliasMap = {}\n\n for (const [alias, spec] of Object.entries(info)) {\n normalized[alias] = spec.target\n }\n\n return normalized\n}\n\nexport function resolveModelAlias(modelId: string): string {\n const normalized = normalizeAliasKey(modelId)\n if (!normalized) return modelId\n const aliases = getModelAliases()\n return aliases[normalized] ?? modelId\n}\n\nexport function isOriginalModelNameAllowedForAliases(): boolean {\n const config = getConfig()\n return config.allowOriginalModelNamesForAliases ?? false\n}\n\nexport function getAliasTargetSet(): Set<string> {\n const aliases = getModelAliasesInfo()\n const allowOriginalDefault = isOriginalModelNameAllowedForAliases()\n const targetAllowMap = new Map<string, boolean>()\n\n for (const { target, allowOriginal } of Object.values(aliases)) {\n const normalizedTarget = target.toLowerCase()\n const effectiveAllow = allowOriginal ?? allowOriginalDefault\n const currentAllow = targetAllowMap.get(normalizedTarget)\n if (currentAllow === true) {\n continue\n }\n if (effectiveAllow) {\n targetAllowMap.set(normalizedTarget, true)\n } else if (currentAllow === undefined) {\n targetAllowMap.set(normalizedTarget, false)\n }\n }\n\n const blockedTargets = new Set<string>()\n for (const [target, allowed] of targetAllowMap.entries()) {\n if (!allowed) {\n blockedTargets.add(target)\n }\n }\n\n return blockedTargets\n}\n\nexport function isOriginalModelNameAllowedForTarget(modelId: string): boolean {\n const normalized = normalizeAliasKey(modelId)\n if (!normalized) return true\n const blockedTargets = getAliasTargetSet()\n return !blockedTargets.has(normalized)\n}\n\nexport function getPreferredAliasForTarget(modelId: string): string | null {\n const aliases = getModelAliases()\n const aliasKeys = getAliasKeysForTarget(modelId, aliases)\n return aliasKeys[0] ?? null\n}\n\nfunction getAliasKeysForTarget(\n target: string,\n aliases: ModelAliasMap,\n): Array<string> {\n const normalizedTarget = target.toLowerCase()\n return Object.entries(aliases)\n .filter(([, model]) => model.toLowerCase() === normalizedTarget)\n .map(([alias]) => alias)\n .sort()\n}\n\nfunction getAliasFallbackValue<T extends string>(\n record: Record<string, T> | undefined,\n modelId: string,\n aliases: ModelAliasMap,\n): T | undefined {\n if (!record) return undefined\n\n const aliasKeys = getAliasKeysForTarget(modelId, aliases)\n if (aliasKeys.length === 0) return undefined\n\n const recordByAlias = new Map<string, T>()\n for (const [key, value] of Object.entries(record)) {\n const normalized = normalizeAliasKey(key)\n if (normalized) {\n recordByAlias.set(normalized, value)\n }\n }\n\n for (const alias of aliasKeys) {\n const value = recordByAlias.get(alias)\n if (value !== undefined) {\n return value\n }\n }\n\n return undefined\n}\n\nexport function getExtraPromptForModel(model: string): string {\n const config = getConfig()\n const direct = config.extraPrompts?.[model]\n if (direct !== undefined) return direct\n\n const aliases = getModelAliases()\n const fallback = getAliasFallbackValue(config.extraPrompts, model, aliases)\n return fallback ?? \"\"\n}\n\nexport function getSmallModel(): string {\n const config = getConfig()\n const model = config.smallModel ?? \"gpt-5-mini\"\n if (isOriginalModelNameAllowedForTarget(model)) {\n return model\n }\n\n return getPreferredAliasForTarget(model) ?? model\n}\n\nexport function getLogLevel(): LogLevel {\n const config = getConfig()\n const normalized = normalizeLogLevel(config.logLevel)\n return normalized ?? defaultConfig.logLevel ?? \"info\"\n}\n\nexport function isAccountAffinityEnabled(): boolean {\n const config = getConfig()\n return config.accountAffinity ?? true\n}\n\nexport function getModelRefreshIntervalHours(): number {\n const config = getConfig()\n const normalized = normalizeNonNegativeNumber(\n config.modelRefreshIntervalHours,\n )\n return normalized ?? defaultConfig.modelRefreshIntervalHours ?? 24\n}\n\nexport function getModelRefreshIntervalMs(): number {\n const hours = getModelRefreshIntervalHours()\n if (!Number.isFinite(hours) || hours <= 0) return 0\n return hours * 60 * 60 * 1000\n}\n\nexport function getSessionAffinityRetentionDays(): number {\n const config = getConfig()\n const normalized = normalizeNonNegativeNumber(\n config.sessionAffinityRetentionDays,\n )\n return normalized ?? defaultConfig.sessionAffinityRetentionDays ?? 7\n}\n\nexport function getSessionAffinityRetentionMs(): number {\n const days = getSessionAffinityRetentionDays()\n if (!Number.isFinite(days) || days <= 0) return 0\n return days * 24 * 60 * 60 * 1000\n}\n\nexport function isMessageStartInputTokensFallbackEnabled(): boolean {\n const config = getConfig()\n return config.messageStartInputTokensFallback ?? false\n}\n\nexport function shouldCompactUseSmallModel(): boolean {\n const config = getConfig()\n return config.compactUseSmallModel ?? true\n}\n\nexport function getResponsesApiContextManagementModels(): Array<string> {\n const config = getConfig()\n return (\n config.responsesApiContextManagementModels\n ?? defaultConfig.responsesApiContextManagementModels\n ?? []\n )\n}\n\nexport function isResponsesApiContextManagementModel(model: string): boolean {\n return getResponsesApiContextManagementModels().includes(model)\n}\n\nexport function getReasoningEffortForModel(\n model: string,\n): \"none\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" {\n const config = getConfig()\n const direct = config.modelReasoningEfforts?.[model]\n if (direct !== undefined) return direct\n\n const aliases = getModelAliases()\n const fallback = getAliasFallbackValue(\n config.modelReasoningEfforts,\n model,\n aliases,\n )\n return fallback ?? \"high\"\n}\n\nexport function isForceAgentEnabled(): boolean {\n const config = getConfig()\n return config.forceAgent ?? false\n}\n\nexport function normalizeProviderBaseUrl(url: string): string {\n return url.trim().replace(/\\/+$/u, \"\")\n}\n\nfunction resolveProviderAuthType(\n providerName: string,\n authType?: string,\n): ProviderAuthType | null {\n if (authType === undefined || authType === \"x-api-key\") {\n return \"x-api-key\"\n }\n\n if (authType === \"authorization\") {\n return authType\n }\n\n consola.warn(\n `Provider ${providerName} has invalid authType '${authType}', ignoring provider`,\n )\n return null\n}\n\nexport function getProviderConfig(name: string): ResolvedProviderConfig | null {\n const providerName = name.trim()\n if (!providerName) {\n return null\n }\n\n const config = getConfig()\n const provider = config.providers?.[providerName]\n if (!provider) {\n return null\n }\n\n if (provider.enabled === false) {\n return null\n }\n\n const type = provider.type ?? PROVIDER_TYPE_ANTHROPIC\n if (type !== PROVIDER_TYPE_ANTHROPIC) {\n consola.warn(\n `Provider ${providerName} is ignored because only anthropic type is supported`,\n )\n return null\n }\n\n const baseUrl = normalizeProviderBaseUrl(provider.baseUrl ?? \"\")\n const apiKey = (provider.apiKey ?? \"\").trim()\n const authType = resolveProviderAuthType(providerName, provider.authType)\n if (!authType) {\n return null\n }\n if (!baseUrl || !apiKey) {\n consola.warn(\n `Provider ${providerName} is enabled but missing baseUrl or apiKey`,\n )\n return null\n }\n\n return {\n name: providerName,\n type: PROVIDER_TYPE_ANTHROPIC,\n baseUrl,\n apiKey,\n authType,\n models: provider.models,\n adjustInputTokens: provider.adjustInputTokens,\n }\n}\n\nexport function listEnabledProviders(): Array<string> {\n const config = getConfig()\n const providerNames = Object.keys(config.providers ?? {})\n return providerNames.filter((name) => getProviderConfig(name) !== null)\n}\n\nexport function isMessagesApiEnabled(): boolean {\n const config = getConfig()\n return config.useMessagesApi ?? true\n}\n\nexport function getAnthropicApiKey(): string | undefined {\n const config = getConfig()\n return config.anthropicApiKey ?? process.env.ANTHROPIC_API_KEY ?? undefined\n}\n\nexport function isResponsesApiWebSearchEnabled(): boolean {\n const config = getConfig()\n return config.useResponsesApiWebSearch ?? true\n}\n\nexport function getClaudeTokenMultiplier(): number {\n const config = getConfig()\n return config.claudeTokenMultiplier ?? 1.15\n}\n","import consola from \"consola\"\n\nimport type { AccountRuntime } from \"~/lib/types/account\"\n\nexport interface AffinityContext {\n requestId?: string\n affinityModelId?: string\n}\n\nexport interface AffinityPersistenceStore {\n get(key: string): string | undefined\n set(key: string, accountId: string): void\n delete(key: string): void\n clear(): void\n}\n\nexport type AffinityPersistenceStoreProvider =\n | AffinityPersistenceStore\n | (() => AffinityPersistenceStore | undefined)\n\ninterface AffinityCacheEntry {\n accountId: string\n expiresAt: number\n}\n\nconst DEFAULT_MAX_ENTRIES = 10_000\nconst DEFAULT_TTL_MS = 60 * 60 * 1000 // 1 hour\n\n/**\n * In-memory LRU cache with TTL for account affinity mappings.\n *\n * Uses Map insertion order for LRU eviction: updated or rehydrated entries are\n * deleted and re-inserted so they move to the \"newest\" end.\n */\nexport class AccountAffinityCache {\n private readonly cache = new Map<string, AffinityCacheEntry>()\n private readonly maxEntries: number\n private readonly ttlMs: number\n private persistentStore?: AffinityPersistenceStore\n private persistentStoreProvider?: () => AffinityPersistenceStore | undefined\n\n constructor(\n maxEntries = DEFAULT_MAX_ENTRIES,\n ttlMs = DEFAULT_TTL_MS,\n persistentStore?: AffinityPersistenceStoreProvider,\n ) {\n this.maxEntries = maxEntries\n this.ttlMs = ttlMs\n\n if (typeof persistentStore === \"function\") {\n this.persistentStoreProvider = persistentStore\n } else {\n this.persistentStore = persistentStore\n }\n }\n\n /** Look up the preferred account ID for a cache key. Returns undefined if not found or expired. */\n get(key: string): string | undefined {\n const entry = this.cache.get(key)\n if (entry) {\n if (Date.now() >= entry.expiresAt) {\n this.cache.delete(key)\n } else {\n return entry.accountId\n }\n }\n\n const accountId = this.readPersistentEntry(key)\n if (!accountId) {\n return undefined\n }\n\n this.setMemory(key, accountId)\n return accountId\n }\n\n /** Record a successful account mapping. Refreshes TTL and moves the entry to the newest position. */\n set(key: string, accountId: string): void {\n this.setMemory(key, accountId)\n this.writePersistentEntry(key, accountId)\n }\n\n /** Remove a specific entry. */\n delete(key: string): boolean {\n const deleted = this.cache.delete(key)\n this.deletePersistentEntry(key)\n return deleted\n }\n\n /** Remove all in-memory entries. */\n clearMemory(): void {\n this.cache.clear()\n }\n\n /** Remove all entries. */\n clear(): void {\n this.clearMemory()\n this.clearPersistentEntries()\n }\n\n /** Current number of entries (including potentially expired ones). */\n get size(): number {\n return this.cache.size\n }\n\n private getPersistentStore(): AffinityPersistenceStore | undefined {\n if (this.persistentStore) {\n return this.persistentStore\n }\n if (!this.persistentStoreProvider) {\n return undefined\n }\n\n try {\n const store = this.persistentStoreProvider()\n if (store) {\n this.persistentStore = store\n }\n return store\n } catch (error) {\n this.persistentStoreProvider = undefined\n consola.warn(\"Failed to resolve affinity persistence store:\", error)\n return undefined\n }\n }\n\n private readPersistentEntry(key: string): string | undefined {\n const store = this.getPersistentStore()\n if (!store) {\n return undefined\n }\n\n try {\n return store.get(key)\n } catch (error) {\n consola.warn(\n \"Failed to read affinity mapping from persistent store:\",\n error,\n )\n return undefined\n }\n }\n\n private writePersistentEntry(key: string, accountId: string): void {\n const store = this.getPersistentStore()\n if (!store) {\n return\n }\n\n try {\n store.set(key, accountId)\n } catch (error) {\n consola.warn(\"Failed to persist affinity mapping:\", error)\n }\n }\n\n private deletePersistentEntry(key: string): void {\n const store = this.getPersistentStore()\n if (!store) {\n return\n }\n\n try {\n store.delete(key)\n } catch (error) {\n consola.warn(\"Failed to delete affinity mapping:\", error)\n }\n }\n\n private clearPersistentEntries(): void {\n const store = this.getPersistentStore()\n if (!store) {\n return\n }\n\n try {\n store.clear()\n } catch (error) {\n consola.warn(\"Failed to clear persistent affinity mappings:\", error)\n }\n }\n\n private setMemory(key: string, accountId: string): void {\n // Delete first so re-insertion moves it to the newest position (LRU).\n this.cache.delete(key)\n\n // Evict oldest entries if at capacity.\n while (this.cache.size >= this.maxEntries) {\n const oldest = this.cache.keys().next()\n if (oldest.done) break\n this.cache.delete(oldest.value)\n }\n\n this.cache.set(key, {\n accountId,\n expiresAt: Date.now() + this.ttlMs,\n })\n }\n}\n\n/**\n * Extract the affinity key from the request context.\n * Uses the upstream request ID which is deterministic for the same user message.\n */\nexport function extractAffinityKey(\n context: AffinityContext,\n): string | undefined {\n return context.requestId?.trim() || undefined\n}\n\n/**\n * Build the full cache key by combining the affinity key with the model ID.\n * This prevents cross-model pollution (same session requesting different models\n * can be routed to different accounts).\n */\nexport function buildAffinityCacheKey(\n affinityKey: string,\n modelId: string,\n): string {\n return `${affinityKey}:${modelId}`\n}\n\n/**\n * Check whether an account is a valid affinity candidate.\n * An account is valid if it is not failed and is present in the provided\n * runtime list.\n */\nexport function isAffinityAccountUsable(\n accountId: string,\n accounts: ReadonlyArray<AccountRuntime>,\n): AccountRuntime | undefined {\n const account = accounts.find((a) => a.id === accountId)\n if (!account) return undefined\n if (account.failed) return undefined\n return account\n}\n","import { getConfig } from \"./config\"\n\nexport function isDevModeEnabled(): boolean {\n return getConfig().devMode?.enabled === true\n}\n\nexport function isCapture4xxEnabled(): boolean {\n return getConfig().devMode?.capture4xx === true\n}\n\nexport function isCapture5xxEnabled(): boolean {\n return getConfig().devMode?.capture5xx === true\n}\n\nexport function isCaptureOtherEnabled(): boolean {\n return getConfig().devMode?.captureOther === true\n}\n","import consola from \"consola\"\n\nimport {\n isCapture4xxEnabled,\n isCapture5xxEnabled,\n isCaptureOtherEnabled,\n} from \"~/lib/dev-mode\"\nimport { getRequestOutboundStore } from \"~/lib/request-outbound\"\n\nexport type CopilotFetchCtx = {\n requestId?: string\n capturable?: boolean\n callSite: string\n}\n\nconst pendingCaptures = new Map<string, PersistInput>()\nconst pendingCapturePromises = new Map<string, Promise<void>>()\n\nexport async function flushPendingCapture(requestId: string): Promise<void> {\n const pending = pendingCaptures.get(requestId)\n if (pending) {\n pendingCaptures.delete(requestId)\n pendingCapturePromises.delete(requestId)\n persistNow(pending)\n return\n }\n const promise = pendingCapturePromises.get(requestId)\n if (promise) {\n await promise\n const deferred = pendingCaptures.get(requestId)\n if (deferred) {\n pendingCaptures.delete(requestId)\n persistNow(deferred)\n }\n pendingCapturePromises.delete(requestId)\n }\n}\n\ntype RequestSnapshot = {\n url: string\n method: string\n headers: Record<string, string>\n body: string | null\n bodyKind: \"json\" | \"text\" | \"binary\"\n}\n\nfunction snapshotHeaders(init: RequestInit): Record<string, string> {\n const headers = init.headers\n if (headers instanceof Headers) {\n const out: Record<string, string> = {}\n for (const [key, value] of headers.entries()) {\n out[key] = value\n }\n return out\n }\n\n if (Array.isArray(headers)) {\n const out: Record<string, string> = {}\n for (const [key, value] of headers) {\n out[key] = value\n }\n return out\n }\n\n const out: Record<string, string> = {}\n for (const [key, value] of Object.entries(\n (headers ?? {}) as Record<string, string>,\n )) {\n out[key] = value\n }\n return out\n}\n\nfunction snapshotBody(init: RequestInit): {\n body: string | null\n bodyKind: \"json\" | \"text\" | \"binary\"\n} {\n const body = init.body\n if (body === null || body === undefined) {\n return { body: null, bodyKind: \"text\" }\n }\n\n if (typeof body === \"string\") {\n try {\n JSON.parse(body)\n return { body, bodyKind: \"json\" }\n } catch {\n return { body, bodyKind: \"text\" }\n }\n }\n\n if (body instanceof Uint8Array) {\n return { body: Buffer.from(body).toString(\"base64\"), bodyKind: \"binary\" }\n }\n\n if (body instanceof ArrayBuffer) {\n return {\n body: Buffer.from(new Uint8Array(body)).toString(\"base64\"),\n bodyKind: \"binary\",\n }\n }\n\n return { body: null, bodyKind: \"text\" }\n}\n\nfunction shouldCaptureStatus(status: number): boolean {\n if (status >= 400 && status < 500) return isCapture4xxEnabled()\n if (status >= 500) return isCapture5xxEnabled()\n return isCaptureOtherEnabled()\n}\n\nexport async function copilotFetch(\n input: string | URL,\n init: RequestInit,\n ctx: CopilotFetchCtx,\n): Promise<Response> {\n const urlString = typeof input === \"string\" ? input : input.toString()\n\n const requestSnapshot: RequestSnapshot = {\n url: urlString,\n method: (init.method ?? \"GET\").toUpperCase(),\n headers: snapshotHeaders(init),\n ...snapshotBody(init),\n }\n\n const response = await fetch(input, init)\n\n const shouldCapture =\n ctx.requestId !== undefined\n && ctx.capturable !== false\n && shouldCaptureStatus(response.status)\n\n if (!shouldCapture) {\n return response\n }\n\n const contentType = response.headers.get(\"content-type\") ?? \"\"\n const isSSE = contentType.includes(\"text/event-stream\")\n const responseHeaders: Record<string, string> = {}\n for (const [key, value] of response.headers.entries()) {\n responseHeaders[key] = value\n }\n\n if (!response.body) {\n storePending({\n requestSnapshot,\n status: response.status,\n responseBody: \"\",\n responseBodyKind: isSSE ? \"sse\" : \"json\",\n responseHeaders,\n ctx,\n })\n return response\n }\n\n const [forClient, forCapture] = response.body.tee()\n\n const capturePromise = (async () => {\n const chunks: Array<Uint8Array> = []\n const reader =\n forCapture.getReader() as ReadableStreamDefaultReader<Uint8Array>\n\n try {\n for (;;) {\n const result = await reader.read()\n if (result.done) {\n break\n }\n\n const value = result.value\n if (value instanceof Uint8Array) {\n chunks.push(value)\n }\n }\n\n const buffer = Buffer.concat(chunks.map((chunk) => Buffer.from(chunk)))\n const text = buffer.toString(\"utf8\")\n let responseBodyKind: \"json\" | \"sse\" | \"text\" = \"text\"\n\n if (isSSE) {\n responseBodyKind = \"sse\"\n } else if (contentType.includes(\"application/json\")) {\n responseBodyKind = \"json\"\n }\n\n storePending({\n requestSnapshot,\n status: response.status,\n responseBody: text,\n responseBodyKind,\n responseHeaders,\n ctx,\n })\n } catch (error) {\n consola.debug(\"copilotFetch capture stream failed\", error)\n }\n })()\n\n if (ctx.requestId) {\n pendingCapturePromises.set(ctx.requestId, capturePromise)\n }\n\n return new Response(forClient, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n })\n}\n\ntype PersistInput = {\n requestSnapshot: RequestSnapshot\n status: number\n responseBody: string\n responseBodyKind: \"json\" | \"sse\" | \"text\"\n responseHeaders: Record<string, string>\n ctx: CopilotFetchCtx\n}\n\nfunction storePending(input: PersistInput): void {\n const id = input.ctx.requestId\n if (!id) return\n pendingCaptures.set(id, input)\n}\n\nfunction persistNow({\n requestSnapshot,\n status,\n responseBody,\n responseBodyKind,\n responseHeaders,\n ctx,\n}: PersistInput): void {\n if (!ctx.requestId) {\n return\n }\n\n try {\n getRequestOutboundStore().insert({\n requestId: ctx.requestId,\n httpStatus: status,\n upstreamUrl: requestSnapshot.url,\n upstreamMethod: requestSnapshot.method,\n requestHeaders: requestSnapshot.headers,\n requestBody: requestSnapshot.body,\n requestBodyKind: requestSnapshot.bodyKind,\n responseStatus: status,\n responseHeaders,\n responseBody,\n responseBodyKind,\n })\n } catch (error) {\n consola.debug(\"copilotFetch persist failed\", error)\n }\n}\n","import consola from \"consola\"\nimport fs from \"node:fs/promises\"\n\nimport type { AccountContext } from \"~/lib/types/account\"\n\nimport { copilotBaseUrl, copilotModelsHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { PATHS } from \"~/lib/paths\"\nimport { accountFromState } from \"~/lib/state\"\n\nimport { copilotFetch } from \"./copilot-fetch\"\n\nexport const getModels = async (\n account?: AccountContext,\n options?: {\n requestId?: string\n },\n) => {\n const ctx = account ?? accountFromState()\n const response = await copilotFetch(\n `${copilotBaseUrl(ctx)}/models`,\n {\n headers: copilotModelsHeaders(ctx),\n },\n {\n requestId: options?.requestId,\n callSite: \"models\",\n capturable: false,\n },\n )\n\n if (!response.ok) {\n const errorText = await response.clone().text()\n\n consola.error(\"Failed to get models response body\", errorText)\n\n throw new HTTPError(\"Failed to get models\", response)\n }\n\n const models = (await response.json()) as ModelsResponse\n\n // Persist models response for debugging/inspection.\n // Best effort: do not fail startup if the local write fails.\n try {\n await fs.mkdir(PATHS.APP_DIR, { recursive: true })\n await fs.writeFile(\n PATHS.MODELS_PATH,\n `${JSON.stringify(models, null, 2)}\\n`,\n {\n encoding: \"utf8\",\n mode: 0o600,\n },\n )\n } catch {\n // ignore\n }\n\n return models\n}\n\nexport interface ModelsResponse {\n data: Array<Model>\n object: string\n}\n\ninterface ModelLimits {\n max_context_window_tokens?: number\n max_output_tokens?: number\n max_prompt_tokens?: number\n max_inputs?: number\n}\n\ninterface ModelSupports {\n max_thinking_budget?: number\n min_thinking_budget?: number\n tool_calls?: boolean\n parallel_tool_calls?: boolean\n dimensions?: boolean\n streaming?: boolean\n structured_outputs?: boolean\n vision?: boolean\n adaptive_thinking?: boolean\n reasoning_effort?: Array<string>\n}\n\ninterface ModelCapabilities {\n family: string\n limits: ModelLimits\n object: string\n supports: ModelSupports\n tokenizer: string\n type: string\n}\n\ninterface ModelBilling {\n is_premium?: boolean\n multiplier?: number\n}\n\nexport interface Model {\n billing?: ModelBilling\n capabilities: ModelCapabilities\n id: string\n model_picker_enabled: boolean\n name: string\n object: string\n preview: boolean\n vendor: string\n version: string\n policy?: {\n state: string\n terms: string\n }\n supported_endpoints?: Array<string>\n}\n","import consola from \"consola\"\n\nimport type {\n AccountContext,\n AccountRuntime,\n AccountType,\n} from \"~/lib/types/account\"\nimport type { QuotaDetail } from \"~/services/github/get-copilot-usage\"\n\nexport type AuthSnapshot = Readonly<{\n githubToken: string\n accountType: AccountType\n}>\n\nexport const takeAuthSnapshot = (account: AccountRuntime): AuthSnapshot => ({\n githubToken: account.githubToken,\n accountType: account.accountType,\n})\n\nexport const isAuthSnapshotCurrent = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n): boolean =>\n account.githubToken === snapshot.githubToken\n && account.accountType === snapshot.accountType\n\nexport const isSameAuthSnapshot = (\n a: AuthSnapshot | undefined,\n b: AuthSnapshot,\n): boolean => {\n if (!a) return false\n return a.githubToken === b.githubToken && a.accountType === b.accountType\n}\n\nexport const toAccountContextFromSnapshot = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n copilotToken?: string,\n): AccountContext => ({\n accountLogin: account.accountLogin,\n githubToken: snapshot.githubToken,\n copilotToken,\n ...(account.copilotApiUrl !== undefined ?\n { copilotApiUrl: account.copilotApiUrl }\n : {}),\n accountType: snapshot.accountType,\n vsCodeVersion: account.vsCodeVersion,\n clientDeviceId: account.clientDeviceId,\n clientMachineId: account.clientMachineId,\n clientSessionId: account.clientSessionId,\n})\n\nexport const applyCopilotTokenIfCurrent = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n copilotToken: string,\n): boolean => {\n if (!isAuthSnapshotCurrent(account, snapshot)) {\n return false\n }\n\n account.copilotToken = copilotToken\n return true\n}\n\nexport const applyModelsIfCurrent = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n models: AccountRuntime[\"models\"],\n): boolean => {\n if (!isAuthSnapshotCurrent(account, snapshot)) {\n return false\n }\n\n account.models = models\n return true\n}\n\nexport const applyTokenRefreshSuccessIfCurrent = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n token: string,\n): boolean => {\n if (!isAuthSnapshotCurrent(account, snapshot)) {\n return false\n }\n\n account.copilotToken = token\n account.failed = false\n account.failureReason = undefined\n return true\n}\n\nexport const applyTokenRefreshFailureIfCurrent = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n error: unknown,\n): boolean => {\n if (!isAuthSnapshotCurrent(account, snapshot)) {\n return false\n }\n\n account.failed = true\n account.failureReason = String(error)\n return true\n}\n\nexport const applyQuotaRefreshSuccessIfCurrent = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n result: {\n premium: QuotaDetail\n copilotApiUrl?: string\n },\n): boolean => {\n if (!isAuthSnapshotCurrent(account, snapshot)) {\n return false\n }\n\n const { premium, copilotApiUrl } = result\n\n account.premiumEntitlement = premium.entitlement\n account.premiumRemaining = premium.remaining\n account.unlimited = premium.unlimited\n account.overagePermitted = premium.overage_permitted\n if (copilotApiUrl) {\n account.copilotApiUrl = copilotApiUrl\n }\n account.lastQuotaFetch = Date.now()\n account.failed = false\n account.failureReason = undefined\n return true\n}\n\nexport const setAccountFailedState = (\n account: AccountRuntime,\n reason: string,\n): void => {\n account.failed = true\n account.failureReason = reason\n consola.warn(`Account ${account.id} marked as failed: ${reason}`)\n}\n\nexport const applyUnauthorizedIfCurrent = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n reason: string,\n): boolean => {\n if (!isAuthSnapshotCurrent(account, snapshot)) {\n return false\n }\n\n setAccountFailedState(account, reason)\n return true\n}\n","import type { AccountRuntime } from \"~/lib/types/account\"\nimport type { Model } from \"~/services/copilot/get-models\"\n\nexport type QuotaReservation = Readonly<{ id: symbol }>\n\nexport const getCostUnits = (model: Model): number => {\n // Per user decision: missing billing => treat as free (costUnits = 0)\n const billing = model.billing\n if (!billing) {\n return 0\n }\n\n if (billing.is_premium !== true) {\n return 0\n }\n\n const multiplier = billing.multiplier\n if (\n typeof multiplier !== \"number\"\n || !Number.isFinite(multiplier)\n || multiplier <= 0\n ) {\n return 1\n }\n\n return multiplier\n}\n\nexport const getEffectivePremiumRemaining = (\n account: AccountRuntime,\n): number | undefined => {\n if (account.premiumRemaining === undefined) {\n return undefined\n }\n\n const reserved = account.premiumReserved ?? 0\n return account.premiumRemaining - reserved\n}\n\nexport const reservePremiumUnits = (\n account: AccountRuntime,\n units: number,\n): QuotaReservation | undefined => {\n if (units <= 0) {\n return undefined\n }\n\n const id = Symbol(\"quotaReservation\")\n\n if (!account.premiumReservations) {\n account.premiumReservations = new Map()\n }\n\n account.premiumReservations.set(id, units)\n account.premiumReserved = (account.premiumReserved ?? 0) + units\n\n return { id }\n}\n\nexport const releasePremiumReservation = (\n account: AccountRuntime,\n reservation?: QuotaReservation,\n): void => {\n if (!reservation) {\n return\n }\n\n const reservations = account.premiumReservations\n if (!reservations) {\n return\n }\n\n const reservedUnits = reservations.get(reservation.id)\n if (reservedUnits === undefined) {\n return\n }\n\n reservations.delete(reservation.id)\n\n const nextReserved = (account.premiumReserved ?? 0) - reservedUnits\n account.premiumReserved = Math.max(0, nextReserved)\n\n if (reservations.size === 0) {\n account.premiumReservations = undefined\n }\n}\n","import type { Database } from \"bun:sqlite\"\n\nimport { consola } from \"consola\"\n\nexport interface DailyStats {\n date: string\n request_count: number\n premium_consumed: number\n tokens_total: number\n error_count: number\n}\n\nexport interface DailyAccountStats extends DailyStats {\n account_id: string\n}\n\nexport interface PremiumStatsResponse {\n daily: Array<DailyStats>\n by_account: Array<DailyAccountStats>\n range: { from: string; to: string; granularity: \"day\" | \"hour\" }\n}\n\nexport const DEFAULT_STATS_RETENTION_DAYS = 180\n\nexport function toLocalDateString(ms: number): string {\n const d = new Date(ms)\n return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, \"0\")}-${String(d.getDate()).padStart(2, \"0\")}`\n}\n\nexport class StatsStore {\n private readonly db: Database\n private readonly upsertStmt: ReturnType<Database[\"query\"]>\n private readonly insertSnapshotStmt: ReturnType<Database[\"query\"]>\n\n constructor(db: Database) {\n this.db = db\n this.upsertStmt = db.query(`\n INSERT INTO daily_premium_stats\n (date, account_id, request_count, cost_units_sum, tokens_total, error_count, updated_at_ms)\n VALUES (?, ?, 1, ?, ?, ?, ?)\n ON CONFLICT(date, account_id) DO UPDATE SET\n request_count = request_count + 1,\n cost_units_sum = cost_units_sum + excluded.cost_units_sum,\n tokens_total = tokens_total + excluded.tokens_total,\n error_count = error_count + excluded.error_count,\n updated_at_ms = excluded.updated_at_ms\n `)\n this.insertSnapshotStmt = db.query(`\n INSERT INTO quota_snapshots\n (account_id, snapshot_at_ms, remaining, entitlement, unlimited, source)\n VALUES (?, ?, ?, ?, ?, ?)\n `)\n }\n\n upsertDailyStats(record: {\n startedAtMs: number\n accountId: string\n costUnits: number\n tokensTotal: number\n hasError: boolean\n }): void {\n const date = toLocalDateString(record.startedAtMs)\n this.upsertStmt.run(\n date,\n record.accountId,\n record.costUnits,\n record.tokensTotal,\n record.hasError ? 1 : 0,\n Date.now(),\n )\n }\n\n insertQuotaSnapshot(record: {\n accountId: string\n snapshotAtMs: number\n remaining: number\n entitlement: number\n unlimited: boolean\n source: string\n }): void {\n this.insertSnapshotStmt.run(\n record.accountId,\n record.snapshotAtMs,\n record.remaining,\n record.entitlement,\n record.unlimited ? 1 : 0,\n record.source,\n )\n }\n\n getConsumptionFromSnapshots(params: {\n fromMs: number\n toMs: number\n granularity: \"day\" | \"hour\"\n accountId?: string\n }): Array<{ date: string; account_id: string; premium_consumed: number }> {\n const dateExpr =\n params.granularity === \"hour\" ?\n \"strftime('%Y-%m-%dT%H:00:00Z', snapshot_at_ms / 1000, 'unixepoch')\"\n : \"date(snapshot_at_ms / 1000, 'unixepoch', 'localtime')\"\n\n const accountFilter = params.accountId ? \" AND account_id = ?\" : \"\"\n const args: Array<string | number> = []\n\n // baseline CTE: WHERE snapshot_at_ms < ?\n args.push(params.fromMs)\n // baseline CTE: AND account_id = ? (if filtered)\n if (params.accountId) args.push(params.accountId)\n\n // all_snaps CTE: WHERE snapshot_at_ms >= ? AND snapshot_at_ms <= ?\n args.push(params.fromMs, params.toMs)\n // all_snaps CTE: AND account_id = ? (if filtered)\n if (params.accountId) args.push(params.accountId)\n\n // outer WHERE: snapshot_at_ms >= ?\n args.push(params.fromMs)\n\n return this.db\n .query(\n `WITH baseline AS (\n SELECT qs.account_id, qs.snapshot_at_ms, qs.remaining, qs.id\n FROM quota_snapshots qs\n INNER JOIN (\n SELECT account_id, MAX(snapshot_at_ms) AS max_ts\n FROM quota_snapshots\n WHERE snapshot_at_ms < ?\n AND unlimited = 0${accountFilter}\n GROUP BY account_id\n ) latest ON qs.account_id = latest.account_id\n AND qs.snapshot_at_ms = latest.max_ts\n ),\n all_snaps AS (\n SELECT account_id, snapshot_at_ms, remaining, id\n FROM baseline\n UNION ALL\n SELECT account_id, snapshot_at_ms, remaining, id\n FROM quota_snapshots\n WHERE snapshot_at_ms >= ? AND snapshot_at_ms <= ?\n AND unlimited = 0${accountFilter}\n ),\n with_prev AS (\n SELECT\n account_id,\n snapshot_at_ms,\n remaining,\n LAG(remaining) OVER (\n PARTITION BY account_id ORDER BY snapshot_at_ms, id\n ) AS prev_remaining\n FROM all_snaps\n )\n SELECT\n ${dateExpr} AS date,\n account_id,\n SUM(\n CASE WHEN prev_remaining IS NOT NULL AND prev_remaining > remaining\n THEN prev_remaining - remaining\n ELSE 0\n END\n ) AS premium_consumed\n FROM with_prev\n WHERE snapshot_at_ms >= ?\n GROUP BY 1, 2\n ORDER BY 1, 2`,\n )\n .all(...args) as Array<{\n date: string\n account_id: string\n premium_consumed: number\n }>\n }\n\n getDailyPremiumStats(params: {\n from: string\n to: string\n accountId?: string\n }): { daily: Array<DailyStats>; byAccount: Array<DailyAccountStats> } {\n const accountFilter = params.accountId ? \" AND account_id = ?\" : \"\"\n const args: Array<string | number> = [params.from, params.to]\n if (params.accountId) args.push(params.accountId)\n\n const dailyMetrics = this.db\n .query(\n `SELECT date,\n SUM(request_count) AS request_count,\n SUM(tokens_total) AS tokens_total,\n SUM(error_count) AS error_count\n FROM daily_premium_stats\n WHERE date >= ? AND date <= ?${accountFilter}\n GROUP BY date\n ORDER BY date`,\n )\n .all(...args) as Array<{\n date: string\n request_count: number\n tokens_total: number\n error_count: number\n }>\n\n const byAccountMetrics = this.db\n .query(\n `SELECT date, account_id, request_count, tokens_total, error_count\n FROM daily_premium_stats\n WHERE date >= ? AND date <= ?${accountFilter}\n ORDER BY date, account_id`,\n )\n .all(...args) as Array<{\n date: string\n account_id: string\n request_count: number\n tokens_total: number\n error_count: number\n }>\n\n const fromMs = this.localDateToMs(params.from)\n const toMs = this.localDateEndMs(params.to)\n\n const consumption = this.getConsumptionFromSnapshots({\n fromMs,\n toMs,\n granularity: \"day\",\n accountId: params.accountId,\n })\n\n return this.mergeMetricsAndConsumption(\n dailyMetrics,\n byAccountMetrics,\n consumption,\n )\n }\n\n getHourlyPremiumStats(params: {\n fromMs: number\n toMs: number\n accountId?: string\n }): { daily: Array<DailyStats>; byAccount: Array<DailyAccountStats> } {\n const accountFilter = params.accountId ? \" AND account_id = ?\" : \"\"\n const dailyArgs: Array<string | number> = [params.fromMs, params.toMs]\n if (params.accountId) dailyArgs.push(params.accountId)\n\n const dailyMetrics = this.db\n .query(\n `SELECT strftime('%Y-%m-%dT%H:00:00Z', started_at_ms / 1000, 'unixepoch') AS date,\n COUNT(*) AS request_count,\n COALESCE(SUM(tokens_total), 0) AS tokens_total,\n SUM(CASE WHEN error_name IS NOT NULL THEN 1 ELSE 0 END) AS error_count\n FROM request_log\n WHERE cost_units > 0\n AND started_at_ms >= ? AND started_at_ms <= ?${accountFilter}\n GROUP BY 1\n ORDER BY 1`,\n )\n .all(...dailyArgs) as Array<{\n date: string\n request_count: number\n tokens_total: number\n error_count: number\n }>\n\n const byAccountFilter =\n params.accountId ? \" AND account_id = ?\" : \" AND account_id IS NOT NULL\"\n const byAccountArgs: Array<string | number> = [params.fromMs, params.toMs]\n if (params.accountId) byAccountArgs.push(params.accountId)\n\n const byAccountMetrics = this.db\n .query(\n `SELECT strftime('%Y-%m-%dT%H:00:00Z', started_at_ms / 1000, 'unixepoch') AS date,\n account_id,\n COUNT(*) AS request_count,\n COALESCE(SUM(tokens_total), 0) AS tokens_total,\n SUM(CASE WHEN error_name IS NOT NULL THEN 1 ELSE 0 END) AS error_count\n FROM request_log\n WHERE cost_units > 0\n AND started_at_ms >= ? AND started_at_ms <= ?${byAccountFilter}\n GROUP BY 1, 2\n ORDER BY 1, 2`,\n )\n .all(...byAccountArgs) as Array<{\n date: string\n account_id: string\n request_count: number\n tokens_total: number\n error_count: number\n }>\n\n const consumption = this.getConsumptionFromSnapshots({\n fromMs: params.fromMs,\n toMs: params.toMs,\n granularity: \"hour\",\n accountId: params.accountId,\n })\n\n return this.mergeMetricsAndConsumption(\n dailyMetrics,\n byAccountMetrics,\n consumption,\n )\n }\n\n cleanupStatsRetention(\n retentionDays: number = DEFAULT_STATS_RETENTION_DAYS,\n ): void {\n try {\n const nowMs = Date.now()\n const cutoffMs = nowMs - retentionDays * 24 * 60 * 60 * 1000\n const cutoffDate = toLocalDateString(cutoffMs)\n this.db\n .query(\"DELETE FROM daily_premium_stats WHERE date < ?;\")\n .run(cutoffDate)\n\n // Keep the latest snapshot per account before the cutoff as baseline\n // for getConsumptionFromSnapshots() which needs a pre-range reference.\n this.db\n .query(\n `DELETE FROM quota_snapshots\n WHERE snapshot_at_ms < ?\n AND id NOT IN (\n SELECT qs.id\n FROM quota_snapshots qs\n INNER JOIN (\n SELECT account_id, MAX(snapshot_at_ms) AS max_ts\n FROM quota_snapshots\n WHERE snapshot_at_ms < ?\n GROUP BY account_id\n ) latest ON qs.account_id = latest.account_id\n AND qs.snapshot_at_ms = latest.max_ts\n );`,\n )\n .run(cutoffMs, cutoffMs)\n } catch (error) {\n consola.debug(\"Failed to cleanup stats retention\", error)\n }\n }\n\n private localDateToMs(dateStr: string): number {\n const [y, m, d] = dateStr.split(\"-\").map(Number)\n return new Date(y, m - 1, d).getTime()\n }\n\n /** End-of-day ms (next local midnight - 1ms), DST-safe. */\n private localDateEndMs(dateStr: string): number {\n const [y, m, d] = dateStr.split(\"-\").map(Number)\n return new Date(y, m - 1, d + 1).getTime() - 1\n }\n\n private mergeMetricsAndConsumption(\n dailyMetrics: Array<{\n date: string\n request_count: number\n tokens_total: number\n error_count: number\n }>,\n byAccountMetrics: Array<{\n date: string\n account_id: string\n request_count: number\n tokens_total: number\n error_count: number\n }>,\n consumption: Array<{\n date: string\n account_id: string\n premium_consumed: number\n }>,\n ): { daily: Array<DailyStats>; byAccount: Array<DailyAccountStats> } {\n const consumptionMap = new Map<string, number>()\n const dateConsumptionMap = new Map<string, number>()\n for (const c of consumption) {\n consumptionMap.set(`${c.date}|${c.account_id}`, c.premium_consumed)\n dateConsumptionMap.set(\n c.date,\n (dateConsumptionMap.get(c.date) ?? 0) + c.premium_consumed,\n )\n }\n\n const allDates = new Set([\n ...dailyMetrics.map((m) => m.date),\n ...consumption.map((c) => c.date),\n ])\n const metricsMap = new Map(dailyMetrics.map((m) => [m.date, m]))\n\n const daily: Array<DailyStats> = [...allDates].sort().map((date) => {\n const m = metricsMap.get(date)\n return {\n date,\n request_count: m?.request_count ?? 0,\n premium_consumed: dateConsumptionMap.get(date) ?? 0,\n tokens_total: m?.tokens_total ?? 0,\n error_count: m?.error_count ?? 0,\n }\n })\n\n const allAccountDateKeys = new Set([\n ...byAccountMetrics.map((m) => `${m.date}|${m.account_id}`),\n ...consumption.map((c) => `${c.date}|${c.account_id}`),\n ])\n const byAccountMetricsMap = new Map(\n byAccountMetrics.map((m) => [`${m.date}|${m.account_id}`, m]),\n )\n\n const byAccount: Array<DailyAccountStats> = [...allAccountDateKeys]\n .sort()\n .map((key) => {\n const [date, account_id] = key.split(\"|\")\n const m = byAccountMetricsMap.get(key)\n return {\n date,\n account_id,\n request_count: m?.request_count ?? 0,\n premium_consumed: consumptionMap.get(key) ?? 0,\n tokens_total: m?.tokens_total ?? 0,\n error_count: m?.error_count ?? 0,\n }\n })\n\n return { daily, byAccount }\n }\n}\n","import type { Database, SQLQueryBindings } from \"bun:sqlite\"\nimport type { Context } from \"hono\"\n\nimport consola from \"consola\"\n\nimport type {\n ChatCompletionChunk,\n ChatCompletionResponse,\n} from \"~/services/copilot/create-chat-completions\"\nimport type { EmbeddingResponse } from \"~/services/copilot/create-embeddings\"\nimport type {\n ResponseStreamEvent,\n ResponsesResult,\n ResponseUsage,\n} from \"~/services/copilot/create-responses\"\n\nimport type { AccountSelectionReason } from \"./accounts-manager\"\nimport type { AffinityKeySource } from \"./utils\"\n\nimport { getAdminDb, getAdminDbPath, getAdminDbUserVersion } from \"./admin-db\"\nimport { consumeOutboundHeadersSnapshot } from \"./request-context\"\nimport { StatsStore } from \"./stats-store\"\n\nconst DEFAULT_RETENTION_DAYS = 35\nconst DEFAULT_MAX_ROWS = 200_000\n\nconst INSERT_WARN_THROTTLE_MS = 30_000\n\nlet lastInsertWarnAtMs = 0\nlet suppressedInsertWarnCount = 0\n\nfunction warnInsertFailure(error: unknown): void {\n const now = Date.now()\n\n if (now - lastInsertWarnAtMs < INSERT_WARN_THROTTLE_MS) {\n suppressedInsertWarnCount++\n return\n }\n\n const suppressed = suppressedInsertWarnCount\n suppressedInsertWarnCount = 0\n lastInsertWarnAtMs = now\n\n const suffix =\n suppressed > 0 ? ` (suppressed ${suppressed} similar errors)` : \"\"\n consola.warn(`Failed to insert request log${suffix}`, error)\n}\n\nfunction toDbNull<T>(value: T | null | undefined): T | null {\n return value === undefined ? null : value\n}\n\nfunction toDbBool(value: boolean | undefined): 0 | 1 | null {\n if (value === true) return 1\n if (value === false) return 0\n return null\n}\n\nexport type ClientIpInfo = {\n ip?: string\n source?: string\n}\n\nexport function getClientIpInfo(c: Context): ClientIpInfo {\n const cf = c.req.header(\"cf-connecting-ip\")\n if (cf) return { ip: cf.trim(), source: \"cf-connecting-ip\" }\n\n const xff = c.req.header(\"x-forwarded-for\")\n if (xff) {\n const first = xff.split(\",\")[0]?.trim()\n if (first) return { ip: first, source: \"x-forwarded-for\" }\n }\n\n const xri = c.req.header(\"x-real-ip\")\n if (xri) return { ip: xri.trim(), source: \"x-real-ip\" }\n\n return {}\n}\n\nexport type NormalizedUsage = {\n tokensInput?: number\n tokensOutput?: number\n tokensTotal?: number\n tokensCachedInput?: number\n usageJson?: string\n}\n\nexport function normalizeChatCompletionsUsage(\n usage?: ChatCompletionResponse[\"usage\"] | ChatCompletionChunk[\"usage\"],\n): NormalizedUsage {\n if (!usage) return {}\n\n const cached = usage.prompt_tokens_details?.cached_tokens ?? 0\n const prompt = usage.prompt_tokens\n const completion = usage.completion_tokens\n const total = usage.total_tokens\n\n return {\n tokensCachedInput: cached,\n tokensInput: Math.max(0, prompt - cached),\n tokensOutput: completion,\n tokensTotal: total,\n usageJson: JSON.stringify(usage),\n }\n}\n\nexport function normalizeResponsesUsage(\n usage?: ResponseUsage | null,\n): NormalizedUsage {\n if (!usage) return {}\n\n const cached = usage.input_tokens_details?.cached_tokens ?? 0\n const input = usage.input_tokens\n const output = usage.output_tokens ?? 0\n const total = usage.total_tokens\n\n return {\n tokensCachedInput: cached,\n tokensInput: Math.max(0, input - cached),\n tokensOutput: output,\n tokensTotal: total,\n usageJson: JSON.stringify(usage),\n }\n}\n\ntype AnthropicUsage = {\n input_tokens?: number\n output_tokens?: number\n cache_creation_input_tokens?: number\n cache_read_input_tokens?: number\n service_tier?: \"standard\" | \"priority\" | \"batch\"\n}\n\nexport function normalizeMessagesUsage(\n usage?: AnthropicUsage | null,\n): NormalizedUsage {\n if (!usage) return {}\n\n const cached = usage.cache_read_input_tokens ?? 0\n const input = usage.input_tokens\n const output = usage.output_tokens\n const hasInput = typeof input === \"number\"\n const hasOutput = typeof output === \"number\"\n const tokensInput = hasInput ? Math.max(0, input - cached) : undefined\n const tokensOutput = hasOutput ? output : undefined\n const tokensTotal =\n hasInput || hasOutput ? (input ?? 0) + (output ?? 0) : undefined\n\n return {\n tokensCachedInput: cached,\n tokensInput,\n tokensOutput,\n tokensTotal,\n usageJson: JSON.stringify(usage),\n }\n}\n\nexport function normalizeEmbeddingsUsage(\n usage?: EmbeddingResponse[\"usage\"],\n): NormalizedUsage {\n if (!usage) return {}\n\n return {\n tokensCachedInput: 0,\n tokensInput: usage.prompt_tokens,\n tokensOutput: 0,\n tokensTotal: usage.total_tokens,\n usageJson: JSON.stringify(usage),\n }\n}\n\nexport type RequestLogInsert = {\n requestId: string\n startedAtMs: number\n finishedAtMs?: number\n durationMs?: number\n ttfbMs?: number\n\n method: string\n path: string\n upstreamEndpoint?: string\n stream: boolean\n\n accountId?: string\n accountType?: string\n costUnits?: number\n clientModel?: string\n upstreamModel?: string\n\n clientIp?: string\n clientIpSource?: string\n userAgent?: string\n\n userId?: string\n safetyIdentifier?: string\n promptCacheKey?: string\n initiator?: \"agent\" | \"user\"\n isSubagent?: boolean\n upstreamRequestId?: string\n outboundXRequestId?: string\n outboundXAgentTaskId?: string\n outboundXInteractionId?: string\n outboundXInteractionType?: string\n outboundOpenaiIntent?: string\n outboundUserAgent?: string\n affinityKeyUsed?: string\n affinityKeySource?: AffinityKeySource\n selectionReason?: AccountSelectionReason\n\n tokensInput?: number\n tokensOutput?: number\n tokensTotal?: number\n tokensCachedInput?: number\n usageJson?: string\n\n premiumRemainingBefore?: number\n premiumRemainingAfter?: number\n premiumRemainingDiff?: number\n premiumUnlimitedBefore?: boolean\n premiumUnlimitedAfter?: boolean\n\n httpStatus?: number\n errorName?: string\n errorStatus?: number\n errorMessage?: string\n upstreamErrorMessageRaw?: string\n selectionFailureReason?: string\n\n affinityHit?: boolean\n affinityCacheKey?: string\n}\n\nexport type RequestLogRow = {\n id: number\n request_id: string\n started_at_ms: number\n finished_at_ms: number | null\n duration_ms: number | null\n ttfb_ms: number | null\n\n method: string\n path: string\n upstream_endpoint: string | null\n stream: number\n\n account_id: string | null\n account_type: string | null\n cost_units: number | null\n client_model: string | null\n upstream_model: string | null\n\n client_ip: string | null\n client_ip_source: string | null\n user_agent: string | null\n\n user_id: string | null\n safety_identifier: string | null\n prompt_cache_key: string | null\n initiator: string | null\n is_subagent: number | null\n upstream_request_id: string | null\n outbound_x_request_id: string | null\n outbound_x_agent_task_id: string | null\n outbound_x_interaction_id: string | null\n outbound_x_interaction_type: string | null\n outbound_openai_intent: string | null\n outbound_user_agent: string | null\n affinity_key_used: string | null\n affinity_key_source: string | null\n selection_reason: string | null\n\n tokens_input: number | null\n tokens_output: number | null\n tokens_total: number | null\n tokens_cached_input: number | null\n usage_json: string | null\n\n premium_remaining_before: number | null\n premium_remaining_after: number | null\n premium_remaining_diff: number | null\n premium_unlimited_before: number | null\n premium_unlimited_after: number | null\n\n http_status: number | null\n error_name: string | null\n error_status: number | null\n error_message: string | null\n upstream_error_message_raw: string | null\n selection_failure_reason: string | null\n\n affinity_hit: number | null\n affinity_cache_key: string | null\n}\n\nexport type RequestLogQuery = {\n limit: number\n cursorId?: number\n\n accountId?: string\n upstreamModel?: string\n clientModel?: string\n upstreamEndpoint?: string\n path?: string\n status?: number\n hasError?: boolean\n fromMs?: number\n toMs?: number\n}\n\nexport type SessionUsageKey = {\n promptCacheKey: string\n safetyIdentifier: string\n clientModel: string\n}\n\nexport type RequestLogQueryResult = {\n items: Array<RequestLogRow>\n nextCursorId?: number\n hasMore: boolean\n}\n\nexport type AccountStatsRow = {\n account_id: string\n request_count: number\n error_count: number\n tokens_total: number\n avg_duration_ms: number\n last_request_at_ms: number\n}\n\nfunction pickRecordedHeader(\n explicitValue: string | undefined,\n snapshotValue: string | undefined,\n): string | undefined {\n return explicitValue ?? snapshotValue\n}\n\nfunction buildInsertArgs(record: RequestLogInsert) {\n const outboundHeadersSnapshot = consumeOutboundHeadersSnapshot()\n const recordedOutboundHeaders = {\n xRequestId: pickRecordedHeader(\n record.outboundXRequestId,\n outboundHeadersSnapshot?.xRequestId,\n ),\n xAgentTaskId: pickRecordedHeader(\n record.outboundXAgentTaskId,\n outboundHeadersSnapshot?.xAgentTaskId,\n ),\n xInteractionId: pickRecordedHeader(\n record.outboundXInteractionId,\n outboundHeadersSnapshot?.xInteractionId,\n ),\n xInteractionType: pickRecordedHeader(\n record.outboundXInteractionType,\n outboundHeadersSnapshot?.xInteractionType,\n ),\n openaiIntent: pickRecordedHeader(\n record.outboundOpenaiIntent,\n outboundHeadersSnapshot?.openaiIntent,\n ),\n userAgent: pickRecordedHeader(\n record.outboundUserAgent,\n outboundHeadersSnapshot?.userAgent,\n ),\n }\n\n return [\n record.requestId,\n record.startedAtMs,\n toDbNull(record.finishedAtMs),\n toDbNull(record.durationMs),\n toDbNull(record.ttfbMs),\n\n record.method,\n record.path,\n toDbNull(record.upstreamEndpoint),\n record.stream ? 1 : 0,\n\n toDbNull(record.accountId),\n toDbNull(record.accountType),\n toDbNull(record.costUnits),\n toDbNull(record.clientModel),\n toDbNull(record.upstreamModel),\n\n toDbNull(record.clientIp),\n toDbNull(record.clientIpSource),\n toDbNull(record.userAgent),\n toDbNull(record.userId),\n toDbNull(record.safetyIdentifier),\n toDbNull(record.promptCacheKey),\n toDbNull(record.initiator),\n toDbBool(record.isSubagent),\n toDbNull(record.upstreamRequestId),\n toDbNull(recordedOutboundHeaders.xRequestId),\n toDbNull(recordedOutboundHeaders.xAgentTaskId),\n toDbNull(recordedOutboundHeaders.xInteractionId),\n toDbNull(recordedOutboundHeaders.xInteractionType),\n toDbNull(recordedOutboundHeaders.openaiIntent),\n toDbNull(recordedOutboundHeaders.userAgent),\n toDbNull(record.affinityKeyUsed),\n toDbNull(record.affinityKeySource),\n toDbNull(record.selectionReason),\n\n toDbNull(record.tokensInput),\n toDbNull(record.tokensOutput),\n toDbNull(record.tokensTotal),\n toDbNull(record.tokensCachedInput),\n toDbNull(record.usageJson),\n\n toDbNull(record.premiumRemainingBefore),\n toDbNull(record.premiumRemainingAfter),\n toDbNull(record.premiumRemainingDiff),\n toDbBool(record.premiumUnlimitedBefore),\n toDbBool(record.premiumUnlimitedAfter),\n\n toDbNull(record.httpStatus),\n toDbNull(record.errorName),\n toDbNull(record.errorStatus),\n toDbNull(record.errorMessage),\n toDbNull(record.upstreamErrorMessageRaw),\n toDbNull(record.selectionFailureReason),\n\n toDbBool(record.affinityHit),\n toDbNull(record.affinityCacheKey),\n ] as const\n}\n\nexport class RequestHistoryStore {\n private readonly db: Database\n private readonly insertStmt: ReturnType<Database[\"query\"]>\n\n private readonly getByRequestIdStmt: ReturnType<Database[\"query\"]>\n private readonly getLastCompletedUsageBySessionStmt: ReturnType<\n Database[\"query\"]\n >\n\n constructor(db: Database) {\n this.db = db\n\n const insertColumns = [\n \"request_id\",\n \"started_at_ms\",\n \"finished_at_ms\",\n \"duration_ms\",\n \"ttfb_ms\",\n \"method\",\n \"path\",\n \"upstream_endpoint\",\n \"stream\",\n \"account_id\",\n \"account_type\",\n \"cost_units\",\n \"client_model\",\n \"upstream_model\",\n \"client_ip\",\n \"client_ip_source\",\n \"user_agent\",\n \"user_id\",\n \"safety_identifier\",\n \"prompt_cache_key\",\n \"initiator\",\n \"is_subagent\",\n \"upstream_request_id\",\n \"outbound_x_request_id\",\n \"outbound_x_agent_task_id\",\n \"outbound_x_interaction_id\",\n \"outbound_x_interaction_type\",\n \"outbound_openai_intent\",\n \"outbound_user_agent\",\n \"affinity_key_used\",\n \"affinity_key_source\",\n \"selection_reason\",\n \"tokens_input\",\n \"tokens_output\",\n \"tokens_total\",\n \"tokens_cached_input\",\n \"usage_json\",\n \"premium_remaining_before\",\n \"premium_remaining_after\",\n \"premium_remaining_diff\",\n \"premium_unlimited_before\",\n \"premium_unlimited_after\",\n \"http_status\",\n \"error_name\",\n \"error_status\",\n \"error_message\",\n \"upstream_error_message_raw\",\n \"selection_failure_reason\",\n \"affinity_hit\",\n \"affinity_cache_key\",\n ]\n\n this.insertStmt = db.query(`\n INSERT INTO request_log (${insertColumns.join(\", \")})\n VALUES (${insertColumns.map(() => \"?\").join(\", \")});\n `)\n\n this.getByRequestIdStmt = db.query(\n \"SELECT * FROM request_log WHERE request_id = ? LIMIT 1;\",\n )\n\n this.getLastCompletedUsageBySessionStmt = db.query(`\n SELECT\n tokens_input,\n tokens_output,\n tokens_total,\n tokens_cached_input\n FROM request_log\n WHERE prompt_cache_key = ?\n AND safety_identifier = ?\n AND client_model = ?\n AND finished_at_ms IS NOT NULL\n AND tokens_input IS NOT NULL\n ORDER BY finished_at_ms DESC\n LIMIT 1;\n `)\n }\n\n insert(record: RequestLogInsert): void {\n try {\n const args = buildInsertArgs(record)\n\n this.insertStmt.run(...args)\n\n // Write-time aggregation for premium stats\n if (\n record.costUnits !== undefined\n && record.costUnits > 0\n && record.accountId\n ) {\n try {\n getStatsStoreInstance()?.upsertDailyStats({\n startedAtMs: record.startedAtMs,\n accountId: record.accountId,\n costUnits: record.costUnits,\n tokensTotal: record.tokensTotal ?? 0,\n hasError: record.errorName !== undefined,\n })\n } catch {\n // Stats aggregation is best-effort; never break request logging\n }\n }\n } catch (error) {\n warnInsertFailure(error)\n }\n }\n\n getByRequestId(requestId: string): RequestLogRow | null {\n try {\n const row = this.getByRequestIdStmt.get(requestId) as\n | RequestLogRow\n | null\n | undefined\n return row ?? null\n } catch (error) {\n consola.debug(\"Failed to fetch request log by request_id\", error)\n return null\n }\n }\n\n getLastCompletedUsageBySession(\n session: SessionUsageKey,\n ): NormalizedUsage | null {\n if (\n !session.promptCacheKey\n || !session.safetyIdentifier\n || !session.clientModel\n ) {\n return null\n }\n\n try {\n const row = this.getLastCompletedUsageBySessionStmt.get(\n session.promptCacheKey,\n session.safetyIdentifier,\n session.clientModel,\n ) as\n | {\n tokens_input: number | null\n tokens_output: number | null\n tokens_total: number | null\n tokens_cached_input: number | null\n }\n | null\n | undefined\n\n if (!row || row.tokens_input === null) {\n return null\n }\n\n const tokensOutput =\n row.tokens_output === null ? undefined : row.tokens_output\n const tokensTotal =\n row.tokens_total === null ? undefined : row.tokens_total\n const tokensCachedInput =\n row.tokens_cached_input === null ? undefined : row.tokens_cached_input\n\n return {\n tokensInput: row.tokens_input,\n tokensOutput,\n tokensTotal,\n tokensCachedInput,\n }\n } catch (error) {\n consola.debug(\"Failed to fetch last completed usage by session\", error)\n return null\n }\n }\n\n query(params: RequestLogQuery): RequestLogQueryResult {\n const limit = Math.max(1, Math.min(params.limit, 200))\n\n const where: Array<string> = []\n const values: Array<SQLQueryBindings> = []\n\n if (params.cursorId !== undefined) {\n where.push(\"id < ?\")\n values.push(params.cursorId)\n }\n\n if (params.accountId) {\n where.push(\"account_id = ?\")\n values.push(params.accountId)\n }\n\n if (params.upstreamModel) {\n where.push(\"upstream_model = ?\")\n values.push(params.upstreamModel)\n }\n\n if (params.clientModel) {\n where.push(\"client_model = ?\")\n values.push(params.clientModel)\n }\n\n if (params.upstreamEndpoint) {\n where.push(\"upstream_endpoint = ?\")\n values.push(params.upstreamEndpoint)\n }\n\n if (params.path) {\n where.push(\"path = ?\")\n values.push(params.path)\n }\n\n if (params.status !== undefined) {\n where.push(\"http_status = ?\")\n values.push(params.status)\n }\n\n if (params.hasError === true) {\n where.push(\"http_status >= 400\")\n }\n if (params.hasError === false) {\n where.push(\"http_status < 400\")\n }\n\n if (params.fromMs !== undefined) {\n where.push(\"started_at_ms >= ?\")\n values.push(params.fromMs)\n }\n\n if (params.toMs !== undefined) {\n where.push(\"started_at_ms <= ?\")\n values.push(params.toMs)\n }\n\n const whereSql = where.length > 0 ? `WHERE ${where.join(\" AND \")}` : \"\"\n\n const sql = `\n SELECT *\n FROM request_log\n ${whereSql}\n ORDER BY id DESC\n LIMIT ?;\n `\n\n const rows = this.db\n .query(sql)\n .all(...values, limit + 1) as Array<RequestLogRow>\n\n const items = rows.slice(0, limit)\n const hasMore = rows.length > limit\n const nextCursorId = hasMore ? items.at(-1)?.id : undefined\n\n return {\n items,\n nextCursorId,\n hasMore,\n }\n }\n\n getAccountStatsSince(\n sinceMs: number,\n ): Record<string, AccountStatsRow | undefined> {\n try {\n const sql = `\n SELECT\n account_id,\n COUNT(*) AS request_count,\n SUM(CASE WHEN http_status >= 400 THEN 1 ELSE 0 END) AS error_count,\n COALESCE(SUM(tokens_total), 0) AS tokens_total,\n COALESCE(AVG(duration_ms), 0) AS avg_duration_ms,\n COALESCE(MAX(started_at_ms), 0) AS last_request_at_ms\n FROM request_log\n WHERE started_at_ms >= ? AND account_id IS NOT NULL\n GROUP BY account_id;\n `\n\n const rows = this.db.query(sql).all(sinceMs) as Array<AccountStatsRow>\n const map: Record<string, AccountStatsRow | undefined> = {}\n for (const row of rows) {\n map[row.account_id] = row\n }\n return map\n } catch (error) {\n consola.debug(\"Failed to fetch account stats\", error)\n return {}\n }\n }\n\n cleanupRetention(\n retentionDays: number = DEFAULT_RETENTION_DAYS,\n maxRows: number = DEFAULT_MAX_ROWS,\n ): void {\n try {\n const cutoffMs = Date.now() - retentionDays * 24 * 60 * 60 * 1000\n this.db\n .query(\"DELETE FROM request_log WHERE started_at_ms < ?;\")\n .run(cutoffMs)\n\n const countRow = this.db\n .query(\"SELECT COUNT(*) AS c FROM request_log;\")\n .get() as { c: number }\n\n const count = countRow.c\n if (count <= maxRows) {\n return\n }\n\n const offset = maxRows - 1\n const threshold = this.db\n .query(\"SELECT id FROM request_log ORDER BY id DESC LIMIT 1 OFFSET ?;\")\n .get(offset) as { id?: number } | null\n\n const thresholdId = threshold?.id\n if (!thresholdId) {\n return\n }\n\n this.db.query(\"DELETE FROM request_log WHERE id < ?;\").run(thresholdId)\n } catch (error) {\n consola.debug(\"Failed to cleanup request_log retention\", error)\n }\n\n import(\"./request-outbound\")\n .then((m) => m.getRequestOutboundStore().cleanupOrphans())\n .catch(() => {})\n }\n\n meta(): {\n dbPath: string\n userVersion: number\n retentionDays: number\n maxRows: number\n } {\n return {\n dbPath: getAdminDbPath(),\n userVersion: getAdminDbUserVersion(this.db),\n retentionDays: DEFAULT_RETENTION_DAYS,\n maxRows: DEFAULT_MAX_ROWS,\n }\n }\n}\n\nexport type RequestHistoryStoreApi = {\n insert(record: RequestLogInsert): void\n getByRequestId(requestId: string): RequestLogRow | null\n getLastCompletedUsageBySession(\n session: SessionUsageKey,\n ): NormalizedUsage | null\n query(params: RequestLogQuery): RequestLogQueryResult\n getAccountStatsSince(\n sinceMs: number,\n ): Record<string, AccountStatsRow | undefined>\n cleanupRetention(retentionDays?: number, maxRows?: number): void\n meta(): {\n dbPath: string\n userVersion: number\n retentionDays: number\n maxRows: number\n }\n}\n\nconst STORE_INIT_WARN_THROTTLE_MS = 30_000\nconst STORE_INIT_RETRY_DELAY_MS = 30_000\n\nlet lastStoreInitWarnAtMs = 0\nlet suppressedStoreInitWarnCount = 0\nlet nextStoreRetryAtMs = 0\n\nfunction warnStoreInitFailure(error: unknown): void {\n const now = Date.now()\n\n if (now - lastStoreInitWarnAtMs < STORE_INIT_WARN_THROTTLE_MS) {\n suppressedStoreInitWarnCount++\n return\n }\n\n const suppressed = suppressedStoreInitWarnCount\n suppressedStoreInitWarnCount = 0\n lastStoreInitWarnAtMs = now\n\n const suffix =\n suppressed > 0 ? ` (suppressed ${suppressed} similar errors)` : \"\"\n consola.warn(`Request history store is disabled${suffix}`, error)\n}\n\nconst disabledStore: RequestHistoryStoreApi = {\n insert: () => {},\n getByRequestId: () => null,\n getLastCompletedUsageBySession: () => null,\n query: () => ({ items: [], hasMore: false }),\n getAccountStatsSince: () => ({}),\n cleanupRetention: () => {},\n meta: () => ({\n dbPath: getAdminDbPath(),\n userVersion: 0,\n retentionDays: DEFAULT_RETENTION_DAYS,\n maxRows: DEFAULT_MAX_ROWS,\n }),\n}\n\nlet sharedStore: RequestHistoryStoreApi | null = null\nlet maintenanceStarted = false\n\nlet sharedStatsStore: StatsStore | null = null\n\nfunction getStatsStoreInstance(): StatsStore | null {\n if (sharedStatsStore) return sharedStatsStore\n try {\n sharedStatsStore = new StatsStore(getAdminDb())\n return sharedStatsStore\n } catch {\n return null\n }\n}\n\nexport function getRequestHistoryStore(): RequestHistoryStoreApi {\n if (sharedStore) {\n return sharedStore\n }\n\n const now = Date.now()\n if (now < nextStoreRetryAtMs) {\n return disabledStore\n }\n\n try {\n sharedStore = new RequestHistoryStore(getAdminDb())\n\n if (!maintenanceStarted) {\n maintenanceStarted = true\n\n // Run once at startup.\n sharedStore.cleanupRetention()\n getStatsStoreInstance()?.cleanupStatsRetention()\n\n // Then daily.\n setInterval(\n () => {\n sharedStore?.cleanupRetention()\n try {\n getStatsStoreInstance()?.cleanupStatsRetention()\n } catch {\n // Stats cleanup is best-effort\n }\n },\n 24 * 60 * 60 * 1000,\n )\n }\n\n return sharedStore\n } catch (error) {\n nextStoreRetryAtMs = now + STORE_INIT_RETRY_DELAY_MS\n warnStoreInitFailure(error)\n return disabledStore\n }\n}\n\nexport function extractResponsesUsageFromStreamEvent(\n event: ResponseStreamEvent,\n): NormalizedUsage {\n if (\n event.type === \"response.completed\"\n || event.type === \"response.incomplete\"\n ) {\n return normalizeResponsesUsage(event.response.usage)\n }\n\n if (event.type === \"response.failed\") {\n return normalizeResponsesUsage(event.response.usage)\n }\n\n return {}\n}\n\nexport function extractResponsesUsageFromResult(\n result: ResponsesResult,\n): NormalizedUsage {\n return normalizeResponsesUsage(result.usage)\n}\n\nexport function getStatsStore(): StatsStore | null {\n return getStatsStoreInstance()\n}\n","import type { Database } from \"bun:sqlite\"\n\nimport consola from \"consola\"\n\nimport { getAdminDb } from \"./admin-db\"\nimport { getSessionAffinityRetentionMs } from \"./config\"\n\nconst DAY_MS = 24 * 60 * 60 * 1000\nconst DEFAULT_MAX_AGE_MS = 7 * DAY_MS\nconst CLEANUP_INTERVAL_MS = DAY_MS\n\nconst maybeUnref = (timer: ReturnType<typeof setInterval>) => {\n timer.unref()\n}\n\nexport class SessionAffinityStore {\n private readonly db: Database\n\n constructor(db: Database) {\n this.db = db\n }\n\n get(cacheKey: string): string | undefined {\n let row: { account_id?: string } | null\n\n try {\n row = this.db\n .query(\n \"SELECT account_id FROM session_affinity WHERE cache_key = ? LIMIT 1;\",\n )\n .get(cacheKey) as { account_id?: string } | null\n } catch (error) {\n consola.warn(\"Failed to read session affinity mapping:\", error)\n return undefined\n }\n\n if (!row?.account_id) {\n return undefined\n }\n\n try {\n this.db\n .query(\n \"UPDATE session_affinity SET last_used_at_ms = ? WHERE cache_key = ?;\",\n )\n .run(Date.now(), cacheKey)\n } catch (error) {\n consola.warn(\"Failed to update session affinity last_used_at_ms:\", error)\n }\n\n return row.account_id\n }\n\n set(cacheKey: string, accountId: string): void {\n const now = Date.now()\n\n try {\n this.db\n .query(\n `\n INSERT INTO session_affinity (\n cache_key,\n account_id,\n created_at_ms,\n last_confirmed_at_ms,\n last_used_at_ms\n ) VALUES (?, ?, ?, ?, ?)\n ON CONFLICT(cache_key) DO UPDATE SET\n account_id = excluded.account_id,\n last_confirmed_at_ms = excluded.last_confirmed_at_ms,\n last_used_at_ms = excluded.last_used_at_ms;\n `,\n )\n .run(cacheKey, accountId, now, now, now)\n } catch (error) {\n consola.warn(\"Failed to persist session affinity mapping:\", error)\n }\n }\n\n delete(cacheKey: string): void {\n try {\n this.db\n .query(\"DELETE FROM session_affinity WHERE cache_key = ?;\")\n .run(cacheKey)\n } catch (error) {\n consola.warn(\"Failed to delete session affinity mapping:\", error)\n }\n }\n\n clear(): void {\n try {\n this.db.query(\"DELETE FROM session_affinity;\").run()\n } catch (error) {\n consola.warn(\"Failed to clear session affinity mappings:\", error)\n }\n }\n\n cleanup(maxAgeMs: number = DEFAULT_MAX_AGE_MS): void {\n try {\n this.db\n .query(\"DELETE FROM session_affinity WHERE last_used_at_ms < ?;\")\n .run(Date.now() - maxAgeMs)\n } catch (error) {\n consola.warn(\"Failed to cleanup session affinity mappings:\", error)\n }\n }\n}\n\nlet sharedSessionAffinityStore: SessionAffinityStore | null = null\nlet sharedCleanupInterval: ReturnType<typeof setInterval> | undefined\n\nfunction clearSharedSessionAffinityCleanup(): void {\n if (!sharedCleanupInterval) {\n return\n }\n\n clearInterval(sharedCleanupInterval)\n sharedCleanupInterval = undefined\n}\n\nexport function getSharedSessionAffinityStore(): SessionAffinityStore {\n if (!sharedSessionAffinityStore) {\n sharedSessionAffinityStore = new SessionAffinityStore(getAdminDb())\n }\n\n return sharedSessionAffinityStore\n}\n\nexport function applySharedSessionAffinityRetention(\n retentionMs: number = getSessionAffinityRetentionMs(),\n): void {\n clearSharedSessionAffinityCleanup()\n\n if (!Number.isFinite(retentionMs) || retentionMs <= 0) {\n return\n }\n\n try {\n const store = getSharedSessionAffinityStore()\n store.cleanup(retentionMs)\n\n sharedCleanupInterval = setInterval(() => {\n store.cleanup(retentionMs)\n }, CLEANUP_INTERVAL_MS)\n maybeUnref(sharedCleanupInterval)\n } catch (error) {\n consola.warn(\"Failed to apply session affinity retention:\", error)\n }\n}\n","interface SessionOwnershipCacheEntry {\n accountId: string\n expiresAt: number\n}\n\nconst DEFAULT_MAX_ENTRIES = 10_000\nconst DEFAULT_TTL_MS = 60 * 60 * 1000\n\n/**\n * In-memory TTL/LRU cache for root-session ownership.\n *\n * Uses Map insertion order for eviction: read/write hits move an entry to the\n * newest position, and writes refresh TTL.\n */\nexport class SessionOwnershipCache {\n private readonly cache = new Map<string, SessionOwnershipCacheEntry>()\n private readonly maxEntries: number\n private readonly ttlMs: number\n\n constructor(maxEntries = DEFAULT_MAX_ENTRIES, ttlMs = DEFAULT_TTL_MS) {\n this.maxEntries = maxEntries\n this.ttlMs = ttlMs\n }\n\n get(rootSessionId: string): string | undefined {\n const entry = this.cache.get(rootSessionId)\n if (!entry) {\n return undefined\n }\n\n if (Date.now() >= entry.expiresAt) {\n this.cache.delete(rootSessionId)\n return undefined\n }\n\n this.cache.delete(rootSessionId)\n this.cache.set(rootSessionId, entry)\n return entry.accountId\n }\n\n set(rootSessionId: string, accountId: string): void {\n this.cache.delete(rootSessionId)\n\n while (this.cache.size >= this.maxEntries) {\n const oldest = this.cache.keys().next()\n if (oldest.done) {\n break\n }\n this.cache.delete(oldest.value)\n }\n\n this.cache.set(rootSessionId, {\n accountId,\n expiresAt: Date.now() + this.ttlMs,\n })\n }\n\n clear(): void {\n this.cache.clear()\n }\n}\n","/* eslint-disable max-lines */\nimport consola from \"consola\"\nimport fs from \"node:fs\"\n\nimport type {\n AccountContext,\n AccountMeta,\n AccountRuntime,\n AccountType,\n} from \"~/lib/types/account\"\n\nimport {\n AccountAffinityCache,\n buildAffinityCacheKey,\n extractAffinityKey,\n isAffinityAccountUsable,\n type AffinityContext,\n type AffinityPersistenceStoreProvider,\n} from \"~/lib/account-affinity\"\nimport { resolveModelAlias } from \"~/lib/config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { getModels, type Model } from \"~/services/copilot/get-models\"\nimport { getCopilotToken } from \"~/services/github/get-copilot-token\"\nimport { getCopilotUsage } from \"~/services/github/get-copilot-usage\"\nimport { getGitHubUser } from \"~/services/github/get-user\"\n\nimport {\n buildIdentityKey,\n createAccountSessionId,\n getCurrentIdentityEnvironment,\n} from \"./account-client-identity\"\nimport {\n applyCopilotTokenIfCurrent,\n applyModelsIfCurrent,\n applyQuotaRefreshSuccessIfCurrent,\n applyTokenRefreshFailureIfCurrent,\n applyTokenRefreshSuccessIfCurrent,\n applyUnauthorizedIfCurrent,\n isAuthSnapshotCurrent,\n isSameAuthSnapshot,\n setAccountFailedState,\n takeAuthSnapshot,\n toAccountContextFromSnapshot,\n type AuthSnapshot,\n} from \"./accounts-manager-auth\"\nimport {\n getCostUnits,\n getEffectivePremiumRemaining,\n releasePremiumReservation,\n reservePremiumUnits,\n type QuotaReservation,\n} from \"./accounts-manager-quota\"\nimport {\n hasLegacyToken,\n hasRegistry,\n ensureAccountClientIdentity,\n isAccountEnabled,\n listAccountsFromRegistry,\n loadAccountToken,\n readLegacyToken,\n saveAccountToken,\n addAccountToRegistry,\n} from \"./accounts-registry\"\nimport { PATHS } from \"./paths\"\nimport { getStatsStore } from \"./request-history\"\nimport { getSharedSessionAffinityStore } from \"./session-affinity-store\"\nimport { SessionOwnershipCache } from \"./session-ownership\"\n\n/** Quota cache TTL in milliseconds (45 seconds) for pre-request selection. */\nconst QUOTA_CACHE_TTL = 45 * 1000\n\n/** Debounce delay for registry reload in milliseconds */\nconst RELOAD_DEBOUNCE_MS = 500\n\n/** Registry watcher restart initial delay in milliseconds */\nconst WATCHER_RESTART_INITIAL_DELAY_MS = 1000\n/** Registry watcher restart max delay in milliseconds */\nconst WATCHER_RESTART_MAX_DELAY_MS = 60 * 1000\n/** Session refresh base interval in milliseconds. */\nconst SESSION_REFRESH_BASE_MS = 60 * 60 * 1000\n/** Session refresh jitter window in milliseconds. */\nconst SESSION_REFRESH_JITTER_MS = 20 * 60 * 1000\n\n/** Minimum delay between account initializations in milliseconds. */\nconst INIT_STAGGER_MIN_MS = 2000\n/** Maximum delay between account initializations in milliseconds. */\nconst INIT_STAGGER_MAX_MS = 5000\n/** Random jitter window added to token refresh delay in milliseconds. */\nconst TOKEN_REFRESH_JITTER_MS = 30_000\n\nexport interface AccountRequestCandidate {\n modelId: string\n endpoint: string\n}\n\nexport type { QuotaReservation } from \"./accounts-manager-quota\"\nexport type { AffinityContext } from \"~/lib/account-affinity\"\n\nexport type AccountSelectionContext = AffinityContext & {\n ownershipLookupSessionId?: string\n ownershipWriteSessionId?: string\n}\n\nexport type SelectAccountForRequestFailureReason =\n | \"NO_ACCOUNTS\"\n | \"MODEL_NOT_SUPPORTED\"\n | \"NO_QUOTA\"\n\nexport type AccountSelectionReason =\n | \"affinity_hit\"\n | \"affinity_miss\"\n | \"preferred_account_unavailable\"\n | \"no_session_key\"\n | \"rotated_after_miss\"\n | \"subagent_owner_hit\"\n | \"subagent_owner_miss\"\n | \"subagent_owner_unusable_fallback\"\n | \"subagent_marker_invalid_fallback\"\n\ntype SelectAccountForRequestSuccess = {\n ok: true\n account: AccountRuntime\n selectedModel: Model\n endpoint: string\n costUnits: number\n reservation?: QuotaReservation\n /** Call after a successful upstream response to persist the affinity mapping. */\n confirmAffinity?: () => void\n /** Call after a successful upstream response to persist the ownership mapping. */\n confirmOwnership?: () => void\n /** Whether this selection was served from the affinity cache. */\n affinityHit?: boolean\n /** The cache key used for affinity lookup (e.g. `\"session-1:claude-sonnet-4\"`). */\n affinityCacheKey?: string\n /** High-level reason for why this account was selected. */\n selectionReason?: AccountSelectionReason\n}\n\nexport type SelectAccountForRequestResult =\n | SelectAccountForRequestSuccess\n | {\n ok: false\n reason: SelectAccountForRequestFailureReason\n selectionReason?: AccountSelectionReason\n }\n\nexport type AccountStatusEntry = {\n id: string\n entitlement?: number\n remaining?: number\n unlimited?: boolean\n overagePermitted?: boolean\n failed?: boolean\n failureReason?: string\n enabled?: boolean\n}\n\nfunction getInitialSelectionReason(\n cacheKey: string | undefined,\n rotationStart: number,\n): AccountSelectionReason {\n if (!cacheKey) {\n return \"no_session_key\"\n }\n\n return rotationStart > 0 ? \"rotated_after_miss\" : \"affinity_miss\"\n}\n\nfunction preserveSubagentSelectionReason(\n initialSelectionReason: AccountSelectionReason,\n nextSelectionReason: AccountSelectionReason,\n): AccountSelectionReason {\n return initialSelectionReason.startsWith(\"subagent_\") ?\n initialSelectionReason\n : nextSelectionReason\n}\n\ntype ScoredAccountRuntime = {\n account: AccountRuntime\n effectiveRemaining: number\n}\n\nexport interface AccountsManagerOptions {\n persistentAffinityStore?: AffinityPersistenceStoreProvider\n}\n\n/** Manages multiple GitHub Copilot accounts at runtime. */\nexport class AccountsManager {\n private accounts: Map<string, AccountRuntime> = new Map()\n private accountOrder: Array<string> = []\n private temporaryAccount?: AccountRuntime\n private vsCodeVersion?: string\n private accountAffinityEnabled = true\n private affinityCache: AccountAffinityCache\n private sessionOwnership = new SessionOwnershipCache()\n private sessionOwnershipGeneration = 0\n private loadBalanceCursor = 0\n\n constructor(options: AccountsManagerOptions = {}) {\n const { persistentAffinityStore } = options\n\n this.affinityCache = new AccountAffinityCache(\n undefined,\n undefined,\n persistentAffinityStore,\n )\n }\n\n private quotaRefreshSnapshotByAccount = new WeakMap<\n AccountRuntime,\n AuthSnapshot\n >()\n private modelsRefreshSnapshotByAccount = new WeakMap<\n AccountRuntime,\n AuthSnapshot\n >()\n private tokenRefreshEnabledAccounts = new WeakSet<AccountRuntime>()\n private modelsRefreshTimer?: ReturnType<typeof setTimeout>\n private modelsRefreshIntervalMs = 0\n\n // Registry file watcher for hot reload\n private registryWatcher?: fs.FSWatcher\n private reloadDebounceTimer?: ReturnType<typeof setTimeout>\n private registryWatcherRestartTimer?: ReturnType<typeof setTimeout>\n private registryWatcherRestartDelayMs = WATCHER_RESTART_INITIAL_DELAY_MS\n private isReloading = false\n private currentReloadPromise?: Promise<void>\n\n /** Initialize accounts manager (load registry, migrate legacy token). */\n async initialize(vsCodeVersion?: string): Promise<void> {\n this.vsCodeVersion = vsCodeVersion\n\n // Check if we need to migrate legacy token\n const hasReg = await hasRegistry()\n const hasLegacy = await hasLegacyToken()\n\n if (!hasReg && hasLegacy) {\n await this.migrateLegacyToken()\n }\n\n // Load accounts from registry\n const accountMetas = await listAccountsFromRegistry()\n\n for (const meta of accountMetas) {\n const token = await loadAccountToken(meta.id)\n if (!token) {\n consola.warn(`No token found for account ${meta.id}, skipping`)\n continue\n }\n\n const runtime: AccountRuntime = {\n ...meta,\n accountLogin: meta.id,\n githubToken: token,\n vsCodeVersion: this.vsCodeVersion,\n }\n\n this.accounts.set(meta.id, runtime)\n this.accountOrder.push(meta.id)\n }\n\n // Initialize Copilot tokens for all accounts (staggered to avoid burst traffic)\n let isFirstAccount = true\n for (const account of this.accounts.values()) {\n if (!isFirstAccount) {\n const staggerDelay =\n INIT_STAGGER_MIN_MS\n + Math.floor(\n Math.random() * (INIT_STAGGER_MAX_MS - INIT_STAGGER_MIN_MS),\n )\n consola.debug(\n `Staggering initialization of account ${account.id} by ${staggerDelay}ms`,\n )\n await new Promise((resolve) => setTimeout(resolve, staggerDelay))\n }\n isFirstAccount = false\n\n try {\n await this.initializeAccount(account)\n } catch (error) {\n consola.error(`Failed to initialize account ${account.id}:`, error)\n account.failed = true\n account.failureReason = String(error)\n }\n }\n\n consola.info(`Loaded ${this.accounts.size} account(s)`)\n\n // Start watching the registry file for hot reload\n this.startRegistryWatcher()\n }\n\n setAccountAffinityEnabled(enabled: boolean): void {\n this.accountAffinityEnabled = enabled\n if (!enabled) {\n this.affinityCache.clearMemory()\n }\n }\n\n setModelsRefreshIntervalMs(intervalMs: number): void {\n this.modelsRefreshIntervalMs =\n Number.isFinite(intervalMs) && intervalMs > 0 ? intervalMs : 0\n this.scheduleModelsRefresh()\n }\n\n private computeTokenRefreshDelayMs(refreshInSeconds: number): number {\n const baseDelay = Math.max((refreshInSeconds - 60) * 1000, 1000)\n const jitter = Math.floor(Math.random() * TOKEN_REFRESH_JITTER_MS)\n // Ensure the jittered delay doesn't exceed the token's validity window\n const maxSafeDelay = Math.max(refreshInSeconds * 1000 - 1000, 1000)\n return Math.min(baseDelay + jitter, maxSafeDelay)\n }\n\n private computeSessionRefreshDelayMs(): number {\n const randomDelay = Math.floor(Math.random() * SESSION_REFRESH_JITTER_MS)\n return SESSION_REFRESH_BASE_MS + randomDelay\n }\n\n private resolveAccountLogin(account: AccountRuntime): string {\n return account.accountLogin ?? account.id\n }\n\n private commitAccountIdentity(\n account: AccountRuntime,\n {\n identityKey,\n login,\n deviceId,\n machineId,\n }: {\n identityKey: string\n login: string\n deviceId: string\n machineId: string\n },\n ): void {\n account.accountLogin = login\n account.identityKey = identityKey\n account.clientDeviceId = deviceId\n account.clientMachineId = machineId\n }\n\n private async applyAccountIdentity(account: AccountRuntime): Promise<void> {\n const login = this.resolveAccountLogin(account)\n const { oauthApp, enterpriseDomain } = getCurrentIdentityEnvironment()\n const identityKey = buildIdentityKey({\n login,\n oauthApp,\n enterpriseDomain,\n })\n const identity = await ensureAccountClientIdentity({\n login,\n oauthApp,\n enterpriseDomain,\n })\n\n this.commitAccountIdentity(account, {\n identityKey,\n login,\n deviceId: identity.deviceId,\n machineId: identity.machineId,\n })\n\n if (!account.clientSessionId) {\n account.clientSessionId = createAccountSessionId()\n consola.debug(\n `Generated VSCode session ID for account ${account.id}: ${account.clientSessionId}`,\n )\n }\n\n this.startSessionRefresh(account)\n }\n\n private shouldContinueTokenRefresh(\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n ): boolean {\n return (\n this.tokenRefreshEnabledAccounts.has(account)\n && isAuthSnapshotCurrent(account, snapshot)\n )\n }\n\n private async runTokenRefreshTick(\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n refreshInSeconds: number,\n ): Promise<void> {\n if (!this.shouldContinueTokenRefresh(account, snapshot)) {\n return\n }\n\n try {\n const ctx = toAccountContextFromSnapshot(account, snapshot)\n const { token, refresh_in } = await getCopilotToken(ctx)\n\n if (!this.shouldContinueTokenRefresh(account, snapshot)) {\n return\n }\n\n const applied = applyTokenRefreshSuccessIfCurrent(\n account,\n snapshot,\n token,\n )\n if (!applied) {\n return\n }\n\n consola.debug(`Refreshed token for account ${account.id}`)\n\n // Schedule next refresh using the new refresh interval.\n if (!this.shouldContinueTokenRefresh(account, snapshot)) {\n return\n }\n this.startTokenRefresh(account, refresh_in)\n } catch (error) {\n consola.error(`Failed to refresh token for ${account.id}:`, error)\n\n if (!this.shouldContinueTokenRefresh(account, snapshot)) {\n return\n }\n\n applyTokenRefreshFailureIfCurrent(account, snapshot, error)\n\n // Retry using the previous refresh interval (best effort).\n if (!this.shouldContinueTokenRefresh(account, snapshot)) {\n return\n }\n this.startTokenRefresh(account, refreshInSeconds)\n }\n }\n\n private finalizeQuotaRefreshPromise(\n account: AccountRuntime,\n promise: Promise<void>,\n ): void {\n if (account.quotaRefreshPromise !== promise) {\n return\n }\n\n account.isRefreshingQuota = false\n account.quotaRefreshPromise = undefined\n this.quotaRefreshSnapshotByAccount.delete(account)\n }\n\n /** Initialize a single account. */\n private async initializeAccount(account: AccountRuntime): Promise<void> {\n await this.applyAccountIdentity(account)\n const snapshot = takeAuthSnapshot(account)\n\n try {\n // Get Copilot token\n const tokenCtx = toAccountContextFromSnapshot(account, snapshot)\n const { token, refresh_in } = await getCopilotToken(tokenCtx)\n\n if (!applyCopilotTokenIfCurrent(account, snapshot, token)) {\n return\n }\n\n // Resolve the account-specific Copilot endpoint before the first models fetch.\n await this.refreshQuota(account)\n\n // Start token refresh timer\n this.startTokenRefresh(account, refresh_in)\n\n // Get models\n const modelsCtx = toAccountContextFromSnapshot(account, snapshot, token)\n const models = await getModels(modelsCtx)\n\n if (!applyModelsIfCurrent(account, snapshot, models)) {\n return\n }\n account.lastModelsFetch = Date.now()\n\n consola.debug(`Account ${account.id} initialized`)\n } catch (error) {\n // Ignore stale results if registry hot reload changed auth.\n if (!isAuthSnapshotCurrent(account, snapshot)) {\n return\n }\n\n throw error\n }\n }\n\n /** Migrate legacy github_token to the new multi-account system. */\n private async migrateLegacyToken(): Promise<void> {\n const token = await readLegacyToken()\n if (!token) return\n\n try {\n // Get user info to determine the account ID\n const user = await getGitHubUser({\n githubToken: token,\n accountType: \"individual\",\n })\n const id = user.login\n\n // Save token to new location\n await saveAccountToken(id, token)\n\n // Add to registry\n await addAccountToRegistry({\n id,\n accountType: \"individual\",\n addedAt: Date.now(),\n })\n\n consola.info(`Migrated legacy token to account: ${id}`)\n } catch (error) {\n consola.error(\"Failed to migrate legacy token:\", error)\n }\n }\n\n /** Start token refresh timer for an account. */\n private startTokenRefresh(\n account: AccountRuntime,\n refreshInSeconds: number,\n ): void {\n // Stop existing timer if any\n this.stopTokenRefresh(account)\n\n this.tokenRefreshEnabledAccounts.add(account)\n\n const snapshot = takeAuthSnapshot(account)\n const delayMs = this.computeTokenRefreshDelayMs(refreshInSeconds)\n\n account.refreshTimer = setTimeout(() => {\n void this.runTokenRefreshTick(account, snapshot, refreshInSeconds)\n }, delayMs)\n }\n\n /** Stop token refresh timer for an account. */\n private stopTokenRefresh(account: AccountRuntime): void {\n this.tokenRefreshEnabledAccounts.delete(account)\n\n if (account.refreshTimer) {\n clearTimeout(account.refreshTimer)\n account.refreshTimer = undefined\n }\n }\n\n /** Stop all token refresh timers. */\n private stopAllTokenRefresh(): void {\n for (const account of this.accounts.values()) {\n this.stopTokenRefresh(account)\n }\n if (this.temporaryAccount) {\n this.stopTokenRefresh(this.temporaryAccount)\n }\n }\n\n private startSessionRefresh(account: AccountRuntime): void {\n this.stopSessionRefresh(account)\n\n const delayMs = this.computeSessionRefreshDelayMs()\n consola.debug(\n `Scheduling next VSCode session ID refresh for ${account.id} in ${Math.round(\n delayMs / 1000,\n )} seconds`,\n )\n\n account.sessionRefreshTimer = setTimeout(() => {\n try {\n account.clientSessionId = createAccountSessionId()\n consola.debug(\n `Refreshed VSCode session ID for account ${account.id}: ${account.clientSessionId}`,\n )\n } catch (error) {\n consola.error(\n `Failed to refresh VSCode session ID for ${account.id}, rescheduling...`,\n error,\n )\n } finally {\n this.startSessionRefresh(account)\n }\n }, delayMs)\n }\n\n private stopSessionRefresh(account: AccountRuntime): void {\n if (account.sessionRefreshTimer) {\n clearTimeout(account.sessionRefreshTimer)\n account.sessionRefreshTimer = undefined\n }\n }\n\n private stopAllSessionRefresh(): void {\n for (const account of this.accounts.values()) {\n this.stopSessionRefresh(account)\n }\n\n if (this.temporaryAccount) {\n this.stopSessionRefresh(this.temporaryAccount)\n }\n }\n\n private scheduleModelsRefresh(): void {\n this.stopModelsRefresh()\n\n if (!this.modelsRefreshIntervalMs || this.modelsRefreshIntervalMs <= 0) {\n return\n }\n\n this.modelsRefreshTimer = setTimeout(() => {\n void this.runModelsRefreshTick()\n }, this.modelsRefreshIntervalMs)\n }\n\n private stopModelsRefresh(): void {\n if (this.modelsRefreshTimer) {\n clearTimeout(this.modelsRefreshTimer)\n this.modelsRefreshTimer = undefined\n }\n }\n\n private async runModelsRefreshTick(): Promise<void> {\n try {\n await this.refreshAllModels()\n } catch (error) {\n consola.error(\"Failed to refresh models:\", error)\n } finally {\n this.scheduleModelsRefresh()\n }\n }\n\n private finalizeModelsRefreshPromise(\n account: AccountRuntime,\n promise: Promise<void>,\n ): void {\n if (account.modelsRefreshPromise !== promise) {\n return\n }\n\n account.isRefreshingModels = false\n account.modelsRefreshPromise = undefined\n this.modelsRefreshSnapshotByAccount.delete(account)\n }\n\n private async refreshModels(account: AccountRuntime): Promise<void> {\n if (!account.copilotToken) {\n consola.debug(\n `Skip model refresh for ${account.id}: missing Copilot token`,\n )\n return\n }\n\n const snapshot = takeAuthSnapshot(account)\n\n if (account.modelsRefreshPromise) {\n const existingSnapshot = this.modelsRefreshSnapshotByAccount.get(account)\n if (isSameAuthSnapshot(existingSnapshot, snapshot)) {\n await account.modelsRefreshPromise\n return\n }\n }\n\n account.isRefreshingModels = true\n\n const ctx = toAccountContextFromSnapshot(\n account,\n snapshot,\n account.copilotToken,\n )\n\n const promise = (async () => {\n try {\n const models = await getModels(ctx)\n const applied = applyModelsIfCurrent(account, snapshot, models)\n if (applied) {\n account.lastModelsFetch = Date.now()\n }\n } catch (error) {\n if (error instanceof HTTPError && error.response.status === 401) {\n applyUnauthorizedIfCurrent(account, snapshot, \"Unauthorized (401)\")\n return\n }\n\n consola.error(`Failed to refresh models for ${account.id}:`, error)\n }\n })()\n\n account.modelsRefreshPromise = promise\n this.modelsRefreshSnapshotByAccount.set(account, snapshot)\n\n void promise.finally(() => {\n this.finalizeModelsRefreshPromise(account, promise)\n })\n\n await promise\n }\n\n private async refreshAllModels(): Promise<void> {\n const accounts: Array<AccountRuntime> = []\n\n if (this.temporaryAccount) {\n accounts.push(this.temporaryAccount)\n }\n\n for (const id of this.accountOrder) {\n const account = this.accounts.get(id)\n if (account) {\n accounts.push(account)\n }\n }\n\n if (accounts.length === 0) {\n return\n }\n\n await Promise.allSettled(\n accounts.map((account) => this.refreshModels(account)),\n )\n }\n\n /** Refresh quota information for an account. */\n async refreshQuota(account: AccountRuntime): Promise<void> {\n const snapshot = takeAuthSnapshot(account)\n\n if (account.quotaRefreshPromise) {\n const existingSnapshot = this.quotaRefreshSnapshotByAccount.get(account)\n if (isSameAuthSnapshot(existingSnapshot, snapshot)) {\n await account.quotaRefreshPromise\n return\n }\n }\n\n account.isRefreshingQuota = true\n\n const ctx = toAccountContextFromSnapshot(account, snapshot)\n const promise = (async () => {\n try {\n const usage = await getCopilotUsage(ctx)\n const premium = usage.quota_snapshots.premium_interactions\n const applied = applyQuotaRefreshSuccessIfCurrent(account, snapshot, {\n premium,\n copilotApiUrl: usage.endpoints.api,\n })\n\n if (applied) {\n try {\n getStatsStore()?.insertQuotaSnapshot({\n accountId: account.id,\n snapshotAtMs: Date.now(),\n remaining: premium.remaining,\n entitlement: premium.entitlement,\n unlimited: premium.unlimited,\n source: \"refresh\",\n })\n } catch {\n // Best-effort: don't fail the quota refresh if snapshot insert fails\n }\n }\n } catch (error) {\n if (error instanceof HTTPError && error.response.status === 401) {\n applyUnauthorizedIfCurrent(account, snapshot, \"Unauthorized (401)\")\n return\n }\n\n consola.error(`Failed to refresh quota for ${account.id}:`, error)\n // Don't mark as failed for non-401 quota refresh errors\n }\n })()\n\n account.quotaRefreshPromise = promise\n this.quotaRefreshSnapshotByAccount.set(account, snapshot)\n\n void promise.finally(() => {\n this.finalizeQuotaRefreshPromise(account, promise)\n })\n\n await promise\n }\n\n /** Check if quota cache is expired. */\n private isQuotaCacheExpired(account: AccountRuntime): boolean {\n if (!account.lastQuotaFetch) return true\n return Date.now() - account.lastQuotaFetch > QUOTA_CACHE_TTL\n }\n\n private isAccountFailed(account: AccountRuntime): boolean {\n return account.failed === true\n }\n\n private useOverageFallback(fallback: {\n account: AccountRuntime\n model: Model\n endpoint: string\n costUnits: number\n }): SelectAccountForRequestSuccess {\n const reservation = reservePremiumUnits(\n fallback.account,\n fallback.costUnits,\n )\n return {\n ok: true,\n account: fallback.account,\n selectedModel: fallback.model,\n endpoint: fallback.endpoint,\n costUnits: fallback.costUnits,\n reservation,\n }\n }\n\n private isModelSupportedForEndpoint(model: Model, endpoint: string): boolean {\n if (endpoint === \"/responses\") {\n return model.supported_endpoints?.includes(endpoint) ?? false\n }\n\n const supported = model.supported_endpoints\n if (!supported) {\n return true\n }\n\n return supported.includes(endpoint)\n }\n\n private pickSupportedCandidate(\n account: AccountRuntime,\n candidates: Array<AccountRequestCandidate>,\n ): { candidate: AccountRequestCandidate; model: Model } | null {\n const models = account.models?.data\n if (!models) {\n return null\n }\n\n for (const candidate of candidates) {\n const model = models.find((m) => m.id === candidate.modelId)\n if (!model) {\n continue\n }\n\n if (!this.isModelSupportedForEndpoint(model, candidate.endpoint)) {\n continue\n }\n\n return { candidate, model }\n }\n\n return null\n }\n\n private async selectAccountForCandidates(\n orderedAccounts: Array<AccountRuntime>,\n candidates: Array<AccountRequestCandidate>,\n ): Promise<SelectAccountForRequestResult> {\n if (orderedAccounts.length === 0) {\n return { ok: false, reason: \"NO_ACCOUNTS\" }\n }\n\n let supportedCandidateFound = false\n let overageFallback:\n | {\n account: AccountRuntime\n model: Model\n endpoint: string\n costUnits: number\n }\n | undefined\n\n for (const account of orderedAccounts) {\n if (this.isAccountFailed(account)) {\n continue\n }\n\n const supported = this.pickSupportedCandidate(account, candidates)\n if (!supported) {\n continue\n }\n\n supportedCandidateFound = true\n\n const { candidate, model } = supported\n const costUnits = getCostUnits(model)\n\n if (costUnits <= 0) {\n // Free model: sequential routing (first available account).\n // When account affinity is enabled, the caller (selectAccountForRequest)\n // handles cache lookup/write-back; this path only runs on cache miss.\n return {\n ok: true,\n account,\n selectedModel: model,\n endpoint: candidate.endpoint,\n costUnits,\n }\n }\n\n if (!account.unlimited && this.isQuotaCacheExpired(account)) {\n await this.refreshQuota(account)\n }\n\n if (this.isAccountFailed(account)) {\n continue\n }\n\n if (account.unlimited) {\n return {\n ok: true,\n account,\n selectedModel: model,\n endpoint: candidate.endpoint,\n costUnits,\n }\n }\n\n // Check if account has sufficient quota.\n const effectiveRemaining = getEffectivePremiumRemaining(account)\n if (effectiveRemaining !== undefined && effectiveRemaining < costUnits) {\n // Insufficient quota - store as overage fallback if permitted, but keep\n // looking for accounts with quota to avoid unnecessary overage charges.\n if (account.overagePermitted && !overageFallback) {\n overageFallback = {\n account,\n model,\n endpoint: candidate.endpoint,\n costUnits,\n }\n }\n continue\n }\n\n const reservation = reservePremiumUnits(account, costUnits)\n\n return {\n ok: true,\n account,\n selectedModel: model,\n endpoint: candidate.endpoint,\n costUnits,\n reservation,\n }\n }\n\n if (!supportedCandidateFound) {\n return { ok: false, reason: \"MODEL_NOT_SUPPORTED\" }\n }\n\n // No account with quota found - use overage fallback if available.\n return overageFallback ?\n this.useOverageFallback(overageFallback)\n : { ok: false, reason: \"NO_QUOTA\" }\n }\n\n /**\n * Try to use a preferred (affinity) account for the request.\n * Returns a successful selection if the account is usable; null otherwise.\n */\n\n private async tryAffinityAccount(\n preferredAccountId: string,\n orderedAccounts: Array<AccountRuntime>,\n candidates: Array<AccountRequestCandidate>,\n ): Promise<SelectAccountForRequestSuccess | null> {\n const account = isAffinityAccountUsable(preferredAccountId, orderedAccounts)\n if (!account) {\n return null\n }\n\n // Try original candidates first, then alias-resolved candidates.\n const supported =\n this.pickSupportedCandidate(account, candidates)\n ?? this.pickAliasFallbackCandidate(account, candidates)\n if (!supported) {\n return null\n }\n\n return this.validateAffinityQuota(account, supported)\n }\n\n /**\n * Resolve model aliases and try to pick a supported candidate.\n * Returns null if no alias differs or the account doesn't support the alias.\n */\n private pickAliasFallbackCandidate(\n account: AccountRuntime,\n candidates: Array<AccountRequestCandidate>,\n ): { candidate: AccountRequestCandidate; model: Model } | null {\n const aliasCandidates = candidates.map((candidate) => {\n const modelId = resolveModelAlias(candidate.modelId)\n if (modelId === candidate.modelId) return candidate\n return { ...candidate, modelId }\n })\n const aliasChanged = aliasCandidates.some(\n (candidate, index) => candidate.modelId !== candidates[index].modelId,\n )\n if (!aliasChanged) return null\n\n return this.pickSupportedCandidate(account, aliasCandidates)\n }\n\n /**\n * Validate quota for an affinity candidate. Free models pass immediately;\n * premium models go through quota refresh / reservation.\n */\n private async validateAffinityQuota(\n account: AccountRuntime,\n supported: { candidate: AccountRequestCandidate; model: Model },\n ): Promise<SelectAccountForRequestSuccess | null> {\n const { candidate, model } = supported\n const costUnits = getCostUnits(model)\n\n // Free model — no quota checks needed.\n if (costUnits <= 0) {\n return {\n ok: true,\n account,\n selectedModel: model,\n endpoint: candidate.endpoint,\n costUnits,\n }\n }\n\n // Premium model — validate quota.\n if (!account.unlimited && this.isQuotaCacheExpired(account)) {\n await this.refreshQuota(account)\n }\n\n if (this.isAccountFailed(account)) {\n return null\n }\n\n if (account.unlimited) {\n return {\n ok: true,\n account,\n selectedModel: model,\n endpoint: candidate.endpoint,\n costUnits,\n }\n }\n\n const effectiveRemaining = getEffectivePremiumRemaining(account)\n if (effectiveRemaining !== undefined && effectiveRemaining < costUnits) {\n return null\n }\n\n const reservation = reservePremiumUnits(account, costUnits)\n\n return {\n ok: true,\n account,\n selectedModel: model,\n endpoint: candidate.endpoint,\n costUnits,\n reservation,\n }\n }\n\n /**\n * Select an available account for a specific request (model + endpoint).\n * When account affinity is enabled, routes to the previously successful account\n * for the same affinity key + model combination.\n * Uses reservation to avoid oversubscribing premium quota under concurrency.\n */\n async selectAccountForRequest(\n candidates: Array<AccountRequestCandidate>,\n context?: AccountSelectionContext,\n ): Promise<SelectAccountForRequestResult> {\n if (candidates.length === 0) {\n throw new Error(\"selectAccountForRequest requires at least one candidate\")\n }\n\n const orderedAccounts = this.getOrderedEnabledAccounts()\n const ownerSelection = await this.selectPreferredSessionOwner({\n lookupSessionId: context?.ownershipLookupSessionId,\n orderedAccounts,\n candidates,\n })\n if (ownerSelection.result) {\n this.attachConfirmOwnership(\n ownerSelection.result,\n context?.ownershipWriteSessionId,\n )\n return ownerSelection.result\n }\n\n const affinityPlan = this.buildAffinitySelectionPlan({\n orderedAccounts,\n candidates,\n context,\n ownerSelectionReason: ownerSelection.selectionReason,\n })\n const preferredSelection = await this.selectPreferredAffinityAccount({\n cacheKey: affinityPlan.cacheKey,\n orderedAccounts,\n candidates,\n initialSelectionReason: affinityPlan.initialSelectionReason,\n })\n if (preferredSelection.result) {\n this.attachConfirmOwnership(\n preferredSelection.result,\n context?.ownershipWriteSessionId,\n )\n return preferredSelection.result\n }\n\n let accountsForSelection = affinityPlan.defaultAccountsForSelection\n let premiumRemainingOrderedAccountIds = new Set<string>()\n let selectionReason = preferredSelection.selectionReason\n\n if (\n affinityPlan.canReorderOnAffinityCacheMiss\n && preferredSelection.affinityCacheMiss\n ) {\n const affinityMissOrder =\n this.orderAccountsForAffinityCacheMiss(orderedAccounts)\n accountsForSelection = affinityMissOrder.accounts\n premiumRemainingOrderedAccountIds =\n affinityMissOrder.premiumRemainingOrderedAccountIds\n }\n\n const result = await this.selectWithAliasFallback(\n accountsForSelection,\n candidates,\n )\n if (result.ok && premiumRemainingOrderedAccountIds.has(result.account.id)) {\n selectionReason = \"affinity_miss\"\n }\n\n return this.finalizeSelectedAccount({\n result,\n cacheKey: affinityPlan.cacheKey,\n selectionReason,\n ownershipWriteSessionId: context?.ownershipWriteSessionId,\n })\n }\n\n private getOrderedEnabledAccounts(): Array<AccountRuntime> {\n return [\n ...(this.temporaryAccount ? [this.temporaryAccount] : []),\n ...this.accountOrder\n .map((id) => this.accounts.get(id))\n .filter((account): account is AccountRuntime => account !== undefined),\n ].filter((account) => isAccountEnabled(account))\n }\n\n private buildAffinitySelectionPlan(params: {\n orderedAccounts: Array<AccountRuntime>\n candidates: Array<AccountRequestCandidate>\n context?: AccountSelectionContext\n ownerSelectionReason?: AccountSelectionReason\n }): {\n cacheKey: string | undefined\n defaultAccountsForSelection: Array<AccountRuntime>\n initialSelectionReason: AccountSelectionReason\n canReorderOnAffinityCacheMiss: boolean\n } {\n const { orderedAccounts, candidates, context, ownerSelectionReason } =\n params\n const affinityKey =\n this.accountAffinityEnabled && context ?\n extractAffinityKey(context)\n : undefined\n const modelKey = context?.affinityModelId ?? candidates[0].modelId\n const cacheKey =\n affinityKey ? buildAffinityCacheKey(affinityKey, modelKey) : undefined\n const shouldRotate =\n this.accountAffinityEnabled && orderedAccounts.length > 1\n const rotationStart =\n shouldRotate ? this.loadBalanceCursor % orderedAccounts.length : 0\n\n return {\n cacheKey,\n defaultAccountsForSelection:\n shouldRotate ? this.rotateAccounts(orderedAccounts) : orderedAccounts,\n initialSelectionReason:\n ownerSelectionReason\n ?? getInitialSelectionReason(cacheKey, rotationStart),\n canReorderOnAffinityCacheMiss:\n ownerSelectionReason === undefined && cacheKey !== undefined,\n }\n }\n\n private finalizeSelectedAccount(params: {\n result: SelectAccountForRequestResult\n cacheKey: string | undefined\n selectionReason: AccountSelectionReason\n ownershipWriteSessionId: string | undefined\n }): SelectAccountForRequestResult {\n const { result, cacheKey, selectionReason, ownershipWriteSessionId } =\n params\n if (!result.ok) {\n return {\n ...result,\n selectionReason,\n }\n }\n\n this.loadBalanceCursor++\n result.selectionReason = selectionReason\n result.affinityCacheKey = cacheKey\n\n if (cacheKey) {\n result.confirmAffinity = () => {\n if (!this.accountAffinityEnabled) return\n this.affinityCache.set(cacheKey, result.account.id)\n }\n }\n\n this.attachConfirmOwnership(result, ownershipWriteSessionId)\n return result\n }\n\n invalidateAffinity(cacheKey: string): void {\n const normalizedCacheKey = cacheKey.trim()\n if (!normalizedCacheKey) {\n return\n }\n\n this.affinityCache.delete(normalizedCacheKey)\n }\n\n private attachConfirmOwnership(\n result: SelectAccountForRequestSuccess,\n ownershipWriteSessionId: string | undefined,\n ): void {\n const rootSessionId = ownershipWriteSessionId?.trim()\n if (!rootSessionId) {\n return\n }\n\n const generation = this.sessionOwnershipGeneration\n result.confirmOwnership = () => {\n if (generation !== this.sessionOwnershipGeneration) {\n return\n }\n this.sessionOwnership.set(rootSessionId, result.account.id)\n }\n }\n\n private async selectPreferredSessionOwner(params: {\n lookupSessionId: string | undefined\n orderedAccounts: Array<AccountRuntime>\n candidates: Array<AccountRequestCandidate>\n }): Promise<{\n result?: SelectAccountForRequestSuccess\n selectionReason?: AccountSelectionReason\n }> {\n const { lookupSessionId, orderedAccounts, candidates } = params\n\n if (lookupSessionId === undefined) {\n return {}\n }\n\n const rootSessionId = lookupSessionId.trim()\n if (!rootSessionId) {\n return { selectionReason: \"subagent_marker_invalid_fallback\" }\n }\n\n const preferredAccountId = this.sessionOwnership.get(rootSessionId)\n if (!preferredAccountId) {\n return { selectionReason: \"subagent_owner_miss\" }\n }\n\n const ownerResult = await this.tryAffinityAccount(\n preferredAccountId,\n orderedAccounts,\n candidates,\n )\n if (!ownerResult) {\n return { selectionReason: \"subagent_owner_unusable_fallback\" }\n }\n\n ownerResult.selectionReason = \"subagent_owner_hit\"\n\n return {\n result: ownerResult,\n }\n }\n\n /**\n * Try the preferred account from the affinity cache before normal selection.\n */\n private async selectPreferredAffinityAccount(params: {\n cacheKey: string | undefined\n orderedAccounts: Array<AccountRuntime>\n candidates: Array<AccountRequestCandidate>\n initialSelectionReason: AccountSelectionReason\n }): Promise<{\n result?: SelectAccountForRequestSuccess\n selectionReason: AccountSelectionReason\n affinityCacheMiss: boolean\n }> {\n const { cacheKey, orderedAccounts, candidates, initialSelectionReason } =\n params\n\n if (!cacheKey) {\n return {\n selectionReason: initialSelectionReason,\n affinityCacheMiss: false,\n }\n }\n\n const preferredId = this.affinityCache.get(cacheKey)\n if (!preferredId) {\n return {\n selectionReason: initialSelectionReason,\n affinityCacheMiss: true,\n }\n }\n\n const affinityResult = await this.tryAffinityAccount(\n preferredId,\n orderedAccounts,\n candidates,\n )\n if (!affinityResult) {\n this.affinityCache.delete(cacheKey)\n return {\n selectionReason: preserveSubagentSelectionReason(\n initialSelectionReason,\n \"preferred_account_unavailable\",\n ),\n affinityCacheMiss: false,\n }\n }\n\n const selectionReason = preserveSubagentSelectionReason(\n initialSelectionReason,\n \"affinity_hit\",\n )\n affinityResult.affinityHit = true\n affinityResult.affinityCacheKey = cacheKey\n affinityResult.selectionReason = selectionReason\n affinityResult.confirmAffinity = () => {\n if (!this.accountAffinityEnabled) return\n this.affinityCache.set(cacheKey, affinityResult.account.id)\n }\n\n return {\n result: affinityResult,\n selectionReason,\n affinityCacheMiss: false,\n }\n }\n\n /**\n * Rotate the accounts array by the current load-balance cursor for round-robin distribution.\n * This ensures cache-miss requests are spread across accounts instead of always hitting the first.\n */\n private rotateAccounts(\n accounts: Array<AccountRuntime>,\n ): Array<AccountRuntime> {\n const start = this.loadBalanceCursor % accounts.length\n if (start === 0) return accounts\n return [...accounts.slice(start), ...accounts.slice(0, start)]\n }\n\n private orderAccountsForAffinityCacheMiss(\n orderedAccounts: Array<AccountRuntime>,\n ): {\n accounts: Array<AccountRuntime>\n premiumRemainingOrderedAccountIds: Set<string>\n } {\n const scoredAccounts = orderedAccounts\n .map((account) => ({\n account,\n effectiveRemaining: getEffectivePremiumRemaining(account),\n }))\n .filter(\n (entry): entry is ScoredAccountRuntime =>\n entry.effectiveRemaining !== undefined,\n )\n .sort((left, right) => right.effectiveRemaining - left.effectiveRemaining)\n\n if (scoredAccounts.length > 0) {\n const scoredAccountsInSelectionOrder =\n this.shuffleWithinEqualRemainingBuckets(scoredAccounts).map(\n ({ account }) => account,\n )\n const scoredAccountSet = new Set(scoredAccountsInSelectionOrder)\n const unknownQuotaAccounts = orderedAccounts.filter(\n (account) => !scoredAccountSet.has(account) && !account.unlimited,\n )\n const unlimitedAccounts = orderedAccounts.filter(\n (account) => !scoredAccountSet.has(account) && account.unlimited,\n )\n return {\n accounts: [\n ...scoredAccountsInSelectionOrder,\n ...unknownQuotaAccounts,\n ...unlimitedAccounts,\n ],\n premiumRemainingOrderedAccountIds: new Set(\n scoredAccountsInSelectionOrder.map((account) => account.id),\n ),\n }\n }\n\n const premiumRemainingOrderedAccountIds = new Set<string>()\n const unlimitedAccounts = orderedAccounts.filter(\n (account) => account.unlimited,\n )\n if (unlimitedAccounts.length === 0) {\n return {\n accounts: orderedAccounts,\n premiumRemainingOrderedAccountIds,\n }\n }\n\n const unknownQuotaAccounts = orderedAccounts.filter(\n (account) => !account.unlimited,\n )\n return {\n accounts: [\n ...this.shuffleArray(unlimitedAccounts),\n ...unknownQuotaAccounts,\n ],\n premiumRemainingOrderedAccountIds,\n }\n }\n\n private shuffleWithinEqualRemainingBuckets(\n scoredAccounts: Array<ScoredAccountRuntime>,\n ): Array<ScoredAccountRuntime> {\n const shuffled: Array<ScoredAccountRuntime> = []\n\n let index = 0\n while (index < scoredAccounts.length) {\n const currentRemaining = scoredAccounts[index].effectiveRemaining\n let bucketEnd = index + 1\n while (\n bucketEnd < scoredAccounts.length\n && scoredAccounts[bucketEnd].effectiveRemaining === currentRemaining\n ) {\n bucketEnd++\n }\n\n shuffled.push(\n ...this.shuffleArray(scoredAccounts.slice(index, bucketEnd)),\n )\n index = bucketEnd\n }\n\n return shuffled\n }\n\n private shuffleArray<T>(items: Array<T>): Array<T> {\n if (items.length <= 1) {\n return items\n }\n\n const shuffled = [...items]\n for (let index = shuffled.length - 1; index > 0; index--) {\n const randomIndex = Math.floor(Math.random() * (index + 1))\n ;[shuffled[index], shuffled[randomIndex]] = [\n shuffled[randomIndex],\n shuffled[index],\n ]\n }\n\n return shuffled\n }\n\n /**\n * Normal account selection with alias fallback.\n * Extracted to keep selectAccountForRequest readable after adding affinity logic.\n */\n private async selectWithAliasFallback(\n orderedAccounts: Array<AccountRuntime>,\n candidates: Array<AccountRequestCandidate>,\n ): Promise<SelectAccountForRequestResult> {\n const primary = await this.selectAccountForCandidates(\n orderedAccounts,\n candidates,\n )\n if (primary.ok || primary.reason !== \"MODEL_NOT_SUPPORTED\") {\n return primary\n }\n\n const aliasCandidates = candidates.map((candidate) => {\n const modelId = resolveModelAlias(candidate.modelId)\n if (modelId === candidate.modelId) return candidate\n return { ...candidate, modelId }\n })\n const aliasChanged = aliasCandidates.some(\n (candidate, index) => candidate.modelId !== candidates[index].modelId,\n )\n if (!aliasChanged) {\n return primary\n }\n\n return this.selectAccountForCandidates(orderedAccounts, aliasCandidates)\n }\n\n /**\n * Finalize quota after a request completes.\n * This releases any in-flight reservation and refreshes the actual quota from the API.\n */\n async finalizeQuota(\n account: AccountRuntime,\n reservation?: QuotaReservation,\n ): Promise<void> {\n releasePremiumReservation(account, reservation)\n\n try {\n await this.refreshQuota(account)\n } catch (error) {\n consola.debug(`Failed to finalize quota for ${account.id}:`, error)\n }\n }\n\n /**\n * Mark an account as failed.\n */\n markAccountFailed(id: string, reason: string): void {\n const account = this.accounts.get(id)\n if (account) {\n setAccountFailedState(account, reason)\n return\n }\n\n if (this.temporaryAccount && this.temporaryAccount.id === id) {\n setAccountFailedState(this.temporaryAccount, reason)\n }\n }\n\n /**\n * Get status of all accounts.\n */\n getAccountStatus(): Array<AccountStatusEntry> {\n const statuses: Array<AccountStatusEntry> = []\n\n if (this.temporaryAccount) {\n statuses.push({\n id: \"(temporary)\",\n entitlement: this.temporaryAccount.premiumEntitlement,\n remaining: this.temporaryAccount.premiumRemaining,\n unlimited: this.temporaryAccount.unlimited,\n overagePermitted: this.temporaryAccount.overagePermitted,\n failed: this.temporaryAccount.failed,\n failureReason: this.temporaryAccount.failureReason,\n })\n }\n\n for (const id of this.accountOrder) {\n const account = this.accounts.get(id)\n if (account) {\n statuses.push({\n id: account.id,\n entitlement: account.premiumEntitlement,\n remaining: account.premiumRemaining,\n unlimited: account.unlimited,\n overagePermitted: account.overagePermitted,\n failed: account.failed,\n failureReason: account.failureReason,\n enabled: account.enabled,\n })\n }\n }\n\n return statuses\n }\n\n /**\n * Set a temporary account from a GitHub token (--github-token).\n * This account takes priority over registered accounts.\n */\n async setTemporaryAccount(\n githubToken: string,\n accountType: AccountType,\n ): Promise<void> {\n const user = await getGitHubUser({ githubToken, accountType })\n\n if (this.temporaryAccount) {\n this.stopTokenRefresh(this.temporaryAccount)\n this.stopSessionRefresh(this.temporaryAccount)\n }\n\n const runtime: AccountRuntime = {\n id: \"(temporary)\",\n accountLogin: user.login,\n accountType,\n addedAt: Date.now(),\n githubToken,\n vsCodeVersion: this.vsCodeVersion,\n }\n\n try {\n await this.initializeAccount(runtime)\n this.temporaryAccount = runtime\n consola.info(\"Temporary account initialized\")\n } catch (error) {\n consola.error(\"Failed to initialize temporary account:\", error)\n throw error\n }\n }\n\n /**\n * Check if any accounts are available.\n */\n hasAccounts(): boolean {\n return this.accounts.size > 0 || this.temporaryAccount !== undefined\n }\n\n /**\n * Get the first available account's models.\n * Used for caching models in legacy compatibility mode.\n */\n getFirstAccountModels(): AccountRuntime[\"models\"] {\n if (this.temporaryAccount?.models) {\n return this.temporaryAccount.models\n }\n\n for (const id of this.accountOrder) {\n const account = this.accounts.get(id)\n if (account?.models) {\n return account.models\n }\n }\n\n return undefined\n }\n\n /**\n * Get account context by account ID.\n * Returns null if no account with the given ID exists.\n */\n getAccountContextById(id: string): AccountContext | null {\n if (this.temporaryAccount && this.temporaryAccount.id === id) {\n return this.toAccountContext(this.temporaryAccount)\n }\n\n const account = this.accounts.get(id)\n if (account) {\n return this.toAccountContext(account)\n }\n\n return null\n }\n\n /**\n * Get account context by index.\n * Index 0 is the temporary account (if exists), otherwise the first registered account.\n * Returns null if index is out of bounds.\n */\n getAccountContextByIndex(index: number): AccountContext | null {\n // Build the same order as getAccountStatus()\n const allAccounts: Array<AccountRuntime> = []\n\n if (this.temporaryAccount) {\n allAccounts.push(this.temporaryAccount)\n }\n\n for (const id of this.accountOrder) {\n const account = this.accounts.get(id)\n if (account) {\n allAccounts.push(account)\n }\n }\n\n if (index < 0 || index >= allAccounts.length) {\n return null\n }\n\n return this.toAccountContext(allAccounts[index])\n }\n\n /**\n * Get the total number of accounts (including temporary).\n */\n getAccountCount(): number {\n return (this.temporaryAccount ? 1 : 0) + this.accountOrder.length\n }\n\n /**\n * Convert AccountRuntime to AccountContext for service calls.\n */\n private toAccountContext(account: AccountRuntime): AccountContext {\n return {\n accountLogin: account.accountLogin,\n githubToken: account.githubToken,\n copilotToken: account.copilotToken,\n ...(account.copilotApiUrl !== undefined ?\n { copilotApiUrl: account.copilotApiUrl }\n : {}),\n accountType: account.accountType,\n vsCodeVersion: account.vsCodeVersion,\n clientDeviceId: account.clientDeviceId,\n clientMachineId: account.clientMachineId,\n clientSessionId: account.clientSessionId,\n }\n }\n\n /**\n * Start watching the registry file for changes.\n * Enables hot reload of accounts when the file is modified.\n */\n private startRegistryWatcher(): void {\n // Stop existing watcher if any\n this.stopRegistryWatcher()\n\n try {\n this.registryWatcher = fs.watch(\n PATHS.ACCOUNTS_REGISTRY_PATH,\n (eventType) => {\n // Only react to 'change' events (file content modified)\n if (eventType === \"change\") {\n this.scheduleReload()\n }\n },\n )\n\n // Successful start: reset restart backoff.\n this.registryWatcherRestartDelayMs = WATCHER_RESTART_INITIAL_DELAY_MS\n if (this.registryWatcherRestartTimer) {\n clearTimeout(this.registryWatcherRestartTimer)\n this.registryWatcherRestartTimer = undefined\n }\n\n // Handle watcher errors (e.g., file deleted)\n this.registryWatcher.on(\"error\", (error) => {\n consola.debug(\"Registry watcher error:\", error)\n\n const delayMs = this.registryWatcherRestartDelayMs\n this.registryWatcherRestartDelayMs = Math.min(\n this.registryWatcherRestartDelayMs * 2,\n WATCHER_RESTART_MAX_DELAY_MS,\n )\n\n // Close broken watcher to avoid repeated error events.\n this.stopRegistryWatcher()\n\n // Try to restart the watcher after a delay (with backoff)\n this.registryWatcherRestartTimer = setTimeout(() => {\n this.registryWatcherRestartTimer = undefined\n this.startRegistryWatcher()\n }, delayMs)\n\n consola.debug(`Restarting registry watcher in ${delayMs}ms`)\n })\n\n consola.debug(\"Started registry file watcher\")\n } catch (error) {\n consola.warn(\"Failed to start registry watcher:\", error)\n }\n }\n\n /**\n * Immediately reload the registry, bypassing the debounce delay.\n * If a reload is already running, waits for it to complete and then\n * runs another reload to ensure the latest changes are captured.\n */\n async reloadRegistryNow(): Promise<void> {\n if (this.reloadDebounceTimer) {\n clearTimeout(this.reloadDebounceTimer)\n this.reloadDebounceTimer = undefined\n }\n // Wait for any in-progress reload before starting a fresh one\n if (this.currentReloadPromise) {\n await this.currentReloadPromise\n }\n await this.reloadRegistry()\n }\n\n /**\n * Schedule a registry reload with debouncing.\n */\n private scheduleReload(): void {\n // Clear existing timer\n if (this.reloadDebounceTimer) {\n clearTimeout(this.reloadDebounceTimer)\n }\n\n // Schedule reload after debounce delay\n this.reloadDebounceTimer = setTimeout(() => {\n void this.reloadRegistry()\n }, RELOAD_DEBOUNCE_MS)\n }\n\n /**\n * Reload the registry and perform incremental updates.\n * Adds new accounts, removes deleted ones, and reinitializes existing accounts\n * when token/accountType changes.\n */\n private async reloadRegistry(): Promise<void> {\n // Prevent concurrent reloads\n if (this.isReloading) {\n return\n }\n this.isReloading = true\n\n this.currentReloadPromise = (async () => {\n try {\n const newMetas = await listAccountsFromRegistry()\n const newIds = new Set(newMetas.map((m) => m.id))\n const currentIds = new Set(this.accountOrder)\n\n // Track changes for logging\n const added: Array<string> = []\n const removed: Array<string> = []\n const updated: Array<string> = []\n\n this.removeDeletedAccounts(currentIds, newIds, removed)\n\n // Add new accounts (newIds - currentIds)\n for (const meta of newMetas) {\n if (!currentIds.has(meta.id)) {\n await this.addNewAccount(meta, added)\n }\n }\n\n // Update existing accounts when meta/token changed\n await this.reinitializeUpdatedAccounts(newMetas, currentIds, updated)\n\n // Update accountOrder to reflect new order\n this.accountOrder = newMetas\n .map((m) => m.id)\n .filter((id) => this.accounts.has(id))\n\n // Reset load-balance cursor on account list/order changes.\n this.loadBalanceCursor = 0\n\n this.logRegistryReloadChanges(added, removed, updated)\n } catch (error) {\n consola.error(\"Failed to reload registry:\", error)\n this.shutdown()\n process.exit(1)\n } finally {\n this.isReloading = false\n this.currentReloadPromise = undefined\n }\n })()\n\n await this.currentReloadPromise\n }\n\n private removeDeletedAccounts(\n currentIds: Set<string>,\n newIds: Set<string>,\n removed: Array<string>,\n ): void {\n for (const id of currentIds) {\n if (!newIds.has(id)) {\n const account = this.accounts.get(id)\n if (!account) {\n continue\n }\n\n this.stopTokenRefresh(account)\n this.stopSessionRefresh(account)\n this.accounts.delete(id)\n removed.push(id)\n }\n }\n }\n\n private async reinitializeUpdatedAccounts(\n newMetas: Array<AccountMeta>,\n currentIds: Set<string>,\n updated: Array<string>,\n ): Promise<void> {\n for (const meta of newMetas) {\n if (!currentIds.has(meta.id)) {\n continue\n }\n\n const account = this.accounts.get(meta.id)\n if (!account) {\n continue\n }\n\n const token = await loadAccountToken(meta.id)\n if (!token) {\n consola.warn(`No token found for account ${meta.id}, skipping update`)\n continue\n }\n\n const accountTypeChanged = account.accountType !== meta.accountType\n const tokenChanged = account.githubToken !== token\n const addedAtChanged = account.addedAt !== meta.addedAt\n\n // Keep runtime metadata in sync with the registry.\n if (accountTypeChanged) {\n account.accountType = meta.accountType\n }\n if (addedAtChanged) {\n account.addedAt = meta.addedAt\n }\n // Always sync the enabled flag so toggle takes effect immediately.\n account.enabled = meta.enabled\n account.accountLogin = meta.id\n if (tokenChanged) {\n account.githubToken = token\n }\n\n if (!accountTypeChanged && !tokenChanged) {\n continue\n }\n\n try {\n await this.initializeAccount(account)\n updated.push(meta.id)\n } catch (error) {\n consola.error(\n `Failed to reinitialize account ${meta.id} after update:`,\n error,\n )\n account.failed = true\n account.failureReason = String(error)\n updated.push(`${meta.id} (failed)`)\n }\n }\n }\n\n private logRegistryReloadChanges(\n added: Array<string>,\n removed: Array<string>,\n updated: Array<string>,\n ): void {\n if (added.length === 0 && removed.length === 0 && updated.length === 0) {\n return\n }\n\n const changes: Array<string> = []\n if (added.length > 0) {\n changes.push(`added: ${added.join(\", \")}`)\n }\n if (removed.length > 0) {\n changes.push(`removed: ${removed.join(\", \")}`)\n }\n if (updated.length > 0) {\n changes.push(`updated: ${updated.join(\", \")}`)\n }\n\n consola.info(\n `Registry reloaded (${changes.join(\"; \")}). Total: ${this.accounts.size} account(s)`,\n )\n }\n\n /**\n * Helper to add a new account during reload.\n */\n private async addNewAccount(\n meta: { id: string; accountType: AccountType; addedAt: number },\n added: Array<string>,\n ): Promise<void> {\n const token = await loadAccountToken(meta.id)\n if (!token) {\n consola.warn(`No token found for new account ${meta.id}, skipping`)\n return\n }\n\n const runtime: AccountRuntime = {\n ...meta,\n accountLogin: meta.id,\n githubToken: token,\n vsCodeVersion: this.vsCodeVersion,\n }\n\n try {\n await this.initializeAccount(runtime)\n this.accounts.set(meta.id, runtime)\n added.push(meta.id)\n } catch (error) {\n consola.error(`Failed to initialize new account ${meta.id}:`, error)\n runtime.failed = true\n runtime.failureReason = String(error)\n this.accounts.set(meta.id, runtime)\n added.push(`${meta.id} (failed)`)\n }\n }\n\n /**\n * Stop the registry file watcher.\n */\n private stopRegistryWatcher(): void {\n if (this.reloadDebounceTimer) {\n clearTimeout(this.reloadDebounceTimer)\n this.reloadDebounceTimer = undefined\n }\n if (this.registryWatcherRestartTimer) {\n clearTimeout(this.registryWatcherRestartTimer)\n this.registryWatcherRestartTimer = undefined\n }\n if (this.registryWatcher) {\n this.registryWatcher.close()\n this.registryWatcher = undefined\n }\n }\n\n /**\n * Shutdown the manager and clean up resources.\n */\n shutdown(): void {\n this.sessionOwnershipGeneration++\n this.stopRegistryWatcher()\n this.stopAllTokenRefresh()\n this.stopAllSessionRefresh()\n this.stopModelsRefresh()\n this.affinityCache.clearMemory()\n this.sessionOwnership.clear()\n this.loadBalanceCursor = 0\n this.accounts.clear()\n this.accountOrder = []\n this.temporaryAccount = undefined\n }\n}\n\n/** Singleton instance of AccountsManager */\nexport const accountsManager = new AccountsManager({\n persistentAffinityStore: getSharedSessionAffinityStore,\n})\n"],"mappings":"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"}
|