@nextclaw/agent-chat-ui 0.5.4 → 0.6.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/index.d.ts +54 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +512 -195
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -399,6 +399,10 @@ const INPUT_SURFACE_PANEL_DESKTOP_SHRINK_RATIO = .82;
|
|
|
399
399
|
const INPUT_SURFACE_PANEL_DESKTOP_MIN_WIDTH = 560;
|
|
400
400
|
const INPUT_SURFACE_PANEL_MAX_HEIGHT = createChatPopoverAvailableHeightLimit("24rem");
|
|
401
401
|
const INPUT_SURFACE_PANEL_MIN_HEIGHT = createChatPopoverAvailableHeightLimit("240px");
|
|
402
|
+
function itemMatchesFilter(item, filter) {
|
|
403
|
+
if (!filter.sectionKeys || filter.sectionKeys.length === 0) return true;
|
|
404
|
+
return Boolean(item.sectionKey && filter.sectionKeys.includes(item.sectionKey));
|
|
405
|
+
}
|
|
402
406
|
const ChatInputSurfaceMenu = forwardRef(function ChatInputSurfaceMenu(props, ref) {
|
|
403
407
|
const { Popover, PopoverAnchor, PopoverContent } = ChatUiPrimitives;
|
|
404
408
|
const { elementRef: anchorRef, width: panelWidth } = useElementWidth();
|
|
@@ -407,12 +411,30 @@ const ChatInputSurfaceMenu = forwardRef(function ChatInputSurfaceMenu(props, ref
|
|
|
407
411
|
index: 0,
|
|
408
412
|
itemsSignature: ""
|
|
409
413
|
});
|
|
410
|
-
const { isOpen, isLoading, items, texts, onSelectItem, onOpenChange, onDetailsPointerDown } = props;
|
|
411
|
-
const
|
|
412
|
-
const
|
|
414
|
+
const { isOpen, isLoading, filterOptions, items, texts, onSelectItem, onOpenChange, onDetailsPointerDown } = props;
|
|
415
|
+
const [activeFilterKey, setActiveFilterKey] = useState(filterOptions?.[0]?.key ?? null);
|
|
416
|
+
const resolvedActiveFilterKey = useMemo(() => {
|
|
417
|
+
if (!filterOptions?.length) return null;
|
|
418
|
+
return filterOptions.some((filter) => filter.key === activeFilterKey) ? activeFilterKey : filterOptions[0].key;
|
|
419
|
+
}, [activeFilterKey, filterOptions]);
|
|
420
|
+
const activeFilter = useMemo(() => filterOptions?.find((filter) => filter.key === resolvedActiveFilterKey) ?? null, [filterOptions, resolvedActiveFilterKey]);
|
|
421
|
+
const filterViews = useMemo(() => filterOptions?.map((filter) => ({
|
|
422
|
+
...filter,
|
|
423
|
+
count: items.filter((item) => itemMatchesFilter(item, filter)).length
|
|
424
|
+
})) ?? [], [filterOptions, items]);
|
|
425
|
+
const visibleItems = useMemo(() => activeFilter ? items.filter((item) => itemMatchesFilter(item, activeFilter)) : items, [activeFilter, items]);
|
|
426
|
+
const itemsSignature = useMemo(() => visibleItems.map((item) => item.key).join(""), [visibleItems]);
|
|
427
|
+
const hasItemSections = useMemo(() => visibleItems.some((item) => Boolean(item.sectionLabel?.trim())), [visibleItems]);
|
|
413
428
|
const activeIndex = activeState.itemsSignature === itemsSignature ? activeState.index : 0;
|
|
414
|
-
const activeIndexInRange =
|
|
415
|
-
const activeItem =
|
|
429
|
+
const activeIndexInRange = visibleItems.length === 0 ? 0 : Math.min(activeIndex, visibleItems.length - 1);
|
|
430
|
+
const activeItem = visibleItems[activeIndexInRange] ?? null;
|
|
431
|
+
const handleFilterSelect = useCallback((filterKey) => {
|
|
432
|
+
setActiveFilterKey(filterKey);
|
|
433
|
+
setActiveState({
|
|
434
|
+
index: 0,
|
|
435
|
+
itemsSignature: ""
|
|
436
|
+
});
|
|
437
|
+
}, []);
|
|
416
438
|
const setActiveIndexForCurrentItems = useCallback((nextIndex) => {
|
|
417
439
|
setActiveState((currentState) => {
|
|
418
440
|
const currentIndex = currentState.itemsSignature === itemsSignature ? currentState.index : 0;
|
|
@@ -433,35 +455,35 @@ const ChatInputSurfaceMenu = forwardRef(function ChatInputSurfaceMenu(props, ref
|
|
|
433
455
|
onOpenChange(false);
|
|
434
456
|
return true;
|
|
435
457
|
}
|
|
436
|
-
if (
|
|
458
|
+
if (visibleItems.length === 0) return false;
|
|
437
459
|
if (event.key === "ArrowDown") {
|
|
438
460
|
event.preventDefault();
|
|
439
|
-
setActiveIndexForCurrentItems((index) => (index + 1) %
|
|
461
|
+
setActiveIndexForCurrentItems((index) => (index + 1) % visibleItems.length);
|
|
440
462
|
return true;
|
|
441
463
|
}
|
|
442
464
|
if (event.key === "ArrowUp") {
|
|
443
465
|
event.preventDefault();
|
|
444
|
-
setActiveIndexForCurrentItems((index) => (index - 1 +
|
|
466
|
+
setActiveIndexForCurrentItems((index) => (index - 1 + visibleItems.length) % visibleItems.length);
|
|
445
467
|
return true;
|
|
446
468
|
}
|
|
447
469
|
if (event.key === "Enter" && !event.shiftKey || event.key === "Tab") {
|
|
448
470
|
event.preventDefault();
|
|
449
|
-
onSelectItem(
|
|
471
|
+
onSelectItem(visibleItems[activeIndexInRange]);
|
|
450
472
|
return true;
|
|
451
473
|
}
|
|
452
474
|
return false;
|
|
453
475
|
} }), [
|
|
454
476
|
activeIndexInRange,
|
|
455
477
|
isOpen,
|
|
456
|
-
items,
|
|
457
478
|
onOpenChange,
|
|
458
479
|
onSelectItem,
|
|
459
|
-
setActiveIndexForCurrentItems
|
|
480
|
+
setActiveIndexForCurrentItems,
|
|
481
|
+
visibleItems
|
|
460
482
|
]);
|
|
461
483
|
useActiveItemScroll({
|
|
462
484
|
containerRef: listRef,
|
|
463
485
|
activeIndex: activeIndexInRange,
|
|
464
|
-
itemCount:
|
|
486
|
+
itemCount: visibleItems.length,
|
|
465
487
|
isEnabled: isOpen && !isLoading,
|
|
466
488
|
getItemSelector: (index) => `[data-input-surface-index="${index}"]`
|
|
467
489
|
});
|
|
@@ -487,59 +509,78 @@ const ChatInputSurfaceMenu = forwardRef(function ChatInputSurfaceMenu(props, ref
|
|
|
487
509
|
children: /* @__PURE__ */ jsxs("div", {
|
|
488
510
|
className: "grid min-h-0 flex-1 grid-cols-[minmax(220px,300px)_minmax(0,1fr)]",
|
|
489
511
|
style: { minHeight: INPUT_SURFACE_PANEL_MIN_HEIGHT },
|
|
490
|
-
children: [/* @__PURE__ */
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
className: "space-y-1",
|
|
506
|
-
children: items.map((item, index) => {
|
|
507
|
-
const { key, sectionKey, sectionLabel, title, subtitle } = item;
|
|
508
|
-
const isActive = index === activeIndexInRange;
|
|
509
|
-
const previousItem = items[index - 1];
|
|
510
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
511
|
-
className: "space-y-1",
|
|
512
|
-
children: [hasItemSections && Boolean(sectionLabel?.trim()) && previousItem?.sectionKey !== sectionKey ? /* @__PURE__ */ jsx("div", {
|
|
513
|
-
className: "px-2 pb-0.5 pt-1.5 text-[11px] font-semibold uppercase tracking-wide text-gray-500",
|
|
514
|
-
children: sectionLabel
|
|
515
|
-
}) : null, /* @__PURE__ */ jsxs("button", {
|
|
516
|
-
type: "button",
|
|
517
|
-
role: "option",
|
|
518
|
-
"aria-selected": isActive,
|
|
519
|
-
"data-input-surface-index": index,
|
|
520
|
-
onPointerMove: (event) => {
|
|
521
|
-
if (event.pointerType !== "touch") setActiveIndexForCurrentItems(index);
|
|
522
|
-
},
|
|
523
|
-
onPointerDown: (event) => {
|
|
524
|
-
if (event.button > 0) return;
|
|
525
|
-
event.preventDefault();
|
|
526
|
-
onSelectItem(item);
|
|
527
|
-
},
|
|
528
|
-
onClick: (event) => {
|
|
529
|
-
if (event.detail === 0) onSelectItem(item);
|
|
530
|
-
},
|
|
531
|
-
className: `flex w-full items-start gap-2 rounded-lg px-2 py-1.5 text-left transition ${isActive ? "bg-gray-100 text-gray-900" : "text-gray-700 hover:bg-gray-50"}`,
|
|
532
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
533
|
-
className: "truncate text-xs font-semibold",
|
|
534
|
-
children: title
|
|
535
|
-
}), /* @__PURE__ */ jsx("span", {
|
|
536
|
-
className: "truncate text-xs text-gray-500",
|
|
537
|
-
children: subtitle
|
|
538
|
-
})]
|
|
512
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
513
|
+
className: "flex min-h-0 flex-col border-r border-gray-200",
|
|
514
|
+
children: [!isLoading && filterViews.length > 0 ? /* @__PURE__ */ jsx("div", {
|
|
515
|
+
className: "flex shrink-0 gap-1 overflow-x-auto px-2.5 pb-2 pt-2.5",
|
|
516
|
+
children: filterViews.map(({ count, key, label }) => {
|
|
517
|
+
const isActive = key === resolvedActiveFilterKey;
|
|
518
|
+
return /* @__PURE__ */ jsxs("button", {
|
|
519
|
+
type: "button",
|
|
520
|
+
"aria-pressed": isActive,
|
|
521
|
+
onPointerDown: (event) => event.preventDefault(),
|
|
522
|
+
onClick: () => handleFilterSelect(key),
|
|
523
|
+
className: `inline-flex shrink-0 items-center gap-1 rounded-full border px-2 py-1 text-[11px] font-semibold transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40 ${isActive ? "border-primary/30 bg-primary/10 text-primary" : "border-gray-200 bg-white text-gray-600 hover:border-gray-300 hover:bg-gray-50"}`,
|
|
524
|
+
children: [/* @__PURE__ */ jsx("span", { children: label }), /* @__PURE__ */ jsx("span", {
|
|
525
|
+
className: isActive ? "text-primary/70" : "text-gray-400",
|
|
526
|
+
children: count
|
|
539
527
|
})]
|
|
540
528
|
}, key);
|
|
541
529
|
})
|
|
542
|
-
})
|
|
530
|
+
}) : null, /* @__PURE__ */ jsx("div", {
|
|
531
|
+
ref: listRef,
|
|
532
|
+
role: "listbox",
|
|
533
|
+
"aria-label": texts.sectionLabel,
|
|
534
|
+
className: `custom-scrollbar min-h-0 flex-1 overflow-y-auto overscroll-contain ${!isLoading && filterViews.length > 0 ? "px-2.5 pb-2.5" : "p-2.5"}`,
|
|
535
|
+
children: isLoading ? /* @__PURE__ */ jsx("div", {
|
|
536
|
+
className: "p-2 text-xs text-gray-500",
|
|
537
|
+
children: texts.loadingLabel
|
|
538
|
+
}) : /* @__PURE__ */ jsxs(Fragment$1, { children: [!hasItemSections ? /* @__PURE__ */ jsx("div", {
|
|
539
|
+
className: "mb-2 px-2 text-[11px] font-semibold uppercase tracking-wide text-gray-500",
|
|
540
|
+
children: texts.sectionLabel
|
|
541
|
+
}) : null, visibleItems.length === 0 ? /* @__PURE__ */ jsx("div", {
|
|
542
|
+
className: "px-2 text-xs text-gray-400",
|
|
543
|
+
children: texts.emptyLabel
|
|
544
|
+
}) : /* @__PURE__ */ jsx("div", {
|
|
545
|
+
className: "space-y-1",
|
|
546
|
+
children: visibleItems.map((item, index) => {
|
|
547
|
+
const { key, sectionKey, sectionLabel, title, subtitle } = item;
|
|
548
|
+
const isActive = index === activeIndexInRange;
|
|
549
|
+
const previousItem = visibleItems[index - 1];
|
|
550
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
551
|
+
className: "space-y-1",
|
|
552
|
+
children: [hasItemSections && Boolean(sectionLabel?.trim()) && previousItem?.sectionKey !== sectionKey ? /* @__PURE__ */ jsx("div", {
|
|
553
|
+
className: "px-2 pb-0.5 pt-1.5 text-[11px] font-semibold uppercase tracking-wide text-gray-500",
|
|
554
|
+
children: sectionLabel
|
|
555
|
+
}) : null, /* @__PURE__ */ jsxs("button", {
|
|
556
|
+
type: "button",
|
|
557
|
+
role: "option",
|
|
558
|
+
"aria-selected": isActive,
|
|
559
|
+
"data-input-surface-index": index,
|
|
560
|
+
onPointerMove: (event) => {
|
|
561
|
+
if (event.pointerType !== "touch") setActiveIndexForCurrentItems(index);
|
|
562
|
+
},
|
|
563
|
+
onPointerDown: (event) => {
|
|
564
|
+
if (event.button > 0) return;
|
|
565
|
+
event.preventDefault();
|
|
566
|
+
onSelectItem(item);
|
|
567
|
+
},
|
|
568
|
+
onClick: (event) => {
|
|
569
|
+
if (event.detail === 0) onSelectItem(item);
|
|
570
|
+
},
|
|
571
|
+
className: `flex w-full items-start gap-2 rounded-lg px-2 py-1.5 text-left transition ${isActive ? "bg-gray-100 text-gray-900" : "text-gray-700 hover:bg-gray-50"}`,
|
|
572
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
573
|
+
className: "truncate text-xs font-semibold",
|
|
574
|
+
children: title
|
|
575
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
576
|
+
className: "truncate text-xs text-gray-500",
|
|
577
|
+
children: subtitle
|
|
578
|
+
})]
|
|
579
|
+
})]
|
|
580
|
+
}, key);
|
|
581
|
+
})
|
|
582
|
+
})] })
|
|
583
|
+
})]
|
|
543
584
|
}), /* @__PURE__ */ jsx("div", {
|
|
544
585
|
className: "custom-scrollbar min-h-0 min-w-0 overflow-y-auto overscroll-contain p-2.5",
|
|
545
586
|
onPointerDown: onDetailsPointerDown,
|
|
@@ -634,6 +675,7 @@ function ChatInputSurfaceHost(props) {
|
|
|
634
675
|
ref: menuRef,
|
|
635
676
|
isOpen,
|
|
636
677
|
isLoading: inputSurface.isLoading,
|
|
678
|
+
filterOptions: inputSurface.filterOptions,
|
|
637
679
|
items: inputSurface.items,
|
|
638
680
|
texts: inputSurface.texts,
|
|
639
681
|
onSelectItem: (item) => {
|
|
@@ -775,7 +817,14 @@ function ChatInputBarActions({ sendError, sendErrorDetailsLabel, isSending, canS
|
|
|
775
817
|
})] })]
|
|
776
818
|
}) : null, /* @__PURE__ */ jsxs("div", {
|
|
777
819
|
className: "flex items-center gap-2",
|
|
778
|
-
children: [contextWindow ? /* @__PURE__ */ jsx(ContextWindowIndicator, { contextWindow }) : null, isSending
|
|
820
|
+
children: [contextWindow ? /* @__PURE__ */ jsx(ContextWindowIndicator, { contextWindow }) : null, !isSending || !sendDisabled ? /* @__PURE__ */ jsx(ChatButton, {
|
|
821
|
+
size: "icon",
|
|
822
|
+
className: "h-8 w-8 rounded-full",
|
|
823
|
+
"aria-label": sendButtonLabel,
|
|
824
|
+
onClick: () => void onSend(),
|
|
825
|
+
disabled: sendDisabled,
|
|
826
|
+
children: /* @__PURE__ */ jsx(ArrowUp, { className: "h-5 w-5" })
|
|
827
|
+
}) : canStopGeneration ? /* @__PURE__ */ jsx(ChatButton, {
|
|
779
828
|
size: "icon",
|
|
780
829
|
variant: "outline",
|
|
781
830
|
className: "h-8 w-8 rounded-full",
|
|
@@ -799,14 +848,7 @@ function ChatInputBarActions({ sendError, sendErrorDetailsLabel, isSending, canS
|
|
|
799
848
|
className: "text-xs",
|
|
800
849
|
children: stopHint
|
|
801
850
|
})
|
|
802
|
-
})] }) })
|
|
803
|
-
size: "icon",
|
|
804
|
-
className: "h-8 w-8 rounded-full",
|
|
805
|
-
"aria-label": sendButtonLabel,
|
|
806
|
-
onClick: () => void onSend(),
|
|
807
|
-
disabled: sendDisabled,
|
|
808
|
-
children: /* @__PURE__ */ jsx(ArrowUp, { className: "h-5 w-5" })
|
|
809
|
-
})]
|
|
851
|
+
})] }) })]
|
|
810
852
|
})]
|
|
811
853
|
});
|
|
812
854
|
}
|
|
@@ -1281,11 +1323,11 @@ function buildTokenClassName(tokenKind) {
|
|
|
1281
1323
|
"gap-1.5",
|
|
1282
1324
|
"rounded-lg",
|
|
1283
1325
|
"border",
|
|
1284
|
-
"border-
|
|
1285
|
-
"bg-
|
|
1326
|
+
"border-border",
|
|
1327
|
+
"bg-muted",
|
|
1286
1328
|
"px-2",
|
|
1287
1329
|
"align-baseline",
|
|
1288
|
-
"text-
|
|
1330
|
+
"text-foreground",
|
|
1289
1331
|
"transition-[border-color,background-color,box-shadow,color]",
|
|
1290
1332
|
"duration-150"
|
|
1291
1333
|
].join(" ");
|
|
@@ -1310,7 +1352,7 @@ function buildTokenClassName(tokenKind) {
|
|
|
1310
1352
|
}
|
|
1311
1353
|
function ChatComposerTokenChip({ label, tokenKind }) {
|
|
1312
1354
|
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
|
|
1313
|
-
className: tokenKind === "file" ? "inline-flex h-4.5 w-4.5 shrink-0 items-center justify-center rounded-md bg-
|
|
1355
|
+
className: tokenKind === "file" ? "inline-flex h-4.5 w-4.5 shrink-0 items-center justify-center rounded-md bg-card text-muted-foreground ring-1 ring-border" : "inline-flex h-3.5 w-3.5 shrink-0 items-center justify-center text-primary/70",
|
|
1314
1356
|
children: tokenKind === "file" ? /* @__PURE__ */ jsx(ImageIcon, {
|
|
1315
1357
|
"aria-hidden": "true",
|
|
1316
1358
|
className: "h-3 w-3"
|
|
@@ -1322,7 +1364,7 @@ function ChatComposerTokenChip({ label, tokenKind }) {
|
|
|
1322
1364
|
className: "h-3 w-3"
|
|
1323
1365
|
})
|
|
1324
1366
|
}), /* @__PURE__ */ jsx("span", {
|
|
1325
|
-
className: tokenKind === "file" ? "min-w-0 flex-1 truncate text-[12px] font-medium text-
|
|
1367
|
+
className: tokenKind === "file" ? "min-w-0 flex-1 truncate text-[12px] font-medium text-foreground" : "truncate",
|
|
1326
1368
|
children: label
|
|
1327
1369
|
})] });
|
|
1328
1370
|
}
|
|
@@ -1786,7 +1828,6 @@ function deleteChatComposerContent(params) {
|
|
|
1786
1828
|
//#region src/components/chat/ui/chat-input-bar/lexical/chat-composer-lexical-controller.ts
|
|
1787
1829
|
function resolveLexicalComposerKeyboardAction(params) {
|
|
1788
1830
|
const { canStopGeneration, isComposing, isSending, key, shiftKey } = params;
|
|
1789
|
-
if (key === "Enter" && !shiftKey && isSending) return { type: "consume" };
|
|
1790
1831
|
if (key === "Escape") {
|
|
1791
1832
|
if (isSending && canStopGeneration) return { type: "stop-generation" };
|
|
1792
1833
|
return { type: "noop" };
|
|
@@ -1853,7 +1894,6 @@ function handleLexicalComposerKeyboardCommand(params) {
|
|
|
1853
1894
|
});
|
|
1854
1895
|
if (action.type !== "noop") nativeEvent.preventDefault();
|
|
1855
1896
|
switch (action.type) {
|
|
1856
|
-
case "consume": return true;
|
|
1857
1897
|
case "stop-generation":
|
|
1858
1898
|
actions.onStop();
|
|
1859
1899
|
return true;
|
|
@@ -2269,10 +2309,11 @@ function InputBarHint({ hint }) {
|
|
|
2269
2309
|
})
|
|
2270
2310
|
});
|
|
2271
2311
|
}
|
|
2272
|
-
const ChatInputBar = forwardRef(function ChatInputBar({ composer, hint, inputSurface, slashMenu, surface, toolbar: toolbarProps }, ref) {
|
|
2312
|
+
const ChatInputBar = forwardRef(function ChatInputBar({ composer, hint, inputSurface, slashMenu, surface, toolbar: toolbarProps, topSlot }, ref) {
|
|
2273
2313
|
const composerRef = useRef(null);
|
|
2274
2314
|
const resolvedInputSurface = inputSurface ?? (slashMenu ? {
|
|
2275
2315
|
isLoading: slashMenu.isLoading,
|
|
2316
|
+
filterOptions: slashMenu.filterOptions,
|
|
2276
2317
|
items: slashMenu.items,
|
|
2277
2318
|
onSelectItem: slashMenu.onSelectItem,
|
|
2278
2319
|
texts: {
|
|
@@ -2309,6 +2350,10 @@ const ChatInputBar = forwardRef(function ChatInputBar({ composer, hint, inputSur
|
|
|
2309
2350
|
children: /* @__PURE__ */ jsxs("div", {
|
|
2310
2351
|
className: "overflow-hidden rounded-2xl border border-border bg-card shadow-card",
|
|
2311
2352
|
children: [
|
|
2353
|
+
topSlot ? /* @__PURE__ */ jsx("div", {
|
|
2354
|
+
className: "px-3 pb-0 pt-2 sm:px-4 sm:pt-2.5",
|
|
2355
|
+
children: topSlot
|
|
2356
|
+
}) : null,
|
|
2312
2357
|
/* @__PURE__ */ jsx("div", {
|
|
2313
2358
|
className: "relative",
|
|
2314
2359
|
children: /* @__PURE__ */ jsx(ChatInputSurfaceHost, {
|
|
@@ -2649,7 +2694,7 @@ var ChatCodeSyntaxHighlighter = class {
|
|
|
2649
2694
|
const chatCodeSyntaxHighlighter = new ChatCodeSyntaxHighlighter();
|
|
2650
2695
|
//#endregion
|
|
2651
2696
|
//#region src/components/chat/ui/chat-message-list/chat-code-block.tsx
|
|
2652
|
-
const CODE_LANGUAGE_REGEX = /language-([a-z0-9-]+)/i;
|
|
2697
|
+
const CODE_LANGUAGE_REGEX$1 = /language-([a-z0-9-]+)/i;
|
|
2653
2698
|
function flattenNodeText(value) {
|
|
2654
2699
|
if (typeof value === "string" || typeof value === "number") return String(value);
|
|
2655
2700
|
if (Array.isArray(value)) return value.map(flattenNodeText).join("");
|
|
@@ -2660,7 +2705,7 @@ function normalizeCodeText(value) {
|
|
|
2660
2705
|
return content.endsWith("\n") ? content.slice(0, -1) : content;
|
|
2661
2706
|
}
|
|
2662
2707
|
function resolveCodeLanguage(className) {
|
|
2663
|
-
return (className ? CODE_LANGUAGE_REGEX.exec(className) : null)?.[1]?.toLowerCase() || "text";
|
|
2708
|
+
return (className ? CODE_LANGUAGE_REGEX$1.exec(className) : null)?.[1]?.toLowerCase() || "text";
|
|
2664
2709
|
}
|
|
2665
2710
|
function ChatCodeBlock({ className, children, texts }) {
|
|
2666
2711
|
const language = useMemo(() => resolveCodeLanguage(className), [className]);
|
|
@@ -2693,6 +2738,176 @@ function ChatCodeBlock({ className, children, texts }) {
|
|
|
2693
2738
|
});
|
|
2694
2739
|
}
|
|
2695
2740
|
//#endregion
|
|
2741
|
+
//#region src/components/chat/ui/chat-message-list/utils/chat-inline-display.utils.ts
|
|
2742
|
+
const INLINE_DISPLAY_LANGUAGE = "nextclaw-inline";
|
|
2743
|
+
const CODE_LANGUAGE_REGEX = /language-([a-z0-9-]+)/i;
|
|
2744
|
+
const FILE_PREVIEW_VIEWERS = new Set([
|
|
2745
|
+
"auto",
|
|
2746
|
+
"source",
|
|
2747
|
+
"rendered"
|
|
2748
|
+
]);
|
|
2749
|
+
function isRecord$1(value) {
|
|
2750
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2751
|
+
}
|
|
2752
|
+
function readString(value) {
|
|
2753
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
2754
|
+
}
|
|
2755
|
+
function readPositiveInteger(value) {
|
|
2756
|
+
return Number.isInteger(value) && Number(value) > 0 ? Number(value) : void 0;
|
|
2757
|
+
}
|
|
2758
|
+
function readFilePreviewViewer(value) {
|
|
2759
|
+
const viewer = readString(value);
|
|
2760
|
+
return viewer && FILE_PREVIEW_VIEWERS.has(viewer) ? viewer : void 0;
|
|
2761
|
+
}
|
|
2762
|
+
function readTargetPayload(record) {
|
|
2763
|
+
const { payload } = record;
|
|
2764
|
+
return isRecord$1(payload) ? payload : null;
|
|
2765
|
+
}
|
|
2766
|
+
function readFileTarget(record) {
|
|
2767
|
+
const payload = readTargetPayload(record);
|
|
2768
|
+
if (!payload) return null;
|
|
2769
|
+
const path = readString(payload.path);
|
|
2770
|
+
if (!path) return null;
|
|
2771
|
+
return {
|
|
2772
|
+
type: "file",
|
|
2773
|
+
payload: {
|
|
2774
|
+
path,
|
|
2775
|
+
line: readPositiveInteger(payload.line),
|
|
2776
|
+
column: readPositiveInteger(payload.column),
|
|
2777
|
+
viewer: readFilePreviewViewer(payload.viewer)
|
|
2778
|
+
}
|
|
2779
|
+
};
|
|
2780
|
+
}
|
|
2781
|
+
function readUrlTarget(record) {
|
|
2782
|
+
const payload = readTargetPayload(record);
|
|
2783
|
+
if (!payload) return null;
|
|
2784
|
+
const url = readString(payload.url);
|
|
2785
|
+
if (!url) return null;
|
|
2786
|
+
return {
|
|
2787
|
+
type: "url",
|
|
2788
|
+
payload: { url }
|
|
2789
|
+
};
|
|
2790
|
+
}
|
|
2791
|
+
function readPanelAppTarget(record) {
|
|
2792
|
+
const payload = readTargetPayload(record);
|
|
2793
|
+
if (!payload) return null;
|
|
2794
|
+
const appId = readString(payload.appId);
|
|
2795
|
+
if (!appId) return null;
|
|
2796
|
+
return {
|
|
2797
|
+
type: "panel_app",
|
|
2798
|
+
payload: { appId }
|
|
2799
|
+
};
|
|
2800
|
+
}
|
|
2801
|
+
function readJsonTarget(record) {
|
|
2802
|
+
const payload = readTargetPayload(record);
|
|
2803
|
+
if (!payload || !("value" in payload)) return null;
|
|
2804
|
+
return {
|
|
2805
|
+
type: "json",
|
|
2806
|
+
payload: { value: payload.value }
|
|
2807
|
+
};
|
|
2808
|
+
}
|
|
2809
|
+
function readInlineDisplayTarget(value) {
|
|
2810
|
+
if (!isRecord$1(value)) return null;
|
|
2811
|
+
const type = readString(value.type);
|
|
2812
|
+
if (type === "file") return readFileTarget(value);
|
|
2813
|
+
if (type === "url") return readUrlTarget(value);
|
|
2814
|
+
if (type === "panel_app") return readPanelAppTarget(value);
|
|
2815
|
+
if (type === "json") return readJsonTarget(value);
|
|
2816
|
+
return null;
|
|
2817
|
+
}
|
|
2818
|
+
function isChatInlineDisplayLanguage(className) {
|
|
2819
|
+
return (className ? CODE_LANGUAGE_REGEX.exec(className) : null)?.[1]?.toLowerCase() === INLINE_DISPLAY_LANGUAGE;
|
|
2820
|
+
}
|
|
2821
|
+
function parseChatInlineDisplayDirective(rawText) {
|
|
2822
|
+
const text = rawText.endsWith("\n") ? rawText.slice(0, -1) : rawText;
|
|
2823
|
+
let parsed;
|
|
2824
|
+
try {
|
|
2825
|
+
parsed = JSON.parse(text);
|
|
2826
|
+
} catch {
|
|
2827
|
+
return null;
|
|
2828
|
+
}
|
|
2829
|
+
if (!isRecord$1(parsed)) return null;
|
|
2830
|
+
const target = readInlineDisplayTarget(parsed.target);
|
|
2831
|
+
if (!target) return null;
|
|
2832
|
+
return {
|
|
2833
|
+
target,
|
|
2834
|
+
title: readString(parsed.title),
|
|
2835
|
+
description: readString(parsed.description)
|
|
2836
|
+
};
|
|
2837
|
+
}
|
|
2838
|
+
function getChatInlineDisplayLabel(display) {
|
|
2839
|
+
if (display.title) return display.title;
|
|
2840
|
+
if (display.target.type === "file") {
|
|
2841
|
+
const segments = display.target.payload.path.split("/").filter(Boolean);
|
|
2842
|
+
return segments[segments.length - 1] ?? display.target.payload.path;
|
|
2843
|
+
}
|
|
2844
|
+
if (display.target.type === "url") return display.target.payload.url;
|
|
2845
|
+
if (display.target.type === "panel_app") return display.target.payload.appId;
|
|
2846
|
+
return "JSON";
|
|
2847
|
+
}
|
|
2848
|
+
function getChatInlineDisplayDetail(display) {
|
|
2849
|
+
if (display.target.type === "file") return display.target.payload.path;
|
|
2850
|
+
if (display.target.type === "url") return display.target.payload.url;
|
|
2851
|
+
if (display.target.type === "panel_app") return display.target.payload.appId;
|
|
2852
|
+
return JSON.stringify(display.target.payload.value, null, 2);
|
|
2853
|
+
}
|
|
2854
|
+
//#endregion
|
|
2855
|
+
//#region src/components/chat/ui/chat-message-list/chat-inline-display.tsx
|
|
2856
|
+
function ChatInlineDisplayIcon({ display }) {
|
|
2857
|
+
const className = "h-3.5 w-3.5 shrink-0 text-muted-foreground";
|
|
2858
|
+
if (display.target.type === "file") return /* @__PURE__ */ jsx(FileText, {
|
|
2859
|
+
className,
|
|
2860
|
+
"aria-hidden": true
|
|
2861
|
+
});
|
|
2862
|
+
if (display.target.type === "url") return /* @__PURE__ */ jsx(Globe, {
|
|
2863
|
+
className,
|
|
2864
|
+
"aria-hidden": true
|
|
2865
|
+
});
|
|
2866
|
+
if (display.target.type === "panel_app") return /* @__PURE__ */ jsx(AppWindow, {
|
|
2867
|
+
className,
|
|
2868
|
+
"aria-hidden": true
|
|
2869
|
+
});
|
|
2870
|
+
return /* @__PURE__ */ jsx(Code2, {
|
|
2871
|
+
className,
|
|
2872
|
+
"aria-hidden": true
|
|
2873
|
+
});
|
|
2874
|
+
}
|
|
2875
|
+
function formatJsonDetail(value) {
|
|
2876
|
+
return value.length > 1200 ? `${value.slice(0, 1200)}\n...` : value;
|
|
2877
|
+
}
|
|
2878
|
+
function ChatInlineDisplayFallback({ display }) {
|
|
2879
|
+
const label = getChatInlineDisplayLabel(display);
|
|
2880
|
+
const detail = getChatInlineDisplayDetail(display);
|
|
2881
|
+
const formattedDetail = display.target.type === "json" ? formatJsonDetail(detail) : detail;
|
|
2882
|
+
return /* @__PURE__ */ jsxs("section", {
|
|
2883
|
+
className: cn("my-2 max-w-full border-l-2 border-border bg-muted/30 px-3 py-2", "text-xs leading-relaxed text-foreground"),
|
|
2884
|
+
"data-nextclaw-inline-display": "true",
|
|
2885
|
+
"data-nextclaw-inline-display-type": display.target.type,
|
|
2886
|
+
children: [
|
|
2887
|
+
/* @__PURE__ */ jsxs("div", {
|
|
2888
|
+
className: "flex min-w-0 items-center gap-2",
|
|
2889
|
+
children: [/* @__PURE__ */ jsx(ChatInlineDisplayIcon, { display }), /* @__PURE__ */ jsx("span", {
|
|
2890
|
+
className: "min-w-0 truncate font-medium",
|
|
2891
|
+
children: label
|
|
2892
|
+
})]
|
|
2893
|
+
}),
|
|
2894
|
+
display.description ? /* @__PURE__ */ jsx("p", {
|
|
2895
|
+
className: "mt-1 line-clamp-2 text-[12px] text-muted-foreground",
|
|
2896
|
+
children: display.description
|
|
2897
|
+
}) : null,
|
|
2898
|
+
/* @__PURE__ */ jsx("pre", {
|
|
2899
|
+
className: cn("mt-1 max-h-40 overflow-auto whitespace-pre-wrap break-words", "font-mono text-[11px] leading-relaxed text-muted-foreground"),
|
|
2900
|
+
children: formattedDetail
|
|
2901
|
+
})
|
|
2902
|
+
]
|
|
2903
|
+
});
|
|
2904
|
+
}
|
|
2905
|
+
function ChatInlineDisplay({ display, renderInlineDisplay }) {
|
|
2906
|
+
const rendered = renderInlineDisplay?.(display);
|
|
2907
|
+
if (rendered !== void 0 && rendered !== null) return /* @__PURE__ */ jsx(Fragment$1, { children: rendered });
|
|
2908
|
+
return /* @__PURE__ */ jsx(ChatInlineDisplayFallback, { display });
|
|
2909
|
+
}
|
|
2910
|
+
//#endregion
|
|
2696
2911
|
//#region src/components/chat/ui/chat-message-list/chat-message-markdown.tsx
|
|
2697
2912
|
const MARKDOWN_MAX_CHARS = 14e4;
|
|
2698
2913
|
const SAFE_LINK_PROTOCOLS = new Set([
|
|
@@ -2705,24 +2920,7 @@ const INLINE_TOKEN_KIND_ATTR = "data-chat-inline-token-kind";
|
|
|
2705
2920
|
const INLINE_TOKEN_KEY_ATTR = "data-chat-inline-token-key";
|
|
2706
2921
|
const INLINE_TOKEN_LABEL_ATTR = "data-chat-inline-token-label";
|
|
2707
2922
|
const INLINE_TOKEN_RAW_TEXT_ATTR = "data-chat-inline-token-raw-text";
|
|
2708
|
-
const
|
|
2709
|
-
"cjs",
|
|
2710
|
-
"css",
|
|
2711
|
-
"cts",
|
|
2712
|
-
"js",
|
|
2713
|
-
"json",
|
|
2714
|
-
"jsx",
|
|
2715
|
-
"md",
|
|
2716
|
-
"mdx",
|
|
2717
|
-
"mjs",
|
|
2718
|
-
"mts",
|
|
2719
|
-
"tsx",
|
|
2720
|
-
"ts",
|
|
2721
|
-
"txt",
|
|
2722
|
-
"yaml",
|
|
2723
|
-
"yml"
|
|
2724
|
-
].join("|");
|
|
2725
|
-
const PROJECT_RELATIVE_FILE_HREF_PATTERN = new RegExp(`^(?![a-zA-Z][a-zA-Z\\d+.-]*:)(?!//)(?:(?:[^/\\s?#]+/)+[^?#\\s]+\\.[A-Za-z0-9_-]+|[^/\\s?#]+\\.(?:${PROJECT_RELATIVE_FILE_EXTENSIONS}))(?::\\d+(?::\\d+)?)?(?:[?#].*)?$`, "i");
|
|
2923
|
+
const PROJECT_RELATIVE_FILE_HREF_PATTERN = new RegExp(`^(?![a-zA-Z][a-zA-Z\\d+.-]*:)(?!//)(?:(?:[^/\\s?#]+/)+[^?#\\s]+\\.[A-Za-z0-9_-]+|[^/\\s?#]+\\.(?:cjs|css|cts|html?|js|json|jsx|mdx?|mjs|mts|tsx?|txt|ya?ml))(?::\\d+(?::\\d+)?)?(?:[?#].*)?$`, "i");
|
|
2726
2924
|
function trimMarkdown(value) {
|
|
2727
2925
|
if (value.length <= MARKDOWN_MAX_CHARS) return value;
|
|
2728
2926
|
return `${value.slice(0, MARKDOWN_MAX_CHARS)}\n\n...`;
|
|
@@ -2744,6 +2942,7 @@ function looksLikeLocalFileHref(href) {
|
|
|
2744
2942
|
return href.startsWith("./") || href.startsWith("../") || href.startsWith("/Users/") || href.startsWith("/home/") || href.startsWith("/tmp/") || href.startsWith("/var/") || PROJECT_RELATIVE_FILE_HREF_PATTERN.test(href) || /^\/.+\.[A-Za-z0-9_-]+(?::\d+(?::\d+)?)?$/.test(href);
|
|
2745
2943
|
}
|
|
2746
2944
|
function parseLocalFileAction(href) {
|
|
2945
|
+
const viewer = new URLSearchParams(href.split("#")[0]?.split("?")[1] ?? "").get("viewer");
|
|
2747
2946
|
const normalizedHref = href.split("#")[0]?.split("?")[0] ?? href;
|
|
2748
2947
|
const decodedHref = decodeURIComponent(normalizedHref);
|
|
2749
2948
|
if (!looksLikeLocalFileHref(decodedHref)) return null;
|
|
@@ -2755,6 +2954,7 @@ function parseLocalFileAction(href) {
|
|
|
2755
2954
|
path: rawPath,
|
|
2756
2955
|
label: rawPath.split("/").filter(Boolean).pop() ?? rawPath,
|
|
2757
2956
|
viewMode: "preview",
|
|
2957
|
+
...viewer === "source" || viewer === "rendered" ? { previewViewer: viewer } : {},
|
|
2758
2958
|
...typeof line === "number" ? { line } : {},
|
|
2759
2959
|
...typeof column === "number" ? { column } : {}
|
|
2760
2960
|
};
|
|
@@ -2848,7 +3048,7 @@ function readStringProp(props, key) {
|
|
|
2848
3048
|
const value = props[key];
|
|
2849
3049
|
return typeof value === "string" && value.length > 0 ? value : null;
|
|
2850
3050
|
}
|
|
2851
|
-
function ChatMessageMarkdown({ text, role, texts, inline = false, inlineTokens, onFileOpen }) {
|
|
3051
|
+
function ChatMessageMarkdown({ text, role, texts, inline = false, inlineTokens, onFileOpen, renderInlineDisplay }) {
|
|
2852
3052
|
const isUser = role === "user";
|
|
2853
3053
|
const remarkPlugins = useMemo(() => inlineTokens && inlineTokens.length > 0 ? [remarkGfm, createRemarkInlineTokenPlugin(inlineTokens)] : [remarkGfm], [inlineTokens]);
|
|
2854
3054
|
const markdownComponents = useMemo(() => ({
|
|
@@ -2869,7 +3069,7 @@ function ChatMessageMarkdown({ text, role, texts, inline = false, inlineTokens,
|
|
|
2869
3069
|
children
|
|
2870
3070
|
});
|
|
2871
3071
|
},
|
|
2872
|
-
a: ({ href, children, ...rest }) => {
|
|
3072
|
+
a: ({ node: _node, href, children, ...rest }) => {
|
|
2873
3073
|
const safeHref = resolveSafeHref(href);
|
|
2874
3074
|
if (!safeHref) return /* @__PURE__ */ jsx("span", {
|
|
2875
3075
|
className: "chat-link-invalid",
|
|
@@ -2892,14 +3092,14 @@ function ChatMessageMarkdown({ text, role, texts, inline = false, inlineTokens,
|
|
|
2892
3092
|
children
|
|
2893
3093
|
});
|
|
2894
3094
|
},
|
|
2895
|
-
table: ({ children, ...rest }) => /* @__PURE__ */ jsx("div", {
|
|
3095
|
+
table: ({ node: _node, children, ...rest }) => /* @__PURE__ */ jsx("div", {
|
|
2896
3096
|
className: "chat-table-wrap",
|
|
2897
3097
|
children: /* @__PURE__ */ jsx("table", {
|
|
2898
3098
|
...rest,
|
|
2899
3099
|
children
|
|
2900
3100
|
})
|
|
2901
3101
|
}),
|
|
2902
|
-
input: ({ type, checked, ...rest }) => {
|
|
3102
|
+
input: ({ node: _node, type, checked, ...rest }) => {
|
|
2903
3103
|
if (type !== "checkbox") return /* @__PURE__ */ jsx("input", {
|
|
2904
3104
|
...rest,
|
|
2905
3105
|
type
|
|
@@ -2913,7 +3113,7 @@ function ChatMessageMarkdown({ text, role, texts, inline = false, inlineTokens,
|
|
|
2913
3113
|
className: "chat-task-checkbox"
|
|
2914
3114
|
});
|
|
2915
3115
|
},
|
|
2916
|
-
img: ({ src, alt, ...rest }) => {
|
|
3116
|
+
img: ({ node: _node, src, alt, ...rest }) => {
|
|
2917
3117
|
const safeSrc = resolveSafeHref(src);
|
|
2918
3118
|
if (!safeSrc) return null;
|
|
2919
3119
|
return /* @__PURE__ */ jsx("img", {
|
|
@@ -2924,12 +3124,18 @@ function ChatMessageMarkdown({ text, role, texts, inline = false, inlineTokens,
|
|
|
2924
3124
|
decoding: "async"
|
|
2925
3125
|
});
|
|
2926
3126
|
},
|
|
2927
|
-
code: ({ className, children, ...rest }) => {
|
|
2928
|
-
|
|
3127
|
+
code: ({ node: _node, className, children, ...rest }) => {
|
|
3128
|
+
const plainText = String(children ?? "");
|
|
3129
|
+
if (!className && !plainText.includes("\n")) return /* @__PURE__ */ jsx("code", {
|
|
2929
3130
|
...rest,
|
|
2930
3131
|
className: cn("chat-inline-code", className),
|
|
2931
3132
|
children
|
|
2932
3133
|
});
|
|
3134
|
+
const inlineDisplay = isChatInlineDisplayLanguage(className) ? parseChatInlineDisplayDirective(plainText) : null;
|
|
3135
|
+
if (inlineDisplay) return /* @__PURE__ */ jsx(ChatInlineDisplay, {
|
|
3136
|
+
display: inlineDisplay,
|
|
3137
|
+
renderInlineDisplay
|
|
3138
|
+
});
|
|
2933
3139
|
return /* @__PURE__ */ jsx(ChatCodeBlock, {
|
|
2934
3140
|
className,
|
|
2935
3141
|
texts,
|
|
@@ -2940,6 +3146,7 @@ function ChatMessageMarkdown({ text, role, texts, inline = false, inlineTokens,
|
|
|
2940
3146
|
inline,
|
|
2941
3147
|
isUser,
|
|
2942
3148
|
onFileOpen,
|
|
3149
|
+
renderInlineDisplay,
|
|
2943
3150
|
texts
|
|
2944
3151
|
]);
|
|
2945
3152
|
return /* @__PURE__ */ jsx(inline ? "span" : "div", {
|
|
@@ -3371,12 +3578,20 @@ function useReasoningBlockOpenState(params) {
|
|
|
3371
3578
|
//#region src/components/chat/hooks/use-sticky-bottom-scroll.ts
|
|
3372
3579
|
const DEFAULT_STICKY_THRESHOLD_PX = 10;
|
|
3373
3580
|
function useStickyBottomScroll({ contentVersion, hasContent, isLoading, resetKey, scrollRef, stickyThresholdPx }) {
|
|
3581
|
+
const [isAtBottom, setIsAtBottom] = useState(true);
|
|
3374
3582
|
const isStickyRef = useRef(true);
|
|
3375
3583
|
const isProgrammaticScrollRef = useRef(false);
|
|
3376
3584
|
const previousResetKeyRef = useRef(null);
|
|
3377
3585
|
const pendingInitialScrollRef = useRef(false);
|
|
3378
3586
|
const scheduledScrollFrameRef = useRef(null);
|
|
3379
|
-
const
|
|
3587
|
+
const updateStickyState = useCallback((nextIsAtBottom) => {
|
|
3588
|
+
isStickyRef.current = nextIsAtBottom;
|
|
3589
|
+
setIsAtBottom(nextIsAtBottom);
|
|
3590
|
+
}, []);
|
|
3591
|
+
const resolveIsAtBottom = useCallback((element) => {
|
|
3592
|
+
return element.scrollHeight - element.scrollTop - element.clientHeight <= (stickyThresholdPx ?? DEFAULT_STICKY_THRESHOLD_PX);
|
|
3593
|
+
}, [stickyThresholdPx]);
|
|
3594
|
+
const queueScrollToBottom = useCallback((behavior = "auto") => {
|
|
3380
3595
|
if (!scrollRef.current) return;
|
|
3381
3596
|
if (scheduledScrollFrameRef.current !== null) cancelAnimationFrame(scheduledScrollFrameRef.current);
|
|
3382
3597
|
scheduledScrollFrameRef.current = requestAnimationFrame(() => {
|
|
@@ -3384,24 +3599,36 @@ function useStickyBottomScroll({ contentVersion, hasContent, isLoading, resetKey
|
|
|
3384
3599
|
const currentElement = scrollRef.current;
|
|
3385
3600
|
if (!currentElement) return;
|
|
3386
3601
|
isProgrammaticScrollRef.current = true;
|
|
3387
|
-
currentElement.
|
|
3602
|
+
if (typeof currentElement.scrollTo === "function") currentElement.scrollTo({
|
|
3603
|
+
top: currentElement.scrollHeight,
|
|
3604
|
+
behavior
|
|
3605
|
+
});
|
|
3606
|
+
else currentElement.scrollTop = currentElement.scrollHeight;
|
|
3388
3607
|
});
|
|
3389
3608
|
}, [scrollRef]);
|
|
3390
|
-
const
|
|
3609
|
+
const scrollToBottom = useCallback(() => {
|
|
3610
|
+
updateStickyState(true);
|
|
3611
|
+
queueScrollToBottom();
|
|
3612
|
+
}, [queueScrollToBottom, updateStickyState]);
|
|
3613
|
+
const onScroll = useCallback(() => {
|
|
3391
3614
|
if (isProgrammaticScrollRef.current) {
|
|
3392
3615
|
isProgrammaticScrollRef.current = false;
|
|
3393
3616
|
return;
|
|
3394
3617
|
}
|
|
3395
3618
|
const element = scrollRef.current;
|
|
3396
3619
|
if (!element) return;
|
|
3397
|
-
|
|
3398
|
-
}
|
|
3620
|
+
updateStickyState(resolveIsAtBottom(element));
|
|
3621
|
+
}, [
|
|
3622
|
+
resolveIsAtBottom,
|
|
3623
|
+
scrollRef,
|
|
3624
|
+
updateStickyState
|
|
3625
|
+
]);
|
|
3399
3626
|
useEffect(() => {
|
|
3400
3627
|
if (previousResetKeyRef.current === resetKey) return;
|
|
3401
3628
|
previousResetKeyRef.current = resetKey;
|
|
3402
|
-
|
|
3629
|
+
updateStickyState(true);
|
|
3403
3630
|
pendingInitialScrollRef.current = true;
|
|
3404
|
-
}, [resetKey]);
|
|
3631
|
+
}, [resetKey, updateStickyState]);
|
|
3405
3632
|
useEffect(() => {
|
|
3406
3633
|
return () => {
|
|
3407
3634
|
const scheduledScrollFrame = scheduledScrollFrameRef.current;
|
|
@@ -3432,7 +3659,11 @@ function useStickyBottomScroll({ contentVersion, hasContent, isLoading, resetKey
|
|
|
3432
3659
|
queueScrollToBottom,
|
|
3433
3660
|
scrollRef
|
|
3434
3661
|
]);
|
|
3435
|
-
return {
|
|
3662
|
+
return {
|
|
3663
|
+
isAtBottom,
|
|
3664
|
+
onScroll,
|
|
3665
|
+
scrollToBottom
|
|
3666
|
+
};
|
|
3436
3667
|
}
|
|
3437
3668
|
//#endregion
|
|
3438
3669
|
//#region src/components/chat/ui/chat-message-list/chat-reasoning-block.tsx
|
|
@@ -3639,6 +3870,20 @@ function readLineNumberColumnWidth(block) {
|
|
|
3639
3870
|
function readCodeColumnWidth(block) {
|
|
3640
3871
|
return `calc(${block.lines.reduce((currentMax, line) => Math.max(currentMax, Math.max(1, line.text.length)), 1)}ch + 1.25rem)`;
|
|
3641
3872
|
}
|
|
3873
|
+
function readPathExtension(path) {
|
|
3874
|
+
const fileName = path.split(/[\\/]/).filter(Boolean).pop() ?? path;
|
|
3875
|
+
const cleanName = fileName.split(/[?#]/)[0] ?? fileName;
|
|
3876
|
+
const extensionStart = cleanName.lastIndexOf(".");
|
|
3877
|
+
if (extensionStart <= 0 || extensionStart === cleanName.length - 1) return null;
|
|
3878
|
+
return cleanName.slice(extensionStart + 1).toLowerCase();
|
|
3879
|
+
}
|
|
3880
|
+
function readBlockLanguage(block) {
|
|
3881
|
+
return block.languageHint?.trim() || readPathExtension(block.path) || "text";
|
|
3882
|
+
}
|
|
3883
|
+
function readLanguageClassName(language) {
|
|
3884
|
+
const normalized = language.toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
|
3885
|
+
return normalized ? `language-${normalized}` : "language-text";
|
|
3886
|
+
}
|
|
3642
3887
|
function getLineNumberTone(line) {
|
|
3643
3888
|
if (line.kind === "remove") return "border-r border-rose-200 bg-rose-50 text-rose-700";
|
|
3644
3889
|
if (line.kind === "add") return "border-r border-emerald-200 bg-emerald-50 text-emerald-700";
|
|
@@ -3660,14 +3905,17 @@ function FileOperationLineNumberCell({ layout, line, lineNumberColumnWidth }) {
|
|
|
3660
3905
|
children: readVisibleLineNumber(line)
|
|
3661
3906
|
});
|
|
3662
3907
|
}
|
|
3663
|
-
function FileOperationCodeCell({ line }) {
|
|
3908
|
+
function FileOperationCodeCell({ language, line }) {
|
|
3909
|
+
const highlightedCode = useMemo(() => chatCodeSyntaxHighlighter.highlight(line.text || " ", language), [language, line.text]);
|
|
3664
3910
|
return /* @__PURE__ */ jsx("span", {
|
|
3665
3911
|
"data-file-code-row": "true",
|
|
3666
|
-
|
|
3667
|
-
|
|
3912
|
+
"data-file-code-language": highlightedCode.language,
|
|
3913
|
+
"data-highlighted": highlightedCode.highlighted ? "true" : "false",
|
|
3914
|
+
className: cn("chat-file-code-syntax hljs block min-w-0 flex-1 whitespace-pre px-2.5", readLanguageClassName(highlightedCode.language), getCodeRowTone(line)),
|
|
3915
|
+
dangerouslySetInnerHTML: { __html: highlightedCode.html }
|
|
3668
3916
|
});
|
|
3669
3917
|
}
|
|
3670
|
-
function FileOperationLineRow({ line, showLineNumbers, lineNumberColumnWidth }) {
|
|
3918
|
+
function FileOperationLineRow({ language, line, showLineNumbers, lineNumberColumnWidth }) {
|
|
3671
3919
|
return /* @__PURE__ */ jsxs("div", {
|
|
3672
3920
|
"data-file-line-row": "true",
|
|
3673
3921
|
className: FILE_ROW_CLASS_NAME,
|
|
@@ -3675,13 +3923,17 @@ function FileOperationLineRow({ line, showLineNumbers, lineNumberColumnWidth })
|
|
|
3675
3923
|
layout: "compact",
|
|
3676
3924
|
line,
|
|
3677
3925
|
lineNumberColumnWidth
|
|
3678
|
-
}) : null, /* @__PURE__ */ jsx(FileOperationCodeCell, {
|
|
3926
|
+
}) : null, /* @__PURE__ */ jsx(FileOperationCodeCell, {
|
|
3927
|
+
language,
|
|
3928
|
+
line
|
|
3929
|
+
})]
|
|
3679
3930
|
});
|
|
3680
3931
|
}
|
|
3681
3932
|
function FileOperationWorkspaceSurface({ block }) {
|
|
3682
3933
|
const showLineNumbers = readHasBlockLineNumbers(block);
|
|
3683
3934
|
const lineNumberColumnWidth = readLineNumberColumnWidth(block);
|
|
3684
3935
|
const codeColumnWidth = readCodeColumnWidth(block);
|
|
3936
|
+
const language = readBlockLanguage(block);
|
|
3685
3937
|
return /* @__PURE__ */ jsxs("div", {
|
|
3686
3938
|
"data-file-code-surface": "true",
|
|
3687
3939
|
"data-file-code-surface-layout": "workspace",
|
|
@@ -3708,7 +3960,10 @@ function FileOperationWorkspaceSurface({ block }) {
|
|
|
3708
3960
|
children: block.lines.map((line, index) => /* @__PURE__ */ jsx("div", {
|
|
3709
3961
|
"data-file-code-canvas-row": "true",
|
|
3710
3962
|
className: FILE_ROW_CLASS_NAME,
|
|
3711
|
-
children: /* @__PURE__ */ jsx(FileOperationCodeCell, {
|
|
3963
|
+
children: /* @__PURE__ */ jsx(FileOperationCodeCell, {
|
|
3964
|
+
language,
|
|
3965
|
+
line
|
|
3966
|
+
})
|
|
3712
3967
|
}, readLineKey("code", line, index)))
|
|
3713
3968
|
}), /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 bg-card" })]
|
|
3714
3969
|
})]
|
|
@@ -3720,6 +3975,7 @@ function FileOperationCodeSurface({ block, layout = "compact" }) {
|
|
|
3720
3975
|
const lineNumberColumnWidth = readLineNumberColumnWidth(block);
|
|
3721
3976
|
const codeColumnWidth = readCodeColumnWidth(block);
|
|
3722
3977
|
const surfaceMinWidth = showLineNumbers ? `calc(${lineNumberColumnWidth} + ${codeColumnWidth})` : codeColumnWidth;
|
|
3978
|
+
const language = readBlockLanguage(block);
|
|
3723
3979
|
return /* @__PURE__ */ jsx("div", {
|
|
3724
3980
|
"data-file-code-surface": "true",
|
|
3725
3981
|
"data-file-code-surface-layout": "compact",
|
|
@@ -3729,6 +3985,7 @@ function FileOperationCodeSurface({ block, layout = "compact" }) {
|
|
|
3729
3985
|
className: "min-w-full",
|
|
3730
3986
|
style: { minWidth: surfaceMinWidth },
|
|
3731
3987
|
children: block.lines.map((line, index) => /* @__PURE__ */ jsx(FileOperationLineRow, {
|
|
3988
|
+
language,
|
|
3732
3989
|
line,
|
|
3733
3990
|
showLineNumbers,
|
|
3734
3991
|
lineNumberColumnWidth
|
|
@@ -4039,20 +4296,21 @@ function GenericToolSection({ label, tone, children }) {
|
|
|
4039
4296
|
function TerminalExecutionView({ card }) {
|
|
4040
4297
|
const output = normalizeTerminalOutput(card.output, card.outputData);
|
|
4041
4298
|
const isRunning = card.statusTone === "running";
|
|
4042
|
-
const
|
|
4299
|
+
const commandPart = card.summary?.replace(/^(command|path|args|query|input):\s*/i, "");
|
|
4300
|
+
const hasOutput = output.trim().length > 0;
|
|
4301
|
+
const canExpand = isRunning || hasOutput || Boolean(commandPart?.trim());
|
|
4043
4302
|
const { expanded, onToggle } = useToolCardExpandedState({
|
|
4044
|
-
canExpand
|
|
4303
|
+
canExpand,
|
|
4045
4304
|
isRunning,
|
|
4046
4305
|
autoExpandWhileRunning: false,
|
|
4047
|
-
expandOnError:
|
|
4306
|
+
expandOnError: canExpand,
|
|
4048
4307
|
statusTone: card.statusTone
|
|
4049
4308
|
});
|
|
4050
|
-
const commandPart = card.summary?.replace(/^(command|path|args|query|input):\s*/i, "");
|
|
4051
4309
|
return /* @__PURE__ */ jsxs(ToolCardRoot, { children: [/* @__PURE__ */ jsx(ToolCardHeader, {
|
|
4052
4310
|
card,
|
|
4053
4311
|
icon: Terminal,
|
|
4054
4312
|
expanded,
|
|
4055
|
-
canExpand
|
|
4313
|
+
canExpand,
|
|
4056
4314
|
onToggle
|
|
4057
4315
|
}), expanded && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
|
|
4058
4316
|
className: "px-3 pb-2 font-mono w-full max-h-48 overflow-y-auto custom-scrollbar min-h-0 text-[12px]",
|
|
@@ -4069,10 +4327,13 @@ function TerminalExecutionView({ card }) {
|
|
|
4069
4327
|
}) : /* @__PURE__ */ jsx("div", { className: "h-3 w-32 bg-muted rounded animate-pulse mt-2" })
|
|
4070
4328
|
})]
|
|
4071
4329
|
})
|
|
4072
|
-
}),
|
|
4073
|
-
className:
|
|
4074
|
-
children:
|
|
4075
|
-
|
|
4330
|
+
}), (hasOutput || !isRunning) && /* @__PURE__ */ jsx(ToolCardContent, {
|
|
4331
|
+
className: hasOutput ? void 0 : "bg-muted/20 py-2",
|
|
4332
|
+
children: /* @__PURE__ */ jsxs("pre", {
|
|
4333
|
+
className: cn("font-mono text-[12px] text-muted-foreground whitespace-pre-wrap break-all w-full max-w-full max-h-64 overflow-y-auto overflow-x-hidden min-w-0 custom-scrollbar leading-relaxed", hasOutput ? "px-0" : "rounded-md border border-dashed border-border bg-card/70 px-3 py-2 italic"),
|
|
4334
|
+
children: [hasOutput ? output : card.emptyLabel, isRunning && hasOutput && /* @__PURE__ */ jsx("span", { className: "inline-block w-1.5 h-3 ml-1 bg-primary/60 animate-pulse align-middle" })]
|
|
4335
|
+
})
|
|
4336
|
+
})] })] });
|
|
4076
4337
|
}
|
|
4077
4338
|
function FileOperationView({ card, onFileOpen }) {
|
|
4078
4339
|
const output = card.output?.trim() ?? "";
|
|
@@ -4218,75 +4479,130 @@ function ChatToolCard({ card, onToolAction, onFileOpen, renderToolAgent, renderP
|
|
|
4218
4479
|
}
|
|
4219
4480
|
//#endregion
|
|
4220
4481
|
//#region src/components/chat/ui/chat-message-list/chat-message.tsx
|
|
4221
|
-
|
|
4482
|
+
function isMessageInProgress(status) {
|
|
4483
|
+
return status === "pending" || status === "streaming";
|
|
4484
|
+
}
|
|
4485
|
+
function isProcessPart(part) {
|
|
4486
|
+
return part.type === "reasoning" || part.type === "tool-card";
|
|
4487
|
+
}
|
|
4488
|
+
function splitAssistantProcess(message) {
|
|
4489
|
+
if (message.role !== "assistant" || !message.processSummary || isMessageInProgress(message.status)) return null;
|
|
4490
|
+
let lastProcessPartIndex = -1;
|
|
4491
|
+
for (let index = message.parts.length - 1; index >= 0; index -= 1) if (isProcessPart(message.parts[index])) {
|
|
4492
|
+
lastProcessPartIndex = index;
|
|
4493
|
+
break;
|
|
4494
|
+
}
|
|
4495
|
+
if (lastProcessPartIndex < 0 || lastProcessPartIndex >= message.parts.length - 1) return null;
|
|
4496
|
+
return {
|
|
4497
|
+
processParts: message.parts.slice(0, lastProcessPartIndex + 1),
|
|
4498
|
+
finalParts: message.parts.slice(lastProcessPartIndex + 1)
|
|
4499
|
+
};
|
|
4500
|
+
}
|
|
4501
|
+
function renderChatMessagePart({ index, isInProgress, isLastPart, isUser, onFileOpen, onToolAction, part, renderInlineDisplay, renderPanelAppCard, renderToolAgent, role, texts }) {
|
|
4502
|
+
const { type } = part;
|
|
4503
|
+
if (type === "markdown") {
|
|
4504
|
+
const { inlineTokens, text } = part;
|
|
4505
|
+
return /* @__PURE__ */ jsx(ChatMessageMarkdown, {
|
|
4506
|
+
text,
|
|
4507
|
+
role,
|
|
4508
|
+
texts,
|
|
4509
|
+
inlineTokens,
|
|
4510
|
+
onFileOpen,
|
|
4511
|
+
renderInlineDisplay
|
|
4512
|
+
}, `markdown-${index}`);
|
|
4513
|
+
}
|
|
4514
|
+
if (type === "reasoning") {
|
|
4515
|
+
const { label, text } = part;
|
|
4516
|
+
return /* @__PURE__ */ jsx(ChatReasoningBlock, {
|
|
4517
|
+
label,
|
|
4518
|
+
text,
|
|
4519
|
+
isUser,
|
|
4520
|
+
isInProgress: isInProgress && isLastPart
|
|
4521
|
+
}, `reasoning-${index}`);
|
|
4522
|
+
}
|
|
4523
|
+
if (type === "tool-card") {
|
|
4524
|
+
const { card } = part;
|
|
4525
|
+
return /* @__PURE__ */ jsx("div", {
|
|
4526
|
+
className: "mt-0.5",
|
|
4527
|
+
children: /* @__PURE__ */ jsx(ChatToolCard, {
|
|
4528
|
+
card,
|
|
4529
|
+
onToolAction,
|
|
4530
|
+
onFileOpen,
|
|
4531
|
+
renderToolAgent,
|
|
4532
|
+
renderPanelAppCard
|
|
4533
|
+
})
|
|
4534
|
+
}, `tool-${index}`);
|
|
4535
|
+
}
|
|
4536
|
+
if (type === "file") {
|
|
4537
|
+
const { file } = part;
|
|
4538
|
+
return /* @__PURE__ */ jsx(ChatMessageFile, {
|
|
4539
|
+
file,
|
|
4540
|
+
isUser,
|
|
4541
|
+
texts
|
|
4542
|
+
}, `file-${index}`);
|
|
4543
|
+
}
|
|
4544
|
+
if (type === "unknown") {
|
|
4545
|
+
const { label, rawType, text } = part;
|
|
4546
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
4547
|
+
className: "rounded-lg border border-border bg-muted/60 px-2.5 py-2 text-xs text-muted-foreground",
|
|
4548
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
4549
|
+
className: "font-semibold text-foreground",
|
|
4550
|
+
children: [
|
|
4551
|
+
label,
|
|
4552
|
+
": ",
|
|
4553
|
+
rawType
|
|
4554
|
+
]
|
|
4555
|
+
}), text ? /* @__PURE__ */ jsx("pre", {
|
|
4556
|
+
className: "mt-1 whitespace-pre-wrap break-words text-[11px] text-muted-foreground",
|
|
4557
|
+
children: text
|
|
4558
|
+
}) : null]
|
|
4559
|
+
}, `unknown-${index}`);
|
|
4560
|
+
}
|
|
4561
|
+
return null;
|
|
4562
|
+
}
|
|
4563
|
+
const ChatMessage = memo(function ChatMessage({ message, texts, onToolAction, onFileOpen, renderInlineDisplay, renderToolAgent, renderPanelAppCard }) {
|
|
4222
4564
|
const { role } = message;
|
|
4223
4565
|
const isUser = role === "user";
|
|
4224
|
-
const
|
|
4566
|
+
const isInProgress = isMessageInProgress(message.status);
|
|
4567
|
+
const processSplit = splitAssistantProcess(message);
|
|
4568
|
+
const renderPart = (part, index) => renderChatMessagePart({
|
|
4569
|
+
part,
|
|
4570
|
+
index,
|
|
4571
|
+
role,
|
|
4572
|
+
isUser,
|
|
4573
|
+
isInProgress,
|
|
4574
|
+
isLastPart: index === message.parts.length - 1,
|
|
4575
|
+
texts,
|
|
4576
|
+
onToolAction,
|
|
4577
|
+
onFileOpen,
|
|
4578
|
+
renderInlineDisplay,
|
|
4579
|
+
renderToolAgent,
|
|
4580
|
+
renderPanelAppCard
|
|
4581
|
+
});
|
|
4225
4582
|
return /* @__PURE__ */ jsx("div", {
|
|
4226
|
-
className: cn("inline-block w-fit max-w-full rounded-2xl border px-4 shadow-sm", isUser ? "border-primary bg-primary py-3 text-primary-foreground" : role === "assistant" ? "border-border bg-card pb-3 pt-4 text-card-foreground" : "border-border bg-muted/45 py-3 text-foreground"),
|
|
4583
|
+
className: cn("inline-block w-fit max-w-full rounded-2xl border px-4 shadow-sm has-[[data-chat-message-wide-content=true]]:w-full", isUser ? "border-primary bg-primary py-3 text-primary-foreground" : role === "assistant" ? "border-border bg-card pb-3 pt-4 text-card-foreground" : "border-border bg-muted/45 py-3 text-foreground"),
|
|
4227
4584
|
children: /* @__PURE__ */ jsx("div", {
|
|
4228
4585
|
className: "space-y-2",
|
|
4229
|
-
children:
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
}
|
|
4250
|
-
if (type === "tool-card") {
|
|
4251
|
-
const { card } = part;
|
|
4252
|
-
return /* @__PURE__ */ jsx("div", {
|
|
4253
|
-
className: "mt-0.5",
|
|
4254
|
-
children: /* @__PURE__ */ jsx(ChatToolCard, {
|
|
4255
|
-
card,
|
|
4256
|
-
onToolAction,
|
|
4257
|
-
onFileOpen,
|
|
4258
|
-
renderToolAgent,
|
|
4259
|
-
renderPanelAppCard
|
|
4260
|
-
})
|
|
4261
|
-
}, `tool-${index}`);
|
|
4262
|
-
}
|
|
4263
|
-
if (type === "file") {
|
|
4264
|
-
const { file } = part;
|
|
4265
|
-
return /* @__PURE__ */ jsx(ChatMessageFile, {
|
|
4266
|
-
file,
|
|
4267
|
-
isUser,
|
|
4268
|
-
texts
|
|
4269
|
-
}, `file-${index}`);
|
|
4270
|
-
}
|
|
4271
|
-
if (type === "unknown") {
|
|
4272
|
-
const { label, rawType, text } = part;
|
|
4273
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
4274
|
-
className: "rounded-lg border border-border bg-muted/60 px-2.5 py-2 text-xs text-muted-foreground",
|
|
4275
|
-
children: [/* @__PURE__ */ jsxs("div", {
|
|
4276
|
-
className: "font-semibold text-foreground",
|
|
4277
|
-
children: [
|
|
4278
|
-
label,
|
|
4279
|
-
": ",
|
|
4280
|
-
rawType
|
|
4281
|
-
]
|
|
4282
|
-
}), text ? /* @__PURE__ */ jsx("pre", {
|
|
4283
|
-
className: "mt-1 whitespace-pre-wrap break-words text-[11px] text-muted-foreground",
|
|
4284
|
-
children: text
|
|
4285
|
-
}) : null]
|
|
4286
|
-
}, `unknown-${index}`);
|
|
4287
|
-
}
|
|
4288
|
-
return null;
|
|
4289
|
-
})
|
|
4586
|
+
children: processSplit ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("details", {
|
|
4587
|
+
className: "group/process text-xs text-muted-foreground",
|
|
4588
|
+
children: [/* @__PURE__ */ jsxs("summary", {
|
|
4589
|
+
className: "flex cursor-pointer list-none items-center gap-1.5 border-b border-border/60 pb-2 font-medium transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/35 [&::-webkit-details-marker]:hidden",
|
|
4590
|
+
children: [
|
|
4591
|
+
/* @__PURE__ */ jsx(ChevronRight, {
|
|
4592
|
+
className: "h-3.5 w-3.5 group-open/process:hidden",
|
|
4593
|
+
strokeWidth: 2.5
|
|
4594
|
+
}),
|
|
4595
|
+
/* @__PURE__ */ jsx(ChevronDown, {
|
|
4596
|
+
className: "hidden h-3.5 w-3.5 group-open/process:block",
|
|
4597
|
+
strokeWidth: 2.5
|
|
4598
|
+
}),
|
|
4599
|
+
/* @__PURE__ */ jsx("span", { children: message.processSummary?.label })
|
|
4600
|
+
]
|
|
4601
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
4602
|
+
className: "space-y-2 pt-2",
|
|
4603
|
+
children: processSplit.processParts.map(renderPart)
|
|
4604
|
+
})]
|
|
4605
|
+
}), processSplit.finalParts.map((part, index) => renderPart(part, processSplit.processParts.length + index))] }) : message.parts.map(renderPart)
|
|
4290
4606
|
})
|
|
4291
4607
|
});
|
|
4292
4608
|
});
|
|
@@ -4386,7 +4702,7 @@ function ChatTypingIndicator({ label }) {
|
|
|
4386
4702
|
})]
|
|
4387
4703
|
});
|
|
4388
4704
|
}
|
|
4389
|
-
function ChatMessageList({ className, isSending, messages, onFileOpen, onToolAction, renderPanelAppCard, renderToolAgent, texts }) {
|
|
4705
|
+
function ChatMessageList({ className, isSending, messages, onFileOpen, onToolAction, renderInlineDisplay, renderPanelAppCard, renderToolAgent, texts }) {
|
|
4390
4706
|
const visibleMessages = messages.filter(hasRenderableMessageContent);
|
|
4391
4707
|
const hasRenderableAssistantDraft = visibleMessages.some((message) => message.role === "assistant" && (message.status === "streaming" || message.status === "pending"));
|
|
4392
4708
|
return /* @__PURE__ */ jsxs("div", {
|
|
@@ -4399,12 +4715,13 @@ function ChatMessageList({ className, isSending, messages, onFileOpen, onToolAct
|
|
|
4399
4715
|
children: [
|
|
4400
4716
|
!isUser ? /* @__PURE__ */ jsx(ChatMessageAvatar, { role: message.role }) : null,
|
|
4401
4717
|
/* @__PURE__ */ jsxs("div", {
|
|
4402
|
-
className: cn("w-fit max-w-[92%] space-y-2", isUser && "flex flex-col items-end"),
|
|
4718
|
+
className: cn("w-fit max-w-[92%] space-y-2 has-[[data-chat-message-wide-content=true]]:w-full", isUser && "flex flex-col items-end"),
|
|
4403
4719
|
children: [/* @__PURE__ */ jsx(ChatMessage, {
|
|
4404
4720
|
message,
|
|
4405
4721
|
texts,
|
|
4406
4722
|
onToolAction,
|
|
4407
4723
|
onFileOpen,
|
|
4724
|
+
renderInlineDisplay,
|
|
4408
4725
|
renderToolAgent,
|
|
4409
4726
|
renderPanelAppCard
|
|
4410
4727
|
}), /* @__PURE__ */ jsx("div", {
|