@code-yeongyu/senpi 2026.7.14 → 2026.7.16-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (455) hide show
  1. package/CHANGELOG.md +143 -0
  2. package/README.md +6 -6
  3. package/dist/bun/cli.js +2 -0
  4. package/dist/bun/cli.js.map +1 -1
  5. package/dist/cli/args.js +1 -1
  6. package/dist/cli/args.js.map +1 -1
  7. package/dist/cli/list-models.d.ts +2 -2
  8. package/dist/cli/list-models.d.ts.map +1 -1
  9. package/dist/cli/list-models.js +3 -3
  10. package/dist/cli/list-models.js.map +1 -1
  11. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  12. package/dist/core/agent-session-runtime.js +3 -0
  13. package/dist/core/agent-session-runtime.js.map +1 -1
  14. package/dist/core/agent-session-services.d.ts +4 -3
  15. package/dist/core/agent-session-services.d.ts.map +1 -1
  16. package/dist/core/agent-session-services.js +14 -5
  17. package/dist/core/agent-session-services.js.map +1 -1
  18. package/dist/core/agent-session.d.ts +8 -4
  19. package/dist/core/agent-session.d.ts.map +1 -1
  20. package/dist/core/agent-session.js +81 -30
  21. package/dist/core/agent-session.js.map +1 -1
  22. package/dist/core/auth-providers.js +1 -1
  23. package/dist/core/auth-providers.js.map +1 -1
  24. package/dist/core/auth-storage.d.ts +32 -87
  25. package/dist/core/auth-storage.d.ts.map +1 -1
  26. package/dist/core/auth-storage.js +158 -221
  27. package/dist/core/auth-storage.js.map +1 -1
  28. package/dist/core/cache-stats.d.ts +2 -2
  29. package/dist/core/cache-stats.d.ts.map +1 -1
  30. package/dist/core/cache-stats.js +1 -1
  31. package/dist/core/cache-stats.js.map +1 -1
  32. package/dist/core/compaction/branch-summarization.d.ts +1 -1
  33. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  34. package/dist/core/compaction/branch-summarization.js.map +1 -1
  35. package/dist/core/dynamic-prompt/build.d.ts.map +1 -1
  36. package/dist/core/dynamic-prompt/build.js +6 -1
  37. package/dist/core/dynamic-prompt/build.js.map +1 -1
  38. package/dist/core/extensions/builtin/bash-timeout/timeout.js +2 -2
  39. package/dist/core/extensions/builtin/bash-timeout/timeout.js.map +1 -1
  40. package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.d.ts.map +1 -1
  41. package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.js +22 -13
  42. package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.js.map +1 -1
  43. package/dist/core/extensions/builtin/terminal/runtime-session.d.ts +1 -1
  44. package/dist/core/extensions/builtin/terminal/runtime-session.d.ts.map +1 -1
  45. package/dist/core/extensions/builtin/terminal/runtime-session.js +3 -2
  46. package/dist/core/extensions/builtin/terminal/runtime-session.js.map +1 -1
  47. package/dist/core/extensions/loader.d.ts.map +1 -1
  48. package/dist/core/extensions/loader.js +8 -2
  49. package/dist/core/extensions/loader.js.map +1 -1
  50. package/dist/core/extensions/runner.d.ts +1 -0
  51. package/dist/core/extensions/runner.d.ts.map +1 -1
  52. package/dist/core/extensions/runner.js +3 -0
  53. package/dist/core/extensions/runner.js.map +1 -1
  54. package/dist/core/extensions/types.d.ts +15 -2
  55. package/dist/core/extensions/types.d.ts.map +1 -1
  56. package/dist/core/extensions/types.js.map +1 -1
  57. package/dist/core/model-config.d.ts +589 -0
  58. package/dist/core/model-config.d.ts.map +1 -0
  59. package/dist/core/model-config.js +288 -0
  60. package/dist/core/model-config.js.map +1 -0
  61. package/dist/core/model-registry.d.ts +17 -146
  62. package/dist/core/model-registry.d.ts.map +1 -1
  63. package/dist/core/model-registry.js +69 -943
  64. package/dist/core/model-registry.js.map +1 -1
  65. package/dist/core/model-resolver.d.ts +8 -5
  66. package/dist/core/model-resolver.d.ts.map +1 -1
  67. package/dist/core/model-resolver.js +19 -18
  68. package/dist/core/model-resolver.js.map +1 -1
  69. package/dist/core/model-runtime.d.ts +81 -0
  70. package/dist/core/model-runtime.d.ts.map +1 -0
  71. package/dist/core/model-runtime.js +442 -0
  72. package/dist/core/model-runtime.js.map +1 -0
  73. package/dist/core/models-store.d.ts +17 -0
  74. package/dist/core/models-store.d.ts.map +1 -0
  75. package/dist/core/models-store.js +46 -0
  76. package/dist/core/models-store.js.map +1 -0
  77. package/dist/core/package-manager.d.ts.map +1 -1
  78. package/dist/core/package-manager.js +7 -2
  79. package/dist/core/package-manager.js.map +1 -1
  80. package/dist/core/provider-composer.d.ts +64 -0
  81. package/dist/core/provider-composer.d.ts.map +1 -0
  82. package/dist/core/provider-composer.js +406 -0
  83. package/dist/core/provider-composer.js.map +1 -0
  84. package/dist/core/provider-display-names.d.ts.map +1 -1
  85. package/dist/core/provider-display-names.js +2 -1
  86. package/dist/core/provider-display-names.js.map +1 -1
  87. package/dist/core/radius.d.ts +2 -0
  88. package/dist/core/radius.d.ts.map +1 -0
  89. package/dist/core/radius.js +2 -0
  90. package/dist/core/radius.js.map +1 -0
  91. package/dist/core/remote-catalog-provider.d.ts +5 -0
  92. package/dist/core/remote-catalog-provider.d.ts.map +1 -0
  93. package/dist/core/remote-catalog-provider.js +83 -0
  94. package/dist/core/remote-catalog-provider.js.map +1 -0
  95. package/dist/core/runtime-credentials.d.ts +15 -0
  96. package/dist/core/runtime-credentials.d.ts.map +1 -0
  97. package/dist/core/runtime-credentials.js +35 -0
  98. package/dist/core/runtime-credentials.js.map +1 -0
  99. package/dist/core/sdk.d.ts +11 -20
  100. package/dist/core/sdk.d.ts.map +1 -1
  101. package/dist/core/sdk.js +61 -89
  102. package/dist/core/sdk.js.map +1 -1
  103. package/dist/core/skills.js +1 -1
  104. package/dist/core/skills.js.map +1 -1
  105. package/dist/core/system-prompt.d.ts.map +1 -1
  106. package/dist/core/system-prompt.js +1 -11
  107. package/dist/core/system-prompt.js.map +1 -1
  108. package/dist/index.d.ts +2 -1
  109. package/dist/index.d.ts.map +1 -1
  110. package/dist/index.js +2 -2
  111. package/dist/index.js.map +1 -1
  112. package/dist/main.d.ts.map +1 -1
  113. package/dist/main.js +10 -13
  114. package/dist/main.js.map +1 -1
  115. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  116. package/dist/modes/interactive/components/assistant-message.js +22 -10
  117. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  118. package/dist/modes/interactive/components/footer.js +1 -1
  119. package/dist/modes/interactive/components/footer.js.map +1 -1
  120. package/dist/modes/interactive/components/login-dialog.d.ts +4 -8
  121. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  122. package/dist/modes/interactive/components/login-dialog.js +14 -12
  123. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  124. package/dist/modes/interactive/components/model-selector.d.ts +13 -4
  125. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  126. package/dist/modes/interactive/components/model-selector.js +84 -41
  127. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  128. package/dist/modes/interactive/components/oauth-selector.d.ts +4 -4
  129. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  130. package/dist/modes/interactive/components/oauth-selector.js +14 -25
  131. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  132. package/dist/modes/interactive/interactive-mode.d.ts +5 -1
  133. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  134. package/dist/modes/interactive/interactive-mode.js +155 -129
  135. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  136. package/dist/package-manager-cli.d.ts.map +1 -1
  137. package/dist/package-manager-cli.js +70 -8
  138. package/dist/package-manager-cli.js.map +1 -1
  139. package/docs/custom-provider.md +8 -11
  140. package/docs/extensions.md +78 -555
  141. package/docs/models.md +4 -0
  142. package/docs/packages.md +1 -0
  143. package/docs/providers.md +23 -11
  144. package/docs/sdk.md +79 -105
  145. package/docs/usage.md +1 -0
  146. package/examples/AGENTS.md +34 -0
  147. package/examples/extensions/README.md +1 -0
  148. package/examples/extensions/custom-provider-anthropic/index.ts +1 -1
  149. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  150. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  151. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  152. package/examples/extensions/gondolin/package-lock.json +2 -2
  153. package/examples/extensions/gondolin/package.json +1 -1
  154. package/examples/extensions/kimi-deferred-tools.ts +61 -0
  155. package/examples/extensions/sandbox/package-lock.json +2 -2
  156. package/examples/extensions/sandbox/package.json +1 -1
  157. package/examples/extensions/with-deps/package-lock.json +2 -2
  158. package/examples/extensions/with-deps/package.json +1 -1
  159. package/examples/sdk/02-custom-model.ts +5 -8
  160. package/examples/sdk/09-api-keys-and-oauth.ts +13 -31
  161. package/examples/sdk/12-full-control.ts +8 -13
  162. package/examples/sdk/README.md +14 -18
  163. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +32 -0
  164. package/node_modules/@code-yeongyu/senpi-codemode/package.json +3 -3
  165. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/local-module-loader.ts +2 -2
  166. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/rewrite-imports.ts +4 -4
  167. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/render.ts +32 -32
  168. package/node_modules/@earendil-works/pi-agent-core/package.json +4 -4
  169. package/node_modules/@earendil-works/pi-ai/README.md +80 -25
  170. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.d.ts.map +1 -1
  171. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js +23 -42
  172. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js.map +1 -1
  173. package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.d.ts.map +1 -1
  174. package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.js +10 -6
  175. package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.js.map +1 -1
  176. package/node_modules/@earendil-works/pi-ai/dist/api/lazy.d.ts.map +1 -1
  177. package/node_modules/@earendil-works/pi-ai/dist/api/lazy.js +9 -10
  178. package/node_modules/@earendil-works/pi-ai/dist/api/lazy.js.map +1 -1
  179. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.d.ts +1 -0
  180. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.d.ts.map +1 -1
  181. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js +4 -3
  182. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js.map +1 -1
  183. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.d.ts +2 -1
  184. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.d.ts.map +1 -1
  185. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js +54 -5
  186. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js.map +1 -1
  187. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.d.ts.map +1 -1
  188. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.js +23 -0
  189. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.js.map +1 -1
  190. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.d.ts +1 -0
  191. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.d.ts.map +1 -1
  192. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js +24 -6
  193. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js.map +1 -1
  194. package/node_modules/@earendil-works/pi-ai/dist/api/pi-messages.d.ts +97 -0
  195. package/node_modules/@earendil-works/pi-ai/dist/api/pi-messages.d.ts.map +1 -0
  196. package/node_modules/@earendil-works/pi-ai/dist/api/pi-messages.js +307 -0
  197. package/node_modules/@earendil-works/pi-ai/dist/api/pi-messages.js.map +1 -0
  198. package/node_modules/@earendil-works/pi-ai/dist/api/pi-messages.lazy.d.ts +3 -0
  199. package/node_modules/@earendil-works/pi-ai/dist/api/pi-messages.lazy.d.ts.map +1 -0
  200. package/node_modules/@earendil-works/pi-ai/dist/api/pi-messages.lazy.js +3 -0
  201. package/node_modules/@earendil-works/pi-ai/dist/api/pi-messages.lazy.js.map +1 -0
  202. package/node_modules/@earendil-works/pi-ai/dist/auth/credential-store.d.ts +2 -1
  203. package/node_modules/@earendil-works/pi-ai/dist/auth/credential-store.d.ts.map +1 -1
  204. package/node_modules/@earendil-works/pi-ai/dist/auth/credential-store.js +3 -0
  205. package/node_modules/@earendil-works/pi-ai/dist/auth/credential-store.js.map +1 -1
  206. package/node_modules/@earendil-works/pi-ai/dist/auth/helpers.d.ts +1 -0
  207. package/node_modules/@earendil-works/pi-ai/dist/auth/helpers.d.ts.map +1 -1
  208. package/node_modules/@earendil-works/pi-ai/dist/auth/helpers.js +4 -3
  209. package/node_modules/@earendil-works/pi-ai/dist/auth/helpers.js.map +1 -1
  210. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/anthropic.d.ts +9 -0
  211. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/anthropic.d.ts.map +1 -0
  212. package/node_modules/@earendil-works/pi-ai/dist/{utils → auth}/oauth/anthropic.js +51 -116
  213. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/anthropic.js.map +1 -0
  214. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/device-code.d.ts.map +1 -0
  215. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/device-code.js.map +1 -0
  216. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/github-copilot.d.ts +6 -0
  217. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/github-copilot.d.ts.map +1 -0
  218. package/node_modules/@earendil-works/pi-ai/dist/{utils → auth}/oauth/github-copilot.js +18 -77
  219. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/github-copilot.js.map +1 -0
  220. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/load.d.ts +23 -0
  221. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/load.d.ts.map +1 -0
  222. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/load.js +49 -0
  223. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/load.js.map +1 -0
  224. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/oauth-page.d.ts.map +1 -0
  225. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/oauth-page.js.map +1 -0
  226. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/openai-codex.d.ts +9 -0
  227. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/openai-codex.d.ts.map +1 -0
  228. package/node_modules/@earendil-works/pi-ai/dist/{utils → auth}/oauth/openai-codex.js +61 -155
  229. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/openai-codex.js.map +1 -0
  230. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/pkce.d.ts.map +1 -0
  231. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/pkce.js.map +1 -0
  232. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/radius.d.ts +16 -0
  233. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/radius.d.ts.map +1 -0
  234. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/radius.js +316 -0
  235. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/radius.js.map +1 -0
  236. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/xai.d.ts +6 -0
  237. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/xai.d.ts.map +1 -0
  238. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/xai.js +189 -0
  239. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/xai.js.map +1 -0
  240. package/node_modules/@earendil-works/pi-ai/dist/auth/resolve.d.ts +2 -4
  241. package/node_modules/@earendil-works/pi-ai/dist/auth/resolve.d.ts.map +1 -1
  242. package/node_modules/@earendil-works/pi-ai/dist/auth/resolve.js +9 -7
  243. package/node_modules/@earendil-works/pi-ai/dist/auth/resolve.js.map +1 -1
  244. package/node_modules/@earendil-works/pi-ai/dist/auth/types.d.ts +49 -10
  245. package/node_modules/@earendil-works/pi-ai/dist/auth/types.d.ts.map +1 -1
  246. package/node_modules/@earendil-works/pi-ai/dist/auth/types.js.map +1 -1
  247. package/node_modules/@earendil-works/pi-ai/dist/bun-oauth.d.ts +3 -0
  248. package/node_modules/@earendil-works/pi-ai/dist/bun-oauth.d.ts.map +1 -0
  249. package/node_modules/@earendil-works/pi-ai/dist/bun-oauth.js +17 -0
  250. package/node_modules/@earendil-works/pi-ai/dist/bun-oauth.js.map +1 -0
  251. package/node_modules/@earendil-works/pi-ai/dist/cli.js +58 -76
  252. package/node_modules/@earendil-works/pi-ai/dist/cli.js.map +1 -1
  253. package/node_modules/@earendil-works/pi-ai/dist/compat/extension-oauth-types.d.ts +42 -0
  254. package/node_modules/@earendil-works/pi-ai/dist/compat/extension-oauth-types.d.ts.map +1 -0
  255. package/node_modules/@earendil-works/pi-ai/dist/compat/extension-oauth-types.js +2 -0
  256. package/node_modules/@earendil-works/pi-ai/dist/compat/extension-oauth-types.js.map +1 -0
  257. package/node_modules/@earendil-works/pi-ai/dist/compat.d.ts +2 -0
  258. package/node_modules/@earendil-works/pi-ai/dist/compat.d.ts.map +1 -1
  259. package/node_modules/@earendil-works/pi-ai/dist/compat.js +49 -22
  260. package/node_modules/@earendil-works/pi-ai/dist/compat.js.map +1 -1
  261. package/node_modules/@earendil-works/pi-ai/dist/env-api-keys.d.ts.map +1 -1
  262. package/node_modules/@earendil-works/pi-ai/dist/env-api-keys.js +1 -0
  263. package/node_modules/@earendil-works/pi-ai/dist/env-api-keys.js.map +1 -1
  264. package/node_modules/@earendil-works/pi-ai/dist/images-models.d.ts +4 -2
  265. package/node_modules/@earendil-works/pi-ai/dist/images-models.d.ts.map +1 -1
  266. package/node_modules/@earendil-works/pi-ai/dist/images-models.js +5 -4
  267. package/node_modules/@earendil-works/pi-ai/dist/images-models.js.map +1 -1
  268. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts +3 -1
  269. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts.map +1 -1
  270. package/node_modules/@earendil-works/pi-ai/dist/index.js +1 -0
  271. package/node_modules/@earendil-works/pi-ai/dist/index.js.map +1 -1
  272. package/node_modules/@earendil-works/pi-ai/dist/models-store.d.ts +25 -0
  273. package/node_modules/@earendil-works/pi-ai/dist/models-store.d.ts.map +1 -0
  274. package/node_modules/@earendil-works/pi-ai/dist/models-store.js +16 -0
  275. package/node_modules/@earendil-works/pi-ai/dist/models-store.js.map +1 -0
  276. package/node_modules/@earendil-works/pi-ai/dist/models.d.ts +69 -30
  277. package/node_modules/@earendil-works/pi-ai/dist/models.d.ts.map +1 -1
  278. package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts +328 -120
  279. package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts.map +1 -1
  280. package/node_modules/@earendil-works/pi-ai/dist/models.js +217 -31
  281. package/node_modules/@earendil-works/pi-ai/dist/models.js.map +1 -1
  282. package/node_modules/@earendil-works/pi-ai/dist/oauth.d.ts +2 -1
  283. package/node_modules/@earendil-works/pi-ai/dist/oauth.d.ts.map +1 -1
  284. package/node_modules/@earendil-works/pi-ai/dist/oauth.js +1 -1
  285. package/node_modules/@earendil-works/pi-ai/dist/oauth.js.map +1 -1
  286. package/node_modules/@earendil-works/pi-ai/dist/providers/all.d.ts +11 -6
  287. package/node_modules/@earendil-works/pi-ai/dist/providers/all.d.ts.map +1 -1
  288. package/node_modules/@earendil-works/pi-ai/dist/providers/all.js +3 -0
  289. package/node_modules/@earendil-works/pi-ai/dist/providers/all.js.map +1 -1
  290. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.d.ts.map +1 -1
  291. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js +51 -10
  292. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
  293. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  294. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js +1 -1
  295. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js.map +1 -1
  296. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-ai-gateway.d.ts.map +1 -1
  297. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-ai-gateway.js +4 -3
  298. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-ai-gateway.js.map +1 -1
  299. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-auth.d.ts.map +1 -1
  300. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-auth.js +13 -20
  301. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-auth.js.map +1 -1
  302. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-stream.d.ts +8 -0
  303. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-stream.d.ts.map +1 -0
  304. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-stream.js +21 -0
  305. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-stream.js.map +1 -0
  306. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-workers-ai.d.ts.map +1 -1
  307. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-workers-ai.js +2 -1
  308. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-workers-ai.js.map +1 -1
  309. package/node_modules/@earendil-works/pi-ai/dist/providers/github-copilot.d.ts.map +1 -1
  310. package/node_modules/@earendil-works/pi-ai/dist/providers/github-copilot.js +11 -1
  311. package/node_modules/@earendil-works/pi-ai/dist/providers/github-copilot.js.map +1 -1
  312. package/node_modules/@earendil-works/pi-ai/dist/providers/github-copilot.models.d.ts +1 -6
  313. package/node_modules/@earendil-works/pi-ai/dist/providers/github-copilot.models.d.ts.map +1 -1
  314. package/node_modules/@earendil-works/pi-ai/dist/providers/github-copilot.models.js +1 -2
  315. package/node_modules/@earendil-works/pi-ai/dist/providers/github-copilot.models.js.map +1 -1
  316. package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.d.ts.map +1 -1
  317. package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.js +56 -5
  318. package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.js.map +1 -1
  319. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.d.ts +66 -0
  320. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.d.ts.map +1 -1
  321. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.js +42 -0
  322. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.js.map +1 -1
  323. package/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai-cn.models.d.ts +36 -0
  324. package/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai-cn.models.d.ts.map +1 -1
  325. package/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai-cn.models.js +19 -0
  326. package/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai-cn.models.js.map +1 -1
  327. package/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai.models.d.ts +36 -0
  328. package/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai.models.d.ts.map +1 -1
  329. package/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai.models.js +19 -0
  330. package/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai.models.js.map +1 -1
  331. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex.d.ts.map +1 -1
  332. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex.js +1 -1
  333. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex.js.map +1 -1
  334. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode.models.d.ts +57 -0
  335. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode.models.d.ts.map +1 -1
  336. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode.models.js +19 -0
  337. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode.models.js.map +1 -1
  338. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.d.ts +42 -0
  339. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.d.ts.map +1 -1
  340. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js +175 -139
  341. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js.map +1 -1
  342. package/node_modules/@earendil-works/pi-ai/dist/providers/radius-config.d.ts +26 -0
  343. package/node_modules/@earendil-works/pi-ai/dist/providers/radius-config.d.ts.map +1 -0
  344. package/node_modules/@earendil-works/pi-ai/dist/providers/radius-config.js +59 -0
  345. package/node_modules/@earendil-works/pi-ai/dist/providers/radius-config.js.map +1 -0
  346. package/node_modules/@earendil-works/pi-ai/dist/providers/radius.d.ts +9 -0
  347. package/node_modules/@earendil-works/pi-ai/dist/providers/radius.d.ts.map +1 -0
  348. package/node_modules/@earendil-works/pi-ai/dist/providers/radius.js +54 -0
  349. package/node_modules/@earendil-works/pi-ai/dist/providers/radius.js.map +1 -0
  350. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.d.ts +84 -0
  351. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.d.ts.map +1 -1
  352. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.js +74 -2
  353. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.js.map +1 -1
  354. package/node_modules/@earendil-works/pi-ai/dist/providers/xai.d.ts +1 -1
  355. package/node_modules/@earendil-works/pi-ai/dist/providers/xai.d.ts.map +1 -1
  356. package/node_modules/@earendil-works/pi-ai/dist/providers/xai.js +15 -3
  357. package/node_modules/@earendil-works/pi-ai/dist/providers/xai.js.map +1 -1
  358. package/node_modules/@earendil-works/pi-ai/dist/providers/xai.models.d.ts +6 -114
  359. package/node_modules/@earendil-works/pi-ai/dist/providers/xai.models.d.ts.map +1 -1
  360. package/node_modules/@earendil-works/pi-ai/dist/providers/xai.models.js +3 -92
  361. package/node_modules/@earendil-works/pi-ai/dist/providers/xai.models.js.map +1 -1
  362. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/context-transformer.d.ts.map +1 -1
  363. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/context-transformer.js +9 -0
  364. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/context-transformer.js.map +1 -1
  365. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/index.d.ts +1 -1
  366. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/index.d.ts.map +1 -1
  367. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/index.js +6 -2
  368. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/index.js.map +1 -1
  369. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/coerce-parameters.d.ts +8 -0
  370. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/coerce-parameters.d.ts.map +1 -0
  371. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/coerce-parameters.js +92 -0
  372. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/coerce-parameters.js.map +1 -0
  373. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/format.d.ts +6 -0
  374. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/format.d.ts.map +1 -0
  375. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/format.js +54 -0
  376. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/format.js.map +1 -0
  377. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/index.d.ts +4 -0
  378. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/index.d.ts.map +1 -0
  379. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/index.js +4 -0
  380. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/index.js.map +1 -0
  381. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-match.d.ts +7 -0
  382. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-match.d.ts.map +1 -0
  383. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-match.js +16 -0
  384. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-match.js.map +1 -0
  385. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-tag-scanner.d.ts +19 -0
  386. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-tag-scanner.d.ts.map +1 -0
  387. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-tag-scanner.js +217 -0
  388. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-tag-scanner.js.map +1 -0
  389. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/parse.d.ts +4 -0
  390. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/parse.d.ts.map +1 -0
  391. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/parse.js +46 -0
  392. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/parse.js.map +1 -0
  393. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream-boundary.d.ts +13 -0
  394. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream-boundary.d.ts.map +1 -0
  395. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream-boundary.js +144 -0
  396. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream-boundary.js.map +1 -0
  397. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream.d.ts +5 -0
  398. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream.d.ts.map +1 -0
  399. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream.js +208 -0
  400. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream.js.map +1 -0
  401. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/tool-resolver.d.ts +4 -0
  402. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/tool-resolver.d.ts.map +1 -0
  403. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/tool-resolver.js +17 -0
  404. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/tool-resolver.js.map +1 -0
  405. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/xml-entities.d.ts +5 -0
  406. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/xml-entities.d.ts.map +1 -0
  407. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/xml-entities.js +34 -0
  408. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/xml-entities.js.map +1 -0
  409. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/types.d.ts +3 -1
  410. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/types.d.ts.map +1 -1
  411. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/types.js.map +1 -1
  412. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +12 -5
  413. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
  414. package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
  415. package/node_modules/@earendil-works/pi-ai/package.json +6 -1
  416. package/node_modules/@earendil-works/pi-pty/native/prebuilds/darwin-arm64/senpi_pty.darwin-arm64.node +0 -0
  417. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  418. package/node_modules/@earendil-works/pi-tui/dist/utils.d.ts.map +1 -1
  419. package/node_modules/@earendil-works/pi-tui/dist/utils.js +22 -4
  420. package/node_modules/@earendil-works/pi-tui/dist/utils.js.map +1 -1
  421. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  422. package/package.json +6 -6
  423. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/anthropic.d.ts +0 -27
  424. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/anthropic.d.ts.map +0 -1
  425. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/anthropic.js.map +0 -1
  426. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.d.ts.map +0 -1
  427. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.js.map +0 -1
  428. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.d.ts +0 -32
  429. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +0 -1
  430. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.js.map +0 -1
  431. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.d.ts +0 -58
  432. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.d.ts.map +0 -1
  433. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.js +0 -122
  434. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.js.map +0 -1
  435. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/load.d.ts +0 -5
  436. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/load.d.ts.map +0 -1
  437. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/load.js +0 -22
  438. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/load.js.map +0 -1
  439. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/oauth-page.d.ts.map +0 -1
  440. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/oauth-page.js.map +0 -1
  441. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.d.ts +0 -45
  442. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.d.ts.map +0 -1
  443. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.js.map +0 -1
  444. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/pkce.d.ts.map +0 -1
  445. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/pkce.js.map +0 -1
  446. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/types.d.ts +0 -64
  447. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/types.d.ts.map +0 -1
  448. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/types.js +0 -2
  449. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/types.js.map +0 -1
  450. /package/node_modules/@earendil-works/pi-ai/dist/{utils → auth}/oauth/device-code.d.ts +0 -0
  451. /package/node_modules/@earendil-works/pi-ai/dist/{utils → auth}/oauth/device-code.js +0 -0
  452. /package/node_modules/@earendil-works/pi-ai/dist/{utils → auth}/oauth/oauth-page.d.ts +0 -0
  453. /package/node_modules/@earendil-works/pi-ai/dist/{utils → auth}/oauth/oauth-page.js +0 -0
  454. /package/node_modules/@earendil-works/pi-ai/dist/{utils → auth}/oauth/pkce.d.ts +0 -0
  455. /package/node_modules/@earendil-works/pi-ai/dist/{utils → auth}/oauth/pkce.js +0 -0
@@ -1,997 +1,123 @@
1
- /**
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";
1
+ import { join } from "node:path";
10
2
  import { getAgentDir } from "../config.js";
11
- import { stripJsonComments } from "../utils/json.js";
12
- import { normalizePath } from "../utils/paths.js";
3
+ import { AuthStorage } from "./auth-storage.js";
4
+ import { ModelRuntime as DefaultModelRuntime } from "./model-runtime.js";
13
5
  import { BUILT_IN_PROVIDER_DISPLAY_NAMES } from "./provider-display-names.js";
14
- import { 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
- toolCallFormat: Type.Optional(Type.Union([
99
- Type.Literal("hermes"),
100
- Type.Literal("gemma4"),
101
- Type.Literal("gemma4-delimiter"),
102
- Type.Literal("xml"),
103
- Type.Literal("yaml-xml"),
104
- ])),
105
- supportsLongCacheRetention: Type.Optional(Type.Boolean()),
106
- });
107
- const OpenAIResponsesCompatSchema = Type.Object({
108
- supportsDeveloperRole: Type.Optional(Type.Boolean()),
109
- sendSessionIdHeader: Type.Optional(Type.Boolean()),
110
- supportsLongCacheRetention: Type.Optional(Type.Boolean()),
111
- supportsWebSocket: Type.Optional(Type.Boolean()),
112
- supportsWebSearchPreview: Type.Optional(Type.Boolean()),
113
- supportsToolSearch: Type.Optional(Type.Boolean()),
114
- });
115
- const AnthropicMessagesCompatSchema = Type.Object({
116
- supportsEagerToolInputStreaming: Type.Optional(Type.Boolean()),
117
- supportsLongCacheRetention: Type.Optional(Type.Boolean()),
118
- supportsDisabledThinking: Type.Optional(Type.Boolean()),
119
- sendSessionAffinityHeaders: Type.Optional(Type.Boolean()),
120
- supportsCacheControlOnTools: Type.Optional(Type.Boolean()),
121
- supportsToolChoice: Type.Optional(Type.Boolean()),
122
- supportsForcedToolChoice: Type.Optional(Type.Boolean()),
123
- forceAdaptiveThinking: Type.Optional(Type.Boolean()),
124
- supportsToolReferences: Type.Optional(Type.Boolean()),
125
- });
126
- const ProviderCompatSchema = Type.Union([
127
- OpenAICompletionsCompatSchema,
128
- OpenAIResponsesCompatSchema,
129
- AnthropicMessagesCompatSchema,
130
- ]);
131
- const ModelCostRatesSchema = {
132
- input: Type.Number(),
133
- output: Type.Number(),
134
- cacheRead: Type.Number(),
135
- cacheWrite: Type.Number(),
136
- };
137
- const ModelCostTierSchema = Type.Object({
138
- inputTokensAbove: Type.Number(),
139
- ...ModelCostRatesSchema,
140
- });
141
- const ModelCostSchema = Type.Object({
142
- ...ModelCostRatesSchema,
143
- tiers: Type.Optional(Type.Array(ModelCostTierSchema)),
144
- });
145
- // Schema for custom model definition
146
- // Most fields are optional with sensible defaults for local models (Ollama, LM Studio, etc.)
147
- const ExtraBodySchema = Type.Record(Type.String(), Type.Unknown());
148
- const ServiceTierSchema = Type.Union([Type.Literal("auto"), Type.Literal("flex"), Type.Literal("priority")]);
149
- const CacheRetentionSchema = Type.Union([Type.Literal("none"), Type.Literal("short"), Type.Literal("long")]);
150
- const ModelDefinitionSchema = Type.Object({
151
- id: Type.String({ minLength: 1 }),
152
- name: Type.Optional(Type.String({ minLength: 1 })),
153
- upstreamModelId: Type.Optional(Type.String({ minLength: 1 })),
154
- serviceTier: Type.Optional(ServiceTierSchema),
155
- promptPreset: Type.Optional(Type.String({ minLength: 1 })),
156
- api: Type.Optional(Type.String({ minLength: 1 })),
157
- baseUrl: Type.Optional(Type.String({ minLength: 1 })),
158
- reasoning: Type.Optional(Type.Boolean()),
159
- thinkingLevelMap: Type.Optional(ThinkingLevelMapSchema),
160
- input: Type.Optional(Type.Array(Type.Union([Type.Literal("text"), Type.Literal("image"), Type.Literal("video")]))),
161
- cost: Type.Optional(ModelCostSchema),
162
- contextWindow: Type.Optional(Type.Number()),
163
- maxTokens: Type.Optional(Type.Number()),
164
- headers: Type.Optional(Type.Record(Type.String(), Type.String())),
165
- extraBody: Type.Optional(ExtraBodySchema),
166
- cacheRetention: Type.Optional(CacheRetentionSchema),
167
- compat: Type.Optional(ProviderCompatSchema),
168
- });
169
- // Schema for per-model overrides (all fields optional, merged with built-in model)
170
- const ModelOverrideSchema = Type.Object({
171
- name: Type.Optional(Type.String({ minLength: 1 })),
172
- promptPreset: Type.Optional(Type.String({ minLength: 1 })),
173
- reasoning: Type.Optional(Type.Boolean()),
174
- thinkingLevelMap: Type.Optional(ThinkingLevelMapSchema),
175
- thinkingLevelMapMode: Type.Optional(Type.Union([Type.Literal("merge"), Type.Literal("replace")])),
176
- input: Type.Optional(Type.Array(Type.Union([Type.Literal("text"), Type.Literal("image"), Type.Literal("video")]))),
177
- cost: Type.Optional(Type.Object({
178
- input: Type.Optional(Type.Number()),
179
- output: Type.Optional(Type.Number()),
180
- cacheRead: Type.Optional(Type.Number()),
181
- cacheWrite: Type.Optional(Type.Number()),
182
- tiers: Type.Optional(Type.Array(ModelCostTierSchema)),
183
- })),
184
- contextWindow: Type.Optional(Type.Number()),
185
- maxTokens: Type.Optional(Type.Number()),
186
- headers: Type.Optional(Type.Record(Type.String(), Type.String())),
187
- extraBody: Type.Optional(ExtraBodySchema),
188
- cacheRetention: Type.Optional(CacheRetentionSchema),
189
- compat: Type.Optional(ProviderCompatSchema),
190
- });
191
- const ProviderConfigSchema = Type.Object({
192
- name: Type.Optional(Type.String({ minLength: 1 })),
193
- disabled: Type.Optional(Type.Boolean()),
194
- baseUrl: Type.Optional(Type.String({ minLength: 1 })),
195
- apiKey: Type.Optional(Type.String({ minLength: 1 })),
196
- api: Type.Optional(Type.String({ minLength: 1 })),
197
- headers: Type.Optional(Type.Record(Type.String(), Type.String())),
198
- extraBody: Type.Optional(ExtraBodySchema),
199
- cacheRetention: Type.Optional(CacheRetentionSchema),
200
- compat: Type.Optional(ProviderCompatSchema),
201
- authHeader: Type.Optional(Type.Boolean()),
202
- whitelist: Type.Optional(Type.Array(Type.String({ minLength: 1 }))),
203
- blacklist: Type.Optional(Type.Array(Type.String({ minLength: 1 }))),
204
- models: Type.Optional(Type.Array(ModelDefinitionSchema)),
205
- modelOverrides: Type.Optional(Type.Record(Type.String(), ModelOverrideSchema)),
206
- });
207
- const ModelsConfigSchema = Type.Object({
208
- disabledProviders: Type.Optional(Type.Array(Type.String({ minLength: 1 }))),
209
- providers: Type.Record(Type.String(), ProviderConfigSchema),
210
- });
211
- const validateModelsConfig = Compile(ModelsConfigSchema);
212
- function formatValidationPath(error) {
213
- if (error.keyword === "required") {
214
- const requiredProperties = error.params.requiredProperties;
215
- const requiredProperty = requiredProperties?.[0];
216
- if (requiredProperty) {
217
- const basePath = error.instancePath.replace(/^\//, "").replace(/\//g, ".");
218
- return basePath ? `${basePath}.${requiredProperty}` : requiredProperty;
219
- }
220
- }
221
- const path = error.instancePath.replace(/^\//, "").replace(/\//g, ".");
222
- return path || "root";
223
- }
224
- function emptyCustomModelsResult(error) {
225
- return {
226
- models: [],
227
- overrides: new Map(),
228
- modelOverrides: new Map(),
229
- disabledProviders: new Set(),
230
- modelWhitelists: new Map(),
231
- modelBlacklists: new Map(),
232
- error,
233
- };
234
- }
235
- function mergeCompat(baseCompat, overrideCompat) {
236
- if (!overrideCompat)
237
- return baseCompat;
238
- const base = baseCompat;
239
- const override = overrideCompat;
240
- const merged = { ...base, ...override };
241
- const baseCompletions = base;
242
- const overrideCompletions = override;
243
- const mergedCompletions = merged;
244
- if (baseCompletions?.openRouterRouting || overrideCompletions.openRouterRouting) {
245
- mergedCompletions.openRouterRouting = {
246
- ...baseCompletions?.openRouterRouting,
247
- ...overrideCompletions.openRouterRouting,
248
- };
249
- }
250
- if (baseCompletions?.vercelGatewayRouting || overrideCompletions.vercelGatewayRouting) {
251
- mergedCompletions.vercelGatewayRouting = {
252
- ...baseCompletions?.vercelGatewayRouting,
253
- ...overrideCompletions.vercelGatewayRouting,
254
- };
255
- }
256
- if (baseCompletions?.chatTemplateKwargs || overrideCompletions.chatTemplateKwargs) {
257
- mergedCompletions.chatTemplateKwargs = {
258
- ...baseCompletions?.chatTemplateKwargs,
259
- ...overrideCompletions.chatTemplateKwargs,
260
- };
261
- }
262
- return merged;
263
- }
264
- /**
265
- * Deep merge a model override into a model.
266
- * Handles nested objects (cost, compat) by merging rather than replacing.
267
- */
268
- function applyModelOverride(model, override) {
269
- const modelWithConfigMetadata = model;
270
- const result = { ...modelWithConfigMetadata };
271
- // Simple field overrides
272
- if (override.name !== undefined)
273
- result.name = override.name;
274
- if (override.promptPreset !== undefined)
275
- result.promptPreset = override.promptPreset;
276
- if (override.reasoning !== undefined)
277
- result.reasoning = override.reasoning;
278
- if (override.thinkingLevelMap !== undefined) {
279
- result.thinkingLevelMap =
280
- override.thinkingLevelMapMode === "replace"
281
- ? { ...override.thinkingLevelMap }
282
- : { ...modelWithConfigMetadata.thinkingLevelMap, ...override.thinkingLevelMap };
283
- }
284
- if (override.input !== undefined)
285
- result.input = override.input;
286
- if (override.contextWindow !== undefined)
287
- result.contextWindow = override.contextWindow;
288
- if (override.maxTokens !== undefined)
289
- result.maxTokens = override.maxTokens;
290
- if (override.cacheRetention !== undefined)
291
- result.cacheRetention = override.cacheRetention;
292
- // Merge cost (partial override)
293
- if (override.cost) {
294
- result.cost = {
295
- input: override.cost.input ?? model.cost.input,
296
- output: override.cost.output ?? model.cost.output,
297
- cacheRead: override.cost.cacheRead ?? model.cost.cacheRead,
298
- cacheWrite: override.cost.cacheWrite ?? model.cost.cacheWrite,
299
- tiers: override.cost.tiers ?? model.cost.tiers,
300
- };
301
- }
302
- // Deep merge compat
303
- result.compat = mergeCompat(model.compat, override.compat);
304
- return result;
305
- }
6
+ export { clearApiKeyCache } from "./provider-composer.js";
306
7
  /**
307
- * Model registry - loads and manages models, resolves API keys via AuthStorage.
8
+ * Synchronous compatibility facade exposed to extensions.
9
+ * Coding-agent internals use ModelRuntime directly.
308
10
  */
309
11
  export class ModelRegistry {
310
- constructor(authStorage, modelsJsonPath) {
311
- this.models = [];
312
- this.providerRequestConfigs = new Map();
313
- this.modelRequestHeaders = new Map();
314
- this.modelRequestExtraBody = new Map();
315
- this.modelRequestUpstreamIds = new Map();
316
- this.modelRequestServiceTiers = new Map();
317
- this.configModelOverrides = new Map();
318
- this.registeredProviders = new Map();
319
- this.loadError = undefined;
12
+ constructor(runtime, authStorage = AuthStorage.inMemory()) {
13
+ this.runtime = runtime;
320
14
  this.authStorage = authStorage;
321
- this.modelsJsonPath = modelsJsonPath ? normalizePath(modelsJsonPath) : undefined;
322
- this.loadModels();
323
15
  }
324
16
  static create(authStorage, modelsJsonPath = join(getAgentDir(), "models.json")) {
325
- return new ModelRegistry(authStorage, modelsJsonPath);
17
+ return new ModelRegistry(DefaultModelRuntime.createSync({ credentials: authStorage, modelsPath: modelsJsonPath }), authStorage);
326
18
  }
327
19
  static inMemory(authStorage) {
328
- return new ModelRegistry(authStorage, undefined);
20
+ return new ModelRegistry(DefaultModelRuntime.createSync({ credentials: authStorage, modelsPath: null }), authStorage);
21
+ }
22
+ get modelRuntime() {
23
+ return this.runtime;
329
24
  }
330
- /**
331
- * Reload models from disk (built-in + custom from models.json).
332
- */
25
+ /** Reload models.json asynchronously. Await before making synchronous registry reads. */
333
26
  refresh() {
334
- this.providerRequestConfigs.clear();
335
- this.modelRequestHeaders.clear();
336
- this.modelRequestExtraBody.clear();
337
- this.modelRequestUpstreamIds.clear();
338
- this.modelRequestServiceTiers.clear();
339
- this.loadError = undefined;
340
- // Ensure dynamic API/OAuth registrations are rebuilt from current provider state.
341
- resetApiProviders();
342
- resetOAuthProviders();
343
- this.loadModels();
344
- for (const [providerName, config] of this.registeredProviders.entries()) {
345
- this.applyProviderConfig(providerName, config);
346
- }
27
+ return this.runtime.reloadConfig();
347
28
  }
348
- /**
349
- * Get any error from loading models.json (undefined if no error).
350
- */
351
29
  getError() {
352
- return this.loadError;
30
+ return this.runtime.getError();
353
31
  }
354
- loadModels() {
355
- // Load custom models and overrides from models.json
356
- const { models: customModels, overrides, modelOverrides, disabledProviders, modelWhitelists, modelBlacklists, error, } = this.modelsJsonPath ? this.loadCustomModels(this.modelsJsonPath) : emptyCustomModelsResult();
357
- this.configModelOverrides = modelOverrides;
358
- if (error) {
359
- this.loadError = error;
360
- // Keep built-in models even if custom models failed to load
361
- }
362
- const builtInModels = this.loadBuiltInModels(overrides, modelOverrides, disabledProviders, modelWhitelists, modelBlacklists);
363
- let combined = this.mergeCustomModels(builtInModels, customModels);
364
- // Let OAuth providers modify their models (e.g., update baseUrl)
365
- for (const oauthProvider of this.authStorage.getOAuthProviders()) {
366
- const cred = this.authStorage.get(oauthProvider.id);
367
- if (cred?.type === "oauth" && oauthProvider.modifyModels) {
368
- combined = oauthProvider.modifyModels(combined, cred);
369
- }
370
- }
371
- this.models = combined;
32
+ getAll() {
33
+ return [...this.runtime.getModels()];
372
34
  }
373
- /** Load built-in models and apply provider/model overrides */
374
- loadBuiltInModels(overrides, modelOverrides, disabledProviders, modelWhitelists, modelBlacklists) {
375
- return getProviders().flatMap((provider) => {
376
- if (disabledProviders.has(provider)) {
35
+ getAvailable() {
36
+ if (this.runtime.hasAvailabilitySnapshot()) {
37
+ return [...this.runtime.getAvailableSnapshot()];
38
+ }
39
+ return this.runtime.getProviders().flatMap((provider) => {
40
+ if (!this.authStorage.hasAuth(provider.id) && !this.runtime.getProviderAuthStatus(provider.id).configured) {
377
41
  return [];
378
42
  }
379
- const models = getModels(provider);
380
- const providerOverride = overrides.get(provider);
381
- const perModelOverrides = modelOverrides.get(provider);
382
- const whitelist = modelWhitelists.get(provider);
383
- const blacklist = modelBlacklists.get(provider);
384
- return models.flatMap((m) => {
385
- if (whitelist && !whitelist.has(m.id))
386
- return [];
387
- if (blacklist?.has(m.id))
388
- return [];
389
- let model = m;
390
- // Apply provider-level baseUrl/headers/compat override
391
- if (providerOverride) {
392
- model = {
393
- ...model,
394
- baseUrl: providerOverride.baseUrl ?? model.baseUrl,
395
- compat: mergeCompat(model.compat, providerOverride.compat),
396
- cacheRetention: model.cacheRetention ?? providerOverride.cacheRetention,
397
- };
398
- }
399
- // Apply per-model override
400
- const modelOverride = perModelOverrides?.get(m.id);
401
- if (modelOverride) {
402
- model = applyModelOverride(model, modelOverride);
403
- }
404
- return [model];
405
- });
43
+ const models = this.runtime.getModels(provider.id);
44
+ return [...(provider.filterModels?.(models, this.authStorage.get(provider.id)) ?? models)];
406
45
  });
407
46
  }
408
- getConfiguredModelOverride(providerName, modelId) {
409
- return this.configModelOverrides.get(providerName)?.get(modelId);
410
- }
411
- applyConfiguredModelOverride(providerName, model) {
412
- const modelOverride = this.getConfiguredModelOverride(providerName, model.id);
413
- return modelOverride ? applyModelOverride(model, modelOverride) : model;
414
- }
415
- /** Merge custom models into built-in list by provider+id (custom wins on conflicts). */
416
- mergeCustomModels(builtInModels, customModels) {
417
- const merged = [...builtInModels];
418
- for (const customModel of customModels) {
419
- const existingIndex = merged.findIndex((m) => m.provider === customModel.provider && m.id === customModel.id);
420
- if (existingIndex >= 0) {
421
- merged[existingIndex] = customModel;
422
- }
423
- else {
424
- merged.push(customModel);
425
- }
426
- }
427
- return merged;
428
- }
429
- loadCustomModels(modelsJsonPath) {
430
- if (!existsSync(modelsJsonPath)) {
431
- return emptyCustomModelsResult();
432
- }
433
- try {
434
- const content = readFileSync(modelsJsonPath, "utf-8");
435
- const parsed = JSON.parse(stripJsonComments(content));
436
- if (!validateModelsConfig.Check(parsed)) {
437
- const errors = validateModelsConfig
438
- .Errors(parsed)
439
- .map((error) => ` - ${formatValidationPath(error)}: ${error.message}`)
440
- .join("\n") || "Unknown schema error";
441
- return emptyCustomModelsResult(`Invalid models.json schema:\n${errors}\n\nFile: ${modelsJsonPath}`);
442
- }
443
- const config = parsed;
444
- // Additional validation
445
- this.validateConfig(config);
446
- const overrides = new Map();
447
- const modelOverrides = new Map();
448
- const disabledProviders = new Set(config.disabledProviders ?? []);
449
- const modelWhitelists = new Map();
450
- const modelBlacklists = new Map();
451
- for (const [providerName, providerConfig] of Object.entries(config.providers)) {
452
- if (providerConfig.disabled) {
453
- disabledProviders.add(providerName);
454
- }
455
- if (providerConfig.whitelist) {
456
- modelWhitelists.set(providerName, new Set(providerConfig.whitelist));
457
- }
458
- if (providerConfig.blacklist) {
459
- modelBlacklists.set(providerName, new Set(providerConfig.blacklist));
460
- }
461
- if (providerConfig.baseUrl || providerConfig.compat || providerConfig.cacheRetention) {
462
- overrides.set(providerName, {
463
- baseUrl: providerConfig.baseUrl,
464
- compat: providerConfig.compat,
465
- cacheRetention: providerConfig.cacheRetention,
466
- });
467
- }
468
- this.storeProviderRequestConfig(providerName, providerConfig);
469
- if (providerConfig.modelOverrides) {
470
- modelOverrides.set(providerName, new Map(Object.entries(providerConfig.modelOverrides)));
471
- for (const [modelId, modelOverride] of Object.entries(providerConfig.modelOverrides)) {
472
- this.storeModelHeaders(providerName, modelId, modelOverride.headers);
473
- this.storeModelExtraBody(providerName, modelId, modelOverride.extraBody);
474
- }
475
- }
476
- }
477
- return {
478
- models: this.parseModels(config, disabledProviders, modelWhitelists, modelBlacklists),
479
- overrides,
480
- modelOverrides,
481
- disabledProviders,
482
- modelWhitelists,
483
- modelBlacklists,
484
- error: undefined,
485
- };
486
- }
487
- catch (error) {
488
- if (error instanceof SyntaxError) {
489
- return emptyCustomModelsResult(`Failed to parse models.json: ${error.message}\n\nFile: ${modelsJsonPath}`);
490
- }
491
- return emptyCustomModelsResult(`Failed to load models.json: ${error instanceof Error ? error.message : error}\n\nFile: ${modelsJsonPath}`);
492
- }
493
- }
494
- validateConfig(config) {
495
- const builtInProviders = new Set(getProviders());
496
- for (const [providerName, providerConfig] of Object.entries(config.providers)) {
497
- if (providerConfig.disabled)
498
- continue;
499
- const isBuiltIn = builtInProviders.has(providerName);
500
- const hasProviderApi = !!providerConfig.api;
501
- const models = providerConfig.models ?? [];
502
- const hasModelOverrides = providerConfig.modelOverrides && Object.keys(providerConfig.modelOverrides).length > 0;
503
- if (models.length === 0) {
504
- // Override-only config: needs baseUrl, headers, compat, modelOverrides, extraBody, or some combination.
505
- if (!providerConfig.baseUrl &&
506
- !providerConfig.headers &&
507
- !providerConfig.compat &&
508
- !providerConfig.cacheRetention &&
509
- !hasModelOverrides &&
510
- !providerConfig.extraBody &&
511
- !providerConfig.whitelist &&
512
- !providerConfig.blacklist) {
513
- throw new Error(`Provider ${providerName}: must specify "baseUrl", "headers", "compat", "cacheRetention", "modelOverrides", "extraBody", or "models".`);
514
- }
515
- }
516
- else if (!isBuiltIn) {
517
- // Non-built-in providers with custom models require an endpoint.
518
- // Auth can come from auth.json, --api-key, or provider request config.
519
- if (!providerConfig.baseUrl) {
520
- throw new Error(`Provider ${providerName}: "baseUrl" is required when defining custom models.`);
521
- }
522
- }
523
- // Built-in providers with custom models: baseUrl/apiKey/api are optional,
524
- // inherited from built-in models. Auth comes from env vars / auth storage.
525
- for (const modelDef of models) {
526
- const hasModelApi = !!modelDef.api;
527
- if (!hasProviderApi && !hasModelApi && !isBuiltIn) {
528
- throw new Error(`Provider ${providerName}, model ${modelDef.id}: no "api" specified. Set at provider or model level.`);
529
- }
530
- // For built-in providers, api is optional — inherited from built-in models.
531
- if (!modelDef.id)
532
- throw new Error(`Provider ${providerName}: model missing "id"`);
533
- // Validate contextWindow/maxTokens only if provided (they have defaults)
534
- if (modelDef.contextWindow !== undefined && modelDef.contextWindow <= 0)
535
- throw new Error(`Provider ${providerName}, model ${modelDef.id}: invalid contextWindow`);
536
- if (modelDef.maxTokens !== undefined && modelDef.maxTokens <= 0)
537
- throw new Error(`Provider ${providerName}, model ${modelDef.id}: invalid maxTokens`);
538
- }
539
- }
540
- }
541
- parseModels(config, disabledProviders, modelWhitelists, modelBlacklists) {
542
- const models = [];
543
- const builtInProviders = new Set(getProviders());
544
- // Cache built-in defaults (api, baseUrl) per provider, extracted from first model.
545
- const builtInDefaultsCache = new Map();
546
- const getBuiltInDefaults = (providerName) => {
547
- if (!builtInProviders.has(providerName))
548
- return undefined;
549
- if (builtInDefaultsCache.has(providerName))
550
- return builtInDefaultsCache.get(providerName);
551
- const builtIn = getModels(providerName);
552
- if (builtIn.length === 0)
553
- return undefined;
554
- const defaults = { api: builtIn[0].api, baseUrl: builtIn[0].baseUrl };
555
- builtInDefaultsCache.set(providerName, defaults);
556
- return defaults;
557
- };
558
- for (const [providerName, providerConfig] of Object.entries(config.providers)) {
559
- if (disabledProviders.has(providerName))
560
- continue;
561
- const modelDefs = providerConfig.models ?? [];
562
- if (modelDefs.length === 0)
563
- continue; // Override-only, no custom models
564
- const builtInDefaults = getBuiltInDefaults(providerName);
565
- const whitelist = modelWhitelists.get(providerName);
566
- const blacklist = modelBlacklists.get(providerName);
567
- for (const modelDef of modelDefs) {
568
- if (whitelist && !whitelist.has(modelDef.id))
569
- continue;
570
- if (blacklist?.has(modelDef.id))
571
- continue;
572
- const api = modelDef.api ?? providerConfig.api ?? builtInDefaults?.api;
573
- if (!api)
574
- continue;
575
- const baseUrl = modelDef.baseUrl ?? providerConfig.baseUrl ?? builtInDefaults?.baseUrl;
576
- if (!baseUrl)
577
- continue;
578
- const compat = mergeCompat(providerConfig.compat, modelDef.compat);
579
- this.storeModelHeaders(providerName, modelDef.id, modelDef.headers);
580
- this.storeModelExtraBody(providerName, modelDef.id, modelDef.extraBody);
581
- this.storeModelUpstreamId(providerName, modelDef.id, modelDef.upstreamModelId);
582
- this.storeModelServiceTier(providerName, modelDef.id, modelDef.serviceTier);
583
- const defaultCost = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
584
- models.push({
585
- id: modelDef.id,
586
- name: modelDef.name ?? modelDef.id,
587
- promptPreset: modelDef.promptPreset,
588
- api: api,
589
- provider: providerName,
590
- baseUrl,
591
- reasoning: modelDef.reasoning ?? false,
592
- cacheRetention: modelDef.cacheRetention ?? providerConfig.cacheRetention,
593
- thinkingLevelMap: modelDef.thinkingLevelMap,
594
- input: (modelDef.input ?? ["text"]),
595
- cost: modelDef.cost ?? defaultCost,
596
- contextWindow: modelDef.contextWindow ?? 128000,
597
- maxTokens: modelDef.maxTokens ?? 16384,
598
- headers: undefined,
599
- compat,
600
- });
601
- }
602
- }
603
- return models;
604
- }
605
- /**
606
- * Get all models (built-in + custom).
607
- * If models.json had errors, returns only built-in models.
608
- */
609
- getAll() {
610
- return this.models;
611
- }
612
- /**
613
- * Get only models that have auth configured.
614
- * This is a fast check that doesn't refresh OAuth tokens.
615
- */
616
- getAvailable() {
617
- return this.models.filter((m) => this.hasConfiguredAuth(m));
618
- }
619
- /**
620
- * Find a model by provider and ID.
621
- */
622
47
  find(provider, modelId) {
623
- return this.models.find((m) => m.provider === provider && m.id === modelId);
624
- }
625
- getUpstreamModelId(model) {
626
- return this.modelRequestUpstreamIds.get(this.getModelRequestKey(model.provider, model.id));
48
+ return this.runtime.getModel(provider, modelId);
627
49
  }
628
- /**
629
- * Get API key for a model.
630
- */
631
50
  hasConfiguredAuth(model) {
632
- const providerApiKey = this.providerRequestConfigs.get(model.provider)?.apiKey;
633
- return (this.authStorage.hasAuth(model.provider) ||
634
- (providerApiKey !== undefined && isConfigValueConfigured(providerApiKey)));
51
+ return this.authStorage.hasAuth(model.provider) || this.runtime.getProviderAuthStatus(model.provider).configured;
635
52
  }
636
- getModelRequestKey(provider, modelId) {
637
- return `${provider}:${modelId}`;
638
- }
639
- storeProviderRequestConfig(providerName, config, preservedApiKey) {
640
- const apiKey = config.apiKey ?? preservedApiKey;
641
- if (!apiKey && !config.headers && !config.extraBody && config.authHeader !== true) {
642
- this.providerRequestConfigs.delete(providerName);
643
- return;
644
- }
645
- this.providerRequestConfigs.set(providerName, {
646
- apiKey,
647
- headers: config.headers,
648
- extraBody: config.extraBody,
649
- authHeader: config.authHeader,
650
- });
651
- }
652
- storeModelHeaders(providerName, modelId, headers) {
653
- const key = this.getModelRequestKey(providerName, modelId);
654
- if (!headers || Object.keys(headers).length === 0) {
655
- this.modelRequestHeaders.delete(key);
656
- return;
657
- }
658
- this.modelRequestHeaders.set(key, headers);
659
- }
660
- storeModelExtraBody(providerName, modelId, extraBody) {
661
- const key = this.getModelRequestKey(providerName, modelId);
662
- if (!extraBody || Object.keys(extraBody).length === 0) {
663
- this.modelRequestExtraBody.delete(key);
664
- return;
665
- }
666
- this.modelRequestExtraBody.set(key, extraBody);
667
- }
668
- storeModelUpstreamId(providerName, modelId, upstreamModelId) {
669
- const key = this.getModelRequestKey(providerName, modelId);
670
- if (!upstreamModelId) {
671
- this.modelRequestUpstreamIds.delete(key);
672
- return;
673
- }
674
- this.modelRequestUpstreamIds.set(key, upstreamModelId);
675
- }
676
- storeModelServiceTier(providerName, modelId, serviceTier) {
677
- const key = this.getModelRequestKey(providerName, modelId);
678
- if (!serviceTier) {
679
- this.modelRequestServiceTiers.delete(key);
680
- return;
681
- }
682
- this.modelRequestServiceTiers.set(key, serviceTier);
683
- }
684
- clearModelRequestConfigForProvider(providerName) {
685
- const prefix = `${providerName}:`;
686
- for (const key of this.modelRequestHeaders.keys()) {
687
- if (key.startsWith(prefix)) {
688
- this.modelRequestHeaders.delete(key);
689
- }
690
- }
691
- for (const key of this.modelRequestExtraBody.keys()) {
692
- if (key.startsWith(prefix)) {
693
- this.modelRequestExtraBody.delete(key);
694
- }
695
- }
696
- for (const key of this.modelRequestUpstreamIds.keys()) {
697
- if (key.startsWith(prefix)) {
698
- this.modelRequestUpstreamIds.delete(key);
699
- }
700
- }
701
- for (const key of this.modelRequestServiceTiers.keys()) {
702
- if (key.startsWith(prefix)) {
703
- this.modelRequestServiceTiers.delete(key);
704
- }
705
- }
53
+ getUpstreamModelId(model) {
54
+ return this.runtime.getCompatibilityRequestConfig(model).upstreamModelId;
706
55
  }
707
- /**
708
- * Get API key and request headers for a model.
709
- */
710
56
  async getApiKeyAndHeaders(model) {
711
57
  try {
712
- const providerConfig = this.providerRequestConfigs.get(model.provider);
713
- const providerEnv = this.authStorage.getProviderEnv(model.provider);
714
- const apiKeyFromAuthStorage = await this.authStorage.getApiKey(model.provider, { includeFallback: false });
715
- const apiKey = apiKeyFromAuthStorage ??
716
- (providerConfig?.apiKey
717
- ? resolveConfigValueOrThrow(providerConfig.apiKey, `API key for provider "${model.provider}"`, providerEnv)
718
- : undefined);
719
- const modelRequestKey = this.getModelRequestKey(model.provider, model.id);
720
- const providerHeaders = resolveHeadersOrThrow(providerConfig?.headers, `provider "${model.provider}"`, providerEnv);
721
- const modelHeaders = resolveHeadersOrThrow(this.modelRequestHeaders.get(modelRequestKey), `model "${model.provider}/${model.id}"`, providerEnv);
722
- let headers = model.headers || providerHeaders || modelHeaders
723
- ? { ...model.headers, ...providerHeaders, ...modelHeaders }
724
- : undefined;
725
- if (providerConfig?.authHeader) {
726
- if (!apiKey) {
58
+ const resolution = await this.runtime.getAuth(model);
59
+ const compatibility = this.runtime.getCompatibilityRequestConfig(model, resolution?.env);
60
+ if (!resolution) {
61
+ if (compatibility.authHeader) {
727
62
  return { ok: false, error: `No API key found for "${model.provider}"` };
728
63
  }
729
- headers = { ...headers, Authorization: `Bearer ${apiKey}` };
730
- }
731
- const providerExtraBody = providerConfig?.extraBody;
732
- const modelExtraBody = this.modelRequestExtraBody.get(modelRequestKey);
733
- const extraBody = providerExtraBody || modelExtraBody ? { ...providerExtraBody, ...modelExtraBody } : undefined;
734
- const upstreamModelId = this.modelRequestUpstreamIds.get(modelRequestKey);
735
- const serviceTier = this.modelRequestServiceTiers.get(modelRequestKey);
736
- const resolved = { ok: true };
737
- if (apiKey !== undefined) {
738
- resolved.apiKey = apiKey;
739
- }
740
- if (headers && Object.keys(headers).length > 0) {
741
- resolved.headers = headers;
742
- }
743
- if (extraBody && Object.keys(extraBody).length > 0) {
744
- resolved.extraBody = extraBody;
745
- }
746
- if (upstreamModelId !== undefined) {
747
- resolved.upstreamModelId = upstreamModelId;
748
- }
749
- if (serviceTier !== undefined) {
750
- resolved.serviceTier = serviceTier;
751
- }
752
- if (providerEnv && Object.keys(providerEnv).length > 0) {
753
- resolved.env = providerEnv;
64
+ const headers = compatibility.headers
65
+ ? Object.fromEntries(Object.entries(compatibility.headers).filter((entry) => entry[1] !== null))
66
+ : undefined;
67
+ return { ok: true, headers, extraBody: compatibility.extraBody };
754
68
  }
755
- return resolved;
69
+ const headers = resolution.auth.headers
70
+ ? Object.fromEntries(Object.entries(resolution.auth.headers).filter((entry) => entry[1] !== null))
71
+ : undefined;
72
+ return {
73
+ ok: true,
74
+ apiKey: resolution.auth.apiKey,
75
+ headers,
76
+ extraBody: compatibility.extraBody,
77
+ upstreamModelId: compatibility.upstreamModelId,
78
+ serviceTier: compatibility.serviceTier,
79
+ env: resolution.env,
80
+ };
756
81
  }
757
82
  catch (error) {
83
+ const cause = error instanceof Error ? error.cause : undefined;
84
+ const message = cause instanceof Error ? cause.message : error instanceof Error ? error.message : String(error);
758
85
  return {
759
86
  ok: false,
760
- error: error instanceof Error ? error.message : String(error),
87
+ error: message === "authHeader requires a resolved API key"
88
+ ? `No API key found for "${model.provider}"`
89
+ : message,
761
90
  };
762
91
  }
763
92
  }
764
- /**
765
- * Return auth status for a provider, including request auth configured in models.json.
766
- * This intentionally does not execute command-backed config values.
767
- */
768
93
  getProviderAuthStatus(provider) {
769
- const authStatus = this.authStorage.getAuthStatus(provider);
770
- if (authStatus.source) {
771
- return authStatus;
772
- }
773
- const providerApiKey = this.providerRequestConfigs.get(provider)?.apiKey;
774
- if (!providerApiKey) {
775
- return authStatus;
776
- }
777
- if (isCommandConfigValue(providerApiKey)) {
778
- return { configured: true, source: "models_json_command" };
779
- }
780
- const envVarNames = getConfigValueEnvVarNames(providerApiKey);
781
- if (envVarNames.length > 0) {
782
- return isConfigValueConfigured(providerApiKey)
783
- ? { configured: true, source: "environment", label: envVarNames.join(", ") }
784
- : { configured: false };
785
- }
786
- return { configured: true, source: "models_json_key" };
94
+ return this.runtime.getProviderAuthStatus(provider);
787
95
  }
788
- /**
789
- * Get display name for a provider.
790
- */
791
96
  getProviderDisplayName(provider) {
792
- const registeredProvider = this.registeredProviders.get(provider);
793
- const oauthProvider = this.authStorage.getOAuthProviders().find((p) => p.id === provider);
794
- return (registeredProvider?.name ??
795
- registeredProvider?.oauth?.name ??
796
- oauthProvider?.name ??
797
- BUILT_IN_PROVIDER_DISPLAY_NAMES[provider] ??
798
- provider);
97
+ return this.runtime.getProvider(provider)?.name ?? BUILT_IN_PROVIDER_DISPLAY_NAMES[provider] ?? provider;
799
98
  }
800
- /**
801
- * Get API key for a provider.
802
- */
803
99
  async getApiKeyForProvider(provider) {
804
- const apiKey = await this.authStorage.getApiKey(provider);
805
- if (apiKey !== undefined) {
806
- return apiKey;
100
+ try {
101
+ return (await this.runtime.getAuth(provider))?.auth.apiKey;
102
+ }
103
+ catch {
104
+ return undefined;
807
105
  }
808
- const providerApiKey = this.providerRequestConfigs.get(provider)?.apiKey;
809
- return providerApiKey
810
- ? resolveConfigValueUncached(providerApiKey, this.authStorage.getProviderEnv(provider))
811
- : undefined;
812
106
  }
813
- /**
814
- * Check if a model is using OAuth credentials (subscription).
815
- */
816
107
  isUsingOAuth(model) {
817
- const cred = this.authStorage.get(model.provider);
818
- return cred?.type === "oauth";
108
+ return this.authStorage.get(model.provider)?.type === "oauth" || this.runtime.isUsingOAuth(model.provider);
819
109
  }
820
- /**
821
- * Register a provider dynamically (from extensions).
822
- *
823
- * If provider has models: replaces all existing models for this provider.
824
- * If provider has only baseUrl/headers: overrides existing models' URLs.
825
- * If provider has oauth: registers OAuth provider for /login support.
826
- */
827
110
  registerProvider(providerName, config) {
828
- this.validateProviderConfig(providerName, config);
829
- this.applyProviderConfig(providerName, config);
830
- this.upsertRegisteredProvider(providerName, config);
111
+ this.runtime.registerProvider(providerName, config);
831
112
  }
832
- /**
833
- * Unregister a previously registered provider.
834
- *
835
- * Removes the provider from the registry and reloads models from disk so that
836
- * built-in models overridden by this provider are restored to their original state.
837
- * Also resets dynamic OAuth and API stream registrations before reapplying
838
- * remaining dynamic providers.
839
- * Has no effect if the provider was never registered.
840
- */
841
113
  unregisterProvider(providerName) {
842
- if (!this.registeredProviders.has(providerName))
843
- return;
844
- this.registeredProviders.delete(providerName);
845
- this.refresh();
846
- }
847
- /**
848
- * Upsert a provider config into registeredProviders.
849
- * If the provider is already registered, defined values in the incoming config
850
- * override existing ones; undefined values are preserved from the stored config.
851
- * If the provider is not registered, the incoming config is stored as-is.
852
- */
853
- upsertRegisteredProvider(providerName, config) {
854
- const existing = this.registeredProviders.get(providerName);
855
- if (!existing) {
856
- this.registeredProviders.set(providerName, config);
857
- return;
858
- }
859
- const next = { ...existing };
860
- if (config.name !== undefined)
861
- next.name = config.name;
862
- if (config.baseUrl !== undefined)
863
- next.baseUrl = config.baseUrl;
864
- if (config.apiKey !== undefined)
865
- next.apiKey = config.apiKey;
866
- if (config.api !== undefined)
867
- next.api = config.api;
868
- if (config.streamSimple !== undefined)
869
- next.streamSimple = config.streamSimple;
870
- if (config.oauth !== undefined)
871
- next.oauth = config.oauth;
872
- if (config.models !== undefined)
873
- next.models = config.models;
874
- if (config.headers !== undefined) {
875
- next.headers = config.headers;
876
- }
877
- else {
878
- delete next.headers;
879
- }
880
- if (config.extraBody !== undefined) {
881
- next.extraBody = config.extraBody;
882
- }
883
- else {
884
- delete next.extraBody;
885
- }
886
- if (config.cacheRetention !== undefined) {
887
- next.cacheRetention = config.cacheRetention;
888
- }
889
- else {
890
- delete next.cacheRetention;
891
- }
892
- if (config.authHeader !== undefined) {
893
- next.authHeader = config.authHeader;
894
- }
895
- else {
896
- delete next.authHeader;
897
- }
898
- this.registeredProviders.set(providerName, next);
114
+ this.runtime.unregisterProvider(providerName);
899
115
  }
900
- validateProviderConfig(providerName, config) {
901
- if (config.streamSimple && !config.api) {
902
- throw new Error(`Provider ${providerName}: "api" is required when registering streamSimple.`);
903
- }
904
- if (!config.models || config.models.length === 0) {
905
- return;
906
- }
907
- if (!config.baseUrl) {
908
- throw new Error(`Provider ${providerName}: "baseUrl" is required when defining models.`);
909
- }
910
- if (!config.apiKey && !config.oauth) {
911
- throw new Error(`Provider ${providerName}: "apiKey" or "oauth" is required when defining models.`);
912
- }
913
- for (const modelDef of config.models) {
914
- const api = modelDef.api || config.api;
915
- if (!api) {
916
- throw new Error(`Provider ${providerName}, model ${modelDef.id}: no "api" specified.`);
917
- }
918
- }
116
+ getRegisteredProviderConfig(providerName) {
117
+ return this.runtime.getRegisteredProviderConfig(providerName);
919
118
  }
920
- applyProviderConfig(providerName, config) {
921
- // Register OAuth provider if provided
922
- if (config.oauth) {
923
- // Ensure the OAuth provider ID matches the provider name
924
- const oauthProvider = {
925
- ...config.oauth,
926
- id: providerName,
927
- };
928
- registerOAuthProvider(oauthProvider);
929
- }
930
- if (config.streamSimple) {
931
- const streamSimple = config.streamSimple;
932
- registerApiProvider({
933
- api: config.api,
934
- stream: (model, context, options) => streamSimple(model, context, options),
935
- streamSimple,
936
- }, `provider:${providerName}`);
937
- }
938
- this.storeProviderRequestConfig(providerName, config, this.registeredProviders.get(providerName)?.apiKey);
939
- if (config.models && config.models.length > 0) {
940
- // Full replacement: remove existing models for this provider
941
- this.models = this.models.filter((m) => m.provider !== providerName);
942
- this.clearModelRequestConfigForProvider(providerName);
943
- // Parse and add new models
944
- for (const modelDef of config.models) {
945
- const api = modelDef.api || config.api;
946
- const modelOverride = this.getConfiguredModelOverride(providerName, modelDef.id);
947
- const headers = modelDef.headers || modelOverride?.headers
948
- ? { ...modelDef.headers, ...modelOverride?.headers }
949
- : undefined;
950
- const extraBody = modelDef.extraBody || modelOverride?.extraBody
951
- ? { ...modelDef.extraBody, ...modelOverride?.extraBody }
952
- : undefined;
953
- this.storeModelHeaders(providerName, modelDef.id, headers);
954
- this.storeModelExtraBody(providerName, modelDef.id, extraBody);
955
- this.storeModelUpstreamId(providerName, modelDef.id, modelDef.upstreamModelId);
956
- this.storeModelServiceTier(providerName, modelDef.id, modelDef.serviceTier);
957
- const model = this.applyConfiguredModelOverride(providerName, {
958
- id: modelDef.id,
959
- name: modelDef.name,
960
- api: api,
961
- provider: providerName,
962
- baseUrl: modelDef.baseUrl ?? config.baseUrl,
963
- reasoning: modelDef.reasoning,
964
- cacheRetention: modelDef.cacheRetention ?? config.cacheRetention,
965
- thinkingLevelMap: modelDef.thinkingLevelMap,
966
- input: modelDef.input,
967
- cost: modelDef.cost,
968
- contextWindow: modelDef.contextWindow,
969
- maxTokens: modelDef.maxTokens,
970
- headers: undefined,
971
- compat: modelDef.compat,
972
- });
973
- this.models.push(model);
974
- }
975
- // Apply OAuth modifyModels if credentials exist (e.g., to update baseUrl)
976
- if (config.oauth?.modifyModels) {
977
- const cred = this.authStorage.get(providerName);
978
- if (cred?.type === "oauth") {
979
- this.models = config.oauth.modifyModels(this.models, cred);
980
- }
981
- }
982
- }
983
- else if (config.baseUrl || config.headers || config.extraBody || config.cacheRetention) {
984
- // Override-only: update baseUrl for existing models. Request headers and extraBody are resolved per request.
985
- this.models = this.models.map((m) => {
986
- if (m.provider !== providerName)
987
- return m;
988
- return {
989
- ...m,
990
- baseUrl: config.baseUrl ?? m.baseUrl,
991
- cacheRetention: m.cacheRetention ?? config.cacheRetention,
992
- };
993
- });
994
- }
119
+ getRegisteredProviderIds() {
120
+ return this.runtime.getRegisteredProviderIds();
995
121
  }
996
122
  }
997
123
  //# sourceMappingURL=model-registry.js.map