@paymanai/payman-ask-sdk 4.0.4 → 4.0.6

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
@@ -247,6 +247,43 @@ function initSentryIfNeeded(dsn) {
247
247
  }
248
248
  });
249
249
  }
250
+
251
+ // src/utils/feedbackClient.ts
252
+ var NEGATIVE_FEEDBACK_REASONS = [
253
+ { value: "NOT_FACTUALLY_CORRECT", label: "Not factually correct" },
254
+ { value: "INCOMPLETE_RESPONSE", label: "Incomplete response" },
255
+ { value: "DID_NOT_FOLLOW_REQUEST", label: "Did not follow my request" },
256
+ { value: "OVERACTIVE_REFUSAL", label: "Refused unnecessarily" },
257
+ { value: "ISSUE_WITH_THOUGHT_PROCESS", label: "Issue with reasoning" },
258
+ { value: "REPORT_CONTENT", label: "Report content" },
259
+ { value: "OTHER", label: "Other" }
260
+ ];
261
+ async function submitAskFeedback({
262
+ baseUrl,
263
+ headers,
264
+ executionId,
265
+ feedback,
266
+ details,
267
+ signal
268
+ }) {
269
+ const base = baseUrl.replace(/\/+$/, "");
270
+ const resp = await fetch(
271
+ `${base}/api/ask/executions/${encodeURIComponent(executionId)}/feedback`,
272
+ {
273
+ method: "POST",
274
+ headers: {
275
+ "Content-Type": "application/json",
276
+ Accept: "application/json",
277
+ ...headers ?? {}
278
+ },
279
+ body: JSON.stringify(details ? { feedback, details } : { feedback }),
280
+ signal
281
+ }
282
+ );
283
+ if (!resp.ok) {
284
+ throw new Error(`Feedback failed: ${resp.status} ${resp.statusText}`);
285
+ }
286
+ }
250
287
  function ImageLightbox({
251
288
  src,
252
289
  alt = "",
@@ -1709,6 +1746,143 @@ function ThinkingBlockV2({
1709
1746
  ) }) })
1710
1747
  ] });
1711
1748
  }
1749
+ var MAX_DETAILS_CHARS = 2e3;
1750
+ function FeedbackReasonModal({
1751
+ open,
1752
+ onClose,
1753
+ onSubmit
1754
+ }) {
1755
+ const [reason, setReason] = react.useState(
1756
+ NEGATIVE_FEEDBACK_REASONS[0].value
1757
+ );
1758
+ const [details, setDetails] = react.useState("");
1759
+ const [submitting, setSubmitting] = react.useState(false);
1760
+ const [error, setError] = react.useState(null);
1761
+ react.useEffect(() => {
1762
+ if (open) {
1763
+ setReason(NEGATIVE_FEEDBACK_REASONS[0].value);
1764
+ setDetails("");
1765
+ setError(null);
1766
+ setSubmitting(false);
1767
+ }
1768
+ }, [open]);
1769
+ const handleKeyDown = react.useCallback(
1770
+ (event) => {
1771
+ if (event.key === "Escape") onClose();
1772
+ },
1773
+ [onClose]
1774
+ );
1775
+ react.useEffect(() => {
1776
+ if (!open || typeof document === "undefined") return;
1777
+ document.addEventListener("keydown", handleKeyDown);
1778
+ const previousOverflow = document.body.style.overflow;
1779
+ document.body.style.overflow = "hidden";
1780
+ return () => {
1781
+ document.removeEventListener("keydown", handleKeyDown);
1782
+ document.body.style.overflow = previousOverflow;
1783
+ };
1784
+ }, [handleKeyDown, open]);
1785
+ const handleSubmit = async () => {
1786
+ setSubmitting(true);
1787
+ setError(null);
1788
+ try {
1789
+ await onSubmit(reason, details.trim() ? details.trim() : void 0);
1790
+ onClose();
1791
+ } catch (e) {
1792
+ setError(e instanceof Error ? e.message : "Could not send feedback");
1793
+ setSubmitting(false);
1794
+ }
1795
+ };
1796
+ return /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: open ? /* @__PURE__ */ jsxRuntime.jsx(
1797
+ framerMotion.motion.div,
1798
+ {
1799
+ className: "payman-v2-feedback-modal-backdrop",
1800
+ initial: { opacity: 0 },
1801
+ animate: { opacity: 1 },
1802
+ exit: { opacity: 0 },
1803
+ transition: { duration: 0.18 },
1804
+ onClick: onClose,
1805
+ role: "presentation",
1806
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
1807
+ framerMotion.motion.div,
1808
+ {
1809
+ initial: { opacity: 0, y: 12, scale: 0.98 },
1810
+ animate: { opacity: 1, y: 0, scale: 1 },
1811
+ exit: { opacity: 0, y: 8, scale: 0.98 },
1812
+ transition: { duration: 0.2, ease: [0.16, 1, 0.3, 1] },
1813
+ className: "payman-v2-feedback-modal-dialog",
1814
+ onClick: (event) => event.stopPropagation(),
1815
+ role: "dialog",
1816
+ "aria-modal": "true",
1817
+ "aria-labelledby": "payman-v2-feedback-title",
1818
+ children: [
1819
+ /* @__PURE__ */ jsxRuntime.jsx(
1820
+ "h2",
1821
+ {
1822
+ id: "payman-v2-feedback-title",
1823
+ className: "payman-v2-feedback-modal-title",
1824
+ children: "Tell us what went wrong"
1825
+ }
1826
+ ),
1827
+ /* @__PURE__ */ jsxRuntime.jsx(
1828
+ "label",
1829
+ {
1830
+ className: "payman-v2-feedback-modal-label",
1831
+ htmlFor: "payman-v2-feedback-reason",
1832
+ children: "What was the issue?"
1833
+ }
1834
+ ),
1835
+ /* @__PURE__ */ jsxRuntime.jsx(
1836
+ "select",
1837
+ {
1838
+ id: "payman-v2-feedback-reason",
1839
+ className: "payman-v2-feedback-modal-select",
1840
+ value: reason,
1841
+ onChange: (e) => setReason(e.target.value),
1842
+ disabled: submitting,
1843
+ children: NEGATIVE_FEEDBACK_REASONS.map((r) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: r.value, children: r.label }, r.value))
1844
+ }
1845
+ ),
1846
+ /* @__PURE__ */ jsxRuntime.jsx(
1847
+ "textarea",
1848
+ {
1849
+ className: "payman-v2-feedback-modal-textarea",
1850
+ placeholder: "Add details (optional)",
1851
+ value: details,
1852
+ maxLength: MAX_DETAILS_CHARS,
1853
+ onChange: (e) => setDetails(e.target.value),
1854
+ disabled: submitting
1855
+ }
1856
+ ),
1857
+ error ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "payman-v2-feedback-modal-error", children: error }) : null,
1858
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-feedback-modal-actions", children: [
1859
+ /* @__PURE__ */ jsxRuntime.jsx(
1860
+ "button",
1861
+ {
1862
+ type: "button",
1863
+ onClick: onClose,
1864
+ disabled: submitting,
1865
+ className: "payman-v2-feedback-modal-btn payman-v2-feedback-modal-btn-secondary",
1866
+ children: "Cancel"
1867
+ }
1868
+ ),
1869
+ /* @__PURE__ */ jsxRuntime.jsx(
1870
+ "button",
1871
+ {
1872
+ type: "button",
1873
+ onClick: handleSubmit,
1874
+ disabled: submitting,
1875
+ className: "payman-v2-feedback-modal-btn payman-v2-feedback-modal-btn-primary",
1876
+ children: submitting ? "Sending\u2026" : "Submit"
1877
+ }
1878
+ )
1879
+ ] })
1880
+ ]
1881
+ }
1882
+ )
1883
+ }
1884
+ ) : null });
1885
+ }
1712
1886
  var RESPONSE_SPEED = {
1713
1887
  normal: [2, 4],
1714
1888
  fast: 1,
@@ -1791,12 +1965,26 @@ function AssistantMessageV2({
1791
1965
  message,
1792
1966
  onImageClick,
1793
1967
  onExecutionTraceClick,
1794
- onFeedback,
1968
+ onSubmitFeedback,
1795
1969
  actions,
1796
1970
  typingSpeed = 4
1797
1971
  }) {
1798
1972
  const [copied, setCopied] = react.useState(false);
1799
1973
  const [activeFeedback, setActiveFeedback] = react.useState(null);
1974
+ const [reasonModalOpen, setReasonModalOpen] = react.useState(false);
1975
+ const canSubmitFeedback = !!onSubmitFeedback && !!message.executionId;
1976
+ const handlePositiveFeedback = () => {
1977
+ if (!canSubmitFeedback || activeFeedback === "up") return;
1978
+ const previous = activeFeedback;
1979
+ setActiveFeedback("up");
1980
+ Promise.resolve(
1981
+ onSubmitFeedback?.({
1982
+ messageId: message.id,
1983
+ executionId: message.executionId,
1984
+ feedback: "POSITIVE"
1985
+ })
1986
+ ).catch(() => setActiveFeedback(previous));
1987
+ };
1800
1988
  const [toast, setToast] = react.useState(null);
1801
1989
  const copyResetTimerRef = react.useRef(null);
1802
1990
  const toastTimerRef = react.useRef(null);
@@ -2036,14 +2224,10 @@ function AssistantMessageV2({
2036
2224
  children: copied ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { style: { width: 16, height: 16 } }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { style: { width: 16, height: 16 } })
2037
2225
  }
2038
2226
  ) }),
2039
- showThumbsUp && /* @__PURE__ */ jsxRuntime.jsx(ActionTooltipV2, { label: "Good response", children: /* @__PURE__ */ jsxRuntime.jsx(
2227
+ showThumbsUp && canSubmitFeedback && /* @__PURE__ */ jsxRuntime.jsx(ActionTooltipV2, { label: "Good response", children: /* @__PURE__ */ jsxRuntime.jsx(
2040
2228
  "button",
2041
2229
  {
2042
- onClick: () => {
2043
- const next = activeFeedback === "up" ? null : "up";
2044
- setActiveFeedback(next);
2045
- if (next) onFeedback?.({ messageId: message.id, feedback: "up" });
2046
- },
2230
+ onClick: handlePositiveFeedback,
2047
2231
  className: cn(
2048
2232
  "payman-v2-assistant-msg-action-btn",
2049
2233
  activeFeedback === "up" && "payman-v2-assistant-msg-action-btn-active"
@@ -2052,14 +2236,10 @@ function AssistantMessageV2({
2052
2236
  children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ThumbsUp, { style: { width: 15, height: 15 } })
2053
2237
  }
2054
2238
  ) }),
2055
- showThumbsDown && /* @__PURE__ */ jsxRuntime.jsx(ActionTooltipV2, { label: "Bad response", children: /* @__PURE__ */ jsxRuntime.jsx(
2239
+ showThumbsDown && canSubmitFeedback && /* @__PURE__ */ jsxRuntime.jsx(ActionTooltipV2, { label: "Bad response", children: /* @__PURE__ */ jsxRuntime.jsx(
2056
2240
  "button",
2057
2241
  {
2058
- onClick: () => {
2059
- const next = activeFeedback === "down" ? null : "down";
2060
- setActiveFeedback(next);
2061
- if (next) onFeedback?.({ messageId: message.id, feedback: "down" });
2062
- },
2242
+ onClick: () => setReasonModalOpen(true),
2063
2243
  className: cn(
2064
2244
  "payman-v2-assistant-msg-action-btn",
2065
2245
  activeFeedback === "down" && "payman-v2-assistant-msg-action-btn-active"
@@ -2079,7 +2259,23 @@ function AssistantMessageV2({
2079
2259
  ) }),
2080
2260
  totalElapsedLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "payman-v2-assistant-msg-elapsed", children: totalElapsedLabel })
2081
2261
  ] })
2082
- ] })
2262
+ ] }),
2263
+ /* @__PURE__ */ jsxRuntime.jsx(
2264
+ FeedbackReasonModal,
2265
+ {
2266
+ open: reasonModalOpen,
2267
+ onClose: () => setReasonModalOpen(false),
2268
+ onSubmit: async (reason, details) => {
2269
+ await onSubmitFeedback?.({
2270
+ messageId: message.id,
2271
+ executionId: message.executionId,
2272
+ feedback: reason,
2273
+ details
2274
+ });
2275
+ setActiveFeedback("down");
2276
+ }
2277
+ }
2278
+ )
2083
2279
  ] });
2084
2280
  }
2085
2281
  var DEFAULT_MAX_LENGTH = 6;
@@ -2360,7 +2556,7 @@ var MessageListV2 = react.forwardRef(
2360
2556
  onApproveAction,
2361
2557
  onRejectAction,
2362
2558
  onResendAction,
2363
- onMessageFeedback,
2559
+ onSubmitFeedback,
2364
2560
  typingSpeed = 4
2365
2561
  }, ref) {
2366
2562
  const scrollRef = react.useRef(null);
@@ -2500,7 +2696,7 @@ var MessageListV2 = react.forwardRef(
2500
2696
  message,
2501
2697
  onImageClick,
2502
2698
  onExecutionTraceClick,
2503
- onFeedback: onMessageFeedback,
2699
+ onSubmitFeedback,
2504
2700
  actions: messageActions?.assistantMessageActions,
2505
2701
  typingSpeed
2506
2702
  }
@@ -3268,6 +3464,316 @@ function ImageLightboxV2({ src, alt, onClose }) {
3268
3464
  document.body
3269
3465
  );
3270
3466
  }
3467
+ var PRE_PIPELINE_STEPS = /* @__PURE__ */ new Set([
3468
+ "record_execution",
3469
+ "resolve_provider",
3470
+ "resolve_mcp_servers",
3471
+ "build_pipeline",
3472
+ "load_skill_index"
3473
+ ]);
3474
+ function stepColor(step) {
3475
+ if (step.status === "failed") return "#ef4444";
3476
+ if (PRE_PIPELINE_STEPS.has(step.step)) return "#f59e0b";
3477
+ return "#3b82f6";
3478
+ }
3479
+ function formatMs(ms) {
3480
+ if (ms == null) return "\u2014";
3481
+ if (ms < 1e3) return `${ms} ms`;
3482
+ return `${(ms / 1e3).toFixed(2)} s`;
3483
+ }
3484
+ function TraceTimelineModal({
3485
+ open,
3486
+ onClose,
3487
+ executionId,
3488
+ apiBaseUrl,
3489
+ apiHeaders
3490
+ }) {
3491
+ const [trace, setTrace] = react.useState(null);
3492
+ const [loading, setLoading] = react.useState(false);
3493
+ const [error, setError] = react.useState(null);
3494
+ react.useEffect(() => {
3495
+ if (!open || !executionId) return;
3496
+ const ctrl = new AbortController();
3497
+ setLoading(true);
3498
+ setError(null);
3499
+ setTrace(null);
3500
+ const base = apiBaseUrl.replace(/\/+$/, "");
3501
+ fetch(`${base}/api/ask/executions/${encodeURIComponent(executionId)}/trace`, {
3502
+ method: "GET",
3503
+ headers: { Accept: "application/json", ...apiHeaders },
3504
+ signal: ctrl.signal
3505
+ }).then(async (resp) => {
3506
+ if (!resp.ok) {
3507
+ throw new Error(`Trace fetch failed: ${resp.status} ${resp.statusText}`);
3508
+ }
3509
+ return resp.json();
3510
+ }).then((data) => setTrace(data)).catch((e) => {
3511
+ if (e.name === "AbortError") return;
3512
+ setError(e instanceof Error ? e.message : "Trace fetch failed");
3513
+ }).finally(() => setLoading(false));
3514
+ return () => ctrl.abort();
3515
+ }, [open, executionId, apiBaseUrl, apiHeaders]);
3516
+ const totalMs = react.useMemo(() => {
3517
+ if (!trace) return 0;
3518
+ const meta = trace.runMetadata?.totalTimeMs;
3519
+ if (typeof meta === "number" && meta > 0) return meta;
3520
+ const starts = trace.pipelineSteps.map((s) => s.startTime);
3521
+ const ends = trace.pipelineSteps.map((s) => s.endTime ?? s.startTime).filter((t) => typeof t === "number");
3522
+ if (starts.length === 0 || ends.length === 0) return 0;
3523
+ return Math.max(...ends) - Math.min(...starts);
3524
+ }, [trace]);
3525
+ const accountedMs = react.useMemo(
3526
+ () => (trace?.pipelineSteps ?? []).reduce(
3527
+ (sum, s) => sum + (s.durationMs ?? 0),
3528
+ 0
3529
+ ),
3530
+ [trace]
3531
+ );
3532
+ const unaccountedMs = Math.max(totalMs - accountedMs, 0);
3533
+ if (typeof document === "undefined") return null;
3534
+ return reactDom.createPortal(
3535
+ /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: open && /* @__PURE__ */ jsxRuntime.jsx(
3536
+ framerMotion.motion.div,
3537
+ {
3538
+ initial: { opacity: 0 },
3539
+ animate: { opacity: 1 },
3540
+ exit: { opacity: 0 },
3541
+ transition: { duration: 0.15 },
3542
+ onClick: onClose,
3543
+ style: {
3544
+ position: "fixed",
3545
+ inset: 0,
3546
+ background: "rgba(0,0,0,0.45)",
3547
+ zIndex: 9999,
3548
+ display: "flex",
3549
+ alignItems: "center",
3550
+ justifyContent: "center",
3551
+ padding: 24
3552
+ },
3553
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
3554
+ framerMotion.motion.div,
3555
+ {
3556
+ initial: { y: 12, opacity: 0 },
3557
+ animate: { y: 0, opacity: 1 },
3558
+ exit: { y: 12, opacity: 0 },
3559
+ transition: { duration: 0.18 },
3560
+ onClick: (e) => e.stopPropagation(),
3561
+ style: {
3562
+ background: "#0b1220",
3563
+ color: "#e5e7eb",
3564
+ borderRadius: 12,
3565
+ width: "100%",
3566
+ maxWidth: 760,
3567
+ maxHeight: "85vh",
3568
+ overflow: "auto",
3569
+ boxShadow: "0 20px 60px rgba(0,0,0,0.45)",
3570
+ fontFamily: "ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif"
3571
+ },
3572
+ children: [
3573
+ /* @__PURE__ */ jsxRuntime.jsxs(
3574
+ "header",
3575
+ {
3576
+ style: {
3577
+ display: "flex",
3578
+ alignItems: "center",
3579
+ justifyContent: "space-between",
3580
+ padding: "14px 18px",
3581
+ borderBottom: "1px solid rgba(255,255,255,0.08)"
3582
+ },
3583
+ children: [
3584
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3585
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 14, fontWeight: 600 }, children: "Execution trace" }),
3586
+ /* @__PURE__ */ jsxRuntime.jsx(
3587
+ "div",
3588
+ {
3589
+ style: {
3590
+ fontSize: 11,
3591
+ opacity: 0.6,
3592
+ marginTop: 2,
3593
+ fontFamily: "ui-monospace, SFMono-Regular, monospace"
3594
+ },
3595
+ children: executionId ?? ""
3596
+ }
3597
+ )
3598
+ ] }),
3599
+ /* @__PURE__ */ jsxRuntime.jsx(
3600
+ "button",
3601
+ {
3602
+ onClick: onClose,
3603
+ "aria-label": "Close",
3604
+ style: {
3605
+ background: "transparent",
3606
+ border: 0,
3607
+ color: "#e5e7eb",
3608
+ cursor: "pointer",
3609
+ padding: 6,
3610
+ borderRadius: 6
3611
+ },
3612
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { style: { width: 18, height: 18 } })
3613
+ }
3614
+ )
3615
+ ]
3616
+ }
3617
+ ),
3618
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { padding: 18 }, children: [
3619
+ loading && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { opacity: 0.7, fontSize: 13 }, children: "Loading trace\u2026" }),
3620
+ error && /* @__PURE__ */ jsxRuntime.jsx(
3621
+ "div",
3622
+ {
3623
+ style: {
3624
+ color: "#fca5a5",
3625
+ fontSize: 13,
3626
+ whiteSpace: "pre-wrap"
3627
+ },
3628
+ children: error
3629
+ }
3630
+ ),
3631
+ trace && !loading && !error && /* @__PURE__ */ jsxRuntime.jsx(
3632
+ TimelineBars,
3633
+ {
3634
+ trace,
3635
+ totalMs,
3636
+ unaccountedMs
3637
+ }
3638
+ )
3639
+ ] })
3640
+ ]
3641
+ }
3642
+ )
3643
+ }
3644
+ ) }),
3645
+ document.body
3646
+ );
3647
+ }
3648
+ function TimelineBars({
3649
+ trace,
3650
+ totalMs,
3651
+ unaccountedMs
3652
+ }) {
3653
+ const bars = trace.pipelineSteps.map((step) => {
3654
+ const duration = step.durationMs ?? 0;
3655
+ const widthPct = totalMs > 0 ? duration / totalMs * 100 : 0;
3656
+ const llmMs = step.llmCall?.durationMs ?? null;
3657
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginBottom: 8 }, children: [
3658
+ /* @__PURE__ */ jsxRuntime.jsxs(
3659
+ "div",
3660
+ {
3661
+ style: {
3662
+ display: "flex",
3663
+ justifyContent: "space-between",
3664
+ fontSize: 12,
3665
+ marginBottom: 4,
3666
+ fontFamily: "ui-monospace, SFMono-Regular, monospace"
3667
+ },
3668
+ children: [
3669
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
3670
+ step.step,
3671
+ step.status === "failed" && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#fca5a5", marginLeft: 6 }, children: "(failed)" })
3672
+ ] }),
3673
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { opacity: 0.75 }, children: [
3674
+ formatMs(duration),
3675
+ llmMs != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { marginLeft: 8, opacity: 0.6 }, children: [
3676
+ "(LLM ",
3677
+ formatMs(llmMs),
3678
+ ")"
3679
+ ] })
3680
+ ] })
3681
+ ]
3682
+ }
3683
+ ),
3684
+ /* @__PURE__ */ jsxRuntime.jsx(
3685
+ "div",
3686
+ {
3687
+ style: {
3688
+ height: 8,
3689
+ background: "rgba(255,255,255,0.06)",
3690
+ borderRadius: 4,
3691
+ overflow: "hidden"
3692
+ },
3693
+ children: /* @__PURE__ */ jsxRuntime.jsx(
3694
+ "div",
3695
+ {
3696
+ style: {
3697
+ height: "100%",
3698
+ width: `${Math.max(widthPct, 0.3)}%`,
3699
+ background: stepColor(step),
3700
+ transition: "width 0.2s ease"
3701
+ }
3702
+ }
3703
+ )
3704
+ }
3705
+ )
3706
+ ] }, `${step.step}-${step.startTime}`);
3707
+ });
3708
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3709
+ bars,
3710
+ unaccountedMs > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginBottom: 8 }, children: [
3711
+ /* @__PURE__ */ jsxRuntime.jsxs(
3712
+ "div",
3713
+ {
3714
+ style: {
3715
+ display: "flex",
3716
+ justifyContent: "space-between",
3717
+ fontSize: 12,
3718
+ marginBottom: 4,
3719
+ fontFamily: "ui-monospace, SFMono-Regular, monospace",
3720
+ opacity: 0.7
3721
+ },
3722
+ children: [
3723
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "(unaccounted)" }),
3724
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatMs(unaccountedMs) })
3725
+ ]
3726
+ }
3727
+ ),
3728
+ /* @__PURE__ */ jsxRuntime.jsx(
3729
+ "div",
3730
+ {
3731
+ style: {
3732
+ height: 8,
3733
+ background: "rgba(255,255,255,0.06)",
3734
+ borderRadius: 4,
3735
+ overflow: "hidden"
3736
+ },
3737
+ children: /* @__PURE__ */ jsxRuntime.jsx(
3738
+ "div",
3739
+ {
3740
+ style: {
3741
+ height: "100%",
3742
+ width: `${unaccountedMs / Math.max(totalMs, 1) * 100}%`,
3743
+ background: "repeating-linear-gradient(45deg, rgba(255,255,255,0.18) 0 4px, transparent 4px 8px)"
3744
+ }
3745
+ }
3746
+ )
3747
+ }
3748
+ )
3749
+ ] }),
3750
+ /* @__PURE__ */ jsxRuntime.jsxs(
3751
+ "div",
3752
+ {
3753
+ style: {
3754
+ marginTop: 14,
3755
+ paddingTop: 12,
3756
+ borderTop: "1px solid rgba(255,255,255,0.08)",
3757
+ fontSize: 12,
3758
+ display: "flex",
3759
+ justifyContent: "space-between",
3760
+ opacity: 0.85
3761
+ },
3762
+ children: [
3763
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
3764
+ trace.pipelineSteps.length,
3765
+ " step",
3766
+ trace.pipelineSteps.length === 1 ? "" : "s"
3767
+ ] }),
3768
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontFamily: "ui-monospace, SFMono-Regular, monospace" }, children: [
3769
+ "total: ",
3770
+ formatMs(totalMs)
3771
+ ] })
3772
+ ]
3773
+ }
3774
+ )
3775
+ ] });
3776
+ }
3271
3777
  var DEFAULT_USER_ACTION_STATE = {
3272
3778
  request: null,
3273
3779
  result: null};
@@ -3458,12 +3964,39 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
3458
3964
  ]
3459
3965
  );
3460
3966
  const {
3461
- onExecutionTraceClick,
3967
+ onExecutionTraceClick: rawOnExecutionTraceClick,
3462
3968
  onResetSession,
3463
3969
  onUploadImageClick,
3464
3970
  onAttachFileClick,
3465
3971
  onMessageFeedback
3466
3972
  } = callbacks;
3973
+ const [debugTraceExecutionId, setDebugTraceExecutionId] = react.useState(null);
3974
+ const handleSubmitFeedback = react.useCallback(
3975
+ async ({ messageId, executionId, feedback, details }) => {
3976
+ if (!executionId) {
3977
+ throw new Error("Cannot submit feedback before the response completes");
3978
+ }
3979
+ await submitAskFeedback({
3980
+ baseUrl: config.api.baseUrl,
3981
+ headers: config.api.headers,
3982
+ executionId,
3983
+ feedback,
3984
+ details
3985
+ });
3986
+ onMessageFeedback?.({
3987
+ messageId,
3988
+ feedback: feedback === "POSITIVE" ? "up" : "down"
3989
+ });
3990
+ },
3991
+ [config.api.baseUrl, config.api.headers, onMessageFeedback]
3992
+ );
3993
+ const onExecutionTraceClick = react.useMemo(() => {
3994
+ if (!config.debug) return rawOnExecutionTraceClick;
3995
+ return (data) => {
3996
+ rawOnExecutionTraceClick?.(data);
3997
+ if (data.executionId) setDebugTraceExecutionId(data.executionId);
3998
+ };
3999
+ }, [config.debug, rawOnExecutionTraceClick]);
3467
4000
  const performResetSession = react.useCallback(() => {
3468
4001
  resetToEmptyStateRef.current = true;
3469
4002
  setEditingMessageId(null);
@@ -3521,6 +4054,7 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
3521
4054
  showEmptyStateIcon = true,
3522
4055
  emptyStateComponent,
3523
4056
  showResetSession = false,
4057
+ enableDeepModeToggle = true,
3524
4058
  showAttachmentButton = true,
3525
4059
  showUploadImageButton = true,
3526
4060
  showAttachFileButton = true,
@@ -3576,6 +4110,7 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
3576
4110
  stopRecording();
3577
4111
  };
3578
4112
  const isV2InputDisabled = !isSessionParamsConfigured || disableInput;
4113
+ const effectiveAnalysisMode = enableDeepModeToggle ? analysisMode : "fast";
3579
4114
  const isEmpty = messages.length === 0;
3580
4115
  if (isChatDisabled) {
3581
4116
  if (disabledComponent) {
@@ -3634,7 +4169,7 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
3634
4169
  if (isRecording) stopRecording();
3635
4170
  if (text.trim() && !disableInput && isSessionParamsConfigured) {
3636
4171
  setEditingMessageId(null);
3637
- void sendMessage(text.trim(), { analysisMode });
4172
+ void sendMessage(text.trim(), { analysisMode: effectiveAnalysisMode });
3638
4173
  }
3639
4174
  };
3640
4175
  const handleVoicePress = react.useCallback(async () => {
@@ -3661,7 +4196,9 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
3661
4196
  (message) => message.id === messageId && message.role === "user"
3662
4197
  );
3663
4198
  if (!targetMessage?.content.trim()) return;
3664
- void sendMessage(targetMessage.content.trim(), { analysisMode });
4199
+ void sendMessage(targetMessage.content.trim(), {
4200
+ analysisMode: effectiveAnalysisMode
4201
+ });
3665
4202
  const bump = () => messageListV2Ref.current?.scrollToBottom("instant");
3666
4203
  requestAnimationFrame(() => {
3667
4204
  bump();
@@ -3669,7 +4206,7 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
3669
4206
  window.setTimeout(bump, 120);
3670
4207
  });
3671
4208
  });
3672
- }, [isWaitingForResponse, messages, sendMessage, analysisMode]);
4209
+ }, [isWaitingForResponse, messages, sendMessage, effectiveAnalysisMode]);
3673
4210
  const handleClearEditing = react.useCallback(() => {
3674
4211
  setEditingMessageId(null);
3675
4212
  }, []);
@@ -3748,8 +4285,8 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
3748
4285
  onAttachFileClick,
3749
4286
  editingMessageId,
3750
4287
  onClearEditing: handleClearEditing,
3751
- analysisMode,
3752
- onAnalysisModeChange: setAnalysisMode,
4288
+ analysisMode: enableDeepModeToggle ? analysisMode : void 0,
4289
+ onAnalysisModeChange: enableDeepModeToggle ? setAnalysisMode : void 0,
3753
4290
  slashCommands
3754
4291
  }
3755
4292
  )
@@ -3789,7 +4326,7 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
3789
4326
  onResendAction: isUserActionSupported ? async () => {
3790
4327
  await resendOtp();
3791
4328
  } : void 0,
3792
- onMessageFeedback
4329
+ onSubmitFeedback: handleSubmitFeedback
3793
4330
  }
3794
4331
  ),
3795
4332
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -3824,8 +4361,8 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
3824
4361
  onAttachFileClick,
3825
4362
  editingMessageId,
3826
4363
  onClearEditing: handleClearEditing,
3827
- analysisMode,
3828
- onAnalysisModeChange: setAnalysisMode,
4364
+ analysisMode: enableDeepModeToggle ? analysisMode : void 0,
4365
+ onAnalysisModeChange: enableDeepModeToggle ? setAnalysisMode : void 0,
3829
4366
  slashCommands
3830
4367
  }
3831
4368
  )
@@ -3848,6 +4385,16 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
3848
4385
  onClose: closeResetSessionConfirm,
3849
4386
  onConfirm: performResetSession
3850
4387
  }
4388
+ ),
4389
+ config.debug && /* @__PURE__ */ jsxRuntime.jsx(
4390
+ TraceTimelineModal,
4391
+ {
4392
+ open: debugTraceExecutionId !== null,
4393
+ onClose: () => setDebugTraceExecutionId(null),
4394
+ executionId: debugTraceExecutionId,
4395
+ apiBaseUrl: config.api.baseUrl,
4396
+ apiHeaders: config.api.headers
4397
+ }
3851
4398
  )
3852
4399
  ]
3853
4400
  }