@phi-code-admin/phi-code 0.74.2 → 0.75.0

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 (656) hide show
  1. package/CHANGELOG.md +1186 -4
  2. package/README.md +478 -379
  3. package/dist/bun/cli.d.ts +3 -0
  4. package/dist/bun/cli.d.ts.map +1 -0
  5. package/dist/bun/cli.js +9 -0
  6. package/dist/bun/cli.js.map +1 -0
  7. package/dist/bun/register-bedrock.d.ts +2 -0
  8. package/dist/bun/register-bedrock.d.ts.map +1 -0
  9. package/dist/bun/register-bedrock.js +4 -0
  10. package/dist/bun/register-bedrock.js.map +1 -0
  11. package/dist/bun/restore-sandbox-env.d.ts +13 -0
  12. package/dist/bun/restore-sandbox-env.d.ts.map +1 -0
  13. package/dist/bun/restore-sandbox-env.js +32 -0
  14. package/dist/bun/restore-sandbox-env.js.map +1 -0
  15. package/dist/cli/args.d.ts +12 -7
  16. package/dist/cli/args.d.ts.map +1 -1
  17. package/dist/cli/args.js +87 -45
  18. package/dist/cli/args.js.map +1 -1
  19. package/dist/cli/config-selector.d.ts.map +1 -1
  20. package/dist/cli/config-selector.js.map +1 -1
  21. package/dist/cli/file-processor.d.ts.map +1 -1
  22. package/dist/cli/file-processor.js +4 -0
  23. package/dist/cli/file-processor.js.map +1 -1
  24. package/dist/cli/initial-message.d.ts +18 -0
  25. package/dist/cli/initial-message.d.ts.map +1 -0
  26. package/dist/cli/initial-message.js +22 -0
  27. package/dist/cli/initial-message.js.map +1 -0
  28. package/dist/cli/list-models.d.ts.map +1 -1
  29. package/dist/cli/list-models.js +7 -1
  30. package/dist/cli/list-models.js.map +1 -1
  31. package/dist/cli/session-picker.d.ts.map +1 -1
  32. package/dist/cli/session-picker.js +2 -1
  33. package/dist/cli/session-picker.js.map +1 -1
  34. package/dist/cli.d.ts.map +1 -1
  35. package/dist/cli.js +9 -5
  36. package/dist/cli.js.map +1 -1
  37. package/dist/config.d.ts +24 -0
  38. package/dist/config.d.ts.map +1 -1
  39. package/dist/config.js +226 -30
  40. package/dist/config.js.map +1 -1
  41. package/dist/core/agent-session-runtime.d.ts +117 -0
  42. package/dist/core/agent-session-runtime.d.ts.map +1 -0
  43. package/dist/core/agent-session-runtime.js +300 -0
  44. package/dist/core/agent-session-runtime.js.map +1 -0
  45. package/dist/core/agent-session-services.d.ts +86 -0
  46. package/dist/core/agent-session-services.d.ts.map +1 -0
  47. package/dist/core/agent-session-services.js +117 -0
  48. package/dist/core/agent-session-services.js.map +1 -0
  49. package/dist/core/agent-session.d.ts +63 -82
  50. package/dist/core/agent-session.d.ts.map +1 -1
  51. package/dist/core/agent-session.js +674 -628
  52. package/dist/core/agent-session.js.map +1 -1
  53. package/dist/core/api-key-store.d.ts +87 -0
  54. package/dist/core/api-key-store.d.ts.map +1 -0
  55. package/dist/core/api-key-store.js +168 -0
  56. package/dist/core/api-key-store.js.map +1 -0
  57. package/dist/core/auth-guidance.d.ts +5 -0
  58. package/dist/core/auth-guidance.d.ts.map +1 -0
  59. package/dist/core/auth-guidance.js +21 -0
  60. package/dist/core/auth-guidance.js.map +1 -0
  61. package/dist/core/auth-storage.d.ts +12 -5
  62. package/dist/core/auth-storage.d.ts.map +1 -1
  63. package/dist/core/auth-storage.js +34 -8
  64. package/dist/core/auth-storage.js.map +1 -1
  65. package/dist/core/bash-executor.d.ts +0 -15
  66. package/dist/core/bash-executor.d.ts.map +1 -1
  67. package/dist/core/bash-executor.js +28 -129
  68. package/dist/core/bash-executor.js.map +1 -1
  69. package/dist/core/compaction/branch-summarization.d.ts +2 -0
  70. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  71. package/dist/core/compaction/branch-summarization.js +3 -2
  72. package/dist/core/compaction/branch-summarization.js.map +1 -1
  73. package/dist/core/compaction/compaction.d.ts +4 -4
  74. package/dist/core/compaction/compaction.d.ts.map +1 -1
  75. package/dist/core/compaction/compaction.js +32 -27
  76. package/dist/core/compaction/compaction.js.map +1 -1
  77. package/dist/core/compaction/index.d.ts.map +1 -1
  78. package/dist/core/compaction/utils.d.ts.map +1 -1
  79. package/dist/core/compaction/utils.js.map +1 -1
  80. package/dist/core/config-watcher.d.ts +47 -0
  81. package/dist/core/config-watcher.d.ts.map +1 -0
  82. package/dist/core/config-watcher.js +135 -0
  83. package/dist/core/config-watcher.js.map +1 -0
  84. package/dist/core/default-models.json +80 -0
  85. package/dist/core/defaults.d.ts.map +1 -1
  86. package/dist/core/diagnostics.d.ts.map +1 -1
  87. package/dist/core/event-bus.d.ts.map +1 -1
  88. package/dist/core/event-bus.js.map +1 -1
  89. package/dist/core/exec.d.ts.map +1 -1
  90. package/dist/core/exec.js +7 -3
  91. package/dist/core/exec.js.map +1 -1
  92. package/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
  93. package/dist/core/export-html/ansi-to-html.js +1 -1
  94. package/dist/core/export-html/ansi-to-html.js.map +1 -1
  95. package/dist/core/export-html/index.d.ts +7 -4
  96. package/dist/core/export-html/index.d.ts.map +1 -1
  97. package/dist/core/export-html/index.js +15 -13
  98. package/dist/core/export-html/index.js.map +1 -1
  99. package/dist/core/export-html/template.css +112 -17
  100. package/dist/core/export-html/template.html +1 -0
  101. package/dist/core/export-html/template.js +312 -64
  102. package/dist/core/export-html/tool-renderer.d.ts +9 -10
  103. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  104. package/dist/core/export-html/tool-renderer.js +61 -16
  105. package/dist/core/export-html/tool-renderer.js.map +1 -1
  106. package/dist/core/extensions/index.d.ts +5 -4
  107. package/dist/core/extensions/index.d.ts.map +1 -1
  108. package/dist/core/extensions/index.js +2 -2
  109. package/dist/core/extensions/index.js.map +1 -1
  110. package/dist/core/extensions/loader.d.ts +0 -1
  111. package/dist/core/extensions/loader.d.ts.map +1 -1
  112. package/dist/core/extensions/loader.js +98 -18
  113. package/dist/core/extensions/loader.js.map +1 -1
  114. package/dist/core/extensions/runner.d.ts +27 -14
  115. package/dist/core/extensions/runner.d.ts.map +1 -1
  116. package/dist/core/extensions/runner.js +299 -115
  117. package/dist/core/extensions/runner.js.map +1 -1
  118. package/dist/core/extensions/types.d.ts +200 -44
  119. package/dist/core/extensions/types.d.ts.map +1 -1
  120. package/dist/core/extensions/types.js +10 -0
  121. package/dist/core/extensions/types.js.map +1 -1
  122. package/dist/core/extensions/wrapper.d.ts +4 -11
  123. package/dist/core/extensions/wrapper.d.ts.map +1 -1
  124. package/dist/core/extensions/wrapper.js +7 -87
  125. package/dist/core/extensions/wrapper.js.map +1 -1
  126. package/dist/core/footer-data-provider.d.ts +22 -2
  127. package/dist/core/footer-data-provider.d.ts.map +1 -1
  128. package/dist/core/footer-data-provider.js +225 -49
  129. package/dist/core/footer-data-provider.js.map +1 -1
  130. package/dist/core/index.d.ts +5 -2
  131. package/dist/core/index.d.ts.map +1 -1
  132. package/dist/core/index.js +5 -2
  133. package/dist/core/index.js.map +1 -1
  134. package/dist/core/keybindings.d.ts +348 -50
  135. package/dist/core/keybindings.d.ts.map +1 -1
  136. package/dist/core/keybindings.js +276 -132
  137. package/dist/core/keybindings.js.map +1 -1
  138. package/dist/core/messages.d.ts.map +1 -1
  139. package/dist/core/messages.js.map +1 -1
  140. package/dist/core/model-registry.d.ts +41 -5
  141. package/dist/core/model-registry.d.ts.map +1 -1
  142. package/dist/core/model-registry.js +316 -136
  143. package/dist/core/model-registry.js.map +1 -1
  144. package/dist/core/model-resolver.d.ts +6 -0
  145. package/dist/core/model-resolver.d.ts.map +1 -1
  146. package/dist/core/model-resolver.js +70 -37
  147. package/dist/core/model-resolver.js.map +1 -1
  148. package/dist/core/output-guard.d.ts +6 -0
  149. package/dist/core/output-guard.d.ts.map +1 -0
  150. package/dist/core/output-guard.js +59 -0
  151. package/dist/core/output-guard.js.map +1 -0
  152. package/dist/core/package-manager.d.ts +49 -7
  153. package/dist/core/package-manager.d.ts.map +1 -1
  154. package/dist/core/package-manager.js +655 -122
  155. package/dist/core/package-manager.js.map +1 -1
  156. package/dist/core/prompt-templates.d.ts +12 -10
  157. package/dist/core/prompt-templates.d.ts.map +1 -1
  158. package/dist/core/prompt-templates.js +37 -38
  159. package/dist/core/prompt-templates.js.map +1 -1
  160. package/dist/core/provider-display-names.d.ts +2 -0
  161. package/dist/core/provider-display-names.d.ts.map +1 -0
  162. package/dist/core/provider-display-names.js +33 -0
  163. package/dist/core/provider-display-names.js.map +1 -0
  164. package/dist/core/resolve-config-value.d.ts +6 -0
  165. package/dist/core/resolve-config-value.d.ts.map +1 -1
  166. package/dist/core/resolve-config-value.js +75 -8
  167. package/dist/core/resolve-config-value.js.map +1 -1
  168. package/dist/core/resource-loader.d.ts +18 -8
  169. package/dist/core/resource-loader.d.ts.map +1 -1
  170. package/dist/core/resource-loader.js +217 -123
  171. package/dist/core/resource-loader.js.map +1 -1
  172. package/dist/core/sdk.d.ts +25 -8
  173. package/dist/core/sdk.d.ts.map +1 -1
  174. package/dist/core/sdk.js +84 -37
  175. package/dist/core/sdk.js.map +1 -1
  176. package/dist/core/session-cwd.d.ts +19 -0
  177. package/dist/core/session-cwd.d.ts.map +1 -0
  178. package/dist/core/session-cwd.js +38 -0
  179. package/dist/core/session-cwd.js.map +1 -0
  180. package/dist/core/session-manager.d.ts +11 -1
  181. package/dist/core/session-manager.d.ts.map +1 -1
  182. package/dist/core/session-manager.js +42 -27
  183. package/dist/core/session-manager.js.map +1 -1
  184. package/dist/core/settings-manager.d.ts +34 -5
  185. package/dist/core/settings-manager.d.ts.map +1 -1
  186. package/dist/core/settings-manager.js +113 -13
  187. package/dist/core/settings-manager.js.map +1 -1
  188. package/dist/core/skills.d.ts +13 -11
  189. package/dist/core/skills.d.ts.map +1 -1
  190. package/dist/core/skills.js +59 -19
  191. package/dist/core/skills.js.map +1 -1
  192. package/dist/core/slash-commands.d.ts +2 -3
  193. package/dist/core/slash-commands.d.ts.map +1 -1
  194. package/dist/core/slash-commands.js +9 -6
  195. package/dist/core/slash-commands.js.map +1 -1
  196. package/dist/core/source-info.d.ts +18 -0
  197. package/dist/core/source-info.d.ts.map +1 -0
  198. package/dist/core/source-info.js +19 -0
  199. package/dist/core/source-info.js.map +1 -0
  200. package/dist/core/system-prompt.d.ts +3 -3
  201. package/dist/core/system-prompt.d.ts.map +1 -1
  202. package/dist/core/system-prompt.js +16 -55
  203. package/dist/core/system-prompt.js.map +1 -1
  204. package/dist/core/telemetry.d.ts +3 -0
  205. package/dist/core/telemetry.d.ts.map +1 -0
  206. package/dist/core/telemetry.js +9 -0
  207. package/dist/core/telemetry.js.map +1 -0
  208. package/dist/core/timings.d.ts +1 -0
  209. package/dist/core/timings.d.ts.map +1 -1
  210. package/dist/core/timings.js +6 -0
  211. package/dist/core/timings.js.map +1 -1
  212. package/dist/core/tools/bash.d.ts +27 -14
  213. package/dist/core/tools/bash.d.ts.map +1 -1
  214. package/dist/core/tools/bash.js +301 -208
  215. package/dist/core/tools/bash.js.map +1 -1
  216. package/dist/core/tools/edit-diff.d.ts +23 -1
  217. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  218. package/dist/core/tools/edit-diff.js +154 -59
  219. package/dist/core/tools/edit-diff.js.map +1 -1
  220. package/dist/core/tools/edit.d.ts +22 -12
  221. package/dist/core/tools/edit.d.ts.map +1 -1
  222. package/dist/core/tools/edit.js +243 -65
  223. package/dist/core/tools/edit.js.map +1 -1
  224. package/dist/core/tools/file-mutation-queue.d.ts +6 -0
  225. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -0
  226. package/dist/core/tools/file-mutation-queue.js +37 -0
  227. package/dist/core/tools/file-mutation-queue.js.map +1 -0
  228. package/dist/core/tools/find.d.ts +10 -14
  229. package/dist/core/tools/find.d.ts.map +1 -1
  230. package/dist/core/tools/find.js +202 -110
  231. package/dist/core/tools/find.js.map +1 -1
  232. package/dist/core/tools/grep.d.ts +14 -22
  233. package/dist/core/tools/grep.d.ts.map +1 -1
  234. package/dist/core/tools/grep.js +100 -35
  235. package/dist/core/tools/grep.js.map +1 -1
  236. package/dist/core/tools/index.d.ts +27 -60
  237. package/dist/core/tools/index.d.ts.map +1 -1
  238. package/dist/core/tools/index.js +96 -45
  239. package/dist/core/tools/index.js.map +1 -1
  240. package/dist/core/tools/ls.d.ts +8 -11
  241. package/dist/core/tools/ls.d.ts.map +1 -1
  242. package/dist/core/tools/ls.js +66 -15
  243. package/dist/core/tools/ls.js.map +1 -1
  244. package/dist/core/tools/output-accumulator.d.ts +50 -0
  245. package/dist/core/tools/output-accumulator.d.ts.map +1 -0
  246. package/dist/core/tools/output-accumulator.js +178 -0
  247. package/dist/core/tools/output-accumulator.js.map +1 -0
  248. package/dist/core/tools/path-utils.d.ts.map +1 -1
  249. package/dist/core/tools/path-utils.js +1 -1
  250. package/dist/core/tools/path-utils.js.map +1 -1
  251. package/dist/core/tools/read.d.ts +9 -13
  252. package/dist/core/tools/read.d.ts.map +1 -1
  253. package/dist/core/tools/read.js +175 -52
  254. package/dist/core/tools/read.js.map +1 -1
  255. package/dist/core/tools/render-utils.d.ts +21 -0
  256. package/dist/core/tools/render-utils.d.ts.map +1 -0
  257. package/dist/core/tools/render-utils.js +49 -0
  258. package/dist/core/tools/render-utils.js.map +1 -0
  259. package/dist/core/tools/tool-definition-wrapper.d.ts +14 -0
  260. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -0
  261. package/dist/core/tools/tool-definition-wrapper.js +34 -0
  262. package/dist/core/tools/tool-definition-wrapper.js.map +1 -0
  263. package/dist/core/tools/truncate.d.ts.map +1 -1
  264. package/dist/core/tools/truncate.js.map +1 -1
  265. package/dist/core/tools/write.d.ts +8 -11
  266. package/dist/core/tools/write.d.ts.map +1 -1
  267. package/dist/core/tools/write.js +167 -32
  268. package/dist/core/tools/write.js.map +1 -1
  269. package/dist/index.d.ts +12 -9
  270. package/dist/index.d.ts.map +1 -1
  271. package/dist/index.js +12 -10
  272. package/dist/index.js.map +1 -1
  273. package/dist/main.d.ts +5 -1
  274. package/dist/main.d.ts.map +1 -1
  275. package/dist/main.js +326 -404
  276. package/dist/main.js.map +1 -1
  277. package/dist/migrations.d.ts +2 -2
  278. package/dist/migrations.d.ts.map +1 -1
  279. package/dist/migrations.js +24 -4
  280. package/dist/migrations.js.map +1 -1
  281. package/dist/modes/index.d.ts.map +1 -1
  282. package/dist/modes/interactive/components/armin.d.ts.map +1 -1
  283. package/dist/modes/interactive/components/armin.js +10 -6
  284. package/dist/modes/interactive/components/armin.js.map +1 -1
  285. package/dist/modes/interactive/components/assistant-message.d.ts +5 -1
  286. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  287. package/dist/modes/interactive/components/assistant-message.js +32 -3
  288. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  289. package/dist/modes/interactive/components/bash-execution.d.ts +0 -1
  290. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  291. package/dist/modes/interactive/components/bash-execution.js +31 -12
  292. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  293. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  294. package/dist/modes/interactive/components/bordered-loader.js +7 -1
  295. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  296. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  297. package/dist/modes/interactive/components/branch-summary-message.js +5 -3
  298. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  299. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  300. package/dist/modes/interactive/components/compaction-summary-message.js +5 -3
  301. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  302. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  303. package/dist/modes/interactive/components/config-selector.js +49 -16
  304. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  305. package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
  306. package/dist/modes/interactive/components/countdown-timer.js +5 -0
  307. package/dist/modes/interactive/components/countdown-timer.js.map +1 -1
  308. package/dist/modes/interactive/components/custom-editor.d.ts +3 -3
  309. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  310. package/dist/modes/interactive/components/custom-editor.js +14 -7
  311. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  312. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  313. package/dist/modes/interactive/components/custom-message.js +6 -1
  314. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  315. package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
  316. package/dist/modes/interactive/components/daxnuts.js +8 -6
  317. package/dist/modes/interactive/components/daxnuts.js.map +1 -1
  318. package/dist/modes/interactive/components/diff.d.ts.map +1 -1
  319. package/dist/modes/interactive/components/diff.js.map +1 -1
  320. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  321. package/dist/modes/interactive/components/dynamic-border.js +1 -0
  322. package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  323. package/dist/modes/interactive/components/earendil-announcement.d.ts +5 -0
  324. package/dist/modes/interactive/components/earendil-announcement.d.ts.map +1 -0
  325. package/dist/modes/interactive/components/earendil-announcement.js +40 -0
  326. package/dist/modes/interactive/components/earendil-announcement.js.map +1 -0
  327. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  328. package/dist/modes/interactive/components/extension-editor.js +16 -10
  329. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  330. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  331. package/dist/modes/interactive/components/extension-input.js +13 -7
  332. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  333. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  334. package/dist/modes/interactive/components/extension-selector.js +18 -11
  335. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  336. package/dist/modes/interactive/components/footer.d.ts +1 -0
  337. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  338. package/dist/modes/interactive/components/footer.js +7 -2
  339. package/dist/modes/interactive/components/footer.js.map +1 -1
  340. package/dist/modes/interactive/components/index.d.ts +1 -1
  341. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  342. package/dist/modes/interactive/components/index.js +1 -1
  343. package/dist/modes/interactive/components/index.js.map +1 -1
  344. package/dist/modes/interactive/components/keybinding-hints.d.ts +8 -36
  345. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  346. package/dist/modes/interactive/components/keybinding-hints.js +23 -48
  347. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  348. package/dist/modes/interactive/components/login-dialog.d.ts +5 -1
  349. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  350. package/dist/modes/interactive/components/login-dialog.js +35 -14
  351. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  352. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  353. package/dist/modes/interactive/components/model-selector.js +41 -22
  354. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  355. package/dist/modes/interactive/components/oauth-selector.d.ts +18 -6
  356. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  357. package/dist/modes/interactive/components/oauth-selector.js +104 -31
  358. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  359. package/dist/modes/interactive/components/scoped-models-selector.d.ts +5 -12
  360. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  361. package/dist/modes/interactive/components/scoped-models-selector.js +61 -42
  362. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  363. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
  364. package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  365. package/dist/modes/interactive/components/session-selector.d.ts +2 -1
  366. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  367. package/dist/modes/interactive/components/session-selector.js +109 -73
  368. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  369. package/dist/modes/interactive/components/settings-selector.d.ts +9 -0
  370. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  371. package/dist/modes/interactive/components/settings-selector.js +84 -4
  372. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  373. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
  374. package/dist/modes/interactive/components/show-images-selector.js +6 -1
  375. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  376. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  377. package/dist/modes/interactive/components/skill-invocation-message.js +5 -3
  378. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  379. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
  380. package/dist/modes/interactive/components/theme-selector.js +7 -1
  381. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  382. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  383. package/dist/modes/interactive/components/thinking-selector.js +6 -1
  384. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  385. package/dist/modes/interactive/components/tool-execution.d.ts +20 -34
  386. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  387. package/dist/modes/interactive/components/tool-execution.js +158 -636
  388. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  389. package/dist/modes/interactive/components/tree-selector.d.ts +21 -2
  390. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  391. package/dist/modes/interactive/components/tree-selector.js +224 -52
  392. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  393. package/dist/modes/interactive/components/user-message-selector.d.ts +2 -2
  394. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  395. package/dist/modes/interactive/components/user-message-selector.js +20 -16
  396. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  397. package/dist/modes/interactive/components/user-message.d.ts +1 -0
  398. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  399. package/dist/modes/interactive/components/user-message.js +8 -6
  400. package/dist/modes/interactive/components/user-message.js.map +1 -1
  401. package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
  402. package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
  403. package/dist/modes/interactive/interactive-mode.d.ts +67 -39
  404. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  405. package/dist/modes/interactive/interactive-mode.js +1556 -680
  406. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  407. package/dist/modes/interactive/theme/dark.json +1 -1
  408. package/dist/modes/interactive/theme/light.json +1 -1
  409. package/dist/modes/interactive/theme/theme.d.ts +3 -0
  410. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  411. package/dist/modes/interactive/theme/theme.js +101 -72
  412. package/dist/modes/interactive/theme/theme.js.map +1 -1
  413. package/dist/modes/print-mode.d.ts +2 -2
  414. package/dist/modes/print-mode.d.ts.map +1 -1
  415. package/dist/modes/print-mode.js +107 -77
  416. package/dist/modes/print-mode.js.map +1 -1
  417. package/dist/modes/rpc/jsonl.d.ts +17 -0
  418. package/dist/modes/rpc/jsonl.d.ts.map +1 -0
  419. package/dist/modes/rpc/jsonl.js +49 -0
  420. package/dist/modes/rpc/jsonl.js.map +1 -0
  421. package/dist/modes/rpc/rpc-client.d.ts +8 -1
  422. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  423. package/dist/modes/rpc/rpc-client.js +22 -16
  424. package/dist/modes/rpc/rpc-client.js.map +1 -1
  425. package/dist/modes/rpc/rpc-mode.d.ts +2 -2
  426. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  427. package/dist/modes/rpc/rpc-mode.js +184 -94
  428. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  429. package/dist/modes/rpc/rpc-types.d.ts +14 -4
  430. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  431. package/dist/modes/rpc/rpc-types.js.map +1 -1
  432. package/dist/package-manager-cli.d.ts +4 -0
  433. package/dist/package-manager-cli.d.ts.map +1 -0
  434. package/dist/package-manager-cli.js +460 -0
  435. package/dist/package-manager-cli.js.map +1 -0
  436. package/dist/utils/changelog.d.ts.map +1 -1
  437. package/dist/utils/changelog.js.map +1 -1
  438. package/dist/utils/child-process.d.ts +12 -0
  439. package/dist/utils/child-process.d.ts.map +1 -0
  440. package/dist/utils/child-process.js +86 -0
  441. package/dist/utils/child-process.js.map +1 -0
  442. package/dist/utils/clipboard-image.d.ts.map +1 -1
  443. package/dist/utils/clipboard-image.js +94 -11
  444. package/dist/utils/clipboard-image.js.map +1 -1
  445. package/dist/utils/clipboard-native.d.ts +1 -0
  446. package/dist/utils/clipboard-native.d.ts.map +1 -1
  447. package/dist/utils/clipboard-native.js.map +1 -1
  448. package/dist/utils/clipboard.d.ts +1 -1
  449. package/dist/utils/clipboard.d.ts.map +1 -1
  450. package/dist/utils/clipboard.js +96 -46
  451. package/dist/utils/clipboard.js.map +1 -1
  452. package/dist/utils/exif-orientation.d.ts +5 -0
  453. package/dist/utils/exif-orientation.d.ts.map +1 -0
  454. package/dist/utils/exif-orientation.js +158 -0
  455. package/dist/utils/exif-orientation.js.map +1 -0
  456. package/dist/utils/frontmatter.d.ts.map +1 -1
  457. package/dist/utils/frontmatter.js.map +1 -1
  458. package/dist/utils/fs-watch.d.ts +5 -0
  459. package/dist/utils/fs-watch.d.ts.map +1 -0
  460. package/dist/utils/fs-watch.js +25 -0
  461. package/dist/utils/fs-watch.js.map +1 -0
  462. package/dist/utils/git.d.ts.map +1 -1
  463. package/dist/utils/git.js.map +1 -1
  464. package/dist/utils/image-convert.d.ts.map +1 -1
  465. package/dist/utils/image-convert.js +5 -1
  466. package/dist/utils/image-convert.js.map +1 -1
  467. package/dist/utils/image-resize.d.ts +5 -5
  468. package/dist/utils/image-resize.d.ts.map +1 -1
  469. package/dist/utils/image-resize.js +51 -95
  470. package/dist/utils/image-resize.js.map +1 -1
  471. package/dist/utils/mime.d.ts.map +1 -1
  472. package/dist/utils/mime.js.map +1 -1
  473. package/dist/utils/paths.d.ts +16 -0
  474. package/dist/utils/paths.d.ts.map +1 -0
  475. package/dist/utils/paths.js +50 -0
  476. package/dist/utils/paths.js.map +1 -0
  477. package/dist/utils/photon.d.ts.map +1 -1
  478. package/dist/utils/photon.js.map +1 -1
  479. package/dist/utils/pi-user-agent.d.ts +2 -0
  480. package/dist/utils/pi-user-agent.d.ts.map +1 -0
  481. package/dist/utils/pi-user-agent.js +5 -0
  482. package/dist/utils/pi-user-agent.js.map +1 -0
  483. package/dist/utils/shell.d.ts +10 -6
  484. package/dist/utils/shell.d.ts.map +1 -1
  485. package/dist/utils/shell.js +29 -25
  486. package/dist/utils/shell.js.map +1 -1
  487. package/dist/utils/sleep.d.ts.map +1 -1
  488. package/dist/utils/sleep.js.map +1 -1
  489. package/dist/utils/tools-manager.d.ts.map +1 -1
  490. package/dist/utils/tools-manager.js +11 -6
  491. package/dist/utils/tools-manager.js.map +1 -1
  492. package/dist/utils/version-check.d.ts +14 -0
  493. package/dist/utils/version-check.d.ts.map +1 -0
  494. package/dist/utils/version-check.js +77 -0
  495. package/dist/utils/version-check.js.map +1 -0
  496. package/docs/compaction.md +394 -0
  497. package/docs/custom-provider.md +646 -0
  498. package/docs/development.md +71 -0
  499. package/docs/docs.json +148 -0
  500. package/docs/extensions.md +2596 -0
  501. package/docs/images/doom-extension.png +0 -0
  502. package/docs/images/exy.png +0 -0
  503. package/docs/images/interactive-mode.png +0 -0
  504. package/docs/images/tree-view.png +0 -0
  505. package/docs/index.md +70 -0
  506. package/docs/json.md +82 -0
  507. package/docs/keybindings.md +197 -0
  508. package/docs/models.md +474 -0
  509. package/docs/packages.md +223 -0
  510. package/docs/prompt-templates.md +88 -0
  511. package/docs/providers.md +243 -0
  512. package/docs/quickstart.md +142 -0
  513. package/docs/rpc.md +1407 -0
  514. package/docs/sdk.md +1149 -0
  515. package/docs/session-format.md +412 -0
  516. package/docs/sessions.md +137 -0
  517. package/docs/settings.md +279 -0
  518. package/docs/shell-aliases.md +13 -0
  519. package/docs/skills.md +232 -0
  520. package/docs/terminal-setup.md +106 -0
  521. package/docs/termux.md +127 -0
  522. package/docs/themes.md +295 -0
  523. package/docs/tmux.md +61 -0
  524. package/docs/tui.md +918 -0
  525. package/docs/usage.md +277 -0
  526. package/docs/windows.md +17 -0
  527. package/examples/README.md +25 -0
  528. package/examples/extensions/README.md +208 -0
  529. package/examples/extensions/auto-commit-on-exit.ts +49 -0
  530. package/examples/extensions/bash-spawn-hook.ts +30 -0
  531. package/examples/extensions/bookmark.ts +50 -0
  532. package/examples/extensions/border-status-editor.ts +150 -0
  533. package/examples/extensions/built-in-tool-renderer.ts +249 -0
  534. package/examples/extensions/claude-rules.ts +86 -0
  535. package/examples/extensions/commands.ts +72 -0
  536. package/examples/extensions/confirm-destructive.ts +59 -0
  537. package/examples/extensions/custom-compaction.ts +127 -0
  538. package/examples/extensions/custom-footer.ts +64 -0
  539. package/examples/extensions/custom-header.ts +73 -0
  540. package/examples/extensions/custom-provider-anthropic/index.ts +604 -0
  541. package/examples/extensions/custom-provider-anthropic/package-lock.json +24 -0
  542. package/examples/extensions/custom-provider-anthropic/package.json +19 -0
  543. package/examples/extensions/custom-provider-gitlab-duo/index.ts +349 -0
  544. package/examples/extensions/custom-provider-gitlab-duo/package.json +16 -0
  545. package/examples/extensions/custom-provider-gitlab-duo/test.ts +82 -0
  546. package/examples/extensions/dirty-repo-guard.ts +56 -0
  547. package/examples/extensions/doom-overlay/README.md +46 -0
  548. package/examples/extensions/doom-overlay/doom/build/doom.js +21 -0
  549. package/examples/extensions/doom-overlay/doom/build/doom.wasm +0 -0
  550. package/examples/extensions/doom-overlay/doom/build.sh +152 -0
  551. package/examples/extensions/doom-overlay/doom/doomgeneric_pi.c +72 -0
  552. package/examples/extensions/doom-overlay/doom-component.ts +132 -0
  553. package/examples/extensions/doom-overlay/doom-engine.ts +173 -0
  554. package/examples/extensions/doom-overlay/doom-keys.ts +104 -0
  555. package/examples/extensions/doom-overlay/index.ts +74 -0
  556. package/examples/extensions/doom-overlay/wad-finder.ts +51 -0
  557. package/examples/extensions/dynamic-resources/SKILL.md +8 -0
  558. package/examples/extensions/dynamic-resources/dynamic.json +79 -0
  559. package/examples/extensions/dynamic-resources/dynamic.md +5 -0
  560. package/examples/extensions/dynamic-resources/index.ts +15 -0
  561. package/examples/extensions/dynamic-tools.ts +74 -0
  562. package/examples/extensions/event-bus.ts +43 -0
  563. package/examples/extensions/file-trigger.ts +41 -0
  564. package/examples/extensions/git-checkpoint.ts +53 -0
  565. package/examples/extensions/github-issue-autocomplete.ts +185 -0
  566. package/examples/extensions/handoff.ts +191 -0
  567. package/examples/extensions/hello.ts +26 -0
  568. package/examples/extensions/hidden-thinking-label.ts +53 -0
  569. package/examples/extensions/inline-bash.ts +94 -0
  570. package/examples/extensions/input-transform.ts +43 -0
  571. package/examples/extensions/interactive-shell.ts +196 -0
  572. package/examples/extensions/mac-system-theme.ts +47 -0
  573. package/examples/extensions/message-renderer.ts +59 -0
  574. package/examples/extensions/minimal-mode.ts +426 -0
  575. package/examples/extensions/modal-editor.ts +85 -0
  576. package/examples/extensions/model-status.ts +31 -0
  577. package/examples/extensions/notify.ts +55 -0
  578. package/examples/extensions/overlay-qa-tests.ts +1348 -0
  579. package/examples/extensions/overlay-test.ts +150 -0
  580. package/examples/extensions/permission-gate.ts +34 -0
  581. package/examples/extensions/pirate.ts +47 -0
  582. package/examples/extensions/plan-mode/README.md +65 -0
  583. package/examples/extensions/plan-mode/index.ts +340 -0
  584. package/examples/extensions/plan-mode/utils.ts +168 -0
  585. package/examples/extensions/preset.ts +430 -0
  586. package/examples/extensions/prompt-customizer.ts +97 -0
  587. package/examples/extensions/protected-paths.ts +30 -0
  588. package/examples/extensions/provider-payload.ts +18 -0
  589. package/examples/extensions/qna.ts +122 -0
  590. package/examples/extensions/question.ts +264 -0
  591. package/examples/extensions/questionnaire.ts +427 -0
  592. package/examples/extensions/rainbow-editor.ts +88 -0
  593. package/examples/extensions/reload-runtime.ts +37 -0
  594. package/examples/extensions/rpc-demo.ts +118 -0
  595. package/examples/extensions/sandbox/index.ts +321 -0
  596. package/examples/extensions/sandbox/package-lock.json +92 -0
  597. package/examples/extensions/sandbox/package.json +19 -0
  598. package/examples/extensions/send-user-message.ts +97 -0
  599. package/examples/extensions/session-name.ts +27 -0
  600. package/examples/extensions/shutdown-command.ts +63 -0
  601. package/examples/extensions/snake.ts +343 -0
  602. package/examples/extensions/space-invaders.ts +560 -0
  603. package/examples/extensions/ssh.ts +220 -0
  604. package/examples/extensions/status-line.ts +32 -0
  605. package/examples/extensions/structured-output.ts +65 -0
  606. package/examples/extensions/subagent/README.md +172 -0
  607. package/examples/extensions/subagent/agents/planner.md +37 -0
  608. package/examples/extensions/subagent/agents/reviewer.md +35 -0
  609. package/examples/extensions/subagent/agents/scout.md +50 -0
  610. package/examples/extensions/subagent/agents/worker.md +24 -0
  611. package/examples/extensions/subagent/agents.ts +126 -0
  612. package/examples/extensions/subagent/index.ts +987 -0
  613. package/examples/extensions/subagent/prompts/implement-and-review.md +10 -0
  614. package/examples/extensions/subagent/prompts/implement.md +10 -0
  615. package/examples/extensions/subagent/prompts/scout-and-plan.md +9 -0
  616. package/examples/extensions/summarize.ts +206 -0
  617. package/examples/extensions/system-prompt-header.ts +17 -0
  618. package/examples/extensions/tic-tac-toe.ts +1008 -0
  619. package/examples/extensions/timed-confirm.ts +70 -0
  620. package/examples/extensions/titlebar-spinner.ts +58 -0
  621. package/examples/extensions/todo.ts +297 -0
  622. package/examples/extensions/tool-override.ts +144 -0
  623. package/examples/extensions/tools.ts +141 -0
  624. package/examples/extensions/trigger-compact.ts +50 -0
  625. package/examples/extensions/truncated-tool.ts +195 -0
  626. package/examples/extensions/widget-placement.ts +9 -0
  627. package/examples/extensions/with-deps/index.ts +32 -0
  628. package/examples/extensions/with-deps/package-lock.json +31 -0
  629. package/examples/extensions/with-deps/package.json +22 -0
  630. package/examples/extensions/working-indicator.ts +123 -0
  631. package/examples/extensions/working-message-test.ts +25 -0
  632. package/examples/rpc-extension-ui.ts +632 -0
  633. package/examples/sdk/01-minimal.ts +22 -0
  634. package/examples/sdk/02-custom-model.ts +49 -0
  635. package/examples/sdk/03-custom-prompt.ts +62 -0
  636. package/examples/sdk/04-skills.ts +55 -0
  637. package/examples/sdk/05-tools.ts +44 -0
  638. package/examples/sdk/06-extensions.ts +90 -0
  639. package/examples/sdk/07-context-files.ts +42 -0
  640. package/examples/sdk/08-prompt-templates.ts +51 -0
  641. package/examples/sdk/09-api-keys-and-oauth.ts +48 -0
  642. package/examples/sdk/10-settings.ts +53 -0
  643. package/examples/sdk/11-sessions.ts +48 -0
  644. package/examples/sdk/12-full-control.ts +73 -0
  645. package/examples/sdk/13-session-runtime.ts +67 -0
  646. package/examples/sdk/README.md +147 -0
  647. package/extensions/phi/init.ts +15 -1
  648. package/extensions/phi/keys.ts +186 -0
  649. package/extensions/phi/providers/alibaba.ts +126 -0
  650. package/extensions/phi/providers/opencode-go.ts +204 -0
  651. package/extensions/phi/setup.ts +692 -0
  652. package/extensions/phi/smart-router.ts +8 -0
  653. package/extensions/phi/web-search.ts +432 -186
  654. package/package.json +111 -106
  655. package/scripts/copy-assets.sh +0 -0
  656. package/scripts/migrate-sessions.sh +0 -0
@@ -1,31 +1,64 @@
1
1
  /**
2
2
  * Model registry - manages built-in and custom models, provides API key resolution.
3
3
  */
4
+ import { existsSync, readFileSync } from "fs";
5
+ import { join } from "path";
4
6
  import { getModels, getProviders, registerApiProvider, resetApiProviders, } from "phi-code-ai";
5
7
  import { registerOAuthProvider, resetOAuthProviders } from "phi-code-ai/oauth";
6
- import { Type } from "@sinclair/typebox";
7
- import AjvModule from "ajv";
8
- import { existsSync, readFileSync } from "fs";
9
- import { join, dirname } from "path";
10
- import { fileURLToPath } from "url";
8
+ import { Type } from "typebox";
9
+ import { Compile } from "typebox/compile";
11
10
  import { getAgentDir } from "../config.js";
12
- import { clearConfigValueCache, resolveConfigValue, resolveHeaders } from "./resolve-config-value.js";
13
- const Ajv = AjvModule.default || AjvModule;
14
- const ajv = new Ajv();
15
- const __filename = fileURLToPath(import.meta.url);
16
- const __dirname = dirname(__filename);
17
- const DEFAULT_MODELS_PATH = join(__dirname, "default-models.json");
11
+ import { BUILT_IN_PROVIDER_DISPLAY_NAMES } from "./provider-display-names.js";
12
+ import { clearConfigValueCache, resolveConfigValueOrThrow, resolveConfigValueUncached, resolveHeadersOrThrow, } from "./resolve-config-value.js";
18
13
  // Schema for OpenRouter routing preferences
14
+ const PercentileCutoffsSchema = Type.Object({
15
+ p50: Type.Optional(Type.Number()),
16
+ p75: Type.Optional(Type.Number()),
17
+ p90: Type.Optional(Type.Number()),
18
+ p99: Type.Optional(Type.Number()),
19
+ });
19
20
  const OpenRouterRoutingSchema = Type.Object({
20
- only: Type.Optional(Type.Array(Type.String())),
21
+ allow_fallbacks: Type.Optional(Type.Boolean()),
22
+ require_parameters: Type.Optional(Type.Boolean()),
23
+ data_collection: Type.Optional(Type.Union([Type.Literal("deny"), Type.Literal("allow")])),
24
+ zdr: Type.Optional(Type.Boolean()),
25
+ enforce_distillable_text: Type.Optional(Type.Boolean()),
21
26
  order: Type.Optional(Type.Array(Type.String())),
27
+ only: Type.Optional(Type.Array(Type.String())),
28
+ ignore: Type.Optional(Type.Array(Type.String())),
29
+ quantizations: Type.Optional(Type.Array(Type.String())),
30
+ sort: Type.Optional(Type.Union([
31
+ Type.String(),
32
+ Type.Object({
33
+ by: Type.Optional(Type.String()),
34
+ partition: Type.Optional(Type.Union([Type.String(), Type.Null()])),
35
+ }),
36
+ ])),
37
+ max_price: Type.Optional(Type.Object({
38
+ prompt: Type.Optional(Type.Union([Type.Number(), Type.String()])),
39
+ completion: Type.Optional(Type.Union([Type.Number(), Type.String()])),
40
+ image: Type.Optional(Type.Union([Type.Number(), Type.String()])),
41
+ audio: Type.Optional(Type.Union([Type.Number(), Type.String()])),
42
+ request: Type.Optional(Type.Union([Type.Number(), Type.String()])),
43
+ })),
44
+ preferred_min_throughput: Type.Optional(Type.Union([Type.Number(), PercentileCutoffsSchema])),
45
+ preferred_max_latency: Type.Optional(Type.Union([Type.Number(), PercentileCutoffsSchema])),
22
46
  });
23
47
  // Schema for Vercel AI Gateway routing preferences
24
48
  const VercelGatewayRoutingSchema = Type.Object({
25
49
  only: Type.Optional(Type.Array(Type.String())),
26
50
  order: Type.Optional(Type.Array(Type.String())),
27
51
  });
28
- // Schema for OpenAI compatibility settings
52
+ // Schema for thinking level support and provider-specific values
53
+ const ThinkingLevelMapValueSchema = Type.Union([Type.String(), Type.Null()]);
54
+ const ThinkingLevelMapSchema = Type.Object({
55
+ off: Type.Optional(ThinkingLevelMapValueSchema),
56
+ minimal: Type.Optional(ThinkingLevelMapValueSchema),
57
+ low: Type.Optional(ThinkingLevelMapValueSchema),
58
+ medium: Type.Optional(ThinkingLevelMapValueSchema),
59
+ high: Type.Optional(ThinkingLevelMapValueSchema),
60
+ xhigh: Type.Optional(ThinkingLevelMapValueSchema),
61
+ });
29
62
  const OpenAICompletionsCompatSchema = Type.Object({
30
63
  supportsStore: Type.Optional(Type.Boolean()),
31
64
  supportsDeveloperRole: Type.Optional(Type.Boolean()),
@@ -35,15 +68,35 @@ const OpenAICompletionsCompatSchema = Type.Object({
35
68
  requiresToolResultName: Type.Optional(Type.Boolean()),
36
69
  requiresAssistantAfterToolResult: Type.Optional(Type.Boolean()),
37
70
  requiresThinkingAsText: Type.Optional(Type.Boolean()),
38
- requiresMistralToolIds: Type.Optional(Type.Boolean()),
39
- thinkingFormat: Type.Optional(Type.Union([Type.Literal("openai"), Type.Literal("zai"), Type.Literal("qwen")])),
71
+ requiresReasoningContentOnAssistantMessages: Type.Optional(Type.Boolean()),
72
+ thinkingFormat: Type.Optional(Type.Union([
73
+ Type.Literal("openai"),
74
+ Type.Literal("openrouter"),
75
+ Type.Literal("together"),
76
+ Type.Literal("deepseek"),
77
+ Type.Literal("zai"),
78
+ Type.Literal("qwen"),
79
+ Type.Literal("qwen-chat-template"),
80
+ ])),
81
+ cacheControlFormat: Type.Optional(Type.Literal("anthropic")),
40
82
  openRouterRouting: Type.Optional(OpenRouterRoutingSchema),
41
83
  vercelGatewayRouting: Type.Optional(VercelGatewayRoutingSchema),
84
+ supportsStrictMode: Type.Optional(Type.Boolean()),
85
+ supportsLongCacheRetention: Type.Optional(Type.Boolean()),
42
86
  });
43
87
  const OpenAIResponsesCompatSchema = Type.Object({
44
- // Reserved for future use
88
+ sendSessionIdHeader: Type.Optional(Type.Boolean()),
89
+ supportsLongCacheRetention: Type.Optional(Type.Boolean()),
90
+ });
91
+ const AnthropicMessagesCompatSchema = Type.Object({
92
+ supportsEagerToolInputStreaming: Type.Optional(Type.Boolean()),
93
+ supportsLongCacheRetention: Type.Optional(Type.Boolean()),
45
94
  });
46
- const OpenAICompatSchema = Type.Union([OpenAICompletionsCompatSchema, OpenAIResponsesCompatSchema]);
95
+ const ProviderCompatSchema = Type.Union([
96
+ OpenAICompletionsCompatSchema,
97
+ OpenAIResponsesCompatSchema,
98
+ AnthropicMessagesCompatSchema,
99
+ ]);
47
100
  // Schema for custom model definition
48
101
  // Most fields are optional with sensible defaults for local models (Ollama, LM Studio, etc.)
49
102
  const ModelDefinitionSchema = Type.Object({
@@ -52,6 +105,7 @@ const ModelDefinitionSchema = Type.Object({
52
105
  api: Type.Optional(Type.String({ minLength: 1 })),
53
106
  baseUrl: Type.Optional(Type.String({ minLength: 1 })),
54
107
  reasoning: Type.Optional(Type.Boolean()),
108
+ thinkingLevelMap: Type.Optional(ThinkingLevelMapSchema),
55
109
  input: Type.Optional(Type.Array(Type.Union([Type.Literal("text"), Type.Literal("image")]))),
56
110
  cost: Type.Optional(Type.Object({
57
111
  input: Type.Number(),
@@ -62,12 +116,13 @@ const ModelDefinitionSchema = Type.Object({
62
116
  contextWindow: Type.Optional(Type.Number()),
63
117
  maxTokens: Type.Optional(Type.Number()),
64
118
  headers: Type.Optional(Type.Record(Type.String(), Type.String())),
65
- compat: Type.Optional(OpenAICompatSchema),
119
+ compat: Type.Optional(ProviderCompatSchema),
66
120
  });
67
121
  // Schema for per-model overrides (all fields optional, merged with built-in model)
68
122
  const ModelOverrideSchema = Type.Object({
69
123
  name: Type.Optional(Type.String({ minLength: 1 })),
70
124
  reasoning: Type.Optional(Type.Boolean()),
125
+ thinkingLevelMap: Type.Optional(ThinkingLevelMapSchema),
71
126
  input: Type.Optional(Type.Array(Type.Union([Type.Literal("text"), Type.Literal("image")]))),
72
127
  cost: Type.Optional(Type.Object({
73
128
  input: Type.Optional(Type.Number()),
@@ -78,13 +133,15 @@ const ModelOverrideSchema = Type.Object({
78
133
  contextWindow: Type.Optional(Type.Number()),
79
134
  maxTokens: Type.Optional(Type.Number()),
80
135
  headers: Type.Optional(Type.Record(Type.String(), Type.String())),
81
- compat: Type.Optional(OpenAICompatSchema),
136
+ compat: Type.Optional(ProviderCompatSchema),
82
137
  });
83
138
  const ProviderConfigSchema = Type.Object({
139
+ name: Type.Optional(Type.String({ minLength: 1 })),
84
140
  baseUrl: Type.Optional(Type.String({ minLength: 1 })),
85
141
  apiKey: Type.Optional(Type.String({ minLength: 1 })),
86
142
  api: Type.Optional(Type.String({ minLength: 1 })),
87
143
  headers: Type.Optional(Type.Record(Type.String(), Type.String())),
144
+ compat: Type.Optional(ProviderCompatSchema),
88
145
  authHeader: Type.Optional(Type.Boolean()),
89
146
  models: Type.Optional(Type.Array(ModelDefinitionSchema)),
90
147
  modelOverrides: Type.Optional(Type.Record(Type.String(), ModelOverrideSchema)),
@@ -92,7 +149,25 @@ const ProviderConfigSchema = Type.Object({
92
149
  const ModelsConfigSchema = Type.Object({
93
150
  providers: Type.Record(Type.String(), ProviderConfigSchema),
94
151
  });
95
- ajv.addSchema(ModelsConfigSchema, "ModelsConfig");
152
+ const validateModelsConfig = Compile(ModelsConfigSchema);
153
+ function formatValidationPath(error) {
154
+ if (error.keyword === "required") {
155
+ const requiredProperties = error.params.requiredProperties;
156
+ const requiredProperty = requiredProperties?.[0];
157
+ if (requiredProperty) {
158
+ const basePath = error.instancePath.replace(/^\//, "").replace(/\//g, ".");
159
+ return basePath ? `${basePath}.${requiredProperty}` : requiredProperty;
160
+ }
161
+ }
162
+ const path = error.instancePath.replace(/^\//, "").replace(/\//g, ".");
163
+ return path || "root";
164
+ }
165
+ /** Strip `//` line comments and trailing commas from JSON, leaving string literals untouched. */
166
+ function stripJsonComments(input) {
167
+ return input
168
+ .replace(/"(?:\\.|[^"\\])*"|\/\/[^\n]*/g, (m) => (m[0] === '"' ? m : ""))
169
+ .replace(/"(?:\\.|[^"\\])*"|,(\s*[}\]])/g, (m, tail) => tail ?? (m[0] === '"' ? m : ""));
170
+ }
96
171
  function emptyCustomModelsResult(error) {
97
172
  return { models: [], overrides: new Map(), modelOverrides: new Map(), error };
98
173
  }
@@ -130,6 +205,9 @@ function applyModelOverride(model, override) {
130
205
  result.name = override.name;
131
206
  if (override.reasoning !== undefined)
132
207
  result.reasoning = override.reasoning;
208
+ if (override.thinkingLevelMap !== undefined) {
209
+ result.thinkingLevelMap = { ...model.thinkingLevelMap, ...override.thinkingLevelMap };
210
+ }
133
211
  if (override.input !== undefined)
134
212
  result.input = override.input;
135
213
  if (override.contextWindow !== undefined)
@@ -145,11 +223,6 @@ function applyModelOverride(model, override) {
145
223
  cacheWrite: override.cost.cacheWrite ?? model.cost.cacheWrite,
146
224
  };
147
225
  }
148
- // Merge headers
149
- if (override.headers) {
150
- const resolvedHeaders = resolveHeaders(override.headers);
151
- result.headers = resolvedHeaders ? { ...model.headers, ...resolvedHeaders } : model.headers;
152
- }
153
226
  // Deep merge compat
154
227
  result.compat = mergeCompat(model.compat, override.compat);
155
228
  return result;
@@ -160,29 +233,30 @@ export const clearApiKeyCache = clearConfigValueCache;
160
233
  * Model registry - loads and manages models, resolves API keys via AuthStorage.
161
234
  */
162
235
  export class ModelRegistry {
163
- constructor(authStorage, modelsJsonPath = join(getAgentDir(), "models.json")) {
236
+ authStorage;
237
+ modelsJsonPath;
238
+ models = [];
239
+ providerRequestConfigs = new Map();
240
+ modelRequestHeaders = new Map();
241
+ registeredProviders = new Map();
242
+ loadError = undefined;
243
+ constructor(authStorage, modelsJsonPath) {
164
244
  this.authStorage = authStorage;
165
245
  this.modelsJsonPath = modelsJsonPath;
166
- this.models = [];
167
- this.customProviderApiKeys = new Map();
168
- this.registeredProviders = new Map();
169
- this.loadError = undefined;
170
- // Set up fallback resolver for custom provider API keys
171
- this.authStorage.setFallbackResolver((provider) => {
172
- const keyConfig = this.customProviderApiKeys.get(provider);
173
- if (keyConfig) {
174
- return resolveConfigValue(keyConfig);
175
- }
176
- return undefined;
177
- });
178
- // Load models
179
246
  this.loadModels();
180
247
  }
248
+ static create(authStorage, modelsJsonPath = join(getAgentDir(), "models.json")) {
249
+ return new ModelRegistry(authStorage, modelsJsonPath);
250
+ }
251
+ static inMemory(authStorage) {
252
+ return new ModelRegistry(authStorage, undefined);
253
+ }
181
254
  /**
182
255
  * Reload models from disk (built-in + custom from models.json).
183
256
  */
184
257
  refresh() {
185
- this.customProviderApiKeys.clear();
258
+ this.providerRequestConfigs.clear();
259
+ this.modelRequestHeaders.clear();
186
260
  this.loadError = undefined;
187
261
  // Ensure dynamic API/OAuth registrations are rebuilt from current provider state.
188
262
  resetApiProviders();
@@ -224,13 +298,12 @@ export class ModelRegistry {
224
298
  const perModelOverrides = modelOverrides.get(provider);
225
299
  return models.map((m) => {
226
300
  let model = m;
227
- // Apply provider-level baseUrl/headers override
301
+ // Apply provider-level baseUrl/headers/compat override
228
302
  if (providerOverride) {
229
- const resolvedHeaders = resolveHeaders(providerOverride.headers);
230
303
  model = {
231
304
  ...model,
232
305
  baseUrl: providerOverride.baseUrl ?? model.baseUrl,
233
- headers: resolvedHeaders ? { ...model.headers, ...resolvedHeaders } : model.headers,
306
+ compat: mergeCompat(model.compat, providerOverride.compat),
234
307
  };
235
308
  }
236
309
  // Apply per-model override
@@ -258,68 +331,62 @@ export class ModelRegistry {
258
331
  }
259
332
  loadCustomModels(modelsJsonPath) {
260
333
  if (!existsSync(modelsJsonPath)) {
261
- // If user's models.json doesn't exist, try to load default models
262
- if (existsSync(DEFAULT_MODELS_PATH)) {
263
- return this.loadModelsFromFile(DEFAULT_MODELS_PATH);
264
- }
265
334
  return emptyCustomModelsResult();
266
335
  }
267
- return this.loadModelsFromFile(modelsJsonPath);
268
- }
269
- loadModelsFromFile(filePath) {
270
336
  try {
271
- const content = readFileSync(filePath, "utf-8");
272
- const config = JSON.parse(content);
273
- // Validate schema
274
- const validate = ajv.getSchema("ModelsConfig");
275
- if (!validate(config)) {
276
- const errors = validate.errors?.map((e) => ` - ${e.instancePath || "root"}: ${e.message}`).join("\n") ||
277
- "Unknown schema error";
278
- return emptyCustomModelsResult(`Invalid models.json schema:\n${errors}\n\nFile: ${filePath}`);
337
+ const content = readFileSync(modelsJsonPath, "utf-8");
338
+ const parsed = JSON.parse(stripJsonComments(content));
339
+ if (!validateModelsConfig.Check(parsed)) {
340
+ const errors = validateModelsConfig
341
+ .Errors(parsed)
342
+ .map((error) => ` - ${formatValidationPath(error)}: ${error.message}`)
343
+ .join("\n") || "Unknown schema error";
344
+ return emptyCustomModelsResult(`Invalid models.json schema:\n${errors}\n\nFile: ${modelsJsonPath}`);
279
345
  }
346
+ const config = parsed;
280
347
  // Additional validation
281
348
  this.validateConfig(config);
282
349
  const overrides = new Map();
283
350
  const modelOverrides = new Map();
284
351
  for (const [providerName, providerConfig] of Object.entries(config.providers)) {
285
- // Apply provider-level baseUrl/headers/apiKey override to built-in models when configured.
286
- if (providerConfig.baseUrl || providerConfig.headers || providerConfig.apiKey) {
352
+ if (providerConfig.baseUrl || providerConfig.compat) {
287
353
  overrides.set(providerName, {
288
354
  baseUrl: providerConfig.baseUrl,
289
- headers: providerConfig.headers,
290
- apiKey: providerConfig.apiKey,
355
+ compat: providerConfig.compat,
291
356
  });
292
357
  }
293
- // Store API key for fallback resolver.
294
- if (providerConfig.apiKey) {
295
- this.customProviderApiKeys.set(providerName, providerConfig.apiKey);
296
- }
358
+ this.storeProviderRequestConfig(providerName, providerConfig);
297
359
  if (providerConfig.modelOverrides) {
298
360
  modelOverrides.set(providerName, new Map(Object.entries(providerConfig.modelOverrides)));
361
+ for (const [modelId, modelOverride] of Object.entries(providerConfig.modelOverrides)) {
362
+ this.storeModelHeaders(providerName, modelId, modelOverride.headers);
363
+ }
299
364
  }
300
365
  }
301
366
  return { models: this.parseModels(config), overrides, modelOverrides, error: undefined };
302
367
  }
303
368
  catch (error) {
304
369
  if (error instanceof SyntaxError) {
305
- return emptyCustomModelsResult(`Failed to parse models.json: ${error.message}\n\nFile: ${filePath}`);
370
+ return emptyCustomModelsResult(`Failed to parse models.json: ${error.message}\n\nFile: ${modelsJsonPath}`);
306
371
  }
307
- return emptyCustomModelsResult(`Failed to load models.json: ${error instanceof Error ? error.message : error}\n\nFile: ${filePath}`);
372
+ return emptyCustomModelsResult(`Failed to load models.json: ${error instanceof Error ? error.message : error}\n\nFile: ${modelsJsonPath}`);
308
373
  }
309
374
  }
310
375
  validateConfig(config) {
376
+ const builtInProviders = new Set(getProviders());
311
377
  for (const [providerName, providerConfig] of Object.entries(config.providers)) {
378
+ const isBuiltIn = builtInProviders.has(providerName);
312
379
  const hasProviderApi = !!providerConfig.api;
313
380
  const models = providerConfig.models ?? [];
314
381
  const hasModelOverrides = providerConfig.modelOverrides && Object.keys(providerConfig.modelOverrides).length > 0;
315
382
  if (models.length === 0) {
316
- // Override-only config: needs baseUrl OR modelOverrides (or both)
317
- if (!providerConfig.baseUrl && !hasModelOverrides) {
318
- throw new Error(`Provider ${providerName}: must specify "baseUrl", "modelOverrides", or "models".`);
383
+ // Override-only config: needs baseUrl, headers, compat, modelOverrides, or some combination.
384
+ if (!providerConfig.baseUrl && !providerConfig.headers && !providerConfig.compat && !hasModelOverrides) {
385
+ throw new Error(`Provider ${providerName}: must specify "baseUrl", "headers", "compat", "modelOverrides", or "models".`);
319
386
  }
320
387
  }
321
- else {
322
- // Custom models are merged into provider models and require endpoint + auth.
388
+ else if (!isBuiltIn) {
389
+ // Non-built-in providers with custom models require endpoint + auth.
323
390
  if (!providerConfig.baseUrl) {
324
391
  throw new Error(`Provider ${providerName}: "baseUrl" is required when defining custom models.`);
325
392
  }
@@ -327,11 +394,14 @@ export class ModelRegistry {
327
394
  throw new Error(`Provider ${providerName}: "apiKey" is required when defining custom models.`);
328
395
  }
329
396
  }
397
+ // Built-in providers with custom models: baseUrl/apiKey/api are optional,
398
+ // inherited from built-in models. Auth comes from env vars / auth storage.
330
399
  for (const modelDef of models) {
331
400
  const hasModelApi = !!modelDef.api;
332
- if (!hasProviderApi && !hasModelApi) {
401
+ if (!hasProviderApi && !hasModelApi && !isBuiltIn) {
333
402
  throw new Error(`Provider ${providerName}, model ${modelDef.id}: no "api" specified. Set at provider or model level.`);
334
403
  }
404
+ // For built-in providers, api is optional — inherited from built-in models.
335
405
  if (!modelDef.id)
336
406
  throw new Error(`Provider ${providerName}: model missing "id"`);
337
407
  // Validate contextWindow/maxTokens only if provided (they have defaults)
@@ -344,46 +414,50 @@ export class ModelRegistry {
344
414
  }
345
415
  parseModels(config) {
346
416
  const models = [];
417
+ const builtInProviders = new Set(getProviders());
418
+ // Cache built-in defaults (api, baseUrl) per provider, extracted from first model.
419
+ const builtInDefaultsCache = new Map();
420
+ const getBuiltInDefaults = (providerName) => {
421
+ if (!builtInProviders.has(providerName))
422
+ return undefined;
423
+ if (builtInDefaultsCache.has(providerName))
424
+ return builtInDefaultsCache.get(providerName);
425
+ const builtIn = getModels(providerName);
426
+ if (builtIn.length === 0)
427
+ return undefined;
428
+ const defaults = { api: builtIn[0].api, baseUrl: builtIn[0].baseUrl };
429
+ builtInDefaultsCache.set(providerName, defaults);
430
+ return defaults;
431
+ };
347
432
  for (const [providerName, providerConfig] of Object.entries(config.providers)) {
348
433
  const modelDefs = providerConfig.models ?? [];
349
434
  if (modelDefs.length === 0)
350
435
  continue; // Override-only, no custom models
351
- // Store API key config for fallback resolver
352
- if (providerConfig.apiKey) {
353
- this.customProviderApiKeys.set(providerName, providerConfig.apiKey);
354
- }
436
+ const builtInDefaults = getBuiltInDefaults(providerName);
355
437
  for (const modelDef of modelDefs) {
356
- const api = modelDef.api || providerConfig.api;
438
+ const api = modelDef.api ?? providerConfig.api ?? builtInDefaults?.api;
357
439
  if (!api)
358
440
  continue;
359
- // Merge headers: provider headers are base, model headers override
360
- // Resolve env vars and shell commands in header values
361
- const providerHeaders = resolveHeaders(providerConfig.headers);
362
- const modelHeaders = resolveHeaders(modelDef.headers);
363
- let headers = providerHeaders || modelHeaders ? { ...providerHeaders, ...modelHeaders } : undefined;
364
- // If authHeader is true, add Authorization header with resolved API key
365
- if (providerConfig.authHeader && providerConfig.apiKey) {
366
- const resolvedKey = resolveConfigValue(providerConfig.apiKey);
367
- if (resolvedKey) {
368
- headers = { ...headers, Authorization: `Bearer ${resolvedKey}` };
369
- }
370
- }
371
- // Provider baseUrl is required when custom models are defined.
372
- // Individual models can override it with modelDef.baseUrl.
441
+ const baseUrl = modelDef.baseUrl ?? providerConfig.baseUrl ?? builtInDefaults?.baseUrl;
442
+ if (!baseUrl)
443
+ continue;
444
+ const compat = mergeCompat(providerConfig.compat, modelDef.compat);
445
+ this.storeModelHeaders(providerName, modelDef.id, modelDef.headers);
373
446
  const defaultCost = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
374
447
  models.push({
375
448
  id: modelDef.id,
376
449
  name: modelDef.name ?? modelDef.id,
377
450
  api: api,
378
451
  provider: providerName,
379
- baseUrl: modelDef.baseUrl ?? providerConfig.baseUrl,
452
+ baseUrl,
380
453
  reasoning: modelDef.reasoning ?? false,
454
+ thinkingLevelMap: modelDef.thinkingLevelMap,
381
455
  input: (modelDef.input ?? ["text"]),
382
456
  cost: modelDef.cost ?? defaultCost,
383
457
  contextWindow: modelDef.contextWindow ?? 128000,
384
458
  maxTokens: modelDef.maxTokens ?? 16384,
385
- headers,
386
- compat: modelDef.compat,
459
+ headers: undefined,
460
+ compat,
387
461
  });
388
462
  }
389
463
  }
@@ -401,7 +475,7 @@ export class ModelRegistry {
401
475
  * This is a fast check that doesn't refresh OAuth tokens.
402
476
  */
403
477
  getAvailable() {
404
- return this.models.filter((m) => this.authStorage.hasAuth(m.provider));
478
+ return this.models.filter((m) => this.hasConfiguredAuth(m));
405
479
  }
406
480
  /**
407
481
  * Find a model by provider and ID.
@@ -412,14 +486,109 @@ export class ModelRegistry {
412
486
  /**
413
487
  * Get API key for a model.
414
488
  */
415
- async getApiKey(model) {
416
- return this.authStorage.getApiKey(model.provider);
489
+ hasConfiguredAuth(model) {
490
+ return (this.authStorage.hasAuth(model.provider) ||
491
+ this.providerRequestConfigs.get(model.provider)?.apiKey !== undefined);
492
+ }
493
+ getModelRequestKey(provider, modelId) {
494
+ return `${provider}:${modelId}`;
495
+ }
496
+ storeProviderRequestConfig(providerName, config) {
497
+ if (!config.apiKey && !config.headers && !config.authHeader) {
498
+ return;
499
+ }
500
+ this.providerRequestConfigs.set(providerName, {
501
+ apiKey: config.apiKey,
502
+ headers: config.headers,
503
+ authHeader: config.authHeader,
504
+ });
505
+ }
506
+ storeModelHeaders(providerName, modelId, headers) {
507
+ const key = this.getModelRequestKey(providerName, modelId);
508
+ if (!headers || Object.keys(headers).length === 0) {
509
+ this.modelRequestHeaders.delete(key);
510
+ return;
511
+ }
512
+ this.modelRequestHeaders.set(key, headers);
513
+ }
514
+ /**
515
+ * Get API key and request headers for a model.
516
+ */
517
+ async getApiKeyAndHeaders(model) {
518
+ try {
519
+ const providerConfig = this.providerRequestConfigs.get(model.provider);
520
+ const apiKeyFromAuthStorage = await this.authStorage.getApiKey(model.provider, { includeFallback: false });
521
+ const apiKey = apiKeyFromAuthStorage ??
522
+ (providerConfig?.apiKey
523
+ ? resolveConfigValueOrThrow(providerConfig.apiKey, `API key for provider "${model.provider}"`)
524
+ : undefined);
525
+ const providerHeaders = resolveHeadersOrThrow(providerConfig?.headers, `provider "${model.provider}"`);
526
+ const modelHeaders = resolveHeadersOrThrow(this.modelRequestHeaders.get(this.getModelRequestKey(model.provider, model.id)), `model "${model.provider}/${model.id}"`);
527
+ let headers = model.headers || providerHeaders || modelHeaders
528
+ ? { ...model.headers, ...providerHeaders, ...modelHeaders }
529
+ : undefined;
530
+ if (providerConfig?.authHeader) {
531
+ if (!apiKey) {
532
+ return { ok: false, error: `No API key found for "${model.provider}"` };
533
+ }
534
+ headers = { ...headers, Authorization: `Bearer ${apiKey}` };
535
+ }
536
+ return {
537
+ ok: true,
538
+ apiKey,
539
+ headers: headers && Object.keys(headers).length > 0 ? headers : undefined,
540
+ };
541
+ }
542
+ catch (error) {
543
+ return {
544
+ ok: false,
545
+ error: error instanceof Error ? error.message : String(error),
546
+ };
547
+ }
548
+ }
549
+ /**
550
+ * Return auth status for a provider, including request auth configured in models.json.
551
+ * This intentionally does not execute command-backed config values.
552
+ */
553
+ getProviderAuthStatus(provider) {
554
+ const authStatus = this.authStorage.getAuthStatus(provider);
555
+ if (authStatus.source) {
556
+ return authStatus;
557
+ }
558
+ const providerApiKey = this.providerRequestConfigs.get(provider)?.apiKey;
559
+ if (!providerApiKey) {
560
+ return authStatus;
561
+ }
562
+ if (providerApiKey.startsWith("!")) {
563
+ return { configured: true, source: "models_json_command" };
564
+ }
565
+ if (process.env[providerApiKey]) {
566
+ return { configured: true, source: "environment", label: providerApiKey };
567
+ }
568
+ return { configured: true, source: "models_json_key" };
569
+ }
570
+ /**
571
+ * Get display name for a provider.
572
+ */
573
+ getProviderDisplayName(provider) {
574
+ const registeredProvider = this.registeredProviders.get(provider);
575
+ const oauthProvider = this.authStorage.getOAuthProviders().find((p) => p.id === provider);
576
+ return (registeredProvider?.name ??
577
+ registeredProvider?.oauth?.name ??
578
+ oauthProvider?.name ??
579
+ BUILT_IN_PROVIDER_DISPLAY_NAMES[provider] ??
580
+ provider);
417
581
  }
418
582
  /**
419
583
  * Get API key for a provider.
420
584
  */
421
585
  async getApiKeyForProvider(provider) {
422
- return this.authStorage.getApiKey(provider);
586
+ const apiKey = await this.authStorage.getApiKey(provider, { includeFallback: false });
587
+ if (apiKey !== undefined) {
588
+ return apiKey;
589
+ }
590
+ const providerApiKey = this.providerRequestConfigs.get(provider)?.apiKey;
591
+ return providerApiKey ? resolveConfigValueUncached(providerApiKey) : undefined;
423
592
  }
424
593
  /**
425
594
  * Check if a model is using OAuth credentials (subscription).
@@ -436,8 +605,9 @@ export class ModelRegistry {
436
605
  * If provider has oauth: registers OAuth provider for /login support.
437
606
  */
438
607
  registerProvider(providerName, config) {
439
- this.registeredProviders.set(providerName, config);
608
+ this.validateProviderConfig(providerName, config);
440
609
  this.applyProviderConfig(providerName, config);
610
+ this.upsertRegisteredProvider(providerName, config);
441
611
  }
442
612
  /**
443
613
  * Unregister a previously registered provider.
@@ -452,9 +622,46 @@ export class ModelRegistry {
452
622
  if (!this.registeredProviders.has(providerName))
453
623
  return;
454
624
  this.registeredProviders.delete(providerName);
455
- this.customProviderApiKeys.delete(providerName);
456
625
  this.refresh();
457
626
  }
627
+ /**
628
+ * Upsert a provider config into registeredProviders.
629
+ * If the provider is already registered, defined values in the incoming config
630
+ * override existing ones; undefined values are preserved from the stored config.
631
+ * If the provider is not registered, the incoming config is stored as-is.
632
+ */
633
+ upsertRegisteredProvider(providerName, config) {
634
+ const existing = this.registeredProviders.get(providerName);
635
+ if (!existing) {
636
+ this.registeredProviders.set(providerName, config);
637
+ return;
638
+ }
639
+ for (const k of Object.keys(config)) {
640
+ if (config[k] !== undefined) {
641
+ existing[k] = config[k];
642
+ }
643
+ }
644
+ }
645
+ validateProviderConfig(providerName, config) {
646
+ if (config.streamSimple && !config.api) {
647
+ throw new Error(`Provider ${providerName}: "api" is required when registering streamSimple.`);
648
+ }
649
+ if (!config.models || config.models.length === 0) {
650
+ return;
651
+ }
652
+ if (!config.baseUrl) {
653
+ throw new Error(`Provider ${providerName}: "baseUrl" is required when defining models.`);
654
+ }
655
+ if (!config.apiKey && !config.oauth) {
656
+ throw new Error(`Provider ${providerName}: "apiKey" or "oauth" is required when defining models.`);
657
+ }
658
+ for (const modelDef of config.models) {
659
+ const api = modelDef.api || config.api;
660
+ if (!api) {
661
+ throw new Error(`Provider ${providerName}, model ${modelDef.id}: no "api" specified.`);
662
+ }
663
+ }
664
+ }
458
665
  applyProviderConfig(providerName, config) {
459
666
  // Register OAuth provider if provided
460
667
  if (config.oauth) {
@@ -466,9 +673,6 @@ export class ModelRegistry {
466
673
  registerOAuthProvider(oauthProvider);
467
674
  }
468
675
  if (config.streamSimple) {
469
- if (!config.api) {
470
- throw new Error(`Provider ${providerName}: "api" is required when registering streamSimple.`);
471
- }
472
676
  const streamSimple = config.streamSimple;
473
677
  registerApiProvider({
474
678
  api: config.api,
@@ -476,49 +680,27 @@ export class ModelRegistry {
476
680
  streamSimple,
477
681
  }, `provider:${providerName}`);
478
682
  }
479
- // Store API key for auth resolution
480
- if (config.apiKey) {
481
- this.customProviderApiKeys.set(providerName, config.apiKey);
482
- }
683
+ this.storeProviderRequestConfig(providerName, config);
483
684
  if (config.models && config.models.length > 0) {
484
685
  // Full replacement: remove existing models for this provider
485
686
  this.models = this.models.filter((m) => m.provider !== providerName);
486
- // Validate required fields
487
- if (!config.baseUrl) {
488
- throw new Error(`Provider ${providerName}: "baseUrl" is required when defining models.`);
489
- }
490
- if (!config.apiKey && !config.oauth) {
491
- throw new Error(`Provider ${providerName}: "apiKey" or "oauth" is required when defining models.`);
492
- }
493
687
  // Parse and add new models
494
688
  for (const modelDef of config.models) {
495
689
  const api = modelDef.api || config.api;
496
- if (!api) {
497
- throw new Error(`Provider ${providerName}, model ${modelDef.id}: no "api" specified.`);
498
- }
499
- // Merge headers
500
- const providerHeaders = resolveHeaders(config.headers);
501
- const modelHeaders = resolveHeaders(modelDef.headers);
502
- let headers = providerHeaders || modelHeaders ? { ...providerHeaders, ...modelHeaders } : undefined;
503
- // If authHeader is true, add Authorization header
504
- if (config.authHeader && config.apiKey) {
505
- const resolvedKey = resolveConfigValue(config.apiKey);
506
- if (resolvedKey) {
507
- headers = { ...headers, Authorization: `Bearer ${resolvedKey}` };
508
- }
509
- }
690
+ this.storeModelHeaders(providerName, modelDef.id, modelDef.headers);
510
691
  this.models.push({
511
692
  id: modelDef.id,
512
693
  name: modelDef.name,
513
694
  api: api,
514
695
  provider: providerName,
515
- baseUrl: config.baseUrl,
696
+ baseUrl: modelDef.baseUrl ?? config.baseUrl,
516
697
  reasoning: modelDef.reasoning,
698
+ thinkingLevelMap: modelDef.thinkingLevelMap,
517
699
  input: modelDef.input,
518
700
  cost: modelDef.cost,
519
701
  contextWindow: modelDef.contextWindow,
520
702
  maxTokens: modelDef.maxTokens,
521
- headers,
703
+ headers: undefined,
522
704
  compat: modelDef.compat,
523
705
  });
524
706
  }
@@ -530,16 +712,14 @@ export class ModelRegistry {
530
712
  }
531
713
  }
532
714
  }
533
- else if (config.baseUrl) {
534
- // Override-only: update baseUrl/headers for existing models
535
- const resolvedHeaders = resolveHeaders(config.headers);
715
+ else if (config.baseUrl || config.headers) {
716
+ // Override-only: update baseUrl for existing models. Request headers are resolved per request.
536
717
  this.models = this.models.map((m) => {
537
718
  if (m.provider !== providerName)
538
719
  return m;
539
720
  return {
540
721
  ...m,
541
722
  baseUrl: config.baseUrl ?? m.baseUrl,
542
- headers: resolvedHeaders ? { ...m.headers, ...resolvedHeaders } : m.headers,
543
723
  };
544
724
  });
545
725
  }