@vibe-forge/client 0.9.0 → 0.10.1

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 (301) hide show
  1. package/AGENTS.md +75 -0
  2. package/dist/assets/abap-DLDM7-KI.js +1 -0
  3. package/dist/assets/apex-DNDY2TF8.js +1 -0
  4. package/dist/assets/{arc-D9HxM0yv.js → arc-C1rWFTer.js} +1 -1
  5. package/dist/assets/azcli-Y6nb8tq_.js +1 -0
  6. package/dist/assets/bat-BwHxbl9M.js +1 -0
  7. package/dist/assets/bicep-CFznDFnq.js +2 -0
  8. package/dist/assets/{blockDiagram-c4efeb88-C_pTeiD4.js → blockDiagram-c4efeb88-DlZ9x70F.js} +1 -1
  9. package/dist/assets/{c4Diagram-c83219d4-_oYrCrLr.js → c4Diagram-c83219d4-BKKxi__y.js} +1 -1
  10. package/dist/assets/cameligo-Bf6VGUru.js +1 -0
  11. package/dist/assets/channel-F1aqMANO.js +1 -0
  12. package/dist/assets/{classDiagram-beda092f-9dnkgPhR.js → classDiagram-beda092f-CVGPySZq.js} +1 -1
  13. package/dist/assets/{classDiagram-v2-2358418a-BUIeZpdO.js → classDiagram-v2-2358418a-7kp8GVVj.js} +1 -1
  14. package/dist/assets/clojure-Dnu-v4kV.js +1 -0
  15. package/dist/assets/clone-B-GCuXNo.js +1 -0
  16. package/dist/assets/codicon-ngg6Pgfi.ttf +0 -0
  17. package/dist/assets/coffee-Bd8akH9Z.js +1 -0
  18. package/dist/assets/cpp-BbWJElDN.js +1 -0
  19. package/dist/assets/{createText-1719965b-DuRFplcD.js → createText-1719965b-Dykv8kT9.js} +1 -1
  20. package/dist/assets/csharp-Co3qMtFm.js +1 -0
  21. package/dist/assets/csp-D-4FJmMZ.js +1 -0
  22. package/dist/assets/css-DdJfP1eB.js +3 -0
  23. package/dist/assets/css.worker-BvV5MPou.js +93 -0
  24. package/dist/assets/cssMode-B59COYVW.js +1 -0
  25. package/dist/assets/cypher-cTPe9QuQ.js +1 -0
  26. package/dist/assets/dart-BOtBlQCF.js +1 -0
  27. package/dist/assets/dockerfile-BG73LgW2.js +1 -0
  28. package/dist/assets/ecl-BEgZUVRK.js +1 -0
  29. package/dist/assets/{edges-96097737-CTpq6Ih_.js → edges-96097737-CkZ1ZBro.js} +1 -1
  30. package/dist/assets/editor.worker-CKy7Pnvo.js +26 -0
  31. package/dist/assets/elixir-BkW5O-1t.js +1 -0
  32. package/dist/assets/{erDiagram-0228fc6a-CWFgdO1E.js → erDiagram-0228fc6a-281ADcRp.js} +1 -1
  33. package/dist/assets/flow9-BeJ5waoc.js +1 -0
  34. package/dist/assets/{flowDb-c6c81e3f-8Vdx29oZ.js → flowDb-c6c81e3f-BQjX_flP.js} +1 -1
  35. package/dist/assets/{flowDiagram-50d868cf-6S9wOVNl.js → flowDiagram-50d868cf-DMHZTjES.js} +1 -1
  36. package/dist/assets/flowDiagram-v2-4f6560a1-C5FzdVl1.js +1 -0
  37. package/dist/assets/{flowchart-elk-definition-6af322e1-DVcZ-ZBQ.js → flowchart-elk-definition-6af322e1-CI3yz4z8.js} +1 -1
  38. package/dist/assets/freemarker2-DWnWjibn.js +3 -0
  39. package/dist/assets/fsharp-PahG7c26.js +1 -0
  40. package/dist/assets/{ganttDiagram-a2739b55-DY1QSl-x.js → ganttDiagram-a2739b55-B3IING9L.js} +1 -1
  41. package/dist/assets/{gitGraphDiagram-82fe8481-BP08OBKL.js → gitGraphDiagram-82fe8481-CnArIr_T.js} +1 -1
  42. package/dist/assets/go-acbASCJo.js +1 -0
  43. package/dist/assets/{graph-D8GCszcN.js → graph-BZ1F0Yve.js} +1 -1
  44. package/dist/assets/graphql-BxJiqAUM.js +1 -0
  45. package/dist/assets/handlebars-C1QH9qTz.js +1 -0
  46. package/dist/assets/hcl-DtV1sZF8.js +1 -0
  47. package/dist/assets/html-D1NkqHjC.js +1 -0
  48. package/dist/assets/html.worker-BLJhxQJQ.js +470 -0
  49. package/dist/assets/htmlMode-DAZCE_rA.js +1 -0
  50. package/dist/assets/{index-5325376f-OOoAXU1u.js → index-5325376f-Da9zSHjA.js} +1 -1
  51. package/dist/assets/index-C0vjF3D0.js +1511 -0
  52. package/dist/assets/index-vzEbM21t.css +32 -0
  53. package/dist/assets/{infoDiagram-8eee0895-BHgkXjhJ.js → infoDiagram-8eee0895-DYbFvRM7.js} +1 -1
  54. package/dist/assets/ini-Kd9XrMLS.js +1 -0
  55. package/dist/assets/java-CXBNlu9o.js +1 -0
  56. package/dist/assets/javascript-CoMjGRHa.js +1 -0
  57. package/dist/assets/{journeyDiagram-c64418c1-BljInElp.js → journeyDiagram-c64418c1-Boebox0b.js} +1 -1
  58. package/dist/assets/json.worker-usMZ-FED.js +58 -0
  59. package/dist/assets/jsonMode-D__gAvuz.js +7 -0
  60. package/dist/assets/julia-cl7-CwDS.js +1 -0
  61. package/dist/assets/kotlin-s7OhZKlX.js +1 -0
  62. package/dist/assets/{layout-Cw-SwAFD.js → layout-CTcHNbHp.js} +1 -1
  63. package/dist/assets/less-9HpZscsL.js +2 -0
  64. package/dist/assets/lexon-OrD6JF1K.js +1 -0
  65. package/dist/assets/{line-Q-uZLuUr.js → line-4AwinCz2.js} +1 -1
  66. package/dist/assets/{linear-BahOnNn3.js → linear-CeSMLzJW.js} +1 -1
  67. package/dist/assets/liquid-DZF6egdE.js +1 -0
  68. package/dist/assets/lspLanguageFeatures-6K4lv5S2.js +4 -0
  69. package/dist/assets/lua-Cyyb5UIc.js +1 -0
  70. package/dist/assets/m3-B8OfTtLu.js +1 -0
  71. package/dist/assets/markdown-BFxVWTOG.js +1 -0
  72. package/dist/assets/mdx-Cnt4ka6w.js +1 -0
  73. package/dist/assets/{mermaid.core-BR0Qh3Rd.js → mermaid.core-B0yG5s4D.js} +6 -6
  74. package/dist/assets/{mindmap-definition-8da855dc-Brq2OJUZ.js → mindmap-definition-8da855dc-KJEvXMKj.js} +1 -1
  75. package/dist/assets/mips-CiqrrVzr.js +1 -0
  76. package/dist/assets/msdax-DmeGPVcC.js +1 -0
  77. package/dist/assets/mysql-C_tMU-Nz.js +1 -0
  78. package/dist/assets/objective-c-BDtDVThU.js +1 -0
  79. package/dist/assets/pascal-vHIfCaH5.js +1 -0
  80. package/dist/assets/pascaligo-DtZ0uQbO.js +1 -0
  81. package/dist/assets/perl-Ub6l9XKa.js +1 -0
  82. package/dist/assets/pgsql-BlNEE0v7.js +1 -0
  83. package/dist/assets/php-BBUBE1dy.js +1 -0
  84. package/dist/assets/{pieDiagram-a8764435-uhYdiXro.js → pieDiagram-a8764435-17nFAXPJ.js} +1 -1
  85. package/dist/assets/pla-DSh2-awV.js +1 -0
  86. package/dist/assets/postiats-CocnycG-.js +1 -0
  87. package/dist/assets/powerquery-tScXyioY.js +1 -0
  88. package/dist/assets/powershell-COWaemsV.js +1 -0
  89. package/dist/assets/protobuf-Brw8urJB.js +2 -0
  90. package/dist/assets/pug-8SOpv6rk.js +1 -0
  91. package/dist/assets/python-DA3TtjDv.js +1 -0
  92. package/dist/assets/qsharp-Bw9ernYp.js +1 -0
  93. package/dist/assets/{quadrantDiagram-1e28029f-TwqtEe7e.js → quadrantDiagram-1e28029f-Dt4vubi-.js} +1 -1
  94. package/dist/assets/r-j7ic8hl3.js +1 -0
  95. package/dist/assets/razor-CWDJgvX_.js +1 -0
  96. package/dist/assets/redis-Bu5POkcn.js +1 -0
  97. package/dist/assets/redshift-Bs9aos_-.js +1 -0
  98. package/dist/assets/{requirementDiagram-08caed73-DSXnPRDS.js → requirementDiagram-08caed73-H6aDyDK-.js} +1 -1
  99. package/dist/assets/restructuredtext-CqXO7rUv.js +1 -0
  100. package/dist/assets/ruby-zBfavPgS.js +1 -0
  101. package/dist/assets/rust-BzKRNQWT.js +1 -0
  102. package/dist/assets/{sankeyDiagram-a04cb91d-EADpJeAn.js → sankeyDiagram-a04cb91d-DxsVtbjI.js} +1 -1
  103. package/dist/assets/sb-BBc9UKZt.js +1 -0
  104. package/dist/assets/scala-D9hQfWCl.js +1 -0
  105. package/dist/assets/scheme-BPhDTwHR.js +1 -0
  106. package/dist/assets/scss-CBJaRo0y.js +3 -0
  107. package/dist/assets/{sequenceDiagram-c5b8d532-C8qXvt9z.js → sequenceDiagram-c5b8d532-BHa148XJ.js} +1 -1
  108. package/dist/assets/shell-DiJ1NA_G.js +1 -0
  109. package/dist/assets/solidity-Db0IVjzk.js +1 -0
  110. package/dist/assets/sophia-CnS9iZB_.js +1 -0
  111. package/dist/assets/sparql-CJmd_6j2.js +1 -0
  112. package/dist/assets/sql-ClhHkBeG.js +1 -0
  113. package/dist/assets/st-CHwy0fLd.js +1 -0
  114. package/dist/assets/{stateDiagram-1ecb1508-5W0ghy_S.js → stateDiagram-1ecb1508-DgwBm8LO.js} +1 -1
  115. package/dist/assets/{stateDiagram-v2-c2b004d7-BfwOQJw4.js → stateDiagram-v2-c2b004d7-BK7IQLVc.js} +1 -1
  116. package/dist/assets/{styles-b4e223ce-EkKH_ULb.js → styles-b4e223ce-DzW27Bc-.js} +1 -1
  117. package/dist/assets/{styles-ca3715f6-DwhrtqlU.js → styles-ca3715f6-Dex2GiLT.js} +1 -1
  118. package/dist/assets/{styles-d45a18b0-yqL8KH6x.js → styles-d45a18b0-B6fGtDKS.js} +1 -1
  119. package/dist/assets/{svgDrawCommon-b86b1483--5VjnjhC.js → svgDrawCommon-b86b1483-B4HYgfV5.js} +1 -1
  120. package/dist/assets/swift-Bqt4WxQ4.js +3 -0
  121. package/dist/assets/systemverilog-Bs9z6M-B.js +1 -0
  122. package/dist/assets/tcl-Dm6ycUr_.js +1 -0
  123. package/dist/assets/{timeline-definition-faaaa080-CWOTwik9.js → timeline-definition-faaaa080--QSbWb25.js} +1 -1
  124. package/dist/assets/ts.worker-DGHjMaqB.js +67731 -0
  125. package/dist/assets/tsMode-ZM7ocZCH.js +11 -0
  126. package/dist/assets/twig-Csy3S7wG.js +1 -0
  127. package/dist/assets/typescript-CKWDmBCc.js +1 -0
  128. package/dist/assets/typespec-Btyra-wh.js +1 -0
  129. package/dist/assets/vb-Db0cS2oM.js +1 -0
  130. package/dist/assets/wgsl-BTesnYfV.js +298 -0
  131. package/dist/assets/xml-DuEUAzPi.js +1 -0
  132. package/dist/assets/{xychartDiagram-f5964ef8-CZg47H1t.js → xychartDiagram-f5964ef8-D09Zkv2K.js} +1 -1
  133. package/dist/assets/yaml-DL7QPRYk.js +1 -0
  134. package/dist/favicon.svg +3 -3
  135. package/dist/index.html +2 -2
  136. package/package.json +14 -10
  137. package/public/favicon.svg +3 -3
  138. package/src/api/sessions.ts +36 -0
  139. package/src/api/workspace.ts +19 -0
  140. package/src/api.ts +4 -0
  141. package/src/components/NavRail.scss +9 -10
  142. package/src/components/ShortcutDisplay.scss +38 -0
  143. package/src/components/ShortcutDisplay.tsx +37 -0
  144. package/src/components/ShortcutTooltip.scss +36 -0
  145. package/src/components/ShortcutTooltip.tsx +84 -0
  146. package/src/components/Sidebar.scss +55 -13
  147. package/src/components/Sidebar.tsx +141 -52
  148. package/src/components/chat/AGENTS.md +163 -0
  149. package/src/components/chat/ChatHeader.scss +308 -49
  150. package/src/components/chat/ChatHeader.tsx +394 -80
  151. package/src/components/chat/ChatHistoryView.tsx +353 -69
  152. package/src/components/chat/ChatSettingsView.tsx +5 -3
  153. package/src/components/chat/ChatTimelineView.scss +3 -2
  154. package/src/components/chat/{sender/ThinkingStatus.tsx → ThinkingStatus.tsx} +1 -1
  155. package/src/components/chat/messages/MessageContextMenu.scss +145 -0
  156. package/src/components/chat/messages/MessageContextMenu.tsx +108 -0
  157. package/src/components/chat/messages/MessageContextMenuContent.tsx +87 -0
  158. package/src/components/chat/messages/MessageFooter.tsx +44 -24
  159. package/src/components/chat/messages/MessageItem.scss +157 -10
  160. package/src/components/chat/messages/MessageItem.tsx +382 -13
  161. package/src/components/chat/messages/build-message-context-menu-entries.ts +166 -0
  162. package/src/components/chat/messages/message-content-utils.ts +121 -0
  163. package/src/components/chat/messages/message-turns.ts +88 -0
  164. package/src/components/chat/messages/message-utils.ts +19 -1
  165. package/src/components/chat/sender/@components/adapter-select/AdapterSelectControl.scss +86 -0
  166. package/src/components/chat/sender/@components/adapter-select/AdapterSelectControl.tsx +54 -0
  167. package/src/components/chat/sender/@components/adapter-select/AdapterSelectDropdown.scss +42 -0
  168. package/src/components/chat/sender/@components/effort-select/EffortSelectControl.scss +68 -0
  169. package/src/components/chat/sender/@components/effort-select/EffortSelectControl.tsx +137 -0
  170. package/src/components/chat/sender/@components/effort-select/EffortSelectDropdown.scss +96 -0
  171. package/src/components/chat/sender/@components/model-select/ModelSelectControl.scss +82 -0
  172. package/src/components/chat/sender/@components/model-select/ModelSelectControl.tsx +171 -0
  173. package/src/components/chat/sender/@components/model-select/ModelSelectMenu.scss +95 -0
  174. package/src/components/chat/sender/@components/model-select/ModelSelectMenuLabels.scss +144 -0
  175. package/src/components/chat/sender/@components/model-select/ModelSelectOptionLabel.tsx +109 -0
  176. package/src/components/chat/sender/@components/reference-actions/ReferenceActionsControl.scss +106 -0
  177. package/src/components/chat/sender/@components/reference-actions/ReferenceActionsControl.tsx +156 -0
  178. package/src/components/chat/sender/@components/reference-actions/ReferenceActionsOption.scss +34 -0
  179. package/src/components/chat/sender/@components/reference-actions/ReferencePermissionActionsPopover.tsx +111 -0
  180. package/src/components/chat/sender/@components/sender-attachments/SenderAttachments.scss +103 -0
  181. package/src/components/chat/sender/@components/sender-attachments/SenderAttachments.tsx +47 -0
  182. package/src/components/chat/sender/@components/sender-body/SenderBody.tsx +137 -0
  183. package/src/components/chat/sender/@components/sender-interaction-panel/SenderInteractionPanel.scss +178 -0
  184. package/src/components/chat/sender/@components/sender-interaction-panel/SenderInteractionPanel.tsx +145 -0
  185. package/src/components/chat/sender/@components/sender-monaco-editor/SenderMonacoEditor.scss +47 -0
  186. package/src/components/chat/sender/@components/sender-monaco-editor/SenderMonacoEditor.tsx +121 -0
  187. package/src/components/chat/sender/@components/sender-monaco-editor/monaco-runtime.ts +99 -0
  188. package/src/components/chat/sender/@components/sender-monaco-editor/use-sender-editor-handle.ts +48 -0
  189. package/src/components/chat/sender/@components/sender-monaco-editor/use-sender-monaco-editor.ts +209 -0
  190. package/src/components/chat/sender/@components/sender-monaco-editor/use-sender-monaco-theme.ts +24 -0
  191. package/src/components/chat/sender/@components/sender-submit-action/SenderSubmitAction.scss +54 -0
  192. package/src/components/chat/sender/@components/sender-submit-action/SenderSubmitAction.tsx +80 -0
  193. package/src/components/chat/sender/@components/sender-toolbar/SenderSelectBase.scss +71 -0
  194. package/src/components/chat/sender/@components/sender-toolbar/SenderSelectShared.scss +118 -0
  195. package/src/components/chat/sender/@components/sender-toolbar/SenderToolbar.scss +99 -0
  196. package/src/components/chat/sender/@components/sender-toolbar/SenderToolbar.tsx +87 -0
  197. package/src/components/chat/sender/@core/build-sender-controller-result.ts +119 -0
  198. package/src/components/chat/sender/@core/build-sender-toolbar.ts +122 -0
  199. package/src/components/chat/sender/@core/content-attachments.ts +76 -0
  200. package/src/components/chat/sender/@core/create-sender-toolbar-handlers.ts +115 -0
  201. package/src/components/chat/sender/@core/get-sender-interaction-state.ts +18 -0
  202. package/src/components/chat/sender/@core/get-sender-runtime-state.ts +14 -0
  203. package/src/components/chat/sender/@core/sender-toolbar-bindings.ts +155 -0
  204. package/src/components/chat/sender/@hooks/use-model-select-browser.tsx +189 -0
  205. package/src/components/chat/sender/@hooks/use-sender-attachments.ts +143 -0
  206. package/src/components/chat/sender/@hooks/use-sender-autofocus.ts +34 -0
  207. package/src/components/chat/sender/@hooks/use-sender-completion.ts +62 -0
  208. package/src/components/chat/sender/@hooks/use-sender-composer-state.ts +34 -0
  209. package/src/components/chat/sender/@hooks/use-sender-controller.ts +193 -0
  210. package/src/components/chat/sender/@hooks/use-sender-focus-restore.ts +72 -0
  211. package/src/components/chat/sender/@hooks/use-sender-history.ts +79 -0
  212. package/src/components/chat/sender/@hooks/use-sender-keydown.ts +113 -0
  213. package/src/components/chat/sender/@hooks/use-sender-reference-actions.ts +191 -0
  214. package/src/components/chat/sender/@hooks/use-sender-reference-focus-restore.ts +21 -0
  215. package/src/components/chat/sender/@hooks/use-sender-refs.ts +19 -0
  216. package/src/components/chat/sender/@hooks/use-sender-select-overlays.ts +83 -0
  217. package/src/components/chat/sender/@hooks/use-sender-shortcuts.ts +78 -0
  218. package/src/components/chat/sender/@hooks/use-sender-submit.ts +81 -0
  219. package/src/components/chat/sender/@types/sender-composer.ts +19 -0
  220. package/src/components/chat/sender/@types/sender-editor.ts +12 -0
  221. package/src/components/chat/sender/@types/sender-props.ts +50 -0
  222. package/src/components/chat/sender/@types/sender-toolbar-types.ts +83 -0
  223. package/src/components/chat/sender/@types/sender-types.ts +21 -0
  224. package/src/components/chat/sender/@utils/sender-completion.ts +164 -0
  225. package/src/components/chat/sender/@utils/sender-constants.ts +18 -0
  226. package/src/components/chat/sender/@utils/sender-utils.ts +45 -0
  227. package/src/components/chat/sender/Sender.scss +6 -737
  228. package/src/components/chat/sender/Sender.tsx +53 -921
  229. package/src/components/chat/session-metadata.ts +55 -0
  230. package/src/components/chat/terminal/@hooks/use-terminal-instance.ts +152 -0
  231. package/src/components/chat/terminal/@hooks/use-terminal-session.ts +196 -0
  232. package/src/components/chat/terminal/ChatTerminalView.scss +62 -0
  233. package/src/components/chat/terminal/ChatTerminalView.tsx +114 -0
  234. package/src/components/chat/tools/core/ToolGroup.scss +7 -0
  235. package/src/components/chat/tools/core/ToolGroup.tsx +94 -44
  236. package/src/components/config/ConfigSectionForm.tsx +8 -1
  237. package/src/components/config/ConfigShortcutInput.tsx +9 -2
  238. package/src/components/config/configSchema.ts +12 -2
  239. package/src/components/config/record-editors/ModelServicesRecordEditor.tsx +0 -14
  240. package/src/components/dock-panel/DockPanel.scss +152 -0
  241. package/src/components/dock-panel/DockPanel.tsx +195 -0
  242. package/src/components/layout/AppShell.scss +40 -2
  243. package/src/components/layout/AppShell.tsx +25 -10
  244. package/src/components/sidebar/SessionContextMenu.scss +143 -0
  245. package/src/components/sidebar/SessionContextMenu.tsx +196 -0
  246. package/src/components/sidebar/SessionContextMenuContent.tsx +89 -0
  247. package/src/components/sidebar/SessionItem.scss +150 -67
  248. package/src/components/sidebar/SessionItem.tsx +183 -134
  249. package/src/components/sidebar/SessionList.scss +47 -17
  250. package/src/components/sidebar/SessionList.tsx +31 -16
  251. package/src/components/sidebar/SidebarHeader.scss +329 -49
  252. package/src/components/sidebar/SidebarHeader.tsx +108 -86
  253. package/src/components/sidebar/SidebarHeaderBatchActions.tsx +81 -0
  254. package/src/components/sidebar/SidebarHeaderSearchActions.tsx +176 -0
  255. package/src/components/sidebar/SidebarHeaderSelectField.tsx +24 -0
  256. package/src/components/sidebar/filter-utils.ts +23 -0
  257. package/src/components/workspace/ContextFilePicker.scss +64 -0
  258. package/src/components/workspace/ContextFilePicker.tsx +171 -0
  259. package/src/connectionManager.ts +4 -2
  260. package/src/hooks/chat/interaction-state.ts +67 -0
  261. package/src/hooks/chat/model-selector-data-builders.ts +146 -0
  262. package/src/hooks/chat/model-selector-data-option-utils.ts +62 -0
  263. package/src/hooks/chat/model-selector-data-types.ts +27 -0
  264. package/src/hooks/chat/model-selector-data.ts +109 -0
  265. package/src/hooks/chat/model-selector-recommendations.ts +69 -0
  266. package/src/hooks/chat/model-selector.ts +9 -0
  267. package/src/hooks/chat/use-chat-interaction.ts +13 -8
  268. package/src/hooks/chat/use-chat-model-adapter-selection.tsx +167 -164
  269. package/src/hooks/chat/use-chat-models.tsx +46 -23
  270. package/src/hooks/chat/use-chat-session-actions.ts +69 -23
  271. package/src/hooks/chat/use-chat-session-messages.ts +158 -60
  272. package/src/hooks/chat/use-chat-session.ts +34 -9
  273. package/src/hooks/chat/use-chat-view.ts +26 -6
  274. package/src/hooks/chat/use-composer-control-shortcuts.ts +69 -0
  275. package/src/hooks/chat/use-terminal-dock-visibility.ts +39 -0
  276. package/src/hooks/use-roving-focus-list.ts +104 -0
  277. package/src/hooks/use-sidebar-navigation.ts +9 -4
  278. package/src/hooks/use-sidebar-query-state.ts +79 -0
  279. package/src/main.tsx +6 -1
  280. package/src/resources/locales/en.json +140 -6
  281. package/src/resources/locales/zh.json +140 -6
  282. package/src/routes/ChatRoute.scss +159 -4
  283. package/src/routes/ChatRoute.tsx +72 -10
  284. package/src/runtime-config.ts +21 -0
  285. package/src/store/index.ts +1 -3
  286. package/src/styles/global.scss +12 -2
  287. package/src/utils/chat-links.ts +21 -0
  288. package/src/utils/copy.ts +18 -0
  289. package/src/utils/shortcutUtils.ts +111 -1
  290. package/src/vite-env.d.ts +1 -0
  291. package/src/ws.ts +6 -5
  292. package/vite.config.ts +71 -7
  293. package/dist/assets/channel-Di8KkPU4.js +0 -1
  294. package/dist/assets/clone-B065n6L-.js +0 -1
  295. package/dist/assets/flowDiagram-v2-4f6560a1-nj-oVLPK.js +0 -1
  296. package/dist/assets/index-BZe1Qtye.css +0 -1
  297. package/dist/assets/index-DV3eI2aD.js +0 -557
  298. package/src/components/chat/sender/CompletionMenu.scss +0 -70
  299. package/src/components/chat/sender/CompletionMenu.tsx +0 -58
  300. /package/src/components/chat/{sender/ThinkingStatus.scss → ThinkingStatus.scss} +0 -0
  301. /package/src/components/chat/sender/{interaction-request.ts → @core/interaction-request.ts} +0 -0
@@ -3,8 +3,6 @@ import type { ReactNode } from 'react'
3
3
  import { useTranslation } from 'react-i18next'
4
4
  import useSWR from 'swr'
5
5
 
6
- import { getConfig } from '#~/api.js'
7
- import { getAdapterDisplay } from '#~/resources/adapters.js'
8
6
  import type {
9
7
  AdapterBuiltinModel,
10
8
  ConfigResponse,
@@ -12,8 +10,11 @@ import type {
12
10
  ModelServiceConfig,
13
11
  RecommendedModelConfig
14
12
  } from '@vibe-forge/types'
13
+
14
+ import { getConfig, updateConfig } from '#~/api.js'
15
+ import { ModelSelectOptionLabel } from '#~/components/chat/sender/@components/model-select/ModelSelectOptionLabel'
16
+ import { getAdapterDisplay } from '#~/resources/adapters.js'
15
17
  import {
16
- buildServiceModelSelector,
17
18
  listServiceModels,
18
19
  normalizeNonEmptyString,
19
20
  resolveAdapterForChatModelSelection,
@@ -21,22 +22,34 @@ import {
21
22
  resolveChatAdapterSelection,
22
23
  resolveChatModelSelection,
23
24
  resolveDefaultChatModelSelection,
24
- resolveModelForChatAdapterSelection,
25
- resolveServiceModelSelector
25
+ resolveModelForChatAdapterSelection
26
26
  } from './model-selector'
27
-
28
- export interface ModelSelectOption {
29
- value: string
27
+ import { buildModelSelectorData } from './model-selector-data'
28
+ import type { ModelSelectGroupData, ModelSelectOptionData } from './model-selector-data'
29
+ import {
30
+ buildRecommendedModelKey,
31
+ buildUpdatedUserGeneralSection,
32
+ isModelSelectorRecommendation,
33
+ toggleModelSelectorRecommendation
34
+ } from './model-selector-recommendations'
35
+
36
+ export interface ModelSelectOption extends ModelSelectOptionData {
37
+ canToggleRecommendation: boolean
38
+ isRecommended: boolean
39
+ isUserRecommended: boolean
30
40
  label: React.ReactNode
31
- searchText: string
32
- displayLabel: string
33
41
  }
34
42
 
35
43
  export interface ModelSelectGroup {
44
+ key: string
36
45
  label: React.ReactNode
37
46
  options: ModelSelectOption[]
38
47
  }
39
48
 
49
+ export interface ModelSelectMenuGroup extends Omit<ModelSelectGroupData, 'options'> {
50
+ options: ModelSelectOption[]
51
+ }
52
+
40
53
  type SelectionDriver = 'adapter' | 'model'
41
54
 
42
55
  const ADAPTER_STORAGE_KEY = 'vf_chat_adapter'
@@ -72,7 +85,8 @@ export function useChatModelAdapterSelection({
72
85
  )
73
86
  const [selectedModel, setSelectedModel] = useState<string | undefined>(() => readStorageValue(MODEL_STORAGE_KEY))
74
87
  const [selectionDriver, setSelectionDriver] = useState<SelectionDriver>(() => readSelectionDriver())
75
- const { data: configRes } = useSWR<ConfigResponse>('/api/config', getConfig)
88
+ const [updatingRecommendedModelValue, setUpdatingRecommendedModelValue] = useState<string | undefined>()
89
+ const { data: configRes, mutate } = useSWR<ConfigResponse>('/api/config', getConfig)
76
90
 
77
91
  const mergedAdapters = useMemo(() => {
78
92
  return (configRes?.sources?.merged?.adapters ?? {}) as Record<string, unknown>
@@ -94,6 +108,40 @@ export function useChatModelAdapterSelection({
94
108
  ))
95
109
  }, [configRes?.sources?.merged?.general?.recommendedModels])
96
110
 
111
+ const userRecommendedModels = useMemo(() => {
112
+ const raw = configRes?.sources?.user?.general?.recommendedModels
113
+ if (!Array.isArray(raw)) return []
114
+ return raw.filter((item): item is RecommendedModelConfig => (
115
+ item != null && typeof item === 'object' && typeof item.model === 'string' && item.model.trim() !== ''
116
+ ))
117
+ }, [configRes?.sources?.user?.general?.recommendedModels])
118
+
119
+ const userRecommendedModelKeySet = useMemo(() => {
120
+ return new Set(
121
+ userRecommendedModels
122
+ .filter(isModelSelectorRecommendation)
123
+ .map(item =>
124
+ buildRecommendedModelKey({
125
+ model: item.model,
126
+ service: item.service
127
+ })
128
+ )
129
+ )
130
+ }, [userRecommendedModels])
131
+
132
+ const mergedRecommendedModelKeySet = useMemo(() => {
133
+ return new Set(
134
+ recommendedModels
135
+ .filter(isModelSelectorRecommendation)
136
+ .map(item =>
137
+ buildRecommendedModelKey({
138
+ model: item.model,
139
+ service: item.service
140
+ })
141
+ )
142
+ )
143
+ }, [recommendedModels])
144
+
97
145
  const adapterBuiltinModels = useMemo(() => {
98
146
  return (configRes?.sources?.merged?.adapterBuiltinModels ?? {}) as Record<string, AdapterBuiltinModel[]>
99
147
  }, [configRes?.sources?.merged?.adapterBuiltinModels])
@@ -369,187 +417,142 @@ export function useChatModelAdapterSelection({
369
417
  })
370
418
  }, [availableAdapters])
371
419
 
372
- const modelServiceEntries = useMemo(() => Object.entries(mergedModelServices), [mergedModelServices])
373
- const modelToService = useMemo(() => {
374
- const map = new Map<string, { key: string; title: string }>()
375
- for (const entry of availableServiceModels) {
376
- const serviceValue = mergedModelServices[entry.serviceKey]
377
- const serviceTitle = serviceValue?.title?.trim() !== '' ? serviceValue?.title ?? '' : entry.serviceKey
378
- if (!map.has(entry.model)) {
379
- map.set(entry.model, { key: entry.serviceKey, title: serviceTitle })
380
- }
381
- }
382
- return map
383
- }, [availableServiceModels, mergedModelServices])
384
-
385
- const modelOptions = useMemo<ModelSelectGroup[]>(() => {
386
- const buildOption = (params: {
387
- value: string
388
- title: string
389
- description?: string
390
- serviceKey?: string
391
- serviceTitle?: string
392
- }) => {
393
- const description = params.description?.trim()
394
- const label = (
395
- <div className='model-option'>
396
- <div className='model-option-title'>{params.title}</div>
397
- {description && <div className='model-option-desc'>{description}</div>}
398
- </div>
399
- )
400
- const searchText = [
401
- params.title,
402
- params.value,
403
- params.serviceTitle,
404
- params.serviceKey,
405
- description
406
- ]
407
- .filter(Boolean)
408
- .join(' ')
409
- return {
410
- value: params.value,
411
- label,
412
- searchText,
413
- displayLabel: params.title
414
- }
420
+ const toggleRecommendedModel = useCallback(async (option: ModelSelectOption) => {
421
+ const serviceKey = option.serviceKey?.trim()
422
+ const modelName = option.modelName.trim()
423
+ if (
424
+ configRes?.sources == null ||
425
+ !serviceKey ||
426
+ modelName === '' ||
427
+ updatingRecommendedModelValue === option.value
428
+ ) {
429
+ return
415
430
  }
416
431
 
417
- const resolveFirstAlias = (modelsAlias: Record<string, string[]> | undefined, model: string) => {
418
- if (!modelsAlias) return undefined
419
- for (const [alias, aliasModels] of Object.entries(modelsAlias)) {
420
- if (!Array.isArray(aliasModels)) continue
421
- if (aliasModels.includes(model)) return alias
422
- }
423
- return undefined
424
- }
432
+ setUpdatingRecommendedModelValue(option.value)
425
433
 
426
- const serviceGroups = modelServiceEntries
427
- .map(([serviceKey, serviceValue]) => {
428
- const service = (serviceValue != null && typeof serviceValue === 'object')
429
- ? serviceValue as ModelServiceConfig
430
- : undefined
431
- const serviceTitle = service?.title?.trim() !== '' ? service?.title ?? '' : serviceKey
432
- const groupTitle = serviceTitle?.trim() !== '' ? serviceTitle : serviceKey
433
- const serviceDescription = service?.description
434
- const models = Array.isArray(service?.models)
435
- ? service.models.filter((item: unknown): item is string => typeof item === 'string')
436
- : []
437
- if (models.length === 0) return null
438
- const options = models.map((model: string) => {
439
- const alias = resolveFirstAlias(service?.modelsAlias as Record<string, string[]> | undefined, model)
440
- const title = alias ?? model
441
- const description = alias ? model : serviceTitle
442
- return buildOption({
443
- value: buildServiceModelSelector(serviceKey, model),
444
- title,
445
- description,
446
- serviceKey,
447
- serviceTitle
448
- })
449
- })
450
- return {
451
- label: (
452
- <div className='model-group-label'>
453
- <div className='model-group-title'>{groupTitle}</div>
454
- {serviceDescription && <div className='model-group-desc'>{serviceDescription}</div>}
455
- </div>
456
- ),
457
- options
434
+ try {
435
+ const { recommendedModels: nextRecommendedModels } = toggleModelSelectorRecommendation({
436
+ currentRecommendedModels: configRes?.sources?.user?.general?.recommendedModels,
437
+ nextRecommendedModel: {
438
+ service: serviceKey,
439
+ model: modelName,
440
+ placement: 'modelSelector'
458
441
  }
459
442
  })
460
- .filter((item): item is NonNullable<typeof item> => item != null)
461
-
462
- const recommendedOptions = recommendedModels
463
- .filter((item) => {
464
- if (item.placement && item.placement !== 'modelSelector') return false
465
- return resolveServiceModelSelector({
466
- value: item.service ? buildServiceModelSelector(item.service, item.model) : item.model,
467
- serviceModels: availableServiceModels,
468
- preferredServiceKey: item.service ?? defaultModelService
469
- }) != null
470
- })
471
- .map((item) => {
472
- const serviceInfo = item.service ? mergedModelServices[item.service] : undefined
473
- const serviceTitle = item.service
474
- ? (serviceInfo?.title?.trim() !== '' ? serviceInfo?.title ?? '' : item.service)
475
- : modelToService.get(item.model)?.title
476
- const alias = item.service
477
- ? resolveFirstAlias(serviceInfo?.modelsAlias as Record<string, string[]> | undefined, item.model)
478
- : undefined
479
- const title = item.title?.trim() !== '' ? item.title ?? '' : (alias ?? item.model)
480
- const description = item.description?.trim() !== ''
481
- ? item.description
482
- : serviceTitle
483
- const value = resolveServiceModelSelector({
484
- value: item.service ? buildServiceModelSelector(item.service, item.model) : item.model,
485
- serviceModels: availableServiceModels,
486
- preferredServiceKey: item.service ?? defaultModelService
487
- }) ?? item.model
488
- return buildOption({
489
- value,
490
- title,
491
- description,
492
- serviceKey: item.service ?? modelToService.get(item.model)?.key,
493
- serviceTitle
494
- })
443
+ const nextUserGeneralSection = buildUpdatedUserGeneralSection({
444
+ currentGeneral: configRes?.sources?.user?.general,
445
+ recommendedModels: nextRecommendedModels
495
446
  })
496
447
 
497
- const groups = []
498
- if (recommendedOptions.length > 0) {
499
- const recommendedTitle = t('chat.modelGroupRecommended', { defaultValue: '推荐模型' })
500
- groups.push({
501
- label: (
502
- <div className='model-group-label'>
503
- <div className='model-group-title'>{recommendedTitle}</div>
504
- </div>
505
- ),
506
- options: recommendedOptions
507
- })
448
+ await updateConfig('user', 'general', nextUserGeneralSection)
449
+ await mutate()
450
+ } catch (error) {
451
+ console.error('[chat] failed to update recommended models', error)
452
+ } finally {
453
+ setUpdatingRecommendedModelValue(undefined)
508
454
  }
509
-
510
- for (const [adapterKey, models] of Object.entries(activeBuiltinModels)) {
511
- if (!Array.isArray(models) || models.length === 0) continue
512
- const adapterTitle = t('chat.modelGroupBuiltin', {
513
- adapter: adapterKey,
514
- defaultValue: `${adapterKey} (Default)`
515
- })
516
- groups.push({
517
- label: (
518
- <div className='model-group-label'>
519
- <div className='model-group-title'>{adapterTitle}</div>
520
- </div>
521
- ),
522
- options: models.map(model =>
523
- buildOption({
524
- value: model.value,
525
- title: model.title,
526
- description: model.description
527
- })
528
- )
455
+ }, [configRes?.sources?.user?.general, mutate, updatingRecommendedModelValue])
456
+
457
+ const decorateModelOption = useCallback((option: ModelSelectOptionData): ModelSelectOption => {
458
+ const recommendationKey = option.serviceKey == null
459
+ ? undefined
460
+ : buildRecommendedModelKey({
461
+ model: option.modelName,
462
+ service: option.serviceKey
529
463
  })
464
+ const decoratedOption: ModelSelectOption = {
465
+ ...option,
466
+ canToggleRecommendation: option.serviceKey != null && option.modelName.trim() !== '',
467
+ isRecommended: recommendationKey != null && mergedRecommendedModelKeySet.has(recommendationKey),
468
+ isUserRecommended: recommendationKey != null && userRecommendedModelKeySet.has(recommendationKey),
469
+ label: null
530
470
  }
531
471
 
532
- return [...groups, ...serviceGroups]
472
+ decoratedOption.label = (
473
+ <ModelSelectOptionLabel
474
+ option={decoratedOption}
475
+ onToggleRecommendedModel={toggleRecommendedModel}
476
+ updatingRecommendedModelValue={updatingRecommendedModelValue}
477
+ />
478
+ )
479
+
480
+ return decoratedOption
481
+ }, [mergedRecommendedModelKeySet, toggleRecommendedModel, updatingRecommendedModelValue, userRecommendedModelKeySet])
482
+
483
+ const modelSelectorData = useMemo(() => {
484
+ return buildModelSelectorData({
485
+ activeBuiltinModels,
486
+ availableServiceModels,
487
+ defaultModelService,
488
+ mergedModels,
489
+ mergedModelServices,
490
+ recommendedModels,
491
+ recommendedGroupTitle: t('chat.modelGroupRecommended', { defaultValue: '推荐模型' }),
492
+ servicePreviewGroupTitle: t('chat.modelGroupServices', { defaultValue: '模型服务' }),
493
+ builtinGroupTitle: (adapterKey) =>
494
+ t('chat.modelGroupBuiltin', {
495
+ adapter: adapterKey,
496
+ defaultValue: `${adapterKey} (Default)`
497
+ })
498
+ })
533
499
  }, [
534
500
  activeBuiltinModels,
535
501
  availableServiceModels,
536
502
  defaultModelService,
503
+ mergedModels,
537
504
  mergedModelServices,
538
- modelServiceEntries,
539
- modelToService,
540
505
  recommendedModels,
541
506
  t
542
507
  ])
543
508
 
509
+ const modelSearchOptions = useMemo<ModelSelectOption[]>(() => {
510
+ return modelSelectorData.searchOptions.map(decorateModelOption)
511
+ }, [decorateModelOption, modelSelectorData.searchOptions])
512
+
513
+ const recommendedModelOptions = useMemo<ModelSelectOption[]>(() => {
514
+ return modelSelectorData.recommendedOptions.map(decorateModelOption)
515
+ }, [decorateModelOption, modelSelectorData.recommendedOptions])
516
+
517
+ const servicePreviewModelOptions = useMemo<ModelSelectOption[]>(() => {
518
+ return modelSelectorData.servicePreviewOptions.map(decorateModelOption)
519
+ }, [decorateModelOption, modelSelectorData.servicePreviewOptions])
520
+
521
+ const modelMenuGroups = useMemo<ModelSelectMenuGroup[]>(() => {
522
+ return modelSelectorData.moreModelGroups.map(group => ({
523
+ ...group,
524
+ options: group.options.map(decorateModelOption)
525
+ }))
526
+ }, [decorateModelOption, modelSelectorData.moreModelGroups])
527
+
528
+ const modelOptions = useMemo<ModelSelectGroup[]>(() => {
529
+ return modelSelectorData.flatGroups.map(group => ({
530
+ key: group.key,
531
+ label: (
532
+ <div className='model-group-label'>
533
+ <div className='model-group-title'>{group.title}</div>
534
+ {group.description && <div className='model-group-desc'>{group.description}</div>}
535
+ </div>
536
+ ),
537
+ options: group.options.map(decorateModelOption)
538
+ }))
539
+ }, [decorateModelOption, modelSelectorData.flatGroups])
540
+
544
541
  return {
545
542
  adapterOptions,
546
543
  applySessionSelection,
547
544
  hasAvailableModels,
545
+ modelMenuGroups,
548
546
  modelOptions,
547
+ modelSearchOptions,
548
+ recommendedModelOptions,
549
+ servicePreviewModelOptions,
549
550
  selectedAdapter,
550
551
  selectedModel,
551
552
  selectedModelWithService,
552
553
  setSelectedAdapter: updateSelectedAdapter,
553
- setSelectedModel: updateSelectedModel
554
+ setSelectedModel: updateSelectedModel,
555
+ toggleRecommendedModel,
556
+ updatingRecommendedModelValue
554
557
  }
555
558
  }
@@ -2,13 +2,22 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'
2
2
  import { useTranslation } from 'react-i18next'
3
3
  import useSWR from 'swr'
4
4
 
5
+ import type {
6
+ AdapterBuiltinModel,
7
+ ConfigResponse,
8
+ ModelMetadataConfig,
9
+ ModelServiceConfig,
10
+ RecommendedModelConfig
11
+ } from '@vibe-forge/types'
12
+
5
13
  import { getConfig } from '#~/api.js'
6
- import type { AdapterBuiltinModel, ConfigResponse, ModelServiceConfig, RecommendedModelConfig } from '@vibe-forge/types'
7
14
  import {
8
15
  buildServiceModelSelector,
9
16
  listServiceModels,
10
17
  resolveChatModelSelection,
11
18
  resolveDefaultChatModelSelection,
19
+ resolveModelDisplayMetadata,
20
+ resolveModelServiceTitle,
12
21
  resolveServiceModelSelector
13
22
  } from './model-selector'
14
23
 
@@ -45,6 +54,11 @@ export function useChatModels({
45
54
  return (services ?? {}) as Record<string, ModelServiceConfig>
46
55
  }, [configRes?.sources?.merged?.modelServices])
47
56
 
57
+ const mergedModels = useMemo(() => {
58
+ const models = configRes?.sources?.merged?.models
59
+ return (models ?? {}) as Record<string, ModelMetadataConfig>
60
+ }, [configRes?.sources?.merged?.models])
61
+
48
62
  const recommendedModels = useMemo(() => {
49
63
  const raw = configRes?.sources?.merged?.general?.recommendedModels
50
64
  if (!Array.isArray(raw)) return []
@@ -85,7 +99,10 @@ export function useChatModels({
85
99
  const map = new Map<string, { key: string; title: string }>()
86
100
  for (const entry of availableServiceModels) {
87
101
  const serviceValue = mergedModelServices[entry.serviceKey]
88
- const serviceTitle = serviceValue?.title?.trim() !== '' ? serviceValue?.title ?? '' : entry.serviceKey
102
+ const serviceTitle = resolveModelServiceTitle({
103
+ serviceKey: entry.serviceKey,
104
+ service: serviceValue
105
+ })
89
106
  if (!map.has(entry.model)) {
90
107
  map.set(entry.model, { key: entry.serviceKey, title: serviceTitle })
91
108
  }
@@ -186,21 +203,15 @@ export function useChatModels({
186
203
  }
187
204
  }
188
205
 
189
- const resolveFirstAlias = (modelsAlias: Record<string, string[]> | undefined, model: string) => {
190
- if (!modelsAlias) return undefined
191
- for (const [alias, aliasModels] of Object.entries(modelsAlias)) {
192
- if (!Array.isArray(aliasModels)) continue
193
- if (aliasModels.includes(model)) return alias
194
- }
195
- return undefined
196
- }
197
-
198
206
  const serviceGroups = modelServiceEntries
199
207
  .map(([serviceKey, serviceValue]) => {
200
208
  const service = (serviceValue != null && typeof serviceValue === 'object')
201
209
  ? serviceValue as ModelServiceConfig
202
210
  : undefined
203
- const serviceTitle = service?.title?.trim() !== '' ? service?.title ?? '' : serviceKey
211
+ const serviceTitle = resolveModelServiceTitle({
212
+ serviceKey,
213
+ service
214
+ })
204
215
  const groupTitle = serviceTitle?.trim() !== '' ? serviceTitle : serviceKey
205
216
  const serviceDescription = service?.description
206
217
  const models = Array.isArray(service?.models)
@@ -208,11 +219,15 @@ export function useChatModels({
208
219
  : []
209
220
  if (models.length === 0) return null
210
221
  const options = models.map((model: string) => {
211
- const alias = resolveFirstAlias(service?.modelsAlias as Record<string, string[]> | undefined, model)
212
- const title = alias ?? model
213
- const description = alias ? model : serviceTitle
222
+ const value = buildServiceModelSelector(serviceKey, model)
223
+ const metadata = resolveModelDisplayMetadata({
224
+ model: value,
225
+ models: mergedModels
226
+ })
227
+ const title = metadata?.title ?? metadata?.aliases[0] ?? model
228
+ const description = metadata?.description ?? serviceTitle
214
229
  return buildOption({
215
- value: buildServiceModelSelector(serviceKey, model),
230
+ value,
216
231
  title,
217
232
  description,
218
233
  serviceKey,
@@ -243,17 +258,24 @@ export function useChatModels({
243
258
  .map((item) => {
244
259
  const serviceInfo = item.service ? mergedModelServices[item.service] : undefined
245
260
  const serviceTitle = item.service
246
- ? (serviceInfo?.title?.trim() !== '' ? serviceInfo?.title ?? '' : item.service)
261
+ ? resolveModelServiceTitle({
262
+ serviceKey: item.service,
263
+ service: serviceInfo
264
+ })
247
265
  : modelToService.get(item.model)?.title
248
- const alias = item.service
249
- ? resolveFirstAlias(serviceInfo?.modelsAlias as Record<string, string[]> | undefined, item.model)
250
- : undefined
251
- const title = item.title?.trim() !== '' ? item.title ?? '' : (alias ?? item.model)
266
+ const resolvedModel = item.service ? buildServiceModelSelector(item.service, item.model) : item.model
267
+ const metadata = resolveModelDisplayMetadata({
268
+ model: resolvedModel,
269
+ models: mergedModels
270
+ })
271
+ const title = item.title?.trim() !== ''
272
+ ? item.title ?? ''
273
+ : (metadata?.title ?? metadata?.aliases[0] ?? item.model)
252
274
  const description = item.description?.trim() !== ''
253
275
  ? item.description
254
- : serviceTitle
276
+ : (metadata?.description ?? serviceTitle)
255
277
  const value = resolveServiceModelSelector({
256
- value: item.service ? buildServiceModelSelector(item.service, item.model) : item.model,
278
+ value: resolvedModel,
257
279
  serviceModels: availableServiceModels,
258
280
  preferredServiceKey: item.service ?? defaultModelService
259
281
  }) ?? item.model
@@ -308,6 +330,7 @@ export function useChatModels({
308
330
  availableServiceModels,
309
331
  defaultModelService,
310
332
  modelToService,
333
+ mergedModels,
311
334
  mergedModelServices,
312
335
  modelServiceEntries,
313
336
  recommendedModels,