@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.
- package/LICENSE +21 -0
- package/README.md +77 -0
- package/dist/Invect-CWpIwZ5F.js +92738 -0
- package/dist/Invect.d.ts +25 -0
- package/dist/InvectShell.d.ts +14 -0
- package/dist/api/agent-tools.api.d.ts +1 -0
- package/dist/api/client.d.ts +207 -0
- package/dist/api/credentials.api.d.ts +47 -0
- package/dist/api/executions.api.d.ts +43 -0
- package/dist/api/flows.api.d.ts +100 -0
- package/dist/api/index.d.ts +9 -0
- package/dist/api/node-data.api.d.ts +66 -0
- package/dist/api/query-keys.d.ts +22 -0
- package/dist/api/triggers.api.d.ts +44 -0
- package/dist/api/types.d.ts +147 -0
- package/dist/api/use-flow-run-stream.d.ts +12 -0
- package/dist/assets/invect-branding.d.ts +4 -0
- package/dist/assets/provider-icons/index.d.ts +8 -0
- package/dist/babel-C9OtljFZ.js +9721 -0
- package/dist/components/PageLayout.d.ts +17 -0
- package/dist/components/chat/ChatInput.d.ts +17 -0
- package/dist/components/chat/ChatMessageList.d.ts +14 -0
- package/dist/components/chat/ChatModelSelector.d.ts +11 -0
- package/dist/components/chat/ChatPanel.d.ts +19 -0
- package/dist/components/chat/ChatPromptOverlay.d.ts +13 -0
- package/dist/components/chat/ChatProviderSelector.d.ts +9 -0
- package/dist/components/chat/ChatSettingsPanel.d.ts +11 -0
- package/dist/components/chat/InlineCredentialSetup.d.ts +9 -0
- package/dist/components/chat/MarkdownRenderer.d.ts +7 -0
- package/dist/components/chat/chat-memory.d.ts +21 -0
- package/dist/components/chat/chat.store.d.ts +416 -0
- package/dist/components/chat/index.d.ts +5 -0
- package/dist/components/chat/use-chat.d.ts +28 -0
- package/dist/components/credentials/CreateCredentialModal.d.ts +13 -0
- package/dist/components/credentials/CredentialDetailDialog.d.ts +17 -0
- package/dist/components/credentials/EditCredentialModal.d.ts +11 -0
- package/dist/components/credentials/OAuth2ConnectButton.d.ts +38 -0
- package/dist/components/credentials/OAuth2ProviderSelector.d.ts +15 -0
- package/dist/components/credentials/credential-utils.d.ts +12 -0
- package/dist/components/credentials/index.d.ts +9 -0
- package/dist/components/dashboard/FailedRunsAlert.d.ts +3 -0
- package/dist/components/dashboard/FlowCard.d.ts +7 -0
- package/dist/components/dashboard/RecentActivityTable.d.ts +9 -0
- package/dist/components/dashboard/StatCard.d.ts +10 -0
- package/dist/components/dashboard/index.d.ts +5 -0
- package/dist/components/dashboard/status-helpers.d.ts +5 -0
- package/dist/components/flow-editor/ActionsSidebar.d.ts +2 -0
- package/dist/components/flow-editor/FlowEditor.d.ts +21 -0
- package/dist/components/flow-editor/FlowHeader.d.ts +9 -0
- package/dist/components/flow-editor/FlowLayout.d.ts +24 -0
- package/dist/components/flow-editor/ModeSwitcher.d.ts +7 -0
- package/dist/components/flow-editor/NodeSidebar.d.ts +24 -0
- package/dist/components/flow-editor/RunControls.d.ts +12 -0
- package/dist/components/flow-editor/ToolConfigPanel.d.ts +16 -0
- package/dist/components/flow-editor/ValidationPanel.d.ts +5 -0
- package/dist/components/flow-editor/flow-editor.store.d.ts +1 -0
- package/dist/components/flow-editor/index.d.ts +6 -0
- package/dist/components/flow-editor/inline-edit.d.ts +10 -0
- package/dist/components/flow-editor/node-config-panel/ConfigFieldWithTemplate.d.ts +26 -0
- package/dist/components/flow-editor/node-config-panel/CredentialCombobox.d.ts +21 -0
- package/dist/components/flow-editor/node-config-panel/CredentialsSection.d.ts +19 -0
- package/dist/components/flow-editor/node-config-panel/DroppableInput.d.ts +20 -0
- package/dist/components/flow-editor/node-config-panel/DynamicSelectField.d.ts +22 -0
- package/dist/components/flow-editor/node-config-panel/JsonPreviewPanel.d.ts +25 -0
- package/dist/components/flow-editor/node-config-panel/NodeConfigPanel.d.ts +14 -0
- package/dist/components/flow-editor/node-config-panel/NodeConfigPanelHeader.d.ts +15 -0
- package/dist/components/flow-editor/node-config-panel/ParametersSection.d.ts +16 -0
- package/dist/components/flow-editor/node-config-panel/SearchableSelectField.d.ts +17 -0
- package/dist/components/flow-editor/node-config-panel/SwitchCasesField.d.ts +18 -0
- package/dist/components/flow-editor/node-config-panel/hooks/index.d.ts +2 -0
- package/dist/components/flow-editor/node-config-panel/hooks/use-node-config-panel-state.d.ts +24 -0
- package/dist/components/flow-editor/node-config-panel/hooks/use-node-execution.d.ts +46 -0
- package/dist/components/flow-editor/node-config-panel/hooks/use-upstream-slots.d.ts +16 -0
- package/dist/components/flow-editor/node-config-panel/panels/AgentToolsPanel.d.ts +18 -0
- package/dist/components/flow-editor/node-config-panel/panels/ConfigurationPanel.d.ts +49 -0
- package/dist/components/flow-editor/node-config-panel/panels/DataMapperPane.d.ts +40 -0
- package/dist/components/flow-editor/node-config-panel/panels/InputPanel.d.ts +49 -0
- package/dist/components/flow-editor/node-config-panel/panels/OutputPanel.d.ts +7 -0
- package/dist/components/flow-editor/node-config-panel/panels/index.d.ts +4 -0
- package/dist/components/flow-editor/node-config-panel/types.d.ts +19 -0
- package/dist/components/flow-editor/node-config-panel/use-node-config-panel-store.d.ts +49 -0
- package/dist/components/flow-editor/node-config-panel/use-node-config-state.d.ts +26 -0
- package/dist/components/flow-editor/node-config-panel/use-run-node.d.ts +16 -0
- package/dist/components/flow-editor/node-config-panel/utils.d.ts +9 -0
- package/dist/components/flow-editor/serialize-to-sdk.d.ts +20 -0
- package/dist/components/flow-editor/toolbar-context.d.ts +2 -0
- package/dist/components/flow-editor/use-copy-paste.d.ts +7 -0
- package/dist/components/flow-editor/use-copy-paste.types.d.ts +38 -0
- package/dist/components/flow-editor/use-flow-editor.d.ts +44 -0
- package/dist/components/flow-runs-table/FlowRunsTable.d.ts +6 -0
- package/dist/components/flow-runs-table/index.d.ts +1 -0
- package/dist/components/flow-viewer/FlowRunsView.d.ts +7 -0
- package/dist/components/flow-viewer/FlowStatusView.d.ts +21 -0
- package/dist/components/flow-viewer/RunSelector.d.ts +13 -0
- package/dist/components/flow-viewer/RunsSidebar.d.ts +14 -0
- package/dist/components/flow-viewer/agent-tool-executions-list.d.ts +7 -0
- package/dist/components/flow-viewer/index.d.ts +1 -0
- package/dist/components/flow-viewer/logs-panel.d.ts +18 -0
- package/dist/components/flow-viewer/use-execution-log-data.d.ts +113 -0
- package/dist/components/graph/BatchFlowEdge.d.ts +33 -0
- package/dist/components/graph/LayoutSelector.d.ts +9 -0
- package/dist/components/graph/index.d.ts +47 -0
- package/dist/components/graph/styleUtils.d.ts +124 -0
- package/dist/components/nodes/AgentConfigPanel.d.ts +24 -0
- package/dist/components/nodes/AgentNode.d.ts +8 -0
- package/dist/components/nodes/AgentToolsBox.d.ts +41 -0
- package/dist/components/nodes/NodeAppendix.d.ts +19 -0
- package/dist/components/nodes/NodeStatusIndicator.d.ts +30 -0
- package/dist/components/nodes/NodeViewContext.d.ts +18 -0
- package/dist/components/nodes/ToolParamField.d.ts +28 -0
- package/dist/components/nodes/ToolSelectorModal.d.ts +80 -0
- package/dist/components/nodes/ToolSelectorParts.d.ts +30 -0
- package/dist/components/nodes/UniversalNode.d.ts +2 -0
- package/dist/components/nodes/createContextAwareNodes.d.ts +6 -0
- package/dist/components/nodes/index.d.ts +22 -0
- package/dist/components/nodes/nodeRegistry.d.ts +13 -0
- package/dist/components/nodes/withNodeContext.d.ts +7 -0
- package/dist/components/shared/InvectLoader.d.ts +8 -0
- package/dist/components/shared/InvectLogo.d.ts +9 -0
- package/dist/components/shared/ProviderIcon.d.ts +23 -0
- package/dist/components/side-menu/side-menu.d.ts +4 -0
- package/dist/components/sidebar/BaseSidebar.d.ts +17 -0
- package/dist/components/sidebar/index.d.ts +1 -0
- package/dist/components/triggers/CronPreview.d.ts +12 -0
- package/dist/components/triggers/index.d.ts +1 -0
- package/dist/components/ui/alert-dialog.d.ts +18 -0
- package/dist/components/ui/badge.d.ts +9 -0
- package/dist/components/ui/button.d.ts +13 -0
- package/dist/components/ui/card.d.ts +9 -0
- package/dist/components/ui/codemirror-js-editor.d.ts +25 -0
- package/dist/components/ui/codemirror-json-editor.d.ts +18 -0
- package/dist/components/ui/codemirror-nunjucks-editor.d.ts +13 -0
- package/dist/components/ui/codemirror-vscode-theme.d.ts +24 -0
- package/dist/components/ui/collapsible.d.ts +6 -0
- package/dist/components/ui/command.d.ts +18 -0
- package/dist/components/ui/dialog.d.ts +18 -0
- package/dist/components/ui/dropdown-menu.d.ts +25 -0
- package/dist/components/ui/empty-state.d.ts +21 -0
- package/dist/components/ui/input.d.ts +3 -0
- package/dist/components/ui/label.d.ts +4 -0
- package/dist/components/ui/popover.d.ts +10 -0
- package/dist/components/ui/resizable.d.ts +8 -0
- package/dist/components/ui/scroll-area.d.ts +5 -0
- package/dist/components/ui/select.d.ts +18 -0
- package/dist/components/ui/separator.d.ts +4 -0
- package/dist/components/ui/slider.d.ts +4 -0
- package/dist/components/ui/switch.d.ts +3 -0
- package/dist/components/ui/table.d.ts +10 -0
- package/dist/components/ui/textarea.d.ts +3 -0
- package/dist/components/ui/tooltip.d.ts +7 -0
- package/dist/components/ui/tree-view.d.ts +107 -0
- package/dist/contexts/AgentToolCallbacksContext.d.ts +23 -0
- package/dist/contexts/ApiContext.d.ts +11 -0
- package/dist/contexts/FlowDataContext.d.ts +9 -0
- package/dist/contexts/NodeRegistryContext.d.ts +14 -0
- package/dist/contexts/PluginRegistryContext.d.ts +39 -0
- package/dist/contexts/ThemeProvider.d.ts +18 -0
- package/dist/contexts/ValidationContext.d.ts +22 -0
- package/dist/demo/DemoInvect.d.ts +11 -0
- package/dist/demo/FlowViewer.d.ts +31 -0
- package/dist/demo/demo-api-client.d.ts +33 -0
- package/dist/demo/index.d.ts +6 -0
- package/dist/demo/sample-data.d.ts +1538 -0
- package/dist/demo.d.ts +2 -0
- package/dist/demo.js +2774 -0
- package/dist/estree-ClbRfS-1.js +7076 -0
- package/dist/fonts/geist-cyrillic-wght-normal.woff2 +0 -0
- package/dist/fonts/geist-latin-ext-wght-normal.woff2 +0 -0
- package/dist/fonts/geist-latin-wght-normal.woff2 +0 -0
- package/dist/fonts/iosevka-latin-400-normal.woff2 +0 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/use-document-title.d.ts +1 -0
- package/dist/hooks/use-flow-data.d.ts +22 -0
- package/dist/hooks/use-invect-portal-class.d.ts +21 -0
- package/dist/hooks/useFlowEditorStore.d.ts +1 -0
- package/dist/index.css +3 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +717 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/prettier.d.ts +13 -0
- package/dist/routes/all-flow-runs.d.ts +5 -0
- package/dist/routes/credentials.d.ts +5 -0
- package/dist/routes/flow-route-layout.d.ts +19 -0
- package/dist/routes/flow-runs.d.ts +5 -0
- package/dist/routes/flow.d.ts +5 -0
- package/dist/routes/home.d.ts +5 -0
- package/dist/services/index.d.ts +1 -0
- package/dist/standalone-C3Df7W52.js +3463 -0
- package/dist/stores/executionViewStore.d.ts +64 -0
- package/dist/stores/flow-editor.store.d.ts +137 -0
- package/dist/stores/flowEditorStore.d.ts +1 -0
- package/dist/stores/index.d.ts +2 -0
- package/dist/stores/uiStore.d.ts +45 -0
- package/dist/types/agent-tools.types.d.ts +53 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/node-definition.types.d.ts +85 -0
- package/dist/types/plugin.types.d.ts +100 -0
- package/dist/utils/credentialBranding.d.ts +8 -0
- package/dist/utils/credentialFiltering.d.ts +20 -0
- package/dist/utils/flowTransformations.d.ts +16 -0
- package/dist/utils/layoutUtils.d.ts +23 -0
- package/dist/utils/nodeReferenceUtils.d.ts +37 -0
- package/dist/vendor.d.ts +5 -0
- package/package.json +130 -0
- package/src/.DS_Store +0 -0
- package/src/Invect.tsx +229 -0
- package/src/InvectShell.tsx +55 -0
- package/src/api/agent-tools.api.ts +23 -0
- package/src/api/client.ts +899 -0
- package/src/api/credentials.api.ts +197 -0
- package/src/api/executions.api.ts +228 -0
- package/src/api/flows.api.ts +195 -0
- package/src/api/index.ts +17 -0
- package/src/api/node-data.api.ts +167 -0
- package/src/api/query-keys.ts +44 -0
- package/src/api/triggers.api.ts +120 -0
- package/src/api/types.ts +212 -0
- package/src/api/use-flow-run-stream.ts +206 -0
- package/src/app.css +560 -0
- package/src/assets/.DS_Store +0 -0
- package/src/assets/favicon.ico +0 -0
- package/src/assets/fonts/geist-cyrillic-wght-normal.woff2 +0 -0
- package/src/assets/fonts/geist-latin-ext-wght-normal.woff2 +0 -0
- package/src/assets/fonts/geist-latin-wght-normal.woff2 +0 -0
- package/src/assets/fonts/iosevka-latin-400-normal.woff2 +0 -0
- package/src/assets/invect-branding.ts +51 -0
- package/src/assets/provider-icons/anthropic.svg +1 -0
- package/src/assets/provider-icons/anthropic_light.svg +1 -0
- package/src/assets/provider-icons/github.svg +1 -0
- package/src/assets/provider-icons/github_light.svg +1 -0
- package/src/assets/provider-icons/gmail.svg +1 -0
- package/src/assets/provider-icons/google_calendar.svg +1 -0
- package/src/assets/provider-icons/google_docs.svg +1 -0
- package/src/assets/provider-icons/google_drive.svg +1 -0
- package/src/assets/provider-icons/google_sheets.svg +1 -0
- package/src/assets/provider-icons/index.ts +55 -0
- package/src/assets/provider-icons/linear.svg +1 -0
- package/src/assets/provider-icons/openai.svg +1 -0
- package/src/assets/provider-icons/postgres.svg +1 -0
- package/src/assets/provider-icons/slack.svg +1 -0
- package/src/assets/small-loader-dark.svg +22 -0
- package/src/assets/small-loader-light.svg +22 -0
- package/src/assets/small.svg +7 -0
- package/src/components/.DS_Store +0 -0
- package/src/components/PageLayout.tsx +55 -0
- package/src/components/chat/ChatInput.tsx +115 -0
- package/src/components/chat/ChatMessageList.tsx +788 -0
- package/src/components/chat/ChatModelSelector.tsx +208 -0
- package/src/components/chat/ChatPanel.tsx +243 -0
- package/src/components/chat/ChatPromptOverlay.tsx +150 -0
- package/src/components/chat/ChatProviderSelector.tsx +135 -0
- package/src/components/chat/ChatSettingsPanel.tsx +277 -0
- package/src/components/chat/InlineCredentialSetup.tsx +343 -0
- package/src/components/chat/MarkdownRenderer.tsx +140 -0
- package/src/components/chat/chat-memory.ts +88 -0
- package/src/components/chat/chat.store.ts +479 -0
- package/src/components/chat/index.ts +5 -0
- package/src/components/chat/use-chat.ts +473 -0
- package/src/components/credentials/CreateCredentialModal.tsx +609 -0
- package/src/components/credentials/CredentialDetailDialog.tsx +882 -0
- package/src/components/credentials/EditCredentialModal.tsx +399 -0
- package/src/components/credentials/OAuth2ConnectButton.tsx +288 -0
- package/src/components/credentials/OAuth2ProviderSelector.tsx +360 -0
- package/src/components/credentials/credential-utils.ts +99 -0
- package/src/components/credentials/index.ts +10 -0
- package/src/components/dashboard/FailedRunsAlert.tsx +67 -0
- package/src/components/dashboard/FlowCard.tsx +64 -0
- package/src/components/dashboard/RecentActivityTable.tsx +92 -0
- package/src/components/dashboard/StatCard.tsx +32 -0
- package/src/components/dashboard/index.ts +5 -0
- package/src/components/dashboard/status-helpers.tsx +102 -0
- package/src/components/flow-editor/ActionsSidebar.tsx +503 -0
- package/src/components/flow-editor/FlowEditor.tsx +1002 -0
- package/src/components/flow-editor/FlowHeader.tsx +87 -0
- package/src/components/flow-editor/FlowLayout.tsx +117 -0
- package/src/components/flow-editor/ModeSwitcher.tsx +49 -0
- package/src/components/flow-editor/NodeSidebar.tsx +343 -0
- package/src/components/flow-editor/RunControls.tsx +109 -0
- package/src/components/flow-editor/ToolConfigPanel.tsx +434 -0
- package/src/components/flow-editor/ValidationPanel.tsx +167 -0
- package/src/components/flow-editor/flow-editor.store.ts +2 -0
- package/src/components/flow-editor/index.ts +6 -0
- package/src/components/flow-editor/inline-edit.tsx +111 -0
- package/src/components/flow-editor/node-config-panel/ConfigFieldWithTemplate.tsx +334 -0
- package/src/components/flow-editor/node-config-panel/CredentialCombobox.tsx +217 -0
- package/src/components/flow-editor/node-config-panel/CredentialsSection.tsx +154 -0
- package/src/components/flow-editor/node-config-panel/DroppableInput.tsx +45 -0
- package/src/components/flow-editor/node-config-panel/DynamicSelectField.tsx +223 -0
- package/src/components/flow-editor/node-config-panel/JsonPreviewPanel.tsx +134 -0
- package/src/components/flow-editor/node-config-panel/NodeConfigPanel.tsx +650 -0
- package/src/components/flow-editor/node-config-panel/NodeConfigPanelHeader.tsx +91 -0
- package/src/components/flow-editor/node-config-panel/ParametersSection.tsx +144 -0
- package/src/components/flow-editor/node-config-panel/SearchableSelectField.tsx +126 -0
- package/src/components/flow-editor/node-config-panel/SwitchCasesField.tsx +212 -0
- package/src/components/flow-editor/node-config-panel/hooks/index.ts +2 -0
- package/src/components/flow-editor/node-config-panel/hooks/use-node-config-panel-state.ts +284 -0
- package/src/components/flow-editor/node-config-panel/hooks/use-node-execution.ts +287 -0
- package/src/components/flow-editor/node-config-panel/hooks/use-upstream-slots.ts +310 -0
- package/src/components/flow-editor/node-config-panel/panels/AgentToolsPanel.tsx +837 -0
- package/src/components/flow-editor/node-config-panel/panels/ConfigurationPanel.tsx +383 -0
- package/src/components/flow-editor/node-config-panel/panels/DataMapperPane.tsx +456 -0
- package/src/components/flow-editor/node-config-panel/panels/InputPanel.tsx +338 -0
- package/src/components/flow-editor/node-config-panel/panels/OutputPanel.tsx +109 -0
- package/src/components/flow-editor/node-config-panel/panels/index.ts +4 -0
- package/src/components/flow-editor/node-config-panel/types.ts +20 -0
- package/src/components/flow-editor/node-config-panel/use-node-config-panel-store.ts +283 -0
- package/src/components/flow-editor/node-config-panel/use-node-config-state.ts +172 -0
- package/src/components/flow-editor/node-config-panel/use-run-node.ts +147 -0
- package/src/components/flow-editor/node-config-panel/utils.ts +73 -0
- package/src/components/flow-editor/serialize-to-sdk.ts +204 -0
- package/src/components/flow-editor/toolbar-context.ts +9 -0
- package/src/components/flow-editor/use-copy-paste.ts +575 -0
- package/src/components/flow-editor/use-copy-paste.types.ts +35 -0
- package/src/components/flow-editor/use-flow-editor.ts +241 -0
- package/src/components/flow-runs-table/FlowRunsTable.tsx +631 -0
- package/src/components/flow-runs-table/index.ts +1 -0
- package/src/components/flow-viewer/FlowRunsView.tsx +268 -0
- package/src/components/flow-viewer/FlowStatusView.tsx +351 -0
- package/src/components/flow-viewer/RunSelector.tsx +422 -0
- package/src/components/flow-viewer/RunsSidebar.tsx +125 -0
- package/src/components/flow-viewer/agent-tool-executions-list.tsx +298 -0
- package/src/components/flow-viewer/index.ts +1 -0
- package/src/components/flow-viewer/logs-panel.tsx +567 -0
- package/src/components/flow-viewer/use-execution-log-data.ts +374 -0
- package/src/components/graph/BatchFlowEdge.tsx +229 -0
- package/src/components/graph/LayoutSelector.tsx +42 -0
- package/src/components/graph/index.ts +61 -0
- package/src/components/graph/styleUtils.ts +375 -0
- package/src/components/nodes/.DS_Store +0 -0
- package/src/components/nodes/AgentConfigPanel.tsx +1033 -0
- package/src/components/nodes/AgentNode.tsx +298 -0
- package/src/components/nodes/AgentToolsBox.tsx +193 -0
- package/src/components/nodes/NodeAppendix.tsx +98 -0
- package/src/components/nodes/NodeStatusIndicator.tsx +74 -0
- package/src/components/nodes/NodeViewContext.tsx +45 -0
- package/src/components/nodes/ToolParamField.tsx +282 -0
- package/src/components/nodes/ToolSelectorModal.tsx +648 -0
- package/src/components/nodes/ToolSelectorParts.tsx +505 -0
- package/src/components/nodes/UniversalNode.tsx +356 -0
- package/src/components/nodes/createContextAwareNodes.ts +19 -0
- package/src/components/nodes/index.ts +45 -0
- package/src/components/nodes/nodeRegistry.ts +50 -0
- package/src/components/nodes/withNodeContext.tsx +55 -0
- package/src/components/shared/InvectLoader.tsx +59 -0
- package/src/components/shared/InvectLogo.tsx +59 -0
- package/src/components/shared/ProviderIcon.tsx +115 -0
- package/src/components/side-menu/side-menu.tsx +267 -0
- package/src/components/sidebar/BaseSidebar.tsx +148 -0
- package/src/components/sidebar/index.ts +1 -0
- package/src/components/triggers/CronPreview.tsx +243 -0
- package/src/components/triggers/index.ts +1 -0
- package/src/components/ui/alert-dialog.tsx +152 -0
- package/src/components/ui/badge.tsx +39 -0
- package/src/components/ui/button.tsx +58 -0
- package/src/components/ui/card.tsx +75 -0
- package/src/components/ui/codemirror-js-editor.tsx +432 -0
- package/src/components/ui/codemirror-json-editor.tsx +816 -0
- package/src/components/ui/codemirror-nunjucks-editor.tsx +451 -0
- package/src/components/ui/codemirror-vscode-theme.ts +243 -0
- package/src/components/ui/collapsible.tsx +12 -0
- package/src/components/ui/command.tsx +162 -0
- package/src/components/ui/dialog.tsx +140 -0
- package/src/components/ui/dropdown-menu.tsx +232 -0
- package/src/components/ui/empty-state.tsx +93 -0
- package/src/components/ui/input.tsx +26 -0
- package/src/components/ui/label.tsx +19 -0
- package/src/components/ui/popover.tsx +53 -0
- package/src/components/ui/resizable.tsx +61 -0
- package/src/components/ui/scroll-area.tsx +56 -0
- package/src/components/ui/select.tsx +179 -0
- package/src/components/ui/separator.tsx +26 -0
- package/src/components/ui/slider.tsx +58 -0
- package/src/components/ui/switch.tsx +22 -0
- package/src/components/ui/table.tsx +90 -0
- package/src/components/ui/textarea.tsx +23 -0
- package/src/components/ui/tooltip.tsx +54 -0
- package/src/components/ui/tree-view.tsx +574 -0
- package/src/contexts/AgentToolCallbacksContext.tsx +31 -0
- package/src/contexts/ApiContext.tsx +51 -0
- package/src/contexts/FlowDataContext.tsx +21 -0
- package/src/contexts/NodeRegistryContext.tsx +54 -0
- package/src/contexts/PluginRegistryContext.tsx +182 -0
- package/src/contexts/ThemeProvider.tsx +106 -0
- package/src/contexts/ValidationContext.tsx +122 -0
- package/src/demo/DemoInvect.tsx +42 -0
- package/src/demo/FlowViewer.tsx +294 -0
- package/src/demo/demo-api-client.ts +246 -0
- package/src/demo/index.ts +28 -0
- package/src/demo/sample-data.ts +1980 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/use-document-title.ts +8 -0
- package/src/hooks/use-flow-data.ts +144 -0
- package/src/hooks/use-invect-portal-class.ts +27 -0
- package/src/hooks/useFlowEditorStore.ts +2 -0
- package/src/index.ts +70 -0
- package/src/lib/utils.ts +6 -0
- package/src/prettier.d.ts +13 -0
- package/src/routes/all-flow-runs.tsx +27 -0
- package/src/routes/credentials.tsx +362 -0
- package/src/routes/flow-route-layout.tsx +113 -0
- package/src/routes/flow-runs.tsx +22 -0
- package/src/routes/flow.tsx +22 -0
- package/src/routes/home.tsx +282 -0
- package/src/services/index.ts +6 -0
- package/src/stores/executionViewStore.ts +211 -0
- package/src/stores/flow-editor.store.ts +738 -0
- package/src/stores/flowEditorStore.ts +2 -0
- package/src/stores/index.ts +10 -0
- package/src/stores/uiStore.ts +189 -0
- package/src/types/agent-tools.types.ts +64 -0
- package/src/types/index.ts +5 -0
- package/src/types/node-definition.types.ts +104 -0
- package/src/types/plugin.types.ts +123 -0
- package/src/utils/credentialBranding.ts +116 -0
- package/src/utils/credentialFiltering.ts +68 -0
- package/src/utils/flowTransformations.ts +137 -0
- package/src/utils/layoutUtils.ts +127 -0
- package/src/utils/nodeReferenceUtils.ts +135 -0
- package/src/vendor.d.ts +7 -0
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* InlineCredentialSetup — Inline form for creating an LLM credential
|
|
3
|
+
* directly inside the chat panel (no modal, no navigation).
|
|
4
|
+
*
|
|
5
|
+
* If existing LLM credentials exist, shows a quick picker first.
|
|
6
|
+
* Otherwise shows: Provider (OpenAI/Anthropic/OpenRouter), Name, API Key.
|
|
7
|
+
* On submit: creates credential → validates via list-models → auto-selects.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import React, { useState, useCallback } from 'react';
|
|
11
|
+
import {
|
|
12
|
+
KeyRound,
|
|
13
|
+
Loader2,
|
|
14
|
+
CheckCircle2,
|
|
15
|
+
AlertCircle,
|
|
16
|
+
Eye,
|
|
17
|
+
EyeOff,
|
|
18
|
+
Plus,
|
|
19
|
+
ChevronRight,
|
|
20
|
+
} from 'lucide-react';
|
|
21
|
+
import { Button } from '~/components/ui/button';
|
|
22
|
+
import { Input } from '~/components/ui/input';
|
|
23
|
+
import {
|
|
24
|
+
Select,
|
|
25
|
+
SelectContent,
|
|
26
|
+
SelectItem,
|
|
27
|
+
SelectTrigger,
|
|
28
|
+
SelectValue,
|
|
29
|
+
} from '~/components/ui/select';
|
|
30
|
+
import { useApiClient } from '~/contexts/ApiContext';
|
|
31
|
+
import { useCredentials, useCreateCredential } from '~/api/credentials.api';
|
|
32
|
+
import { useChatStore } from './chat.store';
|
|
33
|
+
|
|
34
|
+
// =====================================
|
|
35
|
+
// Provider presets
|
|
36
|
+
// =====================================
|
|
37
|
+
|
|
38
|
+
const LLM_PROVIDERS = [
|
|
39
|
+
{ value: 'openai', label: 'OpenAI', placeholder: 'sk-...' },
|
|
40
|
+
{ value: 'anthropic', label: 'Anthropic', placeholder: 'sk-ant-...' },
|
|
41
|
+
{ value: 'openrouter', label: 'OpenRouter', placeholder: 'sk-or-...' },
|
|
42
|
+
] as const;
|
|
43
|
+
|
|
44
|
+
type LlmProvider = (typeof LLM_PROVIDERS)[number]['value'];
|
|
45
|
+
|
|
46
|
+
function getDefaultName(provider: LlmProvider): string {
|
|
47
|
+
const label = LLM_PROVIDERS.find((p) => p.value === provider)?.label ?? provider;
|
|
48
|
+
return `${label} (Chat)`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function getBaseUrl(provider: LlmProvider): string | undefined {
|
|
52
|
+
if (provider === 'openrouter') {
|
|
53
|
+
return 'https://openrouter.ai/api/v1';
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// =====================================
|
|
59
|
+
// Component
|
|
60
|
+
// =====================================
|
|
61
|
+
|
|
62
|
+
type FormState = 'idle' | 'creating' | 'validating' | 'success' | 'error';
|
|
63
|
+
|
|
64
|
+
export function InlineCredentialSetup() {
|
|
65
|
+
const { data: existingCredentials = [] } = useCredentials({ type: 'llm', isActive: true });
|
|
66
|
+
const [showCreateForm, setShowCreateForm] = useState(false);
|
|
67
|
+
|
|
68
|
+
// If existing credentials exist and user hasn't clicked "create new", show the picker
|
|
69
|
+
if (existingCredentials.length > 0 && !showCreateForm) {
|
|
70
|
+
return (
|
|
71
|
+
<ExistingCredentialPicker
|
|
72
|
+
credentials={existingCredentials}
|
|
73
|
+
onCreateNew={() => setShowCreateForm(true)}
|
|
74
|
+
/>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<CreateCredentialForm
|
|
80
|
+
onBack={existingCredentials.length > 0 ? () => setShowCreateForm(false) : undefined}
|
|
81
|
+
/>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// =====================================
|
|
86
|
+
// ExistingCredentialPicker
|
|
87
|
+
// =====================================
|
|
88
|
+
|
|
89
|
+
function ExistingCredentialPicker({
|
|
90
|
+
credentials,
|
|
91
|
+
onCreateNew,
|
|
92
|
+
}: {
|
|
93
|
+
credentials: Array<{ id: string; name: string }>;
|
|
94
|
+
onCreateNew: () => void;
|
|
95
|
+
}) {
|
|
96
|
+
const handleSelect = useCallback((id: string) => {
|
|
97
|
+
useChatStore.getState().updateSettings({ credentialId: id });
|
|
98
|
+
}, []);
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<div className="flex flex-col gap-3 rounded-xl border bg-muted/20 p-4 mx-2 w-full max-w-sm">
|
|
102
|
+
<div className="flex flex-col items-center gap-2 pb-1">
|
|
103
|
+
<div className="flex size-9 items-center justify-center rounded-full bg-primary/10">
|
|
104
|
+
<KeyRound className="size-4 text-primary" />
|
|
105
|
+
</div>
|
|
106
|
+
<div className="text-center">
|
|
107
|
+
<p className="text-sm font-semibold text-foreground">Select an LLM provider</p>
|
|
108
|
+
<p className="mt-0.5 text-[11px] text-muted-foreground">
|
|
109
|
+
Choose a credential to power the chat assistant.
|
|
110
|
+
</p>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
|
|
114
|
+
<div className="flex flex-col gap-1.5">
|
|
115
|
+
{credentials.map((c) => (
|
|
116
|
+
<button
|
|
117
|
+
key={c.id}
|
|
118
|
+
type="button"
|
|
119
|
+
onClick={() => handleSelect(c.id)}
|
|
120
|
+
className="flex items-center gap-2 px-3 py-2 text-xs text-left transition-colors border rounded-lg text-foreground/80 border-border/50 bg-background hover:bg-accent/50 hover:border-border"
|
|
121
|
+
>
|
|
122
|
+
<KeyRound className="size-3 text-muted-foreground/50 shrink-0" />
|
|
123
|
+
<span className="flex-1 truncate">{c.name}</span>
|
|
124
|
+
<ChevronRight className="size-3 text-muted-foreground/40 shrink-0" />
|
|
125
|
+
</button>
|
|
126
|
+
))}
|
|
127
|
+
</div>
|
|
128
|
+
|
|
129
|
+
<div className="relative flex items-center gap-2 py-0.5">
|
|
130
|
+
<div className="flex-1 border-t border-border/40" />
|
|
131
|
+
<span className="text-[10px] text-muted-foreground/60">or</span>
|
|
132
|
+
<div className="flex-1 border-t border-border/40" />
|
|
133
|
+
</div>
|
|
134
|
+
|
|
135
|
+
<Button variant="outline" size="sm" className="w-full gap-1.5 text-xs" onClick={onCreateNew}>
|
|
136
|
+
<Plus className="size-3.5" />
|
|
137
|
+
Add New Provider
|
|
138
|
+
</Button>
|
|
139
|
+
</div>
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// =====================================
|
|
144
|
+
// CreateCredentialForm
|
|
145
|
+
// =====================================
|
|
146
|
+
|
|
147
|
+
function CreateCredentialForm({ onBack }: { onBack?: () => void }) {
|
|
148
|
+
const apiClient = useApiClient();
|
|
149
|
+
const createCredential = useCreateCredential();
|
|
150
|
+
|
|
151
|
+
const [provider, setProvider] = useState<LlmProvider>('openai');
|
|
152
|
+
const [name, setName] = useState('');
|
|
153
|
+
const [apiKey, setApiKey] = useState('');
|
|
154
|
+
const [showKey, setShowKey] = useState(false);
|
|
155
|
+
const [formState, setFormState] = useState<FormState>('idle');
|
|
156
|
+
const [errorMsg, setErrorMsg] = useState('');
|
|
157
|
+
const [modelCount, setModelCount] = useState(0);
|
|
158
|
+
|
|
159
|
+
const effectiveName = name.trim() || getDefaultName(provider);
|
|
160
|
+
const canSubmit =
|
|
161
|
+
apiKey.trim().length > 0 && formState !== 'creating' && formState !== 'validating';
|
|
162
|
+
|
|
163
|
+
const handleSubmit = useCallback(
|
|
164
|
+
async (e: React.FormEvent) => {
|
|
165
|
+
e.preventDefault();
|
|
166
|
+
if (!canSubmit) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
setErrorMsg('');
|
|
171
|
+
setFormState('creating');
|
|
172
|
+
|
|
173
|
+
try {
|
|
174
|
+
// 1. Create the credential
|
|
175
|
+
const credential = await createCredential.mutateAsync({
|
|
176
|
+
name: effectiveName,
|
|
177
|
+
type: 'llm',
|
|
178
|
+
authType: 'apiKey',
|
|
179
|
+
config: {
|
|
180
|
+
apiKey: apiKey.trim(),
|
|
181
|
+
...(getBaseUrl(provider) ? { baseUrl: getBaseUrl(provider) } : {}),
|
|
182
|
+
},
|
|
183
|
+
metadata: { provider },
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// 2. Validate by listing models
|
|
187
|
+
setFormState('validating');
|
|
188
|
+
try {
|
|
189
|
+
const models = await apiClient.getChatModels(credential.id);
|
|
190
|
+
setModelCount(models.length);
|
|
191
|
+
} catch {
|
|
192
|
+
// Key created but validation failed — still usable, warn user
|
|
193
|
+
setModelCount(0);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// 3. Auto-select in chat settings
|
|
197
|
+
useChatStore.getState().updateSettings({ credentialId: credential.id });
|
|
198
|
+
|
|
199
|
+
setFormState('success');
|
|
200
|
+
} catch (err: unknown) {
|
|
201
|
+
setFormState('error');
|
|
202
|
+
setErrorMsg((err as Error).message || 'Failed to create credential');
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
[canSubmit, effectiveName, apiKey, provider, createCredential, apiClient],
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
// After success, show brief confirmation then the chat will re-render
|
|
209
|
+
// (because hasConfiguredCredential becomes true via the store update)
|
|
210
|
+
if (formState === 'success') {
|
|
211
|
+
return (
|
|
212
|
+
<div className="flex flex-col items-center gap-3 rounded-xl border bg-muted/20 p-5 mx-2 w-full max-w-sm">
|
|
213
|
+
<div className="flex size-10 items-center justify-center rounded-full bg-success/10">
|
|
214
|
+
<CheckCircle2 className="size-5 text-success" />
|
|
215
|
+
</div>
|
|
216
|
+
<div className="text-center">
|
|
217
|
+
<p className="text-sm font-semibold text-foreground">Provider connected</p>
|
|
218
|
+
<p className="mt-1 text-xs text-muted-foreground">
|
|
219
|
+
{modelCount > 0
|
|
220
|
+
? `API key verified — ${modelCount} models available.`
|
|
221
|
+
: 'Credential saved. You can start chatting now.'}
|
|
222
|
+
</p>
|
|
223
|
+
</div>
|
|
224
|
+
</div>
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return (
|
|
229
|
+
<form
|
|
230
|
+
onSubmit={handleSubmit}
|
|
231
|
+
className="flex flex-col gap-3.5 rounded-xl border bg-muted/20 p-4 mx-2 w-full max-w-sm"
|
|
232
|
+
>
|
|
233
|
+
{/* Header */}
|
|
234
|
+
<div className="flex flex-col items-center gap-2 pb-1">
|
|
235
|
+
<div className="flex size-9 items-center justify-center rounded-full bg-primary/10">
|
|
236
|
+
<KeyRound className="size-4 text-primary" />
|
|
237
|
+
</div>
|
|
238
|
+
<div className="text-center">
|
|
239
|
+
<p className="text-sm font-semibold text-foreground">Connect an LLM provider</p>
|
|
240
|
+
<p className="mt-0.5 text-[11px] text-muted-foreground">
|
|
241
|
+
Add an API key to start chatting with the assistant.
|
|
242
|
+
</p>
|
|
243
|
+
</div>
|
|
244
|
+
</div>
|
|
245
|
+
|
|
246
|
+
{/* Provider */}
|
|
247
|
+
<div className="space-y-1">
|
|
248
|
+
<label className="text-[11px] font-medium text-muted-foreground">Provider</label>
|
|
249
|
+
<Select
|
|
250
|
+
value={provider}
|
|
251
|
+
onValueChange={(v) => {
|
|
252
|
+
setProvider(v as LlmProvider);
|
|
253
|
+
if (!name.trim()) {
|
|
254
|
+
setName('');
|
|
255
|
+
}
|
|
256
|
+
}}
|
|
257
|
+
>
|
|
258
|
+
<SelectTrigger className="h-8 text-xs">
|
|
259
|
+
<SelectValue />
|
|
260
|
+
</SelectTrigger>
|
|
261
|
+
<SelectContent>
|
|
262
|
+
{LLM_PROVIDERS.map((p) => (
|
|
263
|
+
<SelectItem key={p.value} value={p.value}>
|
|
264
|
+
{p.label}
|
|
265
|
+
</SelectItem>
|
|
266
|
+
))}
|
|
267
|
+
</SelectContent>
|
|
268
|
+
</Select>
|
|
269
|
+
</div>
|
|
270
|
+
|
|
271
|
+
{/* Name */}
|
|
272
|
+
<div className="space-y-1">
|
|
273
|
+
<label className="text-[11px] font-medium text-muted-foreground">Name</label>
|
|
274
|
+
<Input
|
|
275
|
+
value={name}
|
|
276
|
+
onChange={(e) => setName(e.target.value)}
|
|
277
|
+
placeholder={getDefaultName(provider)}
|
|
278
|
+
className="h-8 text-xs"
|
|
279
|
+
/>
|
|
280
|
+
</div>
|
|
281
|
+
|
|
282
|
+
{/* API Key */}
|
|
283
|
+
<div className="space-y-1">
|
|
284
|
+
<label className="text-[11px] font-medium text-muted-foreground">API Key</label>
|
|
285
|
+
<div className="relative">
|
|
286
|
+
<Input
|
|
287
|
+
type={showKey ? 'text' : 'password'}
|
|
288
|
+
value={apiKey}
|
|
289
|
+
onChange={(e) => setApiKey(e.target.value)}
|
|
290
|
+
placeholder={LLM_PROVIDERS.find((p) => p.value === provider)?.placeholder ?? 'sk-...'}
|
|
291
|
+
className="h-8 pr-8 text-xs font-mono"
|
|
292
|
+
autoComplete="off"
|
|
293
|
+
spellCheck={false}
|
|
294
|
+
/>
|
|
295
|
+
<button
|
|
296
|
+
type="button"
|
|
297
|
+
onClick={() => setShowKey((s) => !s)}
|
|
298
|
+
className="absolute right-2 top-1/2 -translate-y-1/2 text-muted-foreground/60 hover:text-muted-foreground transition-colors"
|
|
299
|
+
tabIndex={-1}
|
|
300
|
+
>
|
|
301
|
+
{showKey ? <EyeOff className="size-3.5" /> : <Eye className="size-3.5" />}
|
|
302
|
+
</button>
|
|
303
|
+
</div>
|
|
304
|
+
</div>
|
|
305
|
+
|
|
306
|
+
{/* Error */}
|
|
307
|
+
{formState === 'error' && errorMsg && (
|
|
308
|
+
<div className="flex items-start gap-2 rounded-lg bg-destructive/10 px-3 py-2 text-xs text-destructive">
|
|
309
|
+
<AlertCircle className="mt-0.5 size-3.5 shrink-0" />
|
|
310
|
+
<span>{errorMsg}</span>
|
|
311
|
+
</div>
|
|
312
|
+
)}
|
|
313
|
+
|
|
314
|
+
{/* Submit */}
|
|
315
|
+
<Button type="submit" size="sm" className="w-full gap-1.5 text-xs" disabled={!canSubmit}>
|
|
316
|
+
{formState === 'creating' ? (
|
|
317
|
+
<>
|
|
318
|
+
<Loader2 className="size-3.5 animate-spin" />
|
|
319
|
+
Saving…
|
|
320
|
+
</>
|
|
321
|
+
) : formState === 'validating' ? (
|
|
322
|
+
<>
|
|
323
|
+
<Loader2 className="size-3.5 animate-spin" />
|
|
324
|
+
Verifying key…
|
|
325
|
+
</>
|
|
326
|
+
) : (
|
|
327
|
+
'Connect Provider'
|
|
328
|
+
)}
|
|
329
|
+
</Button>
|
|
330
|
+
|
|
331
|
+
{/* Back link */}
|
|
332
|
+
{onBack && (
|
|
333
|
+
<button
|
|
334
|
+
type="button"
|
|
335
|
+
onClick={onBack}
|
|
336
|
+
className="text-[11px] text-muted-foreground hover:text-foreground transition-colors"
|
|
337
|
+
>
|
|
338
|
+
← Back to existing providers
|
|
339
|
+
</button>
|
|
340
|
+
)}
|
|
341
|
+
</form>
|
|
342
|
+
);
|
|
343
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MarkdownRenderer — renders markdown content with theme-aware styling.
|
|
3
|
+
*
|
|
4
|
+
* Uses react-markdown + remark-gfm for full GitHub-flavored markdown support.
|
|
5
|
+
* All styles use CSS variables from the tailwind theme so they adapt to
|
|
6
|
+
* light/dark mode automatically.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import React, { memo } from 'react';
|
|
10
|
+
import ReactMarkdown from 'react-markdown';
|
|
11
|
+
import remarkGfm from 'remark-gfm';
|
|
12
|
+
import { cn } from '~/lib/utils';
|
|
13
|
+
|
|
14
|
+
interface MarkdownRendererProps {
|
|
15
|
+
content: string;
|
|
16
|
+
className?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const MarkdownRenderer = memo(function MarkdownRenderer({
|
|
20
|
+
content,
|
|
21
|
+
className,
|
|
22
|
+
}: MarkdownRendererProps) {
|
|
23
|
+
return (
|
|
24
|
+
<div className={cn('chat-markdown w-full min-w-0 overflow-hidden break-words', className)}>
|
|
25
|
+
<ReactMarkdown
|
|
26
|
+
remarkPlugins={[remarkGfm]}
|
|
27
|
+
components={{
|
|
28
|
+
// Paragraphs
|
|
29
|
+
p: ({ children }) => (
|
|
30
|
+
<p className="mb-2 leading-relaxed break-words last:mb-0">{children}</p>
|
|
31
|
+
),
|
|
32
|
+
|
|
33
|
+
// Headings
|
|
34
|
+
h1: ({ children }) => (
|
|
35
|
+
<h1 className="mt-3 mb-2 text-base font-bold first:mt-0 text-foreground">{children}</h1>
|
|
36
|
+
),
|
|
37
|
+
h2: ({ children }) => (
|
|
38
|
+
<h2 className="text-sm font-bold mb-1.5 mt-2.5 first:mt-0 text-foreground">
|
|
39
|
+
{children}
|
|
40
|
+
</h2>
|
|
41
|
+
),
|
|
42
|
+
h3: ({ children }) => (
|
|
43
|
+
<h3 className="mt-2 mb-1 text-sm font-semibold first:mt-0 text-foreground">
|
|
44
|
+
{children}
|
|
45
|
+
</h3>
|
|
46
|
+
),
|
|
47
|
+
|
|
48
|
+
// Inline code
|
|
49
|
+
code: ({ children, className: codeClassName }) => {
|
|
50
|
+
// Detect if this is inside a <pre> (fenced code block)
|
|
51
|
+
const isBlock = codeClassName?.startsWith('language-');
|
|
52
|
+
if (isBlock) {
|
|
53
|
+
return <code className={cn('text-[11px]', codeClassName)}>{children}</code>;
|
|
54
|
+
}
|
|
55
|
+
return (
|
|
56
|
+
<code className="px-1 py-0.5 rounded-sm bg-muted text-foreground text-[11px] font-medium break-all">
|
|
57
|
+
{children}
|
|
58
|
+
</code>
|
|
59
|
+
);
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
// Code blocks
|
|
63
|
+
pre: ({ children }) => (
|
|
64
|
+
<pre className="mb-2 last:mb-0 p-2.5 rounded-sm bg-muted border border-border text-[11px] leading-relaxed overflow-x-auto max-w-full">
|
|
65
|
+
{children}
|
|
66
|
+
</pre>
|
|
67
|
+
),
|
|
68
|
+
|
|
69
|
+
// Lists
|
|
70
|
+
ul: ({ children }) => (
|
|
71
|
+
<ul className="mb-2 last:mb-0 pl-6 list-disc space-y-0.5 marker:text-muted-foreground">
|
|
72
|
+
{children}
|
|
73
|
+
</ul>
|
|
74
|
+
),
|
|
75
|
+
ol: ({ children }) => (
|
|
76
|
+
<ol className="mb-2 last:mb-0 pl-6 list-decimal space-y-0.5 marker:text-muted-foreground">
|
|
77
|
+
{children}
|
|
78
|
+
</ol>
|
|
79
|
+
),
|
|
80
|
+
li: ({ children }) => <li className="leading-relaxed break-words">{children}</li>,
|
|
81
|
+
|
|
82
|
+
// Blockquotes
|
|
83
|
+
blockquote: ({ children }) => (
|
|
84
|
+
<blockquote className="pl-3 mb-2 italic border-l-2 last:mb-0 border-border text-muted-foreground">
|
|
85
|
+
{children}
|
|
86
|
+
</blockquote>
|
|
87
|
+
),
|
|
88
|
+
|
|
89
|
+
// Links
|
|
90
|
+
a: ({ href, children }) => (
|
|
91
|
+
<a
|
|
92
|
+
href={href}
|
|
93
|
+
target="_blank"
|
|
94
|
+
rel="noopener noreferrer"
|
|
95
|
+
className="underline transition-colors text-primary underline-offset-2 hover:text-foreground"
|
|
96
|
+
>
|
|
97
|
+
{children}
|
|
98
|
+
</a>
|
|
99
|
+
),
|
|
100
|
+
|
|
101
|
+
// Bold & emphasis
|
|
102
|
+
strong: ({ children }) => (
|
|
103
|
+
<strong className="font-semibold text-foreground">{children}</strong>
|
|
104
|
+
),
|
|
105
|
+
em: ({ children }) => <em className="italic">{children}</em>,
|
|
106
|
+
|
|
107
|
+
// Horizontal rule
|
|
108
|
+
hr: () => <hr className="my-3 border-border" />,
|
|
109
|
+
|
|
110
|
+
// Tables
|
|
111
|
+
table: ({ children }) => (
|
|
112
|
+
<div className="max-w-full mb-2 overflow-x-auto last:mb-0">
|
|
113
|
+
<table className="w-full text-[11px] border-collapse border border-border">
|
|
114
|
+
{children}
|
|
115
|
+
</table>
|
|
116
|
+
</div>
|
|
117
|
+
),
|
|
118
|
+
thead: ({ children }) => <thead className="bg-muted">{children}</thead>,
|
|
119
|
+
th: ({ children }) => (
|
|
120
|
+
<th className="px-2 py-1 font-semibold text-left border border-border text-foreground">
|
|
121
|
+
{children}
|
|
122
|
+
</th>
|
|
123
|
+
),
|
|
124
|
+
td: ({ children }) => <td className="px-2 py-1 border border-border">{children}</td>,
|
|
125
|
+
|
|
126
|
+
// Images — basic support
|
|
127
|
+
img: ({ src, alt }) => (
|
|
128
|
+
<img
|
|
129
|
+
src={src}
|
|
130
|
+
alt={alt ?? ''}
|
|
131
|
+
className="max-w-full my-1 border rounded-sm border-border"
|
|
132
|
+
/>
|
|
133
|
+
),
|
|
134
|
+
}}
|
|
135
|
+
>
|
|
136
|
+
{content}
|
|
137
|
+
</ReactMarkdown>
|
|
138
|
+
</div>
|
|
139
|
+
);
|
|
140
|
+
});
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chat Memory — Browser-local persistence via localStorage.
|
|
3
|
+
*
|
|
4
|
+
* Stores notes in two scopes:
|
|
5
|
+
* - Flow-scoped: localStorage key = `invect:chat-memory:flow:<flowId>`
|
|
6
|
+
* - Workspace-scoped: localStorage key = `invect:chat-memory:workspace`
|
|
7
|
+
*
|
|
8
|
+
* Each key stores a JSON array of strings (the note contents).
|
|
9
|
+
* Maximum 50 notes per scope to prevent unbounded growth.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const FLOW_KEY_PREFIX = 'invect:chat-memory:flow:';
|
|
13
|
+
const WORKSPACE_KEY = 'invect:chat-memory:workspace';
|
|
14
|
+
const MAX_NOTES = 50;
|
|
15
|
+
|
|
16
|
+
function getKey(scope: 'flow' | 'workspace', flowId?: string): string {
|
|
17
|
+
if (scope === 'flow') {
|
|
18
|
+
if (!flowId) {
|
|
19
|
+
throw new Error('flowId required for flow-scoped memory');
|
|
20
|
+
}
|
|
21
|
+
return `${FLOW_KEY_PREFIX}${flowId}`;
|
|
22
|
+
}
|
|
23
|
+
return WORKSPACE_KEY;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function readNotes(key: string): string[] {
|
|
27
|
+
try {
|
|
28
|
+
const raw = localStorage.getItem(key);
|
|
29
|
+
if (!raw) {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
const parsed = JSON.parse(raw);
|
|
33
|
+
return Array.isArray(parsed) ? parsed.filter((n): n is string => typeof n === 'string') : [];
|
|
34
|
+
} catch {
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function writeNotes(key: string, notes: string[]): void {
|
|
40
|
+
localStorage.setItem(key, JSON.stringify(notes.slice(0, MAX_NOTES)));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// =====================================
|
|
44
|
+
// Public API
|
|
45
|
+
// =====================================
|
|
46
|
+
|
|
47
|
+
export function getMemoryNotes(scope: 'flow' | 'workspace', flowId?: string): string[] {
|
|
48
|
+
return readNotes(getKey(scope, flowId));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function saveMemoryNote(
|
|
52
|
+
scope: 'flow' | 'workspace',
|
|
53
|
+
content: string,
|
|
54
|
+
flowId?: string,
|
|
55
|
+
): void {
|
|
56
|
+
const key = getKey(scope, flowId);
|
|
57
|
+
const notes = readNotes(key);
|
|
58
|
+
// Avoid duplicates
|
|
59
|
+
if (!notes.includes(content)) {
|
|
60
|
+
notes.push(content);
|
|
61
|
+
writeNotes(key, notes);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function deleteMemoryNote(
|
|
66
|
+
scope: 'flow' | 'workspace',
|
|
67
|
+
content: string,
|
|
68
|
+
flowId?: string,
|
|
69
|
+
): void {
|
|
70
|
+
const key = getKey(scope, flowId);
|
|
71
|
+
const notes = readNotes(key);
|
|
72
|
+
const filtered = notes.filter((n) => n !== content);
|
|
73
|
+
writeNotes(key, filtered);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Get all memory notes for a flow (flow-scoped + workspace-scoped).
|
|
78
|
+
* Returns the shape expected by ChatContext.memoryNotes.
|
|
79
|
+
*/
|
|
80
|
+
export function getAllMemoryNotes(flowId?: string): {
|
|
81
|
+
flowNotes: string[];
|
|
82
|
+
workspaceNotes: string[];
|
|
83
|
+
} {
|
|
84
|
+
return {
|
|
85
|
+
flowNotes: flowId ? getMemoryNotes('flow', flowId) : [],
|
|
86
|
+
workspaceNotes: getMemoryNotes('workspace'),
|
|
87
|
+
};
|
|
88
|
+
}
|