@larkup/workspace-app 0.0.0-stage → 0.2.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 (440) hide show
  1. package/LICENSE +176 -0
  2. package/README.md +4 -2
  3. package/assets/github.svg +3 -0
  4. package/assets/icons/Confluence.png +0 -0
  5. package/assets/icons/Instagram.png +0 -0
  6. package/assets/icons/Northflank.png +0 -0
  7. package/assets/icons/Salesforce.png +0 -0
  8. package/assets/icons/agentskills.png +0 -0
  9. package/assets/icons/airtable.png +0 -0
  10. package/assets/icons/asana.png +0 -0
  11. package/assets/icons/ashby.png +0 -0
  12. package/assets/icons/audio.png +0 -0
  13. package/assets/icons/aws-kendra.png +0 -0
  14. package/assets/icons/aws.svg +38 -0
  15. package/assets/icons/azure-ai-search.png +0 -0
  16. package/assets/icons/azure.svg +1 -0
  17. package/assets/icons/bigquery.png +0 -0
  18. package/assets/icons/bing.png +0 -0
  19. package/assets/icons/bitbucket.png +0 -0
  20. package/assets/icons/brave.png +0 -0
  21. package/assets/icons/browserbase.png +0 -0
  22. package/assets/icons/calendly.png +0 -0
  23. package/assets/icons/chroma.png +0 -0
  24. package/assets/icons/cloudflare.png +0 -0
  25. package/assets/icons/cohere.svg +30 -0
  26. package/assets/icons/databricks.png +0 -0
  27. package/assets/icons/daytonaio.png +0 -0
  28. package/assets/icons/daytonaio2.png +0 -0
  29. package/assets/icons/deepgram.png +0 -0
  30. package/assets/icons/deepl.png +0 -0
  31. package/assets/icons/digital-ocean.webp +0 -0
  32. package/assets/icons/discord.png +0 -0
  33. package/assets/icons/e2b-2.png +0 -0
  34. package/assets/icons/e2b.png +0 -0
  35. package/assets/icons/elevenlabs.png +0 -0
  36. package/assets/icons/email.png +0 -0
  37. package/assets/icons/exa.png +0 -0
  38. package/assets/icons/excel.png +0 -0
  39. package/assets/icons/fal.png +0 -0
  40. package/assets/icons/firecrawl.png +0 -0
  41. package/assets/icons/firecrawl2.png +0 -0
  42. package/assets/icons/flyio.jpeg +0 -0
  43. package/assets/icons/gcp.svg +1 -0
  44. package/assets/icons/gemini.svg +1 -0
  45. package/assets/icons/gmail.png +0 -0
  46. package/assets/icons/google-analytics.png +0 -0
  47. package/assets/icons/google-calender.png +0 -0
  48. package/assets/icons/google-docs.png +0 -0
  49. package/assets/icons/google-drive.png +0 -0
  50. package/assets/icons/google-maps.png +0 -0
  51. package/assets/icons/google-meet.png +0 -0
  52. package/assets/icons/google-sheets.png +0 -0
  53. package/assets/icons/google-slides.png +0 -0
  54. package/assets/icons/google-tasks.png +0 -0
  55. package/assets/icons/google.png +0 -0
  56. package/assets/icons/grok.png +0 -0
  57. package/assets/icons/hubspot.png +0 -0
  58. package/assets/icons/image.png +0 -0
  59. package/assets/icons/jina.svg +1 -0
  60. package/assets/icons/jira.png +0 -0
  61. package/assets/icons/lancedb2.png +0 -0
  62. package/assets/icons/linear.png +0 -0
  63. package/assets/icons/linux.png +0 -0
  64. package/assets/icons/looker.png +0 -0
  65. package/assets/icons/luma.png +0 -0
  66. package/assets/icons/mac.png +0 -0
  67. package/assets/icons/markdown.png +0 -0
  68. package/assets/icons/mcp.png +0 -0
  69. package/assets/icons/mcp.svg +1 -0
  70. package/assets/icons/messenger.svg +1 -0
  71. package/assets/icons/microsoft-intra.png +0 -0
  72. package/assets/icons/microsoft-onenote.png +0 -0
  73. package/assets/icons/microsoft-planner.png +0 -0
  74. package/assets/icons/microsoft-teams.png +0 -0
  75. package/assets/icons/miro.png +0 -0
  76. package/assets/icons/mistral.svg +469 -0
  77. package/assets/icons/modal.png +0 -0
  78. package/assets/icons/ngrok.png +0 -0
  79. package/assets/icons/nomic.png +0 -0
  80. package/assets/icons/onedrive.png +0 -0
  81. package/assets/icons/openai.svg +1 -0
  82. package/assets/icons/outlook-calendar.png +0 -0
  83. package/assets/icons/outlook-email.png +0 -0
  84. package/assets/icons/outlook.png +0 -0
  85. package/assets/icons/pdf.png +0 -0
  86. package/assets/icons/personio.png +0 -0
  87. package/assets/icons/pgvector2.png +0 -0
  88. package/assets/icons/phone.png +0 -0
  89. package/assets/icons/pinecone.png +0 -0
  90. package/assets/icons/pipedrive.png +0 -0
  91. package/assets/icons/power-pi.png +0 -0
  92. package/assets/icons/pylon.png +0 -0
  93. package/assets/icons/python.png +0 -0
  94. package/assets/icons/qdrant.svg +35 -0
  95. package/assets/icons/revai.png +0 -0
  96. package/assets/icons/revai.svg +1 -0
  97. package/assets/icons/sap.png +0 -0
  98. package/assets/icons/serpapi.svg +34 -0
  99. package/assets/icons/serper.png +0 -0
  100. package/assets/icons/servicenow.png +0 -0
  101. package/assets/icons/sharepoint.png +0 -0
  102. package/assets/icons/slack.png +0 -0
  103. package/assets/icons/snowflake.png +0 -0
  104. package/assets/icons/statistia.png +0 -0
  105. package/assets/icons/stripe.png +0 -0
  106. package/assets/icons/supabase.png +0 -0
  107. package/assets/icons/tableau.png +0 -0
  108. package/assets/icons/tavily.png +0 -0
  109. package/assets/icons/telegram.png +0 -0
  110. package/assets/icons/typescript.png +0 -0
  111. package/assets/icons/vercel copy.svg +1 -0
  112. package/assets/icons/vercel.svg +1 -0
  113. package/assets/icons/vertex-ai.png +0 -0
  114. package/assets/icons/video.png +0 -0
  115. package/assets/icons/voyage-light.png +0 -0
  116. package/assets/icons/weaviate.webp +0 -0
  117. package/assets/icons/webcontainers.svg +11 -0
  118. package/assets/icons/webhook.png +0 -0
  119. package/assets/icons/whatsapp copy.png +0 -0
  120. package/assets/icons/whatsapp.png +0 -0
  121. package/assets/icons/windows.png +0 -0
  122. package/assets/icons/word.png +0 -0
  123. package/assets/icons/zendesk.png +0 -0
  124. package/assets/icons/zoom.png +0 -0
  125. package/assets/notion-white.png +0 -0
  126. package/assets/notion.png +0 -0
  127. package/dist-types/asset-server.d.ts +3 -0
  128. package/dist-types/asset-server.d.ts.map +1 -0
  129. package/dist-types/components/alerts/generic-alert.d.ts +15 -0
  130. package/dist-types/components/alerts/generic-alert.d.ts.map +1 -0
  131. package/dist-types/components/chat/canvas/doc-editor-provider.d.ts +62 -0
  132. package/dist-types/components/chat/canvas/doc-editor-provider.d.ts.map +1 -0
  133. package/dist-types/components/chat/canvas/document-canvas.d.ts +7 -0
  134. package/dist-types/components/chat/canvas/document-canvas.d.ts.map +1 -0
  135. package/dist-types/components/chat/canvas/document-field.d.ts +13 -0
  136. package/dist-types/components/chat/canvas/document-field.d.ts.map +1 -0
  137. package/dist-types/components/chat/canvas/document-viewer.d.ts +2 -0
  138. package/dist-types/components/chat/canvas/document-viewer.d.ts.map +1 -0
  139. package/dist-types/components/chat/canvas/file-attachment-button.d.ts +9 -0
  140. package/dist-types/components/chat/canvas/file-attachment-button.d.ts.map +1 -0
  141. package/dist-types/components/chat/chat-workspace.d.ts +4 -0
  142. package/dist-types/components/chat/chat-workspace.d.ts.map +1 -0
  143. package/dist-types/components/chat/message-actions.d.ts +11 -0
  144. package/dist-types/components/chat/message-actions.d.ts.map +1 -0
  145. package/dist-types/components/chat/message-item.d.ts +20 -0
  146. package/dist-types/components/chat/message-item.d.ts.map +1 -0
  147. package/dist-types/components/chat/message-queue.d.ts +15 -0
  148. package/dist-types/components/chat/message-queue.d.ts.map +1 -0
  149. package/dist-types/components/chat/tools/chat-chart.d.ts +6 -0
  150. package/dist-types/components/chat/tools/chat-chart.d.ts.map +1 -0
  151. package/dist-types/components/chat/tools/chat-citations.d.ts +32 -0
  152. package/dist-types/components/chat/tools/chat-citations.d.ts.map +1 -0
  153. package/dist-types/components/chat/tools/chat-data-table.d.ts +14 -0
  154. package/dist-types/components/chat/tools/chat-data-table.d.ts.map +1 -0
  155. package/dist-types/components/chat/tools/chat-file-export.d.ts +5 -0
  156. package/dist-types/components/chat/tools/chat-file-export.d.ts.map +1 -0
  157. package/dist-types/components/chat/tools/chat-media-preview.d.ts +35 -0
  158. package/dist-types/components/chat/tools/chat-media-preview.d.ts.map +1 -0
  159. package/dist-types/components/chat/tools/chat-sandbox-result.d.ts +17 -0
  160. package/dist-types/components/chat/tools/chat-sandbox-result.d.ts.map +1 -0
  161. package/dist-types/components/chat/tools/chat-signature-request.d.ts +13 -0
  162. package/dist-types/components/chat/tools/chat-signature-request.d.ts.map +1 -0
  163. package/dist-types/components/chat/tools/chat-tabs.d.ts +17 -0
  164. package/dist-types/components/chat/tools/chat-tabs.d.ts.map +1 -0
  165. package/dist-types/components/chat/tools/corpus-data-result.d.ts +36 -0
  166. package/dist-types/components/chat/tools/corpus-data-result.d.ts.map +1 -0
  167. package/dist-types/components/chat/tools/knowledge-base-result.d.ts +14 -0
  168. package/dist-types/components/chat/tools/knowledge-base-result.d.ts.map +1 -0
  169. package/dist-types/components/chat/tools/visual-placement-modal.d.ts +23 -0
  170. package/dist-types/components/chat/tools/visual-placement-modal.d.ts.map +1 -0
  171. package/dist-types/components/configure/custom-model-modal.d.ts +13 -0
  172. package/dist-types/components/configure/custom-model-modal.d.ts.map +1 -0
  173. package/dist-types/components/configure/store-fields.d.ts +11 -0
  174. package/dist-types/components/configure/store-fields.d.ts.map +1 -0
  175. package/dist-types/components/data/corpus-panel.d.ts +12 -0
  176. package/dist-types/components/data/corpus-panel.d.ts.map +1 -0
  177. package/dist-types/components/data/data-entry-mode-switch.d.ts +13 -0
  178. package/dist-types/components/data/data-entry-mode-switch.d.ts.map +1 -0
  179. package/dist-types/components/data/data-primary-action.d.ts +7 -0
  180. package/dist-types/components/data/data-primary-action.d.ts.map +1 -0
  181. package/dist-types/components/data/data-workspace.d.ts +6 -0
  182. package/dist-types/components/data/data-workspace.d.ts.map +1 -0
  183. package/dist-types/components/data/groups-panel.d.ts +5 -0
  184. package/dist-types/components/data/groups-panel.d.ts.map +1 -0
  185. package/dist-types/components/data/integration-resources-panel.d.ts +9 -0
  186. package/dist-types/components/data/integration-resources-panel.d.ts.map +1 -0
  187. package/dist-types/components/data/integrations-panel.d.ts +5 -0
  188. package/dist-types/components/data/integrations-panel.d.ts.map +1 -0
  189. package/dist-types/components/data/jobs-panel.d.ts +6 -0
  190. package/dist-types/components/data/jobs-panel.d.ts.map +1 -0
  191. package/dist-types/components/data/jobs-tracking-button.d.ts +2 -0
  192. package/dist-types/components/data/jobs-tracking-button.d.ts.map +1 -0
  193. package/dist-types/components/data/live-media-progress.d.ts +9 -0
  194. package/dist-types/components/data/live-media-progress.d.ts.map +1 -0
  195. package/dist-types/components/data/media-indexing-jobs-panel.d.ts +34 -0
  196. package/dist-types/components/data/media-indexing-jobs-panel.d.ts.map +1 -0
  197. package/dist-types/components/data/media-panel.d.ts +58 -0
  198. package/dist-types/components/data/media-panel.d.ts.map +1 -0
  199. package/dist-types/components/data/notion-panel.d.ts +6 -0
  200. package/dist-types/components/data/notion-panel.d.ts.map +1 -0
  201. package/dist-types/components/data/paste-panel.d.ts +7 -0
  202. package/dist-types/components/data/paste-panel.d.ts.map +1 -0
  203. package/dist-types/components/data/project-data-page.d.ts +3 -0
  204. package/dist-types/components/data/project-data-page.d.ts.map +1 -0
  205. package/dist-types/components/data/scrape-panel.d.ts +9 -0
  206. package/dist-types/components/data/scrape-panel.d.ts.map +1 -0
  207. package/dist-types/components/data/tabular-preview.d.ts +10 -0
  208. package/dist-types/components/data/tabular-preview.d.ts.map +1 -0
  209. package/dist-types/components/data/tool-indexing-dialog.d.ts +54 -0
  210. package/dist-types/components/data/tool-indexing-dialog.d.ts.map +1 -0
  211. package/dist-types/components/data/upload-panel.d.ts +7 -0
  212. package/dist-types/components/data/upload-panel.d.ts.map +1 -0
  213. package/dist-types/components/data/web-crawler-status.d.ts +3 -0
  214. package/dist-types/components/data/web-crawler-status.d.ts.map +1 -0
  215. package/dist-types/components/projects/project-form-dialog.d.ts +10 -0
  216. package/dist-types/components/projects/project-form-dialog.d.ts.map +1 -0
  217. package/dist-types/components/projects/project-provider.d.ts +34 -0
  218. package/dist-types/components/projects/project-provider.d.ts.map +1 -0
  219. package/dist-types/components/settings/general/agent-customization-section.d.ts +2 -0
  220. package/dist-types/components/settings/general/agent-customization-section.d.ts.map +1 -0
  221. package/dist-types/components/settings/general/mcp-connections-section.d.ts +2 -0
  222. package/dist-types/components/settings/general/mcp-connections-section.d.ts.map +1 -0
  223. package/dist-types/components/settings/general/model-combobox.d.ts +24 -0
  224. package/dist-types/components/settings/general/model-combobox.d.ts.map +1 -0
  225. package/dist-types/components/settings/general/models-section.d.ts +2 -0
  226. package/dist-types/components/settings/general/models-section.d.ts.map +1 -0
  227. package/dist-types/components/settings/general/sandbox-section.d.ts +7 -0
  228. package/dist-types/components/settings/general/sandbox-section.d.ts.map +1 -0
  229. package/dist-types/components/settings/general/search-scraping-section.d.ts +2 -0
  230. package/dist-types/components/settings/general/search-scraping-section.d.ts.map +1 -0
  231. package/dist-types/components/settings/general/storage-indexing-section.d.ts +2 -0
  232. package/dist-types/components/settings/general/storage-indexing-section.d.ts.map +1 -0
  233. package/dist-types/components/ui/alert-dialog.d.ts +19 -0
  234. package/dist-types/components/ui/alert-dialog.d.ts.map +1 -0
  235. package/dist-types/components/ui/alert.d.ts +11 -0
  236. package/dist-types/components/ui/alert.d.ts.map +1 -0
  237. package/dist-types/components/ui/badge.d.ts +8 -0
  238. package/dist-types/components/ui/badge.d.ts.map +1 -0
  239. package/dist-types/components/ui/card.d.ts +2 -0
  240. package/dist-types/components/ui/card.d.ts.map +1 -0
  241. package/dist-types/components/ui/checkbox.d.ts +4 -0
  242. package/dist-types/components/ui/checkbox.d.ts.map +1 -0
  243. package/dist-types/components/ui/collapsible.d.ts +6 -0
  244. package/dist-types/components/ui/collapsible.d.ts.map +1 -0
  245. package/dist-types/components/ui/command.d.ts +20 -0
  246. package/dist-types/components/ui/command.d.ts.map +1 -0
  247. package/dist-types/components/ui/dialog.d.ts +18 -0
  248. package/dist-types/components/ui/dialog.d.ts.map +1 -0
  249. package/dist-types/components/ui/dropdown-menu.d.ts +30 -0
  250. package/dist-types/components/ui/dropdown-menu.d.ts.map +1 -0
  251. package/dist-types/components/ui/input-group.d.ts +19 -0
  252. package/dist-types/components/ui/input-group.d.ts.map +1 -0
  253. package/dist-types/components/ui/input.d.ts +4 -0
  254. package/dist-types/components/ui/input.d.ts.map +1 -0
  255. package/dist-types/components/ui/line-tabs.d.ts +15 -0
  256. package/dist-types/components/ui/line-tabs.d.ts.map +1 -0
  257. package/dist-types/components/ui/popover.d.ts +10 -0
  258. package/dist-types/components/ui/popover.d.ts.map +1 -0
  259. package/dist-types/components/ui/progress.d.ts +8 -0
  260. package/dist-types/components/ui/progress.d.ts.map +1 -0
  261. package/dist-types/components/ui/scroll-area.d.ts +6 -0
  262. package/dist-types/components/ui/scroll-area.d.ts.map +1 -0
  263. package/dist-types/components/ui/sheet.d.ts +15 -0
  264. package/dist-types/components/ui/sheet.d.ts.map +1 -0
  265. package/dist-types/components/ui/slider.d.ts +4 -0
  266. package/dist-types/components/ui/slider.d.ts.map +1 -0
  267. package/dist-types/components/ui/switch.d.ts +6 -0
  268. package/dist-types/components/ui/switch.d.ts.map +1 -0
  269. package/dist-types/components/ui/table.d.ts +2 -0
  270. package/dist-types/components/ui/table.d.ts.map +1 -0
  271. package/dist-types/components/ui/tabs.d.ts +11 -0
  272. package/dist-types/components/ui/tabs.d.ts.map +1 -0
  273. package/dist-types/components/ui/textarea.d.ts +2 -0
  274. package/dist-types/components/ui/textarea.d.ts.map +1 -0
  275. package/dist-types/components/ui/tooltip.d.ts +7 -0
  276. package/dist-types/components/ui/tooltip.d.ts.map +1 -0
  277. package/dist-types/hooks/use-copy-to-clipboard.d.ts +5 -0
  278. package/dist-types/hooks/use-copy-to-clipboard.d.ts.map +1 -0
  279. package/dist-types/hooks/use-integration-auth.d.ts +10 -0
  280. package/dist-types/hooks/use-integration-auth.d.ts.map +1 -0
  281. package/dist-types/hooks/use-live-media-progress.d.ts +14 -0
  282. package/dist-types/hooks/use-live-media-progress.d.ts.map +1 -0
  283. package/dist-types/hooks/use-notion-auth.d.ts +9 -0
  284. package/dist-types/hooks/use-notion-auth.d.ts.map +1 -0
  285. package/dist-types/host.d.ts +20 -0
  286. package/dist-types/host.d.ts.map +1 -0
  287. package/dist-types/lib/browser-cache.d.ts +7 -0
  288. package/dist-types/lib/browser-cache.d.ts.map +1 -0
  289. package/dist-types/lib/chat/chart-config.d.ts +2 -0
  290. package/dist-types/lib/chat/chart-config.d.ts.map +1 -0
  291. package/dist-types/lib/chat/data-export.d.ts +2 -0
  292. package/dist-types/lib/chat/data-export.d.ts.map +1 -0
  293. package/dist-types/lib/chat/live-tool-progress.d.ts +44 -0
  294. package/dist-types/lib/chat/live-tool-progress.d.ts.map +1 -0
  295. package/dist-types/lib/chat/message-feedback.d.ts +2 -0
  296. package/dist-types/lib/chat/message-feedback.d.ts.map +1 -0
  297. package/dist-types/lib/chat/table-presentation.d.ts +2 -0
  298. package/dist-types/lib/chat/table-presentation.d.ts.map +1 -0
  299. package/dist-types/lib/chat/tool-output.d.ts +3 -0
  300. package/dist-types/lib/chat/tool-output.d.ts.map +1 -0
  301. package/dist-types/lib/chat-supporting-clip.d.ts +11 -0
  302. package/dist-types/lib/chat-supporting-clip.d.ts.map +1 -0
  303. package/dist-types/lib/constants/stores.d.ts +6 -0
  304. package/dist-types/lib/constants/stores.d.ts.map +1 -0
  305. package/dist-types/lib/constants/tools.d.ts +27 -0
  306. package/dist-types/lib/constants/tools.d.ts.map +1 -0
  307. package/dist-types/lib/error-formatter.d.ts +2 -0
  308. package/dist-types/lib/error-formatter.d.ts.map +1 -0
  309. package/dist-types/lib/jobs-client.d.ts +7 -0
  310. package/dist-types/lib/jobs-client.d.ts.map +1 -0
  311. package/dist-types/lib/media/pdf.d.ts +6 -0
  312. package/dist-types/lib/media/pdf.d.ts.map +1 -0
  313. package/dist-types/lib/media/progress.d.ts +61 -0
  314. package/dist-types/lib/media/progress.d.ts.map +1 -0
  315. package/dist-types/lib/media/source-selection.d.ts +10 -0
  316. package/dist-types/lib/media/source-selection.d.ts.map +1 -0
  317. package/dist-types/lib/media/tool-indexing-estimate.d.ts +13 -0
  318. package/dist-types/lib/media/tool-indexing-estimate.d.ts.map +1 -0
  319. package/dist-types/lib/media/video-intelligence-capacity.d.ts +2 -0
  320. package/dist-types/lib/media/video-intelligence-capacity.d.ts.map +1 -0
  321. package/dist-types/lib/media/video-runtime-scope.d.ts +2 -0
  322. package/dist-types/lib/media/video-runtime-scope.d.ts.map +1 -0
  323. package/dist-types/lib/shared/error-formatter.d.ts +2 -0
  324. package/dist-types/lib/shared/error-formatter.d.ts.map +1 -0
  325. package/dist-types/lib/utils.d.ts +3 -0
  326. package/dist-types/lib/utils.d.ts.map +1 -0
  327. package/dist-types/storage.d.ts +5 -0
  328. package/dist-types/storage.d.ts.map +1 -0
  329. package/dist-types/store/chat-store.d.ts +19 -0
  330. package/dist-types/store/chat-store.d.ts.map +1 -0
  331. package/dist-types/store/scrape-store.d.ts +42 -0
  332. package/dist-types/store/scrape-store.d.ts.map +1 -0
  333. package/package.json +579 -3
  334. package/scripts/build-assets.mjs +12 -0
  335. package/src/asset-data.json +1 -0
  336. package/src/asset-server.ts +19 -0
  337. package/src/components/alerts/generic-alert.tsx +76 -0
  338. package/src/components/chat/canvas/doc-editor-provider.tsx +338 -0
  339. package/src/components/chat/canvas/document-canvas.tsx +98 -0
  340. package/src/components/chat/canvas/document-field.tsx +167 -0
  341. package/src/components/chat/canvas/document-viewer.tsx +446 -0
  342. package/src/components/chat/canvas/file-attachment-button.tsx +88 -0
  343. package/src/components/chat/chat-workspace.tsx +1552 -0
  344. package/src/components/chat/message-actions.tsx +96 -0
  345. package/src/components/chat/message-item.tsx +1398 -0
  346. package/src/components/chat/message-queue.tsx +86 -0
  347. package/src/components/chat/tools/chat-chart.tsx +558 -0
  348. package/src/components/chat/tools/chat-citations.tsx +152 -0
  349. package/src/components/chat/tools/chat-data-table.tsx +373 -0
  350. package/src/components/chat/tools/chat-file-export.tsx +49 -0
  351. package/src/components/chat/tools/chat-media-preview.tsx +466 -0
  352. package/src/components/chat/tools/chat-sandbox-result.tsx +130 -0
  353. package/src/components/chat/tools/chat-signature-request.tsx +810 -0
  354. package/src/components/chat/tools/chat-tabs.tsx +59 -0
  355. package/src/components/chat/tools/corpus-data-result.tsx +194 -0
  356. package/src/components/chat/tools/knowledge-base-result.tsx +345 -0
  357. package/src/components/chat/tools/visual-placement-modal.tsx +308 -0
  358. package/src/components/configure/custom-model-modal.tsx +209 -0
  359. package/src/components/configure/store-fields.tsx +129 -0
  360. package/src/components/data/corpus-panel.tsx +1223 -0
  361. package/src/components/data/data-entry-mode-switch.tsx +53 -0
  362. package/src/components/data/data-primary-action.ts +6 -0
  363. package/src/components/data/data-workspace.tsx +623 -0
  364. package/src/components/data/groups-panel.tsx +530 -0
  365. package/src/components/data/integration-resources-panel.tsx +282 -0
  366. package/src/components/data/integrations-panel.tsx +392 -0
  367. package/src/components/data/jobs-panel.tsx +490 -0
  368. package/src/components/data/jobs-tracking-button.tsx +224 -0
  369. package/src/components/data/live-media-progress.tsx +79 -0
  370. package/src/components/data/media-indexing-jobs-panel.tsx +190 -0
  371. package/src/components/data/media-panel.tsx +2905 -0
  372. package/src/components/data/notion-panel.tsx +408 -0
  373. package/src/components/data/paste-panel.tsx +82 -0
  374. package/src/components/data/project-data-page.tsx +55 -0
  375. package/src/components/data/scrape-panel.tsx +1290 -0
  376. package/src/components/data/tabular-preview.tsx +205 -0
  377. package/src/components/data/tool-indexing-dialog.tsx +210 -0
  378. package/src/components/data/upload-panel.tsx +1313 -0
  379. package/src/components/data/web-crawler-status.tsx +132 -0
  380. package/src/components/projects/project-form-dialog.tsx +97 -0
  381. package/src/components/projects/project-provider.tsx +143 -0
  382. package/src/components/settings/general/agent-customization-section.tsx +620 -0
  383. package/src/components/settings/general/mcp-connections-section.tsx +907 -0
  384. package/src/components/settings/general/model-combobox.tsx +235 -0
  385. package/src/components/settings/general/models-section.tsx +909 -0
  386. package/src/components/settings/general/sandbox-section.tsx +394 -0
  387. package/src/components/settings/general/search-scraping-section.tsx +757 -0
  388. package/src/components/settings/general/storage-indexing-section.tsx +394 -0
  389. package/src/components/ui/alert-dialog.tsx +162 -0
  390. package/src/components/ui/alert.tsx +69 -0
  391. package/src/components/ui/badge.tsx +49 -0
  392. package/src/components/ui/card.tsx +9 -0
  393. package/src/components/ui/checkbox.tsx +28 -0
  394. package/src/components/ui/collapsible.tsx +17 -0
  395. package/src/components/ui/command.tsx +175 -0
  396. package/src/components/ui/dialog.tsx +138 -0
  397. package/src/components/ui/dropdown-menu.tsx +267 -0
  398. package/src/components/ui/input-group.tsx +146 -0
  399. package/src/components/ui/input.tsx +19 -0
  400. package/src/components/ui/line-tabs.tsx +49 -0
  401. package/src/components/ui/popover.tsx +77 -0
  402. package/src/components/ui/progress.tsx +66 -0
  403. package/src/components/ui/scroll-area.tsx +51 -0
  404. package/src/components/ui/sheet.tsx +125 -0
  405. package/src/components/ui/slider.tsx +52 -0
  406. package/src/components/ui/switch.tsx +32 -0
  407. package/src/components/ui/table.tsx +10 -0
  408. package/src/components/ui/tabs.tsx +77 -0
  409. package/src/components/ui/textarea.tsx +1 -0
  410. package/src/components/ui/tooltip.tsx +54 -0
  411. package/src/hooks/use-copy-to-clipboard.ts +25 -0
  412. package/src/hooks/use-integration-auth.ts +39 -0
  413. package/src/hooks/use-live-media-progress.ts +71 -0
  414. package/src/hooks/use-notion-auth.ts +66 -0
  415. package/src/host.ts +55 -0
  416. package/src/lib/browser-cache.ts +17 -0
  417. package/src/lib/chat/chart-config.ts +1 -0
  418. package/src/lib/chat/data-export.ts +1 -0
  419. package/src/lib/chat/live-tool-progress.ts +69 -0
  420. package/src/lib/chat/message-feedback.ts +1 -0
  421. package/src/lib/chat/table-presentation.ts +1 -0
  422. package/src/lib/chat/tool-output.ts +14 -0
  423. package/src/lib/chat-supporting-clip.ts +16 -0
  424. package/src/lib/constants/stores.ts +12 -0
  425. package/src/lib/constants/tools.ts +178 -0
  426. package/src/lib/error-formatter.ts +30 -0
  427. package/src/lib/jobs-client.ts +27 -0
  428. package/src/lib/media/pdf.ts +57 -0
  429. package/src/lib/media/progress.ts +209 -0
  430. package/src/lib/media/source-selection.ts +47 -0
  431. package/src/lib/media/tool-indexing-estimate.ts +39 -0
  432. package/src/lib/media/video-intelligence-capacity.ts +1 -0
  433. package/src/lib/media/video-runtime-scope.ts +1 -0
  434. package/src/lib/shared/error-formatter.ts +1 -0
  435. package/src/lib/utils.ts +6 -0
  436. package/src/source.css +1 -0
  437. package/src/storage.ts +16 -0
  438. package/src/store/chat-store.ts +19 -0
  439. package/src/store/scrape-store.ts +76 -0
  440. package/src/styles.d.ts +1 -0
@@ -0,0 +1,620 @@
1
+ 'use client';
2
+
3
+ import { workspaceUrl, workspaceFetch as fetch } from '../../../host';
4
+ import { useEffect, useMemo, useRef, useState } from 'react';
5
+ import useSWR from 'swr';
6
+ import {
7
+ FileText,
8
+ Link,
9
+ Loader2,
10
+ Maximize,
11
+ Plus,
12
+ Puzzle,
13
+ Save,
14
+ Search,
15
+ Trash2,
16
+ Upload,
17
+ Wrench,
18
+ AlertCircle,
19
+ Terminal,
20
+ Laptop,
21
+ } from 'lucide-react';
22
+ import { toast } from 'sonner';
23
+ import type { AgentSkill, RagConfig } from '@larkup/core/types';
24
+ import { cn } from '@larkup/workspace-app/lib/utils';
25
+ import { Button } from '@larkup/workspace-ui/button';
26
+ import {
27
+ Dialog,
28
+ DialogClose,
29
+ DialogContent,
30
+ DialogDescription,
31
+ DialogFooter,
32
+ DialogHeader,
33
+ DialogTitle,
34
+ DialogTrigger,
35
+ } from '@larkup/workspace-app/components/ui/dialog';
36
+ import { Input } from '@larkup/workspace-app/components/ui/input';
37
+ import { Switch } from '@larkup/workspace-app/components/ui/switch';
38
+ import { Textarea } from '@larkup/workspace-app/components/ui/textarea';
39
+ import { Tabs, TabsContent } from '@larkup/workspace-app/components/ui/tabs';
40
+ import { McpConnectionsSection } from '@larkup/workspace-app/components/settings/general/mcp-connections-section';
41
+ import { SandboxSection } from '@larkup/workspace-app/components/settings/general/sandbox-section';
42
+ import { LineTabs } from '@larkup/workspace-app/components/ui/line-tabs';
43
+
44
+ import { BUILT_IN_TOOLS, type Tool } from '@larkup/workspace-app/lib/constants/tools';
45
+
46
+ type MarketplaceTool = {
47
+ id: string;
48
+ name: string;
49
+ description: string;
50
+ status: 'available' | 'installed';
51
+ icon?: string;
52
+ packageName?: string;
53
+ version?: string;
54
+ };
55
+ const fetcher = (url: string) => fetch(url).then((response) => response.json());
56
+
57
+ function frontmatterValue(content: string, key: string) {
58
+ const match = content.match(new RegExp(`^${key}:\\s*[\"']?([^\\n\"']+)[\"']?\\s*$`, 'm'));
59
+ return match?.[1]?.trim();
60
+ }
61
+
62
+ function SkillDialog({
63
+ open,
64
+ onOpenChange,
65
+ onAdd,
66
+ }: {
67
+ open: boolean;
68
+ onOpenChange: (open: boolean) => void;
69
+ onAdd: (skill: AgentSkill) => void;
70
+ }) {
71
+ const [source, setSource] = useState<'inline' | 'remote'>('inline');
72
+ const [content, setContent] = useState('');
73
+ const [url, setUrl] = useState('');
74
+ const [name, setName] = useState('');
75
+ const fileInput = useRef<HTMLInputElement>(null);
76
+
77
+ function add() {
78
+ if (source === 'inline' && !content.trim())
79
+ return toast.error('Paste or upload a SKILL.md file first.');
80
+ if (source === 'remote') {
81
+ try {
82
+ new URL(url);
83
+ } catch {
84
+ return toast.error('Enter a valid SKILL.md URL.');
85
+ }
86
+ }
87
+ const inferredName = source === 'inline' ? frontmatterValue(content, 'name') : '';
88
+ const inferredDescription = source === 'inline' ? frontmatterValue(content, 'description') : '';
89
+ const skillName =
90
+ name.trim() ||
91
+ inferredName ||
92
+ (source === 'remote' ? new URL(url).hostname : 'Untitled skill');
93
+ onAdd({
94
+ id: crypto.randomUUID(),
95
+ name: skillName,
96
+ description: inferredDescription || 'Custom agent workflow.',
97
+ source,
98
+ enabled: true,
99
+ ...(source === 'inline' ? { content } : { url }),
100
+ updatedAt: new Date().toISOString(),
101
+ });
102
+ setContent('');
103
+ setUrl('');
104
+ setName('');
105
+ }
106
+
107
+ return (
108
+ <Dialog open={open} onOpenChange={onOpenChange}>
109
+ <DialogContent className="max-h-[calc(100dvh-2rem)] w-full max-w-3xl! overflow-hidden flex flex-col">
110
+ <DialogHeader>
111
+ <DialogTitle>Add an Agent Skill</DialogTitle>
112
+ <DialogDescription>
113
+ Skills use the open `SKILL.md` format: metadata plus task instructions and optional
114
+ resources.
115
+ </DialogDescription>
116
+ </DialogHeader>
117
+
118
+ <div className="grid gap-4 py-2 max-h-[60vh] overflow-y-auto pr-1">
119
+ <div className="space-y-2">
120
+ <label className="text-sm font-medium">Skill name</label>
121
+ <Input
122
+ aria-label="Skill name"
123
+ value={name}
124
+ onChange={(event) => setName(event.target.value)}
125
+ placeholder="Name (read from metadata if blank)"
126
+ />
127
+ </div>
128
+
129
+ <Tabs value={source} onValueChange={(value) => setSource(value as 'inline' | 'remote')}>
130
+ <div className="flex items-center gap-1 mb-4 border-b border-border">
131
+ {(['inline', 'remote'] as const).map((tab) => {
132
+ const isActive = source === tab;
133
+ const label = tab === 'inline' ? 'Local' : 'Remote';
134
+ const Icon = tab === 'inline' ? FileText : Link;
135
+ return (
136
+ <button
137
+ key={tab}
138
+ type="button"
139
+ onClick={() => setSource(tab)}
140
+ className={cn(
141
+ 'relative flex items-center gap-2 px-4 py-2.5 text-sm font-medium transition-colors outline-none',
142
+ isActive ? 'text-foreground' : 'text-muted-foreground hover:text-foreground',
143
+ )}
144
+ >
145
+ <Icon className="size-4" />
146
+ {label}
147
+ {isActive && (
148
+ <span
149
+ aria-hidden="true"
150
+ className="absolute bottom-0 left-0 right-0 h-0.5 rounded-full bg-primary motion-safe:animate-in motion-safe:fade-in motion-safe:slide-in-from-left-2 motion-safe:duration-200"
151
+ />
152
+ )}
153
+ </button>
154
+ );
155
+ })}
156
+ </div>
157
+
158
+ <TabsContent value="inline" className="space-y-3 pt-0">
159
+ <input
160
+ ref={fileInput}
161
+ type="file"
162
+ accept=".md,text/markdown"
163
+ className="hidden"
164
+ onChange={async (event) => {
165
+ const file = event.target.files?.[0];
166
+ if (file) setContent(await file.text());
167
+ event.currentTarget.value = '';
168
+ }}
169
+ />
170
+ <div className="flex items-center justify-between gap-3">
171
+ <p className="text-xs text-muted-foreground leading-relaxed">
172
+ Upload a portable SKILL.md or paste its full contents below.
173
+ </p>
174
+ <Button
175
+ variant="outline"
176
+ size="sm"
177
+ onClick={() => fileInput.current?.click()}
178
+ className="shrink-0 gap-1.5"
179
+ >
180
+ <Upload className="size-3.5" />
181
+ Upload
182
+ </Button>
183
+ </div>
184
+ <Textarea
185
+ value={content}
186
+ onChange={(event) => setContent(event.target.value)}
187
+ placeholder={
188
+ '---\nname: release-checklist\ndescription: Safely prepare a production release.\n---\n\n# Instructions\n...'
189
+ }
190
+ className="min-h-40 resize-none font-mono text-xs"
191
+ />
192
+ </TabsContent>
193
+
194
+ <TabsContent value="remote" className="space-y-3 pt-0">
195
+ <p className="text-xs text-muted-foreground leading-relaxed">
196
+ Keep a canonical remote `SKILL.md` reference so a deployed agent can resolve the
197
+ same versioned workflow.
198
+ </p>
199
+ <Input
200
+ aria-label="Remote SKILL.md URL"
201
+ value={url}
202
+ onChange={(event) => setUrl(event.target.value)}
203
+ placeholder="https://example.com/skills/release/SKILL.md"
204
+ />
205
+ </TabsContent>
206
+ </Tabs>
207
+ </div>
208
+
209
+ <DialogFooter className="mt-2">
210
+ <Button variant="outline" onClick={() => onOpenChange(false)}>
211
+ Cancel
212
+ </Button>
213
+ <Button onClick={add}>Add skill</Button>
214
+ </DialogFooter>
215
+ </DialogContent>
216
+ </Dialog>
217
+ );
218
+ }
219
+
220
+ export function AgentCustomizationSection() {
221
+ const { data: configData, mutate: mutateConfig } = useSWR<{ config: RagConfig }>(
222
+ workspaceUrl('/api/config'),
223
+ fetcher,
224
+ );
225
+ const { data: marketplaceData } = useSWR<{ tools: MarketplaceTool[] }>(
226
+ workspaceUrl('/api/marketplace'),
227
+ fetcher,
228
+ );
229
+ const { data: runtimeData } = useSWR<{ runtime?: { running?: boolean; endpoint?: string } }>(
230
+ workspaceUrl('/api/projects/runtime'),
231
+ fetcher,
232
+ );
233
+ const [prompt, setPrompt] = useState('');
234
+ const [enabledTools, setEnabledTools] = useState<string[]>([]);
235
+ const [skills, setSkills] = useState<AgentSkill[]>([]);
236
+ const [skillSearch, setSkillSearch] = useState('');
237
+ const [skillDialogOpen, setSkillDialogOpen] = useState(false);
238
+ const [activeTab, setActiveTab] = useState('prompt');
239
+ const [saving, setSaving] = useState(false);
240
+
241
+ useEffect(() => {
242
+ if (configData?.config) {
243
+ setPrompt(configData.config.systemPrompt ?? '');
244
+ setEnabledTools(configData.config.enabledTools ?? []);
245
+ setSkills(configData.config.skills ?? []);
246
+ }
247
+ }, [configData]);
248
+ const plugins = useMemo<Tool[]>(
249
+ () =>
250
+ (marketplaceData?.tools ?? [])
251
+ .filter((tool) => tool.status === 'installed')
252
+ .map((tool) => ({ ...tool, icon: Puzzle, plugin: true })),
253
+ [marketplaceData],
254
+ );
255
+ const allTools = useMemo(() => [...BUILT_IN_TOOLS, ...plugins], [plugins]);
256
+ const isEnabled = (id: string) => enabledTools.length === 0 || enabledTools.includes(id);
257
+ async function save(patch: Partial<RagConfig>, message: string) {
258
+ if (!configData?.config) return;
259
+ setSaving(true);
260
+ try {
261
+ const selectedTools = patch.enabledTools ?? enabledTools;
262
+ const installedPlugins = (marketplaceData?.tools ?? [])
263
+ .filter(
264
+ (tool) =>
265
+ tool.status === 'installed' &&
266
+ tool.packageName &&
267
+ (selectedTools.length === 0 || selectedTools.includes(tool.id)),
268
+ )
269
+ .map((tool) => ({
270
+ id: tool.id,
271
+ name: tool.name,
272
+ packageName: tool.packageName!,
273
+ version: tool.version,
274
+ }));
275
+ const response = await fetch(workspaceUrl('/api/config'), {
276
+ method: 'PUT',
277
+ headers: { 'Content-Type': 'application/json' },
278
+ body: JSON.stringify({
279
+ ...configData.config,
280
+ ...patch,
281
+ agentPlugins: marketplaceData ? installedPlugins : configData.config.agentPlugins,
282
+ }),
283
+ });
284
+ const data = await response.json();
285
+ if (!response.ok) throw new Error(data.error ?? 'Could not save Assistant settings.');
286
+ await mutateConfig(data, { revalidate: false });
287
+ toast.success(
288
+ runtimeData?.runtime?.running
289
+ ? `${message} Restart the running Agent to apply it.`
290
+ : message,
291
+ );
292
+ } catch (error) {
293
+ toast.error(error instanceof Error ? error.message : 'Could not save Assistant settings.');
294
+ } finally {
295
+ setSaving(false);
296
+ }
297
+ }
298
+ function toggleTool(id: string, checked: boolean) {
299
+ const allIds = allTools.map((tool) => tool.id);
300
+ const known = enabledTools.length === 0 ? allIds : enabledTools;
301
+ const next = checked ? [...new Set([...known, id])] : known.filter((toolId) => toolId !== id);
302
+ setEnabledTools(next);
303
+ void save({ enabledTools: next }, `${checked ? 'Enabled' : 'Disabled'} tool.`);
304
+ }
305
+
306
+ const filteredSkills = skills.filter(
307
+ (s) =>
308
+ !skillSearch.trim() ||
309
+ s.name.toLowerCase().includes(skillSearch.trim().toLowerCase()) ||
310
+ s.description.toLowerCase().includes(skillSearch.trim().toLowerCase()),
311
+ );
312
+
313
+ function toggleSkill(id: string, enabled: boolean) {
314
+ const next = skills.map((skill) => (skill.id === id ? { ...skill, enabled } : skill));
315
+ setSkills(next);
316
+ void save({ skills: next }, `${enabled ? 'Enabled' : 'Disabled'} skill.`);
317
+ }
318
+
319
+ if (!configData)
320
+ return (
321
+ <div className="flex h-40 items-center justify-center">
322
+ <Loader2 className="size-5 animate-spin text-muted-foreground" />
323
+ </div>
324
+ );
325
+ const ToolGrid = ({ title, tools, empty }: { title: string; tools: Tool[]; empty?: string }) => (
326
+ <div className="space-y-3">
327
+ <div className="flex items-center gap-2">
328
+ <Wrench className="size-4 text-muted-foreground" />
329
+ <h2 className="text-sm font-medium">{title}</h2>
330
+ </div>
331
+ {tools.length === 0 ? (
332
+ <p className="rounded-lg border border-dashed p-5 text-sm text-muted-foreground">{empty}</p>
333
+ ) : (
334
+ <div className="grid gap-3 sm:grid-cols-2">
335
+ {tools.map((tool) => {
336
+ const Icon = tool.icon;
337
+ return (
338
+ <div
339
+ key={tool.id}
340
+ className="flex min-h-22 items-center gap-3 rounded-xl border bg-white/70 px-4 py-4 dark:bg-card/70"
341
+ >
342
+ <div className="flex size-10 shrink-0 items-center justify-center rounded-lg border bg-muted/40">
343
+ <Icon className="size-4.5" />
344
+ </div>
345
+ <div className="min-w-0 flex-1">
346
+ <p className="text-sm font-medium">
347
+ {tool.name}
348
+ {tool.plugin && (
349
+ <span className="ml-2 rounded-md bg-muted px-1.5 py-0.5 text-[10px] font-normal text-muted-foreground">
350
+ Plugin
351
+ </span>
352
+ )}
353
+ </p>
354
+ <p className="mt-0.5 line-clamp-1 text-xs text-muted-foreground">
355
+ {tool.description}
356
+ </p>
357
+ </div>
358
+ <Switch
359
+ checked={isEnabled(tool.id)}
360
+ disabled={saving}
361
+ aria-label={`Toggle ${tool.name}`}
362
+ onCheckedChange={(checked) => toggleTool(tool.id, checked)}
363
+ />
364
+ </div>
365
+ );
366
+ })}
367
+ </div>
368
+ )}
369
+ </div>
370
+ );
371
+
372
+ return (
373
+ <section className="space-y-5">
374
+ <div>
375
+ <h1 className="text-xl font-semibold tracking-tight">Agent Customization</h1>
376
+ <p className="mt-1 text-sm text-muted-foreground">
377
+ Set the instructions and local capabilities available to this Project’s Agent.
378
+ </p>
379
+ </div>
380
+ {/* {runtimeData?.runtime?.running && (
381
+ <div className="flex items-center justify-between gap-3 rounded-lg border border-amber-500/25 bg-amber-500/5 px-3 py-2 text-xs text-muted-foreground">
382
+ <span>Configuration changes are saved. Restart the local Agent to regenerate its prompt, skills, tools, and sandbox settings.</span>
383
+ {runtimeData.runtime.endpoint && <code className="shrink-0 text-foreground">{runtimeData.runtime.endpoint}</code>}
384
+ </div>
385
+ )} */}
386
+ <LineTabs
387
+ activeTab={activeTab}
388
+ onTabChange={setActiveTab}
389
+ tabs={[
390
+ { id: 'prompt', label: 'Prompt', icon: Terminal },
391
+ { id: 'tools', label: 'Tools', icon: Wrench },
392
+ {
393
+ id: 'skills',
394
+ label: 'Skills',
395
+ icon: (props) => <img src="/icons/agentskills.png" alt="" {...props} />,
396
+ },
397
+ {
398
+ id: 'mcp',
399
+ label: 'MCP',
400
+ icon: (props) => <img src="/icons/mcp.svg" alt="" {...props} />,
401
+ },
402
+ { id: 'sandbox', label: 'Sandbox', icon: Laptop },
403
+ ]}
404
+ className="mb-6 pb-0"
405
+ />
406
+
407
+ {activeTab === 'prompt' && (
408
+ <div className="pt-2 animate-in fade-in-0 duration-200">
409
+ <div className="rounded-xl border bg-white/70 p-5 dark:bg-card/70">
410
+ <label htmlFor="assistant-system-prompt" className="text-sm font-medium">
411
+ System prompt
412
+ </label>
413
+ <p className="mt-1 text-xs text-muted-foreground">
414
+ Larkup combines these instructions with its retrieval and tool safety rules.
415
+ </p>
416
+ <div className="relative mt-4">
417
+ <Textarea
418
+ id="assistant-system-prompt"
419
+ value={prompt}
420
+ onChange={(event) => setPrompt(event.target.value)}
421
+ placeholder="You are a helpful research assistant..."
422
+ className="min-h-52 max-h-60 resize-none pb-10 font-mono text-sm"
423
+ />
424
+ <Dialog>
425
+ <DialogTrigger
426
+ render={
427
+ <button
428
+ type="button"
429
+ aria-label="Expand system prompt"
430
+ className="absolute bottom-2 right-2 rounded-md p-1.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground"
431
+ >
432
+ <Maximize className="size-4" />
433
+ </button>
434
+ }
435
+ />
436
+ <DialogContent className="max-w-[90vw] sm:max-w-4xl w-[90vw] h-[90vh] sm:max-h-200 flex flex-col">
437
+ <DialogHeader className="shrink-0 space-y-0 p-3 pb-0">
438
+ <div className="flex items-center gap-2">
439
+ <DialogTitle className="text-lg font-semibold">
440
+ Edit system prompt
441
+ </DialogTitle>
442
+ <FileText className="size-4 text-muted-foreground" />
443
+ </div>
444
+ <DialogDescription>
445
+ Edit the complete prompt without resizing the settings page.
446
+ </DialogDescription>
447
+ </DialogHeader>
448
+ <div className="flex-1 min-h-0 mt-2 relative">
449
+ <Textarea
450
+ value={prompt}
451
+ onChange={(event) => setPrompt(event.target.value)}
452
+ placeholder="You are a helpful research assistant..."
453
+ className="h-full w-full rounded-lg border border-border/40 bg-background px-4 py-3 text-sm text-foreground outline-none transition focus:border-border resize-none [&::-webkit-scrollbar]:w-2 [&::-webkit-scrollbar-thumb]:bg-muted-foreground/20 hover:[&::-webkit-scrollbar-thumb]:bg-muted-foreground/40 [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-track]:bg-transparent font-mono"
454
+ />
455
+ </div>
456
+ <DialogFooter className="mt-6 justify-end flex items-center gap-2 shrink-0">
457
+ <DialogClose render={<Button variant="outline" className="px-3" />}>
458
+ Done
459
+ </DialogClose>
460
+ </DialogFooter>
461
+ </DialogContent>
462
+ </Dialog>
463
+ </div>
464
+ <div className="mt-4 flex justify-end">
465
+ <Button
466
+ onClick={() => void save({ systemPrompt: prompt }, 'Agent prompt saved.')}
467
+ disabled={saving}
468
+ >
469
+ <Save className="size-4" />
470
+ Save prompt
471
+ </Button>
472
+ </div>
473
+ </div>
474
+ </div>
475
+ )}
476
+
477
+ {activeTab === 'tools' && (
478
+ <div className="pt-2 animate-in fade-in-0 duration-200 space-y-7">
479
+ <ToolGrid title="Built-in tools" tools={BUILT_IN_TOOLS} />
480
+ <ToolGrid
481
+ title="Marketplace plugins"
482
+ tools={plugins}
483
+ empty="You have not enabled any local capabilities."
484
+ />
485
+ </div>
486
+ )}
487
+
488
+ {activeTab === 'skills' && (
489
+ <div className="pt-2 animate-in fade-in-0 duration-200 space-y-4">
490
+ <SkillDialog
491
+ open={skillDialogOpen}
492
+ onOpenChange={setSkillDialogOpen}
493
+ onAdd={(skill) => {
494
+ const next = [...skills, skill];
495
+ setSkills(next);
496
+ void save({ skills: next }, 'Skill added.');
497
+ setSkillDialogOpen(false);
498
+ }}
499
+ />
500
+
501
+ <div className="w-full gap-3 flex items-center justify-between">
502
+ {skills.length > 0 && (
503
+ <div className="relative w-full">
504
+ <Search className="absolute left-3 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground" />
505
+ <Input
506
+ placeholder="Search skills…"
507
+ className="h-9 pl-9 w-full bg-white/70 dark:bg-card/70"
508
+ value={skillSearch}
509
+ onChange={(e) => setSkillSearch(e.target.value)}
510
+ />
511
+ </div>
512
+ )}
513
+
514
+ <div className="flex flex-wrap items-start justify-between gap-4 ml-auto">
515
+ {skills.length > 0 && (
516
+ <Button
517
+ onClick={() => setSkillDialogOpen(true)}
518
+ size="default"
519
+ className="gap-1.5 px-3"
520
+ >
521
+ <Plus className="size-3.5" /> Add skill
522
+ </Button>
523
+ )}
524
+ </div>
525
+ </div>
526
+
527
+ {skills.length === 0 ? (
528
+ <div className="rounded-xl px-4 py-20 dark:bg-card/40">
529
+ <div className="flex flex-col items-center gap-3">
530
+ <div className="flex size-12 items-center justify-center rounded-xl border border-border dark:bg-secondary/70">
531
+ <img src="/icons/agentskills.png" alt="" className="size-6 object-contain" />
532
+ </div>
533
+ <div className="text-center">
534
+ <h2 className="text-base font-semibold tracking-tight">No skills added yet</h2>
535
+ <p className="mt-1 text-sm text-muted-foreground">
536
+ Import a SKILL.md or keep a canonical remote skill URL.
537
+ </p>
538
+ </div>
539
+ <Button onClick={() => setSkillDialogOpen(true)} className="mt-2 gap-1.5">
540
+ <Plus className="size-4" /> Add skill
541
+ </Button>
542
+ </div>
543
+ </div>
544
+ ) : filteredSkills.length === 0 ? (
545
+ <div className="flex flex-col items-center gap-2 rounded-xl border border-dashed border-border bg-white/60 px-4 py-14 dark:bg-card/40">
546
+ <AlertCircle className="size-5 text-muted-foreground" />
547
+ <p className="text-sm text-muted-foreground">
548
+ No skills match &ldquo;{skillSearch}&rdquo;
549
+ </p>
550
+ </div>
551
+ ) : (
552
+ <div className="grid gap-3">
553
+ {filteredSkills.map((skill) => (
554
+ <div
555
+ key={skill.id}
556
+ className="flex items-start gap-3 rounded-xl border bg-white/70 p-4 dark:bg-card/70"
557
+ >
558
+ <div className="mt-0.5 flex size-9 shrink-0 items-center justify-center rounded-lg border bg-muted/40">
559
+ {skill.source === 'remote' ? (
560
+ <Link className="size-4" />
561
+ ) : (
562
+ <img src="/icons/agentskills.png" alt="" className="size-4 object-contain" />
563
+ )}
564
+ </div>
565
+ <div className="min-w-0 flex-1">
566
+ <div className="flex flex-wrap items-center gap-2">
567
+ <p className="text-sm font-medium">{skill.name}</p>
568
+ <span className="rounded bg-muted px-1.5 py-0.5 text-[10px] text-muted-foreground">
569
+ {skill.source === 'remote' ? 'Remote' : 'SKILL.md'}
570
+ </span>
571
+ </div>
572
+ <p className="mt-1 text-xs text-muted-foreground">{skill.description}</p>
573
+ {skill.url && (
574
+ <p className="mt-2 truncate font-mono text-[11px] text-muted-foreground">
575
+ {skill.url}
576
+ </p>
577
+ )}
578
+ </div>
579
+ <div className="flex items-center gap-2">
580
+ <Switch
581
+ className={''}
582
+ checked={skill.enabled !== false}
583
+ disabled={saving}
584
+ aria-label={`Toggle ${skill.name}`}
585
+ onCheckedChange={(enabled) => toggleSkill(skill.id, enabled)}
586
+ />
587
+ <Button
588
+ variant="ghost"
589
+ size="icon-sm"
590
+ aria-label={`Remove ${skill.name}`}
591
+ onClick={() => {
592
+ const next = skills.filter((item) => item.id !== skill.id);
593
+ setSkills(next);
594
+ void save({ skills: next }, 'Skill removed.');
595
+ }}
596
+ >
597
+ <Trash2 className="size-4 hover:text-destructive" />
598
+ </Button>
599
+ </div>
600
+ </div>
601
+ ))}
602
+ </div>
603
+ )}
604
+ </div>
605
+ )}
606
+
607
+ {activeTab === 'mcp' && (
608
+ <div className="pt-2 animate-in fade-in-0 duration-200">
609
+ <McpConnectionsSection />
610
+ </div>
611
+ )}
612
+
613
+ {activeTab === 'sandbox' && (
614
+ <div className="pt-2 animate-in fade-in-0 duration-200">
615
+ <SandboxSection embedded />
616
+ </div>
617
+ )}
618
+ </section>
619
+ );
620
+ }