@vertesia/ui 1.5.0-dev.20260725.083715Z → 1.5.0-dev.20260804.124748Z
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/hooks/useScrollableSearch.d.ts +1 -1
- package/lib/core/hooks/useScrollableSearch.d.ts.map +1 -1
- package/lib/core/hooks/useScrollableSearch.js +15 -2
- package/lib/core/hooks/useScrollableSearch.js.map +1 -1
- package/lib/env/index.d.ts +4 -0
- package/lib/env/index.d.ts.map +1 -1
- package/lib/env/index.js.map +1 -1
- package/lib/features/agent/chat/AgentRequestInputOverlay.d.ts +1 -1
- package/lib/features/agent/chat/AgentRequestInputOverlay.d.ts.map +1 -1
- package/lib/features/agent/chat/AgentRequestInputOverlay.js +3 -8
- package/lib/features/agent/chat/AgentRequestInputOverlay.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentConversation.d.ts +8 -1
- package/lib/features/agent/chat/ModernAgentConversation.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentConversation.js +53 -17
- package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.d.ts +2 -1
- package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.js +25 -10
- package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +24 -9
- 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 +15 -3
- 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/MessageInput.d.ts +2 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js +2 -2
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js +2 -2
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.d.ts +9 -1
- package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.js +97 -2
- package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.js.map +1 -1
- package/lib/features/agent/chat/hooks/useAgentStream.d.ts.map +1 -1
- package/lib/features/agent/chat/hooks/useAgentStream.js +12 -3
- package/lib/features/agent/chat/hooks/useAgentStream.js.map +1 -1
- package/lib/features/agent/chat/index.d.ts +1 -1
- package/lib/features/agent/chat/index.d.ts.map +1 -1
- package/lib/features/agent/chat/index.js.map +1 -1
- package/lib/features/facets/PromptsFacetsNav.d.ts +8 -6
- package/lib/features/facets/PromptsFacetsNav.d.ts.map +1 -1
- package/lib/features/facets/PromptsFacetsNav.js +8 -3
- package/lib/features/facets/PromptsFacetsNav.js.map +1 -1
- package/lib/features/store/objects/components/ContentOverview.js +4 -1
- package/lib/features/store/objects/components/ContentOverview.js.map +1 -1
- package/lib/features/store/objects/components/useContentPanelHooks.d.ts +31 -3
- package/lib/features/store/objects/components/useContentPanelHooks.d.ts.map +1 -1
- package/lib/features/store/objects/search/DocumentSearchContext.d.ts +128 -6
- package/lib/features/store/objects/search/DocumentSearchContext.d.ts.map +1 -1
- package/lib/features/store/objects/selection/ObjectsActionContext.d.ts +2 -2
- package/lib/features/store/objects/selection/ObjectsActionContext.d.ts.map +1 -1
- package/lib/features/store/objects/selection/ObjectsActionSpec.d.ts +2 -2
- package/lib/features/store/objects/selection/ObjectsActionSpec.d.ts.map +1 -1
- package/lib/features/store/objects/selection/SelectionActions.d.ts +2 -2
- package/lib/features/store/objects/selection/SelectionActions.d.ts.map +1 -1
- package/lib/features/store/objects/upload/DocumentUploadModal.js.map +1 -1
- package/lib/features/store/types/IntakePolicyEditor.d.ts +2 -2
- package/lib/features/store/types/IntakePolicyEditor.d.ts.map +1 -1
- package/lib/features/store/types/IntakePolicyEditor.js +5 -1
- package/lib/features/store/types/IntakePolicyEditor.js.map +1 -1
- package/lib/features/store/types/IntakePolicyForm.d.ts.map +1 -1
- package/lib/features/store/types/IntakePolicyForm.js +2 -2
- package/lib/features/store/types/IntakePolicyForm.js.map +1 -1
- package/lib/features/store/types/ObjectSchemaEditor.d.ts +2 -2
- package/lib/features/store/types/ObjectSchemaEditor.d.ts.map +1 -1
- package/lib/features/store/types/SelectContentType.d.ts +2 -2
- package/lib/features/store/types/SelectContentType.d.ts.map +1 -1
- package/lib/features/store/types/SelectContentType.js.map +1 -1
- package/lib/features/store/types/SelectContentTypeModal.d.ts +2 -2
- package/lib/features/store/types/SelectContentTypeModal.d.ts.map +1 -1
- package/lib/features/store/types/SelectContentTypeModal.js.map +1 -1
- package/lib/features/store/types/TableLayoutEditor.d.ts +2 -2
- package/lib/features/store/types/TableLayoutEditor.d.ts.map +1 -1
- package/lib/features/store/types/TypeRegistry.d.ts +1267 -6
- package/lib/features/store/types/TypeRegistry.d.ts.map +1 -1
- package/lib/features/store/types/TypeRegistry.js +5 -0
- package/lib/features/store/types/TypeRegistry.js.map +1 -1
- package/lib/features/store/types/intake-policy-editor.logic.d.ts +9 -1
- package/lib/features/store/types/intake-policy-editor.logic.d.ts.map +1 -1
- package/lib/features/store/types/intake-policy-editor.logic.js +9 -1
- package/lib/features/store/types/intake-policy-editor.logic.js.map +1 -1
- package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts +1251 -1
- package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts.map +1 -1
- package/lib/features/store/types/typeCatalogCache.d.ts +2 -2
- package/lib/features/store/types/typeCatalogCache.d.ts.map +1 -1
- package/lib/features/store/types/typeCatalogCache.js +4 -0
- package/lib/features/store/types/typeCatalogCache.js.map +1 -1
- package/lib/features/user/UserInfo.d.ts +118 -7
- package/lib/features/user/UserInfo.d.ts.map +1 -1
- package/lib/i18n/locales/ar.json +2 -1
- package/lib/i18n/locales/de.json +2 -1
- package/lib/i18n/locales/en.json +5 -1
- package/lib/i18n/locales/es.json +2 -1
- package/lib/i18n/locales/fr.json +2 -1
- package/lib/i18n/locales/it.json +2 -1
- package/lib/i18n/locales/ja.json +2 -1
- package/lib/i18n/locales/ko.json +2 -1
- package/lib/i18n/locales/pt.json +2 -1
- package/lib/i18n/locales/ru.json +2 -1
- package/lib/i18n/locales/tr.json +2 -1
- package/lib/i18n/locales/zh-TW.json +2 -1
- package/lib/i18n/locales/zh.json +2 -1
- package/lib/session/UserSession.d.ts +18 -4
- package/lib/session/UserSession.d.ts.map +1 -1
- package/lib/shell/apps/AppInstallationProvider.d.ts +222 -2
- package/lib/shell/apps/AppInstallationProvider.d.ts.map +1 -1
- package/lib/shell/login/InviteAcceptModal.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-features.js +34 -34
- package/lib/vertesia-ui-features.js.map +1 -1
- package/lib/vertesia-ui-i18n.js +13 -13
- package/lib/vertesia-ui-widgets.js +18 -18
- package/lib/vertesia-ui-widgets.js.map +1 -1
- package/lib/widgets/monacoEditor/MonacoEditor.d.ts +7 -1
- package/lib/widgets/monacoEditor/MonacoEditor.d.ts.map +1 -1
- package/lib/widgets/monacoEditor/MonacoEditor.js +62 -6
- package/lib/widgets/monacoEditor/MonacoEditor.js.map +1 -1
- package/package.json +31 -31
- package/src/core/hooks/useScrollableSearch.test.tsx +139 -0
- package/src/core/hooks/useScrollableSearch.tsx +17 -3
- package/src/env/index.ts +2 -0
- package/src/features/agent/chat/AgentChatPlaybackControls.test.tsx +2 -0
- package/src/features/agent/chat/AgentRequestInputOverlay.test.tsx +51 -6
- package/src/features/agent/chat/AgentRequestInputOverlay.tsx +5 -7
- package/src/features/agent/chat/ModernAgentConversation.test.tsx +195 -3
- package/src/features/agent/chat/ModernAgentConversation.tsx +106 -22
- package/src/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.tsx +75 -20
- package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.test.tsx +112 -0
- package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +62 -10
- package/src/features/agent/chat/ModernAgentOutput/AttachmentPreview.tsx +36 -4
- package/src/features/agent/chat/ModernAgentOutput/Header.tsx +2 -2
- package/src/features/agent/chat/ModernAgentOutput/MessageInput.test.tsx +71 -0
- package/src/features/agent/chat/ModernAgentOutput/MessageInput.tsx +3 -1
- package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +18 -4
- package/src/features/agent/chat/ModernAgentOutput/requestInputMessages.test.ts +95 -0
- package/src/features/agent/chat/ModernAgentOutput/requestInputMessages.ts +111 -1
- package/src/features/agent/chat/hooks/useAgentStream.test.tsx +57 -0
- package/src/features/agent/chat/hooks/useAgentStream.ts +12 -3
- package/src/features/agent/chat/index.ts +1 -0
- package/src/features/facets/PromptsFacetsNav.tsx +17 -9
- package/src/features/store/objects/components/ContentOverview.tsx +4 -1
- package/src/features/store/objects/selection/ObjectsActionContext.tsx +2 -2
- package/src/features/store/objects/selection/ObjectsActionSpec.ts +2 -2
- package/src/features/store/objects/selection/SelectionActions.tsx +2 -2
- package/src/features/store/objects/upload/DocumentUploadModal.tsx +2 -2
- package/src/features/store/types/IntakePolicyEditor.tsx +12 -4
- package/src/features/store/types/IntakePolicyForm.tsx +25 -0
- package/src/features/store/types/ObjectSchemaEditor.tsx +2 -2
- package/src/features/store/types/SelectContentType.tsx +9 -9
- package/src/features/store/types/SelectContentTypeModal.tsx +5 -5
- package/src/features/store/types/TableLayoutEditor.tsx +2 -2
- package/src/features/store/types/TypeRegistry.ts +8 -3
- package/src/features/store/types/intake-policy-editor.logic.ts +10 -2
- package/src/features/store/types/typeCatalogCache.ts +10 -3
- package/src/i18n/locales/ar.json +2 -1
- package/src/i18n/locales/de.json +2 -1
- package/src/i18n/locales/en.json +5 -1
- package/src/i18n/locales/es.json +2 -1
- package/src/i18n/locales/fr.json +2 -1
- package/src/i18n/locales/it.json +2 -1
- package/src/i18n/locales/ja.json +2 -1
- package/src/i18n/locales/ko.json +2 -1
- package/src/i18n/locales/pt.json +2 -1
- package/src/i18n/locales/ru.json +2 -1
- package/src/i18n/locales/tr.json +2 -1
- package/src/i18n/locales/zh-TW.json +2 -1
- package/src/i18n/locales/zh.json +2 -1
- package/src/shell/login/InviteAcceptModal.tsx +4 -4
- package/src/widgets/markdown/ArtifactEditingSurface.test.tsx +13 -9
- package/src/widgets/monacoEditor/MonacoEditor.tsx +83 -7
|
@@ -7,15 +7,17 @@ import { RemoteMcpConnectionButton } from '../../oauth/RemoteMcpConnectionButton
|
|
|
7
7
|
import { AskUserWidget } from './AskUserWidget';
|
|
8
8
|
import {
|
|
9
9
|
getRequestInputDisplayText,
|
|
10
|
+
getRequestInputResponseMetadata,
|
|
10
11
|
getToolApprovalResponseMetadata,
|
|
11
12
|
type RequestInputMessageWithUx,
|
|
13
|
+
sendRequestInputResponse,
|
|
12
14
|
} from './ModernAgentOutput/requestInputMessages';
|
|
13
15
|
|
|
14
16
|
export interface AgentRequestInputOverlayProps {
|
|
15
17
|
message?: RequestInputMessageWithUx;
|
|
16
18
|
onSendMessage?: (message: string, metadata?: Record<string, unknown>) => void;
|
|
17
19
|
/** Called after the user connects the MCP server requested by request_mcp_connection. */
|
|
18
|
-
onMcpConnected?: (cfg: McpConnectUxConfig) => void;
|
|
20
|
+
onMcpConnected?: (cfg: McpConnectUxConfig, metadata?: Record<string, unknown>) => void;
|
|
19
21
|
isLoading?: boolean;
|
|
20
22
|
disabled?: boolean;
|
|
21
23
|
className?: string;
|
|
@@ -81,11 +83,7 @@ export function AgentRequestInputOverlay({
|
|
|
81
83
|
const displayText = getRequestInputDisplayText(message);
|
|
82
84
|
const send = (value: string, metadata?: Record<string, unknown>) => {
|
|
83
85
|
if (isDisabled) return;
|
|
84
|
-
|
|
85
|
-
onSendMessage?.(value, metadata);
|
|
86
|
-
} else {
|
|
87
|
-
onSendMessage?.(value);
|
|
88
|
-
}
|
|
86
|
+
sendRequestInputResponse(onSendMessage, message, value, metadata);
|
|
89
87
|
};
|
|
90
88
|
|
|
91
89
|
const wrapperClassName = cn(
|
|
@@ -102,7 +100,7 @@ export function AgentRequestInputOverlay({
|
|
|
102
100
|
<div className="min-w-0 text-sm leading-6 text-foreground/85">{displayText}</div>
|
|
103
101
|
<McpRequestInputControls
|
|
104
102
|
mcpConnect={mcpConnect}
|
|
105
|
-
onMcpConnected={onMcpConnected}
|
|
103
|
+
onMcpConnected={(cfg) => onMcpConnected?.(cfg, getRequestInputResponseMetadata(message))}
|
|
106
104
|
onDecline={() => send(t('agent.mcpDeclinedMessage', { name: mcpConnect.name }))}
|
|
107
105
|
disabled={isDisabled}
|
|
108
106
|
/>
|
|
@@ -60,6 +60,7 @@ vi.mock('./ModernAgentOutput/MessageInput', () => ({
|
|
|
60
60
|
onSend: (message: string) => void;
|
|
61
61
|
activeTaskCount?: number;
|
|
62
62
|
activeWorkstreams?: Array<{ workstream_id: string; status: string }>;
|
|
63
|
+
onSelectWorkstream?: (workstreamId: string) => void;
|
|
63
64
|
isCompleted?: boolean;
|
|
64
65
|
isStreaming?: boolean;
|
|
65
66
|
placeholder?: string;
|
|
@@ -90,6 +91,7 @@ vi.mock('./ModernAgentOutput/AllMessagesMixed', async () => {
|
|
|
90
91
|
return {
|
|
91
92
|
default: ({
|
|
92
93
|
messages,
|
|
94
|
+
workstreamSourceMessages,
|
|
93
95
|
streamingMessages,
|
|
94
96
|
isCompleted,
|
|
95
97
|
bottomRef,
|
|
@@ -101,6 +103,7 @@ vi.mock('./ModernAgentOutput/AllMessagesMixed', async () => {
|
|
|
101
103
|
onActiveWorkstreamChange,
|
|
102
104
|
}: {
|
|
103
105
|
messages: AgentMessage[];
|
|
106
|
+
workstreamSourceMessages?: AgentMessage[];
|
|
104
107
|
streamingMessages: Map<string, unknown>;
|
|
105
108
|
isCompleted?: boolean;
|
|
106
109
|
bottomRef: React.RefObject<HTMLDivElement>;
|
|
@@ -118,6 +121,7 @@ vi.mock('./ModernAgentOutput/AllMessagesMixed', async () => {
|
|
|
118
121
|
);
|
|
119
122
|
mocks.allMessagesMixedProps({
|
|
120
123
|
messages,
|
|
124
|
+
workstreamSourceMessages,
|
|
121
125
|
streamingMessages,
|
|
122
126
|
isCompleted,
|
|
123
127
|
onSendMessage,
|
|
@@ -230,6 +234,7 @@ function latestAllMessagesMixedProps() {
|
|
|
230
234
|
return calls[calls.length - 1]?.[0] as
|
|
231
235
|
| {
|
|
232
236
|
messages: AgentMessage[];
|
|
237
|
+
workstreamSourceMessages?: AgentMessage[];
|
|
233
238
|
streamingMessages: Map<string, unknown>;
|
|
234
239
|
isCompleted?: boolean;
|
|
235
240
|
showInitialRequest?: boolean;
|
|
@@ -253,6 +258,7 @@ function latestRightPanelProps() {
|
|
|
253
258
|
describe('ModernAgentConversation send handling', () => {
|
|
254
259
|
beforeEach(() => {
|
|
255
260
|
vi.clearAllMocks();
|
|
261
|
+
window.sessionStorage.clear();
|
|
256
262
|
mocks.restart.mockResolvedValue({ id: 'agent-run-1' });
|
|
257
263
|
mocks.sendSignal.mockResolvedValue({});
|
|
258
264
|
mocks.getActiveWorkstreams.mockResolvedValue({ running: [] });
|
|
@@ -561,6 +567,37 @@ describe('ModernAgentConversation send handling', () => {
|
|
|
561
567
|
});
|
|
562
568
|
});
|
|
563
569
|
|
|
570
|
+
it('collapses staged files in the start composer', () => {
|
|
571
|
+
const { container } = renderWithProviders(
|
|
572
|
+
<ModernAgentConversation startWorkflow={vi.fn()} hideHeader initialMessage="" />,
|
|
573
|
+
);
|
|
574
|
+
const input = container.querySelector('input[type="file"]');
|
|
575
|
+
const files = ['alpha.txt', 'beta.txt', 'gamma.txt', 'delta.txt', 'epsilon.txt'].map(
|
|
576
|
+
(name) => new File([name], name, { type: 'text/plain' }),
|
|
577
|
+
);
|
|
578
|
+
|
|
579
|
+
if (!input) {
|
|
580
|
+
throw new Error('Expected hidden file input to be rendered');
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
fireEvent.change(input, {
|
|
584
|
+
target: {
|
|
585
|
+
files,
|
|
586
|
+
},
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
expect(screen.getByText('alpha.txt')).not.toBeNull();
|
|
590
|
+
expect(screen.getByText('gamma.txt')).not.toBeNull();
|
|
591
|
+
expect(screen.queryByText('delta.txt')).toBeNull();
|
|
592
|
+
expect(screen.getByText('+2')).not.toBeNull();
|
|
593
|
+
|
|
594
|
+
fireEvent.click(screen.getByRole('button', { name: /show more/i }));
|
|
595
|
+
|
|
596
|
+
expect(screen.getByText('delta.txt')).not.toBeNull();
|
|
597
|
+
expect(screen.getByText('epsilon.txt')).not.toBeNull();
|
|
598
|
+
expect(screen.getByRole('button', { name: /show less/i })).not.toBeNull();
|
|
599
|
+
});
|
|
600
|
+
|
|
564
601
|
it('signals approval mode changes for an active interactive run', async () => {
|
|
565
602
|
mocks.retrieve.mockResolvedValue({
|
|
566
603
|
tool_approval_mode: 'ask',
|
|
@@ -916,11 +953,13 @@ describe('ModernAgentConversation send handling', () => {
|
|
|
916
953
|
onCompactContext?: () => void | Promise<void>;
|
|
917
954
|
};
|
|
918
955
|
|
|
956
|
+
// Prompt-based, matching the server's checkpoint trigger: `total`
|
|
957
|
+
// includes reasoning/result tokens that never re-enter context.
|
|
919
958
|
expect(latestMessageInputProps.contextWindowUsage).toEqual({
|
|
920
|
-
usedTokens:
|
|
959
|
+
usedTokens: 40_000,
|
|
921
960
|
checkpointTokens: 100_000,
|
|
922
|
-
usedPercent:
|
|
923
|
-
remainingPercent:
|
|
961
|
+
usedPercent: 40,
|
|
962
|
+
remainingPercent: 60,
|
|
924
963
|
});
|
|
925
964
|
|
|
926
965
|
act(() => {
|
|
@@ -1059,6 +1098,7 @@ describe('ModernAgentConversation send handling', () => {
|
|
|
1059
1098
|
const latestMessageInputProps = mocks.messageInputProps.mock.lastCall?.[0] as {
|
|
1060
1099
|
activeTaskCount?: number;
|
|
1061
1100
|
activeWorkstreams?: Array<{ workstream_id: string; status: string }>;
|
|
1101
|
+
onSelectWorkstream?: (workstreamId: string) => void;
|
|
1062
1102
|
};
|
|
1063
1103
|
|
|
1064
1104
|
expect(latestRightPanelProps.activeWorkstreams).toEqual([
|
|
@@ -1072,6 +1112,12 @@ describe('ModernAgentConversation send handling', () => {
|
|
|
1072
1112
|
expect.objectContaining({ workstream_id: 'alpha', status: 'running' }),
|
|
1073
1113
|
expect.objectContaining({ workstream_id: 'beta', status: 'running' }),
|
|
1074
1114
|
]);
|
|
1115
|
+
|
|
1116
|
+
act(() => {
|
|
1117
|
+
latestMessageInputProps.onSelectWorkstream?.('beta');
|
|
1118
|
+
});
|
|
1119
|
+
|
|
1120
|
+
expect(latestAllMessagesMixedProps()?.activeWorkstream).toBe('beta');
|
|
1075
1121
|
});
|
|
1076
1122
|
|
|
1077
1123
|
it('shows completed workstream lifecycle messages in the panel without counting them as active', async () => {
|
|
@@ -1488,6 +1534,80 @@ describe('ModernAgentConversation send handling', () => {
|
|
|
1488
1534
|
);
|
|
1489
1535
|
});
|
|
1490
1536
|
|
|
1537
|
+
it('does not resurrect an answered request overlay after remounting before the persisted echo arrives', async () => {
|
|
1538
|
+
const requestMessage = {
|
|
1539
|
+
...createMessage(AgentMessageType.REQUEST_INPUT, 'What is your favorite color?'),
|
|
1540
|
+
details: {
|
|
1541
|
+
request_id: 'ask-user-1',
|
|
1542
|
+
ux: {
|
|
1543
|
+
options: [
|
|
1544
|
+
{ id: 'red', label: 'Red' },
|
|
1545
|
+
{ id: 'blue', label: 'Blue' },
|
|
1546
|
+
],
|
|
1547
|
+
},
|
|
1548
|
+
},
|
|
1549
|
+
};
|
|
1550
|
+
mockStreamState({
|
|
1551
|
+
messages: [requestMessage],
|
|
1552
|
+
isCompleted: false,
|
|
1553
|
+
agentRunStatus: 'RUNNING',
|
|
1554
|
+
});
|
|
1555
|
+
|
|
1556
|
+
const firstView = renderConversation();
|
|
1557
|
+
fireEvent.click(screen.getByRole('button', { name: /Blue/ }));
|
|
1558
|
+
|
|
1559
|
+
await waitFor(() => expect(mocks.sendSignal).toHaveBeenCalledTimes(1));
|
|
1560
|
+
expect(mocks.sendSignal).toHaveBeenCalledWith(
|
|
1561
|
+
'agent-run-1',
|
|
1562
|
+
'UserInput',
|
|
1563
|
+
expect.objectContaining({
|
|
1564
|
+
metadata: expect.objectContaining({
|
|
1565
|
+
request_input_response: { request_id: 'ask-user-1' },
|
|
1566
|
+
}),
|
|
1567
|
+
}),
|
|
1568
|
+
);
|
|
1569
|
+
|
|
1570
|
+
firstView.unmount();
|
|
1571
|
+
renderConversation();
|
|
1572
|
+
|
|
1573
|
+
expect(screen.queryByText('What is your favorite color?')).toBeNull();
|
|
1574
|
+
expect(screen.queryByRole('button', { name: /Blue/ })).toBeNull();
|
|
1575
|
+
});
|
|
1576
|
+
|
|
1577
|
+
it('restores a request overlay after its response fails to send', async () => {
|
|
1578
|
+
mocks.sendSignal.mockRejectedValueOnce(new Error('offline'));
|
|
1579
|
+
const requestMessage = {
|
|
1580
|
+
...createMessage(AgentMessageType.REQUEST_INPUT, 'What is your favorite color?'),
|
|
1581
|
+
details: {
|
|
1582
|
+
request_id: 'ask-user-1',
|
|
1583
|
+
ux: {
|
|
1584
|
+
options: [
|
|
1585
|
+
{ id: 'red', label: 'Red' },
|
|
1586
|
+
{ id: 'blue', label: 'Blue' },
|
|
1587
|
+
],
|
|
1588
|
+
},
|
|
1589
|
+
},
|
|
1590
|
+
};
|
|
1591
|
+
mockStreamState({
|
|
1592
|
+
messages: [requestMessage],
|
|
1593
|
+
isCompleted: false,
|
|
1594
|
+
agentRunStatus: 'RUNNING',
|
|
1595
|
+
});
|
|
1596
|
+
|
|
1597
|
+
const firstView = renderConversation();
|
|
1598
|
+
fireEvent.click(screen.getByRole('button', { name: /Blue/ }));
|
|
1599
|
+
|
|
1600
|
+
await waitFor(() => {
|
|
1601
|
+
expect(mocks.updateOptimisticMessageStatus).toHaveBeenCalledWith(expect.any(String), 'failed');
|
|
1602
|
+
});
|
|
1603
|
+
|
|
1604
|
+
firstView.unmount();
|
|
1605
|
+
renderConversation();
|
|
1606
|
+
|
|
1607
|
+
expect(screen.getByText('What is your favorite color?')).not.toBeNull();
|
|
1608
|
+
expect(screen.getByRole('button', { name: /Blue/ })).not.toBeNull();
|
|
1609
|
+
});
|
|
1610
|
+
|
|
1491
1611
|
it('hides a stale request overlay when a terminal run cannot continue', () => {
|
|
1492
1612
|
mockStreamState({
|
|
1493
1613
|
messages: [
|
|
@@ -2213,6 +2333,78 @@ describe('ModernAgentConversation send handling', () => {
|
|
|
2213
2333
|
);
|
|
2214
2334
|
});
|
|
2215
2335
|
|
|
2336
|
+
it('hides the debug button when the playback toggle is disabled', () => {
|
|
2337
|
+
mockStreamState({
|
|
2338
|
+
messages: [
|
|
2339
|
+
createMessage(AgentMessageType.QUESTION, 'first question'),
|
|
2340
|
+
createMessage(AgentMessageType.ANSWER, 'first answer'),
|
|
2341
|
+
],
|
|
2342
|
+
});
|
|
2343
|
+
|
|
2344
|
+
renderConversation({ hideHeader: false, showPlaybackToggle: false });
|
|
2345
|
+
|
|
2346
|
+
expect(mocks.headerProps).toHaveBeenLastCalledWith(
|
|
2347
|
+
expect.objectContaining({
|
|
2348
|
+
showPlaybackButton: false,
|
|
2349
|
+
}),
|
|
2350
|
+
);
|
|
2351
|
+
});
|
|
2352
|
+
|
|
2353
|
+
it('filters transcript messages as conversation history updates', () => {
|
|
2354
|
+
const question = createMessage(AgentMessageType.QUESTION, 'Summarize the launch plan.');
|
|
2355
|
+
const internalUpdate = createMessage(AgentMessageType.UPDATE, 'Inspecting internal records.');
|
|
2356
|
+
const answer = createMessage(AgentMessageType.ANSWER, 'The launch plan is ready.');
|
|
2357
|
+
const messageFilter = (message: AgentMessage) => message.type !== AgentMessageType.UPDATE;
|
|
2358
|
+
|
|
2359
|
+
mockStreamState({ messages: [question, internalUpdate] });
|
|
2360
|
+
const view = renderConversation({ messageFilter });
|
|
2361
|
+
|
|
2362
|
+
expect(latestAllMessagesMixedProps()?.messages).toEqual([question]);
|
|
2363
|
+
expect(latestAllMessagesMixedProps()?.workstreamSourceMessages).toEqual([question]);
|
|
2364
|
+
|
|
2365
|
+
mockStreamState({ messages: [question, internalUpdate, answer] });
|
|
2366
|
+
view.rerender(
|
|
2367
|
+
<ModernAgentConversation
|
|
2368
|
+
agentRunId="agent-run-1"
|
|
2369
|
+
title="Agent"
|
|
2370
|
+
hideHeader
|
|
2371
|
+
hideMessageInput
|
|
2372
|
+
showRightPanel={false}
|
|
2373
|
+
messageFilter={messageFilter}
|
|
2374
|
+
/>,
|
|
2375
|
+
);
|
|
2376
|
+
|
|
2377
|
+
expect(latestAllMessagesMixedProps()?.messages).toEqual([question, answer]);
|
|
2378
|
+
expect(latestAllMessagesMixedProps()?.workstreamSourceMessages).toEqual([question, answer]);
|
|
2379
|
+
expect(document.querySelector('[data-agent-live-message-count="3"]')).not.toBeNull();
|
|
2380
|
+
expect(document.querySelector('[data-agent-rendered-message-count="2"]')).not.toBeNull();
|
|
2381
|
+
});
|
|
2382
|
+
|
|
2383
|
+
it('keeps pending request input actionable when its transcript row is filtered out', () => {
|
|
2384
|
+
const requestMessage = {
|
|
2385
|
+
...createMessage(AgentMessageType.REQUEST_INPUT, 'Choose a deployment region.'),
|
|
2386
|
+
details: {
|
|
2387
|
+
ux: {
|
|
2388
|
+
options: [
|
|
2389
|
+
{ id: 'us', label: 'United States' },
|
|
2390
|
+
{ id: 'eu', label: 'Europe' },
|
|
2391
|
+
],
|
|
2392
|
+
},
|
|
2393
|
+
},
|
|
2394
|
+
};
|
|
2395
|
+
mockStreamState({
|
|
2396
|
+
messages: [requestMessage],
|
|
2397
|
+
isCompleted: false,
|
|
2398
|
+
agentRunStatus: 'RUNNING',
|
|
2399
|
+
});
|
|
2400
|
+
|
|
2401
|
+
renderConversation({ messageFilter: () => false });
|
|
2402
|
+
|
|
2403
|
+
expect(latestAllMessagesMixedProps()?.messages).toEqual([]);
|
|
2404
|
+
expect(screen.getByText('Choose a deployment region.')).not.toBeNull();
|
|
2405
|
+
expect(screen.getByRole('button', { name: /Europe/ })).not.toBeNull();
|
|
2406
|
+
});
|
|
2407
|
+
|
|
2216
2408
|
it('keeps the replay fixture export action available while messages are empty', () => {
|
|
2217
2409
|
mockStreamState({
|
|
2218
2410
|
messages: [],
|
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
AgentResourceResolverProvider,
|
|
36
36
|
isArtifactRefreshEvent,
|
|
37
37
|
} from '@vertesia/ui/widgets';
|
|
38
|
-
import { ArrowUpIcon, Bot, CheckCircle, Cpu, FileTextIcon, UploadIcon, XIcon } from 'lucide-react';
|
|
38
|
+
import { ArrowUpIcon, Bot, CheckCircle, ChevronDown, Cpu, FileTextIcon, UploadIcon, XIcon } from 'lucide-react';
|
|
39
39
|
import type React from 'react';
|
|
40
40
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
41
41
|
import { McpConnectionsActionMenu } from '../../oauth/McpConnectionsButton.js';
|
|
@@ -65,7 +65,14 @@ import MessageInput, {
|
|
|
65
65
|
type UploadedFile,
|
|
66
66
|
} from './ModernAgentOutput/MessageInput';
|
|
67
67
|
import type { MessageItemClassNames } from './ModernAgentOutput/MessageItem';
|
|
68
|
-
import {
|
|
68
|
+
import {
|
|
69
|
+
clearRequestInputIdAnsweredForSession,
|
|
70
|
+
getPendingRequestInputMessage,
|
|
71
|
+
getRequestInputResolutionKey,
|
|
72
|
+
getRequestInputResponseIdFromMetadata,
|
|
73
|
+
isRequestInputAnsweredForSession,
|
|
74
|
+
markRequestInputIdAnsweredForSession,
|
|
75
|
+
} from './ModernAgentOutput/requestInputMessages';
|
|
69
76
|
import type { StreamingMessageClassNames } from './ModernAgentOutput/StreamingMessage';
|
|
70
77
|
import type { ToolCallGroupClassNames } from './ModernAgentOutput/ToolCallGroup';
|
|
71
78
|
import {
|
|
@@ -98,6 +105,9 @@ export interface StartWorkflowOptions {
|
|
|
98
105
|
tool_approval_mode?: AgentToolApprovalMode;
|
|
99
106
|
}
|
|
100
107
|
|
|
108
|
+
/** Controls whether a persisted message is included in the rendered conversation transcript. */
|
|
109
|
+
export type AgentMessageFilter = (message: AgentMessage) => boolean;
|
|
110
|
+
|
|
101
111
|
export type StartWorkflowFn = (
|
|
102
112
|
initialMessage?: string,
|
|
103
113
|
options?: StartWorkflowOptions,
|
|
@@ -106,6 +116,7 @@ export type StartWorkflowFn = (
|
|
|
106
116
|
export type SendAgentMessageFn = (message: string, inputMetadata?: Record<string, unknown>) => void;
|
|
107
117
|
|
|
108
118
|
const EMPTY_STREAMING_MESSAGES = new Map<string, never>();
|
|
119
|
+
const COLLAPSED_STAGED_FILE_COUNT = 3;
|
|
109
120
|
|
|
110
121
|
function getTimestampMs(timestamp: number | string | undefined): number {
|
|
111
122
|
if (typeof timestamp === 'number') return timestamp;
|
|
@@ -137,8 +148,13 @@ function toContextWindowUsage(messages: AgentMessage[]): ContextWindowUsage | un
|
|
|
137
148
|
const details = messages[index].details;
|
|
138
149
|
if (!details) continue;
|
|
139
150
|
|
|
140
|
-
const tokenUsage = details.token_usage as { total?: unknown } | undefined;
|
|
141
|
-
|
|
151
|
+
const tokenUsage = details.token_usage as { prompt?: unknown; total?: unknown } | undefined;
|
|
152
|
+
// Mirror the server's checkpoint trigger (getContextPressureTokens):
|
|
153
|
+
// the last call's prompt size is the actual context; `total` includes
|
|
154
|
+
// reasoning output that never re-enters context and would overstate
|
|
155
|
+
// pressure on reasoning models. Fall back to total when no breakdown.
|
|
156
|
+
const promptTokens = getNumberDetail(tokenUsage?.prompt);
|
|
157
|
+
const usedTokens = promptTokens && promptTokens > 0 ? promptTokens : getNumberDetail(tokenUsage?.total);
|
|
142
158
|
const checkpointTokens =
|
|
143
159
|
getNumberDetail(details.checkpoint_threshold) ?? getNumberDetail(details.checkpoint_at);
|
|
144
160
|
|
|
@@ -648,6 +664,11 @@ export interface ModernAgentConversationProps {
|
|
|
648
664
|
hideDocumentPanel?: boolean;
|
|
649
665
|
/** Message types to exclude from the conversation view */
|
|
650
666
|
hiddenMessageTypes?: AgentMessageType[];
|
|
667
|
+
/**
|
|
668
|
+
* Optional presentation-only predicate for transcript messages. Returning false hides the message without
|
|
669
|
+
* changing the underlying conversation stream, workflow state, plans, or pending input.
|
|
670
|
+
*/
|
|
671
|
+
messageFilter?: AgentMessageFilter;
|
|
651
672
|
|
|
652
673
|
// Callback to get attached documents when sending messages
|
|
653
674
|
// Returns array of { id, name } to include in message metadata and display
|
|
@@ -727,7 +748,7 @@ export interface ModernAgentConversationProps {
|
|
|
727
748
|
initialToolApprovalMode?: AgentToolApprovalMode;
|
|
728
749
|
/** Force display playback controls on or off. When omitted, local playback can be toggled from the header. */
|
|
729
750
|
enablePlayback?: boolean;
|
|
730
|
-
/** Show
|
|
751
|
+
/** Show the Debug button for local playback controls. Defaults to true; set to false to hide it. */
|
|
731
752
|
showPlaybackToggle?: boolean;
|
|
732
753
|
}
|
|
733
754
|
|
|
@@ -817,6 +838,9 @@ function StartWorkflowView({
|
|
|
817
838
|
|
|
818
839
|
// Staged files - stored locally until workflow starts
|
|
819
840
|
const [stagedFiles, setStagedFiles] = useState<File[]>([]);
|
|
841
|
+
const [areStagedFilesExpanded, setAreStagedFilesExpanded] = useState(false);
|
|
842
|
+
const visibleStagedFiles = areStagedFilesExpanded ? stagedFiles : stagedFiles.slice(0, COLLAPSED_STAGED_FILE_COUNT);
|
|
843
|
+
const hiddenStagedFileCount = stagedFiles.length - COLLAPSED_STAGED_FILE_COUNT;
|
|
820
844
|
|
|
821
845
|
useEffect(() => {
|
|
822
846
|
onAgentWorkingChange?.(isSending);
|
|
@@ -914,6 +938,12 @@ function StartWorkflowView({
|
|
|
914
938
|
setStagedFiles((prev) => prev.filter((_, i) => i !== index));
|
|
915
939
|
}, []);
|
|
916
940
|
|
|
941
|
+
useEffect(() => {
|
|
942
|
+
if (stagedFiles.length <= COLLAPSED_STAGED_FILE_COUNT) {
|
|
943
|
+
setAreStagedFilesExpanded(false);
|
|
944
|
+
}
|
|
945
|
+
}, [stagedFiles.length]);
|
|
946
|
+
|
|
917
947
|
useEffect(() => {
|
|
918
948
|
// Focus the input field when component mounts
|
|
919
949
|
if (inputRef.current) {
|
|
@@ -1208,7 +1238,7 @@ function StartWorkflowView({
|
|
|
1208
1238
|
{/* Staged files display */}
|
|
1209
1239
|
{canStageFiles && stagedFiles.length > 0 && (
|
|
1210
1240
|
<div className="flex flex-wrap gap-2">
|
|
1211
|
-
{
|
|
1241
|
+
{visibleStagedFiles.map((file, index) => (
|
|
1212
1242
|
<div
|
|
1213
1243
|
key={`${file.name}-${file.size}-${file.lastModified}`}
|
|
1214
1244
|
className="flex items-center gap-1.5 rounded-md bg-attention/10 px-2 py-1 text-sm text-attention"
|
|
@@ -1227,6 +1257,26 @@ function StartWorkflowView({
|
|
|
1227
1257
|
</Button>
|
|
1228
1258
|
</div>
|
|
1229
1259
|
))}
|
|
1260
|
+
{stagedFiles.length > COLLAPSED_STAGED_FILE_COUNT && (
|
|
1261
|
+
<Button
|
|
1262
|
+
type="button"
|
|
1263
|
+
variant="ghost"
|
|
1264
|
+
size="sm"
|
|
1265
|
+
aria-expanded={areStagedFilesExpanded}
|
|
1266
|
+
onClick={() => setAreStagedFilesExpanded((expanded) => !expanded)}
|
|
1267
|
+
className="h-8 shrink-0 gap-1 rounded-xl px-2.5 text-xs text-muted"
|
|
1268
|
+
>
|
|
1269
|
+
{!areStagedFilesExpanded && <span>+{hiddenStagedFileCount}</span>}
|
|
1270
|
+
{areStagedFilesExpanded ? t('agent.showLess') : t('agent.showMore')}
|
|
1271
|
+
<ChevronDown
|
|
1272
|
+
className={cn(
|
|
1273
|
+
'size-3.5 transition-transform',
|
|
1274
|
+
areStagedFilesExpanded && 'rotate-180',
|
|
1275
|
+
)}
|
|
1276
|
+
aria-hidden="true"
|
|
1277
|
+
/>
|
|
1278
|
+
</Button>
|
|
1279
|
+
)}
|
|
1230
1280
|
</div>
|
|
1231
1281
|
)}
|
|
1232
1282
|
|
|
@@ -1392,6 +1442,7 @@ function ModernAgentConversationInner({
|
|
|
1392
1442
|
initialToolApprovalMode,
|
|
1393
1443
|
enablePlayback,
|
|
1394
1444
|
showPlaybackToggle = true,
|
|
1445
|
+
messageFilter,
|
|
1395
1446
|
}: ModernAgentConversationProps & { agentRunId: string }) {
|
|
1396
1447
|
const { t } = useUITranslation();
|
|
1397
1448
|
const { client } = useUserSession();
|
|
@@ -1621,13 +1672,16 @@ function ModernAgentConversationInner({
|
|
|
1621
1672
|
|
|
1622
1673
|
const canShowPlaybackToggle = showPlaybackToggle && enablePlayback === undefined && isAgentChatPlaybackAvailable();
|
|
1623
1674
|
const isPlaybackEnabled = enablePlayback ?? (isAgentChatPlaybackEnabled() || isPlaybackToggleEnabled);
|
|
1624
|
-
const
|
|
1675
|
+
const transcriptSourceMessages = useMemo(() => {
|
|
1625
1676
|
// Passive artifact autosaves are surfaced by the editor's own save indicator, not the chat.
|
|
1626
|
-
|
|
1677
|
+
return messages.filter(
|
|
1627
1678
|
(message) => !isPassiveArtifactUpdate(message) && !(hiddenMessageTypes?.includes(message.type) ?? false),
|
|
1628
1679
|
);
|
|
1629
|
-
|
|
1630
|
-
|
|
1680
|
+
}, [hiddenMessageTypes, messages]);
|
|
1681
|
+
const playbackSourceMessages = useMemo(
|
|
1682
|
+
() => filterMessagesForActiveWorkstream(transcriptSourceMessages, activeWorkstream),
|
|
1683
|
+
[activeWorkstream, transcriptSourceMessages],
|
|
1684
|
+
);
|
|
1631
1685
|
const playbackState = useMemo(
|
|
1632
1686
|
() => createPlaybackState(playbackSourceMessages, playbackCursor, isPlaybackEnabled),
|
|
1633
1687
|
[isPlaybackEnabled, playbackCursor, playbackSourceMessages],
|
|
@@ -1637,6 +1691,17 @@ function ModernAgentConversationInner({
|
|
|
1637
1691
|
const isPlaybackAtLatest =
|
|
1638
1692
|
isPlaybackEnabled && !isPlaybackLive && playbackState.cursorIndex === playbackSourceMessages.length - 1;
|
|
1639
1693
|
const displayedMessages = playbackState.displayedMessages;
|
|
1694
|
+
const renderedMessages = useMemo(
|
|
1695
|
+
() => (messageFilter ? displayedMessages.filter((message) => messageFilter(message)) : displayedMessages),
|
|
1696
|
+
[displayedMessages, messageFilter],
|
|
1697
|
+
);
|
|
1698
|
+
const renderedWorkstreamSourceMessages = useMemo(
|
|
1699
|
+
() =>
|
|
1700
|
+
messageFilter
|
|
1701
|
+
? transcriptSourceMessages.filter((message) => messageFilter(message))
|
|
1702
|
+
: transcriptSourceMessages,
|
|
1703
|
+
[messageFilter, transcriptSourceMessages],
|
|
1704
|
+
);
|
|
1640
1705
|
const displayedStreamingMessages = isPlaybackLive ? streamingMessages : EMPTY_STREAMING_MESSAGES;
|
|
1641
1706
|
const playbackDerivedWorkstreams = useMemo(
|
|
1642
1707
|
() => deriveWorkstreamsFromMessages(displayedMessages),
|
|
@@ -1653,10 +1718,15 @@ function ModernAgentConversationInner({
|
|
|
1653
1718
|
useEffect(() => {
|
|
1654
1719
|
onAgentWorkingChange?.(isAgentWorking);
|
|
1655
1720
|
}, [isAgentWorking, onAgentWorkingChange]);
|
|
1656
|
-
const pendingRequestInputMessage = useMemo(
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1721
|
+
const pendingRequestInputMessage = useMemo(() => {
|
|
1722
|
+
const answeredRequestInputKeys = new Set<string>();
|
|
1723
|
+
for (const message of displayedMessages) {
|
|
1724
|
+
if (isRequestInputAnsweredForSession(agentRunId, message)) {
|
|
1725
|
+
answeredRequestInputKeys.add(getRequestInputResolutionKey(message));
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
return getPendingRequestInputMessage(displayedMessages, 'main', answeredRequestInputKeys);
|
|
1729
|
+
}, [agentRunId, displayedMessages]);
|
|
1660
1730
|
// A terminal run silently drops user input unless it can be continued (see the guard in
|
|
1661
1731
|
// handleSendMessage), so never surface an actionable question overlay in that state —
|
|
1662
1732
|
// the terminal status box renders instead.
|
|
@@ -1675,7 +1745,7 @@ function ModernAgentConversationInner({
|
|
|
1675
1745
|
agentRunId,
|
|
1676
1746
|
messageCount: messages.length,
|
|
1677
1747
|
playbackMessageCount: playbackSourceMessages.length,
|
|
1678
|
-
displayedMessageCount:
|
|
1748
|
+
displayedMessageCount: renderedMessages.length,
|
|
1679
1749
|
streamingCount: streamingMessages.size,
|
|
1680
1750
|
displayedStreamingCount: displayedStreamingMessages.size,
|
|
1681
1751
|
initialHistoryStatus,
|
|
@@ -1699,7 +1769,7 @@ function ModernAgentConversationInner({
|
|
|
1699
1769
|
agentRunStatus,
|
|
1700
1770
|
clampedPlaybackCursor,
|
|
1701
1771
|
displayedIsCompleted,
|
|
1702
|
-
|
|
1772
|
+
renderedMessages.length,
|
|
1703
1773
|
displayedStreamingMessages.size,
|
|
1704
1774
|
effectiveIsCompleted,
|
|
1705
1775
|
effectiveWorkflowStatus,
|
|
@@ -2078,6 +2148,7 @@ function ModernAgentConversationInner({
|
|
|
2078
2148
|
return;
|
|
2079
2149
|
}
|
|
2080
2150
|
|
|
2151
|
+
const requestInputId = getRequestInputResponseIdFromMetadata(inputMetadata);
|
|
2081
2152
|
setIsSending(true);
|
|
2082
2153
|
|
|
2083
2154
|
const attachedDocs = getAttachedDocs?.() || [];
|
|
@@ -2120,6 +2191,9 @@ function ModernAgentConversationInner({
|
|
|
2120
2191
|
_messageId: messageId,
|
|
2121
2192
|
_deliveryStatus: 'sending',
|
|
2122
2193
|
...(inputMetadata?.editing_action ? { editing_action: inputMetadata.editing_action } : {}),
|
|
2194
|
+
...(inputMetadata?.request_input_response
|
|
2195
|
+
? { request_input_response: inputMetadata.request_input_response }
|
|
2196
|
+
: {}),
|
|
2123
2197
|
},
|
|
2124
2198
|
};
|
|
2125
2199
|
|
|
@@ -2151,6 +2225,9 @@ function ModernAgentConversationInner({
|
|
|
2151
2225
|
// buffers the signal until the new run is ready to receive it. We reconnect
|
|
2152
2226
|
// the stream in place (rather than remounting via onRestart) so the existing
|
|
2153
2227
|
// timeline is preserved and the new exchange appends seamlessly at the bottom.
|
|
2228
|
+
if (requestInputId) {
|
|
2229
|
+
markRequestInputIdAnsweredForSession(agentRunId, requestInputId);
|
|
2230
|
+
}
|
|
2154
2231
|
const deliver = (async () => {
|
|
2155
2232
|
await waitForPendingToolApprovalModeChange();
|
|
2156
2233
|
if (isWorkflowTerminalRef.current) {
|
|
@@ -2163,6 +2240,9 @@ function ModernAgentConversationInner({
|
|
|
2163
2240
|
|
|
2164
2241
|
deliver
|
|
2165
2242
|
.catch((err) => {
|
|
2243
|
+
if (requestInputId) {
|
|
2244
|
+
clearRequestInputIdAnsweredForSession(agentRunId, requestInputId);
|
|
2245
|
+
}
|
|
2166
2246
|
updateOptimisticMessageStatus(messageId, 'failed');
|
|
2167
2247
|
toast({
|
|
2168
2248
|
status: 'error',
|
|
@@ -2202,7 +2282,7 @@ function ModernAgentConversationInner({
|
|
|
2202
2282
|
// conversation for tool re-discovery and resume it with a confirmation message so the agent
|
|
2203
2283
|
// continues automatically with the newly-available tools.
|
|
2204
2284
|
const handleMcpConnected = useCallback(
|
|
2205
|
-
async (cfg: McpConnectUxConfig) => {
|
|
2285
|
+
async (cfg: McpConnectUxConfig, metadata?: Record<string, unknown>) => {
|
|
2206
2286
|
// Await the dirty-flag signal BEFORE sending the follow-up message so Temporal records
|
|
2207
2287
|
// McpConfigChanged ahead of the UserInput. Otherwise the resume turn could run before
|
|
2208
2288
|
// the flag is set and use the stale tool catalog. An omitted disabled list preserves
|
|
@@ -2212,7 +2292,7 @@ function ModernAgentConversationInner({
|
|
|
2212
2292
|
} catch (err: unknown) {
|
|
2213
2293
|
console.error('Failed to signal MCP config change', err);
|
|
2214
2294
|
}
|
|
2215
|
-
handleSendMessage(t('agent.mcpConnectedMessage', { name: cfg.name }));
|
|
2295
|
+
handleSendMessage(t('agent.mcpConnectedMessage', { name: cfg.name }), metadata);
|
|
2216
2296
|
},
|
|
2217
2297
|
[client, agentRunId, handleSendMessage, t],
|
|
2218
2298
|
);
|
|
@@ -2594,7 +2674,7 @@ function ModernAgentConversationInner({
|
|
|
2594
2674
|
data-agent-playback-enabled={isPlaybackEnabled || undefined}
|
|
2595
2675
|
data-agent-playback-cursor={isPlaybackEnabled ? clampedPlaybackCursor : undefined}
|
|
2596
2676
|
data-agent-live-message-count={messages.length}
|
|
2597
|
-
data-agent-rendered-message-count={
|
|
2677
|
+
data-agent-rendered-message-count={renderedMessages.length}
|
|
2598
2678
|
className={cn(
|
|
2599
2679
|
'flex flex-col min-h-0 min-w-0 border-0',
|
|
2600
2680
|
conversationTab
|
|
@@ -2629,8 +2709,8 @@ function ModernAgentConversationInner({
|
|
|
2629
2709
|
<PendingStartConversation message={pendingStartMessage} startedAt={pendingStartTimestamp} />
|
|
2630
2710
|
) : (
|
|
2631
2711
|
<AllMessagesMixed
|
|
2632
|
-
messages={
|
|
2633
|
-
workstreamSourceMessages={
|
|
2712
|
+
messages={renderedMessages}
|
|
2713
|
+
workstreamSourceMessages={renderedWorkstreamSourceMessages}
|
|
2634
2714
|
bottomRef={bottomRef as React.RefObject<HTMLDivElement>}
|
|
2635
2715
|
isCompleted={displayedIsCompleted}
|
|
2636
2716
|
plan={getActivePlan.plan}
|
|
@@ -2681,7 +2761,10 @@ function ModernAgentConversationInner({
|
|
|
2681
2761
|
/>
|
|
2682
2762
|
) : isViewingPlaybackHistory && playbackActiveWorkstreams.length > 0 ? (
|
|
2683
2763
|
<div className="flex-shrink-0 pb-safe-area">
|
|
2684
|
-
<ActiveWorkstreamsSummary
|
|
2764
|
+
<ActiveWorkstreamsSummary
|
|
2765
|
+
activeWorkstreams={playbackActiveWorkstreams}
|
|
2766
|
+
onSelectWorkstream={setActiveWorkstream}
|
|
2767
|
+
/>
|
|
2685
2768
|
</div>
|
|
2686
2769
|
) : (
|
|
2687
2770
|
shouldRenderLiveMessageInputArea && (
|
|
@@ -2749,6 +2832,7 @@ function ModernAgentConversationInner({
|
|
|
2749
2832
|
isCompactingContext={isCompactingContext}
|
|
2750
2833
|
activeTaskCount={activeTaskCount}
|
|
2751
2834
|
activeWorkstreams={composerActiveWorkstreams}
|
|
2835
|
+
onSelectWorkstream={setActiveWorkstream}
|
|
2752
2836
|
placeholder={composerPlaceholder}
|
|
2753
2837
|
onFilesSelected={canUploadFiles ? handleFileUpload : undefined}
|
|
2754
2838
|
uploadedFiles={uploadedFiles}
|