@xopcai/xopc 0.0.119 → 0.0.121

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 (286) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/dashscope/src/image-generation-provider.d.ts +6 -5
  3. package/dist/extensions/dashscope/src/image-generation-provider.js +40 -64
  4. package/dist/extensions/dashscope/src/image-generation-provider.js.map +1 -1
  5. package/dist/extensions/dashscope/src/index.d.ts +1 -1
  6. package/dist/extensions/dashscope/src/index.js +2 -2
  7. package/dist/extensions/dashscope/xopc.extension.json +3 -2
  8. package/dist/extensions/minimax/src/image-generation-provider.d.ts +7 -5
  9. package/dist/extensions/minimax/src/image-generation-provider.js +43 -37
  10. package/dist/extensions/minimax/src/image-generation-provider.js.map +1 -1
  11. package/dist/extensions/minimax/src/index.d.ts +1 -1
  12. package/dist/extensions/minimax/src/index.js +2 -2
  13. package/dist/extensions/minimax/xopc.extension.json +1 -1
  14. package/dist/extensions/telegram/xopc.extension.json +1 -1
  15. package/dist/gateway/static/root/assets/Combination-HAlzriaz.js +41 -0
  16. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-CU8J6zou.js → agent-avatar-dicebear-4AW4JgSU.js} +1 -1
  17. package/dist/gateway/static/root/assets/agents-2SVUUPlp.js +2 -0
  18. package/dist/gateway/static/root/assets/{app-management-settings-panel-B9vfYoEr.js → app-management-settings-panel-CE6GkGU2.js} +1 -1
  19. package/dist/gateway/static/root/assets/{appearance-settings-ClOzIO24.js → appearance-settings-BmaUjghw.js} +1 -1
  20. package/dist/gateway/static/root/assets/{apps-page-DU0dz9Zo.js → apps-page-BWeQ1I49.js} +1 -1
  21. package/dist/gateway/static/root/assets/{archive-plugin-BkVIgZzA.js → archive-plugin-CX4_KWut.js} +1 -1
  22. package/dist/gateway/static/root/assets/{attachment-load-CaCMWh1D.js → attachment-load-jf-PIIUU.js} +1 -1
  23. package/dist/gateway/static/root/assets/{automation-suggestion-card-DhGDpKP3.js → automation-suggestion-card-BHk5rtJz.js} +1 -1
  24. package/dist/gateway/static/root/assets/automations-page-QHotl53D.js +1 -0
  25. package/dist/gateway/static/root/assets/{binary-plugins-B4TO_bsn.js → binary-plugins-DG9XQikd.js} +1 -1
  26. package/dist/gateway/static/root/assets/{block-editor-DJRWwWNI.js → block-editor-Up_VIxLJ.js} +6 -6
  27. package/dist/gateway/static/root/assets/browser-settings-page-Cmwi6IIQ.js +8 -0
  28. package/dist/gateway/static/root/assets/{capability-presets-api-Befi89CL.js → capability-presets-api-CGM4OyMw.js} +1 -1
  29. package/dist/gateway/static/root/assets/{capability-presets-settings-panel-_G8eb2vJ.js → capability-presets-settings-panel-CzWt0LBb.js} +1 -1
  30. package/dist/gateway/static/root/assets/{channel-recipient-api-BNSuJb5f.js → channel-recipient-api-BEByL4_o.js} +1 -1
  31. package/dist/gateway/static/root/assets/channels-settings-BOMCUe2J.js +1 -0
  32. package/dist/gateway/static/root/assets/connectors-page-C-Dexk_F.js +2 -0
  33. package/dist/gateway/static/root/assets/dist-Mys7eFJ5.js +1 -0
  34. package/dist/gateway/static/root/assets/dist-wO9a2_ID.js +1 -0
  35. package/dist/gateway/static/root/assets/dreaming-settings-WPEj8pir.js +1 -0
  36. package/dist/gateway/static/root/assets/{extension-debug-page-DYh402XV.js → extension-debug-page-DZxa_j7-.js} +1 -1
  37. package/dist/gateway/static/root/assets/{extension-page-Cr_TizrN.js → extension-page-CseziW53.js} +1 -1
  38. package/dist/gateway/static/root/assets/extension-settings-page-B_9J-xyo.js +1 -0
  39. package/dist/gateway/static/root/assets/{fetch-Y7AEX4H3.js → fetch-Cs4ck8zA.js} +1 -1
  40. package/dist/gateway/static/root/assets/{gateway-config-api-RbMmAOpX.js → gateway-config-api-Dl223a7r.js} +1 -1
  41. package/dist/gateway/static/root/assets/gateway-settings-DdzbtW9R.js +1 -0
  42. package/dist/gateway/static/root/assets/{gateway-startup-retry-DiD_Tx4N.js → gateway-startup-retry-IvePwjFE.js} +1 -1
  43. package/dist/gateway/static/root/assets/goal-detail-page-Dxldogms.js +1 -0
  44. package/dist/gateway/static/root/assets/{goals-config-api-DqxVi0p5.js → goals-config-api-CUCP6yCl.js} +1 -1
  45. package/dist/gateway/static/root/assets/goals-page-DU5Nd6Xp.js +2 -0
  46. package/dist/gateway/static/root/assets/goals-settings-Dj87qPxv.js +1 -0
  47. package/dist/gateway/static/root/assets/heartbeat-settings-Cgm5JmwH.js +1 -0
  48. package/dist/gateway/static/root/assets/index-BU1pvxmS.js +191 -0
  49. package/dist/gateway/static/root/assets/index-l54WfSqe.css +1 -0
  50. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-Dvg53qnd.js → keyboard-shortcuts-settings-DJgYw0nB.js} +1 -1
  51. package/dist/gateway/static/root/assets/{locale-store-DjbfSsfA.js → locale-store-Ba72bFmP.js} +1 -1
  52. package/dist/gateway/static/root/assets/logs-page-C10aS4XO.js +2 -0
  53. package/dist/gateway/static/root/assets/{markdown-split-CpHxbtWJ.js → markdown-split-gnQ_EiGo.js} +1 -1
  54. package/dist/gateway/static/root/assets/{media-plugins-SFPQRSxq.js → media-plugins-CQV-mgJn.js} +1 -1
  55. package/dist/gateway/static/root/assets/messages-C6Kc4Jhf.js +3 -0
  56. package/dist/gateway/static/root/assets/models-hub-panel-B35CAfg6.js +2 -0
  57. package/dist/gateway/static/root/assets/note-detail-page-Brlwse8x.js +2 -0
  58. package/dist/gateway/static/root/assets/{note-image-lightbox-BUYURRgn.js → note-image-lightbox-BthwKjLA.js} +1 -1
  59. package/dist/gateway/static/root/assets/{notes-page-BsIBSFyZ.js → notes-page-CoAwRc7L.js} +1 -1
  60. package/dist/gateway/static/root/assets/{preview-open-alternatives-BHz9iWYA.js → preview-open-alternatives-BPMXC-2u.js} +1 -1
  61. package/dist/gateway/static/root/assets/remote-access-hub-B36RQ05h.js +1 -0
  62. package/dist/gateway/static/root/assets/{save-bar-controls-CefkOlRg.js → save-bar-controls-BEHqwZjz.js} +1 -1
  63. package/dist/gateway/static/root/assets/schedule-field-CMY25m97.js +1 -0
  64. package/dist/gateway/static/root/assets/schema-form-CxjxsFfg.js +1 -0
  65. package/dist/gateway/static/root/assets/sessions-page-73THChnj.js +1 -0
  66. package/dist/gateway/static/root/assets/settings-advanced-gate-CR9VsY-R.js +1 -0
  67. package/dist/gateway/static/root/assets/{settings-collapsible-section-BouO6JTi.js → settings-collapsible-section-s-kiLAxP.js} +1 -1
  68. package/dist/gateway/static/root/assets/settings-form-section-CIxIEYxU.js +1 -0
  69. package/dist/gateway/static/root/assets/settings-page-BJ1AhfKI.js +1 -0
  70. package/dist/gateway/static/root/assets/{settings-page-layout-BJ4Gsef5.js → settings-page-layout--6qT7ZJa.js} +1 -1
  71. package/dist/gateway/static/root/assets/{setup-status-panel-CrUjHPQo.js → setup-status-panel-C1TtS1vJ.js} +1 -1
  72. package/dist/gateway/static/root/assets/{share-preview-page-BDy2btRN.js → share-preview-page-BZADSbS1.js} +1 -1
  73. package/dist/gateway/static/root/assets/shares-settings-gqC8Rmhy.js +1 -0
  74. package/dist/gateway/static/root/assets/skill-reload-api-C9P-WYvS.js +1 -0
  75. package/dist/gateway/static/root/assets/skills-page-CEpSvOhF.js +2 -0
  76. package/dist/gateway/static/root/assets/{system-settings-panel-CRngrlnZ.js → system-settings-panel-Czjf0kLJ.js} +1 -1
  77. package/dist/gateway/static/root/assets/{theme-store-CD2wtgZV.js → theme-store-Bt6vAkSB.js} +1 -1
  78. package/dist/gateway/static/root/assets/{typed-models-lib-BltBc0b-.js → typed-models-lib-Cmt8SYdI.js} +1 -1
  79. package/dist/gateway/static/root/assets/{use-channel-catalog-CjN-51e6.js → use-channel-catalog-DyM-ckEQ.js} +1 -1
  80. package/dist/gateway/static/root/assets/user-profile-settings-panel-BygLv8vm.js +1 -0
  81. package/dist/gateway/static/root/assets/{utils-B5M5-YvK.js → utils-CloW8coB.js} +1 -1
  82. package/dist/gateway/static/root/assets/voice-api-key-field-BsoqJba6.js +1 -0
  83. package/dist/gateway/static/root/assets/{voice-player-store-B7ykUlHM.js → voice-player-store-DduWlJYV.js} +1 -1
  84. package/dist/gateway/static/root/assets/workflow-run-setup-panel-CcQeX6l5.js +3 -0
  85. package/dist/gateway/static/root/assets/workflows-page-CeA8A9Ef.js +18 -0
  86. package/dist/gateway/static/root/index.html +9 -10
  87. package/dist/package.js +1 -1
  88. package/dist/src/agent/context/workspace-templates/AGENTS.md +3 -2
  89. package/dist/src/agent/embedded/xopc-auth-storage.d.ts +1 -5
  90. package/dist/src/agent/embedded/xopc-auth-storage.js +2 -8
  91. package/dist/src/agent/embedded/xopc-auth-storage.js.map +1 -1
  92. package/dist/src/agent/embedded/xopc-tools-bridge.js +23 -0
  93. package/dist/src/agent/embedded/xopc-tools-bridge.js.map +1 -1
  94. package/dist/src/agent/goals/checklist-judge.js +1 -1
  95. package/dist/src/agent/goals/checklist-judge.js.map +1 -1
  96. package/dist/src/agent/goals/judge.js +1 -1
  97. package/dist/src/agent/goals/judge.js.map +1 -1
  98. package/dist/src/agent/image/tool-model-config.d.ts +2 -0
  99. package/dist/src/agent/image/tool-model-config.js +2 -2
  100. package/dist/src/agent/image/tool-model-config.js.map +1 -1
  101. package/dist/src/agent/image/understanding/pi-ai-provider.js +1 -1
  102. package/dist/src/agent/image/understanding/pi-ai-provider.js.map +1 -1
  103. package/dist/src/agent/memory/builtin-memory-store.d.ts +1 -1
  104. package/dist/src/agent/memory/builtin-memory-store.js +1 -1
  105. package/dist/src/agent/memory/builtin-memory-store.js.map +1 -1
  106. package/dist/src/agent/memory/builtin-provider.d.ts +2 -2
  107. package/dist/src/agent/memory/builtin-provider.js +2 -2
  108. package/dist/src/agent/memory/builtin-provider.js.map +1 -1
  109. package/dist/src/agent/memory/compaction.d.ts +1 -1
  110. package/dist/src/agent/memory/compaction.js +1 -1
  111. package/dist/src/agent/memory/compaction.js.map +1 -1
  112. package/dist/src/agent/memory/dreaming/light-sweep.d.ts +0 -7
  113. package/dist/src/agent/memory/dreaming/light-sweep.js +16 -277
  114. package/dist/src/agent/memory/dreaming/light-sweep.js.map +1 -1
  115. package/dist/src/agent/memory/dreaming/rem-patterns.d.ts +1 -1
  116. package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
  117. package/dist/src/agent/memory/dreaming/rem-patterns.js.map +1 -1
  118. package/dist/src/agent/memory/dreaming/short-term-store.d.ts +3 -3
  119. package/dist/src/agent/memory/dreaming/short-term-store.js +5 -5
  120. package/dist/src/agent/memory/dreaming/short-term-store.js.map +1 -1
  121. package/dist/src/agent/memory/dreaming/utils.d.ts +2 -2
  122. package/dist/src/agent/memory/dreaming/utils.js +2 -2
  123. package/dist/src/agent/memory/dreaming/utils.js.map +1 -1
  124. package/dist/src/agent/memory/index.d.ts +0 -2
  125. package/dist/src/agent/memory/index.js +1 -2
  126. package/dist/src/agent/middleware/self-verify.d.ts +3 -0
  127. package/dist/src/agent/middleware/self-verify.js +18 -0
  128. package/dist/src/agent/middleware/self-verify.js.map +1 -1
  129. package/dist/src/agent/orchestration/agent-event-handler.js +28 -3
  130. package/dist/src/agent/orchestration/agent-event-handler.js.map +1 -1
  131. package/dist/src/agent/prompt/sections/memory-skills.js +11 -10
  132. package/dist/src/agent/prompt/sections/memory-skills.js.map +1 -1
  133. package/dist/src/agent/prompt/sections/tooling.js +23 -7
  134. package/dist/src/agent/prompt/sections/tooling.js.map +1 -1
  135. package/dist/src/agent/prompt/service-prompt-builder.js +1 -0
  136. package/dist/src/agent/prompt/service-prompt-builder.js.map +1 -1
  137. package/dist/src/agent/prompt/system-prompt.d.ts +1 -0
  138. package/dist/src/agent/prompt/system-prompt.js +13 -1
  139. package/dist/src/agent/prompt/system-prompt.js.map +1 -1
  140. package/dist/src/agent/reply/startup-context.js +6 -105
  141. package/dist/src/agent/reply/startup-context.js.map +1 -1
  142. package/dist/src/agent/sandbox/path-policy.js +30 -6
  143. package/dist/src/agent/sandbox/path-policy.js.map +1 -1
  144. package/dist/src/agent/service/btw-query.js +1 -1
  145. package/dist/src/agent/service/btw-query.js.map +1 -1
  146. package/dist/src/agent/service.d.ts +0 -3
  147. package/dist/src/agent/service.js +0 -41
  148. package/dist/src/agent/service.js.map +1 -1
  149. package/dist/src/agent/starter-agents.js +16 -16
  150. package/dist/src/agent/starter-agents.js.map +1 -1
  151. package/dist/src/agent/tools/image-generate-tool.js +12 -1
  152. package/dist/src/agent/tools/image-generate-tool.js.map +1 -1
  153. package/dist/src/agent/tools/memory-tool.js +2 -2
  154. package/dist/src/agent/tools/memory-tool.js.map +1 -1
  155. package/dist/src/agent/tools/session-search-tool.js +1 -1
  156. package/dist/src/agent/tools/session-search-tool.js.map +1 -1
  157. package/dist/src/agent/tools/web-extract.js +1 -1
  158. package/dist/src/agent/tools/web-extract.js.map +1 -1
  159. package/dist/src/agent-manifest/index.js +2 -2
  160. package/dist/src/agent-manifest/schema.d.ts +66 -0
  161. package/dist/src/agent-manifest/schema.js +28 -2
  162. package/dist/src/agent-manifest/schema.js.map +1 -1
  163. package/dist/src/automations/draft/automation-draft-service.js +1 -1
  164. package/dist/src/automations/draft/automation-draft-service.js.map +1 -1
  165. package/dist/src/cli/commands/agent.js +2 -2
  166. package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
  167. package/dist/src/cli/commands/init.js +1 -1
  168. package/dist/src/cli/commands/init.js.map +1 -1
  169. package/dist/src/cli/commands/models.js +1 -1
  170. package/dist/src/cli/commands/onboard/model.js +161 -11
  171. package/dist/src/cli/commands/onboard/model.js.map +1 -1
  172. package/dist/src/cli/commands/onboard.js +1 -1
  173. package/dist/src/cli/commands/profile.js +1 -1
  174. package/dist/src/cli/commands/tunnel.js +1 -1
  175. package/dist/src/cli/commands/update.js +1 -1
  176. package/dist/src/cli/extension-cli-register.js +1 -1
  177. package/dist/src/cli/templates.js +3 -2
  178. package/dist/src/cli/templates.js.map +1 -1
  179. package/dist/src/config/agent-profile.js +1 -1
  180. package/dist/src/config/default-model.d.ts +11 -0
  181. package/dist/src/config/default-model.js +19 -0
  182. package/dist/src/config/default-model.js.map +1 -0
  183. package/dist/src/config/index.js +3 -3
  184. package/dist/src/config/schema.d.ts +73 -13
  185. package/dist/src/config/schema.js +59 -24
  186. package/dist/src/config/schema.js.map +1 -1
  187. package/dist/src/connectors/registries/smithery.js +10 -9
  188. package/dist/src/connectors/registries/smithery.js.map +1 -1
  189. package/dist/src/daemon/install-plan.js +2 -1
  190. package/dist/src/daemon/install-plan.js.map +1 -1
  191. package/dist/src/gateway/agents-admin.js +1 -1
  192. package/dist/src/gateway/global-defaults-admin.js +6 -16
  193. package/dist/src/gateway/global-defaults-admin.js.map +1 -1
  194. package/dist/src/gateway/hono/lib/config-payload.d.ts +24 -0
  195. package/dist/src/gateway/hono/routes/agents.js +1 -79
  196. package/dist/src/gateway/hono/routes/agents.js.map +1 -1
  197. package/dist/src/gateway/hono/routes/config-patch/misc.js +4 -1
  198. package/dist/src/gateway/hono/routes/config-patch/misc.js.map +1 -1
  199. package/dist/src/gateway/hono/routes/models.js +132 -14
  200. package/dist/src/gateway/hono/routes/models.js.map +1 -1
  201. package/dist/src/gateway/hono/routes/voice.js +1 -1
  202. package/dist/src/gateway/hono/routes/voice.js.map +1 -1
  203. package/dist/src/gateway/image-capabilities.d.ts +11 -1
  204. package/dist/src/gateway/image-capabilities.js +32 -43
  205. package/dist/src/gateway/image-capabilities.js.map +1 -1
  206. package/dist/src/gateway/run-loop.js +1 -1
  207. package/dist/src/gateway/workspace-editor-path.js +9 -1
  208. package/dist/src/gateway/workspace-editor-path.js.map +1 -1
  209. package/dist/src/generated/bundled-image-generation-providers.d.ts +4 -2
  210. package/dist/src/generated/bundled-image-generation-providers.js +6 -4
  211. package/dist/src/generated/bundled-image-generation-providers.js.map +1 -1
  212. package/dist/src/infra/update-restart.js +1 -1
  213. package/dist/src/mcp/channel-bridge.js +1 -1
  214. package/dist/src/media/paths.js +3 -4
  215. package/dist/src/media/paths.js.map +1 -1
  216. package/dist/src/notes/service.js +1 -1
  217. package/dist/src/notes/service.js.map +1 -1
  218. package/dist/src/providers/domestic-presets.d.ts +615 -0
  219. package/dist/src/providers/domestic-presets.js +834 -0
  220. package/dist/src/providers/domestic-presets.js.map +1 -0
  221. package/dist/src/providers/env-keys.js +29 -5
  222. package/dist/src/providers/env-keys.js.map +1 -1
  223. package/dist/src/providers/extension-stream-bridge.js +1 -1
  224. package/dist/src/providers/extension-stream-bridge.js.map +1 -1
  225. package/dist/src/providers/index.d.ts +5 -5
  226. package/dist/src/providers/index.js +101 -21
  227. package/dist/src/providers/index.js.map +1 -1
  228. package/dist/src/providers/model-discovery.d.ts +17 -0
  229. package/dist/src/providers/model-discovery.js +61 -0
  230. package/dist/src/providers/model-discovery.js.map +1 -0
  231. package/dist/src/providers/model-registry.d.ts +1 -1
  232. package/dist/src/providers/model-registry.js +1 -1
  233. package/dist/src/providers/model-registry.js.map +1 -1
  234. package/dist/src/providers/presentation.js +185 -14
  235. package/dist/src/providers/presentation.js.map +1 -1
  236. package/dist/src/session/session-title.js +1 -1
  237. package/dist/src/session/session-title.js.map +1 -1
  238. package/dist/src/storage/sqlite/row-mappers.js +3 -1
  239. package/dist/src/storage/sqlite/row-mappers.js.map +1 -1
  240. package/dist/src/tui/backends/embedded-backend.js +1 -2
  241. package/dist/src/tui/backends/embedded-backend.js.map +1 -1
  242. package/dist/src/tui/xopc-tui-keybindings.d.ts +1 -1
  243. package/dist/src/voice/tts/summarize.js +1 -1
  244. package/dist/src/voice/tts/summarize.js.map +1 -1
  245. package/dist/src/workflows/draft/workflow-draft-service.js +1 -1
  246. package/dist/src/workflows/draft/workflow-draft-service.js.map +1 -1
  247. package/package.json +6 -6
  248. package/dist/gateway/static/root/assets/Combination-BzaXOLd9.js +0 -41
  249. package/dist/gateway/static/root/assets/agents-B0hkpLhP.js +0 -2
  250. package/dist/gateway/static/root/assets/automations-page-CTedroVo.js +0 -1
  251. package/dist/gateway/static/root/assets/browser-settings-page-FCDwOOBK.js +0 -8
  252. package/dist/gateway/static/root/assets/channels-settings-C3d5JBJX.js +0 -1
  253. package/dist/gateway/static/root/assets/connectors-page-yaUNvt5u.js +0 -2
  254. package/dist/gateway/static/root/assets/dist-By6Rh2ee.js +0 -1
  255. package/dist/gateway/static/root/assets/dist-CkobR7mk.js +0 -1
  256. package/dist/gateway/static/root/assets/dist-DokQNVMQ.js +0 -1
  257. package/dist/gateway/static/root/assets/dreaming-settings-DNrdg1Ve.js +0 -1
  258. package/dist/gateway/static/root/assets/extension-settings-page-BU1KoKRj.js +0 -1
  259. package/dist/gateway/static/root/assets/gateway-settings-C79wkXef.js +0 -1
  260. package/dist/gateway/static/root/assets/goal-detail-page-9paXuHdo.js +0 -1
  261. package/dist/gateway/static/root/assets/goals-page-CS0R-Af2.js +0 -2
  262. package/dist/gateway/static/root/assets/goals-settings-CSuzZ8Ae.js +0 -1
  263. package/dist/gateway/static/root/assets/heartbeat-settings-DXPaYJm3.js +0 -1
  264. package/dist/gateway/static/root/assets/index-BoKafJIZ.js +0 -191
  265. package/dist/gateway/static/root/assets/index-CArhCcYn.css +0 -1
  266. package/dist/gateway/static/root/assets/logs-page-DLXPcksQ.js +0 -2
  267. package/dist/gateway/static/root/assets/messages-CrDHEbss.js +0 -3
  268. package/dist/gateway/static/root/assets/models-hub-panel-BDF2iyRk.js +0 -2
  269. package/dist/gateway/static/root/assets/note-detail-page-CSb_hwig.js +0 -2
  270. package/dist/gateway/static/root/assets/remote-access-hub-CwzSovcS.js +0 -1
  271. package/dist/gateway/static/root/assets/schedule-field-CmTRoOcE.js +0 -1
  272. package/dist/gateway/static/root/assets/schema-form-FMKv1vGu.js +0 -1
  273. package/dist/gateway/static/root/assets/sessions-page-PHmX-NmA.js +0 -1
  274. package/dist/gateway/static/root/assets/settings-advanced-gate-BRAeKJN4.js +0 -1
  275. package/dist/gateway/static/root/assets/settings-form-section-D-4lBl6X.js +0 -1
  276. package/dist/gateway/static/root/assets/settings-page-KKrbFjy8.js +0 -1
  277. package/dist/gateway/static/root/assets/shares-settings-B18OBmH5.js +0 -1
  278. package/dist/gateway/static/root/assets/skill-reload-api-C28-2uKQ.js +0 -1
  279. package/dist/gateway/static/root/assets/skills-page-Bm2ebkwl.js +0 -2
  280. package/dist/gateway/static/root/assets/user-profile-settings-panel-DJ1dKwZy.js +0 -1
  281. package/dist/gateway/static/root/assets/voice-api-key-field-CeEevm7z.js +0 -1
  282. package/dist/gateway/static/root/assets/workflow-run-setup-panel-C4PzUQjB.js +0 -3
  283. package/dist/gateway/static/root/assets/workflows-page-BL84_-Ky.js +0 -18
  284. package/dist/src/agent/memory/memory-flush.d.ts +0 -27
  285. package/dist/src/agent/memory/memory-flush.js +0 -124
  286. package/dist/src/agent/memory/memory-flush.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["getPiAiModel","getPiAiProviders","getPiAiModels"],"sources":["../../../src/providers/index.ts"],"sourcesContent":["/**\n * Model provider module - integrates built-in models with custom models from models.json\n */\n\nimport {\n\tgetModel as getPiAiModel,\n\tgetModels as getPiAiModels,\n\tgetProviders as getPiAiProviders,\n\ttype Model,\n\ttype Api,\n} from '@earendil-works/pi-ai';\nimport { getAgentDefaultModelRef, type Config } from '../config/schema.js';\nimport { getModelRegistry } from './model-registry.js';\nimport { CredentialResolver, resolveApiKey, hasCredentials } from '../auth/credentials.js';\nimport { hasProviderAuthOnDiskSync } from '../auth/sync-provider-auth.js';\nimport { getApiKeyFromEnv } from './env-keys.js';\nimport { getProviderRegistry } from './plugin-registry.js';\nimport type { ProviderModelDefinition } from '../extensions/types/providers.js';\n\nexport { getApiKeyFromEnv, PROVIDER_ENV_MAP } from './env-keys.js';\n\n/** Sentinel base URL: model is served by an extension {@link ProviderPluginRegistry} provider. */\nexport const EXTENSION_PROVIDER_BASE_URL = 'extension://provider-plugin';\nconst OPENAI_CODEX_CANONICAL_BASE_URL = 'https://chatgpt.com/backend-api/codex';\n\nfunction normalizeProviderModel(model: Model<Api>): Model<Api> {\n\tif (model.provider === 'openai-codex' && model.api === 'openai-codex-responses') {\n\t\treturn { ...model, baseUrl: OPENAI_CODEX_CANONICAL_BASE_URL } as Model<Api>;\n\t}\n\treturn model;\n}\n\n/** Map a plugin registry model to the pi-ai {@link Model} shape. */\nexport function pluginModelToModel(providerId: string, definition: ProviderModelDefinition): Model<Api> {\n\treturn {\n\t\tprovider: providerId,\n\t\tid: definition.id,\n\t\tname: definition.name,\n\t\tapi: 'openai-completions' as Api,\n\t\tbaseUrl: EXTENSION_PROVIDER_BASE_URL,\n\t\treasoning: false,\n\t\tinput: definition.supportsImages ? (['text', 'image'] as ('text' | 'image')[]) : (['text'] as ('text' | 'image')[]),\n\t\tcontextWindow: definition.contextWindow ?? 128000,\n\t\tmaxTokens: definition.maxOutputTokens ?? 4096,\n\t\tcost: {\n\t\t\tinput: definition.pricing?.input ?? 0,\n\t\t\toutput: definition.pricing?.output ?? 0,\n\t\t\tcacheRead: 0,\n\t\t\tcacheWrite: 0,\n\t\t},\n\t} as Model<Api>;\n}\n\n/**\n * Get API key synchronously: checks registry (models.json) first, then environment variables.\n * Use this for Agent's getApiKey callback which must be synchronous.\n */\nexport function getApiKeySync(provider: string): string | undefined {\n const pluginRegistry = getProviderRegistry();\n if (pluginRegistry.has(provider)) return 'extension-managed';\n\n const registry = getModelRegistry();\n const registryKey = registry.getApiKey(provider);\n if (registryKey) {\n return registryKey;\n }\n return getApiKeyFromEnv(provider);\n}\n\n/**\n * Resolve model reference. Supports:\n * - \"provider/modelId\" format\n * - \"modelId\" auto-detection via pi-ai or custom models\n * @throws if model not found\n */\nexport function resolveModel(ref: string): Model<Api> {\n\tconst trimmedRef = typeof ref === 'string' ? ref.trim() : '';\n\tif (!trimmedRef) {\n\t\tthrow new Error(\n\t\t\t'No default model configured. Choose a model in onboarding or set agents.capabilityPresets.default.models.roles.<role>.model.',\n\t\t);\n\t}\n\n\t// First try ModelRegistry (includes custom models)\n\tconst registry = getModelRegistry();\n\tconst customModel = registry.resolve(trimmedRef);\n\tif (customModel) {\n\t\treturn customModel;\n\t}\n\n\tif (trimmedRef.includes('/')) {\n\t\tconst [provider, modelId] = trimmedRef.split('/');\n\t\tconst piAiModel = getPiAiModel(provider as any, modelId as any);\n\t\tif (piAiModel) return normalizeProviderModel(piAiModel as Model<Api>);\n\n\t\tconst pluginRegistry = getProviderRegistry();\n\t\tconst plugin = pluginRegistry.get(provider);\n\t\tif (plugin) {\n\t\t\tconst pluginModel = plugin.models.find(m => m.id === modelId);\n\t\t\tif (pluginModel) return pluginModelToModel(provider, pluginModel);\n\t\t}\n\t\tthrow new Error(`Model not found: ${trimmedRef}`);\n\t}\n\n\tfor (const provider of getPiAiProviders()) {\n\t\ttry {\n\t\t\tconst models = getPiAiModels(provider);\n\t\t\tconst found = models.find(m => m.id === trimmedRef);\n\t\t\tif (found) return normalizeProviderModel(found as Model<Api>);\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t}\n\n\tconst pluginRegistry = getProviderRegistry();\n\tfor (const plugin of pluginRegistry.listAll()) {\n\t\tconst found = plugin.models.find(m => m.id === trimmedRef);\n\t\tif (found) return pluginModelToModel(plugin.id, found);\n\t}\n\n\tthrow new Error(`Model not found: ${trimmedRef}. Use format: provider/model-id`);\n}\n\nexport function getModelsByProvider(provider: string): readonly Model<Api>[] {\n\tconst registry = getModelRegistry();\n\tconst fromRegistry = registry.getAll().filter(m => m.provider === provider).map(normalizeProviderModel);\n\tconst plugin = getProviderRegistry().get(provider);\n\tif (!plugin) return fromRegistry;\n\tconst pluginModels = plugin.models.map(m => pluginModelToModel(provider, m));\n\treturn [...fromRegistry, ...pluginModels];\n}\n\nexport function getAllProviders(): string[] {\n\tconst registry = getModelRegistry();\n\tconst providers = new Set<string>();\n\n\t// Add built-in providers\n\tfor (const p of getPiAiProviders()) {\n\t\tproviders.add(p);\n\t}\n\n\t// Add custom providers from registry\n\tfor (const m of registry.getAll()) {\n\t\tproviders.add(m.provider);\n\t}\n\n\tfor (const plugin of getProviderRegistry().listAll()) {\n\t\tproviders.add(plugin.id);\n\t}\n\n\treturn Array.from(providers);\n}\n\nexport async function getApiKey(provider: string): Promise<string | undefined> {\n\tif (getProviderRegistry().has(provider)) return 'extension-managed';\n\n\t// Use new credential resolver first (checks: agent private > global > oauth > env)\n\tconst credentialKey = await resolveApiKey(provider);\n\tif (credentialKey) {\n\t\treturn credentialKey;\n\t}\n\n\t// Check registry for custom providers (from models.json)\n\tconst registry = getModelRegistry();\n\tconst registryKey = registry.getApiKey(provider);\n\tif (registryKey) {\n\t\treturn registryKey;\n\t}\n\n\t// Fallback to environment variables\n\treturn getApiKeyFromEnv(provider);\n}\n\n/**\n * Synchronous version for use in non-async contexts\n * Only checks environment variables and registry, not credential system\n */\nexport function isProviderConfiguredSync(provider: string): boolean {\n\tif (getProviderRegistry().has(provider)) return true;\n\n\t// Check registry for custom providers\n\tconst registry = getModelRegistry();\n\tif (registry.getApiKey(provider)) {\n\t\treturn true;\n\t}\n\t// Check environment variables\n\tif (getApiKeyFromEnv(provider)) {\n\t\treturn true;\n\t}\n\t// Gateway UI / CLI store keys in auth-profiles.json (async CredentialResolver); sync path for fallback list\n\treturn hasProviderAuthOnDiskSync(provider);\n}\n\nexport async function isProviderConfigured(provider: string): Promise<boolean> {\n if (getProviderRegistry().has(provider)) return true;\n\n // Check registry first for custom providers (from models.json)\n const registry = getModelRegistry();\n if (registry.getApiKey(provider)) {\n return true;\n }\n return await hasCredentials(provider);\n}\n\n/** Where runtime {@link getApiKey} resolves the key from (no secret values). */\nexport type ProviderActiveKeySource = 'none' | 'agent' | 'gateway' | 'oauth' | 'env' | 'models_json' | 'extension';\n\nexport type ProviderAuthMode = ProviderActiveKeySource;\nexport type ProviderAuthStatus = 'connected' | 'expired' | 'not_connected';\n\nexport interface ProviderAuthState {\n authMode: ProviderAuthMode;\n authStatus: ProviderAuthStatus;\n expiresAt?: number;\n}\n\nexport async function getProviderActiveKeySource(provider: string): Promise<ProviderActiveKeySource> {\n const authState = await getProviderAuthState(provider);\n return authState.authMode;\n}\n\nexport async function getProviderAuthState(provider: string): Promise<ProviderAuthState> {\n if (getProviderRegistry().has(provider)) {\n return { authMode: 'extension', authStatus: 'connected' };\n }\n\n const resolver = new CredentialResolver();\n const fromCredentials = await resolver.resolveApiKeySource(provider);\n if (fromCredentials === 'agent') return { authMode: 'agent', authStatus: 'connected' };\n if (fromCredentials === 'global') return { authMode: 'gateway', authStatus: 'connected' };\n if (fromCredentials === 'oauth') {\n const token = await resolver.loadOAuthTokenRecord(provider);\n const expired = Boolean(token?.expiresAt && token.expiresAt < Date.now());\n return {\n authMode: 'oauth',\n authStatus: expired ? 'expired' : 'connected',\n ...(token?.expiresAt ? { expiresAt: token.expiresAt } : {}),\n };\n }\n if (fromCredentials === 'env') return { authMode: 'env', authStatus: 'connected' };\n\n const expiredOAuthToken = await resolver.loadOAuthTokenRecord(provider);\n if (expiredOAuthToken?.expiresAt && expiredOAuthToken.expiresAt < Date.now()) {\n return {\n authMode: 'oauth',\n authStatus: 'expired',\n expiresAt: expiredOAuthToken.expiresAt,\n };\n }\n\n const registry = getModelRegistry();\n if (registry.getApiKey(provider)) {\n return { authMode: 'models_json', authStatus: 'connected' };\n }\n\n return { authMode: 'none', authStatus: 'not_connected' };\n}\n\nexport async function getConfiguredProviders(): Promise<string[]> {\n\tconst allProviders = getAllProviders();\n\tconst configured: string[] = [];\n\tfor (const p of allProviders) {\n\t\tif (await isProviderConfigured(p)) {\n\t\t\tconfigured.push(p);\n\t\t}\n\t}\n\treturn configured;\n}\n\nexport function getAllModels(): readonly Model<Api>[] {\n\tconst registry = getModelRegistry();\n\tconst registryModels = registry.getAll().map(normalizeProviderModel);\n\tconst pluginProviders = getProviderRegistry().listAll();\n\tif (pluginProviders.length === 0) return registryModels;\n\n\tconst existingIds = new Set(registryModels.map(m => `${m.provider}/${m.id}`));\n\tconst merged: Model<Api>[] = [...registryModels];\n\tfor (const plugin of pluginProviders) {\n\t\tfor (const model of plugin.models) {\n\t\t\tconst compositeId = `${plugin.id}/${model.id}`;\n\t\t\tif (!existingIds.has(compositeId)) {\n\t\t\t\tmerged.push(pluginModelToModel(plugin.id, model));\n\t\t\t\texistingIds.add(compositeId);\n\t\t\t}\n\t\t}\n\t}\n\treturn merged;\n}\n\nexport async function getAvailableModels(): Promise<readonly Model<Api>[]> {\n\tconst allModels = getAllModels();\n\tconst pluginRegistry = getProviderRegistry();\n\tconst available: Model<Api>[] = [];\n\tconst configuredByProvider = new Map<string, boolean>();\n\n\tfor (const model of allModels) {\n\t\tif (pluginRegistry.has(model.provider)) {\n\t\t\tavailable.push(model);\n\t\t\tcontinue;\n\t\t}\n\t\tlet configured = configuredByProvider.get(model.provider);\n\t\tif (configured === undefined) {\n\t\t\tconfigured = await isProviderConfigured(model.provider);\n\t\t\tconfiguredByProvider.set(model.provider, configured);\n\t\t}\n\t\tif (configured) {\n\t\t\tavailable.push(model);\n\t\t}\n\t}\n\treturn available;\n}\n\nexport type { Model, Api } from '@earendil-works/pi-ai';\n\nexport type ProviderCategory = 'common' | 'specialty' | 'oauth' | 'enterprise' | 'extension';\n\nexport interface ProviderMeta {\n name: string;\n category: ProviderCategory;\n supportsOAuth?: boolean;\n supportsApiKey?: boolean;\n}\n\nexport const PROVIDER_META: Record<string, ProviderMeta> = {\n 'openai': { name: 'OpenAI', category: 'common', supportsApiKey: true },\n 'anthropic': { name: 'Anthropic', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'deepseek': { name: 'DeepSeek', category: 'common', supportsApiKey: true },\n 'google': { name: 'Google AI', category: 'common', supportsApiKey: true },\n 'groq': { name: 'Groq', category: 'common', supportsApiKey: true },\n 'minimax': { name: 'MiniMax', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'minimax-cn': { name: 'MiniMax CN', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'kimi-coding': { name: 'Kimi For Coding', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'xai': { name: 'xAI', category: 'specialty', supportsApiKey: true },\n 'mistral': { name: 'Mistral AI', category: 'specialty', supportsApiKey: true },\n 'cerebras': { name: 'Cerebras', category: 'specialty', supportsApiKey: true },\n 'openrouter': { name: 'OpenRouter', category: 'specialty', supportsApiKey: true },\n 'huggingface': { name: 'Hugging Face', category: 'specialty', supportsApiKey: true },\n moonshotai: { name: 'Moonshot AI (Kimi · International)', category: 'common', supportsApiKey: true },\n 'moonshotai-cn': { name: 'Moonshot AI (Kimi · China)', category: 'common', supportsApiKey: true },\n fireworks: { name: 'Fireworks AI', category: 'specialty', supportsApiKey: true },\n together: { name: 'Together AI', category: 'specialty', supportsApiKey: true },\n 'cloudflare-workers-ai': { name: 'Cloudflare Workers AI', category: 'enterprise', supportsApiKey: true },\n 'cloudflare-ai-gateway': { name: 'Cloudflare AI Gateway', category: 'enterprise', supportsApiKey: true },\n xiaomi: { name: 'Xiaomi Mimo', category: 'specialty', supportsApiKey: true },\n 'xiaomi-token-plan-cn': { name: 'Xiaomi Token Plan (CN)', category: 'specialty', supportsApiKey: true },\n 'xiaomi-token-plan-ams': { name: 'Xiaomi Token Plan (AMS)', category: 'specialty', supportsApiKey: true },\n 'xiaomi-token-plan-sgp': { name: 'Xiaomi Token Plan (SGP)', category: 'specialty', supportsApiKey: true },\n 'opencode': { name: 'OpenCode', category: 'specialty', supportsApiKey: true },\n 'opencode-go': { name: 'OpenCode Go', category: 'specialty', supportsApiKey: true },\n /** DashScope (Alibaba) — image, speech, STT; not an LLM KnownProvider. */\n 'dashscope': { name: 'DashScope (Alibaba)', category: 'specialty', supportsApiKey: true },\n /** International GLM (api.z.ai). Auth: API key (ZAI_API_KEY); no published OAuth for this HTTP API. */\n 'zai': { name: 'Zhipu GLM (International · z.ai)', category: 'common', supportsApiKey: true },\n 'amazon-bedrock': { name: 'Amazon Bedrock', category: 'enterprise', supportsApiKey: true },\n 'azure-openai-responses': { name: 'Azure OpenAI', category: 'enterprise', supportsApiKey: true },\n 'google-vertex': { name: 'Google Vertex AI', category: 'enterprise', supportsApiKey: true },\n 'vercel-ai-gateway': { name: 'Vercel AI Gateway', category: 'enterprise', supportsApiKey: true },\n 'github-copilot': { name: 'GitHub Copilot (OAuth)', category: 'oauth', supportsOAuth: true, supportsApiKey: false },\n 'openai-codex': { name: 'OpenAI Codex (OAuth)', category: 'oauth', supportsOAuth: true, supportsApiKey: false },\n 'google-gemini-cli': { name: 'Google Gemini CLI (OAuth)', category: 'oauth', supportsOAuth: true, supportsApiKey: false },\n 'google-antigravity': { name: 'Google Antigravity (OAuth)', category: 'oauth', supportsOAuth: true, supportsApiKey: false },\n};\n\nexport function getSortedProviders(): string[] {\n const all = getAllProviders();\n const catOrder: Record<ProviderCategory, number> = { common: 0, specialty: 1, enterprise: 2, oauth: 3, extension: 4 };\n const pluginRegistry = getProviderRegistry();\n\n return [...all].sort((a, b) => {\n const catA = pluginRegistry.has(a) ? 'extension' : (PROVIDER_META[a]?.category ?? 'specialty');\n const catB = pluginRegistry.has(b) ? 'extension' : (PROVIDER_META[b]?.category ?? 'specialty');\n if (catOrder[catA] !== catOrder[catB]) {\n return catOrder[catA] - catOrder[catB];\n }\n return a.localeCompare(b);\n });\n}\n\nexport function getProviderDisplayName(provider: string): string {\n const plugin = getProviderRegistry().get(provider);\n if (plugin) return plugin.name;\n return PROVIDER_META[provider]?.name || provider;\n}\n\nexport function providerSupportsOAuth(provider: string): boolean {\n return PROVIDER_META[provider]?.supportsOAuth ?? false;\n}\n\nexport function providerSupportsApiKey(provider: string): boolean {\n return PROVIDER_META[provider]?.supportsApiKey ?? true;\n}\n\n// ============================================\n// Dynamic Default Model Resolution\n// ============================================\n\n/**\n * Get a default model reference.\n * Priority:\n * 1. Effective model inherited from the global default preset / agent presets / agent override\n * 2. Empty string when onboarding still needs to choose a global default model\n */\nexport async function getDefaultModel(config?: Config | null | undefined): Promise<string> {\n const modelRef = config ? getAgentDefaultModelRef(config) : undefined;\n if (modelRef) {\n const availableModels = await getAvailableModels();\n const configured = availableModels.find(m =>\n `${m.provider}/${m.id}` === modelRef ||\n m.id === modelRef\n );\n if (configured) {\n return `${configured.provider}/${configured.id}`;\n }\n return modelRef;\n }\n\n return '';\n}\n\n/**\n * Synchronous default model resolution for constructors and sync code paths.\n * Uses catalog/registry only (no async credential checks).\n *\n * When no model is explicitly configured, returns an empty string so setup\n * flows can prompt for the global default model.\n */\nexport function getDefaultModelSync(config?: Config | null | undefined): string {\n const modelRef = config ? getAgentDefaultModelRef(config) : undefined;\n if (modelRef) {\n return modelRef;\n }\n\n return '';\n}\n\n// Re-export ModelRegistry for advanced use cases\nexport { ModelRegistry, getModelRegistry, resetModelRegistry, prewarmModelRegistry } from './model-registry.js';\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["getPiAiModel","getPiAiProviders","getPiAiModels"],"sources":["../../../src/providers/index.ts"],"sourcesContent":["/**\n * Model provider module - integrates built-in models with custom models from models.json\n */\n\nimport {\n\tgetModel as getPiAiModel,\n\tgetModels as getPiAiModels,\n\tgetProviders as getPiAiProviders,\n\ttype Model,\n\ttype Api,\n} from '@earendil-works/pi-ai/compat';\nimport { getAgentDefaultModelRef, type Config } from '../config/schema.js';\nimport { getModelRegistry } from './model-registry.js';\nimport { CredentialResolver, resolveApiKey, hasCredentials } from '../auth/credentials.js';\nimport { hasProviderAuthOnDiskSync } from '../auth/sync-provider-auth.js';\nimport { getApiKeyFromEnv } from './env-keys.js';\nimport { getProviderRegistry } from './plugin-registry.js';\nimport type { ProviderModelDefinition } from '../extensions/types/providers.js';\n\nexport { getApiKeyFromEnv, PROVIDER_ENV_MAP } from './env-keys.js';\n\n/** Sentinel base URL: model is served by an extension {@link ProviderPluginRegistry} provider. */\nexport const EXTENSION_PROVIDER_BASE_URL = 'extension://provider-plugin';\nconst OPENAI_CODEX_CANONICAL_BASE_URL = 'https://chatgpt.com/backend-api/codex';\n\nfunction normalizeProviderModel(model: Model<Api>): Model<Api> {\n\tif (model.provider === 'openai-codex' && model.api === 'openai-codex-responses') {\n\t\treturn { ...model, baseUrl: OPENAI_CODEX_CANONICAL_BASE_URL } as Model<Api>;\n\t}\n\treturn model;\n}\n\n/** Map a plugin registry model to the pi-ai {@link Model} shape. */\nexport function pluginModelToModel(providerId: string, definition: ProviderModelDefinition): Model<Api> {\n\treturn {\n\t\tprovider: providerId,\n\t\tid: definition.id,\n\t\tname: definition.name,\n\t\tapi: 'openai-completions' as Api,\n\t\tbaseUrl: EXTENSION_PROVIDER_BASE_URL,\n\t\treasoning: false,\n\t\tinput: definition.supportsImages ? (['text', 'image'] as ('text' | 'image')[]) : (['text'] as ('text' | 'image')[]),\n\t\tcontextWindow: definition.contextWindow ?? 128000,\n\t\tmaxTokens: definition.maxOutputTokens ?? 4096,\n\t\tcost: {\n\t\t\tinput: definition.pricing?.input ?? 0,\n\t\t\toutput: definition.pricing?.output ?? 0,\n\t\t\tcacheRead: 0,\n\t\t\tcacheWrite: 0,\n\t\t},\n\t} as Model<Api>;\n}\n\n/**\n * Get API key synchronously: checks registry (models.json) first, then environment variables.\n * Use this for Agent's getApiKey callback which must be synchronous.\n */\nexport function getApiKeySync(provider: string): string | undefined {\n const pluginRegistry = getProviderRegistry();\n if (pluginRegistry.has(provider)) return 'extension-managed';\n\n const registry = getModelRegistry();\n const registryKey = registry.getApiKey(provider);\n if (registryKey) {\n return registryKey;\n }\n return getApiKeyFromEnv(provider);\n}\n\n/**\n * Resolve model reference. Supports:\n * - \"provider/modelId\" format\n * - \"modelId\" auto-detection via pi-ai or custom models\n * @throws if model not found\n */\nexport function resolveModel(ref: string): Model<Api> {\n\tconst trimmedRef = typeof ref === 'string' ? ref.trim() : '';\n\tif (!trimmedRef) {\n\t\tthrow new Error(\n\t\t\t'No default model configured. Choose a model in onboarding or set agents.capabilityPresets.default.models.roles.<role>.model.',\n\t\t);\n\t}\n\n\t// First try ModelRegistry (includes custom models)\n\tconst registry = getModelRegistry();\n\tconst customModel = registry.resolve(trimmedRef);\n\tif (customModel) {\n\t\treturn customModel;\n\t}\n\n\tif (trimmedRef.includes('/')) {\n\t\tconst [provider, modelId] = trimmedRef.split('/');\n\t\tconst piAiModel = getPiAiModel(provider as any, modelId as any);\n\t\tif (piAiModel) return normalizeProviderModel(piAiModel as Model<Api>);\n\n\t\tconst pluginRegistry = getProviderRegistry();\n\t\tconst plugin = pluginRegistry.get(provider);\n\t\tif (plugin) {\n\t\t\tconst pluginModel = plugin.models.find(m => m.id === modelId);\n\t\t\tif (pluginModel) return pluginModelToModel(provider, pluginModel);\n\t\t}\n\t\tthrow new Error(`Model not found: ${trimmedRef}`);\n\t}\n\n\tfor (const provider of getPiAiProviders()) {\n\t\ttry {\n\t\t\tconst models = getPiAiModels(provider);\n\t\t\tconst found = models.find(m => m.id === trimmedRef);\n\t\t\tif (found) return normalizeProviderModel(found as Model<Api>);\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t}\n\n\tconst pluginRegistry = getProviderRegistry();\n\tfor (const plugin of pluginRegistry.listAll()) {\n\t\tconst found = plugin.models.find(m => m.id === trimmedRef);\n\t\tif (found) return pluginModelToModel(plugin.id, found);\n\t}\n\n\tthrow new Error(`Model not found: ${trimmedRef}. Use format: provider/model-id`);\n}\n\nexport function getModelsByProvider(provider: string): readonly Model<Api>[] {\n\tconst registry = getModelRegistry();\n\tconst fromRegistry = registry.getAll().filter(m => m.provider === provider).map(normalizeProviderModel);\n\tconst plugin = getProviderRegistry().get(provider);\n\tif (!plugin) return fromRegistry;\n\tconst pluginModels = plugin.models.map(m => pluginModelToModel(provider, m));\n\treturn [...fromRegistry, ...pluginModels];\n}\n\nexport function getAllProviders(): string[] {\n\tconst registry = getModelRegistry();\n\tconst providers = new Set<string>();\n\n\t// Add built-in providers\n\tfor (const p of getPiAiProviders()) {\n\t\tproviders.add(p);\n\t}\n\n\t// Add custom providers from registry\n\tfor (const m of registry.getAll()) {\n\t\tproviders.add(m.provider);\n\t}\n\n\tfor (const plugin of getProviderRegistry().listAll()) {\n\t\tproviders.add(plugin.id);\n\t}\n\n\treturn Array.from(providers);\n}\n\nexport async function getApiKey(provider: string): Promise<string | undefined> {\n\tif (getProviderRegistry().has(provider)) return 'extension-managed';\n\n\t// Use new credential resolver first (checks: agent private > global > oauth > env)\n\tconst credentialKey = await resolveApiKey(provider);\n\tif (credentialKey) {\n\t\treturn credentialKey;\n\t}\n\n\t// Check registry for custom providers (from models.json)\n\tconst registry = getModelRegistry();\n\tconst registryKey = registry.getApiKey(provider);\n\tif (registryKey) {\n\t\treturn registryKey;\n\t}\n\n\t// Fallback to environment variables\n\treturn getApiKeyFromEnv(provider);\n}\n\n/**\n * Synchronous version for use in non-async contexts\n * Only checks environment variables and registry, not credential system\n */\nexport function isProviderConfiguredSync(provider: string): boolean {\n\tif (getProviderRegistry().has(provider)) return true;\n\n\t// Check registry for custom providers\n\tconst registry = getModelRegistry();\n\tif (registry.getApiKey(provider)) {\n\t\treturn true;\n\t}\n\t// Check environment variables\n\tif (getApiKeyFromEnv(provider)) {\n\t\treturn true;\n\t}\n\t// Gateway UI / CLI store keys in auth-profiles.json (async CredentialResolver); sync path for fallback list\n\treturn hasProviderAuthOnDiskSync(provider);\n}\n\nexport async function isProviderConfigured(provider: string): Promise<boolean> {\n if (getProviderRegistry().has(provider)) return true;\n\n // Check registry first for custom providers (from models.json)\n const registry = getModelRegistry();\n if (registry.getApiKey(provider)) {\n return true;\n }\n return await hasCredentials(provider);\n}\n\n/** Where runtime {@link getApiKey} resolves the key from (no secret values). */\nexport type ProviderActiveKeySource = 'none' | 'agent' | 'gateway' | 'oauth' | 'env' | 'models_json' | 'extension';\n\nexport type ProviderAuthMode = ProviderActiveKeySource;\nexport type ProviderAuthStatus = 'connected' | 'expired' | 'not_connected';\n\nexport interface ProviderAuthState {\n authMode: ProviderAuthMode;\n authStatus: ProviderAuthStatus;\n expiresAt?: number;\n}\n\nexport async function getProviderActiveKeySource(provider: string): Promise<ProviderActiveKeySource> {\n const authState = await getProviderAuthState(provider);\n return authState.authMode;\n}\n\nexport async function getProviderAuthState(provider: string): Promise<ProviderAuthState> {\n if (getProviderRegistry().has(provider)) {\n return { authMode: 'extension', authStatus: 'connected' };\n }\n\n const resolver = new CredentialResolver();\n const fromCredentials = await resolver.resolveApiKeySource(provider);\n if (fromCredentials === 'agent') return { authMode: 'agent', authStatus: 'connected' };\n if (fromCredentials === 'global') return { authMode: 'gateway', authStatus: 'connected' };\n if (fromCredentials === 'oauth') {\n const token = await resolver.loadOAuthTokenRecord(provider);\n const expired = Boolean(token?.expiresAt && token.expiresAt < Date.now());\n return {\n authMode: 'oauth',\n authStatus: expired ? 'expired' : 'connected',\n ...(token?.expiresAt ? { expiresAt: token.expiresAt } : {}),\n };\n }\n if (fromCredentials === 'env') return { authMode: 'env', authStatus: 'connected' };\n\n const expiredOAuthToken = await resolver.loadOAuthTokenRecord(provider);\n if (expiredOAuthToken?.expiresAt && expiredOAuthToken.expiresAt < Date.now()) {\n return {\n authMode: 'oauth',\n authStatus: 'expired',\n expiresAt: expiredOAuthToken.expiresAt,\n };\n }\n\n const registry = getModelRegistry();\n if (registry.getApiKey(provider)) {\n return { authMode: 'models_json', authStatus: 'connected' };\n }\n\n return { authMode: 'none', authStatus: 'not_connected' };\n}\n\nexport async function getConfiguredProviders(): Promise<string[]> {\n\tconst allProviders = getAllProviders();\n\tconst configured: string[] = [];\n\tfor (const p of allProviders) {\n\t\tif (await isProviderConfigured(p)) {\n\t\t\tconfigured.push(p);\n\t\t}\n\t}\n\treturn configured;\n}\n\nexport function getAllModels(): readonly Model<Api>[] {\n\tconst registry = getModelRegistry();\n\tconst registryModels = registry.getAll().map(normalizeProviderModel);\n\tconst pluginProviders = getProviderRegistry().listAll();\n\tif (pluginProviders.length === 0) return registryModels;\n\n\tconst existingIds = new Set(registryModels.map(m => `${m.provider}/${m.id}`));\n\tconst merged: Model<Api>[] = [...registryModels];\n\tfor (const plugin of pluginProviders) {\n\t\tfor (const model of plugin.models) {\n\t\t\tconst compositeId = `${plugin.id}/${model.id}`;\n\t\t\tif (!existingIds.has(compositeId)) {\n\t\t\t\tmerged.push(pluginModelToModel(plugin.id, model));\n\t\t\t\texistingIds.add(compositeId);\n\t\t\t}\n\t\t}\n\t}\n\treturn merged;\n}\n\nexport async function getAvailableModels(): Promise<readonly Model<Api>[]> {\n\tconst allModels = getAllModels();\n\tconst pluginRegistry = getProviderRegistry();\n\tconst available: Model<Api>[] = [];\n\tconst configuredByProvider = new Map<string, boolean>();\n\n\tfor (const model of allModels) {\n\t\tif (pluginRegistry.has(model.provider)) {\n\t\t\tavailable.push(model);\n\t\t\tcontinue;\n\t\t}\n\t\tlet configured = configuredByProvider.get(model.provider);\n\t\tif (configured === undefined) {\n\t\t\tconfigured = await isProviderConfigured(model.provider);\n\t\t\tconfiguredByProvider.set(model.provider, configured);\n\t\t}\n\t\tif (configured) {\n\t\t\tavailable.push(model);\n\t\t}\n\t}\n\treturn available;\n}\n\nexport type { Model, Api } from '@earendil-works/pi-ai';\n\nexport type ProviderCategory = 'common' | 'domestic' | 'specialty' | 'oauth' | 'enterprise' | 'extension';\n\nexport interface ProviderMeta {\n name: string;\n category: ProviderCategory;\n supportsOAuth?: boolean;\n supportsApiKey?: boolean;\n}\n\nexport const PROVIDER_META: Record<string, ProviderMeta> = {\n 'openai': { name: 'OpenAI', category: 'common', supportsApiKey: true },\n 'anthropic': { name: 'Anthropic', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'deepseek': { name: 'DeepSeek', category: 'domestic', supportsApiKey: true },\n 'google': { name: 'Google AI', category: 'common', supportsApiKey: true },\n 'groq': { name: 'Groq', category: 'common', supportsApiKey: true },\n 'minimax': { name: 'MiniMax', category: 'domestic', supportsApiKey: true, supportsOAuth: true },\n 'minimax-cn': { name: 'MiniMax CN', category: 'domestic', supportsApiKey: true, supportsOAuth: true },\n 'kimi-coding': { name: 'Kimi For Coding', category: 'domestic', supportsApiKey: true, supportsOAuth: true },\n 'xai': { name: 'xAI', category: 'specialty', supportsApiKey: true },\n 'mistral': { name: 'Mistral AI', category: 'specialty', supportsApiKey: true },\n 'cerebras': { name: 'Cerebras', category: 'specialty', supportsApiKey: true },\n 'openrouter': { name: 'OpenRouter', category: 'specialty', supportsApiKey: true },\n 'huggingface': { name: 'Hugging Face', category: 'specialty', supportsApiKey: true },\n moonshotai: { name: 'Moonshot AI (Kimi · International)', category: 'domestic', supportsApiKey: true },\n 'moonshotai-cn': { name: 'Moonshot AI (Kimi · China)', category: 'domestic', supportsApiKey: true },\n fireworks: { name: 'Fireworks AI', category: 'specialty', supportsApiKey: true },\n together: { name: 'Together AI', category: 'specialty', supportsApiKey: true },\n 'cloudflare-workers-ai': { name: 'Cloudflare Workers AI', category: 'enterprise', supportsApiKey: true },\n 'cloudflare-ai-gateway': { name: 'Cloudflare AI Gateway', category: 'enterprise', supportsApiKey: true },\n xiaomi: { name: 'Xiaomi Mimo', category: 'domestic', supportsApiKey: true },\n 'xiaomi-token-plan-cn': { name: 'Xiaomi Token Plan (CN)', category: 'domestic', supportsApiKey: true },\n 'xiaomi-token-plan-ams': { name: 'Xiaomi Token Plan (AMS)', category: 'domestic', supportsApiKey: true },\n 'xiaomi-token-plan-sgp': { name: 'Xiaomi Token Plan (SGP)', category: 'domestic', supportsApiKey: true },\n 'opencode': { name: 'OpenCode', category: 'specialty', supportsApiKey: true },\n 'opencode-go': { name: 'OpenCode Go', category: 'specialty', supportsApiKey: true },\n 'dashscope': { name: 'DashScope (Alibaba)', category: 'domestic', supportsApiKey: true },\n 'dashscope-cn': { name: 'Alibaba Bailian / DashScope China', category: 'domestic', supportsApiKey: true },\n 'dashscope-intl': { name: 'Alibaba Bailian / DashScope International', category: 'domestic', supportsApiKey: true },\n 'volcengine-ark': { name: 'Volcengine Ark', category: 'domestic', supportsApiKey: true },\n 'volcengine-plan': { name: 'Volcengine Doubao Coding Plan', category: 'domestic', supportsApiKey: true },\n 'byteplus-plan': { name: 'BytePlus Doubao Coding Plan', category: 'domestic', supportsApiKey: true },\n 'stepfun': { name: 'StepFun', category: 'domestic', supportsApiKey: true },\n 'stepfun-cn': { name: 'StepFun China', category: 'domestic', supportsApiKey: true },\n 'stepfun-intl': { name: 'StepFun International', category: 'domestic', supportsApiKey: true },\n 'stepfun-plan': { name: 'StepFun Step Plan', category: 'domestic', supportsApiKey: true },\n 'stepfun-plan-cn': { name: 'StepFun Step Plan China', category: 'domestic', supportsApiKey: true },\n 'stepfun-plan-intl': { name: 'StepFun Step Plan International', category: 'domestic', supportsApiKey: true },\n 'ant-ling': { name: 'Ant Ling', category: 'domestic', supportsApiKey: true },\n 'zhipu-cn': { name: 'Zhipu GLM (China)', category: 'domestic', supportsApiKey: true },\n 'zai-coding-cn': { name: 'Zhipu GLM Coding Plan (China)', category: 'domestic', supportsApiKey: true },\n 'zai-coding-global': { name: 'Zhipu GLM Coding Plan (International)', category: 'domestic', supportsApiKey: true },\n 'zhipu-coding-cn': { name: 'Zhipu GLM Coding Plan (China)', category: 'domestic', supportsApiKey: true },\n /** International GLM (api.z.ai). Auth: API key (ZAI_API_KEY); no published OAuth for this HTTP API. */\n 'zai': { name: 'Zhipu GLM (International · z.ai)', category: 'domestic', supportsApiKey: true },\n 'amazon-bedrock': { name: 'Amazon Bedrock', category: 'enterprise', supportsApiKey: true },\n 'azure-openai-responses': { name: 'Azure OpenAI', category: 'enterprise', supportsApiKey: true },\n 'google-vertex': { name: 'Google Vertex AI', category: 'enterprise', supportsApiKey: true },\n 'vercel-ai-gateway': { name: 'Vercel AI Gateway', category: 'enterprise', supportsApiKey: true },\n 'github-copilot': { name: 'GitHub Copilot (OAuth)', category: 'oauth', supportsOAuth: true, supportsApiKey: false },\n 'openai-codex': { name: 'OpenAI Codex (OAuth)', category: 'oauth', supportsOAuth: true, supportsApiKey: false },\n 'google-gemini-cli': { name: 'Google Gemini CLI (OAuth)', category: 'oauth', supportsOAuth: true, supportsApiKey: false },\n 'google-antigravity': { name: 'Google Antigravity (OAuth)', category: 'oauth', supportsOAuth: true, supportsApiKey: false },\n};\n\nexport function getSortedProviders(): string[] {\n const all = getAllProviders();\n const catOrder: Record<ProviderCategory, number> = {\n common: 0,\n domestic: 1,\n specialty: 2,\n enterprise: 3,\n oauth: 4,\n extension: 5,\n };\n const pluginRegistry = getProviderRegistry();\n\n return [...all].sort((a, b) => {\n const catA = pluginRegistry.has(a) ? 'extension' : (PROVIDER_META[a]?.category ?? 'specialty');\n const catB = pluginRegistry.has(b) ? 'extension' : (PROVIDER_META[b]?.category ?? 'specialty');\n if (catOrder[catA] !== catOrder[catB]) {\n return catOrder[catA] - catOrder[catB];\n }\n return a.localeCompare(b);\n });\n}\n\nexport function getProviderDisplayName(provider: string): string {\n const plugin = getProviderRegistry().get(provider);\n if (plugin) return plugin.name;\n return PROVIDER_META[provider]?.name || provider;\n}\n\nexport function providerSupportsOAuth(provider: string): boolean {\n return PROVIDER_META[provider]?.supportsOAuth ?? false;\n}\n\nexport function providerSupportsApiKey(provider: string): boolean {\n return PROVIDER_META[provider]?.supportsApiKey ?? true;\n}\n\n// ============================================\n// Dynamic Default Model Resolution\n// ============================================\n\n/**\n * Get a default model reference.\n * Priority:\n * 1. Effective model inherited from the global default preset / agent presets / agent override\n * 2. Empty string only when no default model is present in the loaded config\n */\nexport async function getDefaultModel(config?: Config | null | undefined): Promise<string> {\n const modelRef = config ? getAgentDefaultModelRef(config) : undefined;\n if (modelRef) {\n const availableModels = await getAvailableModels();\n const configured = availableModels.find(m =>\n `${m.provider}/${m.id}` === modelRef ||\n m.id === modelRef\n );\n if (configured) {\n return `${configured.provider}/${configured.id}`;\n }\n return modelRef;\n }\n\n return '';\n}\n\n/**\n * Synchronous default model resolution for constructors and sync code paths.\n * Uses catalog/registry only (no async credential checks).\n *\n * When no model is present in the loaded config, returns an empty string so\n * setup flows can prompt for the global default model.\n */\nexport function getDefaultModelSync(config?: Config | null | undefined): string {\n const modelRef = config ? getAgentDefaultModelRef(config) : undefined;\n if (modelRef) {\n return modelRef;\n }\n\n return '';\n}\n\n// Re-export ModelRegistry for advanced use cases\nexport { ModelRegistry, getModelRegistry, resetModelRegistry, prewarmModelRegistry } from './model-registry.js';\n"],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { ProviderConfig } from '../config/models-json.js';
2
+ import type { DomesticProviderModelPreset } from './domestic-presets.js';
3
+ export type DiscoverableProviderApi = Extract<NonNullable<ProviderConfig['api']>, 'openai-completions' | 'openai-responses'>;
4
+ export interface DiscoverProviderModelsParams {
5
+ providerId: string;
6
+ baseUrl: string;
7
+ apiKey?: string;
8
+ api?: ProviderConfig['api'];
9
+ headers?: Record<string, string>;
10
+ timeoutMs?: number;
11
+ limit?: number;
12
+ }
13
+ export interface DiscoveredProviderModel extends DomesticProviderModelPreset {
14
+ source: 'live';
15
+ }
16
+ export declare function isProviderApiDiscoverable(api: ProviderConfig['api'] | undefined): api is DiscoverableProviderApi;
17
+ export declare function discoverProviderModels(params: DiscoverProviderModelsParams): Promise<DiscoveredProviderModel[]>;
@@ -0,0 +1,61 @@
1
+ import { init_resolve_config_value, resolveConfigValue, resolveHeaders } from "../config/resolve-config-value.js";
2
+ //#region src/providers/model-discovery.ts
3
+ init_resolve_config_value();
4
+ function joinEndpoint(baseUrl, suffix) {
5
+ return `${baseUrl.replace(/\/+$/, "")}/${suffix.replace(/^\/+/, "")}`;
6
+ }
7
+ function normalizeModelId(row) {
8
+ if (typeof row === "string") return row.trim() || void 0;
9
+ if (!row || typeof row !== "object") return void 0;
10
+ const id = row.id;
11
+ return typeof id === "string" && id.trim() ? id.trim() : void 0;
12
+ }
13
+ function normalizeOpenAiModels(body, limit) {
14
+ const rows = Array.isArray(body.data) ? body.data : [];
15
+ const ids = /* @__PURE__ */ new Set();
16
+ const models = [];
17
+ for (const row of rows) {
18
+ const id = normalizeModelId(row);
19
+ if (!id || ids.has(id)) continue;
20
+ ids.add(id);
21
+ models.push({
22
+ id,
23
+ name: id,
24
+ input: ["text"],
25
+ source: "live"
26
+ });
27
+ if (models.length >= limit) break;
28
+ }
29
+ return models.sort((a, b) => a.id.localeCompare(b.id, void 0, { sensitivity: "base" }));
30
+ }
31
+ function isProviderApiDiscoverable(api) {
32
+ return !api || api === "openai-completions" || api === "openai-responses";
33
+ }
34
+ async function discoverProviderModels(params) {
35
+ if (!isProviderApiDiscoverable(params.api)) throw new Error(`Model discovery is only supported for OpenAI-compatible providers: ${params.providerId}`);
36
+ if (!URL.canParse(params.baseUrl)) throw new Error(`Invalid Base URL for ${params.providerId}`);
37
+ const resolvedApiKey = params.apiKey ? resolveConfigValue(params.apiKey) : void 0;
38
+ const headers = {
39
+ accept: "application/json",
40
+ ...resolveHeaders(params.headers) ?? {}
41
+ };
42
+ if (resolvedApiKey) headers.authorization = `Bearer ${resolvedApiKey}`;
43
+ const timeout = AbortSignal.timeout(params.timeoutMs ?? 1e4);
44
+ const endpoint = joinEndpoint(params.baseUrl, "/models");
45
+ const res = await fetch(endpoint, {
46
+ method: "GET",
47
+ headers,
48
+ signal: timeout
49
+ });
50
+ if (!res.ok) {
51
+ const text = await res.text().catch(() => "");
52
+ throw new Error(`${params.providerId} model discovery failed (${res.status}) at ${endpoint}${text ? `: ${text.slice(0, 300)}` : ""}`);
53
+ }
54
+ const models = normalizeOpenAiModels(await res.json(), params.limit ?? 500);
55
+ if (models.length === 0) throw new Error(`${params.providerId} model discovery returned no model ids`);
56
+ return models;
57
+ }
58
+ //#endregion
59
+ export { discoverProviderModels, isProviderApiDiscoverable };
60
+
61
+ //# sourceMappingURL=model-discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-discovery.js","names":[],"sources":["../../../src/providers/model-discovery.ts"],"sourcesContent":["import type { ProviderConfig } from '../config/models-json.js';\nimport { resolveConfigValue, resolveHeaders } from '../config/resolve-config-value.js';\n\nimport type { DomesticProviderModelPreset } from './domestic-presets.js';\n\nexport type DiscoverableProviderApi = Extract<\n NonNullable<ProviderConfig['api']>,\n 'openai-completions' | 'openai-responses'\n>;\n\nexport interface DiscoverProviderModelsParams {\n providerId: string;\n baseUrl: string;\n apiKey?: string;\n api?: ProviderConfig['api'];\n headers?: Record<string, string>;\n timeoutMs?: number;\n limit?: number;\n}\n\nexport interface DiscoveredProviderModel extends DomesticProviderModelPreset {\n source: 'live';\n}\n\ninterface OpenAiModelsResponse {\n data?: unknown;\n}\n\nfunction joinEndpoint(baseUrl: string, suffix: string): string {\n return `${baseUrl.replace(/\\/+$/, '')}/${suffix.replace(/^\\/+/, '')}`;\n}\n\nfunction normalizeModelId(row: unknown): string | undefined {\n if (typeof row === 'string') return row.trim() || undefined;\n if (!row || typeof row !== 'object') return undefined;\n const id = (row as { id?: unknown }).id;\n return typeof id === 'string' && id.trim() ? id.trim() : undefined;\n}\n\nfunction normalizeOpenAiModels(body: OpenAiModelsResponse, limit: number): DiscoveredProviderModel[] {\n const rows = Array.isArray(body.data) ? body.data : [];\n const ids = new Set<string>();\n const models: DiscoveredProviderModel[] = [];\n for (const row of rows) {\n const id = normalizeModelId(row);\n if (!id || ids.has(id)) continue;\n ids.add(id);\n models.push({ id, name: id, input: ['text'], source: 'live' });\n if (models.length >= limit) break;\n }\n return models.sort((a, b) => a.id.localeCompare(b.id, undefined, { sensitivity: 'base' }));\n}\n\nexport function isProviderApiDiscoverable(api: ProviderConfig['api'] | undefined): api is DiscoverableProviderApi {\n return !api || api === 'openai-completions' || api === 'openai-responses';\n}\n\nexport async function discoverProviderModels(\n params: DiscoverProviderModelsParams,\n): Promise<DiscoveredProviderModel[]> {\n if (!isProviderApiDiscoverable(params.api)) {\n throw new Error(`Model discovery is only supported for OpenAI-compatible providers: ${params.providerId}`);\n }\n if (!URL.canParse(params.baseUrl)) {\n throw new Error(`Invalid Base URL for ${params.providerId}`);\n }\n\n const resolvedApiKey = params.apiKey ? resolveConfigValue(params.apiKey) : undefined;\n const headers: Record<string, string> = {\n accept: 'application/json',\n ...(resolveHeaders(params.headers) ?? {}),\n };\n if (resolvedApiKey) {\n headers.authorization = `Bearer ${resolvedApiKey}`;\n }\n\n const timeout = AbortSignal.timeout(params.timeoutMs ?? 10_000);\n const endpoint = joinEndpoint(params.baseUrl, '/models');\n const res = await fetch(endpoint, {\n method: 'GET',\n headers,\n signal: timeout,\n });\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(\n `${params.providerId} model discovery failed (${res.status}) at ${endpoint}${\n text ? `: ${text.slice(0, 300)}` : ''\n }`,\n );\n }\n\n const body = (await res.json()) as OpenAiModelsResponse;\n const models = normalizeOpenAiModels(body, params.limit ?? 500);\n if (models.length === 0) {\n throw new Error(`${params.providerId} model discovery returned no model ids`);\n }\n return models;\n}\n"],"mappings":";;2BACuF;AA2BvF,SAAS,aAAa,SAAiB,QAAwB;AAC7D,QAAO,GAAG,QAAQ,QAAQ,QAAQ,GAAG,CAAC,GAAG,OAAO,QAAQ,QAAQ,GAAG;;AAGrE,SAAS,iBAAiB,KAAkC;AAC1D,KAAI,OAAO,QAAQ,SAAU,QAAO,IAAI,MAAM,IAAI,KAAA;AAClD,KAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO,KAAA;CAC5C,MAAM,KAAM,IAAyB;AACrC,QAAO,OAAO,OAAO,YAAY,GAAG,MAAM,GAAG,GAAG,MAAM,GAAG,KAAA;;AAG3D,SAAS,sBAAsB,MAA4B,OAA0C;CACnG,MAAM,OAAO,MAAM,QAAQ,KAAK,KAAK,GAAG,KAAK,OAAO,EAAE;CACtD,MAAM,sBAAM,IAAI,KAAa;CAC7B,MAAM,SAAoC,EAAE;AAC5C,MAAK,MAAM,OAAO,MAAM;EACtB,MAAM,KAAK,iBAAiB,IAAI;AAChC,MAAI,CAAC,MAAM,IAAI,IAAI,GAAG,CAAE;AACxB,MAAI,IAAI,GAAG;AACX,SAAO,KAAK;GAAE;GAAI,MAAM;GAAI,OAAO,CAAC,OAAO;GAAE,QAAQ;GAAQ,CAAC;AAC9D,MAAI,OAAO,UAAU,MAAO;;AAE9B,QAAO,OAAO,MAAM,GAAG,MAAM,EAAE,GAAG,cAAc,EAAE,IAAI,KAAA,GAAW,EAAE,aAAa,QAAQ,CAAC,CAAC;;AAG5F,SAAgB,0BAA0B,KAAwE;AAChH,QAAO,CAAC,OAAO,QAAQ,wBAAwB,QAAQ;;AAGzD,eAAsB,uBACpB,QACoC;AACpC,KAAI,CAAC,0BAA0B,OAAO,IAAI,CACxC,OAAM,IAAI,MAAM,sEAAsE,OAAO,aAAa;AAE5G,KAAI,CAAC,IAAI,SAAS,OAAO,QAAQ,CAC/B,OAAM,IAAI,MAAM,wBAAwB,OAAO,aAAa;CAG9D,MAAM,iBAAiB,OAAO,SAAS,mBAAmB,OAAO,OAAO,GAAG,KAAA;CAC3E,MAAM,UAAkC;EACtC,QAAQ;EACR,GAAI,eAAe,OAAO,QAAQ,IAAI,EAAE;EACzC;AACD,KAAI,eACF,SAAQ,gBAAgB,UAAU;CAGpC,MAAM,UAAU,YAAY,QAAQ,OAAO,aAAa,IAAO;CAC/D,MAAM,WAAW,aAAa,OAAO,SAAS,UAAU;CACxD,MAAM,MAAM,MAAM,MAAM,UAAU;EAChC,QAAQ;EACR;EACA,QAAQ;EACT,CAAC;AACF,KAAI,CAAC,IAAI,IAAI;EACX,MAAM,OAAO,MAAM,IAAI,MAAM,CAAC,YAAY,GAAG;AAC7C,QAAM,IAAI,MACR,GAAG,OAAO,WAAW,2BAA2B,IAAI,OAAO,OAAO,WAChE,OAAO,KAAK,KAAK,MAAM,GAAG,IAAI,KAAK,KAEtC;;CAIH,MAAM,SAAS,sBAAsB,MADjB,IAAI,MAAM,EACa,OAAO,SAAS,IAAI;AAC/D,KAAI,OAAO,WAAW,EACpB,OAAM,IAAI,MAAM,GAAG,OAAO,WAAW,wCAAwC;AAE/E,QAAO"}
@@ -9,7 +9,7 @@
9
9
  * - API key resolution with shell commands, env vars, and literals
10
10
  * - Hot reload support
11
11
  */
12
- import { type Api, type Model } from '@earendil-works/pi-ai';
12
+ import { type Api, type Model } from '@earendil-works/pi-ai/compat';
13
13
  /**
14
14
  * Model Registry - manages all models (built-in + custom)
15
15
  */
@@ -6,7 +6,7 @@ import { init_resolve_config_value, resolveConfigValue, resolveHeaders } from ".
6
6
  import { getDefaultModelValues, init_models_json, validateModelsConfig } from "../config/models-json.js";
7
7
  import { getApiKeyFromEnv, init_env_keys } from "./env-keys.js";
8
8
  import { existsSync, readFileSync } from "fs";
9
- import { getModels, getProviders } from "@earendil-works/pi-ai";
9
+ import { getModels, getProviders } from "@earendil-works/pi-ai/compat";
10
10
  //#region src/providers/model-registry.ts
11
11
  /**
12
12
  * Model Registry - manages built-in and custom models from models.json
@@ -1 +1 @@
1
- {"version":3,"file":"model-registry.js","names":["getModelsJsonPath","getPiAiProviders","getPiAiModels"],"sources":["../../../src/providers/model-registry.ts"],"sourcesContent":["/**\n * Model Registry - manages built-in and custom models from models.json\n * \n * Features:\n * - Loads built-in models from @earendil-works/pi-ai\n * - Loads custom models from ~/.xopc/models.json\n * - Supports provider baseUrl/headers overrides\n * - Supports per-model overrides (modelOverrides)\n * - API key resolution with shell commands, env vars, and literals\n * - Hot reload support\n */\n\nimport {\n\ttype Api,\n\tgetModels as getPiAiModels,\n\tgetProviders as getPiAiProviders,\n\ttype Model,\n\ttype KnownProvider,\n} from '@earendil-works/pi-ai';\nimport { existsSync, readFileSync } from 'fs';\nimport { resolveConfigValue, resolveHeaders } from '../config/resolve-config-value.js';\nimport { getModelsJsonPath } from '../config/models-json.js';\nimport type {\n\tModelsJsonConfig,\n\tModelOverride,\n} from '../config/models-json.js';\nimport { validateModelsConfig, getDefaultModelValues } from '../config/models-json.js';\nimport { createLogger } from '../utils/logger.js';\nimport { getApiKeyFromEnv } from './env-keys.js';\n\nconst log = createLogger('ModelRegistry');\n\n/** Provider override config (baseUrl, headers, apiKey) without custom models */\ninterface ProviderOverride {\n\tbaseUrl?: string;\n\theaders?: Record<string, string>;\n\tapiKey?: string;\n}\n\n/** Result of loading custom models from models.json */\ninterface CustomModelsResult {\n\tmodels: Model<Api>[];\n\t/** Providers with baseUrl/headers/apiKey overrides for built-in models */\n\toverrides: Map<string, ProviderOverride>;\n\t/** Per-model overrides: provider -> modelId -> override */\n\tmodelOverrides: Map<string, Map<string, ModelOverride>>;\n\t/** Custom provider API key configs for fallback resolution */\n\tapiKeyConfigs: Map<string, string>;\n\terror: string | undefined;\n}\n\nfunction emptyCustomModelsResult(error?: string): CustomModelsResult {\n\treturn {\n\t\tmodels: [],\n\t\toverrides: new Map(),\n\t\tmodelOverrides: new Map(),\n\t\tapiKeyConfigs: new Map(),\n\t\terror,\n\t};\n}\n\n/**\n * Deep merge compat settings\n */\nfunction mergeCompat(\n\tbaseCompat: Model<Api>['compat'],\n\toverrideCompat: ModelOverride['compat'],\n): Model<Api>['compat'] | undefined {\n\tif (!overrideCompat) return baseCompat;\n\n\tconst base = baseCompat as Record<string, unknown> | undefined;\n\tconst override = overrideCompat as Record<string, unknown>;\n\tconst merged = { ...base, ...override } as Record<string, unknown>;\n\n\t// Deep merge nested routing objects\n\tconst baseCompletions = base as { openRouterRouting?: unknown; vercelGatewayRouting?: unknown } | undefined;\n\tconst overrideCompletions = override as { openRouterRouting?: unknown; vercelGatewayRouting?: unknown };\n\n\tif (baseCompletions?.openRouterRouting || overrideCompletions?.openRouterRouting) {\n\t\t(merged as { openRouterRouting: unknown }).openRouterRouting = {\n\t\t\t...((baseCompletions?.openRouterRouting as object) || {}),\n\t\t\t...((overrideCompletions?.openRouterRouting as object) || {}),\n\t\t};\n\t}\n\n\tif (baseCompletions?.vercelGatewayRouting || overrideCompletions?.vercelGatewayRouting) {\n\t\t(merged as { vercelGatewayRouting: unknown }).vercelGatewayRouting = {\n\t\t\t...((baseCompletions?.vercelGatewayRouting as object) || {}),\n\t\t\t...((overrideCompletions?.vercelGatewayRouting as object) || {}),\n\t\t};\n\t}\n\n\treturn merged as Model<Api>['compat'];\n}\n\n/**\n * Apply a model override to a model\n */\nfunction applyModelOverride(model: Model<Api>, override: ModelOverride): Model<Api> {\n\tconst result = { ...model };\n\n\tif (override.name !== undefined) result.name = override.name;\n\tif (override.reasoning !== undefined) result.reasoning = override.reasoning;\n\tif (override.input !== undefined) result.input = override.input as ('text' | 'image')[];\n\tif (override.contextWindow !== undefined) result.contextWindow = override.contextWindow;\n\tif (override.maxTokens !== undefined) result.maxTokens = override.maxTokens;\n\n\t// Merge cost (partial override)\n\tif (override.cost) {\n\t\tresult.cost = {\n\t\t\tinput: override.cost.input ?? model.cost.input,\n\t\t\toutput: override.cost.output ?? model.cost.output,\n\t\t\tcacheRead: override.cost.cacheRead ?? model.cost.cacheRead,\n\t\t\tcacheWrite: override.cost.cacheWrite ?? model.cost.cacheWrite,\n\t\t};\n\t}\n\n\t// Merge headers\n\tif (override.headers) {\n\t\tconst resolvedHeaders = resolveHeaders(override.headers);\n\t\tresult.headers = resolvedHeaders ? { ...model.headers, ...resolvedHeaders } : model.headers;\n\t}\n\n\t// Deep merge compat\n\tresult.compat = mergeCompat(model.compat, override.compat);\n\n\treturn result;\n}\n\n/**\n * Model Registry - manages all models (built-in + custom)\n */\nexport class ModelRegistry {\n\tprivate models: Model<Api>[] = [];\n\tprivate customProviderApiKeys: Map<string, string> = new Map();\n\tprivate loadError: string | undefined = undefined;\n\tprivate loaded = false;\n\tprivate prewarmPromise: Promise<void> | null = null;\n\n\t// Performance caches\n\tprivate _availableModelsCache: Model<Api>[] | undefined;\n\tprivate _authStatusCache: Map<string, boolean> = new Map();\n\n\tconstructor(private modelsJsonPath: string = getModelsJsonPath()) {\n\t\t// Catalog loads on first use or via prewarm() — keeps gateway constructor off the hot path.\n\t}\n\n\tisLoaded(): boolean {\n\t\treturn this.loaded;\n\t}\n\n\t/** Synchronously materialize the catalog (idempotent). */\n\tensureLoaded(): void {\n\t\tif (this.loaded) {\n\t\t\treturn;\n\t\t}\n\t\tthis.loadModels();\n\t\tthis.loaded = true;\n\t}\n\n\t/** Background-friendly catalog load (idempotent). */\n\tprewarm(): Promise<void> {\n\t\tif (this.loaded) {\n\t\t\treturn Promise.resolve();\n\t\t}\n\t\tif (this.prewarmPromise) {\n\t\t\treturn this.prewarmPromise;\n\t\t}\n\t\tthis.prewarmPromise = Promise.resolve().then(() => {\n\t\t\tthis.ensureLoaded();\n\t\t});\n\t\treturn this.prewarmPromise;\n\t}\n\n\t/**\n\t * Reload models from disk (built-in + custom from models.json)\n\t * Clears all caches\n\t */\n\trefresh(): void {\n\t\tthis.customProviderApiKeys.clear();\n\t\tthis.loadError = undefined;\n\t\tthis._availableModelsCache = undefined;\n\t\tthis._authStatusCache.clear();\n\t\tthis.prewarmPromise = null;\n\t\tthis.loadModels();\n\t\tthis.loaded = true;\n\t\tlog.info('Model registry refreshed');\n\t}\n\n\t/**\n\t * Get any error from loading models.json (undefined if no error)\n\t */\n\tgetError(): string | undefined {\n\t\treturn this.loadError;\n\t}\n\n\t/**\n\t * Get all models (built-in + custom)\n\t * Results are cached until refresh() is called\n\t */\n\tgetAll(): readonly Model<Api>[] {\n\t\tthis.ensureLoaded();\n\t\treturn this.models;\n\t}\n\n\t/**\n\t * Get only models that have auth configured\n\t * Results are cached on first call until refresh()\n\t */\n\tgetAvailable(): readonly Model<Api>[] {\n\t\tthis.ensureLoaded();\n\t\t// Lazy initialization with caching\n\t\tif (!this._availableModelsCache) {\n\t\t\tthis._availableModelsCache = this.models.filter((m) => this.hasAuth(m.provider));\n\t\t}\n\t\treturn this._availableModelsCache;\n\t}\n\n\t/**\n\t * Find a model by provider and ID\n\t */\n\tfind(provider: string, modelId: string): Model<Api> | undefined {\n\t\tthis.ensureLoaded();\n\t\treturn this.models.find((m) => m.provider === provider && m.id === modelId);\n\t}\n\n\t/**\n\t * Resolve a model reference (provider/modelId or just modelId)\n\t */\n\tresolve(ref: string): Model<Api> | undefined {\n\t\tthis.ensureLoaded();\n\t\t// Handle provider/modelId format\n\t\tif (ref.includes('/')) {\n\t\t\tconst [provider, modelId] = ref.split('/');\n\t\t\treturn this.find(provider, modelId);\n\t\t}\n\n\t\t// Try to find by model ID only (search all providers)\n\t\tfor (const model of this.models) {\n\t\t\tif (model.id === ref) {\n\t\t\t\treturn model;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Get API key for a provider (for custom providers from models.json)\n\t */\n\tgetApiKey(provider: string): string | undefined {\n\t\tthis.ensureLoaded();\n\t\t// First check custom provider configs\n\t\tconst keyConfig = this.customProviderApiKeys.get(provider);\n\t\tif (keyConfig) {\n\t\t\treturn resolveConfigValue(keyConfig);\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Check if a provider has auth configured\n\t * Results are cached until refresh() is called\n\t */\n\tprivate hasAuth(provider: string): boolean {\n\t\t// Check cache first\n\t\tif (this._authStatusCache.has(provider)) {\n\t\t\treturn this._authStatusCache.get(provider)!;\n\t\t}\n\n\t\t// Compute and cache\n\t\tlet result: boolean;\n\t\t\n\t\t// Check custom provider configs from models.json first\n\t\tif (this.customProviderApiKeys.has(provider)) {\n\t\t\tconst key = this.getApiKey(provider);\n\t\t\tresult = !!key;\n\t\t} else {\n\t\t\t// Also check environment variables\n\t\t\tconst envKey = getApiKeyFromEnv(provider);\n\t\t\tresult = !!envKey;\n\t\t}\n\n\t\tthis._authStatusCache.set(provider, result);\n\t\treturn result;\n\t}\n\n\t/**\n\t * Load all models\n\t * Clears caches to ensure fresh data\n\t */\n\tprivate loadModels(): void {\n\t\t// Clear caches before loading\n\t\tthis._availableModelsCache = undefined;\n\t\tthis._authStatusCache.clear();\n\n\t\t// Load custom models and overrides from models.json\n\t\tconst {\n\t\t\tmodels: customModels,\n\t\t\toverrides,\n\t\t\tmodelOverrides,\n\t\t\tapiKeyConfigs,\n\t\t\terror,\n\t\t} = this.loadCustomModels();\n\n\t\tif (error) {\n\t\t\tthis.loadError = error;\n\t\t\tlog.warn({ error }, 'Failed to load models.json, using built-in models only');\n\t\t}\n\n\t\t// Store API key configs for fallback resolution\n\t\tthis.customProviderApiKeys = apiKeyConfigs;\n\n\t\t// Load built-in models with overrides applied\n\t\tconst builtInModels = this.loadBuiltInModels(overrides, modelOverrides);\n\n\t\t// Merge custom models\n\t\tthis.models = this.mergeCustomModels(builtInModels, customModels);\n\n\t\tlog.debug(\n\t\t\t{ builtIn: builtInModels.length, custom: customModels.length, total: this.models.length },\n\t\t\t'Models loaded'\n\t\t);\n\t}\n\n\t/**\n\t * Load built-in models and apply provider/model overrides\n\t */\n\tprivate loadBuiltInModels(\n\t\toverrides: Map<string, ProviderOverride>,\n\t\tmodelOverrides: Map<string, Map<string, ModelOverride>>,\n\t): Model<Api>[] {\n\t\treturn getPiAiProviders().flatMap((provider) => {\n\t\t\ttry {\n\t\t\t\tconst models = getPiAiModels(provider as KnownProvider) as Model<Api>[];\n\t\t\t\tconst providerOverride = overrides.get(provider);\n\t\t\t\tconst perModelOverrides = modelOverrides.get(provider);\n\n\t\t\t\treturn models.map((m) => {\n\t\t\t\t\tlet model = m;\n\n\t\t\t\t\t// Apply provider-level baseUrl/headers override\n\t\t\t\t\tif (providerOverride) {\n\t\t\t\t\t\tconst resolvedHeaders = resolveHeaders(providerOverride.headers);\n\t\t\t\t\t\tmodel = {\n\t\t\t\t\t\t\t...model,\n\t\t\t\t\t\t\tbaseUrl: providerOverride.baseUrl ?? model.baseUrl,\n\t\t\t\t\t\t\theaders: resolvedHeaders ? { ...model.headers, ...resolvedHeaders } : model.headers,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\t// Apply per-model override\n\t\t\t\t\tconst modelOverride = perModelOverrides?.get(m.id);\n\t\t\t\t\tif (modelOverride) {\n\t\t\t\t\t\tmodel = applyModelOverride(model, modelOverride);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn model;\n\t\t\t\t});\n\t\t\t} catch (err) {\n\t\t\t\tconst errorMsg = err instanceof Error ? err.message : String(err);\n\t\t\t\tlog.error({ provider, error: errorMsg }, 'Failed to load built-in models for provider');\n\t\t\t\treturn [];\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Merge custom models into built-in list (custom wins on conflicts)\n\t */\n\tprivate mergeCustomModels(builtInModels: Model<Api>[], customModels: Model<Api>[]): Model<Api>[] {\n\t\tconst merged = [...builtInModels];\n\t\tfor (const customModel of customModels) {\n\t\t\tconst existingIndex = merged.findIndex(\n\t\t\t\t(m) => m.provider === customModel.provider && m.id === customModel.id\n\t\t\t);\n\t\t\tif (existingIndex >= 0) {\n\t\t\t\tmerged[existingIndex] = customModel;\n\t\t\t} else {\n\t\t\t\tmerged.push(customModel);\n\t\t\t}\n\t\t}\n\t\treturn merged;\n\t}\n\n\t/**\n\t * Load custom models from models.json\n\t */\n\tprivate loadCustomModels(): CustomModelsResult {\n\t\tif (!existsSync(this.modelsJsonPath)) {\n\t\t\treturn emptyCustomModelsResult();\n\t\t}\n\n\t\ttry {\n\t\t\tconst content = readFileSync(this.modelsJsonPath, 'utf-8');\n\t\t\tconst config: ModelsJsonConfig = JSON.parse(content);\n\n\t\t\t// Validate schema\n\t\t\tconst validation = validateModelsConfig(config);\n\t\t\tif (!validation.valid) {\n\t\t\t\tconst errors = validation.errors\n\t\t\t\t\t.map((e) => ` - ${e.path}: ${e.message}`)\n\t\t\t\t\t.join('\\n');\n\t\t\t\treturn emptyCustomModelsResult(\n\t\t\t\t\t`Invalid models.json schema:\\n${errors}\\n\\nFile: ${this.modelsJsonPath}`\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst overrides = new Map<string, ProviderOverride>();\n\t\t\tconst modelOverrides = new Map<string, Map<string, ModelOverride>>();\n\t\t\tconst apiKeyConfigs = new Map<string, string>();\n\n\t\t\tfor (const [providerName, providerConfig] of Object.entries(config.providers)) {\n\t\t\t\t// Apply provider-level baseUrl/headers/apiKey override\n\t\t\t\tif (providerConfig.baseUrl || providerConfig.headers || providerConfig.apiKey) {\n\t\t\t\t\toverrides.set(providerName, {\n\t\t\t\t\t\tbaseUrl: providerConfig.baseUrl,\n\t\t\t\t\t\theaders: providerConfig.headers,\n\t\t\t\t\t\tapiKey: providerConfig.apiKey,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Store API key config for fallback resolver\n\t\t\t\tif (providerConfig.apiKey) {\n\t\t\t\t\tapiKeyConfigs.set(providerName, providerConfig.apiKey);\n\t\t\t\t}\n\n\t\t\t\t// Store model overrides\n\t\t\t\tif (providerConfig.modelOverrides) {\n\t\t\t\t\tmodelOverrides.set(providerName, new Map(Object.entries(providerConfig.modelOverrides)));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tmodels: this.parseModels(config),\n\t\t\t\toverrides,\n\t\t\t\tmodelOverrides,\n\t\t\t\tapiKeyConfigs,\n\t\t\t\terror: undefined,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tif (error instanceof SyntaxError) {\n\t\t\t\treturn emptyCustomModelsResult(\n\t\t\t\t\t`Failed to parse models.json: ${error.message}\\n\\nFile: ${this.modelsJsonPath}`\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn emptyCustomModelsResult(\n\t\t\t\t`Failed to load models.json: ${error instanceof Error ? error.message : error}\\n\\nFile: ${this.modelsJsonPath}`\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Parse custom models from config\n\t */\n\tprivate parseModels(config: ModelsJsonConfig): Model<Api>[] {\n\t\tconst models: Model<Api>[] = [];\n\t\tconst defaults = getDefaultModelValues();\n\n\t\tfor (const [providerName, providerConfig] of Object.entries(config.providers)) {\n\t\t\tconst modelDefs = providerConfig.models ?? [];\n\t\t\tif (modelDefs.length === 0) continue;\n\n\t\t\tfor (const modelDef of modelDefs) {\n\t\t\t\tconst api = modelDef.api || providerConfig.api;\n\t\t\t\tif (!api) continue;\n\n\t\t\t\t// Merge headers: provider headers are base, model headers override\n\t\t\t\t// Resolve env vars and shell commands in header values\n\t\t\t\tconst providerHeaders = resolveHeaders(providerConfig.headers);\n\t\t\t\tconst modelHeaders = resolveHeaders(modelDef.headers);\n\t\t\t\tlet headers =\n\t\t\t\t\tproviderHeaders || modelHeaders ? { ...providerHeaders, ...modelHeaders } : undefined;\n\n\t\t\t\t// If authHeader is true, add Authorization header with resolved API key\n\t\t\t\tif (providerConfig.authHeader && providerConfig.apiKey) {\n\t\t\t\t\tconst resolvedKey = resolveConfigValue(providerConfig.apiKey);\n\t\t\t\t\tif (resolvedKey) {\n\t\t\t\t\t\theaders = { ...headers, Authorization: `Bearer ${resolvedKey}` };\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tmodels.push({\n\t\t\t\t\tid: modelDef.id,\n\t\t\t\t\tname: modelDef.name ?? modelDef.id,\n\t\t\t\t\tapi: api as Api,\n\t\t\t\t\tprovider: providerName,\n\t\t\t\t\tbaseUrl: providerConfig.baseUrl!,\n\t\t\t\t\treasoning: modelDef.reasoning ?? false,\n\t\t\t\t\tinput: (modelDef.input ?? defaults.input) as ('text' | 'image')[],\n\t\t\t\t\tcost: modelDef.cost ?? defaults.cost,\n\t\t\t\t\tcontextWindow: modelDef.contextWindow ?? defaults.contextWindow,\n\t\t\t\t\tmaxTokens: modelDef.maxTokens ?? defaults.maxTokens,\n\t\t\t\t\theaders,\n\t\t\t\t\tcompat: modelDef.compat as Model<Api>['compat'],\n\t\t\t\t} as Model<Api>);\n\t\t\t}\n\t\t}\n\n\t\treturn models;\n\t}\n}\n\n// ============================================\n// Global Registry Instance\n// ============================================\n\nlet globalRegistry: ModelRegistry | undefined;\n\nexport function getModelRegistry(): ModelRegistry {\n\tif (!globalRegistry) {\n\t\tglobalRegistry = new ModelRegistry();\n\t}\n\treturn globalRegistry;\n}\n\nexport function resetModelRegistry(): void {\n\tglobalRegistry = undefined;\n}\n\n/** Schedule catalog load on a background turn (gateway post-ready sidecar). */\nexport function prewarmModelRegistry(): Promise<void> {\n\treturn getModelRegistry().prewarm();\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"model-registry.js","names":["getModelsJsonPath","getPiAiProviders","getPiAiModels"],"sources":["../../../src/providers/model-registry.ts"],"sourcesContent":["/**\n * Model Registry - manages built-in and custom models from models.json\n * \n * Features:\n * - Loads built-in models from @earendil-works/pi-ai\n * - Loads custom models from ~/.xopc/models.json\n * - Supports provider baseUrl/headers overrides\n * - Supports per-model overrides (modelOverrides)\n * - API key resolution with shell commands, env vars, and literals\n * - Hot reload support\n */\n\nimport {\n\ttype Api,\n\tgetModels as getPiAiModels,\n\tgetProviders as getPiAiProviders,\n\ttype Model,\n\ttype KnownProvider,\n} from '@earendil-works/pi-ai/compat';\nimport { existsSync, readFileSync } from 'fs';\nimport { resolveConfigValue, resolveHeaders } from '../config/resolve-config-value.js';\nimport { getModelsJsonPath } from '../config/models-json.js';\nimport type {\n\tModelsJsonConfig,\n\tModelOverride,\n} from '../config/models-json.js';\nimport { validateModelsConfig, getDefaultModelValues } from '../config/models-json.js';\nimport { createLogger } from '../utils/logger.js';\nimport { getApiKeyFromEnv } from './env-keys.js';\n\nconst log = createLogger('ModelRegistry');\n\n/** Provider override config (baseUrl, headers, apiKey) without custom models */\ninterface ProviderOverride {\n\tbaseUrl?: string;\n\theaders?: Record<string, string>;\n\tapiKey?: string;\n}\n\n/** Result of loading custom models from models.json */\ninterface CustomModelsResult {\n\tmodels: Model<Api>[];\n\t/** Providers with baseUrl/headers/apiKey overrides for built-in models */\n\toverrides: Map<string, ProviderOverride>;\n\t/** Per-model overrides: provider -> modelId -> override */\n\tmodelOverrides: Map<string, Map<string, ModelOverride>>;\n\t/** Custom provider API key configs for fallback resolution */\n\tapiKeyConfigs: Map<string, string>;\n\terror: string | undefined;\n}\n\nfunction emptyCustomModelsResult(error?: string): CustomModelsResult {\n\treturn {\n\t\tmodels: [],\n\t\toverrides: new Map(),\n\t\tmodelOverrides: new Map(),\n\t\tapiKeyConfigs: new Map(),\n\t\terror,\n\t};\n}\n\n/**\n * Deep merge compat settings\n */\nfunction mergeCompat(\n\tbaseCompat: Model<Api>['compat'],\n\toverrideCompat: ModelOverride['compat'],\n): Model<Api>['compat'] | undefined {\n\tif (!overrideCompat) return baseCompat;\n\n\tconst base = baseCompat as Record<string, unknown> | undefined;\n\tconst override = overrideCompat as Record<string, unknown>;\n\tconst merged = { ...base, ...override } as Record<string, unknown>;\n\n\t// Deep merge nested routing objects\n\tconst baseCompletions = base as { openRouterRouting?: unknown; vercelGatewayRouting?: unknown } | undefined;\n\tconst overrideCompletions = override as { openRouterRouting?: unknown; vercelGatewayRouting?: unknown };\n\n\tif (baseCompletions?.openRouterRouting || overrideCompletions?.openRouterRouting) {\n\t\t(merged as { openRouterRouting: unknown }).openRouterRouting = {\n\t\t\t...((baseCompletions?.openRouterRouting as object) || {}),\n\t\t\t...((overrideCompletions?.openRouterRouting as object) || {}),\n\t\t};\n\t}\n\n\tif (baseCompletions?.vercelGatewayRouting || overrideCompletions?.vercelGatewayRouting) {\n\t\t(merged as { vercelGatewayRouting: unknown }).vercelGatewayRouting = {\n\t\t\t...((baseCompletions?.vercelGatewayRouting as object) || {}),\n\t\t\t...((overrideCompletions?.vercelGatewayRouting as object) || {}),\n\t\t};\n\t}\n\n\treturn merged as Model<Api>['compat'];\n}\n\n/**\n * Apply a model override to a model\n */\nfunction applyModelOverride(model: Model<Api>, override: ModelOverride): Model<Api> {\n\tconst result = { ...model };\n\n\tif (override.name !== undefined) result.name = override.name;\n\tif (override.reasoning !== undefined) result.reasoning = override.reasoning;\n\tif (override.input !== undefined) result.input = override.input as ('text' | 'image')[];\n\tif (override.contextWindow !== undefined) result.contextWindow = override.contextWindow;\n\tif (override.maxTokens !== undefined) result.maxTokens = override.maxTokens;\n\n\t// Merge cost (partial override)\n\tif (override.cost) {\n\t\tresult.cost = {\n\t\t\tinput: override.cost.input ?? model.cost.input,\n\t\t\toutput: override.cost.output ?? model.cost.output,\n\t\t\tcacheRead: override.cost.cacheRead ?? model.cost.cacheRead,\n\t\t\tcacheWrite: override.cost.cacheWrite ?? model.cost.cacheWrite,\n\t\t};\n\t}\n\n\t// Merge headers\n\tif (override.headers) {\n\t\tconst resolvedHeaders = resolveHeaders(override.headers);\n\t\tresult.headers = resolvedHeaders ? { ...model.headers, ...resolvedHeaders } : model.headers;\n\t}\n\n\t// Deep merge compat\n\tresult.compat = mergeCompat(model.compat, override.compat);\n\n\treturn result;\n}\n\n/**\n * Model Registry - manages all models (built-in + custom)\n */\nexport class ModelRegistry {\n\tprivate models: Model<Api>[] = [];\n\tprivate customProviderApiKeys: Map<string, string> = new Map();\n\tprivate loadError: string | undefined = undefined;\n\tprivate loaded = false;\n\tprivate prewarmPromise: Promise<void> | null = null;\n\n\t// Performance caches\n\tprivate _availableModelsCache: Model<Api>[] | undefined;\n\tprivate _authStatusCache: Map<string, boolean> = new Map();\n\n\tconstructor(private modelsJsonPath: string = getModelsJsonPath()) {\n\t\t// Catalog loads on first use or via prewarm() — keeps gateway constructor off the hot path.\n\t}\n\n\tisLoaded(): boolean {\n\t\treturn this.loaded;\n\t}\n\n\t/** Synchronously materialize the catalog (idempotent). */\n\tensureLoaded(): void {\n\t\tif (this.loaded) {\n\t\t\treturn;\n\t\t}\n\t\tthis.loadModels();\n\t\tthis.loaded = true;\n\t}\n\n\t/** Background-friendly catalog load (idempotent). */\n\tprewarm(): Promise<void> {\n\t\tif (this.loaded) {\n\t\t\treturn Promise.resolve();\n\t\t}\n\t\tif (this.prewarmPromise) {\n\t\t\treturn this.prewarmPromise;\n\t\t}\n\t\tthis.prewarmPromise = Promise.resolve().then(() => {\n\t\t\tthis.ensureLoaded();\n\t\t});\n\t\treturn this.prewarmPromise;\n\t}\n\n\t/**\n\t * Reload models from disk (built-in + custom from models.json)\n\t * Clears all caches\n\t */\n\trefresh(): void {\n\t\tthis.customProviderApiKeys.clear();\n\t\tthis.loadError = undefined;\n\t\tthis._availableModelsCache = undefined;\n\t\tthis._authStatusCache.clear();\n\t\tthis.prewarmPromise = null;\n\t\tthis.loadModels();\n\t\tthis.loaded = true;\n\t\tlog.info('Model registry refreshed');\n\t}\n\n\t/**\n\t * Get any error from loading models.json (undefined if no error)\n\t */\n\tgetError(): string | undefined {\n\t\treturn this.loadError;\n\t}\n\n\t/**\n\t * Get all models (built-in + custom)\n\t * Results are cached until refresh() is called\n\t */\n\tgetAll(): readonly Model<Api>[] {\n\t\tthis.ensureLoaded();\n\t\treturn this.models;\n\t}\n\n\t/**\n\t * Get only models that have auth configured\n\t * Results are cached on first call until refresh()\n\t */\n\tgetAvailable(): readonly Model<Api>[] {\n\t\tthis.ensureLoaded();\n\t\t// Lazy initialization with caching\n\t\tif (!this._availableModelsCache) {\n\t\t\tthis._availableModelsCache = this.models.filter((m) => this.hasAuth(m.provider));\n\t\t}\n\t\treturn this._availableModelsCache;\n\t}\n\n\t/**\n\t * Find a model by provider and ID\n\t */\n\tfind(provider: string, modelId: string): Model<Api> | undefined {\n\t\tthis.ensureLoaded();\n\t\treturn this.models.find((m) => m.provider === provider && m.id === modelId);\n\t}\n\n\t/**\n\t * Resolve a model reference (provider/modelId or just modelId)\n\t */\n\tresolve(ref: string): Model<Api> | undefined {\n\t\tthis.ensureLoaded();\n\t\t// Handle provider/modelId format\n\t\tif (ref.includes('/')) {\n\t\t\tconst [provider, modelId] = ref.split('/');\n\t\t\treturn this.find(provider, modelId);\n\t\t}\n\n\t\t// Try to find by model ID only (search all providers)\n\t\tfor (const model of this.models) {\n\t\t\tif (model.id === ref) {\n\t\t\t\treturn model;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Get API key for a provider (for custom providers from models.json)\n\t */\n\tgetApiKey(provider: string): string | undefined {\n\t\tthis.ensureLoaded();\n\t\t// First check custom provider configs\n\t\tconst keyConfig = this.customProviderApiKeys.get(provider);\n\t\tif (keyConfig) {\n\t\t\treturn resolveConfigValue(keyConfig);\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Check if a provider has auth configured\n\t * Results are cached until refresh() is called\n\t */\n\tprivate hasAuth(provider: string): boolean {\n\t\t// Check cache first\n\t\tif (this._authStatusCache.has(provider)) {\n\t\t\treturn this._authStatusCache.get(provider)!;\n\t\t}\n\n\t\t// Compute and cache\n\t\tlet result: boolean;\n\t\t\n\t\t// Check custom provider configs from models.json first\n\t\tif (this.customProviderApiKeys.has(provider)) {\n\t\t\tconst key = this.getApiKey(provider);\n\t\t\tresult = !!key;\n\t\t} else {\n\t\t\t// Also check environment variables\n\t\t\tconst envKey = getApiKeyFromEnv(provider);\n\t\t\tresult = !!envKey;\n\t\t}\n\n\t\tthis._authStatusCache.set(provider, result);\n\t\treturn result;\n\t}\n\n\t/**\n\t * Load all models\n\t * Clears caches to ensure fresh data\n\t */\n\tprivate loadModels(): void {\n\t\t// Clear caches before loading\n\t\tthis._availableModelsCache = undefined;\n\t\tthis._authStatusCache.clear();\n\n\t\t// Load custom models and overrides from models.json\n\t\tconst {\n\t\t\tmodels: customModels,\n\t\t\toverrides,\n\t\t\tmodelOverrides,\n\t\t\tapiKeyConfigs,\n\t\t\terror,\n\t\t} = this.loadCustomModels();\n\n\t\tif (error) {\n\t\t\tthis.loadError = error;\n\t\t\tlog.warn({ error }, 'Failed to load models.json, using built-in models only');\n\t\t}\n\n\t\t// Store API key configs for fallback resolution\n\t\tthis.customProviderApiKeys = apiKeyConfigs;\n\n\t\t// Load built-in models with overrides applied\n\t\tconst builtInModels = this.loadBuiltInModels(overrides, modelOverrides);\n\n\t\t// Merge custom models\n\t\tthis.models = this.mergeCustomModels(builtInModels, customModels);\n\n\t\tlog.debug(\n\t\t\t{ builtIn: builtInModels.length, custom: customModels.length, total: this.models.length },\n\t\t\t'Models loaded'\n\t\t);\n\t}\n\n\t/**\n\t * Load built-in models and apply provider/model overrides\n\t */\n\tprivate loadBuiltInModels(\n\t\toverrides: Map<string, ProviderOverride>,\n\t\tmodelOverrides: Map<string, Map<string, ModelOverride>>,\n\t): Model<Api>[] {\n\t\treturn getPiAiProviders().flatMap((provider) => {\n\t\t\ttry {\n\t\t\t\tconst models = getPiAiModels(provider as KnownProvider) as Model<Api>[];\n\t\t\t\tconst providerOverride = overrides.get(provider);\n\t\t\t\tconst perModelOverrides = modelOverrides.get(provider);\n\n\t\t\t\treturn models.map((m) => {\n\t\t\t\t\tlet model = m;\n\n\t\t\t\t\t// Apply provider-level baseUrl/headers override\n\t\t\t\t\tif (providerOverride) {\n\t\t\t\t\t\tconst resolvedHeaders = resolveHeaders(providerOverride.headers);\n\t\t\t\t\t\tmodel = {\n\t\t\t\t\t\t\t...model,\n\t\t\t\t\t\t\tbaseUrl: providerOverride.baseUrl ?? model.baseUrl,\n\t\t\t\t\t\t\theaders: resolvedHeaders ? { ...model.headers, ...resolvedHeaders } : model.headers,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\t// Apply per-model override\n\t\t\t\t\tconst modelOverride = perModelOverrides?.get(m.id);\n\t\t\t\t\tif (modelOverride) {\n\t\t\t\t\t\tmodel = applyModelOverride(model, modelOverride);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn model;\n\t\t\t\t});\n\t\t\t} catch (err) {\n\t\t\t\tconst errorMsg = err instanceof Error ? err.message : String(err);\n\t\t\t\tlog.error({ provider, error: errorMsg }, 'Failed to load built-in models for provider');\n\t\t\t\treturn [];\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Merge custom models into built-in list (custom wins on conflicts)\n\t */\n\tprivate mergeCustomModels(builtInModels: Model<Api>[], customModels: Model<Api>[]): Model<Api>[] {\n\t\tconst merged = [...builtInModels];\n\t\tfor (const customModel of customModels) {\n\t\t\tconst existingIndex = merged.findIndex(\n\t\t\t\t(m) => m.provider === customModel.provider && m.id === customModel.id\n\t\t\t);\n\t\t\tif (existingIndex >= 0) {\n\t\t\t\tmerged[existingIndex] = customModel;\n\t\t\t} else {\n\t\t\t\tmerged.push(customModel);\n\t\t\t}\n\t\t}\n\t\treturn merged;\n\t}\n\n\t/**\n\t * Load custom models from models.json\n\t */\n\tprivate loadCustomModels(): CustomModelsResult {\n\t\tif (!existsSync(this.modelsJsonPath)) {\n\t\t\treturn emptyCustomModelsResult();\n\t\t}\n\n\t\ttry {\n\t\t\tconst content = readFileSync(this.modelsJsonPath, 'utf-8');\n\t\t\tconst config: ModelsJsonConfig = JSON.parse(content);\n\n\t\t\t// Validate schema\n\t\t\tconst validation = validateModelsConfig(config);\n\t\t\tif (!validation.valid) {\n\t\t\t\tconst errors = validation.errors\n\t\t\t\t\t.map((e) => ` - ${e.path}: ${e.message}`)\n\t\t\t\t\t.join('\\n');\n\t\t\t\treturn emptyCustomModelsResult(\n\t\t\t\t\t`Invalid models.json schema:\\n${errors}\\n\\nFile: ${this.modelsJsonPath}`\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst overrides = new Map<string, ProviderOverride>();\n\t\t\tconst modelOverrides = new Map<string, Map<string, ModelOverride>>();\n\t\t\tconst apiKeyConfigs = new Map<string, string>();\n\n\t\t\tfor (const [providerName, providerConfig] of Object.entries(config.providers)) {\n\t\t\t\t// Apply provider-level baseUrl/headers/apiKey override\n\t\t\t\tif (providerConfig.baseUrl || providerConfig.headers || providerConfig.apiKey) {\n\t\t\t\t\toverrides.set(providerName, {\n\t\t\t\t\t\tbaseUrl: providerConfig.baseUrl,\n\t\t\t\t\t\theaders: providerConfig.headers,\n\t\t\t\t\t\tapiKey: providerConfig.apiKey,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Store API key config for fallback resolver\n\t\t\t\tif (providerConfig.apiKey) {\n\t\t\t\t\tapiKeyConfigs.set(providerName, providerConfig.apiKey);\n\t\t\t\t}\n\n\t\t\t\t// Store model overrides\n\t\t\t\tif (providerConfig.modelOverrides) {\n\t\t\t\t\tmodelOverrides.set(providerName, new Map(Object.entries(providerConfig.modelOverrides)));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tmodels: this.parseModels(config),\n\t\t\t\toverrides,\n\t\t\t\tmodelOverrides,\n\t\t\t\tapiKeyConfigs,\n\t\t\t\terror: undefined,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tif (error instanceof SyntaxError) {\n\t\t\t\treturn emptyCustomModelsResult(\n\t\t\t\t\t`Failed to parse models.json: ${error.message}\\n\\nFile: ${this.modelsJsonPath}`\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn emptyCustomModelsResult(\n\t\t\t\t`Failed to load models.json: ${error instanceof Error ? error.message : error}\\n\\nFile: ${this.modelsJsonPath}`\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Parse custom models from config\n\t */\n\tprivate parseModels(config: ModelsJsonConfig): Model<Api>[] {\n\t\tconst models: Model<Api>[] = [];\n\t\tconst defaults = getDefaultModelValues();\n\n\t\tfor (const [providerName, providerConfig] of Object.entries(config.providers)) {\n\t\t\tconst modelDefs = providerConfig.models ?? [];\n\t\t\tif (modelDefs.length === 0) continue;\n\n\t\t\tfor (const modelDef of modelDefs) {\n\t\t\t\tconst api = modelDef.api || providerConfig.api;\n\t\t\t\tif (!api) continue;\n\n\t\t\t\t// Merge headers: provider headers are base, model headers override\n\t\t\t\t// Resolve env vars and shell commands in header values\n\t\t\t\tconst providerHeaders = resolveHeaders(providerConfig.headers);\n\t\t\t\tconst modelHeaders = resolveHeaders(modelDef.headers);\n\t\t\t\tlet headers =\n\t\t\t\t\tproviderHeaders || modelHeaders ? { ...providerHeaders, ...modelHeaders } : undefined;\n\n\t\t\t\t// If authHeader is true, add Authorization header with resolved API key\n\t\t\t\tif (providerConfig.authHeader && providerConfig.apiKey) {\n\t\t\t\t\tconst resolvedKey = resolveConfigValue(providerConfig.apiKey);\n\t\t\t\t\tif (resolvedKey) {\n\t\t\t\t\t\theaders = { ...headers, Authorization: `Bearer ${resolvedKey}` };\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tmodels.push({\n\t\t\t\t\tid: modelDef.id,\n\t\t\t\t\tname: modelDef.name ?? modelDef.id,\n\t\t\t\t\tapi: api as Api,\n\t\t\t\t\tprovider: providerName,\n\t\t\t\t\tbaseUrl: providerConfig.baseUrl!,\n\t\t\t\t\treasoning: modelDef.reasoning ?? false,\n\t\t\t\t\tinput: (modelDef.input ?? defaults.input) as ('text' | 'image')[],\n\t\t\t\t\tcost: modelDef.cost ?? defaults.cost,\n\t\t\t\t\tcontextWindow: modelDef.contextWindow ?? defaults.contextWindow,\n\t\t\t\t\tmaxTokens: modelDef.maxTokens ?? defaults.maxTokens,\n\t\t\t\t\theaders,\n\t\t\t\t\tcompat: modelDef.compat as Model<Api>['compat'],\n\t\t\t\t} as Model<Api>);\n\t\t\t}\n\t\t}\n\n\t\treturn models;\n\t}\n}\n\n// ============================================\n// Global Registry Instance\n// ============================================\n\nlet globalRegistry: ModelRegistry | undefined;\n\nexport function getModelRegistry(): ModelRegistry {\n\tif (!globalRegistry) {\n\t\tglobalRegistry = new ModelRegistry();\n\t}\n\treturn globalRegistry;\n}\n\nexport function resetModelRegistry(): void {\n\tglobalRegistry = undefined;\n}\n\n/** Schedule catalog load on a background turn (gateway post-ready sidecar). */\nexport function prewarmModelRegistry(): Promise<void> {\n\treturn getModelRegistry().prewarm();\n}\n"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { getProviderRegistry, init_plugin_registry } from "./plugin-registry.js";
2
2
  import { PROVIDER_META, getAllModels, getAllProviders, getModelsByProvider, getProviderDisplayName, init_providers, isProviderConfigured } from "./index.js";
3
+ import { getDomesticProviderPreset, getDomesticProviderPresetIds } from "./domestic-presets.js";
3
4
  //#region src/providers/presentation.ts
4
5
  init_providers();
5
6
  init_plugin_registry();
@@ -9,7 +10,28 @@ const FEATURED_PROVIDER_ORDER = [
9
10
  "xai",
10
11
  "google",
11
12
  "openrouter",
12
- "deepseek"
13
+ "dashscope-cn",
14
+ "dashscope-intl",
15
+ "volcengine-ark",
16
+ "volcengine-plan",
17
+ "byteplus-plan",
18
+ "deepseek",
19
+ "moonshotai",
20
+ "moonshotai-cn",
21
+ "kimi-coding",
22
+ "stepfun-cn",
23
+ "stepfun-intl",
24
+ "stepfun-plan-cn",
25
+ "stepfun-plan-intl",
26
+ "xiaomi",
27
+ "xiaomi-token-plan-cn",
28
+ "ant-ling",
29
+ "zhipu-cn",
30
+ "zai",
31
+ "zai-coding-cn",
32
+ "zhipu-coding-cn",
33
+ "minimax",
34
+ "minimax-cn"
13
35
  ];
14
36
  const PROVIDER_HINTS = {
15
37
  openai: "Frontier OpenAI models from the official API.",
@@ -17,7 +39,34 @@ const PROVIDER_HINTS = {
17
39
  xai: "Grok models from xAI.",
18
40
  google: "Gemini models with strong multimodal and long-context support.",
19
41
  openrouter: "Route many hosted models through one API key.",
42
+ dashscope: "DashScope service provider for Alibaba Model Studio.",
43
+ "dashscope-cn": "Alibaba Bailian Qwen models through the China OpenAI-compatible endpoint.",
44
+ "dashscope-intl": "Alibaba Bailian Qwen models through the international OpenAI-compatible endpoint.",
45
+ "volcengine-ark": "Volcengine Ark OpenAI-compatible endpoints; use your Ark endpoint id as the model id.",
46
+ "volcengine-plan": "Doubao coding-plan models through Volcengine Ark.",
47
+ "byteplus-plan": "Doubao coding-plan models through BytePlus.",
20
48
  deepseek: "DeepSeek V4 models with strong price/performance.",
49
+ moonshotai: "Kimi models through Moonshot International.",
50
+ "moonshotai-cn": "Kimi models through Moonshot China.",
51
+ "kimi-coding": "Kimi dedicated coding endpoint with Anthropic-compatible requests.",
52
+ stepfun: "StepFun OpenAI-compatible endpoint.",
53
+ "stepfun-cn": "StepFun China OpenAI-compatible endpoint.",
54
+ "stepfun-intl": "StepFun international OpenAI-compatible endpoint.",
55
+ "stepfun-plan": "StepFun Step Plan coding/planning endpoint.",
56
+ "stepfun-plan-cn": "StepFun Step Plan China coding/planning endpoint.",
57
+ "stepfun-plan-intl": "StepFun Step Plan international coding/planning endpoint.",
58
+ xiaomi: "Xiaomi MiMo OpenAI-compatible model access.",
59
+ "xiaomi-token-plan-cn": "Xiaomi MiMo Token Plan China endpoint.",
60
+ "xiaomi-token-plan-ams": "Xiaomi MiMo Token Plan Amsterdam endpoint.",
61
+ "xiaomi-token-plan-sgp": "Xiaomi MiMo Token Plan Singapore endpoint.",
62
+ "ant-ling": "Ant Ling models through a domestic OpenAI-compatible endpoint.",
63
+ "zhipu-cn": "Zhipu GLM China through the BigModel OpenAI-compatible API.",
64
+ zai: "Zhipu GLM International through z.ai.",
65
+ "zai-coding-cn": "Zhipu GLM coding-plan China endpoint from pi-ai.",
66
+ "zai-coding-global": "Zhipu GLM coding-plan international endpoint.",
67
+ "zhipu-coding-cn": "Zhipu GLM coding-plan China endpoint.",
68
+ minimax: "MiniMax text models; Anthropic-compatible endpoint is preferred for agent workflows.",
69
+ "minimax-cn": "MiniMax China endpoint for domestic access.",
21
70
  "openai-codex": "OpenAI Codex models through OAuth.",
22
71
  "google-gemini-cli": "Gemini through Google Cloud Code Assist OAuth.",
23
72
  "google-antigravity": "Gemini/Antigravity OAuth model access."
@@ -54,6 +103,32 @@ const RECOMMENDED_MODEL_PATTERNS = {
54
103
  /^grok-3/i,
55
104
  /^grok-code/i
56
105
  ],
106
+ dashscope: [
107
+ /^qwen3\.7-plus$/i,
108
+ /^qwen3\.7-max$/i,
109
+ /^qwen3\.6-flash$/i
110
+ ],
111
+ "dashscope-cn": [
112
+ /^qwen3\.7-plus$/i,
113
+ /^qwen3\.7-max$/i,
114
+ /^qwen3\.6-flash$/i
115
+ ],
116
+ "dashscope-intl": [
117
+ /^qwen3\.7-plus$/i,
118
+ /^qwen3\.7-max$/i,
119
+ /^qwen3\.6-flash$/i
120
+ ],
121
+ "volcengine-ark": [/^ep-your-endpoint-id$/i],
122
+ "volcengine-plan": [
123
+ /^ark-code-latest$/i,
124
+ /^doubao-seed-2\.0-code$/i,
125
+ /^doubao-seed-2\.0-pro$/i
126
+ ],
127
+ "byteplus-plan": [
128
+ /^ark-code-latest$/i,
129
+ /^doubao-seed-2\.0-code$/i,
130
+ /^doubao-seed-2\.0-pro$/i
131
+ ],
57
132
  deepseek: [/^deepseek-v4-flash$/i, /^deepseek-v4-pro$/i],
58
133
  openrouter: [
59
134
  /^openai\/gpt-5/i,
@@ -61,14 +136,89 @@ const RECOMMENDED_MODEL_PATTERNS = {
61
136
  /^google\/gemini-3/i
62
137
  ],
63
138
  moonshotai: [
139
+ /^kimi-k2\.7-code$/i,
64
140
  /^kimi-k2\.6$/i,
65
- /^kimi-k2\.5$/i,
66
- /^kimi-k2-thinking/i
141
+ /^kimi-k2\.5$/i
67
142
  ],
68
143
  "moonshotai-cn": [
144
+ /^kimi-k2\.7-code$/i,
69
145
  /^kimi-k2\.6$/i,
70
- /^kimi-k2\.5$/i,
71
- /^kimi-k2-thinking/i
146
+ /^kimi-k2\.5$/i
147
+ ],
148
+ "kimi-coding": [/^kimi-k2\.7-code$/i, /^kimi-for-coding$/i],
149
+ stepfun: [
150
+ /^step-3\.7-flash$/i,
151
+ /^step-3\.5-flash-2603$/i,
152
+ /^step-3\.5-flash$/i
153
+ ],
154
+ "stepfun-cn": [
155
+ /^step-3\.7-flash$/i,
156
+ /^step-3\.5-flash-2603$/i,
157
+ /^step-3\.5-flash$/i
158
+ ],
159
+ "stepfun-intl": [
160
+ /^step-3\.7-flash$/i,
161
+ /^step-3\.5-flash-2603$/i,
162
+ /^step-3\.5-flash$/i
163
+ ],
164
+ "stepfun-plan": [
165
+ /^step-3\.7-flash$/i,
166
+ /^step-3\.5-flash-2603$/i,
167
+ /^step-3\.5-flash$/i
168
+ ],
169
+ "stepfun-plan-cn": [
170
+ /^step-3\.7-flash$/i,
171
+ /^step-3\.5-flash-2603$/i,
172
+ /^step-3\.5-flash$/i
173
+ ],
174
+ "stepfun-plan-intl": [
175
+ /^step-3\.7-flash$/i,
176
+ /^step-3\.5-flash-2603$/i,
177
+ /^step-3\.5-flash$/i
178
+ ],
179
+ xiaomi: [
180
+ /^mimo-v2\.5-pro$/i,
181
+ /^mimo-v2\.5-pro-ultraspeed$/i,
182
+ /^mimo-v2\.5$/i
183
+ ],
184
+ "xiaomi-token-plan-cn": [
185
+ /^mimo-v2\.5-pro$/i,
186
+ /^mimo-v2\.5-pro-ultraspeed$/i,
187
+ /^mimo-v2\.5$/i
188
+ ],
189
+ "xiaomi-token-plan-ams": [
190
+ /^mimo-v2\.5-pro$/i,
191
+ /^mimo-v2\.5-pro-ultraspeed$/i,
192
+ /^mimo-v2\.5$/i
193
+ ],
194
+ "xiaomi-token-plan-sgp": [
195
+ /^mimo-v2\.5-pro$/i,
196
+ /^mimo-v2\.5-pro-ultraspeed$/i,
197
+ /^mimo-v2\.5$/i
198
+ ],
199
+ "ant-ling": [
200
+ /^Ling-2\.6-1T$/i,
201
+ /^Ling-2\.6-flash$/i,
202
+ /^Ring-2\.6-1T$/i
203
+ ],
204
+ "zhipu-cn": [/^glm-5\.2$/i],
205
+ zai: [/^glm-5\.2$/i],
206
+ "zai-coding-cn": [
207
+ /^glm-5\.2$/i,
208
+ /^glm-5\.1$/i,
209
+ /^glm-5-turbo$/i
210
+ ],
211
+ "zai-coding-global": [/^glm-5\.2$/i],
212
+ "zhipu-coding-cn": [/^glm-5\.2$/i],
213
+ minimax: [
214
+ /^MiniMax-M3$/i,
215
+ /^MiniMax-M2\.7-highspeed$/i,
216
+ /^MiniMax-M2\.7$/i
217
+ ],
218
+ "minimax-cn": [
219
+ /^MiniMax-M3$/i,
220
+ /^MiniMax-M2\.7-highspeed$/i,
221
+ /^MiniMax-M2\.7$/i
72
222
  ]
73
223
  };
74
224
  function modelRef(model) {
@@ -96,6 +246,21 @@ function modelToCatalogView(model) {
96
246
  recommended: isRecommendedModel(model.provider, model.id)
97
247
  };
98
248
  }
249
+ function presetModelToCatalogView(provider, model) {
250
+ const input = model.input ?? ["text"];
251
+ return {
252
+ ref: `${provider}/${model.id}`,
253
+ provider,
254
+ id: model.id,
255
+ name: model.name || model.id,
256
+ reasoning: model.reasoning ?? false,
257
+ input,
258
+ ...model.contextWindow ? { contextWindow: model.contextWindow } : {},
259
+ ...model.maxTokens ? { maxTokens: model.maxTokens } : {},
260
+ vision: input.includes("image"),
261
+ recommended: isRecommendedModel(provider, model.id)
262
+ };
263
+ }
99
264
  function sortModelsForPicker(models) {
100
265
  return [...models].sort((a, b) => {
101
266
  const aRank = recommendedRank(a.provider, a.id);
@@ -106,13 +271,17 @@ function sortModelsForPicker(models) {
106
271
  });
107
272
  }
108
273
  function getRecommendedModelsForProvider(provider, limit = 4) {
109
- return sortModelsForPicker(getModelsByProvider(provider)).filter((model) => isRecommendedModel(provider, model.id)).slice(0, limit).map(modelToCatalogView);
274
+ const fromRegistry = sortModelsForPicker(getModelsByProvider(provider)).filter((model) => isRecommendedModel(provider, model.id)).slice(0, limit).map(modelToCatalogView);
275
+ if (fromRegistry.length > 0) return fromRegistry;
276
+ const preset = getDomesticProviderPreset(provider);
277
+ if (!preset) return [];
278
+ return preset.models.filter((model) => isRecommendedModel(provider, model.id)).slice(0, limit).map((model) => presetModelToCatalogView(provider, model));
110
279
  }
111
280
  function getProviderHint(provider) {
112
281
  return PROVIDER_HINTS[provider];
113
282
  }
114
283
  function getOnboardingFeaturedProviders() {
115
- const providers = new Set(getAllProviders());
284
+ const providers = new Set([...getAllProviders(), ...getDomesticProviderPresetIds()]);
116
285
  return FEATURED_PROVIDER_ORDER.filter((provider) => providers.has(provider));
117
286
  }
118
287
  function sortProvidersForPicker(providers) {
@@ -125,10 +294,11 @@ function sortProvidersForPicker(providers) {
125
294
  const catB = PROVIDER_META[b]?.category ?? "specialty";
126
295
  const catOrder = {
127
296
  common: 0,
128
- specialty: 1,
129
- enterprise: 2,
130
- oauth: 3,
131
- extension: 4
297
+ domestic: 1,
298
+ specialty: 2,
299
+ enterprise: 3,
300
+ oauth: 4,
301
+ extension: 5
132
302
  };
133
303
  if (catOrder[catA] !== catOrder[catB]) return catOrder[catA] - catOrder[catB];
134
304
  return getProviderDisplayName(a).localeCompare(getProviderDisplayName(b), void 0, { sensitivity: "base" });
@@ -136,16 +306,17 @@ function sortProvidersForPicker(providers) {
136
306
  }
137
307
  async function getProviderCatalogViews() {
138
308
  const pluginRegistry = getProviderRegistry();
139
- const providers = sortProvidersForPicker(getAllProviders());
309
+ const providers = sortProvidersForPicker([...new Set([...getAllProviders(), ...getDomesticProviderPresetIds()])]);
140
310
  const modelCounts = /* @__PURE__ */ new Map();
141
311
  for (const model of getAllModels()) modelCounts.set(model.provider, (modelCounts.get(model.provider) ?? 0) + 1);
142
312
  return Promise.all(providers.map(async (provider) => {
143
313
  const plugin = pluginRegistry.get(provider);
144
314
  const meta = PROVIDER_META[provider];
315
+ const domesticPreset = getDomesticProviderPreset(provider);
145
316
  return {
146
317
  id: provider,
147
- name: plugin?.name ?? getProviderDisplayName(provider),
148
- category: plugin ? "extension" : meta?.category ?? "specialty",
318
+ name: plugin?.name ?? domesticPreset?.displayName ?? getProviderDisplayName(provider),
319
+ category: plugin ? "extension" : meta?.category ?? (domesticPreset ? "domestic" : "specialty"),
149
320
  supportsOAuth: plugin ? false : meta?.supportsOAuth ?? false,
150
321
  supportsApiKey: plugin ? false : meta?.supportsApiKey ?? true,
151
322
  configured: plugin ? true : await isProviderConfigured(provider),