@optilogic/chat 1.0.0-beta.7 → 1.0.0-beta.9

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.d.ts CHANGED
@@ -155,6 +155,57 @@ interface GenericWebSocketMessage {
155
155
  */
156
156
  declare const initialAgentResponseState: AgentResponseState;
157
157
 
158
+ /**
159
+ * HITLQuestionPanel — Human-in-the-Loop clarifying question panel.
160
+ *
161
+ * Renders in the input area (replacing UserPromptInput) when the agent asks a
162
+ * clarifying question via the HumanInTheLoop tool. Shows the question details
163
+ * and lets the user respond via option buttons or free-form text.
164
+ *
165
+ * Option clicks select/toggle rather than immediately submitting. The "Send
166
+ * response" button enables once all questions have a selected option OR the
167
+ * textarea has text. On submit, selected options and free-form text are
168
+ * combined into a single formatted string for the backend.
169
+ */
170
+
171
+ interface HITLQuestion {
172
+ reason: string;
173
+ questions: string[];
174
+ options: Record<string, string[]> | null;
175
+ context: string | null;
176
+ timeoutSeconds: number;
177
+ receivedAt: number;
178
+ }
179
+ interface HITLQuestionPanelProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onSubmit"> {
180
+ question: HITLQuestion;
181
+ onSubmit: (response: string) => void;
182
+ onStop: () => void;
183
+ }
184
+ /**
185
+ * Build a single response string from selected options and optional free-form text.
186
+ * Format is designed to be easily parsed by the LLM consuming the response.
187
+ */
188
+ declare function buildResponseString(questions: string[], selectedOptions: Record<string, string>, freeformText: string): string;
189
+ declare const HITLQuestionPanel: React.ForwardRefExoticComponent<HITLQuestionPanelProps & React.RefAttributes<HTMLDivElement>>;
190
+
191
+ /**
192
+ * HITLInteractionRecord — Displays a completed HITL Q&A interaction
193
+ * in the chat message history.
194
+ *
195
+ * Rendered below AgentResponse in the agent message block. Shows the full detail
196
+ * of each clarifying question the agent asked and the user's response.
197
+ */
198
+
199
+ interface HITLInteraction {
200
+ question: HITLQuestion;
201
+ response: string;
202
+ respondedAt: number;
203
+ }
204
+ interface HITLInteractionRecordProps extends React.HTMLAttributes<HTMLDivElement> {
205
+ interaction: HITLInteraction;
206
+ }
207
+ declare const HITLInteractionRecord: React.ForwardRefExoticComponent<HITLInteractionRecordProps & React.RefAttributes<HTMLDivElement>>;
208
+
158
209
  /**
159
210
  * AgentResponse Component
160
211
  *
@@ -180,6 +231,15 @@ interface AgentResponseProps extends React.HTMLAttributes<HTMLDivElement> {
180
231
  onThinkingExpandedChange?: (expanded: boolean) => void;
181
232
  /** Action bar visibility mode */
182
233
  actionsVisible?: boolean | "hover";
234
+ /**
235
+ * Optional HITL (Human-in-the-Loop) interactions to display as a
236
+ * collapsible section within the response. When provided, a "Clarifying
237
+ * Questions" section appears between the thinking/metadata area and
238
+ * the response content.
239
+ */
240
+ hitlInteractions?: HITLInteraction[];
241
+ /** Whether the HITL section starts expanded (default: false) */
242
+ defaultHITLExpanded?: boolean;
183
243
  /**
184
244
  * Custom markdown renderer for the response content.
185
245
  * If not provided, the response will be rendered as plain text.
@@ -392,6 +452,26 @@ interface ActionBarProps extends React.HTMLAttributes<HTMLDivElement> {
392
452
  */
393
453
  declare const ActionBar: React.ForwardRefExoticComponent<ActionBarProps & React.RefAttributes<HTMLDivElement>>;
394
454
 
455
+ /**
456
+ * HITL Section Component
457
+ *
458
+ * Collapsible section for displaying completed HITL (Human-in-the-Loop)
459
+ * interactions within an AgentResponse. Follows the same pattern as
460
+ * ThinkingSection for consistent UX.
461
+ */
462
+
463
+ interface HITLSectionProps extends React.HTMLAttributes<HTMLDivElement> {
464
+ /** The HITL interactions to display */
465
+ interactions: HITLInteraction[];
466
+ /** Whether the section starts expanded (uncontrolled) */
467
+ defaultExpanded?: boolean;
468
+ /** Whether the section is expanded (controlled) */
469
+ isExpanded?: boolean;
470
+ /** Callback when expansion state changes (controlled) */
471
+ onExpandedChange?: (expanded: boolean) => void;
472
+ }
473
+ declare const HITLSection: React.ForwardRefExoticComponent<HITLSectionProps & React.RefAttributes<HTMLDivElement>>;
474
+
395
475
  /**
396
476
  * useThinkingTimer Hook
397
477
  *
@@ -558,4 +638,4 @@ interface UserPromptInputRef {
558
638
  */
559
639
  declare const UserPromptInput: React.ForwardRefExoticComponent<UserPromptInputProps & React.RefAttributes<UserPromptInputRef>>;
560
640
 
561
- export { ActionBar, type ActionBarProps, ActivityIndicators, type ActivityIndicatorsProps, type AgentMessage, AgentResponse, type AgentResponseProps, type AgentResponseState, type AgentResponseStatus, type FeedbackValue, type GenericWebSocketMessage, type KnowledgeItem, type MemoryItem, MetadataRow, type MetadataRowProps, type StatusItem, type ThinkingContent, ThinkingSection, type ThinkingSectionProps, type ThinkingStep, type ToolCall, type UseAgentResponseAccumulatorOptions, type UseAgentResponseAccumulatorReturn, type UseThinkingTimerOptions, UserPrompt, UserPromptInput, type UserPromptInputProps, type UserPromptInputRef, type UserPromptProps, formatTime, formatTotalTime, initialAgentResponseState, useAgentResponseAccumulator, useThinkingTimer };
641
+ export { ActionBar, type ActionBarProps, ActivityIndicators, type ActivityIndicatorsProps, type AgentMessage, AgentResponse, type AgentResponseProps, type AgentResponseState, type AgentResponseStatus, type FeedbackValue, type GenericWebSocketMessage, type HITLInteraction, HITLInteractionRecord, type HITLInteractionRecordProps, type HITLQuestion, HITLQuestionPanel, type HITLQuestionPanelProps, HITLSection, type HITLSectionProps, type KnowledgeItem, type MemoryItem, MetadataRow, type MetadataRowProps, type StatusItem, type ThinkingContent, ThinkingSection, type ThinkingSectionProps, type ThinkingStep, type ToolCall, type UseAgentResponseAccumulatorOptions, type UseAgentResponseAccumulatorReturn, type UseThinkingTimerOptions, UserPrompt, UserPromptInput, type UserPromptInputProps, type UserPromptInputRef, type UserPromptProps, buildResponseString, formatTime, formatTotalTime, initialAgentResponseState, useAgentResponseAccumulator, useThinkingTimer };
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
- import * as React7 from 'react';
2
- import { useState, useCallback, useMemo, useEffect } from 'react';
3
- import { cn, Popover, PopoverTrigger, PopoverContent, IconButton, LoadingSpinner } from '@optilogic/core';
4
- import { Activity, Wrench, Book, HardDrive, Check, Copy, ThumbsUp, ThumbsDown, Square, Loader2, Send, ChevronUp, ChevronDown, ChevronRight } from 'lucide-react';
1
+ import * as React10 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
6
  import { SlateEditor, Text } from '@optilogic/editor';
7
7
 
8
8
  // src/components/agent-response/AgentResponse.tsx
9
- var ActivityIndicators = React7.forwardRef(
9
+ var ActivityIndicators = React10.forwardRef(
10
10
  ({ toolCalls, knowledge, memory, statusUpdates = [], className, ...props }, ref) => {
11
11
  const hasAnyActivity = toolCalls.length > 0 || knowledge.length > 0 || memory.length > 0 || statusUpdates.length > 0;
12
12
  if (!hasAnyActivity) return null;
@@ -125,7 +125,7 @@ function formatTotalTime(seconds) {
125
125
  const minutes = seconds / 60;
126
126
  return `${minutes.toFixed(1)}m`;
127
127
  }
128
- var MetadataRow = React7.forwardRef(
128
+ var MetadataRow = React10.forwardRef(
129
129
  ({
130
130
  hasThinking,
131
131
  isExpanded,
@@ -220,7 +220,7 @@ var ThinkingStepItem = ({ step, renderMarkdown }) => {
220
220
  )
221
221
  ] });
222
222
  };
223
- var ThinkingSection = React7.forwardRef(
223
+ var ThinkingSection = React10.forwardRef(
224
224
  ({ content, isExpanded, renderMarkdown, className, ...props }, ref) => {
225
225
  if (!isExpanded || !content || Array.isArray(content) && content.length === 0) {
226
226
  return null;
@@ -245,7 +245,7 @@ var ThinkingSection = React7.forwardRef(
245
245
  }
246
246
  );
247
247
  ThinkingSection.displayName = "ThinkingSection";
248
- var ActionBar = React7.forwardRef(
248
+ var ActionBar = React10.forwardRef(
249
249
  ({
250
250
  response,
251
251
  isVisible,
@@ -334,6 +334,293 @@ var ActionBar = React7.forwardRef(
334
334
  }
335
335
  );
336
336
  ActionBar.displayName = "ActionBar";
337
+ function buildResponseString(questions, selectedOptions, freeformText) {
338
+ const parts = [];
339
+ for (const q of questions) {
340
+ const answer = selectedOptions[q];
341
+ if (answer) {
342
+ parts.push(`Q: ${q}
343
+ A: ${answer}`);
344
+ }
345
+ }
346
+ const trimmed = freeformText.trim();
347
+ if (trimmed) {
348
+ parts.push(`Additional context: ${trimmed}`);
349
+ }
350
+ return parts.join("\n\n");
351
+ }
352
+ var HITLQuestionPanel = React10.forwardRef(({ question, onSubmit, onStop, className, ...props }, ref) => {
353
+ const [freeformText, setFreeformText] = useState("");
354
+ const [selectedOptions, setSelectedOptions] = useState({});
355
+ const [secondsLeft, setSecondsLeft] = useState(
356
+ () => Math.max(
357
+ 0,
358
+ Math.round(
359
+ question.timeoutSeconds - (Date.now() - question.receivedAt) / 1e3
360
+ )
361
+ )
362
+ );
363
+ const textareaRef = useRef(null);
364
+ useEffect(() => {
365
+ textareaRef.current?.focus();
366
+ }, []);
367
+ useEffect(() => {
368
+ const interval = setInterval(() => {
369
+ const remaining = Math.max(
370
+ 0,
371
+ Math.round(
372
+ question.timeoutSeconds - (Date.now() - question.receivedAt) / 1e3
373
+ )
374
+ );
375
+ setSecondsLeft(remaining);
376
+ if (remaining <= 0) clearInterval(interval);
377
+ }, 1e3);
378
+ return () => clearInterval(interval);
379
+ }, [question.timeoutSeconds, question.receivedAt]);
380
+ const timedOut = secondsLeft <= 0;
381
+ const questionsWithOptions = useMemo(
382
+ () => question.questions.filter((q) => question.options?.[q]?.length),
383
+ [question.questions, question.options]
384
+ );
385
+ const allOptionsSelected = questionsWithOptions.length > 0 && questionsWithOptions.every((q) => selectedOptions[q]);
386
+ const hasFreeformText = freeformText.trim().length > 0;
387
+ const canSubmit = !timedOut && (allOptionsSelected || hasFreeformText);
388
+ const handleOptionClick = useCallback(
389
+ (questionText, option) => {
390
+ if (timedOut) return;
391
+ setSelectedOptions((prev) => {
392
+ if (prev[questionText] === option) {
393
+ const next = { ...prev };
394
+ delete next[questionText];
395
+ return next;
396
+ }
397
+ return { ...prev, [questionText]: option };
398
+ });
399
+ },
400
+ [timedOut]
401
+ );
402
+ const handleSubmit = useCallback(() => {
403
+ if (!canSubmit) return;
404
+ const combined = buildResponseString(
405
+ question.questions,
406
+ selectedOptions,
407
+ freeformText
408
+ );
409
+ onSubmit(combined);
410
+ }, [canSubmit, question.questions, selectedOptions, freeformText, onSubmit]);
411
+ const handleKeyDown = useCallback(
412
+ (e) => {
413
+ if (e.key === "Enter" && !e.shiftKey) {
414
+ e.preventDefault();
415
+ handleSubmit();
416
+ }
417
+ },
418
+ [handleSubmit]
419
+ );
420
+ const formatTime2 = (s) => {
421
+ const m = Math.floor(s / 60);
422
+ const sec = s % 60;
423
+ return `${m}:${sec.toString().padStart(2, "0")}`;
424
+ };
425
+ return /* @__PURE__ */ jsxs(
426
+ "div",
427
+ {
428
+ ref,
429
+ className: cn(
430
+ "rounded-lg border border-border bg-muted p-4 space-y-3",
431
+ className
432
+ ),
433
+ ...props,
434
+ children: [
435
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
436
+ /* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground", children: question.reason }) }),
437
+ /* @__PURE__ */ jsx(
438
+ "span",
439
+ {
440
+ className: cn(
441
+ "text-xs font-mono whitespace-nowrap",
442
+ secondsLeft <= 30 ? "text-destructive" : "text-muted-foreground"
443
+ ),
444
+ children: timedOut ? "Timed out" : formatTime2(secondsLeft)
445
+ }
446
+ )
447
+ ] }),
448
+ 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 }) }),
449
+ /* @__PURE__ */ jsx("div", { className: "space-y-3", children: question.questions.map((q, i) => /* @__PURE__ */ jsxs("div", { children: [
450
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-foreground", children: q }),
451
+ question.options?.[q] && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2 mt-1.5", children: question.options[q].map((option, j) => {
452
+ const isSelected = selectedOptions[q] === option;
453
+ return /* @__PURE__ */ jsx(
454
+ Button,
455
+ {
456
+ variant: isSelected ? "primary" : "outline",
457
+ size: "sm",
458
+ onClick: () => handleOptionClick(q, option),
459
+ disabled: timedOut,
460
+ children: option
461
+ },
462
+ j
463
+ );
464
+ }) })
465
+ ] }, i)) }),
466
+ /* @__PURE__ */ jsx(
467
+ Textarea,
468
+ {
469
+ ref: textareaRef,
470
+ value: freeformText,
471
+ onChange: (e) => setFreeformText(e.target.value),
472
+ onKeyDown: handleKeyDown,
473
+ disabled: timedOut,
474
+ placeholder: "Add additional context or type a full response...",
475
+ rows: 2,
476
+ className: "resize-none"
477
+ }
478
+ ),
479
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
480
+ /* @__PURE__ */ jsx(
481
+ Button,
482
+ {
483
+ variant: "ghost",
484
+ size: "sm",
485
+ onClick: onStop,
486
+ className: "text-destructive hover:text-destructive hover:bg-destructive/10",
487
+ children: "Stop agent"
488
+ }
489
+ ),
490
+ /* @__PURE__ */ jsx(
491
+ Button,
492
+ {
493
+ variant: "primary",
494
+ size: "sm",
495
+ onClick: handleSubmit,
496
+ disabled: !canSubmit,
497
+ children: "Send response"
498
+ }
499
+ )
500
+ ] })
501
+ ]
502
+ }
503
+ );
504
+ });
505
+ HITLQuestionPanel.displayName = "HITLQuestionPanel";
506
+ function parseResponse(response) {
507
+ const answers = {};
508
+ let additionalContext = null;
509
+ const blocks = response.split("\n\n");
510
+ for (const block of blocks) {
511
+ const qaMatch = block.match(/^Q: (.+)\nA: (.+)$/s);
512
+ if (qaMatch) {
513
+ answers[qaMatch[1].trim()] = qaMatch[2].trim();
514
+ } else if (block.startsWith("Additional context: ")) {
515
+ additionalContext = block.slice("Additional context: ".length).trim();
516
+ }
517
+ }
518
+ return { answers, additionalContext };
519
+ }
520
+ var HITLInteractionRecord = React10.forwardRef(({ interaction, className, ...props }, ref) => {
521
+ const { question, response, respondedAt } = interaction;
522
+ const timestamp = new Date(respondedAt).toLocaleTimeString([], {
523
+ hour: "2-digit",
524
+ minute: "2-digit"
525
+ });
526
+ const { answers, additionalContext } = useMemo(
527
+ () => parseResponse(response),
528
+ [response]
529
+ );
530
+ const hasParsedAnswers = Object.keys(answers).length > 0;
531
+ return /* @__PURE__ */ jsxs(
532
+ "div",
533
+ {
534
+ ref,
535
+ className: cn(
536
+ "rounded-lg border border-border bg-muted p-3 space-y-2 text-sm",
537
+ className
538
+ ),
539
+ ...props,
540
+ children: [
541
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
542
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-muted-foreground", children: "Clarifying Question" }),
543
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: timestamp })
544
+ ] }),
545
+ /* @__PURE__ */ jsx("p", { className: "text-foreground font-medium", children: question.reason }),
546
+ 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 }) }),
547
+ /* @__PURE__ */ jsx("div", { className: "space-y-2", children: question.questions.map((q, i) => /* @__PURE__ */ jsxs("div", { children: [
548
+ /* @__PURE__ */ jsx("p", { className: "text-foreground", children: q }),
549
+ question.options?.[q] && /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground ml-2", children: [
550
+ "Options: ",
551
+ question.options[q].join(", ")
552
+ ] }),
553
+ 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: [
554
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Answer: " }),
555
+ answers[q]
556
+ ] })
557
+ ] }, i)) }),
558
+ hasParsedAnswers && additionalContext && /* @__PURE__ */ jsxs("div", { className: "border-t border-border pt-2", children: [
559
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs", children: "Additional context:" }),
560
+ /* @__PURE__ */ jsx("p", { className: "text-foreground mt-0.5", children: additionalContext })
561
+ ] }),
562
+ !hasParsedAnswers && /* @__PURE__ */ jsxs("div", { className: "border-t border-border pt-2", children: [
563
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs", children: "Response:" }),
564
+ /* @__PURE__ */ jsx("p", { className: "text-foreground mt-0.5", children: response })
565
+ ] })
566
+ ]
567
+ }
568
+ );
569
+ });
570
+ HITLInteractionRecord.displayName = "HITLInteractionRecord";
571
+ var HITLSection = React10.forwardRef(
572
+ ({
573
+ interactions,
574
+ defaultExpanded = false,
575
+ isExpanded: controlledExpanded,
576
+ onExpandedChange,
577
+ className,
578
+ ...props
579
+ }, ref) => {
580
+ const [uncontrolledExpanded, setUncontrolledExpanded] = useState(defaultExpanded);
581
+ const isControlled = controlledExpanded !== void 0;
582
+ const isExpanded = isControlled ? controlledExpanded : uncontrolledExpanded;
583
+ const toggleExpanded = useCallback(() => {
584
+ const newValue = !isExpanded;
585
+ if (isControlled) {
586
+ onExpandedChange?.(newValue);
587
+ } else {
588
+ setUncontrolledExpanded(newValue);
589
+ }
590
+ }, [isExpanded, isControlled, onExpandedChange]);
591
+ if (!interactions || interactions.length === 0) {
592
+ return null;
593
+ }
594
+ return /* @__PURE__ */ jsxs(
595
+ "div",
596
+ {
597
+ ref,
598
+ className: cn("border-t border-border", className),
599
+ ...props,
600
+ children: [
601
+ /* @__PURE__ */ jsxs(
602
+ "button",
603
+ {
604
+ onClick: toggleExpanded,
605
+ className: "w-full flex items-center gap-2 py-2 px-3 hover:bg-muted/50 transition-colors text-left",
606
+ children: [
607
+ 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" }),
608
+ /* @__PURE__ */ jsx(MessageCircleQuestion, { className: "w-3.5 h-3.5 text-muted-foreground flex-shrink-0" }),
609
+ /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-foreground/80", children: [
610
+ "Clarifying Questions (",
611
+ interactions.length,
612
+ ")"
613
+ ] })
614
+ ]
615
+ }
616
+ ),
617
+ isExpanded && /* @__PURE__ */ jsx("div", { className: "px-3 pb-3 space-y-2", children: interactions.map((interaction, i) => /* @__PURE__ */ jsx(HITLInteractionRecord, { interaction }, i)) })
618
+ ]
619
+ }
620
+ );
621
+ }
622
+ );
623
+ HITLSection.displayName = "HITLSection";
337
624
  function useThinkingTimer({
338
625
  startTime,
339
626
  endTime,
@@ -523,7 +810,7 @@ function useAgentResponseAccumulator(options) {
523
810
  }, []);
524
811
  return { state, handleMessage, reset };
525
812
  }
526
- var AgentResponse = React7.forwardRef(
813
+ var AgentResponse = React10.forwardRef(
527
814
  ({
528
815
  state,
529
816
  id,
@@ -535,6 +822,8 @@ var AgentResponse = React7.forwardRef(
535
822
  thinkingExpanded: controlledThinkingExpanded,
536
823
  onThinkingExpandedChange,
537
824
  actionsVisible = "hover",
825
+ hitlInteractions,
826
+ defaultHITLExpanded = false,
538
827
  renderMarkdown,
539
828
  renderThinkingMarkdown,
540
829
  className,
@@ -562,7 +851,8 @@ var AgentResponse = React7.forwardRef(
562
851
  return (state.responseCompleteTime - state.firstMessageTime) / 1e3;
563
852
  }, [state.firstMessageTime, state.responseCompleteTime]);
564
853
  const hasThinkingContent = !!state.thinking || state.thinkingSteps && state.thinkingSteps.length > 0 || false;
565
- const hasAnyContent = hasThinkingContent || state.toolCalls.length > 0 || state.knowledge.length > 0 || state.memory.length > 0 || state.statusUpdates.length > 0 || state.response;
854
+ const hasHITLInteractions = hitlInteractions && hitlInteractions.length > 0;
855
+ const hasAnyContent = hasThinkingContent || state.toolCalls.length > 0 || state.knowledge.length > 0 || state.memory.length > 0 || state.statusUpdates.length > 0 || hasHITLInteractions || state.response;
566
856
  const showMetadataRow = hasThinkingContent || state.toolCalls.length > 0 || state.knowledge.length > 0 || state.memory.length > 0 || state.statusUpdates.length > 0 || state.status === "processing";
567
857
  const showActionBar = state.status === "complete" && state.response;
568
858
  const isActionBarVisible = actionsVisible === true || actionsVisible === "hover" && isHovered;
@@ -603,6 +893,13 @@ var AgentResponse = React7.forwardRef(
603
893
  }
604
894
  )
605
895
  ] }),
896
+ hasHITLInteractions && /* @__PURE__ */ jsx(
897
+ HITLSection,
898
+ {
899
+ interactions: hitlInteractions,
900
+ defaultExpanded: defaultHITLExpanded
901
+ }
902
+ ),
606
903
  state.response && /* @__PURE__ */ jsx(
607
904
  "div",
608
905
  {
@@ -631,7 +928,7 @@ var AgentResponse = React7.forwardRef(
631
928
  }
632
929
  );
633
930
  AgentResponse.displayName = "AgentResponse";
634
- var UserPrompt = React7.forwardRef(
931
+ var UserPrompt = React10.forwardRef(
635
932
  ({ content, timestamp, className, ...props }, ref) => {
636
933
  return /* @__PURE__ */ jsxs(
637
934
  "div",
@@ -730,7 +1027,7 @@ function CodeBlockLeaf({ attributes, children, leaf }) {
730
1027
  }
731
1028
  return /* @__PURE__ */ jsx("span", { ...attributes, children });
732
1029
  }
733
- var UserPromptInput = React7.forwardRef(
1030
+ var UserPromptInput = React10.forwardRef(
734
1031
  ({
735
1032
  value = "",
736
1033
  onChange,
@@ -753,14 +1050,14 @@ var UserPromptInput = React7.forwardRef(
753
1050
  className,
754
1051
  ...props
755
1052
  }, ref) => {
756
- const editorRef = React7.useRef(null);
757
- const [internalValue, setInternalValue] = React7.useState(value);
758
- const prevIsSubmitting = React7.useRef(isSubmitting);
759
- const hasEmittedReady = React7.useRef(false);
760
- React7.useEffect(() => {
1053
+ const editorRef = React10.useRef(null);
1054
+ const [internalValue, setInternalValue] = React10.useState(value);
1055
+ const prevIsSubmitting = React10.useRef(isSubmitting);
1056
+ const hasEmittedReady = React10.useRef(false);
1057
+ React10.useEffect(() => {
761
1058
  setInternalValue(value);
762
1059
  }, [value]);
763
- React7.useEffect(() => {
1060
+ React10.useEffect(() => {
764
1061
  if (autoFocus) {
765
1062
  requestAnimationFrame(() => {
766
1063
  requestAnimationFrame(() => {
@@ -769,7 +1066,7 @@ var UserPromptInput = React7.forwardRef(
769
1066
  });
770
1067
  }
771
1068
  }, [autoFocus]);
772
- React7.useEffect(() => {
1069
+ React10.useEffect(() => {
773
1070
  if (!hasEmittedReady.current && onReady) {
774
1071
  requestAnimationFrame(() => {
775
1072
  requestAnimationFrame(() => {
@@ -779,7 +1076,7 @@ var UserPromptInput = React7.forwardRef(
779
1076
  });
780
1077
  }
781
1078
  }, [onReady]);
782
- React7.useEffect(() => {
1079
+ React10.useEffect(() => {
783
1080
  if (refocusAfterSubmit && prevIsSubmitting.current && !isSubmitting) {
784
1081
  requestAnimationFrame(() => {
785
1082
  editorRef.current?.focus();
@@ -787,7 +1084,7 @@ var UserPromptInput = React7.forwardRef(
787
1084
  }
788
1085
  prevIsSubmitting.current = isSubmitting;
789
1086
  }, [isSubmitting, refocusAfterSubmit]);
790
- React7.useImperativeHandle(
1087
+ React10.useImperativeHandle(
791
1088
  ref,
792
1089
  () => ({
793
1090
  focus: () => {
@@ -810,14 +1107,14 @@ var UserPromptInput = React7.forwardRef(
810
1107
  }),
811
1108
  []
812
1109
  );
813
- const handleChange = React7.useCallback(
1110
+ const handleChange = React10.useCallback(
814
1111
  (newValue) => {
815
1112
  setInternalValue(newValue);
816
1113
  onChange?.(newValue);
817
1114
  },
818
1115
  [onChange]
819
1116
  );
820
- const handleSubmit = React7.useCallback(
1117
+ const handleSubmit = React10.useCallback(
821
1118
  (text) => {
822
1119
  if (disabled || isSubmitting) return;
823
1120
  if (!text.trim()) return;
@@ -829,7 +1126,7 @@ var UserPromptInput = React7.forwardRef(
829
1126
  },
830
1127
  [disabled, isSubmitting, onSubmit, clearOnSubmit]
831
1128
  );
832
- const handleSendClick = React7.useCallback(() => {
1129
+ const handleSendClick = React10.useCallback(() => {
833
1130
  const text = editorRef.current?.getText() ?? "";
834
1131
  handleSubmit(text);
835
1132
  }, [handleSubmit]);
@@ -894,6 +1191,6 @@ var UserPromptInput = React7.forwardRef(
894
1191
  );
895
1192
  UserPromptInput.displayName = "UserPromptInput";
896
1193
 
897
- export { ActionBar, ActivityIndicators, AgentResponse, MetadataRow, ThinkingSection, UserPrompt, UserPromptInput, formatTime, formatTotalTime, initialAgentResponseState, useAgentResponseAccumulator, useThinkingTimer };
1194
+ export { ActionBar, ActivityIndicators, AgentResponse, HITLInteractionRecord, HITLQuestionPanel, HITLSection, MetadataRow, ThinkingSection, UserPrompt, UserPromptInput, buildResponseString, formatTime, formatTotalTime, initialAgentResponseState, useAgentResponseAccumulator, useThinkingTimer };
898
1195
  //# sourceMappingURL=index.js.map
899
1196
  //# sourceMappingURL=index.js.map