@ashx-j/lunr 0.2.12 → 0.2.14

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.
Files changed (225) hide show
  1. package/CHANGELOG.md +16 -1
  2. package/README.md +6 -3
  3. package/dist/builtin-extensions/ashxj-tui.d.ts +16 -1
  4. package/dist/builtin-extensions/ashxj-tui.d.ts.map +1 -1
  5. package/dist/builtin-extensions/ashxj-tui.js +44 -20
  6. package/dist/builtin-extensions/ashxj-tui.js.map +1 -1
  7. package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts +2 -0
  8. package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts.map +1 -1
  9. package/dist/builtin-extensions/pi-subagents/src/extension/index.js +27 -22
  10. package/dist/builtin-extensions/pi-subagents/src/extension/index.js.map +1 -1
  11. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.d.ts.map +1 -1
  12. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.js +5 -2
  13. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.js.map +1 -1
  14. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.d.ts.map +1 -1
  15. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.js +12 -1
  16. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.js.map +1 -1
  17. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-status.d.ts +1 -0
  18. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-status.d.ts.map +1 -1
  19. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-status.js +3 -2
  20. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-status.js.map +1 -1
  21. package/dist/builtin-extensions/pi-subagents/src/runs/background/chain-append.d.ts.map +1 -1
  22. package/dist/builtin-extensions/pi-subagents/src/runs/background/chain-append.js +1 -0
  23. package/dist/builtin-extensions/pi-subagents/src/runs/background/chain-append.js.map +1 -1
  24. package/dist/builtin-extensions/pi-subagents/src/runs/background/chain-root-attachment.d.ts.map +1 -1
  25. package/dist/builtin-extensions/pi-subagents/src/runs/background/chain-root-attachment.js +3 -0
  26. package/dist/builtin-extensions/pi-subagents/src/runs/background/chain-root-attachment.js.map +1 -1
  27. package/dist/builtin-extensions/pi-subagents/src/runs/background/fleet-view.d.ts.map +1 -1
  28. package/dist/builtin-extensions/pi-subagents/src/runs/background/fleet-view.js +3 -3
  29. package/dist/builtin-extensions/pi-subagents/src/runs/background/fleet-view.js.map +1 -1
  30. package/dist/builtin-extensions/pi-subagents/src/runs/background/run-status.d.ts.map +1 -1
  31. package/dist/builtin-extensions/pi-subagents/src/runs/background/run-status.js +2 -2
  32. package/dist/builtin-extensions/pi-subagents/src/runs/background/run-status.js.map +1 -1
  33. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.d.ts.map +1 -1
  34. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.js +3 -0
  35. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.js.map +1 -1
  36. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.d.ts.map +1 -1
  37. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js +7 -1
  38. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js.map +1 -1
  39. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.d.ts.map +1 -1
  40. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js +2 -0
  41. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js.map +1 -1
  42. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts +1 -0
  43. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts.map +1 -1
  44. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js +19 -3
  45. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js.map +1 -1
  46. package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.d.ts +10 -1
  47. package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.d.ts.map +1 -1
  48. package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.js +19 -0
  49. package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.js.map +1 -1
  50. package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.d.ts +1 -0
  51. package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.d.ts.map +1 -1
  52. package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.js.map +1 -1
  53. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.d.ts +2 -1
  54. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.d.ts.map +1 -1
  55. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.js +17 -0
  56. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.js.map +1 -1
  57. package/dist/builtin-extensions/pi-subagents/src/shared/formatters.d.ts +3 -1
  58. package/dist/builtin-extensions/pi-subagents/src/shared/formatters.d.ts.map +1 -1
  59. package/dist/builtin-extensions/pi-subagents/src/shared/formatters.js +14 -3
  60. package/dist/builtin-extensions/pi-subagents/src/shared/formatters.js.map +1 -1
  61. package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts +14 -0
  62. package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts.map +1 -1
  63. package/dist/builtin-extensions/pi-subagents/src/shared/types.js.map +1 -1
  64. package/dist/builtin-extensions/pi-subagents/src/tui/fleet.d.ts.map +1 -1
  65. package/dist/builtin-extensions/pi-subagents/src/tui/fleet.js +2 -2
  66. package/dist/builtin-extensions/pi-subagents/src/tui/fleet.js.map +1 -1
  67. package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts.map +1 -1
  68. package/dist/builtin-extensions/pi-subagents/src/tui/render.js +12 -10
  69. package/dist/builtin-extensions/pi-subagents/src/tui/render.js.map +1 -1
  70. package/dist/catalog/models.json +1 -1
  71. package/dist/catalog/providers/amazon-bedrock.json +1 -1
  72. package/dist/catalog/providers/anthropic.json +1 -1
  73. package/dist/catalog/providers/azure-openai-responses.json +1 -1
  74. package/dist/catalog/providers/cloudflare-ai-gateway.json +1 -1
  75. package/dist/catalog/providers/cloudflare-workers-ai.json +1 -1
  76. package/dist/catalog/providers/fireworks.json +1 -1
  77. package/dist/catalog/providers/github-copilot.json +1 -1
  78. package/dist/catalog/providers/google-vertex.json +1 -1
  79. package/dist/catalog/providers/google.json +1 -1
  80. package/dist/catalog/providers/groq.json +1 -1
  81. package/dist/catalog/providers/huggingface.json +1 -1
  82. package/dist/catalog/providers/nvidia.json +1 -1
  83. package/dist/catalog/providers/openai-codex.json +1 -1
  84. package/dist/catalog/providers/openai.json +1 -1
  85. package/dist/catalog/providers/opencode-go.json +1 -1
  86. package/dist/catalog/providers/opencode.json +1 -1
  87. package/dist/catalog/providers/openrouter.json +1 -1
  88. package/dist/catalog/providers/together.json +1 -1
  89. package/dist/catalog/providers/vercel-ai-gateway.json +1 -1
  90. package/dist/catalog/publication.json +131 -3
  91. package/dist/cli/list-models.d.ts.map +1 -1
  92. package/dist/cli/list-models.js +1 -0
  93. package/dist/cli/list-models.js.map +1 -1
  94. package/dist/cli.d.ts.map +1 -1
  95. package/dist/cli.js +52 -27
  96. package/dist/cli.js.map +1 -1
  97. package/dist/core/catalog-cache-scope.d.ts +3 -0
  98. package/dist/core/catalog-cache-scope.d.ts.map +1 -0
  99. package/dist/core/catalog-cache-scope.js +12 -0
  100. package/dist/core/catalog-cache-scope.js.map +1 -0
  101. package/dist/core/catalog-merge.d.ts +2 -0
  102. package/dist/core/catalog-merge.d.ts.map +1 -1
  103. package/dist/core/catalog-merge.js +29 -2
  104. package/dist/core/catalog-merge.js.map +1 -1
  105. package/dist/core/catalog-refresh-polling.d.ts +8 -0
  106. package/dist/core/catalog-refresh-polling.d.ts.map +1 -0
  107. package/dist/core/catalog-refresh-polling.js +30 -0
  108. package/dist/core/catalog-refresh-polling.js.map +1 -0
  109. package/dist/core/codex-catalog.d.ts +3 -0
  110. package/dist/core/codex-catalog.d.ts.map +1 -0
  111. package/dist/core/codex-catalog.js +15 -0
  112. package/dist/core/codex-catalog.js.map +1 -0
  113. package/dist/core/context-breakdown.d.ts +3 -1
  114. package/dist/core/context-breakdown.d.ts.map +1 -1
  115. package/dist/core/context-breakdown.js +5 -2
  116. package/dist/core/context-breakdown.js.map +1 -1
  117. package/dist/core/customize.d.ts +2 -4
  118. package/dist/core/customize.d.ts.map +1 -1
  119. package/dist/core/customize.js +2 -8
  120. package/dist/core/customize.js.map +1 -1
  121. package/dist/core/footer-data-provider.d.ts +3 -4
  122. package/dist/core/footer-data-provider.d.ts.map +1 -1
  123. package/dist/core/footer-data-provider.js +54 -82
  124. package/dist/core/footer-data-provider.js.map +1 -1
  125. package/dist/core/live-catalog.d.ts +5 -2
  126. package/dist/core/live-catalog.d.ts.map +1 -1
  127. package/dist/core/live-catalog.js +108 -27
  128. package/dist/core/live-catalog.js.map +1 -1
  129. package/dist/core/model-runtime.d.ts +8 -0
  130. package/dist/core/model-runtime.d.ts.map +1 -1
  131. package/dist/core/model-runtime.js +64 -12
  132. package/dist/core/model-runtime.js.map +1 -1
  133. package/dist/core/official-catalog.d.ts +4 -0
  134. package/dist/core/official-catalog.d.ts.map +1 -1
  135. package/dist/core/official-catalog.js +86 -21
  136. package/dist/core/official-catalog.js.map +1 -1
  137. package/dist/core/settings-manager.d.ts +7 -6
  138. package/dist/core/settings-manager.d.ts.map +1 -1
  139. package/dist/core/settings-manager.js +13 -17
  140. package/dist/core/settings-manager.js.map +1 -1
  141. package/dist/core/slash-commands.d.ts.map +1 -1
  142. package/dist/core/slash-commands.js +1 -0
  143. package/dist/core/slash-commands.js.map +1 -1
  144. package/dist/index.d.ts +1 -1
  145. package/dist/index.d.ts.map +1 -1
  146. package/dist/index.js.map +1 -1
  147. package/dist/main.d.ts +2 -0
  148. package/dist/main.d.ts.map +1 -1
  149. package/dist/main.js +106 -50
  150. package/dist/main.js.map +1 -1
  151. package/dist/migrations.d.ts +2 -0
  152. package/dist/migrations.d.ts.map +1 -1
  153. package/dist/migrations.js +14 -4
  154. package/dist/migrations.js.map +1 -1
  155. package/dist/modes/interactive/components/assistant-message.d.ts +1 -3
  156. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  157. package/dist/modes/interactive/components/assistant-message.js +4 -32
  158. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  159. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  160. package/dist/modes/interactive/components/custom-editor.js +2 -1
  161. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  162. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  163. package/dist/modes/interactive/components/model-selector.js +4 -1
  164. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  165. package/dist/modes/interactive/components/plan-message.d.ts +1 -3
  166. package/dist/modes/interactive/components/plan-message.d.ts.map +1 -1
  167. package/dist/modes/interactive/components/plan-message.js +1 -16
  168. package/dist/modes/interactive/components/plan-message.js.map +1 -1
  169. package/dist/modes/interactive/components/settings-selector.d.ts +3 -5
  170. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  171. package/dist/modes/interactive/components/settings-selector.js +113 -117
  172. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  173. package/dist/modes/interactive/components/user-message.d.ts +1 -3
  174. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  175. package/dist/modes/interactive/components/user-message.js +2 -19
  176. package/dist/modes/interactive/components/user-message.js.map +1 -1
  177. package/dist/modes/interactive/interactive-mode.d.ts +12 -1
  178. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  179. package/dist/modes/interactive/interactive-mode.js +153 -130
  180. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  181. package/dist/modes/interactive/skill-tag-autocomplete.d.ts +13 -0
  182. package/dist/modes/interactive/skill-tag-autocomplete.d.ts.map +1 -0
  183. package/dist/modes/interactive/skill-tag-autocomplete.js +72 -0
  184. package/dist/modes/interactive/skill-tag-autocomplete.js.map +1 -0
  185. package/dist/modes/interactive/theme/moon.json +0 -1
  186. package/dist/modes/interactive/theme/theme-schema.json +3 -3
  187. package/dist/modes/interactive/theme/theme.d.ts +1 -1
  188. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  189. package/dist/modes/interactive/theme/theme.js +95 -90
  190. package/dist/modes/interactive/theme/theme.js.map +1 -1
  191. package/dist/startup/interactive-view.d.ts +55 -0
  192. package/dist/startup/interactive-view.d.ts.map +1 -0
  193. package/dist/startup/interactive-view.js +332 -0
  194. package/dist/startup/interactive-view.js.map +1 -0
  195. package/dist/startup/launch-routing.d.ts +8 -0
  196. package/dist/startup/launch-routing.d.ts.map +1 -0
  197. package/dist/startup/launch-routing.js +29 -0
  198. package/dist/startup/launch-routing.js.map +1 -0
  199. package/dist/startup/startup-milestones.d.ts +4 -0
  200. package/dist/startup/startup-milestones.d.ts.map +1 -0
  201. package/dist/startup/startup-milestones.js +14 -0
  202. package/dist/startup/startup-milestones.js.map +1 -0
  203. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  204. package/dist/utils/syntax-highlight.js +10 -4
  205. package/dist/utils/syntax-highlight.js.map +1 -1
  206. package/docs/features.md +2 -2
  207. package/docs/interactive-startup.md +58 -0
  208. package/docs/keybindings.md +1 -1
  209. package/docs/model-catalog.md +29 -0
  210. package/docs/quickstart.md +1 -1
  211. package/docs/settings.md +2 -3
  212. package/docs/skills.md +10 -0
  213. package/docs/terminal-setup.md +2 -2
  214. package/docs/usage.md +2 -1
  215. package/docs/windows.md +1 -1
  216. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  217. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  218. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  219. package/examples/extensions/gondolin/package-lock.json +2 -2
  220. package/examples/extensions/gondolin/package.json +1 -1
  221. package/examples/extensions/sandbox/package-lock.json +2 -2
  222. package/examples/extensions/sandbox/package.json +1 -1
  223. package/examples/extensions/with-deps/package-lock.json +2 -2
  224. package/examples/extensions/with-deps/package.json +1 -1
  225. package/package.json +16 -16
@@ -1 +1 @@
1
- {"version":3,"file":"live-catalog.js","sourceRoot":"","sources":["../../src/core/live-catalog.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Api, Credential, Model } from \"@ashx-j/lunr-ai\";\nimport { VERSION } from \"../config.ts\";\nimport { getPiUserAgent } from \"../utils/pi-user-agent.ts\";\nimport { modelKey } from \"./official-catalog.ts\";\n\nexport const LIVE_CATALOG_TIMEOUT_MS = 4000;\nexport const INCOMPLETE_PROMPT_CAP = 8;\nexport const DEFAULT_CONTEXT_WINDOW = 128000;\nexport const DEFAULT_MAX_TOKENS = 8192;\n\nexport const LIVE_LIST_PROVIDER_IDS = [\n\t\"xai\",\n\t\"openrouter\",\n\t\"qwen-cloud\",\n\t\"qwen-cloud-cn\",\n\t\"groq\",\n\t\"openai\",\n\t\"deepseek\",\n] as const;\n\nexport type LiveListProviderId = (typeof LIVE_LIST_PROVIDER_IDS)[number];\n\nconst LIVE_LIST_PROVIDER_SET = new Set<string>(LIVE_LIST_PROVIDER_IDS);\n\nexport function isLiveListProvider(providerId: string): providerId is LiveListProviderId {\n\treturn LIVE_LIST_PROVIDER_SET.has(providerId);\n}\n\nexport interface LiveFieldSupply {\n\tcontextWindow: boolean;\n\tmaxTokens: boolean;\n\tinput: boolean;\n\tname: boolean;\n\tcost: boolean;\n\treasoning: boolean;\n}\n\nexport interface LiveModelDiscovery {\n\tmodel: Model<Api>;\n\tsupplied: LiveFieldSupply;\n}\n\nexport interface IncompleteLiveModel {\n\tprovider: string;\n\tid: string;\n\tname: string;\n\tmissing: Array<\"contextWindow\" | \"maxTokens\" | \"input\">;\n\tdraft: Model<Api>;\n\tavailableApis: Api[];\n}\n\nexport type LiveCatalogStatus = \"ok\" | \"timeout\" | \"error\" | \"skipped\";\n\nexport interface LiveCatalogResult {\n\tproviderId: string;\n\tstatus: LiveCatalogStatus;\n\tdiscoveries: LiveModelDiscovery[];\n\tadded: number;\n\ttotal: number;\n\tincomplete: IncompleteLiveModel[];\n\terror?: string;\n}\n\nconst ZERO_COST = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };\nconst NONE_SUPPLIED: LiveFieldSupply = {\n\tcontextWindow: false,\n\tmaxTokens: false,\n\tinput: false,\n\tname: false,\n\tcost: false,\n\treasoning: false,\n};\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction asFiniteNumber(value: unknown): number | undefined {\n\tif (typeof value === \"number\" && Number.isFinite(value)) return value;\n\tif (typeof value === \"string\" && value.trim()) {\n\t\tconst parsed = Number(value);\n\t\tif (Number.isFinite(parsed)) return parsed;\n\t}\n\treturn undefined;\n}\n\nfunction roundCost(value: number): number {\n\treturn Number(value.toFixed(6));\n}\n\nexport function modelsListUrl(baseUrl: string): string {\n\treturn `${baseUrl.replace(/\\/+$/u, \"\")}/models`;\n}\n\nexport function credentialAuthHeaders(credential: Credential | undefined): Record<string, string> {\n\tif (!credential) return {};\n\tif (credential.type === \"api_key\" && credential.key) {\n\t\treturn { Authorization: `Bearer ${credential.key}` };\n\t}\n\tif (credential.type === \"oauth\" && typeof credential.access === \"string\" && credential.access) {\n\t\treturn { Authorization: `Bearer ${credential.access}` };\n\t}\n\treturn {};\n}\n\n/** OpenAI `{ data: [{ id, ... }] }` plus a bare array. */\nexport function parseOpenAIModelsList(value: unknown): Record<string, unknown>[] {\n\tconst entries = isRecord(value) && Array.isArray(value.data) ? value.data : Array.isArray(value) ? value : [];\n\tconst rows: Record<string, unknown>[] = [];\n\tfor (const entry of entries) {\n\t\tif (typeof entry === \"string\" && entry.trim()) {\n\t\t\trows.push({ id: entry.trim() });\n\t\t\tcontinue;\n\t\t}\n\t\tif (isRecord(entry) && typeof entry.id === \"string\" && entry.id.trim()) rows.push(entry);\n\t}\n\treturn rows;\n}\n\nexport function firstBakedInModel(models: readonly Model<Api>[]): Model<Api> | undefined {\n\treturn models[0];\n}\n\nexport function uniqueApis(models: readonly Model<Api>[]): Api[] {\n\tconst seen = new Set<Api>();\n\tconst apis: Api[] = [];\n\tfor (const model of models) {\n\t\tif (seen.has(model.api)) continue;\n\t\tseen.add(model.api);\n\t\tapis.push(model.api);\n\t}\n\treturn apis;\n}\n\nexport function synthesizeLiveModel(\n\tid: string,\n\ttemplate: Model<Api>,\n\traw: Record<string, unknown> = {},\n): LiveModelDiscovery {\n\tconst name = typeof raw.name === \"string\" && raw.name.trim() ? raw.name.trim() : id;\n\treturn {\n\t\tmodel: {\n\t\t\tid,\n\t\t\tname,\n\t\t\tapi: template.api,\n\t\t\tprovider: template.provider,\n\t\t\tbaseUrl: template.baseUrl,\n\t\t\treasoning: template.reasoning,\n\t\t\tinput: template.input ?? [\"text\"],\n\t\t\tcost: ZERO_COST,\n\t\t\tcontextWindow: DEFAULT_CONTEXT_WINDOW,\n\t\t\tmaxTokens: DEFAULT_MAX_TOKENS,\n\t\t\tcompat: template.compat,\n\t\t\tthinkingLevelMap: template.thinkingLevelMap,\n\t\t},\n\t\tsupplied: {\n\t\t\t...NONE_SUPPLIED,\n\t\t\tname: typeof raw.name === \"string\" && raw.name.trim().length > 0,\n\t\t},\n\t};\n}\n\n/** OpenRouter field mapping (tools filter, pricing × 1e6, context) from generate-models. */\nexport function mapOpenRouterModel(raw: Record<string, unknown>, template: Model<Api>): LiveModelDiscovery | undefined {\n\tconst id = typeof raw.id === \"string\" ? raw.id.trim() : \"\";\n\tif (!id) return undefined;\n\tconst supported = Array.isArray(raw.supported_parameters) ? raw.supported_parameters : [];\n\tif (!supported.includes(\"tools\")) return undefined;\n\n\tconst architecture = isRecord(raw.architecture) ? raw.architecture : undefined;\n\tconst modality = typeof architecture?.modality === \"string\" ? architecture.modality : \"\";\n\tconst input: (\"text\" | \"image\")[] = [\"text\"];\n\tif (modality.includes(\"image\")) input.push(\"image\");\n\n\tconst pricing = isRecord(raw.pricing) ? raw.pricing : undefined;\n\tconst inputCost = roundCost((asFiniteNumber(pricing?.prompt) ?? 0) * 1_000_000);\n\tconst outputCost = roundCost((asFiniteNumber(pricing?.completion) ?? 0) * 1_000_000);\n\tconst cacheReadCost = roundCost((asFiniteNumber(pricing?.input_cache_read) ?? 0) * 1_000_000);\n\tconst cacheWriteCost = roundCost((asFiniteNumber(pricing?.input_cache_write) ?? 0) * 1_000_000);\n\n\tconst topProvider = isRecord(raw.top_provider) ? raw.top_provider : undefined;\n\tconst contextWindow = asFiniteNumber(topProvider?.context_length) ?? asFiniteNumber(raw.context_length);\n\tconst maxTokens = asFiniteNumber(topProvider?.max_completion_tokens) ?? asFiniteNumber(raw.max_completion_tokens);\n\n\tconst name = typeof raw.name === \"string\" && raw.name.trim() ? raw.name.trim() : id;\n\treturn {\n\t\tmodel: {\n\t\t\tid,\n\t\t\tname,\n\t\t\tapi: template.api,\n\t\t\tprovider: template.provider,\n\t\t\tbaseUrl: template.baseUrl,\n\t\t\treasoning: supported.includes(\"reasoning\") || template.reasoning,\n\t\t\tinput,\n\t\t\tcost: {\n\t\t\t\tinput: inputCost,\n\t\t\t\toutput: outputCost,\n\t\t\t\tcacheRead: cacheReadCost,\n\t\t\t\tcacheWrite: cacheWriteCost,\n\t\t\t},\n\t\t\tcontextWindow: contextWindow ?? DEFAULT_CONTEXT_WINDOW,\n\t\t\tmaxTokens: maxTokens ?? DEFAULT_MAX_TOKENS,\n\t\t\tcompat: template.compat,\n\t\t\tthinkingLevelMap: template.thinkingLevelMap,\n\t\t},\n\t\tsupplied: {\n\t\t\tcontextWindow: contextWindow !== undefined,\n\t\t\tmaxTokens: maxTokens !== undefined,\n\t\t\tinput: true,\n\t\t\tname: typeof raw.name === \"string\" && raw.name.trim().length > 0,\n\t\t\tcost: pricing !== undefined,\n\t\t\treasoning: supported.includes(\"reasoning\"),\n\t\t},\n\t};\n}\n\nexport function discoverLiveModels(\n\tproviderId: string,\n\tpayload: unknown,\n\tbakedIn: readonly Model<Api>[],\n): LiveModelDiscovery[] {\n\tconst template = firstBakedInModel(bakedIn);\n\tif (!template) return [];\n\tconst rows = parseOpenAIModelsList(payload);\n\tconst discoveries: LiveModelDiscovery[] = [];\n\tfor (const raw of rows) {\n\t\tconst id = typeof raw.id === \"string\" ? raw.id.trim() : \"\";\n\t\tif (!id) continue;\n\t\tif (providerId === \"openrouter\") {\n\t\t\tconst mapped = mapOpenRouterModel(raw, { ...template, provider: providerId });\n\t\t\tif (mapped) discoveries.push(mapped);\n\t\t\tcontinue;\n\t\t}\n\t\tdiscoveries.push(synthesizeLiveModel(id, { ...template, provider: providerId }, raw));\n\t}\n\treturn discoveries;\n}\n\nexport function missingLiveFields(supplied: LiveFieldSupply): Array<\"contextWindow\" | \"maxTokens\" | \"input\"> {\n\tconst missing: Array<\"contextWindow\" | \"maxTokens\" | \"input\"> = [];\n\tif (!supplied.contextWindow) missing.push(\"contextWindow\");\n\tif (!supplied.maxTokens) missing.push(\"maxTokens\");\n\tif (!supplied.input) missing.push(\"input\");\n\treturn missing;\n}\n\nexport function isLiveModelIncomplete(discovery: LiveModelDiscovery, knownKeys: Set<string>): boolean {\n\tif (knownKeys.has(modelKey(discovery.model.provider, discovery.model.id))) return false;\n\treturn missingLiveFields(discovery.supplied).length > 0;\n}\n\nexport function collectIncompleteLiveModels(\n\tdiscoveries: readonly LiveModelDiscovery[],\n\tbakedIn: readonly Model<Api>[],\n\tknownKeys: Set<string>,\n): IncompleteLiveModel[] {\n\tconst apis = uniqueApis(bakedIn);\n\tconst incomplete: IncompleteLiveModel[] = [];\n\tfor (const discovery of discoveries) {\n\t\tif (!isLiveModelIncomplete(discovery, knownKeys)) continue;\n\t\tincomplete.push({\n\t\t\tprovider: discovery.model.provider,\n\t\t\tid: discovery.model.id,\n\t\t\tname: discovery.model.name,\n\t\t\tmissing: missingLiveFields(discovery.supplied),\n\t\t\tdraft: discovery.model,\n\t\t\tavailableApis: apis,\n\t\t});\n\t}\n\treturn incomplete;\n}\n\nexport function buildLiveOverlay(\n\tbakedIn: readonly Model<Api>[],\n\tdiscoveries: readonly LiveModelDiscovery[],\n): Model<Api>[] {\n\tconst bakedById = new Map(bakedIn.map((model) => [model.id, model]));\n\tconst overlay: Model<Api>[] = [];\n\tfor (const discovery of discoveries) {\n\t\tconst baked = bakedById.get(discovery.model.id);\n\t\tif (!baked) {\n\t\t\toverlay.push(discovery.model);\n\t\t\tcontinue;\n\t\t}\n\t\toverlay.push({\n\t\t\t...baked,\n\t\t\tname: discovery.supplied.name ? discovery.model.name : baked.name,\n\t\t\tcontextWindow: discovery.supplied.contextWindow ? discovery.model.contextWindow : baked.contextWindow,\n\t\t\tmaxTokens: discovery.supplied.maxTokens ? discovery.model.maxTokens : baked.maxTokens,\n\t\t\tinput: discovery.supplied.input ? discovery.model.input : baked.input,\n\t\t\tcost: discovery.supplied.cost ? discovery.model.cost : baked.cost,\n\t\t\treasoning: discovery.supplied.reasoning ? discovery.model.reasoning : baked.reasoning,\n\t\t});\n\t}\n\treturn overlay;\n}\n\nexport function describeIncomplete(model: IncompleteLiveModel): string {\n\tconst labels: string[] = [];\n\tfor (const field of model.missing) {\n\t\tif (field === \"contextWindow\") labels.push(\"context window\");\n\t\telse if (field === \"maxTokens\") labels.push(\"max tokens\");\n\t\telse labels.push(\"input types\");\n\t}\n\tlet missingText = \"metadata\";\n\tif (labels.length === 1) missingText = labels[0] ?? missingText;\n\telse if (labels.length === 2) missingText = `${labels[0]} and ${labels[1]}`;\n\telse if (labels.length > 2) missingText = `${labels.slice(0, -1).join(\", \")}, and ${labels[labels.length - 1]}`;\n\treturn `New model ${model.provider}/${model.id} — missing ${missingText}.`;\n}\n\nexport function parsePositiveInt(value: string | undefined, fallback: number): number {\n\tif (!value?.trim()) return fallback;\n\tconst parsed = Number(value.trim());\n\tif (!Number.isInteger(parsed) || parsed <= 0) return fallback;\n\treturn parsed;\n}\n\nexport interface IncompleteModelAnswers {\n\tcontextWindow?: number;\n\tmaxTokens?: number;\n\tinput?: (\"text\" | \"image\")[];\n\treasoning?: boolean;\n\tapi?: Api;\n}\n\nexport function applyIncompleteAnswers(draft: Model<Api>, answers: IncompleteModelAnswers): Model<Api> {\n\treturn {\n\t\t...draft,\n\t\tcontextWindow: answers.contextWindow ?? draft.contextWindow,\n\t\tmaxTokens: answers.maxTokens ?? draft.maxTokens,\n\t\tinput: answers.input ?? draft.input,\n\t\treasoning: answers.reasoning ?? draft.reasoning,\n\t\tapi: answers.api ?? draft.api,\n\t};\n}\n\nexport interface FetchLiveProviderModelsOptions {\n\tproviderId: string;\n\tbaseUrl: string;\n\tbakedIn: readonly Model<Api>[];\n\tcredential?: Credential;\n\tknownKeys: Set<string>;\n\ttimeoutMs?: number;\n\tsignal?: AbortSignal;\n\tfetchImpl?: typeof fetch;\n}\n\nexport async function fetchLiveProviderModels(options: FetchLiveProviderModelsOptions): Promise<LiveCatalogResult> {\n\tconst empty: LiveCatalogResult = {\n\t\tproviderId: options.providerId,\n\t\tstatus: \"skipped\",\n\t\tdiscoveries: [],\n\t\tadded: 0,\n\t\ttotal: 0,\n\t\tincomplete: [],\n\t};\n\tconst template = firstBakedInModel(options.bakedIn);\n\tif (!template || !options.baseUrl) return empty;\n\n\tconst timeoutMs = options.timeoutMs ?? LIVE_CATALOG_TIMEOUT_MS;\n\tconst controller = new AbortController();\n\tlet timedOut = false;\n\tconst timer = setTimeout(() => {\n\t\ttimedOut = true;\n\t\tcontroller.abort();\n\t}, timeoutMs);\n\tconst onParentAbort = () => controller.abort();\n\toptions.signal?.addEventListener(\"abort\", onParentAbort, { once: true });\n\tif (options.signal?.aborted) controller.abort();\n\n\ttry {\n\t\tconst fetchImpl = options.fetchImpl ?? fetch;\n\t\tconst response = await Promise.race([\n\t\t\tfetchImpl(modelsListUrl(options.baseUrl), {\n\t\t\t\theaders: {\n\t\t\t\t\taccept: \"application/json\",\n\t\t\t\t\t\"User-Agent\": getPiUserAgent(VERSION),\n\t\t\t\t\t...credentialAuthHeaders(options.credential),\n\t\t\t\t},\n\t\t\t\tsignal: controller.signal,\n\t\t\t}),\n\t\t\tnew Promise<never>((_, reject) => {\n\t\t\t\tconst abortError = new Error(\"The operation was aborted\");\n\t\t\t\tabortError.name = \"AbortError\";\n\t\t\t\tcontroller.signal.addEventListener(\"abort\", () => reject(abortError), { once: true });\n\t\t\t\tif (controller.signal.aborted) reject(abortError);\n\t\t\t}),\n\t\t]);\n\t\tif (!response.ok) {\n\t\t\treturn {\n\t\t\t\t...empty,\n\t\t\t\tstatus: \"error\",\n\t\t\t\terror: `HTTP ${response.status}`,\n\t\t\t};\n\t\t}\n\t\tconst discoveries = discoverLiveModels(options.providerId, await response.json(), options.bakedIn);\n\t\tconst bakedIds = new Set(options.bakedIn.map((model) => model.id));\n\t\tconst added = discoveries.filter((discovery) => !bakedIds.has(discovery.model.id)).length;\n\t\treturn {\n\t\t\tproviderId: options.providerId,\n\t\t\tstatus: \"ok\",\n\t\t\tdiscoveries,\n\t\t\tadded,\n\t\t\ttotal: discoveries.length,\n\t\t\tincomplete: collectIncompleteLiveModels(discoveries, options.bakedIn, options.knownKeys),\n\t\t};\n\t} catch (error) {\n\t\tif (options.signal?.aborted && !timedOut) return { ...empty, status: \"skipped\", error: \"aborted\" };\n\t\tif (timedOut || (error instanceof Error && error.name === \"AbortError\")) {\n\t\t\treturn { ...empty, status: \"timeout\", error: \"timed out\" };\n\t\t}\n\t\treturn {\n\t\t\t...empty,\n\t\t\tstatus: \"error\",\n\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t};\n\t} finally {\n\t\tclearTimeout(timer);\n\t\toptions.signal?.removeEventListener(\"abort\", onParentAbort);\n\t}\n}\n"]}
1
+ {"version":3,"file":"live-catalog.js","sourceRoot":"","sources":["../../src/core/live-catalog.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Api, type Credential, isOpenAiChatModel, type Model, parseOpenAiGptVersion } from \"@ashx-j/lunr-ai\";\nimport { codexModelsUrl, resolveCodexCatalogVersion } from \"@ashx-j/lunr-ai/catalog/codex\";\nimport { normalizeCatalogPricing } from \"@ashx-j/lunr-ai/catalog/metadata\";\nimport { VERSION } from \"../config.ts\";\nimport { getPiUserAgent } from \"../utils/pi-user-agent.ts\";\nimport { discoverCodexModels } from \"./codex-catalog.ts\";\nimport { modelKey } from \"./official-catalog.ts\";\n\nexport const LIVE_CATALOG_TIMEOUT_MS = 4000;\nexport const INCOMPLETE_PROMPT_CAP = 8;\nexport const DEFAULT_CONTEXT_WINDOW = 128000;\nexport const DEFAULT_MAX_TOKENS = 8192;\n\nexport const LIVE_LIST_PROVIDER_IDS = [\n\t\"openai-codex\",\n\t\"xai\",\n\t\"openrouter\",\n\t\"qwen-cloud\",\n\t\"qwen-cloud-cn\",\n\t\"groq\",\n\t\"openai\",\n\t\"deepseek\",\n] as const;\n\nexport type LiveListProviderId = (typeof LIVE_LIST_PROVIDER_IDS)[number];\n\nconst LIVE_LIST_PROVIDER_SET = new Set<string>(LIVE_LIST_PROVIDER_IDS);\n\nexport function isLiveListProvider(providerId: string): providerId is LiveListProviderId {\n\treturn LIVE_LIST_PROVIDER_SET.has(providerId);\n}\n\nexport interface LiveFieldSupply {\n\tcontextWindow: boolean;\n\tmaxTokens: boolean;\n\tinput: boolean;\n\tname: boolean;\n\tcost: boolean;\n\treasoning: boolean;\n}\n\nexport interface LiveModelDiscovery {\n\tmodel: Model<Api>;\n\tsupplied: LiveFieldSupply;\n}\n\nexport interface IncompleteLiveModel {\n\tprovider: string;\n\tid: string;\n\tname: string;\n\tmissing: Array<\"contextWindow\" | \"maxTokens\" | \"input\">;\n\tdraft: Model<Api>;\n\tavailableApis: Api[];\n}\n\nexport type LiveCatalogStatus = \"ok\" | \"timeout\" | \"error\" | \"skipped\";\n\nexport interface LiveCatalogResult {\n\tdiscoveryClientVersion?: string;\n\tproviderId: string;\n\tstatus: LiveCatalogStatus;\n\tdiscoveries: LiveModelDiscovery[];\n\tadded: number;\n\ttotal: number;\n\tincomplete: IncompleteLiveModel[];\n\terror?: string;\n}\n\nconst ZERO_COST = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };\nconst NONE_SUPPLIED: LiveFieldSupply = {\n\tcontextWindow: false,\n\tmaxTokens: false,\n\tinput: false,\n\tname: false,\n\tcost: false,\n\treasoning: false,\n};\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction asFiniteNumber(value: unknown): number | undefined {\n\tif (typeof value === \"number\" && Number.isFinite(value)) return value;\n\tif (typeof value === \"string\" && value.trim()) {\n\t\tconst parsed = Number(value);\n\t\tif (Number.isFinite(parsed)) return parsed;\n\t}\n\treturn undefined;\n}\n\nfunction roundCost(value: number): number {\n\treturn Number(value.toFixed(6));\n}\n\nexport function modelsListUrl(baseUrl: string): string {\n\treturn `${baseUrl.replace(/\\/+$/u, \"\")}/models`;\n}\n\nexport function credentialAuthHeaders(credential: Credential | undefined): Record<string, string> {\n\tif (!credential) return {};\n\tif (credential.type === \"api_key\" && credential.key) {\n\t\treturn { Authorization: `Bearer ${credential.key}` };\n\t}\n\tif (credential.type === \"oauth\" && typeof credential.access === \"string\" && credential.access) {\n\t\treturn { Authorization: `Bearer ${credential.access}` };\n\t}\n\treturn {};\n}\n\n/** OpenAI `{ data: [{ id, ... }] }` plus a bare array. */\nexport function parseOpenAIModelsList(value: unknown): Record<string, unknown>[] {\n\tconst entries = isRecord(value) && Array.isArray(value.data) ? value.data : Array.isArray(value) ? value : [];\n\tconst rows: Record<string, unknown>[] = [];\n\tfor (const entry of entries) {\n\t\tif (typeof entry === \"string\" && entry.trim()) {\n\t\t\trows.push({ id: entry.trim() });\n\t\t\tcontinue;\n\t\t}\n\t\tif (isRecord(entry) && typeof entry.id === \"string\" && entry.id.trim()) rows.push(entry);\n\t}\n\treturn rows;\n}\n\nexport function firstBakedInModel(models: readonly Model<Api>[]): Model<Api> | undefined {\n\treturn models[0];\n}\n\nexport function selectLiveTemplate(\n\tproviderId: string,\n\tid: string,\n\tbakedIn: readonly Model<Api>[],\n): Model<Api> | undefined {\n\tconst exact = bakedIn.find((model) => model.id === id);\n\tif (exact) return exact;\n\tconst version = parseOpenAiGptVersion(id);\n\tif (providerId !== \"openai\" || !version || version.major < 5 || isOpenAiChatModel(id)) {\n\t\treturn firstBakedInModel(bakedIn);\n\t}\n\tlet reasoning: Model<Api> | undefined;\n\tfor (const model of bakedIn) {\n\t\tif (model.reasoning && parseOpenAiGptVersion(model.id)) reasoning = model;\n\t}\n\treturn reasoning ?? firstBakedInModel(bakedIn);\n}\n\nexport function uniqueApis(models: readonly Model<Api>[]): Api[] {\n\tconst seen = new Set<Api>();\n\tconst apis: Api[] = [];\n\tfor (const model of models) {\n\t\tif (seen.has(model.api)) continue;\n\t\tseen.add(model.api);\n\t\tapis.push(model.api);\n\t}\n\treturn apis;\n}\n\nexport function synthesizeLiveModel(\n\tid: string,\n\ttemplate: Model<Api>,\n\traw: Record<string, unknown> = {},\n): LiveModelDiscovery {\n\tconst name = typeof raw.name === \"string\" && raw.name.trim() ? raw.name.trim() : id;\n\tconst exact = id === template.id;\n\tconst discovery: LiveModelDiscovery = {\n\t\tmodel: {\n\t\t\tid,\n\t\t\tname,\n\t\t\tapi: template.api,\n\t\t\tprovider: template.provider,\n\t\t\tbaseUrl: template.baseUrl,\n\t\t\treasoning: template.reasoning,\n\t\t\tinput: exact ? template.input : [\"text\"],\n\t\t\tcost: ZERO_COST,\n\t\t\tcontextWindow: DEFAULT_CONTEXT_WINDOW,\n\t\t\tmaxTokens: DEFAULT_MAX_TOKENS,\n\t\t\tcompat: template.compat,\n\t\t\tthinkingLevelMap: exact ? template.thinkingLevelMap : undefined,\n\t\t\tcatalog: { source: \"provider\", supplied: typeof raw.name === \"string\" ? [\"name\"] : [], pricing: \"unknown\" },\n\t\t},\n\t\tsupplied: {\n\t\t\t...NONE_SUPPLIED,\n\t\t\tname: typeof raw.name === \"string\" && raw.name.trim().length > 0,\n\t\t},\n\t};\n\tconst context = asFiniteNumber(raw.context_window ?? raw.context_length ?? raw.max_context_length);\n\tconst output = asFiniteNumber(raw.max_output_tokens ?? raw.max_completion_tokens);\n\tif (context && context > 0) {\n\t\tdiscovery.model.contextWindow = context;\n\t\tdiscovery.supplied.contextWindow = true;\n\t}\n\tif (output && output > 0) {\n\t\tdiscovery.model.maxTokens = output;\n\t\tdiscovery.supplied.maxTokens = true;\n\t}\n\tif (typeof raw.reasoning === \"boolean\") {\n\t\tdiscovery.model.reasoning = raw.reasoning;\n\t\tdiscovery.supplied.reasoning = true;\n\t}\n\tif (Array.isArray(raw.input_modalities)) {\n\t\tconst input = raw.input_modalities.filter(\n\t\t\t(value): value is \"text\" | \"image\" => value === \"text\" || value === \"image\",\n\t\t);\n\t\tif (input.length) {\n\t\t\tdiscovery.model.input = input;\n\t\t\tdiscovery.supplied.input = true;\n\t\t}\n\t}\n\tdiscovery.model.catalog!.supplied = Object.entries(discovery.supplied)\n\t\t.filter(([, value]) => value)\n\t\t.map(([field]) => field) as NonNullable<Model<Api>[\"catalog\"]>[\"supplied\"];\n\treturn discovery;\n}\n\n/** OpenRouter field mapping (tools filter, pricing × 1e6, context) from generate-models. */\nexport function mapOpenRouterModel(raw: Record<string, unknown>, template: Model<Api>): LiveModelDiscovery | undefined {\n\tconst id = typeof raw.id === \"string\" ? raw.id.trim() : \"\";\n\tif (!id) return undefined;\n\tconst supported = Array.isArray(raw.supported_parameters) ? raw.supported_parameters : [];\n\tif (!supported.includes(\"tools\")) return undefined;\n\n\tconst architecture = isRecord(raw.architecture) ? raw.architecture : undefined;\n\tconst modality = typeof architecture?.modality === \"string\" ? architecture.modality : \"\";\n\tconst input: (\"text\" | \"image\")[] = [\"text\"];\n\tif (modality.includes(\"image\")) input.push(\"image\");\n\n\tconst pricing = isRecord(raw.pricing) ? raw.pricing : undefined;\n\tconst inputCost = roundCost((asFiniteNumber(pricing?.prompt) ?? 0) * 1_000_000);\n\tconst outputCost = roundCost((asFiniteNumber(pricing?.completion) ?? 0) * 1_000_000);\n\tconst cacheReadCost = roundCost((asFiniteNumber(pricing?.input_cache_read) ?? 0) * 1_000_000);\n\tconst cacheWriteCost = roundCost((asFiniteNumber(pricing?.input_cache_write) ?? 0) * 1_000_000);\n\n\tconst topProvider = isRecord(raw.top_provider) ? raw.top_provider : undefined;\n\tconst contextWindow = asFiniteNumber(topProvider?.context_length) ?? asFiniteNumber(raw.context_length);\n\tconst maxTokens = asFiniteNumber(topProvider?.max_completion_tokens) ?? asFiniteNumber(raw.max_completion_tokens);\n\n\tconst name = typeof raw.name === \"string\" && raw.name.trim() ? raw.name.trim() : id;\n\treturn {\n\t\tmodel: {\n\t\t\tid,\n\t\t\tname,\n\t\t\tapi: template.api,\n\t\t\tprovider: template.provider,\n\t\t\tbaseUrl: template.baseUrl,\n\t\t\treasoning: supported.includes(\"reasoning\") || template.reasoning,\n\t\t\tinput,\n\t\t\tcost: {\n\t\t\t\tinput: inputCost,\n\t\t\t\toutput: outputCost,\n\t\t\t\tcacheRead: cacheReadCost,\n\t\t\t\tcacheWrite: cacheWriteCost,\n\t\t\t},\n\t\t\tcontextWindow: contextWindow ?? DEFAULT_CONTEXT_WINDOW,\n\t\t\tmaxTokens: maxTokens ?? DEFAULT_MAX_TOKENS,\n\t\t\tcompat: template.compat,\n\t\t\tthinkingLevelMap: template.thinkingLevelMap,\n\t\t},\n\t\tsupplied: {\n\t\t\tcontextWindow: contextWindow !== undefined,\n\t\t\tmaxTokens: maxTokens !== undefined,\n\t\t\tinput: true,\n\t\t\tname: typeof raw.name === \"string\" && raw.name.trim().length > 0,\n\t\t\tcost: asFiniteNumber(pricing?.prompt) !== undefined && asFiniteNumber(pricing?.completion) !== undefined,\n\t\t\treasoning: supported.includes(\"reasoning\"),\n\t\t},\n\t};\n}\n\nexport function discoverLiveModels(\n\tproviderId: string,\n\tpayload: unknown,\n\tbakedIn: readonly Model<Api>[],\n): LiveModelDiscovery[] {\n\tif (providerId === \"openai-codex\")\n\t\treturn discoverCodexModels(payload, bakedIn[0]?.baseUrl ?? \"https://chatgpt.com/backend-api\");\n\tconst fallback = firstBakedInModel(bakedIn);\n\tif (!fallback) return [];\n\tconst rows = parseOpenAIModelsList(payload);\n\tconst discoveries: LiveModelDiscovery[] = [];\n\tfor (const raw of rows) {\n\t\tconst id = typeof raw.id === \"string\" ? raw.id.trim() : \"\";\n\t\tif (!id) continue;\n\t\tif (\n\t\t\traw.tool_call === false ||\n\t\t\traw.type === \"embedding\" ||\n\t\t\t(providerId === \"openai\" &&\n\t\t\t\t/^(?:text-embedding-|tts-|whisper-|dall-e-|gpt-image-|gpt-audio|gpt-realtime|sora-|.*moderation)/i.test(id))\n\t\t)\n\t\t\tcontinue;\n\t\tconst template = { ...(selectLiveTemplate(providerId, id, bakedIn) ?? fallback), provider: providerId };\n\t\tif (providerId === \"openrouter\") {\n\t\t\tconst mapped = mapOpenRouterModel(raw, template);\n\t\t\tif (mapped) {\n\t\t\t\tmapped.model.catalog = {\n\t\t\t\t\tsource: \"provider\",\n\t\t\t\t\t...(!mapped.supplied.cost ? { pricing: \"unknown\" as const } : {}),\n\t\t\t\t\tsupplied: Object.entries(mapped.supplied)\n\t\t\t\t\t\t.filter(([, supplied]) => supplied)\n\t\t\t\t\t\t.map(([key]) => key) as NonNullable<Model<Api>[\"catalog\"]>[\"supplied\"],\n\t\t\t\t};\n\t\t\t\tmapped.model = normalizeCatalogPricing(mapped.model);\n\t\t\t\tif (mapped.model.catalog?.pricing === \"unknown\") mapped.supplied.cost = false;\n\t\t\t\tdiscoveries.push(mapped);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tdiscoveries.push(synthesizeLiveModel(id, template, raw));\n\t}\n\treturn discoveries;\n}\n\nexport function missingLiveFields(supplied: LiveFieldSupply): Array<\"contextWindow\" | \"maxTokens\" | \"input\"> {\n\tconst missing: Array<\"contextWindow\" | \"maxTokens\" | \"input\"> = [];\n\tif (!supplied.contextWindow) missing.push(\"contextWindow\");\n\tif (!supplied.maxTokens) missing.push(\"maxTokens\");\n\tif (!supplied.input) missing.push(\"input\");\n\treturn missing;\n}\n\nexport function isLiveModelIncomplete(discovery: LiveModelDiscovery, knownKeys: Set<string>): boolean {\n\tif (knownKeys.has(modelKey(discovery.model.provider, discovery.model.id))) return false;\n\treturn missingLiveFields(discovery.supplied).length > 0;\n}\n\nexport function collectIncompleteLiveModels(\n\tdiscoveries: readonly LiveModelDiscovery[],\n\tbakedIn: readonly Model<Api>[],\n\tknownKeys: Set<string>,\n): IncompleteLiveModel[] {\n\tconst apis = uniqueApis(bakedIn);\n\tconst incomplete: IncompleteLiveModel[] = [];\n\tfor (const discovery of discoveries) {\n\t\tif (!isLiveModelIncomplete(discovery, knownKeys)) continue;\n\t\tincomplete.push({\n\t\t\tprovider: discovery.model.provider,\n\t\t\tid: discovery.model.id,\n\t\t\tname: discovery.model.name,\n\t\t\tmissing: missingLiveFields(discovery.supplied),\n\t\t\tdraft: discovery.model,\n\t\t\tavailableApis: apis,\n\t\t});\n\t}\n\treturn incomplete;\n}\n\nexport function buildLiveOverlay(\n\tbakedIn: readonly Model<Api>[],\n\tdiscoveries: readonly LiveModelDiscovery[],\n): Model<Api>[] {\n\tconst bakedById = new Map(bakedIn.map((model) => [model.id, model]));\n\tconst overlay: Model<Api>[] = [];\n\tfor (const discovery of discoveries) {\n\t\tconst baked = bakedById.get(discovery.model.id);\n\t\tif (!baked) {\n\t\t\toverlay.push(discovery.model);\n\t\t\tcontinue;\n\t\t}\n\t\toverlay.push({\n\t\t\t...baked,\n\t\t\tcatalog: discovery.model.catalog,\n\t\t\tthinkingLevelMap: discovery.model.catalog?.supplied.includes(\"thinkingLevelMap\")\n\t\t\t\t? discovery.model.thinkingLevelMap\n\t\t\t\t: baked.thinkingLevelMap,\n\t\t\tname: discovery.supplied.name ? discovery.model.name : baked.name,\n\t\t\tcontextWindow: discovery.supplied.contextWindow ? discovery.model.contextWindow : baked.contextWindow,\n\t\t\tmaxTokens: discovery.supplied.maxTokens ? discovery.model.maxTokens : baked.maxTokens,\n\t\t\tinput: discovery.supplied.input ? discovery.model.input : baked.input,\n\t\t\tcost: discovery.supplied.cost ? discovery.model.cost : baked.cost,\n\t\t\treasoning: discovery.supplied.reasoning ? discovery.model.reasoning : baked.reasoning,\n\t\t});\n\t}\n\treturn overlay;\n}\n\nexport function describeIncomplete(model: IncompleteLiveModel): string {\n\tconst labels: string[] = [];\n\tfor (const field of model.missing) {\n\t\tif (field === \"contextWindow\") labels.push(\"context window\");\n\t\telse if (field === \"maxTokens\") labels.push(\"max tokens\");\n\t\telse labels.push(\"input types\");\n\t}\n\tlet missingText = \"metadata\";\n\tif (labels.length === 1) missingText = labels[0] ?? missingText;\n\telse if (labels.length === 2) missingText = `${labels[0]} and ${labels[1]}`;\n\telse if (labels.length > 2) missingText = `${labels.slice(0, -1).join(\", \")}, and ${labels[labels.length - 1]}`;\n\treturn `New model ${model.provider}/${model.id} — missing ${missingText}.`;\n}\n\nexport function parsePositiveInt(value: string | undefined, fallback: number): number {\n\tif (!value?.trim()) return fallback;\n\tconst parsed = Number(value.trim());\n\tif (!Number.isInteger(parsed) || parsed <= 0) return fallback;\n\treturn parsed;\n}\n\nexport interface IncompleteModelAnswers {\n\tcontextWindow?: number;\n\tmaxTokens?: number;\n\tinput?: (\"text\" | \"image\")[];\n\treasoning?: boolean;\n\tapi?: Api;\n}\n\nexport function applyIncompleteAnswers(draft: Model<Api>, answers: IncompleteModelAnswers): Model<Api> {\n\treturn {\n\t\t...draft,\n\t\tcontextWindow: answers.contextWindow ?? draft.contextWindow,\n\t\tmaxTokens: answers.maxTokens ?? draft.maxTokens,\n\t\tinput: answers.input ?? draft.input,\n\t\treasoning: answers.reasoning ?? draft.reasoning,\n\t\tapi: answers.api ?? draft.api,\n\t};\n}\n\nexport interface FetchLiveProviderModelsOptions {\n\tdiscoveryClientVersion?: string;\n\tproviderId: string;\n\tbaseUrl: string;\n\tbakedIn: readonly Model<Api>[];\n\tcredential?: Credential;\n\tknownKeys: Set<string>;\n\ttimeoutMs?: number;\n\tsignal?: AbortSignal;\n\tfetchImpl?: typeof fetch;\n}\n\nexport async function fetchLiveProviderModels(options: FetchLiveProviderModelsOptions): Promise<LiveCatalogResult> {\n\tconst empty: LiveCatalogResult = {\n\t\tproviderId: options.providerId,\n\t\tstatus: \"skipped\",\n\t\tdiscoveries: [],\n\t\tadded: 0,\n\t\ttotal: 0,\n\t\tincomplete: [],\n\t};\n\tconst template = firstBakedInModel(options.bakedIn);\n\tif ((!template && options.providerId !== \"openai-codex\") || !options.baseUrl) return empty;\n\n\tconst timeoutMs = options.timeoutMs ?? LIVE_CATALOG_TIMEOUT_MS;\n\tconst controller = new AbortController();\n\tlet timedOut = false;\n\tconst timer = setTimeout(() => {\n\t\ttimedOut = true;\n\t\tcontroller.abort();\n\t}, timeoutMs);\n\tconst onParentAbort = () => controller.abort();\n\toptions.signal?.addEventListener(\"abort\", onParentAbort, { once: true });\n\tif (options.signal?.aborted) controller.abort();\n\n\ttry {\n\t\tconst fetchImpl = options.fetchImpl ?? fetch;\n\t\tconst codex = options.providerId === \"openai-codex\";\n\t\tconst accountId =\n\t\t\toptions.credential?.type === \"oauth\" && typeof options.credential.accountId === \"string\"\n\t\t\t\t? options.credential.accountId\n\t\t\t\t: undefined;\n\t\tlet discoveryClientVersion = options.discoveryClientVersion;\n\t\tconst payload = await Promise.race([\n\t\t\t(async () => {\n\t\t\t\tif (codex)\n\t\t\t\t\tdiscoveryClientVersion = await resolveCodexCatalogVersion(\n\t\t\t\t\t\tfetchImpl,\n\t\t\t\t\t\tcontroller.signal,\n\t\t\t\t\t\tdiscoveryClientVersion,\n\t\t\t\t\t);\n\t\t\t\tconst response = await fetchImpl(\n\t\t\t\t\tcodex ? codexModelsUrl(options.baseUrl, discoveryClientVersion) : modelsListUrl(options.baseUrl),\n\t\t\t\t\t{\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\taccept: \"application/json\",\n\t\t\t\t\t\t\t\"User-Agent\": getPiUserAgent(VERSION),\n\t\t\t\t\t\t\t...credentialAuthHeaders(options.credential),\n\t\t\t\t\t\t\t...(accountId ? { \"ChatGPT-Account-ID\": accountId } : {}),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tif (!response.ok) throw new Error(`HTTP ${response.status}`);\n\t\t\t\treturn response.json();\n\t\t\t})(),\n\t\t\tnew Promise<never>((_, reject) => {\n\t\t\t\tconst abortError = new Error(\"The operation was aborted\");\n\t\t\t\tabortError.name = \"AbortError\";\n\t\t\t\tcontroller.signal.addEventListener(\"abort\", () => reject(abortError), { once: true });\n\t\t\t\tif (controller.signal.aborted) reject(abortError);\n\t\t\t}),\n\t\t]);\n\t\tconst discoveries = codex\n\t\t\t? discoverCodexModels(payload, options.baseUrl)\n\t\t\t: discoverLiveModels(options.providerId, payload, options.bakedIn);\n\t\tif (!discoveries.length) throw new Error(\"No usable models returned; retaining cached models\");\n\t\tconst bakedIds = new Set(options.bakedIn.map((model) => model.id));\n\t\tconst added = discoveries.filter((discovery) => !bakedIds.has(discovery.model.id)).length;\n\t\treturn {\n\t\t\tproviderId: options.providerId,\n\t\t\tdiscoveryClientVersion,\n\t\t\tstatus: \"ok\",\n\t\t\tdiscoveries,\n\t\t\tadded,\n\t\t\ttotal: discoveries.length,\n\t\t\tincomplete: collectIncompleteLiveModels(discoveries, options.bakedIn, options.knownKeys),\n\t\t};\n\t} catch (error) {\n\t\tif (options.signal?.aborted && !timedOut) return { ...empty, status: \"skipped\", error: \"aborted\" };\n\t\tif (timedOut || (error instanceof Error && error.name === \"AbortError\")) {\n\t\t\treturn { ...empty, status: \"timeout\", error: \"timed out\" };\n\t\t}\n\t\treturn {\n\t\t\t...empty,\n\t\t\tstatus: \"error\",\n\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t};\n\t} finally {\n\t\tclearTimeout(timer);\n\t\toptions.signal?.removeEventListener(\"abort\", onParentAbort);\n\t}\n}\n"]}
@@ -60,6 +60,8 @@ export declare class ModelRuntime implements Models {
60
60
  private lastOfficial;
61
61
  private catalogRefresh;
62
62
  private catalogRefreshAllowsNetwork;
63
+ private nextAutomaticRefresh;
64
+ private automaticRefreshIdentity;
63
65
  private readonly grokHome;
64
66
  private constructor();
65
67
  static create(options?: CreateModelRuntimeOptions): Promise<ModelRuntime>;
@@ -70,6 +72,7 @@ export declare class ModelRuntime implements Models {
70
72
  private bakedInModels;
71
73
  private rebuildProviders;
72
74
  private updateModelSnapshot;
75
+ private isCatalogModelAvailable;
73
76
  private listStoredProviderIds;
74
77
  /** `/model` lists stored creds + models.json/extension keys, never ambient envApiKeyAuth. */
75
78
  private configuredProviderIds;
@@ -119,6 +122,11 @@ export declare class ModelRuntime implements Models {
119
122
  refresh(options?: ModelsRefreshOptions): Promise<CatalogRefreshResult>;
120
123
  private executeCatalogRefresh;
121
124
  getLastCatalogRefresh(): CatalogRefreshResult;
125
+ /** Called after first paint and by the picker; explicit /refresh always bypasses this gate. */
126
+ refreshIfStale(options?: {
127
+ signal?: AbortSignal;
128
+ }): Promise<CatalogRefreshResult>;
129
+ private scopeFor;
122
130
  persistUserModels(rows: readonly UserModelEntry[]): void;
123
131
  private refreshOfficialCatalog;
124
132
  private restoreLiveCatalogs;
@@ -1 +1 @@
1
- {"version":3,"file":"model-runtime.d.ts","sourceRoot":"","sources":["../../src/core/model-runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import { dirname, join } from \"node:path\";\nimport {\n\ttype Api,\n\ttype ApiStreamOptions,\n\ttype AssistantMessage,\n\ttype AssistantMessageEventStream,\n\ttype AuthCheck,\n\ttype AuthInteraction,\n\ttype AuthResult,\n\ttype AuthType,\n\ttype Context,\n\ttype Credential,\n\ttype CredentialInfo,\n\ttype CredentialStore,\n\tcreateModels,\n\tlazyStream,\n\ttype Model,\n\ttype Models,\n\ttype ModelsApiStreamOptions,\n\tModelsError,\n\ttype ModelsRefreshOptions,\n\ttype ModelsRefreshResult,\n\ttype ModelsSimpleStreamOptions,\n\ttype ModelsStore,\n\ttype ModelsStreamTransforms,\n\ttype MutableModels,\n\ttype Provider,\n\ttype ProviderHeaders,\n\ttype SimpleStreamOptions,\n\ttype StreamOptions,\n} from \"@ashx-j/lunr-ai\";\nimport * as builtinProviderCatalog from \"@ashx-j/lunr-ai/providers/all\";\nimport { getAgentDir } from \"../config.ts\";\nimport { AuthStorage as DefaultAuthStorage } from \"./auth-storage.ts\";\nimport { CatalogOverlaySource, knownModelKeys, withCatalogOverlay } from \"./catalog-merge.ts\";\nimport { readGrokCliXaiOAuth, wrapXaiGrokCliCredentials } from \"./grok-cli-auth.ts\";\nimport {\n\tbuildLiveOverlay,\n\tfetchLiveProviderModels,\n\ttype IncompleteLiveModel,\n\tLIVE_LIST_PROVIDER_IDS,\n\ttype LiveCatalogResult,\n} from \"./live-catalog.ts\";\nimport { ModelConfig } from \"./model-config.ts\";\nimport { FileModelsStore, InMemoryCodingAgentModelsStore } from \"./models-store.ts\";\nimport {\n\tloadOfficialCatalog,\n\ttype OfficialCatalogLoadResult,\n\tofficialCatalogCachePath,\n\tofficialEntryToModel,\n\tofficialModelKeys,\n\tpreferOfficialCatalog,\n} from \"./official-catalog.ts\";\nimport {\n\ttype AuthStatus,\n\ttype CompatibilityRequestConfig,\n\tcomposeModelProvider,\n\tconfiguredRequestAuthStatus,\n\ttype ProviderConfigInput,\n\tresolveCompatibilityRequestConfig,\n\tresolveConfiguredModelHeaders,\n\tvalidateExtensionProvider,\n} from \"./provider-composer.ts\";\nimport { RuntimeCredentials } from \"./runtime-credentials.ts\";\nimport { SubscriptionManager } from \"./subscriptions.ts\";\nimport { clearPlanUsageCache } from \"./usage-service.ts\";\nimport { type UserModelEntry, UserModelsStore, userEntryToModel, userModelsPath } from \"./user-models.ts\";\n\ninterface ModelRuntimeSnapshot {\n\tall: readonly Model<Api>[];\n\tavailable: readonly Model<Api>[];\n\tconfiguredProviders: ReadonlySet<string>;\n\tstoredProviders: ReadonlySet<string>;\n\tauth: ReadonlyMap<string, AuthCheck | undefined>;\n}\n\nexport interface CreateModelRuntimeOptions {\n\t/** Credential storage. Defaults to the file at authPath. */\n\tcredentials?: CredentialStore;\n\tauthPath?: string;\n\tmodelsPath?: string | null;\n\tmodelsStore?: ModelsStore;\n\tmodelsStorePath?: string;\n\tallowModelNetwork?: boolean;\n\t/** Applied by callers of `refresh()`, not by `create()` (startup is cache-only). */\n\tmodelRefreshTimeoutMs?: number;\n\t/** Unused. Kept so older callers compiling against this options bag still typecheck. */\n\tcatalogBaseUrl?: string;\n\t/** lunr: subscription-key pool. Defaults to subscriptions.json next to authPath (in-memory for custom stores). */\n\tsubscriptions?: SubscriptionManager;\n\t/**\n\t * Grok CLI home (`~/.grok`) used as a SuperGrok OAuth fallback.\n\t * `null` disables the fallback. Custom `credentials` default to disabled\n\t * unless this is an explicit path.\n\t */\n\tgrokHome?: string | null;\n}\n\nexport interface CatalogRefreshResult extends ModelsRefreshResult {\n\tofficial?: OfficialCatalogLoadResult & { evictedUserRows: number };\n\tlive: LiveCatalogResult[];\n\tincomplete: IncompleteLiveModel[];\n}\n\nexport interface ModelRuntimeAuthOverrides {\n\tapiKey?: string;\n\tenv?: Record<string, string>;\n}\n\nfunction mergeHeaders(\n\tbase: ProviderHeaders | undefined,\n\toverride: ProviderHeaders | undefined,\n): ProviderHeaders | undefined {\n\tif (!base && !override) return undefined;\n\tconst merged = { ...base };\n\tfor (const [name, value] of Object.entries(override ?? {})) {\n\t\tconst lowerName = name.toLowerCase();\n\t\tfor (const existingName of Object.keys(merged)) {\n\t\t\tif (existingName.toLowerCase() === lowerName) delete merged[existingName];\n\t\t}\n\t\tmerged[name] = value;\n\t}\n\treturn merged;\n}\n\n/** Configured pi-ai Models collection used by coding-agent and SDK consumers. */\nexport class ModelRuntime implements Models {\n\tprivate readonly models: MutableModels;\n\tprivate readonly credentials: RuntimeCredentials;\n\t/** lunr: per-provider subscription-key pools; rotation mirrors the active key into the credential store. */\n\treadonly subscriptionManager: SubscriptionManager;\n\tprivate readonly defaultBuiltins: ReadonlyMap<string, Provider>;\n\tprivate readonly builtins = new Map<string, Provider>();\n\tprivate readonly extensionProviders = new Map<string, ProviderConfigInput>();\n\tprivate readonly compositionErrors = new Map<string, string>();\n\tprivate readonly modelsPath: string | undefined;\n\tprivate readonly allowModelNetwork: boolean;\n\tprivate config: ModelConfig;\n\tprivate snapshot: ModelRuntimeSnapshot = {\n\t\tall: [],\n\t\tavailable: [],\n\t\tconfiguredProviders: new Set(),\n\t\tstoredProviders: new Set(),\n\t\tauth: new Map(),\n\t};\n\tprivate availabilityRefresh: Promise<void> | undefined;\n\tprivate availabilityError: string | undefined;\n\tprivate readonly modelsStore: ModelsStore;\n\tprivate readonly overlay = new CatalogOverlaySource();\n\tprivate readonly userModels: UserModelsStore;\n\tprivate readonly officialCachePath: string | undefined;\n\tprivate lastCatalogRefresh: CatalogRefreshResult = { aborted: false, errors: new Map(), live: [], incomplete: [] };\n\tprivate lastOfficial: OfficialCatalogLoadResult | undefined;\n\tprivate catalogRefresh: Promise<CatalogRefreshResult> | undefined;\n\tprivate catalogRefreshAllowsNetwork = false;\n\tprivate readonly grokHome: string | undefined;\n\n\tprivate constructor(\n\t\tcredentials: RuntimeCredentials,\n\t\tconfig: ModelConfig,\n\t\tmodelsPath: string | undefined,\n\t\tmodelsStore: ModelsStore,\n\t\tproviders: readonly Provider[],\n\t\tallowModelNetwork: boolean,\n\t\tsubscriptionManager: SubscriptionManager,\n\t\tcatalogDir: string | undefined,\n\t\tgrokHome: string | undefined,\n\t) {\n\t\tthis.credentials = credentials;\n\t\tthis.config = config;\n\t\tthis.modelsPath = modelsPath;\n\t\tthis.modelsStore = modelsStore;\n\t\tthis.allowModelNetwork = allowModelNetwork;\n\t\tthis.subscriptionManager = subscriptionManager;\n\t\tthis.userModels = new UserModelsStore(catalogDir ? userModelsPath(catalogDir) : undefined);\n\t\tthis.officialCachePath = catalogDir ? officialCatalogCachePath(catalogDir) : undefined;\n\t\tthis.grokHome = grokHome;\n\t\tthis.defaultBuiltins = new Map(providers.map((provider) => [provider.id, provider]));\n\t\tfor (const [providerId, provider] of this.defaultBuiltins) this.builtins.set(providerId, provider);\n\t\tthis.models = createModels({ credentials, modelsStore });\n\t\tthis.rebuildProviders();\n\t}\n\n\tstatic async create(options: CreateModelRuntimeOptions = {}): Promise<ModelRuntime> {\n\t\t// lunr: keep the underlying store — the SubscriptionManager mirrors rotated\n\t\t// keys into it directly, NOT through the RuntimeCredentials overlay (a runtime\n\t\t// --api-key override would shadow the mirror there).\n\t\tconst rawStore = options.credentials ?? DefaultAuthStorage.create(options.authPath);\n\t\tconst grokHomeDisabled =\n\t\t\toptions.grokHome === null || (options.grokHome === undefined && options.credentials !== undefined);\n\t\tconst grokHome = grokHomeDisabled ? undefined : (options.grokHome ?? undefined);\n\t\tconst baseStore = grokHomeDisabled ? rawStore : wrapXaiGrokCliCredentials(rawStore, { grokHome });\n\t\tconst credentials = new RuntimeCredentials(baseStore);\n\t\t// Pool persistence: subscriptions.json next to auth.json. A custom credential\n\t\t// store without an authPath (tests, SDK embeddings) gets a process-local pool\n\t\t// so nothing leaks into the real agent dir.\n\t\tconst subscriptionManager =\n\t\t\toptions.subscriptions ??\n\t\t\t(options.credentials && !options.authPath\n\t\t\t\t? SubscriptionManager.inMemory(baseStore)\n\t\t\t\t: SubscriptionManager.create(\n\t\t\t\t\t\tbaseStore,\n\t\t\t\t\t\toptions.authPath ? join(dirname(options.authPath), \"subscriptions.json\") : undefined,\n\t\t\t\t\t));\n\t\tconst modelsPath =\n\t\t\toptions.modelsPath === null ? undefined : (options.modelsPath ?? join(getAgentDir(), \"models.json\"));\n\t\tconst config = await ModelConfig.load(modelsPath);\n\t\tconst modelsStore =\n\t\t\toptions.modelsStore ??\n\t\t\t(modelsPath\n\t\t\t\t? new FileModelsStore(options.modelsStorePath ?? join(dirname(modelsPath), \"models-store.json\"))\n\t\t\t\t: new InMemoryCodingAgentModelsStore());\n\t\tconst providers = builtinProviderCatalog.builtinProviders();\n\t\tconst catalogDir = modelsPath ? dirname(modelsPath) : options.authPath ? dirname(options.authPath) : undefined;\n\t\tconst runtime = new ModelRuntime(\n\t\t\tcredentials,\n\t\t\tconfig,\n\t\t\tmodelsPath,\n\t\t\tmodelsStore,\n\t\t\tproviders,\n\t\t\toptions.allowModelNetwork ?? process.env.PI_OFFLINE === undefined,\n\t\t\tsubscriptionManager,\n\t\t\tcatalogDir,\n\t\t\tgrokHome,\n\t\t);\n\t\truntime.configureRadiusProviders();\n\t\truntime.rebuildProviders();\n\t\t// lunr: create() must not wait on GitHub / provider /v1/models / a dead NIC.\n\t\t// Disk cache + baked-in + bundled official overlay are enough to start;\n\t\t// /refresh and the model picker still do a live refresh.\n\t\tawait runtime.refresh({ allowNetwork: false });\n\t\treturn runtime;\n\t}\n\n\tprivate configureRadiusProviders(): void {\n\t\tthis.builtins.clear();\n\t\tfor (const [providerId, provider] of this.defaultBuiltins) this.builtins.set(providerId, provider);\n\t\tfor (const providerId of this.config.getProviderIds()) {\n\t\t\tconst config = this.config.getProvider(providerId);\n\t\t\tif (config?.oauth !== \"radius\" || !config.baseUrl) continue;\n\t\t\tthis.builtins.set(\n\t\t\t\tproviderId,\n\t\t\t\tbuiltinProviderCatalog.radiusProvider({\n\t\t\t\t\tid: providerId,\n\t\t\t\t\tname: config.name ?? providerId,\n\t\t\t\t\tgateway: config.baseUrl.replace(/\\/v1\\/?$/u, \"\"),\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate providerIds(): Set<string> {\n\t\treturn new Set([...this.builtins.keys(), ...this.config.getProviderIds(), ...this.extensionProviders.keys()]);\n\t}\n\n\tprivate recomposeProvider(providerId: string): void {\n\t\tconst base = this.builtins.get(providerId);\n\t\tconst extension = this.extensionProviders.get(providerId);\n\t\tif (!base && !this.config.getProvider(providerId) && !extension) {\n\t\t\tthis.models.deleteProvider(providerId);\n\t\t\tthis.compositionErrors.delete(providerId);\n\t\t\treturn;\n\t\t}\n\t\tif (base && !this.config.getProvider(providerId) && !extension) {\n\t\t\t// No models.json/extension overlays: keep builtin auth/stream exact, then apply catalog layers.\n\t\t\tthis.models.setProvider(this.withLocalCatalog(base));\n\t\t\tthis.compositionErrors.delete(providerId);\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tthis.models.setProvider(this.withLocalCatalog(composeModelProvider(providerId, base, this.config, extension)));\n\t\t\tthis.compositionErrors.delete(providerId);\n\t\t} catch (error) {\n\t\t\tthis.compositionErrors.set(providerId, error instanceof Error ? error.message : String(error));\n\t\t\tif (base) this.models.setProvider(this.withLocalCatalog(base));\n\t\t\telse this.models.deleteProvider(providerId);\n\t\t}\n\t}\n\n\tprivate withLocalCatalog(provider: Provider): Provider {\n\t\treturn withCatalogOverlay(provider, this.overlay);\n\t}\n\n\tprivate bakedInModels(providerId: string): Model<Api>[] {\n\t\treturn [...(this.defaultBuiltins.get(providerId)?.getModels() ?? [])];\n\t}\n\n\tprivate rebuildProviders(): void {\n\t\tthis.models.clearProviders();\n\t\tthis.compositionErrors.clear();\n\t\tfor (const providerId of this.providerIds()) this.recomposeProvider(providerId);\n\t\tthis.updateModelSnapshot();\n\t}\n\n\tprivate updateModelSnapshot(): void {\n\t\tconst all = [...this.models.getModels()];\n\t\tthis.snapshot = {\n\t\t\t...this.snapshot,\n\t\t\tall,\n\t\t\tavailable: all.filter((model) => this.snapshot.configuredProviders.has(model.provider)),\n\t\t};\n\t}\n\n\tprivate async listStoredProviderIds(): Promise<Set<string>> {\n\t\tconst credentials = await this.credentials.list();\n\t\treturn new Set(credentials.map((entry) => entry.providerId));\n\t}\n\n\t/** `/model` lists stored creds + models.json/extension keys, never ambient envApiKeyAuth. */\n\tprivate configuredProviderIds(storedProviders: ReadonlySet<string>): Set<string> {\n\t\tconst configured = new Set(storedProviders);\n\t\tfor (const provider of this.models.getProviders()) {\n\t\t\tif (\n\t\t\t\tconfiguredRequestAuthStatus(this.config.getProvider(provider.id), this.extensionProviders.get(provider.id))\n\t\t\t\t\t?.configured\n\t\t\t) {\n\t\t\t\tconfigured.add(provider.id);\n\t\t\t}\n\t\t}\n\t\treturn configured;\n\t}\n\n\tprivate userModelsForStoredProviders(storedProviders: ReadonlySet<string>): Model<Api>[] {\n\t\treturn this.userModels\n\t\t\t.list()\n\t\t\t.filter((row) => storedProviders.has(row.provider))\n\t\t\t.map(userEntryToModel);\n\t}\n\n\tprivate async runAvailabilityRefresh(): Promise<void> {\n\t\tconst providers = this.models.getProviders();\n\t\tconst [available, checks, storedProviders] = await Promise.all([\n\t\t\tthis.models.getAvailable(),\n\t\t\tPromise.all(\n\t\t\t\tproviders.map(\n\t\t\t\t\tasync (provider): Promise<[string, AuthCheck | undefined]> => [\n\t\t\t\t\t\tprovider.id,\n\t\t\t\t\t\tawait this.models.checkAuth(provider.id),\n\t\t\t\t\t],\n\t\t\t\t),\n\t\t\t),\n\t\t\tthis.listStoredProviderIds(),\n\t\t]);\n\t\tconst auth = new Map(checks);\n\t\tconst configuredProviders = this.configuredProviderIds(storedProviders);\n\t\tthis.snapshot = {\n\t\t\tall: [...this.models.getModels()],\n\t\t\tavailable: available.filter((model) => configuredProviders.has(model.provider)),\n\t\t\tconfiguredProviders,\n\t\t\tstoredProviders,\n\t\t\tauth,\n\t\t};\n\t\tthis.availabilityError = undefined;\n\t}\n\n\tprivate queueAvailabilityRefresh(after: Promise<void> | undefined): Promise<void> {\n\t\tconst refresh = (after ?? Promise.resolve()).catch(() => {}).then(() => this.runAvailabilityRefresh());\n\t\tconst recorded = refresh.catch((error) => {\n\t\t\tthis.availabilityError = error instanceof Error ? error.message : String(error);\n\t\t\tthrow error;\n\t\t});\n\t\tconst tracked = recorded.finally(() => {\n\t\t\tif (this.availabilityRefresh === tracked) this.availabilityRefresh = undefined;\n\t\t});\n\t\tthis.availabilityRefresh = tracked;\n\t\treturn tracked;\n\t}\n\n\t/** Coalesce concurrent readers onto the pending refresh. */\n\tprivate refreshAvailability(): Promise<void> {\n\t\treturn this.availabilityRefresh ?? this.queueAvailabilityRefresh(undefined);\n\t}\n\n\t/** Mutations must not observe an in-flight refresh started before them. */\n\tprivate forceRefreshAvailability(): Promise<void> {\n\t\treturn this.queueAvailabilityRefresh(this.availabilityRefresh);\n\t}\n\n\tgetProviders(): readonly Provider[] {\n\t\treturn this.models.getProviders();\n\t}\n\n\tgetProvider(providerId: string): Provider | undefined {\n\t\treturn this.models.getProvider(providerId);\n\t}\n\n\tgetModels(providerId?: string): readonly Model<Api>[] {\n\t\treturn this.models.getModels(providerId);\n\t}\n\n\tgetModel(providerId: string, modelId: string): Model<Api> | undefined {\n\t\treturn this.models.getModel(providerId, modelId);\n\t}\n\n\tasync checkAuth(providerId: string): Promise<AuthCheck | undefined> {\n\t\treturn this.models.checkAuth(providerId);\n\t}\n\n\tasync getAvailable(providerId?: string): Promise<readonly Model<Api>[]> {\n\t\tif (providerId) {\n\t\t\tif (this.availabilityRefresh) {\n\t\t\t\tawait this.availabilityRefresh;\n\t\t\t\treturn this.snapshot.available.filter((model) => model.provider === providerId);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn await this.models.getAvailable(providerId);\n\t\t\t} catch (error) {\n\t\t\t\tthis.availabilityError = error instanceof Error ? error.message : String(error);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\tawait this.refreshAvailability();\n\t\treturn this.snapshot.available;\n\t}\n\n\tgetAvailableSnapshot(): readonly Model<Api>[] {\n\t\treturn this.snapshot.available;\n\t}\n\n\tgetError(): string | undefined {\n\t\tconst errors: string[] = [];\n\t\tconst configError = this.config.getError();\n\t\tif (configError) errors.push(configError);\n\t\tfor (const [providerId, error] of this.compositionErrors) {\n\t\t\terrors.push(`Provider \"${providerId}\": ${error}`);\n\t\t}\n\t\tif (this.availabilityError) errors.push(`Availability refresh: ${this.availabilityError}`);\n\t\treturn errors.length > 0 ? errors.join(\"\\n\\n\") : undefined;\n\t}\n\n\tgetRegisteredProviderConfig(providerId: string): ProviderConfigInput | undefined {\n\t\treturn this.extensionProviders.get(providerId);\n\t}\n\n\tgetRegisteredProviderIds(): readonly string[] {\n\t\treturn [...this.extensionProviders.keys()];\n\t}\n\n\t/** @internal Compatibility fallback for ModelRegistry when provider auth is unconfigured. */\n\tgetCompatibilityRequestConfig(model: Model<Api>): CompatibilityRequestConfig {\n\t\treturn resolveCompatibilityRequestConfig(\n\t\t\tmodel,\n\t\t\tthis.config.getProvider(model.provider),\n\t\t\tthis.extensionProviders.get(model.provider),\n\t\t);\n\t}\n\n\tisUsingOAuth(providerId: string): boolean {\n\t\treturn this.snapshot.auth.get(providerId)?.type === \"oauth\";\n\t}\n\n\thasConfiguredAuth(providerId: string): boolean {\n\t\treturn this.snapshot.configuredProviders.has(providerId);\n\t}\n\n\tgetAuth(providerId: string, overrides?: ModelRuntimeAuthOverrides): Promise<AuthResult | undefined>;\n\tgetAuth(model: Model<Api>, overrides?: ModelRuntimeAuthOverrides): Promise<AuthResult | undefined>;\n\tasync getAuth(\n\t\tproviderOrModel: string | Model<Api>,\n\t\toverrides: ModelRuntimeAuthOverrides = {},\n\t): Promise<AuthResult | undefined> {\n\t\tif (typeof providerOrModel === \"string\") return this.models.getAuth(providerOrModel, overrides);\n\t\tconst resolution = await this.models.getAuth(providerOrModel, overrides);\n\t\tif (!resolution) return undefined;\n\t\tconst configuredHeaders = resolveConfiguredModelHeaders(\n\t\t\tproviderOrModel,\n\t\t\tthis.config.getProvider(providerOrModel.provider),\n\t\t\tthis.extensionProviders.get(providerOrModel.provider),\n\t\t\t{ ...(resolution.env ?? {}), ...(overrides.env ?? {}) },\n\t\t);\n\t\treturn {\n\t\t\t...resolution,\n\t\t\tauth: {\n\t\t\t\t...resolution.auth,\n\t\t\t\theaders: mergeHeaders(resolution.auth.headers, configuredHeaders),\n\t\t\t},\n\t\t};\n\t}\n\n\t/** lunr: whether a runtime --api-key override is active for the provider (it shadows auth.json). */\n\thasRuntimeApiKey(providerId: string): boolean {\n\t\treturn this.credentials.hasRuntimeApiKey(providerId);\n\t}\n\n\tasync setRuntimeApiKey(\n\t\tproviderId: string,\n\t\tapiKey: string,\n\t\toptions?: { allowNetwork?: boolean },\n\t): Promise<void> {\n\t\tthis.credentials.setRuntimeApiKey(providerId, apiKey);\n\t\tconst auth = new Map(this.snapshot.auth).set(providerId, { type: \"api_key\", source: \"runtime API key\" });\n\t\tconst configuredProviders = new Set(this.snapshot.configuredProviders).add(providerId);\n\t\tconst storedProviders = new Set(this.snapshot.storedProviders).add(providerId);\n\t\tthis.snapshot = {\n\t\t\t...this.snapshot,\n\t\t\tauth,\n\t\t\tconfiguredProviders,\n\t\t\tstoredProviders,\n\t\t\tavailable: this.snapshot.all.filter((model) => configuredProviders.has(model.provider)),\n\t\t};\n\t\tawait this.refresh({ allowNetwork: options?.allowNetwork ?? this.allowModelNetwork });\n\t}\n\n\tasync removeRuntimeApiKey(providerId: string): Promise<void> {\n\t\tthis.credentials.removeRuntimeApiKey(providerId);\n\t\tawait this.refresh({ allowNetwork: this.allowModelNetwork });\n\t}\n\n\t/** lunr: whether network model-catalog fetches are allowed (offline mode disables them). */\n\tisNetworkAllowed(): boolean {\n\t\treturn this.allowModelNetwork;\n\t}\n\n\tlistCredentials(): Promise<readonly CredentialInfo[]> {\n\t\treturn this.credentials.list();\n\t}\n\n\tgetProviderAuthStatus(providerId: string): AuthStatus {\n\t\tif (this.credentials.hasRuntimeApiKey(providerId)) return { configured: true, source: \"runtime\" };\n\t\tif (this.snapshot.storedProviders.has(providerId)) return { configured: true, source: \"stored\" };\n\t\tconst configured = configuredRequestAuthStatus(\n\t\t\tthis.config.getProvider(providerId),\n\t\t\tthis.extensionProviders.get(providerId),\n\t\t);\n\t\tif (configured) return configured;\n\t\tconst check = this.snapshot.auth.get(providerId);\n\t\treturn check ? { configured: true, source: \"environment\", label: check.source } : { configured: false };\n\t}\n\n\tprivate async prepareRequest(\n\t\tmodel: Model<Api>,\n\t\toptions: (StreamOptions & ModelsStreamTransforms) | undefined,\n\t): Promise<{ provider: Provider; model: Model<Api>; options: StreamOptions }> {\n\t\tconst provider = this.models.getProvider(model.provider);\n\t\tif (!provider) throw new ModelsError(\"provider\", `Unknown provider: ${model.provider}`);\n\t\tconst resolution = await this.getAuth(model, { apiKey: options?.apiKey, env: options?.env });\n\t\tif (!resolution) throw new ModelsError(\"auth\", `Provider is not configured: ${model.provider}`);\n\n\t\tconst { transformHeaders, ...providerOptions } = options ?? {};\n\t\tlet headers = mergeHeaders(resolution.auth.headers, providerOptions.headers);\n\t\tif (transformHeaders) headers = await transformHeaders(headers ?? {});\n\t\tconst env =\n\t\t\tresolution.env || providerOptions.env\n\t\t\t\t? { ...(resolution.env ?? {}), ...(providerOptions.env ?? {}) }\n\t\t\t\t: undefined;\n\t\treturn {\n\t\t\tprovider,\n\t\t\tmodel: resolution.auth.baseUrl ? { ...model, baseUrl: resolution.auth.baseUrl } : model,\n\t\t\toptions: {\n\t\t\t\t...providerOptions,\n\t\t\t\tapiKey: providerOptions.apiKey ?? resolution.auth.apiKey,\n\t\t\t\theaders,\n\t\t\t\tenv,\n\t\t\t},\n\t\t};\n\t}\n\n\tstream<TApi extends Api>(\n\t\tmodel: Model<TApi>,\n\t\tcontext: Context,\n\t\toptions?: ModelsApiStreamOptions<TApi>,\n\t): AssistantMessageEventStream {\n\t\treturn lazyStream(model, async () => {\n\t\t\tconst prepared = await this.prepareRequest(\n\t\t\t\tmodel,\n\t\t\t\toptions as (StreamOptions & ModelsStreamTransforms) | undefined,\n\t\t\t);\n\t\t\treturn prepared.provider.stream(\n\t\t\t\tprepared.model as Model<TApi>,\n\t\t\t\tcontext,\n\t\t\t\tprepared.options as ApiStreamOptions<TApi>,\n\t\t\t);\n\t\t});\n\t}\n\n\tcomplete<TApi extends Api>(\n\t\tmodel: Model<TApi>,\n\t\tcontext: Context,\n\t\toptions?: ModelsApiStreamOptions<TApi>,\n\t): Promise<AssistantMessage> {\n\t\treturn this.stream(model, context, options).result();\n\t}\n\n\tstreamSimple(model: Model<Api>, context: Context, options?: ModelsSimpleStreamOptions): AssistantMessageEventStream {\n\t\treturn lazyStream(model, async () => {\n\t\t\tconst prepared = await this.prepareRequest(model, options);\n\t\t\treturn prepared.provider.streamSimple(prepared.model, context, prepared.options as SimpleStreamOptions);\n\t\t});\n\t}\n\n\tcompleteSimple(model: Model<Api>, context: Context, options?: ModelsSimpleStreamOptions): Promise<AssistantMessage> {\n\t\treturn this.streamSimple(model, context, options).result();\n\t}\n\n\tasync login(providerId: string, type: AuthType, interaction: AuthInteraction): Promise<Credential> {\n\t\tconst credential = await this.models.login(providerId, type, interaction);\n\t\tclearPlanUsageCache();\n\t\tawait this.refresh({ allowNetwork: this.allowModelNetwork });\n\t\treturn credential;\n\t}\n\n\tasync logout(providerId: string): Promise<void> {\n\t\tawait this.models.logout(providerId);\n\t\tawait this.modelsStore.delete(providerId);\n\t\tthis.userModels.evictProvider(providerId);\n\t\tthis.overlay.setLive(providerId, []);\n\t\t// Reset credential-dependent compatibility projections before the unconfigured provider is skipped by refresh.\n\t\tthis.recomposeProvider(providerId);\n\t\tclearPlanUsageCache();\n\t\tawait this.refresh({ allowNetwork: this.allowModelNetwork });\n\t}\n\n\t/** Copy a live Grok CLI SuperGrok session into lunR `auth.json`. */\n\tasync importGrokCliXaiAuth(): Promise<Credential | undefined> {\n\t\tconst grok = readGrokCliXaiOAuth({ grokHome: this.grokHome });\n\t\tif (!grok) return undefined;\n\t\tconst stored = await this.credentials.modify(\"xai\", async () => grok);\n\t\tclearPlanUsageCache();\n\t\tawait this.refresh({ allowNetwork: this.allowModelNetwork });\n\t\treturn stored;\n\t}\n\n\tasync reloadConfig(): Promise<void> {\n\t\tthis.config = await ModelConfig.load(this.modelsPath);\n\t\tthis.configureRadiusProviders();\n\t\tthis.rebuildProviders();\n\t\tawait this.refresh({ allowNetwork: this.allowModelNetwork });\n\t}\n\n\tasync refresh(options: ModelsRefreshOptions = {}): Promise<CatalogRefreshResult> {\n\t\tconst allowNetwork = options.allowNetwork ?? this.allowModelNetwork;\n\t\tif (this.catalogRefresh) {\n\t\t\t// Join an in-flight refresh that is at least as capable. A cache-only\n\t\t\t// flight must not swallow a later network refresh.\n\t\t\tif (this.catalogRefreshAllowsNetwork || !allowNetwork) {\n\t\t\t\treturn this.catalogRefresh;\n\t\t\t}\n\t\t\tawait this.catalogRefresh.catch(() => {});\n\t\t\treturn this.refresh({ ...options, allowNetwork });\n\t\t}\n\n\t\tconst run = this.executeCatalogRefresh({ ...options, allowNetwork }).finally(() => {\n\t\t\tif (this.catalogRefresh === run) {\n\t\t\t\tthis.catalogRefresh = undefined;\n\t\t\t\tthis.catalogRefreshAllowsNetwork = false;\n\t\t\t}\n\t\t});\n\t\tthis.catalogRefresh = run;\n\t\tthis.catalogRefreshAllowsNetwork = allowNetwork;\n\t\treturn run;\n\t}\n\n\tprivate async executeCatalogRefresh(\n\t\trefreshOptions: ModelsRefreshOptions & { allowNetwork: boolean },\n\t): Promise<CatalogRefreshResult> {\n\t\tconst official = await this.refreshOfficialCatalog(refreshOptions.allowNetwork, refreshOptions.signal);\n\t\tconst live = refreshOptions.allowNetwork\n\t\t\t? await this.refreshLiveCatalogs(\n\t\t\t\t\tofficial ? officialModelKeys(official.catalog) : new Set(),\n\t\t\t\t\trefreshOptions.signal,\n\t\t\t\t)\n\t\t\t: await this.restoreLiveCatalogs();\n\n\t\t// Radius / local-provider / extension refreshModels hooks. Live-list\n\t\t// providers have no refreshModels, so this does not hit pi.dev.\n\t\tconst result = ((await this.models.refresh(refreshOptions)) as ModelsRefreshResult | undefined) ?? {\n\t\t\taborted: refreshOptions.signal?.aborted ?? false,\n\t\t\terrors: new Map(),\n\t\t};\n\t\tconst errors = new Map(result.errors);\n\t\tfor (const entry of live) {\n\t\t\tif (entry.status === \"error\" || entry.status === \"timeout\") {\n\t\t\t\terrors.set(entry.providerId, new Error(entry.error ?? entry.status));\n\t\t\t}\n\t\t}\n\t\tthis.updateModelSnapshot();\n\t\ttry {\n\t\t\tawait this.forceRefreshAvailability();\n\t\t} catch {\n\t\t\t// Availability errors are recorded by forceRefreshAvailability; refreshed models remain usable.\n\t\t}\n\t\tconst catalogResult: CatalogRefreshResult = {\n\t\t\taborted: result.aborted,\n\t\t\terrors,\n\t\t\tofficial,\n\t\t\tlive,\n\t\t\tincomplete: live.flatMap((entry) => entry.incomplete),\n\t\t};\n\t\tthis.lastCatalogRefresh = catalogResult;\n\t\treturn catalogResult;\n\t}\n\n\tgetLastCatalogRefresh(): CatalogRefreshResult {\n\t\treturn this.lastCatalogRefresh;\n\t}\n\n\tpersistUserModels(rows: readonly UserModelEntry[]): void {\n\t\tthis.userModels.upsert(rows);\n\t\tthis.overlay.setUser(this.userModelsForStoredProviders(this.snapshot.storedProviders));\n\t\tthis.updateModelSnapshot();\n\t}\n\n\tprivate async refreshOfficialCatalog(\n\t\tallowNetwork: boolean,\n\t\tsignal?: AbortSignal,\n\t): Promise<(OfficialCatalogLoadResult & { evictedUserRows: number }) | undefined> {\n\t\tconst storedProviders = await this.listStoredProviderIds();\n\t\tconst loaded = preferOfficialCatalog(\n\t\t\tthis.lastOfficial,\n\t\t\tawait loadOfficialCatalog({\n\t\t\t\tallowNetwork,\n\t\t\t\tcachePath: this.officialCachePath,\n\t\t\t\tsignal,\n\t\t\t\tproviderIds: [...storedProviders],\n\t\t\t}),\n\t\t);\n\t\tthis.lastOfficial = loaded;\n\t\tconst evicted = this.userModels.evictOfficial(officialModelKeys(loaded.catalog));\n\t\tconst templateByProvider = new Map<string, Model<Api> | undefined>();\n\t\tconst officialModels = loaded.catalog.models\n\t\t\t.filter((entry) => storedProviders.has(entry.provider))\n\t\t\t.map((entry) => {\n\t\t\t\tif (!templateByProvider.has(entry.provider)) {\n\t\t\t\t\ttemplateByProvider.set(entry.provider, this.bakedInModels(entry.provider)[0]);\n\t\t\t\t}\n\t\t\t\treturn officialEntryToModel(entry, templateByProvider.get(entry.provider));\n\t\t\t});\n\t\tthis.overlay.setOfficial(officialModels);\n\t\tthis.overlay.setUser(this.userModelsForStoredProviders(storedProviders));\n\t\treturn { ...loaded, evictedUserRows: evicted.length };\n\t}\n\n\tprivate async restoreLiveCatalogs(): Promise<LiveCatalogResult[]> {\n\t\tconst storedProviders = await this.listStoredProviderIds();\n\t\tconst results: LiveCatalogResult[] = [];\n\t\tfor (const providerId of LIVE_LIST_PROVIDER_IDS) {\n\t\t\tconst stored = storedProviders.has(providerId) ? await this.modelsStore.read(providerId) : undefined;\n\t\t\tif (stored?.models) this.overlay.setLive(providerId, stored.models);\n\t\t\telse this.overlay.setLive(providerId, []);\n\t\t\tresults.push({\n\t\t\t\tproviderId,\n\t\t\t\tstatus: \"skipped\",\n\t\t\t\tdiscoveries: [],\n\t\t\t\tadded: 0,\n\t\t\t\ttotal: stored?.models.length ?? 0,\n\t\t\t\tincomplete: [],\n\t\t\t});\n\t\t}\n\t\treturn results;\n\t}\n\n\tprivate async refreshLiveCatalogs(officialKeys: Set<string>, signal?: AbortSignal): Promise<LiveCatalogResult[]> {\n\t\tconst storedProviders = await this.listStoredProviderIds();\n\t\tconst known = knownModelKeys(\n\t\t\tLIVE_LIST_PROVIDER_IDS.flatMap((id) => this.bakedInModels(id)),\n\t\t\tofficialKeys,\n\t\t\tthis.userModels.keys(),\n\t\t);\n\n\t\tconst results = await Promise.all(\n\t\t\tLIVE_LIST_PROVIDER_IDS.map(async (providerId) => {\n\t\t\t\tif (!storedProviders.has(providerId)) {\n\t\t\t\t\tthis.overlay.setLive(providerId, []);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tproviderId,\n\t\t\t\t\t\tstatus: \"skipped\" as const,\n\t\t\t\t\t\tdiscoveries: [],\n\t\t\t\t\t\tadded: 0,\n\t\t\t\t\t\ttotal: 0,\n\t\t\t\t\t\tincomplete: [],\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tconst stored = await this.modelsStore.read(providerId);\n\t\t\t\tif (stored?.models) this.overlay.setLive(providerId, stored.models);\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tproviderId,\n\t\t\t\t\t\tstatus: \"skipped\" as const,\n\t\t\t\t\t\tdiscoveries: [],\n\t\t\t\t\t\tadded: 0,\n\t\t\t\t\t\ttotal: stored?.models.length ?? 0,\n\t\t\t\t\t\tincomplete: [],\n\t\t\t\t\t\terror: \"aborted\",\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tconst bakedIn = this.bakedInModels(providerId);\n\t\t\t\tconst provider = this.models.getProvider(providerId) ?? this.defaultBuiltins.get(providerId);\n\t\t\t\tconst baseUrl = provider?.baseUrl ?? bakedIn[0]?.baseUrl;\n\t\t\t\tif (!baseUrl) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tproviderId,\n\t\t\t\t\t\tstatus: \"skipped\" as const,\n\t\t\t\t\t\tdiscoveries: [],\n\t\t\t\t\t\tadded: 0,\n\t\t\t\t\t\ttotal: 0,\n\t\t\t\t\t\tincomplete: [],\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tlet credential: Credential | undefined;\n\t\t\t\ttry {\n\t\t\t\t\tcredential = await this.refreshCredentialFor(providerId);\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tproviderId,\n\t\t\t\t\t\tstatus: \"error\" as const,\n\t\t\t\t\t\tdiscoveries: [],\n\t\t\t\t\t\tadded: 0,\n\t\t\t\t\t\ttotal: stored?.models.length ?? 0,\n\t\t\t\t\t\tincomplete: [],\n\t\t\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tif (!credential) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tproviderId,\n\t\t\t\t\t\tstatus: \"skipped\" as const,\n\t\t\t\t\t\tdiscoveries: [],\n\t\t\t\t\t\tadded: 0,\n\t\t\t\t\t\ttotal: stored?.models.length ?? 0,\n\t\t\t\t\t\tincomplete: [],\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tconst result = await fetchLiveProviderModels({\n\t\t\t\t\tproviderId,\n\t\t\t\t\tbaseUrl,\n\t\t\t\t\tbakedIn,\n\t\t\t\t\tcredential,\n\t\t\t\t\tknownKeys: known,\n\t\t\t\t\tsignal,\n\t\t\t\t});\n\t\t\t\tif (result.status === \"ok\") {\n\t\t\t\t\tconst overlayModels = buildLiveOverlay(bakedIn, result.discoveries);\n\t\t\t\t\tthis.overlay.setLive(providerId, overlayModels);\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait this.modelsStore.write(providerId, { models: overlayModels, checkedAt: Date.now() });\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Store write is best-effort.\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}),\n\t\t);\n\t\treturn results;\n\t}\n\n\tprivate async refreshCredentialFor(providerId: string): Promise<Credential | undefined> {\n\t\tconst stored = await this.credentials.read(providerId);\n\t\t// Same lock + persist path as chat. Returning stored OAuth here skips\n\t\t// refresh and sends expired SuperGrok tokens to GET /models (HTTP 403).\n\t\tconst resolved = await this.getAuth(providerId);\n\t\tif (resolved?.auth.apiKey) return { type: \"api_key\", key: resolved.auth.apiKey, env: resolved.env };\n\t\tif (stored?.type === \"oauth\" && stored.access) return stored;\n\t\tif (stored?.type === \"api_key\" && stored.key) return stored;\n\t\treturn undefined;\n\t}\n\n\tregisterProvider(providerId: string, config: ProviderConfigInput): void {\n\t\t// Validate the incoming registration on its own, like the legacy registry:\n\t\t// a broken re-registration must throw without touching the stored config.\n\t\tvalidateExtensionProvider(providerId, this.builtins.get(providerId), this.config.getProvider(providerId), config);\n\t\t// Re-registration merges defined values over the previous registration and\n\t\t// preserves undefined ones, matching the legacy ModelRegistry contract.\n\t\tconst previous = this.extensionProviders.get(providerId);\n\t\tconst effective: ProviderConfigInput = { ...previous };\n\t\tfor (const [key, value] of Object.entries(config)) {\n\t\t\tif (value !== undefined) (effective as Record<string, unknown>)[key] = value;\n\t\t}\n\t\tthis.extensionProviders.set(providerId, effective);\n\t\tthis.recomposeProvider(providerId);\n\t\tthis.updateModelSnapshot();\n\t\tif (\n\t\t\tthis.snapshot.storedProviders.has(providerId) ||\n\t\t\tconfiguredRequestAuthStatus(this.config.getProvider(providerId), effective)?.configured\n\t\t) {\n\t\t\tconst configuredProviders = new Set(this.snapshot.configuredProviders).add(providerId);\n\t\t\tconst auth = new Map(this.snapshot.auth);\n\t\t\t// Provisional entry until the async refresh lands; never clobber a real check result.\n\t\t\tif (!auth.get(providerId)) {\n\t\t\t\tauth.set(providerId, {\n\t\t\t\t\ttype: effective.oauth && !effective.apiKey ? \"oauth\" : \"api_key\",\n\t\t\t\t\tsource: \"configured provider\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tthis.snapshot = {\n\t\t\t\t...this.snapshot,\n\t\t\t\tauth,\n\t\t\t\tconfiguredProviders,\n\t\t\t\tavailable: this.snapshot.all.filter((model) => configuredProviders.has(model.provider)),\n\t\t\t};\n\t\t}\n\t\tvoid this.refresh({ allowNetwork: false });\n\t}\n\n\tunregisterProvider(providerId: string): void {\n\t\tthis.extensionProviders.delete(providerId);\n\t\tthis.recomposeProvider(providerId);\n\t\tthis.updateModelSnapshot();\n\t\tvoid this.refresh({ allowNetwork: false });\n\t}\n}\n\n/** TUI init / footer / rebind: cache-only. Live refresh is `/refresh` and the model picker. */\nexport async function refreshModelCandidatesForInit(\n\truntime: Pick<ModelRuntime, \"refresh\" | \"getAvailableSnapshot\">,\n): Promise<readonly Model<Api>[]> {\n\tawait runtime.refresh({ allowNetwork: false });\n\treturn runtime.getAvailableSnapshot();\n}\n"]}
1
+ {"version":3,"file":"model-runtime.d.ts","sourceRoot":"","sources":["../../src/core/model-runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import { dirname, join } from \"node:path\";\nimport {\n\ttype Api,\n\ttype ApiStreamOptions,\n\ttype AssistantMessage,\n\ttype AssistantMessageEventStream,\n\ttype AuthCheck,\n\ttype AuthInteraction,\n\ttype AuthResult,\n\ttype AuthType,\n\ttype Context,\n\ttype Credential,\n\ttype CredentialInfo,\n\ttype CredentialStore,\n\tcreateModels,\n\tlazyStream,\n\ttype Model,\n\ttype Models,\n\ttype ModelsApiStreamOptions,\n\tModelsError,\n\ttype ModelsRefreshOptions,\n\ttype ModelsRefreshResult,\n\ttype ModelsSimpleStreamOptions,\n\ttype ModelsStore,\n\ttype ModelsStreamTransforms,\n\ttype MutableModels,\n\ttype Provider,\n\ttype ProviderHeaders,\n\ttype SimpleStreamOptions,\n\ttype StreamOptions,\n} from \"@ashx-j/lunr-ai\";\nimport * as builtinProviderCatalog from \"@ashx-j/lunr-ai/providers/all\";\nimport { getAgentDir } from \"../config.ts\";\nimport { AuthStorage as DefaultAuthStorage } from \"./auth-storage.ts\";\nimport { catalogCacheScope } from \"./catalog-cache-scope.ts\";\nimport { CatalogOverlaySource, knownModelKeys, withCatalogOverlay } from \"./catalog-merge.ts\";\nimport { readGrokCliXaiOAuth, wrapXaiGrokCliCredentials } from \"./grok-cli-auth.ts\";\nimport {\n\tbuildLiveOverlay,\n\tfetchLiveProviderModels,\n\ttype IncompleteLiveModel,\n\tLIVE_LIST_PROVIDER_IDS,\n\ttype LiveCatalogResult,\n} from \"./live-catalog.ts\";\nimport { ModelConfig } from \"./model-config.ts\";\nimport { FileModelsStore, InMemoryCodingAgentModelsStore } from \"./models-store.ts\";\nimport {\n\tloadOfficialCatalog,\n\ttype OfficialCatalogLoadResult,\n\tofficialCatalogCachePath,\n\tofficialEntryToModel,\n\tofficialModelKeys,\n\tpreferOfficialCatalog,\n} from \"./official-catalog.ts\";\nimport {\n\ttype AuthStatus,\n\ttype CompatibilityRequestConfig,\n\tcomposeModelProvider,\n\tconfiguredRequestAuthStatus,\n\ttype ProviderConfigInput,\n\tresolveCompatibilityRequestConfig,\n\tresolveConfiguredModelHeaders,\n\tvalidateExtensionProvider,\n} from \"./provider-composer.ts\";\nimport { RuntimeCredentials } from \"./runtime-credentials.ts\";\nimport { SubscriptionManager } from \"./subscriptions.ts\";\nimport { clearPlanUsageCache } from \"./usage-service.ts\";\nimport { type UserModelEntry, UserModelsStore, userEntryToModel, userModelsPath } from \"./user-models.ts\";\n\ninterface ModelRuntimeSnapshot {\n\tall: readonly Model<Api>[];\n\tavailable: readonly Model<Api>[];\n\tconfiguredProviders: ReadonlySet<string>;\n\tstoredProviders: ReadonlySet<string>;\n\tauth: ReadonlyMap<string, AuthCheck | undefined>;\n}\n\nexport interface CreateModelRuntimeOptions {\n\t/** Credential storage. Defaults to the file at authPath. */\n\tcredentials?: CredentialStore;\n\tauthPath?: string;\n\tmodelsPath?: string | null;\n\tmodelsStore?: ModelsStore;\n\tmodelsStorePath?: string;\n\tallowModelNetwork?: boolean;\n\t/** Applied by callers of `refresh()`, not by `create()` (startup is cache-only). */\n\tmodelRefreshTimeoutMs?: number;\n\t/** Unused. Kept so older callers compiling against this options bag still typecheck. */\n\tcatalogBaseUrl?: string;\n\t/** lunr: subscription-key pool. Defaults to subscriptions.json next to authPath (in-memory for custom stores). */\n\tsubscriptions?: SubscriptionManager;\n\t/**\n\t * Grok CLI home (`~/.grok`) used as a SuperGrok OAuth fallback.\n\t * `null` disables the fallback. Custom `credentials` default to disabled\n\t * unless this is an explicit path.\n\t */\n\tgrokHome?: string | null;\n}\n\nexport interface CatalogRefreshResult extends ModelsRefreshResult {\n\tofficial?: OfficialCatalogLoadResult & { evictedUserRows: number };\n\tlive: LiveCatalogResult[];\n\tincomplete: IncompleteLiveModel[];\n}\n\nexport interface ModelRuntimeAuthOverrides {\n\tapiKey?: string;\n\tenv?: Record<string, string>;\n}\n\nfunction mergeHeaders(\n\tbase: ProviderHeaders | undefined,\n\toverride: ProviderHeaders | undefined,\n): ProviderHeaders | undefined {\n\tif (!base && !override) return undefined;\n\tconst merged = { ...base };\n\tfor (const [name, value] of Object.entries(override ?? {})) {\n\t\tconst lowerName = name.toLowerCase();\n\t\tfor (const existingName of Object.keys(merged)) {\n\t\t\tif (existingName.toLowerCase() === lowerName) delete merged[existingName];\n\t\t}\n\t\tmerged[name] = value;\n\t}\n\treturn merged;\n}\n\n/** Configured pi-ai Models collection used by coding-agent and SDK consumers. */\nexport class ModelRuntime implements Models {\n\tprivate readonly models: MutableModels;\n\tprivate readonly credentials: RuntimeCredentials;\n\t/** lunr: per-provider subscription-key pools; rotation mirrors the active key into the credential store. */\n\treadonly subscriptionManager: SubscriptionManager;\n\tprivate readonly defaultBuiltins: ReadonlyMap<string, Provider>;\n\tprivate readonly builtins = new Map<string, Provider>();\n\tprivate readonly extensionProviders = new Map<string, ProviderConfigInput>();\n\tprivate readonly compositionErrors = new Map<string, string>();\n\tprivate readonly modelsPath: string | undefined;\n\tprivate readonly allowModelNetwork: boolean;\n\tprivate config: ModelConfig;\n\tprivate snapshot: ModelRuntimeSnapshot = {\n\t\tall: [],\n\t\tavailable: [],\n\t\tconfiguredProviders: new Set(),\n\t\tstoredProviders: new Set(),\n\t\tauth: new Map(),\n\t};\n\tprivate availabilityRefresh: Promise<void> | undefined;\n\tprivate availabilityError: string | undefined;\n\tprivate readonly modelsStore: ModelsStore;\n\tprivate readonly overlay = new CatalogOverlaySource();\n\tprivate readonly userModels: UserModelsStore;\n\tprivate readonly officialCachePath: string | undefined;\n\tprivate lastCatalogRefresh: CatalogRefreshResult = { aborted: false, errors: new Map(), live: [], incomplete: [] };\n\tprivate lastOfficial: OfficialCatalogLoadResult | undefined;\n\tprivate catalogRefresh: Promise<CatalogRefreshResult> | undefined;\n\tprivate catalogRefreshAllowsNetwork = false;\n\tprivate nextAutomaticRefresh = 0;\n\tprivate automaticRefreshIdentity = \"\";\n\tprivate readonly grokHome: string | undefined;\n\n\tprivate constructor(\n\t\tcredentials: RuntimeCredentials,\n\t\tconfig: ModelConfig,\n\t\tmodelsPath: string | undefined,\n\t\tmodelsStore: ModelsStore,\n\t\tproviders: readonly Provider[],\n\t\tallowModelNetwork: boolean,\n\t\tsubscriptionManager: SubscriptionManager,\n\t\tcatalogDir: string | undefined,\n\t\tgrokHome: string | undefined,\n\t) {\n\t\tthis.credentials = credentials;\n\t\tthis.config = config;\n\t\tthis.modelsPath = modelsPath;\n\t\tthis.modelsStore = modelsStore;\n\t\tthis.allowModelNetwork = allowModelNetwork;\n\t\tthis.subscriptionManager = subscriptionManager;\n\t\tthis.userModels = new UserModelsStore(catalogDir ? userModelsPath(catalogDir) : undefined);\n\t\tthis.officialCachePath = catalogDir ? officialCatalogCachePath(catalogDir) : undefined;\n\t\tthis.grokHome = grokHome;\n\t\tthis.defaultBuiltins = new Map(providers.map((provider) => [provider.id, provider]));\n\t\tfor (const [providerId, provider] of this.defaultBuiltins) this.builtins.set(providerId, provider);\n\t\tthis.models = createModels({ credentials, modelsStore });\n\t\tthis.rebuildProviders();\n\t}\n\n\tstatic async create(options: CreateModelRuntimeOptions = {}): Promise<ModelRuntime> {\n\t\t// lunr: keep the underlying store — the SubscriptionManager mirrors rotated\n\t\t// keys into it directly, NOT through the RuntimeCredentials overlay (a runtime\n\t\t// --api-key override would shadow the mirror there).\n\t\tconst rawStore = options.credentials ?? DefaultAuthStorage.create(options.authPath);\n\t\tconst grokHomeDisabled =\n\t\t\toptions.grokHome === null || (options.grokHome === undefined && options.credentials !== undefined);\n\t\tconst grokHome = grokHomeDisabled ? undefined : (options.grokHome ?? undefined);\n\t\tconst baseStore = grokHomeDisabled ? rawStore : wrapXaiGrokCliCredentials(rawStore, { grokHome });\n\t\tconst credentials = new RuntimeCredentials(baseStore);\n\t\t// Pool persistence: subscriptions.json next to auth.json. A custom credential\n\t\t// store without an authPath (tests, SDK embeddings) gets a process-local pool\n\t\t// so nothing leaks into the real agent dir.\n\t\tconst subscriptionManager =\n\t\t\toptions.subscriptions ??\n\t\t\t(options.credentials && !options.authPath\n\t\t\t\t? SubscriptionManager.inMemory(baseStore)\n\t\t\t\t: SubscriptionManager.create(\n\t\t\t\t\t\tbaseStore,\n\t\t\t\t\t\toptions.authPath ? join(dirname(options.authPath), \"subscriptions.json\") : undefined,\n\t\t\t\t\t));\n\t\tconst modelsPath =\n\t\t\toptions.modelsPath === null ? undefined : (options.modelsPath ?? join(getAgentDir(), \"models.json\"));\n\t\tconst config = await ModelConfig.load(modelsPath);\n\t\tconst modelsStore =\n\t\t\toptions.modelsStore ??\n\t\t\t(modelsPath\n\t\t\t\t? new FileModelsStore(options.modelsStorePath ?? join(dirname(modelsPath), \"models-store.json\"))\n\t\t\t\t: new InMemoryCodingAgentModelsStore());\n\t\tconst providers = builtinProviderCatalog.builtinProviders();\n\t\tconst catalogDir = modelsPath ? dirname(modelsPath) : options.authPath ? dirname(options.authPath) : undefined;\n\t\tconst runtime = new ModelRuntime(\n\t\t\tcredentials,\n\t\t\tconfig,\n\t\t\tmodelsPath,\n\t\t\tmodelsStore,\n\t\t\tproviders,\n\t\t\toptions.allowModelNetwork ?? process.env.PI_OFFLINE === undefined,\n\t\t\tsubscriptionManager,\n\t\t\tcatalogDir,\n\t\t\tgrokHome,\n\t\t);\n\t\truntime.configureRadiusProviders();\n\t\truntime.rebuildProviders();\n\t\t// lunr: create() must not wait on GitHub / provider /v1/models / a dead NIC.\n\t\t// Disk cache + baked-in + bundled official overlay are enough to start;\n\t\t// /refresh and the model picker still do a live refresh.\n\t\tawait runtime.refresh({ allowNetwork: false });\n\t\treturn runtime;\n\t}\n\n\tprivate configureRadiusProviders(): void {\n\t\tthis.builtins.clear();\n\t\tfor (const [providerId, provider] of this.defaultBuiltins) this.builtins.set(providerId, provider);\n\t\tfor (const providerId of this.config.getProviderIds()) {\n\t\t\tconst config = this.config.getProvider(providerId);\n\t\t\tif (config?.oauth !== \"radius\" || !config.baseUrl) continue;\n\t\t\tthis.builtins.set(\n\t\t\t\tproviderId,\n\t\t\t\tbuiltinProviderCatalog.radiusProvider({\n\t\t\t\t\tid: providerId,\n\t\t\t\t\tname: config.name ?? providerId,\n\t\t\t\t\tgateway: config.baseUrl.replace(/\\/v1\\/?$/u, \"\"),\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate providerIds(): Set<string> {\n\t\treturn new Set([...this.builtins.keys(), ...this.config.getProviderIds(), ...this.extensionProviders.keys()]);\n\t}\n\n\tprivate recomposeProvider(providerId: string): void {\n\t\tconst base = this.builtins.get(providerId);\n\t\tconst extension = this.extensionProviders.get(providerId);\n\t\tif (!base && !this.config.getProvider(providerId) && !extension) {\n\t\t\tthis.models.deleteProvider(providerId);\n\t\t\tthis.compositionErrors.delete(providerId);\n\t\t\treturn;\n\t\t}\n\t\tif (base && !this.config.getProvider(providerId) && !extension) {\n\t\t\t// No models.json/extension overlays: keep builtin auth/stream exact, then apply catalog layers.\n\t\t\tthis.models.setProvider(this.withLocalCatalog(base));\n\t\t\tthis.compositionErrors.delete(providerId);\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\t// Discovery is metadata beneath explicit user configuration and extension model definitions.\n\t\t\tthis.models.setProvider(\n\t\t\t\tcomposeModelProvider(providerId, base ? this.withLocalCatalog(base) : undefined, this.config, extension),\n\t\t\t);\n\t\t\tthis.compositionErrors.delete(providerId);\n\t\t} catch (error) {\n\t\t\tthis.compositionErrors.set(providerId, error instanceof Error ? error.message : String(error));\n\t\t\tif (base) this.models.setProvider(this.withLocalCatalog(base));\n\t\t\telse this.models.deleteProvider(providerId);\n\t\t}\n\t}\n\n\tprivate withLocalCatalog(provider: Provider): Provider {\n\t\treturn withCatalogOverlay(provider, this.overlay);\n\t}\n\n\tprivate bakedInModels(providerId: string): Model<Api>[] {\n\t\treturn [...(this.defaultBuiltins.get(providerId)?.getModels() ?? [])];\n\t}\n\n\tprivate rebuildProviders(): void {\n\t\tthis.models.clearProviders();\n\t\tthis.compositionErrors.clear();\n\t\tfor (const providerId of this.providerIds()) this.recomposeProvider(providerId);\n\t\tthis.updateModelSnapshot();\n\t}\n\n\tprivate updateModelSnapshot(): void {\n\t\tconst all = [...this.models.getModels()];\n\t\tthis.snapshot = {\n\t\t\t...this.snapshot,\n\t\t\tall,\n\t\t\tavailable: all.filter(\n\t\t\t\t(model) => this.snapshot.configuredProviders.has(model.provider) && this.isCatalogModelAvailable(model),\n\t\t\t),\n\t\t};\n\t}\n\n\tprivate isCatalogModelAvailable(model: Model<Api>): boolean {\n\t\tconst config = this.config.getProvider(model.provider);\n\t\treturn (\n\t\t\t!!config?.models?.some((row) => row.id === model.id) ||\n\t\t\t!!this.extensionProviders.get(model.provider)?.models?.some((row) => row.id === model.id) ||\n\t\t\tthis.overlay.isAvailable(model)\n\t\t);\n\t}\n\n\tprivate async listStoredProviderIds(): Promise<Set<string>> {\n\t\tconst credentials = await this.credentials.list();\n\t\treturn new Set(credentials.map((entry) => entry.providerId));\n\t}\n\n\t/** `/model` lists stored creds + models.json/extension keys, never ambient envApiKeyAuth. */\n\tprivate configuredProviderIds(storedProviders: ReadonlySet<string>): Set<string> {\n\t\tconst configured = new Set(storedProviders);\n\t\tfor (const provider of this.models.getProviders()) {\n\t\t\tif (\n\t\t\t\tconfiguredRequestAuthStatus(this.config.getProvider(provider.id), this.extensionProviders.get(provider.id))\n\t\t\t\t\t?.configured\n\t\t\t) {\n\t\t\t\tconfigured.add(provider.id);\n\t\t\t}\n\t\t}\n\t\treturn configured;\n\t}\n\n\tprivate userModelsForStoredProviders(storedProviders: ReadonlySet<string>): Model<Api>[] {\n\t\treturn this.userModels\n\t\t\t.list()\n\t\t\t.filter((row) => storedProviders.has(row.provider))\n\t\t\t.map(userEntryToModel);\n\t}\n\n\tprivate async runAvailabilityRefresh(): Promise<void> {\n\t\tconst providers = this.models.getProviders();\n\t\tconst [available, checks, storedProviders] = await Promise.all([\n\t\t\tthis.models.getAvailable(),\n\t\t\tPromise.all(\n\t\t\t\tproviders.map(\n\t\t\t\t\tasync (provider): Promise<[string, AuthCheck | undefined]> => [\n\t\t\t\t\t\tprovider.id,\n\t\t\t\t\t\tawait this.models.checkAuth(provider.id),\n\t\t\t\t\t],\n\t\t\t\t),\n\t\t\t),\n\t\t\tthis.listStoredProviderIds(),\n\t\t]);\n\t\tconst auth = new Map(checks);\n\t\tconst configuredProviders = this.configuredProviderIds(storedProviders);\n\t\tthis.snapshot = {\n\t\t\tall: [...this.models.getModels()],\n\t\t\tavailable: available.filter(\n\t\t\t\t(model) => configuredProviders.has(model.provider) && this.isCatalogModelAvailable(model),\n\t\t\t),\n\t\t\tconfiguredProviders,\n\t\t\tstoredProviders,\n\t\t\tauth,\n\t\t};\n\t\tthis.availabilityError = undefined;\n\t}\n\n\tprivate queueAvailabilityRefresh(after: Promise<void> | undefined): Promise<void> {\n\t\tconst refresh = (after ?? Promise.resolve()).catch(() => {}).then(() => this.runAvailabilityRefresh());\n\t\tconst recorded = refresh.catch((error) => {\n\t\t\tthis.availabilityError = error instanceof Error ? error.message : String(error);\n\t\t\tthrow error;\n\t\t});\n\t\tconst tracked = recorded.finally(() => {\n\t\t\tif (this.availabilityRefresh === tracked) this.availabilityRefresh = undefined;\n\t\t});\n\t\tthis.availabilityRefresh = tracked;\n\t\treturn tracked;\n\t}\n\n\t/** Coalesce concurrent readers onto the pending refresh. */\n\tprivate refreshAvailability(): Promise<void> {\n\t\treturn this.availabilityRefresh ?? this.queueAvailabilityRefresh(undefined);\n\t}\n\n\t/** Mutations must not observe an in-flight refresh started before them. */\n\tprivate forceRefreshAvailability(): Promise<void> {\n\t\treturn this.queueAvailabilityRefresh(this.availabilityRefresh);\n\t}\n\n\tgetProviders(): readonly Provider[] {\n\t\treturn this.models.getProviders();\n\t}\n\n\tgetProvider(providerId: string): Provider | undefined {\n\t\treturn this.models.getProvider(providerId);\n\t}\n\n\tgetModels(providerId?: string): readonly Model<Api>[] {\n\t\treturn this.models.getModels(providerId);\n\t}\n\n\tgetModel(providerId: string, modelId: string): Model<Api> | undefined {\n\t\treturn this.models.getModel(providerId, modelId);\n\t}\n\n\tasync checkAuth(providerId: string): Promise<AuthCheck | undefined> {\n\t\treturn this.models.checkAuth(providerId);\n\t}\n\n\tasync getAvailable(providerId?: string): Promise<readonly Model<Api>[]> {\n\t\tif (providerId) {\n\t\t\tif (this.availabilityRefresh) {\n\t\t\t\tawait this.availabilityRefresh;\n\t\t\t\treturn this.snapshot.available.filter((model) => model.provider === providerId);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn (await this.models.getAvailable(providerId)).filter((model) => this.isCatalogModelAvailable(model));\n\t\t\t} catch (error) {\n\t\t\t\tthis.availabilityError = error instanceof Error ? error.message : String(error);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\tawait this.refreshAvailability();\n\t\treturn this.snapshot.available;\n\t}\n\n\tgetAvailableSnapshot(): readonly Model<Api>[] {\n\t\treturn this.snapshot.available;\n\t}\n\n\tgetError(): string | undefined {\n\t\tconst errors: string[] = [];\n\t\tconst configError = this.config.getError();\n\t\tif (configError) errors.push(configError);\n\t\tfor (const [providerId, error] of this.compositionErrors) {\n\t\t\terrors.push(`Provider \"${providerId}\": ${error}`);\n\t\t}\n\t\tif (this.availabilityError) errors.push(`Availability refresh: ${this.availabilityError}`);\n\t\treturn errors.length > 0 ? errors.join(\"\\n\\n\") : undefined;\n\t}\n\n\tgetRegisteredProviderConfig(providerId: string): ProviderConfigInput | undefined {\n\t\treturn this.extensionProviders.get(providerId);\n\t}\n\n\tgetRegisteredProviderIds(): readonly string[] {\n\t\treturn [...this.extensionProviders.keys()];\n\t}\n\n\t/** @internal Compatibility fallback for ModelRegistry when provider auth is unconfigured. */\n\tgetCompatibilityRequestConfig(model: Model<Api>): CompatibilityRequestConfig {\n\t\treturn resolveCompatibilityRequestConfig(\n\t\t\tmodel,\n\t\t\tthis.config.getProvider(model.provider),\n\t\t\tthis.extensionProviders.get(model.provider),\n\t\t);\n\t}\n\n\tisUsingOAuth(providerId: string): boolean {\n\t\treturn this.snapshot.auth.get(providerId)?.type === \"oauth\";\n\t}\n\n\thasConfiguredAuth(providerId: string): boolean {\n\t\treturn this.snapshot.configuredProviders.has(providerId);\n\t}\n\n\tgetAuth(providerId: string, overrides?: ModelRuntimeAuthOverrides): Promise<AuthResult | undefined>;\n\tgetAuth(model: Model<Api>, overrides?: ModelRuntimeAuthOverrides): Promise<AuthResult | undefined>;\n\tasync getAuth(\n\t\tproviderOrModel: string | Model<Api>,\n\t\toverrides: ModelRuntimeAuthOverrides = {},\n\t): Promise<AuthResult | undefined> {\n\t\tif (typeof providerOrModel === \"string\") return this.models.getAuth(providerOrModel, overrides);\n\t\tconst resolution = await this.models.getAuth(providerOrModel, overrides);\n\t\tif (!resolution) return undefined;\n\t\tconst configuredHeaders = resolveConfiguredModelHeaders(\n\t\t\tproviderOrModel,\n\t\t\tthis.config.getProvider(providerOrModel.provider),\n\t\t\tthis.extensionProviders.get(providerOrModel.provider),\n\t\t\t{ ...(resolution.env ?? {}), ...(overrides.env ?? {}) },\n\t\t);\n\t\treturn {\n\t\t\t...resolution,\n\t\t\tauth: {\n\t\t\t\t...resolution.auth,\n\t\t\t\theaders: mergeHeaders(resolution.auth.headers, configuredHeaders),\n\t\t\t},\n\t\t};\n\t}\n\n\t/** lunr: whether a runtime --api-key override is active for the provider (it shadows auth.json). */\n\thasRuntimeApiKey(providerId: string): boolean {\n\t\treturn this.credentials.hasRuntimeApiKey(providerId);\n\t}\n\n\tasync setRuntimeApiKey(\n\t\tproviderId: string,\n\t\tapiKey: string,\n\t\toptions?: { allowNetwork?: boolean },\n\t): Promise<void> {\n\t\tthis.credentials.setRuntimeApiKey(providerId, apiKey);\n\t\tconst auth = new Map(this.snapshot.auth).set(providerId, { type: \"api_key\", source: \"runtime API key\" });\n\t\tconst configuredProviders = new Set(this.snapshot.configuredProviders).add(providerId);\n\t\tconst storedProviders = new Set(this.snapshot.storedProviders).add(providerId);\n\t\tthis.snapshot = {\n\t\t\t...this.snapshot,\n\t\t\tauth,\n\t\t\tconfiguredProviders,\n\t\t\tstoredProviders,\n\t\t\tavailable: this.snapshot.all.filter(\n\t\t\t\t(model) => configuredProviders.has(model.provider) && this.isCatalogModelAvailable(model),\n\t\t\t),\n\t\t};\n\t\tawait this.refresh({ allowNetwork: options?.allowNetwork ?? this.allowModelNetwork });\n\t}\n\n\tasync removeRuntimeApiKey(providerId: string): Promise<void> {\n\t\tthis.credentials.removeRuntimeApiKey(providerId);\n\t\tawait this.refresh({ allowNetwork: this.allowModelNetwork });\n\t}\n\n\t/** lunr: whether network model-catalog fetches are allowed (offline mode disables them). */\n\tisNetworkAllowed(): boolean {\n\t\treturn this.allowModelNetwork;\n\t}\n\n\tlistCredentials(): Promise<readonly CredentialInfo[]> {\n\t\treturn this.credentials.list();\n\t}\n\n\tgetProviderAuthStatus(providerId: string): AuthStatus {\n\t\tif (this.credentials.hasRuntimeApiKey(providerId)) return { configured: true, source: \"runtime\" };\n\t\tif (this.snapshot.storedProviders.has(providerId)) return { configured: true, source: \"stored\" };\n\t\tconst configured = configuredRequestAuthStatus(\n\t\t\tthis.config.getProvider(providerId),\n\t\t\tthis.extensionProviders.get(providerId),\n\t\t);\n\t\tif (configured) return configured;\n\t\tconst check = this.snapshot.auth.get(providerId);\n\t\treturn check ? { configured: true, source: \"environment\", label: check.source } : { configured: false };\n\t}\n\n\tprivate async prepareRequest(\n\t\tmodel: Model<Api>,\n\t\toptions: (StreamOptions & ModelsStreamTransforms) | undefined,\n\t): Promise<{ provider: Provider; model: Model<Api>; options: StreamOptions }> {\n\t\tconst provider = this.models.getProvider(model.provider);\n\t\tif (!provider) throw new ModelsError(\"provider\", `Unknown provider: ${model.provider}`);\n\t\tconst resolution = await this.getAuth(model, { apiKey: options?.apiKey, env: options?.env });\n\t\tif (!resolution) throw new ModelsError(\"auth\", `Provider is not configured: ${model.provider}`);\n\n\t\tconst { transformHeaders, ...providerOptions } = options ?? {};\n\t\tlet headers = mergeHeaders(resolution.auth.headers, providerOptions.headers);\n\t\tif (transformHeaders) headers = await transformHeaders(headers ?? {});\n\t\tconst env =\n\t\t\tresolution.env || providerOptions.env\n\t\t\t\t? { ...(resolution.env ?? {}), ...(providerOptions.env ?? {}) }\n\t\t\t\t: undefined;\n\t\treturn {\n\t\t\tprovider,\n\t\t\tmodel: resolution.auth.baseUrl ? { ...model, baseUrl: resolution.auth.baseUrl } : model,\n\t\t\toptions: {\n\t\t\t\t...providerOptions,\n\t\t\t\tapiKey: providerOptions.apiKey ?? resolution.auth.apiKey,\n\t\t\t\theaders,\n\t\t\t\tenv,\n\t\t\t},\n\t\t};\n\t}\n\n\tstream<TApi extends Api>(\n\t\tmodel: Model<TApi>,\n\t\tcontext: Context,\n\t\toptions?: ModelsApiStreamOptions<TApi>,\n\t): AssistantMessageEventStream {\n\t\treturn lazyStream(model, async () => {\n\t\t\tconst prepared = await this.prepareRequest(\n\t\t\t\tmodel,\n\t\t\t\toptions as (StreamOptions & ModelsStreamTransforms) | undefined,\n\t\t\t);\n\t\t\treturn prepared.provider.stream(\n\t\t\t\tprepared.model as Model<TApi>,\n\t\t\t\tcontext,\n\t\t\t\tprepared.options as ApiStreamOptions<TApi>,\n\t\t\t);\n\t\t});\n\t}\n\n\tcomplete<TApi extends Api>(\n\t\tmodel: Model<TApi>,\n\t\tcontext: Context,\n\t\toptions?: ModelsApiStreamOptions<TApi>,\n\t): Promise<AssistantMessage> {\n\t\treturn this.stream(model, context, options).result();\n\t}\n\n\tstreamSimple(model: Model<Api>, context: Context, options?: ModelsSimpleStreamOptions): AssistantMessageEventStream {\n\t\treturn lazyStream(model, async () => {\n\t\t\tconst prepared = await this.prepareRequest(model, options);\n\t\t\treturn prepared.provider.streamSimple(prepared.model, context, prepared.options as SimpleStreamOptions);\n\t\t});\n\t}\n\n\tcompleteSimple(model: Model<Api>, context: Context, options?: ModelsSimpleStreamOptions): Promise<AssistantMessage> {\n\t\treturn this.streamSimple(model, context, options).result();\n\t}\n\n\tasync login(providerId: string, type: AuthType, interaction: AuthInteraction): Promise<Credential> {\n\t\tconst credential = await this.models.login(providerId, type, interaction);\n\t\tclearPlanUsageCache();\n\t\tawait this.refresh({ allowNetwork: this.allowModelNetwork });\n\t\treturn credential;\n\t}\n\n\tasync logout(providerId: string): Promise<void> {\n\t\tawait this.models.logout(providerId);\n\t\tawait this.modelsStore.delete(providerId);\n\t\tthis.userModels.evictProvider(providerId);\n\t\tthis.overlay.setLive(providerId, []);\n\t\t// Reset credential-dependent compatibility projections before the unconfigured provider is skipped by refresh.\n\t\tthis.recomposeProvider(providerId);\n\t\tclearPlanUsageCache();\n\t\tawait this.refresh({ allowNetwork: this.allowModelNetwork });\n\t}\n\n\t/** Copy a live Grok CLI SuperGrok session into lunR `auth.json`. */\n\tasync importGrokCliXaiAuth(): Promise<Credential | undefined> {\n\t\tconst grok = readGrokCliXaiOAuth({ grokHome: this.grokHome });\n\t\tif (!grok) return undefined;\n\t\tconst stored = await this.credentials.modify(\"xai\", async () => grok);\n\t\tclearPlanUsageCache();\n\t\tawait this.refresh({ allowNetwork: this.allowModelNetwork });\n\t\treturn stored;\n\t}\n\n\tasync reloadConfig(): Promise<void> {\n\t\tthis.config = await ModelConfig.load(this.modelsPath);\n\t\tthis.configureRadiusProviders();\n\t\tthis.rebuildProviders();\n\t\tawait this.refresh({ allowNetwork: this.allowModelNetwork });\n\t}\n\n\tasync refresh(options: ModelsRefreshOptions = {}): Promise<CatalogRefreshResult> {\n\t\tconst allowNetwork = options.allowNetwork ?? this.allowModelNetwork;\n\t\tif (this.catalogRefresh) {\n\t\t\t// Join an in-flight refresh that is at least as capable. A cache-only\n\t\t\t// flight must not swallow a later network refresh.\n\t\t\tif (this.catalogRefreshAllowsNetwork || !allowNetwork) {\n\t\t\t\treturn this.catalogRefresh;\n\t\t\t}\n\t\t\tawait this.catalogRefresh.catch(() => {});\n\t\t\treturn this.refresh({ ...options, allowNetwork });\n\t\t}\n\n\t\tconst run = this.executeCatalogRefresh({ ...options, allowNetwork }).finally(() => {\n\t\t\tif (this.catalogRefresh === run) {\n\t\t\t\tthis.catalogRefresh = undefined;\n\t\t\t\tthis.catalogRefreshAllowsNetwork = false;\n\t\t\t}\n\t\t});\n\t\tthis.catalogRefresh = run;\n\t\tthis.catalogRefreshAllowsNetwork = allowNetwork;\n\t\treturn run;\n\t}\n\n\tprivate async executeCatalogRefresh(\n\t\trefreshOptions: ModelsRefreshOptions & { allowNetwork: boolean },\n\t): Promise<CatalogRefreshResult> {\n\t\tconst official = await this.refreshOfficialCatalog(refreshOptions.allowNetwork, refreshOptions.signal);\n\t\tconst live = refreshOptions.allowNetwork\n\t\t\t? await this.refreshLiveCatalogs(\n\t\t\t\t\tofficial ? officialModelKeys(official.catalog) : new Set(),\n\t\t\t\t\trefreshOptions.signal,\n\t\t\t\t)\n\t\t\t: await this.restoreLiveCatalogs();\n\n\t\t// Radius / local-provider / extension refreshModels hooks. Live-list\n\t\t// providers have no refreshModels, so this does not hit pi.dev.\n\t\tconst result = ((await this.models.refresh(refreshOptions)) as ModelsRefreshResult | undefined) ?? {\n\t\t\taborted: refreshOptions.signal?.aborted ?? false,\n\t\t\terrors: new Map(),\n\t\t};\n\t\tconst errors = new Map(result.errors);\n\t\tfor (const [id, error] of Object.entries(official?.errors ?? {})) errors.set(id, new Error(error));\n\t\tfor (const entry of live) {\n\t\t\tif (entry.status === \"error\" || entry.status === \"timeout\") {\n\t\t\t\terrors.set(entry.providerId, new Error(entry.error ?? entry.status));\n\t\t\t}\n\t\t}\n\t\tthis.updateModelSnapshot();\n\t\ttry {\n\t\t\tawait this.forceRefreshAvailability();\n\t\t} catch {\n\t\t\t// Availability errors are recorded by forceRefreshAvailability; refreshed models remain usable.\n\t\t}\n\t\tconst catalogResult: CatalogRefreshResult = {\n\t\t\taborted: result.aborted,\n\t\t\terrors,\n\t\t\tofficial,\n\t\t\tlive,\n\t\t\tincomplete: live.flatMap((entry) => entry.incomplete),\n\t\t};\n\t\tthis.lastCatalogRefresh = catalogResult;\n\t\treturn catalogResult;\n\t}\n\n\tgetLastCatalogRefresh(): CatalogRefreshResult {\n\t\treturn this.lastCatalogRefresh;\n\t}\n\n\t/** Called after first paint and by the picker; explicit /refresh always bypasses this gate. */\n\tasync refreshIfStale(options: { signal?: AbortSignal } = {}): Promise<CatalogRefreshResult> {\n\t\tif (!this.allowModelNetwork || options.signal?.aborted) return this.lastCatalogRefresh;\n\t\tif (this.catalogRefresh) return this.refresh({ allowNetwork: true, signal: options.signal });\n\t\tconst providers = [...(await this.listStoredProviderIds())].sort();\n\t\tconst identity = (await Promise.all(providers.map(async (id) => this.scopeFor(id)))).join(\":\");\n\t\tif (identity === this.automaticRefreshIdentity && Date.now() < this.nextAutomaticRefresh)\n\t\t\treturn this.lastCatalogRefresh;\n\t\tthis.automaticRefreshIdentity = identity;\n\t\t// Bound retries on a broken source; a successful refresh extends the deadline to one hour.\n\t\tthis.nextAutomaticRefresh = Date.now() + 60_000;\n\t\tconst result = await this.refresh({ allowNetwork: true, signal: options.signal });\n\t\tif (!result.aborted && !result.errors.size) this.nextAutomaticRefresh = Date.now() + 3_600_000;\n\t\treturn result;\n\t}\n\n\tprivate async scopeFor(providerId: string): Promise<string> {\n\t\tconst provider = this.models.getProvider(providerId) ?? this.defaultBuiltins.get(providerId);\n\t\treturn catalogCacheScope(providerId, provider?.baseUrl ?? \"\", await this.credentials.read(providerId));\n\t}\n\n\tpersistUserModels(rows: readonly UserModelEntry[]): void {\n\t\tthis.userModels.upsert(rows);\n\t\tthis.overlay.setUser(this.userModelsForStoredProviders(this.snapshot.storedProviders));\n\t\tthis.updateModelSnapshot();\n\t}\n\n\tprivate async refreshOfficialCatalog(\n\t\tallowNetwork: boolean,\n\t\tsignal?: AbortSignal,\n\t): Promise<(OfficialCatalogLoadResult & { evictedUserRows: number }) | undefined> {\n\t\tconst storedProviders = await this.listStoredProviderIds();\n\t\tconst loaded = preferOfficialCatalog(\n\t\t\tthis.lastOfficial,\n\t\t\tawait loadOfficialCatalog({\n\t\t\t\tallowNetwork,\n\t\t\t\tcachePath: this.officialCachePath,\n\t\t\t\tsignal,\n\t\t\t\tproviderIds: [...storedProviders],\n\t\t\t}),\n\t\t);\n\t\tthis.lastOfficial = loaded;\n\t\tconst evicted = this.userModels.evictOfficial(officialModelKeys(loaded.catalog));\n\t\tconst templateByProvider = new Map<string, Model<Api> | undefined>();\n\t\tconst officialModels = loaded.catalog.models\n\t\t\t.filter((entry) => storedProviders.has(entry.provider))\n\t\t\t.map((entry) => {\n\t\t\t\tif (!templateByProvider.has(entry.provider)) {\n\t\t\t\t\ttemplateByProvider.set(entry.provider, this.bakedInModels(entry.provider)[0]);\n\t\t\t\t}\n\t\t\t\treturn officialEntryToModel(entry, templateByProvider.get(entry.provider));\n\t\t\t});\n\t\tthis.overlay.setOfficial(officialModels);\n\t\tthis.overlay.setUser(this.userModelsForStoredProviders(storedProviders));\n\t\treturn { ...loaded, evictedUserRows: evicted.length };\n\t}\n\n\tprivate async restoreLiveCatalogs(): Promise<LiveCatalogResult[]> {\n\t\tconst storedProviders = await this.listStoredProviderIds();\n\t\tconst results: LiveCatalogResult[] = [];\n\t\tfor (const providerId of LIVE_LIST_PROVIDER_IDS) {\n\t\t\tconst stored = storedProviders.has(providerId) ? await this.modelsStore.read(providerId) : undefined;\n\t\t\tconst valid =\n\t\t\t\t(!stored?.scope && providerId !== \"openai-codex\") || stored?.scope === (await this.scopeFor(providerId));\n\t\t\tif (valid && stored?.models) this.overlay.setLive(providerId, stored.models);\n\t\t\telse this.overlay.setLive(providerId, []);\n\t\t\tresults.push({\n\t\t\t\tproviderId,\n\t\t\t\tstatus: \"skipped\",\n\t\t\t\tdiscoveries: [],\n\t\t\t\tadded: 0,\n\t\t\t\ttotal: stored?.models.length ?? 0,\n\t\t\t\tincomplete: [],\n\t\t\t});\n\t\t}\n\t\treturn results;\n\t}\n\n\tprivate async refreshLiveCatalogs(officialKeys: Set<string>, signal?: AbortSignal): Promise<LiveCatalogResult[]> {\n\t\tconst storedProviders = await this.listStoredProviderIds();\n\t\tconst known = knownModelKeys(\n\t\t\tLIVE_LIST_PROVIDER_IDS.flatMap((id) => this.bakedInModels(id)),\n\t\t\tofficialKeys,\n\t\t\tthis.userModels.keys(),\n\t\t);\n\n\t\tconst results = await Promise.all(\n\t\t\tLIVE_LIST_PROVIDER_IDS.map(async (providerId) => {\n\t\t\t\tif (!storedProviders.has(providerId)) {\n\t\t\t\t\tthis.overlay.setLive(providerId, []);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tproviderId,\n\t\t\t\t\t\tstatus: \"skipped\" as const,\n\t\t\t\t\t\tdiscoveries: [],\n\t\t\t\t\t\tadded: 0,\n\t\t\t\t\t\ttotal: 0,\n\t\t\t\t\t\tincomplete: [],\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tconst stored = await this.modelsStore.read(providerId);\n\t\t\t\tconst initialScope = await this.scopeFor(providerId);\n\t\t\t\tif (stored?.models && (stored.scope === initialScope || (!stored.scope && providerId !== \"openai-codex\")))\n\t\t\t\t\tthis.overlay.setLive(providerId, stored.models);\n\t\t\t\telse this.overlay.setLive(providerId, []);\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tproviderId,\n\t\t\t\t\t\tstatus: \"skipped\" as const,\n\t\t\t\t\t\tdiscoveries: [],\n\t\t\t\t\t\tadded: 0,\n\t\t\t\t\t\ttotal: stored?.models.length ?? 0,\n\t\t\t\t\t\tincomplete: [],\n\t\t\t\t\t\terror: \"aborted\",\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tconst bakedIn = this.bakedInModels(providerId);\n\t\t\t\tconst provider = this.models.getProvider(providerId) ?? this.defaultBuiltins.get(providerId);\n\t\t\t\tconst baseUrl = provider?.baseUrl ?? bakedIn[0]?.baseUrl;\n\t\t\t\tif (!baseUrl) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tproviderId,\n\t\t\t\t\t\tstatus: \"skipped\" as const,\n\t\t\t\t\t\tdiscoveries: [],\n\t\t\t\t\t\tadded: 0,\n\t\t\t\t\t\ttotal: 0,\n\t\t\t\t\t\tincomplete: [],\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tlet credential: Credential | undefined;\n\t\t\t\ttry {\n\t\t\t\t\tcredential = await this.refreshCredentialFor(providerId);\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tproviderId,\n\t\t\t\t\t\tstatus: \"error\" as const,\n\t\t\t\t\t\tdiscoveries: [],\n\t\t\t\t\t\tadded: 0,\n\t\t\t\t\t\ttotal: stored?.models.length ?? 0,\n\t\t\t\t\t\tincomplete: [],\n\t\t\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tif (!credential) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tproviderId,\n\t\t\t\t\t\tstatus: \"skipped\" as const,\n\t\t\t\t\t\tdiscoveries: [],\n\t\t\t\t\t\tadded: 0,\n\t\t\t\t\t\ttotal: stored?.models.length ?? 0,\n\t\t\t\t\t\tincomplete: [],\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tconst requestScope = catalogCacheScope(providerId, baseUrl, credential);\n\t\t\t\tconst result = await fetchLiveProviderModels({\n\t\t\t\t\tdiscoveryClientVersion: stored?.scope === requestScope ? stored.discoveryClientVersion : undefined,\n\t\t\t\t\tproviderId,\n\t\t\t\t\tbaseUrl,\n\t\t\t\t\tbakedIn,\n\t\t\t\t\tcredential,\n\t\t\t\t\tknownKeys: known,\n\t\t\t\t\tsignal,\n\t\t\t\t});\n\t\t\t\t// A login/logout during the request must not install the previous account's result.\n\t\t\t\tconst accountChanged = (await this.scopeFor(providerId)) !== requestScope;\n\t\t\t\tif (accountChanged) this.overlay.setLive(providerId, []);\n\t\t\t\tif (signal?.aborted || accountChanged) {\n\t\t\t\t\treturn { ...result, status: \"skipped\" as const, discoveries: [], incomplete: [] };\n\t\t\t\t}\n\t\t\t\tif (result.status === \"ok\") {\n\t\t\t\t\tconst overlayModels = buildLiveOverlay(bakedIn, result.discoveries);\n\t\t\t\t\tthis.overlay.setLive(providerId, overlayModels);\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait this.modelsStore.write(providerId, {\n\t\t\t\t\t\t\tmodels: overlayModels,\n\t\t\t\t\t\t\tcheckedAt: Date.now(),\n\t\t\t\t\t\t\tscope: requestScope,\n\t\t\t\t\t\t\tdiscoveryClientVersion: result.discoveryClientVersion,\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Store write is best-effort.\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}),\n\t\t);\n\t\treturn results;\n\t}\n\n\tprivate async refreshCredentialFor(providerId: string): Promise<Credential | undefined> {\n\t\t// Same lock + persist path as chat. Returning stored OAuth here skips\n\t\t// refresh and sends expired SuperGrok tokens to GET /models (HTTP 403).\n\t\tconst resolved = await this.getAuth(providerId);\n\t\tconst stored = await this.credentials.read(providerId);\n\t\tif (stored?.type === \"oauth\") return { ...stored, access: resolved?.auth.apiKey ?? stored.access };\n\t\tif (resolved?.auth.apiKey) return { type: \"api_key\", key: resolved.auth.apiKey, env: resolved.env };\n\t\tif (stored?.type === \"api_key\" && stored.key) return stored;\n\t\treturn undefined;\n\t}\n\n\tregisterProvider(providerId: string, config: ProviderConfigInput): void {\n\t\t// Validate the incoming registration on its own, like the legacy registry:\n\t\t// a broken re-registration must throw without touching the stored config.\n\t\tvalidateExtensionProvider(providerId, this.builtins.get(providerId), this.config.getProvider(providerId), config);\n\t\t// Re-registration merges defined values over the previous registration and\n\t\t// preserves undefined ones, matching the legacy ModelRegistry contract.\n\t\tconst previous = this.extensionProviders.get(providerId);\n\t\tconst effective: ProviderConfigInput = { ...previous };\n\t\tfor (const [key, value] of Object.entries(config)) {\n\t\t\tif (value !== undefined) (effective as Record<string, unknown>)[key] = value;\n\t\t}\n\t\tthis.extensionProviders.set(providerId, effective);\n\t\tthis.recomposeProvider(providerId);\n\t\tthis.updateModelSnapshot();\n\t\tif (\n\t\t\tthis.snapshot.storedProviders.has(providerId) ||\n\t\t\tconfiguredRequestAuthStatus(this.config.getProvider(providerId), effective)?.configured\n\t\t) {\n\t\t\tconst configuredProviders = new Set(this.snapshot.configuredProviders).add(providerId);\n\t\t\tconst auth = new Map(this.snapshot.auth);\n\t\t\t// Provisional entry until the async refresh lands; never clobber a real check result.\n\t\t\tif (!auth.get(providerId)) {\n\t\t\t\tauth.set(providerId, {\n\t\t\t\t\ttype: effective.oauth && !effective.apiKey ? \"oauth\" : \"api_key\",\n\t\t\t\t\tsource: \"configured provider\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tthis.snapshot = {\n\t\t\t\t...this.snapshot,\n\t\t\t\tauth,\n\t\t\t\tconfiguredProviders,\n\t\t\t\tavailable: this.snapshot.all.filter(\n\t\t\t\t\t(model) => configuredProviders.has(model.provider) && this.isCatalogModelAvailable(model),\n\t\t\t\t),\n\t\t\t};\n\t\t}\n\t\tvoid this.refresh({ allowNetwork: false });\n\t}\n\n\tunregisterProvider(providerId: string): void {\n\t\tthis.extensionProviders.delete(providerId);\n\t\tthis.recomposeProvider(providerId);\n\t\tthis.updateModelSnapshot();\n\t\tvoid this.refresh({ allowNetwork: false });\n\t}\n}\n\n/** TUI init / footer / rebind: cache-only. Live refresh is `/refresh` and the model picker. */\nexport async function refreshModelCandidatesForInit(\n\truntime: Pick<ModelRuntime, \"refresh\" | \"getAvailableSnapshot\">,\n): Promise<readonly Model<Api>[]> {\n\tawait runtime.refresh({ allowNetwork: false });\n\treturn runtime.getAvailableSnapshot();\n}\n"]}
@@ -3,6 +3,7 @@ import { createModels, lazyStream, ModelsError, } from "@ashx-j/lunr-ai";
3
3
  import * as builtinProviderCatalog from "@ashx-j/lunr-ai/providers/all";
4
4
  import { getAgentDir } from "../config.js";
5
5
  import { AuthStorage as DefaultAuthStorage } from "./auth-storage.js";
6
+ import { catalogCacheScope } from "./catalog-cache-scope.js";
6
7
  import { CatalogOverlaySource, knownModelKeys, withCatalogOverlay } from "./catalog-merge.js";
7
8
  import { readGrokCliXaiOAuth, wrapXaiGrokCliCredentials } from "./grok-cli-auth.js";
8
9
  import { buildLiveOverlay, fetchLiveProviderModels, LIVE_LIST_PROVIDER_IDS, } from "./live-catalog.js";
@@ -58,6 +59,8 @@ export class ModelRuntime {
58
59
  lastOfficial;
59
60
  catalogRefresh;
60
61
  catalogRefreshAllowsNetwork = false;
62
+ nextAutomaticRefresh = 0;
63
+ automaticRefreshIdentity = "";
61
64
  grokHome;
62
65
  constructor(credentials, config, modelsPath, modelsStore, providers, allowModelNetwork, subscriptionManager, catalogDir, grokHome) {
63
66
  this.credentials = credentials;
@@ -141,7 +144,8 @@ export class ModelRuntime {
141
144
  return;
142
145
  }
143
146
  try {
144
- this.models.setProvider(this.withLocalCatalog(composeModelProvider(providerId, base, this.config, extension)));
147
+ // Discovery is metadata beneath explicit user configuration and extension model definitions.
148
+ this.models.setProvider(composeModelProvider(providerId, base ? this.withLocalCatalog(base) : undefined, this.config, extension));
145
149
  this.compositionErrors.delete(providerId);
146
150
  }
147
151
  catch (error) {
@@ -170,9 +174,15 @@ export class ModelRuntime {
170
174
  this.snapshot = {
171
175
  ...this.snapshot,
172
176
  all,
173
- available: all.filter((model) => this.snapshot.configuredProviders.has(model.provider)),
177
+ available: all.filter((model) => this.snapshot.configuredProviders.has(model.provider) && this.isCatalogModelAvailable(model)),
174
178
  };
175
179
  }
180
+ isCatalogModelAvailable(model) {
181
+ const config = this.config.getProvider(model.provider);
182
+ return (!!config?.models?.some((row) => row.id === model.id) ||
183
+ !!this.extensionProviders.get(model.provider)?.models?.some((row) => row.id === model.id) ||
184
+ this.overlay.isAvailable(model));
185
+ }
176
186
  async listStoredProviderIds() {
177
187
  const credentials = await this.credentials.list();
178
188
  return new Set(credentials.map((entry) => entry.providerId));
@@ -208,7 +218,7 @@ export class ModelRuntime {
208
218
  const configuredProviders = this.configuredProviderIds(storedProviders);
209
219
  this.snapshot = {
210
220
  all: [...this.models.getModels()],
211
- available: available.filter((model) => configuredProviders.has(model.provider)),
221
+ available: available.filter((model) => configuredProviders.has(model.provider) && this.isCatalogModelAvailable(model)),
212
222
  configuredProviders,
213
223
  storedProviders,
214
224
  auth,
@@ -258,7 +268,7 @@ export class ModelRuntime {
258
268
  return this.snapshot.available.filter((model) => model.provider === providerId);
259
269
  }
260
270
  try {
261
- return await this.models.getAvailable(providerId);
271
+ return (await this.models.getAvailable(providerId)).filter((model) => this.isCatalogModelAvailable(model));
262
272
  }
263
273
  catch (error) {
264
274
  this.availabilityError = error instanceof Error ? error.message : String(error);
@@ -328,7 +338,7 @@ export class ModelRuntime {
328
338
  auth,
329
339
  configuredProviders,
330
340
  storedProviders,
331
- available: this.snapshot.all.filter((model) => configuredProviders.has(model.provider)),
341
+ available: this.snapshot.all.filter((model) => configuredProviders.has(model.provider) && this.isCatalogModelAvailable(model)),
332
342
  };
333
343
  await this.refresh({ allowNetwork: options?.allowNetwork ?? this.allowModelNetwork });
334
344
  }
@@ -462,6 +472,8 @@ export class ModelRuntime {
462
472
  errors: new Map(),
463
473
  };
464
474
  const errors = new Map(result.errors);
475
+ for (const [id, error] of Object.entries(official?.errors ?? {}))
476
+ errors.set(id, new Error(error));
465
477
  for (const entry of live) {
466
478
  if (entry.status === "error" || entry.status === "timeout") {
467
479
  errors.set(entry.providerId, new Error(entry.error ?? entry.status));
@@ -487,6 +499,28 @@ export class ModelRuntime {
487
499
  getLastCatalogRefresh() {
488
500
  return this.lastCatalogRefresh;
489
501
  }
502
+ /** Called after first paint and by the picker; explicit /refresh always bypasses this gate. */
503
+ async refreshIfStale(options = {}) {
504
+ if (!this.allowModelNetwork || options.signal?.aborted)
505
+ return this.lastCatalogRefresh;
506
+ if (this.catalogRefresh)
507
+ return this.refresh({ allowNetwork: true, signal: options.signal });
508
+ const providers = [...(await this.listStoredProviderIds())].sort();
509
+ const identity = (await Promise.all(providers.map(async (id) => this.scopeFor(id)))).join(":");
510
+ if (identity === this.automaticRefreshIdentity && Date.now() < this.nextAutomaticRefresh)
511
+ return this.lastCatalogRefresh;
512
+ this.automaticRefreshIdentity = identity;
513
+ // Bound retries on a broken source; a successful refresh extends the deadline to one hour.
514
+ this.nextAutomaticRefresh = Date.now() + 60_000;
515
+ const result = await this.refresh({ allowNetwork: true, signal: options.signal });
516
+ if (!result.aborted && !result.errors.size)
517
+ this.nextAutomaticRefresh = Date.now() + 3_600_000;
518
+ return result;
519
+ }
520
+ async scopeFor(providerId) {
521
+ const provider = this.models.getProvider(providerId) ?? this.defaultBuiltins.get(providerId);
522
+ return catalogCacheScope(providerId, provider?.baseUrl ?? "", await this.credentials.read(providerId));
523
+ }
490
524
  persistUserModels(rows) {
491
525
  this.userModels.upsert(rows);
492
526
  this.overlay.setUser(this.userModelsForStoredProviders(this.snapshot.storedProviders));
@@ -520,7 +554,8 @@ export class ModelRuntime {
520
554
  const results = [];
521
555
  for (const providerId of LIVE_LIST_PROVIDER_IDS) {
522
556
  const stored = storedProviders.has(providerId) ? await this.modelsStore.read(providerId) : undefined;
523
- if (stored?.models)
557
+ const valid = (!stored?.scope && providerId !== "openai-codex") || stored?.scope === (await this.scopeFor(providerId));
558
+ if (valid && stored?.models)
524
559
  this.overlay.setLive(providerId, stored.models);
525
560
  else
526
561
  this.overlay.setLive(providerId, []);
@@ -551,8 +586,11 @@ export class ModelRuntime {
551
586
  };
552
587
  }
553
588
  const stored = await this.modelsStore.read(providerId);
554
- if (stored?.models)
589
+ const initialScope = await this.scopeFor(providerId);
590
+ if (stored?.models && (stored.scope === initialScope || (!stored.scope && providerId !== "openai-codex")))
555
591
  this.overlay.setLive(providerId, stored.models);
592
+ else
593
+ this.overlay.setLive(providerId, []);
556
594
  if (signal?.aborted) {
557
595
  return {
558
596
  providerId,
@@ -602,7 +640,9 @@ export class ModelRuntime {
602
640
  incomplete: [],
603
641
  };
604
642
  }
643
+ const requestScope = catalogCacheScope(providerId, baseUrl, credential);
605
644
  const result = await fetchLiveProviderModels({
645
+ discoveryClientVersion: stored?.scope === requestScope ? stored.discoveryClientVersion : undefined,
606
646
  providerId,
607
647
  baseUrl,
608
648
  bakedIn,
@@ -610,11 +650,23 @@ export class ModelRuntime {
610
650
  knownKeys: known,
611
651
  signal,
612
652
  });
653
+ // A login/logout during the request must not install the previous account's result.
654
+ const accountChanged = (await this.scopeFor(providerId)) !== requestScope;
655
+ if (accountChanged)
656
+ this.overlay.setLive(providerId, []);
657
+ if (signal?.aborted || accountChanged) {
658
+ return { ...result, status: "skipped", discoveries: [], incomplete: [] };
659
+ }
613
660
  if (result.status === "ok") {
614
661
  const overlayModels = buildLiveOverlay(bakedIn, result.discoveries);
615
662
  this.overlay.setLive(providerId, overlayModels);
616
663
  try {
617
- await this.modelsStore.write(providerId, { models: overlayModels, checkedAt: Date.now() });
664
+ await this.modelsStore.write(providerId, {
665
+ models: overlayModels,
666
+ checkedAt: Date.now(),
667
+ scope: requestScope,
668
+ discoveryClientVersion: result.discoveryClientVersion,
669
+ });
618
670
  }
619
671
  catch {
620
672
  // Store write is best-effort.
@@ -625,14 +677,14 @@ export class ModelRuntime {
625
677
  return results;
626
678
  }
627
679
  async refreshCredentialFor(providerId) {
628
- const stored = await this.credentials.read(providerId);
629
680
  // Same lock + persist path as chat. Returning stored OAuth here skips
630
681
  // refresh and sends expired SuperGrok tokens to GET /models (HTTP 403).
631
682
  const resolved = await this.getAuth(providerId);
683
+ const stored = await this.credentials.read(providerId);
684
+ if (stored?.type === "oauth")
685
+ return { ...stored, access: resolved?.auth.apiKey ?? stored.access };
632
686
  if (resolved?.auth.apiKey)
633
687
  return { type: "api_key", key: resolved.auth.apiKey, env: resolved.env };
634
- if (stored?.type === "oauth" && stored.access)
635
- return stored;
636
688
  if (stored?.type === "api_key" && stored.key)
637
689
  return stored;
638
690
  return undefined;
@@ -667,7 +719,7 @@ export class ModelRuntime {
667
719
  ...this.snapshot,
668
720
  auth,
669
721
  configuredProviders,
670
- available: this.snapshot.all.filter((model) => configuredProviders.has(model.provider)),
722
+ available: this.snapshot.all.filter((model) => configuredProviders.has(model.provider) && this.isCatalogModelAvailable(model)),
671
723
  };
672
724
  }
673
725
  void this.refresh({ allowNetwork: false });