@paymanai/payman-ask-sdk 1.2.24 → 1.2.26

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.js CHANGED
@@ -11,6 +11,7 @@ var jsxRuntime = require('react/jsx-runtime');
11
11
  var ReactMarkdown = require('react-markdown');
12
12
  var remarkGfm = require('remark-gfm');
13
13
  var reactDom = require('react-dom');
14
+ var flubber = require('flubber');
14
15
 
15
16
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
16
17
 
@@ -79,6 +80,114 @@ function formatElapsedTime(ms) {
79
80
  if (ms < 1e3) return `${ms}ms`;
80
81
  return `${(ms / 1e3).toFixed(1)}s`;
81
82
  }
83
+ function captureSentryError(error, context) {
84
+ if (!Sentry__namespace.getClient()) return;
85
+ const tags = {};
86
+ if (context.executionId) tags.executionId = context.executionId;
87
+ if (context.sessionId) tags.sessionId = context.sessionId;
88
+ if (context.route) tags.route = context.route;
89
+ if (context.cfRay) tags.cfRay = context.cfRay;
90
+ if (context.customerId) tags.customerId = context.customerId;
91
+ if (context.customerEmail) tags.customerEmail = context.customerEmail;
92
+ const contexts = {
93
+ chat_session: {
94
+ sessionId: context.sessionId ?? null,
95
+ sessionOwnerId: context.sessionOwnerId ?? null,
96
+ executionId: context.executionId ?? null,
97
+ workflowName: context.workflowName ?? null,
98
+ cfRay: context.cfRay ?? null,
99
+ customerId: context.customerId ?? null,
100
+ customerEmail: context.customerEmail ?? null
101
+ }
102
+ };
103
+ if (typeof error === "string") {
104
+ Sentry__namespace.captureMessage(error, { level: "error", tags, contexts });
105
+ } else {
106
+ Sentry__namespace.captureException(error, { tags, contexts });
107
+ }
108
+ }
109
+ var interceptors = /* @__PURE__ */ new Set();
110
+ var originalFetch = null;
111
+ function patchFetch() {
112
+ if (originalFetch !== null) return;
113
+ if (typeof globalThis === "undefined" || typeof globalThis.fetch !== "function")
114
+ return;
115
+ originalFetch = globalThis.fetch;
116
+ globalThis.fetch = async function(input, init2) {
117
+ const response = await originalFetch.call(this, input, init2);
118
+ if (interceptors.size > 0) {
119
+ const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
120
+ try {
121
+ const cfRay = response.headers.get("cf-ray");
122
+ if (cfRay) {
123
+ for (const entry of interceptors) {
124
+ if (url.includes(entry.urlPattern)) {
125
+ entry.listener(cfRay);
126
+ }
127
+ }
128
+ }
129
+ } catch {
130
+ }
131
+ }
132
+ return response;
133
+ };
134
+ }
135
+ function maybeUnpatchFetch() {
136
+ if (interceptors.size > 0 || originalFetch === null) return;
137
+ globalThis.fetch = originalFetch;
138
+ originalFetch = null;
139
+ }
140
+ function subscribeToCfRay(urlPattern, listener) {
141
+ const entry = { urlPattern, listener };
142
+ patchFetch();
143
+ interceptors.add(entry);
144
+ return () => {
145
+ interceptors.delete(entry);
146
+ maybeUnpatchFetch();
147
+ };
148
+ }
149
+
150
+ // src/utils/errorMessages.ts
151
+ var WORKFLOW_FAILED = "WORKFLOW_FAILED";
152
+ var STREAM_NOT_STARTED = "STREAM_NOT_STARTED";
153
+ var HTTP_ERROR_PREFIX = /^HTTP\s+(\d+)\s*:\s*([\s\S]+)$/;
154
+ function isFriendlyWorkflowError(errorDetails) {
155
+ if (!errorDetails) return false;
156
+ return errorDetails === WORKFLOW_FAILED || errorDetails === STREAM_NOT_STARTED || errorDetails.includes(WORKFLOW_FAILED);
157
+ }
158
+ function parseErrorPayload(payload) {
159
+ try {
160
+ const parsed = JSON.parse(payload);
161
+ if (typeof parsed === "string") {
162
+ return { message: parsed.trim() || void 0 };
163
+ }
164
+ if (typeof parsed === "object" && parsed !== null) {
165
+ const record = parsed;
166
+ return {
167
+ status: typeof record.status === "number" ? record.status : void 0,
168
+ message: typeof record.message === "string" && record.message.trim() ? record.message.trim() : void 0
169
+ };
170
+ }
171
+ } catch {
172
+ }
173
+ return {};
174
+ }
175
+ function getConflictErrorMessage(errorDetails) {
176
+ if (!errorDetails) return void 0;
177
+ const trimmedError = errorDetails.trim();
178
+ const httpMatch = trimmedError.match(HTTP_ERROR_PREFIX);
179
+ const httpStatus = httpMatch ? Number(httpMatch[1]) : void 0;
180
+ const rawPayload = (httpMatch ? httpMatch[2] : trimmedError).trim();
181
+ const payload = parseErrorPayload(rawPayload);
182
+ const status = payload.status ?? httpStatus;
183
+ if (status !== 409) {
184
+ return void 0;
185
+ }
186
+ if (payload.message) {
187
+ return payload.message;
188
+ }
189
+ return rawPayload || void 0;
190
+ }
82
191
  function initSentryIfNeeded(dsn) {
83
192
  if (!dsn) return;
84
193
  if (Sentry__namespace.getClient()) return;
@@ -603,48 +712,6 @@ function createMarkdownComponents(options = {}) {
603
712
  td: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("td", { className: "p-3 align-middle text-sm whitespace-nowrap", children })
604
713
  };
605
714
  }
606
-
607
- // src/utils/errorMessages.ts
608
- var WORKFLOW_FAILED = "WORKFLOW_FAILED";
609
- var STREAM_NOT_STARTED = "STREAM_NOT_STARTED";
610
- var HTTP_ERROR_PREFIX = /^HTTP\s+(\d+)\s*:\s*([\s\S]+)$/;
611
- function isFriendlyWorkflowError(errorDetails) {
612
- if (!errorDetails) return false;
613
- return errorDetails === WORKFLOW_FAILED || errorDetails === STREAM_NOT_STARTED || errorDetails.includes(WORKFLOW_FAILED);
614
- }
615
- function parseErrorPayload(payload) {
616
- try {
617
- const parsed = JSON.parse(payload);
618
- if (typeof parsed === "string") {
619
- return { message: parsed.trim() || void 0 };
620
- }
621
- if (typeof parsed === "object" && parsed !== null) {
622
- const record = parsed;
623
- return {
624
- status: typeof record.status === "number" ? record.status : void 0,
625
- message: typeof record.message === "string" && record.message.trim() ? record.message.trim() : void 0
626
- };
627
- }
628
- } catch {
629
- }
630
- return {};
631
- }
632
- function getConflictErrorMessage(errorDetails) {
633
- if (!errorDetails) return void 0;
634
- const trimmedError = errorDetails.trim();
635
- const httpMatch = trimmedError.match(HTTP_ERROR_PREFIX);
636
- const httpStatus = httpMatch ? Number(httpMatch[1]) : void 0;
637
- const rawPayload = (httpMatch ? httpMatch[2] : trimmedError).trim();
638
- const payload = parseErrorPayload(rawPayload);
639
- const status = payload.status ?? httpStatus;
640
- if (status !== 409) {
641
- return void 0;
642
- }
643
- if (payload.message) {
644
- return payload.message;
645
- }
646
- return rawPayload || void 0;
647
- }
648
715
  function ThinkingBlock({ text }) {
649
716
  const [isOpen, setIsOpen] = react.useState(false);
650
717
  const hasContent = typeof text === "string" && text.trim().length > 0;
@@ -2210,16 +2277,19 @@ function UserMessageV2({
2210
2277
  toastPortal,
2211
2278
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-v2-user-msg payman-v2-fade-in", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-user-msg-group", children: [
2212
2279
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-v2-user-msg-bubble", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "payman-v2-user-msg-text", children: message.content }) }),
2213
- message.isError && message.errorDetails && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-user-msg-error", children: [
2214
- /* @__PURE__ */ jsxRuntime.jsx(
2215
- lucideReact.AlertCircle,
2216
- {
2217
- className: "h-3.5 w-3.5 shrink-0",
2218
- style: { color: "rgba(239, 68, 68, 0.7)", marginTop: "2px" }
2219
- }
2220
- ),
2221
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "payman-v2-user-msg-error-text", children: message.errorDetails })
2222
- ] }),
2280
+ message.isError && message.errorDetails && (() => {
2281
+ const resolvedError = getConflictErrorMessage(message.errorDetails) ?? message.errorDetails;
2282
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-user-msg-error", children: [
2283
+ /* @__PURE__ */ jsxRuntime.jsx(
2284
+ lucideReact.AlertCircle,
2285
+ {
2286
+ className: "h-3.5 w-3.5 shrink-0",
2287
+ style: { color: "rgba(239, 68, 68, 0.7)", marginTop: "2px" }
2288
+ }
2289
+ ),
2290
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "payman-v2-user-msg-error-text", children: resolvedError })
2291
+ ] });
2292
+ })(),
2223
2293
  (timestamp || hasVisibleActions) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-user-msg-actions", children: [
2224
2294
  timestamp ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "payman-v2-user-msg-timestamp", children: timestamp }) : null,
2225
2295
  showCopyAction && /* @__PURE__ */ jsxRuntime.jsx(ActionTooltipV2, { label: "Copy", children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -2460,6 +2530,188 @@ function MarkdownRendererV2({
2460
2530
  }
2461
2531
  );
2462
2532
  }
2533
+ var PAYMAN_PATH = "M174.005 38.1616C159.62 18.4068 138.406 5.43014 114.263 1.62485C90.1187 -2.18045 65.9302 3.63155 46.1599 17.9906C21.9565 35.5752 6.06885 61.5137 1.39776 91.0344C-3.27333 120.555 3.85231 150.135 21.4358 174.305C43.0508 204.004 74.9451 223.506 111.243 229.244L122.415 231.013V171.273C121.968 171.273 121.522 171.302 121.076 171.302C116.955 171.302 112.82 170.975 108.684 170.321C106.795 170.024 104.92 169.638 103.076 169.207V207.839C76.5368 201.031 53.4045 185.364 37.0706 162.934C22.5218 142.941 16.6309 118.474 20.4838 94.037C24.3515 69.6148 37.502 48.1505 57.5103 33.5983C73.1004 22.2715 92.1865 17.6784 111.228 20.6811C130.269 23.6837 147.005 33.9253 158.355 49.5032C167.117 61.5583 170.673 76.2889 168.337 91.0047C166.016 105.72 158.087 118.653 146.038 127.408C136.815 134.112 125.524 136.832 114.248 135.048C102.972 133.264 93.079 127.214 86.355 117.984C81.2823 111.027 79.2443 102.51 80.5831 94.0073C81.922 85.5049 86.5038 78.0429 93.4658 72.9741C98.6129 69.2283 104.92 67.7121 111.213 68.7081C117.506 69.704 123.039 73.0782 126.788 78.2362C129.481 81.9374 130.567 86.4711 129.853 90.9898C129.139 95.5086 126.699 99.4774 122.995 102.183H146.648C147.719 99.5815 148.492 96.8464 148.939 94.0073C150.456 84.39 148.135 74.743 142.408 66.8797C135.625 57.5597 125.613 51.4207 114.218 49.637C102.823 47.8384 91.4129 50.5734 82.0707 57.3665C70.9285 65.4676 63.6095 77.4037 61.4525 91.0047C59.2955 104.606 62.5831 118.221 70.6905 129.355C80.4344 142.748 94.8195 151.548 111.198 154.134C127.577 156.72 143.97 152.781 157.373 143.03C173.603 131.228 184.269 113.822 187.408 94.0073C190.547 74.193 185.757 54.349 173.96 38.117L174.005 38.1616Z";
2534
+ var CIRCLE_PATH = "M95 36C139.183 36 175 71.817 175 116C175 160.183 139.183 196 95 196C50.817 196 15 160.183 15 116C15 71.817 50.817 36 95 36Z";
2535
+ function easeInOut(t) {
2536
+ return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
2537
+ }
2538
+ var TIMINGS = {
2539
+ // Total loop cycle = sum of all phases (ms)
2540
+ holdLogoMs: 900,
2541
+ morphToCircleMs: 550,
2542
+ holdCircleMs: 1100,
2543
+ morphToLogoMs: 550
2544
+ };
2545
+ var TOTAL_CYCLE = TIMINGS.holdLogoMs + TIMINGS.morphToCircleMs + TIMINGS.holdCircleMs + TIMINGS.morphToLogoMs;
2546
+ function phaseAtTime(elapsed) {
2547
+ let t = elapsed % TOTAL_CYCLE;
2548
+ if (t < TIMINGS.holdLogoMs) {
2549
+ return { kind: "hold-logo" };
2550
+ }
2551
+ t -= TIMINGS.holdLogoMs;
2552
+ if (t < TIMINGS.morphToCircleMs) {
2553
+ return {
2554
+ kind: "morph",
2555
+ direction: 1,
2556
+ progress: easeInOut(t / TIMINGS.morphToCircleMs)
2557
+ };
2558
+ }
2559
+ t -= TIMINGS.morphToCircleMs;
2560
+ if (t < TIMINGS.holdCircleMs) {
2561
+ return { kind: "hold-circle", progress: t / TIMINGS.holdCircleMs };
2562
+ }
2563
+ t -= TIMINGS.holdCircleMs;
2564
+ return {
2565
+ kind: "morph",
2566
+ direction: -1,
2567
+ progress: easeInOut(t / TIMINGS.morphToLogoMs)
2568
+ };
2569
+ }
2570
+ var RING_CX = 95;
2571
+ var RING_CY = 116;
2572
+ var RING_R = 65;
2573
+ var RING_STROKE_WIDTH = 22;
2574
+ var RING_CIRCUMFERENCE = 2 * Math.PI * RING_R;
2575
+ var RING_ARC_FRACTION = 0.3;
2576
+ var cachedInterpolators = null;
2577
+ var pendingInterpolators = null;
2578
+ function buildInterpolators() {
2579
+ const opts = { maxSegmentLength: 8 };
2580
+ return {
2581
+ forward: flubber.interpolate(PAYMAN_PATH, CIRCLE_PATH, opts),
2582
+ backward: flubber.interpolate(CIRCLE_PATH, PAYMAN_PATH, opts)
2583
+ };
2584
+ }
2585
+ function loadInterpolatorsAsync() {
2586
+ if (cachedInterpolators) return Promise.resolve(cachedInterpolators);
2587
+ if (pendingInterpolators) return pendingInterpolators;
2588
+ pendingInterpolators = new Promise((resolve) => {
2589
+ const run = () => {
2590
+ cachedInterpolators = buildInterpolators();
2591
+ resolve(cachedInterpolators);
2592
+ };
2593
+ const ric = globalThis.requestIdleCallback;
2594
+ if (typeof ric === "function") {
2595
+ ric(run, { timeout: 200 });
2596
+ } else {
2597
+ setTimeout(run, 0);
2598
+ }
2599
+ });
2600
+ return pendingInterpolators;
2601
+ }
2602
+ function PaymanMark() {
2603
+ const pathRef = react.useRef(null);
2604
+ const ringGroupRef = react.useRef(null);
2605
+ react.useEffect(() => {
2606
+ const reduced = window.matchMedia(
2607
+ "(prefers-reduced-motion: reduce)"
2608
+ ).matches;
2609
+ if (reduced) {
2610
+ pathRef.current?.setAttribute("d", PAYMAN_PATH);
2611
+ pathRef.current?.setAttribute("fill-opacity", "1");
2612
+ ringGroupRef.current?.setAttribute("opacity", "0");
2613
+ return;
2614
+ }
2615
+ let raf = 0;
2616
+ let cancelled = false;
2617
+ const start = performance.now();
2618
+ let interpolators = cachedInterpolators;
2619
+ const tick = (now) => {
2620
+ const elapsed = now - start;
2621
+ const phase = phaseAtTime(elapsed);
2622
+ let d;
2623
+ let fillOpacity = 1;
2624
+ let ringOpacity = 0;
2625
+ const spin = elapsed / 900 * 360;
2626
+ switch (phase.kind) {
2627
+ case "hold-logo":
2628
+ d = PAYMAN_PATH;
2629
+ fillOpacity = 1;
2630
+ ringOpacity = 0;
2631
+ break;
2632
+ case "morph": {
2633
+ if (!interpolators) {
2634
+ d = PAYMAN_PATH;
2635
+ fillOpacity = 1;
2636
+ ringOpacity = 0;
2637
+ break;
2638
+ }
2639
+ d = phase.direction === 1 ? interpolators.forward(phase.progress) : interpolators.backward(phase.progress);
2640
+ const p = phase.direction === 1 ? phase.progress : 1 - phase.progress;
2641
+ fillOpacity = p < 0.6 ? 1 : 1 - (p - 0.6) / 0.4;
2642
+ ringOpacity = p < 0.55 ? 0 : (p - 0.55) / 0.45;
2643
+ break;
2644
+ }
2645
+ case "hold-circle":
2646
+ d = CIRCLE_PATH;
2647
+ fillOpacity = 0;
2648
+ ringOpacity = 1;
2649
+ break;
2650
+ }
2651
+ if (pathRef.current) {
2652
+ pathRef.current.setAttribute("d", d);
2653
+ pathRef.current.setAttribute("fill-opacity", fillOpacity.toFixed(3));
2654
+ }
2655
+ if (ringGroupRef.current) {
2656
+ ringGroupRef.current.setAttribute("opacity", ringOpacity.toFixed(3));
2657
+ ringGroupRef.current.setAttribute(
2658
+ "transform",
2659
+ `rotate(${spin.toFixed(2)} ${RING_CX} ${RING_CY})`
2660
+ );
2661
+ }
2662
+ raf = requestAnimationFrame(tick);
2663
+ };
2664
+ raf = requestAnimationFrame(tick);
2665
+ if (!interpolators) {
2666
+ void loadInterpolatorsAsync().then((result) => {
2667
+ if (!cancelled) interpolators = result;
2668
+ });
2669
+ }
2670
+ return () => {
2671
+ cancelled = true;
2672
+ cancelAnimationFrame(raf);
2673
+ };
2674
+ }, []);
2675
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2676
+ "svg",
2677
+ {
2678
+ className: "payman-v2-thinking-mark",
2679
+ viewBox: "0 0 190 232",
2680
+ "aria-hidden": true,
2681
+ focusable: "false",
2682
+ children: [
2683
+ /* @__PURE__ */ jsxRuntime.jsx("path", { ref: pathRef, d: PAYMAN_PATH, fill: "currentColor" }),
2684
+ /* @__PURE__ */ jsxRuntime.jsxs("g", { ref: ringGroupRef, opacity: 0, children: [
2685
+ /* @__PURE__ */ jsxRuntime.jsx(
2686
+ "circle",
2687
+ {
2688
+ cx: RING_CX,
2689
+ cy: RING_CY,
2690
+ r: RING_R,
2691
+ fill: "none",
2692
+ stroke: "currentColor",
2693
+ strokeWidth: RING_STROKE_WIDTH,
2694
+ strokeOpacity: 0.16
2695
+ }
2696
+ ),
2697
+ /* @__PURE__ */ jsxRuntime.jsx(
2698
+ "circle",
2699
+ {
2700
+ cx: RING_CX,
2701
+ cy: RING_CY,
2702
+ r: RING_R,
2703
+ fill: "none",
2704
+ stroke: "currentColor",
2705
+ strokeWidth: RING_STROKE_WIDTH,
2706
+ strokeLinecap: "round",
2707
+ strokeDasharray: `${RING_CIRCUMFERENCE * RING_ARC_FRACTION} ${RING_CIRCUMFERENCE}`
2708
+ }
2709
+ )
2710
+ ] })
2711
+ ]
2712
+ }
2713
+ );
2714
+ }
2463
2715
  var CURSOR_MESSAGES = [
2464
2716
  "Analyzing",
2465
2717
  "Processing",
@@ -2470,6 +2722,7 @@ var CURSOR_MESSAGES = [
2470
2722
  "Evaluating",
2471
2723
  "Checking",
2472
2724
  "Planning",
2725
+ "Working",
2473
2726
  "Updating",
2474
2727
  "Validating",
2475
2728
  "Monitoring",
@@ -2493,6 +2746,12 @@ var CURSOR_MESSAGES = [
2493
2746
  "Confirming"
2494
2747
  ];
2495
2748
  var FINAL_CURSOR_MESSAGE = "Finishing up";
2749
+ function getMaxDuration(...values) {
2750
+ const defined = values.filter(
2751
+ (value) => typeof value === "number" && Number.isFinite(value)
2752
+ );
2753
+ return defined.length > 0 ? Math.max(...defined) : void 0;
2754
+ }
2496
2755
  function parseThinkingContent(content) {
2497
2756
  const lines = content.split("\n");
2498
2757
  const out = [];
@@ -2524,13 +2783,39 @@ function parseThinkingContent(content) {
2524
2783
  }
2525
2784
  return out;
2526
2785
  }
2786
+ function AnimatedSeconds({
2787
+ value,
2788
+ className,
2789
+ ariaLabel
2790
+ }) {
2791
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("payman-v2-thinking-seconds", className), "aria-label": ariaLabel, children: [
2792
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "payman-v2-thinking-seconds-track", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { initial: false, children: /* @__PURE__ */ jsxRuntime.jsx(
2793
+ framerMotion.motion.span,
2794
+ {
2795
+ className: "payman-v2-thinking-seconds-value",
2796
+ initial: { opacity: 0, y: 6, filter: "blur(2px)" },
2797
+ animate: { opacity: 1, y: 0, filter: "blur(0px)" },
2798
+ exit: { opacity: 0, y: -6, filter: "blur(2px)" },
2799
+ transition: { duration: 0.2, ease: [0.22, 1, 0.36, 1] },
2800
+ children: value
2801
+ },
2802
+ value
2803
+ ) }) }),
2804
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "payman-v2-thinking-seconds-suffix", "aria-hidden": "true", children: "s" })
2805
+ ] });
2806
+ }
2527
2807
  function ThinkingBlockV2({
2528
2808
  content,
2529
2809
  isStreaming,
2530
- durationSec
2810
+ durationSec,
2811
+ startedAt
2531
2812
  }) {
2532
2813
  const [open, setOpen] = react.useState(true);
2533
2814
  const [cursorIdx, setCursorIdx] = react.useState(0);
2815
+ const [elapsedSec, setElapsedSec] = react.useState(
2816
+ () => startedAt ? Math.max(0, Math.floor((Date.now() - startedAt) / 1e3)) : 0
2817
+ );
2818
+ const frozenSecRef = react.useRef(null);
2534
2819
  const prevStreaming = react.useRef(isStreaming);
2535
2820
  const parsed = react.useMemo(() => parseThinkingContent(content), [content]);
2536
2821
  const isFinalizingPhase = react.useMemo(() => {
@@ -2542,9 +2827,26 @@ function ThinkingBlockV2({
2542
2827
  react.useEffect(() => {
2543
2828
  if (prevStreaming.current && !isStreaming) {
2544
2829
  setOpen(false);
2830
+ if (startedAt) {
2831
+ frozenSecRef.current = Math.max(
2832
+ 0,
2833
+ Math.floor((Date.now() - startedAt) / 1e3)
2834
+ );
2835
+ }
2545
2836
  }
2546
2837
  prevStreaming.current = isStreaming;
2547
- }, [isStreaming]);
2838
+ }, [isStreaming, startedAt]);
2839
+ react.useEffect(() => {
2840
+ if (!isStreaming || !startedAt) return;
2841
+ const tick = () => {
2842
+ setElapsedSec(
2843
+ Math.max(0, Math.floor((Date.now() - startedAt) / 1e3))
2844
+ );
2845
+ };
2846
+ tick();
2847
+ const id = window.setInterval(tick, 1e3);
2848
+ return () => window.clearInterval(id);
2849
+ }, [isStreaming, startedAt]);
2548
2850
  react.useEffect(() => {
2549
2851
  if (!isStreaming || isFinalizingPhase) return;
2550
2852
  const id = window.setInterval(() => {
@@ -2552,10 +2854,33 @@ function ThinkingBlockV2({
2552
2854
  }, 4e3);
2553
2855
  return () => window.clearInterval(id);
2554
2856
  }, [isStreaming, isFinalizingPhase]);
2555
- const headerLabel = isStreaming ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "payman-v2-thinking-shimmer", children: "Working on it\u2026" }) : durationSec !== void 0 ? /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
2556
- "Thought for ",
2857
+ const justStoppedSec = !isStreaming && prevStreaming.current && startedAt ? Math.max(0, Math.floor((Date.now() - startedAt) / 1e3)) : void 0;
2858
+ const finalSec = getMaxDuration(
2557
2859
  durationSec,
2558
- "s"
2860
+ frozenSecRef.current,
2861
+ justStoppedSec,
2862
+ !isStreaming ? elapsedSec : void 0
2863
+ );
2864
+ const headerLabel = isStreaming ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "payman-v2-thinking-header-label", children: [
2865
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "payman-v2-thinking-shimmer", children: "Working on it\u2026" }),
2866
+ startedAt !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(
2867
+ AnimatedSeconds,
2868
+ {
2869
+ className: "payman-v2-thinking-timer",
2870
+ ariaLabel: `Elapsed ${elapsedSec} seconds`,
2871
+ value: elapsedSec
2872
+ }
2873
+ )
2874
+ ] }) : finalSec !== null && finalSec !== void 0 ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "payman-v2-thinking-header-label", children: [
2875
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Thought for" }),
2876
+ /* @__PURE__ */ jsxRuntime.jsx(
2877
+ AnimatedSeconds,
2878
+ {
2879
+ className: "payman-v2-thinking-duration",
2880
+ ariaLabel: `Thought for ${finalSec} seconds`,
2881
+ value: finalSec
2882
+ }
2883
+ )
2559
2884
  ] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Thought" });
2560
2885
  const cursorKey = isFinalizingPhase ? "finalizing" : String(cursorIdx);
2561
2886
  const cursorText = isFinalizingPhase ? FINAL_CURSOR_MESSAGE : CURSOR_MESSAGES[cursorIdx];
@@ -2625,27 +2950,28 @@ function ThinkingBlockV2({
2625
2950
  i
2626
2951
  );
2627
2952
  }),
2628
- isStreaming && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-thinking-cursor", children: [
2629
- /* @__PURE__ */ jsxRuntime.jsx(
2630
- "span",
2631
- {
2632
- className: "payman-v2-thinking-cursor-bar",
2633
- "aria-hidden": true
2634
- }
2635
- ),
2636
- /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { mode: "wait", children: /* @__PURE__ */ jsxRuntime.jsx(
2637
- framerMotion.motion.span,
2638
- {
2639
- className: "payman-v2-thinking-cursor-label",
2640
- initial: { opacity: 0, y: 4 },
2641
- animate: { opacity: 1, y: 0 },
2642
- exit: { opacity: 0, y: -4 },
2643
- transition: { duration: 0.2 },
2644
- children: cursorText
2645
- },
2646
- cursorKey
2647
- ) })
2648
- ] })
2953
+ isStreaming && /* @__PURE__ */ jsxRuntime.jsxs(
2954
+ "div",
2955
+ {
2956
+ className: "payman-v2-thinking-cursor",
2957
+ "aria-live": "polite",
2958
+ children: [
2959
+ /* @__PURE__ */ jsxRuntime.jsx(PaymanMark, {}),
2960
+ /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { mode: "wait", children: /* @__PURE__ */ jsxRuntime.jsx(
2961
+ framerMotion.motion.span,
2962
+ {
2963
+ className: "payman-v2-thinking-cursor-label payman-v2-thinking-shimmer",
2964
+ initial: { opacity: 0, y: 2 },
2965
+ animate: { opacity: 1, y: 0 },
2966
+ exit: { opacity: 0, y: -2 },
2967
+ transition: { duration: 0.24, ease: [0.4, 0, 0.2, 1] },
2968
+ children: cursorText
2969
+ },
2970
+ cursorKey
2971
+ ) })
2972
+ ]
2973
+ }
2974
+ )
2649
2975
  ] })
2650
2976
  },
2651
2977
  "thinking-content"
@@ -2795,16 +3121,52 @@ function AssistantMessageV2({
2795
3121
  const showLegacyThinkingPhase = !!message.isStreaming && !message.isError && !rawResponseContent && message.streamProgress === "started";
2796
3122
  const responseTypingEnabled = hasEverStreamed.current && Boolean(rawResponseContent) && !message.isError;
2797
3123
  const { displayedText: displayContent, isTyping: isResponseTyping } = useTypingEffect(rawResponseContent, responseTypingEnabled, RESPONSE_SPEED);
3124
+ const resolvedErrorText = (() => {
3125
+ const conflictErrorMessage2 = getConflictErrorMessage(message.errorDetails);
3126
+ if (conflictErrorMessage2) {
3127
+ return conflictErrorMessage2;
3128
+ }
3129
+ if (isFriendlyWorkflowError(message.errorDetails) && !message.errorDetails) {
3130
+ return "Oops, something went wrong. Please try again.";
3131
+ }
3132
+ return message.errorDetails;
3133
+ })();
3134
+ const requestStartedAt = react.useMemo(() => {
3135
+ if (!message.timestamp) return void 0;
3136
+ const t = Date.parse(message.timestamp);
3137
+ return Number.isFinite(t) ? t : void 0;
3138
+ }, [message.timestamp]);
2798
3139
  const thinkingDuration = (() => {
2799
- if (!message.steps || message.steps.length === 0) return void 0;
2800
- const first = message.steps[0];
2801
- const last = message.steps[message.steps.length - 1];
3140
+ const steps = message.steps;
3141
+ if (!steps || steps.length === 0) return void 0;
3142
+ const last = steps[steps.length - 1];
3143
+ if (requestStartedAt && last.timestamp) {
3144
+ return Math.max(
3145
+ 0,
3146
+ Math.round((last.timestamp - requestStartedAt) / 1e3)
3147
+ );
3148
+ }
3149
+ const first = steps[0];
2802
3150
  if (first.timestamp && last.timestamp) {
2803
3151
  return Math.round((last.timestamp - first.timestamp) / 1e3);
2804
3152
  }
2805
- const total = message.steps.reduce((sum, s) => sum + (s.elapsedMs || 0), 0);
3153
+ const total = steps.reduce((sum, s) => sum + (s.elapsedMs || 0), 0);
2806
3154
  return total > 0 ? Math.round(total / 1e3) : void 0;
2807
3155
  })();
3156
+ const conflictErrorMessage = getConflictErrorMessage(message.errorDetails);
3157
+ const isConflictError = Boolean(conflictErrorMessage);
3158
+ if (isConflictError) {
3159
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-v2-assistant-msg payman-v2-fade-in", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-assistant-msg-error", children: [
3160
+ /* @__PURE__ */ jsxRuntime.jsx(
3161
+ lucideReact.AlertCircle,
3162
+ {
3163
+ className: "payman-v2-assistant-msg-error-icon",
3164
+ style: { width: 16, height: 16 }
3165
+ }
3166
+ ),
3167
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "payman-v2-assistant-msg-error-text", children: conflictErrorMessage }) })
3168
+ ] }) });
3169
+ }
2808
3170
  if (message.isError && !displayContent && !hasThinkingContent) {
2809
3171
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-v2-assistant-msg payman-v2-fade-in", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-assistant-msg-error", children: [
2810
3172
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -2814,7 +3176,7 @@ function AssistantMessageV2({
2814
3176
  style: { width: 16, height: 16 }
2815
3177
  }
2816
3178
  ),
2817
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "payman-v2-assistant-msg-error-text", children: message.errorDetails || "Something went wrong. Please try again." }) })
3179
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: resolvedErrorText ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "payman-v2-assistant-msg-error-text", children: resolvedErrorText }) : null })
2818
3180
  ] }) });
2819
3181
  }
2820
3182
  if (showLegacyThinkingPhase) {
@@ -2847,7 +3209,7 @@ function AssistantMessageV2({
2847
3209
  executionId: message.executionId
2848
3210
  });
2849
3211
  };
2850
- const hasPartialError = message.isError && displayContent;
3212
+ const hasPartialError = message.isError && displayContent && !isConflictError;
2851
3213
  const isDone = !message.isStreaming && displayContent && !hasPartialError && !isResponseTyping;
2852
3214
  const hasVisibleDoneActions = showCopyAction || showTraceAction;
2853
3215
  const isCancelled = message.isCancelled;
@@ -2904,7 +3266,8 @@ function AssistantMessageV2({
2904
3266
  {
2905
3267
  content: thinkingContent,
2906
3268
  isStreaming: isThinkingStreaming,
2907
- durationSec: thinkingDuration
3269
+ durationSec: thinkingDuration,
3270
+ startedAt: requestStartedAt
2908
3271
  }
2909
3272
  ),
2910
3273
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-v2-assistant-msg-content-area", children: displayContent ? /* @__PURE__ */ jsxRuntime.jsx(
@@ -2933,7 +3296,7 @@ function AssistantMessageV2({
2933
3296
  style: { width: 16, height: 16 }
2934
3297
  }
2935
3298
  ),
2936
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "payman-v2-assistant-msg-error-text", children: message.errorDetails || "The response was interrupted." }) })
3299
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: resolvedErrorText ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "payman-v2-assistant-msg-error-text", children: resolvedErrorText }) : null })
2937
3300
  ] }),
2938
3301
  isDone && hasVisibleDoneActions && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-assistant-msg-actions", children: [
2939
3302
  showCopyAction && /* @__PURE__ */ jsxRuntime.jsx(ActionTooltipV2, { label: "Copy", children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -3130,76 +3493,72 @@ function VerificationCardV2({
3130
3493
  const handleCancel = react.useCallback(async () => {
3131
3494
  await onReject(messageId);
3132
3495
  }, [messageId, onReject]);
3496
+ react.useCallback(async () => {
3497
+ if (otp.length !== OTP_LEN || !/^\d+$/.test(otp) || status !== "pending") {
3498
+ return;
3499
+ }
3500
+ if (lastSubmittedRef.current === otp) return;
3501
+ lastSubmittedRef.current = otp;
3502
+ await onApprove(messageId, otp);
3503
+ }, [messageId, onApprove, otp, status]);
3133
3504
  const busy = status === "verifying";
3505
+ status === "pending" && otp.length === OTP_LEN && /^\d+$/.test(otp);
3134
3506
  if (status === "approved" || status === "rejected") {
3135
3507
  return null;
3136
3508
  }
3137
- return /* @__PURE__ */ jsxRuntime.jsx(
3509
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3138
3510
  framerMotion.motion.div,
3139
3511
  {
3140
3512
  className: "payman-v2-verification",
3141
3513
  initial: { opacity: 0, y: 10 },
3142
3514
  animate: { opacity: 1, y: 0 },
3143
3515
  transition: { type: "spring", stiffness: 320, damping: 28 },
3144
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-verification-card", children: [
3145
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-verification-header", children: [
3146
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-verification-header-row", children: [
3516
+ children: [
3517
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-verification-card", children: [
3518
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-verification-header", children: [
3519
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-verification-header-row", children: [
3520
+ /* @__PURE__ */ jsxRuntime.jsx(
3521
+ lucideReact.ShieldCheck,
3522
+ {
3523
+ className: "payman-v2-verification-icon",
3524
+ size: 18,
3525
+ strokeWidth: 1.75,
3526
+ "aria-hidden": true
3527
+ }
3528
+ ),
3529
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "payman-v2-verification-title", children: "Verify" }),
3530
+ action.amount != null ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "payman-v2-verification-amount", children: action.amount }) : action.payeeName ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "payman-v2-verification-payee", children: action.payeeName }) : null
3531
+ ] }),
3532
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "payman-v2-verification-description", children: "Enter the 6-digit code sent to your phone" }),
3147
3533
  /* @__PURE__ */ jsxRuntime.jsx(
3148
- lucideReact.ShieldCheck,
3534
+ OtpInputV2,
3149
3535
  {
3150
- className: "payman-v2-verification-icon",
3151
- size: 18,
3152
- strokeWidth: 1.75,
3153
- "aria-hidden": true
3536
+ value: otp,
3537
+ onChange: setOtp,
3538
+ maxLength: OTP_LEN,
3539
+ disabled: busy,
3540
+ error: otpErrored
3154
3541
  }
3155
3542
  ),
3156
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "payman-v2-verification-title", children: "Verify" }),
3157
- action.amount != null ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "payman-v2-verification-amount", children: action.amount }) : action.payeeName ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "payman-v2-verification-payee", children: action.payeeName }) : null
3543
+ busy ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-verification-submitting", children: [
3544
+ /* @__PURE__ */ jsxRuntime.jsx(
3545
+ framerMotion.motion.span,
3546
+ {
3547
+ "aria-hidden": true,
3548
+ style: { display: "inline-flex" },
3549
+ animate: { rotate: 360 },
3550
+ transition: {
3551
+ repeat: Infinity,
3552
+ duration: 0.7,
3553
+ ease: "linear"
3554
+ },
3555
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { size: 14, strokeWidth: 2 })
3556
+ }
3557
+ ),
3558
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "payman-v2-verification-submitting-text", children: "Verifying..." })
3559
+ ] }) : null
3158
3560
  ] }),
3159
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "payman-v2-verification-description", children: "Enter the 6-digit code sent to your phone" }),
3160
- /* @__PURE__ */ jsxRuntime.jsx(
3161
- OtpInputV2,
3162
- {
3163
- value: otp,
3164
- onChange: setOtp,
3165
- maxLength: OTP_LEN,
3166
- disabled: busy,
3167
- error: otpErrored
3168
- }
3169
- ),
3170
- busy ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-verification-submitting", children: [
3171
- /* @__PURE__ */ jsxRuntime.jsx(
3172
- framerMotion.motion.span,
3173
- {
3174
- "aria-hidden": true,
3175
- style: { display: "inline-flex" },
3176
- animate: { rotate: 360 },
3177
- transition: {
3178
- repeat: Infinity,
3179
- duration: 0.7,
3180
- ease: "linear"
3181
- },
3182
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { size: 14, strokeWidth: 2 })
3183
- }
3184
- ),
3185
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "payman-v2-verification-submitting-text", children: "Verifying..." })
3186
- ] }) : null
3187
- ] }),
3188
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-verification-actions", children: [
3189
- /* @__PURE__ */ jsxRuntime.jsxs(
3190
- "button",
3191
- {
3192
- type: "button",
3193
- className: "payman-v2-verification-resend-btn",
3194
- disabled: busy || resendSec > 0,
3195
- onClick: () => void handleResend(),
3196
- children: [
3197
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCcw, { size: 12, strokeWidth: 2, "aria-hidden": true }),
3198
- resendSec > 0 ? `Resend (${resendSec}s)` : "Resend"
3199
- ]
3200
- }
3201
- ),
3202
- /* @__PURE__ */ jsxRuntime.jsx(
3561
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-v2-verification-actions", children: /* @__PURE__ */ jsxRuntime.jsx(
3203
3562
  "button",
3204
3563
  {
3205
3564
  type: "button",
@@ -3208,9 +3567,19 @@ function VerificationCardV2({
3208
3567
  onClick: () => void handleCancel(),
3209
3568
  children: "Cancel"
3210
3569
  }
3211
- )
3212
- ] })
3213
- ] })
3570
+ ) })
3571
+ ] }),
3572
+ /* @__PURE__ */ jsxRuntime.jsx(
3573
+ "button",
3574
+ {
3575
+ type: "button",
3576
+ className: "payman-v2-verification-resend-link",
3577
+ disabled: busy || resendSec > 0,
3578
+ onClick: () => void handleResend(),
3579
+ children: resendSec > 0 ? `Resend (${resendSec}s)` : "Resend"
3580
+ }
3581
+ )
3582
+ ]
3214
3583
  }
3215
3584
  );
3216
3585
  }
@@ -3432,7 +3801,8 @@ var ChatInputV2 = react.forwardRef(
3432
3801
  onUploadImageClick,
3433
3802
  onAttachFileClick,
3434
3803
  editingMessageId = null,
3435
- onClearEditing
3804
+ onClearEditing,
3805
+ hideSendButton = false
3436
3806
  }, ref) {
3437
3807
  const [value, setValue] = react.useState("");
3438
3808
  const [isFocused, setIsFocused] = react.useState(false);
@@ -3529,7 +3899,7 @@ var ChatInputV2 = react.forwardRef(
3529
3899
  const handleKeyDown = (e) => {
3530
3900
  if (e.key === "Enter" && !e.shiftKey) {
3531
3901
  e.preventDefault();
3532
- if (isStreaming) return;
3902
+ if (isStreaming || hideSendButton) return;
3533
3903
  handleSend();
3534
3904
  }
3535
3905
  };
@@ -3767,7 +4137,7 @@ var ChatInputV2 = react.forwardRef(
3767
4137
  )
3768
4138
  ] })
3769
4139
  ] }),
3770
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-v2-input-controls-right", children: /* @__PURE__ */ jsxRuntime.jsx(
4140
+ !hideSendButton && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-v2-input-controls-right", children: /* @__PURE__ */ jsxRuntime.jsx(
3771
4141
  "button",
3772
4142
  {
3773
4143
  type: "button",
@@ -3943,6 +4313,80 @@ var DEFAULT_USER_ACTION_STATE = {
3943
4313
  };
3944
4314
  var NOOP_ASYNC = async () => {
3945
4315
  };
4316
+ function useSentryChatCallbacks(callbacks, config) {
4317
+ const sentryCtxRef = react.useRef({});
4318
+ const callbacksRef = react.useRef(callbacks);
4319
+ callbacksRef.current = callbacks;
4320
+ const initialSessionId = config.initialSessionId;
4321
+ const apiHeaders = config.api.headers;
4322
+ react.useEffect(() => {
4323
+ sentryCtxRef.current.workflowName = config.workflowName;
4324
+ sentryCtxRef.current.sessionOwnerId = config.sessionParams?.id;
4325
+ if (initialSessionId) {
4326
+ sentryCtxRef.current.sessionId = initialSessionId;
4327
+ }
4328
+ if (apiHeaders) {
4329
+ sentryCtxRef.current.customerId = apiHeaders["x-paygent-wf-mcp-customer-id"] ?? sentryCtxRef.current.customerId;
4330
+ sentryCtxRef.current.customerEmail = apiHeaders["x-paygent-wf-mcp-customer-email"] ?? sentryCtxRef.current.customerEmail;
4331
+ }
4332
+ }, [
4333
+ config.workflowName,
4334
+ config.sessionParams?.id,
4335
+ initialSessionId,
4336
+ apiHeaders
4337
+ ]);
4338
+ react.useEffect(() => {
4339
+ const endpoint = config.api.streamEndpoint || "/api/workflows/ask/stream";
4340
+ return subscribeToCfRay(endpoint, (cfRay) => {
4341
+ sentryCtxRef.current.cfRay = cfRay;
4342
+ });
4343
+ }, [config.api.streamEndpoint]);
4344
+ return react.useMemo(
4345
+ () => ({
4346
+ onMessageSent: (msg) => callbacksRef.current?.onMessageSent?.(msg),
4347
+ onStreamStart: () => callbacksRef.current?.onStreamStart?.(),
4348
+ onStreamComplete: (message) => {
4349
+ if (message.executionId) {
4350
+ sentryCtxRef.current.executionId = message.executionId;
4351
+ }
4352
+ if (message.sessionId) {
4353
+ sentryCtxRef.current.sessionId = message.sessionId;
4354
+ }
4355
+ const content = message.content ?? "";
4356
+ const looksLikeRawErr = content.length >= 10 && (content.includes("errorType=") || /failed:\s*\{/.test(content));
4357
+ const completedEmpty = !message.isStreaming && !message.isCancelled && content.length === 0 && (message.streamProgress === "completed" || message.streamProgress === "error");
4358
+ const hasConflict = !!getConflictErrorMessage(message.errorDetails);
4359
+ const hasFriendlyErr = isFriendlyWorkflowError(message.errorDetails);
4360
+ const shouldCapture = message.isError || hasConflict || hasFriendlyErr || looksLikeRawErr || completedEmpty;
4361
+ if (shouldCapture) {
4362
+ sentryCtxRef.current.route = typeof window !== "undefined" ? window.location.pathname : void 0;
4363
+ captureSentryError(
4364
+ `Workflow error: ${message.errorDetails || content || "Unknown error"}`,
4365
+ { ...sentryCtxRef.current }
4366
+ );
4367
+ }
4368
+ callbacksRef.current?.onStreamComplete?.(message);
4369
+ },
4370
+ onError: (error) => {
4371
+ sentryCtxRef.current.route = typeof window !== "undefined" ? window.location.pathname : void 0;
4372
+ captureSentryError(error, { ...sentryCtxRef.current });
4373
+ callbacksRef.current?.onError?.(error);
4374
+ },
4375
+ onSessionIdChange: (sessionId) => {
4376
+ sentryCtxRef.current.sessionId = sessionId;
4377
+ callbacksRef.current?.onSessionIdChange?.(sessionId);
4378
+ },
4379
+ onExecutionTraceClick: (data) => callbacksRef.current?.onExecutionTraceClick?.(data),
4380
+ onResetSession: () => callbacksRef.current?.onResetSession?.(),
4381
+ onUploadImageClick: () => callbacksRef.current?.onUploadImageClick?.(),
4382
+ onAttachFileClick: () => callbacksRef.current?.onAttachFileClick?.(),
4383
+ onUserActionRequired: (req) => callbacksRef.current?.onUserActionRequired?.(req),
4384
+ onUserActionEvent: (evType, msg) => callbacksRef.current?.onUserActionEvent?.(evType, msg)
4385
+ }),
4386
+ // eslint-disable-next-line react-hooks/exhaustive-deps
4387
+ []
4388
+ );
4389
+ }
3946
4390
  var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
3947
4391
  config,
3948
4392
  callbacks = {},
@@ -4224,6 +4668,7 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
4224
4668
  status
4225
4669
  };
4226
4670
  }, [isUserActionSupported, userActionState.request, userActionState.result]);
4671
+ const hideV2SendDuringVerification = v2UserAction != null && v2UserAction.status !== "approved" && v2UserAction.status !== "rejected";
4227
4672
  const handleV2Send = (text) => {
4228
4673
  if (isRecording) stopRecording();
4229
4674
  if (text.trim() && !disableInput && isSessionParamsConfigured) {
@@ -4342,7 +4787,8 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
4342
4787
  onUploadImageClick,
4343
4788
  onAttachFileClick,
4344
4789
  editingMessageId,
4345
- onClearEditing: handleClearEditing
4790
+ onClearEditing: handleClearEditing,
4791
+ hideSendButton: hideV2SendDuringVerification
4346
4792
  }
4347
4793
  )
4348
4794
  }
@@ -4406,7 +4852,8 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
4406
4852
  onUploadImageClick,
4407
4853
  onAttachFileClick,
4408
4854
  editingMessageId,
4409
- onClearEditing: handleClearEditing
4855
+ onClearEditing: handleClearEditing,
4856
+ hideSendButton: hideV2SendDuringVerification
4410
4857
  }
4411
4858
  )
4412
4859
  ]
@@ -4581,13 +5028,15 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
4581
5028
  });
4582
5029
  var PaymanChatV1Shell = react.forwardRef(
4583
5030
  function PaymanChatV1Shell2(props, ref) {
4584
- const chat = paymanTypescriptAskSdk.useChat(props.config, props.callbacks);
5031
+ const mergedCallbacks = useSentryChatCallbacks(props.callbacks, props.config);
5032
+ const chat = paymanTypescriptAskSdk.useChat(props.config, mergedCallbacks);
4585
5033
  return /* @__PURE__ */ jsxRuntime.jsx(PaymanChatInner, { ...props, chat, ref });
4586
5034
  }
4587
5035
  );
4588
5036
  var PaymanChatV2Shell = react.forwardRef(
4589
5037
  function PaymanChatV2Shell2(props, ref) {
4590
- const chat = paymanTypescriptAskSdk.useChatV2(props.config, props.callbacks);
5038
+ const mergedCallbacks = useSentryChatCallbacks(props.callbacks, props.config);
5039
+ const chat = paymanTypescriptAskSdk.useChatV2(props.config, mergedCallbacks);
4591
5040
  return /* @__PURE__ */ jsxRuntime.jsx(PaymanChatInner, { ...props, chat, ref });
4592
5041
  }
4593
5042
  );
@@ -4646,6 +5095,7 @@ Object.defineProperty(exports, "useVoice", {
4646
5095
  });
4647
5096
  exports.PaymanChat = PaymanChat;
4648
5097
  exports.PaymanChatContext = PaymanChatContext;
5098
+ exports.captureSentryError = captureSentryError;
4649
5099
  exports.cn = cn;
4650
5100
  exports.formatDate = formatDate;
4651
5101
  exports.usePaymanChat = usePaymanChat;