@vertesia/ui 1.4.0-dev.20260615.042549Z → 1.4.0-dev.20260629.130134Z
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/lib/core/components/shadcn/dropdown.d.ts.map +1 -1
- package/lib/core/components/shadcn/dropdown.js +6 -2
- package/lib/core/components/shadcn/dropdown.js.map +1 -1
- package/lib/core/components/shadcn/filters/filterBar.d.ts.map +1 -1
- package/lib/core/components/shadcn/filters/filterBar.js +9 -2
- package/lib/core/components/shadcn/filters/filterBar.js.map +1 -1
- package/lib/core/components/shadcn/modal/ConfirmModal.d.ts +16 -1
- package/lib/core/components/shadcn/modal/ConfirmModal.d.ts.map +1 -1
- package/lib/core/components/shadcn/modal/ConfirmModal.js +25 -3
- package/lib/core/components/shadcn/modal/ConfirmModal.js.map +1 -1
- package/lib/core/components/shadcn/modal/dialog.js +1 -1
- package/lib/core/components/shadcn/modal/dialog.js.map +1 -1
- package/lib/core/components/shadcn/popover.d.ts.map +1 -1
- package/lib/core/components/shadcn/popover.js +3 -1
- package/lib/core/components/shadcn/popover.js.map +1 -1
- package/lib/core/components/shadcn/switch.js +3 -3
- package/lib/core/components/shadcn/switch.js.map +1 -1
- package/lib/core/components/shadcn/tabs.js +1 -1
- package/lib/core/components/shadcn/tabs.js.map +1 -1
- package/lib/core/components/shadcn/tooltip.d.ts.map +1 -1
- package/lib/core/components/shadcn/tooltip.js +3 -1
- package/lib/core/components/shadcn/tooltip.js.map +1 -1
- package/lib/env/index.d.ts +0 -19
- package/lib/env/index.d.ts.map +1 -1
- package/lib/env/index.js +0 -6
- package/lib/env/index.js.map +1 -1
- package/lib/features/agent/PayloadBuilder.d.ts +4 -0
- package/lib/features/agent/PayloadBuilder.d.ts.map +1 -1
- package/lib/features/agent/PayloadBuilder.js +16 -0
- package/lib/features/agent/PayloadBuilder.js.map +1 -1
- package/lib/features/agent/chat/AgentApprovalModeSelector.d.ts +10 -0
- package/lib/features/agent/chat/AgentApprovalModeSelector.d.ts.map +1 -0
- package/lib/features/agent/chat/AgentApprovalModeSelector.js +50 -0
- package/lib/features/agent/chat/AgentApprovalModeSelector.js.map +1 -0
- package/lib/features/agent/chat/AgentChatFixtureReplay.d.ts +2 -1
- package/lib/features/agent/chat/AgentChatFixtureReplay.d.ts.map +1 -1
- package/lib/features/agent/chat/AgentChatFixtureReplay.js +3 -3
- package/lib/features/agent/chat/AgentChatFixtureReplay.js.map +1 -1
- package/lib/features/agent/chat/AgentRequestInputOverlay.d.ts +5 -2
- package/lib/features/agent/chat/AgentRequestInputOverlay.d.ts.map +1 -1
- package/lib/features/agent/chat/AgentRequestInputOverlay.js +41 -7
- package/lib/features/agent/chat/AgentRequestInputOverlay.js.map +1 -1
- package/lib/features/agent/chat/AgentRightPanel.d.ts.map +1 -1
- package/lib/features/agent/chat/AgentRightPanel.js +133 -12
- package/lib/features/agent/chat/AgentRightPanel.js.map +1 -1
- package/lib/features/agent/chat/AnimatedThinkingDots.js +1 -1
- package/lib/features/agent/chat/AnimatedThinkingDots.js.map +1 -1
- package/lib/features/agent/chat/ArtifactsTab.d.ts.map +1 -1
- package/lib/features/agent/chat/ArtifactsTab.js +11 -65
- package/lib/features/agent/chat/ArtifactsTab.js.map +1 -1
- package/lib/features/agent/chat/AskUserWidget.d.ts +3 -1
- package/lib/features/agent/chat/AskUserWidget.d.ts.map +1 -1
- package/lib/features/agent/chat/AskUserWidget.js +4 -3
- package/lib/features/agent/chat/AskUserWidget.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentConversation.d.ts +10 -2
- package/lib/features/agent/chat/ModernAgentConversation.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentConversation.js +526 -117
- package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.d.ts +8 -0
- package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.d.ts.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.js +19 -0
- package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.js.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts +8 -2
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +551 -92
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.js +7 -6
- package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/Header.js +2 -2
- package/lib/features/agent/chat/ModernAgentOutput/Header.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageDeliveryStatus.d.ts +8 -0
- package/lib/features/agent/chat/ModernAgentOutput/MessageDeliveryStatus.d.ts.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/MessageDeliveryStatus.js +61 -0
- package/lib/features/agent/chat/ModernAgentOutput/MessageDeliveryStatus.js.map +1 -0
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.d.ts +15 -2
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js +28 -38
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js +3 -2
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/SlideInPanel.js +2 -1
- package/lib/features/agent/chat/ModernAgentOutput/SlideInPanel.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/SlidingMessages.js +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/SlidingMessages.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.d.ts +5 -0
- package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.js +59 -4
- package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/WorkstreamTabs.js +2 -2
- package/lib/features/agent/chat/ModernAgentOutput/WorkstreamTabs.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.d.ts +9 -0
- package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.js +180 -0
- package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/utils.d.ts +6 -0
- package/lib/features/agent/chat/ModernAgentOutput/utils.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/utils.js +92 -2
- package/lib/features/agent/chat/ModernAgentOutput/utils.js.map +1 -1
- package/lib/features/agent/chat/clipboardFiles.d.ts +15 -0
- package/lib/features/agent/chat/clipboardFiles.d.ts.map +1 -0
- package/lib/features/agent/chat/clipboardFiles.js +35 -0
- package/lib/features/agent/chat/clipboardFiles.js.map +1 -0
- package/lib/features/agent/chat/hooks/useAgentStream.d.ts +6 -0
- package/lib/features/agent/chat/hooks/useAgentStream.d.ts.map +1 -1
- package/lib/features/agent/chat/hooks/useAgentStream.js +218 -37
- package/lib/features/agent/chat/hooks/useAgentStream.js.map +1 -1
- package/lib/features/agent/chat/hooks/useArtifacts.d.ts +1 -8
- package/lib/features/agent/chat/hooks/useArtifacts.d.ts.map +1 -1
- package/lib/features/agent/chat/hooks/useArtifacts.js +10 -28
- package/lib/features/agent/chat/hooks/useArtifacts.js.map +1 -1
- package/lib/features/agent/chat/index.d.ts +2 -1
- package/lib/features/agent/chat/index.d.ts.map +1 -1
- package/lib/features/agent/chat/index.js +2 -1
- package/lib/features/agent/chat/index.js.map +1 -1
- package/lib/features/agent/chat/workstreams.d.ts +1 -0
- package/lib/features/agent/chat/workstreams.d.ts.map +1 -1
- package/lib/features/agent/chat/workstreams.js +28 -0
- package/lib/features/agent/chat/workstreams.js.map +1 -1
- package/lib/features/facets/AgentRunnerFacetsNav.d.ts +10 -1
- package/lib/features/facets/AgentRunnerFacetsNav.d.ts.map +1 -1
- package/lib/features/facets/AgentRunnerFacetsNav.js +6 -3
- package/lib/features/facets/AgentRunnerFacetsNav.js.map +1 -1
- package/lib/features/facets/CollectionsFacetsNav.d.ts +10 -1
- package/lib/features/facets/CollectionsFacetsNav.d.ts.map +1 -1
- package/lib/features/facets/CollectionsFacetsNav.js +14 -5
- package/lib/features/facets/CollectionsFacetsNav.js.map +1 -1
- package/lib/features/facets/PromptsFacetsNav.d.ts +10 -1
- package/lib/features/facets/PromptsFacetsNav.d.ts.map +1 -1
- package/lib/features/facets/PromptsFacetsNav.js +14 -5
- package/lib/features/facets/PromptsFacetsNav.js.map +1 -1
- package/lib/features/facets/RunsFacetsNav.d.ts +10 -1
- package/lib/features/facets/RunsFacetsNav.d.ts.map +1 -1
- package/lib/features/facets/RunsFacetsNav.js +14 -5
- package/lib/features/facets/RunsFacetsNav.js.map +1 -1
- package/lib/features/index.d.ts +0 -1
- package/lib/features/index.d.ts.map +1 -1
- package/lib/features/index.js +0 -1
- package/lib/features/index.js.map +1 -1
- package/lib/features/oauth/McpConnectionsButton.d.ts +30 -0
- package/lib/features/oauth/McpConnectionsButton.d.ts.map +1 -0
- package/lib/features/oauth/McpConnectionsButton.js +70 -0
- package/lib/features/oauth/McpConnectionsButton.js.map +1 -0
- package/lib/features/oauth/McpConnectionsDialog.d.ts +25 -0
- package/lib/features/oauth/McpConnectionsDialog.d.ts.map +1 -0
- package/lib/features/oauth/McpConnectionsDialog.js +26 -0
- package/lib/features/oauth/McpConnectionsDialog.js.map +1 -0
- package/lib/features/oauth/RemoteMcpConnectionButton.d.ts.map +1 -1
- package/lib/features/oauth/RemoteMcpConnectionButton.js +14 -6
- package/lib/features/oauth/RemoteMcpConnectionButton.js.map +1 -1
- package/lib/features/oauth/index.d.ts +3 -0
- package/lib/features/oauth/index.d.ts.map +1 -1
- package/lib/features/oauth/index.js +3 -0
- package/lib/features/oauth/index.js.map +1 -1
- package/lib/features/oauth/useMcpConnections.d.ts +44 -0
- package/lib/features/oauth/useMcpConnections.d.ts.map +1 -0
- package/lib/features/oauth/useMcpConnections.js +168 -0
- package/lib/features/oauth/useMcpConnections.js.map +1 -0
- package/lib/features/permissions/UserPermissionsProvider.d.ts +4 -6
- package/lib/features/permissions/UserPermissionsProvider.d.ts.map +1 -1
- package/lib/features/permissions/UserPermissionsProvider.js +40 -42
- package/lib/features/permissions/UserPermissionsProvider.js.map +1 -1
- package/lib/features/store/objects/DocumentPreviewPanel.d.ts.map +1 -1
- package/lib/features/store/objects/DocumentPreviewPanel.js +2 -1
- package/lib/features/store/objects/DocumentPreviewPanel.js.map +1 -1
- package/lib/features/store/objects/DocumentQuickFilter.d.ts +23 -0
- package/lib/features/store/objects/DocumentQuickFilter.d.ts.map +1 -0
- package/lib/features/store/objects/DocumentQuickFilter.js +30 -0
- package/lib/features/store/objects/DocumentQuickFilter.js.map +1 -0
- package/lib/features/store/objects/DocumentSearchResults.d.ts.map +1 -1
- package/lib/features/store/objects/DocumentSearchResults.js +17 -1
- package/lib/features/store/objects/DocumentSearchResults.js.map +1 -1
- package/lib/features/store/objects/components/ContentOverview.d.ts.map +1 -1
- package/lib/features/store/objects/components/ContentOverview.js +17 -74
- package/lib/features/store/objects/components/ContentOverview.js.map +1 -1
- package/lib/features/store/objects/layout/DocumentTableColumn.d.ts +7 -1
- package/lib/features/store/objects/layout/DocumentTableColumn.d.ts.map +1 -1
- package/lib/features/store/objects/layout/DocumentTableColumn.js +27 -3
- package/lib/features/store/objects/layout/DocumentTableColumn.js.map +1 -1
- package/lib/features/store/objects/layout/documentLayout.js +1 -1
- package/lib/features/store/objects/layout/renderers.d.ts +2 -1
- package/lib/features/store/objects/layout/renderers.d.ts.map +1 -1
- package/lib/features/store/objects/layout/renderers.js +27 -20
- package/lib/features/store/objects/layout/renderers.js.map +1 -1
- package/lib/features/store/types/ContentObjectTypesSearch.d.ts.map +1 -1
- package/lib/features/store/types/ContentObjectTypesSearch.js +4 -1
- package/lib/features/store/types/ContentObjectTypesSearch.js.map +1 -1
- package/lib/features/store/types/ContentObjectTypesTable.d.ts +2 -1
- package/lib/features/store/types/ContentObjectTypesTable.d.ts.map +1 -1
- package/lib/features/store/types/ContentObjectTypesTable.js +8 -3
- package/lib/features/store/types/ContentObjectTypesTable.js.map +1 -1
- package/lib/i18n/instance.d.ts.map +1 -1
- package/lib/i18n/instance.js +1 -0
- package/lib/i18n/instance.js.map +1 -1
- package/lib/i18n/locales/ar.json +72 -45
- package/lib/i18n/locales/de.json +65 -34
- package/lib/i18n/locales/en.json +63 -47
- package/lib/i18n/locales/es.json +65 -35
- package/lib/i18n/locales/fr.json +65 -35
- package/lib/i18n/locales/it.json +72 -42
- package/lib/i18n/locales/ja.json +72 -41
- package/lib/i18n/locales/ko.json +72 -41
- package/lib/i18n/locales/pt.json +72 -42
- package/lib/i18n/locales/ru.json +72 -43
- package/lib/i18n/locales/tr.json +72 -41
- package/lib/i18n/locales/zh-TW.json +72 -41
- package/lib/i18n/locales/zh.json +72 -41
- package/lib/session/UserSession.d.ts +0 -6
- package/lib/session/UserSession.d.ts.map +1 -1
- package/lib/session/UserSession.js +0 -15
- package/lib/session/UserSession.js.map +1 -1
- package/lib/session/UserSessionProvider.d.ts.map +1 -1
- package/lib/session/UserSessionProvider.js +39 -98
- package/lib/session/UserSessionProvider.js.map +1 -1
- package/lib/session/auth/composable.d.ts.map +1 -1
- package/lib/session/auth/composable.js +3 -33
- package/lib/session/auth/composable.js.map +1 -1
- package/lib/shell/login/SignInPrimitives.d.ts.map +1 -1
- package/lib/shell/login/SignInPrimitives.js +3 -2
- package/lib/shell/login/SignInPrimitives.js.map +1 -1
- package/lib/vertesia-ui-core.js +1 -1
- package/lib/vertesia-ui-core.js.map +1 -1
- package/lib/vertesia-ui-env.js +1 -1
- package/lib/vertesia-ui-env.js.map +1 -1
- package/lib/vertesia-ui-features.js +1 -1
- package/lib/vertesia-ui-features.js.map +1 -1
- package/lib/vertesia-ui-i18n.js +1 -1
- package/lib/vertesia-ui-i18n.js.map +1 -1
- package/lib/vertesia-ui-session.js +1 -1
- package/lib/vertesia-ui-session.js.map +1 -1
- package/lib/vertesia-ui-shell.js +1 -1
- package/lib/vertesia-ui-shell.js.map +1 -1
- package/lib/vertesia-ui-widgets.js +1 -1
- package/lib/vertesia-ui-widgets.js.map +1 -1
- package/lib/widgets/schema-editor/editor/Editable.js +1 -1
- package/lib/widgets/schema-editor/editor/Editable.js.map +1 -1
- package/llms.txt +70 -70
- package/package.json +35 -32
- package/src/core/components/shadcn/dropdown.tsx +2 -0
- package/src/core/components/shadcn/filters/filterBar.tsx +9 -2
- package/src/core/components/shadcn/modal/ConfirmModal.tsx +65 -3
- package/src/core/components/shadcn/modal/dialog.tsx +1 -1
- package/src/core/components/shadcn/popover.tsx +1 -0
- package/src/core/components/shadcn/switch.tsx +4 -4
- package/src/core/components/shadcn/tabs.tsx +1 -1
- package/src/core/components/shadcn/tooltip.tsx +1 -0
- package/src/env/index.ts +0 -24
- package/src/features/agent/PayloadBuilder.tsx +18 -0
- package/src/features/agent/chat/AgentApprovalModeSelector.tsx +130 -0
- package/src/features/agent/chat/AgentChatFixtureReplay.test.tsx +22 -2
- package/src/features/agent/chat/AgentChatFixtureReplay.tsx +33 -27
- package/src/features/agent/chat/AgentRequestInputOverlay.test.tsx +122 -0
- package/src/features/agent/chat/AgentRequestInputOverlay.tsx +91 -17
- package/src/features/agent/chat/AgentRightPanel.tsx +238 -50
- package/src/features/agent/chat/AnimatedThinkingDots.tsx +1 -1
- package/src/features/agent/chat/ArtifactsTab.tsx +21 -155
- package/src/features/agent/chat/AskUserWidget.tsx +6 -2
- package/src/features/agent/chat/ModernAgentConversation.test.tsx +1157 -47
- package/src/features/agent/chat/ModernAgentConversation.tsx +703 -136
- package/src/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.tsx +74 -0
- package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.test.tsx +1420 -126
- package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +934 -111
- package/src/features/agent/chat/ModernAgentOutput/AttachmentPreview.tsx +31 -40
- package/src/features/agent/chat/ModernAgentOutput/Header.tsx +28 -28
- package/src/features/agent/chat/ModernAgentOutput/MessageDeliveryStatus.tsx +83 -0
- package/src/features/agent/chat/ModernAgentOutput/MessageInput.test.tsx +38 -2
- package/src/features/agent/chat/ModernAgentOutput/MessageInput.tsx +121 -98
- package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +7 -1
- package/src/features/agent/chat/ModernAgentOutput/SlideInPanel.tsx +3 -3
- package/src/features/agent/chat/ModernAgentOutput/SlidingMessages.tsx +1 -1
- package/src/features/agent/chat/ModernAgentOutput/SummaryConversation.ts +82 -2
- package/src/features/agent/chat/ModernAgentOutput/WorkstreamTabs.tsx +2 -2
- package/src/features/agent/chat/ModernAgentOutput/requestInputMessages.ts +216 -0
- package/src/features/agent/chat/ModernAgentOutput/utils.test.ts +149 -0
- package/src/features/agent/chat/ModernAgentOutput/utils.ts +103 -2
- package/src/features/agent/chat/clipboardFiles.ts +33 -0
- package/src/features/agent/chat/hooks/useAgentStream.test.tsx +355 -4
- package/src/features/agent/chat/hooks/useAgentStream.ts +270 -43
- package/src/features/agent/chat/hooks/useArtifacts.ts +11 -44
- package/src/features/agent/chat/index.ts +10 -1
- package/src/features/agent/chat/workstreams.ts +42 -0
- package/src/features/facets/AgentRunnerFacetsNav.tsx +23 -3
- package/src/features/facets/CollectionsFacetsNav.tsx +30 -5
- package/src/features/facets/PromptsFacetsNav.tsx +30 -5
- package/src/features/facets/RunsFacetsNav.tsx +32 -5
- package/src/features/index.ts +0 -1
- package/src/features/oauth/McpConnectionsButton.test.tsx +248 -0
- package/src/features/oauth/McpConnectionsButton.tsx +269 -0
- package/src/features/oauth/McpConnectionsDialog.tsx +142 -0
- package/src/features/oauth/RemoteMcpConnectionButton.tsx +37 -14
- package/src/features/oauth/index.ts +3 -0
- package/src/features/oauth/useMcpConnections.test.ts +94 -0
- package/src/features/oauth/useMcpConnections.ts +210 -0
- package/src/features/permissions/UserPermissionsProvider.tsx +41 -59
- package/src/features/store/objects/DocumentPreviewPanel.tsx +4 -2
- package/src/features/store/objects/DocumentQuickFilter.tsx +72 -0
- package/src/features/store/objects/DocumentSearchResults.tsx +30 -11
- package/src/features/store/objects/components/ContentOverview.tsx +30 -99
- package/src/features/store/objects/layout/DocumentTableColumn.tsx +29 -4
- package/src/features/store/objects/layout/documentLayout.tsx +1 -1
- package/src/features/store/objects/layout/renderers.tsx +80 -20
- package/src/features/store/types/ContentObjectTypesSearch.tsx +7 -1
- package/src/features/store/types/ContentObjectTypesTable.tsx +34 -4
- package/src/i18n/instance.ts +1 -0
- package/src/i18n/locales/ar.json +72 -45
- package/src/i18n/locales/de.json +65 -34
- package/src/i18n/locales/en.json +63 -47
- package/src/i18n/locales/es.json +65 -35
- package/src/i18n/locales/fr.json +65 -35
- package/src/i18n/locales/it.json +72 -42
- package/src/i18n/locales/ja.json +72 -41
- package/src/i18n/locales/ko.json +72 -41
- package/src/i18n/locales/pt.json +72 -42
- package/src/i18n/locales/ru.json +72 -43
- package/src/i18n/locales/tr.json +72 -41
- package/src/i18n/locales/zh-TW.json +72 -41
- package/src/i18n/locales/zh.json +72 -41
- package/src/i18n/rtl.test.ts +57 -1
- package/src/session/UserSession.ts +0 -16
- package/src/session/UserSessionProvider.tsx +51 -123
- package/src/session/auth/composable.ts +3 -34
- package/src/shell/login/SignInPrimitives.tsx +3 -2
- package/src/widgets/schema-editor/editor/Editable.tsx +1 -1
- package/lib/features/document-viewer/UniversalDocumentViewer.d.ts +0 -73
- package/lib/features/document-viewer/UniversalDocumentViewer.d.ts.map +0 -1
- package/lib/features/document-viewer/UniversalDocumentViewer.js +0 -415
- package/lib/features/document-viewer/UniversalDocumentViewer.js.map +0 -1
- package/lib/features/document-viewer/index.d.ts +0 -2
- package/lib/features/document-viewer/index.d.ts.map +0 -1
- package/lib/features/document-viewer/index.js +0 -2
- package/lib/features/document-viewer/index.js.map +0 -1
- package/src/features/document-viewer/UniversalDocumentViewer.test.tsx +0 -123
- package/src/features/document-viewer/UniversalDocumentViewer.tsx +0 -746
- package/src/features/document-viewer/index.ts +0 -1
- package/src/session/auth/composable.test.ts +0 -79
|
@@ -6,13 +6,14 @@ import {
|
|
|
6
6
|
type JSONSchema,
|
|
7
7
|
type Plan,
|
|
8
8
|
} from '@vertesia/common';
|
|
9
|
-
import { cn } from '@vertesia/ui/core';
|
|
9
|
+
import { Badge, Button, cn, VTooltip } from '@vertesia/ui/core';
|
|
10
10
|
import { i18nInstance, NAMESPACE, useUITranslation } from '@vertesia/ui/i18n';
|
|
11
11
|
import { NavLink } from '@vertesia/ui/router';
|
|
12
12
|
import { MarkdownRenderer, type MarkdownRendererProps } from '@vertesia/ui/widgets';
|
|
13
13
|
import type { Element } from 'hast';
|
|
14
14
|
import {
|
|
15
15
|
AlertTriangle,
|
|
16
|
+
ArrowLeft,
|
|
16
17
|
Bot,
|
|
17
18
|
Brain,
|
|
18
19
|
CheckCircle,
|
|
@@ -31,18 +32,29 @@ import { AskUserWidget } from '../AskUserWidget';
|
|
|
31
32
|
import { ThinkingMessages } from '../WaitingMessages';
|
|
32
33
|
import {
|
|
33
34
|
formatWorkstreamName,
|
|
35
|
+
getWorkstreamActivityDetails,
|
|
34
36
|
getWorkstreamDisplayName,
|
|
35
37
|
getWorkstreamLaunchDetails,
|
|
36
38
|
type WorkstreamLaunchDetails,
|
|
37
39
|
} from '../workstreams.js';
|
|
38
40
|
import { AttachmentPreviewList, parseUserMessageAttachments } from './AttachmentPreview';
|
|
39
41
|
import BatchProgressPanel, { type BatchProgressPanelClassNames } from './BatchProgressPanel';
|
|
42
|
+
import { getMessageDeliveryStatus, MessageDeliveryStatus } from './MessageDeliveryStatus';
|
|
40
43
|
import MessageItem, { type MessageItemClassNames, type MessageItemProps } from './MessageItem';
|
|
41
44
|
import {
|
|
42
45
|
getAnsweredRequestInputKeys,
|
|
46
|
+
getAnsweredToolApprovalRequestInputKeys,
|
|
47
|
+
getHiddenToolApprovalAnswerKeys,
|
|
43
48
|
getPendingRequestInputMessage,
|
|
49
|
+
getRequestInputDisplayText,
|
|
44
50
|
getRequestInputMessageKey,
|
|
51
|
+
getResolvedToolApprovalKeys,
|
|
52
|
+
hasRequestInputUx,
|
|
45
53
|
isRequestInputAnswered,
|
|
54
|
+
isToolApprovalAnswerHidden,
|
|
55
|
+
isToolApprovalRequestInput,
|
|
56
|
+
isToolApprovalRequestInputHidden,
|
|
57
|
+
type RequestInputMessageWithUx,
|
|
46
58
|
} from './requestInputMessages';
|
|
47
59
|
import StreamingMessage, { type StreamingMessageClassNames } from './StreamingMessage';
|
|
48
60
|
import {
|
|
@@ -57,10 +69,12 @@ import {
|
|
|
57
69
|
import ToolCallGroup, { type ToolCallGroupClassNames } from './ToolCallGroup';
|
|
58
70
|
import {
|
|
59
71
|
DONE_STATES,
|
|
72
|
+
filterMessagesForActiveWorkstream,
|
|
60
73
|
getWorkstreamId,
|
|
61
74
|
groupMessagesWithStreaming,
|
|
62
75
|
isInProgress,
|
|
63
76
|
isToolPreambleMessage,
|
|
77
|
+
isUserStoppedMessage,
|
|
64
78
|
mergeConsecutiveToolGroups,
|
|
65
79
|
type RenderableGroup,
|
|
66
80
|
type StreamingData,
|
|
@@ -108,6 +122,23 @@ function formatDuration(seconds: number): string {
|
|
|
108
122
|
return remainingSeconds > 0 ? `${minutes}m ${remainingSeconds}s` : `${minutes}m`;
|
|
109
123
|
}
|
|
110
124
|
|
|
125
|
+
function parseTimestampMs(timestamp: number | string | undefined): number | undefined {
|
|
126
|
+
if (timestamp === undefined || timestamp === null || timestamp === '') return undefined;
|
|
127
|
+
const value = typeof timestamp === 'number' ? timestamp : new Date(timestamp).getTime();
|
|
128
|
+
return Number.isFinite(value) ? value : undefined;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function formatToolDetailTimestamp(timestamp: number | string | undefined): string | undefined {
|
|
132
|
+
const value = parseTimestampMs(timestamp);
|
|
133
|
+
if (value === undefined) return undefined;
|
|
134
|
+
|
|
135
|
+
return new Intl.DateTimeFormat(undefined, {
|
|
136
|
+
hour: '2-digit',
|
|
137
|
+
minute: '2-digit',
|
|
138
|
+
second: '2-digit',
|
|
139
|
+
}).format(new Date(value));
|
|
140
|
+
}
|
|
141
|
+
|
|
111
142
|
function getReadableToolLabel(message: AgentMessage): string {
|
|
112
143
|
const details = message.details as
|
|
113
144
|
| {
|
|
@@ -140,9 +171,7 @@ function getReadableToolLabel(message: AgentMessage): string {
|
|
|
140
171
|
return 'Using tool';
|
|
141
172
|
}
|
|
142
173
|
|
|
143
|
-
function getSummaryWorkLabel(
|
|
144
|
-
if (status === 'error') return 'Work needs attention';
|
|
145
|
-
if (status === 'warning') return 'Work had warnings';
|
|
174
|
+
function getSummaryWorkLabel(isActive: boolean): string {
|
|
146
175
|
return isActive ? 'Working' : 'Worked';
|
|
147
176
|
}
|
|
148
177
|
|
|
@@ -150,8 +179,8 @@ function isTransientThinkingWork(messages: AgentMessage[]): boolean {
|
|
|
150
179
|
return messages.length > 0 && messages.every(isTransientWorkStatusMessage);
|
|
151
180
|
}
|
|
152
181
|
|
|
153
|
-
function getSummaryActivityLabel(
|
|
154
|
-
return getSummaryWorkLabel(
|
|
182
|
+
function getSummaryActivityLabel(isActive: boolean): string {
|
|
183
|
+
return getSummaryWorkLabel(isActive);
|
|
155
184
|
}
|
|
156
185
|
|
|
157
186
|
function hasOpenUserTurn(messages: AgentMessage[]): boolean {
|
|
@@ -160,6 +189,90 @@ function hasOpenUserTurn(messages: AgentMessage[]): boolean {
|
|
|
160
189
|
return latestMessage?.type === AgentMessageType.QUESTION;
|
|
161
190
|
}
|
|
162
191
|
|
|
192
|
+
function hasLatestToolApprovalAllowTurn(messages: AgentMessage[], hiddenToolApprovalAnswerKeys: Set<string>): boolean {
|
|
193
|
+
const mainMessages = messages.filter((message) => getWorkstreamId(message) === 'main');
|
|
194
|
+
const latestMessage = mainMessages[mainMessages.length - 1] ?? messages[messages.length - 1];
|
|
195
|
+
if (!latestMessage || !isToolApprovalAnswerHidden(latestMessage, hiddenToolApprovalAnswerKeys)) return false;
|
|
196
|
+
|
|
197
|
+
const response = getToolApprovalResponse(latestMessage);
|
|
198
|
+
return response === 'allow_once' || response === 'allow_for_run';
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function getWriteArtifactCompletionPath(message: AgentMessage): string | undefined {
|
|
202
|
+
if (message.type !== AgentMessageType.UPDATE) return undefined;
|
|
203
|
+
const details = getDetailsRecord(message);
|
|
204
|
+
if (details.tool !== undefined || details.activity_group_id !== undefined) return undefined;
|
|
205
|
+
const path = typeof details.path === 'string' && details.path.trim() ? details.path.trim() : undefined;
|
|
206
|
+
if (!path) return undefined;
|
|
207
|
+
|
|
208
|
+
return getMessageText(message) === `Prepared and saved artifact to ${path}` ? path : undefined;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function findPreviousWriteArtifactToolMessage(messages: AgentMessage[], index: number): AgentMessage | undefined {
|
|
212
|
+
const workstreamId = getWorkstreamId(messages[index]);
|
|
213
|
+
|
|
214
|
+
for (let prevIndex = index - 1; prevIndex >= 0; prevIndex -= 1) {
|
|
215
|
+
const previous = messages[prevIndex];
|
|
216
|
+
if (getWorkstreamId(previous) !== workstreamId) continue;
|
|
217
|
+
|
|
218
|
+
const details = getDetailsRecord(previous);
|
|
219
|
+
if (details.tool === 'write_artifact' && typeof details.activity_group_id === 'string') return previous;
|
|
220
|
+
|
|
221
|
+
if (previous.type === AgentMessageType.REQUEST_INPUT) continue;
|
|
222
|
+
if (getToolApprovalResponse(previous)) continue;
|
|
223
|
+
if (details.display_role === 'thinking') continue;
|
|
224
|
+
|
|
225
|
+
if (typeof details.tool === 'string' && details.tool !== 'write_artifact') return undefined;
|
|
226
|
+
if (
|
|
227
|
+
previous.type === AgentMessageType.ANSWER ||
|
|
228
|
+
previous.type === AgentMessageType.COMPLETE ||
|
|
229
|
+
previous.type === AgentMessageType.IDLE ||
|
|
230
|
+
previous.type === AgentMessageType.TERMINATED
|
|
231
|
+
) {
|
|
232
|
+
return undefined;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return undefined;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function attachWriteArtifactCompletionMessages(messages: AgentMessage[]): AgentMessage[] {
|
|
240
|
+
return messages.map((message, index) => {
|
|
241
|
+
const path = getWriteArtifactCompletionPath(message);
|
|
242
|
+
if (!path) return message;
|
|
243
|
+
|
|
244
|
+
const previousToolMessage = findPreviousWriteArtifactToolMessage(messages, index);
|
|
245
|
+
const previousDetails = previousToolMessage ? getDetailsRecord(previousToolMessage) : undefined;
|
|
246
|
+
if (!previousDetails) return message;
|
|
247
|
+
|
|
248
|
+
const activityGroupId =
|
|
249
|
+
typeof previousDetails.activity_group_id === 'string' ? previousDetails.activity_group_id : undefined;
|
|
250
|
+
const toolRunId = typeof previousDetails.tool_run_id === 'string' ? previousDetails.tool_run_id : undefined;
|
|
251
|
+
const toolUseId = typeof previousDetails.tool_use_id === 'string' ? previousDetails.tool_use_id : undefined;
|
|
252
|
+
const toolIteration =
|
|
253
|
+
typeof previousDetails.tool_iteration === 'number' ? previousDetails.tool_iteration : undefined;
|
|
254
|
+
|
|
255
|
+
if (!activityGroupId) return message;
|
|
256
|
+
|
|
257
|
+
return {
|
|
258
|
+
...message,
|
|
259
|
+
details: {
|
|
260
|
+
...message.details,
|
|
261
|
+
event_class: 'activity',
|
|
262
|
+
tool: 'write_artifact',
|
|
263
|
+
tool_run_id: toolRunId ?? 'write_artifact',
|
|
264
|
+
tool_use_id: toolUseId ?? toolRunId ?? 'write_artifact',
|
|
265
|
+
tool_iteration: toolIteration,
|
|
266
|
+
tool_status: 'completed',
|
|
267
|
+
tool_event: 'progress',
|
|
268
|
+
activity_group_id: activityGroupId,
|
|
269
|
+
output: getMessageText(message),
|
|
270
|
+
path,
|
|
271
|
+
},
|
|
272
|
+
};
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
|
|
163
276
|
function getMessageText(message: AgentMessage): string {
|
|
164
277
|
if (!message.message) return '';
|
|
165
278
|
if (typeof message.message === 'object') return JSON.stringify(message.message, null, 2);
|
|
@@ -168,7 +281,8 @@ function getMessageText(message: AgentMessage): string {
|
|
|
168
281
|
|
|
169
282
|
interface SummaryMessageProps {
|
|
170
283
|
message: AgentMessage;
|
|
171
|
-
onSendMessage?: (message: string) => void;
|
|
284
|
+
onSendMessage?: (message: string, metadata?: Record<string, unknown>) => void;
|
|
285
|
+
onSelectWorkstream?: (workstreamId: string) => void;
|
|
172
286
|
requestInputAnswered?: boolean;
|
|
173
287
|
StoreLinkComponent?: React.ComponentType<{ href: string; documentId: string; children: React.ReactNode }>;
|
|
174
288
|
CollectionLinkComponent?: React.ComponentType<{ href: string; collectionId: string; children: React.ReactNode }>;
|
|
@@ -177,9 +291,11 @@ interface SummaryMessageProps {
|
|
|
177
291
|
function SummaryWorkstreamLaunchMessage({
|
|
178
292
|
message,
|
|
179
293
|
details,
|
|
294
|
+
onSelectWorkstream,
|
|
180
295
|
}: {
|
|
181
296
|
message: AgentMessage;
|
|
182
297
|
details: WorkstreamLaunchDetails;
|
|
298
|
+
onSelectWorkstream?: (workstreamId: string) => void;
|
|
183
299
|
}) {
|
|
184
300
|
const { t } = useUITranslation();
|
|
185
301
|
const workstreamName = getWorkstreamDisplayName(details.workstreamId, details.interaction);
|
|
@@ -188,7 +304,15 @@ function SummaryWorkstreamLaunchMessage({
|
|
|
188
304
|
|
|
189
305
|
return (
|
|
190
306
|
<div className="mx-auto w-full max-w-3xl px-1" data-workstream-id={details.workstreamId}>
|
|
191
|
-
<
|
|
307
|
+
<button
|
|
308
|
+
type="button"
|
|
309
|
+
className={cn(
|
|
310
|
+
'group flex w-full items-start gap-3 border-b border-border/70 py-2 text-start text-sm text-muted',
|
|
311
|
+
'transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2',
|
|
312
|
+
'focus-visible:ring-focus focus-visible:ring-offset-2 focus-visible:ring-offset-background',
|
|
313
|
+
)}
|
|
314
|
+
onClick={() => onSelectWorkstream?.(details.workstreamId)}
|
|
315
|
+
>
|
|
192
316
|
<Bot className="mt-0.5 size-4 shrink-0 text-muted" aria-hidden="true" />
|
|
193
317
|
<div className="min-w-0 flex-1">
|
|
194
318
|
<div className="flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1">
|
|
@@ -198,7 +322,9 @@ function SummaryWorkstreamLaunchMessage({
|
|
|
198
322
|
{secondaryName && <div className="mt-0.5 truncate text-xs text-muted/75">{secondaryName}</div>}
|
|
199
323
|
<span className="sr-only">{getMessageText(message)}</span>
|
|
200
324
|
</div>
|
|
201
|
-
|
|
325
|
+
{/* rtl-ok: chevron points and nudges toward inline-end in both directions. */}
|
|
326
|
+
<ChevronRight className="mt-0.5 size-4 shrink-0 text-muted transition-transform group-hover:translate-x-0.5 rtl:rotate-180 rtl:group-hover:-translate-x-0.5" />
|
|
327
|
+
</button>
|
|
202
328
|
</div>
|
|
203
329
|
);
|
|
204
330
|
}
|
|
@@ -212,6 +338,8 @@ const SUMMARY_PROSE_CLASS = [
|
|
|
212
338
|
].join(' ');
|
|
213
339
|
|
|
214
340
|
const USER_BUBBLE_COLLAPSE_THRESHOLD = 520;
|
|
341
|
+
const SUMMARY_THOUGHT_COLLAPSE_LINES = 6;
|
|
342
|
+
const SUMMARY_THOUGHT_COLLAPSE_THRESHOLD = 520;
|
|
215
343
|
const STORE_LINK_MARKDOWN_RE =
|
|
216
344
|
/\[[^\]]+\]\((?:\/store\/(?:objects|collections)\/|store:|document:|document:\/\/|collection:)[^)]+\)/;
|
|
217
345
|
const DEFAULT_AGENT_MARKDOWN_COMPONENTS: MarkdownRendererProps['components'] = {
|
|
@@ -428,12 +556,14 @@ function useRotatingThinkingMessageIndex(enabled = true): number {
|
|
|
428
556
|
|
|
429
557
|
function SummaryUserBubble({
|
|
430
558
|
children,
|
|
559
|
+
message,
|
|
431
560
|
workstreamId,
|
|
432
561
|
className,
|
|
433
562
|
artifactRunId,
|
|
434
563
|
markdownComponents,
|
|
435
564
|
}: {
|
|
436
565
|
children: React.ReactNode;
|
|
566
|
+
message?: AgentMessage;
|
|
437
567
|
workstreamId?: string;
|
|
438
568
|
className?: string;
|
|
439
569
|
artifactRunId?: string;
|
|
@@ -446,6 +576,7 @@ function SummaryUserBubble({
|
|
|
446
576
|
const isPlainText = typeof children === 'string' || typeof children === 'number';
|
|
447
577
|
const textContent = isPlainText ? String(children) : '';
|
|
448
578
|
const shouldRenderMarkdown = typeof children === 'string' && STORE_LINK_MARKDOWN_RE.test(children);
|
|
579
|
+
const deliveryStatus = message ? getMessageDeliveryStatus(message) : undefined;
|
|
449
580
|
|
|
450
581
|
useEffect(() => {
|
|
451
582
|
if (!shouldCollapse && isExpanded) {
|
|
@@ -502,6 +633,11 @@ function SummaryUserBubble({
|
|
|
502
633
|
/>
|
|
503
634
|
</button>
|
|
504
635
|
)}
|
|
636
|
+
{message && deliveryStatus ? (
|
|
637
|
+
<div className="mt-1.5 flex justify-end">
|
|
638
|
+
<MessageDeliveryStatus message={message} className="h-4 w-4" />
|
|
639
|
+
</div>
|
|
640
|
+
) : null}
|
|
505
641
|
</div>
|
|
506
642
|
</div>
|
|
507
643
|
);
|
|
@@ -510,12 +646,14 @@ function SummaryUserBubble({
|
|
|
510
646
|
function SummaryMessage({
|
|
511
647
|
message,
|
|
512
648
|
onSendMessage,
|
|
649
|
+
onSelectWorkstream,
|
|
513
650
|
requestInputAnswered = false,
|
|
514
651
|
StoreLinkComponent,
|
|
515
652
|
CollectionLinkComponent,
|
|
516
653
|
}: SummaryMessageProps) {
|
|
517
|
-
const content =
|
|
518
|
-
|
|
654
|
+
const content =
|
|
655
|
+
message.type === AgentMessageType.REQUEST_INPUT ? getRequestInputDisplayText(message) : getMessageText(message);
|
|
656
|
+
const workstreamLaunchDetails = getWorkstreamLaunchDetails(message) ?? getWorkstreamActivityDetails(message);
|
|
519
657
|
const workstreamId = getWorkstreamId(message);
|
|
520
658
|
const runId = (message as { workflow_run_id?: string }).workflow_run_id;
|
|
521
659
|
const parsedQuestion = useMemo(
|
|
@@ -574,7 +712,13 @@ function SummaryMessage({
|
|
|
574
712
|
);
|
|
575
713
|
|
|
576
714
|
if (workstreamLaunchDetails) {
|
|
577
|
-
return
|
|
715
|
+
return (
|
|
716
|
+
<SummaryWorkstreamLaunchMessage
|
|
717
|
+
message={message}
|
|
718
|
+
details={workstreamLaunchDetails}
|
|
719
|
+
onSelectWorkstream={onSelectWorkstream}
|
|
720
|
+
/>
|
|
721
|
+
);
|
|
578
722
|
}
|
|
579
723
|
|
|
580
724
|
if (message.type === AgentMessageType.QUESTION) {
|
|
@@ -597,6 +741,7 @@ function SummaryMessage({
|
|
|
597
741
|
)}
|
|
598
742
|
{questionBody && (
|
|
599
743
|
<SummaryUserBubble
|
|
744
|
+
message={message}
|
|
600
745
|
workstreamId={workstreamId}
|
|
601
746
|
artifactRunId={runId}
|
|
602
747
|
markdownComponents={markdownComponents}
|
|
@@ -620,6 +765,10 @@ function SummaryMessage({
|
|
|
620
765
|
multiSelect={uxConfig.multiSelect}
|
|
621
766
|
onSelect={(optionId) => onSendMessage?.(optionId)}
|
|
622
767
|
onMultiSelect={(optionIds) => onSendMessage?.(optionIds.join(', '))}
|
|
768
|
+
allowFreeResponse={!uxConfig.options?.length || !!uxConfig.free_response}
|
|
769
|
+
placeholder={uxConfig.free_response?.placeholder}
|
|
770
|
+
submitLabel={uxConfig.free_response?.submit_label}
|
|
771
|
+
onSubmit={(value) => onSendMessage?.(value, uxConfig.free_response?.metadata)}
|
|
623
772
|
hideBorder
|
|
624
773
|
compact
|
|
625
774
|
answered={requestInputAnswered}
|
|
@@ -868,12 +1017,21 @@ interface SummaryToolDetailItem {
|
|
|
868
1017
|
kind: SummaryToolDetailKind;
|
|
869
1018
|
label: string;
|
|
870
1019
|
title: string;
|
|
1020
|
+
isPreamble?: boolean;
|
|
871
1021
|
command?: string;
|
|
872
1022
|
text?: string;
|
|
1023
|
+
toolName?: string;
|
|
1024
|
+
startedAt?: number | string;
|
|
1025
|
+
finishedAt?: number | string;
|
|
873
1026
|
status?: ToolExecutionStatus;
|
|
1027
|
+
decisionText?: string;
|
|
874
1028
|
sections: SummaryToolDetailSection[];
|
|
875
1029
|
}
|
|
876
1030
|
|
|
1031
|
+
const SUMMARY_TOOL_STARTED_AT_DETAIL_KEY = '_summary_started_at';
|
|
1032
|
+
const SUMMARY_TOOL_FINISHED_AT_DETAIL_KEY = '_summary_finished_at';
|
|
1033
|
+
const SYNTHETIC_TOOL_APPROVAL_EVENT_SOURCE = 'synthetic_tool_approval_decision';
|
|
1034
|
+
|
|
877
1035
|
const TOOL_DETAIL_SYSTEM_KEYS = new Set([
|
|
878
1036
|
'account_id',
|
|
879
1037
|
'activity_group_id',
|
|
@@ -899,6 +1057,15 @@ const TOOL_DETAIL_SYSTEM_KEYS = new Set([
|
|
|
899
1057
|
'tools',
|
|
900
1058
|
'message_to_human',
|
|
901
1059
|
'progress_messages',
|
|
1060
|
+
'source',
|
|
1061
|
+
'token_usage',
|
|
1062
|
+
'checkpoint_at',
|
|
1063
|
+
'checkpoint_threshold',
|
|
1064
|
+
'approval_decision',
|
|
1065
|
+
'approval_request',
|
|
1066
|
+
'cancellation_reason',
|
|
1067
|
+
SUMMARY_TOOL_STARTED_AT_DETAIL_KEY,
|
|
1068
|
+
SUMMARY_TOOL_FINISHED_AT_DETAIL_KEY,
|
|
902
1069
|
'workflow_run_id',
|
|
903
1070
|
]);
|
|
904
1071
|
|
|
@@ -906,6 +1073,12 @@ function getDetailsRecord(message: AgentMessage): Record<string, unknown> {
|
|
|
906
1073
|
return isRecordValue(message.details) ? message.details : {};
|
|
907
1074
|
}
|
|
908
1075
|
|
|
1076
|
+
function isDocumentPanelEventMessage(message: AgentMessage): boolean {
|
|
1077
|
+
if (message.type !== AgentMessageType.UPDATE) return false;
|
|
1078
|
+
const eventClass = getDetailsRecord(message).event_class;
|
|
1079
|
+
return eventClass === 'document_created' || eventClass === 'document_updated';
|
|
1080
|
+
}
|
|
1081
|
+
|
|
909
1082
|
function humanizeIdentifier(value: string): string {
|
|
910
1083
|
return value
|
|
911
1084
|
.replace(/[_-]+/g, ' ')
|
|
@@ -930,6 +1103,15 @@ function getToolNames(details: Record<string, unknown>): string[] {
|
|
|
930
1103
|
return names;
|
|
931
1104
|
}
|
|
932
1105
|
|
|
1106
|
+
function getUniqueToolName(details: Record<string, unknown>): string | undefined {
|
|
1107
|
+
const names = Array.from(new Set(getToolNames(details)));
|
|
1108
|
+
return names.length > 0 ? names.join(', ') : undefined;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
function getTimestampDetail(value: unknown): number | string | undefined {
|
|
1112
|
+
return typeof value === 'number' || typeof value === 'string' ? value : undefined;
|
|
1113
|
+
}
|
|
1114
|
+
|
|
933
1115
|
const TOOL_TARGET_KEYS = [
|
|
934
1116
|
'query',
|
|
935
1117
|
'path',
|
|
@@ -958,15 +1140,13 @@ function getToolDetailKind(message: AgentMessage): SummaryToolDetailKind {
|
|
|
958
1140
|
const details = getDetailsRecord(message);
|
|
959
1141
|
const toolNames = getToolNames(details).join(' ').toLowerCase();
|
|
960
1142
|
const concreteTool = typeof details.tool === 'string' ? details.tool.toLowerCase() : '';
|
|
961
|
-
const
|
|
962
|
-
const haystack = `${toolNames} ${text}`;
|
|
1143
|
+
const classifierText = concreteTool || toolNames;
|
|
963
1144
|
|
|
964
1145
|
if (isToolPreambleMessage(message)) return 'think';
|
|
965
|
-
if (concreteTool.startsWith('learn_') ||
|
|
1146
|
+
if (concreteTool.startsWith('learn_') || toolNames.includes('learn_')) return 'skill';
|
|
966
1147
|
if (concreteTool === 'discover_tools') return 'discover';
|
|
967
1148
|
if (message.type === AgentMessageType.THOUGHT && !concreteTool) return 'think';
|
|
968
1149
|
|
|
969
|
-
const classifierText = concreteTool || haystack;
|
|
970
1150
|
if (classifierText.includes('search') || classifierText.includes('web') || classifierText.includes('fetch'))
|
|
971
1151
|
return 'search';
|
|
972
1152
|
if (classifierText.includes('read') || classifierText.includes('document') || classifierText.includes('file'))
|
|
@@ -1022,6 +1202,135 @@ function getToolTarget(details: Record<string, unknown>): string | undefined {
|
|
|
1022
1202
|
return undefined;
|
|
1023
1203
|
}
|
|
1024
1204
|
|
|
1205
|
+
function getApprovalDecisionLabel(decision: unknown, toolLabel: string): string | undefined {
|
|
1206
|
+
switch (decision) {
|
|
1207
|
+
case 'denied':
|
|
1208
|
+
case 'denied_with_feedback':
|
|
1209
|
+
return `User declined to use ${toolLabel}.`;
|
|
1210
|
+
case 'timeout':
|
|
1211
|
+
return `Approval timed out for ${toolLabel}.`;
|
|
1212
|
+
case 'reviewer_denied':
|
|
1213
|
+
return `Approval reviewer denied ${toolLabel}.`;
|
|
1214
|
+
case 'cancelled_after_denial':
|
|
1215
|
+
return `Cancelled ${toolLabel} after another tool was denied.`;
|
|
1216
|
+
default:
|
|
1217
|
+
return undefined;
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
function getApprovalDecisionStatusText(decision: unknown): string | undefined {
|
|
1222
|
+
switch (decision) {
|
|
1223
|
+
case 'denied':
|
|
1224
|
+
case 'denied_with_feedback':
|
|
1225
|
+
return 'Declined by user';
|
|
1226
|
+
case 'timeout':
|
|
1227
|
+
return 'Approval timed out';
|
|
1228
|
+
case 'reviewer_denied':
|
|
1229
|
+
return 'Denied by reviewer';
|
|
1230
|
+
case 'cancelled_after_denial':
|
|
1231
|
+
return 'Cancelled after denial';
|
|
1232
|
+
default:
|
|
1233
|
+
return undefined;
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
function getToolApprovalRecord(message: AgentMessage): Record<string, unknown> | undefined {
|
|
1238
|
+
const details = getDetailsRecord(message);
|
|
1239
|
+
const toolApproval = details.tool_approval;
|
|
1240
|
+
return isRecordValue(toolApproval) ? toolApproval : undefined;
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
function getApprovalKeyFromToolApproval(toolApproval: Record<string, unknown> | undefined): string | undefined {
|
|
1244
|
+
const approvalKey = toolApproval?.approval_key;
|
|
1245
|
+
return typeof approvalKey === 'string' && approvalKey.trim() ? approvalKey.trim() : undefined;
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
function getToolApprovalResponse(message: AgentMessage): 'allow_once' | 'allow_for_run' | 'deny' | undefined {
|
|
1249
|
+
if (message.type !== AgentMessageType.QUESTION) return undefined;
|
|
1250
|
+
const normalized = getMessageText(message).trim().toLowerCase();
|
|
1251
|
+
if (normalized === 'allow_once' || normalized === 'allow_for_run' || normalized === 'deny') return normalized;
|
|
1252
|
+
return undefined;
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
function getToolApprovalDisplayName(toolApproval: Record<string, unknown>): string {
|
|
1256
|
+
const title = toolApproval.tool_title;
|
|
1257
|
+
if (typeof title === 'string' && title.trim()) return title.trim();
|
|
1258
|
+
const name = toolApproval.tool_name;
|
|
1259
|
+
if (typeof name === 'string' && name.trim()) return humanizeIdentifier(name.trim());
|
|
1260
|
+
return 'tool action';
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
function buildSyntheticToolApprovalDecisionMessages(
|
|
1264
|
+
messages: AgentMessage[],
|
|
1265
|
+
resolvedToolApprovalKeys: Set<string>,
|
|
1266
|
+
): AgentMessage[] {
|
|
1267
|
+
const syntheticMessages: AgentMessage[] = [];
|
|
1268
|
+
|
|
1269
|
+
messages.forEach((message, index) => {
|
|
1270
|
+
if (message.type !== AgentMessageType.REQUEST_INPUT) return;
|
|
1271
|
+
|
|
1272
|
+
const toolApproval = getToolApprovalRecord(message);
|
|
1273
|
+
const approvalKey = getApprovalKeyFromToolApproval(toolApproval);
|
|
1274
|
+
if (!toolApproval || !approvalKey || resolvedToolApprovalKeys.has(approvalKey)) return;
|
|
1275
|
+
|
|
1276
|
+
const workstreamId = getWorkstreamId(message);
|
|
1277
|
+
let responseMessage: AgentMessage | undefined;
|
|
1278
|
+
for (let nextIndex = index + 1; nextIndex < messages.length; nextIndex += 1) {
|
|
1279
|
+
const nextMessage = messages[nextIndex];
|
|
1280
|
+
if (getWorkstreamId(nextMessage) !== workstreamId) continue;
|
|
1281
|
+
if (nextMessage.type === AgentMessageType.REQUEST_INPUT) break;
|
|
1282
|
+
if (nextMessage.type === AgentMessageType.QUESTION) {
|
|
1283
|
+
responseMessage = nextMessage;
|
|
1284
|
+
break;
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
if (!responseMessage || getToolApprovalResponse(responseMessage) !== 'deny') return;
|
|
1289
|
+
|
|
1290
|
+
const toolName =
|
|
1291
|
+
typeof toolApproval.tool_name === 'string' && toolApproval.tool_name.trim()
|
|
1292
|
+
? toolApproval.tool_name.trim()
|
|
1293
|
+
: 'tool_action';
|
|
1294
|
+
const toolLabel = getToolApprovalDisplayName(toolApproval);
|
|
1295
|
+
const target = typeof toolApproval.target === 'string' && toolApproval.target.trim() ? toolApproval.target : '';
|
|
1296
|
+
const approvalRequest = {
|
|
1297
|
+
tool_name: toolName,
|
|
1298
|
+
tool_title: toolApproval.tool_title,
|
|
1299
|
+
action_summary: toolApproval.action_summary,
|
|
1300
|
+
target: toolApproval.target,
|
|
1301
|
+
approval_key: approvalKey,
|
|
1302
|
+
};
|
|
1303
|
+
|
|
1304
|
+
syntheticMessages.push({
|
|
1305
|
+
timestamp: responseMessage.timestamp ?? message.timestamp,
|
|
1306
|
+
workflow_run_id: responseMessage.workflow_run_id || message.workflow_run_id,
|
|
1307
|
+
type: AgentMessageType.THOUGHT,
|
|
1308
|
+
message: getApprovalDecisionLabel('denied', toolLabel) ?? `User declined to use ${toolLabel}.`,
|
|
1309
|
+
workstream_id: workstreamId,
|
|
1310
|
+
details: {
|
|
1311
|
+
event_class: 'activity',
|
|
1312
|
+
tool: toolName,
|
|
1313
|
+
tool_run_id: `approval:${approvalKey}`,
|
|
1314
|
+
tool_use_id: `approval:${approvalKey}`,
|
|
1315
|
+
tool_status: 'error',
|
|
1316
|
+
tool_event: 'failed',
|
|
1317
|
+
activity_group_id: `approval:${approvalKey}`,
|
|
1318
|
+
approval_decision: 'denied',
|
|
1319
|
+
approval_request: approvalRequest,
|
|
1320
|
+
input: toolApproval.input,
|
|
1321
|
+
target,
|
|
1322
|
+
observation: 'The user declined this tool action.',
|
|
1323
|
+
source: SYNTHETIC_TOOL_APPROVAL_EVENT_SOURCE,
|
|
1324
|
+
},
|
|
1325
|
+
});
|
|
1326
|
+
});
|
|
1327
|
+
|
|
1328
|
+
if (syntheticMessages.length === 0) return messages;
|
|
1329
|
+
return [...messages, ...syntheticMessages].sort(
|
|
1330
|
+
(a, b) => getTimestampMs(a.timestamp) - getTimestampMs(b.timestamp),
|
|
1331
|
+
);
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1025
1334
|
function compactInlineText(value: string, maxLength = 160): string {
|
|
1026
1335
|
const normalized = value.replace(/\s+/g, ' ').trim();
|
|
1027
1336
|
return normalized.length > maxLength ? `${normalized.slice(0, maxLength - 1)}...` : normalized;
|
|
@@ -1082,6 +1391,16 @@ function getRenderableGroupKey(group: RenderableGroup): string {
|
|
|
1082
1391
|
return ['group', group.toolRunId, group.firstTimestamp, firstKey, lastKey].filter(Boolean).join(':');
|
|
1083
1392
|
}
|
|
1084
1393
|
|
|
1394
|
+
function getPreviousRenderableGroupTimestamp(groups: RenderableGroup[], index: number): number | string | undefined {
|
|
1395
|
+
for (let previousIndex = index - 1; previousIndex >= 0; previousIndex--) {
|
|
1396
|
+
const group = groups[previousIndex];
|
|
1397
|
+
if (group.type === 'single') return group.message.timestamp;
|
|
1398
|
+
if (group.type === 'tool_group') return group.firstTimestamp;
|
|
1399
|
+
if (group.type === 'streaming') return group.startTimestamp;
|
|
1400
|
+
}
|
|
1401
|
+
return undefined;
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1085
1404
|
function formatToolSectionValue(value: unknown): string {
|
|
1086
1405
|
const text = stringifyRequestValue(value).trim();
|
|
1087
1406
|
return text.length > 2400 ? `${text.slice(0, 2400)}\n...` : text;
|
|
@@ -1132,16 +1451,11 @@ function getToolDetailSections(message: AgentMessage): SummaryToolDetailSection[
|
|
|
1132
1451
|
|
|
1133
1452
|
addSection('Query', ['query']);
|
|
1134
1453
|
addSection('Input', ['input', 'params', 'arguments', 'args']);
|
|
1135
|
-
addSection(
|
|
1136
|
-
'
|
|
1137
|
-
'stdout',
|
|
1138
|
-
'
|
|
1139
|
-
|
|
1140
|
-
'content',
|
|
1141
|
-
'result_summary',
|
|
1142
|
-
'observation',
|
|
1143
|
-
'display_message',
|
|
1144
|
-
]);
|
|
1454
|
+
addSection(
|
|
1455
|
+
'Output',
|
|
1456
|
+
['output', 'stdout', 'result', 'results', 'content', 'result_summary', 'observation', 'display_message'],
|
|
1457
|
+
typeof details.approval_decision === 'string' ? 'error' : undefined,
|
|
1458
|
+
);
|
|
1145
1459
|
addSection('Files', ['files', 'outputFiles']);
|
|
1146
1460
|
addSection('Error', ['error', 'stderr'], 'error');
|
|
1147
1461
|
if (targetEntry) consumedKeys.add(targetEntry.key);
|
|
@@ -1155,21 +1469,30 @@ function getToolDetailSections(message: AgentMessage): SummaryToolDetailSection[
|
|
|
1155
1469
|
}
|
|
1156
1470
|
|
|
1157
1471
|
function buildSummaryToolDetailItem(message: AgentMessage, index: number): SummaryToolDetailItem | undefined {
|
|
1472
|
+
if (message.type === AgentMessageType.REQUEST_INPUT) return undefined;
|
|
1473
|
+
|
|
1158
1474
|
const text = getMessageText(message);
|
|
1159
1475
|
const details = getDetailsRecord(message);
|
|
1476
|
+
const isPreamble = isToolPreambleMessage(message);
|
|
1160
1477
|
const kind = getToolDetailKind(message);
|
|
1161
1478
|
const toolNames = getToolNames(details);
|
|
1162
1479
|
const target = getToolTarget(details);
|
|
1163
1480
|
const command = typeof details.command === 'string' && details.command.trim() ? details.command.trim() : undefined;
|
|
1164
1481
|
const fallbackTitle = toolNames[0] ? humanizeIdentifier(toolNames[0]) : getReadableToolLabel(message);
|
|
1482
|
+
const approvalDecisionTitle = getApprovalDecisionLabel(details.approval_decision, fallbackTitle);
|
|
1483
|
+
const decisionText = getApprovalDecisionStatusText(details.approval_decision);
|
|
1484
|
+
const messageToHuman =
|
|
1485
|
+
typeof details.message_to_human === 'string' && details.message_to_human.trim()
|
|
1486
|
+
? details.message_to_human.trim()
|
|
1487
|
+
: undefined;
|
|
1165
1488
|
const title =
|
|
1166
1489
|
kind === 'think'
|
|
1167
1490
|
? text || fallbackTitle
|
|
1168
1491
|
: kind === 'command'
|
|
1169
|
-
? compactInlineText(text || command || fallbackTitle)
|
|
1170
|
-
: compactInlineText(target || text || fallbackTitle);
|
|
1492
|
+
? compactInlineText(messageToHuman || (!approvalDecisionTitle ? text : '') || command || fallbackTitle)
|
|
1493
|
+
: compactInlineText(messageToHuman || target || (!approvalDecisionTitle ? text : '') || fallbackTitle);
|
|
1171
1494
|
const normalizedText = text ? (kind === 'think' ? text : compactInlineText(text, 420)) : undefined;
|
|
1172
|
-
const shouldShowText = normalizedText && normalizedText !== title;
|
|
1495
|
+
const shouldShowText = normalizedText && normalizedText !== title && !approvalDecisionTitle;
|
|
1173
1496
|
|
|
1174
1497
|
if (!title && !shouldShowText) return undefined;
|
|
1175
1498
|
|
|
@@ -1178,41 +1501,130 @@ function buildSummaryToolDetailItem(message: AgentMessage, index: number): Summa
|
|
|
1178
1501
|
kind,
|
|
1179
1502
|
label: getToolDetailLabel(kind),
|
|
1180
1503
|
title,
|
|
1504
|
+
isPreamble,
|
|
1181
1505
|
command,
|
|
1182
1506
|
text: shouldShowText ? normalizedText : undefined,
|
|
1183
|
-
|
|
1507
|
+
toolName: getUniqueToolName(details),
|
|
1508
|
+
startedAt: getTimestampDetail(details[SUMMARY_TOOL_STARTED_AT_DETAIL_KEY]) ?? message.timestamp,
|
|
1509
|
+
finishedAt: getTimestampDetail(details[SUMMARY_TOOL_FINISHED_AT_DETAIL_KEY]) ?? message.timestamp,
|
|
1510
|
+
status: approvalDecisionTitle ? 'error' : (details.tool_status as ToolExecutionStatus | undefined),
|
|
1511
|
+
decisionText,
|
|
1184
1512
|
sections: getToolDetailSections(message),
|
|
1185
1513
|
};
|
|
1186
1514
|
}
|
|
1187
1515
|
|
|
1516
|
+
function isPlanToolMessage(message: AgentMessage): boolean {
|
|
1517
|
+
const details = getDetailsRecord(message);
|
|
1518
|
+
return details.tool === 'plan' || details.tool === 'update_plan';
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
function isPlanLifecycleMessage(message: AgentMessage): boolean {
|
|
1522
|
+
const details = getDetailsRecord(message);
|
|
1523
|
+
if (message.type === AgentMessageType.UPDATE && Array.isArray(details.updates)) return true;
|
|
1524
|
+
return message.type === AgentMessageType.PLAN && Array.isArray(details.plan);
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
function getActivityGroupIdentity(details: Record<string, unknown>): string | undefined {
|
|
1528
|
+
return typeof details.activity_group_id === 'string' && details.activity_group_id.trim()
|
|
1529
|
+
? details.activity_group_id.trim()
|
|
1530
|
+
: undefined;
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
function getToolIdentity(details: Record<string, unknown>): string | undefined {
|
|
1534
|
+
if (typeof details.tool_use_id === 'string' && details.tool_use_id.trim()) return details.tool_use_id.trim();
|
|
1535
|
+
if (typeof details.tool_run_id === 'string' && details.tool_run_id.trim()) return details.tool_run_id.trim();
|
|
1536
|
+
if (typeof details.tool === 'string' && details.tool.trim()) return details.tool.trim();
|
|
1537
|
+
return undefined;
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
function getSplitActivityGroups(messages: AgentMessage[]): Set<string> {
|
|
1541
|
+
const startedToolIdentities = new Map<string, Set<string>>();
|
|
1542
|
+
const approvalDecisionToolIdentities = new Map<string, Set<string>>();
|
|
1543
|
+
|
|
1544
|
+
const addIdentity = (
|
|
1545
|
+
groups: Map<string, Set<string>>,
|
|
1546
|
+
activityGroupId: string | undefined,
|
|
1547
|
+
toolIdentity: string | undefined,
|
|
1548
|
+
) => {
|
|
1549
|
+
if (!activityGroupId || !toolIdentity) return;
|
|
1550
|
+
const identities = groups.get(activityGroupId) ?? new Set<string>();
|
|
1551
|
+
identities.add(toolIdentity);
|
|
1552
|
+
groups.set(activityGroupId, identities);
|
|
1553
|
+
};
|
|
1554
|
+
|
|
1555
|
+
for (const message of messages) {
|
|
1556
|
+
const details = getDetailsRecord(message);
|
|
1557
|
+
const activityGroupId = getActivityGroupIdentity(details);
|
|
1558
|
+
const toolIdentity = getToolIdentity(details);
|
|
1559
|
+
|
|
1560
|
+
if (details.tool_event === 'started') {
|
|
1561
|
+
addIdentity(startedToolIdentities, activityGroupId, toolIdentity);
|
|
1562
|
+
}
|
|
1563
|
+
if (typeof details.approval_decision === 'string') {
|
|
1564
|
+
addIdentity(approvalDecisionToolIdentities, activityGroupId, toolIdentity);
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
return new Set(
|
|
1569
|
+
[...startedToolIdentities.entries(), ...approvalDecisionToolIdentities.entries()]
|
|
1570
|
+
.filter(([, identities]) => identities.size > 1)
|
|
1571
|
+
.map(([activityGroupId]) => activityGroupId),
|
|
1572
|
+
);
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
function getSummaryToolGroupId(details: Record<string, unknown>, splitActivityGroups: Set<string>): string | undefined {
|
|
1576
|
+
const activityGroupId = getActivityGroupIdentity(details);
|
|
1577
|
+
const toolIdentity = getToolIdentity(details);
|
|
1578
|
+
|
|
1579
|
+
if (activityGroupId) {
|
|
1580
|
+
if (toolIdentity && splitActivityGroups.has(activityGroupId)) {
|
|
1581
|
+
return `activity:${activityGroupId}:tool:${toolIdentity}`;
|
|
1582
|
+
}
|
|
1583
|
+
return `activity:${activityGroupId}`;
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1586
|
+
if (typeof details.tool_use_id === 'string' && details.tool_use_id.trim()) {
|
|
1587
|
+
return `tool-use:${details.tool_use_id.trim()}`;
|
|
1588
|
+
}
|
|
1589
|
+
if (typeof details.tool_run_id === 'string' && details.tool_run_id.trim())
|
|
1590
|
+
return `run:${details.tool_run_id.trim()}`;
|
|
1591
|
+
return undefined;
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1188
1594
|
function mergeSummaryToolMessages(messages: AgentMessage[]): AgentMessage[] {
|
|
1189
1595
|
const byGroupId = new Map<string, { index: number; messages: AgentMessage[] }>();
|
|
1190
1596
|
const ungrouped: Array<{ index: number; message: AgentMessage }> = [];
|
|
1597
|
+
let currentPlanGroupId: string | undefined;
|
|
1598
|
+
const splitActivityGroups = getSplitActivityGroups(messages);
|
|
1191
1599
|
|
|
1192
1600
|
messages.forEach((message, index) => {
|
|
1193
1601
|
const details = getDetailsRecord(message);
|
|
1194
1602
|
if (isToolPreambleMessage(message)) {
|
|
1195
1603
|
ungrouped.push({ index, message });
|
|
1604
|
+
currentPlanGroupId = undefined;
|
|
1196
1605
|
return;
|
|
1197
1606
|
}
|
|
1198
1607
|
|
|
1199
|
-
const
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
typeof details.tool_run_id === 'string' && details.tool_run_id.trim() ? details.tool_run_id : undefined;
|
|
1205
|
-
const groupId = activityGroupId ? `activity:${activityGroupId}` : runId ? `run:${runId}` : undefined;
|
|
1206
|
-
if (!groupId) {
|
|
1608
|
+
const groupId = getSummaryToolGroupId(details, splitActivityGroups);
|
|
1609
|
+
const legacyPlanGroupId = !groupId && isPlanLifecycleMessage(message) ? currentPlanGroupId : undefined;
|
|
1610
|
+
const effectiveGroupId = groupId ?? legacyPlanGroupId;
|
|
1611
|
+
|
|
1612
|
+
if (!effectiveGroupId) {
|
|
1207
1613
|
ungrouped.push({ index, message });
|
|
1208
1614
|
return;
|
|
1209
1615
|
}
|
|
1210
1616
|
|
|
1211
|
-
const group = byGroupId.get(
|
|
1617
|
+
const group = byGroupId.get(effectiveGroupId);
|
|
1212
1618
|
if (group) {
|
|
1213
1619
|
group.messages.push(message);
|
|
1214
1620
|
} else {
|
|
1215
|
-
byGroupId.set(
|
|
1621
|
+
byGroupId.set(effectiveGroupId, { index, messages: [message] });
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
if (isPlanToolMessage(message)) {
|
|
1625
|
+
currentPlanGroupId = effectiveGroupId;
|
|
1626
|
+
} else if (message.type === AgentMessageType.PLAN) {
|
|
1627
|
+
currentPlanGroupId = undefined;
|
|
1216
1628
|
}
|
|
1217
1629
|
});
|
|
1218
1630
|
|
|
@@ -1223,6 +1635,10 @@ function mergeSummaryToolMessages(messages: AgentMessage[]): AgentMessage[] {
|
|
|
1223
1635
|
const baseMessage = sortedMessages[sortedMessages.length - 1];
|
|
1224
1636
|
const startMessage = sortedMessages.find((message) => getDetailsRecord(message).tool_event === 'started');
|
|
1225
1637
|
const firstTextMessage = sortedMessages.find((message) => getMessageText(message));
|
|
1638
|
+
const latestApprovalDecisionMessage = sortedMessages.findLast((message) => {
|
|
1639
|
+
const details = getDetailsRecord(message);
|
|
1640
|
+
return typeof details.approval_decision === 'string' && Boolean(getMessageText(message));
|
|
1641
|
+
});
|
|
1226
1642
|
const commandTextMessage = sortedMessages.findLast((message) => getMessageText(message).startsWith('$ '));
|
|
1227
1643
|
const latestStatusMessage = sortedMessages.findLast(
|
|
1228
1644
|
(message) =>
|
|
@@ -1236,9 +1652,19 @@ function mergeSummaryToolMessages(messages: AgentMessage[]): AgentMessage[] {
|
|
|
1236
1652
|
if (latestStatusMessage && mergedDetails.error === undefined && mergedDetails.stderr === undefined) {
|
|
1237
1653
|
mergedDetails.error = getMessageText(latestStatusMessage);
|
|
1238
1654
|
}
|
|
1655
|
+
if (
|
|
1656
|
+
!latestStatusMessage &&
|
|
1657
|
+
sortedMessages.some(
|
|
1658
|
+
(message) => message.type === AgentMessageType.PLAN && Array.isArray(message.details?.plan),
|
|
1659
|
+
)
|
|
1660
|
+
) {
|
|
1661
|
+
mergedDetails.tool_status = 'completed';
|
|
1662
|
+
}
|
|
1239
1663
|
if (commandTextMessage && mergedDetails.command === undefined) {
|
|
1240
1664
|
mergedDetails.command = getMessageText(commandTextMessage);
|
|
1241
1665
|
}
|
|
1666
|
+
mergedDetails[SUMMARY_TOOL_STARTED_AT_DETAIL_KEY] = sortedMessages[0]?.timestamp;
|
|
1667
|
+
mergedDetails[SUMMARY_TOOL_FINISHED_AT_DETAIL_KEY] = sortedMessages[sortedMessages.length - 1]?.timestamp;
|
|
1242
1668
|
const messageToHuman =
|
|
1243
1669
|
typeof startMessage?.details?.message_to_human === 'string' ? startMessage.details.message_to_human : '';
|
|
1244
1670
|
|
|
@@ -1246,7 +1672,10 @@ function mergeSummaryToolMessages(messages: AgentMessage[]): AgentMessage[] {
|
|
|
1246
1672
|
index,
|
|
1247
1673
|
message: {
|
|
1248
1674
|
...baseMessage,
|
|
1249
|
-
message:
|
|
1675
|
+
message:
|
|
1676
|
+
latestApprovalDecisionMessage?.message ||
|
|
1677
|
+
messageToHuman ||
|
|
1678
|
+
(firstTextMessage ? firstTextMessage.message : baseMessage.message),
|
|
1250
1679
|
details: mergedDetails,
|
|
1251
1680
|
},
|
|
1252
1681
|
};
|
|
@@ -1296,6 +1725,54 @@ function ToolDetailIcon({ kind, status }: { kind: SummaryToolDetailKind; status?
|
|
|
1296
1725
|
}
|
|
1297
1726
|
}
|
|
1298
1727
|
|
|
1728
|
+
interface ToolDetailMetadataEntry {
|
|
1729
|
+
label: string;
|
|
1730
|
+
value: string;
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
function getToolDetailMetadata(item: SummaryToolDetailItem): ToolDetailMetadataEntry[] {
|
|
1734
|
+
const entries: ToolDetailMetadataEntry[] = [];
|
|
1735
|
+
const startedMs = parseTimestampMs(item.startedAt);
|
|
1736
|
+
const finishedMs = parseTimestampMs(item.finishedAt);
|
|
1737
|
+
const startedAt = formatToolDetailTimestamp(item.startedAt);
|
|
1738
|
+
const finishedAt = formatToolDetailTimestamp(item.finishedAt);
|
|
1739
|
+
|
|
1740
|
+
if (item.toolName) {
|
|
1741
|
+
entries.push({ label: 'Tool', value: item.toolName });
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
if (startedAt && finishedAt && startedMs !== undefined && finishedMs !== undefined && startedMs !== finishedMs) {
|
|
1745
|
+
entries.push({ label: 'Started', value: startedAt });
|
|
1746
|
+
entries.push({ label: 'Ended', value: finishedAt });
|
|
1747
|
+
entries.push({ label: 'Duration', value: formatDuration(getDurationSeconds(item.startedAt, item.finishedAt)) });
|
|
1748
|
+
} else if (startedAt || finishedAt) {
|
|
1749
|
+
entries.push({ label: 'Time', value: startedAt ?? finishedAt ?? '' });
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
return entries;
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
function ToolDetailMetadata({ hasDetailContent, item }: { hasDetailContent: boolean; item: SummaryToolDetailItem }) {
|
|
1756
|
+
const entries = getToolDetailMetadata(item);
|
|
1757
|
+
if (entries.length === 0) return null;
|
|
1758
|
+
|
|
1759
|
+
return (
|
|
1760
|
+
<dl
|
|
1761
|
+
className={cn(
|
|
1762
|
+
'flex flex-wrap gap-x-4 gap-y-1 text-xs',
|
|
1763
|
+
hasDetailContent && 'mb-3 border-b border-border/60 pb-2',
|
|
1764
|
+
)}
|
|
1765
|
+
>
|
|
1766
|
+
{entries.map((entry) => (
|
|
1767
|
+
<div key={entry.label} className="flex min-w-0 items-baseline gap-1.5">
|
|
1768
|
+
<dt className="shrink-0 text-muted">{entry.label}</dt>
|
|
1769
|
+
<dd className="min-w-0 wrap-break-word font-medium text-foreground/80">{entry.value}</dd>
|
|
1770
|
+
</div>
|
|
1771
|
+
))}
|
|
1772
|
+
</dl>
|
|
1773
|
+
);
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1299
1776
|
function ToolDetailSection({ section }: { section: SummaryToolDetailSection }) {
|
|
1300
1777
|
const value = section.value;
|
|
1301
1778
|
const isPrimitive = typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean';
|
|
@@ -1363,6 +1840,8 @@ function formatToolPrimaryText(item: SummaryToolDetailItem): string {
|
|
|
1363
1840
|
|
|
1364
1841
|
function formatToolDetailCopyText(item: SummaryToolDetailItem): string {
|
|
1365
1842
|
const parts = [getToolPanelTitle(item), formatToolPrimaryText(item)];
|
|
1843
|
+
const metadata = getToolDetailMetadata(item).map((entry) => `${entry.label}: ${entry.value}`);
|
|
1844
|
+
if (metadata.length > 0) parts.push(metadata.join('\n'));
|
|
1366
1845
|
if (item.text) parts.push(item.text);
|
|
1367
1846
|
|
|
1368
1847
|
for (const section of item.sections) {
|
|
@@ -1404,9 +1883,10 @@ async function copyTextToClipboard(text: string): Promise<boolean> {
|
|
|
1404
1883
|
}
|
|
1405
1884
|
|
|
1406
1885
|
function SummaryToolDetailPanel({ item }: { item: SummaryToolDetailItem }) {
|
|
1407
|
-
const copyText = formatToolDetailCopyText(item);
|
|
1408
1886
|
const commandText = item.kind === 'command' && item.command ? formatToolPrimaryText(item) : undefined;
|
|
1409
1887
|
const fallbackText = !commandText && item.sections.length === 0 ? item.text : undefined;
|
|
1888
|
+
const hasDetailContent = Boolean(commandText || fallbackText || item.sections.length);
|
|
1889
|
+
const copyText = formatToolDetailCopyText(item);
|
|
1410
1890
|
const [copyState, setCopyState] = useState<'idle' | 'copied' | 'failed'>('idle');
|
|
1411
1891
|
const copyResetRef = useRef<number | undefined>(undefined);
|
|
1412
1892
|
|
|
@@ -1426,23 +1906,26 @@ function SummaryToolDetailPanel({ item }: { item: SummaryToolDetailItem }) {
|
|
|
1426
1906
|
|
|
1427
1907
|
return (
|
|
1428
1908
|
<div className="relative mt-2 rounded-lg border border-border/70 bg-mixer-muted/10 p-3 shadow-sm">
|
|
1429
|
-
|
|
1430
|
-
<
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1909
|
+
{hasDetailContent ? (
|
|
1910
|
+
<div className="absolute end-2 top-2">
|
|
1911
|
+
<button
|
|
1912
|
+
type="button"
|
|
1913
|
+
className={cn(
|
|
1914
|
+
'inline-flex size-7 shrink-0 items-center justify-center rounded-md text-muted opacity-70 transition',
|
|
1915
|
+
'hover:bg-mixer-muted/20 hover:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
|
|
1916
|
+
copyState === 'copied' && 'text-success opacity-100',
|
|
1917
|
+
copyState === 'failed' && 'text-destructive opacity-100',
|
|
1918
|
+
)}
|
|
1919
|
+
onClick={copyDetails}
|
|
1920
|
+
aria-label="Copy tool details"
|
|
1921
|
+
title="Copy tool details"
|
|
1922
|
+
>
|
|
1923
|
+
{copyState === 'copied' ? <CheckCircle className="size-4" /> : <CopyIcon className="size-4" />}
|
|
1924
|
+
</button>
|
|
1925
|
+
</div>
|
|
1926
|
+
) : null}
|
|
1927
|
+
<div className={cn(hasDetailContent && 'pe-7')}>
|
|
1928
|
+
<ToolDetailMetadata item={item} hasDetailContent={hasDetailContent} />
|
|
1446
1929
|
{commandText ? (
|
|
1447
1930
|
<pre className="mb-3 whitespace-pre-wrap break-words font-mono text-sm leading-6 text-foreground/85">
|
|
1448
1931
|
{commandText}
|
|
@@ -1459,15 +1942,20 @@ function SummaryToolDetailPanel({ item }: { item: SummaryToolDetailItem }) {
|
|
|
1459
1942
|
</div>
|
|
1460
1943
|
) : null}
|
|
1461
1944
|
</div>
|
|
1462
|
-
{copyState === 'failed'
|
|
1945
|
+
{copyState === 'failed' && hasDetailContent ? (
|
|
1946
|
+
<div className="mt-3 text-xs text-destructive">Copy failed</div>
|
|
1947
|
+
) : null}
|
|
1463
1948
|
</div>
|
|
1464
1949
|
);
|
|
1465
1950
|
}
|
|
1466
1951
|
|
|
1467
1952
|
function SummaryToolTimelineItem({ item }: { item: SummaryToolDetailItem }) {
|
|
1468
|
-
const
|
|
1469
|
-
const
|
|
1953
|
+
const isDecision = Boolean(item.decisionText);
|
|
1954
|
+
const isAttention = !isDecision && (item.status === 'error' || item.status === 'warning');
|
|
1955
|
+
const hasMetadata = getToolDetailMetadata(item).length > 0;
|
|
1956
|
+
const hasDetails = Boolean(item.command || item.text || item.sections.length || hasMetadata);
|
|
1470
1957
|
const [isExpanded, setIsExpanded] = useState(false);
|
|
1958
|
+
const iconStatus = isDecision ? undefined : item.status;
|
|
1471
1959
|
|
|
1472
1960
|
return (
|
|
1473
1961
|
<div className="min-w-0">
|
|
@@ -1488,11 +1976,15 @@ function SummaryToolTimelineItem({ item }: { item: SummaryToolDetailItem }) {
|
|
|
1488
1976
|
isAttention ? 'text-attention' : 'text-muted',
|
|
1489
1977
|
)}
|
|
1490
1978
|
>
|
|
1491
|
-
<ToolDetailIcon kind={item.kind} status={
|
|
1979
|
+
<ToolDetailIcon kind={item.kind} status={iconStatus} />
|
|
1492
1980
|
</span>
|
|
1493
|
-
<span className="
|
|
1494
|
-
<span className="
|
|
1495
|
-
|
|
1981
|
+
<span className="min-w-0 text-sm text-muted">
|
|
1982
|
+
<span className="break-words">{item.title}</span>
|
|
1983
|
+
{item.decisionText ? (
|
|
1984
|
+
<Badge variant="destructive" className="ms-2 rounded-full shadow-sm shadow-destructive/10">
|
|
1985
|
+
{item.decisionText}
|
|
1986
|
+
</Badge>
|
|
1987
|
+
) : null}
|
|
1496
1988
|
</span>
|
|
1497
1989
|
{hasDetails ? (
|
|
1498
1990
|
<ChevronDown
|
|
@@ -1513,27 +2005,87 @@ function SummaryToolTimelineItem({ item }: { item: SummaryToolDetailItem }) {
|
|
|
1513
2005
|
);
|
|
1514
2006
|
}
|
|
1515
2007
|
|
|
1516
|
-
function
|
|
2008
|
+
function SummaryThoughtProseItem({
|
|
2009
|
+
item,
|
|
2010
|
+
artifactRunId,
|
|
2011
|
+
disableCollapse,
|
|
2012
|
+
}: {
|
|
2013
|
+
item: SummaryToolDetailItem;
|
|
2014
|
+
artifactRunId?: string;
|
|
2015
|
+
disableCollapse?: boolean;
|
|
2016
|
+
}) {
|
|
2017
|
+
const { t } = useUITranslation();
|
|
1517
2018
|
const text = item.text ?? item.title;
|
|
2019
|
+
const normalizedText = text.trim();
|
|
2020
|
+
const [isExpanded, setIsExpanded] = useState(false);
|
|
2021
|
+
const explicitLineCount = normalizedText ? normalizedText.split(/\r?\n/).length : 0;
|
|
2022
|
+
const isLong =
|
|
2023
|
+
normalizedText.length > SUMMARY_THOUGHT_COLLAPSE_THRESHOLD ||
|
|
2024
|
+
explicitLineCount > SUMMARY_THOUGHT_COLLAPSE_LINES;
|
|
2025
|
+
const toggleLabel = isExpanded ? t('agent.showLess') : t('agent.showMore');
|
|
1518
2026
|
|
|
1519
2027
|
return (
|
|
1520
|
-
<div className="min-w-0 py-1
|
|
1521
|
-
<div
|
|
2028
|
+
<div className="min-w-0 py-1">
|
|
2029
|
+
<div
|
|
2030
|
+
data-testid="summary-thought-prose"
|
|
2031
|
+
className={cn(
|
|
2032
|
+
SUMMARY_PROSE_CLASS,
|
|
2033
|
+
isLong &&
|
|
2034
|
+
!disableCollapse &&
|
|
2035
|
+
!isExpanded &&
|
|
2036
|
+
'[display:-webkit-box] overflow-hidden [-webkit-box-orient:vertical] [-webkit-line-clamp:6]',
|
|
2037
|
+
)}
|
|
2038
|
+
style={{ overflowWrap: 'anywhere' }}
|
|
2039
|
+
>
|
|
1522
2040
|
<MarkdownRenderer artifactRunId={artifactRunId} components={DEFAULT_AGENT_MARKDOWN_COMPONENTS}>
|
|
1523
2041
|
{text}
|
|
1524
2042
|
</MarkdownRenderer>
|
|
1525
2043
|
</div>
|
|
2044
|
+
{isLong && !disableCollapse ? (
|
|
2045
|
+
<div className="mt-1.5 flex justify-end">
|
|
2046
|
+
<button
|
|
2047
|
+
type="button"
|
|
2048
|
+
aria-expanded={isExpanded}
|
|
2049
|
+
className={cn(
|
|
2050
|
+
'inline-flex items-center gap-1 text-sm font-medium text-muted transition-colors',
|
|
2051
|
+
'[text-decoration:none] hover:text-foreground hover:[text-decoration:none]',
|
|
2052
|
+
'focus-visible:text-foreground focus-visible:[text-decoration:none]',
|
|
2053
|
+
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
|
|
2054
|
+
)}
|
|
2055
|
+
onClick={() => setIsExpanded((current) => !current)}
|
|
2056
|
+
>
|
|
2057
|
+
{toggleLabel}
|
|
2058
|
+
<ChevronDown
|
|
2059
|
+
className={cn('size-4 transition-transform', isExpanded && 'rotate-180')}
|
|
2060
|
+
aria-hidden="true"
|
|
2061
|
+
/>
|
|
2062
|
+
</button>
|
|
2063
|
+
</div>
|
|
2064
|
+
) : null}
|
|
1526
2065
|
</div>
|
|
1527
2066
|
);
|
|
1528
2067
|
}
|
|
1529
2068
|
|
|
1530
|
-
function SummaryToolTimeline({
|
|
2069
|
+
function SummaryToolTimeline({
|
|
2070
|
+
items,
|
|
2071
|
+
artifactRunId,
|
|
2072
|
+
disablePreambleCollapse,
|
|
2073
|
+
}: {
|
|
2074
|
+
items: SummaryToolDetailItem[];
|
|
2075
|
+
artifactRunId?: string;
|
|
2076
|
+
disablePreambleCollapse?: boolean;
|
|
2077
|
+
}) {
|
|
1531
2078
|
return (
|
|
1532
2079
|
<div className="mt-3">
|
|
1533
2080
|
<div className="space-y-3">
|
|
1534
2081
|
{items.map((item) =>
|
|
1535
|
-
item.kind === 'think' ? (
|
|
1536
|
-
<
|
|
2082
|
+
item.isPreamble || item.kind === 'think' ? (
|
|
2083
|
+
<SummaryThoughtProseItem
|
|
2084
|
+
key={item.key}
|
|
2085
|
+
item={item}
|
|
2086
|
+
artifactRunId={artifactRunId}
|
|
2087
|
+
disableCollapse={disablePreambleCollapse}
|
|
2088
|
+
/>
|
|
1537
2089
|
) : (
|
|
1538
2090
|
<SummaryToolTimelineItem key={item.key} item={item} />
|
|
1539
2091
|
),
|
|
@@ -1563,17 +2115,47 @@ function SummaryStreamingMessage({
|
|
|
1563
2115
|
);
|
|
1564
2116
|
}
|
|
1565
2117
|
|
|
2118
|
+
function SummaryStoppedMessage({
|
|
2119
|
+
message,
|
|
2120
|
+
startTimestamp,
|
|
2121
|
+
endTimestamp,
|
|
2122
|
+
className,
|
|
2123
|
+
}: {
|
|
2124
|
+
message: AgentMessage;
|
|
2125
|
+
startTimestamp?: number | string;
|
|
2126
|
+
endTimestamp?: number | string;
|
|
2127
|
+
className?: string;
|
|
2128
|
+
}) {
|
|
2129
|
+
const { t } = useUITranslation();
|
|
2130
|
+
const duration = formatDuration(
|
|
2131
|
+
getDurationSeconds(startTimestamp ?? message.timestamp, endTimestamp ?? message.timestamp),
|
|
2132
|
+
);
|
|
2133
|
+
|
|
2134
|
+
return (
|
|
2135
|
+
<div className={cn('mx-auto w-full max-w-3xl px-1', className)} data-testid="summary-stopped-message">
|
|
2136
|
+
<div className="flex items-center justify-end gap-2 text-lg font-medium text-muted sm:text-xl">
|
|
2137
|
+
<span>{t('agent.youStoppedAfter', { duration })}</span>
|
|
2138
|
+
<MessageDeliveryStatus message={message} className="h-5 w-5" />
|
|
2139
|
+
</div>
|
|
2140
|
+
<div className="mt-5 border-b border-border/70" />
|
|
2141
|
+
</div>
|
|
2142
|
+
);
|
|
2143
|
+
}
|
|
2144
|
+
|
|
1566
2145
|
function SummaryActivityRow({
|
|
1567
2146
|
label,
|
|
1568
|
-
status,
|
|
1569
2147
|
timestamp,
|
|
1570
2148
|
durationSeconds,
|
|
1571
2149
|
showElapsed,
|
|
1572
2150
|
details,
|
|
1573
2151
|
emptyDetailsLabel,
|
|
1574
2152
|
defaultExpanded = false,
|
|
2153
|
+
disablePreambleCollapse = false,
|
|
1575
2154
|
className,
|
|
1576
2155
|
artifactRunId,
|
|
2156
|
+
onSendMessage,
|
|
2157
|
+
answeredToolApprovalRequestInputKeys,
|
|
2158
|
+
resolvedToolApprovalKeys,
|
|
1577
2159
|
}: {
|
|
1578
2160
|
label: string;
|
|
1579
2161
|
status?: ToolExecutionStatus;
|
|
@@ -1583,23 +2165,37 @@ function SummaryActivityRow({
|
|
|
1583
2165
|
details?: AgentMessage[];
|
|
1584
2166
|
emptyDetailsLabel?: string;
|
|
1585
2167
|
defaultExpanded?: boolean;
|
|
2168
|
+
disablePreambleCollapse?: boolean;
|
|
1586
2169
|
className?: string;
|
|
1587
2170
|
artifactRunId?: string;
|
|
2171
|
+
onSendMessage?: (message: string, metadata?: Record<string, unknown>) => void;
|
|
2172
|
+
answeredToolApprovalRequestInputKeys?: Set<string>;
|
|
2173
|
+
resolvedToolApprovalKeys?: Set<string>;
|
|
1588
2174
|
}) {
|
|
1589
2175
|
const [isExpanded, setIsExpanded] = useState(defaultExpanded);
|
|
1590
2176
|
const isLiveElapsed = showElapsed && durationSeconds === undefined;
|
|
1591
2177
|
const liveElapsed = useLiveElapsedSeconds(timestamp, isLiveElapsed);
|
|
1592
2178
|
const elapsed = durationSeconds ?? liveElapsed;
|
|
1593
2179
|
const shouldShowElapsed = showElapsed && timestamp !== undefined;
|
|
1594
|
-
const isAttention = status === 'error' || status === 'warning';
|
|
1595
2180
|
const detailItems = useMemo(() => buildSummaryToolDetailItems(details ?? []), [details]);
|
|
1596
|
-
const
|
|
2181
|
+
const requestInputMessages = useMemo(
|
|
2182
|
+
() =>
|
|
2183
|
+
(details ?? []).filter(
|
|
2184
|
+
(message): message is RequestInputMessageWithUx =>
|
|
2185
|
+
hasRequestInputUx(message) &&
|
|
2186
|
+
!isToolApprovalRequestInputHidden(
|
|
2187
|
+
message,
|
|
2188
|
+
answeredToolApprovalRequestInputKeys ?? new Set<string>(),
|
|
2189
|
+
resolvedToolApprovalKeys ?? new Set<string>(),
|
|
2190
|
+
),
|
|
2191
|
+
),
|
|
2192
|
+
[answeredToolApprovalRequestInputKeys, details, resolvedToolApprovalKeys],
|
|
2193
|
+
);
|
|
2194
|
+
const canExpand = detailItems.length > 0 || requestInputMessages.length > 0 || Boolean(emptyDetailsLabel);
|
|
1597
2195
|
|
|
1598
2196
|
return (
|
|
1599
2197
|
<div className={cn('mx-auto w-full max-w-3xl px-1', className)}>
|
|
1600
|
-
<div
|
|
1601
|
-
className={cn('border-b border-border/70 pb-3 text-sm', isAttention ? 'text-attention' : 'text-muted')}
|
|
1602
|
-
>
|
|
2198
|
+
<div className="border-b border-border/70 pb-3 text-sm text-muted">
|
|
1603
2199
|
<button
|
|
1604
2200
|
type="button"
|
|
1605
2201
|
className={cn(
|
|
@@ -1624,8 +2220,46 @@ function SummaryActivityRow({
|
|
|
1624
2220
|
) : null}
|
|
1625
2221
|
</button>
|
|
1626
2222
|
{canExpand && isExpanded ? (
|
|
1627
|
-
detailItems.length > 0 ? (
|
|
1628
|
-
|
|
2223
|
+
detailItems.length > 0 || requestInputMessages.length > 0 ? (
|
|
2224
|
+
<>
|
|
2225
|
+
{detailItems.length > 0 ? (
|
|
2226
|
+
<SummaryToolTimeline
|
|
2227
|
+
items={detailItems}
|
|
2228
|
+
artifactRunId={artifactRunId}
|
|
2229
|
+
disablePreambleCollapse={disablePreambleCollapse}
|
|
2230
|
+
/>
|
|
2231
|
+
) : null}
|
|
2232
|
+
{requestInputMessages.length > 0 ? (
|
|
2233
|
+
<div className="mt-3 space-y-3">
|
|
2234
|
+
{requestInputMessages.map((message) => {
|
|
2235
|
+
const uxConfig = message.details.ux;
|
|
2236
|
+
return (
|
|
2237
|
+
<AskUserWidget
|
|
2238
|
+
key={getAgentMessageRenderKey(message, 'work-request-input')}
|
|
2239
|
+
question={getRequestInputDisplayText(message)}
|
|
2240
|
+
options={uxConfig.options}
|
|
2241
|
+
variant={uxConfig.variant}
|
|
2242
|
+
multiSelect={uxConfig.multiSelect}
|
|
2243
|
+
onSelect={(optionId) => onSendMessage?.(optionId)}
|
|
2244
|
+
onMultiSelect={(optionIds) => onSendMessage?.(optionIds.join(', '))}
|
|
2245
|
+
allowFreeResponse={
|
|
2246
|
+
!uxConfig.options?.length || !!uxConfig.free_response
|
|
2247
|
+
}
|
|
2248
|
+
placeholder={uxConfig.free_response?.placeholder}
|
|
2249
|
+
submitLabel={uxConfig.free_response?.submit_label}
|
|
2250
|
+
onSubmit={(value) =>
|
|
2251
|
+
onSendMessage?.(value, uxConfig.free_response?.metadata)
|
|
2252
|
+
}
|
|
2253
|
+
hideBorder
|
|
2254
|
+
compact
|
|
2255
|
+
className="my-0"
|
|
2256
|
+
cardClassName="bg-background/60 shadow-none"
|
|
2257
|
+
/>
|
|
2258
|
+
);
|
|
2259
|
+
})}
|
|
2260
|
+
</div>
|
|
2261
|
+
) : null}
|
|
2262
|
+
</>
|
|
1629
2263
|
) : (
|
|
1630
2264
|
<div className="mt-3 flex items-center gap-2 text-sm text-muted">
|
|
1631
2265
|
<Terminal className="size-4 opacity-70" aria-hidden="true" />
|
|
@@ -1709,7 +2343,7 @@ interface AllMessagesMixedProps {
|
|
|
1709
2343
|
taskLabels?: Map<string, string>; // Maps task IDs to more descriptive labels
|
|
1710
2344
|
streamingMessages?: Map<string, StreamingData>; // Real-time streaming chunks
|
|
1711
2345
|
/** Callback when user sends a message (e.g., from proposal selection) */
|
|
1712
|
-
onSendMessage?: (message: string) => void;
|
|
2346
|
+
onSendMessage?: (message: string, metadata?: Record<string, unknown>) => void;
|
|
1713
2347
|
/** Stable index for thinking messages (changes on 4s interval) */
|
|
1714
2348
|
thinkingMessageIndex?: number;
|
|
1715
2349
|
/** className overrides passed to every MessageItem */
|
|
@@ -1744,12 +2378,18 @@ interface AllMessagesMixedProps {
|
|
|
1744
2378
|
initialRequestTitle?: string;
|
|
1745
2379
|
/** Optional caller-provided renderer for agent-specific request shapes. */
|
|
1746
2380
|
initialRequestTemplate?: AgentInitialRequestTemplate;
|
|
2381
|
+
/** Whether the synthetic initial request fallback should render when no persisted question is present. */
|
|
2382
|
+
showInitialRequest?: boolean;
|
|
1747
2383
|
/** Message types to exclude from the conversation view */
|
|
1748
2384
|
hiddenMessageTypes?: AgentMessageType[];
|
|
1749
2385
|
/** Test/playback mode: keep the current scroll position while the rendered message slice changes. */
|
|
1750
2386
|
disableAutoScroll?: boolean;
|
|
1751
2387
|
/** Whether REQUEST_INPUT messages render their active controls in the transcript. */
|
|
1752
2388
|
renderRequestInputControls?: boolean;
|
|
2389
|
+
/** Active workstream selected by the parent conversation shell. */
|
|
2390
|
+
activeWorkstream?: string;
|
|
2391
|
+
/** Called when the user selects a different workstream from the conversation. */
|
|
2392
|
+
onActiveWorkstreamChange?: (workstreamId: string) => void;
|
|
1753
2393
|
}
|
|
1754
2394
|
|
|
1755
2395
|
// PERFORMANCE: Throttle interval for auto-scroll (ms)
|
|
@@ -1779,9 +2419,12 @@ function AllMessagesMixedComponent({
|
|
|
1779
2419
|
initialRequestSchema,
|
|
1780
2420
|
initialRequestTitle,
|
|
1781
2421
|
initialRequestTemplate,
|
|
2422
|
+
showInitialRequest,
|
|
1782
2423
|
hiddenMessageTypes,
|
|
1783
2424
|
disableAutoScroll = false,
|
|
1784
2425
|
renderRequestInputControls = true,
|
|
2426
|
+
activeWorkstream: controlledActiveWorkstream,
|
|
2427
|
+
onActiveWorkstreamChange,
|
|
1785
2428
|
}: AllMessagesMixedProps) {
|
|
1786
2429
|
if (!artifactRunId) {
|
|
1787
2430
|
console.warn('[AllMessagesMixed] artifactRunId prop is missing!');
|
|
@@ -1789,7 +2432,17 @@ function AllMessagesMixedComponent({
|
|
|
1789
2432
|
|
|
1790
2433
|
const { t } = useUITranslation();
|
|
1791
2434
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
|
1792
|
-
const [
|
|
2435
|
+
const [internalActiveWorkstream, setInternalActiveWorkstream] = useState<string>('all');
|
|
2436
|
+
const activeWorkstream = controlledActiveWorkstream ?? internalActiveWorkstream;
|
|
2437
|
+
const setActiveWorkstream = useCallback(
|
|
2438
|
+
(workstreamId: string) => {
|
|
2439
|
+
if (controlledActiveWorkstream === undefined) {
|
|
2440
|
+
setInternalActiveWorkstream(workstreamId);
|
|
2441
|
+
}
|
|
2442
|
+
onActiveWorkstreamChange?.(workstreamId);
|
|
2443
|
+
},
|
|
2444
|
+
[controlledActiveWorkstream, onActiveWorkstreamChange],
|
|
2445
|
+
);
|
|
1793
2446
|
|
|
1794
2447
|
// PERFORMANCE: Throttle auto-scroll to prevent layout thrashing
|
|
1795
2448
|
// During streaming, scrollIntoView was being called 30+ times/sec
|
|
@@ -1884,9 +2537,9 @@ function AllMessagesMixedComponent({
|
|
|
1884
2537
|
// Sort all messages chronologically and dedupe adjacent identical messages
|
|
1885
2538
|
// Low-signal messages are suppressed at the source (server-side) via shouldSuppressLowSignalMessage
|
|
1886
2539
|
const sortedMessages = React.useMemo(() => {
|
|
1887
|
-
const filtered =
|
|
1888
|
-
|
|
1889
|
-
|
|
2540
|
+
const filtered = messages.filter(
|
|
2541
|
+
(message) => !isDocumentPanelEventMessage(message) && !hiddenMessageTypes?.includes(message.type),
|
|
2542
|
+
);
|
|
1890
2543
|
|
|
1891
2544
|
const sorted = [...filtered].sort((a, b) => {
|
|
1892
2545
|
const timeA = typeof a.timestamp === 'number' ? a.timestamp : new Date(a.timestamp).getTime();
|
|
@@ -1909,17 +2562,60 @@ function AllMessagesMixedComponent({
|
|
|
1909
2562
|
return deduped;
|
|
1910
2563
|
}, [messages, hiddenMessageTypes]);
|
|
1911
2564
|
|
|
1912
|
-
// Get workstreams from messages - only from message.workstream_id
|
|
1913
2565
|
const workstreams = React.useMemo(() => {
|
|
1914
|
-
// Just get the basic workstreams from the messages
|
|
1915
2566
|
const extractedWorkstreams = extractWorkstreams(sortedMessages);
|
|
1916
2567
|
|
|
1917
|
-
|
|
1918
|
-
|
|
2568
|
+
sortedMessages.forEach((message) => {
|
|
2569
|
+
const details = getWorkstreamLaunchDetails(message) ?? getWorkstreamActivityDetails(message);
|
|
2570
|
+
if (!details) return;
|
|
2571
|
+
extractedWorkstreams.set(
|
|
2572
|
+
details.workstreamId,
|
|
2573
|
+
getWorkstreamDisplayName(details.workstreamId, details.interaction),
|
|
2574
|
+
);
|
|
2575
|
+
});
|
|
1919
2576
|
|
|
1920
2577
|
return extractedWorkstreams;
|
|
1921
2578
|
}, [sortedMessages]);
|
|
1922
2579
|
|
|
2580
|
+
const activeWorkstreamName = React.useMemo(() => {
|
|
2581
|
+
if (activeWorkstream === 'all') return undefined;
|
|
2582
|
+
return workstreams.get(activeWorkstream) ?? formatWorkstreamName(activeWorkstream);
|
|
2583
|
+
}, [activeWorkstream, workstreams]);
|
|
2584
|
+
|
|
2585
|
+
const scrollToTop = useCallback(() => {
|
|
2586
|
+
const container = containerRef.current;
|
|
2587
|
+
if (!container) return;
|
|
2588
|
+
|
|
2589
|
+
programmaticScrollRef.current = true;
|
|
2590
|
+
if (typeof container.scrollTo === 'function') {
|
|
2591
|
+
container.scrollTo({ top: 0, behavior: 'smooth' });
|
|
2592
|
+
} else {
|
|
2593
|
+
container.scrollTop = 0;
|
|
2594
|
+
}
|
|
2595
|
+
requestAnimationFrame(() => {
|
|
2596
|
+
programmaticScrollRef.current = false;
|
|
2597
|
+
});
|
|
2598
|
+
}, []);
|
|
2599
|
+
|
|
2600
|
+
const handleSelectWorkstream = useCallback(
|
|
2601
|
+
(workstreamId: string) => {
|
|
2602
|
+
setActiveWorkstream(workstreamId);
|
|
2603
|
+
requestAnimationFrame(scrollToTop);
|
|
2604
|
+
},
|
|
2605
|
+
[scrollToTop, setActiveWorkstream],
|
|
2606
|
+
);
|
|
2607
|
+
|
|
2608
|
+
const handleShowMainAgentChat = useCallback(() => {
|
|
2609
|
+
setActiveWorkstream('all');
|
|
2610
|
+
requestAnimationFrame(scrollToTop);
|
|
2611
|
+
}, [scrollToTop, setActiveWorkstream]);
|
|
2612
|
+
|
|
2613
|
+
useEffect(() => {
|
|
2614
|
+
if (activeWorkstream !== 'all' && !workstreams.has(activeWorkstream)) {
|
|
2615
|
+
setActiveWorkstream('all');
|
|
2616
|
+
}
|
|
2617
|
+
}, [activeWorkstream, workstreams, setActiveWorkstream]);
|
|
2618
|
+
|
|
1923
2619
|
// Count messages per workstream
|
|
1924
2620
|
const workstreamCounts = React.useMemo(() => {
|
|
1925
2621
|
const counts = new Map<string, number>();
|
|
@@ -1942,16 +2638,27 @@ function AllMessagesMixedComponent({
|
|
|
1942
2638
|
|
|
1943
2639
|
// Filter messages based on active workstream
|
|
1944
2640
|
const displayMessages = React.useMemo(() => {
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
return filterMessagesByWorkstream(sortedMessages, activeWorkstream);
|
|
2641
|
+
return attachWriteArtifactCompletionMessages(
|
|
2642
|
+
filterMessagesForActiveWorkstream(sortedMessages, activeWorkstream),
|
|
2643
|
+
);
|
|
1949
2644
|
}, [sortedMessages, activeWorkstream]);
|
|
1950
2645
|
|
|
1951
2646
|
const answeredRequestInputKeys = React.useMemo(
|
|
1952
2647
|
() => getAnsweredRequestInputKeys(displayMessages),
|
|
1953
2648
|
[displayMessages],
|
|
1954
2649
|
);
|
|
2650
|
+
const resolvedToolApprovalKeys = React.useMemo(
|
|
2651
|
+
() => getResolvedToolApprovalKeys(displayMessages),
|
|
2652
|
+
[displayMessages],
|
|
2653
|
+
);
|
|
2654
|
+
const answeredToolApprovalRequestInputKeys = React.useMemo(
|
|
2655
|
+
() => getAnsweredToolApprovalRequestInputKeys(displayMessages),
|
|
2656
|
+
[displayMessages],
|
|
2657
|
+
);
|
|
2658
|
+
const hiddenToolApprovalAnswerKeys = React.useMemo(
|
|
2659
|
+
() => getHiddenToolApprovalAnswerKeys(displayMessages),
|
|
2660
|
+
[displayMessages],
|
|
2661
|
+
);
|
|
1955
2662
|
const externallyRenderedRequestInputKey = React.useMemo(() => {
|
|
1956
2663
|
if (renderRequestInputControls) return undefined;
|
|
1957
2664
|
const pendingRequestInput = getPendingRequestInputMessage(displayMessages);
|
|
@@ -1960,8 +2667,21 @@ function AllMessagesMixedComponent({
|
|
|
1960
2667
|
const shouldHideRequestInputMessage = React.useCallback(
|
|
1961
2668
|
(message: AgentMessage) =>
|
|
1962
2669
|
message.type === AgentMessageType.REQUEST_INPUT &&
|
|
1963
|
-
externallyRenderedRequestInputKey === getRequestInputMessageKey(message)
|
|
1964
|
-
|
|
2670
|
+
(externallyRenderedRequestInputKey === getRequestInputMessageKey(message) ||
|
|
2671
|
+
isToolApprovalRequestInputHidden(
|
|
2672
|
+
message,
|
|
2673
|
+
answeredToolApprovalRequestInputKeys,
|
|
2674
|
+
resolvedToolApprovalKeys,
|
|
2675
|
+
)),
|
|
2676
|
+
[answeredToolApprovalRequestInputKeys, externallyRenderedRequestInputKey, resolvedToolApprovalKeys],
|
|
2677
|
+
);
|
|
2678
|
+
const shouldHideToolApprovalAnswerMessage = React.useCallback(
|
|
2679
|
+
(message: AgentMessage) => isToolApprovalAnswerHidden(message, hiddenToolApprovalAnswerKeys),
|
|
2680
|
+
[hiddenToolApprovalAnswerKeys],
|
|
2681
|
+
);
|
|
2682
|
+
const completionDisplayMessages = React.useMemo(
|
|
2683
|
+
() => displayMessages.filter((message) => !shouldHideToolApprovalAnswerMessage(message)),
|
|
2684
|
+
[displayMessages, shouldHideToolApprovalAnswerMessage],
|
|
1965
2685
|
);
|
|
1966
2686
|
|
|
1967
2687
|
const fallbackWorkingStartedAtRef = useRef(Date.now());
|
|
@@ -1969,11 +2689,14 @@ function AllMessagesMixedComponent({
|
|
|
1969
2689
|
Boolean(prependFriendlyMessage?.trim()) ||
|
|
1970
2690
|
hasInitialRequestValue(initialRequestData) ||
|
|
1971
2691
|
initialRequestTemplate !== undefined;
|
|
2692
|
+
const canRenderInitialRequest = showInitialRequest ?? true;
|
|
2693
|
+
const hasRenderableInitialRequest = hasInitialRequest && canRenderInitialRequest;
|
|
1972
2694
|
const hasPersistedUserQuestion = useMemo(
|
|
1973
2695
|
() => displayMessages.some((message) => message.type === AgentMessageType.QUESTION),
|
|
1974
2696
|
[displayMessages],
|
|
1975
2697
|
);
|
|
1976
|
-
const shouldRenderInitialRequest =
|
|
2698
|
+
const shouldRenderInitialRequest =
|
|
2699
|
+
activeWorkstream === 'all' && hasRenderableInitialRequest && !hasPersistedUserQuestion;
|
|
1977
2700
|
|
|
1978
2701
|
const latestDisplayMessageTimestamp = useMemo(() => {
|
|
1979
2702
|
return displayMessages.reduce((latest, msg) => Math.max(latest, getTimestampMs(msg.timestamp)), -Infinity);
|
|
@@ -1985,11 +2708,30 @@ function AllMessagesMixedComponent({
|
|
|
1985
2708
|
return Math.max(latest, getTimestampMs(msg.timestamp));
|
|
1986
2709
|
}, -Infinity);
|
|
1987
2710
|
}, [displayMessages]);
|
|
2711
|
+
const hasPendingToolApprovalRequest = useMemo(
|
|
2712
|
+
() =>
|
|
2713
|
+
displayMessages.some(
|
|
2714
|
+
(message) =>
|
|
2715
|
+
isToolApprovalRequestInput(message) &&
|
|
2716
|
+
!isToolApprovalRequestInputHidden(
|
|
2717
|
+
message,
|
|
2718
|
+
answeredToolApprovalRequestInputKeys,
|
|
2719
|
+
resolvedToolApprovalKeys,
|
|
2720
|
+
),
|
|
2721
|
+
),
|
|
2722
|
+
[answeredToolApprovalRequestInputKeys, displayMessages, resolvedToolApprovalKeys],
|
|
2723
|
+
);
|
|
2724
|
+
const hasLatestToolApprovalAllow = useMemo(
|
|
2725
|
+
() => hasLatestToolApprovalAllowTurn(displayMessages, hiddenToolApprovalAnswerKeys),
|
|
2726
|
+
[displayMessages, hiddenToolApprovalAnswerKeys],
|
|
2727
|
+
);
|
|
1988
2728
|
|
|
1989
2729
|
const isDisplayCompleted = useMemo(() => {
|
|
1990
|
-
if (
|
|
1991
|
-
|
|
1992
|
-
|
|
2730
|
+
if (hasPendingToolApprovalRequest) return false;
|
|
2731
|
+
if (hasLatestToolApprovalAllow) return false;
|
|
2732
|
+
if (hasOpenUserTurn(completionDisplayMessages)) return false;
|
|
2733
|
+
return isCompleted || !isInProgress(completionDisplayMessages);
|
|
2734
|
+
}, [completionDisplayMessages, hasLatestToolApprovalAllow, hasPendingToolApprovalRequest, isCompleted]);
|
|
1993
2735
|
|
|
1994
2736
|
// Split streaming messages:
|
|
1995
2737
|
// - complete (or stale incomplete) ones are interleaved chronologically
|
|
@@ -2024,8 +2766,19 @@ function AllMessagesMixedComponent({
|
|
|
2024
2766
|
}, [streamingMessages, activeWorkstream, latestNonTransientDisplayMessageTimestamp]);
|
|
2025
2767
|
|
|
2026
2768
|
const summaryDisplayMessages = React.useMemo(
|
|
2027
|
-
() =>
|
|
2028
|
-
|
|
2769
|
+
() =>
|
|
2770
|
+
buildSyntheticToolApprovalDecisionMessages(
|
|
2771
|
+
buildSummaryDisplayMessages(displayMessages, completeStreaming),
|
|
2772
|
+
resolvedToolApprovalKeys,
|
|
2773
|
+
),
|
|
2774
|
+
[displayMessages, completeStreaming, resolvedToolApprovalKeys],
|
|
2775
|
+
);
|
|
2776
|
+
const visibleSummaryDisplayMessages = React.useMemo(
|
|
2777
|
+
() =>
|
|
2778
|
+
summaryDisplayMessages.filter(
|
|
2779
|
+
(message) => !shouldHideRequestInputMessage(message) && !shouldHideToolApprovalAnswerMessage(message),
|
|
2780
|
+
),
|
|
2781
|
+
[summaryDisplayMessages, shouldHideRequestInputMessage, shouldHideToolApprovalAnswerMessage],
|
|
2029
2782
|
);
|
|
2030
2783
|
|
|
2031
2784
|
const latestSummaryObservedTimestamp = useMemo(() => {
|
|
@@ -2040,8 +2793,13 @@ function AllMessagesMixedComponent({
|
|
|
2040
2793
|
}, [incompleteStreaming, latestDisplayMessageTimestamp]);
|
|
2041
2794
|
|
|
2042
2795
|
const summaryConversationItems = React.useMemo(
|
|
2043
|
-
() =>
|
|
2044
|
-
|
|
2796
|
+
() =>
|
|
2797
|
+
buildSummaryConversationItems(
|
|
2798
|
+
visibleSummaryDisplayMessages,
|
|
2799
|
+
isDisplayCompleted,
|
|
2800
|
+
latestSummaryObservedTimestamp,
|
|
2801
|
+
),
|
|
2802
|
+
[visibleSummaryDisplayMessages, isDisplayCompleted, latestSummaryObservedTimestamp],
|
|
2045
2803
|
);
|
|
2046
2804
|
|
|
2047
2805
|
// Group messages with ONLY complete streaming interleaved for stacked view.
|
|
@@ -2058,8 +2816,12 @@ function AllMessagesMixedComponent({
|
|
|
2058
2816
|
// Show an activity indicator when the latest visible conversation state is not terminal.
|
|
2059
2817
|
// Older idle/complete messages from previous turns must not suppress the new turn.
|
|
2060
2818
|
const isAgentWorking = useMemo(() => {
|
|
2061
|
-
|
|
2062
|
-
|
|
2819
|
+
// Also treat an open user turn (the latest message is the user's, awaiting the agent's
|
|
2820
|
+
// first output) as "working" — otherwise nothing animates in the gap between sending a
|
|
2821
|
+
// message and the first streamed token, especially after a stop where the run reads as
|
|
2822
|
+
// completed until the agent posts its next message.
|
|
2823
|
+
return !isDisplayCompleted || hasOpenUserTurn(completionDisplayMessages);
|
|
2824
|
+
}, [completionDisplayMessages, isDisplayCompleted]);
|
|
2063
2825
|
|
|
2064
2826
|
const showActivityFallback = shouldShowSummaryActivityFallback(
|
|
2065
2827
|
summaryConversationItems,
|
|
@@ -2070,15 +2832,18 @@ function AllMessagesMixedComponent({
|
|
|
2070
2832
|
? t('agent.preparing')
|
|
2071
2833
|
: t('agent.working');
|
|
2072
2834
|
const showInitialRequestWaitingCard =
|
|
2073
|
-
displayMessages.length === 0 &&
|
|
2835
|
+
displayMessages.length === 0 &&
|
|
2836
|
+
hasRenderableInitialRequest &&
|
|
2837
|
+
isAgentWorking &&
|
|
2838
|
+
incompleteStreaming.length === 0;
|
|
2074
2839
|
const activityAnchorCandidate = useMemo(
|
|
2075
2840
|
() =>
|
|
2076
2841
|
getSummaryActivityAnchorTimestamp(
|
|
2077
2842
|
summaryConversationItems,
|
|
2078
|
-
|
|
2843
|
+
visibleSummaryDisplayMessages,
|
|
2079
2844
|
fallbackWorkingStartedAtRef.current,
|
|
2080
2845
|
),
|
|
2081
|
-
[summaryConversationItems,
|
|
2846
|
+
[summaryConversationItems, visibleSummaryDisplayMessages],
|
|
2082
2847
|
);
|
|
2083
2848
|
const activityStartedTimestampRef = useRef<number | string>(activityAnchorCandidate);
|
|
2084
2849
|
const wasActivityFallbackVisibleRef = useRef(false);
|
|
@@ -2417,14 +3182,16 @@ function AllMessagesMixedComponent({
|
|
|
2417
3182
|
<WorkstreamTabs
|
|
2418
3183
|
workstreams={workstreams}
|
|
2419
3184
|
activeWorkstream={activeWorkstream}
|
|
2420
|
-
onSelectWorkstream={
|
|
3185
|
+
onSelectWorkstream={handleSelectWorkstream}
|
|
2421
3186
|
count={workstreamCounts}
|
|
2422
3187
|
completionStatus={workstreamCompletionStatus}
|
|
2423
3188
|
/>
|
|
2424
3189
|
</div>
|
|
2425
3190
|
)}
|
|
2426
3191
|
|
|
2427
|
-
{displayMessages.length === 0 &&
|
|
3192
|
+
{displayMessages.length === 0 &&
|
|
3193
|
+
!hasRenderableInitialRequest &&
|
|
3194
|
+
!(isSummaryView && showActivityFallback) ? (
|
|
2428
3195
|
activeWorkstream === 'all' && isAgentWorking && incompleteStreaming.length === 0 ? (
|
|
2429
3196
|
<div className="flex-1 px-2 py-6 sm:px-4">
|
|
2430
3197
|
<InitialRequestWaitingCard
|
|
@@ -2450,6 +3217,28 @@ function AllMessagesMixedComponent({
|
|
|
2450
3217
|
messageListClassName,
|
|
2451
3218
|
)}
|
|
2452
3219
|
>
|
|
3220
|
+
{isSummaryView && activeWorkstream !== 'all' && activeWorkstreamName && (
|
|
3221
|
+
<div className="sticky top-0 z-20 -mx-2 bg-background/95 px-2 pb-2 pt-1 backdrop-blur sm:-mx-4 sm:px-4">
|
|
3222
|
+
<div className="mx-auto flex w-full max-w-3xl items-center gap-2 border-b border-border/70 pb-3">
|
|
3223
|
+
<VTooltip description={t('agent.backToMainAgent')} asChild>
|
|
3224
|
+
<Button
|
|
3225
|
+
type="button"
|
|
3226
|
+
variant="ghost"
|
|
3227
|
+
size="icon"
|
|
3228
|
+
className="size-8 shrink-0 text-muted hover:text-foreground"
|
|
3229
|
+
aria-label={t('agent.backToMainAgent')}
|
|
3230
|
+
onClick={handleShowMainAgentChat}
|
|
3231
|
+
>
|
|
3232
|
+
<ArrowLeft className="size-4" aria-hidden="true" />
|
|
3233
|
+
</Button>
|
|
3234
|
+
</VTooltip>
|
|
3235
|
+
<div className="min-w-0 flex-1 truncate text-sm font-medium text-foreground">
|
|
3236
|
+
{activeWorkstreamName}
|
|
3237
|
+
</div>
|
|
3238
|
+
</div>
|
|
3239
|
+
</div>
|
|
3240
|
+
)}
|
|
3241
|
+
|
|
2453
3242
|
{/* Friendly message — rendered outside the messages array to avoid memo issues/triggering autoscroll */}
|
|
2454
3243
|
{shouldRenderInitialRequest && (
|
|
2455
3244
|
<InitialRequestMessage
|
|
@@ -2544,6 +3333,23 @@ function AllMessagesMixedComponent({
|
|
|
2544
3333
|
// Render single message
|
|
2545
3334
|
const message = group.message;
|
|
2546
3335
|
if (shouldHideRequestInputMessage(message)) return null;
|
|
3336
|
+
if (shouldHideToolApprovalAnswerMessage(message)) return null;
|
|
3337
|
+
if (isUserStoppedMessage(message)) {
|
|
3338
|
+
return (
|
|
3339
|
+
<TimelineEntry key={getAgentMessageRenderKey(message, 'stopped')}>
|
|
3340
|
+
<SummaryStoppedMessage
|
|
3341
|
+
message={message}
|
|
3342
|
+
startTimestamp={
|
|
3343
|
+
getPreviousRenderableGroupTimestamp(
|
|
3344
|
+
groupedMessages,
|
|
3345
|
+
groupIndex,
|
|
3346
|
+
) ?? message.timestamp
|
|
3347
|
+
}
|
|
3348
|
+
endTimestamp={message.timestamp}
|
|
3349
|
+
/>
|
|
3350
|
+
</TimelineEntry>
|
|
3351
|
+
);
|
|
3352
|
+
}
|
|
2547
3353
|
const isLatestMessage =
|
|
2548
3354
|
!isCompleted && isLastGroup && !DONE_STATES.includes(message.type);
|
|
2549
3355
|
|
|
@@ -2639,7 +3445,7 @@ function AllMessagesMixedComponent({
|
|
|
2639
3445
|
return (
|
|
2640
3446
|
<SummaryActivityRow
|
|
2641
3447
|
key={`work-${item.id}-${item.isActive ? 'active' : 'done'}-${item.status}`}
|
|
2642
|
-
label={getSummaryActivityLabel(item.
|
|
3448
|
+
label={getSummaryActivityLabel(item.isActive)}
|
|
2643
3449
|
status={item.status}
|
|
2644
3450
|
timestamp={item.startTimestamp}
|
|
2645
3451
|
durationSeconds={
|
|
@@ -2650,13 +3456,29 @@ function AllMessagesMixedComponent({
|
|
|
2650
3456
|
showElapsed
|
|
2651
3457
|
details={isThinkingOnlyWork ? undefined : item.messages}
|
|
2652
3458
|
defaultExpanded={item.isActive && !isThinkingOnlyWork}
|
|
3459
|
+
disablePreambleCollapse={item.isActive}
|
|
2653
3460
|
className={workingIndicatorClassName}
|
|
3461
|
+
onSendMessage={onSendMessage}
|
|
3462
|
+
answeredToolApprovalRequestInputKeys={answeredToolApprovalRequestInputKeys}
|
|
3463
|
+
resolvedToolApprovalKeys={resolvedToolApprovalKeys}
|
|
3464
|
+
/>
|
|
3465
|
+
);
|
|
3466
|
+
}
|
|
3467
|
+
|
|
3468
|
+
if (item.type === 'stopped') {
|
|
3469
|
+
return (
|
|
3470
|
+
<SummaryStoppedMessage
|
|
3471
|
+
key={getAgentMessageRenderKey(item.message, 'stopped-summary')}
|
|
3472
|
+
message={item.message}
|
|
3473
|
+
startTimestamp={item.startTimestamp}
|
|
3474
|
+
endTimestamp={item.endTimestamp}
|
|
2654
3475
|
/>
|
|
2655
3476
|
);
|
|
2656
3477
|
}
|
|
2657
3478
|
|
|
2658
3479
|
const message = item.message;
|
|
2659
3480
|
if (shouldHideRequestInputMessage(message)) return null;
|
|
3481
|
+
if (shouldHideToolApprovalAnswerMessage(message)) return null;
|
|
2660
3482
|
if (isBatchProgressMessage(message)) {
|
|
2661
3483
|
return (
|
|
2662
3484
|
<MessageErrorBoundary key={getAgentMessageRenderKey(message, 'batch')}>
|
|
@@ -2675,6 +3497,7 @@ function AllMessagesMixedComponent({
|
|
|
2675
3497
|
<SummaryMessage
|
|
2676
3498
|
message={message}
|
|
2677
3499
|
onSendMessage={onSendMessage}
|
|
3500
|
+
onSelectWorkstream={handleSelectWorkstream}
|
|
2678
3501
|
requestInputAnswered={isRequestInputAnswered(
|
|
2679
3502
|
message,
|
|
2680
3503
|
answeredRequestInputKeys,
|