@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 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-Bs3MyQMT.js';
10
+ import { T as ToolCallData } from './tool-call-feed-D9iofJgW.js';
11
11
 
12
12
  /**
13
- * ChatInput message input bar with file attach, drag-and-drop, send/cancel.
14
- *
15
- * - Auto-resizing textarea (up to max height)
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
- * Full chat container: message list + auto-scroll + input area.
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, onSend, onCancel, branding, placeholder, className, hideInput, renderToolDetail, presentation, modelLabel, onModelClick, pendingFiles, onRemoveFile, onAttach, disabled, onOpenUIAction, enableOpenUI, renderRunActions, renderUserMessageActions, renderToolActions, }: ChatContainerProps) => react_jsx_runtime.JSX.Element>;
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, ChatInput, type ChatInputProps, ChatMessage, type ChatMessageProps, MessageList, type MessageListProps, type MessageRole, type PendingFile, ThinkingIndicator, type ThinkingIndicatorProps, UserMessage, type UserMessageProps };
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-5CS3I7Y3.js";
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 as useRef2
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 jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
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__ */ jsx6("div", { className: "my-2 rounded-[var(--radius-lg)] border border-border bg-card p-4 shadow-[var(--shadow-card)]", children: /* @__PURE__ */ jsx6(OpenUIArtifactRenderer, { schema, onAction: onOpenUIAction }) })
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__ */ jsx6("div", { className: "my-2 rounded-[var(--radius-lg)] border border-border bg-card p-4 shadow-[var(--shadow-card)]", children: /* @__PURE__ */ jsx6(OpenUIArtifactRenderer, { schema, onAction: onOpenUIAction }) })
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__ */ jsx6(InlineThinkingItem, { part, defaultOpen: isStreaming && lastAssistantMessage?.id === message.id })
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 = useRef2(null);
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
- const handleSend = useCallback2(
868
- (text) => {
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__ */ jsx6("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx6("div", { className: "max-w-md text-center", children: /* @__PURE__ */ jsx6("div", { className: "text-sm font-medium text-muted-foreground", children: "Start a conversation." }) }) }) : presentation === "timeline" ? /* @__PURE__ */ jsx6("div", { className: "mx-auto flex min-h-full w-full max-w-3xl flex-col justify-end", children: /* @__PURE__ */ jsx6(AgentTimeline, { items: timeline.items, isThinking: timeline.showThinking }) }) : /* @__PURE__ */ jsx6("div", { className: "mx-auto flex min-h-full w-full max-w-3xl flex-col justify-end", children: /* @__PURE__ */ jsx6(
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__ */ jsx6("div", { className: "relative z-10 -mt-10 flex justify-center", children: /* @__PURE__ */ jsxs5(
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__ */ jsx6(ArrowDown, { className: "w-3 h-3" }),
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 as Fragment2, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
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__ */ jsxs6(
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__ */ jsxs6("div", { className: cn("flex items-center gap-2 px-1", isUser && "flex-row-reverse"), children: [
956
- /* @__PURE__ */ jsx7("span", { className: "font-medium text-foreground text-xs", children: isUser ? userLabel : assistantLabel }),
957
- timestamp && /* @__PURE__ */ jsx7("span", { className: "text-muted-foreground text-xs", children: formatTime2(timestamp) })
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__ */ jsxs6(
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__ */ jsx7("div", { className: "whitespace-pre-wrap text-[var(--font-size-base)] leading-[var(--line-height-base)] text-foreground", children: content }) : /* @__PURE__ */ jsxs6(Fragment2, { children: [
969
- content && /* @__PURE__ */ jsx7(Markdown, { className: "tangle-prose text-[var(--font-size-base)] leading-[var(--line-height-base)]", children: content }),
970
- isStreaming && /* @__PURE__ */ jsx7("span", { className: "ml-0.5 inline-block h-4 w-2 animate-pulse rounded-sm bg-[var(--brand-cool)] align-text-bottom" })
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
@@ -5,7 +5,7 @@ import './message-BHWbxBtT.js';
5
5
  import './parts-dj7AcUg0.js';
6
6
  import './active-sessions-store-CeOmXgv5.js';
7
7
  import 'nanostores';
8
- import './tool-call-feed-Bs3MyQMT.js';
8
+ import './tool-call-feed-D9iofJgW.js';
9
9
  import 'react/jsx-runtime';
10
10
 
11
11
  /**