@paymanai/payman-ask-sdk 1.2.19 → 1.2.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
@@ -4,10 +4,12 @@ import { AnimatePresence, motion } from 'framer-motion';
4
4
  import { createContext, forwardRef, useState, useRef, useEffect, useMemo, useImperativeHandle, useCallback, useLayoutEffect, useContext } from 'react';
5
5
  import { clsx } from 'clsx';
6
6
  import { twMerge } from 'tailwind-merge';
7
+ import * as Sentry from '@sentry/react';
7
8
  import { Check, RotateCcw, Mic, ArrowUp, ArrowDown, X, Loader2, User, Clock, Sparkles, Binoculars, ChevronDown, ChevronRight } from 'lucide-react';
8
9
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
9
10
  import ReactMarkdown from 'react-markdown';
10
11
  import remarkGfm from 'remark-gfm';
12
+ import { createPortal } from 'react-dom';
11
13
 
12
14
  var PaymanChatContext = createContext(void 0);
13
15
  function usePaymanChat() {
@@ -52,6 +54,17 @@ function formatElapsedTime(ms) {
52
54
  if (ms < 1e3) return `${ms}ms`;
53
55
  return `${(ms / 1e3).toFixed(1)}s`;
54
56
  }
57
+ function initSentryIfNeeded(dsn) {
58
+ if (!dsn) return;
59
+ if (Sentry.getClient()) return;
60
+ Sentry.init({
61
+ dsn,
62
+ sendDefaultPii: true,
63
+ initialScope: {
64
+ tags: { source: "payman-ask-sdk" }
65
+ }
66
+ });
67
+ }
55
68
  var AI_DISCLAIMER_TEXT = "AI can make mistakes. Please double-check responses.";
56
69
  function ChatInput({
57
70
  value,
@@ -315,6 +328,256 @@ function ChatInput({
315
328
  }
316
329
  );
317
330
  }
331
+ function ImageLightbox({
332
+ src,
333
+ alt = "",
334
+ onClose
335
+ }) {
336
+ const [isMounted, setIsMounted] = useState(false);
337
+ const [isImageLoaded, setIsImageLoaded] = useState(false);
338
+ const overlayStyle = {
339
+ position: "fixed",
340
+ inset: 0,
341
+ zIndex: 2147483647,
342
+ display: "flex",
343
+ alignItems: "center",
344
+ justifyContent: "center",
345
+ padding: 16,
346
+ background: "rgba(2, 6, 23, 0.92)",
347
+ isolation: "isolate"
348
+ };
349
+ const frameStyle = {
350
+ position: "relative",
351
+ width: "min(92vw, 1280px)",
352
+ height: "min(88vh, 920px)",
353
+ display: "flex",
354
+ alignItems: "center",
355
+ justifyContent: "center",
356
+ overflow: "hidden"
357
+ };
358
+ useEffect(() => {
359
+ setIsMounted(true);
360
+ return () => setIsMounted(false);
361
+ }, []);
362
+ useEffect(() => {
363
+ setIsImageLoaded(false);
364
+ }, [src]);
365
+ useEffect(() => {
366
+ if (typeof document === "undefined") return;
367
+ const previousOverflow = document.body.style.overflow;
368
+ document.body.style.overflow = "hidden";
369
+ return () => {
370
+ document.body.style.overflow = previousOverflow;
371
+ };
372
+ }, []);
373
+ useEffect(() => {
374
+ if (typeof document === "undefined") return;
375
+ const handleKeyDown = (event) => {
376
+ if (event.key === "Escape") {
377
+ onClose();
378
+ }
379
+ };
380
+ document.addEventListener("keydown", handleKeyDown);
381
+ return () => {
382
+ document.removeEventListener("keydown", handleKeyDown);
383
+ };
384
+ }, [onClose]);
385
+ if (!isMounted || typeof document === "undefined") {
386
+ return null;
387
+ }
388
+ return createPortal(
389
+ /* @__PURE__ */ jsx(AnimatePresence, { children: /* @__PURE__ */ jsxs(
390
+ motion.div,
391
+ {
392
+ style: overlayStyle,
393
+ initial: { opacity: 0 },
394
+ animate: { opacity: 1 },
395
+ exit: { opacity: 0 },
396
+ transition: { duration: 0.18 },
397
+ onClick: onClose,
398
+ children: [
399
+ /* @__PURE__ */ jsx(
400
+ "button",
401
+ {
402
+ type: "button",
403
+ onClick: onClose,
404
+ className: "absolute top-4 right-4 z-[1] flex h-9 w-9 items-center justify-center rounded-full bg-black/60 text-white/90 transition-colors hover:bg-black/75",
405
+ "aria-label": "Close",
406
+ children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
407
+ }
408
+ ),
409
+ /* @__PURE__ */ jsxs("div", { style: frameStyle, onClick: (event) => event.stopPropagation(), children: [
410
+ !isImageLoaded ? /* @__PURE__ */ jsxs("div", { className: "absolute inset-0 flex flex-col items-center justify-center gap-2", children: [
411
+ /* @__PURE__ */ jsx(Loader2, { className: "h-5 w-5 animate-spin text-white/80" }),
412
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-white/90", children: "Loading image" }),
413
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-white/60", children: "Reference image" })
414
+ ] }) : null,
415
+ /* @__PURE__ */ jsx("div", { className: "flex h-full w-full items-center justify-center p-3 sm:p-4", children: /* @__PURE__ */ jsx(
416
+ "img",
417
+ {
418
+ src,
419
+ alt,
420
+ draggable: false,
421
+ onLoad: () => setIsImageLoaded(true),
422
+ className: `block h-full w-full rounded-xl object-contain shadow-2xl transition-opacity duration-200 ${isImageLoaded ? "opacity-100" : "opacity-0"}`
423
+ }
424
+ ) })
425
+ ] })
426
+ ]
427
+ }
428
+ ) }),
429
+ document.body
430
+ );
431
+ }
432
+ var RAG_IMAGE_PATH_REGEX = /^(?:https?:\/\/[^/\s]+)?\/api\/rag\/chunks\/[^"'\s]+\/image(?:[?#][^"'\s]*)?$/;
433
+ function isUnresolvedRagImageSource(src) {
434
+ return RAG_IMAGE_PATH_REGEX.test(src);
435
+ }
436
+ function LoadingImageCard({
437
+ label,
438
+ description
439
+ }) {
440
+ return /* @__PURE__ */ jsxs("span", { className: "my-3 flex min-h-36 w-full flex-col items-center justify-center gap-2 px-4 py-5 text-center", children: [
441
+ /* @__PURE__ */ jsx(Loader2, { className: "h-5 w-5 animate-spin text-slate-500 dark:text-slate-300" }),
442
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-slate-600 dark:text-slate-200", children: label }),
443
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] leading-relaxed text-slate-500/90 dark:text-slate-300/80", children: description })
444
+ ] });
445
+ }
446
+ function BrokenImageCard({ alt }) {
447
+ return /* @__PURE__ */ jsxs("span", { className: "my-3 flex min-h-44 w-full flex-col items-center justify-center gap-2 rounded-xl border border-dashed border-red-200 bg-red-50/60 px-4 py-5 text-center dark:border-red-900/40 dark:bg-red-950/20", children: [
448
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-red-600 dark:text-red-300", children: "Unable to load image" }),
449
+ alt ? /* @__PURE__ */ jsx("span", { className: "max-w-sm text-[11px] leading-relaxed text-red-500/80 dark:text-red-200/80", children: alt }) : null
450
+ ] });
451
+ }
452
+ function MarkdownImage({
453
+ src,
454
+ alt,
455
+ isResolving = false
456
+ }) {
457
+ const imageFrameStyle = {
458
+ width: "min(100%, 32rem)",
459
+ maxWidth: "100%"
460
+ };
461
+ const imageStyle = {
462
+ display: "block",
463
+ width: "100%",
464
+ height: "auto",
465
+ maxWidth: "100%",
466
+ maxHeight: "18rem",
467
+ objectFit: "contain"
468
+ };
469
+ const [isLoaded, setIsLoaded] = useState(false);
470
+ const [hasError, setHasError] = useState(false);
471
+ const [isLightboxOpen, setIsLightboxOpen] = useState(false);
472
+ const isUnresolvedRagImage = useMemo(
473
+ () => src ? isUnresolvedRagImageSource(src) : false,
474
+ [src]
475
+ );
476
+ const isResolvingRagImage = isResolving && isUnresolvedRagImage;
477
+ useEffect(() => {
478
+ setIsLoaded(false);
479
+ setHasError(false);
480
+ setIsLightboxOpen(false);
481
+ }, [src]);
482
+ if (!src) {
483
+ return null;
484
+ }
485
+ if (isResolvingRagImage) {
486
+ return /* @__PURE__ */ jsx(LoadingImageCard, { label: "Loading image", description: "Reference image" });
487
+ }
488
+ if (hasError) {
489
+ return /* @__PURE__ */ jsx(BrokenImageCard, { alt });
490
+ }
491
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
492
+ /* @__PURE__ */ jsx("span", { className: "my-3 block w-full", children: /* @__PURE__ */ jsx(
493
+ "button",
494
+ {
495
+ type: "button",
496
+ onClick: () => {
497
+ if (isLoaded) {
498
+ setIsLightboxOpen(true);
499
+ }
500
+ },
501
+ disabled: !isLoaded,
502
+ "aria-busy": !isLoaded,
503
+ className: "group relative mx-auto flex w-full items-center justify-center overflow-hidden rounded-xl bg-black/[0.03] px-3 py-3 text-left transition-colors hover:bg-black/[0.05] disabled:cursor-wait disabled:hover:bg-black/[0.03] dark:bg-white/[0.03] dark:hover:bg-white/[0.05] dark:disabled:hover:bg-white/[0.03]",
504
+ style: {
505
+ ...imageFrameStyle,
506
+ ...!isLoaded ? { minHeight: "9rem" } : {}
507
+ },
508
+ children: /* @__PURE__ */ jsx(
509
+ "img",
510
+ {
511
+ src,
512
+ alt: alt || "",
513
+ className: `relative z-[1] block h-auto max-h-[22rem] w-full max-w-full rounded-lg object-contain transition-opacity duration-200 ${isLoaded ? "opacity-100" : "opacity-0"}`,
514
+ style: imageStyle,
515
+ onLoad: () => {
516
+ setHasError(false);
517
+ setIsLoaded(true);
518
+ },
519
+ onError: () => {
520
+ setIsLoaded(false);
521
+ setHasError(true);
522
+ }
523
+ }
524
+ )
525
+ }
526
+ ) }),
527
+ isLightboxOpen && isLoaded ? /* @__PURE__ */ jsx(
528
+ ImageLightbox,
529
+ {
530
+ src,
531
+ alt,
532
+ onClose: () => setIsLightboxOpen(false)
533
+ }
534
+ ) : null
535
+ ] });
536
+ }
537
+ function createMarkdownComponents(options = {}) {
538
+ return {
539
+ p: ({ children }) => /* @__PURE__ */ jsx("p", { className: "mb-3 last:mb-0 text-sm leading-relaxed", children }),
540
+ code: ({ className: codeClassName, children }) => {
541
+ const isInline = !codeClassName;
542
+ return isInline ? /* @__PURE__ */ jsx("code", { className: "payman-agent-code-inline rounded-md px-1.5 py-0.5 font-mono text-xs break-all", children }) : /* @__PURE__ */ jsx("code", { className: "payman-agent-code-block my-2 block overflow-x-auto rounded-lg p-3 font-mono text-xs whitespace-pre", children });
543
+ },
544
+ pre: ({ children }) => /* @__PURE__ */ jsx("pre", { className: "my-2 max-w-full overflow-x-auto rounded-lg", children }),
545
+ ul: ({ children }) => /* @__PURE__ */ jsx("ul", { className: "mb-3 ml-4 list-disc space-y-1 text-sm", children }),
546
+ ol: ({ children }) => /* @__PURE__ */ jsx("ol", { className: "mb-3 ml-4 list-decimal space-y-1 text-sm", children }),
547
+ li: ({ children }) => /* @__PURE__ */ jsx("li", { className: "text-sm leading-relaxed", children }),
548
+ h1: ({ children }) => /* @__PURE__ */ jsx("h1", { className: "mt-4 mb-2 text-lg font-semibold first:mt-0", children }),
549
+ h2: ({ children }) => /* @__PURE__ */ jsx("h2", { className: "mt-3 mb-2 text-base font-semibold first:mt-0", children }),
550
+ h3: ({ children }) => /* @__PURE__ */ jsx("h3", { className: "mt-2 mb-1 text-sm font-semibold first:mt-0", children }),
551
+ strong: ({ children }) => /* @__PURE__ */ jsx("strong", { className: "font-semibold", children }),
552
+ em: ({ children }) => /* @__PURE__ */ jsx("em", { className: "italic", children }),
553
+ blockquote: ({ children }) => /* @__PURE__ */ jsx("blockquote", { className: "payman-agent-blockquote my-2 pl-4 italic", children }),
554
+ hr: () => /* @__PURE__ */ jsx("hr", { className: "payman-agent-hr my-4" }),
555
+ a: ({ href, children }) => /* @__PURE__ */ jsx(
556
+ "a",
557
+ {
558
+ href,
559
+ target: "_blank",
560
+ rel: "noopener noreferrer",
561
+ className: "payman-agent-link underline decoration-1 underline-offset-2",
562
+ children
563
+ }
564
+ ),
565
+ img: ({ src, alt }) => /* @__PURE__ */ jsx(
566
+ MarkdownImage,
567
+ {
568
+ src: typeof src === "string" ? src : void 0,
569
+ alt: typeof alt === "string" ? alt : void 0,
570
+ isResolving: options.isResolvingImages
571
+ }
572
+ ),
573
+ table: ({ children }) => /* @__PURE__ */ jsx("div", { className: "relative my-4 -mx-1 w-full overflow-x-auto", children: /* @__PURE__ */ jsx("table", { className: "payman-agent-table min-w-full caption-bottom overflow-hidden rounded-lg text-sm", children }) }),
574
+ thead: ({ children }) => /* @__PURE__ */ jsx("thead", { className: "payman-agent-thead [&_tr]:border-b", children }),
575
+ tbody: ({ children }) => /* @__PURE__ */ jsx("tbody", { className: "[&_tr:last-child]:border-0", children }),
576
+ tr: ({ children }) => /* @__PURE__ */ jsx("tr", { className: "payman-agent-tr border-b transition-colors", children }),
577
+ th: ({ children }) => /* @__PURE__ */ jsx("th", { className: "h-10 px-3 text-left align-middle text-xs font-medium whitespace-nowrap", children }),
578
+ td: ({ children }) => /* @__PURE__ */ jsx("td", { className: "p-3 align-middle text-sm whitespace-nowrap", children })
579
+ };
580
+ }
318
581
 
319
582
  // src/utils/errorMessages.ts
320
583
  var WORKFLOW_FAILED = "WORKFLOW_FAILED";
@@ -447,6 +710,12 @@ function AgentMessage({
447
710
  ),
448
711
  [message.steps, currentExecutingStepId]
449
712
  );
713
+ const markdownRenderers = useMemo(
714
+ () => createMarkdownComponents({
715
+ isResolvingImages: message.isResolvingImages
716
+ }),
717
+ [message.isResolvingImages]
718
+ );
450
719
  const getStepsLabel = (streaming) => {
451
720
  const count = message.steps.length;
452
721
  const stepWord = count === 1 ? "step" : "steps";
@@ -634,7 +903,7 @@ function AgentMessage({
634
903
  ReactMarkdown,
635
904
  {
636
905
  remarkPlugins: [remarkGfm],
637
- components: markdownComponents(),
906
+ components: markdownRenderers,
638
907
  children: isError ? conflictErrorMessage ?? FRIENDLY_ERROR_MESSAGE : content || (isStreaming ? "Thinking..." : isCancelled ? "Request was stopped." : "")
639
908
  }
640
909
  )
@@ -685,42 +954,6 @@ function AgentMessage({
685
954
  }
686
955
  return messageContent;
687
956
  }
688
- function markdownComponents(_isError) {
689
- return {
690
- p: ({ children }) => /* @__PURE__ */ jsx("p", { className: "mb-3 last:mb-0 text-sm leading-relaxed", children }),
691
- code: ({ className: codeClassName, children }) => {
692
- const isInline = !codeClassName;
693
- return isInline ? /* @__PURE__ */ jsx("code", { className: "px-1.5 py-0.5 rounded-md text-xs font-mono break-all payman-agent-code-inline", children }) : /* @__PURE__ */ jsx("code", { className: "block p-3 rounded-lg text-xs font-mono overflow-x-auto my-2 whitespace-pre payman-agent-code-block", children });
694
- },
695
- pre: ({ children }) => /* @__PURE__ */ jsx("pre", { className: "my-2 overflow-x-auto max-w-full rounded-lg", children }),
696
- ul: ({ children }) => /* @__PURE__ */ jsx("ul", { className: "list-disc ml-4 mb-3 space-y-1 text-sm", children }),
697
- ol: ({ children }) => /* @__PURE__ */ jsx("ol", { className: "list-decimal ml-4 mb-3 space-y-1 text-sm", children }),
698
- li: ({ children }) => /* @__PURE__ */ jsx("li", { className: "text-sm leading-relaxed", children }),
699
- h1: ({ children }) => /* @__PURE__ */ jsx("h1", { className: "text-lg font-semibold mb-2 mt-4 first:mt-0", children }),
700
- h2: ({ children }) => /* @__PURE__ */ jsx("h2", { className: "text-base font-semibold mb-2 mt-3 first:mt-0", children }),
701
- h3: ({ children }) => /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold mb-1 mt-2 first:mt-0", children }),
702
- strong: ({ children }) => /* @__PURE__ */ jsx("strong", { className: "font-semibold", children }),
703
- em: ({ children }) => /* @__PURE__ */ jsx("em", { className: "italic", children }),
704
- blockquote: ({ children }) => /* @__PURE__ */ jsx("blockquote", { className: "pl-4 my-2 italic payman-agent-blockquote", children }),
705
- hr: () => /* @__PURE__ */ jsx("hr", { className: "my-4 payman-agent-hr" }),
706
- a: ({ href, children }) => /* @__PURE__ */ jsx(
707
- "a",
708
- {
709
- href,
710
- target: "_blank",
711
- rel: "noopener noreferrer",
712
- className: "underline underline-offset-2 decoration-1 payman-agent-link",
713
- children
714
- }
715
- ),
716
- table: ({ children }) => /* @__PURE__ */ jsx("div", { className: "relative w-full overflow-x-auto my-4 -mx-1", children: /* @__PURE__ */ jsx("table", { className: "min-w-full caption-bottom text-sm rounded-lg overflow-hidden payman-agent-table", children }) }),
717
- thead: ({ children }) => /* @__PURE__ */ jsx("thead", { className: "[&_tr]:border-b payman-agent-thead", children }),
718
- tbody: ({ children }) => /* @__PURE__ */ jsx("tbody", { className: "[&_tr:last-child]:border-0", children }),
719
- tr: ({ children }) => /* @__PURE__ */ jsx("tr", { className: "border-b transition-colors payman-agent-tr", children }),
720
- th: ({ children }) => /* @__PURE__ */ jsx("th", { className: "h-10 px-3 text-left align-middle font-medium whitespace-nowrap text-xs", children }),
721
- td: ({ children }) => /* @__PURE__ */ jsx("td", { className: "p-3 align-middle text-sm whitespace-nowrap", children })
722
- };
723
- }
724
957
  function UserMessage({
725
958
  message,
726
959
  animated = false,
@@ -1774,6 +2007,11 @@ var PaymanChat = forwardRef(function PaymanChat2({
1774
2007
  const [inputValue, setInputValue] = useState("");
1775
2008
  const prevInputValueRef = useRef(inputValue);
1776
2009
  const [hasEverSentMessage, setHasEverSentMessage] = useState(false);
2010
+ useEffect(() => {
2011
+ if (config.sentryDsn) {
2012
+ initSentryIfNeeded(config.sentryDsn);
2013
+ }
2014
+ }, [config.sentryDsn]);
1777
2015
  const chat = useChat(config, callbacks);
1778
2016
  const {
1779
2017
  messages,