@pheem49/mint 1.14.0 → 1.15.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 (585) hide show
  1. package/CLAUDE.md +1 -1
  2. package/Cargo.lock +291 -11
  3. package/Cargo.toml +1 -1
  4. package/README.md +71 -9
  5. package/ROADMAP.md +30 -0
  6. package/Release_Note.md +579 -465
  7. package/crates/mint-cli/Cargo.toml +3 -1
  8. package/crates/mint-cli/src/agent/approval_prompts.rs +16 -3
  9. package/crates/mint-cli/src/agent/live_status.rs +367 -118
  10. package/crates/mint-cli/src/agent/markdown_render.rs +601 -61
  11. package/crates/mint-cli/src/agent.rs +452 -215
  12. package/crates/mint-cli/src/commands/agent.rs +16 -21
  13. package/crates/mint-cli/src/commands/eval.rs +9 -5
  14. package/crates/mint-cli/src/commands/git.rs +204 -0
  15. package/crates/mint-cli/src/commands/integrations.rs +28 -0
  16. package/crates/mint-cli/src/commands/knowledge.rs +1 -0
  17. package/crates/mint-cli/src/commands/mod.rs +37 -2
  18. package/crates/mint-cli/src/commands/tailnet_web.rs +235 -0
  19. package/crates/mint-cli/src/image.rs +26 -3
  20. package/crates/mint-cli/src/interactive/chat_tui.rs +4742 -0
  21. package/crates/mint-cli/src/interactive/command_ui.rs +477 -0
  22. package/crates/mint-cli/src/interactive/format.rs +8 -0
  23. package/crates/mint-cli/src/interactive/input_box.rs +38 -2
  24. package/crates/mint-cli/src/interactive/picker.rs +180 -37
  25. package/crates/mint-cli/src/interactive/resume_picker.rs +686 -0
  26. package/crates/mint-cli/src/interactive/slash_commands.rs +868 -450
  27. package/crates/mint-cli/src/interactive/thought_viewer.rs +286 -0
  28. package/crates/mint-cli/src/interactive.rs +400 -136
  29. package/crates/mint-cli/src/main.rs +84 -23
  30. package/crates/mint-cli/src/markdown.rs +12 -5
  31. package/crates/mint-cli/src/onboard.rs +32 -30
  32. package/crates/mint-cli/src/plugins_cli.rs +8 -5
  33. package/crates/mint-cli/src/setup.rs +10 -8
  34. package/crates/mint-cli/src/terminal_theme.rs +187 -0
  35. package/crates/mint-cli/src/updater.rs +56 -21
  36. package/crates/mint-core/src/agent/agent_loop.rs +1 -0
  37. package/crates/mint-core/src/agent/chat.rs +843 -177
  38. package/crates/mint-core/src/agent/code_tools.rs +83 -2
  39. package/crates/mint-core/src/agent/memory.rs +658 -20
  40. package/crates/mint-core/src/agent/skills.rs +1 -1
  41. package/crates/mint-core/src/api_server/routes/chat.rs +31 -5
  42. package/crates/mint-core/src/api_server/routes/linked_folders.rs +118 -3
  43. package/crates/mint-core/src/api_server/routes/misc.rs +10 -14
  44. package/crates/mint-core/src/api_server/routes/sessions.rs +44 -0
  45. package/crates/mint-core/src/api_server.rs +22 -3
  46. package/crates/mint-core/src/avatar_bridge.rs +2 -0
  47. package/crates/mint-core/src/browser/cdp.rs +74 -83
  48. package/crates/mint-core/src/browser/evidence.rs +260 -0
  49. package/crates/mint-core/src/browser/input.rs +1 -1
  50. package/crates/mint-core/src/browser/interact.rs +98 -124
  51. package/crates/mint-core/src/browser/lifecycle.rs +75 -4
  52. package/crates/mint-core/src/browser/mod.rs +16 -2
  53. package/crates/mint-core/src/browser/navigate.rs +27 -19
  54. package/crates/mint-core/src/browser/observe.js +40 -0
  55. package/crates/mint-core/src/browser/session.rs +1558 -0
  56. package/crates/mint-core/src/git/branches.rs +348 -0
  57. package/crates/mint-core/src/git/checkpoint.rs +40 -0
  58. package/crates/mint-core/src/git/diff.rs +206 -0
  59. package/crates/mint-core/src/git/mod.rs +10 -2
  60. package/crates/mint-core/src/integrations/channels.rs +1 -0
  61. package/crates/mint-core/src/lib.rs +22 -14
  62. package/crates/mint-core/src/live_sync.rs +28 -9
  63. package/crates/mint-core/src/media/auto_shorts.rs +1 -0
  64. package/crates/mint-core/src/media/gemini_live.rs +12 -1
  65. package/crates/mint-core/src/media/mic_transcribe.rs +1 -0
  66. package/crates/mint-core/src/media/subtitle.rs +1 -0
  67. package/crates/mint-core/src/orchestration/context_render.rs +1 -0
  68. package/crates/mint-core/src/orchestration/memory_skill.rs +6 -1
  69. package/crates/mint-core/src/orchestration/mod.rs +1024 -271
  70. package/crates/mint-core/src/orchestration/tools/browser.rs +16 -139
  71. package/crates/mint-core/src/orchestration/tools/misc.rs +2 -1
  72. package/crates/mint-core/src/orchestration/tools/web.rs +1 -1
  73. package/crates/mint-core/src/prompts/agent.rs +58 -29
  74. package/crates/mint-core/src/prompts/chat.rs +1 -1
  75. package/crates/mint-core/src/prompts/persona.rs +1 -1
  76. package/crates/mint-core/src/prompts/tool_catalog.rs +93 -25
  77. package/crates/mint-core/src/search/linked_folders/index.rs +732 -0
  78. package/crates/mint-core/src/search/linked_folders.rs +391 -130
  79. package/crates/mint-core/src/slash/mod.rs +470 -22
  80. package/crates/mint-core/src/slash/model_fetcher.rs +12 -3
  81. package/crates/mint-core/src/slash/models.rs +66 -10
  82. package/crates/mint-core/src/system/config.rs +230 -0
  83. package/crates/mint-core/src/system/workspace.rs +228 -0
  84. package/crates/mint-core/src/system.rs +1 -0
  85. package/crates/mint-core/tests/memory_persistence.rs +39 -0
  86. package/mint-presentation-demo.mp4 +0 -0
  87. package/out/web/assets/CliSessionsView-BxUVWEEL.js +1 -0
  88. package/out/web/assets/CliSessionsView-CBDTXuQv.css +1 -0
  89. package/out/web/assets/CodeReviewPage-DkMgfcos.css +1 -0
  90. package/out/web/assets/CodeReviewPage-jKlmLJwT.js +3 -0
  91. package/out/web/assets/CommandPalette-DnwPA5hy.js +1 -0
  92. package/out/web/assets/ImageStudioPanel-BR1XFwhR.js +1 -0
  93. package/out/web/assets/ImageStudioPanel-D0lnhQV5.css +1 -0
  94. package/out/web/assets/LinkedFoldersView-bi-CWQ-I.js +1 -0
  95. package/out/web/assets/McpRegistryPicker-D5tEFnyq.js +1 -0
  96. package/out/web/assets/McpServersView-BGG1dhFM.js +1 -0
  97. package/out/web/assets/MintDashboard-BIglDEWX.js +20 -0
  98. package/out/web/assets/MintDashboard-DSMywSgs.css +1 -0
  99. package/out/web/assets/ModelPanel-CbJ1PFoZ.js +1 -0
  100. package/out/web/assets/PicturesLibrary-CQP0fLP1.css +1 -0
  101. package/out/web/assets/PicturesLibrary-DoYN7T1p.js +1 -0
  102. package/out/web/assets/PluginsView-CU1HWXGk.js +1 -0
  103. package/out/web/assets/ScheduledTasksView-Bnl36y2N.js +1 -0
  104. package/out/web/assets/SettingsWindow-DhWLAn9T.css +1 -0
  105. package/out/web/assets/SettingsWindow-Dw8L01pw.js +2 -0
  106. package/out/web/assets/SkillsView-cnl8aY5p.js +2 -0
  107. package/out/web/assets/ToolSurfacePage-CgsQw6l5.css +1 -0
  108. package/out/web/assets/ToolSurfacePage-Cz2VJAPZ.js +37 -0
  109. package/out/web/assets/VeoStudioPanel-D4JnERWR.js +4 -0
  110. package/out/web/assets/VeoStudioPanel-DOj7_WR3.css +1 -0
  111. package/out/web/assets/WorkspacePanel-CbJ1PFoZ.js +1 -0
  112. package/out/web/assets/{abnfDiagram-VCTEODGH-DAOBA7ZG.js → abnfDiagram-VCTEODGH-ByMyfanq.js} +1 -1
  113. package/out/web/assets/{architecture-7GRP2DOG-CgSwQOPQ.js → architecture-7GRP2DOG-CLq2kEOB.js} +1 -1
  114. package/out/web/assets/{architectureDiagram-5GKGNRK7-CYp3yupP.js → architectureDiagram-5GKGNRK7-6PoVSmNG.js} +1 -1
  115. package/out/web/assets/{blockDiagram-NRAW4CY4-CyWybDWr.js → blockDiagram-NRAW4CY4-cKw9mAKi.js} +1 -1
  116. package/out/web/assets/{c4Diagram-UCG6FXSJ-BvY3U709.js → c4Diagram-UCG6FXSJ-Cqy8N5Ge.js} +1 -1
  117. package/out/web/assets/{chunk-75Z2AOVW-TLXCoZYv.js → chunk-75Z2AOVW-3qybijF5.js} +1 -1
  118. package/out/web/assets/chunk-CKBBP62Z-cIrXq6jN.js +2 -0
  119. package/out/web/assets/{chunk-CLGD4ZFX-xjsKtNS7.js → chunk-CLGD4ZFX-CndDQkww.js} +1 -1
  120. package/out/web/assets/chunk-DSNCTWBM-Cc4NxvgD.js +2 -0
  121. package/out/web/assets/chunk-DU6HZSFF-drzh6GsU.js +128 -0
  122. package/out/web/assets/{chunk-F27PBJKO-BFpgF55A.js → chunk-F27PBJKO-FiY35l4v.js} +1 -1
  123. package/out/web/assets/{chunk-G27WJ6UU-DfF7qW-C.js → chunk-G27WJ6UU-Bjt9Il4A.js} +1 -1
  124. package/out/web/assets/{chunk-GMAD6QVW-C-558kh_.js → chunk-GMAD6QVW-Bppi3Ctd.js} +1 -1
  125. package/out/web/assets/{chunk-JQ64N6SF-wJmeGKAw.js → chunk-JQ64N6SF-DGg5kcEV.js} +1 -1
  126. package/out/web/assets/{chunk-LCL6LL3I-C1wHD8Ie.js → chunk-LCL6LL3I-CCYcjd7p.js} +1 -1
  127. package/out/web/assets/{chunk-OBVCFTLP-BsRTPBqs.js → chunk-OBVCFTLP-DJeNil5M.js} +1 -1
  128. package/out/web/assets/{chunk-P2QGCYS3-HZIiM7Ni.js → chunk-P2QGCYS3-lRzkRjBB.js} +1 -1
  129. package/out/web/assets/{chunk-POPQ4Y6H-Dk9wvVb0.js → chunk-POPQ4Y6H-DouASMBW.js} +1 -1
  130. package/out/web/assets/{chunk-PWAF6VOD-BmjYLNbq.js → chunk-PWAF6VOD-DMmD1vVf.js} +1 -1
  131. package/out/web/assets/{chunk-R7TYR2AO-CaHIf-lK.js → chunk-R7TYR2AO-CYLA5UC5.js} +1 -1
  132. package/out/web/assets/{chunk-RHFEMEQ7-_T561hOU.js → chunk-RHFEMEQ7-BiXwEcUT.js} +1 -1
  133. package/out/web/assets/{chunk-SVP7TREG-CM-GGYoY.js → chunk-SVP7TREG-BV-zPslF.js} +1 -1
  134. package/out/web/assets/{chunk-TEH6E4GO-K2A8Vg2C.js → chunk-TEH6E4GO-B2RGEohZ.js} +1 -1
  135. package/out/web/assets/classDiagram-DTDB5LWJ-Dq0smRWk.js +1 -0
  136. package/out/web/assets/classDiagram-v2-JRS7N3AN-Dq0smRWk.js +1 -0
  137. package/out/web/assets/config-C-ZFtipU.css +1 -0
  138. package/out/web/assets/config-eEDngJXO.js +1 -0
  139. package/out/web/assets/core-hQ2VA9Ti.js +1 -0
  140. package/out/web/assets/{cynefin-OW5HDTMX-ClzaB6cc.js → cynefin-OW5HDTMX-Cas4csHM.js} +1 -1
  141. package/out/web/assets/{cynefinDiagram-5FMLGOSQ-D_JzZBzf.js → cynefinDiagram-5FMLGOSQ-Bbpj66Y3.js} +1 -1
  142. package/out/web/assets/{dagre-3AP2YEHR-BDuUeMHj.js → dagre-3AP2YEHR-B0-2RDEd.js} +1 -1
  143. package/out/web/assets/{diagram-S7CK7UJ4-DgtcfE8P.js → diagram-S7CK7UJ4-BdzEjUyH.js} +1 -1
  144. package/out/web/assets/{diagram-UQ7AKVKN-DTLoEYti.js → diagram-UQ7AKVKN-CJDwyPxF.js} +1 -1
  145. package/out/web/assets/{diagram-VSXAHHWV-ChGl9pXz.js → diagram-VSXAHHWV-BxaG1r_B.js} +1 -1
  146. package/out/web/assets/{diagram-VX7I27RA-Be8DWz0S.js → diagram-VX7I27RA-BMmUqm8f.js} +1 -1
  147. package/out/web/assets/{diagram-Z3DM3KII-BMXjRTOF.js → diagram-Z3DM3KII-CFtd03eE.js} +1 -1
  148. package/out/web/assets/dist-js-Bf2bhoku.js +1 -0
  149. package/out/web/assets/{ebnfDiagram-PWID7BFC-8Q9pl1CJ.js → ebnfDiagram-PWID7BFC-DwAen1hO.js} +1 -1
  150. package/out/web/assets/{erDiagram-SSCWMZ5O-DjH8Lnkn.js → erDiagram-SSCWMZ5O-BCZSHACj.js} +1 -1
  151. package/out/web/assets/event-ChBVpRy0.js +1 -0
  152. package/out/web/assets/{eventmodeling-NTZA5JFV-BKUH_DOp.js → eventmodeling-NTZA5JFV-XHStE4E_.js} +1 -1
  153. package/out/web/assets/fira-code-latin-600-normal-BmSSHshu.woff +0 -0
  154. package/out/web/assets/fira-code-latin-600-normal-CvYZpPHg.woff2 +0 -0
  155. package/out/web/assets/fira-code-symbols2-600-normal-Dvq6IQE5.woff +0 -0
  156. package/out/web/assets/flowDiagram-A5DVABFB-BLg7nEcd.js +1 -0
  157. package/out/web/assets/{ganttDiagram-EL5Y4UJY-D7fZKJNM.js → ganttDiagram-EL5Y4UJY-BAEu1Cql.js} +1 -1
  158. package/out/web/assets/{gitGraph-4MIJSDKK-BypWaaBU.js → gitGraph-4MIJSDKK-r32Vyper.js} +1 -1
  159. package/out/web/assets/{gitGraphDiagram-WWUBYQGX-DWiw_3bq.js → gitGraphDiagram-WWUBYQGX-z9o9qt6V.js} +1 -1
  160. package/out/web/assets/index-Btsf4L8M.css +1 -0
  161. package/out/web/assets/index-D8D9MeRA.js +11 -0
  162. package/out/web/assets/{info-A6RAGUB7-KkAUxT4j.js → info-A6RAGUB7-BvLaC2cw.js} +1 -1
  163. package/out/web/assets/{infoDiagram-RXCK75RN-BNb6E48y.js → infoDiagram-RXCK75RN-Be6WAXXw.js} +1 -1
  164. package/out/web/assets/{ishikawaDiagram-5VMMS53U-Caa-JoAK.js → ishikawaDiagram-5VMMS53U-DZjoHJHC.js} +1 -1
  165. package/out/web/assets/{journeyDiagram-EYS64GPL-DOrmFGz6.js → journeyDiagram-EYS64GPL-CtVkjkGm.js} +1 -1
  166. package/out/web/assets/{kanban-definition-3QL26DDD-BOWCYcK0.js → kanban-definition-3QL26DDD-CW5FMv1w.js} +1 -1
  167. package/out/web/assets/lucide-react-Ip3L6Jtn.js +1 -0
  168. package/out/web/assets/markdown-BSeeUbJH.js +38 -0
  169. package/out/web/assets/{mermaid-parser.core-BQqjCkS_.js → mermaid-parser.core-aUgCqsZ5.js} +3 -3
  170. package/out/web/assets/mermaid.core-D57sEiSL.js +11 -0
  171. package/out/web/assets/{mindmap-definition-FBJOCRG2-jTceWpr0.js → mindmap-definition-FBJOCRG2-DAmSpM3a.js} +1 -1
  172. package/out/web/assets/modelManager-tMVmJVAW.js +2 -0
  173. package/out/web/assets/oauthManager-9jxicDWJ.js +1 -0
  174. package/out/web/assets/{packet-AYTQ26CC-CJ5RXgol.js → packet-AYTQ26CC-DJ27iIoJ.js} +1 -1
  175. package/out/web/assets/{pegDiagram-XKGWAZYB-y8wMtd0y.js → pegDiagram-XKGWAZYB-Bj3ii-gS.js} +1 -1
  176. package/out/web/assets/{pie-WAS4IAKB-72fTBbl4.js → pie-WAS4IAKB-DG5mCUbc.js} +1 -1
  177. package/out/web/assets/{pieDiagram-E7YTZNPT-e0O02qWq.js → pieDiagram-E7YTZNPT-BrJLPnDA.js} +1 -1
  178. package/out/web/assets/prompt-latin-700-normal-BfbftDSq.woff +0 -0
  179. package/out/web/assets/prompt-latin-700-normal-I2gc831J.woff2 +0 -0
  180. package/out/web/assets/prompt-thai-700-normal-Cb5ilR-c.woff +0 -0
  181. package/out/web/assets/prompt-thai-700-normal-Cg4aQ0Nn.woff2 +0 -0
  182. package/out/web/assets/{quadrantDiagram-AXDQQJYC-C9phYLom.js → quadrantDiagram-AXDQQJYC-3x_TmF3j.js} +1 -1
  183. package/out/web/assets/{radar-RG4KPBEZ-BAU2hzUT.js → radar-RG4KPBEZ-CrXaTTuV.js} +1 -1
  184. package/out/web/assets/{railroad-74A4TZTK-B0bCAVHC.js → railroad-74A4TZTK-BpqMH9BE.js} +1 -1
  185. package/out/web/assets/{railroad-abnf-HS5TGJTU-WhxO7ndE.js → railroad-abnf-HS5TGJTU-DHI0uLlV.js} +1 -1
  186. package/out/web/assets/{railroad-ebnf-LZEXJU2U-BkA0m7-F.js → railroad-ebnf-LZEXJU2U-CQCb316y.js} +1 -1
  187. package/out/web/assets/{railroad-peg-WCYAUIDC-BsVpHIaj.js → railroad-peg-WCYAUIDC-Ph1giKkH.js} +1 -1
  188. package/out/web/assets/{railroadDiagram-O6MQD6OU-CyOLN65Q.js → railroadDiagram-O6MQD6OU-BRq6wIxx.js} +1 -1
  189. package/out/web/assets/{requirementDiagram-EFPCY7ZU-DQXJ7Dud.js → requirementDiagram-EFPCY7ZU-DIJj6G1g.js} +1 -1
  190. package/out/web/assets/{sankeyDiagram-P5KCCOFB-B2XLyIIc.js → sankeyDiagram-P5KCCOFB-DZajSryq.js} +1 -1
  191. package/out/web/assets/{sequenceDiagram-WJ2MYXX4-DGQY4wwm.js → sequenceDiagram-WJ2MYXX4-DxJCWyZS.js} +1 -1
  192. package/out/web/assets/{stateDiagram-HBIQ2CUA-DHZpDwNy.js → stateDiagram-HBIQ2CUA-k6voi8Vf.js} +1 -1
  193. package/out/web/assets/stateDiagram-v2-4QOOHH4V-DeEc0lGZ.js +1 -0
  194. package/out/web/assets/studio-B1mk40wD.js +1 -0
  195. package/out/web/assets/{swimlanes-XN3QIQJK-Bn_jcZz-.js → swimlanes-XN3QIQJK-igYhTjXB.js} +1 -1
  196. package/out/web/assets/swimlanesDiagram-VK2B7HYN-DpVik9v7.js +8 -0
  197. package/out/web/assets/{timeline-definition-24CTP7MA-CdTERuJZ.js → timeline-definition-24CTP7MA-Dke2p93p.js} +1 -1
  198. package/out/web/assets/{treeView-Q6P3EWNA-TKBKQG6R.js → treeView-Q6P3EWNA-hNELnXUs.js} +1 -1
  199. package/out/web/assets/{treemap-WGGIJYW6-BP7gQoiC.js → treemap-WGGIJYW6-D2B6wDsx.js} +1 -1
  200. package/out/web/assets/{vennDiagram-4TSXK5OY-BHUmxDuK.js → vennDiagram-4TSXK5OY-CDkW7rUP.js} +1 -1
  201. package/out/web/assets/{wardley-WFR3VGLG-9bct5AAN.js → wardley-WFR3VGLG-BECdXETi.js} +1 -1
  202. package/out/web/assets/{wardleyDiagram-VM6X3IG4-BfJwDDso.js → wardleyDiagram-VM6X3IG4-B5BycpQ4.js} +1 -1
  203. package/out/web/assets/window-5qYXKoW7.js +1 -0
  204. package/out/web/assets/{xychartDiagram-S5SC5T6Z-Dqd9Mvpo.js → xychartDiagram-S5SC5T6Z-CtJS3b--.js} +1 -1
  205. package/out/web/index-web.html +3 -4
  206. package/out/web/index.html +3 -4
  207. package/package.json +17 -6
  208. package/skills-lock.json +36 -0
  209. package/slash-commands.json +9 -0
  210. package/src/renderer/index-web.html +1 -0
  211. package/src/renderer/index.html +1 -0
  212. package/src/renderer/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  213. package/src/renderer/shared/agentProgress.ts +168 -3
  214. package/src/renderer/shared/components/AgentActivityDrawer.tsx +6 -6
  215. package/src/renderer/shared/components/AgentActivityTable.tsx +192 -132
  216. package/src/renderer/shared/components/ArtifactPreviewPanel.tsx +4 -4
  217. package/src/renderer/shared/components/AuthGate.tsx +4 -9
  218. package/src/renderer/shared/components/CalculationCard.tsx +41 -15
  219. package/src/renderer/shared/components/ChatMessageItem.tsx +20 -21
  220. package/src/renderer/shared/components/ChatPanel.tsx +432 -193
  221. package/src/renderer/shared/components/ChunkErrorBoundary.tsx +198 -49
  222. package/src/renderer/shared/components/CliSessionsView.tsx +495 -0
  223. package/src/renderer/shared/components/CodeReviewPage.tsx +565 -0
  224. package/src/renderer/shared/components/CommandPalette.tsx +8 -8
  225. package/src/renderer/shared/components/DashboardSidebar.tsx +862 -125
  226. package/src/renderer/shared/components/DesktopTitlebar.tsx +345 -0
  227. package/src/renderer/shared/components/DiffReviewModal.tsx +3 -3
  228. package/src/renderer/shared/components/GitBranchSelector.tsx +442 -0
  229. package/src/renderer/shared/components/ImageGenCard.tsx +31 -12
  230. package/src/renderer/shared/components/ImageSearchCard.tsx +59 -38
  231. package/src/renderer/shared/components/ImageStudioPanel.tsx +40 -41
  232. package/src/renderer/shared/components/InlineThoughtNote.tsx +27 -0
  233. package/src/renderer/shared/components/LinkedFoldersView.tsx +365 -46
  234. package/src/renderer/shared/components/McpRegistryPicker.tsx +1 -1
  235. package/src/renderer/shared/components/McpServersView.tsx +24 -22
  236. package/src/renderer/shared/components/MermaidCard.tsx +14 -8
  237. package/src/renderer/shared/components/MintDashboard.tsx +1141 -508
  238. package/src/renderer/shared/components/ModelSelectorPopover.tsx +535 -214
  239. package/src/renderer/shared/components/PlanChecklistWidget.tsx +1 -1
  240. package/src/renderer/shared/components/PluginsView.tsx +1 -1
  241. package/src/renderer/shared/components/RewindModal.tsx +6 -6
  242. package/src/renderer/shared/components/RunSummaryDashboard.tsx +3 -3
  243. package/src/renderer/shared/components/ScheduledTasksView.tsx +4 -4
  244. package/src/renderer/shared/components/ScreenCaptureDialog.css +221 -0
  245. package/src/renderer/shared/components/ScreenCaptureDialog.tsx +199 -0
  246. package/src/renderer/shared/components/Settings/AgentsTab.tsx +34 -39
  247. package/src/renderer/shared/components/Settings/AudioTab.tsx +8 -8
  248. package/src/renderer/shared/components/Settings/AutomationTab.tsx +8 -58
  249. package/src/renderer/shared/components/Settings/AvatarCropModal.tsx +368 -0
  250. package/src/renderer/shared/components/Settings/GeneralTab.tsx +335 -81
  251. package/src/renderer/shared/components/Settings/MemoryTab.tsx +3 -3
  252. package/src/renderer/shared/components/Settings/PluginsTab.tsx +20 -12
  253. package/src/renderer/shared/components/Settings/ProfileTab.tsx +29 -5
  254. package/src/renderer/shared/components/Settings/SearchableModelCombobox.tsx +411 -0
  255. package/src/renderer/shared/components/Settings/ThemeTab.tsx +401 -158
  256. package/src/renderer/shared/components/SkillsView.tsx +41 -16
  257. package/src/renderer/shared/components/SlashSuggestions.tsx +3 -2
  258. package/src/renderer/shared/components/SourcesBlock.tsx +44 -32
  259. package/src/renderer/shared/components/StockCard.tsx +58 -24
  260. package/src/renderer/shared/components/SubagentDagView.tsx +4 -4
  261. package/src/renderer/shared/components/TerminalDock.tsx +241 -0
  262. package/src/renderer/shared/components/ThinkingBlock.tsx +14 -8
  263. package/src/renderer/shared/components/ToolSurfacePage.tsx +520 -0
  264. package/src/renderer/shared/components/UiFeatureCard.tsx +267 -0
  265. package/src/renderer/shared/components/UiGridCard.tsx +188 -0
  266. package/src/renderer/shared/components/UiMockupWidget.tsx +149 -0
  267. package/src/renderer/shared/components/VeoStudioPanel.tsx +13 -29
  268. package/src/renderer/shared/components/WeatherCard.tsx +3 -3
  269. package/src/renderer/shared/components/WorkspaceContextPopover.tsx +133 -0
  270. package/src/renderer/shared/components/WorkspaceSelector.tsx +149 -0
  271. package/src/renderer/shared/constants/config.ts +28 -3
  272. package/src/renderer/shared/constants/models.ts +189 -2
  273. package/src/renderer/shared/conversation/coordinator.test.ts +27 -0
  274. package/src/renderer/shared/conversation/coordinator.ts +82 -0
  275. package/src/renderer/shared/conversation/syncView.test.ts +46 -0
  276. package/src/renderer/shared/conversation/syncView.ts +43 -0
  277. package/src/renderer/shared/conversation/useConversationCoordinator.ts +106 -0
  278. package/src/renderer/shared/css/agent-observability.css +35 -3
  279. package/src/renderer/shared/css/auth-gate.css +2 -2
  280. package/src/renderer/shared/css/chat-ui-cards.css +495 -0
  281. package/src/renderer/shared/css/code-review.css +823 -0
  282. package/src/renderer/shared/css/code-sessions.css +452 -0
  283. package/src/renderer/shared/css/file-changes.css +132 -0
  284. package/src/renderer/shared/css/image-studio.css +16 -16
  285. package/src/renderer/shared/css/management-views.css +277 -27
  286. package/src/renderer/shared/css/model-selector.css +442 -42
  287. package/src/renderer/shared/css/settings/agents.css +1 -1
  288. package/src/renderer/shared/css/settings/automation.css +13 -13
  289. package/src/renderer/shared/css/settings/general.css +526 -5
  290. package/src/renderer/shared/css/settings/plugins.css +5 -5
  291. package/src/renderer/shared/css/settings/profile.css +331 -1
  292. package/src/renderer/shared/css/settings/theme.css +651 -3
  293. package/src/renderer/shared/css/veo-studio.css +16 -15
  294. package/src/renderer/shared/fonts.ts +19 -37
  295. package/src/renderer/shared/platform.test.ts +34 -0
  296. package/src/renderer/shared/platform.ts +173 -6
  297. package/src/renderer/shared/theme/themeManager.ts +144 -0
  298. package/src/renderer/shared/theme/themes.ts +116 -0
  299. package/src/renderer/shared/theme/tokens.css +318 -0
  300. package/src/renderer/shared/types.ts +82 -1
  301. package/src/renderer/shared/utils/agentActivity.ts +126 -5
  302. package/src/renderer/shared/utils/cardJson.test.ts +35 -0
  303. package/src/renderer/shared/utils/cardJson.ts +30 -0
  304. package/src/renderer/shared/utils/fileIcons.ts +1 -1
  305. package/src/renderer/shared/utils/markdown.tsx +329 -80
  306. package/src/renderer/shared/utils/markdown.webImages.test.tsx +40 -0
  307. package/src/renderer/shared/utils/providers.ts +8 -3
  308. package/src/renderer/shared/utils/screenCapture.ts +43 -0
  309. package/src/renderer/shared/utils/slashCommandProcessor.ts +4 -1
  310. package/src/renderer/shared/utils/ui.ts +4 -64
  311. package/src/renderer/src/App.tsx +7 -0
  312. package/src/renderer/src/components/BrowserShell.tsx +108 -0
  313. package/src/renderer/src/components/BrowserSuggestionsPopup.tsx +91 -0
  314. package/src/renderer/src/components/Live2DStage.tsx +32 -9
  315. package/src/renderer/src/components/MintDashboard.tsx +4 -2
  316. package/src/renderer/src/components/ModelPanel.tsx +2 -1
  317. package/src/renderer/src/components/PicturesLibrary.tsx +3 -2
  318. package/src/renderer/src/components/ScreenPicker.css +190 -0
  319. package/src/renderer/src/components/ScreenPicker.tsx +185 -540
  320. package/src/renderer/src/components/SettingsWindow.tsx +40 -2
  321. package/src/renderer/src/components/SpotlightWindow.tsx +1 -0
  322. package/src/renderer/src/components/WidgetWindow.tsx +27 -3
  323. package/src/renderer/src/components/WorkspacePanel.tsx +61 -43
  324. package/src/renderer/src/components/browser-shell.css +185 -0
  325. package/src/renderer/src/components/browser-suggestions-popup.css +55 -0
  326. package/src/renderer/src/components/liveTranslateFrames.test.ts +23 -0
  327. package/src/renderer/src/components/liveTranslateFrames.ts +34 -0
  328. package/src/renderer/src/css/app-shell.css +394 -113
  329. package/src/renderer/src/css/chat.css +1926 -380
  330. package/src/renderer/src/css/dashboard.css +11 -0
  331. package/src/renderer/src/css/desktop-tools.css +730 -0
  332. package/src/renderer/src/css/misc.css +19 -22
  333. package/src/renderer/src/css/model.css +49 -48
  334. package/src/renderer/src/css/pictures.css +144 -136
  335. package/src/renderer/src/css/settings/base.css +357 -123
  336. package/src/renderer/src/css/sidebar-workspace.css +930 -291
  337. package/src/renderer/src/css/spotlight.css +15 -26
  338. package/src/renderer/src/css/tool-surfaces.css +728 -0
  339. package/src/renderer/src/css/widget.css +35 -7
  340. package/src/renderer/src/env.d.ts +3 -0
  341. package/src/renderer/src/hooks/useProviderModels.ts +2 -9
  342. package/src/renderer/src/index.css +53 -46
  343. package/src/renderer/src/main.tsx +11 -0
  344. package/src/renderer/src/tauri.ts +201 -30
  345. package/src/renderer/src-web/App.tsx +40 -0
  346. package/src/renderer/src-web/components/MintDashboard.tsx +4 -2
  347. package/src/renderer/src-web/components/PicturesLibrary.tsx +3 -2
  348. package/src/renderer/src-web/components/PullToRefresh.tsx +107 -0
  349. package/src/renderer/src-web/components/SettingsWindow.tsx +28 -2
  350. package/src/renderer/src-web/css/app-shell.css +174 -96
  351. package/src/renderer/src-web/css/chat.css +1519 -316
  352. package/src/renderer/src-web/css/dashboard.css +11 -0
  353. package/src/renderer/src-web/css/misc.css +17 -17
  354. package/src/renderer/src-web/css/mobile.css +678 -0
  355. package/src/renderer/src-web/css/model.css +46 -46
  356. package/src/renderer/src-web/css/pictures.css +81 -34
  357. package/src/renderer/src-web/css/pull-to-refresh.css +54 -0
  358. package/src/renderer/src-web/css/settings/base.css +316 -100
  359. package/src/renderer/src-web/css/settings/mobile.css +320 -0
  360. package/src/renderer/src-web/css/sidebar-workspace.css +545 -100
  361. package/src/renderer/src-web/css/spotlight.css +9 -26
  362. package/src/renderer/src-web/css/widget.css +0 -5
  363. package/src/renderer/src-web/env.d.ts +3 -0
  364. package/src/renderer/src-web/hooks/useProviderModels.ts +2 -9
  365. package/src/renderer/src-web/index.css +53 -96
  366. package/src/renderer/src-web/main.tsx +11 -0
  367. package/src/renderer/src-web/tauri.ts +200 -30
  368. package/vite.config.web.ts +1 -0
  369. package/out/web/assets/MintDashboard-DWSqucgb.js +0 -57
  370. package/out/web/assets/SettingsWindow-DFM2aj5B.js +0 -2
  371. package/out/web/assets/chunk-CKBBP62Z-nr1uKPj9.js +0 -2
  372. package/out/web/assets/chunk-DSNCTWBM-Dtj8Rqsd.js +0 -2
  373. package/out/web/assets/chunk-DU6HZSFF-2tv5K1wT.js +0 -128
  374. package/out/web/assets/classDiagram-DTDB5LWJ-BdSFArgw.js +0 -1
  375. package/out/web/assets/classDiagram-v2-JRS7N3AN-BdSFArgw.js +0 -1
  376. package/out/web/assets/core-DImejIUG.js +0 -1
  377. package/out/web/assets/dist-js-BxuKEVWM.js +0 -1
  378. package/out/web/assets/event-BNl8Zahw.js +0 -1
  379. package/out/web/assets/fira-code-cyrillic-400-normal-UC0NFL4U.woff2 +0 -0
  380. package/out/web/assets/fira-code-cyrillic-400-normal-dc1q3VD7.woff +0 -0
  381. package/out/web/assets/fira-code-cyrillic-500-normal-Bu7VCL72.woff +0 -0
  382. package/out/web/assets/fira-code-cyrillic-500-normal-CX35h3Mg.woff2 +0 -0
  383. package/out/web/assets/fira-code-cyrillic-ext-400-normal-Buh61xzB.woff +0 -0
  384. package/out/web/assets/fira-code-cyrillic-ext-400-normal-txZ9Fk_1.woff2 +0 -0
  385. package/out/web/assets/fira-code-cyrillic-ext-500-normal-CYRspHgm.woff2 +0 -0
  386. package/out/web/assets/fira-code-cyrillic-ext-500-normal-CwtLmSFD.woff +0 -0
  387. package/out/web/assets/fira-code-greek-400-normal-B2Gh_Y8s.woff2 +0 -0
  388. package/out/web/assets/fira-code-greek-400-normal-DobhaxvF.woff +0 -0
  389. package/out/web/assets/fira-code-greek-500-normal-CVO0IRNt.woff2 +0 -0
  390. package/out/web/assets/fira-code-greek-500-normal-DEXIWiey.woff +0 -0
  391. package/out/web/assets/fira-code-greek-ext-400-normal-DR7mBgIM.woff2 +0 -0
  392. package/out/web/assets/fira-code-greek-ext-400-normal-DSPUheWg.woff +0 -0
  393. package/out/web/assets/fira-code-greek-ext-500-normal-BO3iq16n.woff2 +0 -0
  394. package/out/web/assets/fira-code-greek-ext-500-normal-CMiNLXER.woff +0 -0
  395. package/out/web/assets/fira-code-latin-ext-400-normal-DG73JjOf.woff +0 -0
  396. package/out/web/assets/fira-code-latin-ext-400-normal-KSMg0QLl.woff2 +0 -0
  397. package/out/web/assets/fira-code-latin-ext-500-normal-CaANqXjI.woff +0 -0
  398. package/out/web/assets/fira-code-latin-ext-500-normal-Crd9e_oI.woff2 +0 -0
  399. package/out/web/assets/flowDiagram-A5DVABFB-BpnHUSU7.js +0 -1
  400. package/out/web/assets/index-CVRg270z.css +0 -1
  401. package/out/web/assets/index-DxZQr9yD.js +0 -10
  402. package/out/web/assets/inter-cyrillic-400-normal-HOLc17fK.woff +0 -0
  403. package/out/web/assets/inter-cyrillic-400-normal-obahsSVq.woff2 +0 -0
  404. package/out/web/assets/inter-cyrillic-500-normal-BasfLYem.woff2 +0 -0
  405. package/out/web/assets/inter-cyrillic-500-normal-CxZf_p3X.woff +0 -0
  406. package/out/web/assets/inter-cyrillic-600-normal-4D_pXhcN.woff +0 -0
  407. package/out/web/assets/inter-cyrillic-600-normal-CWCymEST.woff2 +0 -0
  408. package/out/web/assets/inter-cyrillic-ext-400-normal-BQZuk6qB.woff2 +0 -0
  409. package/out/web/assets/inter-cyrillic-ext-400-normal-DQukG94-.woff +0 -0
  410. package/out/web/assets/inter-cyrillic-ext-500-normal-B0yAr1jD.woff2 +0 -0
  411. package/out/web/assets/inter-cyrillic-ext-500-normal-BmqWE9Dz.woff +0 -0
  412. package/out/web/assets/inter-cyrillic-ext-600-normal-Bcila6Z-.woff +0 -0
  413. package/out/web/assets/inter-cyrillic-ext-600-normal-Dfes3d0z.woff2 +0 -0
  414. package/out/web/assets/inter-greek-400-normal-B4URO6DV.woff2 +0 -0
  415. package/out/web/assets/inter-greek-400-normal-q2sYcFCs.woff +0 -0
  416. package/out/web/assets/inter-greek-500-normal-BIZE56-Y.woff2 +0 -0
  417. package/out/web/assets/inter-greek-500-normal-Xzm54t5V.woff +0 -0
  418. package/out/web/assets/inter-greek-600-normal-BZpKdvQh.woff +0 -0
  419. package/out/web/assets/inter-greek-600-normal-plRanbMR.woff2 +0 -0
  420. package/out/web/assets/inter-greek-ext-400-normal-DGGRlc-M.woff2 +0 -0
  421. package/out/web/assets/inter-greek-ext-400-normal-KugGGMne.woff +0 -0
  422. package/out/web/assets/inter-greek-ext-500-normal-2j5mBUwD.woff +0 -0
  423. package/out/web/assets/inter-greek-ext-500-normal-C4iEst2y.woff2 +0 -0
  424. package/out/web/assets/inter-greek-ext-600-normal-B8X0CLgF.woff +0 -0
  425. package/out/web/assets/inter-greek-ext-600-normal-DRtmH8MT.woff2 +0 -0
  426. package/out/web/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
  427. package/out/web/assets/inter-latin-400-normal-CyCys3Eg.woff +0 -0
  428. package/out/web/assets/inter-latin-500-normal-BL9OpVg8.woff +0 -0
  429. package/out/web/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
  430. package/out/web/assets/inter-latin-600-normal-CiBQ2DWP.woff +0 -0
  431. package/out/web/assets/inter-latin-600-normal-LgqL8muc.woff2 +0 -0
  432. package/out/web/assets/inter-latin-ext-400-normal-77YHD8bZ.woff +0 -0
  433. package/out/web/assets/inter-latin-ext-400-normal-C1nco2VV.woff2 +0 -0
  434. package/out/web/assets/inter-latin-ext-500-normal-BxGbmqWO.woff +0 -0
  435. package/out/web/assets/inter-latin-ext-500-normal-CV4jyFjo.woff2 +0 -0
  436. package/out/web/assets/inter-latin-ext-600-normal-CIVaiw4L.woff +0 -0
  437. package/out/web/assets/inter-latin-ext-600-normal-D2bJ5OIk.woff2 +0 -0
  438. package/out/web/assets/inter-vietnamese-400-normal-Bbgyi5SW.woff +0 -0
  439. package/out/web/assets/inter-vietnamese-400-normal-DMkecbls.woff2 +0 -0
  440. package/out/web/assets/inter-vietnamese-500-normal-DOriooB6.woff2 +0 -0
  441. package/out/web/assets/inter-vietnamese-500-normal-mJboJaSs.woff +0 -0
  442. package/out/web/assets/inter-vietnamese-600-normal-BuLX-rYi.woff +0 -0
  443. package/out/web/assets/inter-vietnamese-600-normal-Cc8MFFhd.woff2 +0 -0
  444. package/out/web/assets/kanit-latin-400-normal-BUlsQXH3.woff2 +0 -0
  445. package/out/web/assets/kanit-latin-400-normal-HVZWrfev.woff +0 -0
  446. package/out/web/assets/kanit-latin-500-normal-CX_4XcKi.woff2 +0 -0
  447. package/out/web/assets/kanit-latin-500-normal-qBha86O4.woff +0 -0
  448. package/out/web/assets/kanit-latin-600-normal-0lS78yAd.woff2 +0 -0
  449. package/out/web/assets/kanit-latin-600-normal-DlacpeTg.woff +0 -0
  450. package/out/web/assets/kanit-latin-ext-400-normal-B2xPf58u.woff2 +0 -0
  451. package/out/web/assets/kanit-latin-ext-400-normal-CHvNKHHD.woff +0 -0
  452. package/out/web/assets/kanit-latin-ext-500-normal-BFdWrG22.woff +0 -0
  453. package/out/web/assets/kanit-latin-ext-500-normal-EHs3suD6.woff2 +0 -0
  454. package/out/web/assets/kanit-latin-ext-600-normal-BBDzoLaj.woff +0 -0
  455. package/out/web/assets/kanit-latin-ext-600-normal-DAX3wtuq.woff2 +0 -0
  456. package/out/web/assets/kanit-thai-400-normal-D2nliXKa.woff +0 -0
  457. package/out/web/assets/kanit-thai-400-normal-D80Pglro.woff2 +0 -0
  458. package/out/web/assets/kanit-thai-500-normal-BB8gri04.woff2 +0 -0
  459. package/out/web/assets/kanit-thai-500-normal-Iy_w0a80.woff +0 -0
  460. package/out/web/assets/kanit-thai-600-normal-Bj6oiaDc.woff2 +0 -0
  461. package/out/web/assets/kanit-thai-600-normal-wbTlPO7I.woff +0 -0
  462. package/out/web/assets/kanit-vietnamese-400-normal-DRI8YWyb.woff2 +0 -0
  463. package/out/web/assets/kanit-vietnamese-400-normal-dow6Bnto.woff +0 -0
  464. package/out/web/assets/kanit-vietnamese-500-normal-BzTrpCM3.woff2 +0 -0
  465. package/out/web/assets/kanit-vietnamese-500-normal-T1ndT7MF.woff +0 -0
  466. package/out/web/assets/kanit-vietnamese-600-normal-Bi7fw3I4.woff2 +0 -0
  467. package/out/web/assets/kanit-vietnamese-600-normal-DXCRAa_8.woff +0 -0
  468. package/out/web/assets/mali-latin-400-normal-ByPcZ8Gx.woff +0 -0
  469. package/out/web/assets/mali-latin-400-normal-Cuc6Ykl8.woff2 +0 -0
  470. package/out/web/assets/mali-latin-500-normal-B01M-LP6.woff2 +0 -0
  471. package/out/web/assets/mali-latin-500-normal-Thgqw_9f.woff +0 -0
  472. package/out/web/assets/mali-latin-600-normal-B9TiUNpT.woff2 +0 -0
  473. package/out/web/assets/mali-latin-600-normal-CycpQCwU.woff +0 -0
  474. package/out/web/assets/mali-latin-ext-400-normal-DUVdJQO4.woff +0 -0
  475. package/out/web/assets/mali-latin-ext-400-normal-iCG1ALuJ.woff2 +0 -0
  476. package/out/web/assets/mali-latin-ext-500-normal-BfJE4UMZ.woff2 +0 -0
  477. package/out/web/assets/mali-latin-ext-500-normal-FoLEyOKS.woff +0 -0
  478. package/out/web/assets/mali-latin-ext-600-normal-BTvIfiCp.woff2 +0 -0
  479. package/out/web/assets/mali-latin-ext-600-normal-DAQcLVmD.woff +0 -0
  480. package/out/web/assets/mali-thai-400-normal-BO7A3bLZ.woff2 +0 -0
  481. package/out/web/assets/mali-thai-400-normal-CX9VrjTn.woff +0 -0
  482. package/out/web/assets/mali-thai-500-normal-Cph2qha9.woff +0 -0
  483. package/out/web/assets/mali-thai-500-normal-D89rMT77.woff2 +0 -0
  484. package/out/web/assets/mali-thai-600-normal-DPgXT6rZ.woff +0 -0
  485. package/out/web/assets/mali-thai-600-normal-DlTx3OsB.woff2 +0 -0
  486. package/out/web/assets/mali-vietnamese-400-normal-DUKxzXaz.woff2 +0 -0
  487. package/out/web/assets/mali-vietnamese-400-normal-gFDLvsOK.woff +0 -0
  488. package/out/web/assets/mali-vietnamese-500-normal--OY07q2c.woff +0 -0
  489. package/out/web/assets/mali-vietnamese-500-normal-KDrNRwfW.woff2 +0 -0
  490. package/out/web/assets/mali-vietnamese-600-normal-CtTMUU7T.woff +0 -0
  491. package/out/web/assets/mali-vietnamese-600-normal-DFlJr66u.woff2 +0 -0
  492. package/out/web/assets/mermaid.core-DYGGlqOf.js +0 -11
  493. package/out/web/assets/mitr-latin-400-normal-Cb18vPmZ.woff +0 -0
  494. package/out/web/assets/mitr-latin-400-normal-CwbkLQ4a.woff2 +0 -0
  495. package/out/web/assets/mitr-latin-500-normal-B4JOhzAi.woff +0 -0
  496. package/out/web/assets/mitr-latin-500-normal-BmClOow2.woff2 +0 -0
  497. package/out/web/assets/mitr-latin-ext-400-normal-B3CPG7Yo.woff2 +0 -0
  498. package/out/web/assets/mitr-latin-ext-400-normal-DTx65hiC.woff +0 -0
  499. package/out/web/assets/mitr-latin-ext-500-normal-B_Diajz1.woff2 +0 -0
  500. package/out/web/assets/mitr-latin-ext-500-normal-DYOsVaVT.woff +0 -0
  501. package/out/web/assets/mitr-thai-400-normal-CS4Do6aM.woff +0 -0
  502. package/out/web/assets/mitr-thai-400-normal-CXWaAdVj.woff2 +0 -0
  503. package/out/web/assets/mitr-thai-500-normal-CVdBrEVH.woff2 +0 -0
  504. package/out/web/assets/mitr-thai-500-normal-CW_B5D-i.woff +0 -0
  505. package/out/web/assets/mitr-vietnamese-400-normal-CPMGWyoC.woff2 +0 -0
  506. package/out/web/assets/mitr-vietnamese-400-normal-Z6XhIpdY.woff +0 -0
  507. package/out/web/assets/mitr-vietnamese-500-normal-CDrv0585.woff2 +0 -0
  508. package/out/web/assets/mitr-vietnamese-500-normal-CMQWyq-Z.woff +0 -0
  509. package/out/web/assets/noto-sans-thai-latin-400-normal-BaWBrqFP.woff2 +0 -0
  510. package/out/web/assets/noto-sans-thai-latin-400-normal-Dh_FJjOB.woff +0 -0
  511. package/out/web/assets/noto-sans-thai-latin-500-normal-BC04jsmm.woff +0 -0
  512. package/out/web/assets/noto-sans-thai-latin-500-normal-fyBKClF1.woff2 +0 -0
  513. package/out/web/assets/noto-sans-thai-latin-600-normal-CemcjnVR.woff2 +0 -0
  514. package/out/web/assets/noto-sans-thai-latin-600-normal-Dbc-dNO6.woff +0 -0
  515. package/out/web/assets/noto-sans-thai-latin-ext-400-normal-B-1H0YkH.woff +0 -0
  516. package/out/web/assets/noto-sans-thai-latin-ext-400-normal-nBP59pVw.woff2 +0 -0
  517. package/out/web/assets/noto-sans-thai-latin-ext-500-normal-B-ZWb8SZ.woff2 +0 -0
  518. package/out/web/assets/noto-sans-thai-latin-ext-500-normal-CrEHO7C8.woff +0 -0
  519. package/out/web/assets/noto-sans-thai-latin-ext-600-normal-PkMZo0xa.woff +0 -0
  520. package/out/web/assets/noto-sans-thai-latin-ext-600-normal-maHHBsez.woff2 +0 -0
  521. package/out/web/assets/noto-sans-thai-thai-400-normal-BEOmKAI1.woff2 +0 -0
  522. package/out/web/assets/noto-sans-thai-thai-400-normal-Dxb_unuU.woff +0 -0
  523. package/out/web/assets/noto-sans-thai-thai-500-normal-BOGXO2tw.woff +0 -0
  524. package/out/web/assets/noto-sans-thai-thai-500-normal-CU_X86GQ.woff2 +0 -0
  525. package/out/web/assets/noto-sans-thai-thai-600-normal-CmgB8_JK.woff +0 -0
  526. package/out/web/assets/noto-sans-thai-thai-600-normal-Cs73sVjl.woff2 +0 -0
  527. package/out/web/assets/oauthManager-DNiwM8Rn.js +0 -2
  528. package/out/web/assets/oauthManager-DuamS1Av.css +0 -1
  529. package/out/web/assets/outfit-latin-300-normal-AWLfuCom.woff +0 -0
  530. package/out/web/assets/outfit-latin-300-normal-CRYTwY6m.woff2 +0 -0
  531. package/out/web/assets/outfit-latin-400-normal-BGsTXAXT.woff2 +0 -0
  532. package/out/web/assets/outfit-latin-400-normal-DMwTpYkH.woff +0 -0
  533. package/out/web/assets/outfit-latin-500-normal-ClnHRwRh.woff +0 -0
  534. package/out/web/assets/outfit-latin-500-normal-DKnIMDSk.woff2 +0 -0
  535. package/out/web/assets/outfit-latin-600-normal-B7SfZ07L.woff2 +0 -0
  536. package/out/web/assets/outfit-latin-600-normal-BEfTtDA7.woff +0 -0
  537. package/out/web/assets/outfit-latin-ext-300-normal-BYS6Dpvq.woff2 +0 -0
  538. package/out/web/assets/outfit-latin-ext-300-normal-CMIMshEd.woff +0 -0
  539. package/out/web/assets/outfit-latin-ext-400-normal-5tcqmc2S.woff2 +0 -0
  540. package/out/web/assets/outfit-latin-ext-400-normal-DHm7mdGe.woff +0 -0
  541. package/out/web/assets/outfit-latin-ext-500-normal-DrCvqoFD.woff +0 -0
  542. package/out/web/assets/outfit-latin-ext-500-normal-zeox_O30.woff2 +0 -0
  543. package/out/web/assets/outfit-latin-ext-600-normal-B85nYjL1.woff2 +0 -0
  544. package/out/web/assets/outfit-latin-ext-600-normal-CWJcPgd7.woff +0 -0
  545. package/out/web/assets/preload-helper-D0uHx7FM.js +0 -1
  546. package/out/web/assets/prompt-latin-ext-400-normal-1pHbN9uy.woff +0 -0
  547. package/out/web/assets/prompt-latin-ext-400-normal-DdSafGZ9.woff2 +0 -0
  548. package/out/web/assets/prompt-latin-ext-500-normal--EZ1um7s.woff2 +0 -0
  549. package/out/web/assets/prompt-latin-ext-500-normal-D-lI1EVT.woff +0 -0
  550. package/out/web/assets/prompt-latin-ext-600-normal-C8b50x67.woff +0 -0
  551. package/out/web/assets/prompt-latin-ext-600-normal-Cg9L7iJU.woff2 +0 -0
  552. package/out/web/assets/prompt-vietnamese-400-normal-BCPzsgPT.woff2 +0 -0
  553. package/out/web/assets/prompt-vietnamese-400-normal-D4pLyeNK.woff +0 -0
  554. package/out/web/assets/prompt-vietnamese-500-normal-DmzxmPwa.woff2 +0 -0
  555. package/out/web/assets/prompt-vietnamese-500-normal-w_sS_j2F.woff +0 -0
  556. package/out/web/assets/prompt-vietnamese-600-normal-1dyohtNh.woff +0 -0
  557. package/out/web/assets/prompt-vietnamese-600-normal-7QWjJBsF.woff2 +0 -0
  558. package/out/web/assets/sarabun-latin-400-normal-DmguIS-7.woff +0 -0
  559. package/out/web/assets/sarabun-latin-400-normal-URPBxl-K.woff2 +0 -0
  560. package/out/web/assets/sarabun-latin-500-normal-BjUTcdxu.woff2 +0 -0
  561. package/out/web/assets/sarabun-latin-500-normal-CJexTAnl.woff +0 -0
  562. package/out/web/assets/sarabun-latin-600-normal-9FonlkKx.woff +0 -0
  563. package/out/web/assets/sarabun-latin-600-normal-DMD3TROr.woff2 +0 -0
  564. package/out/web/assets/sarabun-latin-ext-400-normal-BbP7GpLL.woff2 +0 -0
  565. package/out/web/assets/sarabun-latin-ext-400-normal-BsmTn0SS.woff +0 -0
  566. package/out/web/assets/sarabun-latin-ext-500-normal-Cot16Bd2.woff +0 -0
  567. package/out/web/assets/sarabun-latin-ext-500-normal-DE1LysqI.woff2 +0 -0
  568. package/out/web/assets/sarabun-latin-ext-600-normal-0tXu9x_i.woff +0 -0
  569. package/out/web/assets/sarabun-latin-ext-600-normal-BRxjKUQ6.woff2 +0 -0
  570. package/out/web/assets/sarabun-thai-400-normal-C2DaJlKK.woff2 +0 -0
  571. package/out/web/assets/sarabun-thai-400-normal-CH-UbWgg.woff +0 -0
  572. package/out/web/assets/sarabun-thai-500-normal-BVssjame.woff2 +0 -0
  573. package/out/web/assets/sarabun-thai-500-normal-C3iDLEzi.woff +0 -0
  574. package/out/web/assets/sarabun-thai-600-normal-3dIAQ-_s.woff2 +0 -0
  575. package/out/web/assets/sarabun-thai-600-normal-DWKeTe6a.woff +0 -0
  576. package/out/web/assets/sarabun-vietnamese-400-normal-DPfkSCMy.woff +0 -0
  577. package/out/web/assets/sarabun-vietnamese-400-normal-igdrzAGY.woff2 +0 -0
  578. package/out/web/assets/sarabun-vietnamese-500-normal-CpRVvGRU.woff +0 -0
  579. package/out/web/assets/sarabun-vietnamese-500-normal-Dpe7Br9m.woff2 +0 -0
  580. package/out/web/assets/sarabun-vietnamese-600-normal-BMbOgAW-.woff +0 -0
  581. package/out/web/assets/sarabun-vietnamese-600-normal-DkxrOlLB.woff2 +0 -0
  582. package/out/web/assets/stateDiagram-v2-4QOOHH4V-s6P9g2_b.js +0 -1
  583. package/out/web/assets/swimlanesDiagram-VK2B7HYN-CV9fOLrV.js +0 -8
  584. package/out/web/assets/tauri-CNrHQ2Gb.js +0 -3
  585. package/out/web/assets/window-DkIhgI7B.js +0 -1
@@ -1,8 +1,16 @@
1
- import React, { useState, useEffect, useRef, useMemo } from 'react'
1
+ import React, { useState, useEffect, useRef, useMemo, useCallback } from 'react'
2
2
  import { useProviderModels } from '@/hooks/useProviderModels'
3
- import { fetchProviderModels } from '@/tauri'
4
- import { HF_MODELS } from '../constants/models'
3
+ import { catalogPlatform } from '../platform'
4
+ import { HF_MODELS, getModelMetadata, isFreeModel, OPENROUTER_POPULAR_MODELS } from '../constants/models'
5
5
  import type { CustomProviderConfig } from '../types'
6
+ import anthropicLogo from '@lobehub/icons-static-svg/icons/anthropic.svg?url'
7
+ import deepseekLogo from '@lobehub/icons-static-svg/icons/deepseek-color.svg?url'
8
+ import geminiLogo from '@lobehub/icons-static-svg/icons/gemini-color.svg?url'
9
+ import huggingFaceLogo from '@lobehub/icons-static-svg/icons/huggingface-color.svg?url'
10
+ import lmStudioLogo from '@lobehub/icons-static-svg/icons/lmstudio.svg?url'
11
+ import ollamaLogo from '@lobehub/icons-static-svg/icons/ollama.svg?url'
12
+ import openAiLogo from '@lobehub/icons-static-svg/icons/openai.svg?url'
13
+ import openRouterLogo from '@lobehub/icons-static-svg/icons/openrouter-color.svg?url'
6
14
 
7
15
  interface ModelSelectorPopoverProps {
8
16
  activeProvider: string
@@ -12,10 +20,12 @@ interface ModelSelectorPopoverProps {
12
20
  dynamicOllamaModels?: string[]
13
21
  onSelect: (provider: string, model: string) => void
14
22
  disabled?: boolean
23
+ onUpdateSettings?: (config: any) => void
15
24
  }
16
25
 
17
26
  interface ProviderGroup {
18
27
  id: string
28
+ providerId: string
19
29
  name: string
20
30
  icon: React.ReactNode
21
31
  models: string[]
@@ -27,92 +37,70 @@ interface FlattenedItem {
27
37
  model: string
28
38
  }
29
39
 
30
- // ─── SVG Icons for Providers (NO EMOJIS) ───────────────────────────────────────
40
+ const Effort_LEVELS = [
41
+ { id: 'low', label: 'Low' },
42
+ { id: 'medium', label: 'Medium' },
43
+ { id: 'high', label: 'High' },
44
+ { id: 'extra_high', label: 'Extra High' },
45
+ ] as const
46
+
47
+ function formatEffortDisplay(effort?: string): string {
48
+ if (!effort) return 'Medium'
49
+ const lower = effort.toLowerCase().replace(/[- ]/g, '_')
50
+ if (lower === 'low') return 'Low'
51
+ if (lower === 'high') return 'High'
52
+ if (lower === 'extra_high' || lower === 'extra') return 'Extra High'
53
+ return 'Medium'
54
+ }
55
+
56
+ // Brand marks are bundled locally so the selector never depends on a remote image host.
57
+ const providerLogos: Record<string, { src: string; color?: string }> = {
58
+ anthropic: { src: anthropicLogo, color: '#d97757' },
59
+ deepseek: { src: deepseekLogo },
60
+ gemini: { src: geminiLogo },
61
+ huggingface: { src: huggingFaceLogo },
62
+ local_openai: { src: lmStudioLogo, color: '#8b5cf6' },
63
+ ollama: { src: ollamaLogo, color: '#f3f4f6' },
64
+ openai: { src: openAiLogo, color: '#10a37f' },
65
+ openrouter: { src: openRouterLogo },
66
+ }
31
67
 
32
68
  function ProviderIcon({ provider }: { provider: string }) {
33
69
  const p = provider.toLowerCase()
34
- if (p === 'gemini') {
35
- return (
36
- <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
37
- <polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" />
38
- </svg>
39
- )
40
- }
41
- if (p === 'anthropic') {
42
- return (
43
- <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
44
- <path d="M4.5 16.5c-1.5 1.26-2.5 3.19-2.5 5.5h20c0-2.31-1-4.24-2.5-5.5" />
45
- <path d="M12 2L2 22h20L12 2z" />
46
- </svg>
47
- )
48
- }
49
- if (p === 'openai') {
50
- return (
51
- <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
52
- <circle cx="12" cy="12" r="10" />
53
- <line x1="12" y1="2" x2="12" y2="22" />
54
- <path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6" />
55
- </svg>
56
- )
57
- }
58
- if (p === 'deepseek') {
59
- return (
60
- <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
61
- <circle cx="11" cy="11" r="8" />
62
- <line x1="21" y1="21" x2="16.65" y2="16.65" />
63
- </svg>
64
- )
65
- }
66
- if (p === 'openrouter') {
67
- return (
68
- <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
69
- <polyline points="16 3 21 3 21 8" />
70
- <line x1="4" y1="20" x2="21" y2="3" />
71
- <polyline points="21 16 21 21 16 21" />
72
- <line x1="15" y1="15" x2="21" y2="21" />
73
- <line x1="4" y1="4" x2="9" y2="9" />
74
- </svg>
75
- )
76
- }
77
- if (p === 'huggingface') {
78
- return (
79
- <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
80
- <circle cx="12" cy="12" r="10" />
81
- <path d="M8 14s1.5 2 4 2 4-2 4-2" />
82
- <line x1="9" y1="9" x2="9.01" y2="9" />
83
- <line x1="15" y1="9" x2="15.01" y2="9" />
84
- </svg>
85
- )
86
- }
87
- if (p === 'local_openai') {
88
- return (
89
- <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
90
- <rect x="2" y="3" width="20" height="14" rx="2" ry="2" />
91
- <line x1="8" y1="21" x2="16" y2="21" />
92
- <line x1="12" y1="17" x2="12" y2="21" />
93
- </svg>
94
- )
95
- }
96
- if (p === 'ollama') {
97
- return (
98
- <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
99
- <path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" />
100
- </svg>
101
- )
70
+ const logo = providerLogos[p]
71
+ if (logo) {
72
+ if (logo.color) {
73
+ return (
74
+ <span
75
+ className="provider-brand-logo is-monochrome"
76
+ aria-hidden="true"
77
+ style={{
78
+ '--provider-brand-color': logo.color,
79
+ maskImage: `url("${logo.src}")`,
80
+ WebkitMaskImage: `url("${logo.src}")`,
81
+ } as React.CSSProperties}
82
+ />
83
+ )
84
+ }
85
+ return <img className="provider-brand-logo" src={logo.src} alt="" aria-hidden="true" />
102
86
  }
103
87
  return (
104
- <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
88
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
105
89
  <circle cx="12" cy="12" r="3" />
106
90
  <path d="M19.07 4.93a10 10 0 0 1 0 14.14M4.93 4.93a10 10 0 0 0 0 14.14" />
107
91
  </svg>
108
92
  )
109
93
  }
110
94
 
111
- // ─── SVG Capability Badges (NO EMOJIS) ─────────────────────────────────────────
112
-
113
- function ModelBadge({ type, label }: { type: 'fast' | 'reasoning' | 'top' | 'vision'; label: string }) {
95
+ function ModelBadge({ type, label }: { type: 'fast' | 'reasoning' | 'top' | 'vision' | 'free'; label: string }) {
114
96
  return (
115
97
  <span className={`model-tag-badge badge-${type}`}>
98
+ {type === 'free' && (
99
+ <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
100
+ <path d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z" />
101
+ <line x1="7" y1="7" x2="7.01" y2="7" />
102
+ </svg>
103
+ )}
116
104
  {type === 'fast' && (
117
105
  <svg width="10" height="10" viewBox="0 0 24 24" fill="currentColor">
118
106
  <polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2" />
@@ -148,10 +136,15 @@ function ModelBadge({ type, label }: { type: 'fast' | 'reasoning' | 'top' | 'vis
148
136
  )
149
137
  }
150
138
 
151
- function getModelBadges(modelId: string): Array<{ label: string; type: 'fast' | 'reasoning' | 'top' | 'vision' }> {
139
+ function getModelBadges(modelId: string): Array<{ label: string; type: 'fast' | 'reasoning' | 'top' | 'vision' | 'free' }> {
140
+ const badges: Array<{ label: string; type: 'fast' | 'reasoning' | 'top' | 'vision' | 'free' }> = []
141
+
142
+ if (isFreeModel(modelId)) {
143
+ badges.push({ label: 'FREE', type: 'free' })
144
+ }
145
+
152
146
  const lower = modelId.toLowerCase()
153
147
 
154
- // 1. Dedicated Reasoning models
155
148
  if (
156
149
  lower.includes('reason') ||
157
150
  lower.includes('thinking') ||
@@ -160,15 +153,11 @@ function getModelBadges(modelId: string): Array<{ label: string; type: 'fast' |
160
153
  lower.includes('o3') ||
161
154
  lower.includes('qwq')
162
155
  ) {
163
- return [{ label: 'Reasoning', type: 'reasoning' }]
156
+ badges.push({ label: 'Reasoning', type: 'reasoning' })
164
157
  }
165
-
166
- // 2. Vision / Multimodal models
167
158
  if (lower.includes('vision') || lower.includes('multimodal') || lower.includes('-vl')) {
168
- return [{ label: 'Vision', type: 'vision' }]
159
+ badges.push({ label: 'Vision', type: 'vision' })
169
160
  }
170
-
171
- // 3. Fast / Lightweight models
172
161
  if (
173
162
  lower.includes('flash') ||
174
163
  lower.includes('haiku') ||
@@ -176,10 +165,8 @@ function getModelBadges(modelId: string): Array<{ label: string; type: 'fast' |
176
165
  lower.includes('turbo') ||
177
166
  lower.includes('lite')
178
167
  ) {
179
- return [{ label: 'Fast', type: 'fast' }]
168
+ badges.push({ label: 'Fast', type: 'fast' })
180
169
  }
181
-
182
- // 4. Flagship / Top-tier models
183
170
  if (
184
171
  lower === 'claude-sonnet-5' ||
185
172
  lower === 'claude-opus-5' ||
@@ -189,10 +176,9 @@ function getModelBadges(modelId: string): Array<{ label: string; type: 'fast' |
189
176
  lower === 'deepseek-chat' ||
190
177
  lower === 'deepseek-v4-pro'
191
178
  ) {
192
- return [{ label: 'Top', type: 'top' }]
179
+ badges.push({ label: 'Top', type: 'top' })
193
180
  }
194
-
195
- return []
181
+ return badges
196
182
  }
197
183
 
198
184
  export default function ModelSelectorPopover({
@@ -203,16 +189,32 @@ export default function ModelSelectorPopover({
203
189
  dynamicOllamaModels,
204
190
  onSelect,
205
191
  disabled = false,
192
+ onUpdateSettings,
206
193
  }: ModelSelectorPopoverProps) {
207
194
  const [isOpen, setIsOpen] = useState(false)
195
+ const [mobilePane, setMobilePane] = useState<'models' | 'options'>('models')
208
196
  const [search, setSearch] = useState('')
209
197
  const [highlightedIndex, setHighlightedIndex] = useState(0)
198
+ const [expandOtherModels, setExpandOtherModels] = useState(false)
199
+
200
+ // Local state tracking model thinking overrides for responsive updates
201
+ const [modelThinkingOverrides, setModelThinkingOverrides] = useState<
202
+ Record<string, { enabled?: boolean; effort?: string }>
203
+ >({})
204
+
205
+ // Keep overrides in sync when settingsConfig arrives
206
+ useEffect(() => {
207
+ if (settingsConfig?.modelThinkingConfigs) {
208
+ setModelThinkingOverrides(settingsConfig.modelThinkingConfigs)
209
+ }
210
+ }, [settingsConfig?.modelThinkingConfigs])
211
+
210
212
  const popoverRef = useRef<HTMLDivElement>(null)
211
213
  const triggerRef = useRef<HTMLButtonElement>(null)
212
214
  const searchInputRef = useRef<HTMLInputElement>(null)
213
215
  const listRef = useRef<HTMLDivElement>(null)
214
216
 
215
- // ─── Live Dynamic Models from Hook ──────────────────────────────────────────
217
+ // Dynamic models from hook
216
218
  const { models: dynamicGemini } = useProviderModels('gemini', settingsConfig?.apiKey || '')
217
219
  const { models: dynamicClaude } = useProviderModels('anthropic', settingsConfig?.anthropicApiKey || '')
218
220
  const { models: dynamicOpenAI } = useProviderModels('openai', settingsConfig?.openaiApiKey || '')
@@ -220,7 +222,7 @@ export default function ModelSelectorPopover({
220
222
  const { models: dynamicDeepSeek } = useProviderModels('deepseek', settingsConfig?.deepseekApiKey || '')
221
223
  const { models: dynamicLocal } = useProviderModels('local_openai', '', settingsConfig?.localApiBaseUrl || '')
222
224
 
223
- // ─── Live Dynamic Ollama Models (Self-Fetch Fallback) ───────────────────────
225
+ // Ollama self-fetch fallback
224
226
  const [internalOllamaModels, setInternalOllamaModels] = useState<string[]>([])
225
227
 
226
228
  useEffect(() => {
@@ -247,7 +249,7 @@ export default function ModelSelectorPopover({
247
249
  } catch {}
248
250
 
249
251
  try {
250
- const live = await fetchProviderModels('ollama', '')
252
+ const live = await catalogPlatform.fetchProviderModels('ollama', '')
251
253
  if (!cancelled && live && live.length > 0) {
252
254
  setInternalOllamaModels(live)
253
255
  return
@@ -264,40 +266,59 @@ export default function ModelSelectorPopover({
264
266
  }
265
267
  }, [dynamicOllamaModels, settingsConfig?.ollamaHost, settingsConfig?.ollamaModel])
266
268
 
267
- // ─── Assemble Provider Groups ───────────────────────────────────────────────
269
+ // Assemble Provider Groups
268
270
  const providerGroups = useMemo<ProviderGroup[]>(() => {
269
271
  const list: ProviderGroup[] = []
270
272
 
271
- const addGroup = (id: string, name: string, models: string[]) => {
273
+ const addGroup = (id: string, providerId: string, name: string, models: string[], logoDataUrl?: string) => {
272
274
  if (models.length === 0) return
273
275
  list.push({
274
276
  id,
277
+ providerId,
275
278
  name,
276
- icon: <ProviderIcon provider={id} />,
279
+ icon: logoDataUrl
280
+ ? <img className="provider-brand-logo" src={logoDataUrl} alt="" aria-hidden="true" />
281
+ : <ProviderIcon provider={providerId} />,
277
282
  models,
278
283
  })
279
284
  }
280
285
 
281
286
  if (availableProviders.includes('gemini')) {
282
- addGroup('gemini', 'Google Gemini', dynamicGemini)
287
+ addGroup('gemini', 'gemini', 'Google Gemini', dynamicGemini)
283
288
  }
284
289
  if (availableProviders.includes('anthropic')) {
285
- addGroup('anthropic', 'Anthropic Claude', dynamicClaude)
290
+ addGroup('anthropic', 'anthropic', 'Anthropic Claude', dynamicClaude)
286
291
  }
287
292
  if (availableProviders.includes('openai')) {
288
- addGroup('openai', 'OpenAI', dynamicOpenAI)
293
+ addGroup('openai', 'openai', 'OpenAI', dynamicOpenAI)
289
294
  }
290
295
  if (availableProviders.includes('deepseek')) {
291
- addGroup('deepseek', 'DeepSeek', dynamicDeepSeek)
296
+ addGroup('deepseek', 'deepseek', 'DeepSeek', dynamicDeepSeek)
292
297
  }
293
298
  if (availableProviders.includes('openrouter')) {
294
- addGroup('openrouter', 'OpenRouter', dynamicOpenRouter)
299
+ const popularSet = new Set<string>(OPENROUTER_POPULAR_MODELS)
300
+ const popularModels: string[] = []
301
+ for (const pop of OPENROUTER_POPULAR_MODELS) {
302
+ if (dynamicOpenRouter.includes(pop)) {
303
+ popularModels.push(pop)
304
+ }
305
+ }
306
+ const otherModels = dynamicOpenRouter.filter((m) => !popularSet.has(m))
307
+
308
+ if (popularModels.length > 0) {
309
+ addGroup('openrouter-popular', 'openrouter', 'OpenRouter • Popular & Recommended', popularModels)
310
+ if (otherModels.length > 0) {
311
+ addGroup('openrouter-other', 'openrouter', `OpenRouter • Other models (${otherModels.length})`, otherModels)
312
+ }
313
+ } else {
314
+ addGroup('openrouter', 'openrouter', 'OpenRouter', dynamicOpenRouter)
315
+ }
295
316
  }
296
317
  if (availableProviders.includes('huggingface')) {
297
- addGroup('huggingface', 'Hugging Face', [...HF_MODELS])
318
+ addGroup('huggingface', 'huggingface', 'Hugging Face', [...HF_MODELS])
298
319
  }
299
320
  if (availableProviders.includes('local_openai')) {
300
- addGroup('local_openai', 'LM Studio / Local', dynamicLocal)
321
+ addGroup('local_openai', 'local_openai', 'LM Studio / Local', dynamicLocal)
301
322
  }
302
323
  if (availableProviders.includes('ollama')) {
303
324
  const ollamaList = (dynamicOllamaModels && dynamicOllamaModels.length > 0)
@@ -305,16 +326,15 @@ export default function ModelSelectorPopover({
305
326
  : (internalOllamaModels.length > 0
306
327
  ? internalOllamaModels
307
328
  : (settingsConfig?.ollamaModel ? [settingsConfig.ollamaModel] : []))
308
- addGroup('ollama', 'Ollama', ollamaList)
329
+ addGroup('ollama', 'ollama', 'Ollama', ollamaList)
309
330
  }
310
331
 
311
- // Custom providers
312
332
  const customProviders: CustomProviderConfig[] = settingsConfig?.customProviders || []
313
333
  for (const cp of customProviders) {
314
334
  const pid = `custom:${cp.id}`
315
335
  if (availableProviders.includes(pid)) {
316
336
  const cModels = (cp.models || []).map((m: any) => m.modelId).filter(Boolean)
317
- addGroup(pid, cp.displayName || cp.id, cModels)
337
+ addGroup(pid, pid, cp.displayName || cp.id, cModels, cp.logoDataUrl)
318
338
  }
319
339
  }
320
340
 
@@ -333,20 +353,20 @@ export default function ModelSelectorPopover({
333
353
  settingsConfig?.ollamaModel,
334
354
  ])
335
355
 
336
- // ─── Filter Groups by Search Query ─────────────────────────────────────────
356
+ // Filter Groups by Search Query
337
357
  const filteredGroups = useMemo(() => {
338
358
  const q = search.trim().toLowerCase()
339
359
  if (!q) return providerGroups
340
360
 
341
361
  const results: ProviderGroup[] = []
342
-
343
362
  for (const group of providerGroups) {
344
- const providerMatches = group.name.toLowerCase().includes(q) || group.id.toLowerCase().includes(q)
363
+ const providerMatches =
364
+ group.name.toLowerCase().includes(q) ||
365
+ group.id.toLowerCase().includes(q) ||
366
+ group.providerId.toLowerCase().includes(q)
345
367
  if (providerMatches) {
346
- // Show all models in this provider
347
368
  results.push(group)
348
369
  } else {
349
- // Filter models
350
370
  const matchedModels = group.models.filter((m) => m.toLowerCase().includes(q))
351
371
  if (matchedModels.length > 0) {
352
372
  results.push({
@@ -356,30 +376,104 @@ export default function ModelSelectorPopover({
356
376
  }
357
377
  }
358
378
  }
359
-
360
379
  return results
361
380
  }, [providerGroups, search])
362
381
 
363
- // ─── Flattened Items for Keyboard Navigation ────────────────────────────────
382
+ // Automatically expand other models when searching, or manual toggle
383
+ const isOtherExpanded = Boolean(search.trim()) || expandOtherModels
384
+
385
+ // Flattened Items for Keyboard Navigation
364
386
  const flattenedItems = useMemo<FlattenedItem[]>(() => {
365
387
  const items: FlattenedItem[] = []
366
388
  for (const g of filteredGroups) {
389
+ if (g.id === 'openrouter-other' && !isOtherExpanded) {
390
+ continue
391
+ }
367
392
  for (const m of g.models) {
368
393
  items.push({
369
- providerId: g.id,
394
+ providerId: g.providerId,
370
395
  providerName: g.name,
371
396
  model: m,
372
397
  })
373
398
  }
374
399
  }
375
400
  return items
376
- }, [filteredGroups])
401
+ }, [filteredGroups, isOtherExpanded])
402
+
403
+ // Model currently inspected in the right detail pane
404
+ const [inspectedItem, setInspectedItem] = useState<{ providerId: string; model: string } | null>(null)
377
405
 
378
- // Keep highlighted index in range
406
+ // Initialize or reset inspected item and collapsed state on open
407
+ useEffect(() => {
408
+ if (isOpen) {
409
+ if (activeModel) {
410
+ setInspectedItem({ providerId: activeProvider, model: activeModel })
411
+ } else if (flattenedItems.length > 0) {
412
+ setInspectedItem({ providerId: flattenedItems[0].providerId, model: flattenedItems[0].model })
413
+ }
414
+ } else {
415
+ setExpandOtherModels(false)
416
+ }
417
+ }, [isOpen, activeProvider, activeModel])
418
+
419
+ // Reset highlight on search
379
420
  useEffect(() => {
380
421
  setHighlightedIndex(0)
422
+ if (flattenedItems.length > 0) {
423
+ setInspectedItem({ providerId: flattenedItems[0].providerId, model: flattenedItems[0].model })
424
+ }
381
425
  }, [search])
382
426
 
427
+ // Helper to resolve a model's thinking status
428
+ const getThinkingConfig = useCallback((model: string, provider: string) => {
429
+ const meta = getModelMetadata(model, provider)
430
+ const override = modelThinkingOverrides[model]
431
+ if (override) {
432
+ return {
433
+ supported: meta.supportsThinking,
434
+ enabled: override.enabled ?? true,
435
+ effort: (override.effort || 'medium').toLowerCase(),
436
+ }
437
+ }
438
+ return {
439
+ supported: meta.supportsThinking,
440
+ enabled: meta.supportsThinking ? (settingsConfig?.thinkingEnabled ?? true) : false,
441
+ effort: (settingsConfig?.thinkingEffort || 'medium').toLowerCase(),
442
+ }
443
+ }, [modelThinkingOverrides, settingsConfig?.thinkingEnabled, settingsConfig?.thinkingEffort])
444
+
445
+ // Persist thinking change
446
+ const persistThinking = async (model: string, enabled: boolean, effort: string) => {
447
+ const updatedOverrides = {
448
+ ...modelThinkingOverrides,
449
+ [model]: { enabled, effort },
450
+ }
451
+ setModelThinkingOverrides(updatedOverrides)
452
+
453
+ const updatedConfig = {
454
+ ...(settingsConfig || {}),
455
+ modelThinkingConfigs: updatedOverrides,
456
+ }
457
+
458
+ if (model === activeModel) {
459
+ updatedConfig.thinkingEnabled = enabled
460
+ updatedConfig.thinkingEffort = effort
461
+ }
462
+
463
+ if (onUpdateSettings) {
464
+ onUpdateSettings(updatedConfig)
465
+ }
466
+
467
+ const api = (window as any).settingsApi
468
+ if (api?.saveSettings) {
469
+ try {
470
+ await api.saveSettings(updatedConfig)
471
+ } catch (err) {
472
+ console.error('Failed to save thinking config:', err)
473
+ }
474
+ }
475
+ }
476
+
383
477
  // Click Outside to Close
384
478
  useEffect(() => {
385
479
  if (!isOpen) return
@@ -404,8 +498,9 @@ export default function ModelSelectorPopover({
404
498
  useEffect(() => {
405
499
  if (isOpen) {
406
500
  setSearch('')
501
+ setMobilePane('models')
407
502
  setTimeout(() => {
408
- searchInputRef.current?.focus()
503
+ if (!window.matchMedia('(max-width: 760px)').matches) searchInputRef.current?.focus()
409
504
  }, 50)
410
505
  }
411
506
  }, [isOpen])
@@ -426,11 +521,15 @@ export default function ModelSelectorPopover({
426
521
  if (e.key === 'ArrowDown') {
427
522
  e.preventDefault()
428
523
  if (flattenedItems.length === 0) return
429
- setHighlightedIndex((prev) => (prev + 1) % flattenedItems.length)
524
+ const nextIdx = (highlightedIndex + 1) % flattenedItems.length
525
+ setHighlightedIndex(nextIdx)
526
+ setInspectedItem({ providerId: flattenedItems[nextIdx].providerId, model: flattenedItems[nextIdx].model })
430
527
  } else if (e.key === 'ArrowUp') {
431
528
  e.preventDefault()
432
529
  if (flattenedItems.length === 0) return
433
- setHighlightedIndex((prev) => (prev - 1 + flattenedItems.length) % flattenedItems.length)
530
+ const nextIdx = (highlightedIndex - 1 + flattenedItems.length) % flattenedItems.length
531
+ setHighlightedIndex(nextIdx)
532
+ setInspectedItem({ providerId: flattenedItems[nextIdx].providerId, model: flattenedItems[nextIdx].model })
434
533
  } else if (e.key === 'Enter') {
435
534
  e.preventDefault()
436
535
  const item = flattenedItems[highlightedIndex]
@@ -445,17 +544,42 @@ export default function ModelSelectorPopover({
445
544
  }
446
545
  }
447
546
 
448
- // Active item label for trigger pill
547
+ // Active item label & effort for trigger pill
449
548
  const activeModelDisplay = useMemo(() => {
450
549
  if (!activeModel) return 'Select Model'
451
550
  return activeModel.split('/').pop() || activeModel
452
551
  }, [activeModel])
453
552
 
553
+ const activeThinking = useMemo(() => {
554
+ return getThinkingConfig(activeModel, activeProvider)
555
+ }, [activeModel, activeProvider, getThinkingConfig])
556
+
557
+ // Inspected model details
558
+ const currentInspected = inspectedItem || (activeModel ? { providerId: activeProvider, model: activeModel } : null)
559
+ const inspectedMeta = useMemo(() => {
560
+ if (!currentInspected) return null
561
+ return getModelMetadata(currentInspected.model, currentInspected.providerId)
562
+ }, [currentInspected])
563
+
564
+ const inspectedThinking = useMemo(() => {
565
+ if (!currentInspected) return { supported: false, enabled: false, effort: 'medium' }
566
+ return getThinkingConfig(currentInspected.model, currentInspected.providerId)
567
+ }, [currentInspected, getThinkingConfig])
568
+
569
+ const inspectedBadges = useMemo(() => {
570
+ if (!currentInspected) return []
571
+ return getModelBadges(currentInspected.model)
572
+ }, [currentInspected])
573
+
574
+ const customLogoForProvider = (providerId: string) =>
575
+ (settingsConfig?.customProviders as CustomProviderConfig[] | undefined)
576
+ ?.find((provider) => `custom:${provider.id}` === providerId)?.logoDataUrl
577
+
454
578
  let itemCounter = 0
455
579
 
456
580
  return (
457
581
  <div className="model-selector-container">
458
- {/* ─── Trigger Button ─── */}
582
+ {/* ─── Trigger Button in Chat Bar ─── */}
459
583
  <button
460
584
  ref={triggerRef}
461
585
  type="button"
@@ -467,9 +591,16 @@ export default function ModelSelectorPopover({
467
591
  aria-expanded={isOpen}
468
592
  >
469
593
  <span className="model-selector-trigger-icon">
470
- <ProviderIcon provider={activeProvider} />
594
+ {customLogoForProvider(activeProvider)
595
+ ? <img className="provider-brand-logo" src={customLogoForProvider(activeProvider)} alt="" aria-hidden="true" />
596
+ : <ProviderIcon provider={activeProvider} />}
471
597
  </span>
472
598
  <span className="model-selector-trigger-name">{activeModelDisplay}</span>
599
+ {activeThinking.enabled && (
600
+ <span className="model-selector-trigger-effort">
601
+ {formatEffortDisplay(activeThinking.effort)}
602
+ </span>
603
+ )}
473
604
  <svg
474
605
  className={`model-selector-trigger-chevron ${isOpen ? 'open' : ''}`}
475
606
  width="11"
@@ -485,101 +616,287 @@ export default function ModelSelectorPopover({
485
616
  </svg>
486
617
  </button>
487
618
 
488
- {/* ─── Spotlight Floating Popover ─── */}
619
+ {/* ─── Spotlight 2-Column Master-Detail Floating Popover ─── */}
489
620
  {isOpen && (
490
- <div ref={popoverRef} className="model-spotlight-popover" onKeyDown={handleKeyDown}>
491
- {/* Search Header */}
492
- <div className="model-spotlight-search-bar">
493
- <svg
494
- className="search-icon"
495
- width="13"
496
- height="13"
497
- viewBox="0 0 24 24"
498
- fill="none"
499
- stroke="currentColor"
500
- strokeWidth="2.2"
501
- strokeLinecap="round"
502
- strokeLinejoin="round"
503
- >
504
- <circle cx="11" cy="11" r="8" />
505
- <line x1="21" y1="21" x2="16.65" y2="16.65" />
506
- </svg>
507
- <input
508
- ref={searchInputRef}
509
- type="text"
510
- className="model-spotlight-input"
511
- placeholder="Search model or provider..."
512
- value={search}
513
- onChange={(e) => setSearch(e.target.value)}
514
- />
515
- {search && (
516
- <button
517
- type="button"
518
- className="search-clear-btn"
519
- onClick={() => setSearch('')}
520
- title="Clear search"
621
+ <div ref={popoverRef} className={`model-spotlight-popover mobile-pane-${mobilePane}`} onKeyDown={handleKeyDown}>
622
+ <div className="model-spotlight-mobile-tabs" role="tablist" aria-label="Model selector view">
623
+ <button type="button" role="tab" aria-selected={mobilePane === 'models'} onClick={() => setMobilePane('models')}>Models</button>
624
+ <button type="button" role="tab" aria-selected={mobilePane === 'options'} onClick={() => setMobilePane('options')}>Options</button>
625
+ </div>
626
+ {/* ─── Left Column: Model List ─── */}
627
+ <div className="model-spotlight-left-pane">
628
+ {/* Search Header */}
629
+ <div className="model-spotlight-search-bar">
630
+ <svg
631
+ className="search-icon"
632
+ width="13"
633
+ height="13"
634
+ viewBox="0 0 24 24"
635
+ fill="none"
636
+ stroke="currentColor"
637
+ strokeWidth="2.2"
638
+ strokeLinecap="round"
639
+ strokeLinejoin="round"
521
640
  >
522
- <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
523
- <line x1="18" y1="6" x2="6" y2="18" />
524
- <line x1="6" y1="6" x2="18" y2="18" />
525
- </svg>
526
- </button>
527
- )}
641
+ <circle cx="11" cy="11" r="8" />
642
+ <line x1="21" y1="21" x2="16.65" y2="16.65" />
643
+ </svg>
644
+ <input
645
+ ref={searchInputRef}
646
+ type="text"
647
+ className="model-spotlight-input"
648
+ placeholder="Search models..."
649
+ value={search}
650
+ onChange={(e) => setSearch(e.target.value)}
651
+ />
652
+ {search && (
653
+ <button
654
+ type="button"
655
+ className="search-clear-btn"
656
+ onClick={() => setSearch('')}
657
+ title="Clear search"
658
+ >
659
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
660
+ <line x1="18" y1="6" x2="6" y2="18" />
661
+ <line x1="6" y1="6" x2="18" y2="18" />
662
+ </svg>
663
+ </button>
664
+ )}
665
+ </div>
666
+
667
+ {/* Grouped Model List */}
668
+ <div ref={listRef} className="model-spotlight-list" role="listbox">
669
+ {filteredGroups.length === 0 ? (
670
+ <div className="model-spotlight-empty">
671
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
672
+ <circle cx="11" cy="11" r="8" />
673
+ <line x1="21" y1="21" x2="16.65" y2="16.65" />
674
+ </svg>
675
+ <span>No models found matching &quot;{search}&quot;</span>
676
+ </div>
677
+ ) : (
678
+ filteredGroups.map((group) => {
679
+ const isOtherGroup = group.id === 'openrouter-other'
680
+ const isCollapsed = isOtherGroup && !isOtherExpanded
681
+
682
+ return (
683
+ <div key={group.id} className="model-spotlight-group">
684
+ <div className="model-spotlight-group-header">
685
+ <span className="group-header-icon">{group.icon}</span>
686
+ <span className="group-header-title">{group.name}</span>
687
+ </div>
688
+
689
+ {isCollapsed ? (
690
+ <div className="model-spotlight-see-more-wrap">
691
+ <button
692
+ type="button"
693
+ className="model-spotlight-see-more-btn"
694
+ onClick={() => setExpandOtherModels(true)}
695
+ >
696
+ <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
697
+ <polyline points="6 9 12 15 18 9" />
698
+ </svg>
699
+ <span>Show all {group.models.length} other models</span>
700
+ </button>
701
+ </div>
702
+ ) : (
703
+ <>
704
+ <div className="model-spotlight-group-items">
705
+ {group.models.map((m) => {
706
+ const currentIndex = itemCounter++
707
+ const isSelected = activeProvider === group.providerId && activeModel === m
708
+ const isInspected = currentInspected?.model === m && currentInspected?.providerId === group.providerId
709
+ const itemThinking = getThinkingConfig(m, group.providerId)
710
+
711
+ return (
712
+ <div
713
+ key={m}
714
+ data-item-index={currentIndex}
715
+ className={`model-spotlight-item ${isSelected ? 'is-active' : ''} ${isInspected ? 'is-inspected' : ''}`}
716
+ onClick={() => {
717
+ setInspectedItem({ providerId: group.providerId, model: m })
718
+ onSelect(group.providerId, m)
719
+ if (window.matchMedia('(max-width: 760px)').matches) setMobilePane('options')
720
+ }}
721
+ onMouseEnter={() => {
722
+ setHighlightedIndex(currentIndex)
723
+ setInspectedItem({ providerId: group.providerId, model: m })
724
+ }}
725
+ role="option"
726
+ aria-selected={isSelected}
727
+ >
728
+ <div className="model-item-left">
729
+ <div style={{ display: 'inline-flex', alignItems: 'center', gap: '6px' }}>
730
+ <span className="model-item-provider-icon" aria-hidden="true">
731
+ {group.icon}
732
+ </span>
733
+ <span className="model-item-name">{m.split('/').pop() || m}</span>
734
+ {isFreeModel(m) && (
735
+ <span className="model-tag-badge badge-free">Free</span>
736
+ )}
737
+ </div>
738
+ {m.includes('/') && <span className="model-item-repo">{m}</span>}
739
+ </div>
740
+
741
+ <div className="model-item-right">
742
+ {itemThinking.enabled && (
743
+ <span className="model-item-effort-pill">
744
+ {formatEffortDisplay(itemThinking.effort)}
745
+ </span>
746
+ )}
747
+
748
+ {isSelected && (
749
+ <svg
750
+ className="model-item-check"
751
+ width="14"
752
+ height="14"
753
+ viewBox="0 0 24 24"
754
+ fill="none"
755
+ stroke="var(--accent, #10b981)"
756
+ strokeWidth="2.5"
757
+ strokeLinecap="round"
758
+ strokeLinejoin="round"
759
+ >
760
+ <polyline points="20 6 9 17 4 12" />
761
+ </svg>
762
+ )}
763
+ </div>
764
+ </div>
765
+ )
766
+ })}
767
+ </div>
768
+
769
+ {isOtherGroup && !search.trim() && (
770
+ <div className="model-spotlight-see-more-wrap" style={{ marginTop: '4px' }}>
771
+ <button
772
+ type="button"
773
+ className="model-spotlight-see-more-btn collapse-btn"
774
+ onClick={() => setExpandOtherModels(false)}
775
+ >
776
+ <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
777
+ <polyline points="18 15 12 9 6 15" />
778
+ </svg>
779
+ <span>Collapse other models</span>
780
+ </button>
781
+ </div>
782
+ )}
783
+ </>
784
+ )}
785
+ </div>
786
+ )
787
+ })
788
+ )}
789
+ </div>
528
790
  </div>
529
791
 
530
- {/* Grouped Model List */}
531
- <div ref={listRef} className="model-spotlight-list" role="listbox">
532
- {filteredGroups.length === 0 ? (
533
- <div className="model-spotlight-empty">
534
- <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
535
- <circle cx="11" cy="11" r="8" />
536
- <line x1="21" y1="21" x2="16.65" y2="16.65" />
537
- </svg>
538
- <span>No models found matching &quot;{search}&quot;</span>
539
- </div>
540
- ) : (
541
- filteredGroups.map((group) => (
542
- <div key={group.id} className="model-spotlight-group">
543
- <div className="model-spotlight-group-header">
544
- <span className="group-header-icon">{group.icon}</span>
545
- <span className="group-header-title">{group.name}</span>
792
+ {/* ─── Right Column: Model Detail & Thinking Controls ─── */}
793
+ <div className="model-spotlight-right-pane">
794
+ {currentInspected && inspectedMeta ? (
795
+ <div className="model-detail-container">
796
+ {/* Header: Icon + Name */}
797
+ <div className="model-detail-header">
798
+ <div className="model-detail-icon">
799
+ {customLogoForProvider(currentInspected.providerId)
800
+ ? <img className="provider-brand-logo" src={customLogoForProvider(currentInspected.providerId)} alt="" aria-hidden="true" />
801
+ : <ProviderIcon provider={currentInspected.providerId} />}
546
802
  </div>
803
+ <div className="model-detail-title-wrap">
804
+ <span className="model-detail-title">{currentInspected.model.split('/').pop() || currentInspected.model}</span>
805
+ {currentInspected.model.includes('/') && (
806
+ <span className="model-detail-subtitle">{currentInspected.model}</span>
807
+ )}
808
+ </div>
809
+ </div>
547
810
 
548
- <div className="model-spotlight-group-items">
549
- {group.models.map((m) => {
550
- const currentIndex = itemCounter++
551
- const isSelected = activeProvider === group.id && activeModel === m
552
- const isHighlighted = highlightedIndex === currentIndex
553
- const badges = getModelBadges(m)
554
-
555
- return (
556
- <div
557
- key={m}
558
- data-item-index={currentIndex}
559
- className={`model-spotlight-item ${isSelected ? 'is-active' : ''} ${isHighlighted ? 'is-highlighted' : ''}`}
560
- onClick={() => {
561
- onSelect(group.id, m)
562
- setIsOpen(false)
563
- }}
564
- onMouseEnter={() => setHighlightedIndex(currentIndex)}
565
- role="option"
566
- aria-selected={isSelected}
567
- >
568
- <div className="model-item-left">
569
- <span className="model-item-name">{m.split('/').pop() || m}</span>
570
- {m.includes('/') && <span className="model-item-repo">{m}</span>}
571
- </div>
811
+ {/* Description */}
812
+ <p className="model-detail-description">
813
+ {inspectedMeta.description}
814
+ </p>
815
+
816
+ {/* Badges / Capabilities */}
817
+ <div className="model-detail-tags">
818
+ <span className="model-detail-context-badge">
819
+ {inspectedMeta.contextWindow}
820
+ </span>
821
+ {inspectedBadges.map((b) => (
822
+ <ModelBadge key={b.type} type={b.type} label={b.label} />
823
+ ))}
824
+ </div>
572
825
 
573
- <div className="model-item-right">
574
- <div className="model-item-badges">
575
- {badges.map((b) => (
576
- <ModelBadge key={b.type} type={b.type} label={b.label} />
577
- ))}
578
- </div>
826
+ {/* Divider */}
827
+ <div className="model-detail-divider" />
828
+
829
+ {/* Options Section */}
830
+ <div className="model-detail-section-title">Options</div>
831
+ <div className="model-detail-option-row">
832
+ <div className="option-row-left">
833
+ <svg
834
+ width="15"
835
+ height="15"
836
+ viewBox="0 0 24 24"
837
+ fill="none"
838
+ stroke="currentColor"
839
+ strokeWidth="2"
840
+ strokeLinecap="round"
841
+ strokeLinejoin="round"
842
+ className="option-icon"
843
+ >
844
+ <path d="M12 2a7 7 0 0 1 7 7c0 2.38-1.19 4.47-3 5.74V17a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2v-2.26C6.19 13.47 5 11.38 5 9a7 7 0 0 1 7-7z" />
845
+ <path d="M9 21h6" />
846
+ </svg>
847
+ <span className="option-label">Thinking</span>
848
+ </div>
579
849
 
580
- {isSelected && (
850
+ <button
851
+ type="button"
852
+ role="switch"
853
+ aria-checked={inspectedThinking.enabled}
854
+ className={`model-detail-switch ${inspectedThinking.enabled ? 'checked' : ''}`}
855
+ onClick={() => {
856
+ persistThinking(
857
+ currentInspected.model,
858
+ !inspectedThinking.enabled,
859
+ inspectedThinking.effort
860
+ )
861
+ }}
862
+ title={
863
+ inspectedThinking.enabled
864
+ ? 'Disable thinking'
865
+ : 'Enable thinking'
866
+ }
867
+ >
868
+ <span className="model-detail-switch-thumb" />
869
+ </button>
870
+ </div>
871
+
872
+ {!inspectedThinking.supported && (
873
+ <div className="model-unsupported-note" style={{ color: inspectedThinking.enabled ? 'var(--accent, #10b981)' : undefined }}>
874
+ {inspectedThinking.enabled
875
+ ? 'Thinking enabled (force toggle)'
876
+ : 'Not flagged as reasoning model by default (toggle to force enable)'}
877
+ </div>
878
+ )}
879
+
880
+ {/* Effort Section (visible when Thinking is ON) */}
881
+ {inspectedThinking.enabled && (
882
+ <div className="model-effort-section">
883
+ <div className="model-detail-section-title">Effort</div>
884
+ <div className="model-effort-list">
885
+ {Effort_LEVELS.map((level) => {
886
+ const isCurrent = inspectedThinking.effort === level.id
887
+ return (
888
+ <button
889
+ key={level.id}
890
+ type="button"
891
+ className={`model-effort-item ${isCurrent ? 'is-selected' : ''}`}
892
+ onClick={() => {
893
+ persistThinking(currentInspected.model, true, level.id)
894
+ }}
895
+ >
896
+ <span className="effort-item-label">{level.label}</span>
897
+ {isCurrent && (
581
898
  <svg
582
- className="model-item-check"
899
+ className="effort-item-check"
583
900
  width="14"
584
901
  height="14"
585
902
  viewBox="0 0 24 24"
@@ -592,13 +909,17 @@ export default function ModelSelectorPopover({
592
909
  <polyline points="20 6 9 17 4 12" />
593
910
  </svg>
594
911
  )}
595
- </div>
596
- </div>
597
- )
598
- })}
912
+ </button>
913
+ )
914
+ })}
915
+ </div>
599
916
  </div>
600
- </div>
601
- ))
917
+ )}
918
+ </div>
919
+ ) : (
920
+ <div className="model-detail-empty">
921
+ <span>Select a model to view options</span>
922
+ </div>
602
923
  )}
603
924
  </div>
604
925
  </div>