@optilogic/chat 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.cjs +567 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +378 -0
- package/dist/index.d.ts +378 -0
- package/dist/index.js +537 -0
- package/dist/index.js.map +1 -0
- package/package.json +66 -0
- package/src/components/agent-response/AgentResponse.tsx +232 -0
- package/src/components/agent-response/components/ActionBar.tsx +150 -0
- package/src/components/agent-response/components/ActivityIndicators.tsx +140 -0
- package/src/components/agent-response/components/MetadataRow.tsx +145 -0
- package/src/components/agent-response/components/ThinkingSection.tsx +48 -0
- package/src/components/agent-response/components/index.ts +15 -0
- package/src/components/agent-response/hooks/index.ts +12 -0
- package/src/components/agent-response/hooks/useAgentResponseAccumulator.ts +186 -0
- package/src/components/agent-response/hooks/useThinkingTimer.ts +52 -0
- package/src/components/agent-response/index.ts +48 -0
- package/src/components/agent-response/types.ts +124 -0
- package/src/components/agent-response/utils.ts +48 -0
- package/src/index.ts +46 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useState, useCallback, useMemo, useEffect } from 'react';
|
|
3
|
+
import { cn, Popover, PopoverTrigger, PopoverContent, LoadingSpinner } from '@optilogic/core';
|
|
4
|
+
import { Wrench, Book, HardDrive, Check, Copy, ThumbsUp, ThumbsDown, ChevronUp, ChevronDown } from 'lucide-react';
|
|
5
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
// src/components/agent-response/AgentResponse.tsx
|
|
8
|
+
var ActivityIndicators = React.forwardRef(
|
|
9
|
+
({ toolCalls, knowledge, memory, className, ...props }, ref) => {
|
|
10
|
+
const hasAnyActivity = toolCalls.length > 0 || knowledge.length > 0 || memory.length > 0;
|
|
11
|
+
if (!hasAnyActivity) return null;
|
|
12
|
+
return /* @__PURE__ */ jsxs("div", { ref, className: cn("flex items-center gap-2", className), ...props, children: [
|
|
13
|
+
toolCalls.length > 0 && /* @__PURE__ */ jsxs(Popover, { children: [
|
|
14
|
+
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
15
|
+
"button",
|
|
16
|
+
{
|
|
17
|
+
className: "flex items-center gap-1 text-muted-foreground hover:text-foreground transition-colors",
|
|
18
|
+
onClick: (e) => e.stopPropagation(),
|
|
19
|
+
children: [
|
|
20
|
+
/* @__PURE__ */ jsx(Wrench, { className: "w-3.5 h-3.5" }),
|
|
21
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs", children: toolCalls.length })
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
) }),
|
|
25
|
+
/* @__PURE__ */ jsx(PopoverContent, { className: "w-80", children: /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
26
|
+
/* @__PURE__ */ jsx("h4", { className: "font-medium text-sm", children: "Tool Calls" }),
|
|
27
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-2 max-h-60 overflow-auto", children: toolCalls.map((tool) => /* @__PURE__ */ jsxs("div", { className: "p-2 bg-muted rounded text-xs", children: [
|
|
28
|
+
/* @__PURE__ */ jsx("div", { className: "font-medium", children: tool.name }),
|
|
29
|
+
tool.arguments && /* @__PURE__ */ jsx("pre", { className: "mt-1 text-muted-foreground overflow-x-auto", children: JSON.stringify(tool.arguments, null, 2) })
|
|
30
|
+
] }, tool.id)) })
|
|
31
|
+
] }) })
|
|
32
|
+
] }),
|
|
33
|
+
knowledge.length > 0 && /* @__PURE__ */ jsxs(Popover, { children: [
|
|
34
|
+
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
35
|
+
"button",
|
|
36
|
+
{
|
|
37
|
+
className: "flex items-center gap-1 text-muted-foreground hover:text-foreground transition-colors",
|
|
38
|
+
onClick: (e) => e.stopPropagation(),
|
|
39
|
+
children: [
|
|
40
|
+
/* @__PURE__ */ jsx(Book, { className: "w-3.5 h-3.5" }),
|
|
41
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs", children: knowledge.length })
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
) }),
|
|
45
|
+
/* @__PURE__ */ jsx(PopoverContent, { className: "w-80", children: /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
46
|
+
/* @__PURE__ */ jsx("h4", { className: "font-medium text-sm", children: "Knowledge Retrieved" }),
|
|
47
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-2 max-h-60 overflow-auto", children: knowledge.map((item) => /* @__PURE__ */ jsxs("div", { className: "p-2 bg-muted rounded text-xs", children: [
|
|
48
|
+
/* @__PURE__ */ jsx("div", { className: "font-medium", children: item.source }),
|
|
49
|
+
/* @__PURE__ */ jsx("div", { className: "mt-1 text-muted-foreground", children: item.content })
|
|
50
|
+
] }, item.id)) })
|
|
51
|
+
] }) })
|
|
52
|
+
] }),
|
|
53
|
+
memory.length > 0 && /* @__PURE__ */ jsxs(Popover, { children: [
|
|
54
|
+
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
55
|
+
"button",
|
|
56
|
+
{
|
|
57
|
+
className: "flex items-center gap-1 text-muted-foreground hover:text-foreground transition-colors",
|
|
58
|
+
onClick: (e) => e.stopPropagation(),
|
|
59
|
+
children: [
|
|
60
|
+
/* @__PURE__ */ jsx(HardDrive, { className: "w-3.5 h-3.5" }),
|
|
61
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs", children: memory.length })
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
) }),
|
|
65
|
+
/* @__PURE__ */ jsx(PopoverContent, { className: "w-80", children: /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
66
|
+
/* @__PURE__ */ jsx("h4", { className: "font-medium text-sm", children: "Memory Accessed" }),
|
|
67
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-2 max-h-60 overflow-auto", children: memory.map((item) => /* @__PURE__ */ jsxs("div", { className: "p-2 bg-muted rounded text-xs", children: [
|
|
68
|
+
/* @__PURE__ */ jsx("div", { className: "font-medium", children: item.type }),
|
|
69
|
+
/* @__PURE__ */ jsx("div", { className: "mt-1 text-muted-foreground", children: item.content })
|
|
70
|
+
] }, item.id)) })
|
|
71
|
+
] }) })
|
|
72
|
+
] })
|
|
73
|
+
] });
|
|
74
|
+
}
|
|
75
|
+
);
|
|
76
|
+
ActivityIndicators.displayName = "ActivityIndicators";
|
|
77
|
+
|
|
78
|
+
// src/components/agent-response/utils.ts
|
|
79
|
+
function formatTime(seconds, isComplete) {
|
|
80
|
+
if (seconds < 1) {
|
|
81
|
+
return isComplete ? "<1s" : "0s";
|
|
82
|
+
}
|
|
83
|
+
if (isComplete) {
|
|
84
|
+
if (seconds < 60) {
|
|
85
|
+
return `${Math.round(seconds)}s`;
|
|
86
|
+
}
|
|
87
|
+
const minutes = seconds / 60;
|
|
88
|
+
return `${minutes.toFixed(1)} min`;
|
|
89
|
+
}
|
|
90
|
+
if (seconds < 60) {
|
|
91
|
+
return `${Math.floor(seconds)}s`;
|
|
92
|
+
}
|
|
93
|
+
const mins = Math.floor(seconds / 60);
|
|
94
|
+
const secs = Math.floor(seconds % 60);
|
|
95
|
+
return `${mins}:${secs.toString().padStart(2, "0")}`;
|
|
96
|
+
}
|
|
97
|
+
function formatTotalTime(seconds) {
|
|
98
|
+
if (seconds < 1) {
|
|
99
|
+
return "<1s";
|
|
100
|
+
}
|
|
101
|
+
if (seconds < 60) {
|
|
102
|
+
return `${seconds.toFixed(1)}s`;
|
|
103
|
+
}
|
|
104
|
+
const minutes = seconds / 60;
|
|
105
|
+
return `${minutes.toFixed(1)}m`;
|
|
106
|
+
}
|
|
107
|
+
var MetadataRow = React.forwardRef(
|
|
108
|
+
({
|
|
109
|
+
hasThinking,
|
|
110
|
+
isExpanded,
|
|
111
|
+
onToggle,
|
|
112
|
+
toolCalls,
|
|
113
|
+
knowledge,
|
|
114
|
+
memory,
|
|
115
|
+
status,
|
|
116
|
+
elapsedTime,
|
|
117
|
+
className,
|
|
118
|
+
...props
|
|
119
|
+
}, ref) => {
|
|
120
|
+
const isProcessing = status === "processing";
|
|
121
|
+
const isComplete = status === "complete";
|
|
122
|
+
const hasActivity = toolCalls.length > 0 || knowledge.length > 0 || memory.length > 0;
|
|
123
|
+
const renderLeftContent = () => {
|
|
124
|
+
if (hasThinking) {
|
|
125
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
126
|
+
isExpanded ? /* @__PURE__ */ jsx(ChevronUp, { className: "w-3.5 h-3.5 text-muted-foreground" }) : /* @__PURE__ */ jsx(ChevronDown, { className: "w-3.5 h-3.5 text-muted-foreground" }),
|
|
127
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: isComplete ? `Thought for ${formatTime(elapsedTime, true)}` : `Thinking... ${formatTime(elapsedTime, false)}` })
|
|
128
|
+
] });
|
|
129
|
+
}
|
|
130
|
+
if (isProcessing) {
|
|
131
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
132
|
+
/* @__PURE__ */ jsx(LoadingSpinner, { size: "sm", variant: "muted", className: "w-3.5 h-3.5" }),
|
|
133
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "Processing" })
|
|
134
|
+
] });
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
};
|
|
138
|
+
const leftContent = renderLeftContent();
|
|
139
|
+
if (!leftContent && !hasActivity) {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
return /* @__PURE__ */ jsxs(
|
|
143
|
+
"div",
|
|
144
|
+
{
|
|
145
|
+
ref,
|
|
146
|
+
className: cn("w-full flex items-center justify-between px-3 py-2", className),
|
|
147
|
+
...props,
|
|
148
|
+
children: [
|
|
149
|
+
hasThinking ? /* @__PURE__ */ jsx(
|
|
150
|
+
"button",
|
|
151
|
+
{
|
|
152
|
+
onClick: onToggle,
|
|
153
|
+
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",
|
|
154
|
+
children: leftContent
|
|
155
|
+
}
|
|
156
|
+
) : /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1.5", children: leftContent }),
|
|
157
|
+
/* @__PURE__ */ jsx(
|
|
158
|
+
ActivityIndicators,
|
|
159
|
+
{
|
|
160
|
+
toolCalls,
|
|
161
|
+
knowledge,
|
|
162
|
+
memory
|
|
163
|
+
}
|
|
164
|
+
)
|
|
165
|
+
]
|
|
166
|
+
}
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
);
|
|
170
|
+
MetadataRow.displayName = "MetadataRow";
|
|
171
|
+
var ThinkingSection = React.forwardRef(
|
|
172
|
+
({ content, isExpanded, className, ...props }, ref) => {
|
|
173
|
+
if (!isExpanded || !content) {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
return /* @__PURE__ */ jsx(
|
|
177
|
+
"div",
|
|
178
|
+
{
|
|
179
|
+
ref,
|
|
180
|
+
className: cn("px-3 pb-3 border-t border-border", className),
|
|
181
|
+
...props,
|
|
182
|
+
children: /* @__PURE__ */ jsx("div", { className: "mt-2 max-h-[200px] overflow-y-auto", children: /* @__PURE__ */ jsx("pre", { className: "text-xs text-muted-foreground whitespace-pre-wrap font-mono", children: content }) })
|
|
183
|
+
}
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
);
|
|
187
|
+
ThinkingSection.displayName = "ThinkingSection";
|
|
188
|
+
var ActionBar = React.forwardRef(
|
|
189
|
+
({
|
|
190
|
+
response,
|
|
191
|
+
isVisible,
|
|
192
|
+
totalTimeSeconds,
|
|
193
|
+
feedback,
|
|
194
|
+
onFeedbackChange,
|
|
195
|
+
onResponseCopy,
|
|
196
|
+
className,
|
|
197
|
+
...props
|
|
198
|
+
}, ref) => {
|
|
199
|
+
const [copied, setCopied] = useState(false);
|
|
200
|
+
const handleCopy = useCallback(async () => {
|
|
201
|
+
try {
|
|
202
|
+
await navigator.clipboard.writeText(response);
|
|
203
|
+
setCopied(true);
|
|
204
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
205
|
+
onResponseCopy?.(response);
|
|
206
|
+
} catch (err) {
|
|
207
|
+
console.error("Failed to copy response:", err);
|
|
208
|
+
}
|
|
209
|
+
}, [response, onResponseCopy]);
|
|
210
|
+
const handleThumbsUp = useCallback(() => {
|
|
211
|
+
const newValue = feedback === "up" ? null : "up";
|
|
212
|
+
onFeedbackChange?.(newValue);
|
|
213
|
+
}, [feedback, onFeedbackChange]);
|
|
214
|
+
const handleThumbsDown = useCallback(() => {
|
|
215
|
+
const newValue = feedback === "down" ? null : "down";
|
|
216
|
+
onFeedbackChange?.(newValue);
|
|
217
|
+
}, [feedback, onFeedbackChange]);
|
|
218
|
+
const isThumbsUp = feedback === "up";
|
|
219
|
+
const isThumbsDown = feedback === "down";
|
|
220
|
+
return /* @__PURE__ */ jsxs(
|
|
221
|
+
"div",
|
|
222
|
+
{
|
|
223
|
+
ref,
|
|
224
|
+
className: cn(
|
|
225
|
+
"flex items-center justify-between px-4 py-2",
|
|
226
|
+
"transition-opacity duration-200",
|
|
227
|
+
isVisible ? "opacity-100" : "opacity-0 pointer-events-none",
|
|
228
|
+
className
|
|
229
|
+
),
|
|
230
|
+
...props,
|
|
231
|
+
children: [
|
|
232
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
233
|
+
/* @__PURE__ */ jsx(
|
|
234
|
+
"button",
|
|
235
|
+
{
|
|
236
|
+
onClick: handleCopy,
|
|
237
|
+
className: "p-1.5 rounded hover:bg-muted transition-colors text-muted-foreground hover:text-foreground",
|
|
238
|
+
title: copied ? "Copied!" : "Copy response",
|
|
239
|
+
children: copied ? /* @__PURE__ */ jsx(Check, { className: "w-4 h-4 text-green-500" }) : /* @__PURE__ */ jsx(Copy, { className: "w-4 h-4" })
|
|
240
|
+
}
|
|
241
|
+
),
|
|
242
|
+
/* @__PURE__ */ jsx(
|
|
243
|
+
"button",
|
|
244
|
+
{
|
|
245
|
+
onClick: handleThumbsUp,
|
|
246
|
+
className: cn(
|
|
247
|
+
"p-1.5 rounded hover:bg-muted transition-colors",
|
|
248
|
+
isThumbsUp ? "text-green-500" : "text-muted-foreground hover:text-foreground"
|
|
249
|
+
),
|
|
250
|
+
title: "Good response",
|
|
251
|
+
children: /* @__PURE__ */ jsx(ThumbsUp, { className: cn("w-4 h-4", isThumbsUp && "fill-current") })
|
|
252
|
+
}
|
|
253
|
+
),
|
|
254
|
+
/* @__PURE__ */ jsx(
|
|
255
|
+
"button",
|
|
256
|
+
{
|
|
257
|
+
onClick: handleThumbsDown,
|
|
258
|
+
className: cn(
|
|
259
|
+
"p-1.5 rounded hover:bg-muted transition-colors",
|
|
260
|
+
isThumbsDown ? "text-red-500" : "text-muted-foreground hover:text-foreground"
|
|
261
|
+
),
|
|
262
|
+
title: "Poor response",
|
|
263
|
+
children: /* @__PURE__ */ jsx(ThumbsDown, { className: cn("w-4 h-4", isThumbsDown && "fill-current") })
|
|
264
|
+
}
|
|
265
|
+
)
|
|
266
|
+
] }),
|
|
267
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
268
|
+
"Total time: ",
|
|
269
|
+
formatTotalTime(totalTimeSeconds)
|
|
270
|
+
] })
|
|
271
|
+
]
|
|
272
|
+
}
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
);
|
|
276
|
+
ActionBar.displayName = "ActionBar";
|
|
277
|
+
function useThinkingTimer({
|
|
278
|
+
startTime,
|
|
279
|
+
endTime,
|
|
280
|
+
status
|
|
281
|
+
}) {
|
|
282
|
+
const [elapsed, setElapsed] = useState(0);
|
|
283
|
+
useEffect(() => {
|
|
284
|
+
if (!startTime) {
|
|
285
|
+
setElapsed(0);
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
if (status === "complete" && endTime) {
|
|
289
|
+
setElapsed((endTime - startTime) / 1e3);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
if (status === "processing") {
|
|
293
|
+
const updateElapsed = () => {
|
|
294
|
+
setElapsed((Date.now() - startTime) / 1e3);
|
|
295
|
+
};
|
|
296
|
+
updateElapsed();
|
|
297
|
+
const interval = setInterval(updateElapsed, 1e3);
|
|
298
|
+
return () => clearInterval(interval);
|
|
299
|
+
}
|
|
300
|
+
}, [startTime, endTime, status]);
|
|
301
|
+
return elapsed;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// src/components/agent-response/types.ts
|
|
305
|
+
var initialAgentResponseState = {
|
|
306
|
+
status: "idle",
|
|
307
|
+
thinking: "",
|
|
308
|
+
toolCalls: [],
|
|
309
|
+
knowledge: [],
|
|
310
|
+
memory: [],
|
|
311
|
+
response: "",
|
|
312
|
+
thinkingStartTime: null,
|
|
313
|
+
responseCompleteTime: null,
|
|
314
|
+
firstMessageTime: null
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
// src/components/agent-response/hooks/useAgentResponseAccumulator.ts
|
|
318
|
+
function useAgentResponseAccumulator(options) {
|
|
319
|
+
const [state, setState] = useState(initialAgentResponseState);
|
|
320
|
+
const topic = options?.topic;
|
|
321
|
+
const handleMessage = useCallback(
|
|
322
|
+
(message) => {
|
|
323
|
+
let payload;
|
|
324
|
+
if (topic) {
|
|
325
|
+
const msg = message;
|
|
326
|
+
if (msg.topic !== topic) return;
|
|
327
|
+
payload = msg.message;
|
|
328
|
+
} else {
|
|
329
|
+
payload = message;
|
|
330
|
+
}
|
|
331
|
+
setState((prev) => {
|
|
332
|
+
let newStatus = prev.status;
|
|
333
|
+
const isFirstMessage = prev.status === "idle" && payload.type !== "status";
|
|
334
|
+
if (isFirstMessage) {
|
|
335
|
+
newStatus = "processing";
|
|
336
|
+
}
|
|
337
|
+
const firstMessageTime = prev.firstMessageTime ?? (isFirstMessage ? Date.now() : null);
|
|
338
|
+
switch (payload.type) {
|
|
339
|
+
case "status":
|
|
340
|
+
if (payload.message === "Harness connected" || payload.status === "Harness connected") {
|
|
341
|
+
return { ...initialAgentResponseState };
|
|
342
|
+
}
|
|
343
|
+
return { ...prev, status: newStatus };
|
|
344
|
+
case "thinking": {
|
|
345
|
+
const newThinking = payload.message || payload.content || "";
|
|
346
|
+
const separator = prev.thinking && newThinking ? "\n\n" : "";
|
|
347
|
+
const thinkingStartTime = prev.thinkingStartTime ?? (newThinking ? Date.now() : null);
|
|
348
|
+
return {
|
|
349
|
+
...prev,
|
|
350
|
+
status: newStatus,
|
|
351
|
+
thinking: prev.thinking + separator + newThinking,
|
|
352
|
+
thinkingStartTime,
|
|
353
|
+
firstMessageTime
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
case "tool_call": {
|
|
357
|
+
const toolName = payload.message || payload.tool?.name;
|
|
358
|
+
if (toolName) {
|
|
359
|
+
const newToolCall = {
|
|
360
|
+
id: payload.tool?.id || `tool-${Date.now()}`,
|
|
361
|
+
name: toolName,
|
|
362
|
+
arguments: payload.tool?.arguments,
|
|
363
|
+
timestamp: Date.now()
|
|
364
|
+
};
|
|
365
|
+
return {
|
|
366
|
+
...prev,
|
|
367
|
+
status: newStatus,
|
|
368
|
+
toolCalls: [...prev.toolCalls, newToolCall],
|
|
369
|
+
firstMessageTime
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
return { ...prev, status: newStatus, firstMessageTime };
|
|
373
|
+
}
|
|
374
|
+
case "knowledge": {
|
|
375
|
+
const knowledgeContent = payload.message || payload.knowledge?.content;
|
|
376
|
+
if (knowledgeContent) {
|
|
377
|
+
const newKnowledge = {
|
|
378
|
+
id: payload.knowledge?.id || `knowledge-${Date.now()}`,
|
|
379
|
+
source: payload.knowledge?.source || "unknown",
|
|
380
|
+
content: knowledgeContent,
|
|
381
|
+
timestamp: Date.now()
|
|
382
|
+
};
|
|
383
|
+
return {
|
|
384
|
+
...prev,
|
|
385
|
+
status: newStatus,
|
|
386
|
+
knowledge: [...prev.knowledge, newKnowledge],
|
|
387
|
+
firstMessageTime
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
return { ...prev, status: newStatus, firstMessageTime };
|
|
391
|
+
}
|
|
392
|
+
case "memory": {
|
|
393
|
+
const memoryContent = payload.message || payload.memory?.content;
|
|
394
|
+
if (memoryContent) {
|
|
395
|
+
const newMemory = {
|
|
396
|
+
id: payload.memory?.id || `memory-${Date.now()}`,
|
|
397
|
+
type: payload.memory?.type || "unknown",
|
|
398
|
+
content: memoryContent,
|
|
399
|
+
timestamp: Date.now()
|
|
400
|
+
};
|
|
401
|
+
return {
|
|
402
|
+
...prev,
|
|
403
|
+
status: newStatus,
|
|
404
|
+
memory: [...prev.memory, newMemory],
|
|
405
|
+
firstMessageTime
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
return { ...prev, status: newStatus, firstMessageTime };
|
|
409
|
+
}
|
|
410
|
+
case "response":
|
|
411
|
+
return {
|
|
412
|
+
...prev,
|
|
413
|
+
status: "complete",
|
|
414
|
+
response: payload.message || payload.content || "",
|
|
415
|
+
responseCompleteTime: Date.now(),
|
|
416
|
+
firstMessageTime: prev.firstMessageTime ?? Date.now()
|
|
417
|
+
};
|
|
418
|
+
default:
|
|
419
|
+
return { ...prev, status: newStatus, firstMessageTime };
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
},
|
|
423
|
+
[topic]
|
|
424
|
+
);
|
|
425
|
+
const reset = useCallback(() => {
|
|
426
|
+
setState(initialAgentResponseState);
|
|
427
|
+
}, []);
|
|
428
|
+
return { state, handleMessage, reset };
|
|
429
|
+
}
|
|
430
|
+
var AgentResponse = React.forwardRef(
|
|
431
|
+
({
|
|
432
|
+
state,
|
|
433
|
+
id,
|
|
434
|
+
timestamp,
|
|
435
|
+
feedback,
|
|
436
|
+
onFeedbackChange,
|
|
437
|
+
onResponseCopy,
|
|
438
|
+
defaultThinkingExpanded = false,
|
|
439
|
+
thinkingExpanded: controlledThinkingExpanded,
|
|
440
|
+
onThinkingExpandedChange,
|
|
441
|
+
actionsVisible = "hover",
|
|
442
|
+
renderMarkdown,
|
|
443
|
+
className,
|
|
444
|
+
...props
|
|
445
|
+
}, ref) => {
|
|
446
|
+
const [uncontrolledExpanded, setUncontrolledExpanded] = useState(defaultThinkingExpanded);
|
|
447
|
+
const isThinkingControlled = controlledThinkingExpanded !== void 0;
|
|
448
|
+
const thinkingExpanded = isThinkingControlled ? controlledThinkingExpanded : uncontrolledExpanded;
|
|
449
|
+
const toggleThinking = useCallback(() => {
|
|
450
|
+
const newValue = !thinkingExpanded;
|
|
451
|
+
if (isThinkingControlled) {
|
|
452
|
+
onThinkingExpandedChange?.(newValue);
|
|
453
|
+
} else {
|
|
454
|
+
setUncontrolledExpanded(newValue);
|
|
455
|
+
}
|
|
456
|
+
}, [thinkingExpanded, isThinkingControlled, onThinkingExpandedChange]);
|
|
457
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
458
|
+
const elapsedTime = useThinkingTimer({
|
|
459
|
+
startTime: state.thinkingStartTime,
|
|
460
|
+
endTime: state.responseCompleteTime,
|
|
461
|
+
status: state.status
|
|
462
|
+
});
|
|
463
|
+
const totalTimeSeconds = useMemo(() => {
|
|
464
|
+
if (!state.firstMessageTime || !state.responseCompleteTime) return 0;
|
|
465
|
+
return (state.responseCompleteTime - state.firstMessageTime) / 1e3;
|
|
466
|
+
}, [state.firstMessageTime, state.responseCompleteTime]);
|
|
467
|
+
const hasAnyContent = state.thinking || state.toolCalls.length > 0 || state.knowledge.length > 0 || state.memory.length > 0 || state.response;
|
|
468
|
+
const showMetadataRow = state.thinking || state.toolCalls.length > 0 || state.knowledge.length > 0 || state.memory.length > 0 || state.status === "processing";
|
|
469
|
+
const showActionBar = state.status === "complete" && state.response;
|
|
470
|
+
const isActionBarVisible = actionsVisible === true || actionsVisible === "hover" && isHovered;
|
|
471
|
+
if (!hasAnyContent) {
|
|
472
|
+
return null;
|
|
473
|
+
}
|
|
474
|
+
return /* @__PURE__ */ jsxs(
|
|
475
|
+
"div",
|
|
476
|
+
{
|
|
477
|
+
ref,
|
|
478
|
+
className,
|
|
479
|
+
onMouseEnter: () => setIsHovered(true),
|
|
480
|
+
onMouseLeave: () => setIsHovered(false),
|
|
481
|
+
...props,
|
|
482
|
+
children: [
|
|
483
|
+
/* @__PURE__ */ jsxs("div", { className: "border border-border rounded-lg overflow-hidden", children: [
|
|
484
|
+
showMetadataRow && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
485
|
+
/* @__PURE__ */ jsx(
|
|
486
|
+
MetadataRow,
|
|
487
|
+
{
|
|
488
|
+
hasThinking: !!state.thinking,
|
|
489
|
+
isExpanded: thinkingExpanded,
|
|
490
|
+
onToggle: toggleThinking,
|
|
491
|
+
toolCalls: state.toolCalls,
|
|
492
|
+
knowledge: state.knowledge,
|
|
493
|
+
memory: state.memory,
|
|
494
|
+
status: state.status,
|
|
495
|
+
elapsedTime
|
|
496
|
+
}
|
|
497
|
+
),
|
|
498
|
+
/* @__PURE__ */ jsx(
|
|
499
|
+
ThinkingSection,
|
|
500
|
+
{
|
|
501
|
+
content: state.thinking,
|
|
502
|
+
isExpanded: thinkingExpanded
|
|
503
|
+
}
|
|
504
|
+
)
|
|
505
|
+
] }),
|
|
506
|
+
state.response && /* @__PURE__ */ jsx(
|
|
507
|
+
"div",
|
|
508
|
+
{
|
|
509
|
+
className: cn(
|
|
510
|
+
"bg-muted/50 p-4",
|
|
511
|
+
showMetadataRow && "border-t border-border"
|
|
512
|
+
),
|
|
513
|
+
children: renderMarkdown ? renderMarkdown(state.response) : /* @__PURE__ */ jsx("span", { className: "whitespace-pre-wrap", children: state.response })
|
|
514
|
+
}
|
|
515
|
+
)
|
|
516
|
+
] }),
|
|
517
|
+
showActionBar && /* @__PURE__ */ jsx(
|
|
518
|
+
ActionBar,
|
|
519
|
+
{
|
|
520
|
+
response: state.response,
|
|
521
|
+
isVisible: isActionBarVisible,
|
|
522
|
+
totalTimeSeconds,
|
|
523
|
+
feedback,
|
|
524
|
+
onFeedbackChange,
|
|
525
|
+
onResponseCopy
|
|
526
|
+
}
|
|
527
|
+
)
|
|
528
|
+
]
|
|
529
|
+
}
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
);
|
|
533
|
+
AgentResponse.displayName = "AgentResponse";
|
|
534
|
+
|
|
535
|
+
export { ActionBar, ActivityIndicators, AgentResponse, MetadataRow, ThinkingSection, formatTime, formatTotalTime, initialAgentResponseState, useAgentResponseAccumulator, useThinkingTimer };
|
|
536
|
+
//# sourceMappingURL=index.js.map
|
|
537
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/agent-response/components/ActivityIndicators.tsx","../src/components/agent-response/utils.ts","../src/components/agent-response/components/MetadataRow.tsx","../src/components/agent-response/components/ThinkingSection.tsx","../src/components/agent-response/components/ActionBar.tsx","../src/components/agent-response/hooks/useThinkingTimer.ts","../src/components/agent-response/types.ts","../src/components/agent-response/hooks/useAgentResponseAccumulator.ts","../src/components/agent-response/AgentResponse.tsx"],"names":["React2","jsxs","jsx","cn","React3","React4","useState","useCallback","React5"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Activity Indicators Component\n *\n * Displays tool, knowledge, memory icons with counts and popovers\n */\n\nimport * as React from \"react\";\nimport { Wrench, Book, HardDrive } from \"lucide-react\";\nimport { cn, Popover, PopoverTrigger, PopoverContent } from \"@optilogic/core\";\nimport type { ToolCall, KnowledgeItem, MemoryItem } from \"../types\";\n\nexport interface ActivityIndicatorsProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Tool calls to display */\n toolCalls: ToolCall[];\n /** Knowledge items to display */\n knowledge: KnowledgeItem[];\n /** Memory items to display */\n memory: MemoryItem[];\n}\n\n/**\n * ActivityIndicators Component\n *\n * Displays icons with counts for tool calls, knowledge retrieval, and memory access.\n * Each icon has a popover showing details when clicked.\n *\n * @example\n * <ActivityIndicators\n * toolCalls={state.toolCalls}\n * knowledge={state.knowledge}\n * memory={state.memory}\n * />\n */\nconst ActivityIndicators = React.forwardRef<HTMLDivElement, ActivityIndicatorsProps>(\n ({ toolCalls, knowledge, memory, className, ...props }, ref) => {\n const hasAnyActivity =\n toolCalls.length > 0 || knowledge.length > 0 || memory.length > 0;\n\n if (!hasAnyActivity) return null;\n\n return (\n <div ref={ref} className={cn(\"flex items-center gap-2\", className)} {...props}>\n {/* Tool Calls */}\n {toolCalls.length > 0 && (\n <Popover>\n <PopoverTrigger asChild>\n <button\n className=\"flex items-center gap-1 text-muted-foreground hover:text-foreground transition-colors\"\n onClick={(e) => e.stopPropagation()}\n >\n <Wrench className=\"w-3.5 h-3.5\" />\n <span className=\"text-xs\">{toolCalls.length}</span>\n </button>\n </PopoverTrigger>\n <PopoverContent className=\"w-80\">\n <div className=\"space-y-2\">\n <h4 className=\"font-medium text-sm\">Tool Calls</h4>\n <div className=\"space-y-2 max-h-60 overflow-auto\">\n {toolCalls.map((tool) => (\n <div key={tool.id} className=\"p-2 bg-muted rounded text-xs\">\n <div className=\"font-medium\">{tool.name}</div>\n {tool.arguments && (\n <pre className=\"mt-1 text-muted-foreground overflow-x-auto\">\n {JSON.stringify(tool.arguments, null, 2)}\n </pre>\n )}\n </div>\n ))}\n </div>\n </div>\n </PopoverContent>\n </Popover>\n )}\n\n {/* Knowledge */}\n {knowledge.length > 0 && (\n <Popover>\n <PopoverTrigger asChild>\n <button\n className=\"flex items-center gap-1 text-muted-foreground hover:text-foreground transition-colors\"\n onClick={(e) => e.stopPropagation()}\n >\n <Book className=\"w-3.5 h-3.5\" />\n <span className=\"text-xs\">{knowledge.length}</span>\n </button>\n </PopoverTrigger>\n <PopoverContent className=\"w-80\">\n <div className=\"space-y-2\">\n <h4 className=\"font-medium text-sm\">Knowledge Retrieved</h4>\n <div className=\"space-y-2 max-h-60 overflow-auto\">\n {knowledge.map((item) => (\n <div key={item.id} className=\"p-2 bg-muted rounded text-xs\">\n <div className=\"font-medium\">{item.source}</div>\n <div className=\"mt-1 text-muted-foreground\">\n {item.content}\n </div>\n </div>\n ))}\n </div>\n </div>\n </PopoverContent>\n </Popover>\n )}\n\n {/* Memory */}\n {memory.length > 0 && (\n <Popover>\n <PopoverTrigger asChild>\n <button\n className=\"flex items-center gap-1 text-muted-foreground hover:text-foreground transition-colors\"\n onClick={(e) => e.stopPropagation()}\n >\n <HardDrive className=\"w-3.5 h-3.5\" />\n <span className=\"text-xs\">{memory.length}</span>\n </button>\n </PopoverTrigger>\n <PopoverContent className=\"w-80\">\n <div className=\"space-y-2\">\n <h4 className=\"font-medium text-sm\">Memory Accessed</h4>\n <div className=\"space-y-2 max-h-60 overflow-auto\">\n {memory.map((item) => (\n <div key={item.id} className=\"p-2 bg-muted rounded text-xs\">\n <div className=\"font-medium\">{item.type}</div>\n <div className=\"mt-1 text-muted-foreground\">\n {item.content}\n </div>\n </div>\n ))}\n </div>\n </div>\n </PopoverContent>\n </Popover>\n )}\n </div>\n );\n }\n);\nActivityIndicators.displayName = \"ActivityIndicators\";\n\nexport { ActivityIndicators };\n","/**\n * Agent Response Utility Functions\n */\n\n/**\n * Format elapsed time for display\n * - Under 60s: \"Xs\" (e.g., \"23s\")\n * - 60+ seconds while active: \"M:SS\" (e.g., \"1:23\")\n * - Complete under 60s: \"Xs\" (e.g., \"45s\")\n * - Complete 60-119s: \"1.X min\" (e.g., \"1.2 min\")\n * - Complete 120+ s: \"X.X min\" (e.g., \"2.5 min\")\n */\nexport function formatTime(seconds: number, isComplete: boolean): string {\n if (seconds < 1) {\n return isComplete ? \"<1s\" : \"0s\";\n }\n\n if (isComplete) {\n // Completed state formatting\n if (seconds < 60) {\n return `${Math.round(seconds)}s`;\n }\n const minutes = seconds / 60;\n return `${minutes.toFixed(1)} min`;\n }\n\n // Active state formatting\n if (seconds < 60) {\n return `${Math.floor(seconds)}s`;\n }\n const mins = Math.floor(seconds / 60);\n const secs = Math.floor(seconds % 60);\n return `${mins}:${secs.toString().padStart(2, \"0\")}`;\n}\n\n/**\n * Format total time for action bar display\n */\nexport function formatTotalTime(seconds: number): string {\n if (seconds < 1) {\n return \"<1s\";\n }\n if (seconds < 60) {\n return `${seconds.toFixed(1)}s`;\n }\n const minutes = seconds / 60;\n return `${minutes.toFixed(1)}m`;\n}\n","/**\n * Metadata Row Component\n *\n * Displays thinking toggle, timer, and activity indicators\n */\n\nimport * as React from \"react\";\nimport { ChevronDown, ChevronUp } from \"lucide-react\";\nimport { cn, LoadingSpinner } from \"@optilogic/core\";\nimport { ActivityIndicators } from \"./ActivityIndicators\";\nimport { formatTime } from \"../utils\";\nimport type { AgentResponseStatus, ToolCall, KnowledgeItem, MemoryItem } from \"../types\";\n\nexport interface MetadataRowProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Whether there is thinking content */\n hasThinking: boolean;\n /** Whether the thinking section is expanded */\n isExpanded: boolean;\n /** Toggle callback for thinking expansion */\n onToggle: () => void;\n /** Tool calls to display */\n toolCalls: ToolCall[];\n /** Knowledge items to display */\n knowledge: KnowledgeItem[];\n /** Memory items to display */\n memory: MemoryItem[];\n /** Current response status */\n status: AgentResponseStatus;\n /** Elapsed time in seconds */\n elapsedTime: number;\n}\n\n/**\n * MetadataRow Component\n *\n * Displays the metadata row with thinking toggle, timer, and activity indicators.\n * When thinking content is present, the row is clickable to toggle expansion.\n *\n * @example\n * <MetadataRow\n * hasThinking={!!state.thinking}\n * isExpanded={thinkingExpanded}\n * onToggle={toggleThinking}\n * toolCalls={state.toolCalls}\n * knowledge={state.knowledge}\n * memory={state.memory}\n * status={state.status}\n * elapsedTime={elapsedTime}\n * />\n */\nconst MetadataRow = React.forwardRef<HTMLDivElement, MetadataRowProps>(\n (\n {\n hasThinking,\n isExpanded,\n onToggle,\n toolCalls,\n knowledge,\n memory,\n status,\n elapsedTime,\n className,\n ...props\n },\n ref\n ) => {\n const isProcessing = status === \"processing\";\n const isComplete = status === \"complete\";\n const hasActivity =\n toolCalls.length > 0 || knowledge.length > 0 || memory.length > 0;\n\n // Determine what to show on the left side\n const renderLeftContent = () => {\n // If we have thinking text, show collapse toggle + label + timer\n if (hasThinking) {\n return (\n <div className=\"flex items-center gap-1.5\">\n {isExpanded ? (\n <ChevronUp className=\"w-3.5 h-3.5 text-muted-foreground\" />\n ) : (\n <ChevronDown className=\"w-3.5 h-3.5 text-muted-foreground\" />\n )}\n <span className=\"text-xs text-muted-foreground\">\n {isComplete\n ? `Thought for ${formatTime(elapsedTime, true)}`\n : `Thinking... ${formatTime(elapsedTime, false)}`}\n </span>\n </div>\n );\n }\n\n // If processing but no thinking text yet, show spinner\n if (isProcessing) {\n return (\n <div className=\"flex items-center gap-1.5\">\n <LoadingSpinner size=\"sm\" variant=\"muted\" className=\"w-3.5 h-3.5\" />\n <span className=\"text-xs text-muted-foreground\">Processing</span>\n </div>\n );\n }\n\n // Complete with no thinking - show nothing on left (just activity on right)\n return null;\n };\n\n const leftContent = renderLeftContent();\n\n // If nothing to show (no thinking, not processing, no activity), hide the row\n if (!leftContent && !hasActivity) {\n return null;\n }\n\n // Always use a div for the row to avoid nesting buttons\n // When there's thinking, only the left side is clickable\n return (\n <div\n ref={ref}\n className={cn(\"w-full flex items-center justify-between px-3 py-2\", className)}\n {...props}\n >\n {/* Left content - clickable when there's thinking */}\n {hasThinking ? (\n <button\n onClick={onToggle}\n 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\"\n >\n {leftContent}\n </button>\n ) : (\n <div className=\"flex items-center gap-1.5\">\n {leftContent}\n </div>\n )}\n <ActivityIndicators\n toolCalls={toolCalls}\n knowledge={knowledge}\n memory={memory}\n />\n </div>\n );\n }\n);\nMetadataRow.displayName = \"MetadataRow\";\n\nexport { MetadataRow };\n","/**\n * Thinking Section Component\n *\n * Collapsible section for displaying agent thinking/reasoning content\n */\n\nimport * as React from \"react\";\nimport { cn } from \"@optilogic/core\";\n\nexport interface ThinkingSectionProps extends React.HTMLAttributes<HTMLDivElement> {\n /** The thinking content to display */\n content: string;\n /** Whether the section is expanded */\n isExpanded: boolean;\n}\n\n/**\n * ThinkingSection Component\n *\n * Displays the agent's thinking/reasoning content in a collapsible panel.\n *\n * @example\n * <ThinkingSection content={state.thinking} isExpanded={isExpanded} />\n */\nconst ThinkingSection = React.forwardRef<HTMLDivElement, ThinkingSectionProps>(\n ({ content, isExpanded, className, ...props }, ref) => {\n if (!isExpanded || !content) {\n return null;\n }\n\n return (\n <div\n ref={ref}\n className={cn(\"px-3 pb-3 border-t border-border\", className)}\n {...props}\n >\n <div className=\"mt-2 max-h-[200px] overflow-y-auto\">\n <pre className=\"text-xs text-muted-foreground whitespace-pre-wrap font-mono\">\n {content}\n </pre>\n </div>\n </div>\n );\n }\n);\nThinkingSection.displayName = \"ThinkingSection\";\n\nexport { ThinkingSection };\n","/**\n * Action Bar Component\n *\n * Displays copy, feedback, and timing actions for the response\n */\n\nimport * as React from \"react\";\nimport { useState, useCallback } from \"react\";\nimport { Copy, Check, ThumbsUp, ThumbsDown } from \"lucide-react\";\nimport { cn } from \"@optilogic/core\";\nimport { formatTotalTime } from \"../utils\";\nimport type { FeedbackValue } from \"../types\";\n\nexport interface ActionBarProps extends React.HTMLAttributes<HTMLDivElement> {\n /** The response text (for copying) */\n response: string;\n /** Whether the action bar is visible */\n isVisible: boolean;\n /** Total time in seconds */\n totalTimeSeconds: number;\n /** Current feedback value */\n feedback?: FeedbackValue;\n /** Callback when feedback changes */\n onFeedbackChange?: (feedback: FeedbackValue) => void;\n /** Callback when response is copied */\n onResponseCopy?: (response: string) => void;\n}\n\n/**\n * ActionBar Component\n *\n * Displays action buttons for copying the response, providing feedback,\n * and showing total response time.\n *\n * @example\n * <ActionBar\n * response={state.response}\n * isVisible={isHovered}\n * totalTimeSeconds={totalTime}\n * feedback={feedback}\n * onFeedbackChange={setFeedback}\n * onCopy={handleCopy}\n * />\n */\nconst ActionBar = React.forwardRef<HTMLDivElement, ActionBarProps>(\n (\n {\n response,\n isVisible,\n totalTimeSeconds,\n feedback,\n onFeedbackChange,\n onResponseCopy,\n className,\n ...props\n },\n ref\n ) => {\n const [copied, setCopied] = useState(false);\n\n const handleCopy = useCallback(async () => {\n try {\n await navigator.clipboard.writeText(response);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n onResponseCopy?.(response);\n } catch (err) {\n console.error(\"Failed to copy response:\", err);\n }\n }, [response, onResponseCopy]);\n\n const handleThumbsUp = useCallback(() => {\n const newValue = feedback === \"up\" ? null : \"up\";\n onFeedbackChange?.(newValue);\n }, [feedback, onFeedbackChange]);\n\n const handleThumbsDown = useCallback(() => {\n const newValue = feedback === \"down\" ? null : \"down\";\n onFeedbackChange?.(newValue);\n }, [feedback, onFeedbackChange]);\n\n const isThumbsUp = feedback === \"up\";\n const isThumbsDown = feedback === \"down\";\n\n return (\n <div\n ref={ref}\n className={cn(\n \"flex items-center justify-between px-4 py-2\",\n \"transition-opacity duration-200\",\n isVisible ? \"opacity-100\" : \"opacity-0 pointer-events-none\",\n className\n )}\n {...props}\n >\n {/* Left side - action buttons */}\n <div className=\"flex items-center gap-1\">\n {/* Copy button */}\n <button\n onClick={handleCopy}\n className=\"p-1.5 rounded hover:bg-muted transition-colors text-muted-foreground hover:text-foreground\"\n title={copied ? \"Copied!\" : \"Copy response\"}\n >\n {copied ? (\n <Check className=\"w-4 h-4 text-green-500\" />\n ) : (\n <Copy className=\"w-4 h-4\" />\n )}\n </button>\n\n {/* Thumbs up */}\n <button\n onClick={handleThumbsUp}\n className={cn(\n \"p-1.5 rounded hover:bg-muted transition-colors\",\n isThumbsUp\n ? \"text-green-500\"\n : \"text-muted-foreground hover:text-foreground\"\n )}\n title=\"Good response\"\n >\n <ThumbsUp className={cn(\"w-4 h-4\", isThumbsUp && \"fill-current\")} />\n </button>\n\n {/* Thumbs down */}\n <button\n onClick={handleThumbsDown}\n className={cn(\n \"p-1.5 rounded hover:bg-muted transition-colors\",\n isThumbsDown\n ? \"text-red-500\"\n : \"text-muted-foreground hover:text-foreground\"\n )}\n title=\"Poor response\"\n >\n <ThumbsDown className={cn(\"w-4 h-4\", isThumbsDown && \"fill-current\")} />\n </button>\n </div>\n\n {/* Right side - timing info */}\n <span className=\"text-xs text-muted-foreground\">\n Total time: {formatTotalTime(totalTimeSeconds)}\n </span>\n </div>\n );\n }\n);\nActionBar.displayName = \"ActionBar\";\n\nexport { ActionBar };\n","/**\n * useThinkingTimer Hook\n *\n * Tracks elapsed time during agent thinking/processing\n */\n\nimport { useState, useEffect } from \"react\";\nimport type { AgentResponseStatus } from \"../types\";\n\nexport interface UseThinkingTimerOptions {\n startTime: number | null;\n endTime: number | null;\n status: AgentResponseStatus;\n}\n\n/**\n * Custom hook for thinking timer\n * Returns elapsed time in seconds\n */\nexport function useThinkingTimer({\n startTime,\n endTime,\n status,\n}: UseThinkingTimerOptions): number {\n const [elapsed, setElapsed] = useState(0);\n\n useEffect(() => {\n if (!startTime) {\n setElapsed(0);\n return;\n }\n\n // If complete, calculate final elapsed time\n if (status === \"complete\" && endTime) {\n setElapsed((endTime - startTime) / 1000);\n return;\n }\n\n // If still processing, update every second\n if (status === \"processing\") {\n const updateElapsed = () => {\n setElapsed((Date.now() - startTime) / 1000);\n };\n\n updateElapsed(); // Initial update\n const interval = setInterval(updateElapsed, 1000);\n return () => clearInterval(interval);\n }\n }, [startTime, endTime, status]);\n\n return elapsed;\n}\n","/**\n * Agent Response Component Types\n *\n * Type definitions for the library-ready agent response component\n */\n\n/**\n * Status of the agent response cycle\n */\nexport type AgentResponseStatus = \"idle\" | \"processing\" | \"complete\";\n\n/**\n * Feedback value for the response\n */\nexport type FeedbackValue = \"up\" | \"down\" | null;\n\n/**\n * Tool call information from the agent\n */\nexport interface ToolCall {\n id: string;\n name: string;\n arguments?: Record<string, unknown>;\n timestamp: number;\n}\n\n/**\n * Knowledge retrieval information\n */\nexport interface KnowledgeItem {\n id: string;\n source: string;\n content: string;\n timestamp: number;\n}\n\n/**\n * Memory access information\n */\nexport interface MemoryItem {\n id: string;\n type: string;\n content: string;\n timestamp: number;\n}\n\n/**\n * State shape for the agent response component\n */\nexport interface AgentResponseState {\n /** Current status of the response cycle */\n status: AgentResponseStatus;\n /** Accumulated thinking/reasoning text */\n thinking: string;\n /** Tool calls made during processing */\n toolCalls: ToolCall[];\n /** Knowledge items retrieved */\n knowledge: KnowledgeItem[];\n /** Memory items accessed */\n memory: MemoryItem[];\n /** Final response text */\n response: string;\n /** Timestamp when first thinking message was received (for timer) */\n thinkingStartTime: number | null;\n /** Timestamp when response was completed (for final timer display) */\n responseCompleteTime: number | null;\n /** Timestamp when first message of any type was received (for total time) */\n firstMessageTime: number | null;\n}\n\n/**\n * WebSocket message payload for agent responses\n */\nexport interface AgentMessage {\n type: \"status\" | \"thinking\" | \"tool_call\" | \"knowledge\" | \"memory\" | \"response\";\n /** Message content - for simple string payloads */\n message?: string;\n /** Alternative content field */\n content?: string;\n /** For status messages */\n status?: string;\n /** For tool_call messages */\n tool?: {\n id: string;\n name: string;\n arguments?: Record<string, unknown>;\n };\n /** For knowledge messages */\n knowledge?: {\n id: string;\n source: string;\n content: string;\n };\n /** For memory messages */\n memory?: {\n id: string;\n type: string;\n content: string;\n };\n}\n\n/**\n * Generic websocket message wrapper type\n */\nexport interface GenericWebSocketMessage {\n topic: string;\n message: AgentMessage;\n accountId?: string;\n}\n\n/**\n * Initial state for the agent response component\n */\nexport const initialAgentResponseState: AgentResponseState = {\n status: \"idle\",\n thinking: \"\",\n toolCalls: [],\n knowledge: [],\n memory: [],\n response: \"\",\n thinkingStartTime: null,\n responseCompleteTime: null,\n firstMessageTime: null,\n};\n","/**\n * useAgentResponseAccumulator Hook\n *\n * Accumulates agent response messages into a unified state\n */\n\nimport { useState, useCallback } from \"react\";\nimport {\n initialAgentResponseState,\n type AgentResponseState,\n type AgentMessage,\n type GenericWebSocketMessage,\n type ToolCall,\n type KnowledgeItem,\n type MemoryItem,\n} from \"../types\";\n\nexport interface UseAgentResponseAccumulatorOptions {\n /** WebSocket topic to filter messages (optional, for convenience) */\n topic?: string;\n}\n\nexport interface UseAgentResponseAccumulatorReturn {\n /** Current accumulated state */\n state: AgentResponseState;\n\n /** Handler to process incoming messages */\n handleMessage: (message: unknown) => void;\n\n /** Reset state to initial */\n reset: () => void;\n}\n\n/**\n * Hook for accumulating agent response messages into a unified state\n *\n * @example\n * const { state, handleMessage, reset } = useAgentResponseAccumulator({ topic: \"agent\" });\n *\n * // In your WebSocket handler:\n * websocket.onmessage = (event) => {\n * handleMessage(JSON.parse(event.data));\n * };\n */\nexport function useAgentResponseAccumulator(\n options?: UseAgentResponseAccumulatorOptions\n): UseAgentResponseAccumulatorReturn {\n const [state, setState] = useState<AgentResponseState>(initialAgentResponseState);\n const topic = options?.topic;\n\n const handleMessage = useCallback(\n (message: unknown) => {\n // If topic filter is provided, check for matching topic\n let payload: AgentMessage;\n\n if (topic) {\n const msg = message as GenericWebSocketMessage;\n if (msg.topic !== topic) return;\n payload = msg.message;\n } else {\n // Assume message is the payload directly\n payload = message as AgentMessage;\n }\n\n setState((prev) => {\n // If we receive a non-status message while idle, transition to processing\n let newStatus = prev.status;\n const isFirstMessage = prev.status === \"idle\" && payload.type !== \"status\";\n if (isFirstMessage) {\n newStatus = \"processing\";\n }\n\n // Track first message time for total time calculation\n const firstMessageTime =\n prev.firstMessageTime ?? (isFirstMessage ? Date.now() : null);\n\n switch (payload.type) {\n case \"status\":\n // \"Harness connected\" resets to idle\n if (\n payload.message === \"Harness connected\" ||\n payload.status === \"Harness connected\"\n ) {\n return { ...initialAgentResponseState };\n }\n return { ...prev, status: newStatus };\n\n case \"thinking\": {\n const newThinking = payload.message || payload.content || \"\";\n // Add line break between thinking messages\n const separator = prev.thinking && newThinking ? \"\\n\\n\" : \"\";\n // Set thinkingStartTime on first thinking message\n const thinkingStartTime =\n prev.thinkingStartTime ?? (newThinking ? Date.now() : null);\n return {\n ...prev,\n status: newStatus,\n thinking: prev.thinking + separator + newThinking,\n thinkingStartTime,\n firstMessageTime,\n };\n }\n\n case \"tool_call\": {\n // Handle both formats: { message: \"ToolName\" } or { tool: { id, name, arguments } }\n const toolName = payload.message || payload.tool?.name;\n if (toolName) {\n const newToolCall: ToolCall = {\n id: payload.tool?.id || `tool-${Date.now()}`,\n name: toolName,\n arguments: payload.tool?.arguments,\n timestamp: Date.now(),\n };\n return {\n ...prev,\n status: newStatus,\n toolCalls: [...prev.toolCalls, newToolCall],\n firstMessageTime,\n };\n }\n return { ...prev, status: newStatus, firstMessageTime };\n }\n\n case \"knowledge\": {\n // Handle both formats: { message: \"content\" } or { knowledge: { id, source, content } }\n const knowledgeContent = payload.message || payload.knowledge?.content;\n if (knowledgeContent) {\n const newKnowledge: KnowledgeItem = {\n id: payload.knowledge?.id || `knowledge-${Date.now()}`,\n source: payload.knowledge?.source || \"unknown\",\n content: knowledgeContent,\n timestamp: Date.now(),\n };\n return {\n ...prev,\n status: newStatus,\n knowledge: [...prev.knowledge, newKnowledge],\n firstMessageTime,\n };\n }\n return { ...prev, status: newStatus, firstMessageTime };\n }\n\n case \"memory\": {\n // Handle both formats: { message: \"content\" } or { memory: { id, type, content } }\n const memoryContent = payload.message || payload.memory?.content;\n if (memoryContent) {\n const newMemory: MemoryItem = {\n id: payload.memory?.id || `memory-${Date.now()}`,\n type: payload.memory?.type || \"unknown\",\n content: memoryContent,\n timestamp: Date.now(),\n };\n return {\n ...prev,\n status: newStatus,\n memory: [...prev.memory, newMemory],\n firstMessageTime,\n };\n }\n return { ...prev, status: newStatus, firstMessageTime };\n }\n\n case \"response\":\n return {\n ...prev,\n status: \"complete\",\n response: payload.message || payload.content || \"\",\n responseCompleteTime: Date.now(),\n firstMessageTime: prev.firstMessageTime ?? Date.now(),\n };\n\n default:\n return { ...prev, status: newStatus, firstMessageTime };\n }\n });\n },\n [topic]\n );\n\n const reset = useCallback(() => {\n setState(initialAgentResponseState);\n }, []);\n\n return { state, handleMessage, reset };\n}\n","/**\n * AgentResponse Component\n *\n * A library-ready presentational component for displaying AI agent responses.\n * Displays thinking, tool calls, knowledge retrieval, memory access, and final response.\n */\n\nimport * as React from \"react\";\nimport { useState, useMemo, useCallback } from \"react\";\nimport { cn } from \"@optilogic/core\";\nimport { MetadataRow, ThinkingSection, ActionBar } from \"./components\";\nimport { useThinkingTimer } from \"./hooks\";\nimport type { AgentResponseState, FeedbackValue } from \"./types\";\n\nexport interface AgentResponseProps extends React.HTMLAttributes<HTMLDivElement> {\n /** The response state to render */\n state: AgentResponseState;\n\n /** Optional unique ID (for list keys) */\n id?: string;\n\n /** Optional timestamp to display */\n timestamp?: Date;\n\n /** Feedback state (controlled) */\n feedback?: FeedbackValue;\n onFeedbackChange?: (feedback: FeedbackValue) => void;\n\n /** Callback when the response is copied via the action bar */\n onResponseCopy?: (response: string) => void;\n\n /** Thinking section expansion (controlled or uncontrolled) */\n defaultThinkingExpanded?: boolean;\n thinkingExpanded?: boolean;\n onThinkingExpandedChange?: (expanded: boolean) => void;\n\n /** Action bar visibility mode */\n actionsVisible?: boolean | \"hover\";\n\n /**\n * Custom markdown renderer for the response content.\n * If not provided, the response will be rendered as plain text.\n *\n * @example\n * <AgentResponse\n * state={state}\n * renderMarkdown={(content) => <MyMarkdownRenderer content={content} />}\n * />\n */\n renderMarkdown?: (content: string) => React.ReactNode;\n}\n\n/**\n * AgentResponse Component\n *\n * A complete component for displaying AI agent responses including:\n * - Thinking/reasoning content (collapsible)\n * - Tool calls, knowledge retrieval, and memory access indicators\n * - Final response with optional markdown rendering\n * - Action bar with copy and feedback buttons\n *\n * @example\n * // Basic usage with useAgentResponseAccumulator hook\n * const { state, handleMessage } = useAgentResponseAccumulator();\n *\n * <AgentResponse state={state} />\n *\n * @example\n * // With markdown rendering and feedback\n * <AgentResponse\n * state={state}\n * renderMarkdown={(content) => <ReactMarkdown>{content}</ReactMarkdown>}\n * feedback={feedback}\n * onFeedbackChange={setFeedback}\n * />\n *\n * @example\n * // Controlled thinking expansion\n * <AgentResponse\n * state={state}\n * thinkingExpanded={isExpanded}\n * onThinkingExpandedChange={setIsExpanded}\n * />\n */\nconst AgentResponse = React.forwardRef<HTMLDivElement, AgentResponseProps>(\n (\n {\n state,\n id,\n timestamp,\n feedback,\n onFeedbackChange,\n onResponseCopy,\n defaultThinkingExpanded = false,\n thinkingExpanded: controlledThinkingExpanded,\n onThinkingExpandedChange,\n actionsVisible = \"hover\",\n renderMarkdown,\n className,\n ...props\n },\n ref\n ) => {\n // Uncontrolled thinking expanded state\n const [uncontrolledExpanded, setUncontrolledExpanded] = useState(defaultThinkingExpanded);\n\n // Determine if thinking is controlled\n const isThinkingControlled = controlledThinkingExpanded !== undefined;\n const thinkingExpanded = isThinkingControlled\n ? controlledThinkingExpanded\n : uncontrolledExpanded;\n\n // Toggle thinking handler\n const toggleThinking = useCallback(() => {\n const newValue = !thinkingExpanded;\n if (isThinkingControlled) {\n onThinkingExpandedChange?.(newValue);\n } else {\n setUncontrolledExpanded(newValue);\n }\n }, [thinkingExpanded, isThinkingControlled, onThinkingExpandedChange]);\n\n // Hover state for action bar visibility\n const [isHovered, setIsHovered] = useState(false);\n\n // Thinking timer\n const elapsedTime = useThinkingTimer({\n startTime: state.thinkingStartTime,\n endTime: state.responseCompleteTime,\n status: state.status,\n });\n\n // Calculate total time (from first message to response complete)\n const totalTimeSeconds = useMemo(() => {\n if (!state.firstMessageTime || !state.responseCompleteTime) return 0;\n return (state.responseCompleteTime - state.firstMessageTime) / 1000;\n }, [state.firstMessageTime, state.responseCompleteTime]);\n\n // Derived state: has any content been received?\n const hasAnyContent =\n state.thinking ||\n state.toolCalls.length > 0 ||\n state.knowledge.length > 0 ||\n state.memory.length > 0 ||\n state.response;\n\n // Derived state: should show metadata row?\n const showMetadataRow =\n state.thinking ||\n state.toolCalls.length > 0 ||\n state.knowledge.length > 0 ||\n state.memory.length > 0 ||\n state.status === \"processing\";\n\n // Determine action bar visibility\n const showActionBar = state.status === \"complete\" && state.response;\n const isActionBarVisible =\n actionsVisible === true ||\n (actionsVisible === \"hover\" && isHovered);\n\n // If no content, render nothing\n if (!hasAnyContent) {\n return null;\n }\n\n return (\n <div\n ref={ref}\n className={className}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n {...props}\n >\n {/* Message Content Container */}\n <div className=\"border border-border rounded-lg overflow-hidden\">\n {/* Metadata Row - show if there's any metadata or thinking */}\n {showMetadataRow && (\n <>\n <MetadataRow\n hasThinking={!!state.thinking}\n isExpanded={thinkingExpanded}\n onToggle={toggleThinking}\n toolCalls={state.toolCalls}\n knowledge={state.knowledge}\n memory={state.memory}\n status={state.status}\n elapsedTime={elapsedTime}\n />\n\n {/* Thinking Content - collapsible with max-height */}\n <ThinkingSection\n content={state.thinking}\n isExpanded={thinkingExpanded}\n />\n </>\n )}\n\n {/* Response Section */}\n {state.response && (\n <div\n className={cn(\n \"bg-muted/50 p-4\",\n showMetadataRow && \"border-t border-border\"\n )}\n >\n {renderMarkdown ? (\n renderMarkdown(state.response)\n ) : (\n <span className=\"whitespace-pre-wrap\">{state.response}</span>\n )}\n </div>\n )}\n </div>\n\n {/* Action Bar - outside the message container, visible on hover when complete */}\n {showActionBar && (\n <ActionBar\n response={state.response}\n isVisible={isActionBarVisible}\n totalTimeSeconds={totalTimeSeconds}\n feedback={feedback}\n onFeedbackChange={onFeedbackChange}\n onResponseCopy={onResponseCopy}\n />\n )}\n </div>\n );\n }\n);\nAgentResponse.displayName = \"AgentResponse\";\n\nexport { AgentResponse };\n"]}
|