@optilogic/chat 1.0.0-beta.8 → 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/README.md +93 -0
- package/dist/index.cjs +338 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +81 -1
- package/dist/index.d.ts +81 -1
- package/dist/index.js +322 -25
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/components/agent-response/AgentResponse.tsx +27 -1
- package/src/components/agent-response/components/HITLSection.tsx +95 -0
- package/src/components/agent-response/components/index.ts +3 -0
- package/src/components/agent-response/index.ts +2 -0
- package/src/components/hitl-interactions/HITLInteractionRecord.tsx +139 -0
- package/src/components/hitl-interactions/HITLQuestionPanel.tsx +256 -0
- package/src/components/hitl-interactions/index.ts +18 -0
- package/src/index.ts +13 -0
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
|
|
2
|
-
import { useState, useCallback,
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
757
|
-
const [internalValue, setInternalValue] =
|
|
758
|
-
const prevIsSubmitting =
|
|
759
|
-
const hasEmittedReady =
|
|
760
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|