@paymanai/payman-ask-sdk 4.0.20 → 4.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
- import { createContext, forwardRef, useCallback, useRef, useState, useImperativeHandle, useEffect, useContext, useMemo, useLayoutEffect, Children, isValidElement } from 'react';
1
+ import { createContext, forwardRef, useCallback, useRef, useState, useMemo, useEffect, useImperativeHandle, useLayoutEffect, useContext } from 'react';
2
2
  import { AnimatePresence, motion } from 'framer-motion';
3
3
  import { clsx } from 'clsx';
4
4
  import { twMerge } from 'tailwind-merge';
5
5
  import * as Sentry from '@sentry/react';
6
- import { ArrowDown, Loader2, FileText, X, Pencil, RotateCcw, Telescope, Zap, Plus, ImagePlus, Paperclip, Mic, ArrowUp, Check, AlertCircle, Copy, WifiOff, ThumbsUp, ThumbsDown, Binoculars, Info, Download, ChevronDown, RefreshCw, ExternalLink, User, Clock, Sparkles, ImageOff, Eye, ChevronRight, ShieldCheck } from 'lucide-react';
6
+ import { ArrowDown, Pencil, X, RotateCcw, Telescope, Zap, Plus, ImagePlus, Paperclip, Mic, ArrowUp, Check, AlertCircle, Copy, WifiOff, ThumbsUp, ThumbsDown, Binoculars, Info, Download, Loader2, ChevronDown, User, Clock, Sparkles, ImageOff, Eye, ChevronRight, ShieldCheck } from 'lucide-react';
7
7
  import ReactMarkdown from 'react-markdown';
8
8
  import remarkGfm from 'remark-gfm';
9
9
  import { createPortal } from 'react-dom';
@@ -13,10 +13,7 @@ import { DotLottieReact } from '@lottiefiles/dotlottie-react';
13
13
 
14
14
  var __defProp = Object.defineProperty;
15
15
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
16
- var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
17
- var __defProp2 = Object.defineProperty;
18
- var __defNormalProp2 = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
19
- var __publicField2 = (obj, key, value) => __defNormalProp2(obj, key + "", value);
16
+ var __publicField = (obj, key, value) => __defNormalProp(obj, key + "", value);
20
17
  function generateId() {
21
18
  return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
22
19
  const r = Math.random() * 16 | 0;
@@ -1127,7 +1124,7 @@ async function uploadAttachments(config, files, signal) {
1127
1124
  var UserActionStaleError = class extends Error {
1128
1125
  constructor(userActionId, message = "User action is no longer actionable") {
1129
1126
  super(message);
1130
- __publicField2(this, "userActionId");
1127
+ __publicField(this, "userActionId");
1131
1128
  this.name = "UserActionStaleError";
1132
1129
  this.userActionId = userActionId;
1133
1130
  }
@@ -1808,102 +1805,6 @@ function useVoice(config = {}, callbacks = {}) {
1808
1805
  reset
1809
1806
  };
1810
1807
  }
1811
- function useAttachmentUpload(config) {
1812
- const configRef = useRef(config);
1813
- configRef.current = config;
1814
- const [entries, setEntries] = useState(/* @__PURE__ */ new Map());
1815
- const [orderedIds, setOrderedIds] = useState([]);
1816
- const abortControllersRef = useRef(/* @__PURE__ */ new Map());
1817
- const activeIdsRef = useRef(/* @__PURE__ */ new Set());
1818
- const startUpload = useCallback((id, file) => {
1819
- if (activeIdsRef.current.has(id)) return;
1820
- activeIdsRef.current.add(id);
1821
- const controller = new AbortController();
1822
- abortControllersRef.current.set(id, controller);
1823
- setEntries((prev) => {
1824
- const next = new Map(prev);
1825
- next.set(id, { id, status: "uploading" });
1826
- return next;
1827
- });
1828
- void uploadAttachment(configRef.current, file, controller.signal).then((payload) => {
1829
- if (controller.signal.aborted) return;
1830
- setEntries((prev) => {
1831
- const next = new Map(prev);
1832
- next.set(id, { id, status: "done", payload });
1833
- return next;
1834
- });
1835
- }).catch((error) => {
1836
- if (error.name === "AbortError") return;
1837
- setEntries((prev) => {
1838
- const next = new Map(prev);
1839
- next.set(id, {
1840
- id,
1841
- status: "error",
1842
- error: error.message || "Upload failed"
1843
- });
1844
- return next;
1845
- });
1846
- }).finally(() => {
1847
- abortControllersRef.current.delete(id);
1848
- });
1849
- }, []);
1850
- const syncAttachments = useCallback(
1851
- (attachments) => {
1852
- const nextIds = attachments.map((attachment) => attachment.id);
1853
- setOrderedIds(nextIds);
1854
- const nextIdSet = new Set(nextIds);
1855
- for (const id of activeIdsRef.current) {
1856
- if (nextIdSet.has(id)) continue;
1857
- abortControllersRef.current.get(id)?.abort();
1858
- abortControllersRef.current.delete(id);
1859
- activeIdsRef.current.delete(id);
1860
- }
1861
- setEntries((prev) => {
1862
- const next = new Map(prev);
1863
- for (const id of next.keys()) {
1864
- if (!nextIdSet.has(id)) next.delete(id);
1865
- }
1866
- return next;
1867
- });
1868
- for (const attachment of attachments) {
1869
- startUpload(attachment.id, attachment.file);
1870
- }
1871
- },
1872
- [startUpload]
1873
- );
1874
- const clearAll = useCallback(() => {
1875
- for (const controller of abortControllersRef.current.values()) {
1876
- controller.abort();
1877
- }
1878
- abortControllersRef.current.clear();
1879
- activeIdsRef.current.clear();
1880
- setOrderedIds([]);
1881
- setEntries(/* @__PURE__ */ new Map());
1882
- }, []);
1883
- const entryList = useMemo(
1884
- () => orderedIds.map((id) => entries.get(id)).filter((entry) => entry != null),
1885
- [entries, orderedIds]
1886
- );
1887
- const isUploading = entryList.some((entry) => entry.status === "uploading");
1888
- const hasErrors = entryList.some((entry) => entry.status === "error");
1889
- const allReady = orderedIds.length === 0 || orderedIds.every((id) => entries.get(id)?.status === "done");
1890
- const payloads = entryList.filter((entry) => entry.status === "done" && entry.payload).map((entry) => entry.payload);
1891
- const statusById = useMemo(
1892
- () => Object.fromEntries(
1893
- entryList.map((entry) => [entry.id, entry.status])
1894
- ),
1895
- [entryList]
1896
- );
1897
- return {
1898
- syncAttachments,
1899
- clearAll,
1900
- isUploading,
1901
- hasErrors,
1902
- allReady,
1903
- payloads,
1904
- statusById
1905
- };
1906
- }
1907
1808
  function classifyField(field) {
1908
1809
  if (!field) return "text";
1909
1810
  if (Array.isArray(field.oneOf) && field.oneOf.length > 0) return "select";
@@ -2020,66 +1921,6 @@ function buildContent(schema, values) {
2020
1921
  }
2021
1922
  return content;
2022
1923
  }
2023
- var ATTACHMENTS_SUFFIX_RE = /\n\n\[Attachments:[^\]]*\]\s*$/;
2024
- function stripAttachmentsSuffixFromIntent(intent) {
2025
- return intent.replace(ATTACHMENTS_SUFFIX_RE, "").trimEnd();
2026
- }
2027
- function mapFeedback(feedback) {
2028
- if (!feedback?.feedback) return null;
2029
- return feedback.feedback === "POSITIVE" ? "up" : "down";
2030
- }
2031
- function mapHistoryAttachments(executionId, attachments) {
2032
- const mapped = (attachments ?? []).map((attachment, index) => ({
2033
- id: `${executionId}:att:${index}`,
2034
- filename: attachment.filename,
2035
- mimeType: attachment.mimeType,
2036
- url: attachment.url ?? void 0,
2037
- kind: attachment.mimeType.startsWith("image/") ? "image" : "file"
2038
- }));
2039
- return mapped.length > 0 ? mapped : void 0;
2040
- }
2041
- function mapExecutionHistoryToChatMessages(message) {
2042
- const timestamp = message.startTime || message.endTime || (/* @__PURE__ */ new Date()).toISOString();
2043
- const executionId = message.executionId ?? message.traceId ?? message.id;
2044
- const attachments = mapHistoryAttachments(message.id, message.attachments);
2045
- const rows = [
2046
- {
2047
- id: `${message.id}:user`,
2048
- role: "user",
2049
- content: stripAttachmentsSuffixFromIntent(message.sessionUserIntent),
2050
- timestamp,
2051
- attachments
2052
- }
2053
- ];
2054
- if (message.agentResponse) {
2055
- rows.push({
2056
- id: `${message.id}:assistant`,
2057
- role: "assistant",
2058
- content: message.agentResponse,
2059
- timestamp: message.endTime || timestamp,
2060
- isError: message.status === "FAILED",
2061
- executionId,
2062
- feedback: mapFeedback(message.feedback)
2063
- });
2064
- }
2065
- return rows;
2066
- }
2067
- function mapExecutionHistoryPageToChatMessages(messages) {
2068
- return messages.flatMap(mapExecutionHistoryToChatMessages);
2069
- }
2070
- function attachmentDisplayUrl(attachment) {
2071
- return attachment.previewUrl ?? attachment.url;
2072
- }
2073
- function isImageAttachment(attachment) {
2074
- const displayUrl = attachmentDisplayUrl(attachment);
2075
- return attachment.kind === "image" || Boolean(displayUrl) && attachment.mimeType.startsWith("image/");
2076
- }
2077
- function isPdfAttachmentMeta(attachment) {
2078
- return attachment.mimeType === "application/pdf" || /\.pdf$/i.test(attachment.filename);
2079
- }
2080
- function isPdfFile(file) {
2081
- return file.type === "application/pdf" || /\.pdf$/i.test(file.name);
2082
- }
2083
1924
  var PaymanChatContext = createContext(void 0);
2084
1925
  function usePaymanChat() {
2085
1926
  const context = useContext(PaymanChatContext);
@@ -2190,111 +2031,6 @@ function subscribeToCfRay(urlPattern, listener) {
2190
2031
  };
2191
2032
  }
2192
2033
 
2193
- // src/utils/attachmentConfig.ts
2194
- var DEFAULT_IMAGE_EXTENSIONS = ["png", "jpg", "jpeg", "gif", "webp"];
2195
- var DEFAULT_DOCUMENT_EXTENSIONS = ["pdf", "docx", "xlsx", "xls"];
2196
- function resolveChatAttachmentConfig(config) {
2197
- const nested = config.attachments;
2198
- const enabled = nested?.enabled ?? config.showAttachmentButton ?? true;
2199
- const uploadImage = nested?.uploadImage ?? config.showUploadImageButton ?? true;
2200
- const attachFile = nested?.attachFile ?? config.showAttachFileButton ?? true;
2201
- return {
2202
- showAttachmentButton: enabled && (uploadImage || attachFile),
2203
- showUploadImageButton: enabled && uploadImage,
2204
- showAttachFileButton: enabled && attachFile,
2205
- maxCount: nested?.maxCount ?? nested?.maxImages ?? nested?.maxDocuments,
2206
- maxFileBytes: nested?.maxFileBytes,
2207
- maxTotalBytes: nested?.maxTotalBytes,
2208
- allowedImageExtensions: nested?.imageExtensions ?? DEFAULT_IMAGE_EXTENSIONS,
2209
- allowedFileExtensions: nested?.documentExtensions ?? DEFAULT_DOCUMENT_EXTENSIONS
2210
- };
2211
- }
2212
-
2213
- // src/utils/formatAttachmentBytes.ts
2214
- function formatAttachmentBytes(bytes) {
2215
- if (!Number.isFinite(bytes) || bytes <= 0) return "0 B";
2216
- const units = ["B", "KB", "MB", "GB"];
2217
- let value = bytes;
2218
- let unitIndex = 0;
2219
- while (value >= 1024 && unitIndex < units.length - 1) {
2220
- value /= 1024;
2221
- unitIndex += 1;
2222
- }
2223
- const rounded = unitIndex === 0 ? String(Math.round(value)) : value >= 10 ? value.toFixed(0) : value.toFixed(1).replace(/\.0$/, "");
2224
- return `${rounded} ${units[unitIndex]}`;
2225
- }
2226
-
2227
- // src/utils/pdfLink.ts
2228
- function filenameFromContentDisposition(value) {
2229
- if (!value) return void 0;
2230
- let decoded = value;
2231
- try {
2232
- decoded = decodeURIComponent(value);
2233
- } catch {
2234
- decoded = value;
2235
- }
2236
- const quoted = decoded.match(/filename\*=(?:UTF-8''([^;]+)|"([^"]+)")/i);
2237
- if (quoted?.[1] || quoted?.[2]) {
2238
- return (quoted[1] ?? quoted[2])?.trim();
2239
- }
2240
- const unquoted = decoded.match(/filename=([^;]+)/i);
2241
- return unquoted?.[1]?.replace(/"/g, "").trim();
2242
- }
2243
- function filenameFromUrlPath(href) {
2244
- try {
2245
- const parts = new URL(href).pathname.split("/").filter(Boolean);
2246
- const last = parts[parts.length - 1];
2247
- return last ? decodeURIComponent(last) : void 0;
2248
- } catch {
2249
- return void 0;
2250
- }
2251
- }
2252
- function isPdfUrl(href) {
2253
- if (!href) return false;
2254
- const lower = href.toLowerCase();
2255
- if (lower.includes(".pdf")) return true;
2256
- try {
2257
- const url = new URL(href);
2258
- if (url.pathname.toLowerCase().endsWith(".pdf")) return true;
2259
- const filename = url.searchParams.get("filename");
2260
- if (filename?.toLowerCase().includes(".pdf")) return true;
2261
- for (const key of ["rscd", "response-content-disposition"]) {
2262
- const fromDisposition = filenameFromContentDisposition(
2263
- url.searchParams.get(key)
2264
- );
2265
- if (fromDisposition?.toLowerCase().includes(".pdf")) return true;
2266
- }
2267
- } catch {
2268
- return lower.endsWith(".pdf");
2269
- }
2270
- return false;
2271
- }
2272
- function getPdfTitleFromUrl(href, linkText) {
2273
- const text = linkText?.trim();
2274
- if (text) return text;
2275
- try {
2276
- const url = new URL(href);
2277
- const filename = url.searchParams.get("filename");
2278
- if (filename) {
2279
- return filename.replace(/\.pdf$/i, "").replace(/[-_]+/g, " ").trim();
2280
- }
2281
- for (const key of ["rscd", "response-content-disposition"]) {
2282
- const fromDisposition = filenameFromContentDisposition(
2283
- url.searchParams.get(key)
2284
- );
2285
- if (fromDisposition) {
2286
- return fromDisposition.replace(/\.pdf$/i, "").replace(/[-_]+/g, " ").trim();
2287
- }
2288
- }
2289
- } catch {
2290
- }
2291
- const fromPath = filenameFromUrlPath(href);
2292
- if (fromPath) {
2293
- return fromPath.replace(/\.pdf$/i, "").replace(/[-_]+/g, " ").trim();
2294
- }
2295
- return "Document";
2296
- }
2297
-
2298
2034
  // src/utils/slashCommands.ts
2299
2035
  var DEFAULT_SLASH_COMMANDS = [
2300
2036
  {
@@ -3446,108 +3182,6 @@ function ActionTooltipV2({ label, children }) {
3446
3182
  ] }) })
3447
3183
  ] });
3448
3184
  }
3449
- function FilePreviewShell({
3450
- filename,
3451
- typeLabel,
3452
- onClick,
3453
- thumbnail,
3454
- className,
3455
- "aria-label": ariaLabel
3456
- }) {
3457
- const shellClass = cn(
3458
- "payman-v2-file-preview-shell",
3459
- "payman-v2-file-preview-shell-sent",
3460
- onClick && "payman-v2-file-preview-shell-clickable",
3461
- className
3462
- );
3463
- const body = /* @__PURE__ */ jsxs(Fragment, { children: [
3464
- /* @__PURE__ */ jsx("div", { className: "payman-v2-file-preview-thumb", children: thumbnail ?? /* @__PURE__ */ jsx(
3465
- FileText,
3466
- {
3467
- size: 16,
3468
- strokeWidth: 1.75,
3469
- className: "payman-v2-file-preview-doc-icon"
3470
- }
3471
- ) }),
3472
- /* @__PURE__ */ jsxs("div", { className: "payman-v2-file-preview-info", children: [
3473
- /* @__PURE__ */ jsx("span", { className: "payman-v2-file-preview-name", children: filename }),
3474
- /* @__PURE__ */ jsx("span", { className: "payman-v2-file-preview-type", children: typeLabel })
3475
- ] })
3476
- ] });
3477
- if (onClick) {
3478
- return /* @__PURE__ */ jsx(
3479
- "button",
3480
- {
3481
- type: "button",
3482
- className: shellClass,
3483
- onClick,
3484
- "aria-label": ariaLabel ?? `Open ${filename}`,
3485
- children: body
3486
- }
3487
- );
3488
- }
3489
- return /* @__PURE__ */ jsx("div", { className: shellClass, children: body });
3490
- }
3491
- function FilePreviewBlockLayout({
3492
- children,
3493
- className,
3494
- ...rest
3495
- }) {
3496
- return /* @__PURE__ */ jsx("div", { className: cn("payman-v2-file-preview-item", className), ...rest, children });
3497
- }
3498
- function attachmentTypeLabel(attachment) {
3499
- if (isImageAttachment(attachment)) {
3500
- return "Image";
3501
- }
3502
- const ext = attachment.filename.split(".").pop()?.toUpperCase();
3503
- return ext || "Document";
3504
- }
3505
- function isPdfAttachment(attachment) {
3506
- const displayUrl = attachmentDisplayUrl(attachment);
3507
- return isPdfAttachmentMeta(attachment) || Boolean(displayUrl) && isPdfUrl(displayUrl);
3508
- }
3509
- function AttachmentPreviewBlock({
3510
- attachment,
3511
- onImageClick
3512
- }) {
3513
- const chatContext = useContext(PaymanChatContext);
3514
- const displayUrl = attachmentDisplayUrl(attachment);
3515
- const typeLabel = attachmentTypeLabel(attachment);
3516
- const isImage = isImageAttachment(attachment) && displayUrl;
3517
- const openAttachment = () => {
3518
- if (!displayUrl) return;
3519
- if (isImageAttachment(attachment)) {
3520
- onImageClick?.(displayUrl, attachment.filename);
3521
- return;
3522
- }
3523
- if (isPdfAttachment(attachment)) {
3524
- chatContext?.openPdfSheet(displayUrl, attachment.filename);
3525
- return;
3526
- }
3527
- window.open(displayUrl, "_blank", "noopener,noreferrer");
3528
- };
3529
- if (isImage) {
3530
- return /* @__PURE__ */ jsx(FilePreviewBlockLayout, { children: /* @__PURE__ */ jsx(
3531
- FilePreviewShell,
3532
- {
3533
- filename: attachment.filename,
3534
- typeLabel,
3535
- onClick: openAttachment,
3536
- "aria-label": `Preview ${attachment.filename}`,
3537
- thumbnail: /* @__PURE__ */ jsx("img", { src: displayUrl, alt: "", draggable: false })
3538
- }
3539
- ) });
3540
- }
3541
- return /* @__PURE__ */ jsx(FilePreviewBlockLayout, { children: /* @__PURE__ */ jsx(
3542
- FilePreviewShell,
3543
- {
3544
- filename: attachment.filename,
3545
- typeLabel,
3546
- onClick: displayUrl ? openAttachment : void 0,
3547
- "aria-label": `Open ${attachment.filename}`
3548
- }
3549
- ) });
3550
- }
3551
3185
  function formatMessageTime(timestamp) {
3552
3186
  const value = new Date(timestamp);
3553
3187
  if (Number.isNaN(value.getTime())) return "";
@@ -3560,7 +3194,6 @@ function UserMessageV2({
3560
3194
  message,
3561
3195
  onEdit,
3562
3196
  onRetry,
3563
- onImageClick,
3564
3197
  retryDisabled = false,
3565
3198
  actions
3566
3199
  }) {
@@ -3643,15 +3276,7 @@ function UserMessageV2({
3643
3276
  return /* @__PURE__ */ jsxs(Fragment, { children: [
3644
3277
  toastPortal,
3645
3278
  /* @__PURE__ */ jsx("div", { className: "payman-v2-user-msg payman-v2-fade-in", children: /* @__PURE__ */ jsxs("div", { className: "payman-v2-user-msg-group", children: [
3646
- message.attachments && message.attachments.length > 0 && /* @__PURE__ */ jsx("div", { className: "payman-v2-file-preview payman-v2-user-msg-attachments", children: message.attachments.map((attachment) => /* @__PURE__ */ jsx(
3647
- AttachmentPreviewBlock,
3648
- {
3649
- attachment,
3650
- onImageClick
3651
- },
3652
- attachment.id
3653
- )) }),
3654
- (message.content.trim().length > 0 || !message.attachments?.length) && /* @__PURE__ */ jsx("div", { className: "payman-v2-user-msg-bubble", children: parsedCommand ? /* @__PURE__ */ jsxs("div", { className: "payman-v2-user-msg-command", children: [
3279
+ /* @__PURE__ */ jsx("div", { className: "payman-v2-user-msg-bubble", children: parsedCommand ? /* @__PURE__ */ jsxs("div", { className: "payman-v2-user-msg-command", children: [
3655
3280
  /* @__PURE__ */ jsx("span", { className: "payman-v2-user-msg-command-chip", children: parsedCommand.command }),
3656
3281
  parsedCommand.body.trim() ? /* @__PURE__ */ jsx("p", { className: "payman-v2-user-msg-text", children: parsedCommand.body }) : null
3657
3282
  ] }) : /* @__PURE__ */ jsx("p", { className: "payman-v2-user-msg-text", children: message.content }) }),
@@ -3876,44 +3501,9 @@ function MarkdownImageV2({
3876
3501
  }
3877
3502
  ) });
3878
3503
  }
3879
- function PdfBlockV2({ title, href, onOpen, autoOpen = false }) {
3880
- const autoOpenedHrefRef = useRef(null);
3881
- useEffect(() => {
3882
- if (!autoOpen || autoOpenedHrefRef.current === href) return;
3883
- autoOpenedHrefRef.current = href;
3884
- onOpen(href, title, { auto: true });
3885
- }, [href, autoOpen]);
3886
- return /* @__PURE__ */ jsx(FilePreviewBlockLayout, { "data-payman-file-block": true, children: /* @__PURE__ */ jsx(
3887
- FilePreviewShell,
3888
- {
3889
- filename: title,
3890
- typeLabel: "PDF",
3891
- onClick: () => onOpen(href, title),
3892
- "aria-label": `Open PDF: ${title}`
3893
- }
3894
- ) });
3895
- }
3896
- function childrenToText(children) {
3897
- if (typeof children === "string") return children;
3898
- if (typeof children === "number") return String(children);
3899
- if (Array.isArray(children)) return children.map(childrenToText).join("");
3900
- if (children && typeof children === "object" && "props" in children) {
3901
- return childrenToText(children.props.children);
3902
- }
3903
- return "";
3904
- }
3905
- function isFileBlockChild(child) {
3906
- return isValidElement(child) && typeof child.props === "object" && child.props !== null && "data-payman-file-block" in child.props;
3907
- }
3908
- function buildComponents(onImageClick, isResolvingRef, onPdfClick, autoOpenPdf) {
3504
+ function buildComponents(onImageClick, isResolvingRef) {
3909
3505
  return {
3910
- p: ({ children }) => {
3911
- const childArray = Children.toArray(children);
3912
- if (childArray.length === 1 && isFileBlockChild(childArray[0])) {
3913
- return childArray[0];
3914
- }
3915
- return /* @__PURE__ */ jsx("p", { children });
3916
- },
3506
+ p: ({ children }) => /* @__PURE__ */ jsx("p", { children }),
3917
3507
  code: ({ children }) => /* @__PURE__ */ jsx("code", { children }),
3918
3508
  pre: ({ children }) => /* @__PURE__ */ jsx("div", { className: "payman-v2-markdown-pre", children: /* @__PURE__ */ jsx("pre", { children }) }),
3919
3509
  ul: ({ children }) => /* @__PURE__ */ jsx("ul", { children }),
@@ -3926,15 +3516,7 @@ function buildComponents(onImageClick, isResolvingRef, onPdfClick, autoOpenPdf)
3926
3516
  em: ({ children }) => /* @__PURE__ */ jsx("em", { children }),
3927
3517
  blockquote: ({ children }) => /* @__PURE__ */ jsx("blockquote", { children }),
3928
3518
  hr: () => /* @__PURE__ */ jsx("hr", {}),
3929
- a: ({ href, children }) => {
3930
- const url = href ?? "";
3931
- if (onPdfClick && isPdfUrl(url)) {
3932
- const linkText = childrenToText(children).trim();
3933
- const title = getPdfTitleFromUrl(url, linkText);
3934
- return /* @__PURE__ */ jsx(PdfBlockV2, { href: url, title, onOpen: onPdfClick, autoOpen: autoOpenPdf });
3935
- }
3936
- return /* @__PURE__ */ jsx("a", { href, target: "_blank", rel: "noopener noreferrer", children });
3937
- },
3519
+ a: ({ href, children }) => /* @__PURE__ */ jsx("a", { href, target: "_blank", rel: "noopener noreferrer", children }),
3938
3520
  img: ({ src, alt }) => /* @__PURE__ */ jsx(
3939
3521
  MarkdownImageV2,
3940
3522
  {
@@ -3955,15 +3537,13 @@ function MarkdownRendererV2({
3955
3537
  content,
3956
3538
  isStreaming,
3957
3539
  isResolvingImages,
3958
- onImageClick,
3959
- onPdfClick,
3960
- autoOpenPdf
3540
+ onImageClick
3961
3541
  }) {
3962
3542
  const isResolvingRef = useRef(isResolvingImages);
3963
3543
  isResolvingRef.current = isResolvingImages;
3964
3544
  const components = useMemo(
3965
- () => buildComponents(onImageClick, isResolvingRef, onPdfClick, autoOpenPdf),
3966
- [onImageClick, onPdfClick, autoOpenPdf]
3545
+ () => buildComponents(onImageClick, isResolvingRef),
3546
+ [onImageClick]
3967
3547
  );
3968
3548
  return /* @__PURE__ */ jsx(
3969
3549
  "div",
@@ -4332,17 +3912,6 @@ function stripIncompleteImageToken(text) {
4332
3912
  if (/^!\[[^\]]*\]\([^)]*\)/.test(after)) return text;
4333
3913
  return text.slice(0, lastBang);
4334
3914
  }
4335
- function stripIncompleteLinkToken(text) {
4336
- const lastBracket = text.lastIndexOf("[");
4337
- if (lastBracket === -1) return text;
4338
- if (lastBracket > 0 && text[lastBracket - 1] === "!") return text;
4339
- const after = text.slice(lastBracket);
4340
- if (/^\[[^\]]*\]\([^)]*\)/.test(after)) return text;
4341
- return text.slice(0, lastBracket);
4342
- }
4343
- function stripIncompleteMarkdownTokens(text) {
4344
- return stripIncompleteLinkToken(stripIncompleteImageToken(text));
4345
- }
4346
3915
  function getFeedbackState(message) {
4347
3916
  const feedback = message.feedback;
4348
3917
  if (feedback === "up" || feedback === "down") return feedback;
@@ -4366,12 +3935,6 @@ function AssistantMessageV2({
4366
3935
  () => getFeedbackState(message)
4367
3936
  );
4368
3937
  const [reasonModalOpen, setReasonModalOpen] = useState(false);
4369
- const chatContext = useContext(PaymanChatContext);
4370
- const chatContextRef = useRef(chatContext);
4371
- chatContextRef.current = chatContext;
4372
- const handlePdfClick = useCallback((href, title, options) => {
4373
- chatContextRef.current?.openPdfSheet(href, title, options);
4374
- }, []);
4375
3938
  const canSubmitFeedback = !!onSubmitFeedback && !!message.executionId;
4376
3939
  const [toast, setToast] = useState(null);
4377
3940
  const copyResetTimerRef = useRef(null);
@@ -4396,7 +3959,7 @@ function AssistantMessageV2({
4396
3959
  const raw = message.isStreaming ? message.streamingContent || message.content : message.content;
4397
3960
  if (!raw) return "";
4398
3961
  const normalized = raw.replace(/\\n/g, "\n");
4399
- return message.isStreaming ? stripIncompleteMarkdownTokens(normalized) : normalized;
3962
+ return message.isStreaming ? stripIncompleteImageToken(normalized) : normalized;
4400
3963
  })();
4401
3964
  const isThinkingStreaming = !!message.isStreaming && !rawResponseContent && !message.isError;
4402
3965
  const responseTypingEnabled = hasEverStreamed.current && Boolean(rawResponseContent) && !message.isError;
@@ -4566,12 +4129,10 @@ function AssistantMessageV2({
4566
4129
  /* @__PURE__ */ jsx("div", { className: "payman-v2-assistant-msg-content-area", children: displayContent ? /* @__PURE__ */ jsx(
4567
4130
  MarkdownRendererV2,
4568
4131
  {
4569
- content: message.isStreaming && !isCancelled || isResponseTyping ? stripIncompleteMarkdownTokens(displayContent) : displayContent,
4132
+ content: displayContent,
4570
4133
  isStreaming: message.isStreaming && !isCancelled || isResponseTyping,
4571
4134
  isResolvingImages: message.isResolvingImages,
4572
- onImageClick,
4573
- onPdfClick: handlePdfClick,
4574
- autoOpenPdf: hasEverStreamed.current
4135
+ onImageClick
4575
4136
  }
4576
4137
  ) : !isThinkingStreaming ? /* @__PURE__ */ jsx("span", { className: "payman-v2-assistant-msg-placeholder", children: "..." }) : null }),
4577
4138
  isCancelled && message.isStreaming && /* @__PURE__ */ jsxs("div", { className: "payman-v2-assistant-msg-paused", children: [
@@ -4788,6 +4349,7 @@ function VerificationInline({
4788
4349
  const [code, setCode] = useState("");
4789
4350
  const [errored, setErrored] = useState(false);
4790
4351
  const [resendSec, setResendSec] = useState(0);
4352
+ const [hiddenAfterResend, setHiddenAfterResend] = useState(false);
4791
4353
  const lastSubmittedRef = useRef(null);
4792
4354
  const resendTimerRef = useRef(void 0);
4793
4355
  const status = prompt.status;
@@ -4801,6 +4363,9 @@ function VerificationInline({
4801
4363
  lastSubmittedRef.current = null;
4802
4364
  }
4803
4365
  }, [prompt.subAction, prompt.userActionId]);
4366
+ useEffect(() => {
4367
+ setHiddenAfterResend(false);
4368
+ }, [prompt.expirySeconds, prompt.message, prompt.subAction, prompt.userActionId]);
4804
4369
  useEffect(() => {
4805
4370
  if (code.length < codeLen) lastSubmittedRef.current = null;
4806
4371
  }, [code, codeLen]);
@@ -4851,11 +4416,13 @@ function VerificationInline({
4851
4416
  if (locked || resendSec > 0) return;
4852
4417
  setErrored(false);
4853
4418
  setCode("");
4419
+ setHiddenAfterResend(true);
4854
4420
  lastSubmittedRef.current = null;
4855
4421
  try {
4856
4422
  await onResend(prompt.userActionId);
4857
4423
  startResendCooldown();
4858
4424
  } catch {
4425
+ setHiddenAfterResend(false);
4859
4426
  }
4860
4427
  }, [locked, onResend, prompt.userActionId, resendSec, startResendCooldown]);
4861
4428
  const handleCancel = useCallback(() => {
@@ -4863,6 +4430,7 @@ function VerificationInline({
4863
4430
  void onCancel(prompt.userActionId);
4864
4431
  }, [busy, onCancel, prompt.userActionId]);
4865
4432
  const description = prompt.message?.trim() || (isNumeric ? `Enter the ${codeLen}-digit code to continue` : "Enter the verification code to continue");
4433
+ if (hiddenAfterResend) return null;
4866
4434
  return /* @__PURE__ */ jsxs("div", { className: "payman-v2-ua", role: "group", "aria-label": "Verification required", children: [
4867
4435
  /* @__PURE__ */ jsxs("div", { className: "payman-v2-ua-head", children: [
4868
4436
  /* @__PURE__ */ jsx(ShieldCheck, { className: "payman-v2-ua-icon", size: 15, strokeWidth: 1.75, "aria-hidden": true }),
@@ -4958,6 +4526,9 @@ function SchemaFormInline({
4958
4526
  const busy = status === "submitting";
4959
4527
  const stale = status === "stale";
4960
4528
  const locked = busy || stale || expired;
4529
+ const isUserConfirmation = prompt.subAction === "UserConfirmation";
4530
+ const messageFormat = prompt.metadata?.["payman/messageFormat"];
4531
+ const renderMarkdown = messageFormat === "markdown";
4961
4532
  const setValue = (key, value) => {
4962
4533
  setValues((prev) => ({ ...prev, [key]: value }));
4963
4534
  setErrors((prev) => {
@@ -4983,8 +4554,8 @@ function SchemaFormInline({
4983
4554
  /* @__PURE__ */ jsx("span", { className: "payman-v2-ua-title", children: "Action required" }),
4984
4555
  typeof secondsLeft === "number" && !stale && /* @__PURE__ */ jsx("span", { className: "payman-v2-ua-timer", children: expired ? "Expired" : `${secondsLeft}s` })
4985
4556
  ] }),
4986
- prompt.message?.trim() && /* @__PURE__ */ jsx("p", { className: "payman-v2-ua-desc", children: prompt.message }),
4987
- stale ? /* @__PURE__ */ jsx("p", { className: "payman-v2-ua-stale", children: "This request is no longer available." }) : fields.length === 0 ? /* @__PURE__ */ jsx("p", { className: "payman-v2-ua-desc", children: "This action has no inputs to fill." }) : /* @__PURE__ */ jsx("div", { className: "payman-v2-ua-form", children: fields.map(([key, field]) => {
4557
+ prompt.message?.trim() && (renderMarkdown ? /* @__PURE__ */ jsx("div", { className: "payman-v2-ua-markdown", children: /* @__PURE__ */ jsx(MarkdownRendererV2, { content: prompt.message }) }) : /* @__PURE__ */ jsx("p", { className: "payman-v2-ua-desc", children: prompt.message })),
4558
+ stale ? /* @__PURE__ */ jsx("p", { className: "payman-v2-ua-stale", children: "This request is no longer available." }) : fields.length === 0 ? null : /* @__PURE__ */ jsx("div", { className: "payman-v2-ua-form", children: fields.map(([key, field]) => {
4988
4559
  const widget = classifyField(field);
4989
4560
  const label = field.title || key;
4990
4561
  const required = isRequired(schema, key);
@@ -5057,7 +4628,7 @@ function SchemaFormInline({
5057
4628
  className: "payman-v2-ua-btn payman-v2-ua-btn-primary",
5058
4629
  disabled: locked,
5059
4630
  onClick: handleSubmit,
5060
- children: busy ? "Submitting\u2026" : "Submit"
4631
+ children: busy ? "Submitting\u2026" : isUserConfirmation ? "Confirm" : "Submit"
5061
4632
  }
5062
4633
  ),
5063
4634
  /* @__PURE__ */ jsx(
@@ -5113,10 +4684,25 @@ function useExpiryCountdown(prompt) {
5113
4684
  const expired = initial !== void 0 && secondsLeft === 0;
5114
4685
  return [secondsLeft, expired];
5115
4686
  }
5116
- function UserActionInline({ prompt, onSubmit, onCancel, onResend }) {
4687
+ function UserActionInline({
4688
+ prompt,
4689
+ onSubmit,
4690
+ onCancel,
4691
+ onResend,
4692
+ onExpired
4693
+ }) {
5117
4694
  const [secondsLeft, expired] = useExpiryCountdown(prompt);
4695
+ useEffect(() => {
4696
+ if (expired && prompt.kind !== "notification") onExpired?.();
4697
+ }, [expired, onExpired, prompt.kind]);
5118
4698
  let body;
5119
- if (prompt.kind === "verification") {
4699
+ if (expired && prompt.kind !== "notification") {
4700
+ const note = {
4701
+ id: `${prompt.userActionId}-expired`,
4702
+ message: prompt.kind === "verification" ? "Verification Request Expired" : "User Form Expired"
4703
+ };
4704
+ body = /* @__PURE__ */ jsx(NotificationInline, { notification: note });
4705
+ } else if (prompt.kind === "verification") {
5120
4706
  body = /* @__PURE__ */ jsx(
5121
4707
  VerificationInline,
5122
4708
  {
@@ -5156,10 +4742,23 @@ function UserActionInline({ prompt, onSubmit, onCancel, onResend }) {
5156
4742
  }
5157
4743
  var SCROLL_THRESHOLD2 = 100;
5158
4744
  var USER_SCROLL_UP_EPSILON = 4;
4745
+ var PROMPT_KEY_SEPARATOR = "";
4746
+ function getPromptSlotKey(prompt) {
4747
+ return prompt.toolCallId || prompt.userActionId;
4748
+ }
4749
+ function getPromptViewKey(prompt) {
4750
+ return [
4751
+ getPromptSlotKey(prompt),
4752
+ prompt.userActionId,
4753
+ prompt.subAction ?? "",
4754
+ prompt.expirySeconds ?? "",
4755
+ prompt.message ?? ""
4756
+ ].join(PROMPT_KEY_SEPARATOR);
4757
+ }
5159
4758
  var MessageListV2 = forwardRef(
5160
4759
  function MessageListV22({
5161
4760
  messages,
5162
- isStreaming: _isStreaming = false,
4761
+ isStreaming = false,
5163
4762
  onEditUserMessage,
5164
4763
  onRetryUserMessage,
5165
4764
  onImageClick,
@@ -5171,10 +4770,10 @@ var MessageListV2 = forwardRef(
5171
4770
  onSubmitUserAction,
5172
4771
  onCancelUserAction,
5173
4772
  onResendUserAction,
4773
+ onExpireUserAction,
5174
4774
  onDismissNotification,
5175
4775
  onSubmitFeedback,
5176
- typingSpeed = 4,
5177
- sidePanelOpen = false
4776
+ typingSpeed = 4
5178
4777
  }, ref) {
5179
4778
  const noop = useCallback(async () => {
5180
4779
  }, []);
@@ -5182,11 +4781,11 @@ var MessageListV2 = forwardRef(
5182
4781
  const scrollInnerRef = useRef(null);
5183
4782
  const isNearBottomRef = useRef(true);
5184
4783
  const [showScrollBtn, setShowScrollBtn] = useState(false);
4784
+ const [expiredPromptViewState, setExpiredPromptViewState] = useState({});
4785
+ const expiredUserActionIdsRef = useRef(/* @__PURE__ */ new Set());
5185
4786
  const prevCountRef = useRef(messages.length);
5186
4787
  const pauseStickUntilUserMessageRef = useRef(false);
5187
4788
  const followingBottomRef = useRef(true);
5188
- const sidePanelOpenRef = useRef(sidePanelOpen);
5189
- sidePanelOpenRef.current = sidePanelOpen;
5190
4789
  const lastPinAtRef = useRef(0);
5191
4790
  const prevScrollTopRef = useRef(0);
5192
4791
  const getDistanceFromBottom = useCallback(() => {
@@ -5194,6 +4793,92 @@ var MessageListV2 = forwardRef(
5194
4793
  if (!el) return 0;
5195
4794
  return el.scrollHeight - el.scrollTop - el.clientHeight;
5196
4795
  }, []);
4796
+ const messageActivityFingerprint = useMemo(() => {
4797
+ const last = messages[messages.length - 1];
4798
+ const promptFingerprint = (userActionPrompts ?? []).map((prompt) => `${getPromptViewKey(prompt)}:${prompt.status}`).join(PROMPT_KEY_SEPARATOR);
4799
+ const notificationFingerprint = (notifications ?? []).map((notification) => notification.id).join(PROMPT_KEY_SEPARATOR);
4800
+ if (!last) {
4801
+ return [
4802
+ 0,
4803
+ isStreaming ? "streaming" : "idle",
4804
+ promptFingerprint,
4805
+ notificationFingerprint
4806
+ ].join(PROMPT_KEY_SEPARATOR);
4807
+ }
4808
+ return [
4809
+ messages.length,
4810
+ isStreaming ? "streaming" : "idle",
4811
+ last.id,
4812
+ last.role,
4813
+ last.content ?? "",
4814
+ last.isStreaming ? "streaming" : "done",
4815
+ last.streamProgress ?? "",
4816
+ last.steps?.length ?? 0,
4817
+ last.errorDetails ?? "",
4818
+ promptFingerprint,
4819
+ notificationFingerprint
4820
+ ].join(PROMPT_KEY_SEPARATOR);
4821
+ }, [isStreaming, messages, notifications, userActionPrompts]);
4822
+ const handleUserActionExpired = useCallback(
4823
+ (promptKey, userActionId) => {
4824
+ setExpiredPromptViewState((prev) => {
4825
+ if (prev[promptKey]) return prev;
4826
+ return {
4827
+ ...prev,
4828
+ [promptKey]: { baseline: messageActivityFingerprint, hidden: false }
4829
+ };
4830
+ });
4831
+ if (!expiredUserActionIdsRef.current.has(userActionId)) {
4832
+ expiredUserActionIdsRef.current.add(userActionId);
4833
+ void onExpireUserAction?.(userActionId)?.catch(() => {
4834
+ });
4835
+ }
4836
+ },
4837
+ [messageActivityFingerprint, onExpireUserAction]
4838
+ );
4839
+ useEffect(() => {
4840
+ setExpiredPromptViewState((prev) => {
4841
+ let changed = false;
4842
+ const next = {};
4843
+ for (const [key, state] of Object.entries(prev)) {
4844
+ if (!state.hidden && state.baseline !== messageActivityFingerprint) {
4845
+ next[key] = { ...state, hidden: true };
4846
+ changed = true;
4847
+ } else {
4848
+ next[key] = state;
4849
+ }
4850
+ }
4851
+ return changed ? next : prev;
4852
+ });
4853
+ }, [messageActivityFingerprint]);
4854
+ useEffect(() => {
4855
+ const livePromptKeys = new Set((userActionPrompts ?? []).map(getPromptViewKey));
4856
+ const liveUserActionIds = new Set((userActionPrompts ?? []).map((p) => p.userActionId));
4857
+ for (const userActionId of expiredUserActionIdsRef.current) {
4858
+ if (!liveUserActionIds.has(userActionId)) {
4859
+ expiredUserActionIdsRef.current.delete(userActionId);
4860
+ }
4861
+ }
4862
+ setExpiredPromptViewState((prev) => {
4863
+ let changed = false;
4864
+ const next = {};
4865
+ for (const [key, state] of Object.entries(prev)) {
4866
+ if (livePromptKeys.has(key)) {
4867
+ next[key] = state;
4868
+ } else {
4869
+ changed = true;
4870
+ }
4871
+ }
4872
+ return changed ? next : prev;
4873
+ });
4874
+ }, [userActionPrompts]);
4875
+ const visibleUserActionPrompts = useMemo(
4876
+ () => userActionPrompts?.filter((prompt) => {
4877
+ const promptKey = getPromptViewKey(prompt);
4878
+ return !expiredPromptViewState[promptKey]?.hidden;
4879
+ }),
4880
+ [expiredPromptViewState, userActionPrompts]
4881
+ );
5197
4882
  const pinToBottom = useCallback((behavior = "instant") => {
5198
4883
  const el = scrollRef.current;
5199
4884
  if (!el) return;
@@ -5234,25 +4919,17 @@ var MessageListV2 = forwardRef(
5234
4919
  const nearBottom = distance <= SCROLL_THRESHOLD2;
5235
4920
  isNearBottomRef.current = nearBottom;
5236
4921
  setShowScrollBtn(!nearBottom);
4922
+ const sincePin = performance.now() - lastPinAtRef.current;
4923
+ if (sincePin < 250) return;
5237
4924
  const scrolledUp = currentScrollTop < prevScrollTop - USER_SCROLL_UP_EPSILON;
5238
4925
  if (scrolledUp) {
5239
4926
  followingBottomRef.current = false;
5240
4927
  pauseStickUntilUserMessageRef.current = true;
5241
- return;
5242
- }
5243
- const sincePin = performance.now() - lastPinAtRef.current;
5244
- if (sincePin < 250) return;
5245
- if (nearBottom) {
4928
+ } else if (nearBottom) {
5246
4929
  followingBottomRef.current = true;
5247
4930
  pauseStickUntilUserMessageRef.current = false;
5248
4931
  }
5249
4932
  }, [getDistanceFromBottom]);
5250
- const handleWheel = useCallback((e) => {
5251
- if (e.deltaY < 0) {
5252
- followingBottomRef.current = false;
5253
- pauseStickUntilUserMessageRef.current = true;
5254
- }
5255
- }, []);
5256
4933
  useEffect(() => {
5257
4934
  const prevCount = prevCountRef.current;
5258
4935
  prevCountRef.current = messages.length;
@@ -5262,7 +4939,7 @@ var MessageListV2 = forwardRef(
5262
4939
  pauseStickUntilUserMessageRef.current = false;
5263
4940
  followingBottomRef.current = true;
5264
4941
  requestAnimationFrame(() => scrollToBottom());
5265
- } else if (!sidePanelOpenRef.current && !pauseStickUntilUserMessageRef.current && followingBottomRef.current) {
4942
+ } else if (!pauseStickUntilUserMessageRef.current && followingBottomRef.current) {
5266
4943
  requestAnimationFrame(() => scrollToBottom("instant"));
5267
4944
  }
5268
4945
  }
@@ -5271,16 +4948,27 @@ var MessageListV2 = forwardRef(
5271
4948
  const inner = scrollInnerRef.current;
5272
4949
  if (!inner) return;
5273
4950
  const pinIfFollowing = () => {
5274
- if (sidePanelOpenRef.current) return;
5275
4951
  if (pauseStickUntilUserMessageRef.current) return;
5276
4952
  if (!followingBottomRef.current) return;
5277
- if (getDistanceFromBottom() > SCROLL_THRESHOLD2) return;
5278
4953
  pinToBottom("instant");
5279
4954
  };
5280
- const ro = new ResizeObserver(pinIfFollowing);
4955
+ const ro = new ResizeObserver(() => {
4956
+ pinIfFollowing();
4957
+ });
5281
4958
  ro.observe(inner);
5282
- return () => ro.disconnect();
5283
- }, [pinToBottom, getDistanceFromBottom]);
4959
+ const mo = new MutationObserver(() => {
4960
+ pinIfFollowing();
4961
+ });
4962
+ mo.observe(inner, {
4963
+ childList: true,
4964
+ subtree: true,
4965
+ characterData: true
4966
+ });
4967
+ return () => {
4968
+ ro.disconnect();
4969
+ mo.disconnect();
4970
+ };
4971
+ }, [pinToBottom]);
5284
4972
  useEffect(() => {
5285
4973
  if (messages.length > 0) {
5286
4974
  setTimeout(() => scrollToBottom("instant"), 50);
@@ -5292,7 +4980,6 @@ var MessageListV2 = forwardRef(
5292
4980
  {
5293
4981
  ref: scrollRef,
5294
4982
  onScroll: handleScroll,
5295
- onWheel: handleWheel,
5296
4983
  className: "payman-v2-message-scroll payman-v2-scrollbar",
5297
4984
  children: /* @__PURE__ */ jsxs(
5298
4985
  "div",
@@ -5306,7 +4993,6 @@ var MessageListV2 = forwardRef(
5306
4993
  message,
5307
4994
  onEdit: onEditUserMessage,
5308
4995
  onRetry: onRetryUserMessage,
5309
- onImageClick,
5310
4996
  retryDisabled,
5311
4997
  actions: messageActions?.userMessageActions
5312
4998
  }
@@ -5329,16 +5015,20 @@ var MessageListV2 = forwardRef(
5329
5015
  },
5330
5016
  note.id
5331
5017
  )),
5332
- userActionPrompts?.map((prompt) => /* @__PURE__ */ jsx(
5333
- UserActionInline,
5334
- {
5335
- prompt,
5336
- onSubmit: onSubmitUserAction ?? noop,
5337
- onCancel: onCancelUserAction ?? noop,
5338
- onResend: onResendUserAction ?? noop
5339
- },
5340
- prompt.toolCallId || prompt.userActionId
5341
- ))
5018
+ visibleUserActionPrompts?.map((prompt) => {
5019
+ const promptKey = getPromptViewKey(prompt);
5020
+ return /* @__PURE__ */ jsx(
5021
+ UserActionInline,
5022
+ {
5023
+ prompt,
5024
+ onSubmit: onSubmitUserAction ?? noop,
5025
+ onCancel: onCancelUserAction ?? noop,
5026
+ onResend: onResendUserAction ?? noop,
5027
+ onExpired: () => handleUserActionExpired(promptKey, prompt.userActionId)
5028
+ },
5029
+ promptKey
5030
+ );
5031
+ })
5342
5032
  ]
5343
5033
  }
5344
5034
  )
@@ -5368,121 +5058,11 @@ var MessageListV2 = forwardRef(
5368
5058
  ] });
5369
5059
  }
5370
5060
  );
5371
- function FilePreviewModal({ src, name, onClose }) {
5372
- const [isMounted, setIsMounted] = useState(false);
5373
- const [isLoaded, setIsLoaded] = useState(false);
5374
- useEffect(() => {
5375
- setIsMounted(true);
5376
- return () => setIsMounted(false);
5377
- }, []);
5378
- useEffect(() => {
5379
- setIsLoaded(false);
5380
- }, [src]);
5381
- const handleKeyDown = useCallback(
5382
- (e) => {
5383
- if (e.key === "Escape") onClose();
5384
- },
5385
- [onClose]
5386
- );
5387
- useEffect(() => {
5388
- if (!src || typeof document === "undefined") return;
5389
- document.addEventListener("keydown", handleKeyDown);
5390
- const prev = document.body.style.overflow;
5391
- document.body.style.overflow = "hidden";
5392
- return () => {
5393
- document.removeEventListener("keydown", handleKeyDown);
5394
- document.body.style.overflow = prev;
5395
- };
5396
- }, [src, handleKeyDown]);
5397
- if (!isMounted || typeof document === "undefined") return null;
5398
- return createPortal(
5399
- /* @__PURE__ */ jsx(AnimatePresence, { children: src ? /* @__PURE__ */ jsxs(
5400
- motion.div,
5401
- {
5402
- className: "payman-v2-file-preview-overlay",
5403
- initial: { opacity: 0 },
5404
- animate: { opacity: 1 },
5405
- exit: { opacity: 0 },
5406
- transition: { duration: 0.18 },
5407
- onClick: onClose,
5408
- role: "dialog",
5409
- "aria-modal": "true",
5410
- "aria-label": `Preview: ${name}`,
5411
- children: [
5412
- /* @__PURE__ */ jsx(
5413
- "button",
5414
- {
5415
- type: "button",
5416
- className: "payman-v2-file-preview-close",
5417
- "aria-label": "Close preview",
5418
- onClick: (e) => {
5419
- e.stopPropagation();
5420
- onClose();
5421
- },
5422
- children: /* @__PURE__ */ jsx(X, { size: 18, strokeWidth: 2 })
5423
- }
5424
- ),
5425
- /* @__PURE__ */ jsx(
5426
- motion.div,
5427
- {
5428
- className: "payman-v2-file-preview-inner",
5429
- initial: { scale: 0.93, opacity: 0 },
5430
- animate: { scale: isLoaded ? 1 : 0.93, opacity: isLoaded ? 1 : 0 },
5431
- exit: { scale: 0.93, opacity: 0 },
5432
- transition: { duration: 0.2 },
5433
- onClick: (e) => e.stopPropagation(),
5434
- children: /* @__PURE__ */ jsx(
5435
- "img",
5436
- {
5437
- src,
5438
- alt: name,
5439
- className: "payman-v2-file-preview-img",
5440
- draggable: false,
5441
- onLoad: () => setIsLoaded(true)
5442
- }
5443
- )
5444
- }
5445
- )
5446
- ]
5447
- },
5448
- "file-preview"
5449
- ) : null }),
5450
- document.body
5451
- );
5452
- }
5453
- function normalizeExtension(ext) {
5454
- return ext.replace(/^\./, "").toLowerCase();
5455
- }
5456
- function extOf(filename) {
5457
- return filename.split(".").pop()?.toLowerCase() ?? "";
5458
- }
5459
- function isAllowedImage(file, allowedExtensions) {
5460
- const allowed = new Set(allowedExtensions.map(normalizeExtension));
5461
- const ext = extOf(file.name);
5462
- if (allowed.has(ext)) return true;
5463
- if (!file.type.startsWith("image/")) return false;
5464
- const mimeSubtype = file.type.slice("image/".length).toLowerCase();
5465
- return allowed.has(mimeSubtype) || mimeSubtype === "jpeg" && allowed.has("jpg");
5466
- }
5467
- function isAllowedDocument(file, allowedExtensions) {
5468
- const allowed = new Set(allowedExtensions.map(normalizeExtension));
5469
- return allowed.has(extOf(file.name));
5470
- }
5471
- function fileTypeLabel(file, kind) {
5472
- if (kind === "image") return "Image";
5473
- const ext = extOf(file.name);
5474
- return ext ? ext.toUpperCase() : "Document";
5475
- }
5476
5061
  var ChatInputV2 = forwardRef(
5477
5062
  function ChatInputV22({
5478
5063
  onSend,
5479
5064
  disabled = false,
5480
5065
  isStreaming = false,
5481
- isUploadingAttachments = false,
5482
- attachmentsReady = true,
5483
- hasAttachmentUploadErrors = false,
5484
- attachmentUploadStatusById = {},
5485
- uploadedAttachmentPayloads = [],
5486
5066
  placeholder = "Reply...",
5487
5067
  enableVoice = false,
5488
5068
  voiceAvailable = false,
@@ -5496,13 +5076,6 @@ var ChatInputV2 = forwardRef(
5496
5076
  showAttachFileButton = true,
5497
5077
  onUploadImageClick,
5498
5078
  onAttachFileClick,
5499
- allowedImageExtensions = ["png", "jpg", "jpeg", "gif", "webp"],
5500
- allowedFileExtensions = ["pdf", "docx", "xlsx", "xls"],
5501
- maxCount,
5502
- maxFileBytes,
5503
- maxTotalBytes,
5504
- onFilesChange,
5505
- onAttachmentsChange,
5506
5079
  editingMessageId = null,
5507
5080
  onClearEditing,
5508
5081
  analysisMode,
@@ -5516,140 +5089,21 @@ var ChatInputV2 = forwardRef(
5516
5089
  const [selectedCommandIndex, setSelectedCommandIndex] = useState(0);
5517
5090
  const [inlineHint, setInlineHint] = useState(null);
5518
5091
  const [commandMenuDismissed, setCommandMenuDismissed] = useState(false);
5519
- const [attachedFiles, setAttachedFiles] = useState([]);
5520
- const [previewFile, setPreviewFile] = useState(null);
5521
- const [isSending, setIsSending] = useState(false);
5522
5092
  const textareaRef = useRef(null);
5523
5093
  const actionsRef = useRef(null);
5524
- const imageInputRef = useRef(null);
5525
- const fileInputRef = useRef(null);
5526
5094
  const preRecordTextRef = useRef("");
5527
5095
  const voiceTooltipTimerRef = useRef(
5528
5096
  null
5529
5097
  );
5530
5098
  const voiceDraftSyncActiveRef = useRef(false);
5531
- const chatContext = useContext(PaymanChatContext);
5532
- useEffect(() => {
5533
- return () => {
5534
- attachedFiles.forEach((f) => URL.revokeObjectURL(f.objectUrl));
5535
- };
5536
- }, []);
5537
- const notifyAttachmentList = useCallback(
5538
- (files) => {
5539
- onFilesChange?.(files.map((f) => f.file));
5540
- onAttachmentsChange?.(files.map((f) => ({ id: f.id, file: f.file })));
5541
- },
5542
- [onAttachmentsChange, onFilesChange]
5543
- );
5544
- const clearAttachmentsFromInput = useCallback(() => {
5545
- setAttachedFiles((prev) => {
5546
- prev.forEach((f) => URL.revokeObjectURL(f.objectUrl));
5547
- return [];
5548
- });
5549
- setPreviewFile(null);
5550
- onFilesChange?.([]);
5551
- onAttachmentsChange?.([]);
5552
- }, [onAttachmentsChange, onFilesChange]);
5553
- const addFiles = useCallback(
5554
- (incoming, source) => {
5555
- const isImage = source === "image";
5556
- const allowedExtensions = isImage ? allowedImageExtensions : allowedFileExtensions;
5557
- const isAllowed = isImage ? isAllowedImage : isAllowedDocument;
5558
- const kindLabel = isImage ? "image" : "document";
5559
- setAttachedFiles((prev) => {
5560
- const accepted = [];
5561
- let rejectedType = false;
5562
- let hitCountLimit = false;
5563
- let hitFileSizeLimit = false;
5564
- let hitTotalSizeLimit = false;
5565
- let oversizedName = "";
5566
- const currentTotalBytes = prev.reduce(
5567
- (sum, item) => sum + item.file.size,
5568
- 0
5569
- );
5570
- let addedBytes = 0;
5571
- for (const file of incoming) {
5572
- if (!isAllowed(file, allowedExtensions)) {
5573
- rejectedType = true;
5574
- continue;
5575
- }
5576
- if (maxFileBytes != null && file.size > maxFileBytes) {
5577
- hitFileSizeLimit = true;
5578
- oversizedName = file.name;
5579
- continue;
5580
- }
5581
- if (maxTotalBytes != null && currentTotalBytes + addedBytes + file.size > maxTotalBytes) {
5582
- hitTotalSizeLimit = true;
5583
- break;
5584
- }
5585
- if (maxCount != null && prev.length + accepted.length >= maxCount) {
5586
- hitCountLimit = true;
5587
- break;
5588
- }
5589
- accepted.push({
5590
- id: `${Date.now()}-${Math.random()}`,
5591
- file,
5592
- kind: source,
5593
- objectUrl: URL.createObjectURL(file)
5594
- });
5595
- addedBytes += file.size;
5596
- }
5597
- if (rejectedType) {
5598
- setInlineHint(
5599
- `Unsupported ${kindLabel} type. Allowed: ${allowedExtensions.map(normalizeExtension).join(", ")}.`
5600
- );
5601
- } else if (hitFileSizeLimit) {
5602
- setInlineHint(
5603
- maxFileBytes != null ? `"${oversizedName}" exceeds the ${formatAttachmentBytes(maxFileBytes)} per-file limit.` : "File exceeds the maximum allowed size."
5604
- );
5605
- } else if (hitTotalSizeLimit) {
5606
- setInlineHint(
5607
- maxTotalBytes != null ? `Total attachment size would exceed ${formatAttachmentBytes(maxTotalBytes)}.` : "Total attachment size exceeds the limit."
5608
- );
5609
- } else if (hitCountLimit) {
5610
- setInlineHint(
5611
- maxCount === 1 ? "Only 1 attachment is allowed per message." : `Maximum ${maxCount} attachments allowed per message.`
5612
- );
5613
- }
5614
- if (accepted.length === 0) return prev;
5615
- const updated = [...prev, ...accepted];
5616
- notifyAttachmentList(updated);
5617
- return updated;
5618
- });
5619
- },
5620
- [
5621
- allowedFileExtensions,
5622
- allowedImageExtensions,
5623
- maxCount,
5624
- maxFileBytes,
5625
- maxTotalBytes,
5626
- notifyAttachmentList
5627
- ]
5628
- );
5629
- const removeFile = useCallback(
5630
- (id) => {
5631
- setAttachedFiles((prev) => {
5632
- const target = prev.find((f) => f.id === id);
5633
- if (target) URL.revokeObjectURL(target.objectUrl);
5634
- const updated = prev.filter((f) => f.id !== id);
5635
- notifyAttachmentList(updated);
5636
- return updated;
5637
- });
5638
- setPreviewFile((p) => p?.id === id ? null : p);
5639
- },
5640
- [notifyAttachmentList]
5641
- );
5642
- const imageAccept = allowedImageExtensions.map((e) => `.${e.replace(/^\./, "")}`).join(",");
5643
- const fileAccept = allowedFileExtensions.map((e) => `.${e.replace(/^\./, "")}`).join(",");
5644
- const isInputBusy = isSending || isUploadingAttachments;
5645
- const isInputLocked = disabled || isRecording || isInputBusy;
5646
- const hasAttachmentOptions = showUploadImageButton || showAttachFileButton;
5647
- const showAttachmentMenuButton = showAttachmentButton && hasAttachmentOptions;
5648
- const showVoiceButton = enableVoice && onVoicePress != null;
5649
- const isVoiceButtonDisabled = disabled || !voiceAvailable;
5650
- const commandQuery = value.startsWith("/") && !value.includes("\n") && !/\s/.test(value) ? value.toLowerCase() : null;
5651
- const commandSuggestions = commandQuery == null ? [] : slashCommands.filter(
5652
- (command) => command.name.toLowerCase().startsWith(commandQuery)
5099
+ const isInputLocked = disabled || isRecording;
5100
+ const hasAttachmentOptions = showUploadImageButton || showAttachFileButton;
5101
+ const showAttachmentMenuButton = showAttachmentButton && hasAttachmentOptions;
5102
+ const showVoiceButton = enableVoice && onVoicePress != null;
5103
+ const isVoiceButtonDisabled = disabled || !voiceAvailable;
5104
+ const commandQuery = value.startsWith("/") && !value.includes("\n") && !/\s/.test(value) ? value.toLowerCase() : null;
5105
+ const commandSuggestions = commandQuery == null ? [] : slashCommands.filter(
5106
+ (command) => command.name.toLowerCase().startsWith(commandQuery)
5653
5107
  );
5654
5108
  const showCommandSuggestions = !commandMenuDismissed && !isRecording && !disabled && commandSuggestions.length > 0;
5655
5109
  useEffect(() => {
@@ -5682,10 +5136,9 @@ var ChatInputV2 = forwardRef(
5682
5136
  const end = message.length;
5683
5137
  textarea.setSelectionRange(end, end);
5684
5138
  });
5685
- },
5686
- clearAttachments: clearAttachmentsFromInput
5139
+ }
5687
5140
  }),
5688
- [disabled, clearAttachmentsFromInput]
5141
+ [disabled]
5689
5142
  );
5690
5143
  useEffect(() => {
5691
5144
  if (!showActions) return;
@@ -5719,23 +5172,8 @@ var ChatInputV2 = forwardRef(
5719
5172
  const separator = base && !base.endsWith(" ") && transcribedText ? " " : "";
5720
5173
  setValue(`${base}${separator}${transcribedText}`);
5721
5174
  }, [isRecording, transcribedText]);
5722
- function uploadStatusLabel(status, file, kind) {
5723
- if (status === "uploading") return "Uploading\u2026";
5724
- if (status === "error") return "Upload failed";
5725
- return fileTypeLabel(file, kind);
5726
- }
5727
- const handleSend = useCallback(async () => {
5728
- const hasText = value.trim().length > 0;
5729
- const hasFiles = attachedFiles.length > 0;
5730
- if (!hasText && !hasFiles || disabled || isSending || isUploadingAttachments) return;
5731
- if (hasFiles && !attachmentsReady) {
5732
- setInlineHint("Waiting for attachments to finish uploading.");
5733
- return;
5734
- }
5735
- if (hasFiles && hasAttachmentUploadErrors) {
5736
- setInlineHint("Remove or re-add attachments that failed to upload.");
5737
- return;
5738
- }
5175
+ const handleSend = useCallback(() => {
5176
+ if (!value.trim() || disabled) return;
5739
5177
  const commandHint = getSlashCommandValidationHint(value);
5740
5178
  if (commandHint) {
5741
5179
  setInlineHint(commandHint);
@@ -5745,38 +5183,15 @@ var ChatInputV2 = forwardRef(
5745
5183
  preRecordTextRef.current = "";
5746
5184
  setInlineHint(null);
5747
5185
  onClearEditing?.();
5748
- const textToSend = value.trim();
5749
- const filesToSend = attachedFiles.map((f) => f.file);
5750
- const attachmentsToSend = [...uploadedAttachmentPayloads];
5186
+ onSend(value.trim());
5751
5187
  setValue("");
5752
- clearAttachmentsFromInput();
5753
5188
  requestAnimationFrame(() => {
5754
5189
  if (textareaRef.current) {
5755
5190
  textareaRef.current.style.height = "auto";
5756
5191
  textareaRef.current.focus();
5757
5192
  }
5758
5193
  });
5759
- setIsSending(true);
5760
- try {
5761
- await onSend(textToSend, filesToSend, attachmentsToSend);
5762
- } catch {
5763
- setInlineHint("Failed to send message. Please try again.");
5764
- } finally {
5765
- setIsSending(false);
5766
- }
5767
- }, [
5768
- value,
5769
- attachedFiles,
5770
- uploadedAttachmentPayloads,
5771
- disabled,
5772
- isSending,
5773
- isUploadingAttachments,
5774
- attachmentsReady,
5775
- hasAttachmentUploadErrors,
5776
- onClearEditing,
5777
- onSend,
5778
- clearAttachmentsFromInput
5779
- ]);
5194
+ }, [value, disabled, onClearEditing, onSend]);
5780
5195
  const selectCommand = useCallback(
5781
5196
  (command) => {
5782
5197
  const insertText = command.insertText ?? `${command.name} `;
@@ -5821,30 +5236,18 @@ var ChatInputV2 = forwardRef(
5821
5236
  }
5822
5237
  if (e.key === "Enter" && !e.shiftKey) {
5823
5238
  e.preventDefault();
5824
- if (isStreaming || isSending || isUploadingAttachments) return;
5825
- void handleSend();
5239
+ if (isStreaming) return;
5240
+ handleSend();
5826
5241
  }
5827
5242
  };
5828
5243
  const handleUploadImageClick = () => {
5829
- imageInputRef.current?.click();
5830
5244
  onUploadImageClick?.();
5831
5245
  setShowActions(false);
5832
5246
  };
5833
5247
  const handleAttachFileClick = () => {
5834
- fileInputRef.current?.click();
5835
5248
  onAttachFileClick?.();
5836
5249
  setShowActions(false);
5837
5250
  };
5838
- const handleImageFilesSelected = (e) => {
5839
- const files = Array.from(e.target.files ?? []);
5840
- if (files.length) addFiles(files, "image");
5841
- e.target.value = "";
5842
- };
5843
- const handleDocFilesSelected = (e) => {
5844
- const files = Array.from(e.target.files ?? []);
5845
- if (files.length) addFiles(files, "file");
5846
- e.target.value = "";
5847
- };
5848
5251
  const hideVoiceTooltip = useCallback(() => {
5849
5252
  if (voiceTooltipTimerRef.current) {
5850
5253
  clearTimeout(voiceTooltipTimerRef.current);
@@ -5872,39 +5275,9 @@ var ChatInputV2 = forwardRef(
5872
5275
  }
5873
5276
  onVoicePress();
5874
5277
  };
5875
- const canSend = (value.trim().length > 0 || attachedFiles.length > 0) && !disabled;
5876
- const sendDisabled = !canSend || isStreaming || isUploadingAttachments || !attachmentsReady || hasAttachmentUploadErrors || isSending;
5278
+ const canSend = value.trim().length > 0 && !disabled;
5279
+ const sendDisabled = !canSend || isStreaming;
5877
5280
  return /* @__PURE__ */ jsxs("div", { className: "payman-v2-input-container", children: [
5878
- /* @__PURE__ */ jsx(
5879
- "input",
5880
- {
5881
- ref: imageInputRef,
5882
- type: "file",
5883
- accept: imageAccept,
5884
- multiple: maxCount == null || maxCount > 1,
5885
- style: { display: "none" },
5886
- onChange: handleImageFilesSelected
5887
- }
5888
- ),
5889
- /* @__PURE__ */ jsx(
5890
- "input",
5891
- {
5892
- ref: fileInputRef,
5893
- type: "file",
5894
- accept: fileAccept,
5895
- multiple: maxCount == null || maxCount > 1,
5896
- style: { display: "none" },
5897
- onChange: handleDocFilesSelected
5898
- }
5899
- ),
5900
- /* @__PURE__ */ jsx(
5901
- FilePreviewModal,
5902
- {
5903
- src: previewFile?.kind === "image" ? previewFile.objectUrl : null,
5904
- name: previewFile?.file.name ?? "",
5905
- onClose: () => setPreviewFile(null)
5906
- }
5907
- ),
5908
5281
  /* @__PURE__ */ jsx(AnimatePresence, { children: showCommandSuggestions && /* @__PURE__ */ jsx(
5909
5282
  motion.div,
5910
5283
  {
@@ -5943,115 +5316,6 @@ var ChatInputV2 = forwardRef(
5943
5316
  ),
5944
5317
  children: [
5945
5318
  /* @__PURE__ */ jsxs("div", { className: "payman-v2-input-body", children: [
5946
- /* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: attachedFiles.length > 0 && /* @__PURE__ */ jsx(
5947
- motion.div,
5948
- {
5949
- initial: { opacity: 0, height: 0 },
5950
- animate: { opacity: 1, height: "auto" },
5951
- exit: { opacity: 0, height: 0 },
5952
- transition: { duration: 0.15, ease: "easeOut" },
5953
- className: "payman-v2-file-preview",
5954
- children: attachedFiles.map((af) => {
5955
- const uploadStatus = attachmentUploadStatusById[af.id];
5956
- const isUploadingFile = uploadStatus === "uploading";
5957
- const hasUploadError = uploadStatus === "error";
5958
- return /* @__PURE__ */ jsxs("div", { className: "payman-v2-file-preview-item", children: [
5959
- af.kind === "image" ? /* @__PURE__ */ jsxs(
5960
- "button",
5961
- {
5962
- type: "button",
5963
- className: cn(
5964
- "payman-v2-file-preview-shell payman-v2-file-preview-shell-clickable",
5965
- hasUploadError && "payman-v2-file-preview-shell-error"
5966
- ),
5967
- onClick: () => setPreviewFile(af),
5968
- disabled: isUploadingFile,
5969
- "aria-label": `Preview ${af.file.name}`,
5970
- children: [
5971
- /* @__PURE__ */ jsxs("div", { className: "payman-v2-file-preview-thumb", children: [
5972
- /* @__PURE__ */ jsx(
5973
- "img",
5974
- {
5975
- src: af.objectUrl,
5976
- alt: "",
5977
- draggable: false
5978
- }
5979
- ),
5980
- isUploadingFile && /* @__PURE__ */ jsx("div", { className: "payman-v2-file-preview-uploading", children: /* @__PURE__ */ jsx(Loader2, { size: 14, className: "payman-v2-spin" }) })
5981
- ] }),
5982
- /* @__PURE__ */ jsxs("div", { className: "payman-v2-file-preview-info", children: [
5983
- /* @__PURE__ */ jsx("p", { className: "payman-v2-file-preview-name", children: af.file.name }),
5984
- /* @__PURE__ */ jsx("p", { className: "payman-v2-file-preview-type", children: uploadStatusLabel(uploadStatus, af.file, af.kind) })
5985
- ] })
5986
- ]
5987
- }
5988
- ) : isPdfFile(af.file) ? /* @__PURE__ */ jsxs(
5989
- "button",
5990
- {
5991
- type: "button",
5992
- className: cn(
5993
- "payman-v2-file-preview-shell payman-v2-file-preview-shell-clickable",
5994
- hasUploadError && "payman-v2-file-preview-shell-error"
5995
- ),
5996
- onClick: () => chatContext?.openPdfSheet(
5997
- af.objectUrl,
5998
- af.file.name
5999
- ),
6000
- disabled: isUploadingFile,
6001
- "aria-label": `Preview ${af.file.name}`,
6002
- children: [
6003
- /* @__PURE__ */ jsx("div", { className: "payman-v2-file-preview-thumb", children: isUploadingFile ? /* @__PURE__ */ jsx(Loader2, { size: 16, className: "payman-v2-spin payman-v2-file-preview-doc-icon" }) : /* @__PURE__ */ jsx(
6004
- FileText,
6005
- {
6006
- size: 16,
6007
- strokeWidth: 1.75,
6008
- className: "payman-v2-file-preview-doc-icon"
6009
- }
6010
- ) }),
6011
- /* @__PURE__ */ jsxs("div", { className: "payman-v2-file-preview-info", children: [
6012
- /* @__PURE__ */ jsx("p", { className: "payman-v2-file-preview-name", children: af.file.name }),
6013
- /* @__PURE__ */ jsx("p", { className: "payman-v2-file-preview-type", children: uploadStatusLabel(uploadStatus, af.file, af.kind) })
6014
- ] })
6015
- ]
6016
- }
6017
- ) : /* @__PURE__ */ jsxs(
6018
- "div",
6019
- {
6020
- className: cn(
6021
- "payman-v2-file-preview-shell",
6022
- hasUploadError && "payman-v2-file-preview-shell-error"
6023
- ),
6024
- children: [
6025
- /* @__PURE__ */ jsx("div", { className: "payman-v2-file-preview-thumb", children: isUploadingFile ? /* @__PURE__ */ jsx(Loader2, { size: 16, className: "payman-v2-spin payman-v2-file-preview-doc-icon" }) : /* @__PURE__ */ jsx(
6026
- FileText,
6027
- {
6028
- size: 16,
6029
- strokeWidth: 1.75,
6030
- className: "payman-v2-file-preview-doc-icon"
6031
- }
6032
- ) }),
6033
- /* @__PURE__ */ jsxs("div", { className: "payman-v2-file-preview-info", children: [
6034
- /* @__PURE__ */ jsx("p", { className: "payman-v2-file-preview-name", children: af.file.name }),
6035
- /* @__PURE__ */ jsx("p", { className: "payman-v2-file-preview-type", children: uploadStatusLabel(uploadStatus, af.file, af.kind) })
6036
- ] })
6037
- ]
6038
- }
6039
- ),
6040
- /* @__PURE__ */ jsx(
6041
- "button",
6042
- {
6043
- type: "button",
6044
- className: "payman-v2-file-preview-remove",
6045
- onClick: () => removeFile(af.id),
6046
- "aria-label": `Remove ${af.file.name}`,
6047
- children: /* @__PURE__ */ jsx(X, { size: 12, strokeWidth: 2.5 })
6048
- }
6049
- )
6050
- ] }, af.id);
6051
- })
6052
- },
6053
- "file-preview"
6054
- ) }),
6055
5319
  /* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: editingMessageId && /* @__PURE__ */ jsxs(
6056
5320
  motion.div,
6057
5321
  {
@@ -6283,13 +5547,13 @@ var ChatInputV2 = forwardRef(
6283
5547
  "button",
6284
5548
  {
6285
5549
  type: "button",
6286
- onClick: () => void handleSend(),
5550
+ onClick: handleSend,
6287
5551
  disabled: sendDisabled,
6288
5552
  className: cn(
6289
5553
  "payman-v2-input-send-btn",
6290
5554
  sendDisabled && "payman-v2-input-send-btn-disabled"
6291
5555
  ),
6292
- "aria-label": isUploadingAttachments || isSending ? "Uploading attachments" : "Send message",
5556
+ "aria-label": "Send message",
6293
5557
  children: /* @__PURE__ */ jsx(
6294
5558
  ArrowUp,
6295
5559
  {
@@ -6824,389 +6088,6 @@ function TimelineBars({
6824
6088
  )
6825
6089
  ] });
6826
6090
  }
6827
-
6828
- // src/utils/pdfPreview.ts
6829
- var PdfPreviewError = class extends Error {
6830
- constructor(kind, title, userMessage) {
6831
- super(userMessage);
6832
- __publicField(this, "kind");
6833
- __publicField(this, "title");
6834
- __publicField(this, "userMessage");
6835
- this.name = "PdfPreviewError";
6836
- this.kind = kind;
6837
- this.title = title;
6838
- this.userMessage = userMessage;
6839
- }
6840
- };
6841
- function classifyErrorBody(body, status) {
6842
- const text = body.replace(/\s+/g, " ").trim();
6843
- if (/signed expiry time|must be after signed start time|expired|expir/i.test(text)) {
6844
- return new PdfPreviewError(
6845
- "expired",
6846
- "Link expired",
6847
- "This download link has expired. Ask the assistant to generate a new copy of the document."
6848
- );
6849
- }
6850
- if (/AuthenticationFailed|authorization header|formed correctly including the signature/i.test(
6851
- text
6852
- )) {
6853
- return new PdfPreviewError(
6854
- "forbidden",
6855
- "Link no longer valid",
6856
- "This preview link is no longer valid. Request a fresh download link and try again."
6857
- );
6858
- }
6859
- if (status === 404 || /BlobNotFound|ResourceNotFound|The specified blob does not exist/i.test(text)) {
6860
- return new PdfPreviewError(
6861
- "not_found",
6862
- "Document not found",
6863
- "The file is no longer available. It may have been removed or the link is incorrect."
6864
- );
6865
- }
6866
- if (status === 403) {
6867
- return new PdfPreviewError(
6868
- "forbidden",
6869
- "Can't open document",
6870
- "You may not have access to this file, or the link has expired."
6871
- );
6872
- }
6873
- if (status === 401) {
6874
- return new PdfPreviewError(
6875
- "forbidden",
6876
- "Access denied",
6877
- "This preview link could not be verified. Request a new download link."
6878
- );
6879
- }
6880
- return new PdfPreviewError(
6881
- "unknown",
6882
- "Can't preview document",
6883
- "Something went wrong while opening this file. Try downloading it or request a new link."
6884
- );
6885
- }
6886
- function normalizePdfPreviewError(error) {
6887
- if (error instanceof PdfPreviewError) return error;
6888
- if (error instanceof TypeError) {
6889
- return new PdfPreviewError(
6890
- "network",
6891
- "Connection problem",
6892
- "Could not load the document. Check your connection and try again."
6893
- );
6894
- }
6895
- return new PdfPreviewError(
6896
- "unknown",
6897
- "Can't preview document",
6898
- "Something went wrong while opening this file. Try downloading it or request a new link."
6899
- );
6900
- }
6901
- async function assertPdfBlob(blob, status) {
6902
- if (!blob.size) {
6903
- return Promise.reject(
6904
- new PdfPreviewError(
6905
- "empty",
6906
- "Document unavailable",
6907
- "The file response was empty. Request a new download link and try again."
6908
- )
6909
- );
6910
- }
6911
- const head = await blob.slice(0, Math.min(blob.size, 1024)).text();
6912
- if (head.startsWith("%PDF")) {
6913
- return blob;
6914
- }
6915
- throw classifyErrorBody(head, status);
6916
- }
6917
- async function fetchPdfBlob(src) {
6918
- let response;
6919
- try {
6920
- response = await fetch(src, {
6921
- method: "GET",
6922
- headers: { Accept: "application/pdf,*/*" }
6923
- });
6924
- } catch {
6925
- throw new PdfPreviewError(
6926
- "network",
6927
- "Connection problem",
6928
- "Could not load the document. Check your connection and try again."
6929
- );
6930
- }
6931
- const blob = await response.blob();
6932
- if (!response.ok) {
6933
- const body = await blob.text().catch(() => "");
6934
- throw classifyErrorBody(body, response.status);
6935
- }
6936
- return assertPdfBlob(blob, response.status);
6937
- }
6938
- var MIN_WIDTH = 320;
6939
- var MAX_WIDTH_RATIO = 0.6;
6940
- var DEFAULT_WIDTH = 520;
6941
- var SPRING = { type: "spring", stiffness: 340, damping: 34, mass: 0.85 };
6942
- var SHEET_EXIT = { duration: 0.22, ease: [0.4, 0, 1, 1] };
6943
- function pdfDownloadName(title) {
6944
- const base = title.trim() || "document";
6945
- return base.toLowerCase().endsWith(".pdf") ? base : `${base}.pdf`;
6946
- }
6947
- function clampSplitWidth(w) {
6948
- const maxW = Math.floor(window.innerWidth * MAX_WIDTH_RATIO);
6949
- return Math.max(MIN_WIDTH, Math.min(maxW, w));
6950
- }
6951
- function PdfSheetV2({
6952
- src,
6953
- title,
6954
- onClose,
6955
- mode = "split"
6956
- }) {
6957
- return /* @__PURE__ */ jsx(AnimatePresence, { children: src && /* @__PURE__ */ jsx(
6958
- PdfSheetPanel,
6959
- {
6960
- src,
6961
- title,
6962
- onClose,
6963
- mode
6964
- },
6965
- "pdf-panel"
6966
- ) });
6967
- }
6968
- function PdfSheetPanel({
6969
- src,
6970
- title,
6971
- onClose,
6972
- mode
6973
- }) {
6974
- const isSheet = mode === "sheet";
6975
- const [isLoaded, setIsLoaded] = useState(false);
6976
- const [isDownloading, setIsDownloading] = useState(false);
6977
- const [previewUrl, setPreviewUrl] = useState(null);
6978
- const [previewError, setPreviewError] = useState(null);
6979
- const [loadAttempt, setLoadAttempt] = useState(0);
6980
- const blobRef = useRef(null);
6981
- const objectUrlRef = useRef(null);
6982
- const [panelWidth, setPanelWidth] = useState(DEFAULT_WIDTH);
6983
- const [splitOpened, setSplitOpened] = useState(false);
6984
- const [isDragging, setIsDragging] = useState(false);
6985
- useEffect(() => {
6986
- setIsLoaded(false);
6987
- setPreviewUrl(null);
6988
- setPreviewError(null);
6989
- setPanelWidth(DEFAULT_WIDTH);
6990
- setSplitOpened(false);
6991
- blobRef.current = null;
6992
- if (objectUrlRef.current) {
6993
- URL.revokeObjectURL(objectUrlRef.current);
6994
- objectUrlRef.current = null;
6995
- }
6996
- let cancelled = false;
6997
- const loadPreview = async () => {
6998
- try {
6999
- const blob = await fetchPdfBlob(src);
7000
- if (cancelled) return;
7001
- blobRef.current = blob;
7002
- const objectUrl = URL.createObjectURL(blob);
7003
- objectUrlRef.current = objectUrl;
7004
- setPreviewUrl(objectUrl);
7005
- } catch (error) {
7006
- if (!cancelled) {
7007
- setPreviewError(normalizePdfPreviewError(error));
7008
- }
7009
- }
7010
- };
7011
- void loadPreview();
7012
- return () => {
7013
- cancelled = true;
7014
- if (objectUrlRef.current) {
7015
- URL.revokeObjectURL(objectUrlRef.current);
7016
- objectUrlRef.current = null;
7017
- }
7018
- blobRef.current = null;
7019
- };
7020
- }, [src, loadAttempt]);
7021
- useEffect(() => {
7022
- if (isSheet) return;
7023
- const onWindowResize = () => setPanelWidth((size) => clampSplitWidth(size));
7024
- window.addEventListener("resize", onWindowResize);
7025
- return () => window.removeEventListener("resize", onWindowResize);
7026
- }, [isSheet]);
7027
- const handleKeyDown = useCallback(
7028
- (e) => {
7029
- if (e.key === "Escape") onClose();
7030
- },
7031
- [onClose]
7032
- );
7033
- useEffect(() => {
7034
- document.addEventListener("keydown", handleKeyDown);
7035
- return () => document.removeEventListener("keydown", handleKeyDown);
7036
- }, [handleKeyDown]);
7037
- const canDownload = isLoaded && previewUrl != null && !previewError;
7038
- const handleDownload = async () => {
7039
- const filename = pdfDownloadName(title);
7040
- setIsDownloading(true);
7041
- try {
7042
- const blob = blobRef.current ?? await fetchPdfBlob(src);
7043
- const objectUrl = URL.createObjectURL(blob);
7044
- const a = document.createElement("a");
7045
- a.href = objectUrl;
7046
- a.download = filename;
7047
- a.target = "_blank";
7048
- a.rel = "noopener noreferrer";
7049
- document.body.appendChild(a);
7050
- a.click();
7051
- a.remove();
7052
- URL.revokeObjectURL(objectUrl);
7053
- } catch (error) {
7054
- setPreviewError(normalizePdfPreviewError(error));
7055
- } finally {
7056
- setIsDownloading(false);
7057
- }
7058
- };
7059
- const handleRetry = () => {
7060
- setPreviewError(null);
7061
- setIsLoaded(false);
7062
- setPreviewUrl(null);
7063
- setLoadAttempt((attempt) => attempt + 1);
7064
- };
7065
- const handleOpenInNewTab = () => {
7066
- window.open(src, "_blank", "noopener,noreferrer");
7067
- };
7068
- const onResizeMouseDown = (e) => {
7069
- if (e.button !== 0) return;
7070
- e.preventDefault();
7071
- const startX = e.clientX;
7072
- const startW = panelWidth;
7073
- setIsDragging(true);
7074
- const onMove = (ev) => {
7075
- setPanelWidth(clampSplitWidth(startW + (startX - ev.clientX)));
7076
- };
7077
- const onUp = () => {
7078
- setIsDragging(false);
7079
- document.removeEventListener("mousemove", onMove);
7080
- document.removeEventListener("mouseup", onUp);
7081
- };
7082
- document.addEventListener("mousemove", onMove);
7083
- document.addEventListener("mouseup", onUp);
7084
- };
7085
- return /* @__PURE__ */ jsxs(
7086
- motion.div,
7087
- {
7088
- className: cn(
7089
- "payman-v2-root payman-v2-pdf-sheet-panel",
7090
- isSheet && "payman-v2-pdf-sheet-panel--sheet"
7091
- ),
7092
- style: { minWidth: 0 },
7093
- initial: isSheet ? { x: "100%", opacity: 0 } : { width: 0, opacity: 0 },
7094
- animate: isSheet ? { x: 0, opacity: 1 } : { width: panelWidth, opacity: 1 },
7095
- exit: isSheet ? { x: "100%", opacity: 0, transition: { x: SHEET_EXIT, opacity: SHEET_EXIT } } : { width: 0, opacity: 0, transition: { width: SHEET_EXIT, opacity: SHEET_EXIT } },
7096
- transition: isSheet ? { x: SPRING, opacity: SPRING } : {
7097
- width: splitOpened ? { duration: 0 } : SPRING,
7098
- opacity: SPRING
7099
- },
7100
- onAnimationComplete: () => {
7101
- if (!isSheet && !splitOpened) setSplitOpened(true);
7102
- },
7103
- children: [
7104
- !isSheet && /* @__PURE__ */ jsx(
7105
- "div",
7106
- {
7107
- className: "payman-v2-pdf-sheet-resize-handle",
7108
- onMouseDown: onResizeMouseDown,
7109
- "aria-hidden": "true",
7110
- children: /* @__PURE__ */ jsx("div", { className: "payman-v2-pdf-sheet-resize-grip" })
7111
- }
7112
- ),
7113
- /* @__PURE__ */ jsxs("div", { className: "payman-v2-pdf-sheet-header", children: [
7114
- /* @__PURE__ */ jsxs("div", { className: "payman-v2-pdf-sheet-header-left", children: [
7115
- /* @__PURE__ */ jsx("div", { className: "payman-v2-pdf-sheet-file-icon", children: /* @__PURE__ */ jsx(FileText, { size: 14, strokeWidth: 1.75 }) }),
7116
- /* @__PURE__ */ jsx("span", { className: "payman-v2-pdf-sheet-title", title, children: title || "Document" })
7117
- ] }),
7118
- /* @__PURE__ */ jsxs("div", { className: "payman-v2-pdf-sheet-header-actions", children: [
7119
- /* @__PURE__ */ jsxs(
7120
- "button",
7121
- {
7122
- type: "button",
7123
- className: "payman-v2-pdf-sheet-download-btn",
7124
- "aria-label": "Download PDF",
7125
- disabled: !canDownload || isDownloading,
7126
- onClick: () => void handleDownload(),
7127
- children: [
7128
- isDownloading ? /* @__PURE__ */ jsx(Loader2, { size: 13, strokeWidth: 2, style: { animation: "payman-v2-spin 0.65s linear infinite" } }) : /* @__PURE__ */ jsx(Download, { size: 13, strokeWidth: 2 }),
7129
- /* @__PURE__ */ jsx("span", { children: isDownloading ? "Downloading\u2026" : "Download" })
7130
- ]
7131
- }
7132
- ),
7133
- /* @__PURE__ */ jsx(
7134
- "button",
7135
- {
7136
- type: "button",
7137
- className: "payman-v2-pdf-sheet-close-btn",
7138
- "aria-label": "Close preview",
7139
- onClick: (e) => {
7140
- e.stopPropagation();
7141
- onClose();
7142
- },
7143
- children: /* @__PURE__ */ jsx(X, { size: 15, strokeWidth: 2.25 })
7144
- }
7145
- )
7146
- ] })
7147
- ] }),
7148
- /* @__PURE__ */ jsx("div", { className: "payman-v2-pdf-sheet-body", children: previewError ? /* @__PURE__ */ jsxs("div", { className: "payman-v2-pdf-sheet-error", role: "alert", children: [
7149
- /* @__PURE__ */ jsx("div", { className: "payman-v2-pdf-sheet-error-icon", children: /* @__PURE__ */ jsx(AlertCircle, { size: 22, strokeWidth: 1.75 }) }),
7150
- /* @__PURE__ */ jsx("p", { className: "payman-v2-pdf-sheet-error-title", children: previewError.title }),
7151
- /* @__PURE__ */ jsx("p", { className: "payman-v2-pdf-sheet-error-message", children: previewError.userMessage }),
7152
- /* @__PURE__ */ jsxs("div", { className: "payman-v2-pdf-sheet-error-actions", children: [
7153
- previewError.kind === "network" && /* @__PURE__ */ jsxs(
7154
- "button",
7155
- {
7156
- type: "button",
7157
- className: "payman-v2-pdf-sheet-error-btn",
7158
- onClick: handleRetry,
7159
- children: [
7160
- /* @__PURE__ */ jsx(RefreshCw, { size: 14, strokeWidth: 2 }),
7161
- /* @__PURE__ */ jsx("span", { children: "Try again" })
7162
- ]
7163
- }
7164
- ),
7165
- (previewError.kind === "network" || previewError.kind === "unknown") && /* @__PURE__ */ jsxs(
7166
- "button",
7167
- {
7168
- type: "button",
7169
- className: "payman-v2-pdf-sheet-error-btn payman-v2-pdf-sheet-error-btn-secondary",
7170
- onClick: handleOpenInNewTab,
7171
- children: [
7172
- /* @__PURE__ */ jsx(ExternalLink, { size: 14, strokeWidth: 2 }),
7173
- /* @__PURE__ */ jsx("span", { children: "Open link" })
7174
- ]
7175
- }
7176
- )
7177
- ] })
7178
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
7179
- (!isLoaded || !previewUrl) && /* @__PURE__ */ jsxs("div", { className: "payman-v2-pdf-sheet-loading", children: [
7180
- /* @__PURE__ */ jsx(
7181
- Loader2,
7182
- {
7183
- size: 20,
7184
- strokeWidth: 2,
7185
- style: { animation: "payman-v2-spin 0.65s linear infinite", color: "var(--payman-v2-text-3)" }
7186
- }
7187
- ),
7188
- /* @__PURE__ */ jsx("p", { className: "payman-v2-pdf-sheet-loading-text", children: previewUrl ? "Preparing preview\u2026" : "Opening document\u2026" })
7189
- ] }),
7190
- previewUrl && /* @__PURE__ */ jsx(
7191
- "iframe",
7192
- {
7193
- src: previewUrl,
7194
- title: title || "PDF Preview",
7195
- className: "payman-v2-pdf-sheet-iframe",
7196
- style: {
7197
- opacity: isLoaded ? 1 : 0,
7198
- transition: "opacity 0.3s ease",
7199
- pointerEvents: isDragging ? "none" : "auto"
7200
- },
7201
- onLoad: () => setIsLoaded(true)
7202
- },
7203
- previewUrl
7204
- )
7205
- ] }) })
7206
- ]
7207
- }
7208
- );
7209
- }
7210
6091
  var DEFAULT_USER_ACTION_STATE = {
7211
6092
  prompts: [],
7212
6093
  notifications: []
@@ -7301,8 +6182,7 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
7301
6182
  onLoadMoreMessages,
7302
6183
  isLoadingMoreMessages = false,
7303
6184
  hasMoreMessages = false,
7304
- chat,
7305
- attachmentUpload
6185
+ chat
7306
6186
  }, ref) {
7307
6187
  const [inputValue, setInputValue] = useState("");
7308
6188
  const prevInputValueRef = useRef(inputValue);
@@ -7356,6 +6236,7 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
7356
6236
  const submitUserAction2 = chat.submitUserAction ?? NOOP_ASYNC;
7357
6237
  const cancelUserAction2 = chat.cancelUserAction ?? NOOP_ASYNC;
7358
6238
  const resendUserAction2 = chat.resendUserAction ?? NOOP_ASYNC;
6239
+ const expireUserAction = chat.expireUserAction ?? NOOP_ASYNC;
7359
6240
  const dismissNotification = chat.dismissNotification ?? NOOP;
7360
6241
  const isUserActionSupported = typeof chat.submitUserAction === "function" && typeof chat.cancelUserAction === "function" && typeof chat.resendUserAction === "function";
7361
6242
  const {
@@ -7381,19 +6262,6 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
7381
6262
  }
7382
6263
  }
7383
6264
  );
7384
- const [pdfSheet, setPdfSheet] = useState(null);
7385
- const autoOpenedPdfHrefsRef = useRef(/* @__PURE__ */ new Set());
7386
- const pdfPreviewMode = config.pdfPreviewMode ?? "split";
7387
- const openPdfSheet = useCallback((href, title, options) => {
7388
- if (options?.auto) {
7389
- if (autoOpenedPdfHrefsRef.current.has(href)) return;
7390
- autoOpenedPdfHrefsRef.current.add(href);
7391
- }
7392
- setPdfSheet({ href, title });
7393
- }, []);
7394
- const closePdfSheet = useCallback(() => {
7395
- setPdfSheet(null);
7396
- }, []);
7397
6265
  const contextValue = useMemo(
7398
6266
  () => ({
7399
6267
  resetSession,
@@ -7402,8 +6270,7 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
7402
6270
  cancelStream,
7403
6271
  getSessionId,
7404
6272
  getMessages,
7405
- isWaitingForResponse,
7406
- openPdfSheet
6273
+ isWaitingForResponse
7407
6274
  }),
7408
6275
  [
7409
6276
  resetSession,
@@ -7412,8 +6279,7 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
7412
6279
  cancelStream,
7413
6280
  getSessionId,
7414
6281
  getMessages,
7415
- isWaitingForResponse,
7416
- openPdfSheet
6282
+ isWaitingForResponse
7417
6283
  ]
7418
6284
  );
7419
6285
  const {
@@ -7469,10 +6335,7 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
7469
6335
  setInputValue("");
7470
6336
  setLightboxSrc(null);
7471
6337
  setLightboxAlt("");
7472
- setPdfSheet(null);
7473
- autoOpenedPdfHrefsRef.current.clear();
7474
6338
  chatInputV2Ref.current?.setDraft("");
7475
- chatInputV2Ref.current?.clearAttachments();
7476
6339
  clearTranscript();
7477
6340
  if (isRecording) {
7478
6341
  stopRecording();
@@ -7523,20 +6386,14 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
7523
6386
  emptyStateComponent,
7524
6387
  showResetSession = false,
7525
6388
  enableDeepModeToggle = true,
6389
+ showAttachmentButton = true,
6390
+ showUploadImageButton = true,
6391
+ showAttachFileButton = true,
7526
6392
  messageActions: messageActionsConfig,
7527
6393
  enableSlashCommands = true,
7528
6394
  slashCommands: slashCommandsConfig,
7529
6395
  commandPermissions
7530
6396
  } = config;
7531
- const attachmentSettings = useMemo(
7532
- () => resolveChatAttachmentConfig(config),
7533
- [
7534
- config.attachments,
7535
- config.showAttachmentButton,
7536
- config.showUploadImageButton,
7537
- config.showAttachFileButton
7538
- ]
7539
- );
7540
6397
  const messageActions = useMemo(
7541
6398
  () => ({
7542
6399
  userMessageActions: {
@@ -7624,22 +6481,11 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
7624
6481
  };
7625
6482
  const userActionPrompts = isUserActionSupported ? userActionState.prompts : void 0;
7626
6483
  const notifications = userActionState.notifications;
7627
- const handleAttachmentsChange = useCallback(
7628
- (attachments) => {
7629
- attachmentUpload.syncAttachments(attachments);
7630
- },
7631
- [attachmentUpload]
7632
- );
7633
- const handleV2Send = (text, files = [], attachments = []) => {
6484
+ const handleV2Send = (text) => {
7634
6485
  if (isRecording) stopRecording();
7635
- if ((text.trim() || files.length > 0) && !disableInput && isSessionParamsConfigured) {
7636
- if (files.length > 0 && attachments.length === 0) return;
6486
+ if (text.trim() && !disableInput && isSessionParamsConfigured) {
7637
6487
  setEditingMessageId(null);
7638
- void sendMessage(text.trim(), {
7639
- analysisMode: effectiveAnalysisMode,
7640
- attachments,
7641
- files
7642
- });
6488
+ void sendMessage(text.trim(), { analysisMode: effectiveAnalysisMode });
7643
6489
  }
7644
6490
  };
7645
6491
  const handleVoicePress = useCallback(async () => {
@@ -7687,214 +6533,156 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
7687
6533
  style,
7688
6534
  children: [
7689
6535
  children,
7690
- /* @__PURE__ */ jsxs(
7691
- "div",
6536
+ /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: isEmpty && !hasEverSentMessage ? /* @__PURE__ */ jsx(
6537
+ motion.div,
7692
6538
  {
7693
- className: cn(
7694
- "payman-v2-split-layout",
7695
- pdfPreviewMode === "sheet" && "payman-v2-split-layout--sheet"
7696
- ),
7697
- children: [
7698
- /* @__PURE__ */ jsx("div", { className: "payman-v2-chat-column", children: /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: isEmpty && !hasEverSentMessage ? /* @__PURE__ */ jsx(
7699
- motion.div,
7700
- {
7701
- initial: { opacity: 1 },
7702
- exit: { opacity: 0 },
7703
- transition: { duration: 0.3 },
7704
- className: "payman-v2-chat-layout",
7705
- style: { justifyContent: "center", alignItems: "center" },
7706
- children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", flex: 1, width: "100%" }, children: [
7707
- /* @__PURE__ */ jsx(
7708
- MessageList,
7709
- {
7710
- messages,
7711
- isLoading: false,
7712
- emptyStateText,
7713
- showEmptyStateIcon,
7714
- emptyStateComponent,
7715
- layout,
7716
- showTimestamps,
7717
- stage: config.stage || "DEVELOPMENT",
7718
- animated,
7719
- showAgentName,
7720
- agentName,
7721
- showAvatars,
7722
- showUserAvatar,
7723
- showAssistantAvatar,
7724
- showExecutionSteps,
7725
- showStreamingDot,
7726
- streamingStepsText,
7727
- completedStepsText,
7728
- onExecutionTraceClick,
7729
- onLoadMoreMessages,
7730
- isLoadingMoreMessages,
7731
- hasMoreMessages
7732
- }
7733
- ),
7734
- /* @__PURE__ */ jsx(
7735
- motion.div,
7736
- {
7737
- initial: { opacity: 0, y: 12 },
7738
- animate: { opacity: 1, y: 0 },
7739
- transition: { delay: 0.2, duration: 0.4, ease: [0.25, 0.46, 0.45, 0.94] },
7740
- style: { width: "100%" },
7741
- children: hasAskPermission && /* @__PURE__ */ jsx(
7742
- ChatInputV2,
7743
- {
7744
- ref: chatInputV2Ref,
7745
- onSend: handleV2Send,
7746
- onCancel: cancelStream,
7747
- disabled: isV2InputDisabled,
7748
- isStreaming: isWaitingForResponse,
7749
- isUploadingAttachments: attachmentUpload.isUploading,
7750
- attachmentsReady: attachmentUpload.allReady,
7751
- hasAttachmentUploadErrors: attachmentUpload.hasErrors,
7752
- attachmentUploadStatusById: attachmentUpload.statusById,
7753
- uploadedAttachmentPayloads: attachmentUpload.payloads,
7754
- onAttachmentsChange: handleAttachmentsChange,
7755
- placeholder: isRecording ? "Listening..." : placeholder,
7756
- enableVoice: config.enableVoice === true,
7757
- transcribedText: config.enableVoice === true ? transcribedText : "",
7758
- voiceAvailable: config.enableVoice === true && voiceAvailable,
7759
- isRecording,
7760
- onVoicePress: config.enableVoice === true ? handleVoicePress : void 0,
7761
- onCancelRecording: handleCancelRecording,
7762
- onConfirmRecording: handleConfirmRecording,
7763
- showResetSession,
7764
- onResetSession: requestResetSession,
7765
- showAttachmentButton: attachmentSettings.showAttachmentButton,
7766
- showUploadImageButton: attachmentSettings.showUploadImageButton,
7767
- showAttachFileButton: attachmentSettings.showAttachFileButton,
7768
- allowedImageExtensions: attachmentSettings.allowedImageExtensions,
7769
- allowedFileExtensions: attachmentSettings.allowedFileExtensions,
7770
- maxCount: attachmentSettings.maxCount,
7771
- maxFileBytes: attachmentSettings.maxFileBytes,
7772
- maxTotalBytes: attachmentSettings.maxTotalBytes,
7773
- onUploadImageClick,
7774
- onAttachFileClick,
7775
- editingMessageId,
7776
- onClearEditing: handleClearEditing,
7777
- analysisMode: enableDeepModeToggle ? analysisMode : void 0,
7778
- onAnalysisModeChange: enableDeepModeToggle ? setAnalysisMode : void 0,
7779
- slashCommands
7780
- }
7781
- )
7782
- }
7783
- )
7784
- ] })
7785
- },
7786
- "v2-empty"
7787
- ) : /* @__PURE__ */ jsxs(
7788
- motion.div,
7789
- {
7790
- initial: hasEverSentMessage ? { opacity: 0 } : false,
7791
- animate: { opacity: 1 },
7792
- transition: { duration: 0.3 },
7793
- className: "payman-v2-chat-layout",
7794
- children: [
7795
- /* @__PURE__ */ jsx(
7796
- MessageListV2,
7797
- {
7798
- ref: messageListV2Ref,
7799
- messages,
7800
- isStreaming: isWaitingForResponse,
7801
- sidePanelOpen: !!pdfSheet,
7802
- onEditUserMessage: handleEditMessageDraft,
7803
- onRetryUserMessage: handleRetryUserMessage,
7804
- onImageClick: handleImageClick,
7805
- onExecutionTraceClick,
7806
- messageActions,
7807
- retryDisabled: isWaitingForResponse,
7808
- typingSpeed: config.typingSpeed ?? 4,
7809
- userActionPrompts,
7810
- notifications,
7811
- onSubmitUserAction: isUserActionSupported ? submitUserAction2 : void 0,
7812
- onCancelUserAction: isUserActionSupported ? cancelUserAction2 : void 0,
7813
- onResendUserAction: isUserActionSupported ? resendUserAction2 : void 0,
7814
- onDismissNotification: dismissNotification,
7815
- onSubmitFeedback: handleSubmitFeedback
7816
- }
7817
- ),
7818
- /* @__PURE__ */ jsx(
7819
- StreamingIndicatorV2,
7820
- {
7821
- isStreaming: isWaitingForResponse,
7822
- loadingAnimation: config.loadingAnimation
7823
- }
7824
- ),
7825
- hasAskPermission && /* @__PURE__ */ jsx(
7826
- ChatInputV2,
7827
- {
7828
- ref: chatInputV2Ref,
7829
- onSend: handleV2Send,
7830
- onCancel: cancelStream,
7831
- disabled: isV2InputDisabled,
7832
- isStreaming: isWaitingForResponse,
7833
- isUploadingAttachments: attachmentUpload.isUploading,
7834
- attachmentsReady: attachmentUpload.allReady,
7835
- hasAttachmentUploadErrors: attachmentUpload.hasErrors,
7836
- attachmentUploadStatusById: attachmentUpload.statusById,
7837
- uploadedAttachmentPayloads: attachmentUpload.payloads,
7838
- onAttachmentsChange: handleAttachmentsChange,
7839
- placeholder: isRecording ? "Listening..." : placeholder,
7840
- enableVoice: config.enableVoice === true,
7841
- transcribedText: config.enableVoice === true ? transcribedText : "",
7842
- voiceAvailable: config.enableVoice === true && voiceAvailable,
7843
- isRecording,
7844
- onVoicePress: config.enableVoice === true ? handleVoicePress : void 0,
7845
- onCancelRecording: handleCancelRecording,
7846
- onConfirmRecording: handleConfirmRecording,
7847
- showResetSession,
7848
- onResetSession: requestResetSession,
7849
- showAttachmentButton: attachmentSettings.showAttachmentButton,
7850
- showUploadImageButton: attachmentSettings.showUploadImageButton,
7851
- showAttachFileButton: attachmentSettings.showAttachFileButton,
7852
- allowedImageExtensions: attachmentSettings.allowedImageExtensions,
7853
- allowedFileExtensions: attachmentSettings.allowedFileExtensions,
7854
- maxCount: attachmentSettings.maxCount,
7855
- maxFileBytes: attachmentSettings.maxFileBytes,
7856
- maxTotalBytes: attachmentSettings.maxTotalBytes,
7857
- onUploadImageClick,
7858
- onAttachFileClick,
7859
- editingMessageId,
7860
- onClearEditing: handleClearEditing,
7861
- analysisMode: enableDeepModeToggle ? analysisMode : void 0,
7862
- onAnalysisModeChange: enableDeepModeToggle ? setAnalysisMode : void 0,
7863
- slashCommands
7864
- }
7865
- )
7866
- ]
7867
- },
7868
- "v2-chat"
7869
- ) }) }),
7870
- pdfPreviewMode === "split" && /* @__PURE__ */ jsx(
7871
- PdfSheetV2,
6539
+ initial: { opacity: 1 },
6540
+ exit: { opacity: 0 },
6541
+ transition: { duration: 0.3 },
6542
+ className: "payman-v2-chat-layout",
6543
+ style: { justifyContent: "center", alignItems: "center" },
6544
+ children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", flex: 1, width: "100%" }, children: [
6545
+ /* @__PURE__ */ jsx(
6546
+ MessageList,
7872
6547
  {
7873
- src: pdfSheet?.href ?? null,
7874
- title: pdfSheet?.title ?? "",
7875
- onClose: closePdfSheet,
7876
- mode: "split"
6548
+ messages,
6549
+ isLoading: false,
6550
+ emptyStateText,
6551
+ showEmptyStateIcon,
6552
+ emptyStateComponent,
6553
+ layout,
6554
+ showTimestamps,
6555
+ stage: config.stage || "DEVELOPMENT",
6556
+ animated,
6557
+ showAgentName,
6558
+ agentName,
6559
+ showAvatars,
6560
+ showUserAvatar,
6561
+ showAssistantAvatar,
6562
+ showExecutionSteps,
6563
+ showStreamingDot,
6564
+ streamingStepsText,
6565
+ completedStepsText,
6566
+ onExecutionTraceClick,
6567
+ onLoadMoreMessages,
6568
+ isLoadingMoreMessages,
6569
+ hasMoreMessages
7877
6570
  }
7878
6571
  ),
7879
- pdfPreviewMode === "sheet" && /* @__PURE__ */ jsx(
7880
- "div",
6572
+ /* @__PURE__ */ jsx(
6573
+ motion.div,
7881
6574
  {
7882
- className: "payman-v2-pdf-sheet-top-anchor",
7883
- "aria-hidden": !pdfSheet,
7884
- children: /* @__PURE__ */ jsx(
7885
- PdfSheetV2,
6575
+ initial: { opacity: 0, y: 12 },
6576
+ animate: { opacity: 1, y: 0 },
6577
+ transition: { delay: 0.2, duration: 0.4, ease: [0.25, 0.46, 0.45, 0.94] },
6578
+ style: { width: "100%" },
6579
+ children: hasAskPermission && /* @__PURE__ */ jsx(
6580
+ ChatInputV2,
7886
6581
  {
7887
- src: pdfSheet?.href ?? null,
7888
- title: pdfSheet?.title ?? "",
7889
- onClose: closePdfSheet,
7890
- mode: "sheet"
6582
+ ref: chatInputV2Ref,
6583
+ onSend: handleV2Send,
6584
+ onCancel: cancelStream,
6585
+ disabled: isV2InputDisabled,
6586
+ isStreaming: isWaitingForResponse,
6587
+ placeholder: isRecording ? "Listening..." : placeholder,
6588
+ enableVoice: config.enableVoice === true,
6589
+ transcribedText: config.enableVoice === true ? transcribedText : "",
6590
+ voiceAvailable: config.enableVoice === true && voiceAvailable,
6591
+ isRecording,
6592
+ onVoicePress: config.enableVoice === true ? handleVoicePress : void 0,
6593
+ onCancelRecording: handleCancelRecording,
6594
+ onConfirmRecording: handleConfirmRecording,
6595
+ showResetSession,
6596
+ onResetSession: requestResetSession,
6597
+ showAttachmentButton,
6598
+ showUploadImageButton,
6599
+ showAttachFileButton,
6600
+ onUploadImageClick,
6601
+ onAttachFileClick,
6602
+ editingMessageId,
6603
+ onClearEditing: handleClearEditing,
6604
+ analysisMode: enableDeepModeToggle ? analysisMode : void 0,
6605
+ onAnalysisModeChange: enableDeepModeToggle ? setAnalysisMode : void 0,
6606
+ slashCommands
7891
6607
  }
7892
6608
  )
7893
6609
  }
7894
6610
  )
6611
+ ] })
6612
+ },
6613
+ "v2-empty"
6614
+ ) : /* @__PURE__ */ jsxs(
6615
+ motion.div,
6616
+ {
6617
+ initial: hasEverSentMessage ? { opacity: 0 } : false,
6618
+ animate: { opacity: 1 },
6619
+ transition: { duration: 0.3 },
6620
+ className: "payman-v2-chat-layout",
6621
+ children: [
6622
+ /* @__PURE__ */ jsx(
6623
+ MessageListV2,
6624
+ {
6625
+ ref: messageListV2Ref,
6626
+ messages,
6627
+ isStreaming: isWaitingForResponse,
6628
+ onEditUserMessage: handleEditMessageDraft,
6629
+ onRetryUserMessage: handleRetryUserMessage,
6630
+ onImageClick: handleImageClick,
6631
+ onExecutionTraceClick,
6632
+ messageActions,
6633
+ retryDisabled: isWaitingForResponse,
6634
+ typingSpeed: config.typingSpeed ?? 4,
6635
+ userActionPrompts,
6636
+ notifications,
6637
+ onSubmitUserAction: isUserActionSupported ? submitUserAction2 : void 0,
6638
+ onCancelUserAction: isUserActionSupported ? cancelUserAction2 : void 0,
6639
+ onResendUserAction: isUserActionSupported ? resendUserAction2 : void 0,
6640
+ onExpireUserAction: isUserActionSupported ? expireUserAction : void 0,
6641
+ onDismissNotification: dismissNotification,
6642
+ onSubmitFeedback: handleSubmitFeedback
6643
+ }
6644
+ ),
6645
+ /* @__PURE__ */ jsx(
6646
+ StreamingIndicatorV2,
6647
+ {
6648
+ isStreaming: isWaitingForResponse,
6649
+ loadingAnimation: config.loadingAnimation
6650
+ }
6651
+ ),
6652
+ hasAskPermission && /* @__PURE__ */ jsx(
6653
+ ChatInputV2,
6654
+ {
6655
+ ref: chatInputV2Ref,
6656
+ onSend: handleV2Send,
6657
+ onCancel: cancelStream,
6658
+ disabled: isV2InputDisabled,
6659
+ isStreaming: isWaitingForResponse,
6660
+ placeholder: isRecording ? "Listening..." : placeholder,
6661
+ enableVoice: config.enableVoice === true,
6662
+ transcribedText: config.enableVoice === true ? transcribedText : "",
6663
+ voiceAvailable: config.enableVoice === true && voiceAvailable,
6664
+ isRecording,
6665
+ onVoicePress: config.enableVoice === true ? handleVoicePress : void 0,
6666
+ onCancelRecording: handleCancelRecording,
6667
+ onConfirmRecording: handleConfirmRecording,
6668
+ showResetSession,
6669
+ onResetSession: requestResetSession,
6670
+ showAttachmentButton,
6671
+ showUploadImageButton,
6672
+ showAttachFileButton,
6673
+ onUploadImageClick,
6674
+ onAttachFileClick,
6675
+ editingMessageId,
6676
+ onClearEditing: handleClearEditing,
6677
+ analysisMode: enableDeepModeToggle ? analysisMode : void 0,
6678
+ onAnalysisModeChange: enableDeepModeToggle ? setAnalysisMode : void 0,
6679
+ slashCommands
6680
+ }
6681
+ )
7895
6682
  ]
7896
- }
7897
- ),
6683
+ },
6684
+ "v2-chat"
6685
+ ) }),
7898
6686
  /* @__PURE__ */ jsx(
7899
6687
  ImageLightboxV2,
7900
6688
  {
@@ -7929,19 +6717,10 @@ var PaymanChat = forwardRef(
7929
6717
  function PaymanChat2(props, ref) {
7930
6718
  const mergedCallbacks = useSentryChatCallbacks(props.callbacks, props.config);
7931
6719
  const chat = useChatV2(props.config, mergedCallbacks);
7932
- const attachmentUpload = useAttachmentUpload(props.config);
7933
- return /* @__PURE__ */ jsx(
7934
- PaymanChatInner,
7935
- {
7936
- ...props,
7937
- chat,
7938
- attachmentUpload,
7939
- ref
7940
- }
7941
- );
6720
+ return /* @__PURE__ */ jsx(PaymanChatInner, { ...props, chat, ref });
7942
6721
  }
7943
6722
  );
7944
6723
 
7945
- export { PaymanChat, PaymanChatContext, PdfSheetV2, UserActionStaleError, buildSignedUrlEndpoint, cancelUserAction, captureSentryError, cn, formatAttachmentBytes, formatDate, getPdfTitleFromUrl, isPdfUrl, mapExecutionHistoryPageToChatMessages, mapExecutionHistoryToChatMessages, resendUserAction, stripAttachmentsSuffixFromIntent, submitUserAction, uploadAttachment, uploadAttachments, useAttachmentUpload, useChatV2, usePaymanChat, useVoice };
6724
+ export { PaymanChat, PaymanChatContext, UserActionStaleError, cancelUserAction, captureSentryError, cn, formatDate, resendUserAction, submitUserAction, useChatV2, usePaymanChat, useVoice };
7946
6725
  //# sourceMappingURL=index.mjs.map
7947
6726
  //# sourceMappingURL=index.mjs.map