@parhelia/core 0.1.11004 → 0.1.11007
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/dist/dist/agents-view/AgentCard.d.ts +12 -0
- package/dist/dist/agents-view/AgentCard.js +30 -0
- package/dist/dist/agents-view/AgentCard.js.map +1 -0
- package/dist/dist/agents-view/AgentsView.d.ts +5 -0
- package/dist/dist/agents-view/AgentsView.js +255 -0
- package/dist/dist/agents-view/AgentsView.js.map +1 -0
- package/dist/dist/agents-view/ProfileAgentsGroup.d.ts +17 -0
- package/dist/dist/agents-view/ProfileAgentsGroup.js +13 -0
- package/dist/dist/agents-view/ProfileAgentsGroup.js.map +1 -0
- package/dist/dist/client-components/api.d.ts +1 -0
- package/dist/dist/client-components/api.js +4 -0
- package/dist/dist/client-components/api.js.map +1 -0
- package/dist/dist/client-components/index.d.ts +17 -0
- package/dist/dist/client-components/index.js +18 -0
- package/dist/dist/client-components/index.js.map +1 -0
- package/dist/dist/components/ActionButton.d.ts +14 -0
- package/dist/dist/components/ActionButton.js +6 -0
- package/dist/dist/components/ActionButton.js.map +1 -0
- package/dist/dist/components/Error.d.ts +9 -0
- package/dist/dist/components/Error.js +24 -0
- package/dist/dist/components/Error.js.map +1 -0
- package/dist/dist/components/FilterInput.d.ts +22 -0
- package/dist/dist/components/FilterInput.js +29 -0
- package/dist/dist/components/FilterInput.js.map +1 -0
- package/dist/dist/components/index.d.ts +7 -0
- package/dist/dist/components/index.js +5 -0
- package/dist/dist/components/index.js.map +1 -0
- package/dist/dist/components/ui/CardConnector.d.ts +4 -0
- package/dist/dist/components/ui/CardConnector.js +6 -0
- package/dist/dist/components/ui/CardConnector.js.map +1 -0
- package/dist/dist/components/ui/LanguageSelector.d.ts +8 -0
- package/dist/dist/components/ui/LanguageSelector.js +53 -0
- package/dist/dist/components/ui/LanguageSelector.js.map +1 -0
- package/dist/dist/components/ui/PlaceholderInput.d.ts +41 -0
- package/dist/dist/components/ui/PlaceholderInput.js +160 -0
- package/dist/dist/components/ui/PlaceholderInput.js.map +1 -0
- package/dist/dist/components/ui/PlaceholderInputTypes.d.ts +41 -0
- package/dist/dist/components/ui/PlaceholderInputTypes.js +48 -0
- package/dist/dist/components/ui/PlaceholderInputTypes.js.map +1 -0
- package/dist/dist/components/ui/PlaceholderItemSelector.d.ts +7 -0
- package/dist/dist/components/ui/PlaceholderItemSelector.js +154 -0
- package/dist/dist/components/ui/PlaceholderItemSelector.js.map +1 -0
- package/dist/dist/components/ui/alert.d.ts +7 -0
- package/dist/dist/components/ui/alert.js +21 -0
- package/dist/dist/components/ui/alert.js.map +1 -0
- package/dist/dist/components/ui/badge.d.ts +9 -0
- package/dist/dist/components/ui/badge.js +23 -0
- package/dist/dist/components/ui/badge.js.map +1 -0
- package/dist/dist/components/ui/button.d.ts +10 -0
- package/dist/dist/components/ui/button.js +33 -0
- package/dist/dist/components/ui/button.js.map +1 -0
- package/dist/dist/components/ui/calendar.d.ts +7 -0
- package/dist/dist/components/ui/calendar.js +58 -0
- package/dist/dist/components/ui/calendar.js.map +1 -0
- package/dist/dist/components/ui/card.d.ts +19 -0
- package/dist/dist/components/ui/card.js +78 -0
- package/dist/dist/components/ui/card.js.map +1 -0
- package/dist/dist/components/ui/checkbox.d.ts +4 -0
- package/dist/dist/components/ui/checkbox.js +10 -0
- package/dist/dist/components/ui/checkbox.js.map +1 -0
- package/dist/dist/components/ui/command.d.ts +18 -0
- package/dist/dist/components/ui/command.js +35 -0
- package/dist/dist/components/ui/command.js.map +1 -0
- package/dist/dist/components/ui/context-menu.d.ts +53 -0
- package/dist/dist/components/ui/context-menu.js +290 -0
- package/dist/dist/components/ui/context-menu.js.map +1 -0
- package/dist/dist/components/ui/copy-button.d.ts +10 -0
- package/dist/dist/components/ui/copy-button.js +61 -0
- package/dist/dist/components/ui/copy-button.js.map +1 -0
- package/dist/dist/components/ui/dialog.d.ts +16 -0
- package/dist/dist/components/ui/dialog.js +37 -0
- package/dist/dist/components/ui/dialog.js.map +1 -0
- package/dist/dist/components/ui/dropdown-menu.d.ts +25 -0
- package/dist/dist/components/ui/dropdown-menu.js +52 -0
- package/dist/dist/components/ui/dropdown-menu.js.map +1 -0
- package/dist/dist/components/ui/input.d.ts +3 -0
- package/dist/dist/components/ui/input.js +9 -0
- package/dist/dist/components/ui/input.js.map +1 -0
- package/dist/dist/components/ui/label.d.ts +5 -0
- package/dist/dist/components/ui/label.js +9 -0
- package/dist/dist/components/ui/label.js.map +1 -0
- package/dist/dist/components/ui/menubar.d.ts +26 -0
- package/dist/dist/components/ui/menubar.js +55 -0
- package/dist/dist/components/ui/menubar.js.map +1 -0
- package/dist/dist/components/ui/paste-button.d.ts +14 -0
- package/dist/dist/components/ui/paste-button.js +114 -0
- package/dist/dist/components/ui/paste-button.js.map +1 -0
- package/dist/dist/components/ui/popover.d.ts +11 -0
- package/dist/dist/components/ui/popover.js +66 -0
- package/dist/dist/components/ui/popover.js.map +1 -0
- package/dist/dist/components/ui/progress.d.ts +7 -0
- package/dist/dist/components/ui/progress.js +9 -0
- package/dist/dist/components/ui/progress.js.map +1 -0
- package/dist/dist/components/ui/select.d.ts +18 -0
- package/dist/dist/components/ui/select.js +34 -0
- package/dist/dist/components/ui/select.js.map +1 -0
- package/dist/dist/components/ui/sonner.d.ts +3 -0
- package/dist/dist/components/ui/sonner.js +16 -0
- package/dist/dist/components/ui/sonner.js.map +1 -0
- package/dist/dist/components/ui/switch.d.ts +4 -0
- package/dist/dist/components/ui/switch.js +9 -0
- package/dist/dist/components/ui/switch.js.map +1 -0
- package/dist/dist/components/ui/tabs.d.ts +17 -0
- package/dist/dist/components/ui/tabs.js +27 -0
- package/dist/dist/components/ui/tabs.js.map +1 -0
- package/dist/dist/components/ui/textarea.d.ts +3 -0
- package/dist/dist/components/ui/textarea.js +11 -0
- package/dist/dist/components/ui/textarea.js.map +1 -0
- package/dist/dist/components/ui/tooltip.d.ts +9 -0
- package/dist/dist/components/ui/tooltip.js +18 -0
- package/dist/dist/components/ui/tooltip.js.map +1 -0
- package/dist/dist/components/ui/upload-button.d.ts +15 -0
- package/dist/dist/components/ui/upload-button.js +56 -0
- package/dist/dist/components/ui/upload-button.js.map +1 -0
- package/dist/dist/config/config.d.ts +24 -0
- package/dist/dist/config/config.js +1088 -0
- package/dist/dist/config/config.js.map +1 -0
- package/dist/dist/config/types.d.ts +244 -0
- package/dist/dist/config/types.js +2 -0
- package/dist/dist/config/types.js.map +1 -0
- package/dist/dist/editor/AspectRatioSelector.d.ts +13 -0
- package/dist/dist/editor/AspectRatioSelector.js +71 -0
- package/dist/dist/editor/AspectRatioSelector.js.map +1 -0
- package/dist/dist/editor/ComponentInfo.d.ts +4 -0
- package/dist/dist/editor/ComponentInfo.js +41 -0
- package/dist/dist/editor/ComponentInfo.js.map +1 -0
- package/dist/dist/editor/ConfirmationDialog.d.ts +19 -0
- package/dist/dist/editor/ConfirmationDialog.js +31 -0
- package/dist/dist/editor/ConfirmationDialog.js.map +1 -0
- package/dist/dist/editor/ContentTree.d.ts +39 -0
- package/dist/dist/editor/ContentTree.js +602 -0
- package/dist/dist/editor/ContentTree.js.map +1 -0
- package/dist/dist/editor/ContextMenu.d.ts +15 -0
- package/dist/dist/editor/ContextMenu.js +239 -0
- package/dist/dist/editor/ContextMenu.js.map +1 -0
- package/dist/dist/editor/Editor.d.ts +12 -0
- package/dist/dist/editor/Editor.js +116 -0
- package/dist/dist/editor/Editor.js.map +1 -0
- package/dist/dist/editor/EditorWarning.d.ts +5 -0
- package/dist/dist/editor/EditorWarning.js +12 -0
- package/dist/dist/editor/EditorWarning.js.map +1 -0
- package/dist/dist/editor/EditorWarnings.d.ts +9 -0
- package/dist/dist/editor/EditorWarnings.js +19 -0
- package/dist/dist/editor/EditorWarnings.js.map +1 -0
- package/dist/dist/editor/FieldActionsOverlay.d.ts +18 -0
- package/dist/dist/editor/FieldActionsOverlay.js +201 -0
- package/dist/dist/editor/FieldActionsOverlay.js.map +1 -0
- package/dist/dist/editor/FieldEditorPopup.d.ts +10 -0
- package/dist/dist/editor/FieldEditorPopup.js +23 -0
- package/dist/dist/editor/FieldEditorPopup.js.map +1 -0
- package/dist/dist/editor/FieldHistory.d.ts +7 -0
- package/dist/dist/editor/FieldHistory.js +45 -0
- package/dist/dist/editor/FieldHistory.js.map +1 -0
- package/dist/dist/editor/FieldList.d.ts +19 -0
- package/dist/dist/editor/FieldList.js +90 -0
- package/dist/dist/editor/FieldList.js.map +1 -0
- package/dist/dist/editor/FieldListField.d.ts +16 -0
- package/dist/dist/editor/FieldListField.js +286 -0
- package/dist/dist/editor/FieldListField.js.map +1 -0
- package/dist/dist/editor/FieldListFieldWithFallbacks.d.ts +11 -0
- package/dist/dist/editor/FieldListFieldWithFallbacks.js +120 -0
- package/dist/dist/editor/FieldListFieldWithFallbacks.js.map +1 -0
- package/dist/dist/editor/FloatingToolbar.d.ts +7 -0
- package/dist/dist/editor/FloatingToolbar.js +91 -0
- package/dist/dist/editor/FloatingToolbar.js.map +1 -0
- package/dist/dist/editor/ImageEditButton.d.ts +27 -0
- package/dist/dist/editor/ImageEditButton.js +22 -0
- package/dist/dist/editor/ImageEditButton.js.map +1 -0
- package/dist/dist/editor/ImageEditor.d.ts +5 -0
- package/dist/dist/editor/ImageEditor.js +76 -0
- package/dist/dist/editor/ImageEditor.js.map +1 -0
- package/dist/dist/editor/ItemInfo.d.ts +4 -0
- package/dist/dist/editor/ItemInfo.js +60 -0
- package/dist/dist/editor/ItemInfo.js.map +1 -0
- package/dist/dist/editor/LinkEditorDialog.d.ts +18 -0
- package/dist/dist/editor/LinkEditorDialog.js +101 -0
- package/dist/dist/editor/LinkEditorDialog.js.map +1 -0
- package/dist/dist/editor/MainLayout.d.ts +12 -0
- package/dist/dist/editor/MainLayout.js +124 -0
- package/dist/dist/editor/MainLayout.js.map +1 -0
- package/dist/dist/editor/MobileLayout.d.ts +2 -0
- package/dist/dist/editor/MobileLayout.js +34 -0
- package/dist/dist/editor/MobileLayout.js.map +1 -0
- package/dist/dist/editor/NewEditorClient.d.ts +5 -0
- package/dist/dist/editor/NewEditorClient.js +7 -0
- package/dist/dist/editor/NewEditorClient.js.map +1 -0
- package/dist/dist/editor/PictureCropper.d.ts +6 -0
- package/dist/dist/editor/PictureCropper.js +722 -0
- package/dist/dist/editor/PictureCropper.js.map +1 -0
- package/dist/dist/editor/PictureEditor.d.ts +9 -0
- package/dist/dist/editor/PictureEditor.js +180 -0
- package/dist/dist/editor/PictureEditor.js.map +1 -0
- package/dist/dist/editor/PictureEditorDialog.d.ts +8 -0
- package/dist/dist/editor/PictureEditorDialog.js +195 -0
- package/dist/dist/editor/PictureEditorDialog.js.map +1 -0
- package/dist/dist/editor/QuickItemSwitcher.d.ts +9 -0
- package/dist/dist/editor/QuickItemSwitcher.js +78 -0
- package/dist/dist/editor/QuickItemSwitcher.js.map +1 -0
- package/dist/dist/editor/ScrollingContentTree.d.ts +10 -0
- package/dist/dist/editor/ScrollingContentTree.js +48 -0
- package/dist/dist/editor/ScrollingContentTree.js.map +1 -0
- package/dist/dist/editor/SetupLoadingScreen.d.ts +5 -0
- package/dist/dist/editor/SetupLoadingScreen.js +11 -0
- package/dist/dist/editor/SetupLoadingScreen.js.map +1 -0
- package/dist/dist/editor/Titlebar.d.ts +1 -0
- package/dist/dist/editor/Titlebar.js +46 -0
- package/dist/dist/editor/Titlebar.js.map +1 -0
- package/dist/dist/editor/ai/AgentCostDisplay.d.ts +32 -0
- package/dist/dist/editor/ai/AgentCostDisplay.js +93 -0
- package/dist/dist/editor/ai/AgentCostDisplay.js.map +1 -0
- package/dist/dist/editor/ai/AgentDocumentList.d.ts +8 -0
- package/dist/dist/editor/ai/AgentDocumentList.js +132 -0
- package/dist/dist/editor/ai/AgentDocumentList.js.map +1 -0
- package/dist/dist/editor/ai/AgentHistory.d.ts +11 -0
- package/dist/dist/editor/ai/AgentHistory.js +12 -0
- package/dist/dist/editor/ai/AgentHistory.js.map +1 -0
- package/dist/dist/editor/ai/AgentProfilesOverview.d.ts +9 -0
- package/dist/dist/editor/ai/AgentProfilesOverview.js +16 -0
- package/dist/dist/editor/ai/AgentProfilesOverview.js.map +1 -0
- package/dist/dist/editor/ai/AgentStatusBadge.d.ts +26 -0
- package/dist/dist/editor/ai/AgentStatusBadge.js +126 -0
- package/dist/dist/editor/ai/AgentStatusBadge.js.map +1 -0
- package/dist/dist/editor/ai/AgentTerminal.d.ts +14 -0
- package/dist/dist/editor/ai/AgentTerminal.js +3012 -0
- package/dist/dist/editor/ai/AgentTerminal.js.map +1 -0
- package/dist/dist/editor/ai/Agents.d.ts +4 -0
- package/dist/dist/editor/ai/Agents.js +891 -0
- package/dist/dist/editor/ai/Agents.js.map +1 -0
- package/dist/dist/editor/ai/AiResponseMessage.d.ts +18 -0
- package/dist/dist/editor/ai/AiResponseMessage.js +684 -0
- package/dist/dist/editor/ai/AiResponseMessage.js.map +1 -0
- package/dist/dist/editor/ai/ContextInfoBar.d.ts +14 -0
- package/dist/dist/editor/ai/ContextInfoBar.js +432 -0
- package/dist/dist/editor/ai/ContextInfoBar.js.map +1 -0
- package/dist/dist/editor/ai/DancingDots.d.ts +1 -0
- package/dist/dist/editor/ai/DancingDots.js +6 -0
- package/dist/dist/editor/ai/DancingDots.js.map +1 -0
- package/dist/dist/editor/ai/MediaImage.d.ts +6 -0
- package/dist/dist/editor/ai/MediaImage.js +38 -0
- package/dist/dist/editor/ai/MediaImage.js.map +1 -0
- package/dist/dist/editor/ai/ToolCallDisplay.d.ts +45 -0
- package/dist/dist/editor/ai/ToolCallDisplay.js +292 -0
- package/dist/dist/editor/ai/ToolCallDisplay.js.map +1 -0
- package/dist/dist/editor/ai/aiPageModel.d.ts +24 -0
- package/dist/dist/editor/ai/aiPageModel.js +97 -0
- package/dist/dist/editor/ai/aiPageModel.js.map +1 -0
- package/dist/dist/editor/ai/editorAiContext.d.ts +10 -0
- package/dist/dist/editor/ai/editorAiContext.js +10 -0
- package/dist/dist/editor/ai/editorAiContext.js.map +1 -0
- package/dist/dist/editor/ai/types.d.ts +30 -0
- package/dist/dist/editor/ai/types.js +2 -0
- package/dist/dist/editor/ai/types.js.map +1 -0
- package/dist/dist/editor/ai/useAgentStatus.d.ts +14 -0
- package/dist/dist/editor/ai/useAgentStatus.js +203 -0
- package/dist/dist/editor/ai/useAgentStatus.js.map +1 -0
- package/dist/dist/editor/client/AboutDialog.d.ts +2 -0
- package/dist/dist/editor/client/AboutDialog.js +23 -0
- package/dist/dist/editor/client/AboutDialog.js.map +1 -0
- package/dist/dist/editor/client/EditorShell.d.ts +37 -0
- package/dist/dist/editor/client/EditorShell.js +2283 -0
- package/dist/dist/editor/client/EditorShell.js.map +1 -0
- package/dist/dist/editor/client/GenericDialog.d.ts +10 -0
- package/dist/dist/editor/client/GenericDialog.js +25 -0
- package/dist/dist/editor/client/GenericDialog.js.map +1 -0
- package/dist/dist/editor/client/editContext.d.ts +262 -0
- package/dist/dist/editor/client/editContext.js +29 -0
- package/dist/dist/editor/client/editContext.js.map +1 -0
- package/dist/dist/editor/client/fieldModificationStore.d.ts +25 -0
- package/dist/dist/editor/client/fieldModificationStore.js +184 -0
- package/dist/dist/editor/client/fieldModificationStore.js.map +1 -0
- package/dist/dist/editor/client/helpers.d.ts +12 -0
- package/dist/dist/editor/client/helpers.js +29 -0
- package/dist/dist/editor/client/helpers.js.map +1 -0
- package/dist/dist/editor/client/hooks/useEditorUrlSync.d.ts +18 -0
- package/dist/dist/editor/client/hooks/useEditorUrlSync.js +56 -0
- package/dist/dist/editor/client/hooks/useEditorUrlSync.js.map +1 -0
- package/dist/dist/editor/client/hooks/useEditorWebSocket.d.ts +11 -0
- package/dist/dist/editor/client/hooks/useEditorWebSocket.js +86 -0
- package/dist/dist/editor/client/hooks/useEditorWebSocket.js.map +1 -0
- package/dist/dist/editor/client/hooks/useGlobalEditorKeyDown.d.ts +1 -0
- package/dist/dist/editor/client/hooks/useGlobalEditorKeyDown.js +12 -0
- package/dist/dist/editor/client/hooks/useGlobalEditorKeyDown.js.map +1 -0
- package/dist/dist/editor/client/hooks/useMediaQuery.d.ts +1 -0
- package/dist/dist/editor/client/hooks/useMediaQuery.js +19 -0
- package/dist/dist/editor/client/hooks/useMediaQuery.js.map +1 -0
- package/dist/dist/editor/client/hooks/useMediaSelector.d.ts +12 -0
- package/dist/dist/editor/client/hooks/useMediaSelector.js +30 -0
- package/dist/dist/editor/client/hooks/useMediaSelector.js.map +1 -0
- package/dist/dist/editor/client/hooks/useQuota.d.ts +29 -0
- package/dist/dist/editor/client/hooks/useQuota.js +53 -0
- package/dist/dist/editor/client/hooks/useQuota.js.map +1 -0
- package/dist/dist/editor/client/hooks/useSocketMessageHandler.d.ts +35 -0
- package/dist/dist/editor/client/hooks/useSocketMessageHandler.js +241 -0
- package/dist/dist/editor/client/hooks/useSocketMessageHandler.js.map +1 -0
- package/dist/dist/editor/client/hooks/useWorkbox.d.ts +9 -0
- package/dist/dist/editor/client/hooks/useWorkbox.js +52 -0
- package/dist/dist/editor/client/hooks/useWorkbox.js.map +1 -0
- package/dist/dist/editor/client/itemsRepository.d.ts +38 -0
- package/dist/dist/editor/client/itemsRepository.js +482 -0
- package/dist/dist/editor/client/itemsRepository.js.map +1 -0
- package/dist/dist/editor/client/operations.d.ts +69 -0
- package/dist/dist/editor/client/operations.js +633 -0
- package/dist/dist/editor/client/operations.js.map +1 -0
- package/dist/dist/editor/client/pageModelBuilder.d.ts +6 -0
- package/dist/dist/editor/client/pageModelBuilder.js +171 -0
- package/dist/dist/editor/client/pageModelBuilder.js.map +1 -0
- package/dist/dist/editor/client/ui/EditorChrome.d.ts +12 -0
- package/dist/dist/editor/client/ui/EditorChrome.js +30 -0
- package/dist/dist/editor/client/ui/EditorChrome.js.map +1 -0
- package/dist/dist/editor/client/ui/FullscreenControls.d.ts +7 -0
- package/dist/dist/editor/client/ui/FullscreenControls.js +21 -0
- package/dist/dist/editor/client/ui/FullscreenControls.js.map +1 -0
- package/dist/dist/editor/commands/agentCommands.d.ts +9 -0
- package/dist/dist/editor/commands/agentCommands.js +30 -0
- package/dist/dist/editor/commands/agentCommands.js.map +1 -0
- package/dist/dist/editor/commands/commands.d.ts +19 -0
- package/dist/dist/editor/commands/commands.js +2 -0
- package/dist/dist/editor/commands/commands.js.map +1 -0
- package/dist/dist/editor/commands/componentCommands.d.ts +12 -0
- package/dist/dist/editor/commands/componentCommands.js +367 -0
- package/dist/dist/editor/commands/componentCommands.js.map +1 -0
- package/dist/dist/editor/commands/createVersionCommand.d.ts +4 -0
- package/dist/dist/editor/commands/createVersionCommand.js +24 -0
- package/dist/dist/editor/commands/createVersionCommand.js.map +1 -0
- package/dist/dist/editor/commands/deleteVersionCommand.d.ts +4 -0
- package/dist/dist/editor/commands/deleteVersionCommand.js +53 -0
- package/dist/dist/editor/commands/deleteVersionCommand.js.map +1 -0
- package/dist/dist/editor/commands/itemCommands.d.ts +29 -0
- package/dist/dist/editor/commands/itemCommands.js +448 -0
- package/dist/dist/editor/commands/itemCommands.js.map +1 -0
- package/dist/dist/editor/commands/localizeItem/LocalizeItemDialog.d.ts +8 -0
- package/dist/dist/editor/commands/localizeItem/LocalizeItemDialog.js +91 -0
- package/dist/dist/editor/commands/localizeItem/LocalizeItemDialog.js.map +1 -0
- package/dist/dist/editor/commands/undo.d.ts +15 -0
- package/dist/dist/editor/commands/undo.js +29 -0
- package/dist/dist/editor/commands/undo.js.map +1 -0
- package/dist/dist/editor/componentTreeHelper.d.ts +18 -0
- package/dist/dist/editor/componentTreeHelper.js +123 -0
- package/dist/dist/editor/componentTreeHelper.js.map +1 -0
- package/dist/dist/editor/context-menu/CopyMoveMenu.d.ts +7 -0
- package/dist/dist/editor/context-menu/CopyMoveMenu.js +58 -0
- package/dist/dist/editor/context-menu/CopyMoveMenu.js.map +1 -0
- package/dist/dist/editor/context-menu/InsertMenu.d.ts +9 -0
- package/dist/dist/editor/context-menu/InsertMenu.js +229 -0
- package/dist/dist/editor/context-menu/InsertMenu.js.map +1 -0
- package/dist/dist/editor/control-center/About.d.ts +1 -0
- package/dist/dist/editor/control-center/About.js +8 -0
- package/dist/dist/editor/control-center/About.js.map +1 -0
- package/dist/dist/editor/control-center/AllAgentsPanel.d.ts +5 -0
- package/dist/dist/editor/control-center/AllAgentsPanel.js +126 -0
- package/dist/dist/editor/control-center/AllAgentsPanel.js.map +1 -0
- package/dist/dist/editor/control-center/ControlCenterMenu.d.ts +1 -0
- package/dist/dist/editor/control-center/ControlCenterMenu.js +66 -0
- package/dist/dist/editor/control-center/ControlCenterMenu.js.map +1 -0
- package/dist/dist/editor/control-center/IndexOverview.d.ts +1 -0
- package/dist/dist/editor/control-center/IndexOverview.js +323 -0
- package/dist/dist/editor/control-center/IndexOverview.js.map +1 -0
- package/dist/dist/editor/control-center/Info.d.ts +1 -0
- package/dist/dist/editor/control-center/Info.js +10 -0
- package/dist/dist/editor/control-center/Info.js.map +1 -0
- package/dist/dist/editor/control-center/LatestFeedback.d.ts +1 -0
- package/dist/dist/editor/control-center/LatestFeedback.js +136 -0
- package/dist/dist/editor/control-center/LatestFeedback.js.map +1 -0
- package/dist/dist/editor/control-center/QuotaInfo.d.ts +1 -0
- package/dist/dist/editor/control-center/QuotaInfo.js +102 -0
- package/dist/dist/editor/control-center/QuotaInfo.js.map +1 -0
- package/dist/dist/editor/control-center/Setup.d.ts +1 -0
- package/dist/dist/editor/control-center/Setup.js +174 -0
- package/dist/dist/editor/control-center/Setup.js.map +1 -0
- package/dist/dist/editor/control-center/Status.d.ts +1 -0
- package/dist/dist/editor/control-center/Status.js +79 -0
- package/dist/dist/editor/control-center/Status.js.map +1 -0
- package/dist/dist/editor/control-center/WebSocketMessages.d.ts +1 -0
- package/dist/dist/editor/control-center/WebSocketMessages.js +71 -0
- package/dist/dist/editor/control-center/WebSocketMessages.js.map +1 -0
- package/dist/dist/editor/control-center/parhelia-setup/Overview.d.ts +1 -0
- package/dist/dist/editor/control-center/parhelia-setup/Overview.js +91 -0
- package/dist/dist/editor/control-center/parhelia-setup/Overview.js.map +1 -0
- package/dist/dist/editor/control-center/setup-steps/AiSetupStep/EmbeddingsModelSection.d.ts +2 -0
- package/dist/dist/editor/control-center/setup-steps/AiSetupStep/EmbeddingsModelSection.js +195 -0
- package/dist/dist/editor/control-center/setup-steps/AiSetupStep/EmbeddingsModelSection.js.map +1 -0
- package/dist/dist/editor/control-center/setup-steps/AiSetupStep/index.d.ts +2 -0
- package/dist/dist/editor/control-center/setup-steps/AiSetupStep/index.js +22 -0
- package/dist/dist/editor/control-center/setup-steps/AiSetupStep/index.js.map +1 -0
- package/dist/dist/editor/control-center/setup-steps/AiSetupStep/provider/ProviderSection.d.ts +1 -0
- package/dist/dist/editor/control-center/setup-steps/AiSetupStep/provider/ProviderSection.js +233 -0
- package/dist/dist/editor/control-center/setup-steps/AiSetupStep/provider/ProviderSection.js.map +1 -0
- package/dist/dist/editor/control-center/setup-steps/AiSetupStep/required-containers/RequiredContainersList.d.ts +15 -0
- package/dist/dist/editor/control-center/setup-steps/AiSetupStep/required-containers/RequiredContainersList.js +14 -0
- package/dist/dist/editor/control-center/setup-steps/AiSetupStep/required-containers/RequiredContainersList.js.map +1 -0
- package/dist/dist/editor/control-center/setup-steps/AiSetupStep/required-containers/RequiredContainersSection.d.ts +1 -0
- package/dist/dist/editor/control-center/setup-steps/AiSetupStep/required-containers/RequiredContainersSection.js +94 -0
- package/dist/dist/editor/control-center/setup-steps/AiSetupStep/required-containers/RequiredContainersSection.js.map +1 -0
- package/dist/dist/editor/control-center/setup-steps/AiSetupStep/tools/GenerateToolsSection.d.ts +1 -0
- package/dist/dist/editor/control-center/setup-steps/AiSetupStep/tools/GenerateToolsSection.js +367 -0
- package/dist/dist/editor/control-center/setup-steps/AiSetupStep/tools/GenerateToolsSection.js.map +1 -0
- package/dist/dist/editor/control-center/setup-steps/AiSetupStep/types.d.ts +1 -0
- package/dist/dist/editor/control-center/setup-steps/AiSetupStep/types.js +2 -0
- package/dist/dist/editor/control-center/setup-steps/AiSetupStep/types.js.map +1 -0
- package/dist/dist/editor/control-center/setup-steps/AiSetupStep/utils.d.ts +5 -0
- package/dist/dist/editor/control-center/setup-steps/AiSetupStep/utils.js +44 -0
- package/dist/dist/editor/control-center/setup-steps/AiSetupStep/utils.js.map +1 -0
- package/dist/dist/editor/control-center/setup-steps/DbSetupStep.d.ts +2 -0
- package/dist/dist/editor/control-center/setup-steps/DbSetupStep.js +46 -0
- package/dist/dist/editor/control-center/setup-steps/DbSetupStep.js.map +1 -0
- package/dist/dist/editor/control-center/setup-steps/IndexSetupStep.d.ts +2 -0
- package/dist/dist/editor/control-center/setup-steps/IndexSetupStep.js +36 -0
- package/dist/dist/editor/control-center/setup-steps/IndexSetupStep.js.map +1 -0
- package/dist/dist/editor/control-center/setup-steps/SettingsSetupStep.d.ts +2 -0
- package/dist/dist/editor/control-center/setup-steps/SettingsSetupStep.js +111 -0
- package/dist/dist/editor/control-center/setup-steps/SettingsSetupStep.js.map +1 -0
- package/dist/dist/editor/control-center/setup-steps/SetupOverview.d.ts +14 -0
- package/dist/dist/editor/control-center/setup-steps/SetupOverview.js +38 -0
- package/dist/dist/editor/control-center/setup-steps/SetupOverview.js.map +1 -0
- package/dist/dist/editor/editor-warnings/ItemLocked.d.ts +2 -0
- package/dist/dist/editor/editor-warnings/ItemLocked.js +38 -0
- package/dist/dist/editor/editor-warnings/ItemLocked.js.map +1 -0
- package/dist/dist/editor/editor-warnings/NoLanguageWriteAccess.d.ts +2 -0
- package/dist/dist/editor/editor-warnings/NoLanguageWriteAccess.js +14 -0
- package/dist/dist/editor/editor-warnings/NoLanguageWriteAccess.js.map +1 -0
- package/dist/dist/editor/editor-warnings/NoWorkflowWriteAccess.d.ts +2 -0
- package/dist/dist/editor/editor-warnings/NoWorkflowWriteAccess.js +14 -0
- package/dist/dist/editor/editor-warnings/NoWorkflowWriteAccess.js.map +1 -0
- package/dist/dist/editor/editor-warnings/NoWriteAccess.d.ts +2 -0
- package/dist/dist/editor/editor-warnings/NoWriteAccess.js +14 -0
- package/dist/dist/editor/editor-warnings/NoWriteAccess.js.map +1 -0
- package/dist/dist/editor/editor-warnings/ValidationErrors.d.ts +2 -0
- package/dist/dist/editor/editor-warnings/ValidationErrors.js +28 -0
- package/dist/dist/editor/editor-warnings/ValidationErrors.js.map +1 -0
- package/dist/dist/editor/field-types/AttachmentEditor.d.ts +9 -0
- package/dist/dist/editor/field-types/AttachmentEditor.js +68 -0
- package/dist/dist/editor/field-types/AttachmentEditor.js.map +1 -0
- package/dist/dist/editor/field-types/CheckboxEditor.d.ts +5 -0
- package/dist/dist/editor/field-types/CheckboxEditor.js +30 -0
- package/dist/dist/editor/field-types/CheckboxEditor.js.map +1 -0
- package/dist/dist/editor/field-types/DateFieldEditor.d.ts +5 -0
- package/dist/dist/editor/field-types/DateFieldEditor.js +93 -0
- package/dist/dist/editor/field-types/DateFieldEditor.js.map +1 -0
- package/dist/dist/editor/field-types/DateTimeFieldEditor.d.ts +5 -0
- package/dist/dist/editor/field-types/DateTimeFieldEditor.js +151 -0
- package/dist/dist/editor/field-types/DateTimeFieldEditor.js.map +1 -0
- package/dist/dist/editor/field-types/DropLinkEditor.d.ts +5 -0
- package/dist/dist/editor/field-types/DropLinkEditor.js +42 -0
- package/dist/dist/editor/field-types/DropLinkEditor.js.map +1 -0
- package/dist/dist/editor/field-types/DropListEditor.d.ts +5 -0
- package/dist/dist/editor/field-types/DropListEditor.js +46 -0
- package/dist/dist/editor/field-types/DropListEditor.js.map +1 -0
- package/dist/dist/editor/field-types/ImageFieldEditor.d.ts +5 -0
- package/dist/dist/editor/field-types/ImageFieldEditor.js +34 -0
- package/dist/dist/editor/field-types/ImageFieldEditor.js.map +1 -0
- package/dist/dist/editor/field-types/InternalLinkFieldEditor.d.ts +5 -0
- package/dist/dist/editor/field-types/InternalLinkFieldEditor.js +172 -0
- package/dist/dist/editor/field-types/InternalLinkFieldEditor.js.map +1 -0
- package/dist/dist/editor/field-types/LinkFieldEditor.d.ts +5 -0
- package/dist/dist/editor/field-types/LinkFieldEditor.js +62 -0
- package/dist/dist/editor/field-types/LinkFieldEditor.js.map +1 -0
- package/dist/dist/editor/field-types/MultiLineText.d.ts +7 -0
- package/dist/dist/editor/field-types/MultiLineText.js +48 -0
- package/dist/dist/editor/field-types/MultiLineText.js.map +1 -0
- package/dist/dist/editor/field-types/NameValueListEditor.d.ts +7 -0
- package/dist/dist/editor/field-types/NameValueListEditor.js +101 -0
- package/dist/dist/editor/field-types/NameValueListEditor.js.map +1 -0
- package/dist/dist/editor/field-types/PictureFieldEditor.d.ts +5 -0
- package/dist/dist/editor/field-types/PictureFieldEditor.js +58 -0
- package/dist/dist/editor/field-types/PictureFieldEditor.js.map +1 -0
- package/dist/dist/editor/field-types/RawEditor.d.ts +6 -0
- package/dist/dist/editor/field-types/RawEditor.js +31 -0
- package/dist/dist/editor/field-types/RawEditor.js.map +1 -0
- package/dist/dist/editor/field-types/ReactQuill.d.ts +125 -0
- package/dist/dist/editor/field-types/ReactQuill.js +385 -0
- package/dist/dist/editor/field-types/ReactQuill.js.map +1 -0
- package/dist/dist/editor/field-types/RichTextEditor.d.ts +7 -0
- package/dist/dist/editor/field-types/RichTextEditor.js +21 -0
- package/dist/dist/editor/field-types/RichTextEditor.js.map +1 -0
- package/dist/dist/editor/field-types/RichTextEditorComponent.d.ts +8 -0
- package/dist/dist/editor/field-types/RichTextEditorComponent.js +88 -0
- package/dist/dist/editor/field-types/RichTextEditorComponent.js.map +1 -0
- package/dist/dist/editor/field-types/SingleLineText.d.ts +7 -0
- package/dist/dist/editor/field-types/SingleLineText.js +113 -0
- package/dist/dist/editor/field-types/SingleLineText.js.map +1 -0
- package/dist/dist/editor/field-types/TreeListEditor.d.ts +5 -0
- package/dist/dist/editor/field-types/TreeListEditor.js +387 -0
- package/dist/dist/editor/field-types/TreeListEditor.js.map +1 -0
- package/dist/dist/editor/field-types/richtext/components/EditorDropdown.css +82 -0
- package/dist/dist/editor/field-types/richtext/components/EditorDropdown.d.ts +11 -0
- package/dist/dist/editor/field-types/richtext/components/EditorDropdown.js +83 -0
- package/dist/dist/editor/field-types/richtext/components/EditorDropdown.js.map +1 -0
- package/dist/dist/editor/field-types/richtext/components/ReactSlate.css +208 -0
- package/dist/dist/editor/field-types/richtext/components/ReactSlate.d.ts +5 -0
- package/dist/dist/editor/field-types/richtext/components/ReactSlate.js +607 -0
- package/dist/dist/editor/field-types/richtext/components/ReactSlate.js.map +1 -0
- package/dist/dist/editor/field-types/richtext/components/SimpleDropdown.d.ts +18 -0
- package/dist/dist/editor/field-types/richtext/components/SimpleDropdown.js +71 -0
- package/dist/dist/editor/field-types/richtext/components/SimpleDropdown.js.map +1 -0
- package/dist/dist/editor/field-types/richtext/components/SimpleRichTextEditor.css +325 -0
- package/dist/dist/editor/field-types/richtext/components/SimpleRichTextEditor.d.ts +5 -0
- package/dist/dist/editor/field-types/richtext/components/SimpleRichTextEditor.js +359 -0
- package/dist/dist/editor/field-types/richtext/components/SimpleRichTextEditor.js.map +1 -0
- package/dist/dist/editor/field-types/richtext/components/SimpleToolbar.d.ts +16 -0
- package/dist/dist/editor/field-types/richtext/components/SimpleToolbar.js +181 -0
- package/dist/dist/editor/field-types/richtext/components/SimpleToolbar.js.map +1 -0
- package/dist/dist/editor/field-types/richtext/components/SimpleToolbarButton.d.ts +9 -0
- package/dist/dist/editor/field-types/richtext/components/SimpleToolbarButton.js +14 -0
- package/dist/dist/editor/field-types/richtext/components/SimpleToolbarButton.js.map +1 -0
- package/dist/dist/editor/field-types/richtext/components/ToolbarButton.d.ts +3 -0
- package/dist/dist/editor/field-types/richtext/components/ToolbarButton.js +6 -0
- package/dist/dist/editor/field-types/richtext/components/ToolbarButton.js.map +1 -0
- package/dist/dist/editor/field-types/richtext/config/pluginFactory.d.ts +19 -0
- package/dist/dist/editor/field-types/richtext/config/pluginFactory.js +17 -0
- package/dist/dist/editor/field-types/richtext/config/pluginFactory.js.map +1 -0
- package/dist/dist/editor/field-types/richtext/contextMenuFactory.d.ts +4 -0
- package/dist/dist/editor/field-types/richtext/contextMenuFactory.js +201 -0
- package/dist/dist/editor/field-types/richtext/contextMenuFactory.js.map +1 -0
- package/dist/dist/editor/field-types/richtext/hooks/useProfileCache.d.ts +68 -0
- package/dist/dist/editor/field-types/richtext/hooks/useProfileCache.js +214 -0
- package/dist/dist/editor/field-types/richtext/hooks/useProfileCache.js.map +1 -0
- package/dist/dist/editor/field-types/richtext/hooks/useRichTextProfile.d.ts +25 -0
- package/dist/dist/editor/field-types/richtext/hooks/useRichTextProfile.js +64 -0
- package/dist/dist/editor/field-types/richtext/hooks/useRichTextProfile.js.map +1 -0
- package/dist/dist/editor/field-types/richtext/index.d.ts +6 -0
- package/dist/dist/editor/field-types/richtext/index.js +7 -0
- package/dist/dist/editor/field-types/richtext/index.js.map +1 -0
- package/dist/dist/editor/field-types/richtext/types.d.ts +288 -0
- package/dist/dist/editor/field-types/richtext/types.js +107 -0
- package/dist/dist/editor/field-types/richtext/types.js.map +1 -0
- package/dist/dist/editor/field-types/richtext/utils/conversion.d.ts +7 -0
- package/dist/dist/editor/field-types/richtext/utils/conversion.js +762 -0
- package/dist/dist/editor/field-types/richtext/utils/conversion.js.map +1 -0
- package/dist/dist/editor/field-types/richtext/utils/plugins.d.ts +170 -0
- package/dist/dist/editor/field-types/richtext/utils/plugins.js +490 -0
- package/dist/dist/editor/field-types/richtext/utils/plugins.js.map +1 -0
- package/dist/dist/editor/field-types/richtext/utils/profileMapper.d.ts +38 -0
- package/dist/dist/editor/field-types/richtext/utils/profileMapper.js +386 -0
- package/dist/dist/editor/field-types/richtext/utils/profileMapper.js.map +1 -0
- package/dist/dist/editor/field-types/richtext/utils/profileServiceCache.d.ts +37 -0
- package/dist/dist/editor/field-types/richtext/utils/profileServiceCache.js +119 -0
- package/dist/dist/editor/field-types/richtext/utils/profileServiceCache.js.map +1 -0
- package/dist/dist/editor/fieldTypes.d.ts +129 -0
- package/dist/dist/editor/fieldTypes.js +2 -0
- package/dist/dist/editor/fieldTypes.js.map +1 -0
- package/dist/dist/editor/hooks/useEditorSettings.d.ts +17 -0
- package/dist/dist/editor/hooks/useEditorSettings.js +61 -0
- package/dist/dist/editor/hooks/useEditorSettings.js.map +1 -0
- package/dist/dist/editor/hooks/useParheliaSettings.d.ts +17 -0
- package/dist/dist/editor/hooks/useParheliaSettings.js +61 -0
- package/dist/dist/editor/hooks/useParheliaSettings.js.map +1 -0
- package/dist/dist/editor/media-selector/AiImageSearch.d.ts +4 -0
- package/dist/dist/editor/media-selector/AiImageSearch.js +164 -0
- package/dist/dist/editor/media-selector/AiImageSearch.js.map +1 -0
- package/dist/dist/editor/media-selector/AiImageSearchPrompt.d.ts +3 -0
- package/dist/dist/editor/media-selector/AiImageSearchPrompt.js +57 -0
- package/dist/dist/editor/media-selector/AiImageSearchPrompt.js.map +1 -0
- package/dist/dist/editor/media-selector/MediaFolderBrowser.d.ts +5 -0
- package/dist/dist/editor/media-selector/MediaFolderBrowser.js +182 -0
- package/dist/dist/editor/media-selector/MediaFolderBrowser.js.map +1 -0
- package/dist/dist/editor/media-selector/MediaSelector.d.ts +9 -0
- package/dist/dist/editor/media-selector/MediaSelector.js +8 -0
- package/dist/dist/editor/media-selector/MediaSelector.js.map +1 -0
- package/dist/dist/editor/media-selector/Preview.d.ts +4 -0
- package/dist/dist/editor/media-selector/Preview.js +19 -0
- package/dist/dist/editor/media-selector/Preview.js.map +1 -0
- package/dist/dist/editor/media-selector/Thumbnails.d.ts +8 -0
- package/dist/dist/editor/media-selector/Thumbnails.js +10 -0
- package/dist/dist/editor/media-selector/Thumbnails.js.map +1 -0
- package/dist/dist/editor/media-selector/TreeSelector.d.ts +7 -0
- package/dist/dist/editor/media-selector/TreeSelector.js +183 -0
- package/dist/dist/editor/media-selector/TreeSelector.js.map +1 -0
- package/dist/dist/editor/media-selector/UploadZone.d.ts +4 -0
- package/dist/dist/editor/media-selector/UploadZone.js +81 -0
- package/dist/dist/editor/media-selector/UploadZone.js.map +1 -0
- package/dist/dist/editor/media-selector/index.d.ts +8 -0
- package/dist/dist/editor/media-selector/index.js +9 -0
- package/dist/dist/editor/media-selector/index.js.map +1 -0
- package/dist/dist/editor/menubar/ActiveUsers.d.ts +1 -0
- package/dist/dist/editor/menubar/ActiveUsers.js +120 -0
- package/dist/dist/editor/menubar/ActiveUsers.js.map +1 -0
- package/dist/dist/editor/menubar/ApproveAndPublish.d.ts +1 -0
- package/dist/dist/editor/menubar/ApproveAndPublish.js +13 -0
- package/dist/dist/editor/menubar/ApproveAndPublish.js.map +1 -0
- package/dist/dist/editor/menubar/FavoritesControls.d.ts +8 -0
- package/dist/dist/editor/menubar/FavoritesControls.js +217 -0
- package/dist/dist/editor/menubar/FavoritesControls.js.map +1 -0
- package/dist/dist/editor/menubar/GenericToolbar.d.ts +11 -0
- package/dist/dist/editor/menubar/GenericToolbar.js +10 -0
- package/dist/dist/editor/menubar/GenericToolbar.js.map +1 -0
- package/dist/dist/editor/menubar/ItemActionsMenu.d.ts +3 -0
- package/dist/dist/editor/menubar/ItemActionsMenu.js +23 -0
- package/dist/dist/editor/menubar/ItemActionsMenu.js.map +1 -0
- package/dist/dist/editor/menubar/ItemLanguageVersion.d.ts +1 -0
- package/dist/dist/editor/menubar/ItemLanguageVersion.js +54 -0
- package/dist/dist/editor/menubar/ItemLanguageVersion.js.map +1 -0
- package/dist/dist/editor/menubar/ItemToolbar.d.ts +1 -0
- package/dist/dist/editor/menubar/ItemToolbar.js +11 -0
- package/dist/dist/editor/menubar/ItemToolbar.js.map +1 -0
- package/dist/dist/editor/menubar/NavButtons.d.ts +1 -0
- package/dist/dist/editor/menubar/NavButtons.js +40 -0
- package/dist/dist/editor/menubar/NavButtons.js.map +1 -0
- package/dist/dist/editor/menubar/PageSelector.d.ts +4 -0
- package/dist/dist/editor/menubar/PageSelector.js +152 -0
- package/dist/dist/editor/menubar/PageSelector.js.map +1 -0
- package/dist/dist/editor/menubar/Separator.d.ts +3 -0
- package/dist/dist/editor/menubar/Separator.js +6 -0
- package/dist/dist/editor/menubar/Separator.js.map +1 -0
- package/dist/dist/editor/menubar/SiteInfo.d.ts +1 -0
- package/dist/dist/editor/menubar/SiteInfo.js +24 -0
- package/dist/dist/editor/menubar/SiteInfo.js.map +1 -0
- package/dist/dist/editor/menubar/ToolbarFactory.d.ts +2 -0
- package/dist/dist/editor/menubar/ToolbarFactory.js +55 -0
- package/dist/dist/editor/menubar/ToolbarFactory.js.map +1 -0
- package/dist/dist/editor/menubar/User.d.ts +4 -0
- package/dist/dist/editor/menubar/User.js +18 -0
- package/dist/dist/editor/menubar/User.js.map +1 -0
- package/dist/dist/editor/menubar/VersionSelector.d.ts +10 -0
- package/dist/dist/editor/menubar/VersionSelector.js +53 -0
- package/dist/dist/editor/menubar/VersionSelector.js.map +1 -0
- package/dist/dist/editor/menubar/WorkflowButton.d.ts +1 -0
- package/dist/dist/editor/menubar/WorkflowButton.js +93 -0
- package/dist/dist/editor/menubar/WorkflowButton.js.map +1 -0
- package/dist/dist/editor/menubar/toolbar-sections/CompareControls.d.ts +1 -0
- package/dist/dist/editor/menubar/toolbar-sections/CompareControls.js +11 -0
- package/dist/dist/editor/menubar/toolbar-sections/CompareControls.js.map +1 -0
- package/dist/dist/editor/menubar/toolbar-sections/EditControls.d.ts +7 -0
- package/dist/dist/editor/menubar/toolbar-sections/EditControls.js +15 -0
- package/dist/dist/editor/menubar/toolbar-sections/EditControls.js.map +1 -0
- package/dist/dist/editor/menubar/toolbar-sections/InsertControls.d.ts +1 -0
- package/dist/dist/editor/menubar/toolbar-sections/InsertControls.js +15 -0
- package/dist/dist/editor/menubar/toolbar-sections/InsertControls.js.map +1 -0
- package/dist/dist/editor/menubar/toolbar-sections/ReviewCommands.d.ts +1 -0
- package/dist/dist/editor/menubar/toolbar-sections/ReviewCommands.js +41 -0
- package/dist/dist/editor/menubar/toolbar-sections/ReviewCommands.js.map +1 -0
- package/dist/dist/editor/menubar/toolbar-sections/UtilityControls.d.ts +1 -0
- package/dist/dist/editor/menubar/toolbar-sections/UtilityControls.js +17 -0
- package/dist/dist/editor/menubar/toolbar-sections/UtilityControls.js.map +1 -0
- package/dist/dist/editor/menubar/toolbar-sections/ViewportControls.d.ts +1 -0
- package/dist/dist/editor/menubar/toolbar-sections/ViewportControls.js +21 -0
- package/dist/dist/editor/menubar/toolbar-sections/ViewportControls.js.map +1 -0
- package/dist/dist/editor/menubar/toolbar-sections/index.d.ts +6 -0
- package/dist/dist/editor/menubar/toolbar-sections/index.js +7 -0
- package/dist/dist/editor/menubar/toolbar-sections/index.js.map +1 -0
- package/dist/dist/editor/page-editor-chrome/CommentHighlighting.d.ts +6 -0
- package/dist/dist/editor/page-editor-chrome/CommentHighlighting.js +270 -0
- package/dist/dist/editor/page-editor-chrome/CommentHighlighting.js.map +1 -0
- package/dist/dist/editor/page-editor-chrome/CommentHighlightings.d.ts +4 -0
- package/dist/dist/editor/page-editor-chrome/CommentHighlightings.js +15 -0
- package/dist/dist/editor/page-editor-chrome/CommentHighlightings.js.map +1 -0
- package/dist/dist/editor/page-editor-chrome/FieldActionIndicator.d.ts +4 -0
- package/dist/dist/editor/page-editor-chrome/FieldActionIndicator.js +35 -0
- package/dist/dist/editor/page-editor-chrome/FieldActionIndicator.js.map +1 -0
- package/dist/dist/editor/page-editor-chrome/FieldActionIndicators.d.ts +1 -0
- package/dist/dist/editor/page-editor-chrome/FieldActionIndicators.js +13 -0
- package/dist/dist/editor/page-editor-chrome/FieldActionIndicators.js.map +1 -0
- package/dist/dist/editor/page-editor-chrome/FieldEditedIndicator.d.ts +8 -0
- package/dist/dist/editor/page-editor-chrome/FieldEditedIndicator.js +26 -0
- package/dist/dist/editor/page-editor-chrome/FieldEditedIndicator.js.map +1 -0
- package/dist/dist/editor/page-editor-chrome/FieldEditedIndicators.d.ts +6 -0
- package/dist/dist/editor/page-editor-chrome/FieldEditedIndicators.js +14 -0
- package/dist/dist/editor/page-editor-chrome/FieldEditedIndicators.js.map +1 -0
- package/dist/dist/editor/page-editor-chrome/FrameMenu.d.ts +7 -0
- package/dist/dist/editor/page-editor-chrome/FrameMenu.js +346 -0
- package/dist/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -0
- package/dist/dist/editor/page-editor-chrome/FrameMenus.d.ts +5 -0
- package/dist/dist/editor/page-editor-chrome/FrameMenus.js +22 -0
- package/dist/dist/editor/page-editor-chrome/FrameMenus.js.map +1 -0
- package/dist/dist/editor/page-editor-chrome/InlineEditor.d.ts +5 -0
- package/dist/dist/editor/page-editor-chrome/InlineEditor.js +704 -0
- package/dist/dist/editor/page-editor-chrome/InlineEditor.js.map +1 -0
- package/dist/dist/editor/page-editor-chrome/LockedFieldIndicator.d.ts +1 -0
- package/dist/dist/editor/page-editor-chrome/LockedFieldIndicator.js +33 -0
- package/dist/dist/editor/page-editor-chrome/LockedFieldIndicator.js.map +1 -0
- package/dist/dist/editor/page-editor-chrome/NoLayout.d.ts +1 -0
- package/dist/dist/editor/page-editor-chrome/NoLayout.js +19 -0
- package/dist/dist/editor/page-editor-chrome/NoLayout.js.map +1 -0
- package/dist/dist/editor/page-editor-chrome/PageEditorChrome.d.ts +6 -0
- package/dist/dist/editor/page-editor-chrome/PageEditorChrome.js +64 -0
- package/dist/dist/editor/page-editor-chrome/PageEditorChrome.js.map +1 -0
- package/dist/dist/editor/page-editor-chrome/PictureEditorOverlay.d.ts +1 -0
- package/dist/dist/editor/page-editor-chrome/PictureEditorOverlay.js +190 -0
- package/dist/dist/editor/page-editor-chrome/PictureEditorOverlay.js.map +1 -0
- package/dist/dist/editor/page-editor-chrome/PlaceholderDropZone.d.ts +18 -0
- package/dist/dist/editor/page-editor-chrome/PlaceholderDropZone.js +122 -0
- package/dist/dist/editor/page-editor-chrome/PlaceholderDropZone.js.map +1 -0
- package/dist/dist/editor/page-editor-chrome/PlaceholderDropZones.d.ts +5 -0
- package/dist/dist/editor/page-editor-chrome/PlaceholderDropZones.js +289 -0
- package/dist/dist/editor/page-editor-chrome/PlaceholderDropZones.js.map +1 -0
- package/dist/dist/editor/page-editor-chrome/SuggestionHighlighting.d.ts +6 -0
- package/dist/dist/editor/page-editor-chrome/SuggestionHighlighting.js +224 -0
- package/dist/dist/editor/page-editor-chrome/SuggestionHighlighting.js.map +1 -0
- package/dist/dist/editor/page-editor-chrome/SuggestionHighlightings.d.ts +4 -0
- package/dist/dist/editor/page-editor-chrome/SuggestionHighlightings.js +16 -0
- package/dist/dist/editor/page-editor-chrome/SuggestionHighlightings.js.map +1 -0
- package/dist/dist/editor/page-editor-chrome/useInlineAICompletion.d.ts +7 -0
- package/dist/dist/editor/page-editor-chrome/useInlineAICompletion.js +699 -0
- package/dist/dist/editor/page-editor-chrome/useInlineAICompletion.js.map +1 -0
- package/dist/dist/editor/page-viewer/DeviceToolbar.d.ts +6 -0
- package/dist/dist/editor/page-viewer/DeviceToolbar.js +21 -0
- package/dist/dist/editor/page-viewer/DeviceToolbar.js.map +1 -0
- package/dist/dist/editor/page-viewer/EditorForm.d.ts +8 -0
- package/dist/dist/editor/page-viewer/EditorForm.js +264 -0
- package/dist/dist/editor/page-viewer/EditorForm.js.map +1 -0
- package/dist/dist/editor/page-viewer/EditorFormPopup.d.ts +11 -0
- package/dist/dist/editor/page-viewer/EditorFormPopup.js +41 -0
- package/dist/dist/editor/page-viewer/EditorFormPopup.js.map +1 -0
- package/dist/dist/editor/page-viewer/MiniMap.d.ts +9 -0
- package/dist/dist/editor/page-viewer/MiniMap.js +234 -0
- package/dist/dist/editor/page-viewer/MiniMap.js.map +1 -0
- package/dist/dist/editor/page-viewer/PageViewer.d.ts +10 -0
- package/dist/dist/editor/page-viewer/PageViewer.js +67 -0
- package/dist/dist/editor/page-viewer/PageViewer.js.map +1 -0
- package/dist/dist/editor/page-viewer/PageViewerFrame.d.ts +11 -0
- package/dist/dist/editor/page-viewer/PageViewerFrame.js +846 -0
- package/dist/dist/editor/page-viewer/PageViewerFrame.js.map +1 -0
- package/dist/dist/editor/page-viewer/pageModelSkeletonBuilder.d.ts +3 -0
- package/dist/dist/editor/page-viewer/pageModelSkeletonBuilder.js +349 -0
- package/dist/dist/editor/page-viewer/pageModelSkeletonBuilder.js.map +1 -0
- package/dist/dist/editor/page-viewer/pageViewContext.d.ts +40 -0
- package/dist/dist/editor/page-viewer/pageViewContext.js +155 -0
- package/dist/dist/editor/page-viewer/pageViewContext.js.map +1 -0
- package/dist/dist/editor/pageModel.d.ts +223 -0
- package/dist/dist/editor/pageModel.js +2 -0
- package/dist/dist/editor/pageModel.js.map +1 -0
- package/dist/dist/editor/picture-shared.d.ts +16 -0
- package/dist/dist/editor/picture-shared.js +25 -0
- package/dist/dist/editor/picture-shared.js.map +1 -0
- package/dist/dist/editor/reviews/Comment.d.ts +8 -0
- package/dist/dist/editor/reviews/Comment.js +162 -0
- package/dist/dist/editor/reviews/Comment.js.map +1 -0
- package/dist/dist/editor/reviews/CommentDisplayPopover.d.ts +9 -0
- package/dist/dist/editor/reviews/CommentDisplayPopover.js +104 -0
- package/dist/dist/editor/reviews/CommentDisplayPopover.js.map +1 -0
- package/dist/dist/editor/reviews/CommentEditor.d.ts +20 -0
- package/dist/dist/editor/reviews/CommentEditor.js +57 -0
- package/dist/dist/editor/reviews/CommentEditor.js.map +1 -0
- package/dist/dist/editor/reviews/CommentPopover.d.ts +22 -0
- package/dist/dist/editor/reviews/CommentPopover.js +145 -0
- package/dist/dist/editor/reviews/CommentPopover.js.map +1 -0
- package/dist/dist/editor/reviews/CommentView.d.ts +21 -0
- package/dist/dist/editor/reviews/CommentView.js +52 -0
- package/dist/dist/editor/reviews/CommentView.js.map +1 -0
- package/dist/dist/editor/reviews/Comments.d.ts +3 -0
- package/dist/dist/editor/reviews/Comments.js +118 -0
- package/dist/dist/editor/reviews/Comments.js.map +1 -0
- package/dist/dist/editor/reviews/CreateReviewDialog.d.ts +9 -0
- package/dist/dist/editor/reviews/CreateReviewDialog.js +454 -0
- package/dist/dist/editor/reviews/CreateReviewDialog.js.map +1 -0
- package/dist/dist/editor/reviews/DecisionsMatrix.d.ts +29 -0
- package/dist/dist/editor/reviews/DecisionsMatrix.js +739 -0
- package/dist/dist/editor/reviews/DecisionsMatrix.js.map +1 -0
- package/dist/dist/editor/reviews/DiffView.d.ts +17 -0
- package/dist/dist/editor/reviews/DiffView.js +57 -0
- package/dist/dist/editor/reviews/DiffView.js.map +1 -0
- package/dist/dist/editor/reviews/EditReviewSettingsDialog.d.ts +20 -0
- package/dist/dist/editor/reviews/EditReviewSettingsDialog.js +208 -0
- package/dist/dist/editor/reviews/EditReviewSettingsDialog.js.map +1 -0
- package/dist/dist/editor/reviews/ItemTreeSelector.d.ts +9 -0
- package/dist/dist/editor/reviews/ItemTreeSelector.js +43 -0
- package/dist/dist/editor/reviews/ItemTreeSelector.js.map +1 -0
- package/dist/dist/editor/reviews/MultiReviewManager.d.ts +1 -0
- package/dist/dist/editor/reviews/MultiReviewManager.js +50 -0
- package/dist/dist/editor/reviews/MultiReviewManager.js.map +1 -0
- package/dist/dist/editor/reviews/PagesPanel.d.ts +21 -0
- package/dist/dist/editor/reviews/PagesPanel.js +124 -0
- package/dist/dist/editor/reviews/PagesPanel.js.map +1 -0
- package/dist/dist/editor/reviews/PreconfiguredReviewerSelector.d.ts +9 -0
- package/dist/dist/editor/reviews/PreconfiguredReviewerSelector.js +55 -0
- package/dist/dist/editor/reviews/PreconfiguredReviewerSelector.js.map +1 -0
- package/dist/dist/editor/reviews/PreviewInfo.d.ts +1 -0
- package/dist/dist/editor/reviews/PreviewInfo.js +12 -0
- package/dist/dist/editor/reviews/PreviewInfo.js.map +1 -0
- package/dist/dist/editor/reviews/ReviewDetail.d.ts +8 -0
- package/dist/dist/editor/reviews/ReviewDetail.js +189 -0
- package/dist/dist/editor/reviews/ReviewDetail.js.map +1 -0
- package/dist/dist/editor/reviews/ReviewersPanel.d.ts +14 -0
- package/dist/dist/editor/reviews/ReviewersPanel.js +216 -0
- package/dist/dist/editor/reviews/ReviewersPanel.js.map +1 -0
- package/dist/dist/editor/reviews/Reviews.d.ts +1 -0
- package/dist/dist/editor/reviews/Reviews.js +6 -0
- package/dist/dist/editor/reviews/Reviews.js.map +1 -0
- package/dist/dist/editor/reviews/ReviewsList.d.ts +11 -0
- package/dist/dist/editor/reviews/ReviewsList.js +134 -0
- package/dist/dist/editor/reviews/ReviewsList.js.map +1 -0
- package/dist/dist/editor/reviews/SuggestedEdit.d.ts +4 -0
- package/dist/dist/editor/reviews/SuggestedEdit.js +200 -0
- package/dist/dist/editor/reviews/SuggestedEdit.js.map +1 -0
- package/dist/dist/editor/reviews/SuggestionDisplayPopover.d.ts +9 -0
- package/dist/dist/editor/reviews/SuggestionDisplayPopover.js +204 -0
- package/dist/dist/editor/reviews/SuggestionDisplayPopover.js.map +1 -0
- package/dist/dist/editor/reviews/commentAi.d.ts +7 -0
- package/dist/dist/editor/reviews/commentAi.js +100 -0
- package/dist/dist/editor/reviews/commentAi.js.map +1 -0
- package/dist/dist/editor/reviews/reviewCommands.d.ts +3 -0
- package/dist/dist/editor/reviews/reviewCommands.js +38 -0
- package/dist/dist/editor/reviews/reviewCommands.js.map +1 -0
- package/dist/dist/editor/reviews/useMultiReview.d.ts +42 -0
- package/dist/dist/editor/reviews/useMultiReview.js +377 -0
- package/dist/dist/editor/reviews/useMultiReview.js.map +1 -0
- package/dist/dist/editor/reviews/useReviews.d.ts +12 -0
- package/dist/dist/editor/reviews/useReviews.js +43 -0
- package/dist/dist/editor/reviews/useReviews.js.map +1 -0
- package/dist/dist/editor/services/agentService.d.ts +368 -0
- package/dist/dist/editor/services/agentService.js +721 -0
- package/dist/dist/editor/services/agentService.js.map +1 -0
- package/dist/dist/editor/services/aiService.d.ts +111 -0
- package/dist/dist/editor/services/aiService.js +294 -0
- package/dist/dist/editor/services/aiService.js.map +1 -0
- package/dist/dist/editor/services/componentDesignerService.d.ts +46 -0
- package/dist/dist/editor/services/componentDesignerService.js +72 -0
- package/dist/dist/editor/services/componentDesignerService.js.map +1 -0
- package/dist/dist/editor/services/contentService.d.ts +79 -0
- package/dist/dist/editor/services/contentService.js +127 -0
- package/dist/dist/editor/services/contentService.js.map +1 -0
- package/dist/dist/editor/services/contextService.d.ts +26 -0
- package/dist/dist/editor/services/contextService.js +103 -0
- package/dist/dist/editor/services/contextService.js.map +1 -0
- package/dist/dist/editor/services/editService.d.ts +66 -0
- package/dist/dist/editor/services/editService.js +325 -0
- package/dist/dist/editor/services/editService.js.map +1 -0
- package/dist/dist/editor/services/favouritesService.d.ts +47 -0
- package/dist/dist/editor/services/favouritesService.js +28 -0
- package/dist/dist/editor/services/favouritesService.js.map +1 -0
- package/dist/dist/editor/services/iconService.d.ts +8 -0
- package/dist/dist/editor/services/iconService.js +6 -0
- package/dist/dist/editor/services/iconService.js.map +1 -0
- package/dist/dist/editor/services/indexService.d.ts +13 -0
- package/dist/dist/editor/services/indexService.js +45 -0
- package/dist/dist/editor/services/indexService.js.map +1 -0
- package/dist/dist/editor/services/reviewsService.d.ts +53 -0
- package/dist/dist/editor/services/reviewsService.js +130 -0
- package/dist/dist/editor/services/reviewsService.js.map +1 -0
- package/dist/dist/editor/services/searchService.d.ts +17 -0
- package/dist/dist/editor/services/searchService.js +25 -0
- package/dist/dist/editor/services/searchService.js.map +1 -0
- package/dist/dist/editor/services/serviceHelper.d.ts +10 -0
- package/dist/dist/editor/services/serviceHelper.js +118 -0
- package/dist/dist/editor/services/serviceHelper.js.map +1 -0
- package/dist/dist/editor/services/setupService.d.ts +30 -0
- package/dist/dist/editor/services/setupService.js +17 -0
- package/dist/dist/editor/services/setupService.js.map +1 -0
- package/dist/dist/editor/services/suggestedEditsService.d.ts +18 -0
- package/dist/dist/editor/services/suggestedEditsService.js +44 -0
- package/dist/dist/editor/services/suggestedEditsService.js.map +1 -0
- package/dist/dist/editor/services/systemService.d.ts +4 -0
- package/dist/dist/editor/services/systemService.js +11 -0
- package/dist/dist/editor/services/systemService.js.map +1 -0
- package/dist/dist/editor/services-server/api.d.ts +19 -0
- package/dist/dist/editor/services-server/api.js +111 -0
- package/dist/dist/editor/services-server/api.js.map +1 -0
- package/dist/dist/editor/services-server/graphQL.d.ts +29 -0
- package/dist/dist/editor/services-server/graphQL.js +53 -0
- package/dist/dist/editor/services-server/graphQL.js.map +1 -0
- package/dist/dist/editor/sidebar/Completions.d.ts +1 -0
- package/dist/dist/editor/sidebar/Completions.js +55 -0
- package/dist/dist/editor/sidebar/Completions.js.map +1 -0
- package/dist/dist/editor/sidebar/ComponentPalette.d.ts +1 -0
- package/dist/dist/editor/sidebar/ComponentPalette.js +86 -0
- package/dist/dist/editor/sidebar/ComponentPalette.js.map +1 -0
- package/dist/dist/editor/sidebar/ComponentTree.d.ts +1 -0
- package/dist/dist/editor/sidebar/ComponentTree.js +691 -0
- package/dist/dist/editor/sidebar/ComponentTree.js.map +1 -0
- package/dist/dist/editor/sidebar/Debug.d.ts +1 -0
- package/dist/dist/editor/sidebar/Debug.js +71 -0
- package/dist/dist/editor/sidebar/Debug.js.map +1 -0
- package/dist/dist/editor/sidebar/DictionaryEditor.d.ts +1 -0
- package/dist/dist/editor/sidebar/DictionaryEditor.js +158 -0
- package/dist/dist/editor/sidebar/DictionaryEditor.js.map +1 -0
- package/dist/dist/editor/sidebar/Divider.d.ts +6 -0
- package/dist/dist/editor/sidebar/Divider.js +6 -0
- package/dist/dist/editor/sidebar/Divider.js.map +1 -0
- package/dist/dist/editor/sidebar/EditHistory.d.ts +1 -0
- package/dist/dist/editor/sidebar/EditHistory.js +80 -0
- package/dist/dist/editor/sidebar/EditHistory.js.map +1 -0
- package/dist/dist/editor/sidebar/GraphQL.d.ts +2 -0
- package/dist/dist/editor/sidebar/GraphQL.js +234 -0
- package/dist/dist/editor/sidebar/GraphQL.js.map +1 -0
- package/dist/dist/editor/sidebar/Insert.d.ts +1 -0
- package/dist/dist/editor/sidebar/Insert.js +22 -0
- package/dist/dist/editor/sidebar/Insert.js.map +1 -0
- package/dist/dist/editor/sidebar/LeftToolbar.d.ts +1 -0
- package/dist/dist/editor/sidebar/LeftToolbar.js +16 -0
- package/dist/dist/editor/sidebar/LeftToolbar.js.map +1 -0
- package/dist/dist/editor/sidebar/MainContentTree.d.ts +5 -0
- package/dist/dist/editor/sidebar/MainContentTree.js +70 -0
- package/dist/dist/editor/sidebar/MainContentTree.js.map +1 -0
- package/dist/dist/editor/sidebar/Performance.d.ts +1 -0
- package/dist/dist/editor/sidebar/Performance.js +32 -0
- package/dist/dist/editor/sidebar/Performance.js.map +1 -0
- package/dist/dist/editor/sidebar/SEOInfo.d.ts +1 -0
- package/dist/dist/editor/sidebar/SEOInfo.js +158 -0
- package/dist/dist/editor/sidebar/SEOInfo.js.map +1 -0
- package/dist/dist/editor/sidebar/Sessions.d.ts +1 -0
- package/dist/dist/editor/sidebar/Sessions.js +29 -0
- package/dist/dist/editor/sidebar/Sessions.js.map +1 -0
- package/dist/dist/editor/sidebar/Sidebar.d.ts +1 -0
- package/dist/dist/editor/sidebar/Sidebar.js +13 -0
- package/dist/dist/editor/sidebar/Sidebar.js.map +1 -0
- package/dist/dist/editor/sidebar/SidebarView.d.ts +13 -0
- package/dist/dist/editor/sidebar/SidebarView.js +53 -0
- package/dist/dist/editor/sidebar/SidebarView.js.map +1 -0
- package/dist/dist/editor/sidebar/Validation.d.ts +1 -0
- package/dist/dist/editor/sidebar/Validation.js +51 -0
- package/dist/dist/editor/sidebar/Validation.js.map +1 -0
- package/dist/dist/editor/sidebar/ViewSelector.d.ts +4 -0
- package/dist/dist/editor/sidebar/ViewSelector.js +191 -0
- package/dist/dist/editor/sidebar/ViewSelector.js.map +1 -0
- package/dist/dist/editor/sidebar/Workbox.d.ts +1 -0
- package/dist/dist/editor/sidebar/Workbox.js +79 -0
- package/dist/dist/editor/sidebar/Workbox.js.map +1 -0
- package/dist/dist/editor/ui/CenteredMessage.d.ts +3 -0
- package/dist/dist/editor/ui/CenteredMessage.js +5 -0
- package/dist/dist/editor/ui/CenteredMessage.js.map +1 -0
- package/dist/dist/editor/ui/CopyMoveTargetSelectorDialog.d.ts +10 -0
- package/dist/dist/editor/ui/CopyMoveTargetSelectorDialog.js +38 -0
- package/dist/dist/editor/ui/CopyMoveTargetSelectorDialog.js.map +1 -0
- package/dist/dist/editor/ui/DialogButtons.d.ts +4 -0
- package/dist/dist/editor/ui/DialogButtons.js +6 -0
- package/dist/dist/editor/ui/DialogButtons.js.map +1 -0
- package/dist/dist/editor/ui/DragPreview.d.ts +14 -0
- package/dist/dist/editor/ui/DragPreview.js +33 -0
- package/dist/dist/editor/ui/DragPreview.js.map +1 -0
- package/dist/dist/editor/ui/IconSelectorDialog.d.ts +5 -0
- package/dist/dist/editor/ui/IconSelectorDialog.js +239 -0
- package/dist/dist/editor/ui/IconSelectorDialog.js.map +1 -0
- package/dist/dist/editor/ui/Icons.d.ts +74 -0
- package/dist/dist/editor/ui/Icons.js +106 -0
- package/dist/dist/editor/ui/Icons.js.map +1 -0
- package/dist/dist/editor/ui/ItemList.d.ts +16 -0
- package/dist/dist/editor/ui/ItemList.js +19 -0
- package/dist/dist/editor/ui/ItemList.js.map +1 -0
- package/dist/dist/editor/ui/ItemNameDialogNew.d.ts +10 -0
- package/dist/dist/editor/ui/ItemNameDialogNew.js +82 -0
- package/dist/dist/editor/ui/ItemNameDialogNew.js.map +1 -0
- package/dist/dist/editor/ui/ItemSearch.d.ts +25 -0
- package/dist/dist/editor/ui/ItemSearch.js +92 -0
- package/dist/dist/editor/ui/ItemSearch.js.map +1 -0
- package/dist/dist/editor/ui/PerfectTree.d.ts +78 -0
- package/dist/dist/editor/ui/PerfectTree.js +860 -0
- package/dist/dist/editor/ui/PerfectTree.js.map +1 -0
- package/dist/dist/editor/ui/Section.d.ts +4 -0
- package/dist/dist/editor/ui/Section.js +12 -0
- package/dist/dist/editor/ui/Section.js.map +1 -0
- package/dist/dist/editor/ui/SimpleIconButton.d.ts +14 -0
- package/dist/dist/editor/ui/SimpleIconButton.js +15 -0
- package/dist/dist/editor/ui/SimpleIconButton.js.map +1 -0
- package/dist/dist/editor/ui/SimpleMenu.d.ts +6 -0
- package/dist/dist/editor/ui/SimpleMenu.js +7 -0
- package/dist/dist/editor/ui/SimpleMenu.js.map +1 -0
- package/dist/dist/editor/ui/SimpleTable.d.ts +14 -0
- package/dist/dist/editor/ui/SimpleTable.js +9 -0
- package/dist/dist/editor/ui/SimpleTable.js.map +1 -0
- package/dist/dist/editor/ui/SimpleTabs.d.ts +16 -0
- package/dist/dist/editor/ui/SimpleTabs.js +20 -0
- package/dist/dist/editor/ui/SimpleTabs.js.map +1 -0
- package/dist/dist/editor/ui/SimpleToolbar.d.ts +3 -0
- package/dist/dist/editor/ui/SimpleToolbar.js +5 -0
- package/dist/dist/editor/ui/SimpleToolbar.js.map +1 -0
- package/dist/dist/editor/ui/Spinner.d.ts +4 -0
- package/dist/dist/editor/ui/Spinner.js +18 -0
- package/dist/dist/editor/ui/Spinner.js.map +1 -0
- package/dist/dist/editor/ui/Splitter.d.ts +22 -0
- package/dist/dist/editor/ui/Splitter.js +443 -0
- package/dist/dist/editor/ui/Splitter.js.map +1 -0
- package/dist/dist/editor/ui/TemplateSelectorDialog.d.ts +8 -0
- package/dist/dist/editor/ui/TemplateSelectorDialog.js +138 -0
- package/dist/dist/editor/ui/TemplateSelectorDialog.js.map +1 -0
- package/dist/dist/editor/ui/Toolbar.d.ts +3 -0
- package/dist/dist/editor/ui/Toolbar.js +5 -0
- package/dist/dist/editor/ui/Toolbar.js.map +1 -0
- package/dist/dist/editor/utils/id-helper.d.ts +1 -0
- package/dist/dist/editor/utils/id-helper.js +5 -0
- package/dist/dist/editor/utils/id-helper.js.map +1 -0
- package/dist/dist/editor/utils/insertOptions.d.ts +3 -0
- package/dist/dist/editor/utils/insertOptions.js +43 -0
- package/dist/dist/editor/utils/insertOptions.js.map +1 -0
- package/dist/dist/editor/utils/itemConverters.d.ts +3 -0
- package/dist/dist/editor/utils/itemConverters.js +53 -0
- package/dist/dist/editor/utils/itemConverters.js.map +1 -0
- package/dist/dist/editor/utils/itemutils.d.ts +3 -0
- package/dist/dist/editor/utils/itemutils.js +24 -0
- package/dist/dist/editor/utils/itemutils.js.map +1 -0
- package/dist/dist/editor/utils/jsonCleaner.d.ts +8 -0
- package/dist/dist/editor/utils/jsonCleaner.js +76 -0
- package/dist/dist/editor/utils/jsonCleaner.js.map +1 -0
- package/dist/dist/editor/utils/keyboardNavigation.d.ts +34 -0
- package/dist/dist/editor/utils/keyboardNavigation.js +237 -0
- package/dist/dist/editor/utils/keyboardNavigation.js.map +1 -0
- package/dist/dist/editor/utils/urlUtils.d.ts +9 -0
- package/dist/dist/editor/utils/urlUtils.js +25 -0
- package/dist/dist/editor/utils/urlUtils.js.map +1 -0
- package/dist/dist/editor/utils/useMemoDebug.d.ts +1 -0
- package/dist/dist/editor/utils/useMemoDebug.js +18 -0
- package/dist/dist/editor/utils/useMemoDebug.js.map +1 -0
- package/dist/dist/editor/utils.d.ts +65 -0
- package/dist/dist/editor/utils.js +488 -0
- package/dist/dist/editor/utils.js.map +1 -0
- package/dist/dist/editor/views/CompareView.d.ts +1 -0
- package/dist/dist/editor/views/CompareView.js +148 -0
- package/dist/dist/editor/views/CompareView.js.map +1 -0
- package/dist/dist/editor/views/EditView.d.ts +1 -0
- package/dist/dist/editor/views/EditView.js +15 -0
- package/dist/dist/editor/views/EditView.js.map +1 -0
- package/dist/dist/editor/views/ItemEditor.d.ts +7 -0
- package/dist/dist/editor/views/ItemEditor.js +29 -0
- package/dist/dist/editor/views/ItemEditor.js.map +1 -0
- package/dist/dist/editor/views/MediaFolderEditView.d.ts +4 -0
- package/dist/dist/editor/views/MediaFolderEditView.js +40 -0
- package/dist/dist/editor/views/MediaFolderEditView.js.map +1 -0
- package/dist/dist/editor/views/ParheliaView.d.ts +5 -0
- package/dist/dist/editor/views/ParheliaView.js +163 -0
- package/dist/dist/editor/views/ParheliaView.js.map +1 -0
- package/dist/dist/editor/views/SingleEditView.d.ts +9 -0
- package/dist/dist/editor/views/SingleEditView.js +33 -0
- package/dist/dist/editor/views/SingleEditView.js.map +1 -0
- package/dist/dist/images/bg-shape-black.webp +0 -0
- package/dist/dist/images/wizard-bg.png +0 -0
- package/dist/dist/images/wizard-tour.png +0 -0
- package/dist/dist/images/wizard.png +0 -0
- package/dist/dist/index.d.ts +67 -0
- package/dist/dist/index.js +57 -0
- package/dist/dist/index.js.map +1 -0
- package/dist/dist/lib/safelist.d.ts +1 -0
- package/dist/dist/lib/safelist.js +5 -0
- package/dist/dist/lib/safelist.js.map +1 -0
- package/dist/dist/lib/utils.d.ts +2 -0
- package/dist/dist/lib/utils.js +6 -0
- package/dist/dist/lib/utils.js.map +1 -0
- package/dist/dist/revision.d.ts +2 -0
- package/dist/dist/revision.js +3 -0
- package/dist/dist/revision.js.map +1 -0
- package/dist/dist/setup/SetupWizardPage.d.ts +5 -0
- package/dist/dist/setup/SetupWizardPage.js +8 -0
- package/dist/dist/setup/SetupWizardPage.js.map +1 -0
- package/dist/dist/setup/services/setupWizardService.d.ts +89 -0
- package/dist/dist/setup/services/setupWizardService.js +92 -0
- package/dist/dist/setup/services/setupWizardService.js.map +1 -0
- package/dist/dist/setup/utils/modelPricing.d.ts +7 -0
- package/dist/dist/setup/utils/modelPricing.js +106 -0
- package/dist/dist/setup/utils/modelPricing.js.map +1 -0
- package/dist/dist/setup/wizard/SetupWizard.d.ts +27 -0
- package/dist/dist/setup/wizard/SetupWizard.js +92 -0
- package/dist/dist/setup/wizard/SetupWizard.js.map +1 -0
- package/dist/dist/setup/wizard/index.d.ts +6 -0
- package/dist/dist/setup/wizard/index.js +6 -0
- package/dist/dist/setup/wizard/index.js.map +1 -0
- package/dist/dist/setup/wizard/steps/AgentsStep.d.ts +2 -0
- package/dist/dist/setup/wizard/steps/AgentsStep.js +117 -0
- package/dist/dist/setup/wizard/steps/AgentsStep.js.map +1 -0
- package/dist/dist/setup/wizard/steps/EndpointsStep.d.ts +2 -0
- package/dist/dist/setup/wizard/steps/EndpointsStep.js +94 -0
- package/dist/dist/setup/wizard/steps/EndpointsStep.js.map +1 -0
- package/dist/dist/setup/wizard/steps/ModelsStep.d.ts +2 -0
- package/dist/dist/setup/wizard/steps/ModelsStep.js +287 -0
- package/dist/dist/setup/wizard/steps/ModelsStep.js.map +1 -0
- package/dist/dist/setup/wizard/steps/SearchStep.d.ts +2 -0
- package/dist/dist/setup/wizard/steps/SearchStep.js +95 -0
- package/dist/dist/setup/wizard/steps/SearchStep.js.map +1 -0
- package/dist/dist/splash-screen/ModernSplashScreen.d.ts +8 -0
- package/dist/dist/splash-screen/ModernSplashScreen.js +36 -0
- package/dist/dist/splash-screen/ModernSplashScreen.js.map +1 -0
- package/dist/dist/splash-screen/NewPage.d.ts +3 -0
- package/dist/dist/splash-screen/NewPage.js +145 -0
- package/dist/dist/splash-screen/NewPage.js.map +1 -0
- package/dist/dist/splash-screen/OpenPage.d.ts +1 -0
- package/dist/dist/splash-screen/OpenPage.js +56 -0
- package/dist/dist/splash-screen/OpenPage.js.map +1 -0
- package/dist/dist/splash-screen/ParheliaAssistantChat.d.ts +8 -0
- package/dist/dist/splash-screen/ParheliaAssistantChat.js +169 -0
- package/dist/dist/splash-screen/ParheliaAssistantChat.js.map +1 -0
- package/dist/dist/splash-screen/ParheliaLogo.d.ts +5 -0
- package/dist/dist/splash-screen/ParheliaLogo.js +71 -0
- package/dist/dist/splash-screen/ParheliaLogo.js.map +1 -0
- package/dist/dist/splash-screen/RecentAgents.d.ts +7 -0
- package/dist/dist/splash-screen/RecentAgents.js +76 -0
- package/dist/dist/splash-screen/RecentAgents.js.map +1 -0
- package/dist/dist/splash-screen/RecentPages.d.ts +1 -0
- package/dist/dist/splash-screen/RecentPages.js +59 -0
- package/dist/dist/splash-screen/RecentPages.js.map +1 -0
- package/dist/dist/splash-screen/SectionHeadline.d.ts +4 -0
- package/dist/dist/splash-screen/SectionHeadline.js +7 -0
- package/dist/dist/splash-screen/SectionHeadline.js.map +1 -0
- package/dist/dist/styles.css +6035 -0
- package/dist/dist/tour/Tour.d.ts +3 -0
- package/dist/dist/tour/Tour.js +426 -0
- package/dist/dist/tour/Tour.js.map +1 -0
- package/dist/dist/tour/default-tour.d.ts +9 -0
- package/dist/dist/tour/default-tour.js +302 -0
- package/dist/dist/tour/default-tour.js.map +1 -0
- package/dist/dist/tour/preview-tour.d.ts +2 -0
- package/dist/dist/tour/preview-tour.js +93 -0
- package/dist/dist/tour/preview-tour.js.map +1 -0
- package/dist/dist/types.d.ts +490 -0
- package/dist/dist/types.js +2 -0
- package/dist/dist/types.js.map +1 -0
- package/dist/editor/control-center/parhelia-setup/Overview.d.ts +1 -0
- package/dist/editor/control-center/parhelia-setup/Overview.js +91 -0
- package/dist/editor/control-center/parhelia-setup/Overview.js.map +1 -0
- package/dist/editor/hooks/useEditorSettings.d.ts +17 -0
- package/dist/editor/hooks/useEditorSettings.js +61 -0
- package/dist/editor/hooks/useEditorSettings.js.map +1 -0
- package/dist/editor/page-viewer/EditorFormPopup.d.ts +11 -0
- package/dist/editor/page-viewer/EditorFormPopup.js +41 -0
- package/dist/editor/page-viewer/EditorFormPopup.js.map +1 -0
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/revision.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,3012 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import React, { useEffect, useState, useRef, useCallback, useLayoutEffect, ViewTransition, } from "react";
|
|
3
|
+
import { Send, AlertCircle, Loader2, User, Wand2, Square, Mic, MicOff, ChevronDown, ChevronUp, ListTodo, ExternalLink, } from "lucide-react";
|
|
4
|
+
import { DancingDots } from "./DancingDots";
|
|
5
|
+
import { getAgent, startAgent, updateAgentSettings, updateAgentCostLimit, updateAgentContext, cancelAgent, canonicalizeAgentMetadata, getPendingPrompts, } from "../services/agentService";
|
|
6
|
+
import { useEditContext, useFieldsEditContext } from "../client/editContext";
|
|
7
|
+
import { Textarea } from "../../components/ui/textarea";
|
|
8
|
+
import { Button } from "../../components/ui/button";
|
|
9
|
+
import { PlaceholderInput } from "../../components/ui/PlaceholderInput";
|
|
10
|
+
import { AiResponseMessage } from "./AiResponseMessage";
|
|
11
|
+
import { AgentCostDisplay } from "./AgentCostDisplay";
|
|
12
|
+
import { ContextInfoBar } from "./ContextInfoBar";
|
|
13
|
+
import { AgentDocumentList } from "./AgentDocumentList";
|
|
14
|
+
import { getComponentById } from "../componentTreeHelper";
|
|
15
|
+
import { Popover, PopoverContent, PopoverTrigger, } from "../../components/ui/popover";
|
|
16
|
+
import { SecretAgentIcon } from "../ui/Icons";
|
|
17
|
+
import { formatTime } from "../utils";
|
|
18
|
+
import { Tooltip, TooltipTrigger, TooltipContent, } from "../../components/ui/tooltip";
|
|
19
|
+
// Simple user message component
|
|
20
|
+
const UserMessage = ({ message }) => {
|
|
21
|
+
// Parse source agent name from content if it starts with "[From ...]:"
|
|
22
|
+
// Backend formats messages from other agents as "[From {sourceAgentName}]: {content}"
|
|
23
|
+
const content = message.content || "";
|
|
24
|
+
const fromPattern = /^\[From ([^\]]+)\]:\s*(.*)$/s;
|
|
25
|
+
const match = content.match(fromPattern);
|
|
26
|
+
let sourceAgentName;
|
|
27
|
+
let displayContent = content;
|
|
28
|
+
if (match && match[1]) {
|
|
29
|
+
const extractedName = match[1];
|
|
30
|
+
// If it says "From User", treat it as a regular user message
|
|
31
|
+
if (extractedName.toLowerCase() === "user") {
|
|
32
|
+
sourceAgentName = undefined;
|
|
33
|
+
displayContent = content; // Keep original content
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
sourceAgentName = extractedName;
|
|
37
|
+
displayContent = match[2] || ""; // Remove the "[From ...]:" prefix from content
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
// Fallback: check for source agent name in message metadata or properties
|
|
42
|
+
sourceAgentName =
|
|
43
|
+
message.sourceAgentName ||
|
|
44
|
+
message.metadata?.sourceAgentName ||
|
|
45
|
+
message.sourceAgent?.name;
|
|
46
|
+
}
|
|
47
|
+
const displayName = sourceAgentName ? `[From ${sourceAgentName}]` : "You";
|
|
48
|
+
return (_jsxs("div", { className: "flex gap-3 p-4", children: [_jsx("div", { className: "flex-shrink-0", children: _jsx(User, { className: "h-6 w-6 text-blue-600", strokeWidth: 1 }) }), _jsxs("div", { className: "min-w-0 flex-1 select-text", children: [_jsxs("div", { className: "mb-1 flex items-center gap-2", children: [_jsx("span", { className: "text-xs font-medium text-gray-900", children: displayName }), message.createdDate && (_jsx("span", { className: "text-xs text-gray-400", "data-testid": "user-message-timestamp", "data-timestamp": message.createdDate, children: formatTime(new Date(message.createdDate)) }))] }), _jsx("div", { className: "prose prose-sm max-w-none text-xs text-gray-700 select-text", children: displayContent })] })] }));
|
|
49
|
+
};
|
|
50
|
+
// Helper to extract todos from potentially incomplete JSON during streaming
|
|
51
|
+
const extractPartialTodos = (jsonText) => {
|
|
52
|
+
// First try to parse complete JSON
|
|
53
|
+
try {
|
|
54
|
+
const parsed = JSON.parse(jsonText);
|
|
55
|
+
return Array.isArray(parsed) ? parsed : parsed?.items || [];
|
|
56
|
+
}
|
|
57
|
+
catch (e) {
|
|
58
|
+
// If JSON is incomplete, try to extract whatever todo items we can find
|
|
59
|
+
const items = [];
|
|
60
|
+
// Look for individual todo objects in the partial JSON
|
|
61
|
+
// Match patterns like: { "text": "...", "done": false, "note": "..." }
|
|
62
|
+
// Handle various field orderings (text can be anywhere in the object)
|
|
63
|
+
const textPattern = /"text"\s*:\s*"([^"]+)"/g;
|
|
64
|
+
const textMatches = [];
|
|
65
|
+
let textMatch;
|
|
66
|
+
while ((textMatch = textPattern.exec(jsonText)) !== null) {
|
|
67
|
+
if (textMatch[1]) {
|
|
68
|
+
textMatches.push({
|
|
69
|
+
text: textMatch[1],
|
|
70
|
+
startIdx: textMatch.index,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// For each text field found, try to find the enclosing object
|
|
75
|
+
for (const { text, startIdx } of textMatches) {
|
|
76
|
+
// Find the opening brace before this text field
|
|
77
|
+
let openBrace = -1;
|
|
78
|
+
for (let i = startIdx - 1; i >= 0; i--) {
|
|
79
|
+
if (jsonText[i] === "{") {
|
|
80
|
+
openBrace = i;
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
if (jsonText[i] === "}")
|
|
84
|
+
break; // Hit another object's end
|
|
85
|
+
}
|
|
86
|
+
if (openBrace === -1)
|
|
87
|
+
continue;
|
|
88
|
+
// Find the closing brace after this text field
|
|
89
|
+
let closeBrace = -1;
|
|
90
|
+
let depth = 0;
|
|
91
|
+
for (let i = openBrace; i < jsonText.length; i++) {
|
|
92
|
+
if (jsonText[i] === "{")
|
|
93
|
+
depth++;
|
|
94
|
+
if (jsonText[i] === "}") {
|
|
95
|
+
depth--;
|
|
96
|
+
if (depth === 0) {
|
|
97
|
+
closeBrace = i;
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// Extract the object and try to parse it
|
|
103
|
+
const objStr = closeBrace !== -1
|
|
104
|
+
? jsonText.substring(openBrace, closeBrace + 1)
|
|
105
|
+
: jsonText.substring(openBrace) + "}"; // Try to close incomplete object
|
|
106
|
+
try {
|
|
107
|
+
const obj = JSON.parse(objStr);
|
|
108
|
+
if (obj.text) {
|
|
109
|
+
items.push({
|
|
110
|
+
text: obj.text,
|
|
111
|
+
done: obj.done === true,
|
|
112
|
+
note: obj.note || undefined,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch (e) {
|
|
117
|
+
// Skip malformed objects
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Also try to extract from partial objects at the end
|
|
121
|
+
// Look for the last opening brace and try to parse up to where we have valid content
|
|
122
|
+
const lines = jsonText.split("\n");
|
|
123
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
124
|
+
const partialJson = lines.slice(0, i + 1).join("\n");
|
|
125
|
+
// Try to close any open braces/brackets
|
|
126
|
+
let testJson = partialJson;
|
|
127
|
+
const openBraces = (testJson.match(/\{/g) || []).length;
|
|
128
|
+
const closeBraces = (testJson.match(/\}/g) || []).length;
|
|
129
|
+
const openBrackets = (testJson.match(/\[/g) || []).length;
|
|
130
|
+
const closeBrackets = (testJson.match(/\]/g) || []).length;
|
|
131
|
+
// Add missing closing characters
|
|
132
|
+
testJson += "]".repeat(openBrackets - closeBrackets);
|
|
133
|
+
testJson += "}".repeat(openBraces - closeBraces);
|
|
134
|
+
try {
|
|
135
|
+
const parsed = JSON.parse(testJson);
|
|
136
|
+
const partialItems = Array.isArray(parsed)
|
|
137
|
+
? parsed
|
|
138
|
+
: parsed?.items || [];
|
|
139
|
+
if (partialItems.length > items.length) {
|
|
140
|
+
return partialItems;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
catch (e) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return items;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
const extractTodosFromMessages = (messages) => {
|
|
151
|
+
const todos = [];
|
|
152
|
+
const fencedTodoToken = "```todo_list";
|
|
153
|
+
const plainTodoToken = "todo_list";
|
|
154
|
+
for (const message of messages) {
|
|
155
|
+
if (message.role !== "assistant" || !message.content)
|
|
156
|
+
continue;
|
|
157
|
+
const content = message.content;
|
|
158
|
+
let cursor = 0;
|
|
159
|
+
while (cursor < content.length) {
|
|
160
|
+
const nextFenced = content.indexOf(fencedTodoToken, cursor);
|
|
161
|
+
const nextPlain = content.indexOf(plainTodoToken, cursor);
|
|
162
|
+
let todoStart = -1;
|
|
163
|
+
let isFenced = false;
|
|
164
|
+
if (nextFenced !== -1 && (nextPlain === -1 || nextFenced < nextPlain)) {
|
|
165
|
+
todoStart = nextFenced;
|
|
166
|
+
isFenced = true;
|
|
167
|
+
}
|
|
168
|
+
else if (nextPlain !== -1) {
|
|
169
|
+
// Check if it's at line start
|
|
170
|
+
const before = nextPlain > 0 ? content[nextPlain - 1] : "\n";
|
|
171
|
+
if (before === "\n" || before === "\r" || nextPlain === 0) {
|
|
172
|
+
todoStart = nextPlain;
|
|
173
|
+
isFenced = false;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (todoStart === -1)
|
|
177
|
+
break;
|
|
178
|
+
try {
|
|
179
|
+
let jsonText = "";
|
|
180
|
+
let isComplete = true;
|
|
181
|
+
if (isFenced) {
|
|
182
|
+
const afterToken = todoStart + fencedTodoToken.length;
|
|
183
|
+
const closePos = content.indexOf("```", afterToken);
|
|
184
|
+
if (closePos === -1) {
|
|
185
|
+
// Incomplete fenced block - extract what we have so far
|
|
186
|
+
jsonText = content.slice(afterToken).trim();
|
|
187
|
+
isComplete = false;
|
|
188
|
+
cursor = content.length; // Process till end
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
jsonText = content.slice(afterToken, closePos).trim();
|
|
192
|
+
cursor = closePos + 3;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
const afterToken = todoStart + plainTodoToken.length;
|
|
197
|
+
const braceStart = content.indexOf("{", afterToken);
|
|
198
|
+
if (braceStart === -1)
|
|
199
|
+
break;
|
|
200
|
+
let depth = 0;
|
|
201
|
+
let braceEnd = -1;
|
|
202
|
+
for (let i = braceStart; i < content.length; i++) {
|
|
203
|
+
if (content[i] === "{")
|
|
204
|
+
depth++;
|
|
205
|
+
if (content[i] === "}") {
|
|
206
|
+
depth--;
|
|
207
|
+
if (depth === 0) {
|
|
208
|
+
braceEnd = i;
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
if (braceEnd === -1) {
|
|
214
|
+
// Incomplete JSON - extract what we have
|
|
215
|
+
jsonText = content.slice(braceStart).trim();
|
|
216
|
+
isComplete = false;
|
|
217
|
+
cursor = content.length;
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
jsonText = content.slice(braceStart, braceEnd + 1).trim();
|
|
221
|
+
cursor = braceEnd + 1;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
// Use the partial extraction helper for incomplete JSON
|
|
225
|
+
const todoItems = isComplete
|
|
226
|
+
? (() => {
|
|
227
|
+
try {
|
|
228
|
+
const parsed = JSON.parse(jsonText);
|
|
229
|
+
return Array.isArray(parsed) ? parsed : parsed?.items || [];
|
|
230
|
+
}
|
|
231
|
+
catch (e) {
|
|
232
|
+
return [];
|
|
233
|
+
}
|
|
234
|
+
})()
|
|
235
|
+
: extractPartialTodos(jsonText);
|
|
236
|
+
const title = (() => {
|
|
237
|
+
try {
|
|
238
|
+
const parsed = JSON.parse(jsonText);
|
|
239
|
+
return Array.isArray(parsed) ? undefined : parsed?.title;
|
|
240
|
+
}
|
|
241
|
+
catch (e) {
|
|
242
|
+
return undefined;
|
|
243
|
+
}
|
|
244
|
+
})();
|
|
245
|
+
todoItems.forEach((item) => {
|
|
246
|
+
if (!item)
|
|
247
|
+
return;
|
|
248
|
+
const text = item.text ||
|
|
249
|
+
item.content ||
|
|
250
|
+
item.label ||
|
|
251
|
+
String(item.task || item.title || "");
|
|
252
|
+
if (!text)
|
|
253
|
+
return;
|
|
254
|
+
todos.push({
|
|
255
|
+
id: item.id,
|
|
256
|
+
text,
|
|
257
|
+
done: !!(item.done ??
|
|
258
|
+
item.completed ??
|
|
259
|
+
item.checked ??
|
|
260
|
+
item.status === "completed"),
|
|
261
|
+
note: item.note || item.description,
|
|
262
|
+
messageId: message.id,
|
|
263
|
+
sourceTitle: title,
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
catch (e) {
|
|
268
|
+
cursor++;
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return todos;
|
|
274
|
+
};
|
|
275
|
+
// TodoListPanel component
|
|
276
|
+
const TodoListPanel = ({ messages, agentMetadata, }) => {
|
|
277
|
+
const [isExpanded, setIsExpanded] = useState(true);
|
|
278
|
+
// First try to get todos from agent metadata (real-time updates)
|
|
279
|
+
const metadataTodos = (() => {
|
|
280
|
+
try {
|
|
281
|
+
const todoList = agentMetadata?.additionalData?.todoList;
|
|
282
|
+
if (todoList?.items && Array.isArray(todoList.items)) {
|
|
283
|
+
return todoList.items
|
|
284
|
+
.map((item, idx) => ({
|
|
285
|
+
id: item.id || `metadata-${idx}`,
|
|
286
|
+
text: item.text || item.label || String(item.task || item.title || ""),
|
|
287
|
+
done: !!(item.done ?? item.completed ?? item.checked),
|
|
288
|
+
note: item.note || item.description,
|
|
289
|
+
messageId: undefined,
|
|
290
|
+
sourceTitle: todoList.title,
|
|
291
|
+
}))
|
|
292
|
+
.filter((item) => item.text);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
catch (e) {
|
|
296
|
+
console.error("📋 Error extracting todos from metadata:", e);
|
|
297
|
+
}
|
|
298
|
+
return null;
|
|
299
|
+
})();
|
|
300
|
+
// If we have metadata todos, use them; otherwise extract from messages
|
|
301
|
+
const todos = metadataTodos && metadataTodos.length > 0
|
|
302
|
+
? metadataTodos
|
|
303
|
+
: extractTodosFromMessages(messages);
|
|
304
|
+
// Check if there's an active streaming message with incomplete todo content
|
|
305
|
+
const isUpdating = messages.some((msg) => {
|
|
306
|
+
if (msg.role !== "assistant" || msg.isCompleted)
|
|
307
|
+
return false;
|
|
308
|
+
const content = msg.content || "";
|
|
309
|
+
// Check for incomplete fenced todo blocks
|
|
310
|
+
const fencedStart = content.indexOf("```todo_list");
|
|
311
|
+
if (fencedStart !== -1) {
|
|
312
|
+
const afterStart = fencedStart + "```todo_list".length;
|
|
313
|
+
const closePos = content.indexOf("```", afterStart);
|
|
314
|
+
if (closePos === -1) {
|
|
315
|
+
// Incomplete fenced block
|
|
316
|
+
return true;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
// Check for incomplete plain todo blocks
|
|
320
|
+
const plainStart = content.indexOf("todo_list");
|
|
321
|
+
if (plainStart !== -1 && plainStart !== fencedStart) {
|
|
322
|
+
const before = plainStart > 0 ? content[plainStart - 1] : "\n";
|
|
323
|
+
if (before === "\n" || before === "\r" || plainStart === 0) {
|
|
324
|
+
const braceStart = content.indexOf("{", plainStart);
|
|
325
|
+
if (braceStart !== -1) {
|
|
326
|
+
let depth = 0;
|
|
327
|
+
let braceEnd = -1;
|
|
328
|
+
for (let i = braceStart; i < content.length; i++) {
|
|
329
|
+
if (content[i] === "{")
|
|
330
|
+
depth++;
|
|
331
|
+
if (content[i] === "}") {
|
|
332
|
+
depth--;
|
|
333
|
+
if (depth === 0) {
|
|
334
|
+
braceEnd = i;
|
|
335
|
+
break;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
if (braceEnd === -1) {
|
|
340
|
+
// Incomplete plain block
|
|
341
|
+
return true;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return false;
|
|
347
|
+
});
|
|
348
|
+
if (todos.length === 0 && !isUpdating)
|
|
349
|
+
return null;
|
|
350
|
+
const completedCount = todos.filter((t) => t.done).length;
|
|
351
|
+
const totalCount = todos.length;
|
|
352
|
+
return (_jsxs("div", { className: "border-t border-gray-200 bg-gray-50", children: [_jsxs("button", { onClick: () => setIsExpanded(!isExpanded), className: "flex w-full cursor-pointer items-center justify-between px-4 py-2 text-left transition-colors hover:bg-gray-100", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(ListTodo, { className: "h-4 w-4 text-gray-500", strokeWidth: 1 }), _jsx("span", { className: "text-xs font-medium text-gray-700", children: "Todo List" }), isUpdating ? (_jsxs("span", { className: "flex items-center gap-1 text-xs text-blue-600", children: [_jsx(Loader2, { className: "h-3 w-3 animate-spin", strokeWidth: 1 }), "Updating..."] })) : (_jsxs("span", { className: "text-xs text-gray-500", children: [completedCount, "/", totalCount, " completed"] }))] }), isExpanded ? (_jsx(ChevronUp, { className: "h-4 w-4 text-gray-500", strokeWidth: 1 })) : (_jsx(ChevronDown, { className: "h-4 w-4 text-gray-500", strokeWidth: 1 }))] }), isExpanded && (_jsxs("div", { className: "max-h-64 overflow-y-auto px-4 pb-3", children: [todos.length > 0 && (_jsx("div", { className: "space-y-1.5", children: todos.map((todo, idx) => (_jsxs("div", { className: "flex items-start gap-2 rounded bg-white p-2 text-xs", children: [_jsx("div", { className: "flex-shrink-0 pt-0.5", children: todo.done ? (_jsx("div", { className: "flex h-4 w-4 items-center justify-center rounded border-2 border-green-500 bg-green-500", children: _jsx("svg", { className: "h-3 w-3 text-white", fill: "none", strokeWidth: 2, stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }) }) })) : (_jsx("div", { className: "h-4 w-4 rounded border-2 border-gray-300" })) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: `${todo.done
|
|
353
|
+
? "text-gray-500 line-through"
|
|
354
|
+
: "text-gray-900"}`, children: todo.text }), todo.note && (_jsx("div", { className: "mt-0.5 text-xs text-gray-500", children: todo.note }))] })] }, todo.id || `${todo.messageId}-${idx}`))) })), isUpdating && (_jsxs("div", { className: `flex items-center gap-2 rounded px-3 py-2 text-xs ${todos.length > 0
|
|
355
|
+
? "mt-2 bg-blue-50 text-blue-700"
|
|
356
|
+
: "justify-center bg-white text-gray-500"}`, children: [_jsx(Loader2, { className: "h-3 w-3 animate-spin", strokeWidth: 1 }), _jsx("span", { children: todos.length > 0
|
|
357
|
+
? "Updating todo list..."
|
|
358
|
+
: "Loading todo list..." })] }))] }))] }));
|
|
359
|
+
};
|
|
360
|
+
const groupConsecutiveMessages = (agentMessages) => {
|
|
361
|
+
// Work directly with the messages array - streaming messages are identified by their properties
|
|
362
|
+
const allMessages = agentMessages;
|
|
363
|
+
const groups = [];
|
|
364
|
+
let currentAssistantGroup = [];
|
|
365
|
+
for (const message of allMessages) {
|
|
366
|
+
if (message.role === "user") {
|
|
367
|
+
// Finish any current assistant group
|
|
368
|
+
if (currentAssistantGroup.length > 0) {
|
|
369
|
+
groups.push({
|
|
370
|
+
type: "assistant-group",
|
|
371
|
+
messages: currentAssistantGroup,
|
|
372
|
+
});
|
|
373
|
+
currentAssistantGroup = [];
|
|
374
|
+
}
|
|
375
|
+
// Add user message
|
|
376
|
+
groups.push({ type: "user", messages: [message] });
|
|
377
|
+
}
|
|
378
|
+
else if (message.role === "assistant") {
|
|
379
|
+
// Add to current assistant group
|
|
380
|
+
currentAssistantGroup.push(message);
|
|
381
|
+
}
|
|
382
|
+
// Skip tool messages as they're handled within assistant messages
|
|
383
|
+
}
|
|
384
|
+
// Add any remaining assistant group
|
|
385
|
+
if (currentAssistantGroup.length > 0) {
|
|
386
|
+
groups.push({ type: "assistant-group", messages: currentAssistantGroup });
|
|
387
|
+
}
|
|
388
|
+
return groups;
|
|
389
|
+
};
|
|
390
|
+
// Merge messages from DB and local state with ID-based deduplication
|
|
391
|
+
const mergeMessagesById = (dbMessages, localMessages) => {
|
|
392
|
+
const messageMap = new Map();
|
|
393
|
+
// Normalize ID key (lowercase) to avoid duplicates caused by casing differences
|
|
394
|
+
const keyOf = (id) => (id ? id.toLowerCase() : "");
|
|
395
|
+
// First, add all DB messages (source of truth for completed messages)
|
|
396
|
+
dbMessages.forEach((msg) => {
|
|
397
|
+
if (msg.id)
|
|
398
|
+
messageMap.set(keyOf(msg.id), msg);
|
|
399
|
+
});
|
|
400
|
+
// Then merge local messages (preserve streaming state, prefer longer content)
|
|
401
|
+
localMessages.forEach((localMsg) => {
|
|
402
|
+
if (!localMsg.id)
|
|
403
|
+
return;
|
|
404
|
+
const key = keyOf(localMsg.id);
|
|
405
|
+
const existingMsg = messageMap.get(key);
|
|
406
|
+
if (!existingMsg) {
|
|
407
|
+
// New message only in local state (e.g., streaming)
|
|
408
|
+
messageMap.set(key, localMsg);
|
|
409
|
+
}
|
|
410
|
+
else if (!localMsg.isCompleted && localMsg.messageType === "streaming") {
|
|
411
|
+
// Keep streaming version if more recent/longer
|
|
412
|
+
if (localMsg.content.length > existingMsg.content.length) {
|
|
413
|
+
messageMap.set(key, localMsg);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
// Otherwise, keep the DB version (completed messages from DB are authoritative)
|
|
417
|
+
});
|
|
418
|
+
// Sort by messageIndex or createdDate to maintain order
|
|
419
|
+
// Ignore messageIndex if it's -1 (unassigned/streaming)
|
|
420
|
+
return Array.from(messageMap.values()).sort((a, b) => {
|
|
421
|
+
const aIndex = a.messageIndex === -1 ? Infinity : a.messageIndex;
|
|
422
|
+
const bIndex = b.messageIndex === -1 ? Infinity : b.messageIndex;
|
|
423
|
+
if (aIndex !== bIndex) {
|
|
424
|
+
return aIndex - bIndex;
|
|
425
|
+
}
|
|
426
|
+
return (new Date(a.createdDate || 0).getTime() -
|
|
427
|
+
new Date(b.createdDate || 0).getTime());
|
|
428
|
+
});
|
|
429
|
+
};
|
|
430
|
+
// Calculate total token usage and cost data from agent messages
|
|
431
|
+
const calculateTotalTokens = (messages) => {
|
|
432
|
+
const totals = messages.reduce((acc, message) => {
|
|
433
|
+
return {
|
|
434
|
+
input: acc.input + (message.inputTokens || 0),
|
|
435
|
+
output: acc.output + (message.outputTokens || 0),
|
|
436
|
+
cached: acc.cached + (message.cachedInputTokens || 0),
|
|
437
|
+
cacheWrite: acc.cacheWrite,
|
|
438
|
+
inputCost: acc.inputCost + (message.inputTokenCost || 0),
|
|
439
|
+
outputCost: acc.outputCost + (message.outputTokenCost || 0),
|
|
440
|
+
cachedCost: acc.cachedCost + (message.cachedInputTokenCost || 0),
|
|
441
|
+
cacheWriteCost: acc.cacheWriteCost,
|
|
442
|
+
totalCost: acc.totalCost + (message.totalCost || 0),
|
|
443
|
+
};
|
|
444
|
+
}, {
|
|
445
|
+
input: 0,
|
|
446
|
+
output: 0,
|
|
447
|
+
cached: 0,
|
|
448
|
+
cacheWrite: 0,
|
|
449
|
+
inputCost: 0,
|
|
450
|
+
outputCost: 0,
|
|
451
|
+
cachedCost: 0,
|
|
452
|
+
cacheWriteCost: 0,
|
|
453
|
+
totalCost: 0,
|
|
454
|
+
});
|
|
455
|
+
return totals;
|
|
456
|
+
};
|
|
457
|
+
// Convert agent messages to AI terminal format for a response group
|
|
458
|
+
const convertAgentMessagesToAiFormat = (agentMessages) => {
|
|
459
|
+
return agentMessages.map((agentMessage) => {
|
|
460
|
+
const message = {
|
|
461
|
+
id: agentMessage.id,
|
|
462
|
+
content: agentMessage.content,
|
|
463
|
+
formattedContent: agentMessage.content
|
|
464
|
+
?.replace(/^######\s+(.+)$/gm, "<h6>$1</h6>")
|
|
465
|
+
?.replace(/^#####\s+(.+)$/gm, "<h5>$1</h5>")
|
|
466
|
+
?.replace(/^####\s+(.+)$/gm, "<h4>$1</h4>")
|
|
467
|
+
?.replace(/^###\s+(.+)$/gm, "<h3>$1</h3>")
|
|
468
|
+
?.replace(/^##\s+(.+)$/gm, "<h2>$1</h2>")
|
|
469
|
+
?.replace(/^#\s+(.+)$/gm, "<h1>$1</h1>")
|
|
470
|
+
?.replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>")
|
|
471
|
+
?.replace(/\n/g, "<br/>"),
|
|
472
|
+
name: agentMessage.name,
|
|
473
|
+
role: agentMessage.role,
|
|
474
|
+
createdDate: agentMessage.createdDate,
|
|
475
|
+
tool_calls: agentMessage.toolCalls
|
|
476
|
+
? agentMessage.toolCalls.map((toolCall) => ({
|
|
477
|
+
id: toolCall.toolCallId,
|
|
478
|
+
displayName: toolCall.functionName,
|
|
479
|
+
function: {
|
|
480
|
+
name: toolCall.functionName,
|
|
481
|
+
arguments: toolCall.functionArguments,
|
|
482
|
+
result: toolCall.functionResult,
|
|
483
|
+
error: toolCall.functionError,
|
|
484
|
+
},
|
|
485
|
+
// Pass through approval info if present on the tool call
|
|
486
|
+
requiresApproval: toolCall.requiresApproval,
|
|
487
|
+
}))
|
|
488
|
+
: [],
|
|
489
|
+
};
|
|
490
|
+
if (agentMessage.toolCallId) {
|
|
491
|
+
message.tool_call_id = agentMessage.toolCallId;
|
|
492
|
+
}
|
|
493
|
+
return message;
|
|
494
|
+
});
|
|
495
|
+
};
|
|
496
|
+
// interface AgentTerminalProps {
|
|
497
|
+
// agentStub: Agent;
|
|
498
|
+
// }
|
|
499
|
+
export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive = true, compact = false, hideContext = false, hideBottomControls = false, hideGreeting = false, className, initialPrompt, }) {
|
|
500
|
+
const editContext = useEditContext();
|
|
501
|
+
const fieldsContext = useFieldsEditContext();
|
|
502
|
+
const [agent, setAgent] = useState(undefined);
|
|
503
|
+
const [messages, setMessages] = useState([]);
|
|
504
|
+
const [prompt, setPrompt] = useState("");
|
|
505
|
+
const [inputPlaceholder, setInputPlaceholder] = useState("Type your message... (Enter to send, Shift+Enter or Ctrl+Enter for new line)");
|
|
506
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
507
|
+
const [isConnecting, setIsConnecting] = useState(false);
|
|
508
|
+
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
509
|
+
const [activePlaceholderInput, setActivePlaceholderInput] = useState(null);
|
|
510
|
+
const [agentMetadata, setAgentMetadata] = useState(null);
|
|
511
|
+
// Generate a stable clientSessionId per component instance for stream deduplication
|
|
512
|
+
const clientSessionIdRef = useRef(null);
|
|
513
|
+
if (!clientSessionIdRef.current) {
|
|
514
|
+
clientSessionIdRef.current = crypto.randomUUID();
|
|
515
|
+
}
|
|
516
|
+
// Voice input state
|
|
517
|
+
const [isVoiceSupported, setIsVoiceSupported] = useState(false);
|
|
518
|
+
const [isListening, setIsListening] = useState(false);
|
|
519
|
+
const recognitionRef = useRef(null);
|
|
520
|
+
const prevPlaceholderRef = useRef(null);
|
|
521
|
+
const [isWaitingForResponse, setIsWaitingForResponse] = useState(false);
|
|
522
|
+
const isWaitingRef = useRef(false);
|
|
523
|
+
useEffect(() => {
|
|
524
|
+
isWaitingRef.current = isWaitingForResponse;
|
|
525
|
+
}, [isWaitingForResponse]);
|
|
526
|
+
// Dots visibility controlled by 1s idle timer since last incremental update
|
|
527
|
+
const [showDots, setShowDots] = useState(false);
|
|
528
|
+
const dotsTimeoutRef = useRef(null);
|
|
529
|
+
const hasActiveStreaming = useCallback(() => {
|
|
530
|
+
const current = messagesRef.current || [];
|
|
531
|
+
return current.some((m) => !m.isCompleted && m.messageType === "streaming");
|
|
532
|
+
}, []);
|
|
533
|
+
const hasPendingApprovals = useCallback(() => {
|
|
534
|
+
const current = messagesRef.current || [];
|
|
535
|
+
return current.some((m) => (m.toolCalls || []).some((tc) => {
|
|
536
|
+
const hasApprovalMetadata = !!tc.requiresApproval && tc.isCompleted === false;
|
|
537
|
+
const hasPendingSuffix = (tc.functionName || "").includes("(pending approval)");
|
|
538
|
+
return hasApprovalMetadata || hasPendingSuffix;
|
|
539
|
+
}));
|
|
540
|
+
}, []);
|
|
541
|
+
const resetDotsTimer = useCallback(() => {
|
|
542
|
+
if (dotsTimeoutRef.current) {
|
|
543
|
+
clearTimeout(dotsTimeoutRef.current);
|
|
544
|
+
dotsTimeoutRef.current = null;
|
|
545
|
+
}
|
|
546
|
+
const waiting = isWaitingRef.current;
|
|
547
|
+
const streaming = hasActiveStreaming();
|
|
548
|
+
const pendingApprovals = hasPendingApprovals();
|
|
549
|
+
// Check if agent is waiting for approval
|
|
550
|
+
const currentAgent = agentRef.current;
|
|
551
|
+
const isWaitingForApproval = currentAgent?.status === "waitingForApproval" ||
|
|
552
|
+
currentAgent?.status === 2;
|
|
553
|
+
// Don't show dots if there are pending approvals (waiting for user action)
|
|
554
|
+
// or if the agent status is waitingForApproval
|
|
555
|
+
if (!waiting && !streaming) {
|
|
556
|
+
setShowDots(false);
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
if (pendingApprovals || isWaitingForApproval) {
|
|
560
|
+
setShowDots(false);
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
// Show dots immediately when waiting or streaming
|
|
564
|
+
setShowDots(true);
|
|
565
|
+
dotsTimeoutRef.current = setTimeout(() => {
|
|
566
|
+
// Re-check conditions after a brief delay to avoid flicker
|
|
567
|
+
const stillWaiting = isWaitingRef.current;
|
|
568
|
+
const stillStreaming = hasActiveStreaming();
|
|
569
|
+
const stillPendingApprovals = hasPendingApprovals();
|
|
570
|
+
const stillCurrentAgent = agentRef.current;
|
|
571
|
+
const stillWaitingForApproval = stillCurrentAgent?.status === "waitingForApproval" ||
|
|
572
|
+
stillCurrentAgent?.status === 2;
|
|
573
|
+
setShowDots((stillWaiting || stillStreaming) &&
|
|
574
|
+
!stillPendingApprovals &&
|
|
575
|
+
!stillWaitingForApproval);
|
|
576
|
+
}, 100);
|
|
577
|
+
}, [hasActiveStreaming, hasPendingApprovals]);
|
|
578
|
+
const [resolvedPageName, setResolvedPageName] = useState(undefined);
|
|
579
|
+
const [resolvedComponentName, setResolvedComponentName] = useState(undefined);
|
|
580
|
+
const [resolvedFieldName, setResolvedFieldName] = useState(undefined);
|
|
581
|
+
const [isContextCollapsed, setIsContextCollapsed] = useState(true);
|
|
582
|
+
const [isContextDragOver, setIsContextDragOver] = useState(false);
|
|
583
|
+
const [promptHistory, setPromptHistory] = useState(() => {
|
|
584
|
+
if (typeof window !== "undefined") {
|
|
585
|
+
return JSON.parse(localStorage.getItem("editor.agent.promptHistory") || "[]");
|
|
586
|
+
}
|
|
587
|
+
return [];
|
|
588
|
+
});
|
|
589
|
+
const [currentHistoryIndex, setCurrentHistoryIndex] = useState(-1);
|
|
590
|
+
const [showPredefined, setShowPredefined] = useState(false);
|
|
591
|
+
const [activeProfile, setActiveProfile] = useState(undefined);
|
|
592
|
+
const [selectedModelId, setSelectedModelId] = useState(undefined);
|
|
593
|
+
const [mode, setMode] = useState("supervised");
|
|
594
|
+
const [queuedPrompts, setQueuedPrompts] = useState([]);
|
|
595
|
+
// Remove deprecated cost limit fields from metadata to avoid confusion with agent/profile settings
|
|
596
|
+
const sanitizeAgentMetadata = useCallback((meta) => {
|
|
597
|
+
try {
|
|
598
|
+
if (!meta)
|
|
599
|
+
return meta;
|
|
600
|
+
const clean = { ...meta };
|
|
601
|
+
delete clean.costLimit;
|
|
602
|
+
delete clean.CostLimit;
|
|
603
|
+
delete clean.initialCostLimit;
|
|
604
|
+
delete clean.InitialCostLimit;
|
|
605
|
+
if (clean.additionalData && typeof clean.additionalData === "object") {
|
|
606
|
+
const ad = { ...clean.additionalData };
|
|
607
|
+
delete ad.costLimit;
|
|
608
|
+
delete ad.CostLimit;
|
|
609
|
+
delete ad.initialCostLimit;
|
|
610
|
+
delete ad.InitialCostLimit;
|
|
611
|
+
clean.additionalData = ad;
|
|
612
|
+
}
|
|
613
|
+
return clean;
|
|
614
|
+
}
|
|
615
|
+
catch {
|
|
616
|
+
return meta;
|
|
617
|
+
}
|
|
618
|
+
}, []);
|
|
619
|
+
// Read deterministic flags from query string once
|
|
620
|
+
let deterministicFlags;
|
|
621
|
+
try {
|
|
622
|
+
const params = new URLSearchParams(window.location.search);
|
|
623
|
+
const detParam = params.get("deterministic");
|
|
624
|
+
const deterministic = detParam === "true" ||
|
|
625
|
+
(detParam === null ? params.has("deterministic") : false);
|
|
626
|
+
const seedStr = params.get("seed");
|
|
627
|
+
const seed = seedStr ? Number(seedStr) : undefined;
|
|
628
|
+
deterministicFlags = {
|
|
629
|
+
deterministic,
|
|
630
|
+
seed: Number.isFinite(seed) ? seed : undefined,
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
catch {
|
|
634
|
+
deterministicFlags = {
|
|
635
|
+
deterministic: false,
|
|
636
|
+
seed: undefined,
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
useEffect(() => {
|
|
640
|
+
localStorage.setItem("editor.agent.promptHistory", JSON.stringify(promptHistory));
|
|
641
|
+
}, [promptHistory]);
|
|
642
|
+
// Clear idle timer on unmount
|
|
643
|
+
useEffect(() => {
|
|
644
|
+
return () => {
|
|
645
|
+
if (dotsTimeoutRef.current) {
|
|
646
|
+
clearTimeout(dotsTimeoutRef.current);
|
|
647
|
+
dotsTimeoutRef.current = null;
|
|
648
|
+
}
|
|
649
|
+
};
|
|
650
|
+
}, []);
|
|
651
|
+
// Whenever waiting state changes, restart idle timer logic
|
|
652
|
+
useEffect(() => {
|
|
653
|
+
resetDotsTimer();
|
|
654
|
+
}, [isWaitingForResponse, resetDotsTimer]);
|
|
655
|
+
useEffect(() => {
|
|
656
|
+
// Keep messagesRef synchronized with messages state
|
|
657
|
+
messagesRef.current = messages;
|
|
658
|
+
}, [messages]);
|
|
659
|
+
const [error, setError] = useState(null);
|
|
660
|
+
const [costLimitExceeded, setCostLimitExceeded] = useState(null);
|
|
661
|
+
// Live running totals from backend status updates (tokenUsage)
|
|
662
|
+
const [liveTotals, setLiveTotals] = useState(null);
|
|
663
|
+
// Flag to track when we should create a new message
|
|
664
|
+
const shouldCreateNewMessage = useRef(false);
|
|
665
|
+
// Keep a ref to the current messages for immediate access
|
|
666
|
+
const messagesRef = useRef([]);
|
|
667
|
+
const abortControllerRef = useRef(null);
|
|
668
|
+
const messagesEndRef = useRef(null);
|
|
669
|
+
const textareaRef = useRef(null);
|
|
670
|
+
const messagesContainerRef = useRef(null);
|
|
671
|
+
const [shouldAutoScroll, setShouldAutoScroll] = useState(true);
|
|
672
|
+
// WebSocket subscription state for agent streaming
|
|
673
|
+
const seenMessageIdsRef = useRef(new Set());
|
|
674
|
+
const lastSeqRef = useRef(0);
|
|
675
|
+
const subscribedAgentIdRef = useRef(null);
|
|
676
|
+
// Cache mode/model changes made while the agent is still "new" (not yet persisted)
|
|
677
|
+
const pendingSettingsRef = useRef(null);
|
|
678
|
+
// Auto-scroll to bottom when new messages arrive
|
|
679
|
+
const scrollToBottom = useCallback(() => {
|
|
680
|
+
const container = messagesContainerRef.current;
|
|
681
|
+
if (!container)
|
|
682
|
+
return;
|
|
683
|
+
// Jump precisely to the bottom to avoid ending slightly above due to smooth scrolling animations
|
|
684
|
+
container.scrollTop = container.scrollHeight;
|
|
685
|
+
}, []);
|
|
686
|
+
// Detect speech recognition support (client-only)
|
|
687
|
+
useEffect(() => {
|
|
688
|
+
try {
|
|
689
|
+
if (typeof window === "undefined")
|
|
690
|
+
return;
|
|
691
|
+
const SR = window.SpeechRecognition ||
|
|
692
|
+
window.webkitSpeechRecognition;
|
|
693
|
+
setIsVoiceSupported(!!SR);
|
|
694
|
+
}
|
|
695
|
+
catch {
|
|
696
|
+
setIsVoiceSupported(false);
|
|
697
|
+
}
|
|
698
|
+
}, []);
|
|
699
|
+
// Auto-focus terminal input on mount
|
|
700
|
+
useEffect(() => {
|
|
701
|
+
if (textareaRef.current) {
|
|
702
|
+
textareaRef.current.focus();
|
|
703
|
+
}
|
|
704
|
+
}, []);
|
|
705
|
+
// Start voice recognition
|
|
706
|
+
const startVoice = useCallback(() => {
|
|
707
|
+
try {
|
|
708
|
+
if (isListening)
|
|
709
|
+
return;
|
|
710
|
+
if (typeof window === "undefined")
|
|
711
|
+
return;
|
|
712
|
+
const SR = window.SpeechRecognition ||
|
|
713
|
+
window.webkitSpeechRecognition;
|
|
714
|
+
if (!SR) {
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
const r = new SR();
|
|
718
|
+
r.lang = editContext?.currentItemDescriptor?.language || "en-US";
|
|
719
|
+
r.continuous = true;
|
|
720
|
+
r.interimResults = true;
|
|
721
|
+
r.onstart = () => {
|
|
722
|
+
setIsListening(true);
|
|
723
|
+
prevPlaceholderRef.current = inputPlaceholder;
|
|
724
|
+
setInputPlaceholder("Listening...");
|
|
725
|
+
};
|
|
726
|
+
r.onresult = (event) => {
|
|
727
|
+
let finalText = "";
|
|
728
|
+
let interimText = "";
|
|
729
|
+
for (let i = event.resultIndex; i < event.results.length; i++) {
|
|
730
|
+
const res = event.results[i];
|
|
731
|
+
if (res.isFinal)
|
|
732
|
+
finalText += res[0]?.transcript || "";
|
|
733
|
+
else
|
|
734
|
+
interimText += res[0]?.transcript || "";
|
|
735
|
+
}
|
|
736
|
+
if (interimText) {
|
|
737
|
+
setInputPlaceholder(`Listening... ${interimText.trim()}`);
|
|
738
|
+
}
|
|
739
|
+
else {
|
|
740
|
+
setInputPlaceholder("Listening...");
|
|
741
|
+
}
|
|
742
|
+
if (finalText && finalText.trim()) {
|
|
743
|
+
setPrompt((prev) => {
|
|
744
|
+
const prefix = prev && !prev.endsWith(" ") ? prev + " " : prev;
|
|
745
|
+
return (prefix || "") + finalText.trim() + " ";
|
|
746
|
+
});
|
|
747
|
+
if (textareaRef.current) {
|
|
748
|
+
try {
|
|
749
|
+
const v = textareaRef.current.value || "";
|
|
750
|
+
textareaRef.current.selectionStart = v.length;
|
|
751
|
+
textareaRef.current.selectionEnd = v.length;
|
|
752
|
+
}
|
|
753
|
+
catch { }
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
};
|
|
757
|
+
r.onerror = (e) => {
|
|
758
|
+
console.warn("Speech recognition error", e);
|
|
759
|
+
};
|
|
760
|
+
r.onend = () => {
|
|
761
|
+
setIsListening(false);
|
|
762
|
+
if (prevPlaceholderRef.current !== null) {
|
|
763
|
+
setInputPlaceholder(prevPlaceholderRef.current);
|
|
764
|
+
prevPlaceholderRef.current = null;
|
|
765
|
+
}
|
|
766
|
+
recognitionRef.current = null;
|
|
767
|
+
};
|
|
768
|
+
recognitionRef.current = r;
|
|
769
|
+
r.start();
|
|
770
|
+
}
|
|
771
|
+
catch (e) {
|
|
772
|
+
console.error("Failed to start voice input", e);
|
|
773
|
+
}
|
|
774
|
+
}, [
|
|
775
|
+
editContext?.currentItemDescriptor?.language,
|
|
776
|
+
inputPlaceholder,
|
|
777
|
+
isListening,
|
|
778
|
+
]);
|
|
779
|
+
const stopVoice = useCallback(() => {
|
|
780
|
+
try {
|
|
781
|
+
const r = recognitionRef.current;
|
|
782
|
+
if (r)
|
|
783
|
+
r.stop();
|
|
784
|
+
}
|
|
785
|
+
catch { }
|
|
786
|
+
}, []);
|
|
787
|
+
const toggleVoice = useCallback(() => {
|
|
788
|
+
if (isListening)
|
|
789
|
+
stopVoice();
|
|
790
|
+
else
|
|
791
|
+
startVoice();
|
|
792
|
+
}, [isListening, startVoice, stopVoice]);
|
|
793
|
+
// Cleanup any active recognition on unmount
|
|
794
|
+
useEffect(() => {
|
|
795
|
+
return () => {
|
|
796
|
+
try {
|
|
797
|
+
const r = recognitionRef.current;
|
|
798
|
+
if (r) {
|
|
799
|
+
r.onresult = null;
|
|
800
|
+
r.onerror = null;
|
|
801
|
+
r.onend = null;
|
|
802
|
+
r.stop();
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
catch { }
|
|
806
|
+
recognitionRef.current = null;
|
|
807
|
+
};
|
|
808
|
+
}, []);
|
|
809
|
+
// Check if user is at the bottom of the scroll container
|
|
810
|
+
const isAtBottom = useCallback(() => {
|
|
811
|
+
const container = messagesContainerRef.current;
|
|
812
|
+
if (!container)
|
|
813
|
+
return true;
|
|
814
|
+
const threshold = 100; // pixels from bottom to consider "at bottom"
|
|
815
|
+
return (container.scrollHeight - container.scrollTop - container.clientHeight <
|
|
816
|
+
threshold);
|
|
817
|
+
}, []);
|
|
818
|
+
// Handle scroll events to detect manual scrolling
|
|
819
|
+
const handleScroll = useCallback(() => {
|
|
820
|
+
const atBottom = isAtBottom();
|
|
821
|
+
if (atBottom !== shouldAutoScroll) {
|
|
822
|
+
setShouldAutoScroll(atBottom);
|
|
823
|
+
}
|
|
824
|
+
}, [isAtBottom, shouldAutoScroll]);
|
|
825
|
+
// Shared stream message handlers with messageId support
|
|
826
|
+
const createNewStreamMessage = useCallback((messageId, agentData) => {
|
|
827
|
+
const currentAgent = agentData || agent;
|
|
828
|
+
if (!currentAgent) {
|
|
829
|
+
console.error("❌ createNewStreamMessage: No agent available", {
|
|
830
|
+
messageId,
|
|
831
|
+
agentData: !!agentData,
|
|
832
|
+
agent: !!agent,
|
|
833
|
+
});
|
|
834
|
+
throw new Error("No agent available");
|
|
835
|
+
}
|
|
836
|
+
// Reduced: avoid verbose logging during streaming
|
|
837
|
+
return {
|
|
838
|
+
id: messageId,
|
|
839
|
+
agentId: currentAgent.id,
|
|
840
|
+
messageIndex: -1,
|
|
841
|
+
role: "assistant",
|
|
842
|
+
content: "",
|
|
843
|
+
name: "agent",
|
|
844
|
+
messageType: "streaming",
|
|
845
|
+
isCompleted: false,
|
|
846
|
+
model: currentAgent.model || "",
|
|
847
|
+
tokensUsed: 0,
|
|
848
|
+
inputTokens: 0,
|
|
849
|
+
outputTokens: 0,
|
|
850
|
+
cachedInputTokens: 0,
|
|
851
|
+
inputTokenCost: 0,
|
|
852
|
+
outputTokenCost: 0,
|
|
853
|
+
cachedInputTokenCost: 0,
|
|
854
|
+
totalCost: 0,
|
|
855
|
+
currency: currentAgent.currency || "USD",
|
|
856
|
+
createdDate: new Date().toISOString(),
|
|
857
|
+
toolCalls: [],
|
|
858
|
+
};
|
|
859
|
+
}, [agent]);
|
|
860
|
+
const handleContentChunk = useCallback((message, agentData) => {
|
|
861
|
+
// Get messageId from data, or generate one from agent ID (for backward compatibility)
|
|
862
|
+
// If no messageId is provided, we'll use the last assistant message or create a new one
|
|
863
|
+
let messageId = message.data?.messageId;
|
|
864
|
+
if (!messageId && agentData?.id) {
|
|
865
|
+
// For backward compatibility: if no messageId, find or create the current streaming message
|
|
866
|
+
// This handles cases where the backend doesn't send messageId
|
|
867
|
+
const currentMessages = messagesRef.current;
|
|
868
|
+
const lastStreamingMessage = [...currentMessages]
|
|
869
|
+
.reverse()
|
|
870
|
+
.find((m) => m.role === "assistant" && !m.isCompleted);
|
|
871
|
+
if (lastStreamingMessage) {
|
|
872
|
+
messageId = lastStreamingMessage.id;
|
|
873
|
+
}
|
|
874
|
+
else {
|
|
875
|
+
// If the agent isn't currently running (e.g., we switched tabs after the run
|
|
876
|
+
// completed), skip creating a new streaming message to avoid duplicates.
|
|
877
|
+
const currentAgentStatus = (agentData || agent)?.status;
|
|
878
|
+
const isAgentRunning = currentAgentStatus === "running" || currentAgentStatus === 1;
|
|
879
|
+
if (!isAgentRunning) {
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
// Create a new message ID based on timestamp when the agent is still running
|
|
883
|
+
messageId = crypto.randomUUID();
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
if (!messageId) {
|
|
887
|
+
console.error("Unable to determine messageId for content chunk!");
|
|
888
|
+
return;
|
|
889
|
+
}
|
|
890
|
+
// Clear waiting state when first content chunk arrives
|
|
891
|
+
setIsWaitingForResponse(false);
|
|
892
|
+
isWaitingRef.current = false;
|
|
893
|
+
// Any content chunk is an incremental update -> reset idle timer
|
|
894
|
+
resetDotsTimer();
|
|
895
|
+
// Extract cost/token data from message.cost (new structure)
|
|
896
|
+
const cost = message.cost;
|
|
897
|
+
if (cost &&
|
|
898
|
+
(cost.total !== undefined || cost.tokens?.total !== undefined)) {
|
|
899
|
+
const nextTotals = {
|
|
900
|
+
input: Number(cost.tokens?.input) || 0,
|
|
901
|
+
output: Number(cost.tokens?.output) || 0,
|
|
902
|
+
cached: Number(cost.tokens?.cached) || 0,
|
|
903
|
+
cacheWrite: Number(cost.tokens?.cacheWrite) || 0,
|
|
904
|
+
inputCost: Number(cost.input) || 0,
|
|
905
|
+
outputCost: Number(cost.output) || 0,
|
|
906
|
+
cachedCost: Number(cost.cached) || 0,
|
|
907
|
+
cacheWriteCost: Number(cost.cacheWrite) || 0,
|
|
908
|
+
totalCost: Number(cost.total) || 0,
|
|
909
|
+
currency: "USD",
|
|
910
|
+
};
|
|
911
|
+
const anyNonZero = (nextTotals.totalCost || 0) > 0 ||
|
|
912
|
+
(nextTotals.input || 0) > 0 ||
|
|
913
|
+
(nextTotals.output || 0) > 0 ||
|
|
914
|
+
(nextTotals.cached || 0) > 0 ||
|
|
915
|
+
(nextTotals.cacheWrite || 0) > 0;
|
|
916
|
+
if (anyNonZero) {
|
|
917
|
+
setLiveTotals(nextTotals);
|
|
918
|
+
}
|
|
919
|
+
// Check cost limit if available
|
|
920
|
+
if (cost.limit &&
|
|
921
|
+
cost.total &&
|
|
922
|
+
Number(cost.total) > Number(cost.limit)) {
|
|
923
|
+
setCostLimitExceeded({
|
|
924
|
+
totalCost: Number(cost.total),
|
|
925
|
+
costLimit: Number(cost.limit),
|
|
926
|
+
initialCostLimit: Number(cost.limit),
|
|
927
|
+
});
|
|
928
|
+
setIsWaitingForResponse(false);
|
|
929
|
+
shouldCreateNewMessage.current = false;
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
// Always call setMessages and handle all logic in the callback with latest messages
|
|
933
|
+
setMessages((prev) => {
|
|
934
|
+
// Find existing message by messageId in the latest messages
|
|
935
|
+
const existingMessageIndex = prev.findIndex((msg) => msg.id === messageId);
|
|
936
|
+
if (existingMessageIndex === -1) {
|
|
937
|
+
// Message doesn't exist - create new streaming message
|
|
938
|
+
const newStreamMessage = createNewStreamMessage(messageId, agentData);
|
|
939
|
+
// Set the content for the new message
|
|
940
|
+
const updatedNewMessage = { ...newStreamMessage };
|
|
941
|
+
if (!message.data.isIncremental) {
|
|
942
|
+
updatedNewMessage.content = message.data?.deltaContent || "";
|
|
943
|
+
}
|
|
944
|
+
else {
|
|
945
|
+
updatedNewMessage.content = message.data?.deltaContent || "";
|
|
946
|
+
}
|
|
947
|
+
const updated = [...prev, updatedNewMessage];
|
|
948
|
+
messagesRef.current = updated;
|
|
949
|
+
return updated;
|
|
950
|
+
}
|
|
951
|
+
else {
|
|
952
|
+
// Message exists - update it
|
|
953
|
+
const existingMessage = prev[existingMessageIndex];
|
|
954
|
+
if (!existingMessage)
|
|
955
|
+
return prev;
|
|
956
|
+
// Check if existing content is already longer than what we're trying to stream
|
|
957
|
+
const currentContentLength = existingMessage.content?.length || 0;
|
|
958
|
+
const totalContentLength = message.data?.totalContentLength || 0;
|
|
959
|
+
if (currentContentLength >= totalContentLength &&
|
|
960
|
+
totalContentLength > 0) {
|
|
961
|
+
return prev;
|
|
962
|
+
}
|
|
963
|
+
const updatedMessage = { ...existingMessage };
|
|
964
|
+
if (!message.data.isIncremental) {
|
|
965
|
+
updatedMessage.content = message.data?.deltaContent || "";
|
|
966
|
+
}
|
|
967
|
+
else {
|
|
968
|
+
updatedMessage.content =
|
|
969
|
+
existingMessage.content + (message.data?.deltaContent || "");
|
|
970
|
+
}
|
|
971
|
+
const updated = prev.map((msg, index) => index === existingMessageIndex ? updatedMessage : msg);
|
|
972
|
+
messagesRef.current = updated;
|
|
973
|
+
return updated;
|
|
974
|
+
}
|
|
975
|
+
});
|
|
976
|
+
}, [createNewStreamMessage, agent]);
|
|
977
|
+
const handleToolCall = useCallback((message, agentData) => {
|
|
978
|
+
const toolCallId = message.data?.toolCallId || message.data?.id || crypto.randomUUID();
|
|
979
|
+
// Prefer provided messageId, otherwise fall back to the last streaming assistant message
|
|
980
|
+
let toolCallMessageId = message.data?.messageId;
|
|
981
|
+
if (!toolCallMessageId) {
|
|
982
|
+
const current = messagesRef.current;
|
|
983
|
+
const lastStreaming = [...current]
|
|
984
|
+
.reverse()
|
|
985
|
+
.find((m) => m.role === "assistant" && !m.isCompleted);
|
|
986
|
+
if (lastStreaming?.id) {
|
|
987
|
+
toolCallMessageId = lastStreaming.id;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
// Find or create the target message for this tool call
|
|
991
|
+
if (toolCallMessageId) {
|
|
992
|
+
const currentMessages = messagesRef.current;
|
|
993
|
+
const existingMessageIndex = currentMessages.findIndex((msg) => msg.id === toolCallMessageId);
|
|
994
|
+
if (existingMessageIndex === -1) {
|
|
995
|
+
// Double-check with current ref to prevent race conditions
|
|
996
|
+
const currentMessages = messagesRef.current;
|
|
997
|
+
const existsInRef = currentMessages.find((msg) => msg.id === toolCallMessageId);
|
|
998
|
+
if (!existsInRef) {
|
|
999
|
+
// Create new message for this tool call
|
|
1000
|
+
const newStreamMessage = createNewStreamMessage(toolCallMessageId, agentData);
|
|
1001
|
+
setMessages((prev) => {
|
|
1002
|
+
// Final check before adding to prevent duplicates
|
|
1003
|
+
const finalCheck = prev.find((msg) => msg.id === toolCallMessageId);
|
|
1004
|
+
if (finalCheck) {
|
|
1005
|
+
return prev;
|
|
1006
|
+
}
|
|
1007
|
+
const updated = [...prev, newStreamMessage];
|
|
1008
|
+
messagesRef.current = updated;
|
|
1009
|
+
return updated;
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
// Add tool call to the message in the array
|
|
1015
|
+
if (toolCallMessageId && message.data && toolCallId) {
|
|
1016
|
+
const functionName = message.data.functionName ||
|
|
1017
|
+
message.data.name ||
|
|
1018
|
+
message.data.function?.name ||
|
|
1019
|
+
"unknown";
|
|
1020
|
+
const toolCall = {
|
|
1021
|
+
id: toolCallId,
|
|
1022
|
+
messageId: toolCallMessageId,
|
|
1023
|
+
dbMessageId: message.data.messageId, // Database message ID for approval/rejection
|
|
1024
|
+
toolCallId: toolCallId,
|
|
1025
|
+
functionName: functionName,
|
|
1026
|
+
functionArguments: message.data.functionArguments ||
|
|
1027
|
+
message.data.arguments ||
|
|
1028
|
+
JSON.stringify(message.data.function?.arguments || {}),
|
|
1029
|
+
functionResult: message.data.functionResult || message.data.result || "",
|
|
1030
|
+
functionError: message.data.functionError || message.data.error || "",
|
|
1031
|
+
isCompleted: false,
|
|
1032
|
+
responseTimeMs: message.data.responseTimeMs,
|
|
1033
|
+
createdDate: new Date().toISOString(),
|
|
1034
|
+
requiresApproval: message.data?.requiresApproval,
|
|
1035
|
+
};
|
|
1036
|
+
// Check for duplicates using the current messages ref
|
|
1037
|
+
const currentMessages = messagesRef.current;
|
|
1038
|
+
const targetMessage = currentMessages.find((msg) => msg.id === toolCallMessageId);
|
|
1039
|
+
if (targetMessage) {
|
|
1040
|
+
const existingToolCalls = targetMessage.toolCalls || [];
|
|
1041
|
+
const existingToolCallIndex = existingToolCalls.findIndex((tc) => tc.toolCallId === toolCallId);
|
|
1042
|
+
if (existingToolCallIndex !== -1) {
|
|
1043
|
+
return; // Skip adding duplicate
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
setMessages((prev) => {
|
|
1047
|
+
const updated = prev.map((msg) => {
|
|
1048
|
+
if (msg.id !== toolCallMessageId)
|
|
1049
|
+
return msg;
|
|
1050
|
+
const existingToolCalls = msg.toolCalls || [];
|
|
1051
|
+
return { ...msg, toolCalls: [...existingToolCalls, toolCall] };
|
|
1052
|
+
});
|
|
1053
|
+
messagesRef.current = updated;
|
|
1054
|
+
return updated;
|
|
1055
|
+
});
|
|
1056
|
+
// Tool call activity counts as activity; keep dots hidden for 1s
|
|
1057
|
+
resetDotsTimer();
|
|
1058
|
+
}
|
|
1059
|
+
}, [createNewStreamMessage]);
|
|
1060
|
+
const handleToolResult = useCallback((message, agentData) => {
|
|
1061
|
+
const resultToolCallId = message.data?.toolCallId || message.data?.id || crypto.randomUUID();
|
|
1062
|
+
// Prefer provided messageId, otherwise fall back to the last streaming assistant message
|
|
1063
|
+
let resultMessageId = message.data?.messageId;
|
|
1064
|
+
if (!resultMessageId) {
|
|
1065
|
+
const current = messagesRef.current;
|
|
1066
|
+
const lastStreaming = [...current]
|
|
1067
|
+
.reverse()
|
|
1068
|
+
.find((m) => m.role === "assistant" && !m.isCompleted);
|
|
1069
|
+
if (lastStreaming?.id) {
|
|
1070
|
+
resultMessageId = lastStreaming.id;
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
// Extract cost/token data from tool result if present
|
|
1074
|
+
const cost = message.cost;
|
|
1075
|
+
if (cost &&
|
|
1076
|
+
(cost.total !== undefined || cost.tokens?.total !== undefined)) {
|
|
1077
|
+
const nextTotals = {
|
|
1078
|
+
input: Number(cost.tokens?.input) || 0,
|
|
1079
|
+
output: Number(cost.tokens?.output) || 0,
|
|
1080
|
+
cached: Number(cost.tokens?.cached) || 0,
|
|
1081
|
+
cacheWrite: Number(cost.tokens?.cacheWrite) || 0,
|
|
1082
|
+
inputCost: Number(cost.input) || 0,
|
|
1083
|
+
outputCost: Number(cost.output) || 0,
|
|
1084
|
+
cachedCost: Number(cost.cached) || 0,
|
|
1085
|
+
cacheWriteCost: Number(cost.cacheWrite) || 0,
|
|
1086
|
+
totalCost: Number(cost.total) || 0,
|
|
1087
|
+
currency: "USD",
|
|
1088
|
+
};
|
|
1089
|
+
const anyNonZero = (nextTotals.totalCost || 0) > 0 ||
|
|
1090
|
+
(nextTotals.input || 0) > 0 ||
|
|
1091
|
+
(nextTotals.output || 0) > 0 ||
|
|
1092
|
+
(nextTotals.cached || 0) > 0 ||
|
|
1093
|
+
(nextTotals.cacheWrite || 0) > 0;
|
|
1094
|
+
if (anyNonZero) {
|
|
1095
|
+
setLiveTotals(nextTotals);
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
else {
|
|
1099
|
+
// Fallback: legacy aggregated totals included in the tool result data
|
|
1100
|
+
const data = message.data;
|
|
1101
|
+
if (data &&
|
|
1102
|
+
(data.totalCost !== undefined || data.totalTokens !== undefined)) {
|
|
1103
|
+
const nextTotals = {
|
|
1104
|
+
input: Number(data.totalInputTokens) || 0,
|
|
1105
|
+
output: Number(data.totalOutputTokens) || 0,
|
|
1106
|
+
cached: Number(data.totalCachedTokens) || 0,
|
|
1107
|
+
cacheWrite: Number(data.totalCacheWriteTokens) || 0,
|
|
1108
|
+
inputCost: Number(data.totalInputTokenCost) || 0,
|
|
1109
|
+
outputCost: Number(data.totalOutputTokenCost) || 0,
|
|
1110
|
+
cachedCost: Number(data.totalCachedTokenCost) || 0,
|
|
1111
|
+
cacheWriteCost: Number(data.totalCacheWriteTokenCost) || 0,
|
|
1112
|
+
totalCost: Number(data.totalCost) || 0,
|
|
1113
|
+
currency: data.currency || "USD",
|
|
1114
|
+
};
|
|
1115
|
+
const anyNonZero = (nextTotals.totalCost || 0) > 0 ||
|
|
1116
|
+
(nextTotals.input || 0) > 0 ||
|
|
1117
|
+
(nextTotals.output || 0) > 0 ||
|
|
1118
|
+
(nextTotals.cached || 0) > 0 ||
|
|
1119
|
+
(nextTotals.cacheWrite || 0) > 0;
|
|
1120
|
+
if (anyNonZero) {
|
|
1121
|
+
setLiveTotals(nextTotals);
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
// Update tool result directly in the messages array
|
|
1126
|
+
if (!resultMessageId) {
|
|
1127
|
+
return;
|
|
1128
|
+
}
|
|
1129
|
+
// Update the message with tool result
|
|
1130
|
+
setMessages((prev) => {
|
|
1131
|
+
const updated = prev.map((msg) => {
|
|
1132
|
+
if (msg.id !== resultMessageId)
|
|
1133
|
+
return msg;
|
|
1134
|
+
const updatedMessage = { ...msg };
|
|
1135
|
+
if (!updatedMessage.toolCalls) {
|
|
1136
|
+
updatedMessage.toolCalls = [];
|
|
1137
|
+
}
|
|
1138
|
+
// Find and update the tool call with the result
|
|
1139
|
+
const toolCallIndex = updatedMessage.toolCalls.findIndex((tc) => tc.toolCallId === resultToolCallId);
|
|
1140
|
+
if (toolCallIndex >= 0) {
|
|
1141
|
+
const existingToolCall = updatedMessage.toolCalls[toolCallIndex];
|
|
1142
|
+
if (existingToolCall && message.data) {
|
|
1143
|
+
const updatedToolCalls = [...updatedMessage.toolCalls];
|
|
1144
|
+
const toolCall = {
|
|
1145
|
+
id: existingToolCall.id,
|
|
1146
|
+
messageId: existingToolCall.messageId,
|
|
1147
|
+
toolCallId: existingToolCall.toolCallId,
|
|
1148
|
+
functionName: existingToolCall.functionName,
|
|
1149
|
+
functionArguments: existingToolCall.functionArguments,
|
|
1150
|
+
functionResult: message.data.functionResult || message.data.result || "",
|
|
1151
|
+
functionError: message.data.functionError || message.data.error || "",
|
|
1152
|
+
isCompleted: true,
|
|
1153
|
+
responseTimeMs: message.data.responseTimeMs,
|
|
1154
|
+
createdDate: existingToolCall.createdDate,
|
|
1155
|
+
};
|
|
1156
|
+
updatedToolCalls[toolCallIndex] = toolCall;
|
|
1157
|
+
updatedMessage.toolCalls = updatedToolCalls;
|
|
1158
|
+
}
|
|
1159
|
+
// Check if all tool calls in message are completed
|
|
1160
|
+
const allToolCallsCompleted = updatedMessage.toolCalls.every((tc) => tc.isCompleted);
|
|
1161
|
+
if (allToolCallsCompleted) {
|
|
1162
|
+
shouldCreateNewMessage.current = true;
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
else if (message.data && resultToolCallId && resultMessageId) {
|
|
1166
|
+
// Create new tool call if it doesn't exist
|
|
1167
|
+
const functionName = message.data.functionName ||
|
|
1168
|
+
message.data.name ||
|
|
1169
|
+
message.data.function?.name ||
|
|
1170
|
+
"unknown";
|
|
1171
|
+
const toolCall = {
|
|
1172
|
+
id: resultToolCallId,
|
|
1173
|
+
messageId: resultMessageId,
|
|
1174
|
+
toolCallId: resultToolCallId,
|
|
1175
|
+
functionName: functionName,
|
|
1176
|
+
functionArguments: message.data.functionArguments ||
|
|
1177
|
+
message.data.arguments ||
|
|
1178
|
+
JSON.stringify(message.data.function?.arguments || {}),
|
|
1179
|
+
functionResult: message.data.functionResult || message.data.result || "",
|
|
1180
|
+
functionError: message.data.functionError || message.data.error || "",
|
|
1181
|
+
isCompleted: true,
|
|
1182
|
+
responseTimeMs: message.data.responseTimeMs,
|
|
1183
|
+
createdDate: new Date().toISOString(),
|
|
1184
|
+
};
|
|
1185
|
+
updatedMessage.toolCalls = [...updatedMessage.toolCalls, toolCall];
|
|
1186
|
+
}
|
|
1187
|
+
// Updated tool calls count
|
|
1188
|
+
return updatedMessage;
|
|
1189
|
+
});
|
|
1190
|
+
messagesRef.current = updated;
|
|
1191
|
+
return updated;
|
|
1192
|
+
});
|
|
1193
|
+
// Tool result activity; reset idle timer
|
|
1194
|
+
resetDotsTimer();
|
|
1195
|
+
}, [resetDotsTimer]);
|
|
1196
|
+
// Listen for local approval resolution to update UI
|
|
1197
|
+
useEffect(() => {
|
|
1198
|
+
const onApprovalResolved = (ev) => {
|
|
1199
|
+
try {
|
|
1200
|
+
const detail = ev?.detail || {};
|
|
1201
|
+
const messageId = detail.messageId;
|
|
1202
|
+
const toolCallId = detail.toolCallId;
|
|
1203
|
+
const approved = !!detail.approved;
|
|
1204
|
+
if (!messageId || !toolCallId)
|
|
1205
|
+
return;
|
|
1206
|
+
// Update local state to reflect approval status
|
|
1207
|
+
setMessages((prev) => {
|
|
1208
|
+
const updated = prev.map((m) => {
|
|
1209
|
+
if (m.id !== messageId)
|
|
1210
|
+
return m;
|
|
1211
|
+
const updatedToolCalls = (m.toolCalls || []).map((tc) => {
|
|
1212
|
+
if (tc.toolCallId !== toolCallId)
|
|
1213
|
+
return tc;
|
|
1214
|
+
const base = (tc.functionName || "")
|
|
1215
|
+
.replace(" (pending approval)", "")
|
|
1216
|
+
.replace(" (approved)", "")
|
|
1217
|
+
.replace(" (rejected)", "");
|
|
1218
|
+
return {
|
|
1219
|
+
...tc,
|
|
1220
|
+
functionName: base + (approved ? " (approved)" : " (rejected)"),
|
|
1221
|
+
// Mark tool call as completed when rejected or approved
|
|
1222
|
+
isCompleted: true,
|
|
1223
|
+
// Set error if rejected
|
|
1224
|
+
...(approved ? {} : { functionError: "REJECTED" }),
|
|
1225
|
+
};
|
|
1226
|
+
});
|
|
1227
|
+
// Check if all tool calls are completed
|
|
1228
|
+
const allToolCallsCompleted = updatedToolCalls.length > 0 &&
|
|
1229
|
+
updatedToolCalls.every((tc) => tc.isCompleted);
|
|
1230
|
+
// If all tool calls are completed and message was streaming, mark it as completed
|
|
1231
|
+
const shouldMarkMessageCompleted = allToolCallsCompleted &&
|
|
1232
|
+
!m.isCompleted &&
|
|
1233
|
+
m.messageType === "streaming";
|
|
1234
|
+
return {
|
|
1235
|
+
...m,
|
|
1236
|
+
toolCalls: updatedToolCalls,
|
|
1237
|
+
// Mark message as completed if all tool calls are done
|
|
1238
|
+
...(shouldMarkMessageCompleted
|
|
1239
|
+
? { isCompleted: true, messageType: "completed" }
|
|
1240
|
+
: {}),
|
|
1241
|
+
};
|
|
1242
|
+
});
|
|
1243
|
+
messagesRef.current = updated;
|
|
1244
|
+
return updated;
|
|
1245
|
+
});
|
|
1246
|
+
}
|
|
1247
|
+
catch (err) {
|
|
1248
|
+
console.error("❌ Error handling approval resolution:", err);
|
|
1249
|
+
}
|
|
1250
|
+
};
|
|
1251
|
+
window.addEventListener("agent:toolApprovalResolved", onApprovalResolved);
|
|
1252
|
+
return () => window.removeEventListener("agent:toolApprovalResolved", onApprovalResolved);
|
|
1253
|
+
}, []);
|
|
1254
|
+
// Load agent data and messages
|
|
1255
|
+
const loadAgent = useCallback(async () => {
|
|
1256
|
+
try {
|
|
1257
|
+
// Even if agentStub.status is "new", try to load from backend first
|
|
1258
|
+
// The agent might have been persisted after sending a prompt
|
|
1259
|
+
// Only treat as "new" if backend returns 404
|
|
1260
|
+
const hasExistingMessages = messagesRef.current.length > 0;
|
|
1261
|
+
if (agentStub.status === "new" && !hasExistingMessages) {
|
|
1262
|
+
// Only initialize as new if we have no messages yet (initial mount)
|
|
1263
|
+
// Derive initial profile from provided metadata if present
|
|
1264
|
+
const initialProfileIdFromMeta = (() => {
|
|
1265
|
+
try {
|
|
1266
|
+
return initialMetadata?.additionalData?.profileId;
|
|
1267
|
+
}
|
|
1268
|
+
catch {
|
|
1269
|
+
return undefined;
|
|
1270
|
+
}
|
|
1271
|
+
})();
|
|
1272
|
+
const initialProfileNameFromMeta = (() => {
|
|
1273
|
+
try {
|
|
1274
|
+
return (initialMetadata?.additionalData?.profileName ||
|
|
1275
|
+
initialMetadata?.profile ||
|
|
1276
|
+
undefined);
|
|
1277
|
+
}
|
|
1278
|
+
catch {
|
|
1279
|
+
return undefined;
|
|
1280
|
+
}
|
|
1281
|
+
})();
|
|
1282
|
+
setAgent({
|
|
1283
|
+
...agentStub,
|
|
1284
|
+
messages: [],
|
|
1285
|
+
status: "new",
|
|
1286
|
+
updatedDate: new Date().toISOString(),
|
|
1287
|
+
createdDate: new Date().toISOString(),
|
|
1288
|
+
id: agentStub.id,
|
|
1289
|
+
name: agentStub.name,
|
|
1290
|
+
model: "",
|
|
1291
|
+
currency: "USD",
|
|
1292
|
+
profileId: initialProfileIdFromMeta || "",
|
|
1293
|
+
profileName: initialProfileNameFromMeta || "",
|
|
1294
|
+
totalTokensUsed: 0,
|
|
1295
|
+
totalInputTokens: 0,
|
|
1296
|
+
totalOutputTokens: 0,
|
|
1297
|
+
totalCachedInputTokens: 0,
|
|
1298
|
+
totalInputTokenCost: 0,
|
|
1299
|
+
totalOutputTokenCost: 0,
|
|
1300
|
+
totalCachedInputTokenCost: 0,
|
|
1301
|
+
totalCost: 0,
|
|
1302
|
+
messageCount: 0,
|
|
1303
|
+
});
|
|
1304
|
+
setMessages([]);
|
|
1305
|
+
setError(null);
|
|
1306
|
+
setIsLoading(false);
|
|
1307
|
+
// Initialize local context for a brand-new agent (not yet persisted)
|
|
1308
|
+
// Optionally seed with current page/selection/focused field based on profile setting
|
|
1309
|
+
const item = editContext?.currentItemDescriptor;
|
|
1310
|
+
const profileForSeeding = (() => {
|
|
1311
|
+
try {
|
|
1312
|
+
if (initialProfileIdFromMeta) {
|
|
1313
|
+
const byId = (profiles || []).find((p) => p.id === initialProfileIdFromMeta);
|
|
1314
|
+
if (byId)
|
|
1315
|
+
return byId;
|
|
1316
|
+
}
|
|
1317
|
+
if (initialProfileNameFromMeta) {
|
|
1318
|
+
const byName = (profiles || []).find((p) => p.name === initialProfileNameFromMeta);
|
|
1319
|
+
if (byName)
|
|
1320
|
+
return byName;
|
|
1321
|
+
}
|
|
1322
|
+
return (profiles || [])[0];
|
|
1323
|
+
}
|
|
1324
|
+
catch {
|
|
1325
|
+
return undefined;
|
|
1326
|
+
}
|
|
1327
|
+
})();
|
|
1328
|
+
const shouldSeedContext = (() => {
|
|
1329
|
+
try {
|
|
1330
|
+
// Check for new editorContextMode first
|
|
1331
|
+
const mode = profileForSeeding?.editorContextMode;
|
|
1332
|
+
if (mode !== undefined) {
|
|
1333
|
+
return mode === "onCreate" || mode === "live";
|
|
1334
|
+
}
|
|
1335
|
+
// Backward compatibility: check old includeEditorContextOnCreate boolean
|
|
1336
|
+
if (profileForSeeding?.includeEditorContextOnCreate !== undefined) {
|
|
1337
|
+
return !!profileForSeeding.includeEditorContextOnCreate;
|
|
1338
|
+
}
|
|
1339
|
+
// Default to true when unspecified
|
|
1340
|
+
return true;
|
|
1341
|
+
}
|
|
1342
|
+
catch {
|
|
1343
|
+
return true;
|
|
1344
|
+
}
|
|
1345
|
+
})();
|
|
1346
|
+
// Create context with top-level properties (what ContextInfoBar expects)
|
|
1347
|
+
const localCtx = item && shouldSeedContext
|
|
1348
|
+
? {
|
|
1349
|
+
items: [
|
|
1350
|
+
{
|
|
1351
|
+
id: item.id,
|
|
1352
|
+
language: item.language,
|
|
1353
|
+
version: item.version,
|
|
1354
|
+
name: editContext?.contentEditorItem?.name,
|
|
1355
|
+
},
|
|
1356
|
+
],
|
|
1357
|
+
components: editContext?.selection?.length && item
|
|
1358
|
+
? editContext.selection.map((componentId) => ({
|
|
1359
|
+
componentId,
|
|
1360
|
+
pageItem: {
|
|
1361
|
+
id: item.id,
|
|
1362
|
+
language: item.language,
|
|
1363
|
+
version: item.version,
|
|
1364
|
+
name: editContext?.contentEditorItem?.name,
|
|
1365
|
+
},
|
|
1366
|
+
}))
|
|
1367
|
+
: undefined,
|
|
1368
|
+
field: fieldsContext?.focusedField?.fieldId &&
|
|
1369
|
+
fieldsContext.focusedField?.item?.id
|
|
1370
|
+
? {
|
|
1371
|
+
fieldId: fieldsContext.focusedField.fieldId,
|
|
1372
|
+
fieldName: fieldsContext.focusedField
|
|
1373
|
+
.fieldName,
|
|
1374
|
+
item: {
|
|
1375
|
+
id: fieldsContext.focusedField.item.id,
|
|
1376
|
+
language: fieldsContext.focusedField.item.language ||
|
|
1377
|
+
editContext?.currentItemDescriptor?.language ||
|
|
1378
|
+
"en",
|
|
1379
|
+
version: fieldsContext.focusedField.item.version ??
|
|
1380
|
+
editContext?.currentItemDescriptor?.version ??
|
|
1381
|
+
0,
|
|
1382
|
+
name: editContext?.contentEditorItem?.name,
|
|
1383
|
+
},
|
|
1384
|
+
}
|
|
1385
|
+
: undefined,
|
|
1386
|
+
}
|
|
1387
|
+
: null;
|
|
1388
|
+
let nextMetadata = null;
|
|
1389
|
+
if (initialMetadata) {
|
|
1390
|
+
// Merge initial metadata with local context (using top-level structure)
|
|
1391
|
+
const base = { ...initialMetadata };
|
|
1392
|
+
if (localCtx) {
|
|
1393
|
+
// Merge items (avoid duplicates)
|
|
1394
|
+
if (localCtx.items && localCtx.items.length) {
|
|
1395
|
+
const targetPages = Array.isArray(base.items)
|
|
1396
|
+
? [...base.items]
|
|
1397
|
+
: [];
|
|
1398
|
+
const existingKeys = new Set(targetPages.map((p) => `${p.id}-${p.language || ""}-${p.version || ""}`));
|
|
1399
|
+
const additions = localCtx.items.filter((p) => !existingKeys.has(`${p.id}-${p.language || ""}-${p.version || ""}`));
|
|
1400
|
+
if (additions.length)
|
|
1401
|
+
base.items = [...targetPages, ...additions];
|
|
1402
|
+
}
|
|
1403
|
+
// Merge components (avoid duplicates)
|
|
1404
|
+
if (localCtx.components && localCtx.components.length) {
|
|
1405
|
+
const currentComponents = Array.isArray(base.components)
|
|
1406
|
+
? base.components
|
|
1407
|
+
: [];
|
|
1408
|
+
const existingIds = new Set(currentComponents.map((c) => c.componentId));
|
|
1409
|
+
const additions = localCtx.components.filter((c) => !!c?.componentId && !existingIds.has(c.componentId));
|
|
1410
|
+
if (additions.length)
|
|
1411
|
+
base.components = [...currentComponents, ...additions];
|
|
1412
|
+
}
|
|
1413
|
+
// Set field if missing
|
|
1414
|
+
if (!base.field && localCtx.field) {
|
|
1415
|
+
base.field = localCtx.field;
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
nextMetadata = base;
|
|
1419
|
+
}
|
|
1420
|
+
else {
|
|
1421
|
+
nextMetadata = localCtx;
|
|
1422
|
+
}
|
|
1423
|
+
if (nextMetadata) {
|
|
1424
|
+
setAgentMetadata(sanitizeAgentMetadata(nextMetadata));
|
|
1425
|
+
// If an initial prompt is provided via metadata, seed the input once
|
|
1426
|
+
try {
|
|
1427
|
+
const maybePrompt = nextMetadata?.additionalData
|
|
1428
|
+
?.initialPrompt;
|
|
1429
|
+
if (typeof maybePrompt === "string" && maybePrompt.trim()) {
|
|
1430
|
+
setPrompt(maybePrompt);
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
catch { }
|
|
1434
|
+
}
|
|
1435
|
+
// Only return early if we have no existing messages
|
|
1436
|
+
// If we have messages, continue to load from backend to merge them
|
|
1437
|
+
if (!hasExistingMessages) {
|
|
1438
|
+
return;
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
setIsLoading(true);
|
|
1442
|
+
setError(null);
|
|
1443
|
+
const agentData = await getAgent(agentStub.id);
|
|
1444
|
+
setAgent(agentData);
|
|
1445
|
+
// Merge database messages with any existing local messages using ID-based deduplication
|
|
1446
|
+
// This prevents both missing messages and duplicates
|
|
1447
|
+
// Use messagesRef.current instead of prevMessages to ensure we have the latest messages
|
|
1448
|
+
const dbMessages = agentData.messages || [];
|
|
1449
|
+
// Track all DB message IDs as "seen" to prevent WebSocket duplicates
|
|
1450
|
+
dbMessages.forEach((msg) => {
|
|
1451
|
+
if (msg.id) {
|
|
1452
|
+
seenMessageIdsRef.current.add(msg.id.toLowerCase());
|
|
1453
|
+
}
|
|
1454
|
+
});
|
|
1455
|
+
// Keep local streaming only if the agent is still running; otherwise discard locals
|
|
1456
|
+
const isRunning = agentData.status === "running" || agentData.status === 1;
|
|
1457
|
+
// Filter local messages to only include streaming/incomplete messages that aren't in DB
|
|
1458
|
+
// This prevents duplicates when reloading - DB messages are source of truth for completed messages
|
|
1459
|
+
const localStreaming = isRunning
|
|
1460
|
+
? messagesRef.current.filter((localMsg) => {
|
|
1461
|
+
if (!localMsg.id)
|
|
1462
|
+
return false;
|
|
1463
|
+
// Keep streaming messages that aren't completed
|
|
1464
|
+
if (!localMsg.isCompleted && localMsg.messageType === "streaming") {
|
|
1465
|
+
// Check if this message exists in DB
|
|
1466
|
+
const existsInDb = dbMessages.some((dbMsg) => dbMsg.id &&
|
|
1467
|
+
dbMsg.id.toLowerCase() === localMsg.id.toLowerCase());
|
|
1468
|
+
// Keep if it doesn't exist in DB (truly local streaming)
|
|
1469
|
+
return !existsInDb;
|
|
1470
|
+
}
|
|
1471
|
+
// Don't keep completed messages from local state - DB is source of truth
|
|
1472
|
+
return false;
|
|
1473
|
+
})
|
|
1474
|
+
: [];
|
|
1475
|
+
const merged = mergeMessagesById(dbMessages, localStreaming);
|
|
1476
|
+
messagesRef.current = merged;
|
|
1477
|
+
setMessages(merged);
|
|
1478
|
+
// Normalize waiting/connecting/dots state based on freshly loaded status
|
|
1479
|
+
const runningNow = agentData.status === "running" || agentData.status === 1;
|
|
1480
|
+
const hasStreamingNow = merged.some((m) => !m.isCompleted && m.messageType === "streaming");
|
|
1481
|
+
if (runningNow || hasStreamingNow) {
|
|
1482
|
+
setIsWaitingForResponse(true);
|
|
1483
|
+
isWaitingRef.current = true;
|
|
1484
|
+
}
|
|
1485
|
+
else {
|
|
1486
|
+
setIsWaitingForResponse(false);
|
|
1487
|
+
isWaitingRef.current = false;
|
|
1488
|
+
setIsConnecting(false);
|
|
1489
|
+
}
|
|
1490
|
+
resetDotsTimer();
|
|
1491
|
+
// Check if cost limit was exceeded (detect from existing messages)
|
|
1492
|
+
try {
|
|
1493
|
+
const costLimitMessage = (agentData.messages || []).find((msg) => msg.role === "assistant" &&
|
|
1494
|
+
msg.content &&
|
|
1495
|
+
msg.content.startsWith("⚠️") &&
|
|
1496
|
+
msg.content.includes("Cost limit"));
|
|
1497
|
+
if (costLimitMessage &&
|
|
1498
|
+
costLimitMessage.content &&
|
|
1499
|
+
agentData.costLimit) {
|
|
1500
|
+
// Extract cost from the message if possible
|
|
1501
|
+
const match = costLimitMessage.content.match(/Current cost: \$([0-9.]+)/);
|
|
1502
|
+
const totalCost = match && match[1] ? parseFloat(match[1]) : agentData.totalCost || 0;
|
|
1503
|
+
setCostLimitExceeded({
|
|
1504
|
+
totalCost: totalCost,
|
|
1505
|
+
costLimit: agentData.costLimit,
|
|
1506
|
+
initialCostLimit: agentData.costLimit,
|
|
1507
|
+
});
|
|
1508
|
+
}
|
|
1509
|
+
else if (agentData.costLimit &&
|
|
1510
|
+
agentData.totalCost &&
|
|
1511
|
+
agentData.totalCost > agentData.costLimit) {
|
|
1512
|
+
setCostLimitExceeded({
|
|
1513
|
+
totalCost: agentData.totalCost,
|
|
1514
|
+
costLimit: agentData.costLimit,
|
|
1515
|
+
initialCostLimit: agentData.costLimit,
|
|
1516
|
+
});
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
catch (e) {
|
|
1520
|
+
console.error("Failed to check cost limit on load:", e);
|
|
1521
|
+
}
|
|
1522
|
+
// Parse metadata from DB if present (do not seed for existing agents)
|
|
1523
|
+
const parsedMeta = (() => {
|
|
1524
|
+
try {
|
|
1525
|
+
const contextJson = agentData.agentContext;
|
|
1526
|
+
if (!contextJson)
|
|
1527
|
+
return null;
|
|
1528
|
+
const parsedContext = JSON.parse(contextJson);
|
|
1529
|
+
// Context is stored as flat structure with top-level properties
|
|
1530
|
+
if (parsedContext && typeof parsedContext === "object") {
|
|
1531
|
+
return parsedContext;
|
|
1532
|
+
}
|
|
1533
|
+
return null;
|
|
1534
|
+
}
|
|
1535
|
+
catch {
|
|
1536
|
+
return null;
|
|
1537
|
+
}
|
|
1538
|
+
})();
|
|
1539
|
+
// For existing agents, use database metadata or none
|
|
1540
|
+
setAgentMetadata(sanitizeAgentMetadata(parsedMeta));
|
|
1541
|
+
}
|
|
1542
|
+
catch (err) {
|
|
1543
|
+
console.error("❌ Failed to load agent:", err);
|
|
1544
|
+
// For new agents that don't exist yet, this is expected
|
|
1545
|
+
if (err?.message?.includes("404") ||
|
|
1546
|
+
err?.message?.includes("not found")) {
|
|
1547
|
+
// Agent does not exist, treat as new
|
|
1548
|
+
// But preserve existing messages if we have them (from WebSocket updates)
|
|
1549
|
+
const hasExistingMessages = messagesRef.current.length > 0;
|
|
1550
|
+
setAgent(undefined);
|
|
1551
|
+
if (!hasExistingMessages) {
|
|
1552
|
+
setMessages([]);
|
|
1553
|
+
}
|
|
1554
|
+
setError(null);
|
|
1555
|
+
}
|
|
1556
|
+
else {
|
|
1557
|
+
console.error("❌ Load error:", err.message);
|
|
1558
|
+
setError("Failed to load agent data");
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
finally {
|
|
1562
|
+
setIsLoading(false);
|
|
1563
|
+
}
|
|
1564
|
+
}, [agentStub.id]);
|
|
1565
|
+
// Initial load
|
|
1566
|
+
useEffect(() => {
|
|
1567
|
+
loadAgent();
|
|
1568
|
+
}, [loadAgent]);
|
|
1569
|
+
// Reload agent when tab becomes active to get latest messages
|
|
1570
|
+
const previousIsActiveRef = useRef(isActive);
|
|
1571
|
+
useEffect(() => {
|
|
1572
|
+
const wasInactive = !previousIsActiveRef.current;
|
|
1573
|
+
const isNowActive = isActive;
|
|
1574
|
+
previousIsActiveRef.current = isActive;
|
|
1575
|
+
if (wasInactive && isNowActive && agent) {
|
|
1576
|
+
loadAgent();
|
|
1577
|
+
}
|
|
1578
|
+
}, [isActive, agent?.id, loadAgent]);
|
|
1579
|
+
// Watch for cost limit exceeded based on agent status or cost values
|
|
1580
|
+
useEffect(() => {
|
|
1581
|
+
if (!agent) {
|
|
1582
|
+
setCostLimitExceeded(null);
|
|
1583
|
+
return;
|
|
1584
|
+
}
|
|
1585
|
+
// Check if cost limit exceeded based on status or cost values
|
|
1586
|
+
const statusIndicatesLimit = agent.status === "costLimitReached" || agent.status === 7;
|
|
1587
|
+
const costExceedsLimit = agent.costLimit && agent.totalCost && agent.totalCost > agent.costLimit;
|
|
1588
|
+
if (statusIndicatesLimit || costExceedsLimit) {
|
|
1589
|
+
// Only set if not already set to avoid unnecessary re-renders
|
|
1590
|
+
setCostLimitExceeded((prev) => {
|
|
1591
|
+
const totalCost = agent.totalCost || 0;
|
|
1592
|
+
const costLimit = agent.costLimit || 0;
|
|
1593
|
+
// Check if values actually changed
|
|
1594
|
+
if (prev?.totalCost === totalCost && prev?.costLimit === costLimit) {
|
|
1595
|
+
return prev;
|
|
1596
|
+
}
|
|
1597
|
+
return {
|
|
1598
|
+
totalCost,
|
|
1599
|
+
costLimit,
|
|
1600
|
+
initialCostLimit: costLimit,
|
|
1601
|
+
};
|
|
1602
|
+
});
|
|
1603
|
+
}
|
|
1604
|
+
else {
|
|
1605
|
+
// Clear cost limit exceeded if status changed back
|
|
1606
|
+
setCostLimitExceeded((prev) => (prev ? null : prev));
|
|
1607
|
+
}
|
|
1608
|
+
}, [agent?.status, agent?.totalCost, agent?.costLimit]);
|
|
1609
|
+
// WebSocket message handler for agent streaming
|
|
1610
|
+
const handleAgentWebSocketMessage = useCallback((message) => {
|
|
1611
|
+
if (!agent)
|
|
1612
|
+
return;
|
|
1613
|
+
const messageType = message.type;
|
|
1614
|
+
// Handle agent:name:updated (payload structure is different)
|
|
1615
|
+
if (messageType === "agent:name:updated") {
|
|
1616
|
+
const { agentId: updatedAgentId, agentName } = message.payload;
|
|
1617
|
+
if (updatedAgentId === agent.id && agentName) {
|
|
1618
|
+
setAgent((prev) => (prev ? { ...prev, name: agentName } : prev));
|
|
1619
|
+
}
|
|
1620
|
+
return;
|
|
1621
|
+
}
|
|
1622
|
+
// For other agent messages, check if this is for our agent
|
|
1623
|
+
const agentId = message.payload?.agentId;
|
|
1624
|
+
if (agentId !== agent.id)
|
|
1625
|
+
return;
|
|
1626
|
+
// Handle agent:run:start
|
|
1627
|
+
if (messageType === "agent:run:start") {
|
|
1628
|
+
// Reset run-scoped deduplication so new run seq values (starting at 1)
|
|
1629
|
+
// are not discarded due to previous run's lastSeqRef
|
|
1630
|
+
lastSeqRef.current = 0;
|
|
1631
|
+
// Prep streaming UI state for the new run
|
|
1632
|
+
setIsConnecting(true);
|
|
1633
|
+
setIsWaitingForResponse(true);
|
|
1634
|
+
isWaitingRef.current = true;
|
|
1635
|
+
shouldCreateNewMessage.current = false;
|
|
1636
|
+
resetDotsTimer();
|
|
1637
|
+
return;
|
|
1638
|
+
}
|
|
1639
|
+
// Handle agent:user:message
|
|
1640
|
+
if (messageType === "agent:user:message") {
|
|
1641
|
+
const { messageId, content, timestamp, sourceAgentName, sourceAgent } = message.payload;
|
|
1642
|
+
// Track in seenMessageIds for deduplication
|
|
1643
|
+
const normalizedId = messageId.toLowerCase();
|
|
1644
|
+
if (seenMessageIdsRef.current.has(normalizedId)) {
|
|
1645
|
+
return;
|
|
1646
|
+
}
|
|
1647
|
+
seenMessageIdsRef.current.add(normalizedId);
|
|
1648
|
+
// Add user message to the messages list
|
|
1649
|
+
setMessages((prev) => {
|
|
1650
|
+
// Double-check if message already exists (deduplication)
|
|
1651
|
+
if (prev.some((m) => m.id && m.id.toLowerCase() === normalizedId)) {
|
|
1652
|
+
return prev;
|
|
1653
|
+
}
|
|
1654
|
+
const userMessage = {
|
|
1655
|
+
id: messageId,
|
|
1656
|
+
agentId: agent.id,
|
|
1657
|
+
messageIndex: prev.length,
|
|
1658
|
+
role: "user",
|
|
1659
|
+
content: content,
|
|
1660
|
+
name: "user",
|
|
1661
|
+
messageType: "user",
|
|
1662
|
+
isCompleted: true,
|
|
1663
|
+
model: "",
|
|
1664
|
+
tokensUsed: 0,
|
|
1665
|
+
inputTokens: 0,
|
|
1666
|
+
outputTokens: 0,
|
|
1667
|
+
cachedInputTokens: 0,
|
|
1668
|
+
inputTokenCost: 0,
|
|
1669
|
+
outputTokenCost: 0,
|
|
1670
|
+
cachedInputTokenCost: 0,
|
|
1671
|
+
totalCost: 0,
|
|
1672
|
+
currency: "USD",
|
|
1673
|
+
createdDate: timestamp || new Date().toISOString(),
|
|
1674
|
+
toolCalls: [],
|
|
1675
|
+
// Store source agent information for display
|
|
1676
|
+
...(sourceAgentName || sourceAgent?.name
|
|
1677
|
+
? {
|
|
1678
|
+
sourceAgentName: sourceAgentName || sourceAgent?.name,
|
|
1679
|
+
}
|
|
1680
|
+
: {}),
|
|
1681
|
+
};
|
|
1682
|
+
const updated = [...prev, userMessage];
|
|
1683
|
+
messagesRef.current = updated;
|
|
1684
|
+
return updated;
|
|
1685
|
+
});
|
|
1686
|
+
return;
|
|
1687
|
+
}
|
|
1688
|
+
// Handle agent:prompt:queued
|
|
1689
|
+
if (messageType === "agent:prompt:queued") {
|
|
1690
|
+
const { queueEntry } = message.payload;
|
|
1691
|
+
if (queueEntry) {
|
|
1692
|
+
// Add the new prompt to the queued prompts list
|
|
1693
|
+
setQueuedPrompts((prev) => {
|
|
1694
|
+
// Check if prompt already exists (deduplication)
|
|
1695
|
+
if (prev.some((p) => p.id === queueEntry.id)) {
|
|
1696
|
+
return prev;
|
|
1697
|
+
}
|
|
1698
|
+
return [...prev, queueEntry];
|
|
1699
|
+
});
|
|
1700
|
+
}
|
|
1701
|
+
return;
|
|
1702
|
+
}
|
|
1703
|
+
// Handle agent:prompt:processed
|
|
1704
|
+
if (messageType === "agent:prompt:processed") {
|
|
1705
|
+
const { promptId } = message.payload;
|
|
1706
|
+
if (promptId) {
|
|
1707
|
+
// Remove the processed prompt from the queued prompts list
|
|
1708
|
+
setQueuedPrompts((prev) => prev.filter((p) => p.id !== promptId));
|
|
1709
|
+
}
|
|
1710
|
+
return;
|
|
1711
|
+
}
|
|
1712
|
+
// Handle agent:run:delta (content, tools, etc.)
|
|
1713
|
+
if (messageType === "agent:run:delta") {
|
|
1714
|
+
// Allow deltas if the agent is running OR if we already have an active streaming message
|
|
1715
|
+
// OR if the server provided a messageId for targeted updates.
|
|
1716
|
+
// This avoids dropping early deltas that may arrive before the 'running' status update.
|
|
1717
|
+
const isRunning = agent.status === "running" || agent.status === 1;
|
|
1718
|
+
const hasStreaming = messagesRef.current.some((m) => !m.isCompleted && m.messageType === "streaming");
|
|
1719
|
+
const hasMessageId = !!message?.payload?.data?.messageId ||
|
|
1720
|
+
!!message?.payload?.data?.MessageId;
|
|
1721
|
+
if (!isRunning && !hasStreaming && !hasMessageId) {
|
|
1722
|
+
return; // ignore only if we cannot safely target an existing streaming message
|
|
1723
|
+
}
|
|
1724
|
+
const { seq, type, data, cost } = message.payload;
|
|
1725
|
+
// Deduplicate by sequence
|
|
1726
|
+
if (seq && seq <= lastSeqRef.current) {
|
|
1727
|
+
return; // Already processed
|
|
1728
|
+
}
|
|
1729
|
+
if (seq) {
|
|
1730
|
+
lastSeqRef.current = seq;
|
|
1731
|
+
}
|
|
1732
|
+
// Route based on delta type
|
|
1733
|
+
const agentStreamMessage = {
|
|
1734
|
+
type,
|
|
1735
|
+
data,
|
|
1736
|
+
cost,
|
|
1737
|
+
timestamp: new Date().toISOString(),
|
|
1738
|
+
};
|
|
1739
|
+
if (type === "ContentChunk" || type === "contentChunk") {
|
|
1740
|
+
handleContentChunk(agentStreamMessage, agent);
|
|
1741
|
+
}
|
|
1742
|
+
else if (type === "ToolCall" || type === "toolCall") {
|
|
1743
|
+
handleToolCall(agentStreamMessage, agent);
|
|
1744
|
+
}
|
|
1745
|
+
else if (type === "ToolResult" || type === "toolResult") {
|
|
1746
|
+
handleToolResult(agentStreamMessage, agent);
|
|
1747
|
+
}
|
|
1748
|
+
return;
|
|
1749
|
+
}
|
|
1750
|
+
// Unified: agent:run:status (state only)
|
|
1751
|
+
if (messageType === "agent:run:status") {
|
|
1752
|
+
const { seq, data: statusData } = message.payload;
|
|
1753
|
+
// Deduplicate by sequence
|
|
1754
|
+
if (seq && seq <= lastSeqRef.current) {
|
|
1755
|
+
return;
|
|
1756
|
+
}
|
|
1757
|
+
if (seq) {
|
|
1758
|
+
lastSeqRef.current = seq;
|
|
1759
|
+
}
|
|
1760
|
+
// Route based on statusData.state
|
|
1761
|
+
try {
|
|
1762
|
+
// Normalize various status shapes and handle Cancelled uniformly
|
|
1763
|
+
const normalizedStatus = statusData?.state ||
|
|
1764
|
+
statusData?.Status ||
|
|
1765
|
+
statusData?.status;
|
|
1766
|
+
if (normalizedStatus === "Cancelled" ||
|
|
1767
|
+
normalizedStatus === "canceled") {
|
|
1768
|
+
// Stop indicators and mark any in-progress streaming messages as completed
|
|
1769
|
+
setIsWaitingForResponse(false);
|
|
1770
|
+
isWaitingRef.current = false;
|
|
1771
|
+
setIsConnecting(false);
|
|
1772
|
+
setMessages((prev) => {
|
|
1773
|
+
const updated = prev.map((msg) => !msg.isCompleted && msg.messageType === "streaming"
|
|
1774
|
+
? {
|
|
1775
|
+
...msg,
|
|
1776
|
+
isCompleted: true,
|
|
1777
|
+
messageType: "completed",
|
|
1778
|
+
}
|
|
1779
|
+
: msg);
|
|
1780
|
+
messagesRef.current = updated;
|
|
1781
|
+
return updated;
|
|
1782
|
+
});
|
|
1783
|
+
resetDotsTimer();
|
|
1784
|
+
return;
|
|
1785
|
+
}
|
|
1786
|
+
if (statusData?.state === "streamOpen") {
|
|
1787
|
+
setIsConnecting(false);
|
|
1788
|
+
return;
|
|
1789
|
+
}
|
|
1790
|
+
if (statusData?.state === "tokenUsage") {
|
|
1791
|
+
const totals = statusData?.totals;
|
|
1792
|
+
if (totals) {
|
|
1793
|
+
const totalCost = Number(totals.totalCost) || 0;
|
|
1794
|
+
const statusCostLimit = (() => {
|
|
1795
|
+
try {
|
|
1796
|
+
const v = statusData?.costLimit;
|
|
1797
|
+
const n = v != null ? Number(v) : undefined;
|
|
1798
|
+
return Number.isFinite(n) && n > 0
|
|
1799
|
+
? n
|
|
1800
|
+
: undefined;
|
|
1801
|
+
}
|
|
1802
|
+
catch {
|
|
1803
|
+
return undefined;
|
|
1804
|
+
}
|
|
1805
|
+
})();
|
|
1806
|
+
const nextTotals = {
|
|
1807
|
+
input: Number(totals.totalInputTokens) || 0,
|
|
1808
|
+
output: Number(totals.totalOutputTokens) || 0,
|
|
1809
|
+
cached: Number(totals.totalCachedInputTokens) || 0,
|
|
1810
|
+
cacheWrite: Number(totals.totalCacheWriteTokens) || 0,
|
|
1811
|
+
inputCost: Number(totals.totalInputTokenCost) || 0,
|
|
1812
|
+
outputCost: Number(totals.totalOutputTokenCost) || 0,
|
|
1813
|
+
cachedCost: Number(totals.totalCachedInputTokenCost) || 0,
|
|
1814
|
+
cacheWriteCost: Number(totals.totalCacheWriteTokenCost) || 0,
|
|
1815
|
+
totalCost: totalCost,
|
|
1816
|
+
currency: totals.currency,
|
|
1817
|
+
};
|
|
1818
|
+
const anyNonZero = (nextTotals.totalCost || 0) > 0 ||
|
|
1819
|
+
(nextTotals.input || 0) > 0 ||
|
|
1820
|
+
(nextTotals.output || 0) > 0 ||
|
|
1821
|
+
(nextTotals.cached || 0) > 0 ||
|
|
1822
|
+
(nextTotals.cacheWrite || 0) > 0;
|
|
1823
|
+
if (anyNonZero) {
|
|
1824
|
+
setLiveTotals(nextTotals);
|
|
1825
|
+
}
|
|
1826
|
+
// If server provides costLimit along with totals, persist it locally
|
|
1827
|
+
if (statusCostLimit) {
|
|
1828
|
+
setAgent((prev) => prev &&
|
|
1829
|
+
(!prev.costLimit || prev.costLimit !== statusCostLimit)
|
|
1830
|
+
? { ...prev, costLimit: statusCostLimit }
|
|
1831
|
+
: prev);
|
|
1832
|
+
}
|
|
1833
|
+
if (agent?.costLimit && totalCost > agent.costLimit) {
|
|
1834
|
+
setCostLimitExceeded({
|
|
1835
|
+
totalCost: totalCost,
|
|
1836
|
+
costLimit: agent.costLimit,
|
|
1837
|
+
initialCostLimit: agent.costLimit,
|
|
1838
|
+
});
|
|
1839
|
+
setIsWaitingForResponse(false);
|
|
1840
|
+
shouldCreateNewMessage.current = false;
|
|
1841
|
+
}
|
|
1842
|
+
setMessages((prev) => [...prev]);
|
|
1843
|
+
}
|
|
1844
|
+
return;
|
|
1845
|
+
}
|
|
1846
|
+
if (statusData?.state === "ToolApprovalsRequired") {
|
|
1847
|
+
const msgId = statusData.messageId;
|
|
1848
|
+
const ids = statusData.toolCallIds || [];
|
|
1849
|
+
if (msgId && Array.isArray(ids) && ids.length > 0) {
|
|
1850
|
+
setMessages((prev) => {
|
|
1851
|
+
const updated = prev.map((m) => {
|
|
1852
|
+
if (m.id !== msgId)
|
|
1853
|
+
return m;
|
|
1854
|
+
const existingToolCalls = m.toolCalls || [];
|
|
1855
|
+
const updatedToolCalls = existingToolCalls.map((tc) => {
|
|
1856
|
+
if (!ids.includes(tc.toolCallId))
|
|
1857
|
+
return tc;
|
|
1858
|
+
const fn = tc.functionName || "";
|
|
1859
|
+
return {
|
|
1860
|
+
...tc,
|
|
1861
|
+
functionName: fn.includes("(pending approval)")
|
|
1862
|
+
? fn
|
|
1863
|
+
: fn + " (pending approval)",
|
|
1864
|
+
};
|
|
1865
|
+
});
|
|
1866
|
+
return { ...m, toolCalls: updatedToolCalls };
|
|
1867
|
+
});
|
|
1868
|
+
messagesRef.current = updated;
|
|
1869
|
+
return updated;
|
|
1870
|
+
});
|
|
1871
|
+
}
|
|
1872
|
+
setIsConnecting(false);
|
|
1873
|
+
setIsWaitingForResponse(false);
|
|
1874
|
+
return;
|
|
1875
|
+
}
|
|
1876
|
+
if (statusData?.state === "CostLimitReached") {
|
|
1877
|
+
const totalCost = Number(statusData.totalCost) || 0;
|
|
1878
|
+
const costLimit = Number(statusData.costLimit) || agent?.costLimit || 0;
|
|
1879
|
+
setCostLimitExceeded({
|
|
1880
|
+
totalCost: totalCost,
|
|
1881
|
+
costLimit: costLimit,
|
|
1882
|
+
initialCostLimit: costLimit,
|
|
1883
|
+
});
|
|
1884
|
+
setIsWaitingForResponse(false);
|
|
1885
|
+
setIsConnecting(false);
|
|
1886
|
+
return;
|
|
1887
|
+
}
|
|
1888
|
+
if (statusData?.state === "contextWindow") {
|
|
1889
|
+
window.__agentContextWindowStatus = {
|
|
1890
|
+
model: statusData.model,
|
|
1891
|
+
normalizedModel: statusData.normalizedModel,
|
|
1892
|
+
contextWindowTokens: statusData.contextWindowTokens,
|
|
1893
|
+
maxCompletionTokens: statusData.maxCompletionTokens,
|
|
1894
|
+
estimatedInputTokens: statusData.estimatedInputTokens,
|
|
1895
|
+
messageCount: statusData.messageCount,
|
|
1896
|
+
contextUsedPercent: statusData.contextUsedPercent,
|
|
1897
|
+
};
|
|
1898
|
+
setMessages((prev) => [...prev]);
|
|
1899
|
+
return;
|
|
1900
|
+
}
|
|
1901
|
+
if (statusData?.state === "contextChanged") {
|
|
1902
|
+
const nextContext = statusData.context || {};
|
|
1903
|
+
setAgentMetadata((prev) => {
|
|
1904
|
+
const current = (prev || {});
|
|
1905
|
+
const currentWithoutContext = { ...current };
|
|
1906
|
+
delete currentWithoutContext.context;
|
|
1907
|
+
const next = {
|
|
1908
|
+
...currentWithoutContext,
|
|
1909
|
+
additionalData: {
|
|
1910
|
+
...(current.additionalData || {}),
|
|
1911
|
+
context: nextContext,
|
|
1912
|
+
},
|
|
1913
|
+
};
|
|
1914
|
+
return next;
|
|
1915
|
+
});
|
|
1916
|
+
return;
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
catch (err) {
|
|
1920
|
+
console.error("[AgentTerminal] Error handling status update:", err);
|
|
1921
|
+
}
|
|
1922
|
+
return;
|
|
1923
|
+
}
|
|
1924
|
+
// Lifecycle: agent:run:complete
|
|
1925
|
+
if (messageType === "agent:run:complete") {
|
|
1926
|
+
// Reset deduplication for the next run
|
|
1927
|
+
lastSeqRef.current = 0;
|
|
1928
|
+
// Mark the last assistant message as completed
|
|
1929
|
+
setMessages((prev) => {
|
|
1930
|
+
const updated = prev.map((msg) => msg.role === "assistant" && !msg.isCompleted
|
|
1931
|
+
? {
|
|
1932
|
+
...msg,
|
|
1933
|
+
isCompleted: true,
|
|
1934
|
+
messageType: "completed",
|
|
1935
|
+
}
|
|
1936
|
+
: msg);
|
|
1937
|
+
messagesRef.current = updated;
|
|
1938
|
+
return updated;
|
|
1939
|
+
});
|
|
1940
|
+
setIsWaitingForResponse(false);
|
|
1941
|
+
isWaitingRef.current = false;
|
|
1942
|
+
setIsConnecting(false);
|
|
1943
|
+
shouldCreateNewMessage.current = false;
|
|
1944
|
+
resetDotsTimer();
|
|
1945
|
+
return;
|
|
1946
|
+
}
|
|
1947
|
+
// Lifecycle: agent:run:error
|
|
1948
|
+
if (messageType === "agent:run:error") {
|
|
1949
|
+
const errorMsg = message.payload?.error || "Unknown error";
|
|
1950
|
+
// Reset deduplication for the next run after an error
|
|
1951
|
+
lastSeqRef.current = 0;
|
|
1952
|
+
setError(errorMsg);
|
|
1953
|
+
setIsWaitingForResponse(false);
|
|
1954
|
+
isWaitingRef.current = false;
|
|
1955
|
+
setIsConnecting(false);
|
|
1956
|
+
resetDotsTimer();
|
|
1957
|
+
return;
|
|
1958
|
+
}
|
|
1959
|
+
}, [
|
|
1960
|
+
agent,
|
|
1961
|
+
handleContentChunk,
|
|
1962
|
+
handleToolCall,
|
|
1963
|
+
handleToolResult,
|
|
1964
|
+
resetDotsTimer,
|
|
1965
|
+
]);
|
|
1966
|
+
// Keep refs for latest agent and resetDotsTimer to avoid adding them to effect deps
|
|
1967
|
+
const agentRef = useRef(agent);
|
|
1968
|
+
const resetDotsTimerRef = useRef(resetDotsTimer);
|
|
1969
|
+
const handleAgentWebSocketMessageRef = useRef(handleAgentWebSocketMessage);
|
|
1970
|
+
useEffect(() => {
|
|
1971
|
+
agentRef.current = agent;
|
|
1972
|
+
}, [agent]);
|
|
1973
|
+
useEffect(() => {
|
|
1974
|
+
resetDotsTimerRef.current = resetDotsTimer;
|
|
1975
|
+
}, [resetDotsTimer]);
|
|
1976
|
+
useEffect(() => {
|
|
1977
|
+
handleAgentWebSocketMessageRef.current = handleAgentWebSocketMessage;
|
|
1978
|
+
}, [handleAgentWebSocketMessage]);
|
|
1979
|
+
// Subscribe to agent WebSocket messages when active
|
|
1980
|
+
useEffect(() => {
|
|
1981
|
+
const addListener = editContext?.addSocketMessageListener;
|
|
1982
|
+
if (!isActive || !addListener) {
|
|
1983
|
+
// Unsubscribe if we were previously subscribed
|
|
1984
|
+
if (subscribedAgentIdRef.current) {
|
|
1985
|
+
const socket = globalThis.editorSocket;
|
|
1986
|
+
if (socket && socket.readyState === WebSocket.OPEN) {
|
|
1987
|
+
socket.send(JSON.stringify({
|
|
1988
|
+
type: "agent:unsubscribe",
|
|
1989
|
+
agentId: subscribedAgentIdRef.current,
|
|
1990
|
+
}));
|
|
1991
|
+
}
|
|
1992
|
+
subscribedAgentIdRef.current = null;
|
|
1993
|
+
}
|
|
1994
|
+
return;
|
|
1995
|
+
}
|
|
1996
|
+
// Send subscription message to server
|
|
1997
|
+
const socket = globalThis.editorSocket;
|
|
1998
|
+
if (socket && socket.readyState === WebSocket.OPEN) {
|
|
1999
|
+
socket.send(JSON.stringify({
|
|
2000
|
+
type: "agent:subscribe",
|
|
2001
|
+
agentId: agentStub.id,
|
|
2002
|
+
}));
|
|
2003
|
+
}
|
|
2004
|
+
// Use the addSocketMessageListener helper from editContext
|
|
2005
|
+
// Wrap the handler in a stable function that uses the ref
|
|
2006
|
+
const stableHandler = (message) => {
|
|
2007
|
+
handleAgentWebSocketMessageRef.current(message);
|
|
2008
|
+
};
|
|
2009
|
+
const unsubscribe = addListener(stableHandler);
|
|
2010
|
+
subscribedAgentIdRef.current = agentStub.id;
|
|
2011
|
+
// Reset deduplication state when switching agents
|
|
2012
|
+
seenMessageIdsRef.current.clear();
|
|
2013
|
+
lastSeqRef.current = 0;
|
|
2014
|
+
// Set up streaming state based on agent status (uses latest values via refs)
|
|
2015
|
+
const currentAgent = agentRef.current;
|
|
2016
|
+
if (currentAgent) {
|
|
2017
|
+
const isRunning = currentAgent.status === "running" || currentAgent.status === 1;
|
|
2018
|
+
const isWaitingForApproval = currentAgent.status === "waitingForApproval" ||
|
|
2019
|
+
currentAgent.status === 2;
|
|
2020
|
+
if (isRunning) {
|
|
2021
|
+
setIsWaitingForResponse(true);
|
|
2022
|
+
isWaitingRef.current = true;
|
|
2023
|
+
shouldCreateNewMessage.current = false;
|
|
2024
|
+
resetDotsTimerRef.current();
|
|
2025
|
+
}
|
|
2026
|
+
else if (isWaitingForApproval) {
|
|
2027
|
+
setIsWaitingForResponse(false);
|
|
2028
|
+
isWaitingRef.current = false;
|
|
2029
|
+
resetDotsTimerRef.current();
|
|
2030
|
+
}
|
|
2031
|
+
else {
|
|
2032
|
+
setIsWaitingForResponse(false);
|
|
2033
|
+
isWaitingRef.current = false;
|
|
2034
|
+
resetDotsTimerRef.current();
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
2037
|
+
return () => {
|
|
2038
|
+
// Send unsubscribe message to server
|
|
2039
|
+
const socket = globalThis.editorSocket;
|
|
2040
|
+
if (socket &&
|
|
2041
|
+
socket.readyState === WebSocket.OPEN &&
|
|
2042
|
+
subscribedAgentIdRef.current) {
|
|
2043
|
+
socket.send(JSON.stringify({
|
|
2044
|
+
type: "agent:unsubscribe",
|
|
2045
|
+
agentId: subscribedAgentIdRef.current,
|
|
2046
|
+
}));
|
|
2047
|
+
}
|
|
2048
|
+
unsubscribe();
|
|
2049
|
+
subscribedAgentIdRef.current = null;
|
|
2050
|
+
};
|
|
2051
|
+
}, [isActive, agentStub.id, editContext?.addSocketMessageListener]);
|
|
2052
|
+
// Focus prompt when requested globally (from AI command)
|
|
2053
|
+
useEffect(() => {
|
|
2054
|
+
const focusHandler = () => {
|
|
2055
|
+
try {
|
|
2056
|
+
if (textareaRef.current) {
|
|
2057
|
+
textareaRef.current.focus();
|
|
2058
|
+
// Move caret to end
|
|
2059
|
+
const value = textareaRef.current.value || "";
|
|
2060
|
+
textareaRef.current.selectionStart = value.length;
|
|
2061
|
+
textareaRef.current.selectionEnd = value.length;
|
|
2062
|
+
}
|
|
2063
|
+
}
|
|
2064
|
+
catch { }
|
|
2065
|
+
};
|
|
2066
|
+
window.addEventListener("editor:focusAgentPrompt", focusHandler);
|
|
2067
|
+
return () => window.removeEventListener("editor:focusAgentPrompt", focusHandler);
|
|
2068
|
+
}, []);
|
|
2069
|
+
// Profiles are provided by parent component (Agents). No local loading here.
|
|
2070
|
+
// Select active profile based on agent.profileId or agentStub.profileId
|
|
2071
|
+
useEffect(() => {
|
|
2072
|
+
if (!profiles || profiles.length === 0)
|
|
2073
|
+
return;
|
|
2074
|
+
// For new agents, use agentStub.profileId; for loaded agents, use agent.profileId
|
|
2075
|
+
const profileIdToUse = agent?.profileId || agentStub.profileId;
|
|
2076
|
+
// Use case-insensitive comparison for GUID matching (backend may return different casing)
|
|
2077
|
+
const normalizedProfileId = profileIdToUse?.toLowerCase();
|
|
2078
|
+
const candidate = normalizedProfileId
|
|
2079
|
+
? (profiles.find((p) => p.id?.toLowerCase() === normalizedProfileId) ??
|
|
2080
|
+
profiles[0])
|
|
2081
|
+
: profiles[0];
|
|
2082
|
+
if (candidate && (!activeProfile || activeProfile.id !== candidate.id)) {
|
|
2083
|
+
setActiveProfile(candidate);
|
|
2084
|
+
}
|
|
2085
|
+
}, [profiles, agent?.profileId, agentStub.profileId]);
|
|
2086
|
+
// Fetch initial queued prompts on mount, then rely on WebSocket updates
|
|
2087
|
+
useEffect(() => {
|
|
2088
|
+
if (!agent?.id) {
|
|
2089
|
+
setQueuedPrompts([]);
|
|
2090
|
+
return;
|
|
2091
|
+
}
|
|
2092
|
+
// Fetch once on mount, then rely on WebSocket updates
|
|
2093
|
+
const fetchInitialPrompts = async () => {
|
|
2094
|
+
try {
|
|
2095
|
+
const prompts = await getPendingPrompts(agent.id);
|
|
2096
|
+
setQueuedPrompts(prompts);
|
|
2097
|
+
}
|
|
2098
|
+
catch (error) {
|
|
2099
|
+
console.error("Failed to fetch initial queued prompts:", error);
|
|
2100
|
+
}
|
|
2101
|
+
};
|
|
2102
|
+
fetchInitialPrompts();
|
|
2103
|
+
}, [agent?.id]);
|
|
2104
|
+
// Update selected model when the active profile or agent model changes
|
|
2105
|
+
useEffect(() => {
|
|
2106
|
+
if (!activeProfile)
|
|
2107
|
+
return;
|
|
2108
|
+
const agentModelName = agent?.model; // persisted as model NAME on server
|
|
2109
|
+
const models = activeProfile.models || [];
|
|
2110
|
+
let nextModelId = undefined;
|
|
2111
|
+
if (agentModelName) {
|
|
2112
|
+
const match = models.find((m) => (m.name || "").toLowerCase() === agentModelName.toLowerCase());
|
|
2113
|
+
if (match)
|
|
2114
|
+
nextModelId = match.id;
|
|
2115
|
+
}
|
|
2116
|
+
if (!nextModelId) {
|
|
2117
|
+
nextModelId = activeProfile.defaultModelId || models[0]?.id;
|
|
2118
|
+
}
|
|
2119
|
+
setSelectedModelId(nextModelId || undefined);
|
|
2120
|
+
}, [activeProfile?.id, agent?.model]);
|
|
2121
|
+
// Cleanup stream connection when component unmounts or agent changes
|
|
2122
|
+
useEffect(() => {
|
|
2123
|
+
return () => {
|
|
2124
|
+
if (abortControllerRef.current) {
|
|
2125
|
+
abortControllerRef.current.abort();
|
|
2126
|
+
}
|
|
2127
|
+
};
|
|
2128
|
+
}, [agent?.id]);
|
|
2129
|
+
// Initialize mode from metadata; fall back to agent.Mode from server
|
|
2130
|
+
useEffect(() => {
|
|
2131
|
+
try {
|
|
2132
|
+
const metaMode = agentMetadata?.mode;
|
|
2133
|
+
if (metaMode === "autonomous" ||
|
|
2134
|
+
metaMode === "read-only" ||
|
|
2135
|
+
metaMode === "supervised") {
|
|
2136
|
+
setMode(metaMode);
|
|
2137
|
+
return;
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
catch { }
|
|
2141
|
+
try {
|
|
2142
|
+
const serverMode = agent?.mode;
|
|
2143
|
+
if (serverMode === "autonomous" ||
|
|
2144
|
+
serverMode === "read-only" ||
|
|
2145
|
+
serverMode === "supervised") {
|
|
2146
|
+
setMode(serverMode);
|
|
2147
|
+
}
|
|
2148
|
+
}
|
|
2149
|
+
catch { }
|
|
2150
|
+
}, [agentMetadata, agent?.mode]);
|
|
2151
|
+
// Auto-scroll when messages change (only if user hasn't manually scrolled up)
|
|
2152
|
+
useLayoutEffect(() => {
|
|
2153
|
+
if (shouldAutoScroll) {
|
|
2154
|
+
scrollToBottom();
|
|
2155
|
+
}
|
|
2156
|
+
}, [messages, scrollToBottom, shouldAutoScroll]);
|
|
2157
|
+
// Persist any pending settings (mode/model) once an agent exists server-side
|
|
2158
|
+
const persistPendingSettingsIfNeeded = useCallback(async () => {
|
|
2159
|
+
try {
|
|
2160
|
+
if (!agent?.id)
|
|
2161
|
+
return;
|
|
2162
|
+
const pending = pendingSettingsRef.current;
|
|
2163
|
+
if (!pending)
|
|
2164
|
+
return;
|
|
2165
|
+
const payload = {};
|
|
2166
|
+
if (pending.modelName)
|
|
2167
|
+
payload.model = pending.modelName;
|
|
2168
|
+
if (pending.mode)
|
|
2169
|
+
payload.mode = pending.mode;
|
|
2170
|
+
if (Object.keys(payload).length === 0)
|
|
2171
|
+
return;
|
|
2172
|
+
await updateAgentSettings(agent.id, payload);
|
|
2173
|
+
pendingSettingsRef.current = null;
|
|
2174
|
+
}
|
|
2175
|
+
catch (e) {
|
|
2176
|
+
console.error("Failed to persist pending settings", e);
|
|
2177
|
+
}
|
|
2178
|
+
}, [agent?.id]);
|
|
2179
|
+
const handleSubmit = async () => {
|
|
2180
|
+
if (isSubmitting || !editContext)
|
|
2181
|
+
return;
|
|
2182
|
+
try {
|
|
2183
|
+
setIsSubmitting(true);
|
|
2184
|
+
setError(null);
|
|
2185
|
+
// For new agents, use agentStub.id; for existing agents, use agent.id
|
|
2186
|
+
const agentId = agent?.id || agentStub.id;
|
|
2187
|
+
if (!agentId)
|
|
2188
|
+
return;
|
|
2189
|
+
// Optional context factory: invoke if configured and available, otherwise continue
|
|
2190
|
+
const factoryName = agentMetadata?.additionalData
|
|
2191
|
+
?.contextFactory;
|
|
2192
|
+
if (factoryName) {
|
|
2193
|
+
const factory = editContext.getContextFactory?.(factoryName);
|
|
2194
|
+
if (factory) {
|
|
2195
|
+
try {
|
|
2196
|
+
await Promise.resolve(factory());
|
|
2197
|
+
}
|
|
2198
|
+
catch (e) {
|
|
2199
|
+
console.warn(`Context factory '${factoryName}' failed: ${e?.message || String(e)}`);
|
|
2200
|
+
}
|
|
2201
|
+
}
|
|
2202
|
+
else {
|
|
2203
|
+
console.warn(`Context factory not found: ${factoryName}. Proceeding without it.`);
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
// NOTE: User message is no longer added optimistically here
|
|
2207
|
+
// It will be added when we receive the agent:user:message broadcast from the server
|
|
2208
|
+
// This ensures all tabs (including the sending tab) have the same messageId from the database
|
|
2209
|
+
const request = {
|
|
2210
|
+
agentId: agentId,
|
|
2211
|
+
message: prompt.trim(),
|
|
2212
|
+
sessionId: editContext.sessionId,
|
|
2213
|
+
profileId: activeProfile?.id || profiles[0]?.id || "",
|
|
2214
|
+
profile: activeProfile?.name || profiles[0]?.name || "",
|
|
2215
|
+
model: selectedModelId,
|
|
2216
|
+
mode: mode,
|
|
2217
|
+
context: canonicalizeAgentMetadata(agentMetadata), // Canonicalize to ensure complete field structure
|
|
2218
|
+
deterministic: deterministicFlags.deterministic,
|
|
2219
|
+
seed: deterministicFlags.seed,
|
|
2220
|
+
};
|
|
2221
|
+
// Starting agent
|
|
2222
|
+
// Re-enable auto-scroll when user submits a new message
|
|
2223
|
+
setShouldAutoScroll(true);
|
|
2224
|
+
// No need to create a temporary message - the stream will create messages as needed
|
|
2225
|
+
const response = await startAgent(request);
|
|
2226
|
+
// Check if prompt was queued (agent was already running)
|
|
2227
|
+
const wasQueued = response.message?.toLowerCase().includes("queued") ||
|
|
2228
|
+
response.status === "Queued";
|
|
2229
|
+
if (wasQueued) {
|
|
2230
|
+
// Prompt was queued - show a brief notification but don't set waiting state
|
|
2231
|
+
// The prompt will be processed when the agent becomes idle
|
|
2232
|
+
console.log("Prompt queued for processing");
|
|
2233
|
+
// Don't set isWaitingForResponse since the agent is already running
|
|
2234
|
+
setIsWaitingForResponse(false);
|
|
2235
|
+
isWaitingRef.current = false;
|
|
2236
|
+
}
|
|
2237
|
+
else {
|
|
2238
|
+
// Normal submission - set waiting state to show dancing dots immediately
|
|
2239
|
+
setIsWaitingForResponse(true);
|
|
2240
|
+
// Update the ref immediately so resetDotsTimer sees the new state
|
|
2241
|
+
isWaitingRef.current = true;
|
|
2242
|
+
// Start idle timer; dots appear only if no chunks for >1s
|
|
2243
|
+
resetDotsTimer();
|
|
2244
|
+
}
|
|
2245
|
+
// If user changed mode/model while the agent was new, persist them now
|
|
2246
|
+
await persistPendingSettingsIfNeeded();
|
|
2247
|
+
// Save prompt to history
|
|
2248
|
+
if (prompt.trim()) {
|
|
2249
|
+
setPromptHistory((prev) => [
|
|
2250
|
+
prompt.trim(),
|
|
2251
|
+
...prev.filter((p) => p !== prompt.trim()).slice(0, 9),
|
|
2252
|
+
]);
|
|
2253
|
+
setCurrentHistoryIndex(-1);
|
|
2254
|
+
}
|
|
2255
|
+
setPrompt("");
|
|
2256
|
+
// WebSocket connection is already active via subscription - no need for SSE
|
|
2257
|
+
}
|
|
2258
|
+
catch (err) {
|
|
2259
|
+
console.error("Failed to submit prompt:", err);
|
|
2260
|
+
setError("Failed to submit prompt");
|
|
2261
|
+
setIsWaitingForResponse(false);
|
|
2262
|
+
// Remove the optimistically added user message on error
|
|
2263
|
+
setMessages((prev) => prev.slice(0, -1));
|
|
2264
|
+
}
|
|
2265
|
+
finally {
|
|
2266
|
+
setIsSubmitting(false);
|
|
2267
|
+
}
|
|
2268
|
+
};
|
|
2269
|
+
const handleKeyPress = (e) => {
|
|
2270
|
+
// Submit only on plain Enter (no Ctrl/Meta/Shift/Alt)
|
|
2271
|
+
if (e.key === "Enter" &&
|
|
2272
|
+
!e.ctrlKey &&
|
|
2273
|
+
!e.metaKey &&
|
|
2274
|
+
!e.shiftKey &&
|
|
2275
|
+
!e.altKey) {
|
|
2276
|
+
e.preventDefault();
|
|
2277
|
+
handleSubmit();
|
|
2278
|
+
}
|
|
2279
|
+
if (e.key === "ArrowUp") {
|
|
2280
|
+
// Only navigate history if prompt is empty or we're already navigating history
|
|
2281
|
+
const canNavigateHistory = prompt.trim().length === 0 || currentHistoryIndex !== -1;
|
|
2282
|
+
if (canNavigateHistory) {
|
|
2283
|
+
e.preventDefault();
|
|
2284
|
+
if (promptHistory.length > 0) {
|
|
2285
|
+
const newIndex = currentHistoryIndex < promptHistory.length - 1
|
|
2286
|
+
? currentHistoryIndex + 1
|
|
2287
|
+
: currentHistoryIndex;
|
|
2288
|
+
setCurrentHistoryIndex(newIndex);
|
|
2289
|
+
const historicalPrompt = promptHistory[newIndex];
|
|
2290
|
+
if (textareaRef.current && historicalPrompt) {
|
|
2291
|
+
setPrompt(historicalPrompt);
|
|
2292
|
+
setTimeout(() => {
|
|
2293
|
+
if (textareaRef.current) {
|
|
2294
|
+
textareaRef.current.selectionStart = historicalPrompt.length;
|
|
2295
|
+
textareaRef.current.selectionEnd = historicalPrompt.length;
|
|
2296
|
+
}
|
|
2297
|
+
}, 0);
|
|
2298
|
+
}
|
|
2299
|
+
}
|
|
2300
|
+
}
|
|
2301
|
+
}
|
|
2302
|
+
if (e.key === "ArrowDown" && currentHistoryIndex >= 0) {
|
|
2303
|
+
e.preventDefault();
|
|
2304
|
+
const newIndex = currentHistoryIndex - 1;
|
|
2305
|
+
setCurrentHistoryIndex(newIndex);
|
|
2306
|
+
const historicalPrompt = newIndex >= 0 ? promptHistory[newIndex] || "" : "";
|
|
2307
|
+
setPrompt(historicalPrompt);
|
|
2308
|
+
if (textareaRef.current) {
|
|
2309
|
+
setTimeout(() => {
|
|
2310
|
+
if (textareaRef.current) {
|
|
2311
|
+
textareaRef.current.selectionStart = historicalPrompt.length;
|
|
2312
|
+
textareaRef.current.selectionEnd = historicalPrompt.length;
|
|
2313
|
+
}
|
|
2314
|
+
}, 0);
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
};
|
|
2318
|
+
// Send a message programmatically (used by quick-action buttons)
|
|
2319
|
+
const sendQuickMessage = async (text) => {
|
|
2320
|
+
if (!text.trim() || isSubmitting || !editContext)
|
|
2321
|
+
return;
|
|
2322
|
+
try {
|
|
2323
|
+
setIsSubmitting(true);
|
|
2324
|
+
setError(null);
|
|
2325
|
+
const agentId = agent?.id;
|
|
2326
|
+
if (!agentId)
|
|
2327
|
+
return;
|
|
2328
|
+
// Optional context factory: invoke if configured and available, otherwise continue
|
|
2329
|
+
const factoryName = agentMetadata?.additionalData
|
|
2330
|
+
?.contextFactory;
|
|
2331
|
+
if (factoryName) {
|
|
2332
|
+
const factory = editContext.getContextFactory?.(factoryName);
|
|
2333
|
+
if (factory) {
|
|
2334
|
+
try {
|
|
2335
|
+
await Promise.resolve(factory());
|
|
2336
|
+
}
|
|
2337
|
+
catch (e) {
|
|
2338
|
+
console.warn(`Context factory '${factoryName}' failed: ${e?.message || String(e)}`);
|
|
2339
|
+
}
|
|
2340
|
+
}
|
|
2341
|
+
else {
|
|
2342
|
+
console.warn(`Context factory not found: ${factoryName}. Proceeding without it.`);
|
|
2343
|
+
}
|
|
2344
|
+
}
|
|
2345
|
+
// NOTE: User message is no longer added optimistically here
|
|
2346
|
+
// It will be added when we receive the agent:user:message broadcast from the server
|
|
2347
|
+
// This ensures all tabs (including the sending tab) have the same messageId from the database
|
|
2348
|
+
const request = {
|
|
2349
|
+
agentId: agent.id,
|
|
2350
|
+
message: text.trim(),
|
|
2351
|
+
sessionId: editContext.sessionId,
|
|
2352
|
+
profileId: activeProfile?.id || profiles[0]?.id || "",
|
|
2353
|
+
profile: activeProfile?.name || profiles[0]?.name || "",
|
|
2354
|
+
model: selectedModelId,
|
|
2355
|
+
mode: mode,
|
|
2356
|
+
context: canonicalizeAgentMetadata(agentMetadata), // Canonicalize to ensure complete field structure
|
|
2357
|
+
deterministic: deterministicFlags.deterministic,
|
|
2358
|
+
seed: deterministicFlags.seed,
|
|
2359
|
+
};
|
|
2360
|
+
setIsWaitingForResponse(true);
|
|
2361
|
+
// Update the ref immediately so resetDotsTimer sees the new state
|
|
2362
|
+
isWaitingRef.current = true;
|
|
2363
|
+
resetDotsTimer();
|
|
2364
|
+
setShouldAutoScroll(true);
|
|
2365
|
+
await startAgent(request);
|
|
2366
|
+
// If user changed mode/model while the agent was new, persist them now
|
|
2367
|
+
await persistPendingSettingsIfNeeded();
|
|
2368
|
+
// WebSocket connection is already active via subscription - no need for SSE
|
|
2369
|
+
}
|
|
2370
|
+
catch (err) {
|
|
2371
|
+
console.error("Failed to submit quick message:", err);
|
|
2372
|
+
setError("Failed to submit prompt");
|
|
2373
|
+
setIsWaitingForResponse(false);
|
|
2374
|
+
setMessages((prev) => prev.slice(0, -1));
|
|
2375
|
+
}
|
|
2376
|
+
finally {
|
|
2377
|
+
setIsSubmitting(false);
|
|
2378
|
+
}
|
|
2379
|
+
};
|
|
2380
|
+
// Auto-send initial prompt if provided and agent has no messages yet
|
|
2381
|
+
const initialPromptSentRef = useRef(false);
|
|
2382
|
+
useEffect(() => {
|
|
2383
|
+
if (initialPrompt !== undefined &&
|
|
2384
|
+
!isLoading &&
|
|
2385
|
+
!initialPromptSentRef.current &&
|
|
2386
|
+
messages.length === 0 &&
|
|
2387
|
+
agentStub.id &&
|
|
2388
|
+
editContext &&
|
|
2389
|
+
activeProfile && // MUST have activeProfile set, not just profiles.length
|
|
2390
|
+
profiles.length > 0) {
|
|
2391
|
+
initialPromptSentRef.current = true;
|
|
2392
|
+
// Delay slightly to ensure all state is ready
|
|
2393
|
+
setTimeout(() => {
|
|
2394
|
+
setPrompt(initialPrompt);
|
|
2395
|
+
// Trigger submit programmatically
|
|
2396
|
+
handleSubmit();
|
|
2397
|
+
}, 200);
|
|
2398
|
+
}
|
|
2399
|
+
}, [
|
|
2400
|
+
initialPrompt,
|
|
2401
|
+
isLoading,
|
|
2402
|
+
messages.length,
|
|
2403
|
+
agentStub.id,
|
|
2404
|
+
editContext,
|
|
2405
|
+
activeProfile,
|
|
2406
|
+
profiles.length,
|
|
2407
|
+
handleSubmit,
|
|
2408
|
+
]);
|
|
2409
|
+
// Resolve display names when metadata or editor state changes
|
|
2410
|
+
useEffect(() => {
|
|
2411
|
+
const metaCtx = agentMetadata;
|
|
2412
|
+
if (!metaCtx) {
|
|
2413
|
+
setResolvedPageName(undefined);
|
|
2414
|
+
setResolvedComponentName(undefined);
|
|
2415
|
+
setResolvedFieldName(undefined);
|
|
2416
|
+
return;
|
|
2417
|
+
}
|
|
2418
|
+
// Page names (for now, just resolve the first page)
|
|
2419
|
+
if (metaCtx.items?.length) {
|
|
2420
|
+
const firstPage = metaCtx.items[0];
|
|
2421
|
+
if (firstPage) {
|
|
2422
|
+
let name = firstPage.name;
|
|
2423
|
+
if (!name &&
|
|
2424
|
+
editContext?.contentEditorItem?.descriptor.id === firstPage.id &&
|
|
2425
|
+
editContext?.contentEditorItem?.name) {
|
|
2426
|
+
name = editContext.contentEditorItem.name;
|
|
2427
|
+
}
|
|
2428
|
+
else if (!name) {
|
|
2429
|
+
name = undefined;
|
|
2430
|
+
}
|
|
2431
|
+
setResolvedPageName(name);
|
|
2432
|
+
}
|
|
2433
|
+
else {
|
|
2434
|
+
setResolvedPageName(undefined);
|
|
2435
|
+
}
|
|
2436
|
+
}
|
|
2437
|
+
else
|
|
2438
|
+
setResolvedPageName(undefined);
|
|
2439
|
+
// Component names (for now, just resolve the first component)
|
|
2440
|
+
if (metaCtx.components?.length && editContext?.page) {
|
|
2441
|
+
const firstComponent = metaCtx.components[0];
|
|
2442
|
+
if (firstComponent?.componentId) {
|
|
2443
|
+
try {
|
|
2444
|
+
const comp = getComponentById(firstComponent.componentId, editContext.page);
|
|
2445
|
+
setResolvedComponentName(comp?.name);
|
|
2446
|
+
}
|
|
2447
|
+
catch {
|
|
2448
|
+
setResolvedComponentName(undefined);
|
|
2449
|
+
}
|
|
2450
|
+
}
|
|
2451
|
+
else {
|
|
2452
|
+
setResolvedComponentName(undefined);
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
else
|
|
2456
|
+
setResolvedComponentName(undefined);
|
|
2457
|
+
// Field name (async)
|
|
2458
|
+
(async () => {
|
|
2459
|
+
if (metaCtx.field && editContext?.itemsRepository) {
|
|
2460
|
+
try {
|
|
2461
|
+
// Use the item descriptor from field context if available, otherwise fallback to current item
|
|
2462
|
+
const itemDescriptor = metaCtx.field.item || {
|
|
2463
|
+
id: editContext.currentItemDescriptor?.id || "",
|
|
2464
|
+
language: editContext.currentItemDescriptor?.language || "en",
|
|
2465
|
+
version: editContext.currentItemDescriptor?.version || 0,
|
|
2466
|
+
};
|
|
2467
|
+
const field = await editContext.itemsRepository.getField({
|
|
2468
|
+
item: itemDescriptor,
|
|
2469
|
+
fieldId: metaCtx.field.fieldId,
|
|
2470
|
+
});
|
|
2471
|
+
setResolvedFieldName(field?.name || metaCtx.field.fieldName);
|
|
2472
|
+
}
|
|
2473
|
+
catch {
|
|
2474
|
+
setResolvedFieldName(metaCtx.field.fieldName);
|
|
2475
|
+
}
|
|
2476
|
+
}
|
|
2477
|
+
else
|
|
2478
|
+
setResolvedFieldName(undefined);
|
|
2479
|
+
})();
|
|
2480
|
+
}, [
|
|
2481
|
+
agentMetadata,
|
|
2482
|
+
editContext?.page,
|
|
2483
|
+
editContext?.contentEditorItem,
|
|
2484
|
+
editContext?.currentItemDescriptor,
|
|
2485
|
+
editContext?.itemsRepository,
|
|
2486
|
+
]);
|
|
2487
|
+
// Helper function to build current context from editor state
|
|
2488
|
+
const buildCurrentContext = useCallback(() => {
|
|
2489
|
+
if (!editContext?.currentItemDescriptor)
|
|
2490
|
+
return null;
|
|
2491
|
+
const item = editContext.currentItemDescriptor;
|
|
2492
|
+
return {
|
|
2493
|
+
items: [
|
|
2494
|
+
{
|
|
2495
|
+
id: item.id,
|
|
2496
|
+
language: item.language,
|
|
2497
|
+
version: item.version,
|
|
2498
|
+
name: editContext?.contentEditorItem?.name,
|
|
2499
|
+
},
|
|
2500
|
+
],
|
|
2501
|
+
components: editContext?.selection?.length && item
|
|
2502
|
+
? editContext.selection.map((componentId) => ({
|
|
2503
|
+
componentId,
|
|
2504
|
+
pageItem: {
|
|
2505
|
+
id: item.id,
|
|
2506
|
+
language: item.language,
|
|
2507
|
+
version: item.version,
|
|
2508
|
+
name: editContext?.contentEditorItem?.name,
|
|
2509
|
+
},
|
|
2510
|
+
}))
|
|
2511
|
+
: undefined,
|
|
2512
|
+
field: fieldsContext?.focusedField?.fieldId &&
|
|
2513
|
+
fieldsContext.focusedField?.item?.id
|
|
2514
|
+
? {
|
|
2515
|
+
fieldId: fieldsContext.focusedField.fieldId,
|
|
2516
|
+
fieldName: fieldsContext.focusedField.fieldName,
|
|
2517
|
+
item: {
|
|
2518
|
+
id: fieldsContext.focusedField.item.id,
|
|
2519
|
+
language: fieldsContext.focusedField.item.language ||
|
|
2520
|
+
editContext?.currentItemDescriptor?.language ||
|
|
2521
|
+
"en",
|
|
2522
|
+
version: fieldsContext.focusedField.item.version ??
|
|
2523
|
+
editContext?.currentItemDescriptor?.version ??
|
|
2524
|
+
0,
|
|
2525
|
+
name: editContext?.contentEditorItem?.name,
|
|
2526
|
+
},
|
|
2527
|
+
}
|
|
2528
|
+
: undefined,
|
|
2529
|
+
};
|
|
2530
|
+
}, [
|
|
2531
|
+
editContext?.currentItemDescriptor,
|
|
2532
|
+
editContext?.selection,
|
|
2533
|
+
editContext?.contentEditorItem?.name,
|
|
2534
|
+
fieldsContext?.focusedField,
|
|
2535
|
+
]);
|
|
2536
|
+
// Live context updates: watch for changes and update agent context when in "live" mode
|
|
2537
|
+
const previousContextRef = useRef("");
|
|
2538
|
+
useEffect(() => {
|
|
2539
|
+
// Get profile from activeProfile or find it in profiles array
|
|
2540
|
+
const normalizedAgentProfileId = agent?.profileId?.toLowerCase();
|
|
2541
|
+
const profile = activeProfile ||
|
|
2542
|
+
profiles.find((p) => p.id?.toLowerCase() === normalizedAgentProfileId);
|
|
2543
|
+
if (!profile)
|
|
2544
|
+
return;
|
|
2545
|
+
const mode = profile.editorContextMode;
|
|
2546
|
+
// Only live mode should auto-update; legacy boolean is treated as "onCreate"
|
|
2547
|
+
const isLiveMode = mode === "live";
|
|
2548
|
+
if (!isLiveMode) {
|
|
2549
|
+
return;
|
|
2550
|
+
}
|
|
2551
|
+
// Extract key values for change detection (inside effect to ensure fresh values)
|
|
2552
|
+
const currentItemKey = editContext?.currentItemDescriptor
|
|
2553
|
+
? `${editContext.currentItemDescriptor.id}-${editContext.currentItemDescriptor.language}-${editContext.currentItemDescriptor.version}`
|
|
2554
|
+
: "";
|
|
2555
|
+
const selectionKey = editContext?.selection?.join(",") || "";
|
|
2556
|
+
const focusedFieldKey = fieldsContext?.focusedField?.fieldId || "";
|
|
2557
|
+
// Create a key for the current context state
|
|
2558
|
+
const contextKey = `${currentItemKey}|${selectionKey}|${focusedFieldKey}`;
|
|
2559
|
+
// Skip if context hasn't actually changed
|
|
2560
|
+
if (contextKey === previousContextRef.current) {
|
|
2561
|
+
return;
|
|
2562
|
+
}
|
|
2563
|
+
// Update the previous context key immediately so we only process each change once
|
|
2564
|
+
previousContextRef.current = contextKey;
|
|
2565
|
+
// Apply the update immediately (no debounce) to avoid missing field changes
|
|
2566
|
+
(async () => {
|
|
2567
|
+
try {
|
|
2568
|
+
const currentCtx = buildCurrentContext();
|
|
2569
|
+
if (!currentCtx) {
|
|
2570
|
+
return;
|
|
2571
|
+
}
|
|
2572
|
+
// Merge with existing metadata to preserve other context (like comments)
|
|
2573
|
+
const existingMeta = agentMetadata || {};
|
|
2574
|
+
const merged = {
|
|
2575
|
+
...existingMeta,
|
|
2576
|
+
items: currentCtx.items ? [...currentCtx.items] : undefined,
|
|
2577
|
+
components: currentCtx.components
|
|
2578
|
+
? [...currentCtx.components]
|
|
2579
|
+
: undefined,
|
|
2580
|
+
field: currentCtx.field ? { ...currentCtx.field } : undefined,
|
|
2581
|
+
};
|
|
2582
|
+
// Remove undefined properties to ensure clean state
|
|
2583
|
+
if (!merged.items || merged.items.length === 0) {
|
|
2584
|
+
delete merged.items;
|
|
2585
|
+
}
|
|
2586
|
+
if (!merged.components || merged.components.length === 0) {
|
|
2587
|
+
delete merged.components;
|
|
2588
|
+
}
|
|
2589
|
+
if (!merged.field) {
|
|
2590
|
+
delete merged.field;
|
|
2591
|
+
}
|
|
2592
|
+
// Always update local metadata so UI reflects context even before agent is saved
|
|
2593
|
+
// Create a fresh object to ensure React detects the change
|
|
2594
|
+
const sanitized = sanitizeAgentMetadata(merged);
|
|
2595
|
+
setAgentMetadata(sanitized ? { ...sanitized } : null);
|
|
2596
|
+
// If the agent exists server-side, persist context as well
|
|
2597
|
+
if (agent?.id && agent.status !== "new") {
|
|
2598
|
+
await updateAgentContext(agent.id, merged);
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
catch (err) {
|
|
2602
|
+
console.error("[Live Context] Failed to update context:", err);
|
|
2603
|
+
}
|
|
2604
|
+
})();
|
|
2605
|
+
}, [
|
|
2606
|
+
agent?.id,
|
|
2607
|
+
agent?.status,
|
|
2608
|
+
agent?.profileId,
|
|
2609
|
+
activeProfile?.editorContextMode,
|
|
2610
|
+
profiles,
|
|
2611
|
+
editContext?.currentItemDescriptor?.id,
|
|
2612
|
+
editContext?.currentItemDescriptor?.language,
|
|
2613
|
+
editContext?.currentItemDescriptor?.version,
|
|
2614
|
+
editContext?.selection,
|
|
2615
|
+
fieldsContext?.focusedField?.fieldId,
|
|
2616
|
+
buildCurrentContext,
|
|
2617
|
+
]);
|
|
2618
|
+
// Stop current execution/stream safely
|
|
2619
|
+
const handleStop = useCallback(async () => {
|
|
2620
|
+
try {
|
|
2621
|
+
setIsWaitingForResponse(false);
|
|
2622
|
+
isWaitingRef.current = false;
|
|
2623
|
+
// Request backend to stop the current execution (does NOT close the agent)
|
|
2624
|
+
if (agentStub?.id) {
|
|
2625
|
+
try {
|
|
2626
|
+
await cancelAgent(agentStub.id);
|
|
2627
|
+
}
|
|
2628
|
+
catch (err) {
|
|
2629
|
+
console.error("Failed to cancel agent on backend:", err);
|
|
2630
|
+
// Continue with UI cleanup even if backend call fails
|
|
2631
|
+
}
|
|
2632
|
+
}
|
|
2633
|
+
// Disconnect from the stream
|
|
2634
|
+
if (abortControllerRef.current) {
|
|
2635
|
+
abortControllerRef.current.abort();
|
|
2636
|
+
abortControllerRef.current = null;
|
|
2637
|
+
}
|
|
2638
|
+
setIsConnecting(false);
|
|
2639
|
+
setIsSubmitting(false);
|
|
2640
|
+
// Mark any in-progress streaming messages as completed in UI
|
|
2641
|
+
setMessages((prev) => {
|
|
2642
|
+
const updated = prev.map((msg) => !msg.isCompleted && msg.messageType === "streaming"
|
|
2643
|
+
? { ...msg, isCompleted: true, messageType: "completed" }
|
|
2644
|
+
: msg);
|
|
2645
|
+
messagesRef.current = updated;
|
|
2646
|
+
return updated;
|
|
2647
|
+
});
|
|
2648
|
+
// Update indicator state
|
|
2649
|
+
resetDotsTimer();
|
|
2650
|
+
}
|
|
2651
|
+
catch (e) {
|
|
2652
|
+
console.error("Failed to stop agent execution", e);
|
|
2653
|
+
}
|
|
2654
|
+
}, [resetDotsTimer]);
|
|
2655
|
+
// Determine effective cost limit from agent, profile, or metadata so the cost display
|
|
2656
|
+
// is visible immediately even before any messages or server-side persistence.
|
|
2657
|
+
let effectiveCostLimit;
|
|
2658
|
+
try {
|
|
2659
|
+
const candidates = [
|
|
2660
|
+
agent?.costLimit,
|
|
2661
|
+
activeProfile?.costLimit,
|
|
2662
|
+
];
|
|
2663
|
+
for (const c of candidates) {
|
|
2664
|
+
const n = c != null ? Number(c) : 0;
|
|
2665
|
+
if (Number.isFinite(n) && n > 0) {
|
|
2666
|
+
effectiveCostLimit = n;
|
|
2667
|
+
break;
|
|
2668
|
+
}
|
|
2669
|
+
}
|
|
2670
|
+
}
|
|
2671
|
+
catch { }
|
|
2672
|
+
if (effectiveCostLimit === undefined) {
|
|
2673
|
+
effectiveCostLimit = undefined;
|
|
2674
|
+
}
|
|
2675
|
+
// Calculate total token usage for cost display
|
|
2676
|
+
const totalTokens = calculateTotalTokens(messages);
|
|
2677
|
+
// Determine if the agent is actively executing (submitting, connecting, waiting, or streaming)
|
|
2678
|
+
const isExecuting = isSubmitting ||
|
|
2679
|
+
isConnecting ||
|
|
2680
|
+
isWaitingForResponse ||
|
|
2681
|
+
hasActiveStreaming();
|
|
2682
|
+
// Move useMemo hook before early return to comply with Rules of Hooks
|
|
2683
|
+
const isLiveEditorContextMode = React.useMemo(() => {
|
|
2684
|
+
try {
|
|
2685
|
+
const normalizedAgentProfileId = agent?.profileId?.toLowerCase();
|
|
2686
|
+
const profile = activeProfile ||
|
|
2687
|
+
profiles.find((p) => p.id?.toLowerCase() === normalizedAgentProfileId);
|
|
2688
|
+
const mode = profile?.editorContextMode;
|
|
2689
|
+
return mode === "live";
|
|
2690
|
+
}
|
|
2691
|
+
catch {
|
|
2692
|
+
return false;
|
|
2693
|
+
}
|
|
2694
|
+
}, [activeProfile, profiles, agent?.profileId]);
|
|
2695
|
+
if (isLoading) {
|
|
2696
|
+
return (_jsx("div", { className: "flex h-full items-center justify-center", children: _jsxs("div", { className: "flex items-center gap-2 text-xs text-gray-500", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin", strokeWidth: 1 }), "Loading agent..."] }) }));
|
|
2697
|
+
}
|
|
2698
|
+
const renderContextInfoBar = () => (_jsx(ContextInfoBar, { agent: agent, agentMetadata: agentMetadata, setAgentMetadata: setAgentMetadata, setAgent: setAgent, resolvedPageName: resolvedPageName, resolvedComponentName: resolvedComponentName, resolvedFieldName: resolvedFieldName, isLiveEditorContextMode: isLiveEditorContextMode, activeProfile: activeProfile }));
|
|
2699
|
+
const renderCostLimitBanner = () => {
|
|
2700
|
+
if (!costLimitExceeded)
|
|
2701
|
+
return null;
|
|
2702
|
+
const { totalCost, costLimit, initialCostLimit } = costLimitExceeded;
|
|
2703
|
+
return (_jsxs("div", { className: "m-3 rounded border border-amber-300 bg-amber-50 p-3 text-xs text-amber-900", children: [_jsxs("div", { className: "mb-2 flex items-center gap-2", children: [_jsx(AlertCircle, { className: "h-4 w-4 text-amber-500", strokeWidth: 1 }), _jsxs("span", { children: ["Cost limit exceeded. Spent $", totalCost.toFixed(2), " / $", costLimit.toFixed(2), "."] })] }), _jsx("div", { className: "flex gap-2", children: _jsx("button", { className: "rounded border border-amber-300 bg-white px-2 py-1 hover:bg-amber-100", onClick: async () => {
|
|
2704
|
+
if (!agent?.id)
|
|
2705
|
+
return;
|
|
2706
|
+
try {
|
|
2707
|
+
// Extend cost limit - backend will automatically resume the agent
|
|
2708
|
+
const result = await updateAgentCostLimit(agent.id, "extend");
|
|
2709
|
+
// Update the agent's cost limit in local state
|
|
2710
|
+
if (result.success && result.costLimit !== undefined) {
|
|
2711
|
+
setAgent((prev) => prev ? { ...prev, costLimit: result.costLimit } : prev);
|
|
2712
|
+
}
|
|
2713
|
+
// Clear the banner and set waiting state
|
|
2714
|
+
// Agent will resume automatically via backend's ResumeAgentAsync
|
|
2715
|
+
setCostLimitExceeded(null);
|
|
2716
|
+
setIsWaitingForResponse(true);
|
|
2717
|
+
isWaitingRef.current = true;
|
|
2718
|
+
setShouldAutoScroll(true);
|
|
2719
|
+
}
|
|
2720
|
+
catch (e) {
|
|
2721
|
+
console.error("Failed to extend cost limit:", e);
|
|
2722
|
+
setError(e instanceof Error
|
|
2723
|
+
? e.message
|
|
2724
|
+
: "Failed to extend cost limit");
|
|
2725
|
+
}
|
|
2726
|
+
}, children: "Extend limit and continue" }) })] }));
|
|
2727
|
+
};
|
|
2728
|
+
const renderErrorBanner = () => {
|
|
2729
|
+
const currentAgent = agent || agentStub;
|
|
2730
|
+
const isErrorStatus = currentAgent?.status === "error" || currentAgent?.status === 4;
|
|
2731
|
+
const errorMessage = currentAgent?.statusMessage;
|
|
2732
|
+
if (!isErrorStatus || !errorMessage)
|
|
2733
|
+
return null;
|
|
2734
|
+
return (_jsx("div", { className: "m-3 rounded border border-red-300 bg-red-50 p-3 text-xs text-red-900", children: _jsxs("div", { className: "flex items-start gap-2", children: [_jsx(AlertCircle, { className: "mt-0.5 h-4 w-4 flex-shrink-0 text-red-500", strokeWidth: 1 }), _jsxs("div", { className: "flex-1", children: [_jsx("div", { className: "mb-1 font-semibold", children: "Agent Error" }), _jsx("div", { className: "text-red-800", children: errorMessage })] })] }) }));
|
|
2735
|
+
};
|
|
2736
|
+
return (_jsxs("div", { className: `flex h-full flex-col ${className || ""}`, children: [_jsxs("div", { ref: messagesContainerRef, className: "flex-1 overflow-y-auto", onScroll: handleScroll, children: [error && (_jsx("div", { className: "m-4 rounded-lg border-l-4 border-red-500 bg-red-50 p-3 select-text", children: _jsxs("div", { className: "flex items-start", children: [_jsx(AlertCircle, { className: "mt-0.5 h-5 w-5 text-red-400", strokeWidth: 1 }), _jsxs("div", { className: "ml-3", children: [_jsx("p", { className: "text-sm font-medium text-red-800", children: "Error" }), _jsx("p", { className: "mt-1 text-sm text-red-700", children: error })] })] }) })), messages.length === 0 && !error && !hideGreeting && (_jsx("div", { className: "flex h-full items-center justify-center p-8", children: _jsx("div", { className: "max-w-prose text-center", children: !activeProfile ? (_jsx(Loader2, { className: "mx-auto h-8 w-8 animate-spin text-gray-400" })) : (_jsxs(_Fragment, { children: [activeProfile.svgIcon ? (_jsx("div", { className: "mx-auto mb-4 flex h-24 w-24 items-center justify-center text-gray-400 [&>svg]:h-full [&>svg]:w-full", dangerouslySetInnerHTML: {
|
|
2737
|
+
__html: activeProfile.svgIcon,
|
|
2738
|
+
} })) : (_jsx(SecretAgentIcon, { size: 96, strokeWidth: 1, className: "mx-auto mb-4 text-gray-400" })), activeProfile.greetingMessage ? (_jsx(ViewTransition, { children: _jsx("div", { className: "prose prose-sm mx-auto text-center", dangerouslySetInnerHTML: {
|
|
2739
|
+
__html: activeProfile.greetingMessage,
|
|
2740
|
+
} }) })) : (_jsxs(_Fragment, { children: [_jsx("h3", { className: "mb-2 text-lg font-medium text-gray-900", children: "Start a conversation" }), _jsx("p", { className: "mb-4 text-sm text-gray-500", children: "Send a message to begin working with your AI agent." }), _jsx("div", { className: "text-xs text-gray-400", children: "Your agent can help with content editing, research, and automation tasks." })] }))] })) }) })), renderErrorBanner(), _jsx("div", { className: "space-y-0 divide-y divide-gray-100 select-text", children: groupConsecutiveMessages(messages).map((group, groupIndex) => {
|
|
2741
|
+
if (group.type === "user" && group.messages[0]) {
|
|
2742
|
+
// Render user message
|
|
2743
|
+
return (_jsx(UserMessage, { message: group.messages[0] }, groupIndex));
|
|
2744
|
+
}
|
|
2745
|
+
else {
|
|
2746
|
+
// Render bundled assistant messages
|
|
2747
|
+
// Check if this group contains any streaming message
|
|
2748
|
+
const hasStreamingMessage = group.messages.some((msg) => !msg.isCompleted && msg.messageType === "streaming");
|
|
2749
|
+
// Filter out cost limit error messages (they're shown in the banner instead)
|
|
2750
|
+
const filteredMessages = group.messages.filter((msg) => {
|
|
2751
|
+
const content = msg.content || "";
|
|
2752
|
+
// Skip messages that are cost limit errors (shown in banner instead)
|
|
2753
|
+
return (!content.startsWith("⚠️") || !content.includes("Cost limit"));
|
|
2754
|
+
});
|
|
2755
|
+
// If all messages were filtered out, don't render this group
|
|
2756
|
+
if (filteredMessages.length === 0) {
|
|
2757
|
+
return null;
|
|
2758
|
+
}
|
|
2759
|
+
const convertedMessages = convertAgentMessagesToAiFormat(filteredMessages);
|
|
2760
|
+
return (_jsx(AiResponseMessage, { messages: convertedMessages, finished: !isSubmitting && !isConnecting, editOperations: [], error: error || undefined, profileSvgIcon: activeProfile?.svgIcon, agentId: agent?.id || agentStub.id, agentName: activeProfile?.name, onQuickAction: (action) => {
|
|
2761
|
+
const text = (action.prompt ||
|
|
2762
|
+
action.value ||
|
|
2763
|
+
action.label ||
|
|
2764
|
+
"").trim();
|
|
2765
|
+
if (!text)
|
|
2766
|
+
return;
|
|
2767
|
+
// Check if text contains placeholders ({placeholder} or <placeholder>)
|
|
2768
|
+
const hasPlaceholders = /\{([^}]+)\}|<([^>]+)>/.test(text);
|
|
2769
|
+
if (hasPlaceholders) {
|
|
2770
|
+
// Show placeholder input
|
|
2771
|
+
setActivePlaceholderInput({
|
|
2772
|
+
text,
|
|
2773
|
+
behavior: action.behavior,
|
|
2774
|
+
});
|
|
2775
|
+
return;
|
|
2776
|
+
}
|
|
2777
|
+
if (action.behavior === "compose") {
|
|
2778
|
+
setPrompt(text);
|
|
2779
|
+
setInputPlaceholder(action.placeholder ||
|
|
2780
|
+
"Review and edit, then press Enter to send");
|
|
2781
|
+
if (textareaRef.current) {
|
|
2782
|
+
try {
|
|
2783
|
+
textareaRef.current.focus();
|
|
2784
|
+
const v = textareaRef.current.value || "";
|
|
2785
|
+
textareaRef.current.selectionStart = v.length;
|
|
2786
|
+
textareaRef.current.selectionEnd = v.length;
|
|
2787
|
+
}
|
|
2788
|
+
catch { }
|
|
2789
|
+
}
|
|
2790
|
+
return;
|
|
2791
|
+
}
|
|
2792
|
+
// Stop any current execution before sending the next message
|
|
2793
|
+
if (isExecuting) {
|
|
2794
|
+
try {
|
|
2795
|
+
handleStop();
|
|
2796
|
+
}
|
|
2797
|
+
catch { }
|
|
2798
|
+
}
|
|
2799
|
+
sendQuickMessage(text);
|
|
2800
|
+
} }, groupIndex));
|
|
2801
|
+
}
|
|
2802
|
+
}) }), messages.length > 0 && (_jsx("div", { className: showDots ? "visible" : "invisible", children: _jsx(DancingDots, {}) })), renderCostLimitBanner(), _jsx("div", { ref: messagesEndRef })] }), !hideContext && renderContextInfoBar(), !hideContext && agent?.id && activeProfile && (_jsx(AgentDocumentList, { agentId: agent.id, maxFileSizeMB: activeProfile.maxDocumentSizeMB ?? 10, enabled: activeProfile.enableDocumentUpload ?? false, profileId: activeProfile.id }, `${agent.id}-${agent.updatedDate || ""}-${activeProfile.id}`)), !hideContext && (_jsx(TodoListPanel, { messages: messages, agentMetadata: agentMetadata })), queuedPrompts.length > 0 && (_jsx("div", { className: "border-t border-gray-200 bg-amber-50/50", children: _jsxs("div", { className: "px-4 pt-3 pb-2", children: [_jsxs("div", { className: "mb-2 flex items-center gap-2", children: [_jsx("div", { className: "h-2 w-2 animate-pulse rounded-full bg-amber-500" }), _jsxs("span", { className: "text-xs font-semibold text-amber-900", children: ["Queued Messages (", queuedPrompts.length, ")"] })] }), _jsx("div", { className: "space-y-2", children: queuedPrompts.map((qp) => (_jsx("div", { className: "rounded-md border border-amber-200 bg-white p-2.5 text-xs", children: _jsx("div", { className: "flex items-start justify-between gap-2", children: _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "mb-1 flex items-center gap-1.5", children: qp.sourceAgentName ? (_jsxs(_Fragment, { children: [_jsxs("span", { className: "font-medium text-gray-700", children: ["From ", qp.sourceAgentName] }), qp.priority > 5 && (_jsx("span", { className: "rounded bg-red-100 px-1.5 py-0.5 text-[10px] font-medium text-red-700", children: "High Priority" }))] })) : (_jsx("span", { className: "font-medium text-gray-700", children: "From User" })) }), _jsx("div", { className: "break-words whitespace-pre-wrap text-gray-600", children: qp.prompt }), qp.createdDate && (_jsx("div", { className: "mt-1.5 text-[10px] text-gray-400", children: formatTime(new Date(qp.createdDate)) }))] }) }) }, qp.id))) })] }) })), _jsxs("div", { className: "border-t border-gray-200 p-4", children: [activePlaceholderInput ? (
|
|
2803
|
+
// Placeholder Input (from quick actions)
|
|
2804
|
+
_jsx(PlaceholderInput, { text: activePlaceholderInput.text, showButtons: false, onComplete: (filledText) => {
|
|
2805
|
+
setActivePlaceholderInput(null);
|
|
2806
|
+
if (activePlaceholderInput.behavior === "compose") {
|
|
2807
|
+
setPrompt(filledText);
|
|
2808
|
+
setInputPlaceholder("Review and edit, then press Enter to send");
|
|
2809
|
+
if (textareaRef.current) {
|
|
2810
|
+
try {
|
|
2811
|
+
textareaRef.current.focus();
|
|
2812
|
+
const v = textareaRef.current.value || "";
|
|
2813
|
+
textareaRef.current.selectionStart = v.length;
|
|
2814
|
+
textareaRef.current.selectionEnd = v.length;
|
|
2815
|
+
}
|
|
2816
|
+
catch { }
|
|
2817
|
+
}
|
|
2818
|
+
}
|
|
2819
|
+
else {
|
|
2820
|
+
// Submit behavior or default
|
|
2821
|
+
if (isExecuting) {
|
|
2822
|
+
try {
|
|
2823
|
+
handleStop();
|
|
2824
|
+
}
|
|
2825
|
+
catch { }
|
|
2826
|
+
}
|
|
2827
|
+
sendQuickMessage(filledText);
|
|
2828
|
+
}
|
|
2829
|
+
}, onCancel: () => {
|
|
2830
|
+
setActivePlaceholderInput(null);
|
|
2831
|
+
} })) : prompt && /\{([^}]+)\}|<([^>]+)>/.test(prompt) ? (
|
|
2832
|
+
// Template mode: show PlaceholderInput when prompt contains placeholders
|
|
2833
|
+
_jsx(PlaceholderInput, { text: prompt, showButtons: false, onComplete: (filledText) => {
|
|
2834
|
+
setPrompt(filledText);
|
|
2835
|
+
// Auto-submit after filling placeholders
|
|
2836
|
+
if (filledText.trim()) {
|
|
2837
|
+
if (isExecuting) {
|
|
2838
|
+
try {
|
|
2839
|
+
handleStop();
|
|
2840
|
+
}
|
|
2841
|
+
catch { }
|
|
2842
|
+
}
|
|
2843
|
+
sendQuickMessage(filledText);
|
|
2844
|
+
}
|
|
2845
|
+
}, onCancel: () => {
|
|
2846
|
+
setPrompt("");
|
|
2847
|
+
setInputPlaceholder("Type your message... (Enter to send, Shift+Enter or Ctrl+Enter for new line)");
|
|
2848
|
+
} })) : (_jsx("div", { className: "flex items-stretch gap-2", children: _jsx(Textarea, { ref: textareaRef, value: prompt, onChange: (e) => {
|
|
2849
|
+
setPrompt(e.target.value);
|
|
2850
|
+
// Reset history index when user starts typing
|
|
2851
|
+
if (currentHistoryIndex !== -1) {
|
|
2852
|
+
setCurrentHistoryIndex(-1);
|
|
2853
|
+
}
|
|
2854
|
+
}, onKeyDown: handleKeyPress, placeholder: inputPlaceholder, className: "h-[80px] flex-1 resize-none overflow-y-auto text-xs", "data-testid": "agent-terminal-prompt", disabled: isSubmitting }) })), !hideBottomControls && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-stretch justify-between gap-2", children: [_jsxs("div", { className: "mt-2 flex flex-wrap items-center justify-start gap-2", children: [_jsxs(Tooltip, { delayDuration: 400, children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("select", { className: `h-5 rounded border px-1.5 text-[10px] ${mode === "read-only"
|
|
2855
|
+
? "border-green-300 bg-green-50 text-green-700"
|
|
2856
|
+
: mode === "supervised"
|
|
2857
|
+
? "border-amber-300 bg-amber-50 text-amber-700"
|
|
2858
|
+
: "border-red-300 bg-red-50 text-red-700"}`, value: mode, onChange: async (e) => {
|
|
2859
|
+
const nextMode = e.target.value || "supervised";
|
|
2860
|
+
// Optimistic UI update
|
|
2861
|
+
setMode(nextMode);
|
|
2862
|
+
const current = agentMetadata || {};
|
|
2863
|
+
const nextMeta = {
|
|
2864
|
+
...current,
|
|
2865
|
+
mode: nextMode,
|
|
2866
|
+
};
|
|
2867
|
+
try {
|
|
2868
|
+
if (!agent?.id || agent.status === "new") {
|
|
2869
|
+
setAgentMetadata(nextMeta);
|
|
2870
|
+
// Cache until first start when agent is persisted
|
|
2871
|
+
pendingSettingsRef.current = {
|
|
2872
|
+
...(pendingSettingsRef.current || {}),
|
|
2873
|
+
mode: nextMode,
|
|
2874
|
+
};
|
|
2875
|
+
return;
|
|
2876
|
+
}
|
|
2877
|
+
await updateAgentSettings(agent.id, {
|
|
2878
|
+
mode: nextMode,
|
|
2879
|
+
});
|
|
2880
|
+
setAgentMetadata(nextMeta);
|
|
2881
|
+
setAgent((prev) => prev
|
|
2882
|
+
? { ...prev, metadata: JSON.stringify(nextMeta) }
|
|
2883
|
+
: prev);
|
|
2884
|
+
}
|
|
2885
|
+
catch (e2) {
|
|
2886
|
+
console.error("Failed to persist mode change", e2);
|
|
2887
|
+
}
|
|
2888
|
+
}, title: "Mode", "aria-label": "Mode", "data-testid": "agent-mode-select", children: [_jsx("option", { value: "supervised", children: "Supervised" }), _jsx("option", { value: "autonomous", children: "Autonomous" }), _jsx("option", { value: "read-only", children: "Read-Only" })] }) }), _jsx(TooltipContent, { side: "top", sideOffset: 6, children: _jsxs("div", { className: "max-w-[320px] space-y-1", children: [_jsxs("div", { children: [_jsx("span", { className: "font-semibold text-green-500", children: "Read-Only" }), ": Limited tool access as configured by the profile (Ask Mode Tools)."] }), _jsxs("div", { children: [_jsx("span", { className: "font-semibold text-amber-500", children: "Supervised" }), ": Full tool access, but writes are limited to pages/items in the current context. Creating new items or updating existing items outside the current context requires explicit approval."] }), _jsxs("div", { children: [_jsx("span", { className: "font-semibold text-red-500", children: "Autonomous" }), ": Full tool access; can write across the site/project only limited by user permissions."] })] }) })] }), profiles?.length > 0 && (_jsx("select", { className: "h-5 rounded border px-1.5 text-[10px] text-gray-500", value: activeProfile?.id || "", onChange: async (e) => {
|
|
2889
|
+
const nextProfile = profiles.find((x) => x.id === e.target.value);
|
|
2890
|
+
if (!nextProfile)
|
|
2891
|
+
return;
|
|
2892
|
+
setActiveProfile(nextProfile);
|
|
2893
|
+
try {
|
|
2894
|
+
if (agent?.id && agent.status !== "new") {
|
|
2895
|
+
await updateAgentSettings(agent.id, {
|
|
2896
|
+
profileId: nextProfile.id,
|
|
2897
|
+
profileName: nextProfile.name,
|
|
2898
|
+
});
|
|
2899
|
+
}
|
|
2900
|
+
else {
|
|
2901
|
+
// cache until first start
|
|
2902
|
+
pendingSettingsRef.current = {
|
|
2903
|
+
...(pendingSettingsRef.current || {}),
|
|
2904
|
+
// we cache profile by updating local metadata
|
|
2905
|
+
};
|
|
2906
|
+
setAgentMetadata((current) => {
|
|
2907
|
+
const next = { ...(current || {}) };
|
|
2908
|
+
next.profile = nextProfile.name;
|
|
2909
|
+
next.additionalData = {
|
|
2910
|
+
...(next.additionalData || {}),
|
|
2911
|
+
profileId: nextProfile.id,
|
|
2912
|
+
profileName: nextProfile.name,
|
|
2913
|
+
};
|
|
2914
|
+
return next;
|
|
2915
|
+
});
|
|
2916
|
+
}
|
|
2917
|
+
// reflect in local agent stub so tabs and titles can use it if needed
|
|
2918
|
+
setAgent((prev) => prev
|
|
2919
|
+
? {
|
|
2920
|
+
...prev,
|
|
2921
|
+
metadata: JSON.stringify({
|
|
2922
|
+
...(agentMetadata || {}),
|
|
2923
|
+
profile: nextProfile.name,
|
|
2924
|
+
additionalData: {
|
|
2925
|
+
...(agentMetadata
|
|
2926
|
+
?.additionalData || {}),
|
|
2927
|
+
profileId: nextProfile.id,
|
|
2928
|
+
profileName: nextProfile.name,
|
|
2929
|
+
},
|
|
2930
|
+
}),
|
|
2931
|
+
}
|
|
2932
|
+
: prev);
|
|
2933
|
+
}
|
|
2934
|
+
catch (err) {
|
|
2935
|
+
console.error("Failed to persist agent profile", err);
|
|
2936
|
+
}
|
|
2937
|
+
}, title: "Profile", "aria-label": "Profile", "data-testid": "agent-profile-select", children: profiles.map((p) => (_jsx("option", { value: p.id, children: p.name }, p.id))) })), activeProfile?.models?.length ? (_jsx("select", { className: "h-5 rounded border px-1.5 text-[10px] text-gray-500", value: selectedModelId || "", onChange: async (e) => {
|
|
2938
|
+
const nextId = e.target.value;
|
|
2939
|
+
setSelectedModelId(nextId);
|
|
2940
|
+
const modelName = activeProfile?.models?.find((m) => m.id === nextId)
|
|
2941
|
+
?.name || "";
|
|
2942
|
+
// Update local agent state immediately for UX and to reflect in streaming stub
|
|
2943
|
+
setAgent((prev) => prev ? { ...prev, model: modelName } : prev);
|
|
2944
|
+
// Persist only for existing agents; otherwise cache until first start
|
|
2945
|
+
try {
|
|
2946
|
+
if (agent?.id && agent.status !== "new") {
|
|
2947
|
+
await updateAgentSettings(agent.id, {
|
|
2948
|
+
model: modelName,
|
|
2949
|
+
});
|
|
2950
|
+
}
|
|
2951
|
+
else {
|
|
2952
|
+
pendingSettingsRef.current = {
|
|
2953
|
+
...(pendingSettingsRef.current || {}),
|
|
2954
|
+
modelName,
|
|
2955
|
+
};
|
|
2956
|
+
}
|
|
2957
|
+
}
|
|
2958
|
+
catch (err) {
|
|
2959
|
+
console.error("Failed to persist agent model", err);
|
|
2960
|
+
}
|
|
2961
|
+
}, title: "Model", "aria-label": "Model", "data-testid": "agent-model-select", children: activeProfile.models.map((m) => (_jsx("option", { value: m.id, children: m.name }, m.id))) })) : null, activeProfile?.prompts?.length ? (_jsxs(Popover, { open: showPredefined, onOpenChange: setShowPredefined, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx("button", { className: "rounded p-1 hover:bg-gray-100", onClick: () => { }, title: "Predefined prompts", "aria-label": "Predefined prompts", children: _jsx(Wand2, { className: "h-3 w-3", strokeWidth: 1 }) }) }), _jsx(PopoverContent, { className: "w-64 p-0", align: "start", children: _jsx("div", { className: "max-h-56 overflow-y-auto p-2", children: activeProfile.prompts.map((p, index) => (_jsx("div", { className: "cursor-pointer rounded p-1.5 text-xs text-gray-700 hover:bg-gray-100", onClick: () => {
|
|
2962
|
+
setPrompt(p.prompt);
|
|
2963
|
+
setShowPredefined(false);
|
|
2964
|
+
if (textareaRef.current)
|
|
2965
|
+
textareaRef.current.focus();
|
|
2966
|
+
}, children: p.title }, index))) }) })] })) : null] }), _jsxs("div", { className: "flex items-center gap-1 self-end", children: [isVoiceSupported ? (_jsx(Button, { onClick: toggleVoice, size: "sm", className: "h-5.5 w-5.5 cursor-pointer rounded-full", title: isListening ? "Stop voice input" : "Start voice input", "aria-label": isListening ? "Stop voice input" : "Start voice input", "aria-pressed": isListening, children: isListening ? (_jsx(MicOff, { className: "size-3", strokeWidth: 1 })) : (_jsx(Mic, { className: "size-3", strokeWidth: 1 })) })) : null, _jsx(Button, { onClick: isExecuting ? handleStop : handleSubmit, disabled: !isExecuting && !prompt.trim(), size: "sm", className: "h-5.5 w-5.5 cursor-pointer rounded-full", title: isExecuting ? "Stop" : "Send", "aria-label": isExecuting ? "Stop" : "Send", "data-testid": "agent-send-stop-button", "data-executing": isExecuting ? "true" : "false", children: isExecuting ? (_jsx(Square, { className: "size-3", strokeWidth: 1 })) : (_jsx(Send, { className: "size-3", strokeWidth: 1 })) })] })] }), _jsxs("div", { className: "mt-1 flex items-center gap-2 text-[10px] text-gray-500", children: [_jsx(AgentCostDisplay, { totalTokens: liveTotals
|
|
2967
|
+
? {
|
|
2968
|
+
input: liveTotals.input,
|
|
2969
|
+
output: liveTotals.output,
|
|
2970
|
+
cached: liveTotals.cached,
|
|
2971
|
+
cacheWrite: liveTotals.cacheWrite ?? 0,
|
|
2972
|
+
inputCost: liveTotals.inputCost,
|
|
2973
|
+
outputCost: liveTotals.outputCost,
|
|
2974
|
+
cachedCost: liveTotals.cachedCost,
|
|
2975
|
+
cacheWriteCost: liveTotals.cacheWriteCost ?? 0,
|
|
2976
|
+
totalCost: liveTotals.totalCost,
|
|
2977
|
+
}
|
|
2978
|
+
: totalTokens, costLimit: effectiveCostLimit }), (() => {
|
|
2979
|
+
try {
|
|
2980
|
+
const s = window.__agentContextWindowStatus;
|
|
2981
|
+
if (!s || !s.contextWindowTokens)
|
|
2982
|
+
return null;
|
|
2983
|
+
const pct = typeof s.contextUsedPercent === "number"
|
|
2984
|
+
? `${s.contextUsedPercent.toFixed(1)}%`
|
|
2985
|
+
: undefined;
|
|
2986
|
+
// Helper function to format tokens as "k"
|
|
2987
|
+
const formatTokens = (tokens) => {
|
|
2988
|
+
if (tokens >= 1000) {
|
|
2989
|
+
return `${(tokens / 1000).toFixed(1)}k`;
|
|
2990
|
+
}
|
|
2991
|
+
return tokens.toString();
|
|
2992
|
+
};
|
|
2993
|
+
if (!pct)
|
|
2994
|
+
return null;
|
|
2995
|
+
return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "cursor-help rounded border border-gray-200 bg-gray-50 px-2 py-0.5", children: ["Context: ", pct] }) }), _jsx(TooltipContent, { side: "top", sideOffset: 6, children: _jsxs("div", { className: "max-w-[320px] space-y-1 text-xs", children: [_jsxs("div", { children: [_jsx("span", { className: "font-semibold", children: "Model:" }), " ", s.model, s.normalizedModel && ` (${s.normalizedModel})`] }), _jsxs("div", { children: [_jsx("span", { className: "font-semibold", children: "Context window:" }), " ", formatTokens(s.estimatedInputTokens || 0), " /", " ", formatTokens(s.contextWindowTokens), " tokens"] }), typeof s.maxCompletionTokens === "number" && (_jsxs("div", { children: [_jsx("span", { className: "font-semibold", children: "Max completion:" }), " ", formatTokens(s.maxCompletionTokens), " tokens"] })), _jsxs("div", { children: [_jsx("span", { className: "font-semibold", children: "Used:" }), " ", pct] })] }) })] }));
|
|
2996
|
+
}
|
|
2997
|
+
catch {
|
|
2998
|
+
return null;
|
|
2999
|
+
}
|
|
3000
|
+
})(), activeProfile && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: "flex items-center gap-1 text-gray-400 hover:text-gray-600", onClick: async () => {
|
|
3001
|
+
if (!editContext || !activeProfile?.id)
|
|
3002
|
+
return;
|
|
3003
|
+
// Load the profile item using editContext
|
|
3004
|
+
const lang = editContext?.currentItemDescriptor?.language || "en";
|
|
3005
|
+
await editContext.loadItem({
|
|
3006
|
+
id: activeProfile.id,
|
|
3007
|
+
language: lang,
|
|
3008
|
+
version: 0,
|
|
3009
|
+
});
|
|
3010
|
+
}, children: [_jsx("span", { className: "max-w-[100px] truncate", children: activeProfile.name }), _jsx(ExternalLink, { className: "h-2.5 w-2.5 shrink-0", strokeWidth: 1.5 })] }) }), _jsx(TooltipContent, { side: "top", sideOffset: 6, children: "Open profile settings" })] }))] })] }))] })] }));
|
|
3011
|
+
}
|
|
3012
|
+
//# sourceMappingURL=AgentTerminal.js.map
|