@paymanai/payman-ask-sdk 1.0.0

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 ADDED
@@ -0,0 +1,798 @@
1
+ import { createContext, useContext, useState, useMemo, useRef, useEffect } from 'react';
2
+ import { useChat } from '@paymanai/payman-typescript-ask-sdk';
3
+ export { generateId, streamWorkflowEvents, useChat } from '@paymanai/payman-typescript-ask-sdk';
4
+ import { clsx } from 'clsx';
5
+ import { twMerge } from 'tailwind-merge';
6
+ import { motion, AnimatePresence } from 'framer-motion';
7
+ import { Bot, Pause, Send, User, Loader2, X, ChevronUp, ChevronDown, XCircle, Check, Binoculars } from 'lucide-react';
8
+ import { jsx, jsxs } from 'react/jsx-runtime';
9
+ import ReactMarkdown from 'react-markdown';
10
+ import remarkGfm from 'remark-gfm';
11
+
12
+ var PaymanChatContext = createContext(void 0);
13
+ function usePaymanChat() {
14
+ const context = useContext(PaymanChatContext);
15
+ if (!context) {
16
+ throw new Error("usePaymanChat must be used within a PaymanChat component");
17
+ }
18
+ return context;
19
+ }
20
+ function cn(...inputs) {
21
+ return twMerge(clsx(inputs));
22
+ }
23
+
24
+ // src/utils/formatDate.ts
25
+ function formatDate(timestamp) {
26
+ const date = typeof timestamp === "string" ? new Date(timestamp) : timestamp;
27
+ const now = /* @__PURE__ */ new Date();
28
+ const diffMs = now.getTime() - date.getTime();
29
+ const diffMins = Math.floor(diffMs / 6e4);
30
+ const diffHours = Math.floor(diffMs / 36e5);
31
+ const diffDays = Math.floor(diffMs / 864e5);
32
+ if (diffMins < 1) {
33
+ return "Just now";
34
+ }
35
+ if (diffMins < 60) {
36
+ return `${diffMins}m ago`;
37
+ }
38
+ if (diffHours < 24) {
39
+ return `${diffHours}h ago`;
40
+ }
41
+ if (diffDays < 7) {
42
+ return `${diffDays}d ago`;
43
+ }
44
+ return date.toLocaleDateString("en-US", {
45
+ month: "short",
46
+ day: "numeric",
47
+ year: date.getFullYear() !== now.getFullYear() ? "numeric" : void 0
48
+ });
49
+ }
50
+ function ChatInput({
51
+ value,
52
+ onChange,
53
+ onSend,
54
+ onPause,
55
+ disabled = false,
56
+ placeholder = "Type your message...",
57
+ isWaitingForResponse = false,
58
+ hasSelectedSession = true,
59
+ isSessionParamsConfigured = true,
60
+ onClick,
61
+ className
62
+ }) {
63
+ const textareaRef = useRef(null);
64
+ useEffect(() => {
65
+ if (textareaRef.current) {
66
+ textareaRef.current.style.height = "auto";
67
+ const scrollHeight = textareaRef.current.scrollHeight;
68
+ const maxHeight = 200;
69
+ textareaRef.current.style.height = `${Math.min(scrollHeight, maxHeight)}px`;
70
+ }
71
+ }, [value]);
72
+ const handleKeyDown = (e) => {
73
+ if (e.key === "Enter" && !e.shiftKey) {
74
+ e.preventDefault();
75
+ onSend();
76
+ }
77
+ };
78
+ const isInputDisabled = disabled || isWaitingForResponse;
79
+ const showPauseButton = isWaitingForResponse && onPause;
80
+ const getPlaceholder = () => {
81
+ if (!hasSelectedSession) {
82
+ return "Select a version to start chatting";
83
+ }
84
+ if (!isSessionParamsConfigured) {
85
+ return "Configure User ID and User Label in Session Params";
86
+ }
87
+ return placeholder;
88
+ };
89
+ return /* @__PURE__ */ jsx("div", { className: cn("flex-shrink-0 p-4 w-full", className), style: { flexShrink: 0 }, children: /* @__PURE__ */ jsx("div", { className: "flex justify-center w-full", children: /* @__PURE__ */ jsx("div", { className: "relative w-full px-0", style: { maxWidth: "672px" }, children: /* @__PURE__ */ jsxs(
90
+ motion.div,
91
+ {
92
+ initial: false,
93
+ className: "relative flex items-end overflow-hidden transition-colors bg-input border border-border shadow-sm",
94
+ style: { borderRadius: "24px" },
95
+ children: [
96
+ /* @__PURE__ */ jsx(
97
+ "textarea",
98
+ {
99
+ ref: textareaRef,
100
+ value,
101
+ onChange: (e) => onChange(e.target.value),
102
+ onKeyDown: handleKeyDown,
103
+ onClick,
104
+ disabled: isInputDisabled,
105
+ placeholder: getPlaceholder(),
106
+ className: "bg-transparent text-foreground focus:outline-none resize-none overflow-y-auto disabled:opacity-50 disabled:cursor-not-allowed w-full text-sm placeholder:text-muted-foreground",
107
+ style: {
108
+ minHeight: "48px",
109
+ maxHeight: "200px",
110
+ padding: "12px 48px 12px 16px"
111
+ },
112
+ rows: 1
113
+ }
114
+ ),
115
+ showPauseButton ? /* @__PURE__ */ jsx(
116
+ "button",
117
+ {
118
+ onClick: onPause,
119
+ className: "flex items-center justify-center flex-shrink-0 transition-all bg-primary text-primary-foreground hover:bg-primary/90",
120
+ style: {
121
+ position: "absolute",
122
+ bottom: "8px",
123
+ right: "8px",
124
+ padding: "8px",
125
+ borderRadius: "9999px",
126
+ width: "32px",
127
+ height: "32px"
128
+ },
129
+ "aria-label": "Pause request",
130
+ children: /* @__PURE__ */ jsx(Pause, { className: "w-4 h-4" })
131
+ }
132
+ ) : /* @__PURE__ */ jsx(
133
+ "button",
134
+ {
135
+ onClick: onSend,
136
+ disabled: isInputDisabled || !value.trim(),
137
+ className: "flex items-center justify-center flex-shrink-0 transition-all bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed",
138
+ style: {
139
+ position: "absolute",
140
+ bottom: "8px",
141
+ right: "8px",
142
+ padding: "8px",
143
+ borderRadius: "9999px",
144
+ width: "32px",
145
+ height: "32px"
146
+ },
147
+ "aria-label": "Send message",
148
+ children: /* @__PURE__ */ jsx(Send, { className: "w-4 h-4" })
149
+ }
150
+ )
151
+ ]
152
+ }
153
+ ) }) }) });
154
+ }
155
+ function AgentMessage({
156
+ message,
157
+ animated = false,
158
+ showAgentName = false,
159
+ agentName = "Assistant",
160
+ showAvatar = false,
161
+ layout = "full-width",
162
+ showTimestamp = false,
163
+ showExecutionSteps = false,
164
+ showStreamingDot = false,
165
+ streamingStepsText,
166
+ completedStepsText,
167
+ onExecutionTraceClick
168
+ }) {
169
+ const isStreaming = message.isStreaming ?? false;
170
+ const hasSteps = message.steps && message.steps.length > 0;
171
+ const hasTraceData = !!(message.tracingData || message.executionId) && !isStreaming;
172
+ const isError = message.isError ?? (message.streamProgress === "error" || !!message.errorDetails);
173
+ const isCancelled = message.isCancelled ?? false;
174
+ const currentExecutingStepId = message.currentExecutingStepId;
175
+ const [isStepsExpanded, setIsStepsExpanded] = useState(isStreaming && hasSteps);
176
+ useEffect(() => {
177
+ if (isStreaming && hasSteps) {
178
+ setIsStepsExpanded(true);
179
+ }
180
+ }, [isStreaming, hasSteps]);
181
+ const totalElapsedMs = hasSteps ? message.steps.reduce((sum, step) => sum + (step.elapsedMs || 0), 0) : 0;
182
+ const currentMessage = message.currentMessage;
183
+ const rawContent = message.streamingContent || message.content || "";
184
+ const content = rawContent.replace(/\\n/g, "\n");
185
+ const getStreamingStepsText = (expanded) => {
186
+ const defaultText = `${expanded ? "Hide" : "View"} progress ({count} ${message.steps.length === 1 ? "step" : "steps"})`;
187
+ const text = streamingStepsText || defaultText;
188
+ const prefix = expanded ? "Hide" : "View";
189
+ return text.replace("{count}", message.steps.length.toString()).replace(/^(View|Hide)/, prefix);
190
+ };
191
+ const getCompletedStepsText = (expanded) => {
192
+ if (completedStepsText) {
193
+ const result = completedStepsText.replace("{count}", message.steps.length.toString()).replace("{time}", (totalElapsedMs / 1e3).toFixed(1));
194
+ return result;
195
+ }
196
+ const prefix = expanded ? "Hide" : "View";
197
+ const stepWord = message.steps.length === 1 ? "step" : "steps";
198
+ return `${prefix} execution steps (${message.steps.length} ${stepWord})`;
199
+ };
200
+ const messageContent = /* @__PURE__ */ jsxs("div", { className: "flex gap-4 justify-start items-start w-full", children: [
201
+ showAvatar && /* @__PURE__ */ jsx("div", { className: "h-8 w-8 shrink-0 mt-0.5", children: isStreaming && showStreamingDot ? (
202
+ // Animated dot indicator while streaming
203
+ /* @__PURE__ */ jsx("div", { className: "h-8 w-8 flex items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
204
+ /* @__PURE__ */ jsx("div", { className: "h-2 w-2 rounded-full bg-primary animate-pulse" }),
205
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 h-2 w-2 rounded-full bg-primary animate-ping opacity-75" })
206
+ ] }) })
207
+ ) : (
208
+ // Avatar after completion or if streaming dot is disabled
209
+ /* @__PURE__ */ jsx("div", { className: "h-8 w-8 rounded-full bg-muted flex items-center justify-center", children: /* @__PURE__ */ jsx(Bot, { className: "h-4 w-4 text-muted-foreground" }) })
210
+ ) }),
211
+ /* @__PURE__ */ jsxs("div", { className: cn(
212
+ "min-w-0 flex flex-col",
213
+ layout === "centered" ? "max-w-[85%]" : showAvatar ? "max-w-[85%]" : "max-w-[80%]"
214
+ ), children: [
215
+ /* @__PURE__ */ jsxs(
216
+ "div",
217
+ {
218
+ className: cn(
219
+ "overflow-hidden w-full",
220
+ layout === "centered" ? cn(
221
+ "bg-white border transition-all duration-200 p-3",
222
+ hasSteps ? "rounded-t-2xl rounded-tl-sm border-b-0" : "rounded-2xl rounded-tl-sm",
223
+ message.isStreaming ? "border-neutral-300 shadow-sm" : "border-neutral-200",
224
+ isError && "border-red-200"
225
+ ) : cn(
226
+ "p-3",
227
+ hasSteps && !isStreaming ? "rounded-t-md" : "rounded-md",
228
+ isError ? "bg-destructive/10 border border-destructive/30" : "bg-muted"
229
+ )
230
+ ),
231
+ children: [
232
+ showAgentName && /* @__PURE__ */ jsx("p", { className: "text-xs font-semibold mb-1.5 opacity-60", children: agentName }),
233
+ /* @__PURE__ */ jsx("div", { className: cn("text-sm leading-relaxed", layout === "centered" ? "p-4" : "", showAgentName && "mt-1"), children: isStreaming && !content ? !showAvatar ? (
234
+ // Without avatars (yaak): show spinner
235
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
236
+ /* @__PURE__ */ jsx(Loader2, { className: "w-4 h-4 text-primary animate-spin flex-shrink-0" }),
237
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: currentMessage || /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center", children: [
238
+ "Thinking",
239
+ /* @__PURE__ */ jsxs("span", { className: "ml-1 inline-flex", children: [
240
+ /* @__PURE__ */ jsx("span", { className: "thinking-dot", children: "." }),
241
+ /* @__PURE__ */ jsx("span", { className: "thinking-dot", children: "." }),
242
+ /* @__PURE__ */ jsx("span", { className: "thinking-dot", children: "." })
243
+ ] })
244
+ ] }) })
245
+ ] })
246
+ ) : (
247
+ // With avatars (paygent-central): no spinner in message (dot avatar handles it)
248
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: currentMessage || /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center", children: [
249
+ "Thinking",
250
+ /* @__PURE__ */ jsxs("span", { className: "ml-1 inline-flex", children: [
251
+ /* @__PURE__ */ jsx("span", { className: "thinking-dot", children: "." }),
252
+ /* @__PURE__ */ jsx("span", { className: "thinking-dot", children: "." }),
253
+ /* @__PURE__ */ jsx("span", { className: "thinking-dot", children: "." })
254
+ ] })
255
+ ] }) })
256
+ ) : isCancelled && !content ? (
257
+ // Show cancelled state only when message is cancelled and has no content
258
+ !showAvatar ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
259
+ /* @__PURE__ */ jsx(X, { className: "w-4 h-4 text-muted-foreground flex-shrink-0" }),
260
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: currentMessage || "The request was stopped." })
261
+ ] }) : /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: currentMessage || "The request was stopped." })
262
+ ) : /* @__PURE__ */ jsx("div", { className: cn(
263
+ "prose prose-sm dark:prose-invert max-w-none",
264
+ isError && "text-destructive"
265
+ ), children: /* @__PURE__ */ jsx(
266
+ ReactMarkdown,
267
+ {
268
+ remarkPlugins: [remarkGfm],
269
+ components: {
270
+ p: ({ children }) => /* @__PURE__ */ jsx("p", { className: cn("mb-3 last:mb-0 text-sm leading-relaxed", isError ? "text-destructive" : "text-foreground"), children }),
271
+ code: ({ className: codeClassName, children }) => {
272
+ const isInline = !codeClassName;
273
+ return isInline ? /* @__PURE__ */ jsx("code", { className: cn("px-1.5 py-0.5 rounded text-xs font-mono break-all", isError ? "bg-destructive/10 text-destructive" : "bg-muted"), children }) : /* @__PURE__ */ jsx("code", { className: cn("block p-3 rounded text-xs font-mono overflow-x-auto my-2 whitespace-pre", isError ? "bg-destructive/10 text-destructive" : "bg-muted"), children });
274
+ },
275
+ pre: ({ children }) => /* @__PURE__ */ jsx("pre", { className: cn("my-2 overflow-x-auto max-w-full", isError && "bg-destructive/10"), children }),
276
+ ul: ({ children }) => /* @__PURE__ */ jsx("ul", { className: cn("list-disc ml-4 mb-3 space-y-1 text-sm", isError && "text-destructive"), children }),
277
+ ol: ({ children }) => /* @__PURE__ */ jsx("ol", { className: cn("list-decimal ml-4 mb-3 space-y-1 text-sm", isError && "text-destructive"), children }),
278
+ li: ({ children }) => /* @__PURE__ */ jsx("li", { className: cn("text-sm leading-relaxed", isError ? "text-destructive" : "text-foreground"), children }),
279
+ h1: ({ children }) => /* @__PURE__ */ jsx("h1", { className: cn("text-lg font-semibold mb-2 mt-4 first:mt-0", isError ? "text-destructive" : "text-foreground"), children }),
280
+ h2: ({ children }) => /* @__PURE__ */ jsx("h2", { className: cn("text-base font-semibold mb-2 mt-3 first:mt-0", isError ? "text-destructive" : "text-foreground"), children }),
281
+ h3: ({ children }) => /* @__PURE__ */ jsx("h3", { className: cn("text-sm font-semibold mb-1 mt-2 first:mt-0", isError ? "text-destructive" : "text-foreground"), children }),
282
+ strong: ({ children }) => /* @__PURE__ */ jsx("strong", { className: cn("font-semibold", isError ? "text-destructive" : "text-foreground"), children }),
283
+ em: ({ children }) => /* @__PURE__ */ jsx("em", { className: cn("italic", isError ? "text-destructive" : "text-foreground"), children }),
284
+ blockquote: ({ children }) => /* @__PURE__ */ jsx("blockquote", { className: "border-l-4 border-border pl-4 my-2 italic text-muted-foreground", children }),
285
+ hr: () => /* @__PURE__ */ jsx("hr", { className: "my-4 border-border" }),
286
+ a: ({ href, children }) => /* @__PURE__ */ jsx(
287
+ "a",
288
+ {
289
+ href,
290
+ target: "_blank",
291
+ rel: "noopener noreferrer",
292
+ className: cn("underline underline-offset-2", isError ? "text-destructive hover:text-destructive/80" : "text-primary hover:text-primary/80"),
293
+ children
294
+ }
295
+ ),
296
+ table: ({ children }) => /* @__PURE__ */ jsx("div", { className: "relative w-full overflow-x-auto my-4 -mx-1", children: /* @__PURE__ */ jsx("table", { className: "min-w-full caption-bottom text-sm border border-border rounded-md", children }) }),
297
+ thead: ({ children }) => /* @__PURE__ */ jsx("thead", { className: "[&_tr]:border-b bg-muted/50", children }),
298
+ tbody: ({ children }) => /* @__PURE__ */ jsx("tbody", { className: "[&_tr:last-child]:border-0", children }),
299
+ tr: ({ children }) => /* @__PURE__ */ jsx("tr", { className: "hover:bg-muted/50 border-b transition-colors", children }),
300
+ th: ({ children }) => /* @__PURE__ */ jsx("th", { className: "text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap", children }),
301
+ td: ({ children }) => /* @__PURE__ */ jsx("td", { className: "p-2 align-middle text-foreground", children })
302
+ },
303
+ children: content || (isStreaming ? "Thinking..." : isCancelled ? "The request was stopped." : isError ? "Oops, something went wrong. Please try again." : "")
304
+ }
305
+ ) }) })
306
+ ]
307
+ }
308
+ ),
309
+ showExecutionSteps && hasSteps && !isStreaming && !isError && /* @__PURE__ */ jsxs("div", { className: cn(
310
+ "overflow-hidden",
311
+ layout === "centered" ? "bg-white border border-t-0 border-neutral-200 rounded-b-2xl" : "bg-muted border-t border-border/30 rounded-b-md"
312
+ ), children: [
313
+ /* @__PURE__ */ jsxs(
314
+ "button",
315
+ {
316
+ onClick: () => setIsStepsExpanded(!isStepsExpanded),
317
+ className: cn(
318
+ "w-full px-4 py-2 flex items-center justify-between text-xs transition-colors",
319
+ layout === "centered" ? "text-neutral-500 hover:bg-neutral-50" : "text-muted-foreground hover:bg-muted/70"
320
+ ),
321
+ children: [
322
+ /* @__PURE__ */ jsx("span", { children: getCompletedStepsText(isStepsExpanded) }),
323
+ isStepsExpanded ? /* @__PURE__ */ jsx(ChevronUp, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx(ChevronDown, { className: "h-3 w-3" })
324
+ ]
325
+ }
326
+ ),
327
+ isStepsExpanded && /* @__PURE__ */ jsx(AnimatePresence, { children: /* @__PURE__ */ jsx(
328
+ motion.div,
329
+ {
330
+ initial: { height: 0, opacity: 0 },
331
+ animate: { height: "auto", opacity: 1 },
332
+ exit: { height: 0, opacity: 0 },
333
+ transition: { duration: 0.2 },
334
+ className: "px-4 pb-3 pt-2 space-y-2 bg-background/30",
335
+ children: message.steps.map((step) => {
336
+ const isCurrentlyExecuting = step.id === currentExecutingStepId && step.status === "in_progress" && isStreaming && !isCancelled;
337
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 text-xs", children: [
338
+ isCurrentlyExecuting && /* @__PURE__ */ jsx(Loader2, { className: "h-3 w-3 text-primary animate-spin shrink-0 mt-0.5" }),
339
+ step.status === "pending" && isCancelled && /* @__PURE__ */ jsx(XCircle, { className: "h-3 w-3 text-muted-foreground shrink-0 mt-0.5" }),
340
+ step.status === "pending" && !isCancelled && /* @__PURE__ */ jsx(Loader2, { className: "h-3 w-3 text-primary animate-spin shrink-0 mt-0.5" }),
341
+ step.status === "in_progress" && !isCurrentlyExecuting && /* @__PURE__ */ jsx(Loader2, { className: "h-3 w-3 text-primary animate-spin shrink-0 mt-0.5" }),
342
+ step.status === "completed" && /* @__PURE__ */ jsx(Check, { className: "h-3 w-3 text-primary shrink-0 mt-0.5" }),
343
+ step.status === "error" && /* @__PURE__ */ jsx(X, { className: "h-3 w-3 text-destructive shrink-0 mt-0.5" }),
344
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
345
+ /* @__PURE__ */ jsx(
346
+ "span",
347
+ {
348
+ className: cn(
349
+ "text-muted-foreground break-words",
350
+ step.status === "error" && "text-destructive"
351
+ ),
352
+ children: step.message
353
+ }
354
+ ),
355
+ step.elapsedMs && /* @__PURE__ */ jsxs("span", { className: "ml-1.5 text-[10px] opacity-50", children: [
356
+ "(",
357
+ (step.elapsedMs / 1e3).toFixed(1),
358
+ "s)"
359
+ ] })
360
+ ] })
361
+ ] }, step.id);
362
+ })
363
+ }
364
+ ) })
365
+ ] }),
366
+ hasSteps && isStreaming && /* @__PURE__ */ jsxs("div", { className: cn(
367
+ "overflow-hidden",
368
+ layout === "centered" ? "bg-white border border-t-0 border-neutral-300 rounded-b-2xl" : "bg-muted border-t border-border/30 rounded-b-md"
369
+ ), children: [
370
+ /* @__PURE__ */ jsxs(
371
+ "button",
372
+ {
373
+ onClick: () => setIsStepsExpanded(!isStepsExpanded),
374
+ className: cn(
375
+ "w-full px-4 py-2 flex items-center justify-between text-xs transition-colors",
376
+ layout === "centered" ? "text-neutral-500 hover:bg-neutral-50" : "text-muted-foreground hover:bg-muted/70"
377
+ ),
378
+ children: [
379
+ /* @__PURE__ */ jsx("span", { children: getStreamingStepsText(isStepsExpanded) }),
380
+ isStepsExpanded ? /* @__PURE__ */ jsx(ChevronUp, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx(ChevronDown, { className: "h-3 w-3" })
381
+ ]
382
+ }
383
+ ),
384
+ isStepsExpanded && /* @__PURE__ */ jsx(AnimatePresence, { children: /* @__PURE__ */ jsx(
385
+ motion.div,
386
+ {
387
+ initial: { height: 0, opacity: 0 },
388
+ animate: { height: "auto", opacity: 1 },
389
+ exit: { height: 0, opacity: 0 },
390
+ transition: { duration: 0.2 },
391
+ className: "px-4 pb-3 pt-2 space-y-2 bg-background/30",
392
+ children: message.steps.map((step) => {
393
+ const isCurrentlyExecuting = step.id === currentExecutingStepId && step.status === "in_progress" && isStreaming && !isCancelled;
394
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 text-xs", children: [
395
+ isCurrentlyExecuting && /* @__PURE__ */ jsx(Loader2, { className: "h-3 w-3 text-primary animate-spin shrink-0 mt-0.5" }),
396
+ step.status === "pending" && isCancelled && /* @__PURE__ */ jsx(XCircle, { className: "h-3 w-3 text-muted-foreground shrink-0 mt-0.5" }),
397
+ step.status === "pending" && !isCancelled && /* @__PURE__ */ jsx(Loader2, { className: "h-3 w-3 text-primary animate-spin shrink-0 mt-0.5" }),
398
+ step.status === "in_progress" && !isCurrentlyExecuting && /* @__PURE__ */ jsx(Loader2, { className: "h-3 w-3 text-primary animate-spin shrink-0 mt-0.5" }),
399
+ step.status === "completed" && /* @__PURE__ */ jsx(Check, { className: "h-3 w-3 text-primary shrink-0 mt-0.5" }),
400
+ step.status === "error" && /* @__PURE__ */ jsx(X, { className: "h-3 w-3 text-destructive shrink-0 mt-0.5" }),
401
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
402
+ /* @__PURE__ */ jsx(
403
+ "span",
404
+ {
405
+ className: cn(
406
+ "text-muted-foreground break-words",
407
+ step.status === "error" && "text-destructive"
408
+ ),
409
+ children: step.message
410
+ }
411
+ ),
412
+ step.elapsedMs && /* @__PURE__ */ jsxs("span", { className: "ml-1.5 text-[10px] opacity-50", children: [
413
+ "(",
414
+ (step.elapsedMs / 1e3).toFixed(1),
415
+ "s)"
416
+ ] })
417
+ ] })
418
+ ] }, step.id);
419
+ })
420
+ }
421
+ ) })
422
+ ] })
423
+ ] }),
424
+ hasTraceData && onExecutionTraceClick && /* @__PURE__ */ jsx(
425
+ "button",
426
+ {
427
+ onClick: () => onExecutionTraceClick({
428
+ message,
429
+ tracingData: message.tracingData,
430
+ executionId: message.executionId
431
+ }),
432
+ className: "mt-0.5 p-2 bg-white/5 border border-white/20 rounded-lg shadow-sm hover:bg-white/10 hover:border-highlight transition-colors duration-200 flex-shrink-0",
433
+ title: "View execution trace",
434
+ "aria-label": "View execution trace",
435
+ children: /* @__PURE__ */ jsx(Binoculars, { className: "w-4 h-4 text-foreground" })
436
+ }
437
+ )
438
+ ] });
439
+ if (animated) {
440
+ return /* @__PURE__ */ jsx(
441
+ motion.div,
442
+ {
443
+ initial: { opacity: 0, y: 10 },
444
+ animate: { opacity: 1, y: 0 },
445
+ transition: { duration: 0.2 },
446
+ children: messageContent
447
+ }
448
+ );
449
+ }
450
+ return messageContent;
451
+ }
452
+ function UserMessage({ message, animated = false, showAvatar = false }) {
453
+ const content = /* @__PURE__ */ jsxs("div", { className: "flex gap-4 justify-end w-full", children: [
454
+ /* @__PURE__ */ jsxs("div", { className: "max-w-[85%] min-w-0 flex flex-col items-end", children: [
455
+ /* @__PURE__ */ jsx("div", { className: "rounded-lg p-3 bg-primary text-primary-foreground", children: /* @__PURE__ */ jsx("p", { className: "text-sm whitespace-pre-wrap break-words", children: message.content }) }),
456
+ /* @__PURE__ */ jsx("p", { className: "text-[10px] mt-1 text-muted-foreground", children: formatDate(message.timestamp) })
457
+ ] }),
458
+ showAvatar && /* @__PURE__ */ jsx("div", { className: "h-8 w-8 shrink-0 mt-0.5", children: /* @__PURE__ */ jsx("div", { className: "h-8 w-8 rounded-full bg-primary/10 flex items-center justify-center", children: /* @__PURE__ */ jsx(User, { className: "h-4 w-4 text-primary" }) }) })
459
+ ] });
460
+ if (animated) {
461
+ return /* @__PURE__ */ jsx(
462
+ motion.div,
463
+ {
464
+ initial: { opacity: 0, y: 10 },
465
+ animate: { opacity: 1, y: 0 },
466
+ transition: { duration: 0.3, ease: "easeOut" },
467
+ children: content
468
+ }
469
+ );
470
+ }
471
+ return content;
472
+ }
473
+ function MessageRow({
474
+ message,
475
+ stage = "DEV",
476
+ animated = false,
477
+ showAgentName = false,
478
+ agentName = "Paygent",
479
+ showAvatars = false,
480
+ showUserAvatar,
481
+ showAssistantAvatar,
482
+ layout = "full-width",
483
+ showTimestamps = false,
484
+ showExecutionSteps = false,
485
+ showStreamingDot = false,
486
+ streamingStepsText,
487
+ completedStepsText,
488
+ onExecutionTraceClick
489
+ }) {
490
+ const actualShowUserAvatar = showUserAvatar !== void 0 ? showUserAvatar : showAvatars;
491
+ const actualShowAssistantAvatar = showAssistantAvatar !== void 0 ? showAssistantAvatar : showAvatars;
492
+ if (message.role === "user") {
493
+ return /* @__PURE__ */ jsx(UserMessage, { message, animated, showAvatar: actualShowUserAvatar });
494
+ }
495
+ return /* @__PURE__ */ jsx(
496
+ AgentMessage,
497
+ {
498
+ message,
499
+ stage,
500
+ animated,
501
+ showAgentName,
502
+ agentName,
503
+ showAvatar: actualShowAssistantAvatar,
504
+ layout,
505
+ showTimestamp: showTimestamps,
506
+ showExecutionSteps,
507
+ showStreamingDot,
508
+ streamingStepsText,
509
+ completedStepsText,
510
+ onExecutionTraceClick
511
+ }
512
+ );
513
+ }
514
+ function MessageRowSkeleton({
515
+ isRightAligned = false
516
+ }) {
517
+ return /* @__PURE__ */ jsx(
518
+ "div",
519
+ {
520
+ className: `flex ${isRightAligned ? "justify-end" : "justify-start"} animate-pulse`,
521
+ children: /* @__PURE__ */ jsxs(
522
+ "div",
523
+ {
524
+ className: `flex flex-col ${isRightAligned ? "items-end" : "items-start"} w-full max-w-[80%]`,
525
+ children: [
526
+ /* @__PURE__ */ jsx(
527
+ "div",
528
+ {
529
+ className: `rounded-lg p-3 ${isRightAligned ? "bg-primary/20" : "bg-muted"} w-full`,
530
+ children: /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
531
+ /* @__PURE__ */ jsx("div", { className: "h-3 bg-muted-foreground/20 rounded w-3/4" }),
532
+ /* @__PURE__ */ jsx("div", { className: "h-3 bg-muted-foreground/20 rounded w-full" }),
533
+ /* @__PURE__ */ jsx("div", { className: "h-3 bg-muted-foreground/20 rounded w-5/6" })
534
+ ] })
535
+ }
536
+ ),
537
+ /* @__PURE__ */ jsx("div", { className: "h-2 bg-muted-foreground/20 rounded w-16 mt-1" })
538
+ ]
539
+ }
540
+ )
541
+ }
542
+ );
543
+ }
544
+ function MessageList({
545
+ messages,
546
+ isLoading = false,
547
+ emptyStateText = "What can I help with?",
548
+ showEmptyStateIcon = true,
549
+ layout = "full-width",
550
+ showTimestamps = false,
551
+ stage = "DEV",
552
+ animated = false,
553
+ showAgentName = false,
554
+ agentName = "Paygent",
555
+ showAvatars = false,
556
+ showUserAvatar,
557
+ showAssistantAvatar,
558
+ showExecutionSteps = false,
559
+ showStreamingDot = false,
560
+ streamingStepsText,
561
+ completedStepsText,
562
+ onExecutionTraceClick,
563
+ className
564
+ }) {
565
+ const messagesEndRef = useRef(null);
566
+ useEffect(() => {
567
+ messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
568
+ }, [messages]);
569
+ if (isLoading) {
570
+ return /* @__PURE__ */ jsx("div", { className: cn("flex-1 overflow-y-auto min-h-0", className), children: /* @__PURE__ */ jsx("div", { className: "p-4 space-y-4", children: Array.from({ length: 6 }).map((_, index) => /* @__PURE__ */ jsx(
571
+ MessageRowSkeleton,
572
+ {
573
+ isRightAligned: index % 3 === 0
574
+ },
575
+ `skeleton-${index}`
576
+ )) }) });
577
+ }
578
+ if (messages.length === 0) {
579
+ return /* @__PURE__ */ jsx(
580
+ "div",
581
+ {
582
+ className: cn(
583
+ "flex-1 overflow-y-auto min-h-0 flex flex-col items-center justify-center h-full text-center p-4",
584
+ className
585
+ ),
586
+ children: /* @__PURE__ */ jsxs(
587
+ motion.div,
588
+ {
589
+ initial: { opacity: 0, y: 20 },
590
+ animate: { opacity: 1, y: 0 },
591
+ transition: {
592
+ duration: 0.5,
593
+ ease: "easeOut"
594
+ },
595
+ className: "flex flex-col items-center gap-4",
596
+ children: [
597
+ showEmptyStateIcon && /* @__PURE__ */ jsx("div", { className: "flex h-12 w-12 items-center justify-center", children: /* @__PURE__ */ jsx(Bot, { className: "h-6 w-6 text-muted-foreground" }) }),
598
+ emptyStateText.split("\n").map((line, index) => /* @__PURE__ */ jsx(
599
+ "h2",
600
+ {
601
+ className: cn(
602
+ index === 0 ? layout === "centered" ? "text-2xl font-semibold text-primary" : "text-2xl font-semibold text-foreground" : "text-sm text-muted-foreground"
603
+ ),
604
+ children: line
605
+ },
606
+ index
607
+ ))
608
+ ]
609
+ }
610
+ )
611
+ }
612
+ );
613
+ }
614
+ return /* @__PURE__ */ jsx("div", { className: cn("flex-1 overflow-y-auto min-h-0", className), children: /* @__PURE__ */ jsxs("div", { className: cn(
615
+ "space-y-4",
616
+ layout === "centered" ? "max-w-2xl mx-auto px-4 py-6" : "p-4"
617
+ ), children: [
618
+ messages.map((message) => /* @__PURE__ */ jsx(
619
+ MessageRow,
620
+ {
621
+ message,
622
+ stage,
623
+ animated,
624
+ showAgentName,
625
+ agentName,
626
+ showAvatars,
627
+ showUserAvatar,
628
+ showAssistantAvatar,
629
+ layout,
630
+ showTimestamps,
631
+ showExecutionSteps,
632
+ showStreamingDot,
633
+ streamingStepsText,
634
+ completedStepsText,
635
+ onExecutionTraceClick
636
+ },
637
+ message.id
638
+ )),
639
+ /* @__PURE__ */ jsx("div", { ref: messagesEndRef })
640
+ ] }) });
641
+ }
642
+ function PaymanChat({
643
+ config,
644
+ callbacks = {},
645
+ className,
646
+ style,
647
+ children
648
+ }) {
649
+ const [inputValue, setInputValue] = useState("");
650
+ const {
651
+ messages,
652
+ sendMessage,
653
+ isWaitingForResponse,
654
+ resetSession,
655
+ clearMessages,
656
+ cancelStream,
657
+ getSessionId,
658
+ getMessages
659
+ } = useChat(config, callbacks);
660
+ const contextValue = useMemo(
661
+ () => ({
662
+ resetSession,
663
+ clearMessages,
664
+ cancelStream,
665
+ getSessionId,
666
+ getMessages,
667
+ isWaitingForResponse
668
+ }),
669
+ [
670
+ resetSession,
671
+ clearMessages,
672
+ cancelStream,
673
+ getSessionId,
674
+ getMessages,
675
+ isWaitingForResponse
676
+ ]
677
+ );
678
+ const { onExecutionTraceClick } = callbacks;
679
+ const {
680
+ placeholder = "Type your message...",
681
+ emptyStateText = "What can I help with?",
682
+ sessionParams,
683
+ disableInput = false,
684
+ hasAskPermission = true,
685
+ streamingStepsText,
686
+ completedStepsText,
687
+ showAvatars = false,
688
+ showUserAvatar,
689
+ showAssistantAvatar,
690
+ showAgentName = true,
691
+ agentName = "Assistant",
692
+ showExecutionSteps = true,
693
+ showStreamingDot = true,
694
+ layout = "full-width",
695
+ showTimestamps = false,
696
+ animated = true,
697
+ isChatDisabled = false,
698
+ disabledComponent,
699
+ showEmptyStateIcon = true
700
+ } = config;
701
+ const isSessionParamsConfigured = useMemo(() => {
702
+ if (!sessionParams) return false;
703
+ return !!(sessionParams.id?.trim() && sessionParams.name?.trim());
704
+ }, [sessionParams?.id, sessionParams?.name]);
705
+ const handleSend = () => {
706
+ if (inputValue.trim() && !disableInput && isSessionParamsConfigured) {
707
+ sendMessage(inputValue.trim());
708
+ setInputValue("");
709
+ }
710
+ };
711
+ const isInputDisabled = isWaitingForResponse || !isSessionParamsConfigured || disableInput;
712
+ if (isChatDisabled) {
713
+ if (disabledComponent) {
714
+ return /* @__PURE__ */ jsx(PaymanChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs(
715
+ "div",
716
+ {
717
+ className: cn(
718
+ "bg-card border border-border rounded-lg overflow-hidden flex flex-col flex-[4]",
719
+ className
720
+ ),
721
+ style,
722
+ children: [
723
+ children,
724
+ disabledComponent
725
+ ]
726
+ }
727
+ ) });
728
+ }
729
+ return /* @__PURE__ */ jsx(PaymanChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs(
730
+ "div",
731
+ {
732
+ className: cn(
733
+ "bg-card border border-border rounded-lg overflow-hidden flex flex-col flex-[4]",
734
+ className
735
+ ),
736
+ style,
737
+ children: [
738
+ children,
739
+ /* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-center p-4", children: /* @__PURE__ */ jsx("div", { className: "text-center", children: /* @__PURE__ */ jsx("div", { className: "text-muted-foreground text-sm", children: "Chat is currently disabled" }) }) })
740
+ ]
741
+ }
742
+ ) });
743
+ }
744
+ return /* @__PURE__ */ jsx(PaymanChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs(
745
+ "div",
746
+ {
747
+ className: cn(
748
+ "bg-card border border-border rounded-lg overflow-hidden flex flex-col flex-[4]",
749
+ className
750
+ ),
751
+ style,
752
+ children: [
753
+ children,
754
+ /* @__PURE__ */ jsx(
755
+ MessageList,
756
+ {
757
+ messages,
758
+ isLoading: false,
759
+ emptyStateText,
760
+ showEmptyStateIcon,
761
+ layout,
762
+ showTimestamps,
763
+ stage: config.stage || "DEV",
764
+ animated,
765
+ showAgentName,
766
+ agentName,
767
+ showAvatars,
768
+ showUserAvatar,
769
+ showAssistantAvatar,
770
+ showExecutionSteps,
771
+ showStreamingDot,
772
+ streamingStepsText,
773
+ completedStepsText,
774
+ onExecutionTraceClick
775
+ }
776
+ ),
777
+ hasAskPermission && /* @__PURE__ */ jsx(
778
+ ChatInput,
779
+ {
780
+ value: inputValue,
781
+ onChange: setInputValue,
782
+ onSend: handleSend,
783
+ onPause: cancelStream,
784
+ disabled: isInputDisabled,
785
+ placeholder,
786
+ isWaitingForResponse,
787
+ hasSelectedSession: true,
788
+ isSessionParamsConfigured
789
+ }
790
+ )
791
+ ]
792
+ }
793
+ ) });
794
+ }
795
+
796
+ export { PaymanChat, PaymanChatContext, cn, formatDate, usePaymanChat };
797
+ //# sourceMappingURL=index.mjs.map
798
+ //# sourceMappingURL=index.mjs.map