@tangle-network/ui 7.0.0 → 8.0.0
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/CHANGELOG.md +6 -0
- package/dist/chat.d.ts +7 -71
- package/dist/chat.js +1 -3
- package/dist/{chunk-5CS3I7Y3.js → chunk-UOLL2YHG.js} +21 -353
- package/dist/hooks.d.ts +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -9
- package/dist/run.d.ts +1 -1
- package/dist/run.js +2 -6
- package/dist/sdk-hooks.d.ts +1 -1
- package/dist/{tool-call-feed-Bs3MyQMT.d.ts → tool-call-feed-D9iofJgW.d.ts} +1 -23
- package/package.json +1 -1
- package/src/chat/chat-container.tsx +6 -48
- package/src/chat/chat-message.tsx +0 -4
- package/src/chat/index.ts +0 -1
- package/src/markdown/markdown.stories.tsx +1 -1
- package/src/run/index.ts +4 -1
- package/src/run/tool-call-step.tsx +5 -7
- package/src/chat/chat-input.stories.tsx +0 -142
- package/src/chat/chat-input.tsx +0 -389
- /package/dist/{chunk-LQS34IGP.js → chunk-47XH56SV.js} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @tangle-network/ui
|
|
2
2
|
|
|
3
|
+
## 8.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- 831e935: One composer, no zombie API. `ChatInput` is deleted — the canonical composer is `AgentComposer` in `@tangle-network/sandbox-ui`, composed below the transcript by the app. `ChatContainer` is now transcript-only: the input props (`onSend`, `onCancel`, `placeholder`, `hideInput`, `modelLabel`, `onModelClick`, `pendingFiles`, `onRemoveFile`, `onAttach`, `disabled`) and the `PendingFile` type are removed. `ChatMessage` drops the no-op `avatar`/`hideAvatar` props. `ToolCallStep`/`ToolCallGroup` are no longer exported (internal adapters over `InlineToolItem`); the `ToolCallType`/`ToolCallStatus` types stay public via `ToolCallData`, and `ToolCallFeed` is unchanged.
|
|
8
|
+
|
|
3
9
|
## 7.0.0
|
|
4
10
|
|
|
5
11
|
### Minor Changes
|
package/dist/chat.d.ts
CHANGED
|
@@ -7,83 +7,23 @@ import { AgentBranding } from './types.js';
|
|
|
7
7
|
import { C as CustomToolRenderer } from './tool-display-z4JcDmMQ.js';
|
|
8
8
|
import { R as Run, G as GroupedMessage } from './run-PfLmDAox.js';
|
|
9
9
|
import { OpenUIAction } from './openui.js';
|
|
10
|
-
import { T as ToolCallData } from './tool-call-feed-
|
|
10
|
+
import { T as ToolCallData } from './tool-call-feed-D9iofJgW.js';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* -
|
|
16
|
-
* - Enter to send, Shift+Enter for newline
|
|
17
|
-
* - Drag-and-drop files onto the input with styled overlay
|
|
18
|
-
* - File attachment button (files) + folder attachment button
|
|
19
|
-
* - Pending file/folder chips
|
|
20
|
-
* - Cancel button when streaming
|
|
21
|
-
* - Optional model selector pill
|
|
13
|
+
* Transcript-only container: message list + auto-scroll. Composers are
|
|
14
|
+
* composed BELOW this by the app (the canonical one is `AgentComposer` in
|
|
15
|
+
* `@tangle-network/sandbox-ui`) — this component never renders an input.
|
|
22
16
|
*/
|
|
23
|
-
interface PendingFile {
|
|
24
|
-
id: string;
|
|
25
|
-
name: string;
|
|
26
|
-
size: number;
|
|
27
|
-
type: "file" | "folder";
|
|
28
|
-
/** Number of files inside (for folders) */
|
|
29
|
-
fileCount?: number;
|
|
30
|
-
status: "pending" | "uploading" | "ready" | "error";
|
|
31
|
-
}
|
|
32
|
-
interface ChatInputProps {
|
|
33
|
-
onSend: (message: string, files?: File[]) => void;
|
|
34
|
-
onCancel?: () => void;
|
|
35
|
-
isStreaming?: boolean;
|
|
36
|
-
disabled?: boolean;
|
|
37
|
-
placeholder?: string;
|
|
38
|
-
/** Currently selected model label */
|
|
39
|
-
modelLabel?: string;
|
|
40
|
-
onModelClick?: () => void;
|
|
41
|
-
/** Pending uploaded files */
|
|
42
|
-
pendingFiles?: PendingFile[];
|
|
43
|
-
onRemoveFile?: (id: string) => void;
|
|
44
|
-
/** Called when files are attached (via button or drag-and-drop) */
|
|
45
|
-
onAttach?: (files: FileList) => void;
|
|
46
|
-
/** Called when a folder is selected via the folder button */
|
|
47
|
-
onAttachFolder?: (files: FileList) => void;
|
|
48
|
-
/** Accepted file types for the file input (e.g. ".pdf,.csv") */
|
|
49
|
-
accept?: string;
|
|
50
|
-
/** Drop zone overlay title */
|
|
51
|
-
dropTitle?: string;
|
|
52
|
-
/** Drop zone overlay description */
|
|
53
|
-
dropDescription?: string;
|
|
54
|
-
className?: string;
|
|
55
|
-
/** Label above the input. Set to null to hide. Default: "Agent Command Deck" */
|
|
56
|
-
inputLabel?: string | null;
|
|
57
|
-
/** Status text shown when idle. Set to null to hide. Default: "Ready for next instruction" */
|
|
58
|
-
idleStatus?: string | null;
|
|
59
|
-
/** Status text shown when streaming. Set to null to hide. Default: "Streaming response" */
|
|
60
|
-
streamingStatus?: string | null;
|
|
61
|
-
/** Hide the Cmd+L focus shortcut hint */
|
|
62
|
-
hideShortcutHint?: boolean;
|
|
63
|
-
}
|
|
64
|
-
declare function ChatInput({ onSend, onCancel, isStreaming, disabled, placeholder, modelLabel, onModelClick, pendingFiles, onRemoveFile, onAttach, onAttachFolder, accept, dropTitle, dropDescription, className, inputLabel, idleStatus, streamingStatus, hideShortcutHint, }: ChatInputProps): react_jsx_runtime.JSX.Element;
|
|
65
|
-
|
|
66
17
|
interface ChatContainerProps {
|
|
67
18
|
messages: SessionMessage[];
|
|
68
19
|
partMap: Record<string, SessionPart[]>;
|
|
69
20
|
isStreaming: boolean;
|
|
70
|
-
onSend?: (text: string) => void;
|
|
71
|
-
onCancel?: () => void;
|
|
72
21
|
branding?: AgentBranding;
|
|
73
|
-
placeholder?: string;
|
|
74
22
|
className?: string;
|
|
75
|
-
/** Hide the input area (useful for read-only views). */
|
|
76
|
-
hideInput?: boolean;
|
|
77
23
|
/** Custom renderer for tool details. Return ReactNode to override, null to use default. */
|
|
78
24
|
renderToolDetail?: CustomToolRenderer;
|
|
79
25
|
/** Presentation mode for the session view. */
|
|
80
26
|
presentation?: "runs" | "timeline";
|
|
81
|
-
modelLabel?: string;
|
|
82
|
-
onModelClick?: () => void;
|
|
83
|
-
pendingFiles?: PendingFile[];
|
|
84
|
-
onRemoveFile?: (id: string) => void;
|
|
85
|
-
onAttach?: (files: FileList) => void;
|
|
86
|
-
disabled?: boolean;
|
|
87
27
|
/** Callback when an OpenUI action button is pressed within inline OpenUI blocks. */
|
|
88
28
|
onOpenUIAction?: (action: OpenUIAction) => void;
|
|
89
29
|
/** Enable rendering OpenUI schemas inline in the chat timeline. Defaults to true. */
|
|
@@ -100,10 +40,10 @@ interface ChatContainerProps {
|
|
|
100
40
|
}) => ReactNode;
|
|
101
41
|
}
|
|
102
42
|
/**
|
|
103
|
-
*
|
|
43
|
+
* Chat transcript container: message list + auto-scroll.
|
|
104
44
|
* Orchestrates useRunGroups, useRunCollapseState, and useAutoScroll.
|
|
105
45
|
*/
|
|
106
|
-
declare const ChatContainer: React.MemoExoticComponent<({ messages, partMap, isStreaming,
|
|
46
|
+
declare const ChatContainer: React.MemoExoticComponent<({ messages, partMap, isStreaming, branding, className, renderToolDetail, presentation, onOpenUIAction, enableOpenUI, renderRunActions, renderUserMessageActions, renderToolActions, }: ChatContainerProps) => react_jsx_runtime.JSX.Element>;
|
|
107
47
|
|
|
108
48
|
interface MessageListProps {
|
|
109
49
|
groups: GroupedMessage[];
|
|
@@ -158,10 +98,6 @@ interface ChatMessageProps {
|
|
|
158
98
|
assistantLabel?: string;
|
|
159
99
|
/** Hide the role label row entirely */
|
|
160
100
|
hideRoleLabel?: boolean;
|
|
161
|
-
/** @deprecated Avatars were removed from the bubble design; this prop is ignored. */
|
|
162
|
-
hideAvatar?: boolean;
|
|
163
|
-
/** @deprecated Avatars were removed from the bubble design; this prop is ignored. */
|
|
164
|
-
avatar?: ReactNode;
|
|
165
101
|
}
|
|
166
102
|
declare function ChatMessage({ role, content, toolCalls, isStreaming, timestamp, className, userLabel, assistantLabel, hideRoleLabel, }: ChatMessageProps): react_jsx_runtime.JSX.Element;
|
|
167
103
|
|
|
@@ -229,4 +165,4 @@ interface AgentTimelineProps {
|
|
|
229
165
|
*/
|
|
230
166
|
declare function AgentTimeline({ items, isThinking, emptyState, className, }: AgentTimelineProps): react_jsx_runtime.JSX.Element | null;
|
|
231
167
|
|
|
232
|
-
export { AgentTimeline, type AgentTimelineArtifactItem, type AgentTimelineCustomItem, type AgentTimelineItem, type AgentTimelineMessageItem, type AgentTimelineProps, type AgentTimelineStatusItem, type AgentTimelineTone, type AgentTimelineToolGroupItem, type AgentTimelineToolItem, ChatContainer, type ChatContainerProps,
|
|
168
|
+
export { AgentTimeline, type AgentTimelineArtifactItem, type AgentTimelineCustomItem, type AgentTimelineItem, type AgentTimelineMessageItem, type AgentTimelineProps, type AgentTimelineStatusItem, type AgentTimelineTone, type AgentTimelineToolGroupItem, type AgentTimelineToolItem, ChatContainer, type ChatContainerProps, ChatMessage, type ChatMessageProps, MessageList, type MessageListProps, type MessageRole, ThinkingIndicator, type ThinkingIndicatorProps, UserMessage, type UserMessageProps };
|
package/dist/chat.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AgentTimeline,
|
|
3
3
|
ChatContainer,
|
|
4
|
-
ChatInput,
|
|
5
4
|
ChatMessage,
|
|
6
5
|
MessageList,
|
|
7
6
|
ThinkingIndicator,
|
|
8
7
|
UserMessage
|
|
9
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-UOLL2YHG.js";
|
|
10
9
|
import "./chunk-AZWDI2JG.js";
|
|
11
10
|
import "./chunk-QIRVZMQY.js";
|
|
12
11
|
import "./chunk-RKQDBRTC.js";
|
|
@@ -22,7 +21,6 @@ import "./chunk-RQHJBTEU.js";
|
|
|
22
21
|
export {
|
|
23
22
|
AgentTimeline,
|
|
24
23
|
ChatContainer,
|
|
25
|
-
ChatInput,
|
|
26
24
|
ChatMessage,
|
|
27
25
|
MessageList,
|
|
28
26
|
ThinkingIndicator,
|
|
@@ -27,9 +27,8 @@ import {
|
|
|
27
27
|
// src/chat/chat-container.tsx
|
|
28
28
|
import {
|
|
29
29
|
memo as memo3,
|
|
30
|
-
useCallback as useCallback2,
|
|
31
30
|
useMemo,
|
|
32
|
-
useRef
|
|
31
|
+
useRef
|
|
33
32
|
} from "react";
|
|
34
33
|
import { ArrowDown } from "lucide-react";
|
|
35
34
|
|
|
@@ -303,306 +302,8 @@ function AgentTimeline({
|
|
|
303
302
|
}) });
|
|
304
303
|
}
|
|
305
304
|
|
|
306
|
-
// src/chat/chat-input.tsx
|
|
307
|
-
import { useState as useState2, useRef, useCallback } from "react";
|
|
308
|
-
import { Send, Square, Paperclip, FolderUp, X, Upload } from "lucide-react";
|
|
309
|
-
import { Fragment, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
310
|
-
function ChatInput({
|
|
311
|
-
onSend,
|
|
312
|
-
onCancel,
|
|
313
|
-
isStreaming,
|
|
314
|
-
disabled,
|
|
315
|
-
placeholder = "Ask the agent to inspect files, run commands, or explain results\u2026",
|
|
316
|
-
modelLabel,
|
|
317
|
-
onModelClick,
|
|
318
|
-
pendingFiles = [],
|
|
319
|
-
onRemoveFile,
|
|
320
|
-
onAttach,
|
|
321
|
-
onAttachFolder,
|
|
322
|
-
accept,
|
|
323
|
-
dropTitle = "Drop files to add context",
|
|
324
|
-
dropDescription = "Files will be attached to your next message.",
|
|
325
|
-
className,
|
|
326
|
-
inputLabel = "Agent Command Deck",
|
|
327
|
-
idleStatus = "Ready for next instruction",
|
|
328
|
-
streamingStatus = "Streaming response",
|
|
329
|
-
hideShortcutHint
|
|
330
|
-
}) {
|
|
331
|
-
const [value, setValue] = useState2("");
|
|
332
|
-
const [dragOver, setDragOver] = useState2(false);
|
|
333
|
-
const dragCounter = useRef(0);
|
|
334
|
-
const textareaRef = useRef(null);
|
|
335
|
-
const fileInputRef = useRef(null);
|
|
336
|
-
const folderInputRef = useRef(null);
|
|
337
|
-
const handleSend = useCallback(() => {
|
|
338
|
-
const trimmed = value.trim();
|
|
339
|
-
if (!trimmed || isStreaming || disabled) return;
|
|
340
|
-
onSend(trimmed);
|
|
341
|
-
setValue("");
|
|
342
|
-
if (textareaRef.current) {
|
|
343
|
-
textareaRef.current.style.height = "auto";
|
|
344
|
-
}
|
|
345
|
-
}, [value, isStreaming, disabled, onSend]);
|
|
346
|
-
const handleKeyDown = (e) => {
|
|
347
|
-
if (e.key === "Enter" && !e.shiftKey) {
|
|
348
|
-
e.preventDefault();
|
|
349
|
-
handleSend();
|
|
350
|
-
}
|
|
351
|
-
};
|
|
352
|
-
const handleChange = (e) => {
|
|
353
|
-
setValue(e.target.value);
|
|
354
|
-
const el = e.target;
|
|
355
|
-
el.style.height = "auto";
|
|
356
|
-
el.style.height = `${Math.min(el.scrollHeight, 160)}px`;
|
|
357
|
-
};
|
|
358
|
-
const handleAttachClick = () => {
|
|
359
|
-
fileInputRef.current?.click();
|
|
360
|
-
};
|
|
361
|
-
const handleFolderClick = () => {
|
|
362
|
-
folderInputRef.current?.click();
|
|
363
|
-
};
|
|
364
|
-
const handleFileChange = (e) => {
|
|
365
|
-
if (e.target.files?.length) {
|
|
366
|
-
onAttach?.(e.target.files);
|
|
367
|
-
e.target.value = "";
|
|
368
|
-
}
|
|
369
|
-
};
|
|
370
|
-
const handleFolderChange = (e) => {
|
|
371
|
-
if (e.target.files?.length) {
|
|
372
|
-
(onAttachFolder ?? onAttach)?.(e.target.files);
|
|
373
|
-
e.target.value = "";
|
|
374
|
-
}
|
|
375
|
-
};
|
|
376
|
-
const handleDragEnter = useCallback((e) => {
|
|
377
|
-
e.preventDefault();
|
|
378
|
-
e.stopPropagation();
|
|
379
|
-
dragCounter.current++;
|
|
380
|
-
if (e.dataTransfer?.types.includes("Files")) {
|
|
381
|
-
setDragOver(true);
|
|
382
|
-
}
|
|
383
|
-
}, []);
|
|
384
|
-
const handleDragLeave = useCallback((e) => {
|
|
385
|
-
e.preventDefault();
|
|
386
|
-
e.stopPropagation();
|
|
387
|
-
dragCounter.current--;
|
|
388
|
-
if (dragCounter.current === 0) {
|
|
389
|
-
setDragOver(false);
|
|
390
|
-
}
|
|
391
|
-
}, []);
|
|
392
|
-
const handleDragOver = useCallback((e) => {
|
|
393
|
-
e.preventDefault();
|
|
394
|
-
e.stopPropagation();
|
|
395
|
-
e.dataTransfer.dropEffect = "copy";
|
|
396
|
-
}, []);
|
|
397
|
-
const handleDrop = useCallback((e) => {
|
|
398
|
-
e.preventDefault();
|
|
399
|
-
e.stopPropagation();
|
|
400
|
-
dragCounter.current = 0;
|
|
401
|
-
setDragOver(false);
|
|
402
|
-
const files = e.dataTransfer?.files;
|
|
403
|
-
if (files?.length && onAttach) {
|
|
404
|
-
onAttach(files);
|
|
405
|
-
}
|
|
406
|
-
}, [onAttach]);
|
|
407
|
-
const fileChips = pendingFiles.filter((f) => f.type === "file" || !f.type);
|
|
408
|
-
const folderChips = pendingFiles.filter((f) => f.type === "folder");
|
|
409
|
-
return /* @__PURE__ */ jsxs4(
|
|
410
|
-
"div",
|
|
411
|
-
{
|
|
412
|
-
className: cn("relative", className),
|
|
413
|
-
onDragEnter: onAttach ? handleDragEnter : void 0,
|
|
414
|
-
onDragLeave: onAttach ? handleDragLeave : void 0,
|
|
415
|
-
onDragOver: onAttach ? handleDragOver : void 0,
|
|
416
|
-
onDrop: onAttach ? handleDrop : void 0,
|
|
417
|
-
children: [
|
|
418
|
-
dragOver && /* @__PURE__ */ jsx5("div", { className: "absolute inset-0 z-10 flex items-center justify-center rounded-[var(--radius-xl)] border-2 border-dashed border-border bg-card pointer-events-none", children: /* @__PURE__ */ jsxs4("div", { className: "text-center", children: [
|
|
419
|
-
/* @__PURE__ */ jsx5("div", { className: "mx-auto mb-3 flex h-12 w-12 items-center justify-center rounded-xl bg-[var(--accent-surface-soft)]", children: /* @__PURE__ */ jsx5(Upload, { className: "h-6 w-6 text-primary" }) }),
|
|
420
|
-
/* @__PURE__ */ jsx5("p", { className: "text-sm font-semibold text-foreground", children: dropTitle }),
|
|
421
|
-
/* @__PURE__ */ jsx5("p", { className: "mt-1 text-xs text-muted-foreground", children: dropDescription })
|
|
422
|
-
] }) }),
|
|
423
|
-
pendingFiles.length > 0 && /* @__PURE__ */ jsxs4("div", { className: "mb-3 flex flex-wrap gap-2", children: [
|
|
424
|
-
folderChips.map((f) => /* @__PURE__ */ jsxs4(
|
|
425
|
-
"span",
|
|
426
|
-
{
|
|
427
|
-
className: cn(
|
|
428
|
-
"inline-flex items-center gap-1.5 rounded-[var(--radius-full)] border px-3 py-1.5 text-xs",
|
|
429
|
-
"border-border bg-muted/50",
|
|
430
|
-
f.status === "error" && "border-[var(--code-error)]/30 text-[var(--code-error)]",
|
|
431
|
-
f.status !== "error" && "text-foreground"
|
|
432
|
-
),
|
|
433
|
-
children: [
|
|
434
|
-
/* @__PURE__ */ jsx5(FolderUp, { className: "h-3 w-3 shrink-0" }),
|
|
435
|
-
/* @__PURE__ */ jsx5("span", { className: "truncate max-w-[150px]", children: f.name }),
|
|
436
|
-
f.fileCount !== void 0 && /* @__PURE__ */ jsxs4("span", { className: "text-muted-foreground", children: [
|
|
437
|
-
"(",
|
|
438
|
-
f.fileCount,
|
|
439
|
-
")"
|
|
440
|
-
] }),
|
|
441
|
-
f.status === "uploading" && /* @__PURE__ */ jsx5("span", { className: "w-3 h-3 border-2 border-primary border-t-transparent rounded-full animate-spin" }),
|
|
442
|
-
onRemoveFile && /* @__PURE__ */ jsx5(
|
|
443
|
-
"button",
|
|
444
|
-
{
|
|
445
|
-
type: "button",
|
|
446
|
-
"aria-label": `Remove ${f.name}`,
|
|
447
|
-
onClick: () => onRemoveFile(f.id),
|
|
448
|
-
className: "rounded p-0.5 transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60",
|
|
449
|
-
children: /* @__PURE__ */ jsx5(X, { className: "h-3 w-3" })
|
|
450
|
-
}
|
|
451
|
-
)
|
|
452
|
-
]
|
|
453
|
-
},
|
|
454
|
-
f.id
|
|
455
|
-
)),
|
|
456
|
-
fileChips.map((f) => /* @__PURE__ */ jsxs4(
|
|
457
|
-
"span",
|
|
458
|
-
{
|
|
459
|
-
className: cn(
|
|
460
|
-
"inline-flex items-center gap-1.5 rounded-[var(--radius-full)] border px-3 py-1.5 text-xs",
|
|
461
|
-
"border-border bg-muted/50",
|
|
462
|
-
f.status === "error" && "border-[var(--code-error)]/30 text-[var(--code-error)]",
|
|
463
|
-
f.status !== "error" && "text-foreground"
|
|
464
|
-
),
|
|
465
|
-
children: [
|
|
466
|
-
/* @__PURE__ */ jsx5(Paperclip, { className: "h-3 w-3 shrink-0" }),
|
|
467
|
-
/* @__PURE__ */ jsx5("span", { className: "truncate max-w-[150px]", children: f.name }),
|
|
468
|
-
f.status === "uploading" && /* @__PURE__ */ jsx5("span", { className: "w-3 h-3 border-2 border-primary border-t-transparent rounded-full animate-spin" }),
|
|
469
|
-
onRemoveFile && /* @__PURE__ */ jsx5(
|
|
470
|
-
"button",
|
|
471
|
-
{
|
|
472
|
-
type: "button",
|
|
473
|
-
"aria-label": `Remove ${f.name}`,
|
|
474
|
-
onClick: () => onRemoveFile(f.id),
|
|
475
|
-
className: "rounded p-0.5 transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60",
|
|
476
|
-
children: /* @__PURE__ */ jsx5(X, { className: "h-3 w-3" })
|
|
477
|
-
}
|
|
478
|
-
)
|
|
479
|
-
]
|
|
480
|
-
},
|
|
481
|
-
f.id
|
|
482
|
-
))
|
|
483
|
-
] }),
|
|
484
|
-
/* @__PURE__ */ jsx5("div", { className: "rounded-[24px] border border-[var(--chat-input-border,var(--border-default))] [background:var(--chat-input-bg,var(--bg-card))] shadow-[var(--chat-input-shadow,0_1px_2px_rgba(15,23,42,0.05))] transition-all focus-within:border-[var(--chat-input-focus-border,var(--border-accent))] focus-within:shadow-[var(--chat-input-focus-shadow,0_10px_30px_rgba(15,23,42,0.08))]", children: /* @__PURE__ */ jsxs4("div", { className: "rounded-[24px] px-4 py-[var(--chat-input-py)]", children: [
|
|
485
|
-
(inputLabel !== null || idleStatus !== null || streamingStatus !== null) && /* @__PURE__ */ jsxs4("div", { className: "mb-1.5 flex items-center justify-between gap-3 px-1", children: [
|
|
486
|
-
inputLabel !== null && /* @__PURE__ */ jsx5("div", { className: "text-[var(--chat-label-size,11px)] font-[var(--chat-label-weight,600)] uppercase tracking-[var(--chat-label-tracking,0.16em)] text-[var(--text-muted)]", children: inputLabel }),
|
|
487
|
-
(idleStatus !== null || streamingStatus !== null) && /* @__PURE__ */ jsx5("div", { className: "text-[var(--chat-label-size,11px)] text-[var(--text-muted)]", children: isStreaming ? streamingStatus ?? "" : idleStatus ?? "" })
|
|
488
|
-
] }),
|
|
489
|
-
/* @__PURE__ */ jsxs4("div", { className: "flex items-end gap-2.5", children: [
|
|
490
|
-
onAttach && /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
491
|
-
/* @__PURE__ */ jsx5(
|
|
492
|
-
"button",
|
|
493
|
-
{
|
|
494
|
-
type: "button",
|
|
495
|
-
onClick: handleAttachClick,
|
|
496
|
-
disabled: isStreaming,
|
|
497
|
-
"aria-label": "Attach files",
|
|
498
|
-
title: "Attach files",
|
|
499
|
-
className: "mb-0.5 shrink-0 rounded-[var(--radius-md)] border border-transparent p-2 text-muted-foreground transition-colors hover:border-border hover:bg-accent hover:text-foreground disabled:opacity-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60",
|
|
500
|
-
children: /* @__PURE__ */ jsx5(Paperclip, { className: "h-4 w-4" })
|
|
501
|
-
}
|
|
502
|
-
),
|
|
503
|
-
/* @__PURE__ */ jsx5(
|
|
504
|
-
"input",
|
|
505
|
-
{
|
|
506
|
-
ref: fileInputRef,
|
|
507
|
-
type: "file",
|
|
508
|
-
multiple: true,
|
|
509
|
-
className: "hidden",
|
|
510
|
-
onChange: handleFileChange,
|
|
511
|
-
accept: accept ?? ".pdf,.csv,.xlsx,.xls,.jpg,.jpeg,.png,.gif,.txt,.json,.yaml,.yml"
|
|
512
|
-
}
|
|
513
|
-
)
|
|
514
|
-
] }),
|
|
515
|
-
(onAttachFolder ?? onAttach) && /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
516
|
-
/* @__PURE__ */ jsx5(
|
|
517
|
-
"button",
|
|
518
|
-
{
|
|
519
|
-
type: "button",
|
|
520
|
-
onClick: handleFolderClick,
|
|
521
|
-
disabled: isStreaming,
|
|
522
|
-
"aria-label": "Attach folder",
|
|
523
|
-
title: "Attach folder",
|
|
524
|
-
className: "mb-0.5 shrink-0 rounded-[var(--radius-md)] border border-transparent p-2 text-muted-foreground transition-colors hover:border-border hover:bg-accent hover:text-foreground disabled:opacity-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60",
|
|
525
|
-
children: /* @__PURE__ */ jsx5(FolderUp, { className: "h-4 w-4" })
|
|
526
|
-
}
|
|
527
|
-
),
|
|
528
|
-
/* @__PURE__ */ jsx5(
|
|
529
|
-
"input",
|
|
530
|
-
{
|
|
531
|
-
ref: folderInputRef,
|
|
532
|
-
type: "file",
|
|
533
|
-
multiple: true,
|
|
534
|
-
className: "hidden",
|
|
535
|
-
onChange: handleFolderChange,
|
|
536
|
-
webkitdirectory: ""
|
|
537
|
-
}
|
|
538
|
-
)
|
|
539
|
-
] }),
|
|
540
|
-
/* @__PURE__ */ jsx5(
|
|
541
|
-
"textarea",
|
|
542
|
-
{
|
|
543
|
-
ref: textareaRef,
|
|
544
|
-
value,
|
|
545
|
-
onChange: handleChange,
|
|
546
|
-
onKeyDown: handleKeyDown,
|
|
547
|
-
placeholder,
|
|
548
|
-
disabled: isStreaming || disabled,
|
|
549
|
-
rows: 1,
|
|
550
|
-
"aria-label": "Message input",
|
|
551
|
-
className: "min-h-[42px] max-h-[160px] flex-1 resize-none bg-transparent py-2 text-[15px] leading-6 text-foreground placeholder:text-muted-foreground disabled:opacity-50 focus-visible:outline-none"
|
|
552
|
-
}
|
|
553
|
-
),
|
|
554
|
-
isStreaming ? /* @__PURE__ */ jsx5(
|
|
555
|
-
"button",
|
|
556
|
-
{
|
|
557
|
-
type: "button",
|
|
558
|
-
onClick: onCancel,
|
|
559
|
-
"aria-label": "Stop response",
|
|
560
|
-
className: "mb-0.5 shrink-0 rounded-[var(--radius-lg)] border border-[var(--code-error)]/20 bg-[var(--code-error)]/14 p-2.5 text-[var(--code-error)] transition-colors hover:bg-[var(--code-error)]/24 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--code-error)]/50",
|
|
561
|
-
children: /* @__PURE__ */ jsx5(Square, { className: "h-4 w-4" })
|
|
562
|
-
}
|
|
563
|
-
) : /* @__PURE__ */ jsxs4(
|
|
564
|
-
"button",
|
|
565
|
-
{
|
|
566
|
-
type: "button",
|
|
567
|
-
onClick: handleSend,
|
|
568
|
-
disabled: !value.trim() || disabled,
|
|
569
|
-
"aria-label": "Send message",
|
|
570
|
-
className: "mb-0.5 inline-flex shrink-0 items-center gap-1.5 rounded-full border border-[var(--chat-send-border,var(--border-accent))] [background:var(--chat-send-bg,var(--brand-primary))] px-3.5 py-2.5 text-sm font-medium text-[var(--chat-send-color,white)] shadow-[var(--chat-send-shadow,0_6px_16px_rgba(15,23,42,0.12))] transition-all hover:translate-y-[-1px] hover:[background:var(--chat-send-hover-bg,var(--brand-strong))] disabled:opacity-30 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--chat-send-ring,var(--border-accent))]",
|
|
571
|
-
children: [
|
|
572
|
-
/* @__PURE__ */ jsx5(Send, { className: "h-4 w-4" }),
|
|
573
|
-
/* @__PURE__ */ jsx5("span", { children: "Send" })
|
|
574
|
-
]
|
|
575
|
-
}
|
|
576
|
-
)
|
|
577
|
-
] })
|
|
578
|
-
] }) }),
|
|
579
|
-
(modelLabel || !hideShortcutHint) && /* @__PURE__ */ jsxs4("div", { className: "mt-2 flex items-center justify-between px-1", children: [
|
|
580
|
-
/* @__PURE__ */ jsx5("div", { className: "flex items-center gap-2", children: modelLabel && /* @__PURE__ */ jsxs4(
|
|
581
|
-
"button",
|
|
582
|
-
{
|
|
583
|
-
type: "button",
|
|
584
|
-
onClick: onModelClick,
|
|
585
|
-
"aria-label": `Select model, current model ${modelLabel}`,
|
|
586
|
-
className: "inline-flex items-center gap-1.5 rounded-[var(--radius-full)] border border-border bg-[linear-gradient(180deg,rgba(255,255,255,0.04),transparent)] px-2.5 py-1 text-xs text-muted-foreground transition-colors hover:border-primary/20 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60",
|
|
587
|
-
children: [
|
|
588
|
-
/* @__PURE__ */ jsx5("span", { className: "w-1.5 h-1.5 rounded-full bg-[var(--code-success)]" }),
|
|
589
|
-
modelLabel
|
|
590
|
-
]
|
|
591
|
-
}
|
|
592
|
-
) }),
|
|
593
|
-
!hideShortcutHint && /* @__PURE__ */ jsxs4("span", { className: "text-xs text-muted-foreground", children: [
|
|
594
|
-
/* @__PURE__ */ jsx5("kbd", { className: "px-1 py-0.5 bg-background rounded border border-border text-[10px]", children: "Cmd" }),
|
|
595
|
-
/* @__PURE__ */ jsx5("kbd", { className: "px-1 py-0.5 bg-background rounded border border-border text-[10px] ml-0.5", children: "L" }),
|
|
596
|
-
/* @__PURE__ */ jsx5("span", { className: "ml-1", children: "to focus" })
|
|
597
|
-
] })
|
|
598
|
-
] })
|
|
599
|
-
]
|
|
600
|
-
}
|
|
601
|
-
);
|
|
602
|
-
}
|
|
603
|
-
|
|
604
305
|
// src/chat/chat-container.tsx
|
|
605
|
-
import { jsx as
|
|
306
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
606
307
|
var OPENUI_NODE_TYPES = /* @__PURE__ */ new Set([
|
|
607
308
|
"heading",
|
|
608
309
|
"text",
|
|
@@ -752,7 +453,7 @@ function buildTimelineItems(messages, partMap, isStreaming, onOpenUIAction, enab
|
|
|
752
453
|
items.push({
|
|
753
454
|
id: `${message.id}-openui-${part.id}`,
|
|
754
455
|
kind: "custom",
|
|
755
|
-
content: /* @__PURE__ */
|
|
456
|
+
content: /* @__PURE__ */ jsx5("div", { className: "my-2 rounded-[var(--radius-lg)] border border-border bg-card p-4 shadow-[var(--shadow-card)]", children: /* @__PURE__ */ jsx5(OpenUIArtifactRenderer, { schema, onAction: onOpenUIAction }) })
|
|
756
457
|
});
|
|
757
458
|
}
|
|
758
459
|
}
|
|
@@ -784,7 +485,7 @@ function buildTimelineItems(messages, partMap, isStreaming, onOpenUIAction, enab
|
|
|
784
485
|
items.push({
|
|
785
486
|
id: `${itemId}-openui`,
|
|
786
487
|
kind: "custom",
|
|
787
|
-
content: /* @__PURE__ */
|
|
488
|
+
content: /* @__PURE__ */ jsx5("div", { className: "my-2 rounded-[var(--radius-lg)] border border-border bg-card p-4 shadow-[var(--shadow-card)]", children: /* @__PURE__ */ jsx5(OpenUIArtifactRenderer, { schema, onAction: onOpenUIAction }) })
|
|
788
489
|
});
|
|
789
490
|
const afterJson = part.text.slice(part.text.lastIndexOf("```") + 3).trim();
|
|
790
491
|
if (afterJson) {
|
|
@@ -814,7 +515,7 @@ function buildTimelineItems(messages, partMap, isStreaming, onOpenUIAction, enab
|
|
|
814
515
|
items.push({
|
|
815
516
|
id: itemId,
|
|
816
517
|
kind: "custom",
|
|
817
|
-
content: /* @__PURE__ */
|
|
518
|
+
content: /* @__PURE__ */ jsx5(InlineThinkingItem, { part, defaultOpen: isStreaming && lastAssistantMessage?.id === message.id })
|
|
818
519
|
});
|
|
819
520
|
return;
|
|
820
521
|
}
|
|
@@ -831,27 +532,17 @@ var ChatContainer = memo3(
|
|
|
831
532
|
messages,
|
|
832
533
|
partMap,
|
|
833
534
|
isStreaming,
|
|
834
|
-
onSend,
|
|
835
|
-
onCancel,
|
|
836
535
|
branding,
|
|
837
|
-
placeholder = "Type a message...",
|
|
838
536
|
className,
|
|
839
|
-
hideInput = false,
|
|
840
537
|
renderToolDetail,
|
|
841
538
|
presentation = "runs",
|
|
842
|
-
modelLabel,
|
|
843
|
-
onModelClick,
|
|
844
|
-
pendingFiles,
|
|
845
|
-
onRemoveFile,
|
|
846
|
-
onAttach,
|
|
847
|
-
disabled = false,
|
|
848
539
|
onOpenUIAction,
|
|
849
540
|
enableOpenUI = true,
|
|
850
541
|
renderRunActions,
|
|
851
542
|
renderUserMessageActions,
|
|
852
543
|
renderToolActions
|
|
853
544
|
}) => {
|
|
854
|
-
const scrollRef =
|
|
545
|
+
const scrollRef = useRef(null);
|
|
855
546
|
const groups = useRunGroups({ messages, partMap, isStreaming });
|
|
856
547
|
const runs = groups.filter((g) => g.type === "run").map((g) => g.run);
|
|
857
548
|
const { isCollapsed, toggleCollapse } = useRunCollapseState(runs);
|
|
@@ -864,19 +555,13 @@ var ChatContainer = memo3(
|
|
|
864
555
|
() => buildTimelineItems(messages, partMap, isStreaming, onOpenUIAction, enableOpenUI),
|
|
865
556
|
[messages, partMap, isStreaming, onOpenUIAction, enableOpenUI]
|
|
866
557
|
);
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
onSend?.(text);
|
|
870
|
-
},
|
|
871
|
-
[onSend]
|
|
872
|
-
);
|
|
873
|
-
return /* @__PURE__ */ jsxs5("div", { className: cn("flex h-full flex-col", className), children: [
|
|
874
|
-
/* @__PURE__ */ jsx6(
|
|
558
|
+
return /* @__PURE__ */ jsxs4("div", { className: cn("flex h-full flex-col", className), children: [
|
|
559
|
+
/* @__PURE__ */ jsx5(
|
|
875
560
|
"div",
|
|
876
561
|
{
|
|
877
562
|
ref: scrollRef,
|
|
878
563
|
className: "flex-1 overflow-y-auto [scrollbar-gutter:stable]",
|
|
879
|
-
children: messages.length === 0 ? /* @__PURE__ */
|
|
564
|
+
children: messages.length === 0 ? /* @__PURE__ */ jsx5("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx5("div", { className: "max-w-md text-center", children: /* @__PURE__ */ jsx5("div", { className: "text-sm font-medium text-muted-foreground", children: "Start a conversation." }) }) }) : presentation === "timeline" ? /* @__PURE__ */ jsx5("div", { className: "mx-auto flex min-h-full w-full max-w-3xl flex-col justify-end", children: /* @__PURE__ */ jsx5(AgentTimeline, { items: timeline.items, isThinking: timeline.showThinking }) }) : /* @__PURE__ */ jsx5("div", { className: "mx-auto flex min-h-full w-full max-w-3xl flex-col justify-end", children: /* @__PURE__ */ jsx5(
|
|
880
565
|
MessageList,
|
|
881
566
|
{
|
|
882
567
|
groups,
|
|
@@ -892,7 +577,7 @@ var ChatContainer = memo3(
|
|
|
892
577
|
) })
|
|
893
578
|
}
|
|
894
579
|
),
|
|
895
|
-
!isAtBottom && /* @__PURE__ */
|
|
580
|
+
!isAtBottom && /* @__PURE__ */ jsx5("div", { className: "relative z-10 -mt-10 flex justify-center", children: /* @__PURE__ */ jsxs4(
|
|
896
581
|
"button",
|
|
897
582
|
{
|
|
898
583
|
onClick: scrollToBottom,
|
|
@@ -903,34 +588,18 @@ var ChatContainer = memo3(
|
|
|
903
588
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60"
|
|
904
589
|
),
|
|
905
590
|
children: [
|
|
906
|
-
/* @__PURE__ */
|
|
591
|
+
/* @__PURE__ */ jsx5(ArrowDown, { className: "w-3 h-3" }),
|
|
907
592
|
"Scroll to bottom"
|
|
908
593
|
]
|
|
909
594
|
}
|
|
910
|
-
) })
|
|
911
|
-
!hideInput && onSend && /* @__PURE__ */ jsx6(
|
|
912
|
-
ChatInput,
|
|
913
|
-
{
|
|
914
|
-
onSend: handleSend,
|
|
915
|
-
onCancel,
|
|
916
|
-
isStreaming,
|
|
917
|
-
placeholder,
|
|
918
|
-
modelLabel,
|
|
919
|
-
onModelClick,
|
|
920
|
-
pendingFiles,
|
|
921
|
-
onRemoveFile,
|
|
922
|
-
onAttach,
|
|
923
|
-
disabled,
|
|
924
|
-
className: "shrink-0 border-t border-border bg-background"
|
|
925
|
-
}
|
|
926
|
-
)
|
|
595
|
+
) })
|
|
927
596
|
] });
|
|
928
597
|
}
|
|
929
598
|
);
|
|
930
599
|
ChatContainer.displayName = "ChatContainer";
|
|
931
600
|
|
|
932
601
|
// src/chat/chat-message.tsx
|
|
933
|
-
import { Fragment
|
|
602
|
+
import { Fragment, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
934
603
|
function ChatMessage({
|
|
935
604
|
role,
|
|
936
605
|
content,
|
|
@@ -943,7 +612,7 @@ function ChatMessage({
|
|
|
943
612
|
hideRoleLabel
|
|
944
613
|
}) {
|
|
945
614
|
const isUser = role === "user";
|
|
946
|
-
return /* @__PURE__ */
|
|
615
|
+
return /* @__PURE__ */ jsxs5(
|
|
947
616
|
"div",
|
|
948
617
|
{
|
|
949
618
|
className: cn(
|
|
@@ -952,11 +621,11 @@ function ChatMessage({
|
|
|
952
621
|
className
|
|
953
622
|
),
|
|
954
623
|
children: [
|
|
955
|
-
!hideRoleLabel && /* @__PURE__ */
|
|
956
|
-
/* @__PURE__ */
|
|
957
|
-
timestamp && /* @__PURE__ */
|
|
624
|
+
!hideRoleLabel && /* @__PURE__ */ jsxs5("div", { className: cn("flex items-center gap-2 px-1", isUser && "flex-row-reverse"), children: [
|
|
625
|
+
/* @__PURE__ */ jsx6("span", { className: "font-medium text-foreground text-xs", children: isUser ? userLabel : assistantLabel }),
|
|
626
|
+
timestamp && /* @__PURE__ */ jsx6("span", { className: "text-muted-foreground text-xs", children: formatTime2(timestamp) })
|
|
958
627
|
] }),
|
|
959
|
-
/* @__PURE__ */
|
|
628
|
+
/* @__PURE__ */ jsxs5(
|
|
960
629
|
"div",
|
|
961
630
|
{
|
|
962
631
|
className: cn(
|
|
@@ -965,9 +634,9 @@ function ChatMessage({
|
|
|
965
634
|
isUser ? "border-border bg-muted/50" : "border-border bg-card"
|
|
966
635
|
),
|
|
967
636
|
children: [
|
|
968
|
-
isUser ? /* @__PURE__ */
|
|
969
|
-
content && /* @__PURE__ */
|
|
970
|
-
isStreaming && /* @__PURE__ */
|
|
637
|
+
isUser ? /* @__PURE__ */ jsx6("div", { className: "whitespace-pre-wrap text-[var(--font-size-base)] leading-[var(--line-height-base)] text-foreground", children: content }) : /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
638
|
+
content && /* @__PURE__ */ jsx6(Markdown, { className: "tangle-prose text-[var(--font-size-base)] leading-[var(--line-height-base)]", children: content }),
|
|
639
|
+
isStreaming && /* @__PURE__ */ jsx6("span", { className: "ml-0.5 inline-block h-4 w-2 animate-pulse rounded-sm bg-[var(--brand-cool)] align-text-bottom" })
|
|
971
640
|
] }),
|
|
972
641
|
toolCalls
|
|
973
642
|
]
|
|
@@ -989,7 +658,6 @@ export {
|
|
|
989
658
|
MessageList,
|
|
990
659
|
ThinkingIndicator,
|
|
991
660
|
AgentTimeline,
|
|
992
|
-
ChatInput,
|
|
993
661
|
ChatContainer,
|
|
994
662
|
ChatMessage
|
|
995
663
|
};
|
package/dist/hooks.d.ts
CHANGED