@selesai/code 0.5.13 → 0.5.15

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 (297) hide show
  1. package/README.md +186 -0
  2. package/dist/bun/cli.d.ts.map +1 -1
  3. package/dist/bun/cli.js +2 -0
  4. package/dist/bun/cli.js.map +1 -1
  5. package/dist/cli/args.d.ts.map +1 -1
  6. package/dist/cli/args.js +3 -1
  7. package/dist/cli/args.js.map +1 -1
  8. package/dist/cli/list-models.d.ts +2 -2
  9. package/dist/cli/list-models.d.ts.map +1 -1
  10. package/dist/cli/list-models.js +3 -3
  11. package/dist/cli/list-models.js.map +1 -1
  12. package/dist/config.d.ts +1 -1
  13. package/dist/config.d.ts.map +1 -1
  14. package/dist/config.js +2 -2
  15. package/dist/config.js.map +1 -1
  16. package/dist/core/agent-session-auto-handoff.test.d.ts.map +1 -1
  17. package/dist/core/agent-session-auto-handoff.test.js +2 -2
  18. package/dist/core/agent-session-auto-handoff.test.js.map +1 -1
  19. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  20. package/dist/core/agent-session-runtime.js +3 -0
  21. package/dist/core/agent-session-runtime.js.map +1 -1
  22. package/dist/core/agent-session-services.d.ts +3 -6
  23. package/dist/core/agent-session-services.d.ts.map +1 -1
  24. package/dist/core/agent-session-services.js +23 -9
  25. package/dist/core/agent-session-services.js.map +1 -1
  26. package/dist/core/agent-session.d.ts +28 -10
  27. package/dist/core/agent-session.d.ts.map +1 -1
  28. package/dist/core/agent-session.js +136 -90
  29. package/dist/core/agent-session.js.map +1 -1
  30. package/dist/core/auth-storage.d.ts +20 -98
  31. package/dist/core/auth-storage.d.ts.map +1 -1
  32. package/dist/core/auth-storage.js +59 -251
  33. package/dist/core/auth-storage.js.map +1 -1
  34. package/dist/core/built-in-extensions.d.ts +3 -0
  35. package/dist/core/built-in-extensions.d.ts.map +1 -0
  36. package/dist/core/built-in-extensions.js +3 -0
  37. package/dist/core/built-in-extensions.js.map +1 -0
  38. package/dist/core/cache-stats.d.ts +2 -2
  39. package/dist/core/cache-stats.d.ts.map +1 -1
  40. package/dist/core/cache-stats.js +1 -1
  41. package/dist/core/cache-stats.js.map +1 -1
  42. package/dist/core/compaction/branch-summarization.d.ts +8 -2
  43. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  44. package/dist/core/compaction/branch-summarization.js +8 -11
  45. package/dist/core/compaction/branch-summarization.js.map +1 -1
  46. package/dist/core/compaction/compaction.d.ts +19 -3
  47. package/dist/core/compaction/compaction.d.ts.map +1 -1
  48. package/dist/core/compaction/compaction.js +63 -26
  49. package/dist/core/compaction/compaction.js.map +1 -1
  50. package/dist/core/compaction/utils.d.ts +1 -1
  51. package/dist/core/compaction/utils.d.ts.map +1 -1
  52. package/dist/core/compaction/utils.js +6 -17
  53. package/dist/core/compaction/utils.js.map +1 -1
  54. package/dist/core/extensions/loader.d.ts.map +1 -1
  55. package/dist/core/extensions/loader.js +21 -4
  56. package/dist/core/extensions/loader.js.map +1 -1
  57. package/dist/core/extensions/runner.d.ts +4 -1
  58. package/dist/core/extensions/runner.d.ts.map +1 -1
  59. package/dist/core/extensions/runner.js +39 -0
  60. package/dist/core/extensions/runner.js.map +1 -1
  61. package/dist/core/extensions/types.d.ts +24 -3
  62. package/dist/core/extensions/types.d.ts.map +1 -1
  63. package/dist/core/extensions/types.js.map +1 -1
  64. package/dist/core/extensions/wrapper.d.ts.map +1 -1
  65. package/dist/core/extensions/wrapper.js +22 -3
  66. package/dist/core/extensions/wrapper.js.map +1 -1
  67. package/dist/core/keybindings.d.ts +8 -3
  68. package/dist/core/keybindings.d.ts.map +1 -1
  69. package/dist/core/keybindings.js +7 -3
  70. package/dist/core/keybindings.js.map +1 -1
  71. package/dist/core/llama/client.d.ts +61 -0
  72. package/dist/core/llama/client.d.ts.map +1 -0
  73. package/dist/core/llama/client.js +302 -0
  74. package/dist/core/llama/client.js.map +1 -0
  75. package/dist/core/llama/huggingface.d.ts +23 -0
  76. package/dist/core/llama/huggingface.d.ts.map +1 -0
  77. package/dist/core/llama/huggingface.js +141 -0
  78. package/dist/core/llama/huggingface.js.map +1 -0
  79. package/dist/core/llama/index.d.ts +3 -0
  80. package/dist/core/llama/index.d.ts.map +1 -0
  81. package/dist/core/llama/index.js +208 -0
  82. package/dist/core/llama/index.js.map +1 -0
  83. package/dist/core/llama/provider.d.ts +10 -0
  84. package/dist/core/llama/provider.d.ts.map +1 -0
  85. package/dist/core/llama/provider.js +102 -0
  86. package/dist/core/llama/provider.js.map +1 -0
  87. package/dist/core/llama/ui.d.ts +42 -0
  88. package/dist/core/llama/ui.d.ts.map +1 -0
  89. package/dist/core/llama/ui.js +416 -0
  90. package/dist/core/llama/ui.js.map +1 -0
  91. package/dist/core/model-config.d.ts +513 -0
  92. package/dist/core/model-config.d.ts.map +1 -0
  93. package/dist/core/model-config.js +272 -0
  94. package/dist/core/model-config.js.map +1 -0
  95. package/dist/core/model-registry.d.ts +20 -126
  96. package/dist/core/model-registry.d.ts.map +1 -1
  97. package/dist/core/model-registry.js +62 -780
  98. package/dist/core/model-registry.js.map +1 -1
  99. package/dist/core/model-resolver.d.ts +6 -6
  100. package/dist/core/model-resolver.d.ts.map +1 -1
  101. package/dist/core/model-resolver.js +21 -18
  102. package/dist/core/model-resolver.js.map +1 -1
  103. package/dist/core/model-runtime.d.ts +83 -0
  104. package/dist/core/model-runtime.d.ts.map +1 -0
  105. package/dist/core/model-runtime.js +451 -0
  106. package/dist/core/model-runtime.js.map +1 -0
  107. package/dist/core/models-store.d.ts +17 -0
  108. package/dist/core/models-store.d.ts.map +1 -0
  109. package/dist/core/models-store.js +45 -0
  110. package/dist/core/models-store.js.map +1 -0
  111. package/dist/core/package-manager.d.ts.map +1 -1
  112. package/dist/core/package-manager.js +7 -2
  113. package/dist/core/package-manager.js.map +1 -1
  114. package/dist/core/prompt-templates.d.ts +1 -0
  115. package/dist/core/prompt-templates.d.ts.map +1 -1
  116. package/dist/core/prompt-templates.js +4 -4
  117. package/dist/core/prompt-templates.js.map +1 -1
  118. package/dist/core/provider-composer.d.ts +55 -0
  119. package/dist/core/provider-composer.d.ts.map +1 -0
  120. package/dist/core/provider-composer.js +375 -0
  121. package/dist/core/provider-composer.js.map +1 -0
  122. package/dist/core/radius.d.ts +2 -0
  123. package/dist/core/radius.d.ts.map +1 -0
  124. package/dist/core/radius.js +2 -0
  125. package/dist/core/radius.js.map +1 -0
  126. package/dist/core/remote-catalog-provider.d.ts +5 -0
  127. package/dist/core/remote-catalog-provider.d.ts.map +1 -0
  128. package/dist/core/remote-catalog-provider.js +102 -0
  129. package/dist/core/remote-catalog-provider.js.map +1 -0
  130. package/dist/core/resource-loader.d.ts.map +1 -1
  131. package/dist/core/resource-loader.js +1 -0
  132. package/dist/core/resource-loader.js.map +1 -1
  133. package/dist/core/runtime-credentials.d.ts +17 -0
  134. package/dist/core/runtime-credentials.d.ts.map +1 -0
  135. package/dist/core/runtime-credentials.js +42 -0
  136. package/dist/core/runtime-credentials.js.map +1 -0
  137. package/dist/core/sdk.d.ts +4 -7
  138. package/dist/core/sdk.d.ts.map +1 -1
  139. package/dist/core/sdk.js +18 -25
  140. package/dist/core/sdk.js.map +1 -1
  141. package/dist/core/session-manager.d.ts +12 -7
  142. package/dist/core/session-manager.d.ts.map +1 -1
  143. package/dist/core/session-manager.js +103 -27
  144. package/dist/core/session-manager.js.map +1 -1
  145. package/dist/core/system-prompt.d.ts.map +1 -1
  146. package/dist/core/system-prompt.js +2 -12
  147. package/dist/core/system-prompt.js.map +1 -1
  148. package/dist/core/tools/read.d.ts.map +1 -1
  149. package/dist/core/tools/read.js +1 -1
  150. package/dist/core/tools/read.js.map +1 -1
  151. package/dist/core/usage-totals.d.ts +19 -0
  152. package/dist/core/usage-totals.d.ts.map +1 -0
  153. package/dist/core/usage-totals.js +52 -0
  154. package/dist/core/usage-totals.js.map +1 -0
  155. package/dist/extensions/index.d.ts +3 -0
  156. package/dist/extensions/index.d.ts.map +1 -0
  157. package/dist/extensions/index.js +9 -0
  158. package/dist/extensions/index.js.map +1 -0
  159. package/dist/extensions/llama/client.d.ts +61 -0
  160. package/dist/extensions/llama/client.d.ts.map +1 -0
  161. package/dist/extensions/llama/client.js +309 -0
  162. package/dist/extensions/llama/client.js.map +1 -0
  163. package/dist/extensions/llama/huggingface.d.ts +23 -0
  164. package/dist/extensions/llama/huggingface.d.ts.map +1 -0
  165. package/dist/extensions/llama/huggingface.js +146 -0
  166. package/dist/extensions/llama/huggingface.js.map +1 -0
  167. package/dist/extensions/llama/index.d.ts +3 -0
  168. package/dist/extensions/llama/index.d.ts.map +1 -0
  169. package/dist/extensions/llama/index.js +211 -0
  170. package/dist/extensions/llama/index.js.map +1 -0
  171. package/dist/extensions/llama/provider.d.ts +10 -0
  172. package/dist/extensions/llama/provider.d.ts.map +1 -0
  173. package/dist/extensions/llama/provider.js +106 -0
  174. package/dist/extensions/llama/provider.js.map +1 -0
  175. package/dist/extensions/llama/ui.d.ts +42 -0
  176. package/dist/extensions/llama/ui.d.ts.map +1 -0
  177. package/dist/extensions/llama/ui.js +420 -0
  178. package/dist/extensions/llama/ui.js.map +1 -0
  179. package/dist/extensions/package.json +4 -3
  180. package/dist/extensions/pi-powerline-footer/README.md +1 -1
  181. package/dist/extensions/pi-powerline-footer/guide.ts +227 -0
  182. package/dist/extensions/pi-powerline-footer/index.ts +88 -55
  183. package/dist/extensions/pi-powerline-footer/tests/editor-responsiveness.test.ts +0 -78
  184. package/dist/extensions/pi-powerline-footer/tests/guide.test.ts +102 -0
  185. package/dist/extensions/pi-powerline-footer/welcome.ts +65 -30
  186. package/dist/extensions/tokenin-onboarding.ts +3 -3
  187. package/dist/index.d.ts +4 -3
  188. package/dist/index.d.ts.map +1 -1
  189. package/dist/index.js +3 -3
  190. package/dist/index.js.map +1 -1
  191. package/dist/main.d.ts.map +1 -1
  192. package/dist/main.js +21 -19
  193. package/dist/main.js.map +1 -1
  194. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  195. package/dist/modes/interactive/components/assistant-message.js +22 -10
  196. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  197. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  198. package/dist/modes/interactive/components/custom-editor.js +1 -1
  199. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  200. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  201. package/dist/modes/interactive/components/footer.js +24 -23
  202. package/dist/modes/interactive/components/footer.js.map +1 -1
  203. package/dist/modes/interactive/components/login-dialog.d.ts +5 -5
  204. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  205. package/dist/modes/interactive/components/login-dialog.js +17 -8
  206. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  207. package/dist/modes/interactive/components/model-selector.d.ts +11 -4
  208. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  209. package/dist/modes/interactive/components/model-selector.js +72 -41
  210. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  211. package/dist/modes/interactive/components/oauth-selector.d.ts +4 -4
  212. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  213. package/dist/modes/interactive/components/oauth-selector.js +14 -27
  214. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  215. package/dist/modes/interactive/components/tree-selector.d.ts +5 -0
  216. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  217. package/dist/modes/interactive/components/tree-selector.js +49 -12
  218. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  219. package/dist/modes/interactive/interactive-mode.d.ts +8 -5
  220. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  221. package/dist/modes/interactive/interactive-mode.js +253 -225
  222. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  223. package/dist/modes/rpc/rpc-client.d.ts +4 -0
  224. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  225. package/dist/modes/rpc/rpc-client.js +7 -0
  226. package/dist/modes/rpc/rpc-client.js.map +1 -1
  227. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  228. package/dist/modes/rpc/rpc-mode.js +6 -2
  229. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  230. package/dist/modes/rpc/rpc-types.d.ts +11 -0
  231. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  232. package/dist/modes/rpc/rpc-types.js.map +1 -1
  233. package/dist/package-manager-cli.d.ts.map +1 -1
  234. package/dist/package-manager-cli.js +67 -5
  235. package/dist/package-manager-cli.js.map +1 -1
  236. package/dist/skills/caveman/SKILL.md +1 -0
  237. package/dist/skills/handoff/SKILL.md +1 -0
  238. package/dist/skills/handoff-text/SKILL.md +1 -0
  239. package/dist/skills/implanger/SKILL.md +1 -0
  240. package/dist/skills/improve-codebase/SKILL.md +1 -0
  241. package/dist/skills/planger/SKILL.md +1 -0
  242. package/dist/skills/ponytail/SKILL.md +1 -0
  243. package/dist/skills/ponytail-audit/SKILL.md +1 -0
  244. package/dist/skills/ponytail-debt/SKILL.md +1 -0
  245. package/dist/skills/ponytail-gain/SKILL.md +1 -0
  246. package/dist/skills/ponytail-help/SKILL.md +1 -0
  247. package/dist/skills/ponytail-review/SKILL.md +1 -0
  248. package/dist/skills/workflow-creation/SKILL.md +1 -0
  249. package/dist/utils/clipboard-native.d.ts +1 -0
  250. package/dist/utils/clipboard-native.d.ts.map +1 -1
  251. package/dist/utils/clipboard-native.js.map +1 -1
  252. package/dist/utils/clipboard.d.ts +2 -0
  253. package/dist/utils/clipboard.d.ts.map +1 -1
  254. package/dist/utils/clipboard.js +13 -0
  255. package/dist/utils/clipboard.js.map +1 -1
  256. package/package.json +26 -5
  257. package/dist/agents/architect.md +0 -217
  258. package/dist/agents/builder.md +0 -120
  259. package/dist/agents/commentator.md +0 -130
  260. package/dist/agents/explorer.md +0 -51
  261. package/dist/agents/recapper.md +0 -26
  262. package/dist/extensions/gitignore-guard.ts +0 -132
  263. package/dist/extensions/hooks/claude-codex-hooks.json +0 -44
  264. package/dist/extensions/hooks/copilot-hooks.json +0 -21
  265. package/dist/extensions/hooks/ponytail-activate.js +0 -91
  266. package/dist/extensions/hooks/ponytail-config.js +0 -122
  267. package/dist/extensions/hooks/ponytail-instructions.js +0 -94
  268. package/dist/extensions/hooks/ponytail-mode-tracker.js +0 -55
  269. package/dist/extensions/hooks/ponytail-runtime.js +0 -68
  270. package/dist/extensions/hooks/ponytail-statusline.ps1 +0 -21
  271. package/dist/extensions/hooks/ponytail-statusline.sh +0 -12
  272. package/dist/extensions/hooks/ponytail-subagent.js +0 -22
  273. package/dist/extensions/pi-extension/index.js +0 -189
  274. package/dist/extensions/pi-extension/package.json +0 -8
  275. package/dist/extensions/pi-extension/test/extension.test.js +0 -167
  276. package/dist/extensions/pi-extension/test/helpers.test.js +0 -92
  277. package/dist/extensions/pi-powerline-footer/welcome-dismiss.ts +0 -34
  278. package/dist/extensions/pi-subagents/agents/context-builder.md +0 -46
  279. package/dist/extensions/pi-subagents/agents/delegate.md +0 -12
  280. package/dist/extensions/pi-subagents/agents/oracle.md +0 -73
  281. package/dist/extensions/pi-subagents/agents/planner.md +0 -55
  282. package/dist/extensions/pi-subagents/agents/reviewer.md +0 -79
  283. package/dist/extensions/pi-subagents/agents/scout.md +0 -50
  284. package/dist/extensions/pi-subagents/agents/worker.md +0 -55
  285. package/dist/extensions/pi-subagents/src/runs/shared/spawn-timing.ts +0 -46
  286. package/dist/extensions/pi-subagents/test/unit/spawn-timing.test.ts +0 -45
  287. package/dist/extensions/pi-subagents/tsconfig.runner.json +0 -17
  288. package/dist/extensions/ponytail-pi-extension/index.js +0 -189
  289. package/dist/extensions/ponytail-pi-extension/package.json +0 -8
  290. package/dist/extensions/ponytail-pi-extension/test/extension.test.js +0 -167
  291. package/dist/extensions/ponytail-pi-extension/test/helpers.test.js +0 -92
  292. package/dist/extensions/prototype.ts +0 -713
  293. package/dist/extensions/question.ts +0 -350
  294. package/dist/extensions/quick.ts +0 -630
  295. package/dist/extensions/tps-tracker.ts +0 -280
  296. package/dist/extensions/workflow/task-validators.ts +0 -69
  297. package/dist/skills/selesai-default/SKILL.md +0 -16
@@ -1,826 +1,108 @@
1
+ export { clearApiKeyCache } from "./provider-composer.js";
1
2
  /**
2
- * Model registry - manages built-in and custom models, provides API key resolution.
3
- */
4
- import { getModels, getProviders, registerApiProvider, resetApiProviders, } from "@earendil-works/pi-ai/compat";
5
- import { registerOAuthProvider, resetOAuthProviders } from "@earendil-works/pi-ai/oauth";
6
- import { existsSync, readFileSync } from "fs";
7
- import { join } from "path";
8
- import { Type } from "typebox";
9
- import { Compile } from "typebox/compile";
10
- import { getAgentDir, getBundledDefaultsDir } from "../config.js";
11
- import { stripJsonComments } from "../utils/json.js";
12
- import { normalizePath } from "../utils/paths.js";
13
- import { BUILT_IN_PROVIDER_DISPLAY_NAMES } from "./provider-display-names.js";
14
- import { clearConfigValueCache, getConfigValueEnvVarNames, isCommandConfigValue, isConfigValueConfigured, resolveConfigValueOrThrow, resolveConfigValueUncached, resolveHeadersOrThrow, } from "./resolve-config-value.js";
15
- // Schema for OpenRouter routing preferences
16
- const PercentileCutoffsSchema = Type.Object({
17
- p50: Type.Optional(Type.Number()),
18
- p75: Type.Optional(Type.Number()),
19
- p90: Type.Optional(Type.Number()),
20
- p99: Type.Optional(Type.Number()),
21
- });
22
- const OpenRouterRoutingSchema = Type.Object({
23
- allow_fallbacks: Type.Optional(Type.Boolean()),
24
- require_parameters: Type.Optional(Type.Boolean()),
25
- data_collection: Type.Optional(Type.Union([Type.Literal("deny"), Type.Literal("allow")])),
26
- zdr: Type.Optional(Type.Boolean()),
27
- enforce_distillable_text: Type.Optional(Type.Boolean()),
28
- order: Type.Optional(Type.Array(Type.String())),
29
- only: Type.Optional(Type.Array(Type.String())),
30
- ignore: Type.Optional(Type.Array(Type.String())),
31
- quantizations: Type.Optional(Type.Array(Type.String())),
32
- sort: Type.Optional(Type.Union([
33
- Type.String(),
34
- Type.Object({
35
- by: Type.Optional(Type.String()),
36
- partition: Type.Optional(Type.Union([Type.String(), Type.Null()])),
37
- }),
38
- ])),
39
- max_price: Type.Optional(Type.Object({
40
- prompt: Type.Optional(Type.Union([Type.Number(), Type.String()])),
41
- completion: Type.Optional(Type.Union([Type.Number(), Type.String()])),
42
- image: Type.Optional(Type.Union([Type.Number(), Type.String()])),
43
- audio: Type.Optional(Type.Union([Type.Number(), Type.String()])),
44
- request: Type.Optional(Type.Union([Type.Number(), Type.String()])),
45
- })),
46
- preferred_min_throughput: Type.Optional(Type.Union([Type.Number(), PercentileCutoffsSchema])),
47
- preferred_max_latency: Type.Optional(Type.Union([Type.Number(), PercentileCutoffsSchema])),
48
- });
49
- // Schema for Vercel AI Gateway routing preferences
50
- const VercelGatewayRoutingSchema = Type.Object({
51
- only: Type.Optional(Type.Array(Type.String())),
52
- order: Type.Optional(Type.Array(Type.String())),
53
- });
54
- // Schema for thinking level support and provider-specific values
55
- const ThinkingLevelMapValueSchema = Type.Union([Type.String(), Type.Null()]);
56
- const ThinkingLevelMapSchema = Type.Object({
57
- off: Type.Optional(ThinkingLevelMapValueSchema),
58
- minimal: Type.Optional(ThinkingLevelMapValueSchema),
59
- low: Type.Optional(ThinkingLevelMapValueSchema),
60
- medium: Type.Optional(ThinkingLevelMapValueSchema),
61
- high: Type.Optional(ThinkingLevelMapValueSchema),
62
- xhigh: Type.Optional(ThinkingLevelMapValueSchema),
63
- max: Type.Optional(ThinkingLevelMapValueSchema),
64
- });
65
- const ChatTemplateKwargScalarSchema = Type.Union([Type.String(), Type.Number(), Type.Boolean(), Type.Null()]);
66
- const ChatTemplateKwargVariableSchema = Type.Object({
67
- $var: Type.Union([Type.Literal("thinking.enabled"), Type.Literal("thinking.effort")]),
68
- omitWhenOff: Type.Optional(Type.Boolean()),
69
- });
70
- const ChatTemplateKwargSchema = Type.Union([ChatTemplateKwargScalarSchema, ChatTemplateKwargVariableSchema]);
71
- const OpenAICompletionsCompatSchema = Type.Object({
72
- supportsStore: Type.Optional(Type.Boolean()),
73
- supportsDeveloperRole: Type.Optional(Type.Boolean()),
74
- supportsReasoningEffort: Type.Optional(Type.Boolean()),
75
- supportsUsageInStreaming: Type.Optional(Type.Boolean()),
76
- maxTokensField: Type.Optional(Type.Union([Type.Literal("max_completion_tokens"), Type.Literal("max_tokens")])),
77
- requiresToolResultName: Type.Optional(Type.Boolean()),
78
- requiresAssistantAfterToolResult: Type.Optional(Type.Boolean()),
79
- requiresThinkingAsText: Type.Optional(Type.Boolean()),
80
- requiresReasoningContentOnAssistantMessages: Type.Optional(Type.Boolean()),
81
- thinkingFormat: Type.Optional(Type.Union([
82
- Type.Literal("openai"),
83
- Type.Literal("openrouter"),
84
- Type.Literal("together"),
85
- Type.Literal("deepseek"),
86
- Type.Literal("zai"),
87
- Type.Literal("qwen"),
88
- Type.Literal("chat-template"),
89
- Type.Literal("qwen-chat-template"),
90
- Type.Literal("string-thinking"),
91
- Type.Literal("ant-ling"),
92
- ])),
93
- chatTemplateKwargs: Type.Optional(Type.Record(Type.String(), ChatTemplateKwargSchema)),
94
- cacheControlFormat: Type.Optional(Type.Literal("anthropic")),
95
- openRouterRouting: Type.Optional(OpenRouterRoutingSchema),
96
- vercelGatewayRouting: Type.Optional(VercelGatewayRoutingSchema),
97
- supportsStrictMode: Type.Optional(Type.Boolean()),
98
- supportsLongCacheRetention: Type.Optional(Type.Boolean()),
99
- });
100
- const OpenAIResponsesCompatSchema = Type.Object({
101
- supportsDeveloperRole: Type.Optional(Type.Boolean()),
102
- sendSessionIdHeader: Type.Optional(Type.Boolean()),
103
- supportsLongCacheRetention: Type.Optional(Type.Boolean()),
104
- });
105
- const AnthropicMessagesCompatSchema = Type.Object({
106
- supportsEagerToolInputStreaming: Type.Optional(Type.Boolean()),
107
- supportsLongCacheRetention: Type.Optional(Type.Boolean()),
108
- sendSessionAffinityHeaders: Type.Optional(Type.Boolean()),
109
- supportsCacheControlOnTools: Type.Optional(Type.Boolean()),
110
- forceAdaptiveThinking: Type.Optional(Type.Boolean()),
111
- });
112
- const ProviderCompatSchema = Type.Union([
113
- OpenAICompletionsCompatSchema,
114
- OpenAIResponsesCompatSchema,
115
- AnthropicMessagesCompatSchema,
116
- ]);
117
- const ModelCostRatesSchema = {
118
- input: Type.Number(),
119
- output: Type.Number(),
120
- cacheRead: Type.Number(),
121
- cacheWrite: Type.Number(),
122
- };
123
- const ModelCostTierSchema = Type.Object({
124
- inputTokensAbove: Type.Number(),
125
- ...ModelCostRatesSchema,
126
- });
127
- const ModelCostSchema = Type.Object({
128
- ...ModelCostRatesSchema,
129
- tiers: Type.Optional(Type.Array(ModelCostTierSchema)),
130
- });
131
- // Schema for custom model definition
132
- // Most fields are optional with sensible defaults for local models (Ollama, LM Studio, etc.)
133
- const ModelDefinitionSchema = Type.Object({
134
- id: Type.String({ minLength: 1 }),
135
- name: Type.Optional(Type.String({ minLength: 1 })),
136
- api: Type.Optional(Type.String({ minLength: 1 })),
137
- baseUrl: Type.Optional(Type.String({ minLength: 1 })),
138
- reasoning: Type.Optional(Type.Boolean()),
139
- thinkingLevelMap: Type.Optional(ThinkingLevelMapSchema),
140
- input: Type.Optional(Type.Array(Type.Union([Type.Literal("text"), Type.Literal("image")]))),
141
- cost: Type.Optional(ModelCostSchema),
142
- contextWindow: Type.Optional(Type.Number()),
143
- maxTokens: Type.Optional(Type.Number()),
144
- headers: Type.Optional(Type.Record(Type.String(), Type.String())),
145
- compat: Type.Optional(ProviderCompatSchema),
146
- });
147
- // Schema for per-model overrides (all fields optional, merged with built-in model)
148
- const ModelOverrideSchema = Type.Object({
149
- name: Type.Optional(Type.String({ minLength: 1 })),
150
- reasoning: Type.Optional(Type.Boolean()),
151
- thinkingLevelMap: Type.Optional(ThinkingLevelMapSchema),
152
- input: Type.Optional(Type.Array(Type.Union([Type.Literal("text"), Type.Literal("image")]))),
153
- cost: Type.Optional(Type.Object({
154
- input: Type.Optional(Type.Number()),
155
- output: Type.Optional(Type.Number()),
156
- cacheRead: Type.Optional(Type.Number()),
157
- cacheWrite: Type.Optional(Type.Number()),
158
- tiers: Type.Optional(Type.Array(ModelCostTierSchema)),
159
- })),
160
- contextWindow: Type.Optional(Type.Number()),
161
- maxTokens: Type.Optional(Type.Number()),
162
- headers: Type.Optional(Type.Record(Type.String(), Type.String())),
163
- compat: Type.Optional(ProviderCompatSchema),
164
- });
165
- const ProviderConfigSchema = Type.Object({
166
- name: Type.Optional(Type.String({ minLength: 1 })),
167
- baseUrl: Type.Optional(Type.String({ minLength: 1 })),
168
- apiKey: Type.Optional(Type.String({ minLength: 1 })),
169
- api: Type.Optional(Type.String({ minLength: 1 })),
170
- headers: Type.Optional(Type.Record(Type.String(), Type.String())),
171
- compat: Type.Optional(ProviderCompatSchema),
172
- authHeader: Type.Optional(Type.Boolean()),
173
- models: Type.Optional(Type.Array(ModelDefinitionSchema)),
174
- modelOverrides: Type.Optional(Type.Record(Type.String(), ModelOverrideSchema)),
175
- });
176
- const ModelsConfigSchema = Type.Object({
177
- providers: Type.Record(Type.String(), ProviderConfigSchema),
178
- });
179
- const validateModelsConfig = Compile(ModelsConfigSchema);
180
- function formatValidationPath(error) {
181
- if (error.keyword === "required") {
182
- const requiredProperties = error.params.requiredProperties;
183
- const requiredProperty = requiredProperties?.[0];
184
- if (requiredProperty) {
185
- const basePath = error.instancePath.replace(/^\//, "").replace(/\//g, ".");
186
- return basePath ? `${basePath}.${requiredProperty}` : requiredProperty;
187
- }
188
- }
189
- const path = error.instancePath.replace(/^\//, "").replace(/\//g, ".");
190
- return path || "root";
191
- }
192
- function emptyCustomModelsResult(error) {
193
- return { models: [], overrides: new Map(), modelOverrides: new Map(), error };
194
- }
195
- function mergeCompat(baseCompat, overrideCompat) {
196
- if (!overrideCompat)
197
- return baseCompat;
198
- const base = baseCompat;
199
- const override = overrideCompat;
200
- const merged = { ...base, ...override };
201
- const baseCompletions = base;
202
- const overrideCompletions = override;
203
- const mergedCompletions = merged;
204
- if (baseCompletions?.openRouterRouting || overrideCompletions.openRouterRouting) {
205
- mergedCompletions.openRouterRouting = {
206
- ...baseCompletions?.openRouterRouting,
207
- ...overrideCompletions.openRouterRouting,
208
- };
209
- }
210
- if (baseCompletions?.vercelGatewayRouting || overrideCompletions.vercelGatewayRouting) {
211
- mergedCompletions.vercelGatewayRouting = {
212
- ...baseCompletions?.vercelGatewayRouting,
213
- ...overrideCompletions.vercelGatewayRouting,
214
- };
215
- }
216
- if (baseCompletions?.chatTemplateKwargs || overrideCompletions.chatTemplateKwargs) {
217
- mergedCompletions.chatTemplateKwargs = {
218
- ...baseCompletions?.chatTemplateKwargs,
219
- ...overrideCompletions.chatTemplateKwargs,
220
- };
221
- }
222
- return merged;
223
- }
224
- /**
225
- * Deep merge a model override into a model.
226
- * Handles nested objects (cost, compat) by merging rather than replacing.
227
- */
228
- function applyModelOverride(model, override) {
229
- const result = { ...model };
230
- // Simple field overrides
231
- if (override.name !== undefined)
232
- result.name = override.name;
233
- if (override.reasoning !== undefined)
234
- result.reasoning = override.reasoning;
235
- if (override.thinkingLevelMap !== undefined) {
236
- result.thinkingLevelMap = { ...model.thinkingLevelMap, ...override.thinkingLevelMap };
237
- }
238
- if (override.input !== undefined)
239
- result.input = override.input;
240
- if (override.contextWindow !== undefined)
241
- result.contextWindow = override.contextWindow;
242
- if (override.maxTokens !== undefined)
243
- result.maxTokens = override.maxTokens;
244
- // Merge cost (partial override)
245
- if (override.cost) {
246
- result.cost = {
247
- input: override.cost.input ?? model.cost.input,
248
- output: override.cost.output ?? model.cost.output,
249
- cacheRead: override.cost.cacheRead ?? model.cost.cacheRead,
250
- cacheWrite: override.cost.cacheWrite ?? model.cost.cacheWrite,
251
- tiers: override.cost.tiers ?? model.cost.tiers,
252
- };
253
- }
254
- // Deep merge compat
255
- result.compat = mergeCompat(model.compat, override.compat);
256
- return result;
257
- }
258
- /** Clear the config value command cache. Exported for testing. */
259
- export const clearApiKeyCache = clearConfigValueCache;
260
- /**
261
- * Model registry - loads and manages models, resolves API keys via AuthStorage.
3
+ * Synchronous compatibility facade exposed to extensions.
4
+ * Coding-agent internals use ModelRuntime directly.
262
5
  */
263
6
  export class ModelRegistry {
264
- models = [];
265
- providerRequestConfigs = new Map();
266
- modelRequestHeaders = new Map();
267
- configModelOverrides = new Map();
268
- registeredProviders = new Map();
269
- loadError = undefined;
270
- authStorage;
271
- modelsJsonPath;
272
- constructor(authStorage, modelsJsonPath) {
273
- this.authStorage = authStorage;
274
- this.modelsJsonPath = modelsJsonPath ? normalizePath(modelsJsonPath) : undefined;
275
- this.loadModels();
276
- }
277
- static create(authStorage, modelsJsonPath = join(getAgentDir(), "models.json")) {
278
- return new ModelRegistry(authStorage, modelsJsonPath);
7
+ runtime;
8
+ constructor(runtime) {
9
+ this.runtime = runtime;
279
10
  }
280
- static inMemory(authStorage) {
281
- return new ModelRegistry(authStorage, undefined);
11
+ /** Legacy extension access to the default auth.json store. */
12
+ get authStorage() {
13
+ return this.runtime.getCredentialStore();
282
14
  }
283
- /**
284
- * Reload models from disk (built-in + custom from models.json).
285
- */
15
+ /** Reload models.json asynchronously. Await before making synchronous registry reads. */
286
16
  refresh() {
287
- this.providerRequestConfigs.clear();
288
- this.modelRequestHeaders.clear();
289
- this.loadError = undefined;
290
- // Ensure dynamic API/OAuth registrations are rebuilt from current provider state.
291
- resetApiProviders();
292
- resetOAuthProviders();
293
- this.loadModels();
294
- for (const [providerName, config] of this.registeredProviders.entries()) {
295
- this.applyProviderConfig(providerName, config);
296
- }
17
+ return this.runtime.reloadConfig();
297
18
  }
298
- /**
299
- * Get any error from loading models.json (undefined if no error).
300
- */
301
19
  getError() {
302
- return this.loadError;
303
- }
304
- loadModels() {
305
- const { result, configs } = this.loadModelConfigs();
306
- const { models: customModels, overrides, modelOverrides, error } = result;
307
- this.configModelOverrides = modelOverrides;
308
- if (error) {
309
- this.loadError = error;
310
- // Keep built-in models even if custom models failed to load
311
- }
312
- const builtInModels = this.loadBuiltInModels(overrides, modelOverrides);
313
- let combined = this.mergeCustomModels(builtInModels, customModels);
314
- this.storeRequestConfigs(configs);
315
- // Let OAuth providers modify their models (e.g., update baseUrl)
316
- for (const oauthProvider of this.authStorage.getOAuthProviders()) {
317
- const cred = this.authStorage.get(oauthProvider.id);
318
- if (cred?.type === "oauth" && oauthProvider.modifyModels) {
319
- combined = oauthProvider.modifyModels(combined, cred);
320
- }
321
- }
322
- this.models = combined;
323
- }
324
- loadModelConfigs() {
325
- const paths = [join(getBundledDefaultsDir(), "models.json")];
326
- if (this.modelsJsonPath && !paths.includes(this.modelsJsonPath))
327
- paths.push(this.modelsJsonPath);
328
- const configs = [];
329
- const errors = [];
330
- for (const path of paths) {
331
- const loaded = this.loadModelsConfig(path);
332
- if (loaded.error) {
333
- errors.push(loaded.error);
334
- continue;
335
- }
336
- if (loaded.config)
337
- configs.push(loaded.config);
338
- }
339
- const result = this.buildCustomModelsResult(configs);
340
- if (errors.length > 0 || result.error) {
341
- return { result: { ...result, error: [...errors, result.error].filter(Boolean).join("\n\n") }, configs };
342
- }
343
- return { result, configs };
344
- }
345
- loadModelsConfig(modelsJsonPath) {
346
- if (!existsSync(modelsJsonPath))
347
- return {};
348
- try {
349
- const content = readFileSync(modelsJsonPath, "utf-8");
350
- const parsed = JSON.parse(stripJsonComments(content));
351
- if (!validateModelsConfig.Check(parsed)) {
352
- const errors = validateModelsConfig
353
- .Errors(parsed)
354
- .map((error) => ` - ${formatValidationPath(error)}: ${error.message}`)
355
- .join("\n") || "Unknown schema error";
356
- return { error: `Invalid models.json schema:\n${errors}\n\nFile: ${modelsJsonPath}` };
357
- }
358
- return { config: parsed };
359
- }
360
- catch (error) {
361
- if (error instanceof SyntaxError) {
362
- return { error: `Failed to parse models.json: ${error.message}\n\nFile: ${modelsJsonPath}` };
363
- }
364
- return {
365
- error: `Failed to load models.json: ${error instanceof Error ? error.message : error}\n\nFile: ${modelsJsonPath}`,
366
- };
367
- }
368
- }
369
- buildCustomModelsResult(configs) {
370
- try {
371
- for (const config of configs) {
372
- this.validateConfig(config);
373
- }
374
- const overrides = new Map();
375
- const modelOverrides = new Map();
376
- const models = configs.flatMap((config) => this.parseModels(config));
377
- for (const config of configs) {
378
- for (const [providerName, providerConfig] of Object.entries(config.providers)) {
379
- if (providerConfig.baseUrl || providerConfig.compat) {
380
- overrides.set(providerName, {
381
- baseUrl: providerConfig.baseUrl,
382
- compat: providerConfig.compat,
383
- });
384
- }
385
- if (providerConfig.modelOverrides) {
386
- modelOverrides.set(providerName, new Map(Object.entries(providerConfig.modelOverrides)));
387
- }
388
- }
389
- }
390
- return { models, overrides, modelOverrides, error: undefined };
391
- }
392
- catch (error) {
393
- return emptyCustomModelsResult(`Failed to load models.json: ${error instanceof Error ? error.message : error}`);
394
- }
395
- }
396
- storeRequestConfigs(configs) {
397
- for (const config of configs) {
398
- for (const [providerName, providerConfig] of Object.entries(config.providers)) {
399
- this.storeProviderRequestConfig(providerName, providerConfig);
400
- for (const modelDef of providerConfig.models ?? []) {
401
- this.storeModelHeaders(providerName, modelDef.id, modelDef.headers);
402
- }
403
- if (providerConfig.modelOverrides) {
404
- for (const [modelId, modelOverride] of Object.entries(providerConfig.modelOverrides)) {
405
- this.storeModelHeaders(providerName, modelId, modelOverride.headers);
406
- }
407
- }
408
- }
409
- }
410
- }
411
- /** Load built-in models and apply provider/model overrides */
412
- loadBuiltInModels(overrides, modelOverrides) {
413
- return getProviders().flatMap((provider) => {
414
- const models = getModels(provider);
415
- const providerOverride = overrides.get(provider);
416
- const perModelOverrides = modelOverrides.get(provider);
417
- return models.map((m) => {
418
- let model = m;
419
- // Apply provider-level baseUrl/headers/compat override
420
- if (providerOverride) {
421
- model = {
422
- ...model,
423
- baseUrl: providerOverride.baseUrl ?? model.baseUrl,
424
- compat: mergeCompat(model.compat, providerOverride.compat),
425
- };
426
- }
427
- // Apply per-model override
428
- const modelOverride = perModelOverrides?.get(m.id);
429
- if (modelOverride) {
430
- model = applyModelOverride(model, modelOverride);
431
- }
432
- return model;
433
- });
434
- });
435
- }
436
- getConfiguredModelOverride(providerName, modelId) {
437
- return this.configModelOverrides.get(providerName)?.get(modelId);
438
- }
439
- applyConfiguredModelOverride(providerName, model) {
440
- const modelOverride = this.getConfiguredModelOverride(providerName, model.id);
441
- return modelOverride ? applyModelOverride(model, modelOverride) : model;
442
- }
443
- /** Merge custom models into built-in list by provider+id (custom wins on conflicts). */
444
- mergeCustomModels(builtInModels, customModels) {
445
- const merged = [...builtInModels];
446
- for (const customModel of customModels) {
447
- const existingIndex = merged.findIndex((m) => m.provider === customModel.provider && m.id === customModel.id);
448
- if (existingIndex >= 0) {
449
- merged[existingIndex] = customModel;
450
- }
451
- else {
452
- merged.push(customModel);
453
- }
454
- }
455
- return merged;
456
- }
457
- validateConfig(config) {
458
- const builtInProviders = new Set(getProviders());
459
- for (const [providerName, providerConfig] of Object.entries(config.providers)) {
460
- const isBuiltIn = builtInProviders.has(providerName);
461
- const hasProviderApi = !!providerConfig.api;
462
- const models = providerConfig.models ?? [];
463
- const hasModelOverrides = providerConfig.modelOverrides && Object.keys(providerConfig.modelOverrides).length > 0;
464
- if (models.length === 0) {
465
- // Override-only config: needs baseUrl, headers, compat, modelOverrides, or some combination.
466
- if (!providerConfig.baseUrl &&
467
- !providerConfig.headers &&
468
- !providerConfig.compat &&
469
- !providerConfig.apiKey &&
470
- !hasModelOverrides) {
471
- throw new Error(`Provider ${providerName}: must specify "baseUrl", "headers", "compat", "apiKey", "modelOverrides", or "models".`);
472
- }
473
- }
474
- else if (!isBuiltIn) {
475
- // Non-built-in providers with custom models require an endpoint.
476
- // Auth can come from auth.json, --api-key, or provider request config.
477
- if (!providerConfig.baseUrl) {
478
- throw new Error(`Provider ${providerName}: "baseUrl" is required when defining custom models.`);
479
- }
480
- }
481
- // Built-in providers with custom models: baseUrl/apiKey/api are optional,
482
- // inherited from built-in models. Auth comes from env vars / auth storage.
483
- for (const modelDef of models) {
484
- const hasModelApi = !!modelDef.api;
485
- if (!hasProviderApi && !hasModelApi && !isBuiltIn) {
486
- throw new Error(`Provider ${providerName}, model ${modelDef.id}: no "api" specified. Set at provider or model level.`);
487
- }
488
- // For built-in providers, api is optional — inherited from built-in models.
489
- if (!modelDef.id)
490
- throw new Error(`Provider ${providerName}: model missing "id"`);
491
- // Validate contextWindow/maxTokens only if provided (they have defaults)
492
- if (modelDef.contextWindow !== undefined && modelDef.contextWindow <= 0)
493
- throw new Error(`Provider ${providerName}, model ${modelDef.id}: invalid contextWindow`);
494
- if (modelDef.maxTokens !== undefined && modelDef.maxTokens <= 0)
495
- throw new Error(`Provider ${providerName}, model ${modelDef.id}: invalid maxTokens`);
496
- }
497
- }
20
+ return this.runtime.getError();
498
21
  }
499
- parseModels(config) {
500
- const models = [];
501
- const builtInProviders = new Set(getProviders());
502
- // Cache built-in defaults (api, baseUrl) per provider, extracted from first model.
503
- const builtInDefaultsCache = new Map();
504
- const getBuiltInDefaults = (providerName) => {
505
- if (!builtInProviders.has(providerName))
506
- return undefined;
507
- if (builtInDefaultsCache.has(providerName))
508
- return builtInDefaultsCache.get(providerName);
509
- const builtIn = getModels(providerName);
510
- if (builtIn.length === 0)
511
- return undefined;
512
- const defaults = { api: builtIn[0].api, baseUrl: builtIn[0].baseUrl };
513
- builtInDefaultsCache.set(providerName, defaults);
514
- return defaults;
515
- };
516
- for (const [providerName, providerConfig] of Object.entries(config.providers)) {
517
- const modelDefs = providerConfig.models ?? [];
518
- if (modelDefs.length === 0)
519
- continue; // Override-only, no custom models
520
- const builtInDefaults = getBuiltInDefaults(providerName);
521
- for (const modelDef of modelDefs) {
522
- const api = modelDef.api ?? providerConfig.api ?? builtInDefaults?.api;
523
- if (!api)
524
- continue;
525
- const baseUrl = modelDef.baseUrl ?? providerConfig.baseUrl ?? builtInDefaults?.baseUrl;
526
- if (!baseUrl)
527
- continue;
528
- const compat = mergeCompat(providerConfig.compat, modelDef.compat);
529
- this.storeModelHeaders(providerName, modelDef.id, modelDef.headers);
530
- const defaultCost = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
531
- models.push({
532
- id: modelDef.id,
533
- name: modelDef.name ?? modelDef.id,
534
- api: api,
535
- provider: providerName,
536
- baseUrl,
537
- reasoning: modelDef.reasoning ?? false,
538
- thinkingLevelMap: modelDef.thinkingLevelMap,
539
- input: (modelDef.input ?? ["text"]),
540
- cost: modelDef.cost ?? defaultCost,
541
- contextWindow: modelDef.contextWindow ?? 128000,
542
- maxTokens: modelDef.maxTokens ?? 16384,
543
- headers: undefined,
544
- compat,
545
- });
546
- }
547
- }
548
- return models;
549
- }
550
- /**
551
- * Get all models (built-in + custom).
552
- * If models.json had errors, returns only built-in models.
553
- */
554
22
  getAll() {
555
- return this.models;
23
+ return [...this.runtime.getModels()];
556
24
  }
557
- /**
558
- * Get only models that have auth configured.
559
- * This is a fast check that doesn't refresh OAuth tokens.
560
- */
561
25
  getAvailable() {
562
- return this.models.filter((m) => this.hasConfiguredAuth(m));
26
+ return [...this.runtime.getAvailableSnapshot()];
563
27
  }
564
- /**
565
- * Find a model by provider and ID.
566
- */
567
28
  find(provider, modelId) {
568
- return this.models.find((m) => m.provider === provider && m.id === modelId);
29
+ return this.runtime.getModel(provider, modelId);
569
30
  }
570
- /**
571
- * Get API key for a model.
572
- */
573
31
  hasConfiguredAuth(model) {
574
- const providerApiKey = this.providerRequestConfigs.get(model.provider)?.apiKey;
575
- return (this.authStorage.hasAuth(model.provider) ||
576
- (providerApiKey !== undefined && isConfigValueConfigured(providerApiKey)));
577
- }
578
- getModelRequestKey(provider, modelId) {
579
- return `${provider}:${modelId}`;
580
- }
581
- storeProviderRequestConfig(providerName, config) {
582
- if (!config.apiKey && !config.headers && !config.authHeader) {
583
- return;
584
- }
585
- const existing = this.providerRequestConfigs.get(providerName);
586
- this.providerRequestConfigs.set(providerName, {
587
- apiKey: config.apiKey ?? existing?.apiKey,
588
- headers: config.headers ?? existing?.headers,
589
- authHeader: config.authHeader ?? existing?.authHeader,
590
- });
32
+ return this.runtime.hasConfiguredAuth(model.provider);
591
33
  }
592
- storeModelHeaders(providerName, modelId, headers) {
593
- const key = this.getModelRequestKey(providerName, modelId);
594
- if (!headers || Object.keys(headers).length === 0) {
595
- this.modelRequestHeaders.delete(key);
596
- return;
597
- }
598
- this.modelRequestHeaders.set(key, headers);
599
- }
600
- /**
601
- * Get API key and request headers for a model.
602
- */
603
34
  async getApiKeyAndHeaders(model) {
604
35
  try {
605
- const providerConfig = this.providerRequestConfigs.get(model.provider);
606
- const providerEnv = this.authStorage.getProviderEnv(model.provider);
607
- const apiKeyFromAuthStorage = await this.authStorage.getApiKey(model.provider, { includeFallback: false });
608
- const apiKey = apiKeyFromAuthStorage ??
609
- (providerConfig?.apiKey
610
- ? resolveConfigValueOrThrow(providerConfig.apiKey, `API key for provider "${model.provider}"`, providerEnv)
611
- : undefined);
612
- const providerHeaders = resolveHeadersOrThrow(providerConfig?.headers, `provider "${model.provider}"`, providerEnv);
613
- const modelHeaders = resolveHeadersOrThrow(this.modelRequestHeaders.get(this.getModelRequestKey(model.provider, model.id)), `model "${model.provider}/${model.id}"`, providerEnv);
614
- let headers = model.headers || providerHeaders || modelHeaders
615
- ? { ...model.headers, ...providerHeaders, ...modelHeaders }
616
- : undefined;
617
- if (providerConfig?.authHeader) {
618
- if (!apiKey) {
36
+ const resolution = await this.runtime.getAuth(model);
37
+ if (!resolution) {
38
+ const compatibility = this.runtime.getCompatibilityRequestConfig(model);
39
+ if (compatibility.authHeader) {
619
40
  return { ok: false, error: `No API key found for "${model.provider}"` };
620
41
  }
621
- headers = { ...headers, Authorization: `Bearer ${apiKey}` };
42
+ const headers = compatibility.headers
43
+ ? Object.fromEntries(Object.entries(compatibility.headers).filter((entry) => entry[1] !== null))
44
+ : undefined;
45
+ return { ok: true, headers };
622
46
  }
623
- return {
624
- ok: true,
625
- apiKey,
626
- headers: headers && Object.keys(headers).length > 0 ? headers : undefined,
627
- env: providerEnv && Object.keys(providerEnv).length > 0 ? providerEnv : undefined,
628
- };
47
+ const headers = resolution.auth.headers
48
+ ? Object.fromEntries(Object.entries(resolution.auth.headers).filter((entry) => entry[1] !== null))
49
+ : undefined;
50
+ return { ok: true, apiKey: resolution.auth.apiKey, headers, env: resolution.env };
629
51
  }
630
52
  catch (error) {
53
+ const cause = error instanceof Error ? error.cause : undefined;
54
+ const message = cause instanceof Error ? cause.message : error instanceof Error ? error.message : String(error);
631
55
  return {
632
56
  ok: false,
633
- error: error instanceof Error ? error.message : String(error),
57
+ error: message === "authHeader requires a resolved API key"
58
+ ? `No API key found for "${model.provider}"`
59
+ : message,
634
60
  };
635
61
  }
636
62
  }
637
- /**
638
- * Return auth status for a provider, including request auth configured in models.json.
639
- * This intentionally does not execute command-backed config values.
640
- */
641
63
  getProviderAuthStatus(provider) {
642
- const authStatus = this.authStorage.getAuthStatus(provider);
643
- if (authStatus.source) {
644
- return authStatus;
645
- }
646
- const providerApiKey = this.providerRequestConfigs.get(provider)?.apiKey;
647
- if (!providerApiKey) {
648
- return authStatus;
649
- }
650
- if (isCommandConfigValue(providerApiKey)) {
651
- return { configured: true, source: "models_json_command" };
652
- }
653
- const envVarNames = getConfigValueEnvVarNames(providerApiKey);
654
- if (envVarNames.length > 0) {
655
- return isConfigValueConfigured(providerApiKey)
656
- ? { configured: true, source: "environment", label: envVarNames.join(", ") }
657
- : { configured: false };
658
- }
659
- return { configured: true, source: "models_json_key" };
64
+ return this.runtime.getProviderAuthStatus(provider);
65
+ }
66
+ getProvider(provider) {
67
+ return this.runtime.getProvider(provider);
660
68
  }
661
- /**
662
- * Get display name for a provider.
663
- */
664
69
  getProviderDisplayName(provider) {
665
- const registeredProvider = this.registeredProviders.get(provider);
666
- const oauthProvider = this.authStorage.getOAuthProviders().find((p) => p.id === provider);
667
- return (registeredProvider?.name ??
668
- registeredProvider?.oauth?.name ??
669
- oauthProvider?.name ??
670
- BUILT_IN_PROVIDER_DISPLAY_NAMES[provider] ??
671
- provider);
70
+ return this.runtime.getProvider(provider)?.name ?? provider;
71
+ }
72
+ getProviderAuth(provider) {
73
+ return this.runtime.getAuth(provider);
672
74
  }
673
- /**
674
- * Get API key for a provider.
675
- */
676
75
  async getApiKeyForProvider(provider) {
677
- const apiKey = await this.authStorage.getApiKey(provider);
678
- if (apiKey !== undefined) {
679
- return apiKey;
76
+ try {
77
+ return (await this.runtime.getAuth(provider))?.auth.apiKey;
78
+ }
79
+ catch {
80
+ return undefined;
680
81
  }
681
- const providerApiKey = this.providerRequestConfigs.get(provider)?.apiKey;
682
- return providerApiKey
683
- ? resolveConfigValueUncached(providerApiKey, this.authStorage.getProviderEnv(provider))
684
- : undefined;
685
82
  }
686
- /**
687
- * Check if a model is using OAuth credentials (subscription).
688
- */
689
83
  isUsingOAuth(model) {
690
- const cred = this.authStorage.get(model.provider);
691
- return cred?.type === "oauth";
84
+ return this.runtime.isUsingOAuth(model.provider);
692
85
  }
693
- /**
694
- * Register a provider dynamically (from extensions).
695
- *
696
- * If provider has models: replaces all existing models for this provider.
697
- * If provider has only baseUrl/headers: overrides existing models' URLs.
698
- * If provider has oauth: registers OAuth provider for /login support.
699
- */
700
- registerProvider(providerName, config) {
701
- this.validateProviderConfig(providerName, config);
702
- this.applyProviderConfig(providerName, config);
703
- this.upsertRegisteredProvider(providerName, config);
86
+ registerProvider(providerOrName, config) {
87
+ if (typeof providerOrName === "string") {
88
+ if (!config)
89
+ throw new Error("Provider config is required when registering by name");
90
+ this.runtime.registerProvider(providerOrName, config);
91
+ return;
92
+ }
93
+ this.runtime.registerNativeProvider(providerOrName);
704
94
  }
705
- /**
706
- * Unregister a previously registered provider.
707
- *
708
- * Removes the provider from the registry and reloads models from disk so that
709
- * built-in models overridden by this provider are restored to their original state.
710
- * Also resets dynamic OAuth and API stream registrations before reapplying
711
- * remaining dynamic providers.
712
- * Has no effect if the provider was never registered.
713
- */
714
95
  unregisterProvider(providerName) {
715
- if (!this.registeredProviders.has(providerName))
716
- return;
717
- this.registeredProviders.delete(providerName);
718
- this.refresh();
96
+ this.runtime.unregisterProvider(providerName);
719
97
  }
720
- /**
721
- * Upsert a provider config into registeredProviders.
722
- * If the provider is already registered, defined values in the incoming config
723
- * override existing ones; undefined values are preserved from the stored config.
724
- * If the provider is not registered, the incoming config is stored as-is.
725
- */
726
- upsertRegisteredProvider(providerName, config) {
727
- const existing = this.registeredProviders.get(providerName);
728
- if (!existing) {
729
- this.registeredProviders.set(providerName, config);
730
- return;
731
- }
732
- for (const k of Object.keys(config)) {
733
- if (config[k] !== undefined) {
734
- existing[k] = config[k];
735
- }
736
- }
98
+ getRegisteredProviderConfig(providerName) {
99
+ return this.runtime.getRegisteredProviderConfig(providerName);
737
100
  }
738
- validateProviderConfig(providerName, config) {
739
- if (config.streamSimple && !config.api) {
740
- throw new Error(`Provider ${providerName}: "api" is required when registering streamSimple.`);
741
- }
742
- if (!config.models || config.models.length === 0) {
743
- return;
744
- }
745
- if (!config.baseUrl) {
746
- throw new Error(`Provider ${providerName}: "baseUrl" is required when defining models.`);
747
- }
748
- if (!config.apiKey && !config.oauth) {
749
- throw new Error(`Provider ${providerName}: "apiKey" or "oauth" is required when defining models.`);
750
- }
751
- for (const modelDef of config.models) {
752
- const api = modelDef.api || config.api;
753
- if (!api) {
754
- throw new Error(`Provider ${providerName}, model ${modelDef.id}: no "api" specified.`);
755
- }
756
- }
101
+ getRegisteredNativeProvider(providerName) {
102
+ return this.runtime.getRegisteredNativeProvider(providerName);
757
103
  }
758
- applyProviderConfig(providerName, config) {
759
- // Register OAuth provider if provided
760
- if (config.oauth) {
761
- // Ensure the OAuth provider ID matches the provider name
762
- const oauthProvider = {
763
- ...config.oauth,
764
- id: providerName,
765
- };
766
- registerOAuthProvider(oauthProvider);
767
- }
768
- if (config.streamSimple) {
769
- const streamSimple = config.streamSimple;
770
- registerApiProvider({
771
- api: config.api,
772
- stream: (model, context, options) => streamSimple(model, context, options),
773
- streamSimple,
774
- }, `provider:${providerName}`);
775
- }
776
- this.storeProviderRequestConfig(providerName, config);
777
- if (config.models && config.models.length > 0) {
778
- // Full replacement: remove existing models for this provider
779
- this.models = this.models.filter((m) => m.provider !== providerName);
780
- // Parse and add new models
781
- for (const modelDef of config.models) {
782
- const api = modelDef.api || config.api;
783
- const modelOverride = this.getConfiguredModelOverride(providerName, modelDef.id);
784
- const headers = modelDef.headers || modelOverride?.headers
785
- ? { ...modelDef.headers, ...modelOverride?.headers }
786
- : undefined;
787
- this.storeModelHeaders(providerName, modelDef.id, headers);
788
- const model = this.applyConfiguredModelOverride(providerName, {
789
- id: modelDef.id,
790
- name: modelDef.name,
791
- api: api,
792
- provider: providerName,
793
- baseUrl: modelDef.baseUrl ?? config.baseUrl,
794
- reasoning: modelDef.reasoning,
795
- thinkingLevelMap: modelDef.thinkingLevelMap,
796
- input: modelDef.input,
797
- cost: modelDef.cost,
798
- contextWindow: modelDef.contextWindow,
799
- maxTokens: modelDef.maxTokens,
800
- headers: undefined,
801
- compat: modelDef.compat,
802
- });
803
- this.models.push(model);
804
- }
805
- // Apply OAuth modifyModels if credentials exist (e.g., to update baseUrl)
806
- if (config.oauth?.modifyModels) {
807
- const cred = this.authStorage.get(providerName);
808
- if (cred?.type === "oauth") {
809
- this.models = config.oauth.modifyModels(this.models, cred);
810
- }
811
- }
812
- }
813
- else if (config.baseUrl || config.headers) {
814
- // Override-only: update baseUrl for existing models. Request headers are resolved per request.
815
- this.models = this.models.map((m) => {
816
- if (m.provider !== providerName)
817
- return m;
818
- return {
819
- ...m,
820
- baseUrl: config.baseUrl ?? m.baseUrl,
821
- };
822
- });
823
- }
104
+ getRegisteredProviderIds() {
105
+ return this.runtime.getRegisteredProviderIds();
824
106
  }
825
107
  }
826
108
  //# sourceMappingURL=model-registry.js.map