@optilogic/chat 1.0.0-beta.9 → 1.1.0
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/README.md +43 -0
- package/dist/index.cjs +709 -79
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +283 -4
- package/dist/index.d.ts +283 -4
- package/dist/index.js +674 -53
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/components/agent-response/AgentResponse.tsx +59 -13
- package/src/components/agent-response/components/MetadataRow.tsx +15 -4
- package/src/components/agent-response/components/TruncatedMessage.tsx +52 -0
- package/src/components/agent-response/components/index.ts +3 -0
- package/src/components/agent-response/hooks/useAgentResponseAccumulator.ts +65 -8
- package/src/components/agent-response/index.ts +19 -0
- package/src/components/agent-response/types.ts +61 -1
- package/src/components/agent-timeline/AgentTimeline.tsx +256 -0
- package/src/components/agent-timeline/TimelineAgentBlock.tsx +84 -0
- package/src/components/agent-timeline/TimelineItem.tsx +97 -0
- package/src/components/agent-timeline/index.ts +14 -0
- package/src/components/agent-timeline/types.ts +49 -0
- package/src/components/agent-timeline/utils.ts +189 -0
- package/src/components/hitl-interactions/HITLQuestionPanel.tsx +35 -21
- package/src/components/hitl-interactions/index.ts +1 -1
- package/src/components/inline-actions/ActionMarkdownRenderer.tsx +60 -0
- package/src/components/inline-actions/index.ts +18 -0
- package/src/components/inline-actions/parseResponseSegments.ts +66 -0
- package/src/components/inline-actions/prompts.ts +41 -0
- package/src/components/inline-actions/types.ts +57 -0
- package/src/components/user-prompt-input/UserPromptInput.tsx +13 -8
- package/src/components/user-prompt-input/types.ts +4 -0
- package/src/index.ts +29 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@optilogic/chat",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Chat UI components for Optilogic - AgentResponse and related components for LLM interactions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"README.md"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@optilogic/core": "1.
|
|
28
|
-
"@optilogic/editor": "1.
|
|
27
|
+
"@optilogic/core": "1.1.0",
|
|
28
|
+
"@optilogic/editor": "1.1.0"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
31
|
"react": "^18.0.0 || ^19.0.0",
|
|
@@ -6,12 +6,14 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import * as React from "react";
|
|
9
|
-
import { useState, useMemo, useCallback } from "react";
|
|
9
|
+
import { useState, useRef, useMemo, useCallback } from "react";
|
|
10
10
|
import { cn } from "@optilogic/core";
|
|
11
11
|
import { MetadataRow, ThinkingSection, ActionBar, HITLSection } from "./components";
|
|
12
12
|
import { useThinkingTimer } from "./hooks";
|
|
13
13
|
import type { AgentResponseState, FeedbackValue } from "./types";
|
|
14
14
|
import type { HITLInteraction } from "../hitl-interactions";
|
|
15
|
+
import { AgentTimeline, createTimelineUIState } from "../agent-timeline";
|
|
16
|
+
import type { TimelineUIState } from "../agent-timeline";
|
|
15
17
|
|
|
16
18
|
export interface AgentResponseProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
17
19
|
/** The response state to render */
|
|
@@ -49,6 +51,24 @@ export interface AgentResponseProps extends React.HTMLAttributes<HTMLDivElement>
|
|
|
49
51
|
/** Whether the HITL section starts expanded (default: false) */
|
|
50
52
|
defaultHITLExpanded?: boolean;
|
|
51
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Optional content to display in the MetadataRow's middle area,
|
|
56
|
+
* between the thinking toggle (left) and activity indicators (right).
|
|
57
|
+
* Typically used for ephemeral status messages during processing.
|
|
58
|
+
* The parent is responsible for setting and clearing this content.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* <AgentResponse
|
|
62
|
+
* state={state}
|
|
63
|
+
* statusContent={
|
|
64
|
+
* state.status !== 'complete'
|
|
65
|
+
* ? <TruncatedMessage message="Analyzing data..." />
|
|
66
|
+
* : undefined
|
|
67
|
+
* }
|
|
68
|
+
* />
|
|
69
|
+
*/
|
|
70
|
+
statusContent?: React.ReactNode;
|
|
71
|
+
|
|
52
72
|
/**
|
|
53
73
|
* Custom markdown renderer for the response content.
|
|
54
74
|
* If not provided, the response will be rendered as plain text.
|
|
@@ -72,6 +92,12 @@ export interface AgentResponseProps extends React.HTMLAttributes<HTMLDivElement>
|
|
|
72
92
|
* />
|
|
73
93
|
*/
|
|
74
94
|
renderThinkingMarkdown?: (content: string) => React.ReactNode;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Maximum height of the AgentTimeline scrollable container.
|
|
98
|
+
* Defaults to "300px". Set to "none" to disable the constraint.
|
|
99
|
+
*/
|
|
100
|
+
timelineMaxHeight?: string;
|
|
75
101
|
}
|
|
76
102
|
|
|
77
103
|
/**
|
|
@@ -121,13 +147,18 @@ const AgentResponse = React.forwardRef<HTMLDivElement, AgentResponseProps>(
|
|
|
121
147
|
actionsVisible = "hover",
|
|
122
148
|
hitlInteractions,
|
|
123
149
|
defaultHITLExpanded = false,
|
|
150
|
+
statusContent,
|
|
124
151
|
renderMarkdown,
|
|
125
152
|
renderThinkingMarkdown,
|
|
153
|
+
timelineMaxHeight,
|
|
126
154
|
className,
|
|
127
155
|
...props
|
|
128
156
|
},
|
|
129
157
|
ref
|
|
130
158
|
) => {
|
|
159
|
+
// Ref-backed timeline UI state (survives remounts during streaming)
|
|
160
|
+
const timelineUIStateRef = useRef<TimelineUIState>(createTimelineUIState());
|
|
161
|
+
|
|
131
162
|
// Uncontrolled thinking expanded state
|
|
132
163
|
const [uncontrolledExpanded, setUncontrolledExpanded] = useState(defaultThinkingExpanded);
|
|
133
164
|
|
|
@@ -163,9 +194,10 @@ const AgentResponse = React.forwardRef<HTMLDivElement, AgentResponseProps>(
|
|
|
163
194
|
return (state.responseCompleteTime - state.firstMessageTime) / 1000;
|
|
164
195
|
}, [state.firstMessageTime, state.responseCompleteTime]);
|
|
165
196
|
|
|
166
|
-
// Check if we have any thinking content (plain text or
|
|
197
|
+
// Check if we have any thinking content (plain text, structured, or timeline)
|
|
198
|
+
const hasTimelineEntries = !!(state.timelineEntries && state.timelineEntries.length > 0);
|
|
167
199
|
const hasThinkingContent =
|
|
168
|
-
!!state.thinking || (state.thinkingSteps && state.thinkingSteps.length > 0) || false;
|
|
200
|
+
!!state.thinking || (state.thinkingSteps && state.thinkingSteps.length > 0) || hasTimelineEntries || false;
|
|
169
201
|
|
|
170
202
|
const hasHITLInteractions =
|
|
171
203
|
hitlInteractions && hitlInteractions.length > 0;
|
|
@@ -221,20 +253,34 @@ const AgentResponse = React.forwardRef<HTMLDivElement, AgentResponseProps>(
|
|
|
221
253
|
knowledge={state.knowledge}
|
|
222
254
|
memory={state.memory}
|
|
223
255
|
statusUpdates={state.statusUpdates}
|
|
256
|
+
statusContent={statusContent}
|
|
224
257
|
status={state.status}
|
|
225
258
|
elapsedTime={elapsedTime}
|
|
226
259
|
/>
|
|
227
260
|
|
|
228
|
-
{/* Thinking Content -
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
261
|
+
{/* Thinking Content - AgentTimeline when timeline entries exist, ThinkingSection otherwise */}
|
|
262
|
+
{hasTimelineEntries ? (
|
|
263
|
+
thinkingExpanded && (
|
|
264
|
+
<div className="pb-3 border-t border-border">
|
|
265
|
+
<AgentTimeline
|
|
266
|
+
entries={state.timelineEntries!}
|
|
267
|
+
renderMarkdown={renderThinkingMarkdown}
|
|
268
|
+
uiState={timelineUIStateRef.current}
|
|
269
|
+
maxHeight={timelineMaxHeight}
|
|
270
|
+
/>
|
|
271
|
+
</div>
|
|
272
|
+
)
|
|
273
|
+
) : (
|
|
274
|
+
<ThinkingSection
|
|
275
|
+
content={
|
|
276
|
+
state.thinkingSteps && state.thinkingSteps.length > 0
|
|
277
|
+
? state.thinkingSteps
|
|
278
|
+
: state.thinking
|
|
279
|
+
}
|
|
280
|
+
isExpanded={thinkingExpanded}
|
|
281
|
+
renderMarkdown={renderThinkingMarkdown}
|
|
282
|
+
/>
|
|
283
|
+
)}
|
|
238
284
|
</>
|
|
239
285
|
)}
|
|
240
286
|
|
|
@@ -26,6 +26,8 @@ export interface MetadataRowProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
26
26
|
memory: MemoryItem[];
|
|
27
27
|
/** Status updates to display */
|
|
28
28
|
statusUpdates?: StatusItem[];
|
|
29
|
+
/** Optional content to display in the middle area between left content and activity indicators */
|
|
30
|
+
statusContent?: React.ReactNode;
|
|
29
31
|
/** Current response status */
|
|
30
32
|
status: AgentResponseStatus;
|
|
31
33
|
/** Elapsed time in seconds */
|
|
@@ -60,6 +62,7 @@ const MetadataRow = React.forwardRef<HTMLDivElement, MetadataRowProps>(
|
|
|
60
62
|
knowledge,
|
|
61
63
|
memory,
|
|
62
64
|
statusUpdates = [],
|
|
65
|
+
statusContent,
|
|
63
66
|
status,
|
|
64
67
|
elapsedTime,
|
|
65
68
|
className,
|
|
@@ -108,8 +111,8 @@ const MetadataRow = React.forwardRef<HTMLDivElement, MetadataRowProps>(
|
|
|
108
111
|
|
|
109
112
|
const leftContent = renderLeftContent();
|
|
110
113
|
|
|
111
|
-
// If nothing to show (no thinking, not processing, no activity), hide the row
|
|
112
|
-
if (!leftContent && !hasActivity) {
|
|
114
|
+
// If nothing to show (no thinking, not processing, no activity, no status content), hide the row
|
|
115
|
+
if (!leftContent && !hasActivity && !statusContent) {
|
|
113
116
|
return null;
|
|
114
117
|
}
|
|
115
118
|
|
|
@@ -125,15 +128,23 @@ const MetadataRow = React.forwardRef<HTMLDivElement, MetadataRowProps>(
|
|
|
125
128
|
{hasThinking ? (
|
|
126
129
|
<button
|
|
127
130
|
onClick={onToggle}
|
|
128
|
-
className="flex items-center gap-1.5 hover:bg-muted/50 -ml-1.5 pl-1.5 pr-2 py-0.5 rounded transition-colors"
|
|
131
|
+
className="flex items-center gap-1.5 hover:bg-muted/50 -ml-1.5 pl-1.5 pr-2 py-0.5 rounded transition-colors shrink-0"
|
|
129
132
|
>
|
|
130
133
|
{leftContent}
|
|
131
134
|
</button>
|
|
132
135
|
) : (
|
|
133
|
-
<div className="flex items-center gap-1.5">
|
|
136
|
+
<div className="flex items-center gap-1.5 shrink-0">
|
|
134
137
|
{leftContent}
|
|
135
138
|
</div>
|
|
136
139
|
)}
|
|
140
|
+
|
|
141
|
+
{/* Middle content - status content slot */}
|
|
142
|
+
{statusContent && (
|
|
143
|
+
<div className="flex-1 min-w-0 mx-2">
|
|
144
|
+
{statusContent}
|
|
145
|
+
</div>
|
|
146
|
+
)}
|
|
147
|
+
|
|
137
148
|
<ActivityIndicators
|
|
138
149
|
toolCalls={toolCalls}
|
|
139
150
|
knowledge={knowledge}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Truncated Message Component
|
|
3
|
+
*
|
|
4
|
+
* Renders a single-line text message with CSS-based truncation (text-overflow: ellipsis).
|
|
5
|
+
* Designed as a standalone utility that can be used anywhere, including as
|
|
6
|
+
* the statusContent slot in MetadataRow.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import * as React from "react";
|
|
10
|
+
import { cn } from "@optilogic/core";
|
|
11
|
+
|
|
12
|
+
export interface TruncatedMessageProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
13
|
+
/** The message string to display (truncated with ellipsis if it overflows) */
|
|
14
|
+
message: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* TruncatedMessage Component
|
|
19
|
+
*
|
|
20
|
+
* Displays a single-line text message that truncates with an ellipsis when
|
|
21
|
+
* it overflows its container. Uses CSS text-overflow for zero-JS truncation.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* <TruncatedMessage message="Searching the knowledge base for relevant documents..." />
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* // Inside MetadataRow's statusContent slot
|
|
28
|
+
* <AgentResponse
|
|
29
|
+
* state={state}
|
|
30
|
+
* statusContent={<TruncatedMessage message="Running analysis..." />}
|
|
31
|
+
* />
|
|
32
|
+
*/
|
|
33
|
+
const TruncatedMessage = React.forwardRef<HTMLDivElement, TruncatedMessageProps>(
|
|
34
|
+
({ message, className, ...props }, ref) => {
|
|
35
|
+
return (
|
|
36
|
+
<div
|
|
37
|
+
ref={ref}
|
|
38
|
+
className={cn(
|
|
39
|
+
"text-xs text-muted-foreground truncate min-w-0",
|
|
40
|
+
className
|
|
41
|
+
)}
|
|
42
|
+
title={message}
|
|
43
|
+
{...props}
|
|
44
|
+
>
|
|
45
|
+
{message}
|
|
46
|
+
</div>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
TruncatedMessage.displayName = "TruncatedMessage";
|
|
51
|
+
|
|
52
|
+
export { TruncatedMessage };
|
|
@@ -16,3 +16,6 @@ export type { ActionBarProps } from "./ActionBar";
|
|
|
16
16
|
|
|
17
17
|
export { HITLSection } from "./HITLSection";
|
|
18
18
|
export type { HITLSectionProps } from "./HITLSection";
|
|
19
|
+
|
|
20
|
+
export { TruncatedMessage } from "./TruncatedMessage";
|
|
21
|
+
export type { TruncatedMessageProps } from "./TruncatedMessage";
|
|
@@ -15,7 +15,9 @@ import {
|
|
|
15
15
|
type MemoryItem,
|
|
16
16
|
type StatusItem,
|
|
17
17
|
type ThinkingStep,
|
|
18
|
+
type PotentialResponse,
|
|
18
19
|
} from "../types";
|
|
20
|
+
import { buildTimelineEntries } from "../../agent-timeline/utils";
|
|
19
21
|
|
|
20
22
|
export interface UseAgentResponseAccumulatorOptions {
|
|
21
23
|
/** WebSocket topic to filter messages (optional, for convenience) */
|
|
@@ -94,33 +96,50 @@ export function useAgentResponseAccumulator(
|
|
|
94
96
|
id: payload.thinkingStep.id || `step-${Date.now()}`,
|
|
95
97
|
label: payload.thinkingStep.label,
|
|
96
98
|
content: payload.thinkingStep.content,
|
|
97
|
-
depth: payload.thinkingStep.depth ?? 0,
|
|
99
|
+
depth: payload.thinkingStep.depth ?? payload.depth ?? 0,
|
|
98
100
|
isCollapsed: payload.thinkingStep.isCollapsed,
|
|
101
|
+
timestamp: Date.now(),
|
|
102
|
+
agentName: payload.agentName,
|
|
103
|
+
parentAgent: payload.parentAgent,
|
|
99
104
|
};
|
|
100
105
|
const thinkingStartTime = prev.thinkingStartTime ?? Date.now();
|
|
101
|
-
|
|
106
|
+
const next = {
|
|
102
107
|
...prev,
|
|
103
108
|
status: newStatus,
|
|
104
109
|
thinkingSteps: [...(prev.thinkingSteps || []), newStep],
|
|
105
110
|
thinkingStartTime,
|
|
106
111
|
firstMessageTime,
|
|
107
112
|
};
|
|
113
|
+
return { ...next, timelineEntries: buildTimelineEntries(next) };
|
|
108
114
|
}
|
|
109
115
|
|
|
110
|
-
// Plain text thinking
|
|
116
|
+
// Plain text thinking — concatenate for backward compat AND
|
|
117
|
+
// push a ThinkingStep so the timeline gets individual entries.
|
|
111
118
|
const newThinking = payload.message || payload.content || "";
|
|
112
119
|
// Add line break between thinking messages
|
|
113
120
|
const separator = prev.thinking && newThinking ? "\n\n" : "";
|
|
114
121
|
// Set thinkingStartTime on first thinking message
|
|
115
122
|
const thinkingStartTime =
|
|
116
123
|
prev.thinkingStartTime ?? (newThinking ? Date.now() : null);
|
|
117
|
-
|
|
124
|
+
const prevSteps = prev.thinkingSteps || [];
|
|
125
|
+
const plainStep: ThinkingStep = {
|
|
126
|
+
id: `step-${prevSteps.length}`,
|
|
127
|
+
label: newThinking,
|
|
128
|
+
content: newThinking,
|
|
129
|
+
depth: payload.depth ?? 0,
|
|
130
|
+
timestamp: Date.now(),
|
|
131
|
+
agentName: payload.agentName,
|
|
132
|
+
parentAgent: payload.parentAgent,
|
|
133
|
+
};
|
|
134
|
+
const next = {
|
|
118
135
|
...prev,
|
|
119
136
|
status: newStatus,
|
|
120
137
|
thinking: prev.thinking + separator + newThinking,
|
|
138
|
+
thinkingSteps: [...prevSteps, plainStep],
|
|
121
139
|
thinkingStartTime,
|
|
122
140
|
firstMessageTime,
|
|
123
141
|
};
|
|
142
|
+
return { ...next, timelineEntries: buildTimelineEntries(next) };
|
|
124
143
|
}
|
|
125
144
|
|
|
126
145
|
case "tool_call": {
|
|
@@ -132,13 +151,17 @@ export function useAgentResponseAccumulator(
|
|
|
132
151
|
name: toolName,
|
|
133
152
|
arguments: payload.tool?.arguments,
|
|
134
153
|
timestamp: Date.now(),
|
|
154
|
+
agentName: payload.agentName,
|
|
155
|
+
parentAgent: payload.parentAgent,
|
|
156
|
+
depth: payload.depth,
|
|
135
157
|
};
|
|
136
|
-
|
|
158
|
+
const next = {
|
|
137
159
|
...prev,
|
|
138
160
|
status: newStatus,
|
|
139
161
|
toolCalls: [...prev.toolCalls, newToolCall],
|
|
140
162
|
firstMessageTime,
|
|
141
163
|
};
|
|
164
|
+
return { ...next, timelineEntries: buildTimelineEntries(next) };
|
|
142
165
|
}
|
|
143
166
|
return { ...prev, status: newStatus, firstMessageTime };
|
|
144
167
|
}
|
|
@@ -152,13 +175,17 @@ export function useAgentResponseAccumulator(
|
|
|
152
175
|
source: payload.knowledge?.source || "unknown",
|
|
153
176
|
content: knowledgeContent,
|
|
154
177
|
timestamp: Date.now(),
|
|
178
|
+
agentName: payload.agentName,
|
|
179
|
+
parentAgent: payload.parentAgent,
|
|
180
|
+
depth: payload.depth,
|
|
155
181
|
};
|
|
156
|
-
|
|
182
|
+
const next = {
|
|
157
183
|
...prev,
|
|
158
184
|
status: newStatus,
|
|
159
185
|
knowledge: [...prev.knowledge, newKnowledge],
|
|
160
186
|
firstMessageTime,
|
|
161
187
|
};
|
|
188
|
+
return { ...next, timelineEntries: buildTimelineEntries(next) };
|
|
162
189
|
}
|
|
163
190
|
return { ...prev, status: newStatus, firstMessageTime };
|
|
164
191
|
}
|
|
@@ -172,13 +199,17 @@ export function useAgentResponseAccumulator(
|
|
|
172
199
|
type: payload.memory?.type || "unknown",
|
|
173
200
|
content: memoryContent,
|
|
174
201
|
timestamp: Date.now(),
|
|
202
|
+
agentName: payload.agentName,
|
|
203
|
+
parentAgent: payload.parentAgent,
|
|
204
|
+
depth: payload.depth,
|
|
175
205
|
};
|
|
176
|
-
|
|
206
|
+
const next = {
|
|
177
207
|
...prev,
|
|
178
208
|
status: newStatus,
|
|
179
209
|
memory: [...prev.memory, newMemory],
|
|
180
210
|
firstMessageTime,
|
|
181
211
|
};
|
|
212
|
+
return { ...next, timelineEntries: buildTimelineEntries(next) };
|
|
182
213
|
}
|
|
183
214
|
return { ...prev, status: newStatus, firstMessageTime };
|
|
184
215
|
}
|
|
@@ -200,13 +231,39 @@ export function useAgentResponseAccumulator(
|
|
|
200
231
|
message: statusMessage,
|
|
201
232
|
agent: payload.statusUpdate?.agent,
|
|
202
233
|
timestamp: Date.now(),
|
|
234
|
+
agentName: payload.agentName,
|
|
235
|
+
parentAgent: payload.parentAgent,
|
|
236
|
+
depth: payload.depth,
|
|
203
237
|
};
|
|
204
|
-
|
|
238
|
+
const next = {
|
|
205
239
|
...prev,
|
|
206
240
|
status: newStatus,
|
|
207
241
|
statusUpdates: [...prev.statusUpdates, newStatusItem],
|
|
208
242
|
firstMessageTime,
|
|
209
243
|
};
|
|
244
|
+
return { ...next, timelineEntries: buildTimelineEntries(next) };
|
|
245
|
+
}
|
|
246
|
+
return { ...prev, status: newStatus, firstMessageTime };
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
case "potential_response": {
|
|
250
|
+
const respContent = payload.message || payload.content || "";
|
|
251
|
+
if (respContent) {
|
|
252
|
+
const newResp: PotentialResponse = {
|
|
253
|
+
id: `resp-${Date.now()}`,
|
|
254
|
+
content: respContent,
|
|
255
|
+
timestamp: Date.now(),
|
|
256
|
+
agentName: payload.agentName,
|
|
257
|
+
parentAgent: payload.parentAgent,
|
|
258
|
+
depth: payload.depth,
|
|
259
|
+
};
|
|
260
|
+
const next = {
|
|
261
|
+
...prev,
|
|
262
|
+
status: newStatus,
|
|
263
|
+
potentialResponses: [...(prev.potentialResponses || []), newResp],
|
|
264
|
+
firstMessageTime,
|
|
265
|
+
};
|
|
266
|
+
return { ...next, timelineEntries: buildTimelineEntries(next) };
|
|
210
267
|
}
|
|
211
268
|
return { ...prev, status: newStatus, firstMessageTime };
|
|
212
269
|
}
|
|
@@ -16,11 +16,13 @@ export {
|
|
|
16
16
|
ThinkingSection,
|
|
17
17
|
ActionBar,
|
|
18
18
|
HITLSection,
|
|
19
|
+
TruncatedMessage,
|
|
19
20
|
type ActivityIndicatorsProps,
|
|
20
21
|
type MetadataRowProps,
|
|
21
22
|
type ThinkingSectionProps,
|
|
22
23
|
type ActionBarProps,
|
|
23
24
|
type HITLSectionProps,
|
|
25
|
+
type TruncatedMessageProps,
|
|
24
26
|
} from "./components";
|
|
25
27
|
|
|
26
28
|
// Hooks
|
|
@@ -43,6 +45,7 @@ export type {
|
|
|
43
45
|
StatusItem,
|
|
44
46
|
ThinkingStep,
|
|
45
47
|
ThinkingContent,
|
|
48
|
+
PotentialResponse,
|
|
46
49
|
AgentMessage,
|
|
47
50
|
GenericWebSocketMessage,
|
|
48
51
|
} from "./types";
|
|
@@ -51,3 +54,19 @@ export { initialAgentResponseState } from "./types";
|
|
|
51
54
|
|
|
52
55
|
// Utilities
|
|
53
56
|
export { formatTime, formatTotalTime } from "./utils";
|
|
57
|
+
|
|
58
|
+
// Agent Timeline (replaces ThinkingSection for rich execution visibility)
|
|
59
|
+
export {
|
|
60
|
+
AgentTimeline,
|
|
61
|
+
createTimelineUIState,
|
|
62
|
+
buildTimelineEntries,
|
|
63
|
+
groupIntoAgentRuns,
|
|
64
|
+
deduplicateEntries,
|
|
65
|
+
} from "../agent-timeline";
|
|
66
|
+
export type {
|
|
67
|
+
TimelineUIState,
|
|
68
|
+
TimelineEntry,
|
|
69
|
+
TimelineEntryType,
|
|
70
|
+
AgentRun,
|
|
71
|
+
DisplayEntry,
|
|
72
|
+
} from "../agent-timeline";
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* Type definitions for the library-ready agent response component
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import type { TimelineEntry } from "../agent-timeline/types";
|
|
8
|
+
|
|
7
9
|
/**
|
|
8
10
|
* Status of the agent response cycle
|
|
9
11
|
*/
|
|
@@ -22,6 +24,12 @@ export interface ToolCall {
|
|
|
22
24
|
name: string;
|
|
23
25
|
arguments?: Record<string, unknown>;
|
|
24
26
|
timestamp: number;
|
|
27
|
+
/** Agent that made this call (multi-agent scenarios) */
|
|
28
|
+
agentName?: string | null;
|
|
29
|
+
/** Parent agent name */
|
|
30
|
+
parentAgent?: string | null;
|
|
31
|
+
/** Nesting depth in agent hierarchy */
|
|
32
|
+
depth?: number;
|
|
25
33
|
}
|
|
26
34
|
|
|
27
35
|
/**
|
|
@@ -32,6 +40,12 @@ export interface KnowledgeItem {
|
|
|
32
40
|
source: string;
|
|
33
41
|
content: string;
|
|
34
42
|
timestamp: number;
|
|
43
|
+
/** Agent that retrieved this (multi-agent scenarios) */
|
|
44
|
+
agentName?: string | null;
|
|
45
|
+
/** Parent agent name */
|
|
46
|
+
parentAgent?: string | null;
|
|
47
|
+
/** Nesting depth in agent hierarchy */
|
|
48
|
+
depth?: number;
|
|
35
49
|
}
|
|
36
50
|
|
|
37
51
|
/**
|
|
@@ -42,6 +56,24 @@ export interface MemoryItem {
|
|
|
42
56
|
type: string;
|
|
43
57
|
content: string;
|
|
44
58
|
timestamp: number;
|
|
59
|
+
/** Agent that accessed this (multi-agent scenarios) */
|
|
60
|
+
agentName?: string | null;
|
|
61
|
+
/** Parent agent name */
|
|
62
|
+
parentAgent?: string | null;
|
|
63
|
+
/** Nesting depth in agent hierarchy */
|
|
64
|
+
depth?: number;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Potential response (sub-agent intermediate AI response)
|
|
69
|
+
*/
|
|
70
|
+
export interface PotentialResponse {
|
|
71
|
+
id: string;
|
|
72
|
+
content: string;
|
|
73
|
+
timestamp: number;
|
|
74
|
+
agentName?: string | null;
|
|
75
|
+
parentAgent?: string | null;
|
|
76
|
+
depth?: number;
|
|
45
77
|
}
|
|
46
78
|
|
|
47
79
|
/**
|
|
@@ -53,6 +85,12 @@ export interface StatusItem {
|
|
|
53
85
|
timestamp: number;
|
|
54
86
|
/** Optional agent name if in multi-agent scenario */
|
|
55
87
|
agent?: string;
|
|
88
|
+
/** Agent that produced this (multi-agent scenarios) */
|
|
89
|
+
agentName?: string | null;
|
|
90
|
+
/** Parent agent name */
|
|
91
|
+
parentAgent?: string | null;
|
|
92
|
+
/** Nesting depth in agent hierarchy */
|
|
93
|
+
depth?: number;
|
|
56
94
|
}
|
|
57
95
|
|
|
58
96
|
/**
|
|
@@ -69,6 +107,12 @@ export interface ThinkingStep {
|
|
|
69
107
|
depth: number;
|
|
70
108
|
/** Whether this step should start collapsed (default: false) */
|
|
71
109
|
isCollapsed?: boolean;
|
|
110
|
+
/** Timestamp for timeline ordering */
|
|
111
|
+
timestamp?: number;
|
|
112
|
+
/** Agent that produced this (multi-agent scenarios) */
|
|
113
|
+
agentName?: string | null;
|
|
114
|
+
/** Parent agent name */
|
|
115
|
+
parentAgent?: string | null;
|
|
72
116
|
}
|
|
73
117
|
|
|
74
118
|
/**
|
|
@@ -96,8 +140,14 @@ export interface AgentResponseState {
|
|
|
96
140
|
memory: MemoryItem[];
|
|
97
141
|
/** Status updates from the agent */
|
|
98
142
|
statusUpdates: StatusItem[];
|
|
143
|
+
/** Potential responses (sub-agent intermediate AI responses) */
|
|
144
|
+
potentialResponses?: PotentialResponse[];
|
|
145
|
+
/** Custom timeline entries (consumer-provided) */
|
|
146
|
+
customTimelineEntries?: TimelineEntry[];
|
|
99
147
|
/** Final response text */
|
|
100
148
|
response: string;
|
|
149
|
+
/** Timeline entries derived from all accumulator arrays (for AgentTimeline) */
|
|
150
|
+
timelineEntries?: TimelineEntry[];
|
|
101
151
|
/** Timestamp when first thinking message was received (for timer) */
|
|
102
152
|
thinkingStartTime: number | null;
|
|
103
153
|
/** Timestamp when response was completed (for final timer display) */
|
|
@@ -110,13 +160,21 @@ export interface AgentResponseState {
|
|
|
110
160
|
* WebSocket message payload for agent responses
|
|
111
161
|
*/
|
|
112
162
|
export interface AgentMessage {
|
|
113
|
-
type: "status" | "thinking" | "tool_call" | "knowledge" | "memory" | "response" | "status_update";
|
|
163
|
+
type: "status" | "thinking" | "tool_call" | "knowledge" | "memory" | "response" | "status_update" | "potential_response";
|
|
114
164
|
/** Message content - for simple string payloads */
|
|
115
165
|
message?: string;
|
|
116
166
|
/** Alternative content field */
|
|
117
167
|
content?: string;
|
|
118
168
|
/** For status messages */
|
|
119
169
|
status?: string;
|
|
170
|
+
/** Agent name (multi-agent scenarios) */
|
|
171
|
+
agentName?: string | null;
|
|
172
|
+
/** Parent agent name (multi-agent scenarios) */
|
|
173
|
+
parentAgent?: string | null;
|
|
174
|
+
/** Agent nesting depth (0 = root) */
|
|
175
|
+
depth?: number;
|
|
176
|
+
/** Title/label for timeline display */
|
|
177
|
+
title?: string | null;
|
|
120
178
|
/** For tool_call messages */
|
|
121
179
|
tool?: {
|
|
122
180
|
id: string;
|
|
@@ -170,6 +228,8 @@ export const initialAgentResponseState: AgentResponseState = {
|
|
|
170
228
|
knowledge: [],
|
|
171
229
|
memory: [],
|
|
172
230
|
statusUpdates: [],
|
|
231
|
+
potentialResponses: [],
|
|
232
|
+
customTimelineEntries: [],
|
|
173
233
|
response: "",
|
|
174
234
|
thinkingStartTime: null,
|
|
175
235
|
responseCompleteTime: null,
|