@paymanai/payman-ask-sdk 4.0.5 → 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.mjs CHANGED
@@ -131,11 +131,17 @@ var DEFAULT_SLASH_COMMANDS = [
131
131
  requiredAnyPermissions: ["vault:author", "vault:publish"]
132
132
  }
133
133
  ];
134
+ function hasCommandPermission(granted, requiredPermission) {
135
+ if (granted.has("*") || granted.has(requiredPermission)) return true;
136
+ if (!requiredPermission.includes(".")) return false;
137
+ const wildcard = requiredPermission.substring(0, requiredPermission.lastIndexOf(".")) + ".*";
138
+ return granted.has(wildcard);
139
+ }
134
140
  function filterSlashCommands(commands, permissions) {
135
141
  const granted = new Set(permissions ?? []);
136
142
  return commands.filter((command) => {
137
143
  const required = command.requiredAnyPermissions ?? [];
138
- return required.length === 0 || required.some((permission) => granted.has(permission));
144
+ return required.length === 0 || required.some((permission) => hasCommandPermission(granted, permission));
139
145
  });
140
146
  }
141
147
  function parseSlashCommand(content) {
@@ -148,9 +154,19 @@ function parseSlashCommand(content) {
148
154
  body: match[2] ?? ""
149
155
  };
150
156
  }
151
- function slashCommandBodyIsEmpty(content) {
157
+ function getSlashCommandValidationHint(content) {
152
158
  const parsed = parseSlashCommand(content);
153
- return parsed?.command === "/draft-knowledge" && parsed.body.trim().length === 0;
159
+ if (parsed?.command !== "/draft-knowledge") return null;
160
+ const lines = parsed.body.split(/\r?\n/);
161
+ const title = lines[0]?.trim() ?? "";
162
+ const markdownContent = lines.slice(1).join("\n").trim();
163
+ if (!title) {
164
+ return "Add a title after /draft-knowledge, then add markdown content on the next line.";
165
+ }
166
+ if (!markdownContent) {
167
+ return "Add markdown content on a new line below the title.";
168
+ }
169
+ return null;
154
170
  }
155
171
 
156
172
  // src/utils/errorMessages.ts
@@ -205,6 +221,43 @@ function initSentryIfNeeded(dsn) {
205
221
  }
206
222
  });
207
223
  }
224
+
225
+ // src/utils/feedbackClient.ts
226
+ var NEGATIVE_FEEDBACK_REASONS = [
227
+ { value: "NOT_FACTUALLY_CORRECT", label: "Not factually correct" },
228
+ { value: "INCOMPLETE_RESPONSE", label: "Incomplete response" },
229
+ { value: "DID_NOT_FOLLOW_REQUEST", label: "Did not follow my request" },
230
+ { value: "OVERACTIVE_REFUSAL", label: "Refused unnecessarily" },
231
+ { value: "ISSUE_WITH_THOUGHT_PROCESS", label: "Issue with reasoning" },
232
+ { value: "REPORT_CONTENT", label: "Report content" },
233
+ { value: "OTHER", label: "Other" }
234
+ ];
235
+ async function submitAskFeedback({
236
+ baseUrl,
237
+ headers,
238
+ executionId,
239
+ feedback,
240
+ details,
241
+ signal
242
+ }) {
243
+ const base = baseUrl.replace(/\/+$/, "");
244
+ const resp = await fetch(
245
+ `${base}/api/ask/executions/${encodeURIComponent(executionId)}/feedback`,
246
+ {
247
+ method: "POST",
248
+ headers: {
249
+ "Content-Type": "application/json",
250
+ Accept: "application/json",
251
+ ...headers ?? {}
252
+ },
253
+ body: JSON.stringify(details ? { feedback, details } : { feedback }),
254
+ signal
255
+ }
256
+ );
257
+ if (!resp.ok) {
258
+ throw new Error(`Feedback failed: ${resp.status} ${resp.statusText}`);
259
+ }
260
+ }
208
261
  function ImageLightbox({
209
262
  src,
210
263
  alt = "",
@@ -1667,6 +1720,143 @@ function ThinkingBlockV2({
1667
1720
  ) }) })
1668
1721
  ] });
1669
1722
  }
1723
+ var MAX_DETAILS_CHARS = 2e3;
1724
+ function FeedbackReasonModal({
1725
+ open,
1726
+ onClose,
1727
+ onSubmit
1728
+ }) {
1729
+ const [reason, setReason] = useState(
1730
+ NEGATIVE_FEEDBACK_REASONS[0].value
1731
+ );
1732
+ const [details, setDetails] = useState("");
1733
+ const [submitting, setSubmitting] = useState(false);
1734
+ const [error, setError] = useState(null);
1735
+ useEffect(() => {
1736
+ if (open) {
1737
+ setReason(NEGATIVE_FEEDBACK_REASONS[0].value);
1738
+ setDetails("");
1739
+ setError(null);
1740
+ setSubmitting(false);
1741
+ }
1742
+ }, [open]);
1743
+ const handleKeyDown = useCallback(
1744
+ (event) => {
1745
+ if (event.key === "Escape") onClose();
1746
+ },
1747
+ [onClose]
1748
+ );
1749
+ useEffect(() => {
1750
+ if (!open || typeof document === "undefined") return;
1751
+ document.addEventListener("keydown", handleKeyDown);
1752
+ const previousOverflow = document.body.style.overflow;
1753
+ document.body.style.overflow = "hidden";
1754
+ return () => {
1755
+ document.removeEventListener("keydown", handleKeyDown);
1756
+ document.body.style.overflow = previousOverflow;
1757
+ };
1758
+ }, [handleKeyDown, open]);
1759
+ const handleSubmit = async () => {
1760
+ setSubmitting(true);
1761
+ setError(null);
1762
+ try {
1763
+ await onSubmit(reason, details.trim() ? details.trim() : void 0);
1764
+ onClose();
1765
+ } catch (e) {
1766
+ setError(e instanceof Error ? e.message : "Could not send feedback");
1767
+ setSubmitting(false);
1768
+ }
1769
+ };
1770
+ return /* @__PURE__ */ jsx(AnimatePresence, { children: open ? /* @__PURE__ */ jsx(
1771
+ motion.div,
1772
+ {
1773
+ className: "payman-v2-feedback-modal-backdrop",
1774
+ initial: { opacity: 0 },
1775
+ animate: { opacity: 1 },
1776
+ exit: { opacity: 0 },
1777
+ transition: { duration: 0.18 },
1778
+ onClick: onClose,
1779
+ role: "presentation",
1780
+ children: /* @__PURE__ */ jsxs(
1781
+ motion.div,
1782
+ {
1783
+ initial: { opacity: 0, y: 12, scale: 0.98 },
1784
+ animate: { opacity: 1, y: 0, scale: 1 },
1785
+ exit: { opacity: 0, y: 8, scale: 0.98 },
1786
+ transition: { duration: 0.2, ease: [0.16, 1, 0.3, 1] },
1787
+ className: "payman-v2-feedback-modal-dialog",
1788
+ onClick: (event) => event.stopPropagation(),
1789
+ role: "dialog",
1790
+ "aria-modal": "true",
1791
+ "aria-labelledby": "payman-v2-feedback-title",
1792
+ children: [
1793
+ /* @__PURE__ */ jsx(
1794
+ "h2",
1795
+ {
1796
+ id: "payman-v2-feedback-title",
1797
+ className: "payman-v2-feedback-modal-title",
1798
+ children: "Tell us what went wrong"
1799
+ }
1800
+ ),
1801
+ /* @__PURE__ */ jsx(
1802
+ "label",
1803
+ {
1804
+ className: "payman-v2-feedback-modal-label",
1805
+ htmlFor: "payman-v2-feedback-reason",
1806
+ children: "What was the issue?"
1807
+ }
1808
+ ),
1809
+ /* @__PURE__ */ jsx(
1810
+ "select",
1811
+ {
1812
+ id: "payman-v2-feedback-reason",
1813
+ className: "payman-v2-feedback-modal-select",
1814
+ value: reason,
1815
+ onChange: (e) => setReason(e.target.value),
1816
+ disabled: submitting,
1817
+ children: NEGATIVE_FEEDBACK_REASONS.map((r) => /* @__PURE__ */ jsx("option", { value: r.value, children: r.label }, r.value))
1818
+ }
1819
+ ),
1820
+ /* @__PURE__ */ jsx(
1821
+ "textarea",
1822
+ {
1823
+ className: "payman-v2-feedback-modal-textarea",
1824
+ placeholder: "Add details (optional)",
1825
+ value: details,
1826
+ maxLength: MAX_DETAILS_CHARS,
1827
+ onChange: (e) => setDetails(e.target.value),
1828
+ disabled: submitting
1829
+ }
1830
+ ),
1831
+ error ? /* @__PURE__ */ jsx("p", { className: "payman-v2-feedback-modal-error", children: error }) : null,
1832
+ /* @__PURE__ */ jsxs("div", { className: "payman-v2-feedback-modal-actions", children: [
1833
+ /* @__PURE__ */ jsx(
1834
+ "button",
1835
+ {
1836
+ type: "button",
1837
+ onClick: onClose,
1838
+ disabled: submitting,
1839
+ className: "payman-v2-feedback-modal-btn payman-v2-feedback-modal-btn-secondary",
1840
+ children: "Cancel"
1841
+ }
1842
+ ),
1843
+ /* @__PURE__ */ jsx(
1844
+ "button",
1845
+ {
1846
+ type: "button",
1847
+ onClick: handleSubmit,
1848
+ disabled: submitting,
1849
+ className: "payman-v2-feedback-modal-btn payman-v2-feedback-modal-btn-primary",
1850
+ children: submitting ? "Sending\u2026" : "Submit"
1851
+ }
1852
+ )
1853
+ ] })
1854
+ ]
1855
+ }
1856
+ )
1857
+ }
1858
+ ) : null });
1859
+ }
1670
1860
  var RESPONSE_SPEED = {
1671
1861
  normal: [2, 4],
1672
1862
  fast: 1,
@@ -1749,12 +1939,26 @@ function AssistantMessageV2({
1749
1939
  message,
1750
1940
  onImageClick,
1751
1941
  onExecutionTraceClick,
1752
- onFeedback,
1942
+ onSubmitFeedback,
1753
1943
  actions,
1754
1944
  typingSpeed = 4
1755
1945
  }) {
1756
1946
  const [copied, setCopied] = useState(false);
1757
1947
  const [activeFeedback, setActiveFeedback] = useState(null);
1948
+ const [reasonModalOpen, setReasonModalOpen] = useState(false);
1949
+ const canSubmitFeedback = !!onSubmitFeedback && !!message.executionId;
1950
+ const handlePositiveFeedback = () => {
1951
+ if (!canSubmitFeedback || activeFeedback === "up") return;
1952
+ const previous = activeFeedback;
1953
+ setActiveFeedback("up");
1954
+ Promise.resolve(
1955
+ onSubmitFeedback?.({
1956
+ messageId: message.id,
1957
+ executionId: message.executionId,
1958
+ feedback: "POSITIVE"
1959
+ })
1960
+ ).catch(() => setActiveFeedback(previous));
1961
+ };
1758
1962
  const [toast, setToast] = useState(null);
1759
1963
  const copyResetTimerRef = useRef(null);
1760
1964
  const toastTimerRef = useRef(null);
@@ -1994,14 +2198,10 @@ function AssistantMessageV2({
1994
2198
  children: copied ? /* @__PURE__ */ jsx(Check, { style: { width: 16, height: 16 } }) : /* @__PURE__ */ jsx(Copy, { style: { width: 16, height: 16 } })
1995
2199
  }
1996
2200
  ) }),
1997
- showThumbsUp && /* @__PURE__ */ jsx(ActionTooltipV2, { label: "Good response", children: /* @__PURE__ */ jsx(
2201
+ showThumbsUp && canSubmitFeedback && /* @__PURE__ */ jsx(ActionTooltipV2, { label: "Good response", children: /* @__PURE__ */ jsx(
1998
2202
  "button",
1999
2203
  {
2000
- onClick: () => {
2001
- const next = activeFeedback === "up" ? null : "up";
2002
- setActiveFeedback(next);
2003
- if (next) onFeedback?.({ messageId: message.id, feedback: "up" });
2004
- },
2204
+ onClick: handlePositiveFeedback,
2005
2205
  className: cn(
2006
2206
  "payman-v2-assistant-msg-action-btn",
2007
2207
  activeFeedback === "up" && "payman-v2-assistant-msg-action-btn-active"
@@ -2010,14 +2210,10 @@ function AssistantMessageV2({
2010
2210
  children: /* @__PURE__ */ jsx(ThumbsUp, { style: { width: 15, height: 15 } })
2011
2211
  }
2012
2212
  ) }),
2013
- showThumbsDown && /* @__PURE__ */ jsx(ActionTooltipV2, { label: "Bad response", children: /* @__PURE__ */ jsx(
2213
+ showThumbsDown && canSubmitFeedback && /* @__PURE__ */ jsx(ActionTooltipV2, { label: "Bad response", children: /* @__PURE__ */ jsx(
2014
2214
  "button",
2015
2215
  {
2016
- onClick: () => {
2017
- const next = activeFeedback === "down" ? null : "down";
2018
- setActiveFeedback(next);
2019
- if (next) onFeedback?.({ messageId: message.id, feedback: "down" });
2020
- },
2216
+ onClick: () => setReasonModalOpen(true),
2021
2217
  className: cn(
2022
2218
  "payman-v2-assistant-msg-action-btn",
2023
2219
  activeFeedback === "down" && "payman-v2-assistant-msg-action-btn-active"
@@ -2037,7 +2233,23 @@ function AssistantMessageV2({
2037
2233
  ) }),
2038
2234
  totalElapsedLabel && /* @__PURE__ */ jsx("span", { className: "payman-v2-assistant-msg-elapsed", children: totalElapsedLabel })
2039
2235
  ] })
2040
- ] })
2236
+ ] }),
2237
+ /* @__PURE__ */ jsx(
2238
+ FeedbackReasonModal,
2239
+ {
2240
+ open: reasonModalOpen,
2241
+ onClose: () => setReasonModalOpen(false),
2242
+ onSubmit: async (reason, details) => {
2243
+ await onSubmitFeedback?.({
2244
+ messageId: message.id,
2245
+ executionId: message.executionId,
2246
+ feedback: reason,
2247
+ details
2248
+ });
2249
+ setActiveFeedback("down");
2250
+ }
2251
+ }
2252
+ )
2041
2253
  ] });
2042
2254
  }
2043
2255
  var DEFAULT_MAX_LENGTH = 6;
@@ -2318,7 +2530,7 @@ var MessageListV2 = forwardRef(
2318
2530
  onApproveAction,
2319
2531
  onRejectAction,
2320
2532
  onResendAction,
2321
- onMessageFeedback,
2533
+ onSubmitFeedback,
2322
2534
  typingSpeed = 4
2323
2535
  }, ref) {
2324
2536
  const scrollRef = useRef(null);
@@ -2458,7 +2670,7 @@ var MessageListV2 = forwardRef(
2458
2670
  message,
2459
2671
  onImageClick,
2460
2672
  onExecutionTraceClick,
2461
- onFeedback: onMessageFeedback,
2673
+ onSubmitFeedback,
2462
2674
  actions: messageActions?.assistantMessageActions,
2463
2675
  typingSpeed
2464
2676
  }
@@ -2622,8 +2834,9 @@ var ChatInputV2 = forwardRef(
2622
2834
  }, [isRecording, transcribedText]);
2623
2835
  const handleSend = useCallback(() => {
2624
2836
  if (!value.trim() || disabled) return;
2625
- if (slashCommandBodyIsEmpty(value)) {
2626
- setInlineHint("Add markdown content below the command line.");
2837
+ const commandHint = getSlashCommandValidationHint(value);
2838
+ if (commandHint) {
2839
+ setInlineHint(commandHint);
2627
2840
  return;
2628
2841
  }
2629
2842
  voiceDraftSyncActiveRef.current = false;
@@ -3225,6 +3438,316 @@ function ImageLightboxV2({ src, alt, onClose }) {
3225
3438
  document.body
3226
3439
  );
3227
3440
  }
3441
+ var PRE_PIPELINE_STEPS = /* @__PURE__ */ new Set([
3442
+ "record_execution",
3443
+ "resolve_provider",
3444
+ "resolve_mcp_servers",
3445
+ "build_pipeline",
3446
+ "load_skill_index"
3447
+ ]);
3448
+ function stepColor(step) {
3449
+ if (step.status === "failed") return "#ef4444";
3450
+ if (PRE_PIPELINE_STEPS.has(step.step)) return "#f59e0b";
3451
+ return "#3b82f6";
3452
+ }
3453
+ function formatMs(ms) {
3454
+ if (ms == null) return "\u2014";
3455
+ if (ms < 1e3) return `${ms} ms`;
3456
+ return `${(ms / 1e3).toFixed(2)} s`;
3457
+ }
3458
+ function TraceTimelineModal({
3459
+ open,
3460
+ onClose,
3461
+ executionId,
3462
+ apiBaseUrl,
3463
+ apiHeaders
3464
+ }) {
3465
+ const [trace, setTrace] = useState(null);
3466
+ const [loading, setLoading] = useState(false);
3467
+ const [error, setError] = useState(null);
3468
+ useEffect(() => {
3469
+ if (!open || !executionId) return;
3470
+ const ctrl = new AbortController();
3471
+ setLoading(true);
3472
+ setError(null);
3473
+ setTrace(null);
3474
+ const base = apiBaseUrl.replace(/\/+$/, "");
3475
+ fetch(`${base}/api/ask/executions/${encodeURIComponent(executionId)}/trace`, {
3476
+ method: "GET",
3477
+ headers: { Accept: "application/json", ...apiHeaders },
3478
+ signal: ctrl.signal
3479
+ }).then(async (resp) => {
3480
+ if (!resp.ok) {
3481
+ throw new Error(`Trace fetch failed: ${resp.status} ${resp.statusText}`);
3482
+ }
3483
+ return resp.json();
3484
+ }).then((data) => setTrace(data)).catch((e) => {
3485
+ if (e.name === "AbortError") return;
3486
+ setError(e instanceof Error ? e.message : "Trace fetch failed");
3487
+ }).finally(() => setLoading(false));
3488
+ return () => ctrl.abort();
3489
+ }, [open, executionId, apiBaseUrl, apiHeaders]);
3490
+ const totalMs = useMemo(() => {
3491
+ if (!trace) return 0;
3492
+ const meta = trace.runMetadata?.totalTimeMs;
3493
+ if (typeof meta === "number" && meta > 0) return meta;
3494
+ const starts = trace.pipelineSteps.map((s) => s.startTime);
3495
+ const ends = trace.pipelineSteps.map((s) => s.endTime ?? s.startTime).filter((t) => typeof t === "number");
3496
+ if (starts.length === 0 || ends.length === 0) return 0;
3497
+ return Math.max(...ends) - Math.min(...starts);
3498
+ }, [trace]);
3499
+ const accountedMs = useMemo(
3500
+ () => (trace?.pipelineSteps ?? []).reduce(
3501
+ (sum, s) => sum + (s.durationMs ?? 0),
3502
+ 0
3503
+ ),
3504
+ [trace]
3505
+ );
3506
+ const unaccountedMs = Math.max(totalMs - accountedMs, 0);
3507
+ if (typeof document === "undefined") return null;
3508
+ return createPortal(
3509
+ /* @__PURE__ */ jsx(AnimatePresence, { children: open && /* @__PURE__ */ jsx(
3510
+ motion.div,
3511
+ {
3512
+ initial: { opacity: 0 },
3513
+ animate: { opacity: 1 },
3514
+ exit: { opacity: 0 },
3515
+ transition: { duration: 0.15 },
3516
+ onClick: onClose,
3517
+ style: {
3518
+ position: "fixed",
3519
+ inset: 0,
3520
+ background: "rgba(0,0,0,0.45)",
3521
+ zIndex: 9999,
3522
+ display: "flex",
3523
+ alignItems: "center",
3524
+ justifyContent: "center",
3525
+ padding: 24
3526
+ },
3527
+ children: /* @__PURE__ */ jsxs(
3528
+ motion.div,
3529
+ {
3530
+ initial: { y: 12, opacity: 0 },
3531
+ animate: { y: 0, opacity: 1 },
3532
+ exit: { y: 12, opacity: 0 },
3533
+ transition: { duration: 0.18 },
3534
+ onClick: (e) => e.stopPropagation(),
3535
+ style: {
3536
+ background: "#0b1220",
3537
+ color: "#e5e7eb",
3538
+ borderRadius: 12,
3539
+ width: "100%",
3540
+ maxWidth: 760,
3541
+ maxHeight: "85vh",
3542
+ overflow: "auto",
3543
+ boxShadow: "0 20px 60px rgba(0,0,0,0.45)",
3544
+ fontFamily: "ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif"
3545
+ },
3546
+ children: [
3547
+ /* @__PURE__ */ jsxs(
3548
+ "header",
3549
+ {
3550
+ style: {
3551
+ display: "flex",
3552
+ alignItems: "center",
3553
+ justifyContent: "space-between",
3554
+ padding: "14px 18px",
3555
+ borderBottom: "1px solid rgba(255,255,255,0.08)"
3556
+ },
3557
+ children: [
3558
+ /* @__PURE__ */ jsxs("div", { children: [
3559
+ /* @__PURE__ */ jsx("div", { style: { fontSize: 14, fontWeight: 600 }, children: "Execution trace" }),
3560
+ /* @__PURE__ */ jsx(
3561
+ "div",
3562
+ {
3563
+ style: {
3564
+ fontSize: 11,
3565
+ opacity: 0.6,
3566
+ marginTop: 2,
3567
+ fontFamily: "ui-monospace, SFMono-Regular, monospace"
3568
+ },
3569
+ children: executionId ?? ""
3570
+ }
3571
+ )
3572
+ ] }),
3573
+ /* @__PURE__ */ jsx(
3574
+ "button",
3575
+ {
3576
+ onClick: onClose,
3577
+ "aria-label": "Close",
3578
+ style: {
3579
+ background: "transparent",
3580
+ border: 0,
3581
+ color: "#e5e7eb",
3582
+ cursor: "pointer",
3583
+ padding: 6,
3584
+ borderRadius: 6
3585
+ },
3586
+ children: /* @__PURE__ */ jsx(X, { style: { width: 18, height: 18 } })
3587
+ }
3588
+ )
3589
+ ]
3590
+ }
3591
+ ),
3592
+ /* @__PURE__ */ jsxs("div", { style: { padding: 18 }, children: [
3593
+ loading && /* @__PURE__ */ jsx("div", { style: { opacity: 0.7, fontSize: 13 }, children: "Loading trace\u2026" }),
3594
+ error && /* @__PURE__ */ jsx(
3595
+ "div",
3596
+ {
3597
+ style: {
3598
+ color: "#fca5a5",
3599
+ fontSize: 13,
3600
+ whiteSpace: "pre-wrap"
3601
+ },
3602
+ children: error
3603
+ }
3604
+ ),
3605
+ trace && !loading && !error && /* @__PURE__ */ jsx(
3606
+ TimelineBars,
3607
+ {
3608
+ trace,
3609
+ totalMs,
3610
+ unaccountedMs
3611
+ }
3612
+ )
3613
+ ] })
3614
+ ]
3615
+ }
3616
+ )
3617
+ }
3618
+ ) }),
3619
+ document.body
3620
+ );
3621
+ }
3622
+ function TimelineBars({
3623
+ trace,
3624
+ totalMs,
3625
+ unaccountedMs
3626
+ }) {
3627
+ const bars = trace.pipelineSteps.map((step) => {
3628
+ const duration = step.durationMs ?? 0;
3629
+ const widthPct = totalMs > 0 ? duration / totalMs * 100 : 0;
3630
+ const llmMs = step.llmCall?.durationMs ?? null;
3631
+ return /* @__PURE__ */ jsxs("div", { style: { marginBottom: 8 }, children: [
3632
+ /* @__PURE__ */ jsxs(
3633
+ "div",
3634
+ {
3635
+ style: {
3636
+ display: "flex",
3637
+ justifyContent: "space-between",
3638
+ fontSize: 12,
3639
+ marginBottom: 4,
3640
+ fontFamily: "ui-monospace, SFMono-Regular, monospace"
3641
+ },
3642
+ children: [
3643
+ /* @__PURE__ */ jsxs("span", { children: [
3644
+ step.step,
3645
+ step.status === "failed" && /* @__PURE__ */ jsx("span", { style: { color: "#fca5a5", marginLeft: 6 }, children: "(failed)" })
3646
+ ] }),
3647
+ /* @__PURE__ */ jsxs("span", { style: { opacity: 0.75 }, children: [
3648
+ formatMs(duration),
3649
+ llmMs != null && /* @__PURE__ */ jsxs("span", { style: { marginLeft: 8, opacity: 0.6 }, children: [
3650
+ "(LLM ",
3651
+ formatMs(llmMs),
3652
+ ")"
3653
+ ] })
3654
+ ] })
3655
+ ]
3656
+ }
3657
+ ),
3658
+ /* @__PURE__ */ jsx(
3659
+ "div",
3660
+ {
3661
+ style: {
3662
+ height: 8,
3663
+ background: "rgba(255,255,255,0.06)",
3664
+ borderRadius: 4,
3665
+ overflow: "hidden"
3666
+ },
3667
+ children: /* @__PURE__ */ jsx(
3668
+ "div",
3669
+ {
3670
+ style: {
3671
+ height: "100%",
3672
+ width: `${Math.max(widthPct, 0.3)}%`,
3673
+ background: stepColor(step),
3674
+ transition: "width 0.2s ease"
3675
+ }
3676
+ }
3677
+ )
3678
+ }
3679
+ )
3680
+ ] }, `${step.step}-${step.startTime}`);
3681
+ });
3682
+ return /* @__PURE__ */ jsxs("div", { children: [
3683
+ bars,
3684
+ unaccountedMs > 0 && /* @__PURE__ */ jsxs("div", { style: { marginBottom: 8 }, children: [
3685
+ /* @__PURE__ */ jsxs(
3686
+ "div",
3687
+ {
3688
+ style: {
3689
+ display: "flex",
3690
+ justifyContent: "space-between",
3691
+ fontSize: 12,
3692
+ marginBottom: 4,
3693
+ fontFamily: "ui-monospace, SFMono-Regular, monospace",
3694
+ opacity: 0.7
3695
+ },
3696
+ children: [
3697
+ /* @__PURE__ */ jsx("span", { children: "(unaccounted)" }),
3698
+ /* @__PURE__ */ jsx("span", { children: formatMs(unaccountedMs) })
3699
+ ]
3700
+ }
3701
+ ),
3702
+ /* @__PURE__ */ jsx(
3703
+ "div",
3704
+ {
3705
+ style: {
3706
+ height: 8,
3707
+ background: "rgba(255,255,255,0.06)",
3708
+ borderRadius: 4,
3709
+ overflow: "hidden"
3710
+ },
3711
+ children: /* @__PURE__ */ jsx(
3712
+ "div",
3713
+ {
3714
+ style: {
3715
+ height: "100%",
3716
+ width: `${unaccountedMs / Math.max(totalMs, 1) * 100}%`,
3717
+ background: "repeating-linear-gradient(45deg, rgba(255,255,255,0.18) 0 4px, transparent 4px 8px)"
3718
+ }
3719
+ }
3720
+ )
3721
+ }
3722
+ )
3723
+ ] }),
3724
+ /* @__PURE__ */ jsxs(
3725
+ "div",
3726
+ {
3727
+ style: {
3728
+ marginTop: 14,
3729
+ paddingTop: 12,
3730
+ borderTop: "1px solid rgba(255,255,255,0.08)",
3731
+ fontSize: 12,
3732
+ display: "flex",
3733
+ justifyContent: "space-between",
3734
+ opacity: 0.85
3735
+ },
3736
+ children: [
3737
+ /* @__PURE__ */ jsxs("span", { children: [
3738
+ trace.pipelineSteps.length,
3739
+ " step",
3740
+ trace.pipelineSteps.length === 1 ? "" : "s"
3741
+ ] }),
3742
+ /* @__PURE__ */ jsxs("span", { style: { fontFamily: "ui-monospace, SFMono-Regular, monospace" }, children: [
3743
+ "total: ",
3744
+ formatMs(totalMs)
3745
+ ] })
3746
+ ]
3747
+ }
3748
+ )
3749
+ ] });
3750
+ }
3228
3751
  var DEFAULT_USER_ACTION_STATE = {
3229
3752
  request: null,
3230
3753
  result: null};
@@ -3415,12 +3938,39 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
3415
3938
  ]
3416
3939
  );
3417
3940
  const {
3418
- onExecutionTraceClick,
3941
+ onExecutionTraceClick: rawOnExecutionTraceClick,
3419
3942
  onResetSession,
3420
3943
  onUploadImageClick,
3421
3944
  onAttachFileClick,
3422
3945
  onMessageFeedback
3423
3946
  } = callbacks;
3947
+ const [debugTraceExecutionId, setDebugTraceExecutionId] = useState(null);
3948
+ const handleSubmitFeedback = useCallback(
3949
+ async ({ messageId, executionId, feedback, details }) => {
3950
+ if (!executionId) {
3951
+ throw new Error("Cannot submit feedback before the response completes");
3952
+ }
3953
+ await submitAskFeedback({
3954
+ baseUrl: config.api.baseUrl,
3955
+ headers: config.api.headers,
3956
+ executionId,
3957
+ feedback,
3958
+ details
3959
+ });
3960
+ onMessageFeedback?.({
3961
+ messageId,
3962
+ feedback: feedback === "POSITIVE" ? "up" : "down"
3963
+ });
3964
+ },
3965
+ [config.api.baseUrl, config.api.headers, onMessageFeedback]
3966
+ );
3967
+ const onExecutionTraceClick = useMemo(() => {
3968
+ if (!config.debug) return rawOnExecutionTraceClick;
3969
+ return (data) => {
3970
+ rawOnExecutionTraceClick?.(data);
3971
+ if (data.executionId) setDebugTraceExecutionId(data.executionId);
3972
+ };
3973
+ }, [config.debug, rawOnExecutionTraceClick]);
3424
3974
  const performResetSession = useCallback(() => {
3425
3975
  resetToEmptyStateRef.current = true;
3426
3976
  setEditingMessageId(null);
@@ -3478,6 +4028,7 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
3478
4028
  showEmptyStateIcon = true,
3479
4029
  emptyStateComponent,
3480
4030
  showResetSession = false,
4031
+ enableDeepModeToggle = true,
3481
4032
  showAttachmentButton = true,
3482
4033
  showUploadImageButton = true,
3483
4034
  showAttachFileButton = true,
@@ -3533,6 +4084,7 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
3533
4084
  stopRecording();
3534
4085
  };
3535
4086
  const isV2InputDisabled = !isSessionParamsConfigured || disableInput;
4087
+ const effectiveAnalysisMode = enableDeepModeToggle ? analysisMode : "fast";
3536
4088
  const isEmpty = messages.length === 0;
3537
4089
  if (isChatDisabled) {
3538
4090
  if (disabledComponent) {
@@ -3591,7 +4143,7 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
3591
4143
  if (isRecording) stopRecording();
3592
4144
  if (text.trim() && !disableInput && isSessionParamsConfigured) {
3593
4145
  setEditingMessageId(null);
3594
- void sendMessage(text.trim(), { analysisMode });
4146
+ void sendMessage(text.trim(), { analysisMode: effectiveAnalysisMode });
3595
4147
  }
3596
4148
  };
3597
4149
  const handleVoicePress = useCallback(async () => {
@@ -3618,7 +4170,9 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
3618
4170
  (message) => message.id === messageId && message.role === "user"
3619
4171
  );
3620
4172
  if (!targetMessage?.content.trim()) return;
3621
- void sendMessage(targetMessage.content.trim(), { analysisMode });
4173
+ void sendMessage(targetMessage.content.trim(), {
4174
+ analysisMode: effectiveAnalysisMode
4175
+ });
3622
4176
  const bump = () => messageListV2Ref.current?.scrollToBottom("instant");
3623
4177
  requestAnimationFrame(() => {
3624
4178
  bump();
@@ -3626,7 +4180,7 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
3626
4180
  window.setTimeout(bump, 120);
3627
4181
  });
3628
4182
  });
3629
- }, [isWaitingForResponse, messages, sendMessage, analysisMode]);
4183
+ }, [isWaitingForResponse, messages, sendMessage, effectiveAnalysisMode]);
3630
4184
  const handleClearEditing = useCallback(() => {
3631
4185
  setEditingMessageId(null);
3632
4186
  }, []);
@@ -3705,8 +4259,8 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
3705
4259
  onAttachFileClick,
3706
4260
  editingMessageId,
3707
4261
  onClearEditing: handleClearEditing,
3708
- analysisMode,
3709
- onAnalysisModeChange: setAnalysisMode,
4262
+ analysisMode: enableDeepModeToggle ? analysisMode : void 0,
4263
+ onAnalysisModeChange: enableDeepModeToggle ? setAnalysisMode : void 0,
3710
4264
  slashCommands
3711
4265
  }
3712
4266
  )
@@ -3746,7 +4300,7 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
3746
4300
  onResendAction: isUserActionSupported ? async () => {
3747
4301
  await resendOtp();
3748
4302
  } : void 0,
3749
- onMessageFeedback
4303
+ onSubmitFeedback: handleSubmitFeedback
3750
4304
  }
3751
4305
  ),
3752
4306
  /* @__PURE__ */ jsx(
@@ -3781,8 +4335,8 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
3781
4335
  onAttachFileClick,
3782
4336
  editingMessageId,
3783
4337
  onClearEditing: handleClearEditing,
3784
- analysisMode,
3785
- onAnalysisModeChange: setAnalysisMode,
4338
+ analysisMode: enableDeepModeToggle ? analysisMode : void 0,
4339
+ onAnalysisModeChange: enableDeepModeToggle ? setAnalysisMode : void 0,
3786
4340
  slashCommands
3787
4341
  }
3788
4342
  )
@@ -3805,6 +4359,16 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
3805
4359
  onClose: closeResetSessionConfirm,
3806
4360
  onConfirm: performResetSession
3807
4361
  }
4362
+ ),
4363
+ config.debug && /* @__PURE__ */ jsx(
4364
+ TraceTimelineModal,
4365
+ {
4366
+ open: debugTraceExecutionId !== null,
4367
+ onClose: () => setDebugTraceExecutionId(null),
4368
+ executionId: debugTraceExecutionId,
4369
+ apiBaseUrl: config.api.baseUrl,
4370
+ apiHeaders: config.api.headers
4371
+ }
3808
4372
  )
3809
4373
  ]
3810
4374
  }