@cntyclub/agent-react 0.9.0 → 0.9.1
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/components/agent-composer.d.ts +7 -1
- package/dist/components/agent-composer.d.ts.map +1 -1
- package/dist/components/agent-panel.d.ts.map +1 -1
- package/dist/components/chat-scroller.d.ts +17 -0
- package/dist/components/chat-scroller.d.ts.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +96 -64
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -4,7 +4,13 @@ export interface AgentComposerProps {
|
|
|
4
4
|
onValueChange: (value: string) => void;
|
|
5
5
|
/** Submit the trimmed text plus any staged files. */
|
|
6
6
|
onSubmit: (text: string) => void;
|
|
7
|
+
/** Hard-disable the input entirely (e.g. a pending approval must be resolved). */
|
|
7
8
|
disabled?: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* A reply is in progress. The textarea stays enabled and focused so the user
|
|
11
|
+
* can start writing their next message, but submitting is blocked until done.
|
|
12
|
+
*/
|
|
13
|
+
busy?: boolean;
|
|
8
14
|
placeholder?: string;
|
|
9
15
|
className?: string;
|
|
10
16
|
/** File upload wiring. Omit `onPickFiles` to hide the attach button. */
|
|
@@ -19,5 +25,5 @@ export interface AgentComposerProps {
|
|
|
19
25
|
* Shift+Enter inserts a newline. Submitting is allowed when there is text OR at
|
|
20
26
|
* least one staged file.
|
|
21
27
|
*/
|
|
22
|
-
export declare function AgentComposer({ acceptAttribute, className, disabled, files, onPickFiles, onRemoveFile, onSubmit, onValueChange, placeholder, value, }: AgentComposerProps): React.JSX.Element;
|
|
28
|
+
export declare function AgentComposer({ acceptAttribute, busy, className, disabled, files, onPickFiles, onRemoveFile, onSubmit, onValueChange, placeholder, value, }: AgentComposerProps): React.JSX.Element;
|
|
23
29
|
//# sourceMappingURL=agent-composer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-composer.d.ts","sourceRoot":"","sources":["../../src/components/agent-composer.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,qDAAqD;IACrD,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wEAAwE;IACxE,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;IACtC,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,EAC5B,eAAe,EACf,SAAS,EACT,QAAQ,EACR,KAAK,EACL,WAAW,EACX,YAAY,EACZ,QAAQ,EACR,aAAa,EACb,WAA6B,EAC7B,KAAK,GACN,EAAE,kBAAkB,
|
|
1
|
+
{"version":3,"file":"agent-composer.d.ts","sourceRoot":"","sources":["../../src/components/agent-composer.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,qDAAqD;IACrD,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,kFAAkF;IAClF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wEAAwE;IACxE,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;IACtC,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,EAC5B,eAAe,EACf,IAAI,EACJ,SAAS,EACT,QAAQ,EACR,KAAK,EACL,WAAW,EACX,YAAY,EACZ,QAAQ,EACR,aAAa,EACb,WAA6B,EAC7B,KAAK,GACN,EAAE,kBAAkB,qBA6HpB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-panel.d.ts","sourceRoot":"","sources":["../../src/components/agent-panel.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agent-panel.d.ts","sourceRoot":"","sources":["../../src/components/agent-panel.tsx"],"names":[],"mappings":"AA8BA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAQ5C,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,WAAW,CAAC;IACpB,IAAI,EAAE,cAAc,GAAG,gBAAgB,CAAC;IACxC,yCAAyC;IACzC,SAAS,EAAE,OAAO,CAAC;IACnB,4DAA4D;IAC5D,kBAAkB,EAAE,OAAO,CAAC;IAC5B,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,iEAAiE;IACjE,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,EACzB,SAAS,EACT,kBAAkB,EAClB,IAAI,EACJ,SAAS,EACT,MAAM,EACN,eAAe,EACf,OAAO,EACP,iBAAiB,GAClB,EAAE,eAAe,qBAkTjB"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export type ChatScrollerProps = React.ComponentProps<"div">;
|
|
3
|
+
/**
|
|
4
|
+
* Scrollable message viewport that stays pinned to the bottom while content
|
|
5
|
+
* grows — including token-by-token streaming, where text is appended to the
|
|
6
|
+
* SAME message rather than adding new ones.
|
|
7
|
+
*
|
|
8
|
+
* Why not the UI kit's ChatMessages autoScroll: that container uses CSS
|
|
9
|
+
* `scroll-smooth`, so a programmatic jump to the bottom emits intermediate
|
|
10
|
+
* `scroll` events mid-animation whose distance-from-bottom is large, which
|
|
11
|
+
* flips its "pinned" flag to false — after the first delta it stops following.
|
|
12
|
+
* Here we scroll INSTANTLY (no smooth), so the only resulting scroll event is
|
|
13
|
+
* at the true bottom and the pin holds for the whole stream. The user can still
|
|
14
|
+
* scroll up to read history (that unpins), and scrolling back down re-pins.
|
|
15
|
+
*/
|
|
16
|
+
export declare function ChatScroller({ children, className, ...props }: ChatScrollerProps): React.JSX.Element;
|
|
17
|
+
//# sourceMappingURL=chat-scroller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-scroller.d.ts","sourceRoot":"","sources":["../../src/components/chat-scroller.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,MAAM,MAAM,iBAAiB,GAAG,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;AAE5D;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,iBAAiB,qBA8BhF"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export { AgentApiClient, AgentApiError } from "./api-client";
|
|
|
2
2
|
export { AgentComposer, type AgentComposerProps } from "./components/agent-composer";
|
|
3
3
|
export { AgentPanel, type AgentPanelProps } from "./components/agent-panel";
|
|
4
4
|
export { AgentWidget, type AgentWidgetProps } from "./components/agent-widget";
|
|
5
|
+
export { ChatScroller, type ChatScrollerProps } from "./components/chat-scroller";
|
|
5
6
|
export { DocumentCard } from "./components/document-card";
|
|
6
7
|
export { MessageItem } from "./components/message-item";
|
|
7
8
|
export { TaskChecklist } from "./components/task-checklist";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACrF,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACjG,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAClG,OAAO,EAAE,gBAAgB,EAAE,KAAK,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAC/F,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,WAAW,EACX,YAAY,GACb,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,KAAK,UAAU,EAAE,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChF,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,uBAAuB,EACvB,KAAK,wBAAwB,GAC9B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,gBAAgB,EAAE,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACjF,YAAY,EACV,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,WAAW,EACX,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,YAAY,EACZ,eAAe,EACf,UAAU,EACV,QAAQ,EACR,UAAU,EACV,UAAU,EACV,mBAAmB,EACnB,cAAc,EACd,YAAY,EACZ,iBAAiB,GAClB,MAAM,SAAS,CAAC;AAEjB,YAAY,EACV,UAAU,IAAI,mBAAmB,EACjC,UAAU,IAAI,mBAAmB,EACjC,KAAK,IAAI,cAAc,GACxB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,YAAY,EACZ,KAAK,gBAAgB,EACrB,KAAK,cAAc,GACpB,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACrF,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAClF,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACjG,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAClG,OAAO,EAAE,gBAAgB,EAAE,KAAK,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAC/F,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,WAAW,EACX,YAAY,GACb,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,KAAK,UAAU,EAAE,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChF,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,uBAAuB,EACvB,KAAK,wBAAwB,GAC9B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,gBAAgB,EAAE,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACjF,YAAY,EACV,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,WAAW,EACX,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,YAAY,EACZ,eAAe,EACf,UAAU,EACV,QAAQ,EACR,UAAU,EACV,UAAU,EACV,mBAAmB,EACnB,cAAc,EACd,YAAY,EACZ,iBAAiB,GAClB,MAAM,SAAS,CAAC;AAEjB,YAAY,EACV,UAAU,IAAI,mBAAmB,EACjC,UAAU,IAAI,mBAAmB,EACjC,KAAK,IAAI,cAAc,GACxB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,YAAY,EACZ,KAAK,gBAAgB,EACrB,KAAK,cAAc,GACpB,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Button, cn, ChatMessage, ChatMessageBubble, Markdown, Spinner, Checkbox, Collapsible, CollapsibleTrigger, ChatToolChip, CollapsiblePanel, ChatToolCard, ChatToolCardHeader, ChatToolCardActions, Group, Menu, MenuTrigger, MenuPopup, MenuItem, ChatHeader, ChatHeaderAvatar, ChatHeaderTitle, ChatHeaderActions, Tooltip, TooltipTrigger, TooltipContent, Chat,
|
|
1
|
+
import { Button, cn, ChatMessage, ChatMessageBubble, Markdown, Spinner, Checkbox, Collapsible, CollapsibleTrigger, ChatToolChip, CollapsiblePanel, ChatToolCard, ChatToolCardHeader, ChatToolCardActions, Group, Menu, MenuTrigger, MenuPopup, MenuItem, ChatHeader, ChatHeaderAvatar, ChatHeaderTitle, ChatHeaderActions, Tooltip, TooltipTrigger, TooltipContent, Chat, ChatEmptyState, ChatEmptyStateIcon, ChatEmptyStateTitle, ChatEmptyStateDescription, ChatSuggestions, ChatSuggestion, useMediaQuery, TooltipProvider, Fab, DataTablePaged } from '@cntyclub/ui-react';
|
|
2
2
|
import { FileTextIcon, XIcon, PaperclipIcon, ArrowUpIcon, Maximize2Icon, ListChecksIcon, ChevronDownIcon, CheckIcon, ShieldAlertIcon, CheckCheckIcon, UploadCloudIcon, HistoryIcon, SquarePenIcon, Minimize2Icon, Trash2Icon, SparklesIcon, DownloadIcon, CodeIcon } from 'lucide-react';
|
|
3
|
-
import * as
|
|
3
|
+
import * as React7 from 'react';
|
|
4
4
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
5
|
|
|
6
6
|
// src/api-client.ts
|
|
@@ -219,6 +219,7 @@ function formatBytes(bytes) {
|
|
|
219
219
|
}
|
|
220
220
|
function AgentComposer({
|
|
221
221
|
acceptAttribute: acceptAttribute2,
|
|
222
|
+
busy,
|
|
222
223
|
className,
|
|
223
224
|
disabled,
|
|
224
225
|
files,
|
|
@@ -229,14 +230,18 @@ function AgentComposer({
|
|
|
229
230
|
placeholder = "Ask anything\u2026",
|
|
230
231
|
value
|
|
231
232
|
}) {
|
|
232
|
-
const textareaRef =
|
|
233
|
-
const inputRef =
|
|
234
|
-
const canSubmit = !disabled && (value.trim().length > 0 || files.length > 0);
|
|
235
|
-
const submit =
|
|
233
|
+
const textareaRef = React7.useRef(null);
|
|
234
|
+
const inputRef = React7.useRef(null);
|
|
235
|
+
const canSubmit = !disabled && !busy && (value.trim().length > 0 || files.length > 0);
|
|
236
|
+
const submit = React7.useCallback(() => {
|
|
236
237
|
if (!canSubmit) return;
|
|
237
238
|
onSubmit(value.trim());
|
|
239
|
+
textareaRef.current?.focus();
|
|
238
240
|
}, [canSubmit, onSubmit, value]);
|
|
239
|
-
|
|
241
|
+
React7.useEffect(() => {
|
|
242
|
+
if (!disabled) textareaRef.current?.focus();
|
|
243
|
+
}, [disabled]);
|
|
244
|
+
React7.useEffect(() => {
|
|
240
245
|
const textarea = textareaRef.current;
|
|
241
246
|
if (!textarea) return;
|
|
242
247
|
textarea.style.height = "auto";
|
|
@@ -417,6 +422,32 @@ function groupMessages(messages) {
|
|
|
417
422
|
flush();
|
|
418
423
|
return items;
|
|
419
424
|
}
|
|
425
|
+
function ChatScroller({ children, className, ...props }) {
|
|
426
|
+
const viewportRef = React7.useRef(null);
|
|
427
|
+
const pinnedRef = React7.useRef(true);
|
|
428
|
+
const handleScroll = React7.useCallback(() => {
|
|
429
|
+
const viewport = viewportRef.current;
|
|
430
|
+
if (!viewport) return;
|
|
431
|
+
const distanceFromBottom = viewport.scrollHeight - viewport.scrollTop - viewport.clientHeight;
|
|
432
|
+
pinnedRef.current = distanceFromBottom < 64;
|
|
433
|
+
}, []);
|
|
434
|
+
React7.useEffect(() => {
|
|
435
|
+
const viewport = viewportRef.current;
|
|
436
|
+
if (!viewport || !pinnedRef.current) return;
|
|
437
|
+
viewport.scrollTop = viewport.scrollHeight;
|
|
438
|
+
});
|
|
439
|
+
return /* @__PURE__ */ jsx(
|
|
440
|
+
"div",
|
|
441
|
+
{
|
|
442
|
+
className: cn("flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto p-4", className),
|
|
443
|
+
"data-slot": "chat-scroller",
|
|
444
|
+
onScroll: handleScroll,
|
|
445
|
+
ref: viewportRef,
|
|
446
|
+
...props,
|
|
447
|
+
children
|
|
448
|
+
}
|
|
449
|
+
);
|
|
450
|
+
}
|
|
420
451
|
function MessageItem({ message }) {
|
|
421
452
|
if (message.role === "user") {
|
|
422
453
|
const attachments = message.attachments ?? [];
|
|
@@ -451,8 +482,8 @@ var DEFAULT_PHRASES = [
|
|
|
451
482
|
];
|
|
452
483
|
function ThinkingIndicator({ className, intervalMs = 1800, phrases }) {
|
|
453
484
|
const words = phrases && phrases.length ? phrases : DEFAULT_PHRASES;
|
|
454
|
-
const [index, setIndex] =
|
|
455
|
-
|
|
485
|
+
const [index, setIndex] = React7.useState(0);
|
|
486
|
+
React7.useEffect(() => {
|
|
456
487
|
setIndex(0);
|
|
457
488
|
const timer = setInterval(() => {
|
|
458
489
|
setIndex((current) => (current + 1) % words.length);
|
|
@@ -481,7 +512,7 @@ function ThinkingIndicator({ className, intervalMs = 1800, phrases }) {
|
|
|
481
512
|
className: "fade-in-0 animate-in text-muted-foreground text-xs duration-300",
|
|
482
513
|
children: [
|
|
483
514
|
words[index],
|
|
484
|
-
"\u2026"
|
|
515
|
+
" \u2026"
|
|
485
516
|
]
|
|
486
517
|
},
|
|
487
518
|
index
|
|
@@ -714,7 +745,7 @@ function DownloadButton({ block, size = "sm" }) {
|
|
|
714
745
|
);
|
|
715
746
|
}
|
|
716
747
|
function DocumentViewer({ block, onClose }) {
|
|
717
|
-
|
|
748
|
+
React7.useEffect(() => {
|
|
718
749
|
const onKey = (event) => event.key === "Escape" && onClose();
|
|
719
750
|
window.addEventListener("keydown", onKey);
|
|
720
751
|
return () => window.removeEventListener("keydown", onKey);
|
|
@@ -739,7 +770,7 @@ function DocumentViewer({ block, onClose }) {
|
|
|
739
770
|
] });
|
|
740
771
|
}
|
|
741
772
|
function DocumentCard({ block }) {
|
|
742
|
-
const [open, setOpen] =
|
|
773
|
+
const [open, setOpen] = React7.useState(false);
|
|
743
774
|
const previewLines = (block.preview || "").split("\n").slice(0, 6).join("\n");
|
|
744
775
|
return /* @__PURE__ */ jsxs("div", { className: "w-full max-w-full overflow-hidden rounded-xl border border-border bg-card shadow-xs", children: [
|
|
745
776
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-border/72 border-b px-3 py-2", children: [
|
|
@@ -861,7 +892,7 @@ function StepDetail({
|
|
|
861
892
|
] });
|
|
862
893
|
}
|
|
863
894
|
function ToolActivityGroup({ describeToolCall, steps }) {
|
|
864
|
-
const [open, setOpen] =
|
|
895
|
+
const [open, setOpen] = React7.useState(false);
|
|
865
896
|
if (steps.length === 0) return null;
|
|
866
897
|
const last = steps[steps.length - 1];
|
|
867
898
|
const anyRunning = steps.some((step) => step.status === "running");
|
|
@@ -964,19 +995,19 @@ function AgentPanel({
|
|
|
964
995
|
onClose,
|
|
965
996
|
onToggleAgentMode
|
|
966
997
|
}) {
|
|
967
|
-
const [draft, setDraft] =
|
|
968
|
-
const [view, setView] =
|
|
969
|
-
const [files, setFiles] =
|
|
970
|
-
const [uploadError, setUploadError] =
|
|
971
|
-
const [dragging, setDragging] =
|
|
972
|
-
const dragDepth =
|
|
998
|
+
const [draft, setDraft] = React7.useState("");
|
|
999
|
+
const [view, setView] = React7.useState("chat");
|
|
1000
|
+
const [files, setFiles] = React7.useState([]);
|
|
1001
|
+
const [uploadError, setUploadError] = React7.useState(null);
|
|
1002
|
+
const [dragging, setDragging] = React7.useState(false);
|
|
1003
|
+
const dragDepth = React7.useRef(0);
|
|
973
1004
|
const agentName = config.agentName ?? chat.agentInfo?.name ?? "Assistant";
|
|
974
1005
|
const uploadEnabled = fileUploadEnabled(config);
|
|
975
1006
|
const suggestions = config.suggestions ?? [
|
|
976
1007
|
"What can you help me with?",
|
|
977
1008
|
"Give me a quick summary of my data."
|
|
978
1009
|
];
|
|
979
|
-
const addFiles =
|
|
1010
|
+
const addFiles = React7.useCallback(
|
|
980
1011
|
(incoming) => {
|
|
981
1012
|
const accepted = [];
|
|
982
1013
|
let rejection = null;
|
|
@@ -993,10 +1024,10 @@ function AgentPanel({
|
|
|
993
1024
|
},
|
|
994
1025
|
[config]
|
|
995
1026
|
);
|
|
996
|
-
const removeFile =
|
|
1027
|
+
const removeFile = React7.useCallback((index) => {
|
|
997
1028
|
setFiles((current) => current.filter((_, i) => i !== index));
|
|
998
1029
|
}, []);
|
|
999
|
-
const handleSubmit =
|
|
1030
|
+
const handleSubmit = React7.useCallback(
|
|
1000
1031
|
(text) => {
|
|
1001
1032
|
const staged = files;
|
|
1002
1033
|
setDraft("");
|
|
@@ -1006,7 +1037,7 @@ function AgentPanel({
|
|
|
1006
1037
|
},
|
|
1007
1038
|
[chat, files]
|
|
1008
1039
|
);
|
|
1009
|
-
const onDragEnter =
|
|
1040
|
+
const onDragEnter = React7.useCallback(
|
|
1010
1041
|
(event) => {
|
|
1011
1042
|
if (!uploadEnabled || !event.dataTransfer?.types?.includes("Files")) return;
|
|
1012
1043
|
dragDepth.current += 1;
|
|
@@ -1014,12 +1045,12 @@ function AgentPanel({
|
|
|
1014
1045
|
},
|
|
1015
1046
|
[uploadEnabled]
|
|
1016
1047
|
);
|
|
1017
|
-
const onDragLeave =
|
|
1048
|
+
const onDragLeave = React7.useCallback((event) => {
|
|
1018
1049
|
if (!event.dataTransfer?.types?.includes("Files")) return;
|
|
1019
1050
|
dragDepth.current = Math.max(0, dragDepth.current - 1);
|
|
1020
1051
|
if (dragDepth.current === 0) setDragging(false);
|
|
1021
1052
|
}, []);
|
|
1022
|
-
const onDrop =
|
|
1053
|
+
const onDrop = React7.useCallback(
|
|
1023
1054
|
(event) => {
|
|
1024
1055
|
if (!uploadEnabled) return;
|
|
1025
1056
|
event.preventDefault();
|
|
@@ -1030,7 +1061,7 @@ function AgentPanel({
|
|
|
1030
1061
|
},
|
|
1031
1062
|
[addFiles, uploadEnabled]
|
|
1032
1063
|
);
|
|
1033
|
-
const openHistory =
|
|
1064
|
+
const openHistory = React7.useCallback(() => {
|
|
1034
1065
|
setView("history");
|
|
1035
1066
|
void chat.refreshConversations();
|
|
1036
1067
|
}, [chat]);
|
|
@@ -1160,7 +1191,7 @@ function AgentPanel({
|
|
|
1160
1191
|
},
|
|
1161
1192
|
conversation.id
|
|
1162
1193
|
)) }) : /* @__PURE__ */ jsxs(Chat, { children: [
|
|
1163
|
-
/* @__PURE__ */ jsx(
|
|
1194
|
+
/* @__PURE__ */ jsx(ChatScroller, { className: cn(agentMode && "mx-auto w-full max-w-3xl"), children: chat.messages.length === 0 && !chat.sending ? /* @__PURE__ */ jsxs(ChatEmptyState, { children: [
|
|
1164
1195
|
/* @__PURE__ */ jsx(ChatEmptyStateIcon, {}),
|
|
1165
1196
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
1166
1197
|
/* @__PURE__ */ jsxs(ChatEmptyStateTitle, { children: [
|
|
@@ -1215,8 +1246,9 @@ function AgentPanel({
|
|
|
1215
1246
|
AgentComposer,
|
|
1216
1247
|
{
|
|
1217
1248
|
acceptAttribute: acceptAttribute(config),
|
|
1249
|
+
busy,
|
|
1218
1250
|
className: cn(agentMode && "mx-auto w-full max-w-3xl"),
|
|
1219
|
-
disabled:
|
|
1251
|
+
disabled: chat.pendingApprovals.length > 0,
|
|
1220
1252
|
files,
|
|
1221
1253
|
onPickFiles: uploadEnabled ? addFiles : void 0,
|
|
1222
1254
|
onRemoveFile: removeFile,
|
|
@@ -1252,16 +1284,16 @@ function buildOptimisticUserMessage(text, files) {
|
|
|
1252
1284
|
};
|
|
1253
1285
|
}
|
|
1254
1286
|
function useAgentChat(config) {
|
|
1255
|
-
const client =
|
|
1256
|
-
const [agentInfo, setAgentInfo] =
|
|
1257
|
-
const [conversationId, setConversationId] =
|
|
1258
|
-
const [conversations, setConversations] =
|
|
1259
|
-
const [messages, setMessages] =
|
|
1260
|
-
const [pendingApprovals, setPendingApprovals] =
|
|
1261
|
-
const [sending, setSending] =
|
|
1262
|
-
const [resolvingApprovalId, setResolvingApprovalId] =
|
|
1263
|
-
const [error, setError] =
|
|
1264
|
-
|
|
1287
|
+
const client = React7.useMemo(() => new AgentApiClient(config), [config]);
|
|
1288
|
+
const [agentInfo, setAgentInfo] = React7.useState(null);
|
|
1289
|
+
const [conversationId, setConversationId] = React7.useState(null);
|
|
1290
|
+
const [conversations, setConversations] = React7.useState([]);
|
|
1291
|
+
const [messages, setMessages] = React7.useState([]);
|
|
1292
|
+
const [pendingApprovals, setPendingApprovals] = React7.useState([]);
|
|
1293
|
+
const [sending, setSending] = React7.useState(false);
|
|
1294
|
+
const [resolvingApprovalId, setResolvingApprovalId] = React7.useState(null);
|
|
1295
|
+
const [error, setError] = React7.useState(null);
|
|
1296
|
+
React7.useEffect(() => {
|
|
1265
1297
|
let cancelled = false;
|
|
1266
1298
|
client.getConfig().then((info) => {
|
|
1267
1299
|
if (!cancelled) setAgentInfo(info);
|
|
@@ -1271,11 +1303,11 @@ function useAgentChat(config) {
|
|
|
1271
1303
|
cancelled = true;
|
|
1272
1304
|
};
|
|
1273
1305
|
}, [client]);
|
|
1274
|
-
const handleFailure =
|
|
1306
|
+
const handleFailure = React7.useCallback((err) => {
|
|
1275
1307
|
const message = err instanceof AgentApiError ? err.message : "Something went wrong. Please try again.";
|
|
1276
1308
|
setError(message);
|
|
1277
1309
|
}, []);
|
|
1278
|
-
const applyResponse =
|
|
1310
|
+
const applyResponse = React7.useCallback(
|
|
1279
1311
|
(response) => {
|
|
1280
1312
|
if (response.status === "error" && !response.messages?.length) {
|
|
1281
1313
|
setError(response.message ?? "The assistant could not answer.");
|
|
@@ -1297,7 +1329,7 @@ function useAgentChat(config) {
|
|
|
1297
1329
|
},
|
|
1298
1330
|
[]
|
|
1299
1331
|
);
|
|
1300
|
-
const handleStreamEvent =
|
|
1332
|
+
const handleStreamEvent = React7.useCallback(
|
|
1301
1333
|
(event, ctx) => {
|
|
1302
1334
|
switch (event.type) {
|
|
1303
1335
|
case "conversation":
|
|
@@ -1362,7 +1394,7 @@ function useAgentChat(config) {
|
|
|
1362
1394
|
[]
|
|
1363
1395
|
);
|
|
1364
1396
|
const streamingEnabled = config.streaming !== false && typeof ReadableStream !== "undefined";
|
|
1365
|
-
const send =
|
|
1397
|
+
const send = React7.useCallback(
|
|
1366
1398
|
async (text, files) => {
|
|
1367
1399
|
if (sending) return;
|
|
1368
1400
|
if (!text.trim() && !(files && files.length)) return;
|
|
@@ -1393,7 +1425,7 @@ function useAgentChat(config) {
|
|
|
1393
1425
|
},
|
|
1394
1426
|
[applyResponse, client, conversationId, handleFailure, handleStreamEvent, sending, streamingEnabled]
|
|
1395
1427
|
);
|
|
1396
|
-
const resolveApproval =
|
|
1428
|
+
const resolveApproval = React7.useCallback(
|
|
1397
1429
|
async (callId, approve) => {
|
|
1398
1430
|
if (resolvingApprovalId) return;
|
|
1399
1431
|
setResolvingApprovalId(callId);
|
|
@@ -1422,13 +1454,13 @@ function useAgentChat(config) {
|
|
|
1422
1454
|
},
|
|
1423
1455
|
[applyResponse, client, handleFailure, handleStreamEvent, resolvingApprovalId, streamingEnabled]
|
|
1424
1456
|
);
|
|
1425
|
-
const newChat =
|
|
1457
|
+
const newChat = React7.useCallback(() => {
|
|
1426
1458
|
setConversationId(null);
|
|
1427
1459
|
setMessages([]);
|
|
1428
1460
|
setPendingApprovals([]);
|
|
1429
1461
|
setError(null);
|
|
1430
1462
|
}, []);
|
|
1431
|
-
const refreshConversations =
|
|
1463
|
+
const refreshConversations = React7.useCallback(async () => {
|
|
1432
1464
|
try {
|
|
1433
1465
|
const { conversations: list } = await client.listConversations();
|
|
1434
1466
|
setConversations(list);
|
|
@@ -1436,7 +1468,7 @@ function useAgentChat(config) {
|
|
|
1436
1468
|
handleFailure(err);
|
|
1437
1469
|
}
|
|
1438
1470
|
}, [client, handleFailure]);
|
|
1439
|
-
const openConversation =
|
|
1471
|
+
const openConversation = React7.useCallback(
|
|
1440
1472
|
async (id) => {
|
|
1441
1473
|
setError(null);
|
|
1442
1474
|
try {
|
|
@@ -1450,7 +1482,7 @@ function useAgentChat(config) {
|
|
|
1450
1482
|
},
|
|
1451
1483
|
[client, handleFailure]
|
|
1452
1484
|
);
|
|
1453
|
-
const deleteConversation =
|
|
1485
|
+
const deleteConversation = React7.useCallback(
|
|
1454
1486
|
async (id) => {
|
|
1455
1487
|
try {
|
|
1456
1488
|
await client.deleteConversation(id);
|
|
@@ -1462,7 +1494,7 @@ function useAgentChat(config) {
|
|
|
1462
1494
|
},
|
|
1463
1495
|
[client, conversationId, handleFailure, newChat]
|
|
1464
1496
|
);
|
|
1465
|
-
const clearError =
|
|
1497
|
+
const clearError = React7.useCallback(() => setError(null), []);
|
|
1466
1498
|
return {
|
|
1467
1499
|
agentInfo,
|
|
1468
1500
|
clearError,
|
|
@@ -1497,11 +1529,11 @@ function readStored(clientId) {
|
|
|
1497
1529
|
}
|
|
1498
1530
|
}
|
|
1499
1531
|
function useAlwaysApprove(clientId) {
|
|
1500
|
-
const [approved, setApproved] =
|
|
1501
|
-
|
|
1532
|
+
const [approved, setApproved] = React7.useState(() => /* @__PURE__ */ new Set());
|
|
1533
|
+
React7.useEffect(() => {
|
|
1502
1534
|
setApproved(readStored(clientId));
|
|
1503
1535
|
}, [clientId]);
|
|
1504
|
-
const persist =
|
|
1536
|
+
const persist = React7.useCallback(
|
|
1505
1537
|
(next) => {
|
|
1506
1538
|
setApproved(next);
|
|
1507
1539
|
if (typeof window === "undefined") return;
|
|
@@ -1512,8 +1544,8 @@ function useAlwaysApprove(clientId) {
|
|
|
1512
1544
|
},
|
|
1513
1545
|
[clientId]
|
|
1514
1546
|
);
|
|
1515
|
-
const isAlwaysApproved =
|
|
1516
|
-
const setAlwaysApprove =
|
|
1547
|
+
const isAlwaysApproved = React7.useCallback((toolName) => approved.has(toolName), [approved]);
|
|
1548
|
+
const setAlwaysApprove = React7.useCallback(
|
|
1517
1549
|
(toolName) => {
|
|
1518
1550
|
if (approved.has(toolName)) return;
|
|
1519
1551
|
const next = new Set(approved);
|
|
@@ -1522,7 +1554,7 @@ function useAlwaysApprove(clientId) {
|
|
|
1522
1554
|
},
|
|
1523
1555
|
[approved, persist]
|
|
1524
1556
|
);
|
|
1525
|
-
const clearAlwaysApprove =
|
|
1557
|
+
const clearAlwaysApprove = React7.useCallback(
|
|
1526
1558
|
(toolName) => {
|
|
1527
1559
|
if (!approved.has(toolName)) return;
|
|
1528
1560
|
const next = new Set(approved);
|
|
@@ -1534,16 +1566,16 @@ function useAlwaysApprove(clientId) {
|
|
|
1534
1566
|
return { clearAlwaysApprove, isAlwaysApproved, setAlwaysApprove };
|
|
1535
1567
|
}
|
|
1536
1568
|
function AgentWidget({ config, onOpenChange, open: controlledOpen }) {
|
|
1537
|
-
const [uncontrolledOpen, setUncontrolledOpen] =
|
|
1569
|
+
const [uncontrolledOpen, setUncontrolledOpen] = React7.useState(false);
|
|
1538
1570
|
const open = controlledOpen ?? uncontrolledOpen;
|
|
1539
|
-
const setOpen =
|
|
1571
|
+
const setOpen = React7.useCallback(
|
|
1540
1572
|
(next) => {
|
|
1541
1573
|
setUncontrolledOpen(next);
|
|
1542
1574
|
onOpenChange?.(next);
|
|
1543
1575
|
},
|
|
1544
1576
|
[onOpenChange]
|
|
1545
1577
|
);
|
|
1546
|
-
const [agentMode, setAgentMode] =
|
|
1578
|
+
const [agentMode, setAgentMode] = React7.useState(false);
|
|
1547
1579
|
const isDesktop = useMediaQuery("(min-width: 640px)", {
|
|
1548
1580
|
defaultSSRValue: true,
|
|
1549
1581
|
ssr: true
|
|
@@ -1553,14 +1585,14 @@ function AgentWidget({ config, onOpenChange, open: controlledOpen }) {
|
|
|
1553
1585
|
const alwaysApprove = useAlwaysApprove(config.clientId);
|
|
1554
1586
|
const { pendingApprovals, resolveApproval, resolvingApprovalId } = chat;
|
|
1555
1587
|
const { isAlwaysApproved } = alwaysApprove;
|
|
1556
|
-
|
|
1588
|
+
React7.useEffect(() => {
|
|
1557
1589
|
if (!open || resolvingApprovalId) return;
|
|
1558
1590
|
const target = pendingApprovals.find((approval) => isAlwaysApproved(approval.tool_name));
|
|
1559
1591
|
if (target) void resolveApproval(target.id, true);
|
|
1560
1592
|
}, [open, pendingApprovals, resolvingApprovalId, isAlwaysApproved, resolveApproval]);
|
|
1561
|
-
const firedWriteIds =
|
|
1593
|
+
const firedWriteIds = React7.useRef(/* @__PURE__ */ new Set());
|
|
1562
1594
|
const { onWriteSuccess } = config;
|
|
1563
|
-
|
|
1595
|
+
React7.useEffect(() => {
|
|
1564
1596
|
if (!onWriteSuccess) return;
|
|
1565
1597
|
for (const message of chat.messages) {
|
|
1566
1598
|
if (message.role !== "tool" || !message.is_write || message.tool_status !== "success") continue;
|
|
@@ -1570,9 +1602,9 @@ function AgentWidget({ config, onOpenChange, open: controlledOpen }) {
|
|
|
1570
1602
|
onWriteSuccess({ arguments: args, toolName: message.tool_name ?? "" });
|
|
1571
1603
|
}
|
|
1572
1604
|
}, [chat.messages, onWriteSuccess]);
|
|
1573
|
-
const lastNavigatedMessageId =
|
|
1605
|
+
const lastNavigatedMessageId = React7.useRef(null);
|
|
1574
1606
|
const { messages } = chat;
|
|
1575
|
-
|
|
1607
|
+
React7.useEffect(() => {
|
|
1576
1608
|
if (!open || fullscreen || !config.navigate || !config.pages?.length) return;
|
|
1577
1609
|
const toolMessages = messages.filter((message) => message.role === "tool");
|
|
1578
1610
|
const latest = toolMessages[toolMessages.length - 1];
|
|
@@ -1584,7 +1616,7 @@ function AgentWidget({ config, onOpenChange, open: controlledOpen }) {
|
|
|
1584
1616
|
const path = mapping.buildRoute ? mapping.buildRoute(args) : mapping.route;
|
|
1585
1617
|
if (path) config.navigate(path);
|
|
1586
1618
|
}, [config, fullscreen, messages, open]);
|
|
1587
|
-
const closePanel =
|
|
1619
|
+
const closePanel = React7.useCallback(() => {
|
|
1588
1620
|
setOpen(false);
|
|
1589
1621
|
setAgentMode(false);
|
|
1590
1622
|
}, [setOpen]);
|
|
@@ -1663,6 +1695,6 @@ function defineAgentConfig(config) {
|
|
|
1663
1695
|
return config;
|
|
1664
1696
|
}
|
|
1665
1697
|
|
|
1666
|
-
export { AgentApiClient, AgentApiError, AgentComposer, AgentPanel, AgentWidget, DEFAULT_ACCEPT, DocumentCard, MessageItem, TaskChecklist, ThinkingIndicator, ToolActivityGroup, ToolApprovalCard, acceptAttribute, acceptedExtensions, defineAgentConfig, deriveDetails, fileUploadEnabled, formatBytes, groupMessages, humanizeToolName, resolveToolPresentation, useAgentChat, useAlwaysApprove, validateFile };
|
|
1698
|
+
export { AgentApiClient, AgentApiError, AgentComposer, AgentPanel, AgentWidget, ChatScroller, DEFAULT_ACCEPT, DocumentCard, MessageItem, TaskChecklist, ThinkingIndicator, ToolActivityGroup, ToolApprovalCard, acceptAttribute, acceptedExtensions, defineAgentConfig, deriveDetails, fileUploadEnabled, formatBytes, groupMessages, humanizeToolName, resolveToolPresentation, useAgentChat, useAlwaysApprove, validateFile };
|
|
1667
1699
|
//# sourceMappingURL=index.js.map
|
|
1668
1700
|
//# sourceMappingURL=index.js.map
|