@usecrow/ui 0.1.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/README.md +202 -0
- package/dist/index.cjs +638 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +166 -0
- package/dist/index.d.ts +166 -0
- package/dist/index.js +624 -0
- package/dist/index.js.map +1 -0
- package/dist/styles.css +3 -0
- package/package.json +70 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,624 @@
|
|
|
1
|
+
import { createContext, useRef, useEffect, useMemo, useContext, useState, useCallback } from 'react';
|
|
2
|
+
import { CrowClient } from '@usecrow/client';
|
|
3
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
|
+
import { clsx } from 'clsx';
|
|
5
|
+
|
|
6
|
+
var CrowContext = createContext(null);
|
|
7
|
+
function CrowProvider({
|
|
8
|
+
children,
|
|
9
|
+
productId,
|
|
10
|
+
apiUrl,
|
|
11
|
+
model
|
|
12
|
+
}) {
|
|
13
|
+
const clientRef = useRef(null);
|
|
14
|
+
if (!clientRef.current) {
|
|
15
|
+
clientRef.current = new CrowClient({ productId, apiUrl, model });
|
|
16
|
+
}
|
|
17
|
+
const client = clientRef.current;
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
return () => {
|
|
20
|
+
client.destroy();
|
|
21
|
+
};
|
|
22
|
+
}, [client]);
|
|
23
|
+
const value = useMemo(() => ({ client }), [client]);
|
|
24
|
+
return /* @__PURE__ */ jsx(CrowContext.Provider, { value, children });
|
|
25
|
+
}
|
|
26
|
+
function useCrowClient() {
|
|
27
|
+
const context = useContext(CrowContext);
|
|
28
|
+
if (!context) {
|
|
29
|
+
throw new Error("useCrowClient must be used within a CrowProvider");
|
|
30
|
+
}
|
|
31
|
+
return context.client;
|
|
32
|
+
}
|
|
33
|
+
function useCrowClientOptional() {
|
|
34
|
+
const context = useContext(CrowContext);
|
|
35
|
+
return context?.client ?? null;
|
|
36
|
+
}
|
|
37
|
+
function useChat({ client, onStreamEvent }) {
|
|
38
|
+
const [messages, setMessages] = useState(client.messages);
|
|
39
|
+
const [isLoading, setIsLoading] = useState(client.isLoading);
|
|
40
|
+
const onStreamEventRef = useRef(onStreamEvent);
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
onStreamEventRef.current = onStreamEvent;
|
|
43
|
+
});
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
const unsubMessages = client.onMessages(setMessages);
|
|
46
|
+
const unsubLoading = client.onLoading(setIsLoading);
|
|
47
|
+
setMessages(client.messages);
|
|
48
|
+
setIsLoading(client.isLoading);
|
|
49
|
+
return () => {
|
|
50
|
+
unsubMessages();
|
|
51
|
+
unsubLoading();
|
|
52
|
+
};
|
|
53
|
+
}, [client]);
|
|
54
|
+
const sendMessage = useCallback(
|
|
55
|
+
async (content) => {
|
|
56
|
+
for await (const event of client.sendMessage(content)) {
|
|
57
|
+
onStreamEventRef.current?.(event);
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
[client]
|
|
61
|
+
);
|
|
62
|
+
const stop = useCallback(() => {
|
|
63
|
+
client.stop();
|
|
64
|
+
}, [client]);
|
|
65
|
+
const clearMessages = useCallback(() => {
|
|
66
|
+
client.clearMessages();
|
|
67
|
+
}, [client]);
|
|
68
|
+
return {
|
|
69
|
+
messages,
|
|
70
|
+
isLoading,
|
|
71
|
+
sendMessage,
|
|
72
|
+
stop,
|
|
73
|
+
clearMessages
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function ChatBubble({ isOpen, onClick, className }) {
|
|
77
|
+
return /* @__PURE__ */ jsx(
|
|
78
|
+
"button",
|
|
79
|
+
{
|
|
80
|
+
onClick,
|
|
81
|
+
className: clsx(
|
|
82
|
+
"crow-fixed crow-z-[999999] crow-rounded-full",
|
|
83
|
+
"crow-w-14 crow-h-14 crow-flex crow-items-center crow-justify-center",
|
|
84
|
+
"crow-bg-crow-primary hover:crow-bg-crow-primary-dark",
|
|
85
|
+
"crow-shadow-lg hover:crow-shadow-xl crow-transition-all crow-duration-300",
|
|
86
|
+
"hover:crow-scale-110",
|
|
87
|
+
className
|
|
88
|
+
),
|
|
89
|
+
style: {
|
|
90
|
+
right: "20px",
|
|
91
|
+
bottom: "20px"
|
|
92
|
+
},
|
|
93
|
+
"aria-label": isOpen ? "Close chat" : "Open chat",
|
|
94
|
+
children: isOpen ? /* @__PURE__ */ jsx(
|
|
95
|
+
"svg",
|
|
96
|
+
{
|
|
97
|
+
className: "crow-w-6 crow-h-6 crow-text-white",
|
|
98
|
+
fill: "none",
|
|
99
|
+
stroke: "currentColor",
|
|
100
|
+
viewBox: "0 0 24 24",
|
|
101
|
+
children: /* @__PURE__ */ jsx(
|
|
102
|
+
"path",
|
|
103
|
+
{
|
|
104
|
+
strokeLinecap: "round",
|
|
105
|
+
strokeLinejoin: "round",
|
|
106
|
+
strokeWidth: 2,
|
|
107
|
+
d: "M19 9l-7 7-7-7"
|
|
108
|
+
}
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
) : /* @__PURE__ */ jsx(
|
|
112
|
+
"svg",
|
|
113
|
+
{
|
|
114
|
+
className: "crow-w-6 crow-h-6 crow-text-white",
|
|
115
|
+
fill: "none",
|
|
116
|
+
stroke: "currentColor",
|
|
117
|
+
viewBox: "0 0 24 24",
|
|
118
|
+
children: /* @__PURE__ */ jsx(
|
|
119
|
+
"path",
|
|
120
|
+
{
|
|
121
|
+
strokeLinecap: "round",
|
|
122
|
+
strokeLinejoin: "round",
|
|
123
|
+
strokeWidth: 2,
|
|
124
|
+
d: "M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"
|
|
125
|
+
}
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
function WidgetHeader({
|
|
133
|
+
title = "Chat",
|
|
134
|
+
onNewChat,
|
|
135
|
+
onClose,
|
|
136
|
+
showNewChat = true,
|
|
137
|
+
showClose = false,
|
|
138
|
+
className
|
|
139
|
+
}) {
|
|
140
|
+
return /* @__PURE__ */ jsxs(
|
|
141
|
+
"div",
|
|
142
|
+
{
|
|
143
|
+
className: clsx(
|
|
144
|
+
"crow-flex crow-items-center crow-justify-between crow-px-4 crow-py-3",
|
|
145
|
+
"crow-border-b crow-border-gray-200 crow-bg-white",
|
|
146
|
+
className
|
|
147
|
+
),
|
|
148
|
+
children: [
|
|
149
|
+
/* @__PURE__ */ jsx("h2", { className: "crow-font-semibold crow-text-gray-900", children: title }),
|
|
150
|
+
/* @__PURE__ */ jsxs("div", { className: "crow-flex crow-items-center crow-gap-2", children: [
|
|
151
|
+
showNewChat && onNewChat && /* @__PURE__ */ jsx(
|
|
152
|
+
"button",
|
|
153
|
+
{
|
|
154
|
+
onClick: onNewChat,
|
|
155
|
+
className: "crow-p-1.5 crow-rounded-lg crow-text-gray-500 hover:crow-bg-gray-100 hover:crow-text-gray-700 crow-transition-colors",
|
|
156
|
+
"aria-label": "New chat",
|
|
157
|
+
children: /* @__PURE__ */ jsx(
|
|
158
|
+
"svg",
|
|
159
|
+
{
|
|
160
|
+
className: "crow-w-5 crow-h-5",
|
|
161
|
+
fill: "none",
|
|
162
|
+
stroke: "currentColor",
|
|
163
|
+
viewBox: "0 0 24 24",
|
|
164
|
+
children: /* @__PURE__ */ jsx(
|
|
165
|
+
"path",
|
|
166
|
+
{
|
|
167
|
+
strokeLinecap: "round",
|
|
168
|
+
strokeLinejoin: "round",
|
|
169
|
+
strokeWidth: 2,
|
|
170
|
+
d: "M12 4v16m8-8H4"
|
|
171
|
+
}
|
|
172
|
+
)
|
|
173
|
+
}
|
|
174
|
+
)
|
|
175
|
+
}
|
|
176
|
+
),
|
|
177
|
+
showClose && onClose && /* @__PURE__ */ jsx(
|
|
178
|
+
"button",
|
|
179
|
+
{
|
|
180
|
+
onClick: onClose,
|
|
181
|
+
className: "crow-p-1.5 crow-rounded-lg crow-text-gray-500 hover:crow-bg-gray-100 hover:crow-text-gray-700 crow-transition-colors",
|
|
182
|
+
"aria-label": "Close",
|
|
183
|
+
children: /* @__PURE__ */ jsx(
|
|
184
|
+
"svg",
|
|
185
|
+
{
|
|
186
|
+
className: "crow-w-5 crow-h-5",
|
|
187
|
+
fill: "none",
|
|
188
|
+
stroke: "currentColor",
|
|
189
|
+
viewBox: "0 0 24 24",
|
|
190
|
+
children: /* @__PURE__ */ jsx(
|
|
191
|
+
"path",
|
|
192
|
+
{
|
|
193
|
+
strokeLinecap: "round",
|
|
194
|
+
strokeLinejoin: "round",
|
|
195
|
+
strokeWidth: 2,
|
|
196
|
+
d: "M6 18L18 6M6 6l12 12"
|
|
197
|
+
}
|
|
198
|
+
)
|
|
199
|
+
}
|
|
200
|
+
)
|
|
201
|
+
}
|
|
202
|
+
)
|
|
203
|
+
] })
|
|
204
|
+
]
|
|
205
|
+
}
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
function formatTime(date) {
|
|
209
|
+
return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
|
210
|
+
}
|
|
211
|
+
function MessageBubble({ message, isStreaming = false }) {
|
|
212
|
+
const isUser = message.role === "user";
|
|
213
|
+
const isWaiting = !message.content && !isUser;
|
|
214
|
+
return /* @__PURE__ */ jsxs(
|
|
215
|
+
"div",
|
|
216
|
+
{
|
|
217
|
+
className: clsx(
|
|
218
|
+
"crow-flex crow-flex-col",
|
|
219
|
+
isUser ? "crow-items-end" : "crow-items-start"
|
|
220
|
+
),
|
|
221
|
+
children: [
|
|
222
|
+
message.thinking && /* @__PURE__ */ jsx("div", { className: "crow-mb-2 crow-text-xs crow-text-gray-500 crow-bg-gray-100 crow-rounded-lg crow-px-3 crow-py-2 crow-max-w-[80%]", children: /* @__PURE__ */ jsxs("details", { open: !message.thinkingComplete, children: [
|
|
223
|
+
/* @__PURE__ */ jsx("summary", { className: "crow-cursor-pointer crow-font-medium", children: message.thinkingComplete ? "Reasoning" : "Thinking..." }),
|
|
224
|
+
/* @__PURE__ */ jsx("div", { className: "crow-mt-1 crow-text-gray-600 crow-whitespace-pre-wrap", children: message.thinking })
|
|
225
|
+
] }) }),
|
|
226
|
+
isWaiting && /* @__PURE__ */ jsxs("div", { className: "crow-flex crow-items-center crow-gap-1 crow-text-gray-500 crow-text-sm crow-px-3 crow-py-2", children: [
|
|
227
|
+
/* @__PURE__ */ jsx("span", { className: "crow-animate-pulse", children: "\u25CF" }),
|
|
228
|
+
/* @__PURE__ */ jsx("span", { className: "crow-animate-pulse crow-animation-delay-100", children: "\u25CF" }),
|
|
229
|
+
/* @__PURE__ */ jsx("span", { className: "crow-animate-pulse crow-animation-delay-200", children: "\u25CF" })
|
|
230
|
+
] }),
|
|
231
|
+
message.content && /* @__PURE__ */ jsxs(
|
|
232
|
+
"div",
|
|
233
|
+
{
|
|
234
|
+
className: clsx(
|
|
235
|
+
"crow-max-w-[80%] crow-rounded-2xl crow-px-4 crow-py-2 crow-transition-all",
|
|
236
|
+
isUser ? "crow-bg-crow-primary crow-text-white" : "crow-bg-gray-100 crow-text-gray-900"
|
|
237
|
+
),
|
|
238
|
+
children: [
|
|
239
|
+
/* @__PURE__ */ jsxs("div", { className: "crow-text-sm crow-whitespace-pre-wrap", children: [
|
|
240
|
+
message.content,
|
|
241
|
+
isStreaming && /* @__PURE__ */ jsx("span", { className: "crow-inline-block crow-w-1 crow-h-4 crow-ml-0.5 crow-bg-current crow-animate-pulse" })
|
|
242
|
+
] }),
|
|
243
|
+
/* @__PURE__ */ jsx("div", { className: "crow-text-xs crow-opacity-60 crow-mt-1", children: formatTime(message.timestamp) })
|
|
244
|
+
]
|
|
245
|
+
}
|
|
246
|
+
),
|
|
247
|
+
message.citations && message.citations.length > 0 && /* @__PURE__ */ jsx("div", { className: "crow-mt-1 crow-flex crow-flex-wrap crow-gap-1", children: message.citations.map((citation, idx) => /* @__PURE__ */ jsx(
|
|
248
|
+
"span",
|
|
249
|
+
{
|
|
250
|
+
className: "crow-text-xs crow-bg-blue-100 crow-text-blue-700 crow-px-2 crow-py-0.5 crow-rounded",
|
|
251
|
+
children: citation.filename
|
|
252
|
+
},
|
|
253
|
+
idx
|
|
254
|
+
)) })
|
|
255
|
+
]
|
|
256
|
+
}
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
function MessageList({ messages, isLoading = false, className }) {
|
|
260
|
+
const containerRef = useRef(null);
|
|
261
|
+
useEffect(() => {
|
|
262
|
+
if (containerRef.current) {
|
|
263
|
+
containerRef.current.scrollTop = containerRef.current.scrollHeight;
|
|
264
|
+
}
|
|
265
|
+
}, [messages]);
|
|
266
|
+
return /* @__PURE__ */ jsx(
|
|
267
|
+
"div",
|
|
268
|
+
{
|
|
269
|
+
ref: containerRef,
|
|
270
|
+
className: `crow-flex-1 crow-overflow-y-auto crow-px-4 crow-py-4 crow-space-y-3 ${className || ""}`,
|
|
271
|
+
children: messages.map((message, index) => {
|
|
272
|
+
const isLastBotMessage = message.role === "assistant" && index === messages.length - 1;
|
|
273
|
+
return /* @__PURE__ */ jsx(
|
|
274
|
+
MessageBubble,
|
|
275
|
+
{
|
|
276
|
+
message,
|
|
277
|
+
isStreaming: isLastBotMessage && isLoading
|
|
278
|
+
},
|
|
279
|
+
message.id
|
|
280
|
+
);
|
|
281
|
+
})
|
|
282
|
+
}
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
function PromptInput({
|
|
286
|
+
onSend,
|
|
287
|
+
onStop,
|
|
288
|
+
isLoading = false,
|
|
289
|
+
placeholder = "Type your message...",
|
|
290
|
+
disabled = false,
|
|
291
|
+
className
|
|
292
|
+
}) {
|
|
293
|
+
const [value, setValue] = useState("");
|
|
294
|
+
const textareaRef = useRef(null);
|
|
295
|
+
useEffect(() => {
|
|
296
|
+
const textarea = textareaRef.current;
|
|
297
|
+
if (textarea) {
|
|
298
|
+
textarea.style.height = "auto";
|
|
299
|
+
textarea.style.height = `${Math.min(textarea.scrollHeight, 200)}px`;
|
|
300
|
+
}
|
|
301
|
+
}, [value]);
|
|
302
|
+
const handleSubmit = useCallback(() => {
|
|
303
|
+
if (value.trim() && !isLoading) {
|
|
304
|
+
onSend(value.trim());
|
|
305
|
+
setValue("");
|
|
306
|
+
}
|
|
307
|
+
}, [value, isLoading, onSend]);
|
|
308
|
+
const handleKeyDown = useCallback(
|
|
309
|
+
(e) => {
|
|
310
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
311
|
+
e.preventDefault();
|
|
312
|
+
handleSubmit();
|
|
313
|
+
}
|
|
314
|
+
},
|
|
315
|
+
[handleSubmit]
|
|
316
|
+
);
|
|
317
|
+
const hasContent = value.trim().length > 0;
|
|
318
|
+
return /* @__PURE__ */ jsxs(
|
|
319
|
+
"div",
|
|
320
|
+
{
|
|
321
|
+
className: clsx(
|
|
322
|
+
"crow-flex crow-items-end crow-gap-2 crow-p-3 crow-border-t crow-border-gray-200 crow-bg-white",
|
|
323
|
+
className
|
|
324
|
+
),
|
|
325
|
+
children: [
|
|
326
|
+
/* @__PURE__ */ jsx(
|
|
327
|
+
"textarea",
|
|
328
|
+
{
|
|
329
|
+
ref: textareaRef,
|
|
330
|
+
value,
|
|
331
|
+
onChange: (e) => setValue(e.target.value),
|
|
332
|
+
onKeyDown: handleKeyDown,
|
|
333
|
+
placeholder,
|
|
334
|
+
disabled: disabled || isLoading,
|
|
335
|
+
rows: 1,
|
|
336
|
+
className: clsx(
|
|
337
|
+
"crow-flex-1 crow-resize-none crow-border crow-border-gray-300 crow-rounded-xl crow-px-4 crow-py-2",
|
|
338
|
+
"crow-text-sm crow-text-gray-900 crow-placeholder-gray-500",
|
|
339
|
+
"focus:crow-outline-none focus:crow-ring-2 focus:crow-ring-crow-primary focus:crow-border-transparent",
|
|
340
|
+
"disabled:crow-bg-gray-50 disabled:crow-cursor-not-allowed"
|
|
341
|
+
)
|
|
342
|
+
}
|
|
343
|
+
),
|
|
344
|
+
/* @__PURE__ */ jsx(
|
|
345
|
+
"button",
|
|
346
|
+
{
|
|
347
|
+
onClick: isLoading ? onStop : handleSubmit,
|
|
348
|
+
disabled: !isLoading && !hasContent,
|
|
349
|
+
className: clsx(
|
|
350
|
+
"crow-flex-shrink-0 crow-w-10 crow-h-10 crow-rounded-full crow-flex crow-items-center crow-justify-center",
|
|
351
|
+
"crow-transition-all crow-duration-200",
|
|
352
|
+
isLoading ? "crow-bg-red-500 hover:crow-bg-red-600 crow-text-white" : hasContent ? "crow-bg-crow-primary hover:crow-bg-crow-primary-dark crow-text-white" : "crow-bg-gray-200 crow-text-gray-400 crow-cursor-not-allowed"
|
|
353
|
+
),
|
|
354
|
+
"aria-label": isLoading ? "Stop generation" : "Send message",
|
|
355
|
+
children: isLoading ? /* @__PURE__ */ jsx("svg", { className: "crow-w-4 crow-h-4", fill: "currentColor", viewBox: "0 0 16 16", children: /* @__PURE__ */ jsx("rect", { width: "10", height: "10", x: "3", y: "3", rx: "1" }) }) : /* @__PURE__ */ jsx("svg", { className: "crow-w-4 crow-h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 12h14M12 5l7 7-7 7" }) })
|
|
356
|
+
}
|
|
357
|
+
)
|
|
358
|
+
]
|
|
359
|
+
}
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
function CrowWidget({
|
|
363
|
+
productId,
|
|
364
|
+
apiUrl,
|
|
365
|
+
model,
|
|
366
|
+
agentName = "Assistant",
|
|
367
|
+
defaultCollapsed = true,
|
|
368
|
+
onIdentify,
|
|
369
|
+
tools,
|
|
370
|
+
className,
|
|
371
|
+
zIndex = 999999
|
|
372
|
+
}) {
|
|
373
|
+
const contextClient = useCrowClientOptional();
|
|
374
|
+
const standaloneClientRef = useRef(null);
|
|
375
|
+
if (!contextClient && !standaloneClientRef.current) {
|
|
376
|
+
standaloneClientRef.current = new CrowClient({ productId, apiUrl, model });
|
|
377
|
+
}
|
|
378
|
+
const client = contextClient || standaloneClientRef.current;
|
|
379
|
+
useEffect(() => {
|
|
380
|
+
return () => {
|
|
381
|
+
if (standaloneClientRef.current) {
|
|
382
|
+
standaloneClientRef.current.destroy();
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
}, []);
|
|
386
|
+
useEffect(() => {
|
|
387
|
+
if (tools) {
|
|
388
|
+
client.registerTools(tools);
|
|
389
|
+
}
|
|
390
|
+
}, [client, tools]);
|
|
391
|
+
useEffect(() => {
|
|
392
|
+
if (onIdentify) {
|
|
393
|
+
onIdentify((options) => client.identify(options));
|
|
394
|
+
}
|
|
395
|
+
}, [client, onIdentify]);
|
|
396
|
+
const [isCollapsed, setIsCollapsed] = useState(defaultCollapsed);
|
|
397
|
+
const { messages, isLoading, sendMessage, stop, clearMessages } = useChat({
|
|
398
|
+
client
|
|
399
|
+
});
|
|
400
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
401
|
+
/* @__PURE__ */ jsx(ChatBubble, { isOpen: !isCollapsed, onClick: () => setIsCollapsed(!isCollapsed) }),
|
|
402
|
+
!isCollapsed && /* @__PURE__ */ jsxs(
|
|
403
|
+
"div",
|
|
404
|
+
{
|
|
405
|
+
className: clsx(
|
|
406
|
+
"crow-fixed crow-flex crow-flex-col",
|
|
407
|
+
"crow-bg-white crow-rounded-2xl crow-shadow-2xl",
|
|
408
|
+
"crow-border crow-border-gray-200",
|
|
409
|
+
"crow-overflow-hidden crow-animate-fade-in",
|
|
410
|
+
className
|
|
411
|
+
),
|
|
412
|
+
style: {
|
|
413
|
+
zIndex,
|
|
414
|
+
right: "20px",
|
|
415
|
+
bottom: "90px",
|
|
416
|
+
width: "380px",
|
|
417
|
+
height: "550px",
|
|
418
|
+
maxHeight: "calc(100vh - 120px)"
|
|
419
|
+
},
|
|
420
|
+
children: [
|
|
421
|
+
/* @__PURE__ */ jsx(
|
|
422
|
+
WidgetHeader,
|
|
423
|
+
{
|
|
424
|
+
title: agentName,
|
|
425
|
+
onNewChat: clearMessages,
|
|
426
|
+
showNewChat: true
|
|
427
|
+
}
|
|
428
|
+
),
|
|
429
|
+
/* @__PURE__ */ jsx(
|
|
430
|
+
MessageList,
|
|
431
|
+
{
|
|
432
|
+
messages,
|
|
433
|
+
isLoading,
|
|
434
|
+
className: "crow-flex-1"
|
|
435
|
+
}
|
|
436
|
+
),
|
|
437
|
+
/* @__PURE__ */ jsx(
|
|
438
|
+
PromptInput,
|
|
439
|
+
{
|
|
440
|
+
onSend: sendMessage,
|
|
441
|
+
onStop: stop,
|
|
442
|
+
isLoading,
|
|
443
|
+
placeholder: "Type your message..."
|
|
444
|
+
}
|
|
445
|
+
)
|
|
446
|
+
]
|
|
447
|
+
}
|
|
448
|
+
)
|
|
449
|
+
] });
|
|
450
|
+
}
|
|
451
|
+
function CrowCopilot({
|
|
452
|
+
productId,
|
|
453
|
+
apiUrl,
|
|
454
|
+
model,
|
|
455
|
+
title = "Copilot",
|
|
456
|
+
position = "right",
|
|
457
|
+
width = 400,
|
|
458
|
+
showClose = false,
|
|
459
|
+
onClose,
|
|
460
|
+
onIdentify,
|
|
461
|
+
tools,
|
|
462
|
+
className
|
|
463
|
+
}) {
|
|
464
|
+
const contextClient = useCrowClientOptional();
|
|
465
|
+
const standaloneClientRef = useRef(null);
|
|
466
|
+
if (!contextClient && !standaloneClientRef.current && productId) {
|
|
467
|
+
standaloneClientRef.current = new CrowClient({ productId, apiUrl, model });
|
|
468
|
+
}
|
|
469
|
+
const client = contextClient || standaloneClientRef.current;
|
|
470
|
+
if (!client) {
|
|
471
|
+
console.error(
|
|
472
|
+
"[CrowCopilot] No client available. Either wrap in CrowProvider or provide productId prop."
|
|
473
|
+
);
|
|
474
|
+
return null;
|
|
475
|
+
}
|
|
476
|
+
useEffect(() => {
|
|
477
|
+
return () => {
|
|
478
|
+
if (standaloneClientRef.current) {
|
|
479
|
+
standaloneClientRef.current.destroy();
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
}, []);
|
|
483
|
+
useEffect(() => {
|
|
484
|
+
if (tools) {
|
|
485
|
+
client.registerTools(tools);
|
|
486
|
+
}
|
|
487
|
+
}, [client, tools]);
|
|
488
|
+
useEffect(() => {
|
|
489
|
+
if (onIdentify) {
|
|
490
|
+
onIdentify((options) => client.identify(options));
|
|
491
|
+
}
|
|
492
|
+
}, [client, onIdentify]);
|
|
493
|
+
const { messages, isLoading, sendMessage, stop, clearMessages } = useChat({
|
|
494
|
+
client
|
|
495
|
+
});
|
|
496
|
+
const widthStyle = typeof width === "number" ? `${width}px` : width;
|
|
497
|
+
return /* @__PURE__ */ jsxs(
|
|
498
|
+
"div",
|
|
499
|
+
{
|
|
500
|
+
className: clsx(
|
|
501
|
+
"crow-flex crow-flex-col crow-h-full",
|
|
502
|
+
"crow-bg-white crow-border-gray-200",
|
|
503
|
+
position === "left" ? "crow-border-r" : "crow-border-l",
|
|
504
|
+
className
|
|
505
|
+
),
|
|
506
|
+
style: { width: widthStyle },
|
|
507
|
+
children: [
|
|
508
|
+
/* @__PURE__ */ jsx(
|
|
509
|
+
WidgetHeader,
|
|
510
|
+
{
|
|
511
|
+
title,
|
|
512
|
+
onNewChat: clearMessages,
|
|
513
|
+
onClose,
|
|
514
|
+
showNewChat: true,
|
|
515
|
+
showClose
|
|
516
|
+
}
|
|
517
|
+
),
|
|
518
|
+
/* @__PURE__ */ jsx(
|
|
519
|
+
MessageList,
|
|
520
|
+
{
|
|
521
|
+
messages,
|
|
522
|
+
isLoading,
|
|
523
|
+
className: "crow-flex-1"
|
|
524
|
+
}
|
|
525
|
+
),
|
|
526
|
+
/* @__PURE__ */ jsx(
|
|
527
|
+
PromptInput,
|
|
528
|
+
{
|
|
529
|
+
onSend: sendMessage,
|
|
530
|
+
onStop: stop,
|
|
531
|
+
isLoading,
|
|
532
|
+
placeholder: "Ask anything..."
|
|
533
|
+
}
|
|
534
|
+
)
|
|
535
|
+
]
|
|
536
|
+
}
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
function useIdentity({ client }) {
|
|
540
|
+
const [isIdentified, setIsIdentified] = useState(client.isIdentified());
|
|
541
|
+
const [isVerified, setIsVerified] = useState(client.isVerified());
|
|
542
|
+
useEffect(() => {
|
|
543
|
+
client.on({
|
|
544
|
+
onVerificationStatus: (verified) => {
|
|
545
|
+
setIsVerified(verified);
|
|
546
|
+
}
|
|
547
|
+
});
|
|
548
|
+
setIsIdentified(client.isIdentified());
|
|
549
|
+
setIsVerified(client.isVerified());
|
|
550
|
+
}, [client]);
|
|
551
|
+
const identify = useCallback(
|
|
552
|
+
(options) => {
|
|
553
|
+
client.identify(options);
|
|
554
|
+
setIsIdentified(true);
|
|
555
|
+
},
|
|
556
|
+
[client]
|
|
557
|
+
);
|
|
558
|
+
const resetUser = useCallback(() => {
|
|
559
|
+
client.resetUser();
|
|
560
|
+
setIsIdentified(false);
|
|
561
|
+
setIsVerified(false);
|
|
562
|
+
}, [client]);
|
|
563
|
+
return {
|
|
564
|
+
isIdentified,
|
|
565
|
+
isVerified,
|
|
566
|
+
identify,
|
|
567
|
+
resetUser
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
function useConversations({
|
|
571
|
+
client
|
|
572
|
+
}) {
|
|
573
|
+
const [conversations, setConversations] = useState([]);
|
|
574
|
+
const [isLoadingConversations, setIsLoadingConversations] = useState(false);
|
|
575
|
+
const [isLoadingHistory, setIsLoadingHistory] = useState(false);
|
|
576
|
+
const loadConversations = useCallback(async () => {
|
|
577
|
+
setIsLoadingConversations(true);
|
|
578
|
+
try {
|
|
579
|
+
const convs = await client.getConversations();
|
|
580
|
+
setConversations(convs);
|
|
581
|
+
} finally {
|
|
582
|
+
setIsLoadingConversations(false);
|
|
583
|
+
}
|
|
584
|
+
}, [client]);
|
|
585
|
+
const loadHistory = useCallback(
|
|
586
|
+
async (conversationId) => {
|
|
587
|
+
setIsLoadingHistory(true);
|
|
588
|
+
try {
|
|
589
|
+
return await client.loadHistory(conversationId);
|
|
590
|
+
} finally {
|
|
591
|
+
setIsLoadingHistory(false);
|
|
592
|
+
}
|
|
593
|
+
},
|
|
594
|
+
[client]
|
|
595
|
+
);
|
|
596
|
+
const switchConversation = useCallback(
|
|
597
|
+
async (conversationId) => {
|
|
598
|
+
setIsLoadingHistory(true);
|
|
599
|
+
try {
|
|
600
|
+
await client.switchConversation(conversationId);
|
|
601
|
+
} finally {
|
|
602
|
+
setIsLoadingHistory(false);
|
|
603
|
+
}
|
|
604
|
+
},
|
|
605
|
+
[client]
|
|
606
|
+
);
|
|
607
|
+
const startNewConversation = useCallback(() => {
|
|
608
|
+
client.clearMessages();
|
|
609
|
+
}, [client]);
|
|
610
|
+
return {
|
|
611
|
+
conversations,
|
|
612
|
+
isLoadingConversations,
|
|
613
|
+
isLoadingHistory,
|
|
614
|
+
currentConversationId: client.conversationId,
|
|
615
|
+
loadConversations,
|
|
616
|
+
loadHistory,
|
|
617
|
+
switchConversation,
|
|
618
|
+
startNewConversation
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
export { ChatBubble, CrowCopilot, CrowProvider, CrowWidget, MessageBubble, MessageList, PromptInput, WidgetHeader, useChat, useConversations, useCrowClient, useCrowClientOptional, useIdentity };
|
|
623
|
+
//# sourceMappingURL=index.js.map
|
|
624
|
+
//# sourceMappingURL=index.js.map
|