@optilogic/chat 1.0.0-beta.1 → 1.0.0-beta.10

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/dist/index.cjs CHANGED
@@ -1,9 +1,10 @@
1
1
  'use strict';
2
2
 
3
- var React = require('react');
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');
7
+ var editor = require('@optilogic/editor');
7
8
 
8
9
  function _interopNamespace(e) {
9
10
  if (e && e.__esModule) return e;
@@ -23,14 +24,34 @@ function _interopNamespace(e) {
23
24
  return Object.freeze(n);
24
25
  }
25
26
 
26
- var React__namespace = /*#__PURE__*/_interopNamespace(React);
27
+ var React11__namespace = /*#__PURE__*/_interopNamespace(React11);
27
28
 
28
29
  // src/components/agent-response/AgentResponse.tsx
29
- var ActivityIndicators = React__namespace.forwardRef(
30
- ({ toolCalls, knowledge, memory, className, ...props }, ref) => {
31
- const hasAnyActivity = toolCalls.length > 0 || knowledge.length > 0 || memory.length > 0;
30
+ var ActivityIndicators = React11__namespace.forwardRef(
31
+ ({ toolCalls, knowledge, memory, statusUpdates = [], className, ...props }, ref) => {
32
+ const hasAnyActivity = toolCalls.length > 0 || knowledge.length > 0 || memory.length > 0 || statusUpdates.length > 0;
32
33
  if (!hasAnyActivity) return null;
33
34
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: core.cn("flex items-center gap-2", className), ...props, children: [
35
+ statusUpdates.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(core.Popover, { children: [
36
+ /* @__PURE__ */ jsxRuntime.jsx(core.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
37
+ "button",
38
+ {
39
+ className: "flex items-center gap-1 text-muted-foreground hover:text-foreground transition-colors",
40
+ onClick: (e) => e.stopPropagation(),
41
+ children: [
42
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Activity, { className: "w-3.5 h-3.5" }),
43
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs", children: statusUpdates.length })
44
+ ]
45
+ }
46
+ ) }),
47
+ /* @__PURE__ */ jsxRuntime.jsx(core.PopoverContent, { className: "w-80", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
48
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "font-medium text-sm", children: "Status Updates" }),
49
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2 max-h-60 overflow-auto", children: statusUpdates.map((item) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-2 bg-muted rounded text-xs", children: [
50
+ item.agent && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium text-muted-foreground", children: item.agent }),
51
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: item.agent ? "mt-1" : "", children: item.message })
52
+ ] }, item.id)) })
53
+ ] }) })
54
+ ] }),
34
55
  toolCalls.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(core.Popover, { children: [
35
56
  /* @__PURE__ */ jsxRuntime.jsx(core.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
36
57
  "button",
@@ -125,7 +146,7 @@ function formatTotalTime(seconds) {
125
146
  const minutes = seconds / 60;
126
147
  return `${minutes.toFixed(1)}m`;
127
148
  }
128
- var MetadataRow = React__namespace.forwardRef(
149
+ var MetadataRow = React11__namespace.forwardRef(
129
150
  ({
130
151
  hasThinking,
131
152
  isExpanded,
@@ -133,6 +154,8 @@ var MetadataRow = React__namespace.forwardRef(
133
154
  toolCalls,
134
155
  knowledge,
135
156
  memory,
157
+ statusUpdates = [],
158
+ statusContent,
136
159
  status,
137
160
  elapsedTime,
138
161
  className,
@@ -140,7 +163,7 @@ var MetadataRow = React__namespace.forwardRef(
140
163
  }, ref) => {
141
164
  const isProcessing = status === "processing";
142
165
  const isComplete = status === "complete";
143
- const hasActivity = toolCalls.length > 0 || knowledge.length > 0 || memory.length > 0;
166
+ const hasActivity = toolCalls.length > 0 || knowledge.length > 0 || memory.length > 0 || statusUpdates.length > 0;
144
167
  const renderLeftContent = () => {
145
168
  if (hasThinking) {
146
169
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
@@ -157,7 +180,7 @@ var MetadataRow = React__namespace.forwardRef(
157
180
  return null;
158
181
  };
159
182
  const leftContent = renderLeftContent();
160
- if (!leftContent && !hasActivity) {
183
+ if (!leftContent && !hasActivity && !statusContent) {
161
184
  return null;
162
185
  }
163
186
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -171,16 +194,18 @@ var MetadataRow = React__namespace.forwardRef(
171
194
  "button",
172
195
  {
173
196
  onClick: onToggle,
174
- 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",
175
198
  children: leftContent
176
199
  }
177
- ) : /* @__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 }),
178
202
  /* @__PURE__ */ jsxRuntime.jsx(
179
203
  ActivityIndicators,
180
204
  {
181
205
  toolCalls,
182
206
  knowledge,
183
- memory
207
+ memory,
208
+ statusUpdates
184
209
  }
185
210
  )
186
211
  ]
@@ -189,24 +214,61 @@ var MetadataRow = React__namespace.forwardRef(
189
214
  }
190
215
  );
191
216
  MetadataRow.displayName = "MetadataRow";
192
- var ThinkingSection = React__namespace.forwardRef(
193
- ({ content, isExpanded, className, ...props }, ref) => {
194
- if (!isExpanded || !content) {
217
+ var ThinkingStepItem = ({ step, renderMarkdown }) => {
218
+ const [isCollapsed, setIsCollapsed] = React11.useState(step.isCollapsed ?? false);
219
+ const toggleCollapse = React11.useCallback(() => {
220
+ setIsCollapsed((prev) => !prev);
221
+ }, []);
222
+ const indentPadding = step.depth * 16;
223
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-b border-border/50 last:border-b-0", children: [
224
+ /* @__PURE__ */ jsxRuntime.jsxs(
225
+ "button",
226
+ {
227
+ onClick: toggleCollapse,
228
+ className: "w-full flex items-center gap-1.5 py-1.5 px-2 hover:bg-muted/50 transition-colors text-left",
229
+ style: { paddingLeft: `${indentPadding + 8}px` },
230
+ children: [
231
+ 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" }),
232
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-foreground/80", children: step.label })
233
+ ]
234
+ }
235
+ ),
236
+ !isCollapsed && /* @__PURE__ */ jsxRuntime.jsx(
237
+ "div",
238
+ {
239
+ className: "pb-2 px-2",
240
+ style: { paddingLeft: `${indentPadding + 28}px` },
241
+ children: renderMarkdown ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground", children: renderMarkdown(step.content) }) : /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "text-xs text-muted-foreground whitespace-pre-wrap font-mono", children: step.content })
242
+ }
243
+ )
244
+ ] });
245
+ };
246
+ var ThinkingSection = React11__namespace.forwardRef(
247
+ ({ content, isExpanded, renderMarkdown, className, ...props }, ref) => {
248
+ if (!isExpanded || !content || Array.isArray(content) && content.length === 0) {
195
249
  return null;
196
250
  }
251
+ const isStructured = Array.isArray(content);
197
252
  return /* @__PURE__ */ jsxRuntime.jsx(
198
253
  "div",
199
254
  {
200
255
  ref,
201
256
  className: core.cn("px-3 pb-3 border-t border-border", className),
202
257
  ...props,
203
- children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 max-h-[200px] overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "text-xs text-muted-foreground whitespace-pre-wrap font-mono", children: content }) })
258
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 max-h-[200px] overflow-y-auto", children: isStructured ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-0", children: content.map((step) => /* @__PURE__ */ jsxRuntime.jsx(
259
+ ThinkingStepItem,
260
+ {
261
+ step,
262
+ renderMarkdown
263
+ },
264
+ step.id
265
+ )) }) : renderMarkdown ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground", children: renderMarkdown(content) }) : /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "text-xs text-muted-foreground whitespace-pre-wrap font-mono", children: content }) })
204
266
  }
205
267
  );
206
268
  }
207
269
  );
208
270
  ThinkingSection.displayName = "ThinkingSection";
209
- var ActionBar = React__namespace.forwardRef(
271
+ var ActionBar = React11__namespace.forwardRef(
210
272
  ({
211
273
  response,
212
274
  isVisible,
@@ -217,8 +279,8 @@ var ActionBar = React__namespace.forwardRef(
217
279
  className,
218
280
  ...props
219
281
  }, ref) => {
220
- const [copied, setCopied] = React.useState(false);
221
- const handleCopy = React.useCallback(async () => {
282
+ const [copied, setCopied] = React11.useState(false);
283
+ const handleCopy = React11.useCallback(async () => {
222
284
  try {
223
285
  await navigator.clipboard.writeText(response);
224
286
  setCopied(true);
@@ -228,11 +290,11 @@ var ActionBar = React__namespace.forwardRef(
228
290
  console.error("Failed to copy response:", err);
229
291
  }
230
292
  }, [response, onResponseCopy]);
231
- const handleThumbsUp = React.useCallback(() => {
293
+ const handleThumbsUp = React11.useCallback(() => {
232
294
  const newValue = feedback === "up" ? null : "up";
233
295
  onFeedbackChange?.(newValue);
234
296
  }, [feedback, onFeedbackChange]);
235
- const handleThumbsDown = React.useCallback(() => {
297
+ const handleThumbsDown = React11.useCallback(() => {
236
298
  const newValue = feedback === "down" ? null : "down";
237
299
  onFeedbackChange?.(newValue);
238
300
  }, [feedback, onFeedbackChange]);
@@ -295,13 +357,320 @@ var ActionBar = React__namespace.forwardRef(
295
357
  }
296
358
  );
297
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);
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";
298
667
  function useThinkingTimer({
299
668
  startTime,
300
669
  endTime,
301
670
  status
302
671
  }) {
303
- const [elapsed, setElapsed] = React.useState(0);
304
- React.useEffect(() => {
672
+ const [elapsed, setElapsed] = React11.useState(0);
673
+ React11.useEffect(() => {
305
674
  if (!startTime) {
306
675
  setElapsed(0);
307
676
  return;
@@ -329,6 +698,7 @@ var initialAgentResponseState = {
329
698
  toolCalls: [],
330
699
  knowledge: [],
331
700
  memory: [],
701
+ statusUpdates: [],
332
702
  response: "",
333
703
  thinkingStartTime: null,
334
704
  responseCompleteTime: null,
@@ -337,9 +707,9 @@ var initialAgentResponseState = {
337
707
 
338
708
  // src/components/agent-response/hooks/useAgentResponseAccumulator.ts
339
709
  function useAgentResponseAccumulator(options) {
340
- const [state, setState] = React.useState(initialAgentResponseState);
710
+ const [state, setState] = React11.useState(initialAgentResponseState);
341
711
  const topic = options?.topic;
342
- const handleMessage = React.useCallback(
712
+ const handleMessage = React11.useCallback(
343
713
  (message) => {
344
714
  let payload;
345
715
  if (topic) {
@@ -363,6 +733,23 @@ function useAgentResponseAccumulator(options) {
363
733
  }
364
734
  return { ...prev, status: newStatus };
365
735
  case "thinking": {
736
+ if (payload.thinkingStep) {
737
+ const newStep = {
738
+ id: payload.thinkingStep.id || `step-${Date.now()}`,
739
+ label: payload.thinkingStep.label,
740
+ content: payload.thinkingStep.content,
741
+ depth: payload.thinkingStep.depth ?? 0,
742
+ isCollapsed: payload.thinkingStep.isCollapsed
743
+ };
744
+ const thinkingStartTime2 = prev.thinkingStartTime ?? Date.now();
745
+ return {
746
+ ...prev,
747
+ status: newStatus,
748
+ thinkingSteps: [...prev.thinkingSteps || [], newStep],
749
+ thinkingStartTime: thinkingStartTime2,
750
+ firstMessageTime
751
+ };
752
+ }
366
753
  const newThinking = payload.message || payload.content || "";
367
754
  const separator = prev.thinking && newThinking ? "\n\n" : "";
368
755
  const thinkingStartTime = prev.thinkingStartTime ?? (newThinking ? Date.now() : null);
@@ -436,6 +823,24 @@ function useAgentResponseAccumulator(options) {
436
823
  responseCompleteTime: Date.now(),
437
824
  firstMessageTime: prev.firstMessageTime ?? Date.now()
438
825
  };
826
+ case "status_update": {
827
+ const statusMessage = payload.message || payload.statusUpdate?.message;
828
+ if (statusMessage) {
829
+ const newStatusItem = {
830
+ id: payload.statusUpdate?.id || `status-${Date.now()}`,
831
+ message: statusMessage,
832
+ agent: payload.statusUpdate?.agent,
833
+ timestamp: Date.now()
834
+ };
835
+ return {
836
+ ...prev,
837
+ status: newStatus,
838
+ statusUpdates: [...prev.statusUpdates, newStatusItem],
839
+ firstMessageTime
840
+ };
841
+ }
842
+ return { ...prev, status: newStatus, firstMessageTime };
843
+ }
439
844
  default:
440
845
  return { ...prev, status: newStatus, firstMessageTime };
441
846
  }
@@ -443,12 +848,12 @@ function useAgentResponseAccumulator(options) {
443
848
  },
444
849
  [topic]
445
850
  );
446
- const reset = React.useCallback(() => {
851
+ const reset = React11.useCallback(() => {
447
852
  setState(initialAgentResponseState);
448
853
  }, []);
449
854
  return { state, handleMessage, reset };
450
855
  }
451
- var AgentResponse = React__namespace.forwardRef(
856
+ var AgentResponse = React11__namespace.forwardRef(
452
857
  ({
453
858
  state,
454
859
  id,
@@ -460,14 +865,18 @@ var AgentResponse = React__namespace.forwardRef(
460
865
  thinkingExpanded: controlledThinkingExpanded,
461
866
  onThinkingExpandedChange,
462
867
  actionsVisible = "hover",
868
+ hitlInteractions,
869
+ defaultHITLExpanded = false,
870
+ statusContent,
463
871
  renderMarkdown,
872
+ renderThinkingMarkdown,
464
873
  className,
465
874
  ...props
466
875
  }, ref) => {
467
- const [uncontrolledExpanded, setUncontrolledExpanded] = React.useState(defaultThinkingExpanded);
876
+ const [uncontrolledExpanded, setUncontrolledExpanded] = React11.useState(defaultThinkingExpanded);
468
877
  const isThinkingControlled = controlledThinkingExpanded !== void 0;
469
878
  const thinkingExpanded = isThinkingControlled ? controlledThinkingExpanded : uncontrolledExpanded;
470
- const toggleThinking = React.useCallback(() => {
879
+ const toggleThinking = React11.useCallback(() => {
471
880
  const newValue = !thinkingExpanded;
472
881
  if (isThinkingControlled) {
473
882
  onThinkingExpandedChange?.(newValue);
@@ -475,18 +884,20 @@ var AgentResponse = React__namespace.forwardRef(
475
884
  setUncontrolledExpanded(newValue);
476
885
  }
477
886
  }, [thinkingExpanded, isThinkingControlled, onThinkingExpandedChange]);
478
- const [isHovered, setIsHovered] = React.useState(false);
887
+ const [isHovered, setIsHovered] = React11.useState(false);
479
888
  const elapsedTime = useThinkingTimer({
480
889
  startTime: state.thinkingStartTime,
481
890
  endTime: state.responseCompleteTime,
482
891
  status: state.status
483
892
  });
484
- const totalTimeSeconds = React.useMemo(() => {
893
+ const totalTimeSeconds = React11.useMemo(() => {
485
894
  if (!state.firstMessageTime || !state.responseCompleteTime) return 0;
486
895
  return (state.responseCompleteTime - state.firstMessageTime) / 1e3;
487
896
  }, [state.firstMessageTime, state.responseCompleteTime]);
488
- const hasAnyContent = state.thinking || state.toolCalls.length > 0 || state.knowledge.length > 0 || state.memory.length > 0 || state.response;
489
- const showMetadataRow = state.thinking || state.toolCalls.length > 0 || state.knowledge.length > 0 || state.memory.length > 0 || state.status === "processing";
897
+ const hasThinkingContent = !!state.thinking || state.thinkingSteps && state.thinkingSteps.length > 0 || false;
898
+ const hasHITLInteractions = hitlInteractions && hitlInteractions.length > 0;
899
+ const hasAnyContent = hasThinkingContent || state.toolCalls.length > 0 || state.knowledge.length > 0 || state.memory.length > 0 || state.statusUpdates.length > 0 || hasHITLInteractions || state.response;
900
+ const showMetadataRow = hasThinkingContent || state.toolCalls.length > 0 || state.knowledge.length > 0 || state.memory.length > 0 || state.statusUpdates.length > 0 || state.status === "processing";
490
901
  const showActionBar = state.status === "complete" && state.response;
491
902
  const isActionBarVisible = actionsVisible === true || actionsVisible === "hover" && isHovered;
492
903
  if (!hasAnyContent) {
@@ -506,12 +917,14 @@ var AgentResponse = React__namespace.forwardRef(
506
917
  /* @__PURE__ */ jsxRuntime.jsx(
507
918
  MetadataRow,
508
919
  {
509
- hasThinking: !!state.thinking,
920
+ hasThinking: hasThinkingContent,
510
921
  isExpanded: thinkingExpanded,
511
922
  onToggle: toggleThinking,
512
923
  toolCalls: state.toolCalls,
513
924
  knowledge: state.knowledge,
514
925
  memory: state.memory,
926
+ statusUpdates: state.statusUpdates,
927
+ statusContent,
515
928
  status: state.status,
516
929
  elapsedTime
517
930
  }
@@ -519,11 +932,19 @@ var AgentResponse = React__namespace.forwardRef(
519
932
  /* @__PURE__ */ jsxRuntime.jsx(
520
933
  ThinkingSection,
521
934
  {
522
- content: state.thinking,
523
- isExpanded: thinkingExpanded
935
+ content: state.thinkingSteps && state.thinkingSteps.length > 0 ? state.thinkingSteps : state.thinking,
936
+ isExpanded: thinkingExpanded,
937
+ renderMarkdown: renderThinkingMarkdown
524
938
  }
525
939
  )
526
940
  ] }),
941
+ hasHITLInteractions && /* @__PURE__ */ jsxRuntime.jsx(
942
+ HITLSection,
943
+ {
944
+ interactions: hitlInteractions,
945
+ defaultExpanded: defaultHITLExpanded
946
+ }
947
+ ),
527
948
  state.response && /* @__PURE__ */ jsxRuntime.jsx(
528
949
  "div",
529
950
  {
@@ -552,12 +973,281 @@ var AgentResponse = React__namespace.forwardRef(
552
973
  }
553
974
  );
554
975
  AgentResponse.displayName = "AgentResponse";
976
+ var UserPrompt = React11__namespace.forwardRef(
977
+ ({ content, timestamp, className, ...props }, ref) => {
978
+ return /* @__PURE__ */ jsxRuntime.jsxs(
979
+ "div",
980
+ {
981
+ ref,
982
+ className: core.cn(
983
+ "w-fit max-w-[80%] rounded-lg px-4 pt-3.5 pb-3",
984
+ "bg-secondary text-secondary-foreground",
985
+ className
986
+ ),
987
+ ...props,
988
+ children: [
989
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "whitespace-pre-wrap", children: content }),
990
+ timestamp && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-secondary-foreground/70 mt-1", children: timestamp.toLocaleTimeString([], {
991
+ hour: "2-digit",
992
+ minute: "2-digit"
993
+ }) })
994
+ ]
995
+ }
996
+ );
997
+ }
998
+ );
999
+ UserPrompt.displayName = "UserPrompt";
1000
+ function createCodeBlockDecorate(entry) {
1001
+ const [node, path] = entry;
1002
+ const ranges = [];
1003
+ if (!editor.Text.isText(node)) {
1004
+ return ranges;
1005
+ }
1006
+ const { text } = node;
1007
+ const backtickPositions = [];
1008
+ let searchStart = 0;
1009
+ while (true) {
1010
+ const pos = text.indexOf("```", searchStart);
1011
+ if (pos === -1) break;
1012
+ backtickPositions.push(pos);
1013
+ searchStart = pos + 3;
1014
+ }
1015
+ let i = 0;
1016
+ while (i < backtickPositions.length) {
1017
+ const openPos = backtickPositions[i];
1018
+ const closePos = backtickPositions[i + 1];
1019
+ ranges.push({
1020
+ anchor: { path, offset: openPos },
1021
+ focus: { path, offset: openPos + 3 },
1022
+ codeDelimiter: true
1023
+ });
1024
+ if (closePos !== void 0) {
1025
+ if (closePos > openPos + 3) {
1026
+ ranges.push({
1027
+ anchor: { path, offset: openPos + 3 },
1028
+ focus: { path, offset: closePos },
1029
+ codeBlock: true
1030
+ });
1031
+ }
1032
+ ranges.push({
1033
+ anchor: { path, offset: closePos },
1034
+ focus: { path, offset: closePos + 3 },
1035
+ codeDelimiter: true
1036
+ });
1037
+ i += 2;
1038
+ } else {
1039
+ if (text.length > openPos + 3) {
1040
+ ranges.push({
1041
+ anchor: { path, offset: openPos + 3 },
1042
+ focus: { path, offset: text.length },
1043
+ codeBlock: true
1044
+ });
1045
+ }
1046
+ i += 1;
1047
+ }
1048
+ }
1049
+ return ranges;
1050
+ }
1051
+ function CodeBlockLeaf({ attributes, children, leaf }) {
1052
+ const leafAny = leaf;
1053
+ if (leafAny.codeBlock) {
1054
+ return /* @__PURE__ */ jsxRuntime.jsx(
1055
+ "span",
1056
+ {
1057
+ ...attributes,
1058
+ className: "bg-muted/50 text-muted-foreground font-mono text-sm rounded px-1",
1059
+ children
1060
+ }
1061
+ );
1062
+ }
1063
+ if (leafAny.codeDelimiter) {
1064
+ return /* @__PURE__ */ jsxRuntime.jsx(
1065
+ "span",
1066
+ {
1067
+ ...attributes,
1068
+ className: "text-muted-foreground/50 font-mono text-sm",
1069
+ children
1070
+ }
1071
+ );
1072
+ }
1073
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { ...attributes, children });
1074
+ }
1075
+ var UserPromptInput = React11__namespace.forwardRef(
1076
+ ({
1077
+ value = "",
1078
+ onChange,
1079
+ onSubmit,
1080
+ clearOnSubmit = true,
1081
+ placeholder = "Type your message...",
1082
+ disabled = false,
1083
+ isSubmitting = false,
1084
+ onStop,
1085
+ disableWhileSubmitting = true,
1086
+ autoFocus = false,
1087
+ refocusAfterSubmit = false,
1088
+ onReady,
1089
+ minRows = 1,
1090
+ maxRows = 6,
1091
+ renderActions,
1092
+ enableTags = false,
1093
+ onTagCreate,
1094
+ onTagDelete,
1095
+ className,
1096
+ ...props
1097
+ }, ref) => {
1098
+ const editorRef = React11__namespace.useRef(null);
1099
+ const [internalValue, setInternalValue] = React11__namespace.useState(value);
1100
+ const prevIsSubmitting = React11__namespace.useRef(isSubmitting);
1101
+ const hasEmittedReady = React11__namespace.useRef(false);
1102
+ React11__namespace.useEffect(() => {
1103
+ setInternalValue(value);
1104
+ }, [value]);
1105
+ React11__namespace.useEffect(() => {
1106
+ if (autoFocus) {
1107
+ requestAnimationFrame(() => {
1108
+ requestAnimationFrame(() => {
1109
+ editorRef.current?.focus();
1110
+ });
1111
+ });
1112
+ }
1113
+ }, [autoFocus]);
1114
+ React11__namespace.useEffect(() => {
1115
+ if (!hasEmittedReady.current && onReady) {
1116
+ requestAnimationFrame(() => {
1117
+ requestAnimationFrame(() => {
1118
+ hasEmittedReady.current = true;
1119
+ onReady();
1120
+ });
1121
+ });
1122
+ }
1123
+ }, [onReady]);
1124
+ React11__namespace.useEffect(() => {
1125
+ if (refocusAfterSubmit && prevIsSubmitting.current && !isSubmitting) {
1126
+ requestAnimationFrame(() => {
1127
+ editorRef.current?.focus();
1128
+ });
1129
+ }
1130
+ prevIsSubmitting.current = isSubmitting;
1131
+ }, [isSubmitting, refocusAfterSubmit]);
1132
+ React11__namespace.useImperativeHandle(
1133
+ ref,
1134
+ () => ({
1135
+ focus: () => {
1136
+ try {
1137
+ editorRef.current?.focus();
1138
+ } catch {
1139
+ requestAnimationFrame(() => {
1140
+ requestAnimationFrame(() => {
1141
+ editorRef.current?.focus();
1142
+ });
1143
+ });
1144
+ }
1145
+ },
1146
+ clear: () => {
1147
+ editorRef.current?.clear();
1148
+ setInternalValue("");
1149
+ },
1150
+ getText: () => editorRef.current?.getText() ?? "",
1151
+ insertText: (text) => editorRef.current?.insertText(text)
1152
+ }),
1153
+ []
1154
+ );
1155
+ const handleChange = React11__namespace.useCallback(
1156
+ (newValue) => {
1157
+ setInternalValue(newValue);
1158
+ onChange?.(newValue);
1159
+ },
1160
+ [onChange]
1161
+ );
1162
+ const handleSubmit = React11__namespace.useCallback(
1163
+ (text) => {
1164
+ if (disabled || isSubmitting) return;
1165
+ if (!text.trim()) return;
1166
+ onSubmit?.(text.trim());
1167
+ if (clearOnSubmit) {
1168
+ editorRef.current?.clear();
1169
+ setInternalValue("");
1170
+ }
1171
+ },
1172
+ [disabled, isSubmitting, onSubmit, clearOnSubmit]
1173
+ );
1174
+ const handleSendClick = React11__namespace.useCallback(() => {
1175
+ const text = editorRef.current?.getText() ?? "";
1176
+ handleSubmit(text);
1177
+ }, [handleSubmit]);
1178
+ const hasContent = internalValue.trim().length > 0;
1179
+ const canSubmit = hasContent && !disabled && !isSubmitting;
1180
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1181
+ "div",
1182
+ {
1183
+ className: core.cn(
1184
+ "rounded-lg border border-input bg-background",
1185
+ disabled && "opacity-50 cursor-not-allowed",
1186
+ className
1187
+ ),
1188
+ ...props,
1189
+ children: [
1190
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pl-2 pr-0 pt-1 pb-1", children: /* @__PURE__ */ jsxRuntime.jsx(
1191
+ editor.SlateEditor,
1192
+ {
1193
+ ref: editorRef,
1194
+ value: internalValue,
1195
+ onChange: handleChange,
1196
+ onSubmit: handleSubmit,
1197
+ clearOnSubmit: false,
1198
+ placeholder,
1199
+ disabled: disabled || disableWhileSubmitting && isSubmitting,
1200
+ enableTags,
1201
+ onTagCreate,
1202
+ onTagDelete,
1203
+ minRows,
1204
+ maxRows,
1205
+ decorate: createCodeBlockDecorate,
1206
+ renderLeaf: CodeBlockLeaf
1207
+ }
1208
+ ) }),
1209
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between pl-2 pr-1 pb-1 pt-1", children: [
1210
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1", children: renderActions?.() }),
1211
+ isSubmitting && onStop ? /* @__PURE__ */ jsxRuntime.jsx(
1212
+ core.IconButton,
1213
+ {
1214
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Square, {}),
1215
+ variant: "filled",
1216
+ size: "sm",
1217
+ "aria-label": "Stop",
1218
+ onClick: onStop
1219
+ }
1220
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
1221
+ core.IconButton,
1222
+ {
1223
+ icon: isSubmitting ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, {}),
1224
+ variant: "filled",
1225
+ size: "sm",
1226
+ "aria-label": isSubmitting ? "Sending..." : "Send message",
1227
+ disabled: !canSubmit,
1228
+ onClick: handleSendClick
1229
+ }
1230
+ )
1231
+ ] })
1232
+ ]
1233
+ }
1234
+ );
1235
+ }
1236
+ );
1237
+ UserPromptInput.displayName = "UserPromptInput";
555
1238
 
556
1239
  exports.ActionBar = ActionBar;
557
1240
  exports.ActivityIndicators = ActivityIndicators;
558
1241
  exports.AgentResponse = AgentResponse;
1242
+ exports.HITLInteractionRecord = HITLInteractionRecord;
1243
+ exports.HITLQuestionPanel = HITLQuestionPanel;
1244
+ exports.HITLSection = HITLSection;
559
1245
  exports.MetadataRow = MetadataRow;
560
1246
  exports.ThinkingSection = ThinkingSection;
1247
+ exports.TruncatedMessage = TruncatedMessage;
1248
+ exports.UserPrompt = UserPrompt;
1249
+ exports.UserPromptInput = UserPromptInput;
1250
+ exports.buildResponseString = buildResponseString;
561
1251
  exports.formatTime = formatTime;
562
1252
  exports.formatTotalTime = formatTotalTime;
563
1253
  exports.initialAgentResponseState = initialAgentResponseState;