@invect/ui 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (419) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +77 -0
  3. package/dist/Invect-CWpIwZ5F.js +92738 -0
  4. package/dist/Invect.d.ts +25 -0
  5. package/dist/InvectShell.d.ts +14 -0
  6. package/dist/api/agent-tools.api.d.ts +1 -0
  7. package/dist/api/client.d.ts +207 -0
  8. package/dist/api/credentials.api.d.ts +47 -0
  9. package/dist/api/executions.api.d.ts +43 -0
  10. package/dist/api/flows.api.d.ts +100 -0
  11. package/dist/api/index.d.ts +9 -0
  12. package/dist/api/node-data.api.d.ts +66 -0
  13. package/dist/api/query-keys.d.ts +22 -0
  14. package/dist/api/triggers.api.d.ts +44 -0
  15. package/dist/api/types.d.ts +147 -0
  16. package/dist/api/use-flow-run-stream.d.ts +12 -0
  17. package/dist/assets/invect-branding.d.ts +4 -0
  18. package/dist/assets/provider-icons/index.d.ts +8 -0
  19. package/dist/babel-C9OtljFZ.js +9721 -0
  20. package/dist/components/PageLayout.d.ts +17 -0
  21. package/dist/components/chat/ChatInput.d.ts +17 -0
  22. package/dist/components/chat/ChatMessageList.d.ts +14 -0
  23. package/dist/components/chat/ChatModelSelector.d.ts +11 -0
  24. package/dist/components/chat/ChatPanel.d.ts +19 -0
  25. package/dist/components/chat/ChatPromptOverlay.d.ts +13 -0
  26. package/dist/components/chat/ChatProviderSelector.d.ts +9 -0
  27. package/dist/components/chat/ChatSettingsPanel.d.ts +11 -0
  28. package/dist/components/chat/InlineCredentialSetup.d.ts +9 -0
  29. package/dist/components/chat/MarkdownRenderer.d.ts +7 -0
  30. package/dist/components/chat/chat-memory.d.ts +21 -0
  31. package/dist/components/chat/chat.store.d.ts +416 -0
  32. package/dist/components/chat/index.d.ts +5 -0
  33. package/dist/components/chat/use-chat.d.ts +28 -0
  34. package/dist/components/credentials/CreateCredentialModal.d.ts +13 -0
  35. package/dist/components/credentials/CredentialDetailDialog.d.ts +17 -0
  36. package/dist/components/credentials/EditCredentialModal.d.ts +11 -0
  37. package/dist/components/credentials/OAuth2ConnectButton.d.ts +38 -0
  38. package/dist/components/credentials/OAuth2ProviderSelector.d.ts +15 -0
  39. package/dist/components/credentials/credential-utils.d.ts +12 -0
  40. package/dist/components/credentials/index.d.ts +9 -0
  41. package/dist/components/dashboard/FailedRunsAlert.d.ts +3 -0
  42. package/dist/components/dashboard/FlowCard.d.ts +7 -0
  43. package/dist/components/dashboard/RecentActivityTable.d.ts +9 -0
  44. package/dist/components/dashboard/StatCard.d.ts +10 -0
  45. package/dist/components/dashboard/index.d.ts +5 -0
  46. package/dist/components/dashboard/status-helpers.d.ts +5 -0
  47. package/dist/components/flow-editor/ActionsSidebar.d.ts +2 -0
  48. package/dist/components/flow-editor/FlowEditor.d.ts +21 -0
  49. package/dist/components/flow-editor/FlowHeader.d.ts +9 -0
  50. package/dist/components/flow-editor/FlowLayout.d.ts +24 -0
  51. package/dist/components/flow-editor/ModeSwitcher.d.ts +7 -0
  52. package/dist/components/flow-editor/NodeSidebar.d.ts +24 -0
  53. package/dist/components/flow-editor/RunControls.d.ts +12 -0
  54. package/dist/components/flow-editor/ToolConfigPanel.d.ts +16 -0
  55. package/dist/components/flow-editor/ValidationPanel.d.ts +5 -0
  56. package/dist/components/flow-editor/flow-editor.store.d.ts +1 -0
  57. package/dist/components/flow-editor/index.d.ts +6 -0
  58. package/dist/components/flow-editor/inline-edit.d.ts +10 -0
  59. package/dist/components/flow-editor/node-config-panel/ConfigFieldWithTemplate.d.ts +26 -0
  60. package/dist/components/flow-editor/node-config-panel/CredentialCombobox.d.ts +21 -0
  61. package/dist/components/flow-editor/node-config-panel/CredentialsSection.d.ts +19 -0
  62. package/dist/components/flow-editor/node-config-panel/DroppableInput.d.ts +20 -0
  63. package/dist/components/flow-editor/node-config-panel/DynamicSelectField.d.ts +22 -0
  64. package/dist/components/flow-editor/node-config-panel/JsonPreviewPanel.d.ts +25 -0
  65. package/dist/components/flow-editor/node-config-panel/NodeConfigPanel.d.ts +14 -0
  66. package/dist/components/flow-editor/node-config-panel/NodeConfigPanelHeader.d.ts +15 -0
  67. package/dist/components/flow-editor/node-config-panel/ParametersSection.d.ts +16 -0
  68. package/dist/components/flow-editor/node-config-panel/SearchableSelectField.d.ts +17 -0
  69. package/dist/components/flow-editor/node-config-panel/SwitchCasesField.d.ts +18 -0
  70. package/dist/components/flow-editor/node-config-panel/hooks/index.d.ts +2 -0
  71. package/dist/components/flow-editor/node-config-panel/hooks/use-node-config-panel-state.d.ts +24 -0
  72. package/dist/components/flow-editor/node-config-panel/hooks/use-node-execution.d.ts +46 -0
  73. package/dist/components/flow-editor/node-config-panel/hooks/use-upstream-slots.d.ts +16 -0
  74. package/dist/components/flow-editor/node-config-panel/panels/AgentToolsPanel.d.ts +18 -0
  75. package/dist/components/flow-editor/node-config-panel/panels/ConfigurationPanel.d.ts +49 -0
  76. package/dist/components/flow-editor/node-config-panel/panels/DataMapperPane.d.ts +40 -0
  77. package/dist/components/flow-editor/node-config-panel/panels/InputPanel.d.ts +49 -0
  78. package/dist/components/flow-editor/node-config-panel/panels/OutputPanel.d.ts +7 -0
  79. package/dist/components/flow-editor/node-config-panel/panels/index.d.ts +4 -0
  80. package/dist/components/flow-editor/node-config-panel/types.d.ts +19 -0
  81. package/dist/components/flow-editor/node-config-panel/use-node-config-panel-store.d.ts +49 -0
  82. package/dist/components/flow-editor/node-config-panel/use-node-config-state.d.ts +26 -0
  83. package/dist/components/flow-editor/node-config-panel/use-run-node.d.ts +16 -0
  84. package/dist/components/flow-editor/node-config-panel/utils.d.ts +9 -0
  85. package/dist/components/flow-editor/serialize-to-sdk.d.ts +20 -0
  86. package/dist/components/flow-editor/toolbar-context.d.ts +2 -0
  87. package/dist/components/flow-editor/use-copy-paste.d.ts +7 -0
  88. package/dist/components/flow-editor/use-copy-paste.types.d.ts +38 -0
  89. package/dist/components/flow-editor/use-flow-editor.d.ts +44 -0
  90. package/dist/components/flow-runs-table/FlowRunsTable.d.ts +6 -0
  91. package/dist/components/flow-runs-table/index.d.ts +1 -0
  92. package/dist/components/flow-viewer/FlowRunsView.d.ts +7 -0
  93. package/dist/components/flow-viewer/FlowStatusView.d.ts +21 -0
  94. package/dist/components/flow-viewer/RunSelector.d.ts +13 -0
  95. package/dist/components/flow-viewer/RunsSidebar.d.ts +14 -0
  96. package/dist/components/flow-viewer/agent-tool-executions-list.d.ts +7 -0
  97. package/dist/components/flow-viewer/index.d.ts +1 -0
  98. package/dist/components/flow-viewer/logs-panel.d.ts +18 -0
  99. package/dist/components/flow-viewer/use-execution-log-data.d.ts +113 -0
  100. package/dist/components/graph/BatchFlowEdge.d.ts +33 -0
  101. package/dist/components/graph/LayoutSelector.d.ts +9 -0
  102. package/dist/components/graph/index.d.ts +47 -0
  103. package/dist/components/graph/styleUtils.d.ts +124 -0
  104. package/dist/components/nodes/AgentConfigPanel.d.ts +24 -0
  105. package/dist/components/nodes/AgentNode.d.ts +8 -0
  106. package/dist/components/nodes/AgentToolsBox.d.ts +41 -0
  107. package/dist/components/nodes/NodeAppendix.d.ts +19 -0
  108. package/dist/components/nodes/NodeStatusIndicator.d.ts +30 -0
  109. package/dist/components/nodes/NodeViewContext.d.ts +18 -0
  110. package/dist/components/nodes/ToolParamField.d.ts +28 -0
  111. package/dist/components/nodes/ToolSelectorModal.d.ts +80 -0
  112. package/dist/components/nodes/ToolSelectorParts.d.ts +30 -0
  113. package/dist/components/nodes/UniversalNode.d.ts +2 -0
  114. package/dist/components/nodes/createContextAwareNodes.d.ts +6 -0
  115. package/dist/components/nodes/index.d.ts +22 -0
  116. package/dist/components/nodes/nodeRegistry.d.ts +13 -0
  117. package/dist/components/nodes/withNodeContext.d.ts +7 -0
  118. package/dist/components/shared/InvectLoader.d.ts +8 -0
  119. package/dist/components/shared/InvectLogo.d.ts +9 -0
  120. package/dist/components/shared/ProviderIcon.d.ts +23 -0
  121. package/dist/components/side-menu/side-menu.d.ts +4 -0
  122. package/dist/components/sidebar/BaseSidebar.d.ts +17 -0
  123. package/dist/components/sidebar/index.d.ts +1 -0
  124. package/dist/components/triggers/CronPreview.d.ts +12 -0
  125. package/dist/components/triggers/index.d.ts +1 -0
  126. package/dist/components/ui/alert-dialog.d.ts +18 -0
  127. package/dist/components/ui/badge.d.ts +9 -0
  128. package/dist/components/ui/button.d.ts +13 -0
  129. package/dist/components/ui/card.d.ts +9 -0
  130. package/dist/components/ui/codemirror-js-editor.d.ts +25 -0
  131. package/dist/components/ui/codemirror-json-editor.d.ts +18 -0
  132. package/dist/components/ui/codemirror-nunjucks-editor.d.ts +13 -0
  133. package/dist/components/ui/codemirror-vscode-theme.d.ts +24 -0
  134. package/dist/components/ui/collapsible.d.ts +6 -0
  135. package/dist/components/ui/command.d.ts +18 -0
  136. package/dist/components/ui/dialog.d.ts +18 -0
  137. package/dist/components/ui/dropdown-menu.d.ts +25 -0
  138. package/dist/components/ui/empty-state.d.ts +21 -0
  139. package/dist/components/ui/input.d.ts +3 -0
  140. package/dist/components/ui/label.d.ts +4 -0
  141. package/dist/components/ui/popover.d.ts +10 -0
  142. package/dist/components/ui/resizable.d.ts +8 -0
  143. package/dist/components/ui/scroll-area.d.ts +5 -0
  144. package/dist/components/ui/select.d.ts +18 -0
  145. package/dist/components/ui/separator.d.ts +4 -0
  146. package/dist/components/ui/slider.d.ts +4 -0
  147. package/dist/components/ui/switch.d.ts +3 -0
  148. package/dist/components/ui/table.d.ts +10 -0
  149. package/dist/components/ui/textarea.d.ts +3 -0
  150. package/dist/components/ui/tooltip.d.ts +7 -0
  151. package/dist/components/ui/tree-view.d.ts +107 -0
  152. package/dist/contexts/AgentToolCallbacksContext.d.ts +23 -0
  153. package/dist/contexts/ApiContext.d.ts +11 -0
  154. package/dist/contexts/FlowDataContext.d.ts +9 -0
  155. package/dist/contexts/NodeRegistryContext.d.ts +14 -0
  156. package/dist/contexts/PluginRegistryContext.d.ts +39 -0
  157. package/dist/contexts/ThemeProvider.d.ts +18 -0
  158. package/dist/contexts/ValidationContext.d.ts +22 -0
  159. package/dist/demo/DemoInvect.d.ts +11 -0
  160. package/dist/demo/FlowViewer.d.ts +31 -0
  161. package/dist/demo/demo-api-client.d.ts +33 -0
  162. package/dist/demo/index.d.ts +6 -0
  163. package/dist/demo/sample-data.d.ts +1538 -0
  164. package/dist/demo.d.ts +2 -0
  165. package/dist/demo.js +2774 -0
  166. package/dist/estree-ClbRfS-1.js +7076 -0
  167. package/dist/fonts/geist-cyrillic-wght-normal.woff2 +0 -0
  168. package/dist/fonts/geist-latin-ext-wght-normal.woff2 +0 -0
  169. package/dist/fonts/geist-latin-wght-normal.woff2 +0 -0
  170. package/dist/fonts/iosevka-latin-400-normal.woff2 +0 -0
  171. package/dist/hooks/index.d.ts +1 -0
  172. package/dist/hooks/use-document-title.d.ts +1 -0
  173. package/dist/hooks/use-flow-data.d.ts +22 -0
  174. package/dist/hooks/use-invect-portal-class.d.ts +21 -0
  175. package/dist/hooks/useFlowEditorStore.d.ts +1 -0
  176. package/dist/index.css +3 -0
  177. package/dist/index.d.ts +22 -0
  178. package/dist/index.js +717 -0
  179. package/dist/lib/utils.d.ts +2 -0
  180. package/dist/prettier.d.ts +13 -0
  181. package/dist/routes/all-flow-runs.d.ts +5 -0
  182. package/dist/routes/credentials.d.ts +5 -0
  183. package/dist/routes/flow-route-layout.d.ts +19 -0
  184. package/dist/routes/flow-runs.d.ts +5 -0
  185. package/dist/routes/flow.d.ts +5 -0
  186. package/dist/routes/home.d.ts +5 -0
  187. package/dist/services/index.d.ts +1 -0
  188. package/dist/standalone-C3Df7W52.js +3463 -0
  189. package/dist/stores/executionViewStore.d.ts +64 -0
  190. package/dist/stores/flow-editor.store.d.ts +137 -0
  191. package/dist/stores/flowEditorStore.d.ts +1 -0
  192. package/dist/stores/index.d.ts +2 -0
  193. package/dist/stores/uiStore.d.ts +45 -0
  194. package/dist/types/agent-tools.types.d.ts +53 -0
  195. package/dist/types/index.d.ts +2 -0
  196. package/dist/types/node-definition.types.d.ts +85 -0
  197. package/dist/types/plugin.types.d.ts +100 -0
  198. package/dist/utils/credentialBranding.d.ts +8 -0
  199. package/dist/utils/credentialFiltering.d.ts +20 -0
  200. package/dist/utils/flowTransformations.d.ts +16 -0
  201. package/dist/utils/layoutUtils.d.ts +23 -0
  202. package/dist/utils/nodeReferenceUtils.d.ts +37 -0
  203. package/dist/vendor.d.ts +5 -0
  204. package/package.json +130 -0
  205. package/src/.DS_Store +0 -0
  206. package/src/Invect.tsx +229 -0
  207. package/src/InvectShell.tsx +55 -0
  208. package/src/api/agent-tools.api.ts +23 -0
  209. package/src/api/client.ts +899 -0
  210. package/src/api/credentials.api.ts +197 -0
  211. package/src/api/executions.api.ts +228 -0
  212. package/src/api/flows.api.ts +195 -0
  213. package/src/api/index.ts +17 -0
  214. package/src/api/node-data.api.ts +167 -0
  215. package/src/api/query-keys.ts +44 -0
  216. package/src/api/triggers.api.ts +120 -0
  217. package/src/api/types.ts +212 -0
  218. package/src/api/use-flow-run-stream.ts +206 -0
  219. package/src/app.css +560 -0
  220. package/src/assets/.DS_Store +0 -0
  221. package/src/assets/favicon.ico +0 -0
  222. package/src/assets/fonts/geist-cyrillic-wght-normal.woff2 +0 -0
  223. package/src/assets/fonts/geist-latin-ext-wght-normal.woff2 +0 -0
  224. package/src/assets/fonts/geist-latin-wght-normal.woff2 +0 -0
  225. package/src/assets/fonts/iosevka-latin-400-normal.woff2 +0 -0
  226. package/src/assets/invect-branding.ts +51 -0
  227. package/src/assets/provider-icons/anthropic.svg +1 -0
  228. package/src/assets/provider-icons/anthropic_light.svg +1 -0
  229. package/src/assets/provider-icons/github.svg +1 -0
  230. package/src/assets/provider-icons/github_light.svg +1 -0
  231. package/src/assets/provider-icons/gmail.svg +1 -0
  232. package/src/assets/provider-icons/google_calendar.svg +1 -0
  233. package/src/assets/provider-icons/google_docs.svg +1 -0
  234. package/src/assets/provider-icons/google_drive.svg +1 -0
  235. package/src/assets/provider-icons/google_sheets.svg +1 -0
  236. package/src/assets/provider-icons/index.ts +55 -0
  237. package/src/assets/provider-icons/linear.svg +1 -0
  238. package/src/assets/provider-icons/openai.svg +1 -0
  239. package/src/assets/provider-icons/postgres.svg +1 -0
  240. package/src/assets/provider-icons/slack.svg +1 -0
  241. package/src/assets/small-loader-dark.svg +22 -0
  242. package/src/assets/small-loader-light.svg +22 -0
  243. package/src/assets/small.svg +7 -0
  244. package/src/components/.DS_Store +0 -0
  245. package/src/components/PageLayout.tsx +55 -0
  246. package/src/components/chat/ChatInput.tsx +115 -0
  247. package/src/components/chat/ChatMessageList.tsx +788 -0
  248. package/src/components/chat/ChatModelSelector.tsx +208 -0
  249. package/src/components/chat/ChatPanel.tsx +243 -0
  250. package/src/components/chat/ChatPromptOverlay.tsx +150 -0
  251. package/src/components/chat/ChatProviderSelector.tsx +135 -0
  252. package/src/components/chat/ChatSettingsPanel.tsx +277 -0
  253. package/src/components/chat/InlineCredentialSetup.tsx +343 -0
  254. package/src/components/chat/MarkdownRenderer.tsx +140 -0
  255. package/src/components/chat/chat-memory.ts +88 -0
  256. package/src/components/chat/chat.store.ts +479 -0
  257. package/src/components/chat/index.ts +5 -0
  258. package/src/components/chat/use-chat.ts +473 -0
  259. package/src/components/credentials/CreateCredentialModal.tsx +609 -0
  260. package/src/components/credentials/CredentialDetailDialog.tsx +882 -0
  261. package/src/components/credentials/EditCredentialModal.tsx +399 -0
  262. package/src/components/credentials/OAuth2ConnectButton.tsx +288 -0
  263. package/src/components/credentials/OAuth2ProviderSelector.tsx +360 -0
  264. package/src/components/credentials/credential-utils.ts +99 -0
  265. package/src/components/credentials/index.ts +10 -0
  266. package/src/components/dashboard/FailedRunsAlert.tsx +67 -0
  267. package/src/components/dashboard/FlowCard.tsx +64 -0
  268. package/src/components/dashboard/RecentActivityTable.tsx +92 -0
  269. package/src/components/dashboard/StatCard.tsx +32 -0
  270. package/src/components/dashboard/index.ts +5 -0
  271. package/src/components/dashboard/status-helpers.tsx +102 -0
  272. package/src/components/flow-editor/ActionsSidebar.tsx +503 -0
  273. package/src/components/flow-editor/FlowEditor.tsx +1002 -0
  274. package/src/components/flow-editor/FlowHeader.tsx +87 -0
  275. package/src/components/flow-editor/FlowLayout.tsx +117 -0
  276. package/src/components/flow-editor/ModeSwitcher.tsx +49 -0
  277. package/src/components/flow-editor/NodeSidebar.tsx +343 -0
  278. package/src/components/flow-editor/RunControls.tsx +109 -0
  279. package/src/components/flow-editor/ToolConfigPanel.tsx +434 -0
  280. package/src/components/flow-editor/ValidationPanel.tsx +167 -0
  281. package/src/components/flow-editor/flow-editor.store.ts +2 -0
  282. package/src/components/flow-editor/index.ts +6 -0
  283. package/src/components/flow-editor/inline-edit.tsx +111 -0
  284. package/src/components/flow-editor/node-config-panel/ConfigFieldWithTemplate.tsx +334 -0
  285. package/src/components/flow-editor/node-config-panel/CredentialCombobox.tsx +217 -0
  286. package/src/components/flow-editor/node-config-panel/CredentialsSection.tsx +154 -0
  287. package/src/components/flow-editor/node-config-panel/DroppableInput.tsx +45 -0
  288. package/src/components/flow-editor/node-config-panel/DynamicSelectField.tsx +223 -0
  289. package/src/components/flow-editor/node-config-panel/JsonPreviewPanel.tsx +134 -0
  290. package/src/components/flow-editor/node-config-panel/NodeConfigPanel.tsx +650 -0
  291. package/src/components/flow-editor/node-config-panel/NodeConfigPanelHeader.tsx +91 -0
  292. package/src/components/flow-editor/node-config-panel/ParametersSection.tsx +144 -0
  293. package/src/components/flow-editor/node-config-panel/SearchableSelectField.tsx +126 -0
  294. package/src/components/flow-editor/node-config-panel/SwitchCasesField.tsx +212 -0
  295. package/src/components/flow-editor/node-config-panel/hooks/index.ts +2 -0
  296. package/src/components/flow-editor/node-config-panel/hooks/use-node-config-panel-state.ts +284 -0
  297. package/src/components/flow-editor/node-config-panel/hooks/use-node-execution.ts +287 -0
  298. package/src/components/flow-editor/node-config-panel/hooks/use-upstream-slots.ts +310 -0
  299. package/src/components/flow-editor/node-config-panel/panels/AgentToolsPanel.tsx +837 -0
  300. package/src/components/flow-editor/node-config-panel/panels/ConfigurationPanel.tsx +383 -0
  301. package/src/components/flow-editor/node-config-panel/panels/DataMapperPane.tsx +456 -0
  302. package/src/components/flow-editor/node-config-panel/panels/InputPanel.tsx +338 -0
  303. package/src/components/flow-editor/node-config-panel/panels/OutputPanel.tsx +109 -0
  304. package/src/components/flow-editor/node-config-panel/panels/index.ts +4 -0
  305. package/src/components/flow-editor/node-config-panel/types.ts +20 -0
  306. package/src/components/flow-editor/node-config-panel/use-node-config-panel-store.ts +283 -0
  307. package/src/components/flow-editor/node-config-panel/use-node-config-state.ts +172 -0
  308. package/src/components/flow-editor/node-config-panel/use-run-node.ts +147 -0
  309. package/src/components/flow-editor/node-config-panel/utils.ts +73 -0
  310. package/src/components/flow-editor/serialize-to-sdk.ts +204 -0
  311. package/src/components/flow-editor/toolbar-context.ts +9 -0
  312. package/src/components/flow-editor/use-copy-paste.ts +575 -0
  313. package/src/components/flow-editor/use-copy-paste.types.ts +35 -0
  314. package/src/components/flow-editor/use-flow-editor.ts +241 -0
  315. package/src/components/flow-runs-table/FlowRunsTable.tsx +631 -0
  316. package/src/components/flow-runs-table/index.ts +1 -0
  317. package/src/components/flow-viewer/FlowRunsView.tsx +268 -0
  318. package/src/components/flow-viewer/FlowStatusView.tsx +351 -0
  319. package/src/components/flow-viewer/RunSelector.tsx +422 -0
  320. package/src/components/flow-viewer/RunsSidebar.tsx +125 -0
  321. package/src/components/flow-viewer/agent-tool-executions-list.tsx +298 -0
  322. package/src/components/flow-viewer/index.ts +1 -0
  323. package/src/components/flow-viewer/logs-panel.tsx +567 -0
  324. package/src/components/flow-viewer/use-execution-log-data.ts +374 -0
  325. package/src/components/graph/BatchFlowEdge.tsx +229 -0
  326. package/src/components/graph/LayoutSelector.tsx +42 -0
  327. package/src/components/graph/index.ts +61 -0
  328. package/src/components/graph/styleUtils.ts +375 -0
  329. package/src/components/nodes/.DS_Store +0 -0
  330. package/src/components/nodes/AgentConfigPanel.tsx +1033 -0
  331. package/src/components/nodes/AgentNode.tsx +298 -0
  332. package/src/components/nodes/AgentToolsBox.tsx +193 -0
  333. package/src/components/nodes/NodeAppendix.tsx +98 -0
  334. package/src/components/nodes/NodeStatusIndicator.tsx +74 -0
  335. package/src/components/nodes/NodeViewContext.tsx +45 -0
  336. package/src/components/nodes/ToolParamField.tsx +282 -0
  337. package/src/components/nodes/ToolSelectorModal.tsx +648 -0
  338. package/src/components/nodes/ToolSelectorParts.tsx +505 -0
  339. package/src/components/nodes/UniversalNode.tsx +356 -0
  340. package/src/components/nodes/createContextAwareNodes.ts +19 -0
  341. package/src/components/nodes/index.ts +45 -0
  342. package/src/components/nodes/nodeRegistry.ts +50 -0
  343. package/src/components/nodes/withNodeContext.tsx +55 -0
  344. package/src/components/shared/InvectLoader.tsx +59 -0
  345. package/src/components/shared/InvectLogo.tsx +59 -0
  346. package/src/components/shared/ProviderIcon.tsx +115 -0
  347. package/src/components/side-menu/side-menu.tsx +267 -0
  348. package/src/components/sidebar/BaseSidebar.tsx +148 -0
  349. package/src/components/sidebar/index.ts +1 -0
  350. package/src/components/triggers/CronPreview.tsx +243 -0
  351. package/src/components/triggers/index.ts +1 -0
  352. package/src/components/ui/alert-dialog.tsx +152 -0
  353. package/src/components/ui/badge.tsx +39 -0
  354. package/src/components/ui/button.tsx +58 -0
  355. package/src/components/ui/card.tsx +75 -0
  356. package/src/components/ui/codemirror-js-editor.tsx +432 -0
  357. package/src/components/ui/codemirror-json-editor.tsx +816 -0
  358. package/src/components/ui/codemirror-nunjucks-editor.tsx +451 -0
  359. package/src/components/ui/codemirror-vscode-theme.ts +243 -0
  360. package/src/components/ui/collapsible.tsx +12 -0
  361. package/src/components/ui/command.tsx +162 -0
  362. package/src/components/ui/dialog.tsx +140 -0
  363. package/src/components/ui/dropdown-menu.tsx +232 -0
  364. package/src/components/ui/empty-state.tsx +93 -0
  365. package/src/components/ui/input.tsx +26 -0
  366. package/src/components/ui/label.tsx +19 -0
  367. package/src/components/ui/popover.tsx +53 -0
  368. package/src/components/ui/resizable.tsx +61 -0
  369. package/src/components/ui/scroll-area.tsx +56 -0
  370. package/src/components/ui/select.tsx +179 -0
  371. package/src/components/ui/separator.tsx +26 -0
  372. package/src/components/ui/slider.tsx +58 -0
  373. package/src/components/ui/switch.tsx +22 -0
  374. package/src/components/ui/table.tsx +90 -0
  375. package/src/components/ui/textarea.tsx +23 -0
  376. package/src/components/ui/tooltip.tsx +54 -0
  377. package/src/components/ui/tree-view.tsx +574 -0
  378. package/src/contexts/AgentToolCallbacksContext.tsx +31 -0
  379. package/src/contexts/ApiContext.tsx +51 -0
  380. package/src/contexts/FlowDataContext.tsx +21 -0
  381. package/src/contexts/NodeRegistryContext.tsx +54 -0
  382. package/src/contexts/PluginRegistryContext.tsx +182 -0
  383. package/src/contexts/ThemeProvider.tsx +106 -0
  384. package/src/contexts/ValidationContext.tsx +122 -0
  385. package/src/demo/DemoInvect.tsx +42 -0
  386. package/src/demo/FlowViewer.tsx +294 -0
  387. package/src/demo/demo-api-client.ts +246 -0
  388. package/src/demo/index.ts +28 -0
  389. package/src/demo/sample-data.ts +1980 -0
  390. package/src/hooks/index.ts +1 -0
  391. package/src/hooks/use-document-title.ts +8 -0
  392. package/src/hooks/use-flow-data.ts +144 -0
  393. package/src/hooks/use-invect-portal-class.ts +27 -0
  394. package/src/hooks/useFlowEditorStore.ts +2 -0
  395. package/src/index.ts +70 -0
  396. package/src/lib/utils.ts +6 -0
  397. package/src/prettier.d.ts +13 -0
  398. package/src/routes/all-flow-runs.tsx +27 -0
  399. package/src/routes/credentials.tsx +362 -0
  400. package/src/routes/flow-route-layout.tsx +113 -0
  401. package/src/routes/flow-runs.tsx +22 -0
  402. package/src/routes/flow.tsx +22 -0
  403. package/src/routes/home.tsx +282 -0
  404. package/src/services/index.ts +6 -0
  405. package/src/stores/executionViewStore.ts +211 -0
  406. package/src/stores/flow-editor.store.ts +738 -0
  407. package/src/stores/flowEditorStore.ts +2 -0
  408. package/src/stores/index.ts +10 -0
  409. package/src/stores/uiStore.ts +189 -0
  410. package/src/types/agent-tools.types.ts +64 -0
  411. package/src/types/index.ts +5 -0
  412. package/src/types/node-definition.types.ts +104 -0
  413. package/src/types/plugin.types.ts +123 -0
  414. package/src/utils/credentialBranding.ts +116 -0
  415. package/src/utils/credentialFiltering.ts +68 -0
  416. package/src/utils/flowTransformations.ts +137 -0
  417. package/src/utils/layoutUtils.ts +127 -0
  418. package/src/utils/nodeReferenceUtils.ts +135 -0
  419. package/src/vendor.d.ts +7 -0
@@ -0,0 +1,837 @@
1
+ 'use client';
2
+
3
+ import { memo, useState, useMemo, useCallback, useEffect } from 'react';
4
+ import { useQueryClient } from '@tanstack/react-query';
5
+ import { ScrollArea } from '../../../ui/scroll-area';
6
+ import { Button } from '../../../ui/button';
7
+ import { Badge } from '../../../ui/badge';
8
+ import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '../../../ui/collapsible';
9
+ import { Separator } from '../../../ui/separator';
10
+ import { cn } from '../../../../lib/utils';
11
+ import {
12
+ Plus,
13
+ Search,
14
+ ChevronRight,
15
+ X,
16
+ Trash2,
17
+ Wrench,
18
+ ChevronDown,
19
+ ChevronsUpDown,
20
+ Check,
21
+ } from 'lucide-react';
22
+ import { ProviderIcon } from '../../../shared/ProviderIcon';
23
+ import { ToolParamField, type AddCredentialRequest } from '../../../nodes/ToolParamField';
24
+ import { CreateCredentialModal } from '../../../credentials/CreateCredentialModal';
25
+ import { OAuth2ProviderSelector } from '../../../credentials/OAuth2ProviderSelector';
26
+ import { Popover, PopoverContent, PopoverTrigger } from '../../../ui/popover';
27
+ import {
28
+ Command,
29
+ CommandEmpty,
30
+ CommandGroup,
31
+ CommandInput,
32
+ CommandItem,
33
+ CommandList,
34
+ } from '../../../ui/command';
35
+ import { useCreateCredential } from '../../../../api/credentials.api';
36
+ import { useNodeRegistry } from '../../../../contexts/NodeRegistryContext';
37
+ import type { ToolDefinition, AddedToolInstance } from '../../../nodes/ToolSelectorModal';
38
+ import type { NodeParamField } from '../../../../types/node-definition.types';
39
+ import type { CreateCredentialInput, Credential } from '../../../../api/types';
40
+
41
+ // ─── Types ─────────────────────────────────────────────────────────
42
+
43
+ type ToolSubView = 'discovery' | `instance-${string}`;
44
+
45
+ export interface AgentToolsPanelProps {
46
+ /** Available tools fetched from the API */
47
+ availableTools: ToolDefinition[];
48
+ /** Currently added tool instances on this agent */
49
+ addedTools: AddedToolInstance[];
50
+ /** Called to add a tool instance */
51
+ onAddTool: (toolId: string) => string;
52
+ /** Called to remove a tool instance */
53
+ onRemoveTool: (instanceId: string) => void;
54
+ /** Called to update a tool instance */
55
+ onUpdateTool: (
56
+ instanceId: string,
57
+ updates: Partial<Omit<AddedToolInstance, 'instanceId' | 'toolId'>>,
58
+ ) => void;
59
+ /** Portal container for sub-modals */
60
+ portalContainer?: HTMLElement | null;
61
+ /** Pre-select a specific tool instance (e.g. opened from AgentToolsBox click) */
62
+ initialToolInstanceId?: string | null;
63
+ }
64
+
65
+ // ─── Main Panel ────────────────────────────────────────────────────
66
+
67
+ export const AgentToolsPanel = memo(function AgentToolsPanel({
68
+ availableTools,
69
+ addedTools,
70
+ onAddTool,
71
+ onRemoveTool,
72
+ onUpdateTool,
73
+ portalContainer,
74
+ initialToolInstanceId,
75
+ }: AgentToolsPanelProps) {
76
+ const [activeView, setActiveView] = useState<ToolSubView>(
77
+ initialToolInstanceId ? `instance-${initialToolInstanceId}` : 'discovery',
78
+ );
79
+ const [searchQuery, setSearchQuery] = useState('');
80
+
81
+ // Credential modal state
82
+ const queryClient = useQueryClient();
83
+ const [isCreateCredentialOpen, setIsCreateCredentialOpen] = useState(false);
84
+ const [isOAuth2SelectorOpen, setIsOAuth2SelectorOpen] = useState(false);
85
+ const [activeCredentialField, setActiveCredentialField] = useState<string | null>(null);
86
+ const [activeOAuth2Providers, setActiveOAuth2Providers] = useState<string[] | null>(null);
87
+ const createCredentialMutation = useCreateCredential();
88
+
89
+ // Filter tools for discovery
90
+ const filteredTools = useMemo(() => {
91
+ return availableTools.filter((tool) => {
92
+ const q = searchQuery.toLowerCase();
93
+ return (
94
+ !q ||
95
+ tool.name.toLowerCase().includes(q) ||
96
+ tool.description.toLowerCase().includes(q) ||
97
+ tool.id.toLowerCase().includes(q) ||
98
+ (tool.provider?.name ?? '').toLowerCase().includes(q)
99
+ );
100
+ });
101
+ }, [availableTools, searchQuery]);
102
+
103
+ // Group by provider
104
+ const toolsByProvider = useMemo(() => {
105
+ const grouped: Record<
106
+ string,
107
+ { tools: ToolDefinition[]; provider: ToolDefinition['provider'] }
108
+ > = {};
109
+ for (const tool of filteredTools) {
110
+ const providerKey = tool.provider?.id ?? 'other';
111
+ if (!grouped[providerKey]) {
112
+ grouped[providerKey] = { tools: [], provider: tool.provider };
113
+ }
114
+ grouped[providerKey].tools.push(tool);
115
+ }
116
+ return grouped;
117
+ }, [filteredTools]);
118
+
119
+ const handleAddTool = useCallback(
120
+ (tool: ToolDefinition) => {
121
+ const instanceId = onAddTool(tool.id);
122
+ if (instanceId) {
123
+ setActiveView(`instance-${instanceId}`);
124
+ }
125
+ },
126
+ [onAddTool],
127
+ );
128
+
129
+ const handleRemoveTool = useCallback(
130
+ (instanceId: string) => {
131
+ onRemoveTool(instanceId);
132
+ setActiveView('discovery');
133
+ },
134
+ [onRemoveTool],
135
+ );
136
+
137
+ const getToolForInstance = useCallback(
138
+ (instance: AddedToolInstance) => {
139
+ return availableTools.find((t) => t.id === instance.toolId);
140
+ },
141
+ [availableTools],
142
+ );
143
+
144
+ const selectedInstance = useMemo(() => {
145
+ if (!activeView.startsWith('instance-')) {
146
+ return null;
147
+ }
148
+ const instanceId = activeView.replace('instance-', '');
149
+ return addedTools.find((t) => t.instanceId === instanceId) ?? null;
150
+ }, [activeView, addedTools]);
151
+
152
+ // Reset view if selected instance was removed
153
+ useEffect(() => {
154
+ if (activeView.startsWith('instance-') && !selectedInstance) {
155
+ setActiveView('discovery');
156
+ }
157
+ }, [activeView, selectedInstance]);
158
+
159
+ // Credential handlers
160
+ const handleAddCredential = useCallback((request: AddCredentialRequest) => {
161
+ setActiveCredentialField(request.fieldName);
162
+ if (request.oauth2Providers && request.oauth2Providers.length > 0) {
163
+ setActiveOAuth2Providers(request.oauth2Providers);
164
+ setIsOAuth2SelectorOpen(true);
165
+ } else {
166
+ setIsCreateCredentialOpen(true);
167
+ }
168
+ }, []);
169
+
170
+ const handleCredentialCreated = useCallback(
171
+ async (createdCredential: Credential) => {
172
+ await queryClient.refetchQueries({ queryKey: ['credentials'] });
173
+ if (activeCredentialField && selectedInstance) {
174
+ onUpdateTool(selectedInstance.instanceId, {
175
+ params: { ...selectedInstance.params, [activeCredentialField]: createdCredential.id },
176
+ });
177
+ }
178
+ setIsCreateCredentialOpen(false);
179
+ setIsOAuth2SelectorOpen(false);
180
+ setActiveCredentialField(null);
181
+ setActiveOAuth2Providers(null);
182
+ },
183
+ [queryClient, activeCredentialField, selectedInstance, onUpdateTool],
184
+ );
185
+
186
+ const handleCreateCredential = useCallback(
187
+ (input: CreateCredentialInput) => {
188
+ createCredentialMutation.mutate(input, {
189
+ onSuccess: (created) => handleCredentialCreated(created),
190
+ });
191
+ },
192
+ [createCredentialMutation, handleCredentialCreated],
193
+ );
194
+
195
+ const getInstanceCount = useCallback(
196
+ (toolId: string) => addedTools.filter((t) => t.toolId === toolId).length,
197
+ [addedTools],
198
+ );
199
+
200
+ const MAX_INLINE_TOOLS = 3;
201
+ const useCombobox = addedTools.length > MAX_INLINE_TOOLS;
202
+ const [comboboxOpen, setComboboxOpen] = useState(false);
203
+
204
+ // Selected instance label for combobox trigger
205
+ const comboboxLabel = useMemo(() => {
206
+ if (activeView === 'discovery') {
207
+ return null;
208
+ }
209
+ return selectedInstance?.name ?? null;
210
+ }, [activeView, selectedInstance]);
211
+
212
+ return (
213
+ <div className="flex flex-col h-full">
214
+ {/* ── Tool Strip (horizontal bar) ─────────────────────── */}
215
+ <div className="flex items-center gap-1.5 px-3 py-2 border-b border-border shrink-0">
216
+ <button
217
+ onClick={() => setActiveView('discovery')}
218
+ className={cn(
219
+ 'flex items-center gap-1.5 px-2.5 py-1 rounded-md text-xs font-medium shrink-0 transition-colors',
220
+ activeView === 'discovery'
221
+ ? 'bg-accent text-accent-foreground'
222
+ : 'text-muted-foreground hover:bg-muted/50 hover:text-foreground',
223
+ )}
224
+ >
225
+ <Plus className="w-3 h-3" />
226
+ Add
227
+ </button>
228
+
229
+ {useCombobox ? (
230
+ /* ── Combobox dropdown for >3 tools ─────────────── */
231
+ <Popover open={comboboxOpen} onOpenChange={setComboboxOpen} modal>
232
+ <PopoverTrigger asChild>
233
+ <button
234
+ className={cn(
235
+ 'flex items-center gap-1.5 px-2.5 py-1 rounded-md text-xs transition-colors min-w-0',
236
+ 'border border-border hover:bg-muted/50',
237
+ comboboxLabel ? 'text-foreground font-medium' : 'text-muted-foreground',
238
+ )}
239
+ >
240
+ {comboboxLabel ? (
241
+ <>
242
+ {selectedInstance &&
243
+ (() => {
244
+ const tool = getToolForInstance(selectedInstance);
245
+ return tool?.provider?.id ? (
246
+ <ProviderIcon
247
+ providerId={tool.provider.id}
248
+ svgIcon={tool.provider.svgIcon}
249
+ icon={tool.provider.icon}
250
+ className="w-3.5 h-3.5 shrink-0"
251
+ />
252
+ ) : (
253
+ <Wrench className="w-3.5 h-3.5 shrink-0" />
254
+ );
255
+ })()}
256
+ <span className="truncate max-w-28">{comboboxLabel}</span>
257
+ </>
258
+ ) : (
259
+ <span>Select tool…</span>
260
+ )}
261
+ <Badge variant="secondary" className="h-4 px-1 text-[10px] shrink-0 tabular-nums">
262
+ {addedTools.length}
263
+ </Badge>
264
+ <ChevronsUpDown className="w-3 h-3 shrink-0 text-muted-foreground" />
265
+ </button>
266
+ </PopoverTrigger>
267
+ <PopoverContent className="w-56 p-0" align="start">
268
+ <Command>
269
+ <CommandInput placeholder="Search tools…" className="h-8 text-xs" />
270
+ <CommandList>
271
+ <CommandEmpty>No tools found.</CommandEmpty>
272
+ <CommandGroup>
273
+ {addedTools.map((instance) => {
274
+ const tool = getToolForInstance(instance);
275
+ const isActive = activeView === `instance-${instance.instanceId}`;
276
+ return (
277
+ <CommandItem
278
+ key={instance.instanceId}
279
+ value={instance.name}
280
+ onSelect={() => {
281
+ setActiveView(`instance-${instance.instanceId}`);
282
+ setComboboxOpen(false);
283
+ }}
284
+ className="gap-2 text-xs"
285
+ >
286
+ <span className="shrink-0">
287
+ {tool?.provider?.id ? (
288
+ <ProviderIcon
289
+ providerId={tool.provider.id}
290
+ svgIcon={tool.provider.svgIcon}
291
+ icon={tool.provider.icon}
292
+ className="w-3.5 h-3.5"
293
+ />
294
+ ) : (
295
+ <Wrench className="w-3.5 h-3.5" />
296
+ )}
297
+ </span>
298
+ <span className="truncate flex-1">{instance.name}</span>
299
+ {isActive && <Check className="w-3.5 h-3.5 shrink-0" />}
300
+ </CommandItem>
301
+ );
302
+ })}
303
+ </CommandGroup>
304
+ </CommandList>
305
+ </Command>
306
+ </PopoverContent>
307
+ </Popover>
308
+ ) : (
309
+ /* ── Inline pill chips for ≤3 tools ────────────── */
310
+ addedTools.map((instance) => {
311
+ const tool = getToolForInstance(instance);
312
+ const isActive = activeView === `instance-${instance.instanceId}`;
313
+ return (
314
+ <button
315
+ key={instance.instanceId}
316
+ onClick={() => setActiveView(`instance-${instance.instanceId}`)}
317
+ className={cn(
318
+ 'flex items-center gap-1.5 px-2.5 py-1 rounded-md text-xs shrink-0 transition-colors group max-w-40',
319
+ isActive
320
+ ? 'bg-accent text-accent-foreground font-medium'
321
+ : 'text-muted-foreground hover:bg-muted/50 hover:text-foreground',
322
+ )}
323
+ >
324
+ <span className="shrink-0">
325
+ {tool?.provider?.id ? (
326
+ <ProviderIcon
327
+ providerId={tool.provider.id}
328
+ svgIcon={tool.provider.svgIcon}
329
+ icon={tool.provider.icon}
330
+ className="w-3.5 h-3.5"
331
+ />
332
+ ) : (
333
+ <Wrench className="w-3.5 h-3.5" />
334
+ )}
335
+ </span>
336
+ <span className="truncate">{instance.name}</span>
337
+ </button>
338
+ );
339
+ })
340
+ )}
341
+ </div>
342
+
343
+ {/* ── Detail Area ─────────────────────────────────────── */}
344
+ <ScrollArea className="flex-1 min-h-0">
345
+ <div className="p-3">
346
+ {activeView === 'discovery' ? (
347
+ <ToolDiscoveryView
348
+ searchQuery={searchQuery}
349
+ onSearchChange={setSearchQuery}
350
+ toolsByProvider={toolsByProvider}
351
+ getInstanceCount={getInstanceCount}
352
+ onAddTool={handleAddTool}
353
+ addedTools={addedTools}
354
+ getToolForInstance={getToolForInstance}
355
+ onSelectInstance={(instanceId) => setActiveView(`instance-${instanceId}`)}
356
+ onRemoveTool={handleRemoveTool}
357
+ />
358
+ ) : selectedInstance ? (
359
+ <ToolInstanceView
360
+ instance={selectedInstance}
361
+ tool={getToolForInstance(selectedInstance) ?? null}
362
+ onUpdate={onUpdateTool}
363
+ onRemove={() => handleRemoveTool(selectedInstance.instanceId)}
364
+ onAddCredential={handleAddCredential}
365
+ />
366
+ ) : null}
367
+ </div>
368
+ </ScrollArea>
369
+
370
+ {/* Credential modals */}
371
+ <CreateCredentialModal
372
+ open={isCreateCredentialOpen}
373
+ onClose={() => {
374
+ setIsCreateCredentialOpen(false);
375
+ setActiveCredentialField(null);
376
+ }}
377
+ onSubmit={handleCreateCredential}
378
+ isLoading={createCredentialMutation.isPending}
379
+ portalContainer={portalContainer}
380
+ />
381
+
382
+ <OAuth2ProviderSelector
383
+ open={isOAuth2SelectorOpen}
384
+ onOpenChange={(o) => {
385
+ if (!o) {
386
+ setIsOAuth2SelectorOpen(false);
387
+ setActiveCredentialField(null);
388
+ setActiveOAuth2Providers(null);
389
+ }
390
+ }}
391
+ onCredentialCreated={handleCredentialCreated}
392
+ portalContainer={portalContainer}
393
+ filterProviders={activeOAuth2Providers ?? undefined}
394
+ />
395
+ </div>
396
+ );
397
+ });
398
+
399
+ // ─── Tool Discovery View ───────────────────────────────────────────
400
+
401
+ function ToolDiscoveryView({
402
+ searchQuery,
403
+ onSearchChange,
404
+ toolsByProvider,
405
+ getInstanceCount,
406
+ onAddTool,
407
+ addedTools,
408
+ getToolForInstance,
409
+ onSelectInstance,
410
+ onRemoveTool,
411
+ }: {
412
+ searchQuery: string;
413
+ onSearchChange: (query: string) => void;
414
+ toolsByProvider: Record<
415
+ string,
416
+ { tools: ToolDefinition[]; provider: ToolDefinition['provider'] }
417
+ >;
418
+ getInstanceCount: (toolId: string) => number;
419
+ onAddTool: (tool: ToolDefinition) => void;
420
+ addedTools: AddedToolInstance[];
421
+ getToolForInstance: (instance: AddedToolInstance) => ToolDefinition | undefined;
422
+ onSelectInstance: (instanceId: string) => void;
423
+ onRemoveTool: (instanceId: string) => void;
424
+ }) {
425
+ // Track collapsed groups (all groups start expanded)
426
+ const [collapsedGroups, setCollapsedGroups] = useState<Set<string>>(() => new Set());
427
+ const isSearching = searchQuery.length > 0;
428
+
429
+ const toggleGroup = useCallback((providerId: string) => {
430
+ setCollapsedGroups((prev) => {
431
+ const next = new Set(prev);
432
+ if (next.has(providerId)) {
433
+ next.delete(providerId);
434
+ } else {
435
+ next.add(providerId);
436
+ }
437
+ return next;
438
+ });
439
+ }, []);
440
+
441
+ const sortedProviderIds = useMemo(() => {
442
+ return Object.keys(toolsByProvider).sort((a, b) => {
443
+ const nameA = toolsByProvider[a].provider?.name ?? a;
444
+ const nameB = toolsByProvider[b].provider?.name ?? b;
445
+ // Core first, then alphabetical
446
+ if (a === 'core') {
447
+ return -1;
448
+ }
449
+ if (b === 'core') {
450
+ return 1;
451
+ }
452
+ return nameA.localeCompare(nameB);
453
+ });
454
+ }, [toolsByProvider]);
455
+
456
+ return (
457
+ <div className="space-y-3">
458
+ {/* ── Added Tools Grid ──────────────────────────────── */}
459
+ {addedTools.length > 0 && (
460
+ <div className="space-y-2">
461
+ <div className="flex items-center justify-between">
462
+ <h4 className="text-[11px] font-semibold tracking-wider uppercase text-muted-foreground">
463
+ Added Tools
464
+ </h4>
465
+ <Badge variant="secondary" className="h-4 px-1.5 text-[10px]">
466
+ {addedTools.length}
467
+ </Badge>
468
+ </div>
469
+ <div className="grid grid-cols-2 gap-2">
470
+ {addedTools.map((instance) => {
471
+ const tool = getToolForInstance(instance);
472
+ const bgColor =
473
+ tool?.provider?.id === 'core' || tool?.provider?.id === 'triggers'
474
+ ? 'bg-accent text-primary'
475
+ : 'bg-muted text-muted-foreground';
476
+ return (
477
+ <div
478
+ key={instance.instanceId}
479
+ className="relative flex items-center gap-2 p-2 transition-all border rounded-lg cursor-pointer group border-border hover:border-primary/50 hover:bg-accent/50"
480
+ onClick={() => onSelectInstance(instance.instanceId)}
481
+ >
482
+ <div
483
+ className={cn(
484
+ 'flex h-7 w-7 shrink-0 items-center justify-center rounded-md',
485
+ bgColor,
486
+ )}
487
+ >
488
+ <ProviderIcon
489
+ providerId={tool?.provider?.id}
490
+ svgIcon={tool?.provider?.svgIcon}
491
+ icon={tool?.provider?.icon}
492
+ className="w-4 h-4"
493
+ />
494
+ </div>
495
+ <span className="flex-1 min-w-0 text-xs font-medium truncate">
496
+ {instance.name}
497
+ </span>
498
+ <button
499
+ className="absolute hidden p-0.5 rounded group-hover:flex top-1 right-1 text-muted-foreground hover:text-destructive hover:bg-destructive/10"
500
+ onClick={(e) => {
501
+ e.stopPropagation();
502
+ onRemoveTool(instance.instanceId);
503
+ }}
504
+ >
505
+ <X className="w-3 h-3" />
506
+ </button>
507
+ </div>
508
+ );
509
+ })}
510
+ </div>
511
+ <Separator className="mt-1" />
512
+ </div>
513
+ )}
514
+
515
+ {/* Search */}
516
+ <div className="relative">
517
+ <Search className="absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 pointer-events-none text-muted-foreground" />
518
+ <input
519
+ type="text"
520
+ placeholder="Search tools…"
521
+ value={searchQuery}
522
+ onChange={(e) => onSearchChange(e.target.value)}
523
+ className="h-8 w-full rounded-lg border border-border bg-transparent pl-9 pr-3 text-xs outline-none placeholder:text-muted-foreground focus:border-primary/50"
524
+ />
525
+ {searchQuery && (
526
+ <button
527
+ onClick={() => onSearchChange('')}
528
+ className="absolute -translate-y-1/2 right-3 top-1/2 text-muted-foreground hover:text-foreground"
529
+ >
530
+ <X className="w-3 h-3" />
531
+ </button>
532
+ )}
533
+ </div>
534
+
535
+ {/* Tools grouped by provider */}
536
+ <div className="space-y-3">
537
+ {sortedProviderIds.map((providerId) => {
538
+ const group = toolsByProvider[providerId];
539
+ // Show if searching (always expand) or not manually collapsed
540
+ const shouldShow = isSearching || !collapsedGroups.has(providerId);
541
+
542
+ return (
543
+ <div key={providerId}>
544
+ {/* Provider group header */}
545
+ <button
546
+ type="button"
547
+ onClick={() => toggleGroup(providerId)}
548
+ className="flex items-center gap-1.5 mb-2 w-full text-[11px] font-semibold tracking-wider uppercase text-muted-foreground hover:text-foreground transition-colors"
549
+ >
550
+ <ChevronRight
551
+ className={cn(
552
+ 'w-3 h-3 shrink-0 transition-transform duration-200',
553
+ shouldShow && 'rotate-90',
554
+ )}
555
+ />
556
+ {group.provider?.id && (
557
+ <ProviderIcon
558
+ providerId={group.provider.id}
559
+ svgIcon={group.provider.svgIcon}
560
+ icon={group.provider.icon}
561
+ className="w-4 h-4"
562
+ />
563
+ )}
564
+ <span className="flex-1 text-left">{group.provider?.name ?? providerId}</span>
565
+ <span className="text-[10px] font-normal tabular-nums">{group.tools.length}</span>
566
+ </button>
567
+
568
+ {/* Tool list */}
569
+ {shouldShow && (
570
+ <div className="space-y-1.5">
571
+ {group.tools.map((tool) => {
572
+ const count = getInstanceCount(tool.id);
573
+ const bgColor =
574
+ tool.provider?.id === 'core' || tool.provider?.id === 'triggers'
575
+ ? 'bg-accent text-primary'
576
+ : 'bg-muted text-muted-foreground';
577
+
578
+ return (
579
+ <div
580
+ key={tool.id}
581
+ className="relative flex items-center gap-2.5 p-2.5 transition-all border rounded-lg group border-border cursor-pointer hover:border-muted-foreground/50 hover:bg-muted/50"
582
+ onClick={() => onAddTool(tool)}
583
+ title={tool.description}
584
+ >
585
+ {/* Icon */}
586
+ <div
587
+ className={cn(
588
+ 'flex h-8 w-8 shrink-0 items-center justify-center rounded-md',
589
+ bgColor,
590
+ )}
591
+ >
592
+ <ProviderIcon
593
+ providerId={tool.provider?.id}
594
+ svgIcon={tool.provider?.svgIcon}
595
+ icon={tool.provider?.icon}
596
+ className="w-5 h-5"
597
+ />
598
+ </div>
599
+
600
+ {/* Text */}
601
+ <div className="flex-1 min-w-0">
602
+ <div className="flex items-center gap-2">
603
+ <span className="text-sm font-medium truncate">{tool.name}</span>
604
+ {count > 0 && (
605
+ <Badge variant="secondary" className="h-4 px-1 text-[10px] shrink-0">
606
+ ×{count}
607
+ </Badge>
608
+ )}
609
+ </div>
610
+ <p className="overflow-hidden text-xs text-muted-foreground line-clamp-1 text-ellipsis">
611
+ {tool.description}
612
+ </p>
613
+ </div>
614
+
615
+ {/* Add button (hover) */}
616
+ <Button
617
+ size="sm"
618
+ variant="ghost"
619
+ className="w-6 h-6 p-0 transition-opacity opacity-0 shrink-0 group-hover:opacity-100 hover:bg-primary/10 hover:text-primary"
620
+ onClick={(e) => {
621
+ e.stopPropagation();
622
+ onAddTool(tool);
623
+ }}
624
+ >
625
+ <Plus className="w-3 h-3" />
626
+ </Button>
627
+ </div>
628
+ );
629
+ })}
630
+ </div>
631
+ )}
632
+ </div>
633
+ );
634
+ })}
635
+
636
+ {sortedProviderIds.length === 0 && (
637
+ <div className="py-8 text-center text-muted-foreground">
638
+ <p className="text-sm">No tools match your search.</p>
639
+ </div>
640
+ )}
641
+ </div>
642
+ </div>
643
+ );
644
+ }
645
+
646
+ // ─── Tool Instance View ────────────────────────────────────────────
647
+
648
+ function ToolInstanceView({
649
+ instance,
650
+ tool,
651
+ onUpdate,
652
+ onRemove,
653
+ onAddCredential,
654
+ }: {
655
+ instance: AddedToolInstance;
656
+ tool: ToolDefinition | null;
657
+ onUpdate: (
658
+ instanceId: string,
659
+ updates: Partial<Omit<AddedToolInstance, 'instanceId' | 'toolId'>>,
660
+ ) => void;
661
+ onRemove: () => void;
662
+ onAddCredential: (request: AddCredentialRequest) => void;
663
+ }) {
664
+ const [showSchema, setShowSchema] = useState(false);
665
+ const { getNodeDefinition } = useNodeRegistry();
666
+
667
+ // Get param fields from the underlying node definition
668
+ const nodeDefinition = tool?.nodeType ? getNodeDefinition(tool.nodeType) : undefined;
669
+ const paramFields = useMemo(() => {
670
+ const allFields = nodeDefinition?.paramFields ?? [];
671
+ const visibleFields = allFields.filter((field: NodeParamField) => !field.hidden);
672
+ return visibleFields.sort((a: NodeParamField, b: NodeParamField) => {
673
+ if (a.type === 'credential' && b.type !== 'credential') {
674
+ return -1;
675
+ }
676
+ if (a.type !== 'credential' && b.type === 'credential') {
677
+ return 1;
678
+ }
679
+ return 0;
680
+ });
681
+ }, [nodeDefinition]);
682
+
683
+ // Compute effective input schema
684
+ const effectiveInputSchema = useMemo(() => {
685
+ if (!tool?.inputSchema || !instance) {
686
+ return tool?.inputSchema;
687
+ }
688
+
689
+ const aiChosenModes = (instance.params._aiChosenModes as Record<string, boolean>) ?? {};
690
+ const schema = tool.inputSchema as {
691
+ properties?: Record<string, unknown>;
692
+ required?: string[];
693
+ };
694
+ if (!schema.properties) {
695
+ return schema;
696
+ }
697
+
698
+ const filteredProperties: Record<string, unknown> = {};
699
+ for (const [key, value] of Object.entries(schema.properties)) {
700
+ if (aiChosenModes[key] ?? true) {
701
+ filteredProperties[key] = value;
702
+ }
703
+ }
704
+
705
+ return {
706
+ ...schema,
707
+ properties: filteredProperties,
708
+ required: schema.required?.filter((key) => aiChosenModes[key] ?? true),
709
+ };
710
+ }, [tool?.inputSchema, instance]);
711
+
712
+ return (
713
+ <div className="space-y-4">
714
+ {/* Header */}
715
+ <div className="flex items-start justify-between">
716
+ <div className="space-y-1 min-w-0 flex-1">
717
+ <div className="flex items-center gap-2">
718
+ {tool?.provider?.id && (
719
+ <ProviderIcon
720
+ providerId={tool.provider.id}
721
+ svgIcon={tool.provider.svgIcon}
722
+ icon={tool.provider.icon}
723
+ className="w-4 h-4 text-muted-foreground shrink-0"
724
+ />
725
+ )}
726
+ <span className="text-sm font-semibold truncate">{instance.name}</span>
727
+ </div>
728
+ <p className="text-[10px] text-muted-foreground font-mono">
729
+ {tool?.id ?? instance.toolId}
730
+ </p>
731
+ </div>
732
+ <Button
733
+ variant="ghost"
734
+ size="sm"
735
+ className="text-destructive hover:text-destructive hover:bg-destructive/10 shrink-0"
736
+ onClick={onRemove}
737
+ >
738
+ <Trash2 className="w-3.5 h-3.5 mr-1" />
739
+ Remove
740
+ </Button>
741
+ </div>
742
+
743
+ {/* Instance name & description */}
744
+ <div className="space-y-3">
745
+ <div className="space-y-1.5">
746
+ <label className="text-[10px] font-semibold tracking-wider uppercase text-muted-foreground">
747
+ Instance Name
748
+ </label>
749
+ <input
750
+ type="text"
751
+ value={instance.name}
752
+ onChange={(e) => onUpdate(instance.instanceId, { name: e.target.value })}
753
+ className="h-7 w-full rounded-md border border-border bg-transparent px-2 text-xs outline-none placeholder:text-muted-foreground focus:border-primary/50"
754
+ />
755
+ </div>
756
+
757
+ <div className="space-y-1.5">
758
+ <label className="text-[10px] font-semibold tracking-wider uppercase text-muted-foreground">
759
+ Instance Description
760
+ </label>
761
+ <textarea
762
+ value={instance.description}
763
+ onChange={(e) => onUpdate(instance.instanceId, { description: e.target.value })}
764
+ rows={2}
765
+ className="w-full rounded-md border border-border bg-transparent px-2 py-1.5 text-xs outline-none placeholder:text-muted-foreground focus:border-primary/50 resize-none"
766
+ />
767
+ </div>
768
+ </div>
769
+
770
+ {/* Parameters */}
771
+ {paramFields.length > 0 && (
772
+ <div className="space-y-2.5">
773
+ <div className="flex items-center gap-1.5">
774
+ <Wrench className="w-3 h-3 text-muted-foreground" />
775
+ <h4 className="text-[10px] font-semibold tracking-wider uppercase text-muted-foreground">
776
+ Parameters
777
+ </h4>
778
+ </div>
779
+
780
+ <div className="space-y-3">
781
+ {paramFields.map((field: NodeParamField) => {
782
+ const isCredentialField = field.type === 'credential';
783
+ const aiChosenModes =
784
+ (instance.params._aiChosenModes as Record<string, boolean>) ?? {};
785
+ // Credential fields default to NOT ai-chosen; others default to ai-chosen
786
+ const aiChosen = isCredentialField ? false : (aiChosenModes[field.name] ?? true);
787
+
788
+ return (
789
+ <ToolParamField
790
+ key={field.name}
791
+ field={field}
792
+ value={instance.params[field.name]}
793
+ onChange={(value) => {
794
+ onUpdate(instance.instanceId, {
795
+ params: { ...instance.params, [field.name]: value },
796
+ });
797
+ }}
798
+ aiChosen={aiChosen}
799
+ onAiChosenChange={(enabled) => {
800
+ const currentModes =
801
+ (instance.params._aiChosenModes as Record<string, boolean>) ?? {};
802
+ onUpdate(instance.instanceId, {
803
+ params: {
804
+ ...instance.params,
805
+ _aiChosenModes: { ...currentModes, [field.name]: enabled },
806
+ },
807
+ });
808
+ }}
809
+ onAddCredential={onAddCredential}
810
+ />
811
+ );
812
+ })}
813
+ </div>
814
+ </div>
815
+ )}
816
+
817
+ {/* Effective Schema */}
818
+ {tool?.inputSchema && (
819
+ <Collapsible open={showSchema} onOpenChange={setShowSchema}>
820
+ <CollapsibleTrigger className="flex items-center gap-1.5 text-[10px] font-semibold tracking-wider uppercase text-muted-foreground hover:text-foreground transition-colors">
821
+ {showSchema ? (
822
+ <ChevronDown className="w-3 h-3" />
823
+ ) : (
824
+ <ChevronRight className="w-3 h-3" />
825
+ )}
826
+ Effective Schema
827
+ </CollapsibleTrigger>
828
+ <CollapsibleContent className="mt-2">
829
+ <pre className="p-2.5 rounded-md bg-muted/50 border border-border text-[10px] font-mono text-muted-foreground overflow-auto max-h-48">
830
+ {JSON.stringify(effectiveInputSchema, null, 2)}
831
+ </pre>
832
+ </CollapsibleContent>
833
+ </Collapsible>
834
+ )}
835
+ </div>
836
+ );
837
+ }