@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.js CHANGED
@@ -1,15 +1,36 @@
1
- import * as React from 'react';
2
- import { useState, useCallback, useMemo, useEffect } from 'react';
3
- import { cn, Popover, PopoverTrigger, PopoverContent, LoadingSpinner } from '@optilogic/core';
4
- import { Wrench, Book, HardDrive, Check, Copy, ThumbsUp, ThumbsDown, ChevronUp, ChevronDown } from 'lucide-react';
1
+ import * as React11 from 'react';
2
+ import { useState, useCallback, useRef, useEffect, useMemo } from 'react';
3
+ import { cn, Popover, PopoverTrigger, PopoverContent, Button, Textarea, IconButton, LoadingSpinner } from '@optilogic/core';
4
+ import { Activity, Wrench, Book, HardDrive, Check, Copy, ThumbsUp, ThumbsDown, ChevronDown, ChevronRight, MessageCircleQuestion, Square, Loader2, Send, ChevronUp } from 'lucide-react';
5
5
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
6
+ import { SlateEditor, Text } from '@optilogic/editor';
6
7
 
7
8
  // src/components/agent-response/AgentResponse.tsx
8
- var ActivityIndicators = React.forwardRef(
9
- ({ toolCalls, knowledge, memory, className, ...props }, ref) => {
10
- const hasAnyActivity = toolCalls.length > 0 || knowledge.length > 0 || memory.length > 0;
9
+ var ActivityIndicators = React11.forwardRef(
10
+ ({ toolCalls, knowledge, memory, statusUpdates = [], className, ...props }, ref) => {
11
+ const hasAnyActivity = toolCalls.length > 0 || knowledge.length > 0 || memory.length > 0 || statusUpdates.length > 0;
11
12
  if (!hasAnyActivity) return null;
12
13
  return /* @__PURE__ */ jsxs("div", { ref, className: cn("flex items-center gap-2", className), ...props, children: [
14
+ statusUpdates.length > 0 && /* @__PURE__ */ jsxs(Popover, { children: [
15
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
16
+ "button",
17
+ {
18
+ className: "flex items-center gap-1 text-muted-foreground hover:text-foreground transition-colors",
19
+ onClick: (e) => e.stopPropagation(),
20
+ children: [
21
+ /* @__PURE__ */ jsx(Activity, { className: "w-3.5 h-3.5" }),
22
+ /* @__PURE__ */ jsx("span", { className: "text-xs", children: statusUpdates.length })
23
+ ]
24
+ }
25
+ ) }),
26
+ /* @__PURE__ */ jsx(PopoverContent, { className: "w-80", children: /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
27
+ /* @__PURE__ */ jsx("h4", { className: "font-medium text-sm", children: "Status Updates" }),
28
+ /* @__PURE__ */ jsx("div", { className: "space-y-2 max-h-60 overflow-auto", children: statusUpdates.map((item) => /* @__PURE__ */ jsxs("div", { className: "p-2 bg-muted rounded text-xs", children: [
29
+ item.agent && /* @__PURE__ */ jsx("div", { className: "font-medium text-muted-foreground", children: item.agent }),
30
+ /* @__PURE__ */ jsx("div", { className: item.agent ? "mt-1" : "", children: item.message })
31
+ ] }, item.id)) })
32
+ ] }) })
33
+ ] }),
13
34
  toolCalls.length > 0 && /* @__PURE__ */ jsxs(Popover, { children: [
14
35
  /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
15
36
  "button",
@@ -104,7 +125,7 @@ function formatTotalTime(seconds) {
104
125
  const minutes = seconds / 60;
105
126
  return `${minutes.toFixed(1)}m`;
106
127
  }
107
- var MetadataRow = React.forwardRef(
128
+ var MetadataRow = React11.forwardRef(
108
129
  ({
109
130
  hasThinking,
110
131
  isExpanded,
@@ -112,6 +133,8 @@ var MetadataRow = React.forwardRef(
112
133
  toolCalls,
113
134
  knowledge,
114
135
  memory,
136
+ statusUpdates = [],
137
+ statusContent,
115
138
  status,
116
139
  elapsedTime,
117
140
  className,
@@ -119,7 +142,7 @@ var MetadataRow = React.forwardRef(
119
142
  }, ref) => {
120
143
  const isProcessing = status === "processing";
121
144
  const isComplete = status === "complete";
122
- const hasActivity = toolCalls.length > 0 || knowledge.length > 0 || memory.length > 0;
145
+ const hasActivity = toolCalls.length > 0 || knowledge.length > 0 || memory.length > 0 || statusUpdates.length > 0;
123
146
  const renderLeftContent = () => {
124
147
  if (hasThinking) {
125
148
  return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
@@ -136,7 +159,7 @@ var MetadataRow = React.forwardRef(
136
159
  return null;
137
160
  };
138
161
  const leftContent = renderLeftContent();
139
- if (!leftContent && !hasActivity) {
162
+ if (!leftContent && !hasActivity && !statusContent) {
140
163
  return null;
141
164
  }
142
165
  return /* @__PURE__ */ jsxs(
@@ -150,16 +173,18 @@ var MetadataRow = React.forwardRef(
150
173
  "button",
151
174
  {
152
175
  onClick: onToggle,
153
- className: "flex items-center gap-1.5 hover:bg-muted/50 -ml-1.5 pl-1.5 pr-2 py-0.5 rounded transition-colors",
176
+ 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",
154
177
  children: leftContent
155
178
  }
156
- ) : /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1.5", children: leftContent }),
179
+ ) : /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1.5 shrink-0", children: leftContent }),
180
+ statusContent && /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0 mx-2", children: statusContent }),
157
181
  /* @__PURE__ */ jsx(
158
182
  ActivityIndicators,
159
183
  {
160
184
  toolCalls,
161
185
  knowledge,
162
- memory
186
+ memory,
187
+ statusUpdates
163
188
  }
164
189
  )
165
190
  ]
@@ -168,24 +193,61 @@ var MetadataRow = React.forwardRef(
168
193
  }
169
194
  );
170
195
  MetadataRow.displayName = "MetadataRow";
171
- var ThinkingSection = React.forwardRef(
172
- ({ content, isExpanded, className, ...props }, ref) => {
173
- if (!isExpanded || !content) {
196
+ var ThinkingStepItem = ({ step, renderMarkdown }) => {
197
+ const [isCollapsed, setIsCollapsed] = useState(step.isCollapsed ?? false);
198
+ const toggleCollapse = useCallback(() => {
199
+ setIsCollapsed((prev) => !prev);
200
+ }, []);
201
+ const indentPadding = step.depth * 16;
202
+ return /* @__PURE__ */ jsxs("div", { className: "border-b border-border/50 last:border-b-0", children: [
203
+ /* @__PURE__ */ jsxs(
204
+ "button",
205
+ {
206
+ onClick: toggleCollapse,
207
+ className: "w-full flex items-center gap-1.5 py-1.5 px-2 hover:bg-muted/50 transition-colors text-left",
208
+ style: { paddingLeft: `${indentPadding + 8}px` },
209
+ children: [
210
+ isCollapsed ? /* @__PURE__ */ jsx(ChevronRight, { className: "w-3 h-3 text-muted-foreground flex-shrink-0" }) : /* @__PURE__ */ jsx(ChevronDown, { className: "w-3 h-3 text-muted-foreground flex-shrink-0" }),
211
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-foreground/80", children: step.label })
212
+ ]
213
+ }
214
+ ),
215
+ !isCollapsed && /* @__PURE__ */ jsx(
216
+ "div",
217
+ {
218
+ className: "pb-2 px-2",
219
+ style: { paddingLeft: `${indentPadding + 28}px` },
220
+ children: renderMarkdown ? /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: renderMarkdown(step.content) }) : /* @__PURE__ */ jsx("pre", { className: "text-xs text-muted-foreground whitespace-pre-wrap font-mono", children: step.content })
221
+ }
222
+ )
223
+ ] });
224
+ };
225
+ var ThinkingSection = React11.forwardRef(
226
+ ({ content, isExpanded, renderMarkdown, className, ...props }, ref) => {
227
+ if (!isExpanded || !content || Array.isArray(content) && content.length === 0) {
174
228
  return null;
175
229
  }
230
+ const isStructured = Array.isArray(content);
176
231
  return /* @__PURE__ */ jsx(
177
232
  "div",
178
233
  {
179
234
  ref,
180
235
  className: cn("px-3 pb-3 border-t border-border", className),
181
236
  ...props,
182
- children: /* @__PURE__ */ jsx("div", { className: "mt-2 max-h-[200px] overflow-y-auto", children: /* @__PURE__ */ jsx("pre", { className: "text-xs text-muted-foreground whitespace-pre-wrap font-mono", children: content }) })
237
+ children: /* @__PURE__ */ jsx("div", { className: "mt-2 max-h-[200px] overflow-y-auto", children: isStructured ? /* @__PURE__ */ jsx("div", { className: "space-y-0", children: content.map((step) => /* @__PURE__ */ jsx(
238
+ ThinkingStepItem,
239
+ {
240
+ step,
241
+ renderMarkdown
242
+ },
243
+ step.id
244
+ )) }) : renderMarkdown ? /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: renderMarkdown(content) }) : /* @__PURE__ */ jsx("pre", { className: "text-xs text-muted-foreground whitespace-pre-wrap font-mono", children: content }) })
183
245
  }
184
246
  );
185
247
  }
186
248
  );
187
249
  ThinkingSection.displayName = "ThinkingSection";
188
- var ActionBar = React.forwardRef(
250
+ var ActionBar = React11.forwardRef(
189
251
  ({
190
252
  response,
191
253
  isVisible,
@@ -274,6 +336,313 @@ var ActionBar = React.forwardRef(
274
336
  }
275
337
  );
276
338
  ActionBar.displayName = "ActionBar";
339
+ function buildResponseString(questions, selectedOptions, freeformText) {
340
+ const parts = [];
341
+ for (const q of questions) {
342
+ const answer = selectedOptions[q];
343
+ if (answer) {
344
+ parts.push(`Q: ${q}
345
+ A: ${answer}`);
346
+ }
347
+ }
348
+ const trimmed = freeformText.trim();
349
+ if (trimmed) {
350
+ parts.push(`Additional context: ${trimmed}`);
351
+ }
352
+ return parts.join("\n\n");
353
+ }
354
+ var HITLQuestionPanel = React11.forwardRef(({ question, onSubmit, onStop, className, ...props }, ref) => {
355
+ const [freeformText, setFreeformText] = useState("");
356
+ const [selectedOptions, setSelectedOptions] = useState({});
357
+ const hasTimeout = question.timeoutSeconds != null;
358
+ const [secondsLeft, setSecondsLeft] = useState(
359
+ () => hasTimeout ? Math.max(
360
+ 0,
361
+ Math.round(
362
+ question.timeoutSeconds - (Date.now() - question.receivedAt) / 1e3
363
+ )
364
+ ) : Infinity
365
+ );
366
+ const textareaRef = useRef(null);
367
+ useEffect(() => {
368
+ textareaRef.current?.focus();
369
+ }, []);
370
+ useEffect(() => {
371
+ if (!hasTimeout) return;
372
+ const interval = setInterval(() => {
373
+ const remaining = Math.max(
374
+ 0,
375
+ Math.round(
376
+ question.timeoutSeconds - (Date.now() - question.receivedAt) / 1e3
377
+ )
378
+ );
379
+ setSecondsLeft(remaining);
380
+ if (remaining <= 0) clearInterval(interval);
381
+ }, 1e3);
382
+ return () => clearInterval(interval);
383
+ }, [hasTimeout, question.timeoutSeconds, question.receivedAt]);
384
+ const timedOut = hasTimeout && secondsLeft <= 0;
385
+ const questionsWithOptions = useMemo(
386
+ () => question.questions.filter((q) => question.options?.[q]?.length),
387
+ [question.questions, question.options]
388
+ );
389
+ const allOptionsSelected = questionsWithOptions.length > 0 && questionsWithOptions.every((q) => selectedOptions[q]);
390
+ const hasFreeformText = freeformText.trim().length > 0;
391
+ const canSubmit = !timedOut && (allOptionsSelected || hasFreeformText);
392
+ const handleOptionClick = useCallback(
393
+ (questionText, option) => {
394
+ if (timedOut) return;
395
+ setSelectedOptions((prev) => {
396
+ if (prev[questionText] === option) {
397
+ const next = { ...prev };
398
+ delete next[questionText];
399
+ return next;
400
+ }
401
+ return { ...prev, [questionText]: option };
402
+ });
403
+ },
404
+ [timedOut]
405
+ );
406
+ const handleSubmit = useCallback(() => {
407
+ if (!canSubmit) return;
408
+ const combined = buildResponseString(
409
+ question.questions,
410
+ selectedOptions,
411
+ freeformText
412
+ );
413
+ onSubmit(combined);
414
+ }, [canSubmit, question.questions, selectedOptions, freeformText, onSubmit]);
415
+ const handleKeyDown = useCallback(
416
+ (e) => {
417
+ if (e.key === "Enter" && !e.shiftKey) {
418
+ e.preventDefault();
419
+ handleSubmit();
420
+ }
421
+ },
422
+ [handleSubmit]
423
+ );
424
+ const formatTime2 = (s) => {
425
+ const m = Math.floor(s / 60);
426
+ const sec = s % 60;
427
+ return `${m}:${sec.toString().padStart(2, "0")}`;
428
+ };
429
+ return /* @__PURE__ */ jsxs(
430
+ "div",
431
+ {
432
+ ref,
433
+ className: cn(
434
+ "rounded-lg border border-border bg-muted p-4 space-y-3",
435
+ className
436
+ ),
437
+ ...props,
438
+ children: [
439
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
440
+ /* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground", children: question.reason }) }),
441
+ hasTimeout && /* @__PURE__ */ jsx(
442
+ "span",
443
+ {
444
+ className: cn(
445
+ "text-xs font-mono whitespace-nowrap",
446
+ secondsLeft <= 30 ? "text-destructive" : "text-muted-foreground"
447
+ ),
448
+ children: timedOut ? "Timed out" : formatTime2(secondsLeft)
449
+ }
450
+ )
451
+ ] }),
452
+ question.context && /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground bg-background rounded p-2 border border-border max-h-24 overflow-y-auto", children: /* @__PURE__ */ jsx("pre", { className: "whitespace-pre-wrap font-mono", children: question.context }) }),
453
+ /* @__PURE__ */ jsx("div", { className: "space-y-3", children: question.questions.map((q, i) => /* @__PURE__ */ jsxs("div", { children: [
454
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-foreground", children: q }),
455
+ question.options?.[q] && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2 mt-1.5", children: question.options[q].map((option, j) => {
456
+ const isSelected = selectedOptions[q] === option;
457
+ return /* @__PURE__ */ jsx(
458
+ Button,
459
+ {
460
+ variant: isSelected ? "primary" : "outline",
461
+ size: "sm",
462
+ onClick: () => handleOptionClick(q, option),
463
+ disabled: timedOut,
464
+ children: option
465
+ },
466
+ j
467
+ );
468
+ }) })
469
+ ] }, i)) }),
470
+ /* @__PURE__ */ jsx(
471
+ Textarea,
472
+ {
473
+ ref: textareaRef,
474
+ value: freeformText,
475
+ onChange: (e) => setFreeformText(e.target.value),
476
+ onKeyDown: handleKeyDown,
477
+ disabled: timedOut,
478
+ placeholder: "Add additional context or type a full response...",
479
+ rows: 2,
480
+ className: "resize-none"
481
+ }
482
+ ),
483
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
484
+ /* @__PURE__ */ jsx(
485
+ Button,
486
+ {
487
+ variant: "ghost",
488
+ size: "sm",
489
+ onClick: onStop,
490
+ className: "text-destructive hover:text-destructive hover:bg-destructive/10",
491
+ children: "Stop agent"
492
+ }
493
+ ),
494
+ /* @__PURE__ */ jsx(
495
+ Button,
496
+ {
497
+ variant: "primary",
498
+ size: "sm",
499
+ onClick: handleSubmit,
500
+ disabled: !canSubmit,
501
+ children: "Send response"
502
+ }
503
+ )
504
+ ] })
505
+ ]
506
+ }
507
+ );
508
+ });
509
+ HITLQuestionPanel.displayName = "HITLQuestionPanel";
510
+ function parseResponse(response) {
511
+ const answers = {};
512
+ let additionalContext = null;
513
+ const blocks = response.split("\n\n");
514
+ for (const block of blocks) {
515
+ const qaMatch = block.match(/^Q: (.+)\nA: (.+)$/s);
516
+ if (qaMatch) {
517
+ answers[qaMatch[1].trim()] = qaMatch[2].trim();
518
+ } else if (block.startsWith("Additional context: ")) {
519
+ additionalContext = block.slice("Additional context: ".length).trim();
520
+ }
521
+ }
522
+ return { answers, additionalContext };
523
+ }
524
+ var HITLInteractionRecord = React11.forwardRef(({ interaction, className, ...props }, ref) => {
525
+ const { question, response, respondedAt } = interaction;
526
+ const timestamp = new Date(respondedAt).toLocaleTimeString([], {
527
+ hour: "2-digit",
528
+ minute: "2-digit"
529
+ });
530
+ const { answers, additionalContext } = useMemo(
531
+ () => parseResponse(response),
532
+ [response]
533
+ );
534
+ const hasParsedAnswers = Object.keys(answers).length > 0;
535
+ return /* @__PURE__ */ jsxs(
536
+ "div",
537
+ {
538
+ ref,
539
+ className: cn(
540
+ "rounded-lg border border-border bg-muted p-3 space-y-2 text-sm",
541
+ className
542
+ ),
543
+ ...props,
544
+ children: [
545
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
546
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-muted-foreground", children: "Clarifying Question" }),
547
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: timestamp })
548
+ ] }),
549
+ /* @__PURE__ */ jsx("p", { className: "text-foreground font-medium", children: question.reason }),
550
+ question.context && /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground bg-background rounded p-2 border border-border", children: /* @__PURE__ */ jsx("pre", { className: "whitespace-pre-wrap font-mono", children: question.context }) }),
551
+ /* @__PURE__ */ jsx("div", { className: "space-y-2", children: question.questions.map((q, i) => /* @__PURE__ */ jsxs("div", { children: [
552
+ /* @__PURE__ */ jsx("p", { className: "text-foreground", children: q }),
553
+ question.options?.[q] && /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground ml-2", children: [
554
+ "Options: ",
555
+ question.options[q].join(", ")
556
+ ] }),
557
+ hasParsedAnswers && answers[q] && /* @__PURE__ */ jsxs("p", { className: "text-xs text-foreground ml-2 mt-0.5 bg-background rounded px-2 py-1 border border-border", children: [
558
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Answer: " }),
559
+ answers[q]
560
+ ] })
561
+ ] }, i)) }),
562
+ hasParsedAnswers && additionalContext && /* @__PURE__ */ jsxs("div", { className: "border-t border-border pt-2", children: [
563
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs", children: "Additional context:" }),
564
+ /* @__PURE__ */ jsx("p", { className: "text-foreground mt-0.5", children: additionalContext })
565
+ ] }),
566
+ !hasParsedAnswers && /* @__PURE__ */ jsxs("div", { className: "border-t border-border pt-2", children: [
567
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs", children: "Response:" }),
568
+ /* @__PURE__ */ jsx("p", { className: "text-foreground mt-0.5", children: response })
569
+ ] })
570
+ ]
571
+ }
572
+ );
573
+ });
574
+ HITLInteractionRecord.displayName = "HITLInteractionRecord";
575
+ var HITLSection = React11.forwardRef(
576
+ ({
577
+ interactions,
578
+ defaultExpanded = false,
579
+ isExpanded: controlledExpanded,
580
+ onExpandedChange,
581
+ className,
582
+ ...props
583
+ }, ref) => {
584
+ const [uncontrolledExpanded, setUncontrolledExpanded] = useState(defaultExpanded);
585
+ const isControlled = controlledExpanded !== void 0;
586
+ const isExpanded = isControlled ? controlledExpanded : uncontrolledExpanded;
587
+ const toggleExpanded = useCallback(() => {
588
+ const newValue = !isExpanded;
589
+ if (isControlled) {
590
+ onExpandedChange?.(newValue);
591
+ } else {
592
+ setUncontrolledExpanded(newValue);
593
+ }
594
+ }, [isExpanded, isControlled, onExpandedChange]);
595
+ if (!interactions || interactions.length === 0) {
596
+ return null;
597
+ }
598
+ return /* @__PURE__ */ jsxs(
599
+ "div",
600
+ {
601
+ ref,
602
+ className: cn("border-t border-border", className),
603
+ ...props,
604
+ children: [
605
+ /* @__PURE__ */ jsxs(
606
+ "button",
607
+ {
608
+ onClick: toggleExpanded,
609
+ className: "w-full flex items-center gap-2 py-2 px-3 hover:bg-muted/50 transition-colors text-left",
610
+ children: [
611
+ isExpanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "w-3.5 h-3.5 text-muted-foreground flex-shrink-0" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "w-3.5 h-3.5 text-muted-foreground flex-shrink-0" }),
612
+ /* @__PURE__ */ jsx(MessageCircleQuestion, { className: "w-3.5 h-3.5 text-muted-foreground flex-shrink-0" }),
613
+ /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-foreground/80", children: [
614
+ "Clarifying Questions (",
615
+ interactions.length,
616
+ ")"
617
+ ] })
618
+ ]
619
+ }
620
+ ),
621
+ isExpanded && /* @__PURE__ */ jsx("div", { className: "px-3 pb-3 space-y-2", children: interactions.map((interaction, i) => /* @__PURE__ */ jsx(HITLInteractionRecord, { interaction }, i)) })
622
+ ]
623
+ }
624
+ );
625
+ }
626
+ );
627
+ HITLSection.displayName = "HITLSection";
628
+ var TruncatedMessage = React11.forwardRef(
629
+ ({ message, className, ...props }, ref) => {
630
+ return /* @__PURE__ */ jsx(
631
+ "div",
632
+ {
633
+ ref,
634
+ className: cn(
635
+ "text-xs text-muted-foreground truncate min-w-0",
636
+ className
637
+ ),
638
+ title: message,
639
+ ...props,
640
+ children: message
641
+ }
642
+ );
643
+ }
644
+ );
645
+ TruncatedMessage.displayName = "TruncatedMessage";
277
646
  function useThinkingTimer({
278
647
  startTime,
279
648
  endTime,
@@ -308,6 +677,7 @@ var initialAgentResponseState = {
308
677
  toolCalls: [],
309
678
  knowledge: [],
310
679
  memory: [],
680
+ statusUpdates: [],
311
681
  response: "",
312
682
  thinkingStartTime: null,
313
683
  responseCompleteTime: null,
@@ -342,6 +712,23 @@ function useAgentResponseAccumulator(options) {
342
712
  }
343
713
  return { ...prev, status: newStatus };
344
714
  case "thinking": {
715
+ if (payload.thinkingStep) {
716
+ const newStep = {
717
+ id: payload.thinkingStep.id || `step-${Date.now()}`,
718
+ label: payload.thinkingStep.label,
719
+ content: payload.thinkingStep.content,
720
+ depth: payload.thinkingStep.depth ?? 0,
721
+ isCollapsed: payload.thinkingStep.isCollapsed
722
+ };
723
+ const thinkingStartTime2 = prev.thinkingStartTime ?? Date.now();
724
+ return {
725
+ ...prev,
726
+ status: newStatus,
727
+ thinkingSteps: [...prev.thinkingSteps || [], newStep],
728
+ thinkingStartTime: thinkingStartTime2,
729
+ firstMessageTime
730
+ };
731
+ }
345
732
  const newThinking = payload.message || payload.content || "";
346
733
  const separator = prev.thinking && newThinking ? "\n\n" : "";
347
734
  const thinkingStartTime = prev.thinkingStartTime ?? (newThinking ? Date.now() : null);
@@ -415,6 +802,24 @@ function useAgentResponseAccumulator(options) {
415
802
  responseCompleteTime: Date.now(),
416
803
  firstMessageTime: prev.firstMessageTime ?? Date.now()
417
804
  };
805
+ case "status_update": {
806
+ const statusMessage = payload.message || payload.statusUpdate?.message;
807
+ if (statusMessage) {
808
+ const newStatusItem = {
809
+ id: payload.statusUpdate?.id || `status-${Date.now()}`,
810
+ message: statusMessage,
811
+ agent: payload.statusUpdate?.agent,
812
+ timestamp: Date.now()
813
+ };
814
+ return {
815
+ ...prev,
816
+ status: newStatus,
817
+ statusUpdates: [...prev.statusUpdates, newStatusItem],
818
+ firstMessageTime
819
+ };
820
+ }
821
+ return { ...prev, status: newStatus, firstMessageTime };
822
+ }
418
823
  default:
419
824
  return { ...prev, status: newStatus, firstMessageTime };
420
825
  }
@@ -427,7 +832,7 @@ function useAgentResponseAccumulator(options) {
427
832
  }, []);
428
833
  return { state, handleMessage, reset };
429
834
  }
430
- var AgentResponse = React.forwardRef(
835
+ var AgentResponse = React11.forwardRef(
431
836
  ({
432
837
  state,
433
838
  id,
@@ -439,7 +844,11 @@ var AgentResponse = React.forwardRef(
439
844
  thinkingExpanded: controlledThinkingExpanded,
440
845
  onThinkingExpandedChange,
441
846
  actionsVisible = "hover",
847
+ hitlInteractions,
848
+ defaultHITLExpanded = false,
849
+ statusContent,
442
850
  renderMarkdown,
851
+ renderThinkingMarkdown,
443
852
  className,
444
853
  ...props
445
854
  }, ref) => {
@@ -464,8 +873,10 @@ var AgentResponse = React.forwardRef(
464
873
  if (!state.firstMessageTime || !state.responseCompleteTime) return 0;
465
874
  return (state.responseCompleteTime - state.firstMessageTime) / 1e3;
466
875
  }, [state.firstMessageTime, state.responseCompleteTime]);
467
- const hasAnyContent = state.thinking || state.toolCalls.length > 0 || state.knowledge.length > 0 || state.memory.length > 0 || state.response;
468
- const showMetadataRow = state.thinking || state.toolCalls.length > 0 || state.knowledge.length > 0 || state.memory.length > 0 || state.status === "processing";
876
+ const hasThinkingContent = !!state.thinking || state.thinkingSteps && state.thinkingSteps.length > 0 || false;
877
+ const hasHITLInteractions = hitlInteractions && hitlInteractions.length > 0;
878
+ const hasAnyContent = hasThinkingContent || state.toolCalls.length > 0 || state.knowledge.length > 0 || state.memory.length > 0 || state.statusUpdates.length > 0 || hasHITLInteractions || state.response;
879
+ const showMetadataRow = hasThinkingContent || state.toolCalls.length > 0 || state.knowledge.length > 0 || state.memory.length > 0 || state.statusUpdates.length > 0 || state.status === "processing";
469
880
  const showActionBar = state.status === "complete" && state.response;
470
881
  const isActionBarVisible = actionsVisible === true || actionsVisible === "hover" && isHovered;
471
882
  if (!hasAnyContent) {
@@ -485,12 +896,14 @@ var AgentResponse = React.forwardRef(
485
896
  /* @__PURE__ */ jsx(
486
897
  MetadataRow,
487
898
  {
488
- hasThinking: !!state.thinking,
899
+ hasThinking: hasThinkingContent,
489
900
  isExpanded: thinkingExpanded,
490
901
  onToggle: toggleThinking,
491
902
  toolCalls: state.toolCalls,
492
903
  knowledge: state.knowledge,
493
904
  memory: state.memory,
905
+ statusUpdates: state.statusUpdates,
906
+ statusContent,
494
907
  status: state.status,
495
908
  elapsedTime
496
909
  }
@@ -498,11 +911,19 @@ var AgentResponse = React.forwardRef(
498
911
  /* @__PURE__ */ jsx(
499
912
  ThinkingSection,
500
913
  {
501
- content: state.thinking,
502
- isExpanded: thinkingExpanded
914
+ content: state.thinkingSteps && state.thinkingSteps.length > 0 ? state.thinkingSteps : state.thinking,
915
+ isExpanded: thinkingExpanded,
916
+ renderMarkdown: renderThinkingMarkdown
503
917
  }
504
918
  )
505
919
  ] }),
920
+ hasHITLInteractions && /* @__PURE__ */ jsx(
921
+ HITLSection,
922
+ {
923
+ interactions: hitlInteractions,
924
+ defaultExpanded: defaultHITLExpanded
925
+ }
926
+ ),
506
927
  state.response && /* @__PURE__ */ jsx(
507
928
  "div",
508
929
  {
@@ -531,7 +952,269 @@ var AgentResponse = React.forwardRef(
531
952
  }
532
953
  );
533
954
  AgentResponse.displayName = "AgentResponse";
955
+ var UserPrompt = React11.forwardRef(
956
+ ({ content, timestamp, className, ...props }, ref) => {
957
+ return /* @__PURE__ */ jsxs(
958
+ "div",
959
+ {
960
+ ref,
961
+ className: cn(
962
+ "w-fit max-w-[80%] rounded-lg px-4 pt-3.5 pb-3",
963
+ "bg-secondary text-secondary-foreground",
964
+ className
965
+ ),
966
+ ...props,
967
+ children: [
968
+ /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap", children: content }),
969
+ timestamp && /* @__PURE__ */ jsx("p", { className: "text-xs text-secondary-foreground/70 mt-1", children: timestamp.toLocaleTimeString([], {
970
+ hour: "2-digit",
971
+ minute: "2-digit"
972
+ }) })
973
+ ]
974
+ }
975
+ );
976
+ }
977
+ );
978
+ UserPrompt.displayName = "UserPrompt";
979
+ function createCodeBlockDecorate(entry) {
980
+ const [node, path] = entry;
981
+ const ranges = [];
982
+ if (!Text.isText(node)) {
983
+ return ranges;
984
+ }
985
+ const { text } = node;
986
+ const backtickPositions = [];
987
+ let searchStart = 0;
988
+ while (true) {
989
+ const pos = text.indexOf("```", searchStart);
990
+ if (pos === -1) break;
991
+ backtickPositions.push(pos);
992
+ searchStart = pos + 3;
993
+ }
994
+ let i = 0;
995
+ while (i < backtickPositions.length) {
996
+ const openPos = backtickPositions[i];
997
+ const closePos = backtickPositions[i + 1];
998
+ ranges.push({
999
+ anchor: { path, offset: openPos },
1000
+ focus: { path, offset: openPos + 3 },
1001
+ codeDelimiter: true
1002
+ });
1003
+ if (closePos !== void 0) {
1004
+ if (closePos > openPos + 3) {
1005
+ ranges.push({
1006
+ anchor: { path, offset: openPos + 3 },
1007
+ focus: { path, offset: closePos },
1008
+ codeBlock: true
1009
+ });
1010
+ }
1011
+ ranges.push({
1012
+ anchor: { path, offset: closePos },
1013
+ focus: { path, offset: closePos + 3 },
1014
+ codeDelimiter: true
1015
+ });
1016
+ i += 2;
1017
+ } else {
1018
+ if (text.length > openPos + 3) {
1019
+ ranges.push({
1020
+ anchor: { path, offset: openPos + 3 },
1021
+ focus: { path, offset: text.length },
1022
+ codeBlock: true
1023
+ });
1024
+ }
1025
+ i += 1;
1026
+ }
1027
+ }
1028
+ return ranges;
1029
+ }
1030
+ function CodeBlockLeaf({ attributes, children, leaf }) {
1031
+ const leafAny = leaf;
1032
+ if (leafAny.codeBlock) {
1033
+ return /* @__PURE__ */ jsx(
1034
+ "span",
1035
+ {
1036
+ ...attributes,
1037
+ className: "bg-muted/50 text-muted-foreground font-mono text-sm rounded px-1",
1038
+ children
1039
+ }
1040
+ );
1041
+ }
1042
+ if (leafAny.codeDelimiter) {
1043
+ return /* @__PURE__ */ jsx(
1044
+ "span",
1045
+ {
1046
+ ...attributes,
1047
+ className: "text-muted-foreground/50 font-mono text-sm",
1048
+ children
1049
+ }
1050
+ );
1051
+ }
1052
+ return /* @__PURE__ */ jsx("span", { ...attributes, children });
1053
+ }
1054
+ var UserPromptInput = React11.forwardRef(
1055
+ ({
1056
+ value = "",
1057
+ onChange,
1058
+ onSubmit,
1059
+ clearOnSubmit = true,
1060
+ placeholder = "Type your message...",
1061
+ disabled = false,
1062
+ isSubmitting = false,
1063
+ onStop,
1064
+ disableWhileSubmitting = true,
1065
+ autoFocus = false,
1066
+ refocusAfterSubmit = false,
1067
+ onReady,
1068
+ minRows = 1,
1069
+ maxRows = 6,
1070
+ renderActions,
1071
+ enableTags = false,
1072
+ onTagCreate,
1073
+ onTagDelete,
1074
+ className,
1075
+ ...props
1076
+ }, ref) => {
1077
+ const editorRef = React11.useRef(null);
1078
+ const [internalValue, setInternalValue] = React11.useState(value);
1079
+ const prevIsSubmitting = React11.useRef(isSubmitting);
1080
+ const hasEmittedReady = React11.useRef(false);
1081
+ React11.useEffect(() => {
1082
+ setInternalValue(value);
1083
+ }, [value]);
1084
+ React11.useEffect(() => {
1085
+ if (autoFocus) {
1086
+ requestAnimationFrame(() => {
1087
+ requestAnimationFrame(() => {
1088
+ editorRef.current?.focus();
1089
+ });
1090
+ });
1091
+ }
1092
+ }, [autoFocus]);
1093
+ React11.useEffect(() => {
1094
+ if (!hasEmittedReady.current && onReady) {
1095
+ requestAnimationFrame(() => {
1096
+ requestAnimationFrame(() => {
1097
+ hasEmittedReady.current = true;
1098
+ onReady();
1099
+ });
1100
+ });
1101
+ }
1102
+ }, [onReady]);
1103
+ React11.useEffect(() => {
1104
+ if (refocusAfterSubmit && prevIsSubmitting.current && !isSubmitting) {
1105
+ requestAnimationFrame(() => {
1106
+ editorRef.current?.focus();
1107
+ });
1108
+ }
1109
+ prevIsSubmitting.current = isSubmitting;
1110
+ }, [isSubmitting, refocusAfterSubmit]);
1111
+ React11.useImperativeHandle(
1112
+ ref,
1113
+ () => ({
1114
+ focus: () => {
1115
+ try {
1116
+ editorRef.current?.focus();
1117
+ } catch {
1118
+ requestAnimationFrame(() => {
1119
+ requestAnimationFrame(() => {
1120
+ editorRef.current?.focus();
1121
+ });
1122
+ });
1123
+ }
1124
+ },
1125
+ clear: () => {
1126
+ editorRef.current?.clear();
1127
+ setInternalValue("");
1128
+ },
1129
+ getText: () => editorRef.current?.getText() ?? "",
1130
+ insertText: (text) => editorRef.current?.insertText(text)
1131
+ }),
1132
+ []
1133
+ );
1134
+ const handleChange = React11.useCallback(
1135
+ (newValue) => {
1136
+ setInternalValue(newValue);
1137
+ onChange?.(newValue);
1138
+ },
1139
+ [onChange]
1140
+ );
1141
+ const handleSubmit = React11.useCallback(
1142
+ (text) => {
1143
+ if (disabled || isSubmitting) return;
1144
+ if (!text.trim()) return;
1145
+ onSubmit?.(text.trim());
1146
+ if (clearOnSubmit) {
1147
+ editorRef.current?.clear();
1148
+ setInternalValue("");
1149
+ }
1150
+ },
1151
+ [disabled, isSubmitting, onSubmit, clearOnSubmit]
1152
+ );
1153
+ const handleSendClick = React11.useCallback(() => {
1154
+ const text = editorRef.current?.getText() ?? "";
1155
+ handleSubmit(text);
1156
+ }, [handleSubmit]);
1157
+ const hasContent = internalValue.trim().length > 0;
1158
+ const canSubmit = hasContent && !disabled && !isSubmitting;
1159
+ return /* @__PURE__ */ jsxs(
1160
+ "div",
1161
+ {
1162
+ className: cn(
1163
+ "rounded-lg border border-input bg-background",
1164
+ disabled && "opacity-50 cursor-not-allowed",
1165
+ className
1166
+ ),
1167
+ ...props,
1168
+ children: [
1169
+ /* @__PURE__ */ jsx("div", { className: "pl-2 pr-0 pt-1 pb-1", children: /* @__PURE__ */ jsx(
1170
+ SlateEditor,
1171
+ {
1172
+ ref: editorRef,
1173
+ value: internalValue,
1174
+ onChange: handleChange,
1175
+ onSubmit: handleSubmit,
1176
+ clearOnSubmit: false,
1177
+ placeholder,
1178
+ disabled: disabled || disableWhileSubmitting && isSubmitting,
1179
+ enableTags,
1180
+ onTagCreate,
1181
+ onTagDelete,
1182
+ minRows,
1183
+ maxRows,
1184
+ decorate: createCodeBlockDecorate,
1185
+ renderLeaf: CodeBlockLeaf
1186
+ }
1187
+ ) }),
1188
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between pl-2 pr-1 pb-1 pt-1", children: [
1189
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", children: renderActions?.() }),
1190
+ isSubmitting && onStop ? /* @__PURE__ */ jsx(
1191
+ IconButton,
1192
+ {
1193
+ icon: /* @__PURE__ */ jsx(Square, {}),
1194
+ variant: "filled",
1195
+ size: "sm",
1196
+ "aria-label": "Stop",
1197
+ onClick: onStop
1198
+ }
1199
+ ) : /* @__PURE__ */ jsx(
1200
+ IconButton,
1201
+ {
1202
+ icon: isSubmitting ? /* @__PURE__ */ jsx(Loader2, { className: "animate-spin" }) : /* @__PURE__ */ jsx(Send, {}),
1203
+ variant: "filled",
1204
+ size: "sm",
1205
+ "aria-label": isSubmitting ? "Sending..." : "Send message",
1206
+ disabled: !canSubmit,
1207
+ onClick: handleSendClick
1208
+ }
1209
+ )
1210
+ ] })
1211
+ ]
1212
+ }
1213
+ );
1214
+ }
1215
+ );
1216
+ UserPromptInput.displayName = "UserPromptInput";
534
1217
 
535
- export { ActionBar, ActivityIndicators, AgentResponse, MetadataRow, ThinkingSection, formatTime, formatTotalTime, initialAgentResponseState, useAgentResponseAccumulator, useThinkingTimer };
1218
+ export { ActionBar, ActivityIndicators, AgentResponse, HITLInteractionRecord, HITLQuestionPanel, HITLSection, MetadataRow, ThinkingSection, TruncatedMessage, UserPrompt, UserPromptInput, buildResponseString, formatTime, formatTotalTime, initialAgentResponseState, useAgentResponseAccumulator, useThinkingTimer };
536
1219
  //# sourceMappingURL=index.js.map
537
1220
  //# sourceMappingURL=index.js.map