@paymanai/payman-ask-sdk 4.0.6 → 4.0.8
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 +126 -55
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +127 -56
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +138 -15
- package/dist/styles.css.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { createContext, forwardRef, useRef, useState, useCallback, useImperative
|
|
|
5
5
|
import { clsx } from 'clsx';
|
|
6
6
|
import { twMerge } from 'tailwind-merge';
|
|
7
7
|
import * as Sentry from '@sentry/react';
|
|
8
|
-
import { ArrowDown, Pencil, X, RotateCcw, Telescope, Zap, Plus, ImagePlus, Paperclip, Mic, ArrowUp, Check, AlertCircle, Copy, WifiOff, ThumbsUp, ThumbsDown, Binoculars, ShieldCheck, Download, Loader2, User, Clock, Sparkles, ImageOff, Eye,
|
|
8
|
+
import { ArrowDown, Pencil, X, RotateCcw, Telescope, Zap, Plus, ImagePlus, Paperclip, Mic, ArrowUp, Check, AlertCircle, Copy, WifiOff, ThumbsUp, ThumbsDown, Binoculars, ShieldCheck, Download, Loader2, ChevronDown, User, Clock, Sparkles, ImageOff, Eye, ChevronRight } from 'lucide-react';
|
|
9
9
|
import ReactMarkdown from 'react-markdown';
|
|
10
10
|
import remarkGfm from 'remark-gfm';
|
|
11
11
|
import { createPortal } from 'react-dom';
|
|
@@ -232,28 +232,38 @@ var NEGATIVE_FEEDBACK_REASONS = [
|
|
|
232
232
|
{ value: "REPORT_CONTENT", label: "Report content" },
|
|
233
233
|
{ value: "OTHER", label: "Other" }
|
|
234
234
|
];
|
|
235
|
-
|
|
235
|
+
var DEFAULT_STREAM_ENDPOINT = "/api/playground/ask/stream";
|
|
236
|
+
async function submitFeedback({
|
|
236
237
|
baseUrl,
|
|
238
|
+
streamEndpoint,
|
|
237
239
|
headers,
|
|
240
|
+
authToken,
|
|
241
|
+
stage,
|
|
242
|
+
stageQueryParam,
|
|
238
243
|
executionId,
|
|
239
244
|
feedback,
|
|
240
245
|
details,
|
|
241
246
|
signal
|
|
242
247
|
}) {
|
|
243
248
|
const base = baseUrl.replace(/\/+$/, "");
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
249
|
+
const endpointPath = (streamEndpoint || DEFAULT_STREAM_ENDPOINT).split("?")[0].replace(/\/+$/, "");
|
|
250
|
+
const basePath = endpointPath.endsWith("/stream") ? endpointPath.slice(0, -"/stream".length) : endpointPath;
|
|
251
|
+
const query = new URLSearchParams();
|
|
252
|
+
if (stage) query.set(stageQueryParam ?? "stage", stage);
|
|
253
|
+
const qs = query.toString() ? `?${query.toString()}` : "";
|
|
254
|
+
const url = `${base}${basePath}/executions/${encodeURIComponent(executionId)}/feedback${qs}`;
|
|
255
|
+
const requestHeaders = {
|
|
256
|
+
"Content-Type": "application/json",
|
|
257
|
+
Accept: "application/json",
|
|
258
|
+
...headers ?? {}
|
|
259
|
+
};
|
|
260
|
+
if (authToken) requestHeaders.Authorization = `Bearer ${authToken}`;
|
|
261
|
+
const resp = await fetch(url, {
|
|
262
|
+
method: "POST",
|
|
263
|
+
headers: requestHeaders,
|
|
264
|
+
body: JSON.stringify(details ? { feedback, details } : { feedback }),
|
|
265
|
+
signal
|
|
266
|
+
});
|
|
257
267
|
if (!resp.ok) {
|
|
258
268
|
throw new Error(`Feedback failed: ${resp.status} ${resp.statusText}`);
|
|
259
269
|
}
|
|
@@ -1732,19 +1742,26 @@ function FeedbackReasonModal({
|
|
|
1732
1742
|
const [details, setDetails] = useState("");
|
|
1733
1743
|
const [submitting, setSubmitting] = useState(false);
|
|
1734
1744
|
const [error, setError] = useState(null);
|
|
1745
|
+
const [reasonOpen, setReasonOpen] = useState(false);
|
|
1735
1746
|
useEffect(() => {
|
|
1736
1747
|
if (open) {
|
|
1737
1748
|
setReason(NEGATIVE_FEEDBACK_REASONS[0].value);
|
|
1738
1749
|
setDetails("");
|
|
1739
1750
|
setError(null);
|
|
1740
1751
|
setSubmitting(false);
|
|
1752
|
+
setReasonOpen(false);
|
|
1741
1753
|
}
|
|
1742
1754
|
}, [open]);
|
|
1743
1755
|
const handleKeyDown = useCallback(
|
|
1744
1756
|
(event) => {
|
|
1745
|
-
if (event.key
|
|
1757
|
+
if (event.key !== "Escape") return;
|
|
1758
|
+
if (reasonOpen) {
|
|
1759
|
+
setReasonOpen(false);
|
|
1760
|
+
return;
|
|
1761
|
+
}
|
|
1762
|
+
onClose();
|
|
1746
1763
|
},
|
|
1747
|
-
[onClose]
|
|
1764
|
+
[onClose, reasonOpen]
|
|
1748
1765
|
);
|
|
1749
1766
|
useEffect(() => {
|
|
1750
1767
|
if (!open || typeof document === "undefined") return;
|
|
@@ -1759,6 +1776,7 @@ function FeedbackReasonModal({
|
|
|
1759
1776
|
const handleSubmit = async () => {
|
|
1760
1777
|
setSubmitting(true);
|
|
1761
1778
|
setError(null);
|
|
1779
|
+
setReasonOpen(false);
|
|
1762
1780
|
try {
|
|
1763
1781
|
await onSubmit(reason, details.trim() ? details.trim() : void 0);
|
|
1764
1782
|
onClose();
|
|
@@ -1767,6 +1785,7 @@ function FeedbackReasonModal({
|
|
|
1767
1785
|
setSubmitting(false);
|
|
1768
1786
|
}
|
|
1769
1787
|
};
|
|
1788
|
+
const selectedReason = NEGATIVE_FEEDBACK_REASONS.find((item) => item.value === reason) ?? NEGATIVE_FEEDBACK_REASONS[0];
|
|
1770
1789
|
return /* @__PURE__ */ jsx(AnimatePresence, { children: open ? /* @__PURE__ */ jsx(
|
|
1771
1790
|
motion.div,
|
|
1772
1791
|
{
|
|
@@ -1790,6 +1809,17 @@ function FeedbackReasonModal({
|
|
|
1790
1809
|
"aria-modal": "true",
|
|
1791
1810
|
"aria-labelledby": "payman-v2-feedback-title",
|
|
1792
1811
|
children: [
|
|
1812
|
+
/* @__PURE__ */ jsx(
|
|
1813
|
+
"button",
|
|
1814
|
+
{
|
|
1815
|
+
type: "button",
|
|
1816
|
+
onClick: onClose,
|
|
1817
|
+
disabled: submitting,
|
|
1818
|
+
className: "payman-v2-feedback-modal-close",
|
|
1819
|
+
"aria-label": "Close feedback modal",
|
|
1820
|
+
children: /* @__PURE__ */ jsx(X, { size: 18, strokeWidth: 2 })
|
|
1821
|
+
}
|
|
1822
|
+
),
|
|
1793
1823
|
/* @__PURE__ */ jsx(
|
|
1794
1824
|
"h2",
|
|
1795
1825
|
{
|
|
@@ -1806,15 +1836,73 @@ function FeedbackReasonModal({
|
|
|
1806
1836
|
children: "What was the issue?"
|
|
1807
1837
|
}
|
|
1808
1838
|
),
|
|
1809
|
-
/* @__PURE__ */
|
|
1810
|
-
"
|
|
1839
|
+
/* @__PURE__ */ jsxs(
|
|
1840
|
+
"div",
|
|
1811
1841
|
{
|
|
1812
1842
|
id: "payman-v2-feedback-reason",
|
|
1813
|
-
className: "payman-v2-feedback-modal-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1843
|
+
className: "payman-v2-feedback-modal-reason",
|
|
1844
|
+
onBlur: (event) => {
|
|
1845
|
+
const nextTarget = event.relatedTarget;
|
|
1846
|
+
if (!nextTarget || !event.currentTarget.contains(nextTarget)) {
|
|
1847
|
+
setReasonOpen(false);
|
|
1848
|
+
}
|
|
1849
|
+
},
|
|
1850
|
+
children: [
|
|
1851
|
+
/* @__PURE__ */ jsxs(
|
|
1852
|
+
"button",
|
|
1853
|
+
{
|
|
1854
|
+
type: "button",
|
|
1855
|
+
className: "payman-v2-feedback-modal-reason-trigger",
|
|
1856
|
+
"aria-haspopup": "listbox",
|
|
1857
|
+
"aria-expanded": reasonOpen,
|
|
1858
|
+
"aria-controls": "payman-v2-feedback-reason-options",
|
|
1859
|
+
disabled: submitting,
|
|
1860
|
+
onClick: () => setReasonOpen((current) => !current),
|
|
1861
|
+
children: [
|
|
1862
|
+
/* @__PURE__ */ jsx("span", { children: selectedReason.label }),
|
|
1863
|
+
/* @__PURE__ */ jsx(
|
|
1864
|
+
ChevronDown,
|
|
1865
|
+
{
|
|
1866
|
+
size: 17,
|
|
1867
|
+
strokeWidth: 2,
|
|
1868
|
+
className: reasonOpen ? "payman-v2-feedback-modal-reason-chevron payman-v2-feedback-modal-reason-chevron-open" : "payman-v2-feedback-modal-reason-chevron"
|
|
1869
|
+
}
|
|
1870
|
+
)
|
|
1871
|
+
]
|
|
1872
|
+
}
|
|
1873
|
+
),
|
|
1874
|
+
reasonOpen ? /* @__PURE__ */ jsx(
|
|
1875
|
+
"div",
|
|
1876
|
+
{
|
|
1877
|
+
id: "payman-v2-feedback-reason-options",
|
|
1878
|
+
className: "payman-v2-feedback-modal-reason-menu",
|
|
1879
|
+
role: "listbox",
|
|
1880
|
+
"aria-label": "Feedback issue",
|
|
1881
|
+
tabIndex: -1,
|
|
1882
|
+
children: NEGATIVE_FEEDBACK_REASONS.map((item) => {
|
|
1883
|
+
const isSelected = item.value === reason;
|
|
1884
|
+
return /* @__PURE__ */ jsxs(
|
|
1885
|
+
"button",
|
|
1886
|
+
{
|
|
1887
|
+
type: "button",
|
|
1888
|
+
className: isSelected ? "payman-v2-feedback-modal-reason-option payman-v2-feedback-modal-reason-option-selected" : "payman-v2-feedback-modal-reason-option",
|
|
1889
|
+
role: "option",
|
|
1890
|
+
"aria-selected": isSelected,
|
|
1891
|
+
onClick: () => {
|
|
1892
|
+
setReason(item.value);
|
|
1893
|
+
setReasonOpen(false);
|
|
1894
|
+
},
|
|
1895
|
+
children: [
|
|
1896
|
+
/* @__PURE__ */ jsx("span", { children: item.label }),
|
|
1897
|
+
isSelected ? /* @__PURE__ */ jsx(Check, { size: 16, strokeWidth: 2 }) : null
|
|
1898
|
+
]
|
|
1899
|
+
},
|
|
1900
|
+
item.value
|
|
1901
|
+
);
|
|
1902
|
+
})
|
|
1903
|
+
}
|
|
1904
|
+
) : null
|
|
1905
|
+
]
|
|
1818
1906
|
}
|
|
1819
1907
|
),
|
|
1820
1908
|
/* @__PURE__ */ jsx(
|
|
@@ -1988,34 +2076,6 @@ function AssistantMessageV2({
|
|
|
1988
2076
|
void 0,
|
|
1989
2077
|
typingSpeed
|
|
1990
2078
|
);
|
|
1991
|
-
const elapsedMs = (() => {
|
|
1992
|
-
const fromServer = message.totalElapsedMs;
|
|
1993
|
-
if (typeof fromServer === "number" && Number.isFinite(fromServer) && fromServer > 0) {
|
|
1994
|
-
return fromServer;
|
|
1995
|
-
}
|
|
1996
|
-
const steps = message.steps;
|
|
1997
|
-
if (!steps || steps.length === 0) return void 0;
|
|
1998
|
-
let earliest = Number.POSITIVE_INFINITY;
|
|
1999
|
-
let latest = Number.NEGATIVE_INFINITY;
|
|
2000
|
-
for (const s of steps) {
|
|
2001
|
-
if (!s.timestamp) continue;
|
|
2002
|
-
if (s.timestamp < earliest) earliest = s.timestamp;
|
|
2003
|
-
const end = s.timestamp + (s.elapsedMs ?? 0);
|
|
2004
|
-
if (end > latest) latest = end;
|
|
2005
|
-
}
|
|
2006
|
-
if (!Number.isFinite(earliest) || !Number.isFinite(latest)) {
|
|
2007
|
-
const total = steps.reduce((sum, s) => sum + (s.elapsedMs || 0), 0);
|
|
2008
|
-
return total > 0 ? total : void 0;
|
|
2009
|
-
}
|
|
2010
|
-
const diff = latest - earliest;
|
|
2011
|
-
return diff > 0 ? diff : void 0;
|
|
2012
|
-
})();
|
|
2013
|
-
function formatElapsed(ms) {
|
|
2014
|
-
if (ms === void 0) return void 0;
|
|
2015
|
-
if (ms < 1e3) return `${Math.round(ms)}ms`;
|
|
2016
|
-
return `${(ms / 1e3).toFixed(1)}s`;
|
|
2017
|
-
}
|
|
2018
|
-
const totalElapsedLabel = formatElapsed(elapsedMs);
|
|
2019
2079
|
const stickyLabel = (() => {
|
|
2020
2080
|
const steps = message.steps;
|
|
2021
2081
|
if (!steps || steps.length === 0) return void 0;
|
|
@@ -2230,8 +2290,7 @@ function AssistantMessageV2({
|
|
|
2230
2290
|
"aria-label": "Trace response",
|
|
2231
2291
|
children: /* @__PURE__ */ jsx(Binoculars, { style: { width: 16, height: 16 } })
|
|
2232
2292
|
}
|
|
2233
|
-
) })
|
|
2234
|
-
totalElapsedLabel && /* @__PURE__ */ jsx("span", { className: "payman-v2-assistant-msg-elapsed", children: totalElapsedLabel })
|
|
2293
|
+
) })
|
|
2235
2294
|
] })
|
|
2236
2295
|
] }),
|
|
2237
2296
|
/* @__PURE__ */ jsx(
|
|
@@ -3950,9 +4009,13 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
|
|
|
3950
4009
|
if (!executionId) {
|
|
3951
4010
|
throw new Error("Cannot submit feedback before the response completes");
|
|
3952
4011
|
}
|
|
3953
|
-
await
|
|
4012
|
+
await submitFeedback({
|
|
3954
4013
|
baseUrl: config.api.baseUrl,
|
|
4014
|
+
streamEndpoint: config.api.streamEndpoint,
|
|
3955
4015
|
headers: config.api.headers,
|
|
4016
|
+
authToken: config.api.authToken,
|
|
4017
|
+
stage: config.stage,
|
|
4018
|
+
stageQueryParam: config.stageQueryParam,
|
|
3956
4019
|
executionId,
|
|
3957
4020
|
feedback,
|
|
3958
4021
|
details
|
|
@@ -3962,7 +4025,15 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
|
|
|
3962
4025
|
feedback: feedback === "POSITIVE" ? "up" : "down"
|
|
3963
4026
|
});
|
|
3964
4027
|
},
|
|
3965
|
-
[
|
|
4028
|
+
[
|
|
4029
|
+
config.api.baseUrl,
|
|
4030
|
+
config.api.streamEndpoint,
|
|
4031
|
+
config.api.headers,
|
|
4032
|
+
config.api.authToken,
|
|
4033
|
+
config.stage,
|
|
4034
|
+
config.stageQueryParam,
|
|
4035
|
+
onMessageFeedback
|
|
4036
|
+
]
|
|
3966
4037
|
);
|
|
3967
4038
|
const onExecutionTraceClick = useMemo(() => {
|
|
3968
4039
|
if (!config.debug) return rawOnExecutionTraceClick;
|