@optilogic/chat 1.0.0-beta.8 → 1.0.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 +136 -0
- package/dist/index.cjs +989 -58
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +361 -2
- package/dist/index.d.ts +361 -2
- package/dist/index.js +964 -46
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/components/agent-response/AgentResponse.tsx +86 -14
- package/src/components/agent-response/components/HITLSection.tsx +95 -0
- 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 +6 -0
- package/src/components/agent-response/hooks/useAgentResponseAccumulator.ts +65 -8
- package/src/components/agent-response/index.ts +21 -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/HITLInteractionRecord.tsx +139 -0
- package/src/components/hitl-interactions/HITLQuestionPanel.tsx +270 -0
- package/src/components/hitl-interactions/index.ts +18 -0
- 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 +42 -0
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var React11 = require('react');
|
|
4
4
|
var core = require('@optilogic/core');
|
|
5
5
|
var lucideReact = require('lucide-react');
|
|
6
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
@@ -24,10 +24,10 @@ function _interopNamespace(e) {
|
|
|
24
24
|
return Object.freeze(n);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
var
|
|
27
|
+
var React11__namespace = /*#__PURE__*/_interopNamespace(React11);
|
|
28
28
|
|
|
29
29
|
// src/components/agent-response/AgentResponse.tsx
|
|
30
|
-
var ActivityIndicators =
|
|
30
|
+
var ActivityIndicators = React11__namespace.forwardRef(
|
|
31
31
|
({ toolCalls, knowledge, memory, statusUpdates = [], className, ...props }, ref) => {
|
|
32
32
|
const hasAnyActivity = toolCalls.length > 0 || knowledge.length > 0 || memory.length > 0 || statusUpdates.length > 0;
|
|
33
33
|
if (!hasAnyActivity) return null;
|
|
@@ -146,7 +146,7 @@ function formatTotalTime(seconds) {
|
|
|
146
146
|
const minutes = seconds / 60;
|
|
147
147
|
return `${minutes.toFixed(1)}m`;
|
|
148
148
|
}
|
|
149
|
-
var MetadataRow =
|
|
149
|
+
var MetadataRow = React11__namespace.forwardRef(
|
|
150
150
|
({
|
|
151
151
|
hasThinking,
|
|
152
152
|
isExpanded,
|
|
@@ -155,6 +155,7 @@ var MetadataRow = React7__namespace.forwardRef(
|
|
|
155
155
|
knowledge,
|
|
156
156
|
memory,
|
|
157
157
|
statusUpdates = [],
|
|
158
|
+
statusContent,
|
|
158
159
|
status,
|
|
159
160
|
elapsedTime,
|
|
160
161
|
className,
|
|
@@ -179,7 +180,7 @@ var MetadataRow = React7__namespace.forwardRef(
|
|
|
179
180
|
return null;
|
|
180
181
|
};
|
|
181
182
|
const leftContent = renderLeftContent();
|
|
182
|
-
if (!leftContent && !hasActivity) {
|
|
183
|
+
if (!leftContent && !hasActivity && !statusContent) {
|
|
183
184
|
return null;
|
|
184
185
|
}
|
|
185
186
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -193,10 +194,11 @@ var MetadataRow = React7__namespace.forwardRef(
|
|
|
193
194
|
"button",
|
|
194
195
|
{
|
|
195
196
|
onClick: onToggle,
|
|
196
|
-
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",
|
|
197
|
+
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",
|
|
197
198
|
children: leftContent
|
|
198
199
|
}
|
|
199
|
-
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1.5", children: leftContent }),
|
|
200
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1.5 shrink-0", children: leftContent }),
|
|
201
|
+
statusContent && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-w-0 mx-2", children: statusContent }),
|
|
200
202
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
201
203
|
ActivityIndicators,
|
|
202
204
|
{
|
|
@@ -213,8 +215,8 @@ var MetadataRow = React7__namespace.forwardRef(
|
|
|
213
215
|
);
|
|
214
216
|
MetadataRow.displayName = "MetadataRow";
|
|
215
217
|
var ThinkingStepItem = ({ step, renderMarkdown }) => {
|
|
216
|
-
const [isCollapsed, setIsCollapsed] =
|
|
217
|
-
const toggleCollapse =
|
|
218
|
+
const [isCollapsed, setIsCollapsed] = React11.useState(step.isCollapsed ?? false);
|
|
219
|
+
const toggleCollapse = React11.useCallback(() => {
|
|
218
220
|
setIsCollapsed((prev) => !prev);
|
|
219
221
|
}, []);
|
|
220
222
|
const indentPadding = step.depth * 16;
|
|
@@ -241,7 +243,7 @@ var ThinkingStepItem = ({ step, renderMarkdown }) => {
|
|
|
241
243
|
)
|
|
242
244
|
] });
|
|
243
245
|
};
|
|
244
|
-
var ThinkingSection =
|
|
246
|
+
var ThinkingSection = React11__namespace.forwardRef(
|
|
245
247
|
({ content, isExpanded, renderMarkdown, className, ...props }, ref) => {
|
|
246
248
|
if (!isExpanded || !content || Array.isArray(content) && content.length === 0) {
|
|
247
249
|
return null;
|
|
@@ -266,7 +268,7 @@ var ThinkingSection = React7__namespace.forwardRef(
|
|
|
266
268
|
}
|
|
267
269
|
);
|
|
268
270
|
ThinkingSection.displayName = "ThinkingSection";
|
|
269
|
-
var ActionBar =
|
|
271
|
+
var ActionBar = React11__namespace.forwardRef(
|
|
270
272
|
({
|
|
271
273
|
response,
|
|
272
274
|
isVisible,
|
|
@@ -277,8 +279,8 @@ var ActionBar = React7__namespace.forwardRef(
|
|
|
277
279
|
className,
|
|
278
280
|
...props
|
|
279
281
|
}, ref) => {
|
|
280
|
-
const [copied, setCopied] =
|
|
281
|
-
const handleCopy =
|
|
282
|
+
const [copied, setCopied] = React11.useState(false);
|
|
283
|
+
const handleCopy = React11.useCallback(async () => {
|
|
282
284
|
try {
|
|
283
285
|
await navigator.clipboard.writeText(response);
|
|
284
286
|
setCopied(true);
|
|
@@ -288,11 +290,11 @@ var ActionBar = React7__namespace.forwardRef(
|
|
|
288
290
|
console.error("Failed to copy response:", err);
|
|
289
291
|
}
|
|
290
292
|
}, [response, onResponseCopy]);
|
|
291
|
-
const handleThumbsUp =
|
|
293
|
+
const handleThumbsUp = React11.useCallback(() => {
|
|
292
294
|
const newValue = feedback === "up" ? null : "up";
|
|
293
295
|
onFeedbackChange?.(newValue);
|
|
294
296
|
}, [feedback, onFeedbackChange]);
|
|
295
|
-
const handleThumbsDown =
|
|
297
|
+
const handleThumbsDown = React11.useCallback(() => {
|
|
296
298
|
const newValue = feedback === "down" ? null : "down";
|
|
297
299
|
onFeedbackChange?.(newValue);
|
|
298
300
|
}, [feedback, onFeedbackChange]);
|
|
@@ -355,13 +357,320 @@ var ActionBar = React7__namespace.forwardRef(
|
|
|
355
357
|
}
|
|
356
358
|
);
|
|
357
359
|
ActionBar.displayName = "ActionBar";
|
|
360
|
+
function buildResponseString(questions, selectedOptions, freeformText) {
|
|
361
|
+
const parts = [];
|
|
362
|
+
for (const q of questions) {
|
|
363
|
+
const answer = selectedOptions[q];
|
|
364
|
+
if (answer) {
|
|
365
|
+
parts.push(`Q: ${q}
|
|
366
|
+
A: ${answer}`);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
const trimmed = freeformText.trim();
|
|
370
|
+
if (trimmed) {
|
|
371
|
+
parts.push(`Additional context: ${trimmed}`);
|
|
372
|
+
}
|
|
373
|
+
return parts.join("\n\n");
|
|
374
|
+
}
|
|
375
|
+
var HITLQuestionPanel = React11__namespace.forwardRef(({ question, onSubmit, onStop, className, ...props }, ref) => {
|
|
376
|
+
const [freeformText, setFreeformText] = React11.useState("");
|
|
377
|
+
const [selectedOptions, setSelectedOptions] = React11.useState({});
|
|
378
|
+
const hasTimeout = question.timeoutSeconds != null;
|
|
379
|
+
const [secondsLeft, setSecondsLeft] = React11.useState(
|
|
380
|
+
() => hasTimeout ? Math.max(
|
|
381
|
+
0,
|
|
382
|
+
Math.round(
|
|
383
|
+
question.timeoutSeconds - (Date.now() - question.receivedAt) / 1e3
|
|
384
|
+
)
|
|
385
|
+
) : Infinity
|
|
386
|
+
);
|
|
387
|
+
const textareaRef = React11.useRef(null);
|
|
388
|
+
React11.useEffect(() => {
|
|
389
|
+
textareaRef.current?.focus();
|
|
390
|
+
}, []);
|
|
391
|
+
React11.useEffect(() => {
|
|
392
|
+
if (!hasTimeout) return;
|
|
393
|
+
const interval = setInterval(() => {
|
|
394
|
+
const remaining = Math.max(
|
|
395
|
+
0,
|
|
396
|
+
Math.round(
|
|
397
|
+
question.timeoutSeconds - (Date.now() - question.receivedAt) / 1e3
|
|
398
|
+
)
|
|
399
|
+
);
|
|
400
|
+
setSecondsLeft(remaining);
|
|
401
|
+
if (remaining <= 0) clearInterval(interval);
|
|
402
|
+
}, 1e3);
|
|
403
|
+
return () => clearInterval(interval);
|
|
404
|
+
}, [hasTimeout, question.timeoutSeconds, question.receivedAt]);
|
|
405
|
+
const timedOut = hasTimeout && secondsLeft <= 0;
|
|
406
|
+
const questionsWithOptions = React11.useMemo(
|
|
407
|
+
() => question.questions.filter((q) => question.options?.[q]?.length),
|
|
408
|
+
[question.questions, question.options]
|
|
409
|
+
);
|
|
410
|
+
const allOptionsSelected = questionsWithOptions.length > 0 && questionsWithOptions.every((q) => selectedOptions[q]);
|
|
411
|
+
const hasFreeformText = freeformText.trim().length > 0;
|
|
412
|
+
const canSubmit = !timedOut && (allOptionsSelected || hasFreeformText);
|
|
413
|
+
const handleOptionClick = React11.useCallback(
|
|
414
|
+
(questionText, option) => {
|
|
415
|
+
if (timedOut) return;
|
|
416
|
+
setSelectedOptions((prev) => {
|
|
417
|
+
if (prev[questionText] === option) {
|
|
418
|
+
const next = { ...prev };
|
|
419
|
+
delete next[questionText];
|
|
420
|
+
return next;
|
|
421
|
+
}
|
|
422
|
+
return { ...prev, [questionText]: option };
|
|
423
|
+
});
|
|
424
|
+
},
|
|
425
|
+
[timedOut]
|
|
426
|
+
);
|
|
427
|
+
const handleSubmit = React11.useCallback(() => {
|
|
428
|
+
if (!canSubmit) return;
|
|
429
|
+
const combined = buildResponseString(
|
|
430
|
+
question.questions,
|
|
431
|
+
selectedOptions,
|
|
432
|
+
freeformText
|
|
433
|
+
);
|
|
434
|
+
onSubmit(combined, { selectedOptions, freeformText });
|
|
435
|
+
}, [canSubmit, question.questions, selectedOptions, freeformText, onSubmit]);
|
|
436
|
+
const handleKeyDown = React11.useCallback(
|
|
437
|
+
(e) => {
|
|
438
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
439
|
+
e.preventDefault();
|
|
440
|
+
handleSubmit();
|
|
441
|
+
}
|
|
442
|
+
},
|
|
443
|
+
[handleSubmit]
|
|
444
|
+
);
|
|
445
|
+
const formatTime2 = (s) => {
|
|
446
|
+
const m = Math.floor(s / 60);
|
|
447
|
+
const sec = s % 60;
|
|
448
|
+
return `${m}:${sec.toString().padStart(2, "0")}`;
|
|
449
|
+
};
|
|
450
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
451
|
+
"div",
|
|
452
|
+
{
|
|
453
|
+
ref,
|
|
454
|
+
className: core.cn(
|
|
455
|
+
"rounded-lg border border-border bg-muted p-4 space-y-3",
|
|
456
|
+
className
|
|
457
|
+
),
|
|
458
|
+
...props,
|
|
459
|
+
children: [
|
|
460
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-3", children: [
|
|
461
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-foreground", children: question.reason }) }),
|
|
462
|
+
hasTimeout && /* @__PURE__ */ jsxRuntime.jsx(
|
|
463
|
+
"span",
|
|
464
|
+
{
|
|
465
|
+
className: core.cn(
|
|
466
|
+
"text-xs font-mono whitespace-nowrap",
|
|
467
|
+
secondsLeft <= 30 ? "text-destructive" : "text-muted-foreground"
|
|
468
|
+
),
|
|
469
|
+
children: timedOut ? "Timed out" : formatTime2(secondsLeft)
|
|
470
|
+
}
|
|
471
|
+
)
|
|
472
|
+
] }),
|
|
473
|
+
question.context && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground bg-background rounded p-2 border border-border max-h-24 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "whitespace-pre-wrap font-mono", children: question.context }) }),
|
|
474
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: question.questions.map((q, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
475
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-foreground", children: q }),
|
|
476
|
+
question.options?.[q] && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2 mt-1.5", children: question.options[q].map((option, j) => {
|
|
477
|
+
const isSelected = selectedOptions[q] === option;
|
|
478
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
479
|
+
core.Button,
|
|
480
|
+
{
|
|
481
|
+
variant: isSelected ? "primary" : "outline",
|
|
482
|
+
size: "sm",
|
|
483
|
+
onClick: () => handleOptionClick(q, option),
|
|
484
|
+
disabled: timedOut,
|
|
485
|
+
children: option
|
|
486
|
+
},
|
|
487
|
+
j
|
|
488
|
+
);
|
|
489
|
+
}) })
|
|
490
|
+
] }, i)) }),
|
|
491
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
492
|
+
core.Textarea,
|
|
493
|
+
{
|
|
494
|
+
ref: textareaRef,
|
|
495
|
+
value: freeformText,
|
|
496
|
+
onChange: (e) => setFreeformText(e.target.value),
|
|
497
|
+
onKeyDown: handleKeyDown,
|
|
498
|
+
disabled: timedOut,
|
|
499
|
+
placeholder: "Add additional context or type a full response...",
|
|
500
|
+
rows: 2,
|
|
501
|
+
className: "resize-none"
|
|
502
|
+
}
|
|
503
|
+
),
|
|
504
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
505
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
506
|
+
core.Button,
|
|
507
|
+
{
|
|
508
|
+
variant: "ghost",
|
|
509
|
+
size: "sm",
|
|
510
|
+
onClick: onStop,
|
|
511
|
+
className: "text-destructive hover:text-destructive hover:bg-destructive/10",
|
|
512
|
+
children: "Stop agent"
|
|
513
|
+
}
|
|
514
|
+
),
|
|
515
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
516
|
+
core.Button,
|
|
517
|
+
{
|
|
518
|
+
variant: "primary",
|
|
519
|
+
size: "sm",
|
|
520
|
+
onClick: handleSubmit,
|
|
521
|
+
disabled: !canSubmit,
|
|
522
|
+
children: "Send response"
|
|
523
|
+
}
|
|
524
|
+
)
|
|
525
|
+
] })
|
|
526
|
+
]
|
|
527
|
+
}
|
|
528
|
+
);
|
|
529
|
+
});
|
|
530
|
+
HITLQuestionPanel.displayName = "HITLQuestionPanel";
|
|
531
|
+
function parseResponse(response) {
|
|
532
|
+
const answers = {};
|
|
533
|
+
let additionalContext = null;
|
|
534
|
+
const blocks = response.split("\n\n");
|
|
535
|
+
for (const block of blocks) {
|
|
536
|
+
const qaMatch = block.match(/^Q: (.+)\nA: (.+)$/s);
|
|
537
|
+
if (qaMatch) {
|
|
538
|
+
answers[qaMatch[1].trim()] = qaMatch[2].trim();
|
|
539
|
+
} else if (block.startsWith("Additional context: ")) {
|
|
540
|
+
additionalContext = block.slice("Additional context: ".length).trim();
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
return { answers, additionalContext };
|
|
544
|
+
}
|
|
545
|
+
var HITLInteractionRecord = React11__namespace.forwardRef(({ interaction, className, ...props }, ref) => {
|
|
546
|
+
const { question, response, respondedAt } = interaction;
|
|
547
|
+
const timestamp = new Date(respondedAt).toLocaleTimeString([], {
|
|
548
|
+
hour: "2-digit",
|
|
549
|
+
minute: "2-digit"
|
|
550
|
+
});
|
|
551
|
+
const { answers, additionalContext } = React11.useMemo(
|
|
552
|
+
() => parseResponse(response),
|
|
553
|
+
[response]
|
|
554
|
+
);
|
|
555
|
+
const hasParsedAnswers = Object.keys(answers).length > 0;
|
|
556
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
557
|
+
"div",
|
|
558
|
+
{
|
|
559
|
+
ref,
|
|
560
|
+
className: core.cn(
|
|
561
|
+
"rounded-lg border border-border bg-muted p-3 space-y-2 text-sm",
|
|
562
|
+
className
|
|
563
|
+
),
|
|
564
|
+
...props,
|
|
565
|
+
children: [
|
|
566
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
567
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-muted-foreground", children: "Clarifying Question" }),
|
|
568
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: timestamp })
|
|
569
|
+
] }),
|
|
570
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-foreground font-medium", children: question.reason }),
|
|
571
|
+
question.context && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground bg-background rounded p-2 border border-border", children: /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "whitespace-pre-wrap font-mono", children: question.context }) }),
|
|
572
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: question.questions.map((q, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
573
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-foreground", children: q }),
|
|
574
|
+
question.options?.[q] && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-muted-foreground ml-2", children: [
|
|
575
|
+
"Options: ",
|
|
576
|
+
question.options[q].join(", ")
|
|
577
|
+
] }),
|
|
578
|
+
hasParsedAnswers && answers[q] && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-foreground ml-2 mt-0.5 bg-background rounded px-2 py-1 border border-border", children: [
|
|
579
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Answer: " }),
|
|
580
|
+
answers[q]
|
|
581
|
+
] })
|
|
582
|
+
] }, i)) }),
|
|
583
|
+
hasParsedAnswers && additionalContext && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-border pt-2", children: [
|
|
584
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground text-xs", children: "Additional context:" }),
|
|
585
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-foreground mt-0.5", children: additionalContext })
|
|
586
|
+
] }),
|
|
587
|
+
!hasParsedAnswers && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-border pt-2", children: [
|
|
588
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground text-xs", children: "Response:" }),
|
|
589
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-foreground mt-0.5", children: response })
|
|
590
|
+
] })
|
|
591
|
+
]
|
|
592
|
+
}
|
|
593
|
+
);
|
|
594
|
+
});
|
|
595
|
+
HITLInteractionRecord.displayName = "HITLInteractionRecord";
|
|
596
|
+
var HITLSection = React11__namespace.forwardRef(
|
|
597
|
+
({
|
|
598
|
+
interactions,
|
|
599
|
+
defaultExpanded = false,
|
|
600
|
+
isExpanded: controlledExpanded,
|
|
601
|
+
onExpandedChange,
|
|
602
|
+
className,
|
|
603
|
+
...props
|
|
604
|
+
}, ref) => {
|
|
605
|
+
const [uncontrolledExpanded, setUncontrolledExpanded] = React11.useState(defaultExpanded);
|
|
606
|
+
const isControlled = controlledExpanded !== void 0;
|
|
607
|
+
const isExpanded = isControlled ? controlledExpanded : uncontrolledExpanded;
|
|
608
|
+
const toggleExpanded = React11.useCallback(() => {
|
|
609
|
+
const newValue = !isExpanded;
|
|
610
|
+
if (isControlled) {
|
|
611
|
+
onExpandedChange?.(newValue);
|
|
612
|
+
} else {
|
|
613
|
+
setUncontrolledExpanded(newValue);
|
|
614
|
+
}
|
|
615
|
+
}, [isExpanded, isControlled, onExpandedChange]);
|
|
616
|
+
if (!interactions || interactions.length === 0) {
|
|
617
|
+
return null;
|
|
618
|
+
}
|
|
619
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
620
|
+
"div",
|
|
621
|
+
{
|
|
622
|
+
ref,
|
|
623
|
+
className: core.cn("border-t border-border", className),
|
|
624
|
+
...props,
|
|
625
|
+
children: [
|
|
626
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
627
|
+
"button",
|
|
628
|
+
{
|
|
629
|
+
onClick: toggleExpanded,
|
|
630
|
+
className: "w-full flex items-center gap-2 py-2 px-3 hover:bg-muted/50 transition-colors text-left",
|
|
631
|
+
children: [
|
|
632
|
+
isExpanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "w-3.5 h-3.5 text-muted-foreground flex-shrink-0" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "w-3.5 h-3.5 text-muted-foreground flex-shrink-0" }),
|
|
633
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageCircleQuestion, { className: "w-3.5 h-3.5 text-muted-foreground flex-shrink-0" }),
|
|
634
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-medium text-foreground/80", children: [
|
|
635
|
+
"Clarifying Questions (",
|
|
636
|
+
interactions.length,
|
|
637
|
+
")"
|
|
638
|
+
] })
|
|
639
|
+
]
|
|
640
|
+
}
|
|
641
|
+
),
|
|
642
|
+
isExpanded && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 pb-3 space-y-2", children: interactions.map((interaction, i) => /* @__PURE__ */ jsxRuntime.jsx(HITLInteractionRecord, { interaction }, i)) })
|
|
643
|
+
]
|
|
644
|
+
}
|
|
645
|
+
);
|
|
646
|
+
}
|
|
647
|
+
);
|
|
648
|
+
HITLSection.displayName = "HITLSection";
|
|
649
|
+
var TruncatedMessage = React11__namespace.forwardRef(
|
|
650
|
+
({ message, className, ...props }, ref) => {
|
|
651
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
652
|
+
"div",
|
|
653
|
+
{
|
|
654
|
+
ref,
|
|
655
|
+
className: core.cn(
|
|
656
|
+
"text-xs text-muted-foreground truncate min-w-0",
|
|
657
|
+
className
|
|
658
|
+
),
|
|
659
|
+
title: message,
|
|
660
|
+
...props,
|
|
661
|
+
children: message
|
|
662
|
+
}
|
|
663
|
+
);
|
|
664
|
+
}
|
|
665
|
+
);
|
|
666
|
+
TruncatedMessage.displayName = "TruncatedMessage";
|
|
358
667
|
function useThinkingTimer({
|
|
359
668
|
startTime,
|
|
360
669
|
endTime,
|
|
361
670
|
status
|
|
362
671
|
}) {
|
|
363
|
-
const [elapsed, setElapsed] =
|
|
364
|
-
|
|
672
|
+
const [elapsed, setElapsed] = React11.useState(0);
|
|
673
|
+
React11.useEffect(() => {
|
|
365
674
|
if (!startTime) {
|
|
366
675
|
setElapsed(0);
|
|
367
676
|
return;
|
|
@@ -390,17 +699,157 @@ var initialAgentResponseState = {
|
|
|
390
699
|
knowledge: [],
|
|
391
700
|
memory: [],
|
|
392
701
|
statusUpdates: [],
|
|
702
|
+
potentialResponses: [],
|
|
703
|
+
customTimelineEntries: [],
|
|
393
704
|
response: "",
|
|
394
705
|
thinkingStartTime: null,
|
|
395
706
|
responseCompleteTime: null,
|
|
396
707
|
firstMessageTime: null
|
|
397
708
|
};
|
|
398
709
|
|
|
710
|
+
// src/components/agent-timeline/utils.ts
|
|
711
|
+
function buildTimelineEntries(state) {
|
|
712
|
+
const entries = [];
|
|
713
|
+
if (state.thinkingSteps) {
|
|
714
|
+
let idx = 0;
|
|
715
|
+
for (const step of state.thinkingSteps) {
|
|
716
|
+
entries.push({
|
|
717
|
+
id: `tl-think-${idx++}`,
|
|
718
|
+
type: "thinking",
|
|
719
|
+
agentName: step.agentName ?? null,
|
|
720
|
+
parentAgent: step.parentAgent ?? null,
|
|
721
|
+
depth: step.depth ?? 0,
|
|
722
|
+
content: step.content,
|
|
723
|
+
title: step.label,
|
|
724
|
+
timestamp: step.timestamp ?? 0
|
|
725
|
+
});
|
|
726
|
+
}
|
|
727
|
+
} else if (state.thinking) {
|
|
728
|
+
entries.push({
|
|
729
|
+
id: "tl-think-0",
|
|
730
|
+
type: "thinking",
|
|
731
|
+
agentName: null,
|
|
732
|
+
parentAgent: null,
|
|
733
|
+
depth: 0,
|
|
734
|
+
content: state.thinking,
|
|
735
|
+
title: null,
|
|
736
|
+
timestamp: state.thinkingStartTime ?? 0
|
|
737
|
+
});
|
|
738
|
+
}
|
|
739
|
+
let toolIdx = 0;
|
|
740
|
+
for (const tool of state.toolCalls) {
|
|
741
|
+
entries.push({
|
|
742
|
+
id: `tl-tool-${toolIdx++}`,
|
|
743
|
+
type: "tool_call",
|
|
744
|
+
agentName: tool.agentName ?? null,
|
|
745
|
+
parentAgent: tool.parentAgent ?? null,
|
|
746
|
+
depth: tool.depth ?? 0,
|
|
747
|
+
content: tool.name,
|
|
748
|
+
title: null,
|
|
749
|
+
timestamp: tool.timestamp
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
let knowIdx = 0;
|
|
753
|
+
for (const item of state.knowledge) {
|
|
754
|
+
entries.push({
|
|
755
|
+
id: `tl-know-${knowIdx++}`,
|
|
756
|
+
type: "knowledge",
|
|
757
|
+
agentName: item.agentName ?? null,
|
|
758
|
+
parentAgent: item.parentAgent ?? null,
|
|
759
|
+
depth: item.depth ?? 0,
|
|
760
|
+
content: item.content,
|
|
761
|
+
title: item.source,
|
|
762
|
+
timestamp: item.timestamp
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
let memIdx = 0;
|
|
766
|
+
for (const item of state.memory) {
|
|
767
|
+
entries.push({
|
|
768
|
+
id: `tl-mem-${memIdx++}`,
|
|
769
|
+
type: "memory",
|
|
770
|
+
agentName: item.agentName ?? null,
|
|
771
|
+
parentAgent: item.parentAgent ?? null,
|
|
772
|
+
depth: item.depth ?? 0,
|
|
773
|
+
content: item.content,
|
|
774
|
+
title: item.type,
|
|
775
|
+
timestamp: item.timestamp
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
let statIdx = 0;
|
|
779
|
+
for (const item of state.statusUpdates) {
|
|
780
|
+
entries.push({
|
|
781
|
+
id: `tl-stat-${statIdx++}`,
|
|
782
|
+
type: "status_update",
|
|
783
|
+
agentName: item.agentName ?? item.agent ?? null,
|
|
784
|
+
parentAgent: item.parentAgent ?? null,
|
|
785
|
+
depth: item.depth ?? 0,
|
|
786
|
+
content: item.message,
|
|
787
|
+
title: null,
|
|
788
|
+
timestamp: item.timestamp
|
|
789
|
+
});
|
|
790
|
+
}
|
|
791
|
+
if (state.potentialResponses) {
|
|
792
|
+
let respIdx = 0;
|
|
793
|
+
for (const resp of state.potentialResponses) {
|
|
794
|
+
entries.push({
|
|
795
|
+
id: `tl-resp-${respIdx++}`,
|
|
796
|
+
type: "ai_response",
|
|
797
|
+
agentName: resp.agentName ?? null,
|
|
798
|
+
parentAgent: resp.parentAgent ?? null,
|
|
799
|
+
depth: resp.depth ?? 0,
|
|
800
|
+
content: resp.content,
|
|
801
|
+
title: null,
|
|
802
|
+
timestamp: resp.timestamp
|
|
803
|
+
});
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
if (state.customTimelineEntries) {
|
|
807
|
+
entries.push(...state.customTimelineEntries);
|
|
808
|
+
}
|
|
809
|
+
entries.sort((a, b) => a.timestamp - b.timestamp);
|
|
810
|
+
return entries;
|
|
811
|
+
}
|
|
812
|
+
function groupIntoAgentRuns(entries) {
|
|
813
|
+
const runs = [];
|
|
814
|
+
let currentRun = null;
|
|
815
|
+
for (const entry of entries) {
|
|
816
|
+
const name = entry.agentName || "Agent";
|
|
817
|
+
if (!currentRun || currentRun.agentName !== name) {
|
|
818
|
+
currentRun = {
|
|
819
|
+
agentName: name,
|
|
820
|
+
parentAgent: entry.parentAgent,
|
|
821
|
+
depth: entry.depth,
|
|
822
|
+
entries: []
|
|
823
|
+
};
|
|
824
|
+
runs.push(currentRun);
|
|
825
|
+
}
|
|
826
|
+
currentRun.entries.push({ entry, count: 1 });
|
|
827
|
+
}
|
|
828
|
+
for (const run of runs) {
|
|
829
|
+
run.entries = deduplicateEntries(run.entries);
|
|
830
|
+
}
|
|
831
|
+
return runs;
|
|
832
|
+
}
|
|
833
|
+
function deduplicateEntries(entries) {
|
|
834
|
+
if (entries.length === 0) return [];
|
|
835
|
+
const result = [entries[0]];
|
|
836
|
+
for (let i = 1; i < entries.length; i++) {
|
|
837
|
+
const prev = result[result.length - 1];
|
|
838
|
+
const curr = entries[i];
|
|
839
|
+
if (prev.entry.type === curr.entry.type && prev.entry.content === curr.entry.content) {
|
|
840
|
+
prev.count += curr.count;
|
|
841
|
+
} else {
|
|
842
|
+
result.push({ ...curr });
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
return result;
|
|
846
|
+
}
|
|
847
|
+
|
|
399
848
|
// src/components/agent-response/hooks/useAgentResponseAccumulator.ts
|
|
400
849
|
function useAgentResponseAccumulator(options) {
|
|
401
|
-
const [state, setState] =
|
|
850
|
+
const [state, setState] = React11.useState(initialAgentResponseState);
|
|
402
851
|
const topic = options?.topic;
|
|
403
|
-
const handleMessage =
|
|
852
|
+
const handleMessage = React11.useCallback(
|
|
404
853
|
(message) => {
|
|
405
854
|
let payload;
|
|
406
855
|
if (topic) {
|
|
@@ -429,28 +878,44 @@ function useAgentResponseAccumulator(options) {
|
|
|
429
878
|
id: payload.thinkingStep.id || `step-${Date.now()}`,
|
|
430
879
|
label: payload.thinkingStep.label,
|
|
431
880
|
content: payload.thinkingStep.content,
|
|
432
|
-
depth: payload.thinkingStep.depth ?? 0,
|
|
433
|
-
isCollapsed: payload.thinkingStep.isCollapsed
|
|
881
|
+
depth: payload.thinkingStep.depth ?? payload.depth ?? 0,
|
|
882
|
+
isCollapsed: payload.thinkingStep.isCollapsed,
|
|
883
|
+
timestamp: Date.now(),
|
|
884
|
+
agentName: payload.agentName,
|
|
885
|
+
parentAgent: payload.parentAgent
|
|
434
886
|
};
|
|
435
887
|
const thinkingStartTime2 = prev.thinkingStartTime ?? Date.now();
|
|
436
|
-
|
|
888
|
+
const next2 = {
|
|
437
889
|
...prev,
|
|
438
890
|
status: newStatus,
|
|
439
891
|
thinkingSteps: [...prev.thinkingSteps || [], newStep],
|
|
440
892
|
thinkingStartTime: thinkingStartTime2,
|
|
441
893
|
firstMessageTime
|
|
442
894
|
};
|
|
895
|
+
return { ...next2, timelineEntries: buildTimelineEntries(next2) };
|
|
443
896
|
}
|
|
444
897
|
const newThinking = payload.message || payload.content || "";
|
|
445
898
|
const separator = prev.thinking && newThinking ? "\n\n" : "";
|
|
446
899
|
const thinkingStartTime = prev.thinkingStartTime ?? (newThinking ? Date.now() : null);
|
|
447
|
-
|
|
900
|
+
const prevSteps = prev.thinkingSteps || [];
|
|
901
|
+
const plainStep = {
|
|
902
|
+
id: `step-${prevSteps.length}`,
|
|
903
|
+
label: newThinking,
|
|
904
|
+
content: newThinking,
|
|
905
|
+
depth: payload.depth ?? 0,
|
|
906
|
+
timestamp: Date.now(),
|
|
907
|
+
agentName: payload.agentName,
|
|
908
|
+
parentAgent: payload.parentAgent
|
|
909
|
+
};
|
|
910
|
+
const next = {
|
|
448
911
|
...prev,
|
|
449
912
|
status: newStatus,
|
|
450
913
|
thinking: prev.thinking + separator + newThinking,
|
|
914
|
+
thinkingSteps: [...prevSteps, plainStep],
|
|
451
915
|
thinkingStartTime,
|
|
452
916
|
firstMessageTime
|
|
453
917
|
};
|
|
918
|
+
return { ...next, timelineEntries: buildTimelineEntries(next) };
|
|
454
919
|
}
|
|
455
920
|
case "tool_call": {
|
|
456
921
|
const toolName = payload.message || payload.tool?.name;
|
|
@@ -459,14 +924,18 @@ function useAgentResponseAccumulator(options) {
|
|
|
459
924
|
id: payload.tool?.id || `tool-${Date.now()}`,
|
|
460
925
|
name: toolName,
|
|
461
926
|
arguments: payload.tool?.arguments,
|
|
462
|
-
timestamp: Date.now()
|
|
927
|
+
timestamp: Date.now(),
|
|
928
|
+
agentName: payload.agentName,
|
|
929
|
+
parentAgent: payload.parentAgent,
|
|
930
|
+
depth: payload.depth
|
|
463
931
|
};
|
|
464
|
-
|
|
932
|
+
const next = {
|
|
465
933
|
...prev,
|
|
466
934
|
status: newStatus,
|
|
467
935
|
toolCalls: [...prev.toolCalls, newToolCall],
|
|
468
936
|
firstMessageTime
|
|
469
937
|
};
|
|
938
|
+
return { ...next, timelineEntries: buildTimelineEntries(next) };
|
|
470
939
|
}
|
|
471
940
|
return { ...prev, status: newStatus, firstMessageTime };
|
|
472
941
|
}
|
|
@@ -477,14 +946,18 @@ function useAgentResponseAccumulator(options) {
|
|
|
477
946
|
id: payload.knowledge?.id || `knowledge-${Date.now()}`,
|
|
478
947
|
source: payload.knowledge?.source || "unknown",
|
|
479
948
|
content: knowledgeContent,
|
|
480
|
-
timestamp: Date.now()
|
|
949
|
+
timestamp: Date.now(),
|
|
950
|
+
agentName: payload.agentName,
|
|
951
|
+
parentAgent: payload.parentAgent,
|
|
952
|
+
depth: payload.depth
|
|
481
953
|
};
|
|
482
|
-
|
|
954
|
+
const next = {
|
|
483
955
|
...prev,
|
|
484
956
|
status: newStatus,
|
|
485
957
|
knowledge: [...prev.knowledge, newKnowledge],
|
|
486
958
|
firstMessageTime
|
|
487
959
|
};
|
|
960
|
+
return { ...next, timelineEntries: buildTimelineEntries(next) };
|
|
488
961
|
}
|
|
489
962
|
return { ...prev, status: newStatus, firstMessageTime };
|
|
490
963
|
}
|
|
@@ -495,14 +968,18 @@ function useAgentResponseAccumulator(options) {
|
|
|
495
968
|
id: payload.memory?.id || `memory-${Date.now()}`,
|
|
496
969
|
type: payload.memory?.type || "unknown",
|
|
497
970
|
content: memoryContent,
|
|
498
|
-
timestamp: Date.now()
|
|
971
|
+
timestamp: Date.now(),
|
|
972
|
+
agentName: payload.agentName,
|
|
973
|
+
parentAgent: payload.parentAgent,
|
|
974
|
+
depth: payload.depth
|
|
499
975
|
};
|
|
500
|
-
|
|
976
|
+
const next = {
|
|
501
977
|
...prev,
|
|
502
978
|
status: newStatus,
|
|
503
979
|
memory: [...prev.memory, newMemory],
|
|
504
980
|
firstMessageTime
|
|
505
981
|
};
|
|
982
|
+
return { ...next, timelineEntries: buildTimelineEntries(next) };
|
|
506
983
|
}
|
|
507
984
|
return { ...prev, status: newStatus, firstMessageTime };
|
|
508
985
|
}
|
|
@@ -521,14 +998,39 @@ function useAgentResponseAccumulator(options) {
|
|
|
521
998
|
id: payload.statusUpdate?.id || `status-${Date.now()}`,
|
|
522
999
|
message: statusMessage,
|
|
523
1000
|
agent: payload.statusUpdate?.agent,
|
|
524
|
-
timestamp: Date.now()
|
|
1001
|
+
timestamp: Date.now(),
|
|
1002
|
+
agentName: payload.agentName,
|
|
1003
|
+
parentAgent: payload.parentAgent,
|
|
1004
|
+
depth: payload.depth
|
|
525
1005
|
};
|
|
526
|
-
|
|
1006
|
+
const next = {
|
|
527
1007
|
...prev,
|
|
528
1008
|
status: newStatus,
|
|
529
1009
|
statusUpdates: [...prev.statusUpdates, newStatusItem],
|
|
530
1010
|
firstMessageTime
|
|
531
1011
|
};
|
|
1012
|
+
return { ...next, timelineEntries: buildTimelineEntries(next) };
|
|
1013
|
+
}
|
|
1014
|
+
return { ...prev, status: newStatus, firstMessageTime };
|
|
1015
|
+
}
|
|
1016
|
+
case "potential_response": {
|
|
1017
|
+
const respContent = payload.message || payload.content || "";
|
|
1018
|
+
if (respContent) {
|
|
1019
|
+
const newResp = {
|
|
1020
|
+
id: `resp-${Date.now()}`,
|
|
1021
|
+
content: respContent,
|
|
1022
|
+
timestamp: Date.now(),
|
|
1023
|
+
agentName: payload.agentName,
|
|
1024
|
+
parentAgent: payload.parentAgent,
|
|
1025
|
+
depth: payload.depth
|
|
1026
|
+
};
|
|
1027
|
+
const next = {
|
|
1028
|
+
...prev,
|
|
1029
|
+
status: newStatus,
|
|
1030
|
+
potentialResponses: [...prev.potentialResponses || [], newResp],
|
|
1031
|
+
firstMessageTime
|
|
1032
|
+
};
|
|
1033
|
+
return { ...next, timelineEntries: buildTimelineEntries(next) };
|
|
532
1034
|
}
|
|
533
1035
|
return { ...prev, status: newStatus, firstMessageTime };
|
|
534
1036
|
}
|
|
@@ -539,12 +1041,293 @@ function useAgentResponseAccumulator(options) {
|
|
|
539
1041
|
},
|
|
540
1042
|
[topic]
|
|
541
1043
|
);
|
|
542
|
-
const reset =
|
|
1044
|
+
const reset = React11.useCallback(() => {
|
|
543
1045
|
setState(initialAgentResponseState);
|
|
544
1046
|
}, []);
|
|
545
1047
|
return { state, handleMessage, reset };
|
|
546
1048
|
}
|
|
547
|
-
var
|
|
1049
|
+
var ICON_MAP = {
|
|
1050
|
+
thinking: lucideReact.Brain,
|
|
1051
|
+
tool_call: lucideReact.Wrench,
|
|
1052
|
+
knowledge: lucideReact.BookOpen,
|
|
1053
|
+
memory: lucideReact.HardDrive,
|
|
1054
|
+
status_update: lucideReact.Activity,
|
|
1055
|
+
ai_response: lucideReact.MessageSquare,
|
|
1056
|
+
error: lucideReact.AlertCircle
|
|
1057
|
+
};
|
|
1058
|
+
function TimelineItem({
|
|
1059
|
+
displayEntry,
|
|
1060
|
+
renderMarkdown,
|
|
1061
|
+
isExpanded,
|
|
1062
|
+
onToggleExpanded
|
|
1063
|
+
}) {
|
|
1064
|
+
const { entry, count } = displayEntry;
|
|
1065
|
+
const Icon = ICON_MAP[entry.type] ?? lucideReact.Activity;
|
|
1066
|
+
const isLong = entry.content.length > 200 || entry.content.split("\n").length > 3;
|
|
1067
|
+
const canExpand = isLong || entry.type === "ai_response";
|
|
1068
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "py-1 flex items-start gap-2 group", children: [
|
|
1069
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "w-3.5 h-3.5 text-muted-foreground flex-shrink-0 mt-0.5" }),
|
|
1070
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children: isExpanded && entry.type === "ai_response" && renderMarkdown ? (
|
|
1071
|
+
// Expanded AI response: rendered markdown
|
|
1072
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1073
|
+
renderMarkdown(entry.content),
|
|
1074
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1075
|
+
"button",
|
|
1076
|
+
{
|
|
1077
|
+
onClick: onToggleExpanded,
|
|
1078
|
+
className: "text-[10px] text-muted-foreground/70 hover:text-muted-foreground mt-1",
|
|
1079
|
+
children: "Show less"
|
|
1080
|
+
}
|
|
1081
|
+
)
|
|
1082
|
+
] })
|
|
1083
|
+
) : isExpanded ? (
|
|
1084
|
+
// Expanded non-AI: plain text
|
|
1085
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1086
|
+
/* @__PURE__ */ jsxRuntime.jsx("pre", { className: "text-xs text-muted-foreground whitespace-pre-wrap font-mono", children: entry.content }),
|
|
1087
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1088
|
+
"button",
|
|
1089
|
+
{
|
|
1090
|
+
onClick: onToggleExpanded,
|
|
1091
|
+
className: "text-[10px] text-muted-foreground/70 hover:text-muted-foreground mt-1",
|
|
1092
|
+
children: "Show less"
|
|
1093
|
+
}
|
|
1094
|
+
)
|
|
1095
|
+
] })
|
|
1096
|
+
) : (
|
|
1097
|
+
// Collapsed: truncated with optional expand
|
|
1098
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-1.5 min-w-0", children: [
|
|
1099
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1100
|
+
"div",
|
|
1101
|
+
{
|
|
1102
|
+
className: `text-xs text-muted-foreground min-w-0 ${canExpand ? "line-clamp-2 cursor-pointer hover:text-foreground/80" : ""}`,
|
|
1103
|
+
onClick: canExpand ? onToggleExpanded : void 0,
|
|
1104
|
+
children: entry.content
|
|
1105
|
+
}
|
|
1106
|
+
),
|
|
1107
|
+
count > 1 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[10px] text-muted-foreground/60 whitespace-nowrap flex-shrink-0", children: [
|
|
1108
|
+
"(x",
|
|
1109
|
+
count,
|
|
1110
|
+
")"
|
|
1111
|
+
] })
|
|
1112
|
+
] })
|
|
1113
|
+
) })
|
|
1114
|
+
] });
|
|
1115
|
+
}
|
|
1116
|
+
function TimelineAgentBlock({
|
|
1117
|
+
block,
|
|
1118
|
+
renderMarkdown,
|
|
1119
|
+
isSingleAgent,
|
|
1120
|
+
isCollapsed,
|
|
1121
|
+
onToggleCollapsed,
|
|
1122
|
+
expandedItems,
|
|
1123
|
+
onToggleItemExpanded
|
|
1124
|
+
}) {
|
|
1125
|
+
const indentPx = block.depth * 16;
|
|
1126
|
+
if (isSingleAgent && block.depth === 0) {
|
|
1127
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { paddingLeft: `${indentPx}px` }, children: block.entries.map((displayEntry, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1128
|
+
TimelineItem,
|
|
1129
|
+
{
|
|
1130
|
+
displayEntry,
|
|
1131
|
+
renderMarkdown,
|
|
1132
|
+
isExpanded: expandedItems.has(displayEntry.entry.id),
|
|
1133
|
+
onToggleExpanded: () => onToggleItemExpanded(displayEntry.entry.id)
|
|
1134
|
+
},
|
|
1135
|
+
displayEntry.entry.id + "-" + i
|
|
1136
|
+
)) });
|
|
1137
|
+
}
|
|
1138
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { paddingLeft: `${indentPx}px` }, children: [
|
|
1139
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1140
|
+
"button",
|
|
1141
|
+
{
|
|
1142
|
+
onClick: onToggleCollapsed,
|
|
1143
|
+
className: "w-full flex items-center gap-1.5 py-1 hover:bg-muted/50 -ml-1 pl-1 pr-2 rounded transition-colors text-left",
|
|
1144
|
+
children: [
|
|
1145
|
+
isCollapsed ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "w-3 h-3 text-muted-foreground flex-shrink-0" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "w-3 h-3 text-muted-foreground flex-shrink-0" }),
|
|
1146
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-foreground/80", children: block.agentName }),
|
|
1147
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[10px] text-muted-foreground/60", children: [
|
|
1148
|
+
"(",
|
|
1149
|
+
block.entries.reduce((sum, e) => sum + e.count, 0),
|
|
1150
|
+
")"
|
|
1151
|
+
] })
|
|
1152
|
+
]
|
|
1153
|
+
}
|
|
1154
|
+
),
|
|
1155
|
+
!isCollapsed && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-4", children: block.entries.map((displayEntry, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1156
|
+
TimelineItem,
|
|
1157
|
+
{
|
|
1158
|
+
displayEntry,
|
|
1159
|
+
renderMarkdown,
|
|
1160
|
+
isExpanded: expandedItems.has(displayEntry.entry.id),
|
|
1161
|
+
onToggleExpanded: () => onToggleItemExpanded(displayEntry.entry.id)
|
|
1162
|
+
},
|
|
1163
|
+
displayEntry.entry.id + "-" + i
|
|
1164
|
+
)) })
|
|
1165
|
+
] });
|
|
1166
|
+
}
|
|
1167
|
+
function createTimelineUIState() {
|
|
1168
|
+
return {
|
|
1169
|
+
expandedItems: /* @__PURE__ */ new Set(),
|
|
1170
|
+
collapsedRuns: /* @__PURE__ */ new Set(),
|
|
1171
|
+
activeFilters: /* @__PURE__ */ new Set()
|
|
1172
|
+
};
|
|
1173
|
+
}
|
|
1174
|
+
var TYPE_CONFIG = [
|
|
1175
|
+
{ type: "status_update", icon: lucideReact.Activity, label: "Status" },
|
|
1176
|
+
{ type: "thinking", icon: lucideReact.Brain, label: "Thinking" },
|
|
1177
|
+
{ type: "tool_call", icon: lucideReact.Wrench, label: "Tools" },
|
|
1178
|
+
{ type: "knowledge", icon: lucideReact.BookOpen, label: "Knowledge" },
|
|
1179
|
+
{ type: "memory", icon: lucideReact.HardDrive, label: "Memory" },
|
|
1180
|
+
{ type: "ai_response", icon: lucideReact.MessageSquare, label: "AI" },
|
|
1181
|
+
{ type: "error", icon: lucideReact.AlertCircle, label: "Errors" }
|
|
1182
|
+
];
|
|
1183
|
+
function AgentTimeline({ entries, renderMarkdown, uiState, maxHeight = "300px" }) {
|
|
1184
|
+
const containerRef = React11.useRef(null);
|
|
1185
|
+
const [renderTick, setRenderTick] = React11.useState(0);
|
|
1186
|
+
const forceRender = React11.useCallback(() => setRenderTick((t) => t + 1), []);
|
|
1187
|
+
const [internalExpandedItems] = React11.useState(() => /* @__PURE__ */ new Set());
|
|
1188
|
+
const [internalCollapsedRuns] = React11.useState(() => /* @__PURE__ */ new Set());
|
|
1189
|
+
const [internalActiveFilters] = React11.useState(() => /* @__PURE__ */ new Set());
|
|
1190
|
+
const expandedItems = uiState?.expandedItems ?? internalExpandedItems;
|
|
1191
|
+
const collapsedRuns = uiState?.collapsedRuns ?? internalCollapsedRuns;
|
|
1192
|
+
const activeFilters = uiState?.activeFilters ?? internalActiveFilters;
|
|
1193
|
+
const availableTypes = React11.useMemo(() => {
|
|
1194
|
+
const types = /* @__PURE__ */ new Set();
|
|
1195
|
+
for (const entry of entries) {
|
|
1196
|
+
types.add(entry.type);
|
|
1197
|
+
}
|
|
1198
|
+
return types;
|
|
1199
|
+
}, [entries]);
|
|
1200
|
+
const filteredEntries = React11.useMemo(
|
|
1201
|
+
() => activeFilters.size === 0 ? entries : entries.filter((e) => activeFilters.has(e.type)),
|
|
1202
|
+
[entries, activeFilters, renderTick]
|
|
1203
|
+
);
|
|
1204
|
+
const agentRuns = React11.useMemo(() => groupIntoAgentRuns(filteredEntries), [filteredEntries, renderTick]);
|
|
1205
|
+
const toggleFilter = React11.useCallback((type) => {
|
|
1206
|
+
if (activeFilters.has(type)) {
|
|
1207
|
+
activeFilters.delete(type);
|
|
1208
|
+
} else {
|
|
1209
|
+
activeFilters.add(type);
|
|
1210
|
+
}
|
|
1211
|
+
forceRender();
|
|
1212
|
+
}, [activeFilters, forceRender]);
|
|
1213
|
+
const clearFilters = React11.useCallback(() => {
|
|
1214
|
+
activeFilters.clear();
|
|
1215
|
+
forceRender();
|
|
1216
|
+
}, [activeFilters, forceRender]);
|
|
1217
|
+
const toggleItemExpanded = React11.useCallback((entryId) => {
|
|
1218
|
+
if (expandedItems.has(entryId)) {
|
|
1219
|
+
expandedItems.delete(entryId);
|
|
1220
|
+
} else {
|
|
1221
|
+
expandedItems.add(entryId);
|
|
1222
|
+
}
|
|
1223
|
+
forceRender();
|
|
1224
|
+
}, [expandedItems, forceRender]);
|
|
1225
|
+
const collapseAll = React11.useCallback(() => {
|
|
1226
|
+
collapsedRuns.clear();
|
|
1227
|
+
agentRuns.forEach((run, i) => {
|
|
1228
|
+
collapsedRuns.add(`${run.agentName}-${i}`);
|
|
1229
|
+
});
|
|
1230
|
+
expandedItems.clear();
|
|
1231
|
+
forceRender();
|
|
1232
|
+
}, [agentRuns, collapsedRuns, expandedItems, forceRender]);
|
|
1233
|
+
const expandAll = React11.useCallback(() => {
|
|
1234
|
+
collapsedRuns.clear();
|
|
1235
|
+
agentRuns.forEach((run, i) => {
|
|
1236
|
+
collapsedRuns.add(`${run.agentName}-${i}:expanded`);
|
|
1237
|
+
});
|
|
1238
|
+
forceRender();
|
|
1239
|
+
}, [agentRuns, collapsedRuns, forceRender]);
|
|
1240
|
+
if (entries.length === 0) return null;
|
|
1241
|
+
const isSingle = agentRuns.length === 1;
|
|
1242
|
+
const hasActiveFilter = activeFilters.size > 0;
|
|
1243
|
+
const scrollStyle = maxHeight !== "none" ? { maxHeight } : void 0;
|
|
1244
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1245
|
+
"div",
|
|
1246
|
+
{
|
|
1247
|
+
ref: containerRef,
|
|
1248
|
+
className: maxHeight !== "none" ? "overflow-y-auto" : "",
|
|
1249
|
+
style: scrollStyle,
|
|
1250
|
+
children: [
|
|
1251
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sticky top-0 z-10 bg-background flex items-center gap-1 py-1.5 mb-1 border-b border-border/50 flex-wrap pl-2", children: [
|
|
1252
|
+
TYPE_CONFIG.filter((tc) => availableTypes.has(tc.type)).map((tc) => {
|
|
1253
|
+
const isActive = activeFilters.has(tc.type);
|
|
1254
|
+
const count = entries.filter((e) => e.type === tc.type).length;
|
|
1255
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1256
|
+
"button",
|
|
1257
|
+
{
|
|
1258
|
+
onClick: () => toggleFilter(tc.type),
|
|
1259
|
+
className: `inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-[10px] transition-colors ${isActive ? "bg-accent text-accent-foreground ring-1 ring-accent-foreground/20" : "text-muted-foreground/60 hover:text-muted-foreground hover:bg-muted/50"}`,
|
|
1260
|
+
title: `${isActive ? "Hide" : "Show only"} ${tc.label}`,
|
|
1261
|
+
children: [
|
|
1262
|
+
/* @__PURE__ */ jsxRuntime.jsx(tc.icon, { className: "w-3 h-3" }),
|
|
1263
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: count })
|
|
1264
|
+
]
|
|
1265
|
+
},
|
|
1266
|
+
tc.type
|
|
1267
|
+
);
|
|
1268
|
+
}),
|
|
1269
|
+
hasActiveFilter && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1270
|
+
"button",
|
|
1271
|
+
{
|
|
1272
|
+
onClick: clearFilters,
|
|
1273
|
+
className: "text-[10px] text-muted-foreground/60 hover:text-muted-foreground px-1",
|
|
1274
|
+
children: "Clear"
|
|
1275
|
+
}
|
|
1276
|
+
),
|
|
1277
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1" }),
|
|
1278
|
+
!isSingle && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1279
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1280
|
+
"button",
|
|
1281
|
+
{
|
|
1282
|
+
onClick: collapseAll,
|
|
1283
|
+
className: "inline-flex items-center gap-0.5 text-[10px] text-muted-foreground/60 hover:text-muted-foreground px-1 py-0.5 rounded hover:bg-muted/50 transition-colors",
|
|
1284
|
+
title: "Collapse all",
|
|
1285
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsDownUp, { className: "w-3 h-3" })
|
|
1286
|
+
}
|
|
1287
|
+
),
|
|
1288
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1289
|
+
"button",
|
|
1290
|
+
{
|
|
1291
|
+
onClick: expandAll,
|
|
1292
|
+
className: "inline-flex items-center gap-0.5 text-[10px] text-muted-foreground/60 hover:text-muted-foreground px-1 py-0.5 rounded hover:bg-muted/50 transition-colors",
|
|
1293
|
+
title: "Expand all",
|
|
1294
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsUpDown, { className: "w-3 h-3" })
|
|
1295
|
+
}
|
|
1296
|
+
)
|
|
1297
|
+
] })
|
|
1298
|
+
] }),
|
|
1299
|
+
filteredEntries.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[10px] text-muted-foreground/50 py-2 text-center", children: "No entries match the selected filters" }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-0.5", children: agentRuns.map((run, i) => {
|
|
1300
|
+
const runKey = `${run.agentName}-${i}`;
|
|
1301
|
+
const defaultCollapsed = run.depth > 0;
|
|
1302
|
+
const isCollapsed = collapsedRuns.has(runKey) ? true : collapsedRuns.has(`${runKey}:expanded`) ? false : defaultCollapsed;
|
|
1303
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1304
|
+
TimelineAgentBlock,
|
|
1305
|
+
{
|
|
1306
|
+
block: run,
|
|
1307
|
+
renderMarkdown,
|
|
1308
|
+
isSingleAgent: isSingle,
|
|
1309
|
+
isCollapsed,
|
|
1310
|
+
onToggleCollapsed: () => {
|
|
1311
|
+
if (isCollapsed) {
|
|
1312
|
+
collapsedRuns.delete(runKey);
|
|
1313
|
+
collapsedRuns.add(`${runKey}:expanded`);
|
|
1314
|
+
} else {
|
|
1315
|
+
collapsedRuns.delete(`${runKey}:expanded`);
|
|
1316
|
+
collapsedRuns.add(runKey);
|
|
1317
|
+
}
|
|
1318
|
+
forceRender();
|
|
1319
|
+
},
|
|
1320
|
+
expandedItems,
|
|
1321
|
+
onToggleItemExpanded: toggleItemExpanded
|
|
1322
|
+
},
|
|
1323
|
+
runKey
|
|
1324
|
+
);
|
|
1325
|
+
}) })
|
|
1326
|
+
]
|
|
1327
|
+
}
|
|
1328
|
+
);
|
|
1329
|
+
}
|
|
1330
|
+
var AgentResponse = React11__namespace.forwardRef(
|
|
548
1331
|
({
|
|
549
1332
|
state,
|
|
550
1333
|
id,
|
|
@@ -556,15 +1339,20 @@ var AgentResponse = React7__namespace.forwardRef(
|
|
|
556
1339
|
thinkingExpanded: controlledThinkingExpanded,
|
|
557
1340
|
onThinkingExpandedChange,
|
|
558
1341
|
actionsVisible = "hover",
|
|
1342
|
+
hitlInteractions,
|
|
1343
|
+
defaultHITLExpanded = false,
|
|
1344
|
+
statusContent,
|
|
559
1345
|
renderMarkdown,
|
|
560
1346
|
renderThinkingMarkdown,
|
|
1347
|
+
timelineMaxHeight,
|
|
561
1348
|
className,
|
|
562
1349
|
...props
|
|
563
1350
|
}, ref) => {
|
|
564
|
-
const
|
|
1351
|
+
const timelineUIStateRef = React11.useRef(createTimelineUIState());
|
|
1352
|
+
const [uncontrolledExpanded, setUncontrolledExpanded] = React11.useState(defaultThinkingExpanded);
|
|
565
1353
|
const isThinkingControlled = controlledThinkingExpanded !== void 0;
|
|
566
1354
|
const thinkingExpanded = isThinkingControlled ? controlledThinkingExpanded : uncontrolledExpanded;
|
|
567
|
-
const toggleThinking =
|
|
1355
|
+
const toggleThinking = React11.useCallback(() => {
|
|
568
1356
|
const newValue = !thinkingExpanded;
|
|
569
1357
|
if (isThinkingControlled) {
|
|
570
1358
|
onThinkingExpandedChange?.(newValue);
|
|
@@ -572,18 +1360,20 @@ var AgentResponse = React7__namespace.forwardRef(
|
|
|
572
1360
|
setUncontrolledExpanded(newValue);
|
|
573
1361
|
}
|
|
574
1362
|
}, [thinkingExpanded, isThinkingControlled, onThinkingExpandedChange]);
|
|
575
|
-
const [isHovered, setIsHovered] =
|
|
1363
|
+
const [isHovered, setIsHovered] = React11.useState(false);
|
|
576
1364
|
const elapsedTime = useThinkingTimer({
|
|
577
1365
|
startTime: state.thinkingStartTime,
|
|
578
1366
|
endTime: state.responseCompleteTime,
|
|
579
1367
|
status: state.status
|
|
580
1368
|
});
|
|
581
|
-
const totalTimeSeconds =
|
|
1369
|
+
const totalTimeSeconds = React11.useMemo(() => {
|
|
582
1370
|
if (!state.firstMessageTime || !state.responseCompleteTime) return 0;
|
|
583
1371
|
return (state.responseCompleteTime - state.firstMessageTime) / 1e3;
|
|
584
1372
|
}, [state.firstMessageTime, state.responseCompleteTime]);
|
|
585
|
-
const
|
|
586
|
-
const
|
|
1373
|
+
const hasTimelineEntries = !!(state.timelineEntries && state.timelineEntries.length > 0);
|
|
1374
|
+
const hasThinkingContent = !!state.thinking || state.thinkingSteps && state.thinkingSteps.length > 0 || hasTimelineEntries || false;
|
|
1375
|
+
const hasHITLInteractions = hitlInteractions && hitlInteractions.length > 0;
|
|
1376
|
+
const hasAnyContent = hasThinkingContent || state.toolCalls.length > 0 || state.knowledge.length > 0 || state.memory.length > 0 || state.statusUpdates.length > 0 || hasHITLInteractions || state.response;
|
|
587
1377
|
const showMetadataRow = hasThinkingContent || state.toolCalls.length > 0 || state.knowledge.length > 0 || state.memory.length > 0 || state.statusUpdates.length > 0 || state.status === "processing";
|
|
588
1378
|
const showActionBar = state.status === "complete" && state.response;
|
|
589
1379
|
const isActionBarVisible = actionsVisible === true || actionsVisible === "hover" && isHovered;
|
|
@@ -611,11 +1401,20 @@ var AgentResponse = React7__namespace.forwardRef(
|
|
|
611
1401
|
knowledge: state.knowledge,
|
|
612
1402
|
memory: state.memory,
|
|
613
1403
|
statusUpdates: state.statusUpdates,
|
|
1404
|
+
statusContent,
|
|
614
1405
|
status: state.status,
|
|
615
1406
|
elapsedTime
|
|
616
1407
|
}
|
|
617
1408
|
),
|
|
618
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1409
|
+
hasTimelineEntries ? thinkingExpanded && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pb-3 border-t border-border", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1410
|
+
AgentTimeline,
|
|
1411
|
+
{
|
|
1412
|
+
entries: state.timelineEntries,
|
|
1413
|
+
renderMarkdown: renderThinkingMarkdown,
|
|
1414
|
+
uiState: timelineUIStateRef.current,
|
|
1415
|
+
maxHeight: timelineMaxHeight
|
|
1416
|
+
}
|
|
1417
|
+
) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
619
1418
|
ThinkingSection,
|
|
620
1419
|
{
|
|
621
1420
|
content: state.thinkingSteps && state.thinkingSteps.length > 0 ? state.thinkingSteps : state.thinking,
|
|
@@ -624,6 +1423,13 @@ var AgentResponse = React7__namespace.forwardRef(
|
|
|
624
1423
|
}
|
|
625
1424
|
)
|
|
626
1425
|
] }),
|
|
1426
|
+
hasHITLInteractions && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1427
|
+
HITLSection,
|
|
1428
|
+
{
|
|
1429
|
+
interactions: hitlInteractions,
|
|
1430
|
+
defaultExpanded: defaultHITLExpanded
|
|
1431
|
+
}
|
|
1432
|
+
),
|
|
627
1433
|
state.response && /* @__PURE__ */ jsxRuntime.jsx(
|
|
628
1434
|
"div",
|
|
629
1435
|
{
|
|
@@ -652,7 +1458,7 @@ var AgentResponse = React7__namespace.forwardRef(
|
|
|
652
1458
|
}
|
|
653
1459
|
);
|
|
654
1460
|
AgentResponse.displayName = "AgentResponse";
|
|
655
|
-
var UserPrompt =
|
|
1461
|
+
var UserPrompt = React11__namespace.forwardRef(
|
|
656
1462
|
({ content, timestamp, className, ...props }, ref) => {
|
|
657
1463
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
658
1464
|
"div",
|
|
@@ -751,7 +1557,7 @@ function CodeBlockLeaf({ attributes, children, leaf }) {
|
|
|
751
1557
|
}
|
|
752
1558
|
return /* @__PURE__ */ jsxRuntime.jsx("span", { ...attributes, children });
|
|
753
1559
|
}
|
|
754
|
-
var UserPromptInput =
|
|
1560
|
+
var UserPromptInput = React11__namespace.forwardRef(
|
|
755
1561
|
({
|
|
756
1562
|
value = "",
|
|
757
1563
|
onChange,
|
|
@@ -761,6 +1567,8 @@ var UserPromptInput = React7__namespace.forwardRef(
|
|
|
761
1567
|
disabled = false,
|
|
762
1568
|
isSubmitting = false,
|
|
763
1569
|
onStop,
|
|
1570
|
+
stopTooltip,
|
|
1571
|
+
stopClassName,
|
|
764
1572
|
disableWhileSubmitting = true,
|
|
765
1573
|
autoFocus = false,
|
|
766
1574
|
refocusAfterSubmit = false,
|
|
@@ -774,14 +1582,14 @@ var UserPromptInput = React7__namespace.forwardRef(
|
|
|
774
1582
|
className,
|
|
775
1583
|
...props
|
|
776
1584
|
}, ref) => {
|
|
777
|
-
const editorRef =
|
|
778
|
-
const [internalValue, setInternalValue] =
|
|
779
|
-
const prevIsSubmitting =
|
|
780
|
-
const hasEmittedReady =
|
|
781
|
-
|
|
1585
|
+
const editorRef = React11__namespace.useRef(null);
|
|
1586
|
+
const [internalValue, setInternalValue] = React11__namespace.useState(value);
|
|
1587
|
+
const prevIsSubmitting = React11__namespace.useRef(isSubmitting);
|
|
1588
|
+
const hasEmittedReady = React11__namespace.useRef(false);
|
|
1589
|
+
React11__namespace.useEffect(() => {
|
|
782
1590
|
setInternalValue(value);
|
|
783
1591
|
}, [value]);
|
|
784
|
-
|
|
1592
|
+
React11__namespace.useEffect(() => {
|
|
785
1593
|
if (autoFocus) {
|
|
786
1594
|
requestAnimationFrame(() => {
|
|
787
1595
|
requestAnimationFrame(() => {
|
|
@@ -790,7 +1598,7 @@ var UserPromptInput = React7__namespace.forwardRef(
|
|
|
790
1598
|
});
|
|
791
1599
|
}
|
|
792
1600
|
}, [autoFocus]);
|
|
793
|
-
|
|
1601
|
+
React11__namespace.useEffect(() => {
|
|
794
1602
|
if (!hasEmittedReady.current && onReady) {
|
|
795
1603
|
requestAnimationFrame(() => {
|
|
796
1604
|
requestAnimationFrame(() => {
|
|
@@ -800,7 +1608,7 @@ var UserPromptInput = React7__namespace.forwardRef(
|
|
|
800
1608
|
});
|
|
801
1609
|
}
|
|
802
1610
|
}, [onReady]);
|
|
803
|
-
|
|
1611
|
+
React11__namespace.useEffect(() => {
|
|
804
1612
|
if (refocusAfterSubmit && prevIsSubmitting.current && !isSubmitting) {
|
|
805
1613
|
requestAnimationFrame(() => {
|
|
806
1614
|
editorRef.current?.focus();
|
|
@@ -808,7 +1616,7 @@ var UserPromptInput = React7__namespace.forwardRef(
|
|
|
808
1616
|
}
|
|
809
1617
|
prevIsSubmitting.current = isSubmitting;
|
|
810
1618
|
}, [isSubmitting, refocusAfterSubmit]);
|
|
811
|
-
|
|
1619
|
+
React11__namespace.useImperativeHandle(
|
|
812
1620
|
ref,
|
|
813
1621
|
() => ({
|
|
814
1622
|
focus: () => {
|
|
@@ -831,14 +1639,14 @@ var UserPromptInput = React7__namespace.forwardRef(
|
|
|
831
1639
|
}),
|
|
832
1640
|
[]
|
|
833
1641
|
);
|
|
834
|
-
const handleChange =
|
|
1642
|
+
const handleChange = React11__namespace.useCallback(
|
|
835
1643
|
(newValue) => {
|
|
836
1644
|
setInternalValue(newValue);
|
|
837
1645
|
onChange?.(newValue);
|
|
838
1646
|
},
|
|
839
1647
|
[onChange]
|
|
840
1648
|
);
|
|
841
|
-
const handleSubmit =
|
|
1649
|
+
const handleSubmit = React11__namespace.useCallback(
|
|
842
1650
|
(text) => {
|
|
843
1651
|
if (disabled || isSubmitting) return;
|
|
844
1652
|
if (!text.trim()) return;
|
|
@@ -850,7 +1658,7 @@ var UserPromptInput = React7__namespace.forwardRef(
|
|
|
850
1658
|
},
|
|
851
1659
|
[disabled, isSubmitting, onSubmit, clearOnSubmit]
|
|
852
1660
|
);
|
|
853
|
-
const handleSendClick =
|
|
1661
|
+
const handleSendClick = React11__namespace.useCallback(() => {
|
|
854
1662
|
const text = editorRef.current?.getText() ?? "";
|
|
855
1663
|
handleSubmit(text);
|
|
856
1664
|
}, [handleSubmit]);
|
|
@@ -887,16 +1695,17 @@ var UserPromptInput = React7__namespace.forwardRef(
|
|
|
887
1695
|
) }),
|
|
888
1696
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between pl-2 pr-1 pb-1 pt-1", children: [
|
|
889
1697
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1", children: renderActions?.() }),
|
|
890
|
-
isSubmitting && onStop ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1698
|
+
isSubmitting && onStop ? /* @__PURE__ */ jsxRuntime.jsx(core.Tooltip, { content: stopTooltip, disabled: !stopTooltip, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
891
1699
|
core.IconButton,
|
|
892
1700
|
{
|
|
893
1701
|
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Square, {}),
|
|
894
1702
|
variant: "filled",
|
|
895
1703
|
size: "sm",
|
|
896
|
-
"aria-label": "Stop",
|
|
897
|
-
onClick: onStop
|
|
1704
|
+
"aria-label": stopTooltip || "Stop",
|
|
1705
|
+
onClick: onStop,
|
|
1706
|
+
className: stopClassName
|
|
898
1707
|
}
|
|
899
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1708
|
+
) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
900
1709
|
core.IconButton,
|
|
901
1710
|
{
|
|
902
1711
|
icon: isSubmitting ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, {}),
|
|
@@ -915,16 +1724,138 @@ var UserPromptInput = React7__namespace.forwardRef(
|
|
|
915
1724
|
);
|
|
916
1725
|
UserPromptInput.displayName = "UserPromptInput";
|
|
917
1726
|
|
|
1727
|
+
// src/components/inline-actions/parseResponseSegments.ts
|
|
1728
|
+
var ACTION_BLOCK_REGEX = /```json:action\s*\n([\s\S]*?)```/g;
|
|
1729
|
+
function parseResponseSegments(text) {
|
|
1730
|
+
if (!text) return [];
|
|
1731
|
+
const segments = [];
|
|
1732
|
+
let lastIndex = 0;
|
|
1733
|
+
ACTION_BLOCK_REGEX.lastIndex = 0;
|
|
1734
|
+
let match;
|
|
1735
|
+
while ((match = ACTION_BLOCK_REGEX.exec(text)) !== null) {
|
|
1736
|
+
const before = text.slice(lastIndex, match.index);
|
|
1737
|
+
if (before.trim()) {
|
|
1738
|
+
segments.push({ kind: "markdown", content: before });
|
|
1739
|
+
}
|
|
1740
|
+
const jsonContent = match[1].trim();
|
|
1741
|
+
let parsed = null;
|
|
1742
|
+
try {
|
|
1743
|
+
parsed = JSON.parse(jsonContent);
|
|
1744
|
+
} catch {
|
|
1745
|
+
}
|
|
1746
|
+
if (parsed && typeof parsed === "object" && typeof parsed.type === "string") {
|
|
1747
|
+
segments.push({
|
|
1748
|
+
kind: "action",
|
|
1749
|
+
actionType: parsed.type,
|
|
1750
|
+
payload: parsed
|
|
1751
|
+
});
|
|
1752
|
+
} else {
|
|
1753
|
+
const rawBlock = match[0];
|
|
1754
|
+
segments.push({ kind: "markdown", content: rawBlock });
|
|
1755
|
+
}
|
|
1756
|
+
lastIndex = match.index + match[0].length;
|
|
1757
|
+
}
|
|
1758
|
+
const trailing = text.slice(lastIndex);
|
|
1759
|
+
if (trailing.trim()) {
|
|
1760
|
+
segments.push({ kind: "markdown", content: trailing });
|
|
1761
|
+
}
|
|
1762
|
+
return segments;
|
|
1763
|
+
}
|
|
1764
|
+
function ActionMarkdownRenderer({
|
|
1765
|
+
content,
|
|
1766
|
+
registry,
|
|
1767
|
+
renderMarkdown,
|
|
1768
|
+
onAction,
|
|
1769
|
+
isLatest
|
|
1770
|
+
}) {
|
|
1771
|
+
const segments = React11.useMemo(() => parseResponseSegments(content), [content]);
|
|
1772
|
+
if (segments.length === 1 && segments[0].kind === "markdown") {
|
|
1773
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: renderMarkdown(segments[0].content) });
|
|
1774
|
+
}
|
|
1775
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: segments.map((segment, index) => {
|
|
1776
|
+
if (segment.kind === "markdown") {
|
|
1777
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { children: renderMarkdown(segment.content) }, `md-${index}`);
|
|
1778
|
+
}
|
|
1779
|
+
const Component = registry[segment.actionType];
|
|
1780
|
+
if (!Component) {
|
|
1781
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1782
|
+
"pre",
|
|
1783
|
+
{
|
|
1784
|
+
className: "my-4 p-4 rounded-lg border border-border bg-muted text-sm font-mono overflow-x-auto",
|
|
1785
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: JSON.stringify(segment.payload, null, 2) })
|
|
1786
|
+
},
|
|
1787
|
+
`action-fallback-${index}`
|
|
1788
|
+
);
|
|
1789
|
+
}
|
|
1790
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1791
|
+
Component,
|
|
1792
|
+
{
|
|
1793
|
+
payload: segment.payload,
|
|
1794
|
+
onAction,
|
|
1795
|
+
isLatest
|
|
1796
|
+
},
|
|
1797
|
+
`action-${segment.actionType}-${index}`
|
|
1798
|
+
);
|
|
1799
|
+
}) });
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
// src/components/inline-actions/prompts.ts
|
|
1803
|
+
var INLINE_ACTION_PROMPT = `
|
|
1804
|
+
<inline_actions>
|
|
1805
|
+
When your response should include interactive components (like query viewers,
|
|
1806
|
+
data tables, or executable actions), embed them as fenced code blocks using
|
|
1807
|
+
the \`json:action\` language tag:
|
|
1808
|
+
|
|
1809
|
+
\`\`\`json:action
|
|
1810
|
+
{
|
|
1811
|
+
"type": "action-type-here",
|
|
1812
|
+
...action-specific fields
|
|
1813
|
+
}
|
|
1814
|
+
\`\`\`
|
|
1815
|
+
|
|
1816
|
+
Rules:
|
|
1817
|
+
- Each block must contain valid JSON with a "type" field.
|
|
1818
|
+
- The "type" must match a registered action component on the frontend.
|
|
1819
|
+
- Multiple action blocks per response are allowed.
|
|
1820
|
+
- Surround action blocks with normal markdown text for user context.
|
|
1821
|
+
- The action block is rendered as an interactive component in the chat UI.
|
|
1822
|
+
- SQL strings inside JSON must be properly escaped (newlines as \\n, quotes as \\").
|
|
1823
|
+
|
|
1824
|
+
Available action types:
|
|
1825
|
+
|
|
1826
|
+
- "optimap-query": Displays SQL queries with a button to execute them and
|
|
1827
|
+
update the 3D globe map.
|
|
1828
|
+
Required fields:
|
|
1829
|
+
- type: "optimap-query"
|
|
1830
|
+
- locations_sql: string (the validated locations SQL query)
|
|
1831
|
+
- routes_sql: string (the validated routes SQL query)
|
|
1832
|
+
- database_name: string (the target database name)
|
|
1833
|
+
</inline_actions>
|
|
1834
|
+
`;
|
|
1835
|
+
|
|
918
1836
|
exports.ActionBar = ActionBar;
|
|
1837
|
+
exports.ActionMarkdownRenderer = ActionMarkdownRenderer;
|
|
919
1838
|
exports.ActivityIndicators = ActivityIndicators;
|
|
920
1839
|
exports.AgentResponse = AgentResponse;
|
|
1840
|
+
exports.AgentTimeline = AgentTimeline;
|
|
1841
|
+
exports.HITLInteractionRecord = HITLInteractionRecord;
|
|
1842
|
+
exports.HITLQuestionPanel = HITLQuestionPanel;
|
|
1843
|
+
exports.HITLSection = HITLSection;
|
|
1844
|
+
exports.INLINE_ACTION_PROMPT = INLINE_ACTION_PROMPT;
|
|
921
1845
|
exports.MetadataRow = MetadataRow;
|
|
922
1846
|
exports.ThinkingSection = ThinkingSection;
|
|
1847
|
+
exports.TruncatedMessage = TruncatedMessage;
|
|
923
1848
|
exports.UserPrompt = UserPrompt;
|
|
924
1849
|
exports.UserPromptInput = UserPromptInput;
|
|
1850
|
+
exports.buildResponseString = buildResponseString;
|
|
1851
|
+
exports.buildTimelineEntries = buildTimelineEntries;
|
|
1852
|
+
exports.createTimelineUIState = createTimelineUIState;
|
|
1853
|
+
exports.deduplicateEntries = deduplicateEntries;
|
|
925
1854
|
exports.formatTime = formatTime;
|
|
926
1855
|
exports.formatTotalTime = formatTotalTime;
|
|
1856
|
+
exports.groupIntoAgentRuns = groupIntoAgentRuns;
|
|
927
1857
|
exports.initialAgentResponseState = initialAgentResponseState;
|
|
1858
|
+
exports.parseResponseSegments = parseResponseSegments;
|
|
928
1859
|
exports.useAgentResponseAccumulator = useAgentResponseAccumulator;
|
|
929
1860
|
exports.useThinkingTimer = useThinkingTimer;
|
|
930
1861
|
//# sourceMappingURL=index.cjs.map
|