@paymanai/payman-ask-sdk 1.2.21 → 1.2.23
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.d.mts +31 -1
- package/dist/index.d.ts +31 -1
- package/dist/index.js +178 -43
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +178 -44
- package/dist/index.mjs.map +1 -1
- package/dist/index.native.js +144 -13
- package/dist/index.native.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -246,6 +246,8 @@ type ChatInputProps = {
|
|
|
246
246
|
showResetSession?: boolean;
|
|
247
247
|
/** Handler called when the reset session button is clicked */
|
|
248
248
|
onResetSession?: () => void;
|
|
249
|
+
/** React Native: called when the text input is focused (e.g. to scroll messages above the keyboard). */
|
|
250
|
+
onInputFocus?: () => void;
|
|
249
251
|
};
|
|
250
252
|
type MessageListProps = {
|
|
251
253
|
/** Messages to display */
|
|
@@ -298,6 +300,15 @@ type MessageListProps = {
|
|
|
298
300
|
isLoadingMoreMessages?: boolean;
|
|
299
301
|
/** Whether there are more messages to load */
|
|
300
302
|
hasMoreMessages?: boolean;
|
|
303
|
+
/**
|
|
304
|
+
* React Native: while true, keep scrolling to the end as layout updates (waiting for assistant reply).
|
|
305
|
+
*/
|
|
306
|
+
isWaitingForResponse?: boolean;
|
|
307
|
+
/**
|
|
308
|
+
* React Native: ref to register a no-arg function that scrolls the message list to the end.
|
|
309
|
+
* Used so the parent can scroll when the input is focused and the keyboard opens.
|
|
310
|
+
*/
|
|
311
|
+
scrollToEndHandleRef?: React__default.MutableRefObject<(() => void) | null>;
|
|
301
312
|
};
|
|
302
313
|
type MessageRowProps = {
|
|
303
314
|
/** Message to display */
|
|
@@ -506,4 +517,23 @@ declare function cn(...inputs: ClassValue[]): string;
|
|
|
506
517
|
*/
|
|
507
518
|
declare function formatDate(timestamp: string | Date): string;
|
|
508
519
|
|
|
509
|
-
|
|
520
|
+
interface ChatSessionContext {
|
|
521
|
+
sessionId?: string;
|
|
522
|
+
sessionOwnerId?: string;
|
|
523
|
+
workflowName?: string;
|
|
524
|
+
executionId?: string;
|
|
525
|
+
cfRay?: string;
|
|
526
|
+
route?: string;
|
|
527
|
+
customerId?: string;
|
|
528
|
+
customerEmail?: string;
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* Reports an error to Sentry enriched with chat session context.
|
|
532
|
+
* Tags and context are scoped to this event so they don't leak
|
|
533
|
+
* to unrelated errors.
|
|
534
|
+
*
|
|
535
|
+
* No-op when Sentry is not initialised.
|
|
536
|
+
*/
|
|
537
|
+
declare function captureSentryError(error: Error | string, context: ChatSessionContext): void;
|
|
538
|
+
|
|
539
|
+
export { type APIConfig, type AgentMessageProps, type ChatCallbacks, type ChatConfig, type ChatHeaderProps, type ChatInputProps, type ChatSessionContext, type ChunkDisplay, type MessageDisplay, type MessageListProps, type MessageRole, type MessageRowProps, type OtpInputProps, PaymanChat, PaymanChatContext, type PaymanChatContextValue, type PaymanChatProps, type PaymanChatRef, type SessionParams, type StreamProgress, type StreamingMessageProps, type StreamingStep, type UserActionModalProps, type UserMessageProps, type WorkflowStage, captureSentryError, cn, formatDate, usePaymanChat };
|
package/dist/index.d.ts
CHANGED
|
@@ -246,6 +246,8 @@ type ChatInputProps = {
|
|
|
246
246
|
showResetSession?: boolean;
|
|
247
247
|
/** Handler called when the reset session button is clicked */
|
|
248
248
|
onResetSession?: () => void;
|
|
249
|
+
/** React Native: called when the text input is focused (e.g. to scroll messages above the keyboard). */
|
|
250
|
+
onInputFocus?: () => void;
|
|
249
251
|
};
|
|
250
252
|
type MessageListProps = {
|
|
251
253
|
/** Messages to display */
|
|
@@ -298,6 +300,15 @@ type MessageListProps = {
|
|
|
298
300
|
isLoadingMoreMessages?: boolean;
|
|
299
301
|
/** Whether there are more messages to load */
|
|
300
302
|
hasMoreMessages?: boolean;
|
|
303
|
+
/**
|
|
304
|
+
* React Native: while true, keep scrolling to the end as layout updates (waiting for assistant reply).
|
|
305
|
+
*/
|
|
306
|
+
isWaitingForResponse?: boolean;
|
|
307
|
+
/**
|
|
308
|
+
* React Native: ref to register a no-arg function that scrolls the message list to the end.
|
|
309
|
+
* Used so the parent can scroll when the input is focused and the keyboard opens.
|
|
310
|
+
*/
|
|
311
|
+
scrollToEndHandleRef?: React__default.MutableRefObject<(() => void) | null>;
|
|
301
312
|
};
|
|
302
313
|
type MessageRowProps = {
|
|
303
314
|
/** Message to display */
|
|
@@ -506,4 +517,23 @@ declare function cn(...inputs: ClassValue[]): string;
|
|
|
506
517
|
*/
|
|
507
518
|
declare function formatDate(timestamp: string | Date): string;
|
|
508
519
|
|
|
509
|
-
|
|
520
|
+
interface ChatSessionContext {
|
|
521
|
+
sessionId?: string;
|
|
522
|
+
sessionOwnerId?: string;
|
|
523
|
+
workflowName?: string;
|
|
524
|
+
executionId?: string;
|
|
525
|
+
cfRay?: string;
|
|
526
|
+
route?: string;
|
|
527
|
+
customerId?: string;
|
|
528
|
+
customerEmail?: string;
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* Reports an error to Sentry enriched with chat session context.
|
|
532
|
+
* Tags and context are scoped to this event so they don't leak
|
|
533
|
+
* to unrelated errors.
|
|
534
|
+
*
|
|
535
|
+
* No-op when Sentry is not initialised.
|
|
536
|
+
*/
|
|
537
|
+
declare function captureSentryError(error: Error | string, context: ChatSessionContext): void;
|
|
538
|
+
|
|
539
|
+
export { type APIConfig, type AgentMessageProps, type ChatCallbacks, type ChatConfig, type ChatHeaderProps, type ChatInputProps, type ChatSessionContext, type ChunkDisplay, type MessageDisplay, type MessageListProps, type MessageRole, type MessageRowProps, type OtpInputProps, PaymanChat, PaymanChatContext, type PaymanChatContextValue, type PaymanChatProps, type PaymanChatRef, type SessionParams, type StreamProgress, type StreamingMessageProps, type StreamingStep, type UserActionModalProps, type UserMessageProps, type WorkflowStage, captureSentryError, cn, formatDate, usePaymanChat };
|
package/dist/index.js
CHANGED
|
@@ -79,6 +79,114 @@ function formatElapsedTime(ms) {
|
|
|
79
79
|
if (ms < 1e3) return `${ms}ms`;
|
|
80
80
|
return `${(ms / 1e3).toFixed(1)}s`;
|
|
81
81
|
}
|
|
82
|
+
function captureSentryError(error, context) {
|
|
83
|
+
if (!Sentry__namespace.getClient()) return;
|
|
84
|
+
const tags = {};
|
|
85
|
+
if (context.executionId) tags.executionId = context.executionId;
|
|
86
|
+
if (context.sessionId) tags.sessionId = context.sessionId;
|
|
87
|
+
if (context.route) tags.route = context.route;
|
|
88
|
+
if (context.cfRay) tags.cfRay = context.cfRay;
|
|
89
|
+
if (context.customerId) tags.customerId = context.customerId;
|
|
90
|
+
if (context.customerEmail) tags.customerEmail = context.customerEmail;
|
|
91
|
+
const contexts = {
|
|
92
|
+
chat_session: {
|
|
93
|
+
sessionId: context.sessionId ?? null,
|
|
94
|
+
sessionOwnerId: context.sessionOwnerId ?? null,
|
|
95
|
+
executionId: context.executionId ?? null,
|
|
96
|
+
workflowName: context.workflowName ?? null,
|
|
97
|
+
cfRay: context.cfRay ?? null,
|
|
98
|
+
customerId: context.customerId ?? null,
|
|
99
|
+
customerEmail: context.customerEmail ?? null
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
if (typeof error === "string") {
|
|
103
|
+
Sentry__namespace.captureMessage(error, { level: "error", tags, contexts });
|
|
104
|
+
} else {
|
|
105
|
+
Sentry__namespace.captureException(error, { tags, contexts });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
var interceptors = /* @__PURE__ */ new Set();
|
|
109
|
+
var originalFetch = null;
|
|
110
|
+
function patchFetch() {
|
|
111
|
+
if (originalFetch !== null) return;
|
|
112
|
+
if (typeof globalThis === "undefined" || typeof globalThis.fetch !== "function")
|
|
113
|
+
return;
|
|
114
|
+
originalFetch = globalThis.fetch;
|
|
115
|
+
globalThis.fetch = async function(input, init2) {
|
|
116
|
+
const response = await originalFetch.call(this, input, init2);
|
|
117
|
+
if (interceptors.size > 0) {
|
|
118
|
+
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
119
|
+
try {
|
|
120
|
+
const cfRay = response.headers.get("cf-ray");
|
|
121
|
+
if (cfRay) {
|
|
122
|
+
for (const entry of interceptors) {
|
|
123
|
+
if (url.includes(entry.urlPattern)) {
|
|
124
|
+
entry.listener(cfRay);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
} catch {
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return response;
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function maybeUnpatchFetch() {
|
|
135
|
+
if (interceptors.size > 0 || originalFetch === null) return;
|
|
136
|
+
globalThis.fetch = originalFetch;
|
|
137
|
+
originalFetch = null;
|
|
138
|
+
}
|
|
139
|
+
function subscribeToCfRay(urlPattern, listener) {
|
|
140
|
+
const entry = { urlPattern, listener };
|
|
141
|
+
patchFetch();
|
|
142
|
+
interceptors.add(entry);
|
|
143
|
+
return () => {
|
|
144
|
+
interceptors.delete(entry);
|
|
145
|
+
maybeUnpatchFetch();
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// src/utils/errorMessages.ts
|
|
150
|
+
var WORKFLOW_FAILED = "WORKFLOW_FAILED";
|
|
151
|
+
var STREAM_NOT_STARTED = "STREAM_NOT_STARTED";
|
|
152
|
+
var HTTP_ERROR_PREFIX = /^HTTP\s+(\d+)\s*:\s*([\s\S]+)$/;
|
|
153
|
+
function isFriendlyWorkflowError(errorDetails) {
|
|
154
|
+
if (!errorDetails) return false;
|
|
155
|
+
return errorDetails === WORKFLOW_FAILED || errorDetails === STREAM_NOT_STARTED || errorDetails.includes(WORKFLOW_FAILED);
|
|
156
|
+
}
|
|
157
|
+
function parseErrorPayload(payload) {
|
|
158
|
+
try {
|
|
159
|
+
const parsed = JSON.parse(payload);
|
|
160
|
+
if (typeof parsed === "string") {
|
|
161
|
+
return { message: parsed.trim() || void 0 };
|
|
162
|
+
}
|
|
163
|
+
if (typeof parsed === "object" && parsed !== null) {
|
|
164
|
+
const record = parsed;
|
|
165
|
+
return {
|
|
166
|
+
status: typeof record.status === "number" ? record.status : void 0,
|
|
167
|
+
message: typeof record.message === "string" && record.message.trim() ? record.message.trim() : void 0
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
} catch {
|
|
171
|
+
}
|
|
172
|
+
return {};
|
|
173
|
+
}
|
|
174
|
+
function getConflictErrorMessage(errorDetails) {
|
|
175
|
+
if (!errorDetails) return void 0;
|
|
176
|
+
const trimmedError = errorDetails.trim();
|
|
177
|
+
const httpMatch = trimmedError.match(HTTP_ERROR_PREFIX);
|
|
178
|
+
const httpStatus = httpMatch ? Number(httpMatch[1]) : void 0;
|
|
179
|
+
const rawPayload = (httpMatch ? httpMatch[2] : trimmedError).trim();
|
|
180
|
+
const payload = parseErrorPayload(rawPayload);
|
|
181
|
+
const status = payload.status ?? httpStatus;
|
|
182
|
+
if (status !== 409) {
|
|
183
|
+
return void 0;
|
|
184
|
+
}
|
|
185
|
+
if (payload.message) {
|
|
186
|
+
return payload.message;
|
|
187
|
+
}
|
|
188
|
+
return rawPayload || void 0;
|
|
189
|
+
}
|
|
82
190
|
function initSentryIfNeeded(dsn) {
|
|
83
191
|
if (!dsn) return;
|
|
84
192
|
if (Sentry__namespace.getClient()) return;
|
|
@@ -603,48 +711,6 @@ function createMarkdownComponents(options = {}) {
|
|
|
603
711
|
td: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("td", { className: "p-3 align-middle text-sm whitespace-nowrap", children })
|
|
604
712
|
};
|
|
605
713
|
}
|
|
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
714
|
function ThinkingBlock({ text }) {
|
|
649
715
|
const [isOpen, setIsOpen] = react.useState(false);
|
|
650
716
|
const hasContent = typeof text === "string" && text.trim().length > 0;
|
|
@@ -2037,7 +2103,75 @@ var PaymanChat = react.forwardRef(function PaymanChat2({
|
|
|
2037
2103
|
initSentryIfNeeded(config.sentryDsn);
|
|
2038
2104
|
}
|
|
2039
2105
|
}, [config.sentryDsn]);
|
|
2040
|
-
const
|
|
2106
|
+
const sentryCtxRef = react.useRef({});
|
|
2107
|
+
const callbacksRef = react.useRef(callbacks);
|
|
2108
|
+
callbacksRef.current = callbacks;
|
|
2109
|
+
const initialSessionId = config.initialSessionId;
|
|
2110
|
+
const apiHeaders = config.api.headers;
|
|
2111
|
+
react.useEffect(() => {
|
|
2112
|
+
sentryCtxRef.current.workflowName = config.workflowName;
|
|
2113
|
+
sentryCtxRef.current.sessionOwnerId = config.sessionParams?.id;
|
|
2114
|
+
if (initialSessionId) {
|
|
2115
|
+
sentryCtxRef.current.sessionId = initialSessionId;
|
|
2116
|
+
}
|
|
2117
|
+
if (apiHeaders) {
|
|
2118
|
+
sentryCtxRef.current.customerId = apiHeaders["x-paygent-wf-mcp-customer-id"] ?? sentryCtxRef.current.customerId;
|
|
2119
|
+
sentryCtxRef.current.customerEmail = apiHeaders["x-paygent-wf-mcp-customer-email"] ?? sentryCtxRef.current.customerEmail;
|
|
2120
|
+
}
|
|
2121
|
+
}, [
|
|
2122
|
+
config.workflowName,
|
|
2123
|
+
config.sessionParams?.id,
|
|
2124
|
+
initialSessionId,
|
|
2125
|
+
apiHeaders
|
|
2126
|
+
]);
|
|
2127
|
+
react.useEffect(() => {
|
|
2128
|
+
const endpoint = config.api.streamEndpoint || "/api/workflows/ask/stream";
|
|
2129
|
+
return subscribeToCfRay(endpoint, (cfRay) => {
|
|
2130
|
+
sentryCtxRef.current.cfRay = cfRay;
|
|
2131
|
+
});
|
|
2132
|
+
}, [config.api.streamEndpoint]);
|
|
2133
|
+
const sentryCallbacks = react.useMemo(
|
|
2134
|
+
() => ({
|
|
2135
|
+
onMessageSent: (msg) => callbacksRef.current.onMessageSent?.(msg),
|
|
2136
|
+
onStreamStart: () => callbacksRef.current.onStreamStart?.(),
|
|
2137
|
+
onStreamComplete: (message) => {
|
|
2138
|
+
if (message.executionId)
|
|
2139
|
+
sentryCtxRef.current.executionId = message.executionId;
|
|
2140
|
+
if (message.sessionId)
|
|
2141
|
+
sentryCtxRef.current.sessionId = message.sessionId;
|
|
2142
|
+
const content = message.content ?? "";
|
|
2143
|
+
const looksLikeRawErr = content.length >= 10 && (content.includes("errorType=") || /failed:\s*\{/.test(content));
|
|
2144
|
+
const completedEmpty = !message.isStreaming && !message.isCancelled && content.length === 0 && (message.streamProgress === "completed" || message.streamProgress === "error");
|
|
2145
|
+
const hasConflict = !!getConflictErrorMessage(message.errorDetails);
|
|
2146
|
+
const hasFriendlyErr = isFriendlyWorkflowError(message.errorDetails);
|
|
2147
|
+
const shouldCapture = message.isError || hasConflict || hasFriendlyErr || looksLikeRawErr || completedEmpty;
|
|
2148
|
+
if (shouldCapture) {
|
|
2149
|
+
sentryCtxRef.current.route = typeof window !== "undefined" ? window.location.pathname : void 0;
|
|
2150
|
+
captureSentryError(
|
|
2151
|
+
`Workflow error: ${message.errorDetails || content || "Unknown error"}`,
|
|
2152
|
+
{ ...sentryCtxRef.current }
|
|
2153
|
+
);
|
|
2154
|
+
}
|
|
2155
|
+
callbacksRef.current.onStreamComplete?.(message);
|
|
2156
|
+
},
|
|
2157
|
+
onError: (error) => {
|
|
2158
|
+
sentryCtxRef.current.route = typeof window !== "undefined" ? window.location.pathname : void 0;
|
|
2159
|
+
captureSentryError(error, { ...sentryCtxRef.current });
|
|
2160
|
+
callbacksRef.current.onError?.(error);
|
|
2161
|
+
},
|
|
2162
|
+
onSessionIdChange: (sessionId) => {
|
|
2163
|
+
sentryCtxRef.current.sessionId = sessionId;
|
|
2164
|
+
callbacksRef.current.onSessionIdChange?.(sessionId);
|
|
2165
|
+
},
|
|
2166
|
+
onExecutionTraceClick: (data) => callbacksRef.current.onExecutionTraceClick?.(data),
|
|
2167
|
+
onResetSession: () => callbacksRef.current.onResetSession?.(),
|
|
2168
|
+
onUserActionRequired: (req) => callbacksRef.current.onUserActionRequired?.(req),
|
|
2169
|
+
onUserActionEvent: (evType, msg) => callbacksRef.current.onUserActionEvent?.(evType, msg)
|
|
2170
|
+
}),
|
|
2171
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2172
|
+
[]
|
|
2173
|
+
);
|
|
2174
|
+
const chat = paymanTypescriptAskSdk.useChat(config, sentryCallbacks);
|
|
2041
2175
|
const {
|
|
2042
2176
|
messages,
|
|
2043
2177
|
sendMessage,
|
|
@@ -2382,6 +2516,7 @@ Object.defineProperty(exports, "useVoice", {
|
|
|
2382
2516
|
});
|
|
2383
2517
|
exports.PaymanChat = PaymanChat;
|
|
2384
2518
|
exports.PaymanChatContext = PaymanChatContext;
|
|
2519
|
+
exports.captureSentryError = captureSentryError;
|
|
2385
2520
|
exports.cn = cn;
|
|
2386
2521
|
exports.formatDate = formatDate;
|
|
2387
2522
|
exports.usePaymanChat = usePaymanChat;
|