@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
@@ -0,0 +1,121 @@
1
+ 'use client';
2
+
3
+ import { Field, Select, Input, PasswordInput } from './Primitives';
4
+ import { PROVIDER_PRESETS, ALL_PROVIDER_IDS, type ProviderId } from '@/lib/agent/providers';
5
+ import ModelInput from '@/components/shared/ModelInput';
6
+ import type { CustomProviderFormState } from './useCustomProviderForm';
7
+ import type { AiTabProps } from './types';
8
+
9
+ interface CustomProviderFieldsProps {
10
+ form: CustomProviderFormState;
11
+ t: AiTabProps['t'];
12
+ locale: string;
13
+ /** "compact" = inline in AiTab (name+protocol side by side), "full" = modal layout */
14
+ layout?: 'compact' | 'full';
15
+ }
16
+
17
+ /**
18
+ * Shared form fields for provider editing.
19
+ * Renders: Name, Protocol, Base URL, API Key, Model.
20
+ */
21
+ export default function CustomProviderFields({
22
+ form, t, locale, layout = 'full',
23
+ }: CustomProviderFieldsProps) {
24
+ const basePreset = PROVIDER_PRESETS[form.protocol];
25
+
26
+ const nameLabel = locale === 'zh' ? '名称' : 'Name';
27
+ const protocolLabel = locale === 'zh' ? '协议' : 'Protocol';
28
+ const namePlaceholder = locale === 'zh' ? '输入名称' : 'Enter name';
29
+
30
+ const nameHint = form.isDuplicateName
31
+ ? (locale === 'zh' ? '名称已存在' : 'Name already exists')
32
+ : undefined;
33
+
34
+ return (
35
+ <div className="space-y-3">
36
+ {/* Name + Protocol */}
37
+ {layout === 'compact' ? (
38
+ <div className="grid grid-cols-2 gap-3">
39
+ <Field label={nameLabel} hint={nameHint} hintError={form.isDuplicateName}>
40
+ <Input
41
+ value={form.name}
42
+ onChange={e => form.setName(e.target.value)}
43
+ placeholder={namePlaceholder}
44
+ autoFocus
45
+ />
46
+ </Field>
47
+ <Field label={protocolLabel}>
48
+ <Select
49
+ value={form.protocol}
50
+ onChange={e => form.setProtocol(e.target.value as ProviderId)}
51
+ >
52
+ {ALL_PROVIDER_IDS.map(id => (
53
+ <option key={id} value={id}>
54
+ {locale === 'zh' ? PROVIDER_PRESETS[id].nameZh : PROVIDER_PRESETS[id].name}
55
+ </option>
56
+ ))}
57
+ </Select>
58
+ </Field>
59
+ </div>
60
+ ) : (
61
+ <>
62
+ <Field label={nameLabel} hint={nameHint} hintError={form.isDuplicateName}>
63
+ <Input
64
+ value={form.name}
65
+ onChange={e => form.setName(e.target.value)}
66
+ placeholder={namePlaceholder}
67
+ />
68
+ </Field>
69
+ <Field label={protocolLabel}>
70
+ <Select
71
+ value={form.protocol}
72
+ onChange={e => form.setProtocol(e.target.value as ProviderId)}
73
+ >
74
+ {ALL_PROVIDER_IDS.map(id => (
75
+ <option key={id} value={id}>
76
+ {locale === 'zh' ? PROVIDER_PRESETS[id].nameZh : PROVIDER_PRESETS[id].name}
77
+ </option>
78
+ ))}
79
+ </Select>
80
+ </Field>
81
+ </>
82
+ )}
83
+
84
+ {/* Base URL */}
85
+ <Field label="Base URL">
86
+ <Input
87
+ value={form.baseUrl}
88
+ onChange={e => form.setBaseUrl(e.target.value)}
89
+ placeholder={basePreset.fixedBaseUrl || 'https://api.example.com/v1'}
90
+ />
91
+ </Field>
92
+
93
+ {/* API Key */}
94
+ <Field
95
+ label={<>API Key <span className="text-muted-foreground/50 font-normal">{locale === 'zh' ? '(可选)' : '(optional)'}</span></>}
96
+ >
97
+ <PasswordInput
98
+ value={form.apiKey}
99
+ onChange={form.setApiKey}
100
+ placeholder="sk-..."
101
+ />
102
+ </Field>
103
+
104
+ {/* Model */}
105
+ <Field label={locale === 'zh' ? '模型' : 'Model'}>
106
+ <ModelInput
107
+ value={form.model}
108
+ onChange={form.setModel}
109
+ placeholder={basePreset.defaultModel}
110
+ provider={form.protocol}
111
+ apiKey={form.apiKey}
112
+ baseUrl={form.baseUrl}
113
+ supportsListModels={!!form.baseUrl.trim()}
114
+ allowNoKey
115
+ browseLabel={t.settings.ai.listModels}
116
+ noModelsLabel={t.settings.ai.noModelsFound}
117
+ />
118
+ </Field>
119
+ </div>
120
+ );
121
+ }
@@ -3,7 +3,7 @@
3
3
  import { useState, useCallback, useMemo, useRef } from 'react';
4
4
  import { Trash2, Edit2, Layers } from 'lucide-react';
5
5
  import { useLocale } from '@/lib/stores/locale-store';
6
- import { type CustomProvider, generateCustomProviderId, isValidCustomProvider } from '@/lib/custom-endpoints';
6
+ import { type CustomProvider, generateCustomProviderId, isValidProvider } from '@/lib/custom-endpoints';
7
7
  import { SettingCard } from './Primitives';
8
8
  import ProviderModal from './ProviderModal';
9
9
 
@@ -76,7 +76,7 @@ export default function CustomProvidersCard({
76
76
  <div className="flex-1 min-w-0">
77
77
  <div className="font-medium text-sm">{provider.name}</div>
78
78
  <div className="text-xs text-muted-foreground mt-1">
79
- {provider.baseProviderId} · {provider.model}
79
+ {provider.protocol} · {provider.model}
80
80
  </div>
81
81
  <div className="text-2xs text-muted-foreground/60 mt-1 truncate font-mono">
82
82
  {provider.baseUrl}
@@ -4,7 +4,7 @@ import { useState, useEffect, useCallback, useSyncExternalStore, useRef } from '
4
4
  import { Copy, Check, RefreshCw, Trash2, Sparkles, ChevronDown, ChevronRight, Loader2, Cpu, Zap, Database as DatabaseIcon, HardDrive, RotateCcw, FlaskConical } from 'lucide-react';
5
5
  import { toast } from '@/lib/toast';
6
6
  import type { KnowledgeTabProps } from './types';
7
- import { Field, Input, EnvBadge, SectionLabel, Toggle, SettingCard, SettingRow } from './Primitives';
7
+ import { Field, Input, EnvBadge, SectionLabel, Toggle, SettingCard, SettingRow, PasswordInput } from './Primitives';
8
8
  import { ConfirmDialog } from '@/components/agents/AgentsPrimitives';
9
9
  import { apiFetch } from '@/lib/api';
10
10
  import { copyToClipboard } from '@/lib/clipboard';
@@ -103,9 +103,6 @@ export function KnowledgeTab({ data, setData, t }: KnowledgeTabProps) {
103
103
  () => 'http://localhost',
104
104
  );
105
105
 
106
- const [showPassword, setShowPassword] = useState(false);
107
- const isPasswordMasked = data.webPassword === '***set***';
108
-
109
106
  const [resetting, setResetting] = useState(false);
110
107
  // revealed holds the plaintext token after regenerate, until user navigates away
111
108
  const [revealedToken, setRevealedToken] = useState<string | null>(null);
@@ -198,22 +195,11 @@ export function KnowledgeTab({ data, setData, t }: KnowledgeTabProps) {
198
195
  title={k.securityTitle ?? 'Security'}
199
196
  >
200
197
  <Field label={k.webPassword} hint={k.webPasswordHint}>
201
- <div className="flex gap-2">
202
- <Input
203
- type={showPassword ? 'text' : 'password'}
204
- value={isPasswordMasked ? '••••••••' : (data.webPassword ?? '')}
205
- onChange={e => setData(d => d ? { ...d, webPassword: e.target.value } : d)}
206
- onFocus={() => { if (isPasswordMasked) setData(d => d ? { ...d, webPassword: '' } : d); }}
207
- placeholder={k.passwordPlaceholder ?? 'Leave empty to disable'}
208
- />
209
- <button
210
- type="button"
211
- onClick={() => setShowPassword(v => !v)}
212
- className="px-3 py-2 text-sm rounded-lg border border-border text-muted-foreground hover:text-foreground hover:bg-muted transition-colors shrink-0"
213
- >
214
- {showPassword ? (k.passwordHide ?? 'Hide') : (k.passwordShow ?? 'Show')}
215
- </button>
216
- </div>
198
+ <PasswordInput
199
+ value={data.webPassword ?? ''}
200
+ onChange={v => setData(d => d ? { ...d, webPassword: v } : d)}
201
+ placeholder={k.passwordPlaceholder ?? 'Leave empty to disable'}
202
+ />
217
203
  </Field>
218
204
 
219
205
  <Field
@@ -6,6 +6,7 @@ import CustomSelect from '@/components/CustomSelect';
6
6
  import { apiFetch } from '@/lib/api';
7
7
  import { copyToClipboard } from '@/lib/clipboard';
8
8
  import { toast } from '@/lib/toast';
9
+ import { PasswordInput } from './Primitives';
9
10
  import type { AgentInfo, McpAgentInstallProps } from './types';
10
11
 
11
12
  /* ── Agent Install ─────────────────────────────────────────────── */
@@ -177,8 +178,12 @@ export default function AgentInstall({ agents, t, onRefresh, mode = 'mcp', activ
177
178
  </div>
178
179
  <div className="space-y-1">
179
180
  <label className="text-muted-foreground">{m?.httpToken ?? 'Auth Token'}</label>
180
- <input type="password" value={httpToken} onChange={e => setHttpToken(e.target.value)} placeholder="Bearer token"
181
- className="w-full px-2.5 py-1.5 text-xs rounded-md border border-border bg-background font-mono text-foreground outline-none focus-visible:ring-1 focus-visible:ring-ring" />
181
+ <PasswordInput
182
+ value={httpToken}
183
+ onChange={setHttpToken}
184
+ placeholder="Bearer token"
185
+ size="sm"
186
+ />
182
187
  </div>
183
188
  </div>
184
189
  )}
@@ -1,18 +1,18 @@
1
1
  'use client';
2
2
 
3
3
  import React, { useState, useRef, useEffect, useCallback, useMemo, useId } from 'react';
4
- import { ChevronDown, Check } from 'lucide-react';
4
+ import { ChevronDown, Check, Eye, EyeOff } from 'lucide-react';
5
5
 
6
6
  export function SectionLabel({ children }: { children: React.ReactNode }) {
7
7
  return <p className="text-xs font-medium text-muted-foreground uppercase tracking-wider mb-3">{children}</p>;
8
8
  }
9
9
 
10
- export function Field({ label, hint, children }: { label: React.ReactNode; hint?: string; children: React.ReactNode }) {
10
+ export function Field({ label, hint, hintError, children }: { label: React.ReactNode; hint?: string; hintError?: boolean; children: React.ReactNode }) {
11
11
  return (
12
12
  <div className="space-y-1.5">
13
13
  <label className="text-sm text-foreground font-medium">{label}</label>
14
14
  {children}
15
- {hint && <p className="text-xs text-muted-foreground">{hint}</p>}
15
+ {hint && <p className={`text-xs ${hintError ? 'text-destructive' : 'text-muted-foreground'}`}>{hint}</p>}
16
16
  </div>
17
17
  );
18
18
  }
@@ -26,6 +26,51 @@ export function Input({ className = '', ...props }: React.InputHTMLAttributes<HT
26
26
  );
27
27
  }
28
28
 
29
+ /**
30
+ * Password/secret input with inline eye toggle.
31
+ * Eye only shows when input has content. Icon sits inside the border.
32
+ */
33
+ export function PasswordInput({ value, onChange, placeholder, disabled, className = '', size = 'md' }: {
34
+ value: string;
35
+ onChange: (v: string) => void;
36
+ placeholder?: string;
37
+ disabled?: boolean;
38
+ className?: string;
39
+ size?: 'sm' | 'md';
40
+ }) {
41
+ const [show, setShow] = useState(false);
42
+ const sm = size === 'sm';
43
+ return (
44
+ <div className={`flex items-center border border-border rounded-lg bg-background focus-within:ring-1 focus-within:ring-ring overflow-hidden ${className}`}>
45
+ <input
46
+ type={show ? 'text' : 'password'}
47
+ value={value}
48
+ onChange={e => onChange(e.target.value)}
49
+ placeholder={placeholder ?? '••••••••'}
50
+ disabled={disabled}
51
+ className={`flex-1 bg-transparent text-foreground placeholder:text-muted-foreground outline-none disabled:opacity-50 ${
52
+ sm ? 'px-2.5 py-1.5 text-xs font-mono' : 'px-3 py-2 text-sm'
53
+ }`}
54
+ />
55
+ {!!value && (
56
+ <button
57
+ type="button"
58
+ tabIndex={-1}
59
+ onMouseDown={e => e.preventDefault()}
60
+ onClick={() => setShow(v => !v)}
61
+ disabled={disabled}
62
+ className={`shrink-0 text-muted-foreground hover:text-foreground transition-colors disabled:opacity-50 ${
63
+ sm ? 'p-1.5' : 'p-2'
64
+ }`}
65
+ title={show ? 'Hide' : 'Show'}
66
+ >
67
+ {show ? <EyeOff size={sm ? 14 : 16} /> : <Eye size={sm ? 14 : 16} />}
68
+ </button>
69
+ )}
70
+ </div>
71
+ );
72
+ }
73
+
29
74
  interface SelectOption { value: string; label: string }
30
75
 
31
76
  export function Select({ value, onChange, children, className = '', disabled }: {
@@ -195,107 +240,6 @@ export function Toggle({ checked, onChange, size = 'md', disabled, title, onClic
195
240
  );
196
241
  }
197
242
 
198
- export function ApiKeyInput({ value, onChange, placeholder, disabled, labels }: {
199
- value: string;
200
- onChange: (v: string) => void;
201
- placeholder?: string;
202
- disabled?: boolean;
203
- labels?: { change?: string; cancel?: string };
204
- }) {
205
- const isMasked = value === '***set***';
206
- const [editing, setEditing] = useState(false);
207
- const [draft, setDraft] = useState('');
208
- const inputRef = useRef<HTMLInputElement>(null);
209
- const prevValueRef = useRef(value);
210
-
211
- // Reset editing when the masked value identity changes (e.g. provider switch)
212
- useEffect(() => {
213
- if (prevValueRef.current !== value) {
214
- prevValueRef.current = value;
215
- setEditing(false);
216
- setDraft('');
217
- }
218
- }, [value]);
219
-
220
- const commitDraft = useCallback(() => {
221
- if (draft.trim()) {
222
- onChange(draft);
223
- }
224
- setEditing(false);
225
- setDraft('');
226
- }, [draft, onChange]);
227
-
228
- const cancelEdit = useCallback(() => {
229
- setEditing(false);
230
- setDraft('');
231
- }, []);
232
-
233
- const changeLabel = labels?.change ?? 'Change';
234
- const cancelLabel = labels?.cancel ?? 'Cancel';
235
-
236
- // Masked state: show dots + "Change" button. No clearing on click.
237
- if (isMasked && !editing) {
238
- return (
239
- <div className="flex items-center gap-2">
240
- <div className="flex-1 px-3 py-2 text-sm bg-muted/50 border border-border rounded-lg text-muted-foreground select-none tracking-widest">
241
- ••••••••••••
242
- </div>
243
- <button
244
- type="button"
245
- onClick={() => {
246
- setDraft('');
247
- setEditing(true);
248
- requestAnimationFrame(() => inputRef.current?.focus());
249
- }}
250
- disabled={disabled}
251
- className="shrink-0 px-3 py-2 text-xs font-medium rounded-lg border border-border text-muted-foreground hover:text-foreground hover:bg-muted transition-colors disabled:opacity-50"
252
- >
253
- {changeLabel}
254
- </button>
255
- </div>
256
- );
257
- }
258
-
259
- // Edit mode (replacing masked key) — uses local draft, commits on Enter/blur
260
- if (editing) {
261
- return (
262
- <div className="flex items-center gap-2">
263
- <input
264
- ref={inputRef}
265
- type="password"
266
- value={draft}
267
- onChange={e => setDraft(e.target.value)}
268
- onKeyDown={e => { if (e.key === 'Enter') commitDraft(); }}
269
- onBlur={commitDraft}
270
- placeholder={placeholder ?? 'sk-...'}
271
- disabled={disabled}
272
- className="flex-1 px-3 py-2 text-sm bg-background border border-border rounded-lg text-foreground placeholder:text-muted-foreground outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:opacity-50"
273
- />
274
- <button
275
- type="button"
276
- onMouseDown={e => e.preventDefault()}
277
- onClick={cancelEdit}
278
- className="shrink-0 px-3 py-2 text-xs font-medium rounded-lg border border-border text-muted-foreground hover:text-foreground hover:bg-muted transition-colors"
279
- >
280
- {cancelLabel}
281
- </button>
282
- </div>
283
- );
284
- }
285
-
286
- // Normal (no masked key) — direct editing
287
- return (
288
- <input
289
- type="password"
290
- value={value}
291
- onChange={e => onChange(e.target.value)}
292
- placeholder={placeholder ?? 'sk-...'}
293
- disabled={disabled}
294
- className="w-full px-3 py-2 text-sm bg-background border border-border rounded-lg text-foreground placeholder:text-muted-foreground outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:opacity-50"
295
- />
296
- );
297
- }
298
-
299
243
  /**
300
244
  * 💡 SUGGESTION #10: Unified primary button primitive for amber actions
301
245
  * Replaces inline `style={{ background: 'var(--amber)', color: 'var(--amber-foreground)' }}` pattern