@iota-uz/sdk 0.4.19 → 0.4.20
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/bichat/index.cjs +1065 -338
- package/dist/bichat/index.cjs.map +1 -1
- package/dist/bichat/index.d.cts +41 -1
- package/dist/bichat/index.d.ts +41 -1
- package/dist/bichat/index.mjs +1070 -344
- package/dist/bichat/index.mjs.map +1 -1
- package/package.json +1 -1
- package/tailwind/compiled.css +1 -1
package/dist/bichat/index.mjs
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import React, { createContext,
|
|
2
|
-
import {
|
|
1
|
+
import React, { createContext, memo, useState, useEffect, useMemo, useCallback, lazy, forwardRef, useRef, useImperativeHandle, isValidElement, cloneElement, useContext, useId, useSyncExternalStore, Suspense, Component, Children } from 'react';
|
|
2
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
3
3
|
import ReactApexChart from 'react-apexcharts';
|
|
4
4
|
import ApexCharts from 'apexcharts';
|
|
5
|
-
import { X, Bug, ArrowUp, ArrowDown, Stack, Paperclip, PaperPlaneRight, CircleNotch, ArrowUUpLeft, PencilSimple, Check, Bookmark, ArrowsClockwise, Archive, Trash, DotsThree,
|
|
5
|
+
import { Warning, ArrowClockwise, X, Bug, ArrowUp, ArrowDown, Stack, Paperclip, PaperPlaneRight, CircleNotch, ArrowUUpLeft, PencilSimple, Check, Bookmark, ArrowsClockwise, Archive, Trash, DotsThree, Image, ArrowCounterClockwise, ImageBroken, CaretLeft, CaretRight, MagnifyingGlassMinus, MagnifyingGlassPlus, ArrowsIn, Info, CheckCircle, XCircle, Spinner, MagnifyingGlass, WarningCircle, CaretDown, Copy, FilePdf, FileXls, FileCsv, FileDoc, FileCode, FileText, File as File$1, ChartBar, DownloadSimple, Download, ChatCircleDots, PencilSimpleLine, ArrowLeft, PaperPlaneTilt, ArrowRight, Timer, Lightning, Database, Wrench, ClockCounterClockwise, Lightbulb, Package, Plus, ArrowsCounterClockwise, Gear, Users, List, CaretLineLeft, CaretLineRight, Code, ArrowSquareOut, SpinnerGap, FloppyDisk, Sidebar } from '@phosphor-icons/react';
|
|
6
6
|
import { Prism } from 'react-syntax-highlighter';
|
|
7
7
|
import { vscDarkPlus, vs } from 'react-syntax-highlighter/dist/esm/styles/prism';
|
|
8
8
|
import ReactMarkdown from 'react-markdown';
|
|
9
9
|
import remarkGfm from 'remark-gfm';
|
|
10
|
-
import { useMotionValue, useTransform,
|
|
10
|
+
import { motion, useMotionValue, useTransform, AnimatePresence, useReducedMotion } from 'framer-motion';
|
|
11
11
|
import 'react-dom/client';
|
|
12
12
|
import { startOfDay, differenceInDays, differenceInMinutes, differenceInHours, format } from 'date-fns';
|
|
13
|
-
import { Menu, MenuButton, MenuItems, MenuItem, Dialog, DialogBackdrop, DialogPanel, DialogTitle, Description,
|
|
13
|
+
import { Menu, MenuButton, MenuItems, MenuItem, Dialog, DialogBackdrop, DialogPanel, DialogTitle, Description, Transition } from '@headlessui/react';
|
|
14
14
|
import { createPortal } from 'react-dom';
|
|
15
15
|
|
|
16
16
|
var __defProp = Object.defineProperty;
|
|
@@ -180,6 +180,37 @@ var init_ChartCard = __esm({
|
|
|
180
180
|
DEFAULT_COLORS = ["#6366f1", "#06b6d4", "#f59e0b", "#ef4444", "#8b5cf6"];
|
|
181
181
|
}
|
|
182
182
|
});
|
|
183
|
+
var TableExportButton;
|
|
184
|
+
var init_TableExportButton = __esm({
|
|
185
|
+
"ui/src/bichat/components/TableExportButton.tsx"() {
|
|
186
|
+
init_useTranslation();
|
|
187
|
+
TableExportButton = memo(function TableExportButton2({
|
|
188
|
+
onClick,
|
|
189
|
+
disabled = false,
|
|
190
|
+
label,
|
|
191
|
+
disabledTooltip
|
|
192
|
+
}) {
|
|
193
|
+
const { t } = useTranslation();
|
|
194
|
+
const resolvedLabel = label ?? t("BiChat.Export");
|
|
195
|
+
const resolvedDisabledTooltip = disabledTooltip ?? t("BiChat.Common.PleaseWait");
|
|
196
|
+
return /* @__PURE__ */ jsxs(
|
|
197
|
+
"button",
|
|
198
|
+
{
|
|
199
|
+
type: "button",
|
|
200
|
+
onClick,
|
|
201
|
+
disabled,
|
|
202
|
+
className: "cursor-pointer inline-flex items-center gap-1 px-2 py-1 text-xs font-medium text-green-700 dark:text-green-400 hover:text-green-800 dark:hover:text-green-300 disabled:text-gray-400 disabled:cursor-not-allowed transition-colors rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50",
|
|
203
|
+
"aria-label": resolvedLabel,
|
|
204
|
+
title: disabled ? resolvedDisabledTooltip : resolvedLabel,
|
|
205
|
+
children: [
|
|
206
|
+
/* @__PURE__ */ jsx(FileXls, { size: 16, weight: "fill" }),
|
|
207
|
+
/* @__PURE__ */ jsx("span", { children: resolvedLabel })
|
|
208
|
+
]
|
|
209
|
+
}
|
|
210
|
+
);
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
});
|
|
183
214
|
|
|
184
215
|
// ui/src/bichat/utils/citationProcessor.ts
|
|
185
216
|
function processCitations(content, citations) {
|
|
@@ -292,37 +323,6 @@ var init_chartSpec = __esm({
|
|
|
292
323
|
]);
|
|
293
324
|
}
|
|
294
325
|
});
|
|
295
|
-
var TableExportButton;
|
|
296
|
-
var init_TableExportButton = __esm({
|
|
297
|
-
"ui/src/bichat/components/TableExportButton.tsx"() {
|
|
298
|
-
init_useTranslation();
|
|
299
|
-
TableExportButton = memo(function TableExportButton2({
|
|
300
|
-
onClick,
|
|
301
|
-
disabled = false,
|
|
302
|
-
label,
|
|
303
|
-
disabledTooltip
|
|
304
|
-
}) {
|
|
305
|
-
const { t } = useTranslation();
|
|
306
|
-
const resolvedLabel = label ?? t("BiChat.Export");
|
|
307
|
-
const resolvedDisabledTooltip = disabledTooltip ?? t("BiChat.Common.PleaseWait");
|
|
308
|
-
return /* @__PURE__ */ jsxs(
|
|
309
|
-
"button",
|
|
310
|
-
{
|
|
311
|
-
type: "button",
|
|
312
|
-
onClick,
|
|
313
|
-
disabled,
|
|
314
|
-
className: "cursor-pointer inline-flex items-center gap-1 px-2 py-1 text-xs font-medium text-green-700 dark:text-green-400 hover:text-green-800 dark:hover:text-green-300 disabled:text-gray-400 disabled:cursor-not-allowed transition-colors rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50",
|
|
315
|
-
"aria-label": resolvedLabel,
|
|
316
|
-
title: disabled ? resolvedDisabledTooltip : resolvedLabel,
|
|
317
|
-
children: [
|
|
318
|
-
/* @__PURE__ */ jsx(FileXls, { size: 16, weight: "fill" }),
|
|
319
|
-
/* @__PURE__ */ jsx("span", { children: resolvedLabel })
|
|
320
|
-
]
|
|
321
|
-
}
|
|
322
|
-
);
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
});
|
|
326
326
|
var TableWithExport;
|
|
327
327
|
var init_TableWithExport = __esm({
|
|
328
328
|
"ui/src/bichat/components/TableWithExport.tsx"() {
|
|
@@ -1537,6 +1537,12 @@ var ChatMachine = class {
|
|
|
1537
1537
|
streamErrorRetryable: false
|
|
1538
1538
|
});
|
|
1539
1539
|
}
|
|
1540
|
+
_notifySessionsUpdated(reason, sessionId) {
|
|
1541
|
+
if (typeof window === "undefined") return;
|
|
1542
|
+
window.dispatchEvent(new CustomEvent("bichat:sessions-updated", {
|
|
1543
|
+
detail: { reason, sessionId }
|
|
1544
|
+
}));
|
|
1545
|
+
}
|
|
1540
1546
|
_cancel() {
|
|
1541
1547
|
if (this.abortController) {
|
|
1542
1548
|
this.abortController.abort();
|
|
@@ -1804,7 +1810,11 @@ var ChatMachine = class {
|
|
|
1804
1810
|
}
|
|
1805
1811
|
}
|
|
1806
1812
|
const targetSessionId = createdSessionId || activeSessionId;
|
|
1813
|
+
if (targetSessionId && targetSessionId !== "new") {
|
|
1814
|
+
this._notifySessionsUpdated("message_sent", targetSessionId);
|
|
1815
|
+
}
|
|
1807
1816
|
if (shouldNavigateAfter && targetSessionId && targetSessionId !== "new") {
|
|
1817
|
+
this._notifySessionsUpdated("session_created", targetSessionId);
|
|
1808
1818
|
if (this.onSessionCreated) {
|
|
1809
1819
|
this.onSessionCreated(targetSessionId);
|
|
1810
1820
|
} else {
|
|
@@ -1994,6 +2004,8 @@ var ChatMachine = class {
|
|
|
1994
2004
|
this._clearStreamError();
|
|
1995
2005
|
const convertedAttachments = attachments.map((att) => ({
|
|
1996
2006
|
clientKey: att.clientKey || crypto.randomUUID(),
|
|
2007
|
+
id: att.id,
|
|
2008
|
+
uploadId: att.uploadId,
|
|
1997
2009
|
filename: att.filename,
|
|
1998
2010
|
mimeType: att.mimeType,
|
|
1999
2011
|
sizeBytes: att.sizeBytes,
|
|
@@ -2656,6 +2668,9 @@ var MemoizedAttachmentGrid = React.memo(AttachmentGrid);
|
|
|
2656
2668
|
MemoizedAttachmentGrid.displayName = "AttachmentGrid";
|
|
2657
2669
|
var AttachmentGrid_default = MemoizedAttachmentGrid;
|
|
2658
2670
|
init_useTranslation();
|
|
2671
|
+
var MIN_SCALE = 0.25;
|
|
2672
|
+
var MAX_SCALE = 5;
|
|
2673
|
+
var ZOOM_STEP = 0.25;
|
|
2659
2674
|
function ImageModal({
|
|
2660
2675
|
isOpen,
|
|
2661
2676
|
onClose,
|
|
@@ -2668,9 +2683,23 @@ function ImageModal({
|
|
|
2668
2683
|
const [isImageLoaded, setIsImageLoaded] = useState(false);
|
|
2669
2684
|
const [imageError, setImageError] = useState(false);
|
|
2670
2685
|
const [retryKey, setRetryKey] = useState(0);
|
|
2686
|
+
const [scale, setScale] = useState(1);
|
|
2687
|
+
const [position, setPosition] = useState({ x: 0, y: 0 });
|
|
2688
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
2689
|
+
const dragStartRef = useRef({ x: 0, y: 0 });
|
|
2690
|
+
const positionRef = useRef({ x: 0, y: 0 });
|
|
2691
|
+
const scaleRef = useRef(1);
|
|
2692
|
+
const imageAreaRef = useRef(null);
|
|
2671
2693
|
const hasMultipleImages = allAttachments && allAttachments.length > 1;
|
|
2672
2694
|
const canNavigatePrev = hasMultipleImages && currentIndex > 0;
|
|
2673
2695
|
const canNavigateNext = hasMultipleImages && currentIndex < (allAttachments?.length || 1) - 1;
|
|
2696
|
+
const isZoomed = scale > 1;
|
|
2697
|
+
useEffect(() => {
|
|
2698
|
+
scaleRef.current = scale;
|
|
2699
|
+
}, [scale]);
|
|
2700
|
+
useEffect(() => {
|
|
2701
|
+
positionRef.current = position;
|
|
2702
|
+
}, [position]);
|
|
2674
2703
|
useEffect(() => {
|
|
2675
2704
|
if (!isOpen) return;
|
|
2676
2705
|
const handleKeyDown = (e) => {
|
|
@@ -2678,6 +2707,14 @@ function ImageModal({
|
|
|
2678
2707
|
onNavigate("prev");
|
|
2679
2708
|
} else if (e.key === "ArrowRight" && onNavigate && canNavigateNext) {
|
|
2680
2709
|
onNavigate("next");
|
|
2710
|
+
} else if (e.key === "+" || e.key === "=") {
|
|
2711
|
+
setScale((s) => Math.min(s + ZOOM_STEP, MAX_SCALE));
|
|
2712
|
+
} else if (e.key === "-") {
|
|
2713
|
+
setScale((s) => Math.max(s - ZOOM_STEP, MIN_SCALE));
|
|
2714
|
+
if (scaleRef.current - ZOOM_STEP <= 1) setPosition({ x: 0, y: 0 });
|
|
2715
|
+
} else if (e.key === "0") {
|
|
2716
|
+
setScale(1);
|
|
2717
|
+
setPosition({ x: 0, y: 0 });
|
|
2681
2718
|
}
|
|
2682
2719
|
};
|
|
2683
2720
|
document.addEventListener("keydown", handleKeyDown);
|
|
@@ -2686,128 +2723,246 @@ function ImageModal({
|
|
|
2686
2723
|
useEffect(() => {
|
|
2687
2724
|
setIsImageLoaded(false);
|
|
2688
2725
|
setImageError(false);
|
|
2726
|
+
setScale(1);
|
|
2727
|
+
setPosition({ x: 0, y: 0 });
|
|
2689
2728
|
}, [attachment]);
|
|
2729
|
+
useEffect(() => {
|
|
2730
|
+
const el = imageAreaRef.current;
|
|
2731
|
+
if (!el || !isOpen) return;
|
|
2732
|
+
const handler = (e) => {
|
|
2733
|
+
const delta = e.deltaY > 0 ? -ZOOM_STEP : ZOOM_STEP;
|
|
2734
|
+
const current = scaleRef.current;
|
|
2735
|
+
const newScale = Math.min(Math.max(current + delta, MIN_SCALE), MAX_SCALE);
|
|
2736
|
+
if (newScale === current) return;
|
|
2737
|
+
e.preventDefault();
|
|
2738
|
+
setScale(newScale);
|
|
2739
|
+
if (newScale <= 1) setPosition({ x: 0, y: 0 });
|
|
2740
|
+
};
|
|
2741
|
+
el.addEventListener("wheel", handler, { passive: false });
|
|
2742
|
+
return () => el.removeEventListener("wheel", handler);
|
|
2743
|
+
}, [isOpen]);
|
|
2690
2744
|
const handleRetry = useCallback(() => {
|
|
2691
2745
|
setImageError(false);
|
|
2692
2746
|
setIsImageLoaded(false);
|
|
2693
2747
|
setRetryKey((k) => k + 1);
|
|
2694
2748
|
}, []);
|
|
2749
|
+
const zoomIn = useCallback(() => {
|
|
2750
|
+
setScale((s) => Math.min(s + ZOOM_STEP, MAX_SCALE));
|
|
2751
|
+
}, []);
|
|
2752
|
+
const zoomOut = useCallback(() => {
|
|
2753
|
+
setScale((s) => Math.max(s - ZOOM_STEP, MIN_SCALE));
|
|
2754
|
+
if (scaleRef.current - ZOOM_STEP <= 1) setPosition({ x: 0, y: 0 });
|
|
2755
|
+
}, []);
|
|
2756
|
+
const resetZoom = useCallback(() => {
|
|
2757
|
+
setScale(1);
|
|
2758
|
+
setPosition({ x: 0, y: 0 });
|
|
2759
|
+
}, []);
|
|
2760
|
+
const handleDoubleClick = useCallback(() => {
|
|
2761
|
+
const current = scaleRef.current;
|
|
2762
|
+
if (current !== 1) {
|
|
2763
|
+
setScale(1);
|
|
2764
|
+
setPosition({ x: 0, y: 0 });
|
|
2765
|
+
} else {
|
|
2766
|
+
setScale(2);
|
|
2767
|
+
}
|
|
2768
|
+
}, []);
|
|
2769
|
+
const handleMouseDown = useCallback((e) => {
|
|
2770
|
+
if (scaleRef.current <= 1) return;
|
|
2771
|
+
e.preventDefault();
|
|
2772
|
+
setIsDragging(true);
|
|
2773
|
+
dragStartRef.current = {
|
|
2774
|
+
x: e.clientX - positionRef.current.x,
|
|
2775
|
+
y: e.clientY - positionRef.current.y
|
|
2776
|
+
};
|
|
2777
|
+
}, []);
|
|
2778
|
+
const handleMouseMove = useCallback((e) => {
|
|
2779
|
+
if (!isDragging) return;
|
|
2780
|
+
setPosition({
|
|
2781
|
+
x: e.clientX - dragStartRef.current.x,
|
|
2782
|
+
y: e.clientY - dragStartRef.current.y
|
|
2783
|
+
});
|
|
2784
|
+
}, [isDragging]);
|
|
2785
|
+
const handleMouseUp = useCallback(() => {
|
|
2786
|
+
setIsDragging(false);
|
|
2787
|
+
}, []);
|
|
2788
|
+
const handleBackdropClick = useCallback((e) => {
|
|
2789
|
+
if (e.target === e.currentTarget && !isZoomed) {
|
|
2790
|
+
onClose();
|
|
2791
|
+
}
|
|
2792
|
+
}, [isZoomed, onClose]);
|
|
2695
2793
|
const previewUrl = attachment.preview || createDataUrl(attachment.base64Data, attachment.mimeType);
|
|
2794
|
+
const zoomPercent = Math.round(scale * 100);
|
|
2696
2795
|
return /* @__PURE__ */ jsxs(Dialog, { open: isOpen, onClose, className: "relative", style: { zIndex: 99999 }, children: [
|
|
2697
2796
|
/* @__PURE__ */ jsx(
|
|
2698
2797
|
DialogBackdrop,
|
|
2699
2798
|
{
|
|
2700
|
-
className: "fixed inset-0",
|
|
2701
|
-
style: { zIndex: 99999
|
|
2799
|
+
className: "fixed inset-0 bg-black/90 backdrop-blur-sm",
|
|
2800
|
+
style: { zIndex: 99999 }
|
|
2702
2801
|
}
|
|
2703
2802
|
),
|
|
2704
|
-
/* @__PURE__ */ jsxs(
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
/* @__PURE__ */ jsx("
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
onClick: onClose,
|
|
2719
|
-
className: "cursor-pointer flex items-center justify-center w-8 h-8 rounded-md bg-gray-100 hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700 text-gray-500 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-gray-400",
|
|
2720
|
-
"aria-label": t("BiChat.Image.Close"),
|
|
2721
|
-
type: "button",
|
|
2722
|
-
children: /* @__PURE__ */ jsx(X, { size: 18, weight: "bold" })
|
|
2723
|
-
}
|
|
2724
|
-
)
|
|
2725
|
-
] }),
|
|
2726
|
-
/* @__PURE__ */ jsxs(
|
|
2727
|
-
"div",
|
|
2728
|
-
{
|
|
2729
|
-
className: "relative flex-1 flex items-center justify-center min-h-0",
|
|
2730
|
-
onClick: (e) => {
|
|
2731
|
-
if (e.target === e.currentTarget) onClose();
|
|
2732
|
-
},
|
|
2733
|
-
children: [
|
|
2734
|
-
!isImageLoaded && !imageError && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-3", children: [
|
|
2735
|
-
/* @__PURE__ */ jsx("div", { className: "w-8 h-8 border-2 border-gray-300 dark:border-gray-700 border-t-gray-500 dark:border-t-gray-400 rounded-full animate-spin" }),
|
|
2736
|
-
/* @__PURE__ */ jsx("span", { className: "text-xs text-gray-400 dark:text-gray-500", children: t("BiChat.Loading") })
|
|
2737
|
-
] }) }),
|
|
2738
|
-
imageError && /* @__PURE__ */ jsxs("div", { role: "alert", className: "flex flex-col items-center justify-center text-center max-w-xs", children: [
|
|
2739
|
-
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-center w-16 h-16 rounded-2xl bg-gray-100 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 mb-5", children: /* @__PURE__ */ jsx(ImageBroken, { size: 28, className: "text-gray-400 dark:text-gray-500", weight: "duotone" }) }),
|
|
2740
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: t("BiChat.Image.FailedToLoad") }),
|
|
2741
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs text-gray-400 dark:text-gray-500 mb-5 truncate max-w-full", children: attachment.filename }),
|
|
2742
|
-
/* @__PURE__ */ jsxs(
|
|
2743
|
-
"button",
|
|
2744
|
-
{
|
|
2745
|
-
type: "button",
|
|
2746
|
-
onClick: handleRetry,
|
|
2747
|
-
className: "cursor-pointer inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 border border-gray-200 dark:border-gray-700 rounded-lg transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-gray-400",
|
|
2748
|
-
"aria-label": t("BiChat.Image.Retry"),
|
|
2749
|
-
children: [
|
|
2750
|
-
/* @__PURE__ */ jsx(ArrowClockwise, { size: 16, weight: "bold" }),
|
|
2751
|
-
t("BiChat.Retry.Label")
|
|
2752
|
-
]
|
|
2753
|
-
}
|
|
2754
|
-
)
|
|
2803
|
+
/* @__PURE__ */ jsxs(
|
|
2804
|
+
DialogPanel,
|
|
2805
|
+
{
|
|
2806
|
+
className: "fixed inset-0 flex flex-col",
|
|
2807
|
+
style: { zIndex: 1e5 },
|
|
2808
|
+
onMouseMove: handleMouseMove,
|
|
2809
|
+
onMouseUp: handleMouseUp,
|
|
2810
|
+
onMouseLeave: handleMouseUp,
|
|
2811
|
+
children: [
|
|
2812
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center px-5 py-3 shrink-0", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
|
|
2813
|
+
hasMultipleImages && /* @__PURE__ */ jsxs("span", { className: "text-xs text-white/50 tabular-nums whitespace-nowrap font-medium", children: [
|
|
2814
|
+
currentIndex + 1,
|
|
2815
|
+
" / ",
|
|
2816
|
+
allAttachments?.length
|
|
2755
2817
|
] }),
|
|
2756
|
-
/* @__PURE__ */ jsx(
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
className:
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2818
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-white/90 truncate font-medium", children: attachment.filename }),
|
|
2819
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-white/40 whitespace-nowrap", children: formatFileSize(attachment.sizeBytes) })
|
|
2820
|
+
] }) }),
|
|
2821
|
+
/* @__PURE__ */ jsxs(
|
|
2822
|
+
"div",
|
|
2823
|
+
{
|
|
2824
|
+
ref: imageAreaRef,
|
|
2825
|
+
className: "relative flex-1 flex items-center justify-center min-h-0 px-4 pb-4",
|
|
2826
|
+
onClick: handleBackdropClick,
|
|
2827
|
+
style: { cursor: isZoomed ? isDragging ? "grabbing" : "grab" : "default" },
|
|
2828
|
+
children: [
|
|
2829
|
+
/* @__PURE__ */ jsx(
|
|
2830
|
+
"button",
|
|
2831
|
+
{
|
|
2832
|
+
onClick: onClose,
|
|
2833
|
+
className: "absolute top-3 right-5 z-30 cursor-pointer flex items-center justify-center w-10 h-10 rounded-full bg-black/50 hover:bg-black/70 backdrop-blur-md text-white/80 hover:text-white border border-white/10 transition-all duration-200 shadow-lg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/30",
|
|
2834
|
+
"aria-label": t("BiChat.Image.Close"),
|
|
2835
|
+
type: "button",
|
|
2836
|
+
children: /* @__PURE__ */ jsx(X, { size: 20, weight: "bold" })
|
|
2837
|
+
}
|
|
2838
|
+
),
|
|
2839
|
+
!isImageLoaded && !imageError && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-3", children: [
|
|
2840
|
+
/* @__PURE__ */ jsx("div", { className: "w-8 h-8 border-2 border-white/20 border-t-white/60 rounded-full animate-spin" }),
|
|
2841
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-white/40", children: t("BiChat.Loading") })
|
|
2842
|
+
] }) }),
|
|
2843
|
+
imageError && /* @__PURE__ */ jsxs("div", { role: "alert", className: "flex flex-col items-center justify-center text-center max-w-xs", children: [
|
|
2844
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-center w-16 h-16 rounded-2xl bg-white/5 border border-white/10 mb-5", children: /* @__PURE__ */ jsx(ImageBroken, { size: 28, className: "text-white/30", weight: "duotone" }) }),
|
|
2845
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-white/70 mb-1", children: t("BiChat.Image.FailedToLoad") }),
|
|
2846
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-white/30 mb-5 truncate max-w-full", children: attachment.filename }),
|
|
2847
|
+
/* @__PURE__ */ jsxs(
|
|
2848
|
+
"button",
|
|
2849
|
+
{
|
|
2850
|
+
type: "button",
|
|
2851
|
+
onClick: handleRetry,
|
|
2852
|
+
className: "cursor-pointer inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-white/80 bg-white/10 hover:bg-white/15 border border-white/10 rounded-lg transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/30",
|
|
2853
|
+
"aria-label": t("BiChat.Image.Retry"),
|
|
2854
|
+
children: [
|
|
2855
|
+
/* @__PURE__ */ jsx(ArrowClockwise, { size: 16, weight: "bold" }),
|
|
2856
|
+
t("BiChat.Retry.Label")
|
|
2857
|
+
]
|
|
2858
|
+
}
|
|
2859
|
+
)
|
|
2860
|
+
] }),
|
|
2861
|
+
/* @__PURE__ */ jsx(
|
|
2862
|
+
"img",
|
|
2863
|
+
{
|
|
2864
|
+
src: previewUrl,
|
|
2865
|
+
alt: attachment.filename,
|
|
2866
|
+
className: [
|
|
2867
|
+
"relative z-0 max-w-[85vw] max-h-[calc(100vh-160px)] object-contain select-none rounded-lg",
|
|
2868
|
+
"transition-opacity duration-300 ease-out",
|
|
2869
|
+
isImageLoaded ? "opacity-100" : "opacity-0"
|
|
2870
|
+
].join(" "),
|
|
2871
|
+
style: {
|
|
2872
|
+
transform: `translate(${position.x}px, ${position.y}px) scale(${scale})`,
|
|
2873
|
+
transformOrigin: "center center",
|
|
2874
|
+
transition: isDragging ? "opacity 0.3s ease-out" : "transform 0.2s ease-out, opacity 0.3s ease-out"
|
|
2875
|
+
},
|
|
2876
|
+
onLoad: () => setIsImageLoaded(true),
|
|
2877
|
+
onError: () => setImageError(true),
|
|
2878
|
+
onMouseDown: handleMouseDown,
|
|
2879
|
+
onDoubleClick: handleDoubleClick,
|
|
2880
|
+
loading: "lazy",
|
|
2881
|
+
draggable: false
|
|
2882
|
+
},
|
|
2883
|
+
retryKey
|
|
2884
|
+
),
|
|
2885
|
+
hasMultipleImages && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2886
|
+
/* @__PURE__ */ jsx(
|
|
2887
|
+
"button",
|
|
2888
|
+
{
|
|
2889
|
+
onClick: () => onNavigate?.("prev"),
|
|
2890
|
+
disabled: !canNavigatePrev || !isImageLoaded || imageError,
|
|
2891
|
+
className: [
|
|
2892
|
+
"absolute left-4 top-1/2 -translate-y-1/2 z-20",
|
|
2893
|
+
"flex items-center justify-center w-11 h-11 rounded-full",
|
|
2894
|
+
"transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/30",
|
|
2895
|
+
canNavigatePrev && isImageLoaded && !imageError ? "cursor-pointer bg-black/40 hover:bg-black/60 backdrop-blur-md text-white/80 hover:text-white shadow-lg border border-white/10" : "bg-black/20 text-white/20 cursor-not-allowed"
|
|
2896
|
+
].join(" "),
|
|
2897
|
+
"aria-label": t("BiChat.Image.Previous"),
|
|
2898
|
+
type: "button",
|
|
2899
|
+
children: /* @__PURE__ */ jsx(CaretLeft, { size: 20, weight: "bold" })
|
|
2900
|
+
}
|
|
2901
|
+
),
|
|
2902
|
+
/* @__PURE__ */ jsx(
|
|
2903
|
+
"button",
|
|
2904
|
+
{
|
|
2905
|
+
onClick: () => onNavigate?.("next"),
|
|
2906
|
+
disabled: !canNavigateNext || !isImageLoaded || imageError,
|
|
2907
|
+
className: [
|
|
2908
|
+
"absolute right-4 top-1/2 -translate-y-1/2 z-20",
|
|
2909
|
+
"flex items-center justify-center w-11 h-11 rounded-full",
|
|
2910
|
+
"transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/30",
|
|
2911
|
+
canNavigateNext && isImageLoaded && !imageError ? "cursor-pointer bg-black/40 hover:bg-black/60 backdrop-blur-md text-white/80 hover:text-white shadow-lg border border-white/10" : "bg-black/20 text-white/20 cursor-not-allowed"
|
|
2912
|
+
].join(" "),
|
|
2913
|
+
"aria-label": t("BiChat.Image.Next"),
|
|
2914
|
+
type: "button",
|
|
2915
|
+
children: /* @__PURE__ */ jsx(CaretRight, { size: 20, weight: "bold" })
|
|
2916
|
+
}
|
|
2917
|
+
)
|
|
2918
|
+
] }),
|
|
2919
|
+
isImageLoaded && !imageError && /* @__PURE__ */ jsxs("div", { className: "absolute bottom-6 left-1/2 -translate-x-1/2 z-20 flex items-center gap-0.5 bg-black/50 backdrop-blur-xl rounded-full px-1.5 py-1.5 border border-white/10 shadow-2xl", children: [
|
|
2920
|
+
/* @__PURE__ */ jsx(
|
|
2921
|
+
"button",
|
|
2922
|
+
{
|
|
2923
|
+
type: "button",
|
|
2924
|
+
onClick: zoomOut,
|
|
2925
|
+
disabled: scale <= MIN_SCALE,
|
|
2926
|
+
className: "cursor-pointer flex items-center justify-center w-8 h-8 rounded-full text-white/70 hover:text-white hover:bg-white/10 transition-colors disabled:text-white/20 disabled:cursor-not-allowed disabled:hover:bg-transparent",
|
|
2927
|
+
"aria-label": t("BiChat.Image.ZoomOut"),
|
|
2928
|
+
children: /* @__PURE__ */ jsx(MagnifyingGlassMinus, { size: 16, weight: "bold" })
|
|
2929
|
+
}
|
|
2930
|
+
),
|
|
2931
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs text-white/60 tabular-nums font-medium min-w-[3.5rem] text-center select-none", children: [
|
|
2932
|
+
zoomPercent,
|
|
2933
|
+
"%"
|
|
2934
|
+
] }),
|
|
2935
|
+
/* @__PURE__ */ jsx(
|
|
2936
|
+
"button",
|
|
2937
|
+
{
|
|
2938
|
+
type: "button",
|
|
2939
|
+
onClick: zoomIn,
|
|
2940
|
+
disabled: scale >= MAX_SCALE,
|
|
2941
|
+
className: "cursor-pointer flex items-center justify-center w-8 h-8 rounded-full text-white/70 hover:text-white hover:bg-white/10 transition-colors disabled:text-white/20 disabled:cursor-not-allowed disabled:hover:bg-transparent",
|
|
2942
|
+
"aria-label": t("BiChat.Image.ZoomIn"),
|
|
2943
|
+
children: /* @__PURE__ */ jsx(MagnifyingGlassPlus, { size: 16, weight: "bold" })
|
|
2944
|
+
}
|
|
2945
|
+
),
|
|
2946
|
+
isZoomed && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2947
|
+
/* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-white/15 mx-1" }),
|
|
2948
|
+
/* @__PURE__ */ jsx(
|
|
2949
|
+
"button",
|
|
2950
|
+
{
|
|
2951
|
+
type: "button",
|
|
2952
|
+
onClick: resetZoom,
|
|
2953
|
+
className: "cursor-pointer flex items-center justify-center w-8 h-8 rounded-full text-white/70 hover:text-white hover:bg-white/10 transition-colors",
|
|
2954
|
+
"aria-label": t("BiChat.Image.ResetZoom"),
|
|
2955
|
+
children: /* @__PURE__ */ jsx(ArrowsIn, { size: 16, weight: "bold" })
|
|
2956
|
+
}
|
|
2957
|
+
)
|
|
2958
|
+
] })
|
|
2959
|
+
] })
|
|
2960
|
+
]
|
|
2961
|
+
}
|
|
2962
|
+
)
|
|
2963
|
+
]
|
|
2964
|
+
}
|
|
2965
|
+
)
|
|
2811
2966
|
] });
|
|
2812
2967
|
}
|
|
2813
2968
|
var ImageModal_default = ImageModal;
|
|
@@ -2859,6 +3014,7 @@ function UserMessage({
|
|
|
2859
3014
|
const [draftContent, setDraftContent] = useState("");
|
|
2860
3015
|
const [isCopied, setIsCopied] = useState(false);
|
|
2861
3016
|
const copyFeedbackTimeoutRef = useRef(null);
|
|
3017
|
+
const editTextareaRef = useRef(null);
|
|
2862
3018
|
const classes = mergeClassNames(defaultClassNames, classNameOverrides);
|
|
2863
3019
|
useEffect(() => {
|
|
2864
3020
|
return () => {
|
|
@@ -2868,6 +3024,16 @@ function UserMessage({
|
|
|
2868
3024
|
}
|
|
2869
3025
|
};
|
|
2870
3026
|
}, []);
|
|
3027
|
+
useEffect(() => {
|
|
3028
|
+
if (isEditing && editTextareaRef.current) {
|
|
3029
|
+
const textarea = editTextareaRef.current;
|
|
3030
|
+
textarea.focus();
|
|
3031
|
+
textarea.selectionStart = textarea.value.length;
|
|
3032
|
+
textarea.selectionEnd = textarea.value.length;
|
|
3033
|
+
textarea.style.height = "auto";
|
|
3034
|
+
textarea.style.height = `${Math.min(textarea.scrollHeight, 300)}px`;
|
|
3035
|
+
}
|
|
3036
|
+
}, [isEditing]);
|
|
2871
3037
|
const normalizedAttachments = turn.attachments.map((attachment) => {
|
|
2872
3038
|
if (!attachment.mimeType.startsWith("image/")) {
|
|
2873
3039
|
return attachment;
|
|
@@ -2952,6 +3118,21 @@ function UserMessage({
|
|
|
2952
3118
|
onEdit(turnId, newContent);
|
|
2953
3119
|
setIsEditing(false);
|
|
2954
3120
|
}, [onEdit, turnId, draftContent, turn.content]);
|
|
3121
|
+
const handleEditKeyDown = useCallback((e) => {
|
|
3122
|
+
if (e.key === "Escape") {
|
|
3123
|
+
e.preventDefault();
|
|
3124
|
+
handleEditCancel();
|
|
3125
|
+
} else if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
|
|
3126
|
+
e.preventDefault();
|
|
3127
|
+
handleEditSave();
|
|
3128
|
+
}
|
|
3129
|
+
}, [handleEditCancel, handleEditSave]);
|
|
3130
|
+
const handleDraftChange = useCallback((e) => {
|
|
3131
|
+
setDraftContent(e.target.value);
|
|
3132
|
+
const el = e.target;
|
|
3133
|
+
el.style.height = "auto";
|
|
3134
|
+
el.style.height = `${Math.min(el.scrollHeight, 300)}px`;
|
|
3135
|
+
}, []);
|
|
2955
3136
|
const handleNavigate = useCallback(
|
|
2956
3137
|
(direction) => {
|
|
2957
3138
|
if (selectedImageIndex === null) return;
|
|
@@ -3002,36 +3183,48 @@ function UserMessage({
|
|
|
3002
3183
|
}
|
|
3003
3184
|
)
|
|
3004
3185
|
) }),
|
|
3005
|
-
turn.content && /* @__PURE__ */ jsx("div", { className: classes.bubble, children: /* @__PURE__ */ jsx("div", { className: classes.content, children: isEditing ? /* @__PURE__ */ jsxs("div", { className: "space-y-
|
|
3186
|
+
turn.content && /* @__PURE__ */ jsx("div", { className: classes.bubble, children: /* @__PURE__ */ jsx("div", { className: classes.content, children: isEditing ? /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
3006
3187
|
/* @__PURE__ */ jsx(
|
|
3007
3188
|
"textarea",
|
|
3008
3189
|
{
|
|
3190
|
+
ref: editTextareaRef,
|
|
3009
3191
|
value: draftContent,
|
|
3010
|
-
onChange:
|
|
3011
|
-
|
|
3012
|
-
"
|
|
3192
|
+
onChange: handleDraftChange,
|
|
3193
|
+
onKeyDown: handleEditKeyDown,
|
|
3194
|
+
className: "w-full min-h-[60px] max-h-[300px] resize-none rounded-xl border border-white/20 bg-white/[0.08] px-3.5 py-2.5 text-sm text-white leading-relaxed outline-none focus:bg-white/[0.12] focus:border-white/30 focus:ring-1 focus:ring-white/20 transition-all duration-200",
|
|
3195
|
+
"aria-label": t("BiChat.Message.EditMessage"),
|
|
3196
|
+
rows: 1
|
|
3013
3197
|
}
|
|
3014
3198
|
),
|
|
3015
|
-
/* @__PURE__ */ jsxs("div", { className: "flex justify-
|
|
3016
|
-
/* @__PURE__ */
|
|
3017
|
-
"
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3199
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
|
|
3200
|
+
/* @__PURE__ */ jsxs("span", { className: "text-[11px] text-white/30 select-none hidden sm:inline", children: [
|
|
3201
|
+
"Esc \xB7 ",
|
|
3202
|
+
typeof navigator !== "undefined" && /mac|iphone|ipad/i.test(
|
|
3203
|
+
navigator.userAgentData?.platform ?? navigator?.platform ?? ""
|
|
3204
|
+
) ? "\u2318" : "Ctrl",
|
|
3205
|
+
"+Enter"
|
|
3206
|
+
] }),
|
|
3207
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 ml-auto", children: [
|
|
3208
|
+
/* @__PURE__ */ jsx(
|
|
3209
|
+
"button",
|
|
3210
|
+
{
|
|
3211
|
+
type: "button",
|
|
3212
|
+
onClick: handleEditCancel,
|
|
3213
|
+
className: "cursor-pointer px-3 py-1.5 rounded-lg text-white/60 hover:text-white hover:bg-white/10 transition-colors text-sm",
|
|
3214
|
+
children: t("BiChat.Message.Cancel")
|
|
3215
|
+
}
|
|
3216
|
+
),
|
|
3217
|
+
/* @__PURE__ */ jsx(
|
|
3218
|
+
"button",
|
|
3219
|
+
{
|
|
3220
|
+
type: "button",
|
|
3221
|
+
onClick: handleEditSave,
|
|
3222
|
+
className: "cursor-pointer px-4 py-1.5 rounded-lg bg-white text-primary-700 font-medium text-sm hover:bg-white/90 transition-all shadow-sm disabled:opacity-40 disabled:cursor-not-allowed disabled:shadow-none",
|
|
3223
|
+
disabled: !draftContent.trim() || draftContent === turn.content,
|
|
3224
|
+
children: t("BiChat.Message.Save")
|
|
3225
|
+
}
|
|
3226
|
+
)
|
|
3227
|
+
] })
|
|
3035
3228
|
] })
|
|
3036
3229
|
] }) : renderSlot(slots?.content, contentSlotProps, turn.content) }) }),
|
|
3037
3230
|
!hideActions && /* @__PURE__ */ jsx("div", { className: `${classes.actions} ${isCopied ? "opacity-100" : ""}`, children: renderSlot(
|
|
@@ -3179,67 +3372,295 @@ function StreamingCursor() {
|
|
|
3179
3372
|
}
|
|
3180
3373
|
var StreamingCursor_default = StreamingCursor;
|
|
3181
3374
|
|
|
3182
|
-
// ui/src/bichat/components/AssistantMessage.tsx
|
|
3183
|
-
init_ChartCard();
|
|
3375
|
+
// ui/src/bichat/components/AssistantMessage.tsx
|
|
3376
|
+
init_ChartCard();
|
|
3377
|
+
|
|
3378
|
+
// ui/src/bichat/components/InteractiveTableCard.tsx
|
|
3379
|
+
init_useTranslation();
|
|
3380
|
+
init_TableExportButton();
|
|
3381
|
+
var PAGE_SIZE_OPTIONS = [10, 25, 50, 100, 200];
|
|
3382
|
+
function formatCell(value) {
|
|
3383
|
+
if (value === null || value === void 0) return "NULL";
|
|
3384
|
+
if (typeof value === "object") {
|
|
3385
|
+
try {
|
|
3386
|
+
return JSON.stringify(value);
|
|
3387
|
+
} catch {
|
|
3388
|
+
return String(value);
|
|
3389
|
+
}
|
|
3390
|
+
}
|
|
3391
|
+
return String(value);
|
|
3392
|
+
}
|
|
3393
|
+
var InteractiveTableCard = memo(function InteractiveTableCard2({
|
|
3394
|
+
table,
|
|
3395
|
+
onSendMessage,
|
|
3396
|
+
sendDisabled = false
|
|
3397
|
+
}) {
|
|
3398
|
+
const { t } = useTranslation();
|
|
3399
|
+
const defaultPageSize = Math.min(Math.max(table.pageSize || 25, 1), 200);
|
|
3400
|
+
const [page, setPage] = useState(1);
|
|
3401
|
+
const [pageSize, setPageSize] = useState(defaultPageSize);
|
|
3402
|
+
useEffect(() => {
|
|
3403
|
+
const nextPageSize = Math.min(Math.max(table.pageSize || 25, 1), 200);
|
|
3404
|
+
setPage(1);
|
|
3405
|
+
setPageSize(nextPageSize);
|
|
3406
|
+
}, [table.id, table.pageSize]);
|
|
3407
|
+
const totalRows = table.rows.length;
|
|
3408
|
+
const totalPages = Math.max(1, Math.ceil(totalRows / pageSize));
|
|
3409
|
+
useEffect(() => {
|
|
3410
|
+
if (page > totalPages) {
|
|
3411
|
+
setPage(totalPages);
|
|
3412
|
+
}
|
|
3413
|
+
}, [page, totalPages]);
|
|
3414
|
+
const pageRows = useMemo(() => {
|
|
3415
|
+
const start = (page - 1) * pageSize;
|
|
3416
|
+
return table.rows.slice(start, start + pageSize);
|
|
3417
|
+
}, [page, pageSize, table.rows]);
|
|
3418
|
+
const pageSizeOptions = useMemo(() => {
|
|
3419
|
+
const set = /* @__PURE__ */ new Set([...PAGE_SIZE_OPTIONS, defaultPageSize]);
|
|
3420
|
+
return [...set].sort((a, b) => a - b);
|
|
3421
|
+
}, [defaultPageSize]);
|
|
3422
|
+
const canExportViaPrompt = !!onSendMessage && !!table.exportPrompt;
|
|
3423
|
+
const exportDisabled = sendDisabled || !table.export?.url && !canExportViaPrompt;
|
|
3424
|
+
const handleExport = useCallback(() => {
|
|
3425
|
+
if (table.export?.url) {
|
|
3426
|
+
try {
|
|
3427
|
+
const parsed = new URL(table.export.url, window.location.origin);
|
|
3428
|
+
if (!["http:", "https:", "blob:"].includes(parsed.protocol)) {
|
|
3429
|
+
console.warn("[InteractiveTableCard] Blocked export URL with unsafe protocol:", parsed.protocol);
|
|
3430
|
+
return;
|
|
3431
|
+
}
|
|
3432
|
+
} catch {
|
|
3433
|
+
console.warn("[InteractiveTableCard] Blocked malformed export URL");
|
|
3434
|
+
return;
|
|
3435
|
+
}
|
|
3436
|
+
const link = document.createElement("a");
|
|
3437
|
+
link.href = table.export.url;
|
|
3438
|
+
link.download = table.export.filename || "table_export.xlsx";
|
|
3439
|
+
link.rel = "noopener noreferrer";
|
|
3440
|
+
document.body.appendChild(link);
|
|
3441
|
+
link.click();
|
|
3442
|
+
document.body.removeChild(link);
|
|
3443
|
+
return;
|
|
3444
|
+
}
|
|
3445
|
+
if (canExportViaPrompt && table.exportPrompt) {
|
|
3446
|
+
onSendMessage?.(table.exportPrompt);
|
|
3447
|
+
}
|
|
3448
|
+
}, [canExportViaPrompt, onSendMessage, table.export, table.exportPrompt]);
|
|
3449
|
+
const from = totalRows === 0 ? 0 : (page - 1) * pageSize + 1;
|
|
3450
|
+
const to = Math.min(page * pageSize, totalRows);
|
|
3451
|
+
return /* @__PURE__ */ jsxs("section", { className: "w-full rounded-xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900/40", children: [
|
|
3452
|
+
/* @__PURE__ */ jsxs("header", { className: "flex flex-wrap items-center justify-between gap-2 border-b border-gray-200 dark:border-gray-700 px-3 py-2", children: [
|
|
3453
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
3454
|
+
/* @__PURE__ */ jsx("h4", { className: "truncate text-sm font-semibold text-gray-900 dark:text-gray-100", children: table.title || t("BiChat.Table.QueryResults") }),
|
|
3455
|
+
/* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: [
|
|
3456
|
+
totalRows === 1 ? t("BiChat.Table.OneRowLoaded") : t("BiChat.Table.RowsLoaded", { count: String(totalRows) }),
|
|
3457
|
+
table.truncated ? ` ${t("BiChat.Table.TruncatedSuffix")}` : ""
|
|
3458
|
+
] })
|
|
3459
|
+
] }),
|
|
3460
|
+
/* @__PURE__ */ jsx(
|
|
3461
|
+
TableExportButton,
|
|
3462
|
+
{
|
|
3463
|
+
onClick: handleExport,
|
|
3464
|
+
disabled: exportDisabled,
|
|
3465
|
+
label: t("BiChat.Table.ExportToExcel"),
|
|
3466
|
+
disabledTooltip: sendDisabled ? t("BiChat.Table.PleaseWait") : t("BiChat.Table.ExportUnavailable")
|
|
3467
|
+
}
|
|
3468
|
+
)
|
|
3469
|
+
] }),
|
|
3470
|
+
/* @__PURE__ */ jsx("div", { className: "max-h-[420px] overflow-auto", children: /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse text-sm", children: [
|
|
3471
|
+
/* @__PURE__ */ jsx("thead", { className: "sticky top-0 bg-gray-100 dark:bg-gray-800 z-10", children: /* @__PURE__ */ jsx("tr", { className: "border-b border-gray-200 dark:border-gray-700", children: table.headers.map((header, index) => /* @__PURE__ */ jsx(
|
|
3472
|
+
"th",
|
|
3473
|
+
{
|
|
3474
|
+
className: "px-3 py-2 text-left font-semibold text-gray-700 dark:text-gray-200 whitespace-nowrap",
|
|
3475
|
+
children: header
|
|
3476
|
+
},
|
|
3477
|
+
`${table.id}-header-${index}`
|
|
3478
|
+
)) }) }),
|
|
3479
|
+
/* @__PURE__ */ jsxs("tbody", { children: [
|
|
3480
|
+
pageRows.map((row, rowIndex) => /* @__PURE__ */ jsx(
|
|
3481
|
+
"tr",
|
|
3482
|
+
{
|
|
3483
|
+
className: "border-b border-gray-100 dark:border-gray-800 hover:bg-gray-50 dark:hover:bg-gray-800/40",
|
|
3484
|
+
children: table.columns.map((_, columnIndex) => /* @__PURE__ */ jsx(
|
|
3485
|
+
"td",
|
|
3486
|
+
{
|
|
3487
|
+
className: "px-3 py-2 text-gray-700 dark:text-gray-300 align-top",
|
|
3488
|
+
children: /* @__PURE__ */ jsx("span", { className: "block max-w-[420px] truncate", title: formatCell(row[columnIndex]), children: formatCell(row[columnIndex]) })
|
|
3489
|
+
},
|
|
3490
|
+
`${table.id}-cell-${rowIndex}-${columnIndex}`
|
|
3491
|
+
))
|
|
3492
|
+
},
|
|
3493
|
+
`${table.id}-row-${rowIndex}`
|
|
3494
|
+
)),
|
|
3495
|
+
pageRows.length === 0 && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
|
|
3496
|
+
"td",
|
|
3497
|
+
{
|
|
3498
|
+
colSpan: table.columns.length,
|
|
3499
|
+
className: "px-3 py-6 text-center text-sm text-gray-500 dark:text-gray-400",
|
|
3500
|
+
children: t("BiChat.Table.NoRows")
|
|
3501
|
+
}
|
|
3502
|
+
) })
|
|
3503
|
+
] })
|
|
3504
|
+
] }) }),
|
|
3505
|
+
/* @__PURE__ */ jsxs("footer", { className: "flex flex-wrap items-center justify-between gap-2 border-t border-gray-200 dark:border-gray-700 px-3 py-2", children: [
|
|
3506
|
+
/* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500 dark:text-gray-400", children: t("BiChat.Table.Showing", {
|
|
3507
|
+
from: String(from),
|
|
3508
|
+
to: String(to),
|
|
3509
|
+
total: String(totalRows)
|
|
3510
|
+
}) }),
|
|
3511
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
3512
|
+
/* @__PURE__ */ jsx("label", { className: "text-xs text-gray-500 dark:text-gray-400", htmlFor: `${table.id}-page-size`, children: t("BiChat.Table.RowsLabel") }),
|
|
3513
|
+
/* @__PURE__ */ jsx(
|
|
3514
|
+
"select",
|
|
3515
|
+
{
|
|
3516
|
+
id: `${table.id}-page-size`,
|
|
3517
|
+
value: pageSize,
|
|
3518
|
+
onChange: (event) => {
|
|
3519
|
+
setPageSize(Number(event.target.value));
|
|
3520
|
+
setPage(1);
|
|
3521
|
+
},
|
|
3522
|
+
className: "rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 px-2 py-1 text-xs text-gray-700 dark:text-gray-200",
|
|
3523
|
+
children: pageSizeOptions.map((option) => /* @__PURE__ */ jsx("option", { value: option, children: option }, `${table.id}-size-${option}`))
|
|
3524
|
+
}
|
|
3525
|
+
),
|
|
3526
|
+
/* @__PURE__ */ jsx(
|
|
3527
|
+
"button",
|
|
3528
|
+
{
|
|
3529
|
+
type: "button",
|
|
3530
|
+
onClick: () => setPage((current) => Math.max(1, current - 1)),
|
|
3531
|
+
disabled: page <= 1,
|
|
3532
|
+
className: "cursor-pointer rounded border border-gray-300 dark:border-gray-600 px-2 py-1 text-xs text-gray-700 dark:text-gray-200 disabled:cursor-not-allowed disabled:opacity-50",
|
|
3533
|
+
children: t("BiChat.Table.Prev")
|
|
3534
|
+
}
|
|
3535
|
+
),
|
|
3536
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-gray-500 dark:text-gray-400", children: t("BiChat.Table.PageOf", { page: String(page), total: String(totalPages) }) }),
|
|
3537
|
+
/* @__PURE__ */ jsx(
|
|
3538
|
+
"button",
|
|
3539
|
+
{
|
|
3540
|
+
type: "button",
|
|
3541
|
+
onClick: () => setPage((current) => Math.min(totalPages, current + 1)),
|
|
3542
|
+
disabled: page >= totalPages,
|
|
3543
|
+
className: "cursor-pointer rounded border border-gray-300 dark:border-gray-600 px-2 py-1 text-xs text-gray-700 dark:text-gray-200 disabled:cursor-not-allowed disabled:opacity-50",
|
|
3544
|
+
children: t("BiChat.Table.Next")
|
|
3545
|
+
}
|
|
3546
|
+
)
|
|
3547
|
+
] })
|
|
3548
|
+
] }),
|
|
3549
|
+
table.truncated && /* @__PURE__ */ jsx("p", { className: "border-t border-amber-200 bg-amber-50 px-3 py-2 text-xs text-amber-700 dark:border-amber-700/60 dark:bg-amber-900/20 dark:text-amber-300", children: t("BiChat.Table.TruncatedNotice") })
|
|
3550
|
+
] });
|
|
3551
|
+
});
|
|
3552
|
+
|
|
3553
|
+
// ui/src/bichat/components/SourcesPanel.tsx
|
|
3554
|
+
init_useTranslation();
|
|
3555
|
+
function extractDomain(url) {
|
|
3556
|
+
try {
|
|
3557
|
+
return new URL(url).hostname.replace(/^www\./, "");
|
|
3558
|
+
} catch {
|
|
3559
|
+
return "";
|
|
3560
|
+
}
|
|
3561
|
+
}
|
|
3562
|
+
var PALETTE = [
|
|
3563
|
+
"#c0392b",
|
|
3564
|
+
"#d35400",
|
|
3565
|
+
"#f39c12",
|
|
3566
|
+
"#27ae60",
|
|
3567
|
+
"#16a085",
|
|
3568
|
+
"#2980b9",
|
|
3569
|
+
"#8e44ad",
|
|
3570
|
+
"#d63384"
|
|
3571
|
+
];
|
|
3572
|
+
function domainColor(domain) {
|
|
3573
|
+
let h = 0;
|
|
3574
|
+
for (let i = 0; i < domain.length; i++) h = domain.charCodeAt(i) + ((h << 5) - h);
|
|
3575
|
+
return PALETTE[Math.abs(h) % PALETTE.length];
|
|
3576
|
+
}
|
|
3184
3577
|
function SourcesPanel({ citations }) {
|
|
3185
|
-
|
|
3186
|
-
|
|
3578
|
+
const { t } = useTranslation();
|
|
3579
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
3580
|
+
const open = useCallback(() => setIsOpen(true), []);
|
|
3581
|
+
const close = useCallback(() => setIsOpen(false), []);
|
|
3582
|
+
if (!citations?.length) return null;
|
|
3583
|
+
const domains = [...new Set(
|
|
3584
|
+
citations.filter((c) => c.url).map((c) => extractDomain(c.url)).filter(Boolean)
|
|
3585
|
+
)];
|
|
3586
|
+
const previewDomains = domains.slice(0, 5);
|
|
3587
|
+
if (!isOpen) {
|
|
3588
|
+
return /* @__PURE__ */ jsx("div", { className: "mt-3", children: /* @__PURE__ */ jsxs(
|
|
3589
|
+
"button",
|
|
3590
|
+
{
|
|
3591
|
+
type: "button",
|
|
3592
|
+
onClick: open,
|
|
3593
|
+
className: "cursor-pointer inline-flex items-center gap-2 rounded-full px-3 py-1.5\n bg-gray-50 hover:bg-gray-100 dark:bg-gray-700/50 dark:hover:bg-gray-600/60\n border border-gray-200/70 dark:border-gray-600/40\n transition-colors duration-150\n focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--bichat-primary,theme(colors.blue.500))]/40",
|
|
3594
|
+
children: [
|
|
3595
|
+
previewDomains.length > 0 && /* @__PURE__ */ jsx("span", { className: "flex -space-x-1.5", children: previewDomains.map((domain, i) => /* @__PURE__ */ jsx(
|
|
3596
|
+
"span",
|
|
3597
|
+
{
|
|
3598
|
+
className: "relative w-5 h-5 rounded-full flex items-center justify-center text-[8px] font-bold text-white\n ring-2 ring-white dark:ring-gray-800 select-none",
|
|
3599
|
+
style: { backgroundColor: domainColor(domain), zIndex: previewDomains.length - i },
|
|
3600
|
+
"aria-hidden": "true",
|
|
3601
|
+
children: domain[0]?.toUpperCase()
|
|
3602
|
+
},
|
|
3603
|
+
domain
|
|
3604
|
+
)) }),
|
|
3605
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-gray-600 dark:text-gray-300 tabular-nums", children: [
|
|
3606
|
+
citations.length,
|
|
3607
|
+
" ",
|
|
3608
|
+
t(citations.length === 1 ? "BiChat.Sources.Source" : "BiChat.Sources.Sources")
|
|
3609
|
+
] })
|
|
3610
|
+
]
|
|
3611
|
+
}
|
|
3612
|
+
) });
|
|
3187
3613
|
}
|
|
3188
|
-
return /* @__PURE__ */
|
|
3189
|
-
/* @__PURE__ */ jsxs(
|
|
3614
|
+
return /* @__PURE__ */ jsxs("div", { className: "mt-3 rounded-xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800/90 shadow-sm overflow-hidden", children: [
|
|
3615
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-3", children: [
|
|
3616
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100", children: t("BiChat.Sources.Title") }),
|
|
3190
3617
|
/* @__PURE__ */ jsx(
|
|
3191
|
-
"
|
|
3618
|
+
"button",
|
|
3192
3619
|
{
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
children: /* @__PURE__ */ jsx(
|
|
3198
|
-
"path",
|
|
3199
|
-
{
|
|
3200
|
-
strokeLinecap: "round",
|
|
3201
|
-
strokeLinejoin: "round",
|
|
3202
|
-
strokeWidth: 2,
|
|
3203
|
-
d: "M9 5l7 7-7 7"
|
|
3204
|
-
}
|
|
3205
|
-
)
|
|
3620
|
+
type: "button",
|
|
3621
|
+
onClick: close,
|
|
3622
|
+
className: "cursor-pointer flex items-center justify-center w-7 h-7 rounded-full\n text-gray-400 hover:text-gray-600 dark:text-gray-500 dark:hover:text-gray-300\n hover:bg-gray-100 dark:hover:bg-gray-700\n transition-colors duration-150\n focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--bichat-primary)]/40",
|
|
3623
|
+
"aria-label": t("BiChat.Sources.Close"),
|
|
3624
|
+
children: /* @__PURE__ */ jsx(X, { size: 14, weight: "bold" })
|
|
3206
3625
|
}
|
|
3207
|
-
)
|
|
3208
|
-
/* @__PURE__ */ jsxs("span", { children: [
|
|
3209
|
-
citations.length,
|
|
3210
|
-
" ",
|
|
3211
|
-
citations.length === 1 ? "source" : "sources"
|
|
3212
|
-
] })
|
|
3626
|
+
)
|
|
3213
3627
|
] }),
|
|
3214
|
-
/* @__PURE__ */ jsx(
|
|
3215
|
-
"
|
|
3216
|
-
{
|
|
3217
|
-
className: "
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
/* @__PURE__ */
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
"
|
|
3224
|
-
{
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
}
|
|
3231
|
-
),
|
|
3232
|
-
citation.excerpt && /* @__PURE__ */ jsxs("div", { className: "mt-1 text-gray-600 dark:text-gray-400 italic", children: [
|
|
3233
|
-
'"',
|
|
3234
|
-
citation.excerpt,
|
|
3235
|
-
'"'
|
|
3236
|
-
] })
|
|
3237
|
-
] })
|
|
3628
|
+
/* @__PURE__ */ jsx("div", { className: "max-h-80 overflow-y-auto", children: citations.map((citation, index) => {
|
|
3629
|
+
const domain = citation.url ? extractDomain(citation.url) : "";
|
|
3630
|
+
const cardContent = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3631
|
+
/* @__PURE__ */ jsx("h4", { className: "text-sm font-medium leading-snug text-[var(--bichat-color-accent,theme(colors.blue.600))] dark:text-blue-400", children: citation.title || t("BiChat.Sources.SourceN", { n: String(index + 1) }) }),
|
|
3632
|
+
citation.excerpt && /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-gray-500 dark:text-gray-400 line-clamp-2 leading-relaxed", children: citation.excerpt }),
|
|
3633
|
+
domain && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 mt-1.5", children: [
|
|
3634
|
+
/* @__PURE__ */ jsx(
|
|
3635
|
+
"span",
|
|
3636
|
+
{
|
|
3637
|
+
className: "w-4 h-4 rounded-full flex items-center justify-center text-[7px] font-bold text-white flex-shrink-0 select-none",
|
|
3638
|
+
style: { backgroundColor: domainColor(domain) },
|
|
3639
|
+
"aria-hidden": "true",
|
|
3640
|
+
children: domain[0]?.toUpperCase()
|
|
3641
|
+
}
|
|
3642
|
+
),
|
|
3643
|
+
/* @__PURE__ */ jsx("span", { className: "text-[11px] text-gray-400 dark:text-gray-500 truncate", children: domain })
|
|
3238
3644
|
] })
|
|
3239
|
-
}
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3645
|
+
] });
|
|
3646
|
+
const cardClass = "block px-4 py-3 border-t border-gray-100 dark:border-gray-700/50";
|
|
3647
|
+
if (citation.url) {
|
|
3648
|
+
return /* @__PURE__ */ jsx(
|
|
3649
|
+
"a",
|
|
3650
|
+
{
|
|
3651
|
+
href: citation.url,
|
|
3652
|
+
target: "_blank",
|
|
3653
|
+
rel: "noopener noreferrer",
|
|
3654
|
+
className: `${cardClass} hover:bg-gray-50 dark:hover:bg-gray-700/40 transition-colors duration-100
|
|
3655
|
+
focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--bichat-primary)]/40`,
|
|
3656
|
+
children: cardContent
|
|
3657
|
+
},
|
|
3658
|
+
citation.id
|
|
3659
|
+
);
|
|
3660
|
+
}
|
|
3661
|
+
return /* @__PURE__ */ jsx("div", { className: cardClass, children: cardContent }, citation.id);
|
|
3662
|
+
}) })
|
|
3663
|
+
] });
|
|
3243
3664
|
}
|
|
3244
3665
|
var MIME_BY_TYPE = {
|
|
3245
3666
|
excel: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
@@ -3591,6 +4012,59 @@ function InlineQuestionForm({ pendingQuestion }) {
|
|
|
3591
4012
|
] }) });
|
|
3592
4013
|
}
|
|
3593
4014
|
|
|
4015
|
+
// ui/src/bichat/components/RetryActionArea.tsx
|
|
4016
|
+
init_useTranslation();
|
|
4017
|
+
var RetryActionArea = memo(function RetryActionArea2({
|
|
4018
|
+
onRetry
|
|
4019
|
+
}) {
|
|
4020
|
+
const { t } = useTranslation();
|
|
4021
|
+
return (
|
|
4022
|
+
// Wrapper matches TurnBubble layout for assistant messages (justify-start = left-aligned)
|
|
4023
|
+
/* @__PURE__ */ jsx(
|
|
4024
|
+
motion.div,
|
|
4025
|
+
{
|
|
4026
|
+
initial: { opacity: 0, y: 10 },
|
|
4027
|
+
animate: { opacity: 1, y: 0 },
|
|
4028
|
+
exit: { opacity: 0, y: -10 },
|
|
4029
|
+
transition: { duration: 0.2 },
|
|
4030
|
+
className: "flex justify-start",
|
|
4031
|
+
children: /* @__PURE__ */ jsxs(
|
|
4032
|
+
"div",
|
|
4033
|
+
{
|
|
4034
|
+
className: "flex flex-col gap-3 max-w-2xl rounded-2xl px-5 py-3 shadow-sm bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700",
|
|
4035
|
+
role: "status",
|
|
4036
|
+
"aria-live": "polite",
|
|
4037
|
+
children: [
|
|
4038
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
4039
|
+
/* @__PURE__ */ jsx(
|
|
4040
|
+
Warning,
|
|
4041
|
+
{
|
|
4042
|
+
className: "w-5 h-5 text-amber-500 dark:text-amber-400 flex-shrink-0",
|
|
4043
|
+
weight: "fill"
|
|
4044
|
+
}
|
|
4045
|
+
),
|
|
4046
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-gray-700 dark:text-gray-300", children: t("BiChat.Retry.Subtitle") })
|
|
4047
|
+
] }),
|
|
4048
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxs(
|
|
4049
|
+
"button",
|
|
4050
|
+
{
|
|
4051
|
+
onClick: onRetry,
|
|
4052
|
+
className: "cursor-pointer inline-flex items-center gap-1.5 px-4 py-2 text-sm font-medium text-white bg-primary-600 hover:bg-primary-700 dark:bg-primary-700 dark:hover:bg-primary-600 rounded-lg transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-gray-800",
|
|
4053
|
+
"aria-label": t("BiChat.Retry.Title"),
|
|
4054
|
+
children: [
|
|
4055
|
+
/* @__PURE__ */ jsx(ArrowClockwise, { size: 16, className: "w-4 h-4" }),
|
|
4056
|
+
t("BiChat.Retry.Button")
|
|
4057
|
+
]
|
|
4058
|
+
}
|
|
4059
|
+
) })
|
|
4060
|
+
]
|
|
4061
|
+
}
|
|
4062
|
+
)
|
|
4063
|
+
}
|
|
4064
|
+
)
|
|
4065
|
+
);
|
|
4066
|
+
});
|
|
4067
|
+
|
|
3594
4068
|
// ui/src/bichat/utils/debugMetrics.ts
|
|
3595
4069
|
function formatGenerationDuration(generationMs) {
|
|
3596
4070
|
return generationMs > 1e3 ? `${(generationMs / 1e3).toFixed(2)}s` : `${generationMs}ms`;
|
|
@@ -3889,6 +4363,7 @@ var defaultClassNames2 = {
|
|
|
3889
4363
|
bubble: "bg-white dark:bg-gray-800 rounded-2xl rounded-bl-sm px-4 py-3 shadow-sm",
|
|
3890
4364
|
codeOutputs: "",
|
|
3891
4365
|
charts: "mb-1 w-full",
|
|
4366
|
+
tables: "mb-1 flex flex-col gap-3",
|
|
3892
4367
|
artifacts: "mb-1 flex flex-wrap gap-2",
|
|
3893
4368
|
sources: "",
|
|
3894
4369
|
explanation: "mt-4 border-t border-gray-100 dark:border-gray-700 pt-4",
|
|
@@ -3905,6 +4380,7 @@ function mergeClassNames2(defaults, overrides) {
|
|
|
3905
4380
|
bubble: overrides.bubble ?? defaults.bubble,
|
|
3906
4381
|
codeOutputs: overrides.codeOutputs ?? defaults.codeOutputs,
|
|
3907
4382
|
charts: overrides.charts ?? defaults.charts,
|
|
4383
|
+
tables: overrides.tables ?? defaults.tables,
|
|
3908
4384
|
artifacts: overrides.artifacts ?? defaults.artifacts,
|
|
3909
4385
|
sources: overrides.sources ?? defaults.sources,
|
|
3910
4386
|
explanation: overrides.explanation ?? defaults.explanation,
|
|
@@ -3949,6 +4425,14 @@ function AssistantMessage({
|
|
|
3949
4425
|
const hasContent = turn.content?.trim().length > 0;
|
|
3950
4426
|
const hasExplanation = !!turn.explanation?.trim();
|
|
3951
4427
|
const hasPendingQuestion = !!pendingQuestion && pendingQuestion.status === "PENDING" && pendingQuestion.turnId === turnId;
|
|
4428
|
+
const hasCodeOutputs = !!turn.codeOutputs?.length;
|
|
4429
|
+
const hasChart = !!turn.chartData;
|
|
4430
|
+
const hasTables = !!turn.renderTables?.length;
|
|
4431
|
+
const hasArtifacts = !!turn.artifacts?.length;
|
|
4432
|
+
const hasDebug = showDebug && !!turn.debug;
|
|
4433
|
+
const hasRenderablePayload = hasContent || hasExplanation || hasPendingQuestion || hasCodeOutputs || hasChart || hasTables || hasArtifacts || hasDebug;
|
|
4434
|
+
const canRegenerate = !!onRegenerate && !!turnId && !isSystemMessage && isLastTurn;
|
|
4435
|
+
const showInlineRetry = !hasRenderablePayload && canRegenerate;
|
|
3952
4436
|
const handleCopyClick = useCallback(async () => {
|
|
3953
4437
|
try {
|
|
3954
4438
|
if (onCopy) {
|
|
@@ -3990,15 +4474,18 @@ function AssistantMessage({
|
|
|
3990
4474
|
const codeOutputsSlotProps = {
|
|
3991
4475
|
outputs: turn.codeOutputs || []
|
|
3992
4476
|
};
|
|
4477
|
+
const tablesSlotProps = {
|
|
4478
|
+
tables: turn.renderTables || []
|
|
4479
|
+
};
|
|
3993
4480
|
const artifactsSlotProps = {
|
|
3994
4481
|
artifacts: turn.artifacts || []
|
|
3995
4482
|
};
|
|
3996
4483
|
const actionsSlotProps = {
|
|
3997
4484
|
onCopy: handleCopyClick,
|
|
3998
|
-
onRegenerate:
|
|
4485
|
+
onRegenerate: canRegenerate ? handleRegenerateClick : void 0,
|
|
3999
4486
|
timestamp,
|
|
4000
4487
|
canCopy: hasContent,
|
|
4001
|
-
canRegenerate
|
|
4488
|
+
canRegenerate
|
|
4002
4489
|
};
|
|
4003
4490
|
const explanationSlotProps = {
|
|
4004
4491
|
explanation: turn.explanation || "",
|
|
@@ -4011,14 +4498,30 @@ function AssistantMessage({
|
|
|
4011
4498
|
return slot;
|
|
4012
4499
|
};
|
|
4013
4500
|
return /* @__PURE__ */ jsxs("div", { className: classes.root, children: [
|
|
4014
|
-
!hideAvatar && /* @__PURE__ */ jsx("div", { className: avatarClassName, children: renderSlot(slots?.avatar, avatarSlotProps, isSystemMessage ? "SYS" : "AI") }),
|
|
4501
|
+
!hideAvatar && !showInlineRetry && /* @__PURE__ */ jsx("div", { className: avatarClassName, children: renderSlot(slots?.avatar, avatarSlotProps, isSystemMessage ? "SYS" : "AI") }),
|
|
4015
4502
|
/* @__PURE__ */ jsxs("div", { className: classes.wrapper, children: [
|
|
4503
|
+
showInlineRetry && /* @__PURE__ */ jsx(RetryActionArea, { onRetry: () => {
|
|
4504
|
+
void handleRegenerateClick();
|
|
4505
|
+
} }),
|
|
4016
4506
|
turn.codeOutputs && turn.codeOutputs.length > 0 && /* @__PURE__ */ jsx("div", { className: classes.codeOutputs, children: renderSlot(
|
|
4017
4507
|
slots?.codeOutputs,
|
|
4018
4508
|
codeOutputsSlotProps,
|
|
4019
4509
|
/* @__PURE__ */ jsx(CodeOutputsPanel_default, { outputs: turn.codeOutputs })
|
|
4020
4510
|
) }),
|
|
4021
4511
|
turn.chartData && /* @__PURE__ */ jsx("div", { className: classes.charts, children: renderSlot(slots?.charts, chartsSlotProps, /* @__PURE__ */ jsx(ChartCard, { chartData: turn.chartData })) }),
|
|
4512
|
+
turn.renderTables && turn.renderTables.length > 0 && /* @__PURE__ */ jsx("div", { className: classes.tables, children: renderSlot(
|
|
4513
|
+
slots?.tables,
|
|
4514
|
+
tablesSlotProps,
|
|
4515
|
+
turn.renderTables.map((table) => /* @__PURE__ */ jsx(
|
|
4516
|
+
InteractiveTableCard,
|
|
4517
|
+
{
|
|
4518
|
+
table,
|
|
4519
|
+
onSendMessage,
|
|
4520
|
+
sendDisabled: sendDisabled || isStreaming
|
|
4521
|
+
},
|
|
4522
|
+
table.id
|
|
4523
|
+
))
|
|
4524
|
+
) }),
|
|
4022
4525
|
hasContent && /* @__PURE__ */ jsxs("div", { className: bubbleClassName, children: [
|
|
4023
4526
|
renderSlot(
|
|
4024
4527
|
slots?.content,
|
|
@@ -4108,7 +4611,7 @@ function AssistantMessage({
|
|
|
4108
4611
|
children: isCopied ? /* @__PURE__ */ jsx(Check, { size: 14, weight: "bold" }) : /* @__PURE__ */ jsx(Copy, { size: 14, weight: "regular" })
|
|
4109
4612
|
}
|
|
4110
4613
|
),
|
|
4111
|
-
|
|
4614
|
+
canRegenerate && /* @__PURE__ */ jsx(
|
|
4112
4615
|
"button",
|
|
4113
4616
|
{
|
|
4114
4617
|
onClick: handleRegenerateClick,
|
|
@@ -9230,6 +9733,10 @@ function ErrorAlert({ error }) {
|
|
|
9230
9733
|
);
|
|
9231
9734
|
}
|
|
9232
9735
|
var COLLAPSE_STORAGE_KEY = "bichat-sidebar-collapsed";
|
|
9736
|
+
var SESSION_RECONCILE_POLL_INTERVAL_MS = 2e3;
|
|
9737
|
+
var SESSION_RECONCILE_MAX_POLLS = 30;
|
|
9738
|
+
var ACTIVE_SESSION_MISS_MAX_RETRIES = 8;
|
|
9739
|
+
var ACTIVE_SESSION_MISS_RETRY_DELAY_MS = 1e3;
|
|
9233
9740
|
function useSidebarCollapse() {
|
|
9234
9741
|
const [isCollapsed, setIsCollapsed] = useState(() => {
|
|
9235
9742
|
try {
|
|
@@ -9287,7 +9794,7 @@ function Sidebar2({
|
|
|
9287
9794
|
const shouldReduceMotion = useReducedMotion();
|
|
9288
9795
|
const sessionListRef = useRef(null);
|
|
9289
9796
|
const searchContainerRef = useRef(null);
|
|
9290
|
-
const
|
|
9797
|
+
const activeSessionMissRetriesRef = useRef({});
|
|
9291
9798
|
const { isCollapsed, toggle, collapse } = useSidebarCollapse();
|
|
9292
9799
|
const collapsible = !onClose;
|
|
9293
9800
|
const handleSidebarClick = useCallback(
|
|
@@ -9331,6 +9838,7 @@ function Sidebar2({
|
|
|
9331
9838
|
const [actionError, setActionError] = useState(null);
|
|
9332
9839
|
const accessDenied = loadError?.isPermissionDenied === true;
|
|
9333
9840
|
const [refreshKey, setRefreshKey] = useState(0);
|
|
9841
|
+
const [reconcilePollToken, setReconcilePollToken] = useState(0);
|
|
9334
9842
|
const [showConfirm, setShowConfirm] = useState(false);
|
|
9335
9843
|
const [sessionToArchive, setSessionToArchive] = useState(null);
|
|
9336
9844
|
const fetchSessions = useCallback(async () => {
|
|
@@ -9351,8 +9859,13 @@ function Sidebar2({
|
|
|
9351
9859
|
fetchSessions();
|
|
9352
9860
|
}, [fetchSessions, refreshKey]);
|
|
9353
9861
|
useEffect(() => {
|
|
9354
|
-
const handleSessionsUpdated = () => {
|
|
9862
|
+
const handleSessionsUpdated = (event) => {
|
|
9355
9863
|
setRefreshKey((k) => k + 1);
|
|
9864
|
+
const detail = event.detail;
|
|
9865
|
+
const reason = detail?.reason;
|
|
9866
|
+
if (!reason || reason === "session_created" || reason === "message_sent" || reason === "title_regenerate_requested") {
|
|
9867
|
+
setReconcilePollToken((k) => k + 1);
|
|
9868
|
+
}
|
|
9356
9869
|
};
|
|
9357
9870
|
window.addEventListener("bichat:sessions-updated", handleSessionsUpdated);
|
|
9358
9871
|
return () => {
|
|
@@ -9360,31 +9873,33 @@ function Sidebar2({
|
|
|
9360
9873
|
};
|
|
9361
9874
|
}, []);
|
|
9362
9875
|
useEffect(() => {
|
|
9363
|
-
|
|
9364
|
-
|
|
9365
|
-
|
|
9366
|
-
|
|
9876
|
+
activeSessionMissRetriesRef.current = {};
|
|
9877
|
+
}, [activeSessionId]);
|
|
9878
|
+
useEffect(() => {
|
|
9879
|
+
if (!activeSessionId) return;
|
|
9367
9880
|
if (loading) return;
|
|
9368
9881
|
const hasActiveSession = sessions.some((session) => session.id === activeSessionId);
|
|
9369
9882
|
if (hasActiveSession) {
|
|
9370
|
-
|
|
9371
|
-
refreshForActiveSessionRef.current = null;
|
|
9372
|
-
}
|
|
9883
|
+
delete activeSessionMissRetriesRef.current[activeSessionId];
|
|
9373
9884
|
return;
|
|
9374
9885
|
}
|
|
9375
|
-
|
|
9376
|
-
|
|
9377
|
-
|
|
9886
|
+
const attempts = activeSessionMissRetriesRef.current[activeSessionId] ?? 0;
|
|
9887
|
+
if (attempts >= ACTIVE_SESSION_MISS_MAX_RETRIES) {
|
|
9888
|
+
return;
|
|
9378
9889
|
}
|
|
9890
|
+
activeSessionMissRetriesRef.current[activeSessionId] = attempts + 1;
|
|
9891
|
+
const timeoutId = window.setTimeout(() => {
|
|
9892
|
+
setRefreshKey((k) => k + 1);
|
|
9893
|
+
setReconcilePollToken((k) => k + 1);
|
|
9894
|
+
}, ACTIVE_SESSION_MISS_RETRY_DELAY_MS);
|
|
9895
|
+
return () => window.clearTimeout(timeoutId);
|
|
9379
9896
|
}, [activeSessionId, loading, sessions]);
|
|
9380
9897
|
const hasPlaceholderTitles = useMemo(() => {
|
|
9381
9898
|
const newChatLabel = t("BiChat.Chat.NewChat");
|
|
9382
9899
|
return Array.isArray(sessions) && sessions.some((s) => s && (!s.title || s.title === newChatLabel));
|
|
9383
9900
|
}, [sessions, t]);
|
|
9384
9901
|
useEffect(() => {
|
|
9385
|
-
if (!hasPlaceholderTitles) return;
|
|
9386
|
-
const pollInterval = 2e3;
|
|
9387
|
-
const maxPolls = 5;
|
|
9902
|
+
if (!hasPlaceholderTitles && reconcilePollToken === 0) return;
|
|
9388
9903
|
let pollCount = 0;
|
|
9389
9904
|
const intervalId = setInterval(async () => {
|
|
9390
9905
|
pollCount++;
|
|
@@ -9393,12 +9908,12 @@ function Sidebar2({
|
|
|
9393
9908
|
setSessions(result.sessions);
|
|
9394
9909
|
} catch {
|
|
9395
9910
|
}
|
|
9396
|
-
if (pollCount >=
|
|
9911
|
+
if (pollCount >= SESSION_RECONCILE_MAX_POLLS) {
|
|
9397
9912
|
clearInterval(intervalId);
|
|
9398
9913
|
}
|
|
9399
|
-
},
|
|
9914
|
+
}, SESSION_RECONCILE_POLL_INTERVAL_MS);
|
|
9400
9915
|
return () => clearInterval(intervalId);
|
|
9401
|
-
}, [hasPlaceholderTitles, dataSource]);
|
|
9916
|
+
}, [hasPlaceholderTitles, dataSource, reconcilePollToken]);
|
|
9402
9917
|
const handleArchiveRequest = (sessionId) => {
|
|
9403
9918
|
setSessionToArchive(sessionId);
|
|
9404
9919
|
setShowConfirm(true);
|
|
@@ -9456,7 +9971,9 @@ function Sidebar2({
|
|
|
9456
9971
|
try {
|
|
9457
9972
|
await dataSource.regenerateSessionTitle(sessionId);
|
|
9458
9973
|
toast.success(t("BiChat.Sidebar.TitleRegenerated"));
|
|
9459
|
-
|
|
9974
|
+
window.dispatchEvent(new CustomEvent("bichat:sessions-updated", {
|
|
9975
|
+
detail: { reason: "title_regenerate_requested", sessionId }
|
|
9976
|
+
}));
|
|
9460
9977
|
} catch (err) {
|
|
9461
9978
|
console.error("Failed to regenerate title:", err);
|
|
9462
9979
|
const display = toErrorDisplay(err, t("BiChat.Sidebar.FailedToRegenerateTitle"));
|
|
@@ -10269,59 +10786,6 @@ function BiChatLayout({
|
|
|
10269
10786
|
] })
|
|
10270
10787
|
] });
|
|
10271
10788
|
}
|
|
10272
|
-
|
|
10273
|
-
// ui/src/bichat/components/RetryActionArea.tsx
|
|
10274
|
-
init_useTranslation();
|
|
10275
|
-
var RetryActionArea = memo(function RetryActionArea2({
|
|
10276
|
-
onRetry
|
|
10277
|
-
}) {
|
|
10278
|
-
const { t } = useTranslation();
|
|
10279
|
-
return (
|
|
10280
|
-
// Wrapper matches TurnBubble layout for assistant messages (justify-start = left-aligned)
|
|
10281
|
-
/* @__PURE__ */ jsx(
|
|
10282
|
-
motion.div,
|
|
10283
|
-
{
|
|
10284
|
-
initial: { opacity: 0, y: 10 },
|
|
10285
|
-
animate: { opacity: 1, y: 0 },
|
|
10286
|
-
exit: { opacity: 0, y: -10 },
|
|
10287
|
-
transition: { duration: 0.2 },
|
|
10288
|
-
className: "flex justify-start",
|
|
10289
|
-
children: /* @__PURE__ */ jsxs(
|
|
10290
|
-
"div",
|
|
10291
|
-
{
|
|
10292
|
-
className: "flex flex-col gap-3 max-w-2xl rounded-2xl px-5 py-3 shadow-sm bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700",
|
|
10293
|
-
role: "status",
|
|
10294
|
-
"aria-live": "polite",
|
|
10295
|
-
children: [
|
|
10296
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
10297
|
-
/* @__PURE__ */ jsx(
|
|
10298
|
-
Warning,
|
|
10299
|
-
{
|
|
10300
|
-
className: "w-5 h-5 text-amber-500 dark:text-amber-400 flex-shrink-0",
|
|
10301
|
-
weight: "fill"
|
|
10302
|
-
}
|
|
10303
|
-
),
|
|
10304
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm text-gray-700 dark:text-gray-300", children: t("BiChat.Retry.Subtitle") })
|
|
10305
|
-
] }),
|
|
10306
|
-
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxs(
|
|
10307
|
-
"button",
|
|
10308
|
-
{
|
|
10309
|
-
onClick: onRetry,
|
|
10310
|
-
className: "cursor-pointer inline-flex items-center gap-1.5 px-4 py-2 text-sm font-medium text-white bg-primary-600 hover:bg-primary-700 dark:bg-primary-700 dark:hover:bg-primary-600 rounded-lg transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-gray-800",
|
|
10311
|
-
"aria-label": t("BiChat.Retry.Title"),
|
|
10312
|
-
children: [
|
|
10313
|
-
/* @__PURE__ */ jsx(ArrowClockwise, { size: 16, className: "w-4 h-4" }),
|
|
10314
|
-
t("BiChat.Retry.Button")
|
|
10315
|
-
]
|
|
10316
|
-
}
|
|
10317
|
-
) })
|
|
10318
|
-
]
|
|
10319
|
-
}
|
|
10320
|
-
)
|
|
10321
|
-
}
|
|
10322
|
-
)
|
|
10323
|
-
);
|
|
10324
|
-
});
|
|
10325
10789
|
init_useTranslation();
|
|
10326
10790
|
function MessageActions({
|
|
10327
10791
|
message,
|
|
@@ -12139,6 +12603,75 @@ function toStreamEvent(chunk) {
|
|
|
12139
12603
|
}
|
|
12140
12604
|
}
|
|
12141
12605
|
|
|
12606
|
+
// ui/src/bichat/utils/tableSpec.ts
|
|
12607
|
+
function isRecord2(value) {
|
|
12608
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
12609
|
+
}
|
|
12610
|
+
function readString(value) {
|
|
12611
|
+
if (typeof value !== "string") return null;
|
|
12612
|
+
const trimmed = value.trim();
|
|
12613
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
12614
|
+
}
|
|
12615
|
+
function readPositiveInteger(value) {
|
|
12616
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return null;
|
|
12617
|
+
const n = Math.floor(value);
|
|
12618
|
+
return n > 0 ? n : null;
|
|
12619
|
+
}
|
|
12620
|
+
function normalizeRows(value) {
|
|
12621
|
+
if (!Array.isArray(value)) return [];
|
|
12622
|
+
const rows = [];
|
|
12623
|
+
for (const row of value) {
|
|
12624
|
+
if (!Array.isArray(row)) continue;
|
|
12625
|
+
rows.push(row);
|
|
12626
|
+
}
|
|
12627
|
+
return rows;
|
|
12628
|
+
}
|
|
12629
|
+
function parseExport(value) {
|
|
12630
|
+
if (!isRecord2(value)) return void 0;
|
|
12631
|
+
const url = readString(value.url);
|
|
12632
|
+
if (!url) return void 0;
|
|
12633
|
+
return {
|
|
12634
|
+
url,
|
|
12635
|
+
filename: readString(value.filename) || "table_export.xlsx",
|
|
12636
|
+
rowCount: readPositiveInteger(value.row_count) || readPositiveInteger(value.rowCount) || void 0,
|
|
12637
|
+
fileSizeKB: readPositiveInteger(value.file_size_kb) || readPositiveInteger(value.fileSizeKB) || void 0
|
|
12638
|
+
};
|
|
12639
|
+
}
|
|
12640
|
+
function parseRenderTableDataFromJsonString(json, fallbackId) {
|
|
12641
|
+
const trimmed = json.trim();
|
|
12642
|
+
if (!trimmed) return null;
|
|
12643
|
+
let parsed;
|
|
12644
|
+
try {
|
|
12645
|
+
parsed = JSON.parse(trimmed);
|
|
12646
|
+
} catch {
|
|
12647
|
+
return null;
|
|
12648
|
+
}
|
|
12649
|
+
if (!isRecord2(parsed)) return null;
|
|
12650
|
+
const columns = Array.isArray(parsed.columns) ? parsed.columns.map((column) => readString(column)).filter((column) => column !== null) : [];
|
|
12651
|
+
if (columns.length === 0) return null;
|
|
12652
|
+
const rows = normalizeRows(parsed.rows);
|
|
12653
|
+
const headersRaw = Array.isArray(parsed.headers) ? parsed.headers.map((header) => readString(header)).filter((header) => header !== null) : [];
|
|
12654
|
+
const headers = headersRaw.length === columns.length ? headersRaw : columns;
|
|
12655
|
+
const totalRows = readPositiveInteger(parsed.total_rows) || readPositiveInteger(parsed.totalRows) || rows.length;
|
|
12656
|
+
const pageSize = readPositiveInteger(parsed.page_size) || readPositiveInteger(parsed.pageSize) || 25;
|
|
12657
|
+
const query = readString(parsed.query) || readString(parsed.sql);
|
|
12658
|
+
if (!query) return null;
|
|
12659
|
+
return {
|
|
12660
|
+
id: readString(parsed.id) || fallbackId,
|
|
12661
|
+
title: readString(parsed.title) || void 0,
|
|
12662
|
+
query,
|
|
12663
|
+
columns,
|
|
12664
|
+
headers,
|
|
12665
|
+
rows,
|
|
12666
|
+
totalRows,
|
|
12667
|
+
pageSize,
|
|
12668
|
+
truncated: parsed.truncated === true,
|
|
12669
|
+
truncatedReason: readString(parsed.truncated_reason) || readString(parsed.truncatedReason) || void 0,
|
|
12670
|
+
export: parseExport(parsed.export),
|
|
12671
|
+
exportPrompt: readString(parsed.export_prompt) || readString(parsed.exportPrompt) || void 0
|
|
12672
|
+
};
|
|
12673
|
+
}
|
|
12674
|
+
|
|
12142
12675
|
// ui/src/bichat/data/HttpDataSource.ts
|
|
12143
12676
|
function isSessionNotFoundError(err) {
|
|
12144
12677
|
if (!(err instanceof AppletRPCException)) return false;
|
|
@@ -12169,7 +12702,7 @@ function toSessionArtifact(artifact) {
|
|
|
12169
12702
|
function warnMalformedSessionPayload(message, details) {
|
|
12170
12703
|
console.warn(`[BiChat] ${message}`, details || {});
|
|
12171
12704
|
}
|
|
12172
|
-
function
|
|
12705
|
+
function readString2(value, fallback = "") {
|
|
12173
12706
|
return typeof value === "string" ? value : fallback;
|
|
12174
12707
|
}
|
|
12175
12708
|
function readNonEmptyString(value) {
|
|
@@ -12183,12 +12716,52 @@ function readFiniteNumber(value, fallback = 0) {
|
|
|
12183
12716
|
function readOptionalFiniteNumber(value) {
|
|
12184
12717
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
12185
12718
|
}
|
|
12719
|
+
var MIME_TO_EXTENSION = {
|
|
12720
|
+
"image/jpeg": "jpg",
|
|
12721
|
+
"image/png": "png",
|
|
12722
|
+
"image/gif": "gif",
|
|
12723
|
+
"application/pdf": "pdf"
|
|
12724
|
+
};
|
|
12725
|
+
var SAFE_AUTOCORRECT_MIME_TYPES = new Set(Object.keys(MIME_TO_EXTENSION));
|
|
12726
|
+
function detectMimeFromSignature(bytes) {
|
|
12727
|
+
if (bytes.length >= 8) {
|
|
12728
|
+
const isPng = bytes[0] === 137 && bytes[1] === 80 && bytes[2] === 78 && bytes[3] === 71 && bytes[4] === 13 && bytes[5] === 10 && bytes[6] === 26 && bytes[7] === 10;
|
|
12729
|
+
if (isPng) return "image/png";
|
|
12730
|
+
}
|
|
12731
|
+
if (bytes.length >= 3) {
|
|
12732
|
+
const isJpeg = bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255;
|
|
12733
|
+
if (isJpeg) return "image/jpeg";
|
|
12734
|
+
}
|
|
12735
|
+
if (bytes.length >= 6) {
|
|
12736
|
+
const isGif = bytes[0] === 71 && bytes[1] === 73 && bytes[2] === 70 && bytes[3] === 56 && (bytes[4] === 55 || bytes[4] === 57) && bytes[5] === 97;
|
|
12737
|
+
if (isGif) return "image/gif";
|
|
12738
|
+
}
|
|
12739
|
+
if (bytes.length >= 4) {
|
|
12740
|
+
const isPdf = bytes[0] === 37 && bytes[1] === 80 && bytes[2] === 68 && bytes[3] === 70;
|
|
12741
|
+
if (isPdf) return "application/pdf";
|
|
12742
|
+
}
|
|
12743
|
+
return void 0;
|
|
12744
|
+
}
|
|
12745
|
+
function normalizeFilenameForMime(filename, mimeType) {
|
|
12746
|
+
const expectedExt = MIME_TO_EXTENSION[mimeType];
|
|
12747
|
+
if (!expectedExt) return filename;
|
|
12748
|
+
const lower = filename.toLowerCase();
|
|
12749
|
+
if (mimeType === "image/jpeg" && (lower.endsWith(".jpg") || lower.endsWith(".jpeg"))) {
|
|
12750
|
+
return filename;
|
|
12751
|
+
}
|
|
12752
|
+
if (lower.endsWith(`.${expectedExt}`)) {
|
|
12753
|
+
return filename;
|
|
12754
|
+
}
|
|
12755
|
+
const dotIndex = filename.lastIndexOf(".");
|
|
12756
|
+
const baseName = dotIndex > 0 ? filename.slice(0, dotIndex) : filename;
|
|
12757
|
+
return `${baseName}.${expectedExt}`;
|
|
12758
|
+
}
|
|
12186
12759
|
function normalizeQuestionType(rawType) {
|
|
12187
|
-
const normalized =
|
|
12760
|
+
const normalized = readString2(rawType).trim().toUpperCase().replace(/[\s-]+/g, "_");
|
|
12188
12761
|
return normalized === "MULTIPLE_CHOICE" ? "MULTIPLE_CHOICE" : "SINGLE_CHOICE";
|
|
12189
12762
|
}
|
|
12190
12763
|
function normalizeMessageRole(rawRole) {
|
|
12191
|
-
const normalized =
|
|
12764
|
+
const normalized = readString2(rawRole).trim().toLowerCase();
|
|
12192
12765
|
if (normalized === "user" /* User */) return "user" /* User */;
|
|
12193
12766
|
if (normalized === "system" /* System */) return "system" /* System */;
|
|
12194
12767
|
if (normalized === "tool" /* Tool */) return "tool" /* Tool */;
|
|
@@ -12199,8 +12772,8 @@ function sanitizeAttachment(rawAttachment, turnId, index) {
|
|
|
12199
12772
|
warnMalformedSessionPayload("Dropped malformed attachment entry", { turnId, index });
|
|
12200
12773
|
return null;
|
|
12201
12774
|
}
|
|
12202
|
-
const filename =
|
|
12203
|
-
const mimeType =
|
|
12775
|
+
const filename = readString2(rawAttachment.filename, "attachment");
|
|
12776
|
+
const mimeType = readString2(rawAttachment.mimeType, "application/octet-stream");
|
|
12204
12777
|
const id = readNonEmptyString(rawAttachment.id) || void 0;
|
|
12205
12778
|
const clientKey = readNonEmptyString(rawAttachment.clientKey) || id || `${turnId}-attachment-${index}`;
|
|
12206
12779
|
return {
|
|
@@ -12233,7 +12806,7 @@ function sanitizeAssistantArtifacts(rawArtifacts, turnId) {
|
|
|
12233
12806
|
warnMalformedSessionPayload("Dropped malformed assistant artifact", { turnId, index: i });
|
|
12234
12807
|
continue;
|
|
12235
12808
|
}
|
|
12236
|
-
const type =
|
|
12809
|
+
const type = readString2(raw.type).toLowerCase();
|
|
12237
12810
|
if (type !== "excel" && type !== "pdf") {
|
|
12238
12811
|
continue;
|
|
12239
12812
|
}
|
|
@@ -12244,7 +12817,7 @@ function sanitizeAssistantArtifacts(rawArtifacts, turnId) {
|
|
|
12244
12817
|
}
|
|
12245
12818
|
artifacts.push({
|
|
12246
12819
|
type,
|
|
12247
|
-
filename:
|
|
12820
|
+
filename: readString2(raw.filename, "download"),
|
|
12248
12821
|
url,
|
|
12249
12822
|
sizeReadable: readNonEmptyString(raw.sizeReadable) || void 0,
|
|
12250
12823
|
rowCount: typeof raw.rowCount === "number" && Number.isFinite(raw.rowCount) ? raw.rowCount : void 0,
|
|
@@ -12265,29 +12838,29 @@ function sanitizeAssistantTurn(rawAssistantTurn, fallbackCreatedAt, turnId) {
|
|
|
12265
12838
|
return void 0;
|
|
12266
12839
|
}
|
|
12267
12840
|
const citations = Array.isArray(rawAssistantTurn.citations) ? rawAssistantTurn.citations.filter((item) => isRecord(item)).map((item, index) => ({
|
|
12268
|
-
id:
|
|
12269
|
-
type:
|
|
12270
|
-
title:
|
|
12271
|
-
url:
|
|
12841
|
+
id: readString2(item.id, `${assistantID}-citation-${index}`),
|
|
12842
|
+
type: readString2(item.type),
|
|
12843
|
+
title: readString2(item.title),
|
|
12844
|
+
url: readString2(item.url),
|
|
12272
12845
|
startIndex: readFiniteNumber(item.startIndex),
|
|
12273
12846
|
endIndex: readFiniteNumber(item.endIndex),
|
|
12274
12847
|
excerpt: readNonEmptyString(item.excerpt) || void 0
|
|
12275
12848
|
})) : [];
|
|
12276
12849
|
const toolCalls = Array.isArray(rawAssistantTurn.toolCalls) ? rawAssistantTurn.toolCalls.filter((item) => isRecord(item)).map((item, index) => ({
|
|
12277
|
-
id:
|
|
12278
|
-
name:
|
|
12279
|
-
arguments:
|
|
12850
|
+
id: readString2(item.id, `${assistantID}-tool-${index}`),
|
|
12851
|
+
name: readString2(item.name),
|
|
12852
|
+
arguments: readString2(item.arguments),
|
|
12280
12853
|
result: readNonEmptyString(item.result) || void 0,
|
|
12281
12854
|
error: readNonEmptyString(item.error) || void 0,
|
|
12282
12855
|
durationMs: readFiniteNumber(item.durationMs)
|
|
12283
12856
|
})) : [];
|
|
12284
12857
|
const codeOutputs = Array.isArray(rawAssistantTurn.codeOutputs) ? rawAssistantTurn.codeOutputs.filter((item) => isRecord(item)).map((item) => ({
|
|
12285
12858
|
type: (() => {
|
|
12286
|
-
const normalizedType =
|
|
12859
|
+
const normalizedType = readString2(item.type, "text").toLowerCase();
|
|
12287
12860
|
if (normalizedType === "image" || normalizedType === "error") return normalizedType;
|
|
12288
12861
|
return "text";
|
|
12289
12862
|
})(),
|
|
12290
|
-
content:
|
|
12863
|
+
content: readString2(item.content),
|
|
12291
12864
|
filename: readNonEmptyString(item.filename) || void 0,
|
|
12292
12865
|
mimeType: readNonEmptyString(item.mimeType) || void 0,
|
|
12293
12866
|
sizeBytes: readOptionalFiniteNumber(item.sizeBytes)
|
|
@@ -12303,7 +12876,7 @@ function sanitizeAssistantTurn(rawAssistantTurn, fallbackCreatedAt, turnId) {
|
|
|
12303
12876
|
} : void 0,
|
|
12304
12877
|
tools: Array.isArray(rawAssistantTurn.debug.tools) ? rawAssistantTurn.debug.tools.filter((tool) => isRecord(tool)).map((tool) => ({
|
|
12305
12878
|
callId: readNonEmptyString(tool.callId) || void 0,
|
|
12306
|
-
name:
|
|
12879
|
+
name: readString2(tool.name),
|
|
12307
12880
|
arguments: readNonEmptyString(tool.arguments) || void 0,
|
|
12308
12881
|
result: readNonEmptyString(tool.result) || void 0,
|
|
12309
12882
|
error: readNonEmptyString(tool.error) || void 0,
|
|
@@ -12313,15 +12886,16 @@ function sanitizeAssistantTurn(rawAssistantTurn, fallbackCreatedAt, turnId) {
|
|
|
12313
12886
|
return {
|
|
12314
12887
|
id: assistantID,
|
|
12315
12888
|
role: normalizeMessageRole(rawAssistantTurn.role),
|
|
12316
|
-
content:
|
|
12889
|
+
content: readString2(rawAssistantTurn.content),
|
|
12317
12890
|
explanation: readNonEmptyString(rawAssistantTurn.explanation) || void 0,
|
|
12318
12891
|
citations,
|
|
12319
12892
|
toolCalls,
|
|
12320
12893
|
chartData: void 0,
|
|
12894
|
+
renderTables: void 0,
|
|
12321
12895
|
artifacts: sanitizeAssistantArtifacts(rawAssistantTurn.artifacts, turnId),
|
|
12322
12896
|
codeOutputs,
|
|
12323
12897
|
debug: debugTrace,
|
|
12324
|
-
createdAt:
|
|
12898
|
+
createdAt: readString2(rawAssistantTurn.createdAt, fallbackCreatedAt)
|
|
12325
12899
|
};
|
|
12326
12900
|
}
|
|
12327
12901
|
function sanitizeConversationTurn(rawTurn, index, fallbackSessionID) {
|
|
@@ -12338,19 +12912,19 @@ function sanitizeConversationTurn(rawTurn, index, fallbackSessionID) {
|
|
|
12338
12912
|
warnMalformedSessionPayload("Dropped malformed turn payload (missing user turn id)", { index });
|
|
12339
12913
|
return null;
|
|
12340
12914
|
}
|
|
12341
|
-
const turnID =
|
|
12342
|
-
const createdAt =
|
|
12915
|
+
const turnID = readString2(rawTurn.id, userTurnID);
|
|
12916
|
+
const createdAt = readString2(
|
|
12343
12917
|
rawTurn.createdAt,
|
|
12344
|
-
|
|
12918
|
+
readString2(rawTurn.userTurn.createdAt, (/* @__PURE__ */ new Date()).toISOString())
|
|
12345
12919
|
);
|
|
12346
12920
|
return {
|
|
12347
12921
|
id: turnID,
|
|
12348
|
-
sessionId:
|
|
12922
|
+
sessionId: readString2(rawTurn.sessionId, fallbackSessionID),
|
|
12349
12923
|
userTurn: {
|
|
12350
12924
|
id: userTurnID,
|
|
12351
|
-
content:
|
|
12925
|
+
content: readString2(rawTurn.userTurn.content),
|
|
12352
12926
|
attachments: sanitizeUserAttachments(rawTurn.userTurn.attachments, turnID),
|
|
12353
|
-
createdAt:
|
|
12927
|
+
createdAt: readString2(rawTurn.userTurn.createdAt, createdAt)
|
|
12354
12928
|
},
|
|
12355
12929
|
assistantTurn: sanitizeAssistantTurn(rawTurn.assistantTurn, createdAt, turnID),
|
|
12356
12930
|
createdAt
|
|
@@ -12403,7 +12977,7 @@ function sanitizePendingQuestion(rawPendingQuestion, sessionID) {
|
|
|
12403
12977
|
}
|
|
12404
12978
|
return true;
|
|
12405
12979
|
}).map((question, index) => {
|
|
12406
|
-
const questionID =
|
|
12980
|
+
const questionID = readString2(question.id, `${checkpointID}-q-${index}`);
|
|
12407
12981
|
const options = Array.isArray(question.options) ? question.options.filter((option) => {
|
|
12408
12982
|
if (!option || !isRecord(option)) {
|
|
12409
12983
|
warnMalformedSessionPayload("Dropped malformed pendingQuestion option", {
|
|
@@ -12415,23 +12989,23 @@ function sanitizePendingQuestion(rawPendingQuestion, sessionID) {
|
|
|
12415
12989
|
}
|
|
12416
12990
|
return true;
|
|
12417
12991
|
}).map((option, optionIndex) => {
|
|
12418
|
-
const label =
|
|
12992
|
+
const label = readString2(option.label);
|
|
12419
12993
|
return {
|
|
12420
|
-
id:
|
|
12994
|
+
id: readString2(option.id, `${questionID}-opt-${optionIndex}`),
|
|
12421
12995
|
label,
|
|
12422
12996
|
value: label
|
|
12423
12997
|
};
|
|
12424
12998
|
}) : [];
|
|
12425
12999
|
return {
|
|
12426
13000
|
id: questionID,
|
|
12427
|
-
text:
|
|
13001
|
+
text: readString2(question.text),
|
|
12428
13002
|
type: normalizeQuestionType(question.type),
|
|
12429
13003
|
options
|
|
12430
13004
|
};
|
|
12431
13005
|
}) : [];
|
|
12432
13006
|
return {
|
|
12433
13007
|
id: checkpointID,
|
|
12434
|
-
turnId:
|
|
13008
|
+
turnId: readString2(rawPendingQuestion.turnId),
|
|
12435
13009
|
questions,
|
|
12436
13010
|
status: "PENDING"
|
|
12437
13011
|
};
|
|
@@ -12503,6 +13077,18 @@ function extractChartDataFromToolCalls(toolCalls) {
|
|
|
12503
13077
|
}
|
|
12504
13078
|
return void 0;
|
|
12505
13079
|
}
|
|
13080
|
+
function extractRenderTablesFromToolCalls(toolCalls) {
|
|
13081
|
+
if (!toolCalls) return [];
|
|
13082
|
+
const tables = [];
|
|
13083
|
+
for (const tc of toolCalls) {
|
|
13084
|
+
if (tc.name !== "renderTable" || !tc.result) continue;
|
|
13085
|
+
const parsed = parseRenderTableDataFromJsonString(tc.result, tc.id);
|
|
13086
|
+
if (parsed) {
|
|
13087
|
+
tables.push(parsed);
|
|
13088
|
+
}
|
|
13089
|
+
}
|
|
13090
|
+
return tables;
|
|
13091
|
+
}
|
|
12506
13092
|
var EXPORT_TOOL_NAMES = {
|
|
12507
13093
|
export_query_to_excel: "excel",
|
|
12508
13094
|
export_data_to_excel: "excel",
|
|
@@ -12538,6 +13124,7 @@ function extractDownloadArtifactsFromToolCalls(toolCalls) {
|
|
|
12538
13124
|
function normalizeAssistantTurn(turn) {
|
|
12539
13125
|
const existingArtifacts = turn.artifacts || [];
|
|
12540
13126
|
const fromToolCalls = extractDownloadArtifactsFromToolCalls(turn.toolCalls);
|
|
13127
|
+
const renderTables = turn.renderTables || extractRenderTablesFromToolCalls(turn.toolCalls);
|
|
12541
13128
|
const merged = [...existingArtifacts];
|
|
12542
13129
|
for (const a of fromToolCalls) {
|
|
12543
13130
|
if (!merged.some((e) => e.url === a.url && e.filename === a.filename)) {
|
|
@@ -12548,6 +13135,7 @@ function normalizeAssistantTurn(turn) {
|
|
|
12548
13135
|
...turn,
|
|
12549
13136
|
role: turn.role || "assistant" /* Assistant */,
|
|
12550
13137
|
chartData: turn.chartData || extractChartDataFromToolCalls(turn.toolCalls),
|
|
13138
|
+
renderTables,
|
|
12551
13139
|
citations: turn.citations || [],
|
|
12552
13140
|
artifacts: merged,
|
|
12553
13141
|
codeOutputs: turn.codeOutputs || []
|
|
@@ -12675,6 +13263,52 @@ var HttpDataSource = class {
|
|
|
12675
13263
|
headers.delete("Content-Type");
|
|
12676
13264
|
return headers;
|
|
12677
13265
|
}
|
|
13266
|
+
logAttachmentLifecycle(event, details) {
|
|
13267
|
+
const payload = {
|
|
13268
|
+
source: "HttpDataSource",
|
|
13269
|
+
event,
|
|
13270
|
+
...details
|
|
13271
|
+
};
|
|
13272
|
+
if (event.endsWith("_fail")) {
|
|
13273
|
+
console.warn("[bichat.attachments]", payload);
|
|
13274
|
+
return;
|
|
13275
|
+
}
|
|
13276
|
+
}
|
|
13277
|
+
async normalizeAttachmentFile(attachment, file) {
|
|
13278
|
+
const signatureBytes = new Uint8Array(await file.slice(0, 16).arrayBuffer());
|
|
13279
|
+
const detectedMimeType = detectMimeFromSignature(signatureBytes);
|
|
13280
|
+
const declaredMimeType = (attachment.mimeType || file.type || "").trim().toLowerCase();
|
|
13281
|
+
let resolvedMimeType = declaredMimeType || detectedMimeType || "application/octet-stream";
|
|
13282
|
+
let correctedFromDeclared = false;
|
|
13283
|
+
if (detectedMimeType && declaredMimeType && detectedMimeType !== declaredMimeType) {
|
|
13284
|
+
const safeToCorrect = SAFE_AUTOCORRECT_MIME_TYPES.has(detectedMimeType) && SAFE_AUTOCORRECT_MIME_TYPES.has(declaredMimeType);
|
|
13285
|
+
if (!safeToCorrect) {
|
|
13286
|
+
throw new Error(
|
|
13287
|
+
`Attachment "${attachment.filename}" MIME mismatch: declared "${declaredMimeType}", detected "${detectedMimeType}"`
|
|
13288
|
+
);
|
|
13289
|
+
}
|
|
13290
|
+
resolvedMimeType = detectedMimeType;
|
|
13291
|
+
correctedFromDeclared = true;
|
|
13292
|
+
} else if (detectedMimeType && !declaredMimeType) {
|
|
13293
|
+
resolvedMimeType = detectedMimeType;
|
|
13294
|
+
}
|
|
13295
|
+
const normalizedName = normalizeFilenameForMime(attachment.filename, resolvedMimeType);
|
|
13296
|
+
const normalized = new File([file], normalizedName, {
|
|
13297
|
+
type: resolvedMimeType,
|
|
13298
|
+
lastModified: file.lastModified
|
|
13299
|
+
});
|
|
13300
|
+
this.logAttachmentLifecycle("attachment_decode_success", {
|
|
13301
|
+
attachmentKey: attachment.clientKey,
|
|
13302
|
+
filename: attachment.filename,
|
|
13303
|
+
normalizedFilename: normalized.name,
|
|
13304
|
+
declaredMimeType: declaredMimeType || void 0,
|
|
13305
|
+
detectedMimeType,
|
|
13306
|
+
resolvedMimeType,
|
|
13307
|
+
correctedFromDeclared,
|
|
13308
|
+
sizeBytes: normalized.size
|
|
13309
|
+
});
|
|
13310
|
+
return normalized;
|
|
13311
|
+
}
|
|
12678
13312
|
async uploadFile(file) {
|
|
12679
13313
|
const formData = new FormData();
|
|
12680
13314
|
formData.append("file", file);
|
|
@@ -12707,17 +13341,32 @@ var HttpDataSource = class {
|
|
|
12707
13341
|
}
|
|
12708
13342
|
async attachmentToFile(attachment) {
|
|
12709
13343
|
if (attachment.base64Data && attachment.base64Data.trim().length > 0) {
|
|
12710
|
-
|
|
12711
|
-
|
|
12712
|
-
|
|
12713
|
-
|
|
12714
|
-
|
|
12715
|
-
|
|
13344
|
+
try {
|
|
13345
|
+
const base64Data = attachment.base64Data.trim();
|
|
13346
|
+
const dataUrl = base64Data.startsWith("data:") ? base64Data : `data:${attachment.mimeType || "application/octet-stream"};base64,${base64Data}`;
|
|
13347
|
+
const blob = await fetch(dataUrl).then((response) => response.blob());
|
|
13348
|
+
return new File([blob], attachment.filename, {
|
|
13349
|
+
type: attachment.mimeType || blob.type || "application/octet-stream"
|
|
13350
|
+
});
|
|
13351
|
+
} catch (err) {
|
|
13352
|
+
const message = err instanceof Error ? err.message : "Unknown decode error";
|
|
13353
|
+
throw new Error(`Attachment "${attachment.filename}" decode failed: ${message}`);
|
|
13354
|
+
}
|
|
12716
13355
|
}
|
|
12717
13356
|
if (attachment.url) {
|
|
12718
|
-
|
|
13357
|
+
let parsed;
|
|
13358
|
+
try {
|
|
13359
|
+
parsed = new URL(attachment.url, window.location?.origin ?? "https://localhost");
|
|
13360
|
+
if (!["http:", "https:"].includes(parsed.protocol)) {
|
|
13361
|
+
throw new Error(`Attachment "${attachment.filename}" URL has disallowed protocol: ${parsed.protocol}`);
|
|
13362
|
+
}
|
|
13363
|
+
} catch (err) {
|
|
13364
|
+
if (err instanceof Error && err.message.includes("Attachment")) throw err;
|
|
13365
|
+
throw new Error(`Attachment "${attachment.filename}" has invalid or malformed URL`);
|
|
13366
|
+
}
|
|
13367
|
+
const response = await fetch(parsed.href);
|
|
12719
13368
|
if (!response.ok) {
|
|
12720
|
-
throw new Error(`
|
|
13369
|
+
throw new Error(`Attachment "${attachment.filename}" decode failed: source HTTP ${response.status}`);
|
|
12721
13370
|
}
|
|
12722
13371
|
const blob = await response.blob();
|
|
12723
13372
|
return new File([blob], attachment.filename, {
|
|
@@ -12726,8 +13375,24 @@ var HttpDataSource = class {
|
|
|
12726
13375
|
}
|
|
12727
13376
|
throw new Error(`Attachment "${attachment.filename}" has no uploadable data`);
|
|
12728
13377
|
}
|
|
12729
|
-
|
|
13378
|
+
assertUploadReferences(uploads) {
|
|
13379
|
+
return uploads.map((upload, index) => {
|
|
13380
|
+
if (typeof upload.id !== "number" || !Number.isFinite(upload.id) || upload.id <= 0) {
|
|
13381
|
+
throw new Error(`Attachment upload reference is invalid at index ${index}`);
|
|
13382
|
+
}
|
|
13383
|
+
return { uploadId: upload.id };
|
|
13384
|
+
});
|
|
13385
|
+
}
|
|
13386
|
+
async ensureAttachmentUpload(attachment, context) {
|
|
12730
13387
|
if (typeof attachment.uploadId === "number" && attachment.uploadId > 0) {
|
|
13388
|
+
this.logAttachmentLifecycle("attachment_upload_success", {
|
|
13389
|
+
sessionId: context.sessionId,
|
|
13390
|
+
attachmentIndex: context.attachmentIndex,
|
|
13391
|
+
attachmentKey: attachment.clientKey,
|
|
13392
|
+
filename: attachment.filename,
|
|
13393
|
+
uploadId: attachment.uploadId,
|
|
13394
|
+
reusedUploadId: true
|
|
13395
|
+
});
|
|
12731
13396
|
return {
|
|
12732
13397
|
id: attachment.uploadId,
|
|
12733
13398
|
url: attachment.url || "",
|
|
@@ -12737,8 +13402,64 @@ var HttpDataSource = class {
|
|
|
12737
13402
|
size: attachment.sizeBytes
|
|
12738
13403
|
};
|
|
12739
13404
|
}
|
|
12740
|
-
|
|
12741
|
-
|
|
13405
|
+
this.logAttachmentLifecycle("attachment_decode_start", {
|
|
13406
|
+
sessionId: context.sessionId,
|
|
13407
|
+
attachmentIndex: context.attachmentIndex,
|
|
13408
|
+
attachmentKey: attachment.clientKey,
|
|
13409
|
+
filename: attachment.filename,
|
|
13410
|
+
hasBase64Data: Boolean(attachment.base64Data && attachment.base64Data.trim().length > 0),
|
|
13411
|
+
hasURL: Boolean(attachment.url)
|
|
13412
|
+
});
|
|
13413
|
+
let file;
|
|
13414
|
+
try {
|
|
13415
|
+
const rawFile = await this.attachmentToFile(attachment);
|
|
13416
|
+
file = await this.normalizeAttachmentFile(attachment, rawFile);
|
|
13417
|
+
validateAttachmentFile(file);
|
|
13418
|
+
} catch (err) {
|
|
13419
|
+
const message = err instanceof Error ? err.message : "Unknown attachment decode/validation error";
|
|
13420
|
+
this.logAttachmentLifecycle("attachment_decode_fail", {
|
|
13421
|
+
sessionId: context.sessionId,
|
|
13422
|
+
attachmentIndex: context.attachmentIndex,
|
|
13423
|
+
attachmentKey: attachment.clientKey,
|
|
13424
|
+
filename: attachment.filename,
|
|
13425
|
+
error: message
|
|
13426
|
+
});
|
|
13427
|
+
throw new Error(message);
|
|
13428
|
+
}
|
|
13429
|
+
this.logAttachmentLifecycle("attachment_upload_start", {
|
|
13430
|
+
sessionId: context.sessionId,
|
|
13431
|
+
attachmentIndex: context.attachmentIndex,
|
|
13432
|
+
attachmentKey: attachment.clientKey,
|
|
13433
|
+
filename: file.name,
|
|
13434
|
+
mimeType: file.type,
|
|
13435
|
+
sizeBytes: file.size
|
|
13436
|
+
});
|
|
13437
|
+
try {
|
|
13438
|
+
const upload = await this.uploadFile(file);
|
|
13439
|
+
attachment.uploadId = upload.id;
|
|
13440
|
+
attachment.mimeType = upload.mimetype || file.type;
|
|
13441
|
+
attachment.filename = upload.name || file.name;
|
|
13442
|
+
attachment.sizeBytes = upload.size || file.size;
|
|
13443
|
+
this.logAttachmentLifecycle("attachment_upload_success", {
|
|
13444
|
+
sessionId: context.sessionId,
|
|
13445
|
+
attachmentIndex: context.attachmentIndex,
|
|
13446
|
+
attachmentKey: attachment.clientKey,
|
|
13447
|
+
filename: attachment.filename,
|
|
13448
|
+
uploadId: upload.id,
|
|
13449
|
+
reusedUploadId: false
|
|
13450
|
+
});
|
|
13451
|
+
return upload;
|
|
13452
|
+
} catch (err) {
|
|
13453
|
+
const message = err instanceof Error ? err.message : "Unknown upload error";
|
|
13454
|
+
this.logAttachmentLifecycle("attachment_upload_fail", {
|
|
13455
|
+
sessionId: context.sessionId,
|
|
13456
|
+
attachmentIndex: context.attachmentIndex,
|
|
13457
|
+
attachmentKey: attachment.clientKey,
|
|
13458
|
+
filename: file.name,
|
|
13459
|
+
error: message
|
|
13460
|
+
});
|
|
13461
|
+
throw new Error(`Attachment "${attachment.filename}" upload failed: ${message}`);
|
|
13462
|
+
}
|
|
12742
13463
|
}
|
|
12743
13464
|
async callRPC(method, params) {
|
|
12744
13465
|
return this.rpc.callTyped(method, params);
|
|
@@ -12849,16 +13570,21 @@ var HttpDataSource = class {
|
|
|
12849
13570
|
let connectionTimedOut = false;
|
|
12850
13571
|
try {
|
|
12851
13572
|
const uploads = await Promise.all(
|
|
12852
|
-
attachments.map(
|
|
13573
|
+
attachments.map(
|
|
13574
|
+
(attachment, attachmentIndex) => this.ensureAttachmentUpload(attachment, { sessionId, attachmentIndex })
|
|
13575
|
+
)
|
|
12853
13576
|
);
|
|
13577
|
+
const streamAttachments = this.assertUploadReferences(uploads);
|
|
13578
|
+
this.logAttachmentLifecycle("stream_send_with_upload_ids", {
|
|
13579
|
+
sessionId,
|
|
13580
|
+
attachmentCount: streamAttachments.length
|
|
13581
|
+
});
|
|
12854
13582
|
const payload = {
|
|
12855
13583
|
sessionId,
|
|
12856
13584
|
content,
|
|
12857
13585
|
debugMode: options?.debugMode ?? false,
|
|
12858
13586
|
replaceFromMessageId: options?.replaceFromMessageID,
|
|
12859
|
-
attachments:
|
|
12860
|
-
uploadId: upload.id
|
|
12861
|
-
}))
|
|
13587
|
+
attachments: streamAttachments
|
|
12862
13588
|
};
|
|
12863
13589
|
const timeoutMs = this.config.timeout ?? 0;
|
|
12864
13590
|
if (timeoutMs > 0) {
|
|
@@ -13027,6 +13753,6 @@ function createHttpDataSource(config) {
|
|
|
13027
13753
|
return new HttpDataSource(config);
|
|
13028
13754
|
}
|
|
13029
13755
|
|
|
13030
|
-
export { ATTACHMENT_ACCEPT_ATTRIBUTE, ActionButton, Alert_default as Alert, AllChatsList, ArchiveBanner_default as ArchiveBanner, ArchivedChatList, AssistantMessage, AssistantTurnView, MemoizedAttachmentGrid as AttachmentGrid, AttachmentPreview_default as AttachmentPreview, AttachmentUpload_default as AttachmentUpload, Avatar, BiChatLayout, Bubble, CHART_VISUAL, ChartCard, ChatHeader, ChatMachine, ChatSession, ChatSessionProvider, MemoizedCodeBlock as CodeBlock, CodeOutputsPanel, CompactionDoodle, ConfigProvider, ConfirmModal, ConfirmationStep, DateGroupHeader, DebugPanel, DefaultErrorContent, DownloadCard, MemoizedEditableText as EditableText, MemoizedEmptyState as EmptyState, ErrorBoundary, HttpDataSource, ImageModal, InlineQuestionForm, IotaContextProvider, ListItemSkeleton, MemoizedLoadingSpinner as LoadingSpinner, MemoizedMarkdownRenderer as MarkdownRenderer, MessageActions, MessageInput, MessageList, MessageRole, PermissionGuard, QuestionForm, QuestionStep, RateLimiter, RetryActionArea, ScreenReaderAnnouncer, ScrollToBottomButton, MemoizedSearchInput as SearchInput, SessionArtifactList, SessionArtifactPreview, SessionArtifactsPanel, SessionItem_default as SessionItem, SessionSkeleton, Sidebar2 as Sidebar, MemoizedSkeleton as Skeleton, SkeletonAvatar, SkeletonCard, SkeletonGroup, SkeletonText, SkipLink, Slot, SourcesPanel, StreamError, StreamingCursor, SystemMessage, TableExportButton, TableWithExport, ThemeProvider, Toast, ToastContainer, TouchContextMenu, Turn, TurnBubble, MemoizedTypingIndicator as TypingIndicator, MemoizedUserAvatar as UserAvatar, MemoizedUserFilter as UserFilter, UserMessage, UserTurnView, WelcomeContent, addCSRFHeader, backdropVariants, buttonVariants, convertToBase64, createDataUrl, createHeadersWithCSRF, createHttpDataSource, darkTheme, dropdownVariants, errorMessageVariants, fadeInUpVariants, fadeInVariants, floatingButtonVariants, formatFileSize, getCSRFToken, getFileVisual, getValidChildren, groupSessionsByDate, hasPermission, isImageMimeType, isPermissionDeniedError, lightTheme, listItemVariants, messageContainerVariants, messageVariants, parseBichatStream, parseBichatStreamEvents, parseSSEStream, scaleFadeVariants, sessionItemVariants, staggerContainerVariants, toErrorDisplay, typingDotVariants, useActionButtonContext, useAttachments, useAutoScroll, useAvatarContext, useBubbleContext, useChatInput, useChatMessaging, useChatSession, useConfig, useFocusTrap, useImageGallery, useIotaContext, useKeyboardShortcuts, useLongPress, useMarkdownCopy, useMessageActions, useModalLock, useOptionalChatMessaging, useRequiredConfig, useScrollToBottom, useSidebarState, useStreaming, useTheme, useToast, useTranslation, useTurnContext, validateAttachmentFile, validateFileCount, validateImageFile, verbTransitionVariants };
|
|
13756
|
+
export { ATTACHMENT_ACCEPT_ATTRIBUTE, ActionButton, Alert_default as Alert, AllChatsList, ArchiveBanner_default as ArchiveBanner, ArchivedChatList, AssistantMessage, AssistantTurnView, MemoizedAttachmentGrid as AttachmentGrid, AttachmentPreview_default as AttachmentPreview, AttachmentUpload_default as AttachmentUpload, Avatar, BiChatLayout, Bubble, CHART_VISUAL, ChartCard, ChatHeader, ChatMachine, ChatSession, ChatSessionProvider, MemoizedCodeBlock as CodeBlock, CodeOutputsPanel, CompactionDoodle, ConfigProvider, ConfirmModal, ConfirmationStep, DateGroupHeader, DebugPanel, DefaultErrorContent, DownloadCard, MemoizedEditableText as EditableText, MemoizedEmptyState as EmptyState, ErrorBoundary, HttpDataSource, ImageModal, InlineQuestionForm, InteractiveTableCard, IotaContextProvider, ListItemSkeleton, MemoizedLoadingSpinner as LoadingSpinner, MemoizedMarkdownRenderer as MarkdownRenderer, MessageActions, MessageInput, MessageList, MessageRole, PermissionGuard, QuestionForm, QuestionStep, RateLimiter, RetryActionArea, ScreenReaderAnnouncer, ScrollToBottomButton, MemoizedSearchInput as SearchInput, SessionArtifactList, SessionArtifactPreview, SessionArtifactsPanel, SessionItem_default as SessionItem, SessionSkeleton, Sidebar2 as Sidebar, MemoizedSkeleton as Skeleton, SkeletonAvatar, SkeletonCard, SkeletonGroup, SkeletonText, SkipLink, Slot, SourcesPanel, StreamError, StreamingCursor, SystemMessage, TableExportButton, TableWithExport, ThemeProvider, Toast, ToastContainer, TouchContextMenu, Turn, TurnBubble, MemoizedTypingIndicator as TypingIndicator, MemoizedUserAvatar as UserAvatar, MemoizedUserFilter as UserFilter, UserMessage, UserTurnView, WelcomeContent, addCSRFHeader, backdropVariants, buttonVariants, convertToBase64, createDataUrl, createHeadersWithCSRF, createHttpDataSource, darkTheme, dropdownVariants, errorMessageVariants, fadeInUpVariants, fadeInVariants, floatingButtonVariants, formatFileSize, getCSRFToken, getFileVisual, getValidChildren, groupSessionsByDate, hasPermission, isImageMimeType, isPermissionDeniedError, lightTheme, listItemVariants, messageContainerVariants, messageVariants, parseBichatStream, parseBichatStreamEvents, parseSSEStream, scaleFadeVariants, sessionItemVariants, staggerContainerVariants, toErrorDisplay, typingDotVariants, useActionButtonContext, useAttachments, useAutoScroll, useAvatarContext, useBubbleContext, useChatInput, useChatMessaging, useChatSession, useConfig, useFocusTrap, useImageGallery, useIotaContext, useKeyboardShortcuts, useLongPress, useMarkdownCopy, useMessageActions, useModalLock, useOptionalChatMessaging, useRequiredConfig, useScrollToBottom, useSidebarState, useStreaming, useTheme, useToast, useTranslation, useTurnContext, validateAttachmentFile, validateFileCount, validateImageFile, verbTransitionVariants };
|
|
13031
13757
|
//# sourceMappingURL=index.mjs.map
|
|
13032
13758
|
//# sourceMappingURL=index.mjs.map
|