@geminilight/mindos 0.6.63 → 0.6.65

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 (268) hide show
  1. package/_standalone/.mindos-build-version +1 -1
  2. package/_standalone/.next/BUILD_ID +1 -1
  3. package/_standalone/.next/app-path-routes-manifest.json +21 -21
  4. package/_standalone/.next/build-manifest.json +2 -2
  5. package/_standalone/.next/cache/.previewinfo +1 -1
  6. package/_standalone/.next/cache/.rscinfo +1 -1
  7. package/_standalone/.next/cache/config.json +3 -3
  8. package/_standalone/.next/prerender-manifest.json +3 -3
  9. package/_standalone/.next/server/app/.well-known/agent-card.json/route_client-reference-manifest.js +1 -1
  10. package/_standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  11. package/_standalone/.next/server/app/_global-error.html +2 -2
  12. package/_standalone/.next/server/app/_global-error.rsc +1 -1
  13. package/_standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  14. package/_standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  15. package/_standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  16. package/_standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  17. package/_standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  18. package/_standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  19. package/_standalone/.next/server/app/_not-found/page.js +1 -1
  20. package/_standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  21. package/_standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  22. package/_standalone/.next/server/app/agents/[agentKey]/page.js +1 -1
  23. package/_standalone/.next/server/app/agents/[agentKey]/page.js.nft.json +1 -1
  24. package/_standalone/.next/server/app/agents/[agentKey]/page_client-reference-manifest.js +1 -1
  25. package/_standalone/.next/server/app/agents/page.js +1 -1
  26. package/_standalone/.next/server/app/agents/page.js.nft.json +1 -1
  27. package/_standalone/.next/server/app/agents/page_client-reference-manifest.js +1 -1
  28. package/_standalone/.next/server/app/api/a2a/agents/route_client-reference-manifest.js +1 -1
  29. package/_standalone/.next/server/app/api/a2a/delegations/route_client-reference-manifest.js +1 -1
  30. package/_standalone/.next/server/app/api/a2a/discover/route_client-reference-manifest.js +1 -1
  31. package/_standalone/.next/server/app/api/a2a/route_client-reference-manifest.js +1 -1
  32. package/_standalone/.next/server/app/api/acp/config/route_client-reference-manifest.js +1 -1
  33. package/_standalone/.next/server/app/api/acp/detect/route_client-reference-manifest.js +1 -1
  34. package/_standalone/.next/server/app/api/acp/install/route_client-reference-manifest.js +1 -1
  35. package/_standalone/.next/server/app/api/acp/registry/route_client-reference-manifest.js +1 -1
  36. package/_standalone/.next/server/app/api/acp/session/route_client-reference-manifest.js +1 -1
  37. package/_standalone/.next/server/app/api/agent-activity/route_client-reference-manifest.js +1 -1
  38. package/_standalone/.next/server/app/api/agents/copy-skill/route.js.nft.json +1 -1
  39. package/_standalone/.next/server/app/api/agents/copy-skill/route_client-reference-manifest.js +1 -1
  40. package/_standalone/.next/server/app/api/agents/custom/detect/route_client-reference-manifest.js +1 -1
  41. package/_standalone/.next/server/app/api/agents/custom/route_client-reference-manifest.js +1 -1
  42. package/_standalone/.next/server/app/api/ask/route.js +48 -42
  43. package/_standalone/.next/server/app/api/ask/route.js.nft.json +1 -1
  44. package/_standalone/.next/server/app/api/ask/route_client-reference-manifest.js +1 -1
  45. package/_standalone/.next/server/app/api/ask-sessions/route_client-reference-manifest.js +1 -1
  46. package/_standalone/.next/server/app/api/auth/route_client-reference-manifest.js +1 -1
  47. package/_standalone/.next/server/app/api/backlinks/route.js.nft.json +1 -1
  48. package/_standalone/.next/server/app/api/backlinks/route_client-reference-manifest.js +1 -1
  49. package/_standalone/.next/server/app/api/bootstrap/route.js.nft.json +1 -1
  50. package/_standalone/.next/server/app/api/bootstrap/route_client-reference-manifest.js +1 -1
  51. package/_standalone/.next/server/app/api/changes/route.js.nft.json +1 -1
  52. package/_standalone/.next/server/app/api/changes/route_client-reference-manifest.js +1 -1
  53. package/_standalone/.next/server/app/api/export/route.js.nft.json +1 -1
  54. package/_standalone/.next/server/app/api/export/route_client-reference-manifest.js +1 -1
  55. package/_standalone/.next/server/app/api/extract-pdf/route_client-reference-manifest.js +1 -1
  56. package/_standalone/.next/server/app/api/file/import/route.js +1 -1
  57. package/_standalone/.next/server/app/api/file/import/route.js.nft.json +1 -1
  58. package/_standalone/.next/server/app/api/file/import/route_client-reference-manifest.js +1 -1
  59. package/_standalone/.next/server/app/api/file/raw/route.js.nft.json +1 -1
  60. package/_standalone/.next/server/app/api/file/raw/route_client-reference-manifest.js +1 -1
  61. package/_standalone/.next/server/app/api/file/route.js.nft.json +1 -1
  62. package/_standalone/.next/server/app/api/file/route_client-reference-manifest.js +1 -1
  63. package/_standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  64. package/_standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  65. package/_standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  66. package/_standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  67. package/_standalone/.next/server/app/api/graph/route.js.nft.json +1 -1
  68. package/_standalone/.next/server/app/api/graph/route_client-reference-manifest.js +1 -1
  69. package/_standalone/.next/server/app/api/health/route_client-reference-manifest.js +1 -1
  70. package/_standalone/.next/server/app/api/inbox/route.js.nft.json +1 -1
  71. package/_standalone/.next/server/app/api/inbox/route_client-reference-manifest.js +1 -1
  72. package/_standalone/.next/server/app/api/init/route.js.nft.json +1 -1
  73. package/_standalone/.next/server/app/api/init/route_client-reference-manifest.js +1 -1
  74. package/_standalone/.next/server/app/api/mcp/agents/route.js +1 -1
  75. package/_standalone/.next/server/app/api/mcp/agents/route.js.nft.json +1 -1
  76. package/_standalone/.next/server/app/api/mcp/agents/route_client-reference-manifest.js +1 -1
  77. package/_standalone/.next/server/app/api/mcp/install/route_client-reference-manifest.js +1 -1
  78. package/_standalone/.next/server/app/api/mcp/install-skill/route_client-reference-manifest.js +1 -1
  79. package/_standalone/.next/server/app/api/mcp/restart/route_client-reference-manifest.js +1 -1
  80. package/_standalone/.next/server/app/api/mcp/status/route_client-reference-manifest.js +1 -1
  81. package/_standalone/.next/server/app/api/mcp/uninstall/route_client-reference-manifest.js +1 -1
  82. package/_standalone/.next/server/app/api/monitoring/route.js.nft.json +1 -1
  83. package/_standalone/.next/server/app/api/monitoring/route_client-reference-manifest.js +1 -1
  84. package/_standalone/.next/server/app/api/recent-files/route.js.nft.json +1 -1
  85. package/_standalone/.next/server/app/api/recent-files/route_client-reference-manifest.js +1 -1
  86. package/_standalone/.next/server/app/api/restart/route_client-reference-manifest.js +1 -1
  87. package/_standalone/.next/server/app/api/search/route.js.nft.json +1 -1
  88. package/_standalone/.next/server/app/api/search/route_client-reference-manifest.js +1 -1
  89. package/_standalone/.next/server/app/api/settings/list-models/route.js +1 -1
  90. package/_standalone/.next/server/app/api/settings/list-models/route_client-reference-manifest.js +1 -1
  91. package/_standalone/.next/server/app/api/settings/reset-token/route_client-reference-manifest.js +1 -1
  92. package/_standalone/.next/server/app/api/settings/route.js +1 -1
  93. package/_standalone/.next/server/app/api/settings/route.js.nft.json +1 -1
  94. package/_standalone/.next/server/app/api/settings/route_client-reference-manifest.js +1 -1
  95. package/_standalone/.next/server/app/api/settings/test-key/route.js +1 -1
  96. package/_standalone/.next/server/app/api/settings/test-key/route_client-reference-manifest.js +1 -1
  97. package/_standalone/.next/server/app/api/setup/check-path/route_client-reference-manifest.js +1 -1
  98. package/_standalone/.next/server/app/api/setup/check-port/route_client-reference-manifest.js +1 -1
  99. package/_standalone/.next/server/app/api/setup/generate-token/route_client-reference-manifest.js +1 -1
  100. package/_standalone/.next/server/app/api/setup/ls/route_client-reference-manifest.js +1 -1
  101. package/_standalone/.next/server/app/api/setup/route.js +1 -1
  102. package/_standalone/.next/server/app/api/setup/route_client-reference-manifest.js +1 -1
  103. package/_standalone/.next/server/app/api/skills/route.js +1 -1
  104. package/_standalone/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  105. package/_standalone/.next/server/app/api/sync/route_client-reference-manifest.js +1 -1
  106. package/_standalone/.next/server/app/api/tree-version/route.js.nft.json +1 -1
  107. package/_standalone/.next/server/app/api/tree-version/route_client-reference-manifest.js +1 -1
  108. package/_standalone/.next/server/app/api/uninstall/route_client-reference-manifest.js +1 -1
  109. package/_standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  110. package/_standalone/.next/server/app/api/update-check/route_client-reference-manifest.js +1 -1
  111. package/_standalone/.next/server/app/api/update-status/route_client-reference-manifest.js +1 -1
  112. package/_standalone/.next/server/app/api/workflows/route.js.nft.json +1 -1
  113. package/_standalone/.next/server/app/api/workflows/route_client-reference-manifest.js +1 -1
  114. package/_standalone/.next/server/app/changes/page.js +1 -1
  115. package/_standalone/.next/server/app/changes/page.js.nft.json +1 -1
  116. package/_standalone/.next/server/app/changes/page_client-reference-manifest.js +1 -1
  117. package/_standalone/.next/server/app/echo/[segment]/page.js +2 -2
  118. package/_standalone/.next/server/app/echo/[segment]/page.js.nft.json +1 -1
  119. package/_standalone/.next/server/app/echo/[segment]/page_client-reference-manifest.js +1 -1
  120. package/_standalone/.next/server/app/echo/page.js +1 -1
  121. package/_standalone/.next/server/app/echo/page.js.nft.json +1 -1
  122. package/_standalone/.next/server/app/echo/page_client-reference-manifest.js +1 -1
  123. package/_standalone/.next/server/app/explore/page.js +1 -1
  124. package/_standalone/.next/server/app/explore/page.js.nft.json +1 -1
  125. package/_standalone/.next/server/app/explore/page_client-reference-manifest.js +1 -1
  126. package/_standalone/.next/server/app/help/page.js +1 -1
  127. package/_standalone/.next/server/app/help/page.js.nft.json +1 -1
  128. package/_standalone/.next/server/app/help/page_client-reference-manifest.js +1 -1
  129. package/_standalone/.next/server/app/inbox/history/page.js +1 -1
  130. package/_standalone/.next/server/app/inbox/history/page.js.nft.json +1 -1
  131. package/_standalone/.next/server/app/inbox/history/page_client-reference-manifest.js +1 -1
  132. package/_standalone/.next/server/app/login/page.js +1 -1
  133. package/_standalone/.next/server/app/login/page.js.nft.json +1 -1
  134. package/_standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
  135. package/_standalone/.next/server/app/page.js +1 -1
  136. package/_standalone/.next/server/app/page.js.nft.json +1 -1
  137. package/_standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  138. package/_standalone/.next/server/app/setup/page.js +2 -2
  139. package/_standalone/.next/server/app/setup/page.js.nft.json +1 -1
  140. package/_standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
  141. package/_standalone/.next/server/app/trash/page.js +3 -3
  142. package/_standalone/.next/server/app/trash/page.js.nft.json +1 -1
  143. package/_standalone/.next/server/app/trash/page_client-reference-manifest.js +1 -1
  144. package/_standalone/.next/server/app/view/[...path]/page.js +2 -2
  145. package/_standalone/.next/server/app/view/[...path]/page.js.nft.json +1 -1
  146. package/_standalone/.next/server/app/view/[...path]/page_client-reference-manifest.js +1 -1
  147. package/_standalone/.next/server/app/wiki/page.js +1 -1
  148. package/_standalone/.next/server/app/wiki/page.js.nft.json +1 -1
  149. package/_standalone/.next/server/app/wiki/page_client-reference-manifest.js +1 -1
  150. package/_standalone/.next/server/app-paths-manifest.json +21 -21
  151. package/_standalone/.next/server/chunks/122.js +222 -0
  152. package/_standalone/.next/server/chunks/3113.js +52 -0
  153. package/_standalone/.next/server/chunks/6539.js +1 -1
  154. package/_standalone/.next/server/chunks/8388.js +2 -2
  155. package/_standalone/.next/server/chunks/953.js +3 -3
  156. package/_standalone/.next/server/chunks/9787.js +2 -0
  157. package/_standalone/.next/server/pages/500.html +2 -2
  158. package/_standalone/.next/server/server-reference-manifest.js +1 -1
  159. package/_standalone/.next/server/server-reference-manifest.json +1 -1
  160. package/_standalone/.next/static/chunks/1001-99da82ec8d8c136f.js +1 -0
  161. package/_standalone/.next/static/chunks/5149-4d828886dda479fa.js +1 -0
  162. package/_standalone/.next/static/chunks/{5581-82e5db227f8e9393.js → 5581-c671163a2fe1b312.js} +2 -2
  163. package/_standalone/.next/static/chunks/6636-53238eff89503f03.js +6 -0
  164. package/_standalone/.next/static/chunks/6757-1c1a89720fdda8f0.js +1 -0
  165. package/_standalone/.next/static/chunks/7129-20e9d2463a9da646.js +1 -0
  166. package/_standalone/.next/static/chunks/{3674-be69a8b858ceacdd.js → 7294-cac25d97869afadc.js} +1 -1
  167. package/_standalone/.next/static/chunks/8225-21e5cebc3731ddf0.js +1 -0
  168. package/_standalone/.next/static/chunks/8520-b51810e66293ceb8.js +22 -0
  169. package/_standalone/.next/static/chunks/9207-dc9c31b351a2ed78.js +1 -0
  170. package/_standalone/.next/static/chunks/app/agents/[agentKey]/{page-b0dabe793500383d.js → page-2f5cf97e03dc1cc9.js} +1 -1
  171. package/_standalone/.next/static/chunks/app/agents/{page-1f1ac330c8177cf6.js → page-50eac58d511dcc6e.js} +1 -1
  172. package/_standalone/.next/static/chunks/app/echo/[segment]/page-2a00f4686adf3885.js +11 -0
  173. package/_standalone/.next/static/chunks/app/{layout-50a6b1164ee98ab9.js → layout-2cb7a6602d2e5d5f.js} +62 -58
  174. package/_standalone/.next/static/chunks/app/{page-73802bd31d7f6c9f.js → page-5ab911b2226f6ff7.js} +1 -1
  175. package/_standalone/.next/static/chunks/app/setup/page-907b7c57fad2292b.js +1 -0
  176. package/_standalone/.next/static/chunks/app/trash/page-11a511b065ea84c2.js +1 -0
  177. package/_standalone/.next/static/chunks/app/view/[...path]/{page-808f39963bf04715.js → page-26e47dd4c533a58c.js} +2 -2
  178. package/_standalone/.next/static/css/67e7918f5ed7d147.css +1 -0
  179. package/_standalone/.next/trace +65 -65
  180. package/_standalone/__tests__/api/ask-attachments.test.ts +194 -0
  181. package/_standalone/__tests__/api/settings.test.ts +16 -12
  182. package/_standalone/__tests__/api/setup.test.ts +11 -9
  183. package/_standalone/__tests__/api/test-key.test.ts +0 -10
  184. package/_standalone/__tests__/components/UpdateToast.test.ts +344 -0
  185. package/_standalone/__tests__/core/context.test.ts +48 -426
  186. package/_standalone/__tests__/lib/pi-skills.test.ts +4 -4
  187. package/_standalone/__tests__/lib/settings-ai-client.test.ts +32 -12
  188. package/_standalone/__tests__/setup.ts +5 -5
  189. package/_standalone/components/ask/AskContent.tsx +70 -40
  190. package/_standalone/components/ask/AskHeader.tsx +8 -1
  191. package/_standalone/components/ask/MessageList.tsx +37 -3
  192. package/_standalone/components/ask/ProviderModelCapsule.tsx +51 -129
  193. package/_standalone/components/settings/AiTab.tsx +270 -347
  194. package/_standalone/components/settings/CustomProviderFields.tsx +121 -0
  195. package/_standalone/components/settings/CustomProvidersCard.tsx +2 -2
  196. package/_standalone/components/settings/KnowledgeTab.tsx +6 -20
  197. package/_standalone/components/settings/McpAgentInstall.tsx +7 -2
  198. package/_standalone/components/settings/Primitives.tsx +48 -104
  199. package/_standalone/components/settings/ProviderModal.tsx +38 -221
  200. package/_standalone/components/settings/SettingsContent.tsx +5 -12
  201. package/_standalone/components/settings/TestButton.tsx +64 -0
  202. package/_standalone/components/settings/types.ts +3 -12
  203. package/_standalone/components/settings/useCustomProviderForm.ts +132 -0
  204. package/_standalone/components/setup/StepAI.tsx +3 -3
  205. package/_standalone/components/shared/ModelInput.tsx +18 -4
  206. package/_standalone/components/shared/ProviderSelect.tsx +126 -134
  207. package/_standalone/hooks/useAskChat.ts +97 -13
  208. package/_standalone/hooks/useAskPanel.ts +17 -1
  209. package/_standalone/lib/settings-ai-client.ts +17 -8
  210. package/_standalone/tsconfig.tsbuildinfo +1 -1
  211. package/app/app/api/ask/route.ts +124 -44
  212. package/app/app/api/mcp/agents/route.ts +3 -3
  213. package/app/app/api/settings/list-models/route.ts +15 -26
  214. package/app/app/api/settings/route.ts +14 -59
  215. package/app/app/api/settings/test-key/route.ts +47 -12
  216. package/app/app/api/setup/route.ts +36 -18
  217. package/app/app/api/skills/route.ts +1 -1
  218. package/app/app/layout.tsx +5 -3
  219. package/app/components/HomeContent.tsx +11 -0
  220. package/app/components/UpdateToast.tsx +255 -0
  221. package/app/components/ask/AskContent.tsx +70 -40
  222. package/app/components/ask/AskHeader.tsx +8 -1
  223. package/app/components/ask/MessageList.tsx +37 -3
  224. package/app/components/ask/ProviderModelCapsule.tsx +51 -129
  225. package/app/components/settings/AiTab.tsx +270 -347
  226. package/app/components/settings/CustomProviderFields.tsx +121 -0
  227. package/app/components/settings/CustomProvidersCard.tsx +2 -2
  228. package/app/components/settings/KnowledgeTab.tsx +6 -20
  229. package/app/components/settings/McpAgentInstall.tsx +7 -2
  230. package/app/components/settings/Primitives.tsx +48 -104
  231. package/app/components/settings/ProviderModal.tsx +38 -221
  232. package/app/components/settings/SettingsContent.tsx +5 -12
  233. package/app/components/settings/TestButton.tsx +64 -0
  234. package/app/components/settings/types.ts +3 -12
  235. package/app/components/settings/useCustomProviderForm.ts +132 -0
  236. package/app/components/setup/StepAI.tsx +3 -3
  237. package/app/components/shared/ModelInput.tsx +18 -4
  238. package/app/components/shared/ProviderSelect.tsx +126 -134
  239. package/app/hooks/useAskChat.ts +97 -13
  240. package/app/hooks/useAskPanel.ts +17 -1
  241. package/app/lib/agent/context.ts +65 -0
  242. package/app/lib/agent/providers.ts +25 -0
  243. package/app/lib/agent/tools.ts +1 -1
  244. package/app/lib/custom-endpoints.ts +129 -29
  245. package/app/lib/i18n/modules/settings.ts +20 -0
  246. package/app/lib/pi-integration/skills.ts +16 -4
  247. package/app/lib/settings-ai-client.ts +17 -8
  248. package/app/lib/settings.ts +64 -90
  249. package/app/lib/types.ts +4 -0
  250. package/package.json +1 -1
  251. package/_standalone/.next/server/chunks/530.js +0 -218
  252. package/_standalone/.next/server/chunks/9007.js +0 -2
  253. package/_standalone/.next/server/chunks/9137.js +0 -52
  254. package/_standalone/.next/static/chunks/1309-373ade1b40aea186.js +0 -1
  255. package/_standalone/.next/static/chunks/3165-9189a38fd9ebf6f2.js +0 -1
  256. package/_standalone/.next/static/chunks/4587-5d06728133fff222.js +0 -1
  257. package/_standalone/.next/static/chunks/6261-5ce86db54b19ae46.js +0 -1
  258. package/_standalone/.next/static/chunks/6636-9bbc90fb3b8731fe.js +0 -6
  259. package/_standalone/.next/static/chunks/7637-904b0a381dc3ec02.js +0 -1
  260. package/_standalone/.next/static/chunks/8520-84e607f33c409f91.js +0 -22
  261. package/_standalone/.next/static/chunks/9207-9a4a1a1ede4f8e6e.js +0 -1
  262. package/_standalone/.next/static/chunks/app/echo/[segment]/page-bc5e104eb7ae6327.js +0 -11
  263. package/_standalone/.next/static/chunks/app/setup/page-79acb0baf38184c6.js +0 -1
  264. package/_standalone/.next/static/chunks/app/trash/page-d040db56863da504.js +0 -1
  265. package/_standalone/.next/static/css/1287672978833d07.css +0 -1
  266. package/_standalone/lib/agent/context.ts +0 -403
  267. /package/_standalone/.next/static/{X86rF8dKEO0InosOw4a2_ → eIlwbGas1iRGonlPyEwj7}/_buildManifest.js +0 -0
  268. /package/_standalone/.next/static/{X86rF8dKEO0InosOw4a2_ → eIlwbGas1iRGonlPyEwj7}/_ssgManifest.js +0 -0
@@ -30,6 +30,9 @@ export interface ProviderPreset {
30
30
  id: ProviderId;
31
31
  name: string;
32
32
  nameZh: string;
33
+ shortLabel: string; // 3-8 char label for capsule display (e.g., 'Claude', 'GPT', 'GLM-CN')
34
+ description?: string; // Helper text for settings (e.g., "China region version")
35
+ descriptionZh?: string; // Chinese helper text
33
36
  defaultModel: string;
34
37
  /** If ProviderId differs from pi-ai's KnownProvider (e.g. deepseek → openai) */
35
38
  piProviderOverride?: KnownProvider;
@@ -49,6 +52,7 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
49
52
  id: 'anthropic',
50
53
  name: 'Anthropic',
51
54
  nameZh: 'Anthropic',
55
+ shortLabel: 'Anthropic',
52
56
  defaultModel: 'claude-sonnet-4-6',
53
57
  supportsBaseUrl: true,
54
58
  supportsThinking: true,
@@ -60,6 +64,7 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
60
64
  id: 'openai',
61
65
  name: 'OpenAI',
62
66
  nameZh: 'OpenAI',
67
+ shortLabel: 'OpenAI',
63
68
  defaultModel: 'gpt-5.4',
64
69
  supportsBaseUrl: true,
65
70
  supportsThinking: true,
@@ -71,6 +76,7 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
71
76
  id: 'google',
72
77
  name: 'Google Gemini',
73
78
  nameZh: 'Google Gemini',
79
+ shortLabel: 'Gemini',
74
80
  defaultModel: 'gemini-2.5-flash',
75
81
  supportsBaseUrl: false,
76
82
  supportsThinking: true,
@@ -82,6 +88,7 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
82
88
  id: 'groq',
83
89
  name: 'Groq',
84
90
  nameZh: 'Groq',
91
+ shortLabel: 'Groq',
85
92
  defaultModel: 'llama-3.3-70b-versatile',
86
93
  supportsBaseUrl: false,
87
94
  supportsThinking: false,
@@ -93,6 +100,7 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
93
100
  id: 'xai',
94
101
  name: 'xAI (Grok)',
95
102
  nameZh: 'xAI (Grok)',
103
+ shortLabel: 'xAI',
96
104
  defaultModel: 'grok-3',
97
105
  supportsBaseUrl: false,
98
106
  supportsThinking: false,
@@ -103,6 +111,7 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
103
111
  id: 'openrouter',
104
112
  name: 'OpenRouter',
105
113
  nameZh: 'OpenRouter',
114
+ shortLabel: 'OpenRouter',
106
115
  defaultModel: 'anthropic/claude-sonnet-4',
107
116
  supportsBaseUrl: false,
108
117
  supportsThinking: false,
@@ -113,6 +122,7 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
113
122
  id: 'mistral',
114
123
  name: 'Mistral',
115
124
  nameZh: 'Mistral',
125
+ shortLabel: 'Mistral',
116
126
  defaultModel: 'mistral-large-latest',
117
127
  supportsBaseUrl: false,
118
128
  supportsThinking: false,
@@ -123,6 +133,7 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
123
133
  id: 'deepseek',
124
134
  name: 'DeepSeek',
125
135
  nameZh: 'DeepSeek',
136
+ shortLabel: 'DeepSeek',
126
137
  defaultModel: 'deepseek-chat',
127
138
  piProviderOverride: 'openai' as KnownProvider,
128
139
  fixedBaseUrl: 'https://api.deepseek.com/v1',
@@ -136,6 +147,7 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
136
147
  id: 'zai',
137
148
  name: 'ZhipuAI (GLM)',
138
149
  nameZh: '智谱 AI (GLM 国际版)',
150
+ shortLabel: '智谱GLM',
139
151
  defaultModel: 'glm-4-plus',
140
152
  supportsBaseUrl: false,
141
153
  supportsThinking: true,
@@ -146,6 +158,9 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
146
158
  id: 'zai-cn',
147
159
  name: 'ZhipuAI (GLM China)',
148
160
  nameZh: '智谱 AI (GLM 国内版)',
161
+ shortLabel: '智谱GLM-CN',
162
+ description: 'China region version',
163
+ descriptionZh: '中国区版本',
149
164
  defaultModel: 'glm-4-plus',
150
165
  piProviderOverride: 'zai' as KnownProvider,
151
166
  fixedBaseUrl: 'https://open.bigmodel.cn/api/coding/paas/v4',
@@ -159,6 +174,7 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
159
174
  id: 'kimi-coding',
160
175
  name: 'Kimi Coding',
161
176
  nameZh: 'Kimi Coding (月之暗面)',
177
+ shortLabel: 'Kimi Coding',
162
178
  defaultModel: 'kimi-k2-thinking',
163
179
  supportsBaseUrl: false,
164
180
  supportsThinking: true,
@@ -169,6 +185,7 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
169
185
  id: 'cerebras',
170
186
  name: 'Cerebras',
171
187
  nameZh: 'Cerebras',
188
+ shortLabel: 'Cerebras',
172
189
  defaultModel: 'llama-4-scout-17b-16e',
173
190
  supportsBaseUrl: false,
174
191
  supportsThinking: false,
@@ -179,6 +196,7 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
179
196
  id: 'minimax',
180
197
  name: 'MiniMax',
181
198
  nameZh: 'MiniMax (国际版)',
199
+ shortLabel: 'MiniMax',
182
200
  defaultModel: 'MiniMax-M2.5',
183
201
  supportsBaseUrl: false,
184
202
  supportsThinking: true,
@@ -189,6 +207,9 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
189
207
  id: 'minimax-cn',
190
208
  name: 'MiniMax (China)',
191
209
  nameZh: 'MiniMax (国内版)',
210
+ shortLabel: 'MiniMax-CN',
211
+ description: 'China region version',
212
+ descriptionZh: '中国区版本',
192
213
  defaultModel: 'MiniMax-M2.5',
193
214
  supportsBaseUrl: false,
194
215
  supportsThinking: true,
@@ -199,6 +220,7 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
199
220
  id: 'huggingface',
200
221
  name: 'Hugging Face',
201
222
  nameZh: 'Hugging Face',
223
+ shortLabel: 'HuggingFace',
202
224
  defaultModel: 'Qwen/Qwen3-235B-A22B-Thinking-2507',
203
225
  supportsBaseUrl: false,
204
226
  supportsThinking: true,
@@ -209,6 +231,9 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
209
231
  id: 'ollama',
210
232
  name: 'Ollama',
211
233
  nameZh: 'Ollama (本地)',
234
+ shortLabel: 'Ollama',
235
+ description: 'Local server (requires setup)',
236
+ descriptionZh: '本地服务器 (需要本地部署)',
212
237
  defaultModel: 'llama3.2',
213
238
  piProviderOverride: 'openai' as KnownProvider,
214
239
  fixedBaseUrl: 'http://localhost:11434/v1',
@@ -388,7 +388,7 @@ export const knowledgeBaseTools: AgentTool<any>[] = [
388
388
  parameters: ListSkillsParams,
389
389
  execute: safeExecute(async () => {
390
390
  const projectRoot = process.env.MINDOS_PROJECT_ROOT || path.resolve(process.cwd(), '..');
391
- const skills = scanSkillDirs({ projectRoot, mindRoot: getMindRoot() });
391
+ const skills = await scanSkillDirs({ projectRoot, mindRoot: getMindRoot() });
392
392
  if (skills.length === 0) return textResult('No skills found.');
393
393
  return textResult(skills.map((skill) => `- **${skill.name}** [${skill.origin}]${skill.enabled ? '' : ' (disabled)'} — ${skill.description || 'No description'}\n Path: ${skill.path}`).join('\n'));
394
394
  }),
@@ -1,60 +1,160 @@
1
1
  import { type ProviderId, isProviderId, PROVIDER_PRESETS } from './agent/providers';
2
2
 
3
+ // ─── Unified Provider ───────────────────────────────────────────
4
+
3
5
  /**
4
- * A user-defined provider configuration.
5
- * Allows multiple instances of the same provider type with different
6
- * API keys, base URLs, and custom display names.
6
+ * A provider configuration. All providers are equal — each has a
7
+ * user-visible name, a protocol (openai/anthropic/google/…), and
8
+ * connection details (apiKey, model, baseUrl).
7
9
  */
8
- export interface CustomProvider {
9
- id: string; // "cp_" + 8 random alphanumeric chars
10
+ export interface Provider {
11
+ id: string; // "p_" + 8 random alphanumeric chars
10
12
  name: string; // User-visible display name
11
- baseProviderId: ProviderId; // Protocol to use (openai, anthropic, etc.)
13
+ protocol: ProviderId; // Which API protocol to use
12
14
  apiKey: string;
13
15
  model: string;
14
- baseUrl: string; // Required for custom providers
16
+ baseUrl: string;
15
17
  }
16
18
 
17
- const CP_PREFIX = 'cp_';
19
+ const P_PREFIX = 'p_';
18
20
 
19
- /** Generate a unique custom provider ID */
20
- export function generateCustomProviderId(): string {
21
- return CP_PREFIX + Math.random().toString(36).slice(2, 10);
21
+ /** Generate a unique provider ID */
22
+ export function generateProviderId(): string {
23
+ return P_PREFIX + Math.random().toString(36).slice(2, 10);
22
24
  }
23
25
 
24
- /** Check if an ID refers to a custom provider (vs built-in) */
25
- export function isCustomProviderId(id: string): boolean {
26
- return typeof id === 'string' && id.startsWith(CP_PREFIX);
26
+ /** Check if a string is a provider ID (p_*) */
27
+ export function isProviderEntryId(id: string): boolean {
28
+ return typeof id === 'string' && id.startsWith(P_PREFIX);
27
29
  }
28
30
 
29
- /** Validate that an unknown value is a valid CustomProvider */
30
- export function isValidCustomProvider(e: unknown): e is CustomProvider {
31
+ /** Validate that an unknown value is a valid Provider */
32
+ export function isValidProvider(e: unknown): e is Provider {
31
33
  if (!e || typeof e !== 'object') return false;
32
34
  const obj = e as Record<string, unknown>;
33
35
  return (
34
- typeof obj.id === 'string' && obj.id.startsWith(CP_PREFIX) &&
36
+ typeof obj.id === 'string' && obj.id.startsWith(P_PREFIX) &&
35
37
  typeof obj.name === 'string' && obj.name.trim().length > 0 &&
36
- typeof obj.baseProviderId === 'string' && isProviderId(obj.baseProviderId) &&
38
+ typeof obj.protocol === 'string' && isProviderId(obj.protocol) &&
37
39
  typeof obj.apiKey === 'string' &&
38
40
  typeof obj.model === 'string' &&
39
41
  typeof obj.baseUrl === 'string'
40
42
  );
41
43
  }
42
44
 
43
- /** Parse an array of custom providers from unknown config data, filtering invalid entries */
44
- export function parseCustomProviders(raw: unknown): CustomProvider[] {
45
+ /** Parse an array of providers from unknown config data, filtering invalid entries */
46
+ export function parseProviders(raw: unknown): Provider[] {
45
47
  if (!Array.isArray(raw)) return [];
46
- return raw.filter(isValidCustomProvider);
48
+ return raw.filter(isValidProvider);
47
49
  }
48
50
 
49
- /** Find a custom provider by ID from a list */
50
- export function findCustomProvider(providers: CustomProvider[], id: string): CustomProvider | undefined {
51
+ /** Find a provider by ID from a list */
52
+ export function findProvider(providers: Provider[], id: string): Provider | undefined {
51
53
  return providers.find(p => p.id === id);
52
54
  }
53
55
 
54
- /** Mask API key for display (same pattern as built-in providers) */
55
- export function maskCustomProviderKey(provider: CustomProvider): CustomProvider {
56
- return {
57
- ...provider,
58
- apiKey: provider.apiKey ? '***set***' : '',
59
- };
56
+ // ─── Migration from old format ──────────────────────────────────
57
+
58
+ interface OldProviderConfig { apiKey?: string; model?: string; baseUrl?: string }
59
+ interface OldCustomProvider {
60
+ id: string; name: string; baseProviderId: string;
61
+ apiKey: string; model: string; baseUrl: string;
62
+ }
63
+
64
+ /**
65
+ * Detect whether config.json uses the old format (ai.providers is a dict)
66
+ * and migrate to the new format (ai.providers is an array).
67
+ *
68
+ * Returns null if already in new format (no migration needed).
69
+ */
70
+ export function migrateProviders(parsed: Record<string, unknown>): {
71
+ activeProvider: string;
72
+ providers: Provider[];
73
+ } | null {
74
+ const ai = parsed.ai as Record<string, unknown> | undefined;
75
+ if (!ai) return null;
76
+
77
+ // Already new format: providers is an array
78
+ if (Array.isArray(ai.providers)) return null;
79
+
80
+ // Old format: providers is a dict (or missing)
81
+ const oldProviders = (ai.providers ?? {}) as Record<string, OldProviderConfig>;
82
+ const oldActive = (ai.provider ?? 'openai') as string;
83
+ const oldCustom = (parsed.customProviders ?? []) as OldCustomProvider[];
84
+
85
+ const newProviders: Provider[] = [];
86
+ let activeId = '';
87
+
88
+ // 1. Migrate built-in providers (only those with actual content)
89
+ for (const [protocolId, cfg] of Object.entries(oldProviders)) {
90
+ if (!cfg || !isProviderId(protocolId)) continue;
91
+ // Skip empty entries (no key, no model, no baseUrl)
92
+ if (!cfg.apiKey && !cfg.model && !cfg.baseUrl) continue;
93
+
94
+ const preset = PROVIDER_PRESETS[protocolId];
95
+ const id = generateProviderId();
96
+ newProviders.push({
97
+ id,
98
+ name: preset?.name ?? protocolId,
99
+ protocol: protocolId as ProviderId,
100
+ apiKey: cfg.apiKey ?? '',
101
+ model: cfg.model ?? '',
102
+ baseUrl: cfg.baseUrl ?? '',
103
+ });
104
+
105
+ if (protocolId === oldActive) activeId = id;
106
+ }
107
+
108
+ // 2. Migrate custom providers
109
+ for (const cp of oldCustom) {
110
+ if (!cp.name || !cp.baseProviderId) continue;
111
+ const id = generateProviderId();
112
+ newProviders.push({
113
+ id,
114
+ name: cp.name,
115
+ protocol: (isProviderId(cp.baseProviderId) ? cp.baseProviderId : 'openai') as ProviderId,
116
+ apiKey: cp.apiKey ?? '',
117
+ model: cp.model ?? '',
118
+ baseUrl: cp.baseUrl ?? '',
119
+ });
120
+
121
+ // If old active was a custom provider ID, map it
122
+ if (cp.id === oldActive) activeId = id;
123
+ }
124
+
125
+ // 3. If no active provider was mapped, pick the first one or create a default
126
+ if (!activeId) {
127
+ if (newProviders.length > 0) {
128
+ activeId = newProviders[0].id;
129
+ } else {
130
+ // No providers at all — create default OpenAI entry
131
+ const id = generateProviderId();
132
+ newProviders.push({
133
+ id,
134
+ name: 'OpenAI',
135
+ protocol: 'openai',
136
+ apiKey: '',
137
+ model: PROVIDER_PRESETS.openai?.defaultModel ?? '',
138
+ baseUrl: '',
139
+ });
140
+ activeId = id;
141
+ }
142
+ }
143
+
144
+ return { activeProvider: activeId, providers: newProviders };
145
+ }
146
+
147
+ // ─── Backward compat re-exports (to minimize churn during migration) ──
148
+
149
+ /** @deprecated Use Provider instead */
150
+ export type CustomProvider = Provider;
151
+ /** @deprecated Use generateProviderId instead */
152
+ export const generateCustomProviderId = generateProviderId;
153
+ /** @deprecated Use isProviderEntryId instead */
154
+ export function isCustomProviderId(id: string): boolean {
155
+ return isProviderEntryId(id) || (typeof id === 'string' && id.startsWith('cp_'));
60
156
  }
157
+ /** @deprecated Use parseProviders instead */
158
+ export const parseCustomProviders = parseProviders;
159
+ /** @deprecated Use findProvider instead */
160
+ export const findCustomProvider = findProvider;
@@ -463,6 +463,16 @@ export const settingsEn = {
463
463
  coreDesktopTooOldHint: 'Please update MindOS Desktop first.',
464
464
  coreHint: 'Core updates only restart services — no app restart needed.',
465
465
  shellTitle: 'MindOS Desktop',
466
+ // Update Toast Notification
467
+ updateToast: {
468
+ titleSingle: (type: string, version: string) => `${type} v${version} available`,
469
+ titleMultiple: 'Updates available',
470
+ desktopLabel: 'Desktop',
471
+ coreLabel: 'Core',
472
+ viewDetails: 'View Details',
473
+ skipVersion: 'Skip Version',
474
+ skipAll: 'Skip All',
475
+ },
466
476
  },
467
477
  uninstall: {
468
478
  title: 'Uninstall MindOS',
@@ -953,6 +963,16 @@ export const settingsZh = {
953
963
  coreDesktopTooOldHint: '请先更新 MindOS Desktop。',
954
964
  coreHint: '核心更新只需重启服务,无需重启应用。',
955
965
  shellTitle: 'MindOS Desktop',
966
+ // Update Toast Notification
967
+ updateToast: {
968
+ titleSingle: (type: string, version: string) => `${type} v${version} 可用`,
969
+ titleMultiple: '有可用更新',
970
+ desktopLabel: '桌面版',
971
+ coreLabel: '运行时',
972
+ viewDetails: '查看详情',
973
+ skipVersion: '跳过此版本',
974
+ skipAll: '全部跳过',
975
+ },
956
976
  },
957
977
  uninstall: {
958
978
  title: '卸载 MindOS',
@@ -83,7 +83,7 @@ export function getPiSkillSearchDirs(projectRoot: string, mindRoot: string) {
83
83
  ];
84
84
  }
85
85
 
86
- export function scanSkillDirs(options: ScanSkillOptions): PiSkillInfo[] {
86
+ export async function scanSkillDirs(options: ScanSkillOptions): Promise<PiSkillInfo[]> {
87
87
  const { projectRoot, mindRoot, disabledSkills = [] } = options;
88
88
  const skills: PiSkillInfo[] = [];
89
89
  const seen = new Set<string>();
@@ -91,12 +91,24 @@ export function scanSkillDirs(options: ScanSkillOptions): PiSkillInfo[] {
91
91
  for (const sourceDef of getPiSkillSearchDirs(projectRoot, mindRoot)) {
92
92
  if (!fs.existsSync(sourceDef.dir)) continue;
93
93
 
94
- for (const entry of fs.readdirSync(sourceDef.dir, { withFileTypes: true })) {
94
+ let entries: fs.Dirent[];
95
+ try {
96
+ entries = await fs.promises.readdir(sourceDef.dir, { withFileTypes: true });
97
+ } catch {
98
+ continue;
99
+ }
100
+
101
+ for (const entry of entries) {
95
102
  if (!entry.isDirectory()) continue;
96
103
  const skillFile = path.join(sourceDef.dir, entry.name, 'SKILL.md');
97
- if (!fs.existsSync(skillFile)) continue;
104
+
105
+ let content: string;
106
+ try {
107
+ content = await fs.promises.readFile(skillFile, 'utf-8');
108
+ } catch {
109
+ continue;
110
+ }
98
111
 
99
- const content = fs.readFileSync(skillFile, 'utf-8');
100
112
  const { name, description } = parseSkillMd(content);
101
113
  const skillName = name || entry.name;
102
114
  if (!skillName || seen.has(skillName)) continue;
@@ -2,26 +2,35 @@
2
2
  * Client-side mirror of "can /api/ask run?" using GET /api/settings payload.
3
3
  * Must stay aligned with server `effectiveAiConfig()` provider + key resolution.
4
4
  */
5
- import { type ProviderId, PROVIDER_PRESETS, isProviderId, getApiKeyEnvVar } from './agent/providers';
5
+ import { PROVIDER_PRESETS, isProviderId, getApiKeyEnvVar } from './agent/providers';
6
+ import { type Provider } from './custom-endpoints';
6
7
 
7
8
  export type SettingsJsonForAi = {
8
9
  ai?: {
9
- provider?: string;
10
- providers?: Partial<Record<string, { apiKey?: string }>>;
10
+ activeProvider?: string;
11
+ providers?: Provider[];
11
12
  };
12
13
  envOverrides?: Partial<Record<string, boolean>>;
13
14
  };
14
15
 
15
16
  export function isAiConfiguredForAsk(data: SettingsJsonForAi): boolean {
16
- const provId = data.ai?.provider;
17
- const provider: ProviderId = (provId && isProviderId(provId)) ? provId : 'anthropic';
17
+ const providers = data.ai?.providers ?? [];
18
+ const activeId = data.ai?.activeProvider;
18
19
  const env = data.envOverrides ?? {};
19
20
 
20
- const k = data.ai?.providers?.[provider]?.apiKey;
21
- if (typeof k === 'string' && k.length > 0) return true;
21
+ const current = activeId ? providers.find(p => p.id === activeId) : providers[0];
22
+ if (!current) return false;
22
23
 
23
- const envVar = getApiKeyEnvVar(provider);
24
+ // Has API key directly
25
+ if (current.apiKey && current.apiKey.length > 0) return true;
26
+
27
+ // Has env var override
28
+ const envVar = isProviderId(current.protocol) ? getApiKeyEnvVar(current.protocol) : undefined;
24
29
  if (envVar && env[envVar]) return true;
25
30
 
31
+ // Has fallback key (e.g. Ollama)
32
+ const preset = isProviderId(current.protocol) ? PROVIDER_PRESETS[current.protocol] : undefined;
33
+ if (preset?.apiKeyFallback) return true;
34
+
26
35
  return false;
27
36
  }