@apteva/apteva-kit 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/dist/index.mjs ADDED
@@ -0,0 +1,1190 @@
1
+ "use client";
2
+
3
+ // src/components/Chat/Chat.tsx
4
+ import { useState as useState2, useEffect as useEffect3 } from "react";
5
+
6
+ // src/components/Chat/MessageList.tsx
7
+ import { useEffect as useEffect2, useRef } from "react";
8
+
9
+ // src/utils/cn.ts
10
+ import { clsx } from "clsx";
11
+ import { twMerge } from "tailwind-merge";
12
+ function cn(...inputs) {
13
+ return twMerge(clsx(inputs));
14
+ }
15
+
16
+ // src/utils/mock-data.ts
17
+ var mockMessages = [
18
+ {
19
+ id: "msg-1",
20
+ role: "assistant",
21
+ content: "Hello! I'm your AI assistant. How can I help you today?",
22
+ timestamp: new Date(Date.now() - 36e5)
23
+ },
24
+ {
25
+ id: "msg-2",
26
+ role: "user",
27
+ content: "I want to plan a trip to Europe",
28
+ timestamp: new Date(Date.now() - 35e5)
29
+ },
30
+ {
31
+ id: "msg-3",
32
+ role: "assistant",
33
+ content: "Great choice! Europe has amazing destinations. What's your budget and how many days do you have?",
34
+ timestamp: new Date(Date.now() - 34e5)
35
+ },
36
+ {
37
+ id: "msg-4",
38
+ role: "user",
39
+ content: "Around $2000 for 5 days",
40
+ timestamp: new Date(Date.now() - 33e5)
41
+ },
42
+ {
43
+ id: "msg-5",
44
+ role: "assistant",
45
+ content: "Perfect! I found some great destinations that fit your budget:",
46
+ widgets: [
47
+ {
48
+ type: "list",
49
+ id: "destinations-1",
50
+ props: {
51
+ items: [
52
+ {
53
+ id: "paris",
54
+ title: "Paris, France",
55
+ subtitle: "5 days \u2022 $1,850",
56
+ description: "The City of Light with iconic landmarks",
57
+ metadata: { city: "Paris", country: "France", lat: 48.8566, lng: 2.3522, price: 1850, days: 5 }
58
+ },
59
+ {
60
+ id: "rome",
61
+ title: "Rome, Italy",
62
+ subtitle: "5 days \u2022 $1,650",
63
+ description: "Ancient history meets modern culture",
64
+ metadata: { city: "Rome", country: "Italy", lat: 41.9028, lng: 12.4964, price: 1650, days: 5 }
65
+ },
66
+ {
67
+ id: "barcelona",
68
+ title: "Barcelona, Spain",
69
+ subtitle: "5 days \u2022 $1,450",
70
+ description: "Beautiful beaches and Gaud\xED architecture",
71
+ metadata: { city: "Barcelona", country: "Spain", lat: 41.3851, lng: 2.1734, price: 1450, days: 5 }
72
+ }
73
+ ]
74
+ },
75
+ actions: [
76
+ {
77
+ type: "select_destination",
78
+ label: "Select",
79
+ handler: "client",
80
+ payload: {}
81
+ },
82
+ {
83
+ type: "view_details",
84
+ label: "Details",
85
+ handler: "server",
86
+ payload: {}
87
+ }
88
+ ]
89
+ }
90
+ ],
91
+ timestamp: new Date(Date.now() - 32e5)
92
+ }
93
+ ];
94
+ var mockThreads = [
95
+ {
96
+ id: "thread-1",
97
+ title: "Trip to Europe",
98
+ preview: "Planning a 5-day trip...",
99
+ createdAt: new Date(Date.now() - 864e5),
100
+ updatedAt: new Date(Date.now() - 36e5),
101
+ messageCount: 12
102
+ },
103
+ {
104
+ id: "thread-2",
105
+ title: "Restaurant Recommendations",
106
+ preview: "Looking for good places...",
107
+ createdAt: new Date(Date.now() - 1728e5),
108
+ updatedAt: new Date(Date.now() - 864e5),
109
+ messageCount: 8
110
+ },
111
+ {
112
+ id: "thread-3",
113
+ title: "Budget Planning",
114
+ preview: "Help with monthly budget",
115
+ createdAt: new Date(Date.now() - 2592e5),
116
+ updatedAt: new Date(Date.now() - 1728e5),
117
+ messageCount: 15
118
+ }
119
+ ];
120
+ var mockWidgets = [
121
+ {
122
+ type: "card",
123
+ id: "card-1",
124
+ props: {
125
+ title: "Paris, France",
126
+ description: "5-day adventure in the City of Light",
127
+ image: "https://images.unsplash.com/photo-1502602898657-3e91760cbb34",
128
+ footer: "Total: $1,850"
129
+ },
130
+ actions: [
131
+ {
132
+ type: "book_trip",
133
+ label: "Book Now",
134
+ handler: "client",
135
+ payload: { tripId: "trip-paris" }
136
+ }
137
+ ]
138
+ },
139
+ {
140
+ type: "card",
141
+ id: "card-2",
142
+ props: {
143
+ title: "Rome, Italy",
144
+ description: "Explore ancient wonders",
145
+ image: "https://images.unsplash.com/photo-1552832230-c0197dd311b5",
146
+ footer: "Total: $1,650"
147
+ },
148
+ actions: [
149
+ {
150
+ type: "book_trip",
151
+ label: "Book Now",
152
+ handler: "client",
153
+ payload: { tripId: "trip-rome" }
154
+ }
155
+ ]
156
+ }
157
+ ];
158
+ function generateMockResponse(delay = 1e3) {
159
+ return new Promise((resolve) => {
160
+ setTimeout(() => {
161
+ resolve({
162
+ id: `msg-${Date.now()}`,
163
+ role: "assistant",
164
+ content: "This is a mock response. In production, this would come from your AI agent API.",
165
+ timestamp: /* @__PURE__ */ new Date()
166
+ });
167
+ }, delay);
168
+ });
169
+ }
170
+ function generateMockStreamingResponse(text, onChunk, typingSpeed = 30) {
171
+ return new Promise((resolve) => {
172
+ const words = text.split(" ");
173
+ let currentIndex = 0;
174
+ const interval = setInterval(() => {
175
+ if (currentIndex < words.length) {
176
+ onChunk(words[currentIndex] + " ");
177
+ currentIndex++;
178
+ } else {
179
+ clearInterval(interval);
180
+ resolve();
181
+ }
182
+ }, typingSpeed);
183
+ });
184
+ }
185
+
186
+ // src/components/Widgets/Widgets.tsx
187
+ import { useEffect } from "react";
188
+
189
+ // src/components/Widgets/widget-library/Card.tsx
190
+ import { jsx, jsxs } from "react/jsx-runtime";
191
+ function Card({ widget, onAction }) {
192
+ const { title, description, image, footer } = widget.props;
193
+ return /* @__PURE__ */ jsxs("div", { className: "apteva-widget-card", children: [
194
+ image && /* @__PURE__ */ jsx("img", { src: image, alt: title, className: "w-full h-48 object-cover" }),
195
+ /* @__PURE__ */ jsxs("div", { className: "p-4", children: [
196
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-gray-900 dark:text-white", children: title }),
197
+ description && /* @__PURE__ */ jsx("p", { className: "text-gray-600 dark:text-gray-400 mt-2", children: description })
198
+ ] }),
199
+ (footer || widget.actions && widget.actions.length > 0) && /* @__PURE__ */ jsxs("div", { className: "border-t border-gray-200 dark:border-gray-700 p-4 flex justify-between items-center", children: [
200
+ footer && /* @__PURE__ */ jsx("span", { className: "text-sm text-gray-600 dark:text-gray-400", children: footer }),
201
+ widget.actions && widget.actions.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex gap-2", children: widget.actions.map((action, idx) => /* @__PURE__ */ jsx(
202
+ "button",
203
+ {
204
+ onClick: () => onAction?.({
205
+ type: action.type,
206
+ payload: action.payload,
207
+ widgetId: widget.id,
208
+ timestamp: /* @__PURE__ */ new Date()
209
+ }),
210
+ className: "apteva-widget-button",
211
+ children: action.label
212
+ },
213
+ idx
214
+ )) })
215
+ ] })
216
+ ] });
217
+ }
218
+
219
+ // src/components/Widgets/widget-library/List.tsx
220
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
221
+ function List({ widget, onAction }) {
222
+ const { items } = widget.props;
223
+ return /* @__PURE__ */ jsx2("div", { className: "apteva-widget-list", children: items.map((item) => /* @__PURE__ */ jsxs2("div", { className: "flex items-center p-4 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors", children: [
224
+ item.image && /* @__PURE__ */ jsx2("img", { src: item.image, alt: item.title, className: "w-16 h-16 rounded object-cover" }),
225
+ /* @__PURE__ */ jsxs2("div", { className: "flex-1 ml-4", children: [
226
+ /* @__PURE__ */ jsx2("h4", { className: "font-semibold text-gray-900 dark:text-white", children: item.title }),
227
+ item.subtitle && /* @__PURE__ */ jsx2("p", { className: "text-sm text-gray-600 dark:text-gray-400", children: item.subtitle }),
228
+ item.description && /* @__PURE__ */ jsx2("p", { className: "text-xs text-gray-500 dark:text-gray-500 mt-1", children: item.description })
229
+ ] }),
230
+ widget.actions && widget.actions.length > 0 && /* @__PURE__ */ jsx2("div", { className: "flex gap-2", children: widget.actions.map((action, idx) => /* @__PURE__ */ jsx2(
231
+ "button",
232
+ {
233
+ onClick: () => onAction?.({
234
+ type: action.type,
235
+ payload: item.metadata || item,
236
+ widgetId: widget.id,
237
+ timestamp: /* @__PURE__ */ new Date()
238
+ }),
239
+ className: "px-3 py-1.5 text-sm rounded-lg font-medium transition-colors bg-apteva-500 text-white hover:bg-apteva-600",
240
+ children: action.label
241
+ },
242
+ idx
243
+ )) })
244
+ ] }, item.id)) });
245
+ }
246
+
247
+ // src/components/Widgets/widget-library/Button.tsx
248
+ import { jsx as jsx3 } from "react/jsx-runtime";
249
+ function Button({ widget, onAction }) {
250
+ const { label, variant = "primary", disabled = false } = widget.props;
251
+ const variantClasses = {
252
+ primary: "bg-apteva-500 text-white hover:bg-apteva-600",
253
+ secondary: "bg-gray-500 text-white hover:bg-gray-600",
254
+ outline: "border-2 border-apteva-500 text-apteva-500 hover:bg-apteva-50",
255
+ ghost: "text-apteva-500 hover:bg-apteva-50"
256
+ };
257
+ return /* @__PURE__ */ jsx3(
258
+ "button",
259
+ {
260
+ onClick: () => widget.actions?.[0] && onAction?.({
261
+ type: widget.actions[0].type,
262
+ payload: widget.actions[0].payload,
263
+ widgetId: widget.id,
264
+ timestamp: /* @__PURE__ */ new Date()
265
+ }),
266
+ disabled,
267
+ className: cn("px-4 py-2 rounded-lg font-medium transition-colors", variantClasses[variant], {
268
+ "opacity-50 cursor-not-allowed": disabled
269
+ }),
270
+ children: label
271
+ }
272
+ );
273
+ }
274
+
275
+ // src/components/Widgets/WidgetRenderer.tsx
276
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
277
+ function WidgetRenderer({ widget, onAction }) {
278
+ switch (widget.type) {
279
+ case "card":
280
+ return /* @__PURE__ */ jsx4(Card, { widget, onAction });
281
+ case "list":
282
+ return /* @__PURE__ */ jsx4(List, { widget, onAction });
283
+ case "button":
284
+ return /* @__PURE__ */ jsx4(Button, { widget, onAction });
285
+ default:
286
+ return /* @__PURE__ */ jsxs3("div", { className: "p-4 border border-yellow-300 bg-yellow-50 rounded-lg", children: [
287
+ /* @__PURE__ */ jsxs3("p", { className: "text-sm text-yellow-800", children: [
288
+ "Unknown widget type: ",
289
+ widget.type
290
+ ] }),
291
+ /* @__PURE__ */ jsx4("pre", { className: "text-xs mt-2 overflow-auto", children: JSON.stringify(widget, null, 2) })
292
+ ] });
293
+ }
294
+ }
295
+
296
+ // src/components/Widgets/Widgets.tsx
297
+ import { jsx as jsx5 } from "react/jsx-runtime";
298
+ function Widgets({
299
+ widgets,
300
+ onAction,
301
+ onWidgetMount,
302
+ layout = "stack",
303
+ spacing = "normal",
304
+ columns = 3,
305
+ className
306
+ }) {
307
+ useEffect(() => {
308
+ widgets.forEach((widget) => {
309
+ onWidgetMount?.(widget.id);
310
+ });
311
+ }, [widgets, onWidgetMount]);
312
+ const layoutClasses = {
313
+ stack: "flex flex-col",
314
+ grid: `grid grid-cols-1 md:grid-cols-${columns}`,
315
+ masonry: "columns-1 md:columns-2 lg:columns-3"
316
+ };
317
+ const spacingClasses = {
318
+ tight: "gap-2",
319
+ normal: "gap-4",
320
+ loose: "gap-6"
321
+ };
322
+ return /* @__PURE__ */ jsx5("div", { className: cn(layoutClasses[layout], spacingClasses[spacing], className), children: widgets.map((widget) => /* @__PURE__ */ jsx5(WidgetRenderer, { widget, onAction }, widget.id)) });
323
+ }
324
+
325
+ // src/components/Chat/Message.tsx
326
+ import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
327
+ function Message({ message, onAction }) {
328
+ const isUser = message.role === "user";
329
+ return /* @__PURE__ */ jsxs4("div", { className: cn("apteva-message", isUser ? "apteva-message-user" : "apteva-message-assistant"), children: [
330
+ /* @__PURE__ */ jsx6("div", { className: "whitespace-pre-wrap", children: message.content }),
331
+ message.widgets && message.widgets.length > 0 && /* @__PURE__ */ jsx6("div", { className: "mt-4", children: /* @__PURE__ */ jsx6(Widgets, { widgets: message.widgets, onAction, layout: "stack" }) }),
332
+ /* @__PURE__ */ jsx6("div", { className: "text-xs opacity-70 mt-2", children: message.timestamp.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }) })
333
+ ] });
334
+ }
335
+
336
+ // src/components/Chat/MessageList.tsx
337
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
338
+ function MessageList({ messages, onAction }) {
339
+ const listRef = useRef(null);
340
+ useEffect2(() => {
341
+ if (listRef.current) {
342
+ listRef.current.scrollTop = listRef.current.scrollHeight;
343
+ }
344
+ }, [messages]);
345
+ return /* @__PURE__ */ jsx7("div", { ref: listRef, className: "apteva-message-list", children: messages.length === 0 ? /* @__PURE__ */ jsx7("div", { className: "flex items-center justify-center h-full text-gray-500", children: /* @__PURE__ */ jsxs5("div", { className: "text-center space-y-2", children: [
346
+ /* @__PURE__ */ jsx7("div", { className: "text-4xl", children: "\u{1F4AC}" }),
347
+ /* @__PURE__ */ jsx7("p", { children: "No messages yet. Start a conversation!" })
348
+ ] }) }) : messages.map((message) => /* @__PURE__ */ jsx7(Message, { message, onAction }, message.id)) });
349
+ }
350
+
351
+ // src/components/Chat/Composer.tsx
352
+ import { useState, useRef as useRef2 } from "react";
353
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
354
+ function Composer({ onSendMessage, placeholder = "Type a message...", disabled = false }) {
355
+ const [text, setText] = useState("");
356
+ const textareaRef = useRef2(null);
357
+ const handleKeyDown = (e) => {
358
+ if (e.key === "Enter" && !e.shiftKey) {
359
+ e.preventDefault();
360
+ handleSend();
361
+ }
362
+ };
363
+ const handleSend = () => {
364
+ if (text.trim() && !disabled) {
365
+ onSendMessage(text.trim());
366
+ setText("");
367
+ if (textareaRef.current) {
368
+ textareaRef.current.style.height = "auto";
369
+ }
370
+ }
371
+ };
372
+ const handleChange = (e) => {
373
+ setText(e.target.value);
374
+ e.target.style.height = "auto";
375
+ e.target.style.height = `${e.target.scrollHeight}px`;
376
+ };
377
+ return /* @__PURE__ */ jsxs6("div", { className: "apteva-composer", children: [
378
+ /* @__PURE__ */ jsxs6("div", { className: "flex gap-2", children: [
379
+ /* @__PURE__ */ jsx8(
380
+ "textarea",
381
+ {
382
+ ref: textareaRef,
383
+ value: text,
384
+ onChange: handleChange,
385
+ onKeyDown: handleKeyDown,
386
+ placeholder,
387
+ disabled,
388
+ className: "apteva-composer-input",
389
+ rows: 1,
390
+ style: { maxHeight: "200px" }
391
+ }
392
+ ),
393
+ /* @__PURE__ */ jsx8(
394
+ "button",
395
+ {
396
+ onClick: handleSend,
397
+ disabled: !text.trim() || disabled,
398
+ className: "px-6 py-2 bg-apteva-500 text-white rounded-lg hover:bg-apteva-600 disabled:opacity-50 disabled:cursor-not-allowed transition-colors font-medium",
399
+ children: "Send"
400
+ }
401
+ )
402
+ ] }),
403
+ /* @__PURE__ */ jsx8("div", { className: "text-xs text-gray-500 mt-2", children: "Press Enter to send, Shift+Enter for new line" })
404
+ ] });
405
+ }
406
+
407
+ // src/components/Chat/Chat.tsx
408
+ import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
409
+ function Chat({
410
+ agentId,
411
+ threadId,
412
+ initialMessages = [],
413
+ onThreadChange,
414
+ onMessageSent,
415
+ onAction,
416
+ placeholder = "Type a message...",
417
+ showHeader = true,
418
+ headerTitle = "Chat",
419
+ className
420
+ }) {
421
+ const [messages, setMessages] = useState2(initialMessages.length > 0 ? initialMessages : mockMessages);
422
+ const [isLoading, setIsLoading] = useState2(false);
423
+ useEffect3(() => {
424
+ if (threadId) {
425
+ console.log("Loading thread:", threadId);
426
+ onThreadChange?.(threadId);
427
+ }
428
+ }, [threadId, onThreadChange]);
429
+ const handleSendMessage = async (text) => {
430
+ const userMessage = {
431
+ id: `msg-${Date.now()}`,
432
+ role: "user",
433
+ content: text,
434
+ timestamp: /* @__PURE__ */ new Date()
435
+ };
436
+ setMessages((prev) => [...prev, userMessage]);
437
+ onMessageSent?.(userMessage);
438
+ setIsLoading(true);
439
+ try {
440
+ const response = await generateMockResponse(1e3);
441
+ setMessages((prev) => [...prev, response]);
442
+ } catch (error) {
443
+ console.error("Error generating response:", error);
444
+ } finally {
445
+ setIsLoading(false);
446
+ }
447
+ };
448
+ return /* @__PURE__ */ jsxs7("div", { className: cn("apteva-chat-container", className), children: [
449
+ showHeader && /* @__PURE__ */ jsxs7("div", { className: "border-b border-gray-200 dark:border-gray-700 px-4 py-3", children: [
450
+ /* @__PURE__ */ jsx9("h2", { className: "text-lg font-semibold text-gray-900 dark:text-white", children: headerTitle }),
451
+ /* @__PURE__ */ jsxs7("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: [
452
+ "Agent: ",
453
+ agentId
454
+ ] })
455
+ ] }),
456
+ /* @__PURE__ */ jsx9(MessageList, { messages, onAction }),
457
+ isLoading && /* @__PURE__ */ jsx9("div", { className: "px-4 py-2 text-sm text-gray-500 italic", children: "AI is thinking..." }),
458
+ /* @__PURE__ */ jsx9(Composer, { onSendMessage: handleSendMessage, placeholder, disabled: isLoading })
459
+ ] });
460
+ }
461
+
462
+ // src/components/Command/Command.tsx
463
+ import { useState as useState3, useEffect as useEffect4 } from "react";
464
+ import { Fragment, jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
465
+ function Command({
466
+ agentId,
467
+ command: initialCommand,
468
+ context,
469
+ autoExecute = false,
470
+ allowInput = true,
471
+ placeholder = "Enter your command...",
472
+ submitButtonText = "Execute",
473
+ variant = "default",
474
+ onStart,
475
+ onProgress,
476
+ onChunk,
477
+ onComplete,
478
+ onError,
479
+ loadingText = "Processing...",
480
+ showProgress = true,
481
+ enableStreaming = false,
482
+ resultRenderer,
483
+ className
484
+ }) {
485
+ const [state, setState] = useState3("idle");
486
+ const [result, setResult] = useState3(null);
487
+ const [error, setError] = useState3(null);
488
+ const [progress, setProgress] = useState3(0);
489
+ const [command, setCommand] = useState3(initialCommand || "");
490
+ const [streamedContent, setStreamedContent] = useState3("");
491
+ useEffect4(() => {
492
+ if (autoExecute && state === "idle" && command) {
493
+ executeCommand();
494
+ }
495
+ }, [autoExecute]);
496
+ const executeCommand = async () => {
497
+ if (!command.trim()) {
498
+ setError(new Error("Please enter a command"));
499
+ setState("error");
500
+ return;
501
+ }
502
+ setState("loading");
503
+ setError(null);
504
+ setProgress(0);
505
+ setStreamedContent("");
506
+ onStart?.();
507
+ try {
508
+ if (enableStreaming) {
509
+ const mockStreamChunks = [
510
+ "Initializing...",
511
+ "Connecting to agent...",
512
+ "Processing your request...",
513
+ "Analyzing data sources...",
514
+ "Gathering information...",
515
+ "Generating response...",
516
+ "Finalizing results..."
517
+ ];
518
+ for (let i = 0; i < mockStreamChunks.length; i++) {
519
+ await new Promise((resolve) => setTimeout(resolve, 600 + Math.random() * 400));
520
+ const chunk = mockStreamChunks[i];
521
+ setStreamedContent(chunk);
522
+ onChunk?.(chunk);
523
+ setProgress(Math.round((i + 1) / mockStreamChunks.length * 100));
524
+ onProgress?.(Math.round((i + 1) / mockStreamChunks.length * 100));
525
+ }
526
+ const mockResult = {
527
+ success: true,
528
+ data: {
529
+ summary: `Successfully processed: "${command}"`,
530
+ agentId,
531
+ context,
532
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
533
+ },
534
+ message: "Command executed successfully"
535
+ };
536
+ setResult(mockResult);
537
+ setState("success");
538
+ setProgress(100);
539
+ onComplete?.(mockResult);
540
+ } else {
541
+ const progressInterval = setInterval(() => {
542
+ setProgress((prev) => {
543
+ const next = Math.min(prev + 10, 90);
544
+ onProgress?.(next);
545
+ return next;
546
+ });
547
+ }, 200);
548
+ await new Promise((resolve) => setTimeout(resolve, 2e3));
549
+ clearInterval(progressInterval);
550
+ const mockResult = {
551
+ success: true,
552
+ data: {
553
+ summary: `Command "${command}" executed successfully`,
554
+ agentId,
555
+ context,
556
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
557
+ },
558
+ message: "Execution complete"
559
+ };
560
+ setResult(mockResult);
561
+ setState("success");
562
+ setProgress(100);
563
+ onComplete?.(mockResult);
564
+ }
565
+ } catch (err) {
566
+ const error2 = err instanceof Error ? err : new Error("Unknown error");
567
+ setError(error2);
568
+ setState("error");
569
+ onError?.(error2);
570
+ }
571
+ };
572
+ const resetCommand = () => {
573
+ setState("idle");
574
+ setResult(null);
575
+ setError(null);
576
+ setProgress(0);
577
+ setCommand("");
578
+ };
579
+ const isCompact = variant === "compact";
580
+ return /* @__PURE__ */ jsxs8(
581
+ "div",
582
+ {
583
+ className: cn(
584
+ "relative border-2 rounded-xl bg-white dark:bg-gray-900 transition-all duration-300 flex flex-col",
585
+ state === "loading" && "animate-pulse-border",
586
+ state === "idle" && "border-gray-300 dark:border-gray-700",
587
+ state === "loading" && "border-apteva-500",
588
+ state === "success" && "border-green-500",
589
+ state === "error" && "border-red-500",
590
+ className
591
+ ),
592
+ style: { minHeight: isCompact ? "auto" : "180px" },
593
+ children: [
594
+ /* @__PURE__ */ jsxs8("div", { className: cn("flex-1 flex", isCompact ? "flex-row items-center p-3 gap-3" : "flex-col p-4"), children: [
595
+ state === "idle" && allowInput && !isCompact && /* @__PURE__ */ jsx10(
596
+ "textarea",
597
+ {
598
+ value: command,
599
+ onChange: (e) => setCommand(e.target.value),
600
+ onKeyDown: (e) => {
601
+ if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
602
+ e.preventDefault();
603
+ executeCommand();
604
+ }
605
+ },
606
+ placeholder,
607
+ className: "flex-1 w-full resize-none bg-transparent border-none focus:outline-none text-gray-900 dark:text-white placeholder-gray-400",
608
+ rows: 6
609
+ }
610
+ ),
611
+ state === "idle" && allowInput && isCompact && /* @__PURE__ */ jsxs8(Fragment, { children: [
612
+ /* @__PURE__ */ jsx10(
613
+ "input",
614
+ {
615
+ type: "text",
616
+ value: command,
617
+ onChange: (e) => setCommand(e.target.value),
618
+ onKeyDown: (e) => {
619
+ if (e.key === "Enter") {
620
+ e.preventDefault();
621
+ executeCommand();
622
+ }
623
+ },
624
+ placeholder,
625
+ className: "flex-1 bg-transparent border-none focus:outline-none text-gray-900 dark:text-white placeholder-gray-400 py-1"
626
+ }
627
+ ),
628
+ /* @__PURE__ */ jsx10(
629
+ "button",
630
+ {
631
+ onClick: executeCommand,
632
+ disabled: !command.trim(),
633
+ className: cn(
634
+ "w-8 h-8 rounded-lg flex items-center justify-center font-bold transition-all flex-shrink-0",
635
+ "border border-gray-300 dark:border-gray-600",
636
+ "bg-white dark:bg-gray-800",
637
+ "text-gray-700 dark:text-gray-300",
638
+ "hover:bg-gray-50 dark:hover:bg-gray-700",
639
+ "disabled:opacity-30 disabled:cursor-not-allowed",
640
+ !command.trim() && "border-gray-200 dark:border-gray-700 text-gray-400 dark:text-gray-600"
641
+ ),
642
+ title: "Execute",
643
+ children: "\u2191"
644
+ }
645
+ )
646
+ ] }),
647
+ state === "loading" && !isCompact && /* @__PURE__ */ jsxs8("div", { className: "flex-1 flex flex-col items-center justify-center space-y-4 py-8", children: [
648
+ /* @__PURE__ */ jsx10("div", { className: "w-6 h-6 border-2 border-gray-300 border-t-apteva-500 rounded-full animate-spin" }),
649
+ /* @__PURE__ */ jsx10("div", { className: "text-gray-600 dark:text-gray-400 text-sm text-center max-w-md", children: enableStreaming && streamedContent ? streamedContent : loadingText }),
650
+ showProgress && /* @__PURE__ */ jsxs8("div", { className: "w-full max-w-sm", children: [
651
+ /* @__PURE__ */ jsx10("div", { className: "w-full bg-gray-200 dark:bg-gray-700 rounded-full h-1.5", children: /* @__PURE__ */ jsx10(
652
+ "div",
653
+ {
654
+ className: "bg-apteva-500 h-1.5 rounded-full transition-all duration-300",
655
+ style: { width: `${progress}%` }
656
+ }
657
+ ) }),
658
+ /* @__PURE__ */ jsxs8("p", { className: "text-xs text-gray-500 mt-2 text-center", children: [
659
+ progress,
660
+ "%"
661
+ ] })
662
+ ] })
663
+ ] }),
664
+ state === "loading" && isCompact && /* @__PURE__ */ jsxs8(Fragment, { children: [
665
+ /* @__PURE__ */ jsxs8("div", { className: "flex-1 flex items-center gap-3 py-1", children: [
666
+ /* @__PURE__ */ jsx10("div", { className: "w-4 h-4 border-2 border-gray-300 border-t-apteva-500 rounded-full animate-spin" }),
667
+ /* @__PURE__ */ jsx10("div", { className: "text-gray-600 dark:text-gray-400 text-sm truncate", children: enableStreaming && streamedContent ? streamedContent : loadingText })
668
+ ] }),
669
+ /* @__PURE__ */ jsx10(
670
+ "button",
671
+ {
672
+ disabled: true,
673
+ className: cn(
674
+ "w-8 h-8 rounded-lg flex items-center justify-center font-bold transition-all flex-shrink-0",
675
+ "border border-gray-200 dark:border-gray-700",
676
+ "bg-white dark:bg-gray-800",
677
+ "text-gray-400 dark:text-gray-600",
678
+ "opacity-30 cursor-not-allowed"
679
+ ),
680
+ children: "\u2191"
681
+ }
682
+ )
683
+ ] }),
684
+ state === "error" && /* @__PURE__ */ jsxs8("div", { className: "flex-1 flex flex-col", children: [
685
+ /* @__PURE__ */ jsx10("div", { className: "mb-4 p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg", children: /* @__PURE__ */ jsxs8("div", { className: "flex items-start gap-2", children: [
686
+ /* @__PURE__ */ jsx10("svg", { className: "w-5 h-5 text-red-600 mt-0.5 flex-shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx10("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
687
+ /* @__PURE__ */ jsxs8("div", { children: [
688
+ /* @__PURE__ */ jsx10("h3", { className: "text-sm font-semibold text-red-800 dark:text-red-400", children: "Error" }),
689
+ /* @__PURE__ */ jsx10("p", { className: "text-red-700 dark:text-red-300 text-sm mt-1", children: error?.message })
690
+ ] })
691
+ ] }) }),
692
+ allowInput && /* @__PURE__ */ jsx10(
693
+ "textarea",
694
+ {
695
+ value: command,
696
+ onChange: (e) => setCommand(e.target.value),
697
+ onKeyDown: (e) => {
698
+ if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
699
+ e.preventDefault();
700
+ executeCommand();
701
+ }
702
+ },
703
+ placeholder,
704
+ className: "flex-1 w-full resize-none bg-transparent border-none focus:outline-none text-gray-900 dark:text-white placeholder-gray-400",
705
+ rows: 4
706
+ }
707
+ )
708
+ ] }),
709
+ state === "success" && result && !isCompact && /* @__PURE__ */ jsx10("div", { className: "flex-1 overflow-auto", children: resultRenderer ? resultRenderer(result.data) : /* @__PURE__ */ jsxs8("div", { children: [
710
+ /* @__PURE__ */ jsxs8("div", { className: "flex items-start gap-3 mb-3 p-3 bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-lg", children: [
711
+ /* @__PURE__ */ jsx10("svg", { className: "w-5 h-5 text-green-600 mt-0.5 flex-shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx10("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
712
+ /* @__PURE__ */ jsxs8("div", { className: "flex-1", children: [
713
+ /* @__PURE__ */ jsx10("h3", { className: "text-sm font-semibold text-green-800 dark:text-green-400 mb-1", children: "Success" }),
714
+ /* @__PURE__ */ jsx10("p", { className: "text-green-700 dark:text-green-300 text-sm", children: result.message || "Command executed successfully" })
715
+ ] })
716
+ ] }),
717
+ result.data?.summary && /* @__PURE__ */ jsx10("div", { className: "text-gray-700 dark:text-gray-300 text-sm leading-relaxed", children: result.data.summary })
718
+ ] }) }),
719
+ state === "success" && result && isCompact && /* @__PURE__ */ jsxs8(Fragment, { children: [
720
+ /* @__PURE__ */ jsxs8("div", { className: "flex-1 flex items-center gap-2 py-1", children: [
721
+ /* @__PURE__ */ jsx10("svg", { className: "w-4 h-4 text-green-600 flex-shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx10("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
722
+ /* @__PURE__ */ jsx10("div", { className: "text-green-700 dark:text-green-300 text-sm truncate", children: resultRenderer ? resultRenderer(result.data) : result.message || "Command executed successfully" })
723
+ ] }),
724
+ /* @__PURE__ */ jsx10(
725
+ "button",
726
+ {
727
+ disabled: true,
728
+ className: cn(
729
+ "w-8 h-8 rounded-lg flex items-center justify-center font-bold transition-all flex-shrink-0",
730
+ "border border-gray-200 dark:border-gray-700",
731
+ "bg-white dark:bg-gray-800",
732
+ "text-gray-400 dark:text-gray-600",
733
+ "opacity-30 cursor-not-allowed"
734
+ ),
735
+ children: "\u2191"
736
+ }
737
+ )
738
+ ] })
739
+ ] }),
740
+ !isCompact && /* @__PURE__ */ jsxs8("div", { className: "p-3 flex items-center justify-end gap-2", children: [
741
+ (state === "success" || state === "error") && allowInput && /* @__PURE__ */ jsx10(
742
+ "button",
743
+ {
744
+ onClick: resetCommand,
745
+ className: "px-3 py-1.5 text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white transition-colors",
746
+ children: "Reset"
747
+ }
748
+ ),
749
+ (state === "idle" || state === "error") && /* @__PURE__ */ jsx10(
750
+ "button",
751
+ {
752
+ onClick: executeCommand,
753
+ disabled: !command.trim(),
754
+ className: cn(
755
+ "w-8 h-8 rounded-lg flex items-center justify-center font-bold transition-all",
756
+ "border border-gray-300 dark:border-gray-600",
757
+ "bg-white dark:bg-gray-800",
758
+ "text-gray-700 dark:text-gray-300",
759
+ "hover:bg-gray-50 dark:hover:bg-gray-700",
760
+ "disabled:opacity-30 disabled:cursor-not-allowed",
761
+ !command.trim() && "border-gray-200 dark:border-gray-700 text-gray-400 dark:text-gray-600"
762
+ ),
763
+ title: state === "error" ? "Retry" : "Execute",
764
+ children: state === "error" ? "\u21BB" : "\u2191"
765
+ }
766
+ )
767
+ ] }),
768
+ /* @__PURE__ */ jsx10("style", { dangerouslySetInnerHTML: {
769
+ __html: `
770
+ @keyframes pulse-border {
771
+ 0%, 100% {
772
+ border-color: rgb(59, 130, 246);
773
+ }
774
+ 50% {
775
+ border-color: rgb(147, 197, 253);
776
+ }
777
+ }
778
+ .animate-pulse-border {
779
+ animation: pulse-border 2s ease-in-out infinite;
780
+ }
781
+ `
782
+ } })
783
+ ]
784
+ }
785
+ );
786
+ }
787
+
788
+ // src/components/Prompt/Prompt.tsx
789
+ import { useState as useState4 } from "react";
790
+ import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
791
+ function Prompt({
792
+ agentId,
793
+ placeholder = "Enter your prompt...",
794
+ initialValue = "",
795
+ submitOn = "button",
796
+ debounceMs = 0,
797
+ minLength = 0,
798
+ maxLength,
799
+ onSubmit,
800
+ onResult,
801
+ onChange,
802
+ variant = "inline",
803
+ showSuggestions = false,
804
+ className
805
+ }) {
806
+ const [value, setValue] = useState4(initialValue);
807
+ const [isLoading, setIsLoading] = useState4(false);
808
+ const [suggestions] = useState4(["Plan a trip", "Write a description", "Analyze data"]);
809
+ const handleChange = (e) => {
810
+ const newValue = e.target.value;
811
+ if (!maxLength || newValue.length <= maxLength) {
812
+ setValue(newValue);
813
+ onChange?.(newValue);
814
+ }
815
+ };
816
+ const handleSubmit = async () => {
817
+ if (value.length < minLength) return;
818
+ onSubmit?.(value);
819
+ setIsLoading(true);
820
+ try {
821
+ await new Promise((resolve) => setTimeout(resolve, 1500));
822
+ const mockResult = `Enhanced version: ${value} [AI-generated content]`;
823
+ onResult?.(mockResult);
824
+ setValue("");
825
+ } catch (error) {
826
+ console.error("Error processing prompt:", error);
827
+ } finally {
828
+ setIsLoading(false);
829
+ }
830
+ };
831
+ const handleKeyDown = (e) => {
832
+ if (submitOn === "enter" && e.key === "Enter" && !e.shiftKey) {
833
+ e.preventDefault();
834
+ handleSubmit();
835
+ }
836
+ };
837
+ const handleBlur = () => {
838
+ if (submitOn === "blur" && value.trim()) {
839
+ handleSubmit();
840
+ }
841
+ };
842
+ return /* @__PURE__ */ jsxs9("div", { className: cn("space-y-2", className), children: [
843
+ /* @__PURE__ */ jsxs9("div", { className: "flex gap-2", children: [
844
+ /* @__PURE__ */ jsx11(
845
+ "input",
846
+ {
847
+ type: "text",
848
+ value,
849
+ onChange: handleChange,
850
+ onKeyDown: handleKeyDown,
851
+ onBlur: handleBlur,
852
+ placeholder,
853
+ disabled: isLoading,
854
+ className: "flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-apteva-500 dark:bg-gray-800 dark:border-gray-600 dark:text-white"
855
+ }
856
+ ),
857
+ submitOn === "button" && /* @__PURE__ */ jsx11(
858
+ "button",
859
+ {
860
+ onClick: handleSubmit,
861
+ disabled: isLoading || value.length < minLength,
862
+ className: "px-6 py-2 bg-apteva-500 text-white rounded-lg hover:bg-apteva-600 disabled:opacity-50 disabled:cursor-not-allowed transition-colors font-medium",
863
+ children: isLoading ? "Processing..." : "Generate"
864
+ }
865
+ )
866
+ ] }),
867
+ maxLength && /* @__PURE__ */ jsxs9("p", { className: "text-xs text-gray-500", children: [
868
+ value.length,
869
+ " / ",
870
+ maxLength,
871
+ " characters"
872
+ ] }),
873
+ showSuggestions && !value && /* @__PURE__ */ jsx11("div", { className: "flex flex-wrap gap-2", children: suggestions.map((suggestion, idx) => /* @__PURE__ */ jsx11(
874
+ "button",
875
+ {
876
+ onClick: () => setValue(suggestion),
877
+ className: "px-3 py-1 text-sm bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-full transition-colors",
878
+ children: suggestion
879
+ },
880
+ idx
881
+ )) }),
882
+ isLoading && /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2 text-sm text-gray-500", children: [
883
+ /* @__PURE__ */ jsx11("div", { className: "w-4 h-4 border-2 border-apteva-500 border-t-transparent rounded-full animate-spin" }),
884
+ /* @__PURE__ */ jsx11("span", { children: "AI is processing your request..." })
885
+ ] })
886
+ ] });
887
+ }
888
+
889
+ // src/components/Stream/Stream.tsx
890
+ import { useState as useState5, useEffect as useEffect5 } from "react";
891
+ import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
892
+ function Stream({
893
+ agentId,
894
+ prompt,
895
+ context,
896
+ autoStart = false,
897
+ onStart,
898
+ onChunk,
899
+ onComplete,
900
+ onError,
901
+ variant = "prose",
902
+ showCursor = true,
903
+ typingSpeed = 30,
904
+ className
905
+ }) {
906
+ const [text, setText] = useState5("");
907
+ const [isStreaming, setIsStreaming] = useState5(false);
908
+ const [isComplete, setIsComplete] = useState5(false);
909
+ useEffect5(() => {
910
+ if (autoStart && !isStreaming && !isComplete) {
911
+ startStreaming();
912
+ }
913
+ }, [autoStart]);
914
+ const startStreaming = async () => {
915
+ setIsStreaming(true);
916
+ onStart?.();
917
+ const mockText = "This is a simulated streaming response from the AI agent. In a real implementation, this would stream data from your backend API. The text appears word by word to simulate the streaming effect. You can customize the typing speed and styling based on your needs.";
918
+ try {
919
+ await generateMockStreamingResponse(
920
+ mockText,
921
+ (chunk) => {
922
+ setText((prev) => prev + chunk);
923
+ onChunk?.(chunk);
924
+ },
925
+ typingSpeed
926
+ );
927
+ setIsComplete(true);
928
+ setIsStreaming(false);
929
+ onComplete?.(text + mockText);
930
+ } catch (error) {
931
+ const err = error instanceof Error ? error : new Error("Streaming error");
932
+ onError?.(err);
933
+ setIsStreaming(false);
934
+ }
935
+ };
936
+ const variantClasses = {
937
+ prose: "prose prose-sm max-w-none dark:prose-invert",
938
+ code: "font-mono text-sm bg-gray-900 text-green-400 p-4 rounded-lg",
939
+ plain: "text-gray-900 dark:text-gray-100"
940
+ };
941
+ if (!isStreaming && !isComplete) {
942
+ return /* @__PURE__ */ jsx12("div", { className: cn("p-4", className), children: /* @__PURE__ */ jsx12(
943
+ "button",
944
+ {
945
+ onClick: startStreaming,
946
+ className: "px-6 py-3 bg-apteva-500 text-white rounded-lg hover:bg-apteva-600 transition-colors font-medium",
947
+ children: "Start Streaming"
948
+ }
949
+ ) });
950
+ }
951
+ return /* @__PURE__ */ jsxs10("div", { className: cn(variantClasses[variant], className), children: [
952
+ text,
953
+ isStreaming && showCursor && /* @__PURE__ */ jsx12("span", { className: "apteva-stream-cursor" })
954
+ ] });
955
+ }
956
+
957
+ // src/components/Threads/ThreadList.tsx
958
+ import { useState as useState6 } from "react";
959
+
960
+ // src/components/Threads/ThreadItem.tsx
961
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
962
+ function ThreadItem({ thread, isActive = false, onSelect, onDelete }) {
963
+ return /* @__PURE__ */ jsxs11(
964
+ "div",
965
+ {
966
+ className: cn("apteva-thread-item", {
967
+ "apteva-thread-item-active": isActive
968
+ }),
969
+ onClick: onSelect,
970
+ children: [
971
+ /* @__PURE__ */ jsxs11("div", { className: "flex-1 min-w-0", children: [
972
+ /* @__PURE__ */ jsx13("h4", { className: "font-semibold text-gray-900 dark:text-white truncate", children: thread.title }),
973
+ thread.preview && /* @__PURE__ */ jsx13("p", { className: "text-sm text-gray-600 dark:text-gray-400 truncate", children: thread.preview }),
974
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2 mt-1 text-xs text-gray-500", children: [
975
+ /* @__PURE__ */ jsxs11("span", { children: [
976
+ thread.messageCount,
977
+ " messages"
978
+ ] }),
979
+ /* @__PURE__ */ jsx13("span", { children: "\u2022" }),
980
+ /* @__PURE__ */ jsx13("span", { children: formatRelativeTime(thread.updatedAt) })
981
+ ] })
982
+ ] }),
983
+ onDelete && /* @__PURE__ */ jsx13(
984
+ "button",
985
+ {
986
+ onClick: (e) => {
987
+ e.stopPropagation();
988
+ onDelete();
989
+ },
990
+ className: "p-2 text-gray-400 hover:text-red-500 hover:bg-red-50 rounded transition-colors",
991
+ title: "Delete thread",
992
+ children: "\u{1F5D1}\uFE0F"
993
+ }
994
+ )
995
+ ]
996
+ }
997
+ );
998
+ }
999
+ function formatRelativeTime(date) {
1000
+ const now = /* @__PURE__ */ new Date();
1001
+ const diff = now.getTime() - date.getTime();
1002
+ const minutes = Math.floor(diff / 6e4);
1003
+ const hours = Math.floor(diff / 36e5);
1004
+ const days = Math.floor(diff / 864e5);
1005
+ if (minutes < 1) return "Just now";
1006
+ if (minutes < 60) return `${minutes}m ago`;
1007
+ if (hours < 24) return `${hours}h ago`;
1008
+ if (days < 7) return `${days}d ago`;
1009
+ return date.toLocaleDateString();
1010
+ }
1011
+
1012
+ // src/components/Threads/ThreadList.tsx
1013
+ import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
1014
+ function ThreadList({
1015
+ threads,
1016
+ currentThreadId,
1017
+ onThreadSelect,
1018
+ onThreadDelete,
1019
+ showSearch = false,
1020
+ groupBy = "none"
1021
+ }) {
1022
+ const [searchQuery, setSearchQuery] = useState6("");
1023
+ const filteredThreads = threads.filter(
1024
+ (thread) => thread.title.toLowerCase().includes(searchQuery.toLowerCase()) || thread.preview?.toLowerCase().includes(searchQuery.toLowerCase())
1025
+ );
1026
+ const groupedThreads = groupBy === "date" ? groupThreadsByDate(filteredThreads) : { All: filteredThreads };
1027
+ return /* @__PURE__ */ jsxs12("div", { className: "flex flex-col h-full", children: [
1028
+ showSearch && /* @__PURE__ */ jsx14("div", { className: "p-3 border-b border-gray-200 dark:border-gray-700", children: /* @__PURE__ */ jsx14(
1029
+ "input",
1030
+ {
1031
+ type: "text",
1032
+ placeholder: "Search conversations...",
1033
+ value: searchQuery,
1034
+ onChange: (e) => setSearchQuery(e.target.value),
1035
+ className: "w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-apteva-500 dark:bg-gray-800 dark:border-gray-600 dark:text-white"
1036
+ }
1037
+ ) }),
1038
+ /* @__PURE__ */ jsxs12("div", { className: "flex-1 overflow-y-auto", children: [
1039
+ Object.entries(groupedThreads).map(([group, groupThreads]) => /* @__PURE__ */ jsxs12("div", { children: [
1040
+ groupBy !== "none" && /* @__PURE__ */ jsx14("div", { className: "px-3 py-2 text-xs font-semibold text-gray-500 uppercase", children: group }),
1041
+ groupThreads.map((thread) => /* @__PURE__ */ jsx14(
1042
+ ThreadItem,
1043
+ {
1044
+ thread,
1045
+ isActive: thread.id === currentThreadId,
1046
+ onSelect: () => onThreadSelect?.(thread.id),
1047
+ onDelete: () => onThreadDelete?.(thread.id)
1048
+ },
1049
+ thread.id
1050
+ ))
1051
+ ] }, group)),
1052
+ filteredThreads.length === 0 && /* @__PURE__ */ jsxs12("div", { className: "p-8 text-center text-gray-500", children: [
1053
+ /* @__PURE__ */ jsx14("div", { className: "text-4xl mb-2", children: "\u{1F4AC}" }),
1054
+ /* @__PURE__ */ jsx14("p", { children: "No conversations found" })
1055
+ ] })
1056
+ ] })
1057
+ ] });
1058
+ }
1059
+ function groupThreadsByDate(threads) {
1060
+ const now = /* @__PURE__ */ new Date();
1061
+ const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
1062
+ const yesterday = new Date(today);
1063
+ yesterday.setDate(yesterday.getDate() - 1);
1064
+ const lastWeek = new Date(today);
1065
+ lastWeek.setDate(lastWeek.getDate() - 7);
1066
+ return threads.reduce(
1067
+ (groups, thread) => {
1068
+ const threadDate = new Date(thread.updatedAt);
1069
+ let group = "Older";
1070
+ if (threadDate >= today) {
1071
+ group = "Today";
1072
+ } else if (threadDate >= yesterday) {
1073
+ group = "Yesterday";
1074
+ } else if (threadDate >= lastWeek) {
1075
+ group = "Last 7 Days";
1076
+ }
1077
+ if (!groups[group]) groups[group] = [];
1078
+ groups[group].push(thread);
1079
+ return groups;
1080
+ },
1081
+ {}
1082
+ );
1083
+ }
1084
+
1085
+ // src/components/Threads/Threads.tsx
1086
+ import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
1087
+ function Threads({
1088
+ threads,
1089
+ currentThreadId,
1090
+ onThreadSelect,
1091
+ onThreadDelete,
1092
+ onNewThread,
1093
+ variant = "sidebar",
1094
+ showSearch = false,
1095
+ showNewButton = true,
1096
+ groupBy = "none",
1097
+ className
1098
+ }) {
1099
+ const variantClasses = {
1100
+ sidebar: "h-full border-r border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900",
1101
+ dropdown: "absolute top-full left-0 right-0 mt-2 bg-white dark:bg-gray-800 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 max-h-96 overflow-hidden",
1102
+ tabs: "flex gap-2 border-b border-gray-200 dark:border-gray-700 overflow-x-auto"
1103
+ };
1104
+ if (variant === "tabs") {
1105
+ return /* @__PURE__ */ jsxs13("div", { className: cn(variantClasses[variant], className), children: [
1106
+ threads.slice(0, 5).map((thread) => /* @__PURE__ */ jsx15(
1107
+ "button",
1108
+ {
1109
+ onClick: () => onThreadSelect?.(thread.id),
1110
+ className: cn(
1111
+ "px-4 py-2 whitespace-nowrap font-medium transition-colors",
1112
+ thread.id === currentThreadId ? "border-b-2 border-apteva-500 text-apteva-500" : "text-gray-600 hover:text-gray-900"
1113
+ ),
1114
+ children: thread.title
1115
+ },
1116
+ thread.id
1117
+ )),
1118
+ showNewButton && onNewThread && /* @__PURE__ */ jsx15(
1119
+ "button",
1120
+ {
1121
+ onClick: onNewThread,
1122
+ className: "px-4 py-2 text-gray-600 hover:text-apteva-500 transition-colors font-medium",
1123
+ children: "+ New"
1124
+ }
1125
+ )
1126
+ ] });
1127
+ }
1128
+ return /* @__PURE__ */ jsxs13("div", { className: cn(variantClasses[variant], "flex flex-col", className), children: [
1129
+ showNewButton && onNewThread && /* @__PURE__ */ jsx15("div", { className: "p-3 border-b border-gray-200 dark:border-gray-700", children: /* @__PURE__ */ jsx15(
1130
+ "button",
1131
+ {
1132
+ onClick: onNewThread,
1133
+ className: "w-full px-4 py-2 bg-apteva-500 text-white rounded-lg hover:bg-apteva-600 transition-colors font-medium",
1134
+ children: "+ New Conversation"
1135
+ }
1136
+ ) }),
1137
+ /* @__PURE__ */ jsx15(
1138
+ ThreadList,
1139
+ {
1140
+ threads,
1141
+ currentThreadId,
1142
+ onThreadSelect,
1143
+ onThreadDelete,
1144
+ showSearch,
1145
+ groupBy
1146
+ }
1147
+ )
1148
+ ] });
1149
+ }
1150
+
1151
+ // src/utils/theme-script.ts
1152
+ var themeScript = `
1153
+ (function() {
1154
+ try {
1155
+ // Get system preference
1156
+ const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
1157
+ const colorMode = isDark ? 'dark' : 'light';
1158
+
1159
+ // Set attributes before render
1160
+ document.documentElement.setAttribute('data-color-mode', colorMode);
1161
+
1162
+ // Add dark class for Tailwind
1163
+ if (isDark) {
1164
+ document.documentElement.classList.add('dark');
1165
+ }
1166
+ } catch (e) {
1167
+ console.error('Failed to initialize theme:', e);
1168
+ }
1169
+ })();
1170
+ `;
1171
+ function getThemeScript() {
1172
+ return themeScript;
1173
+ }
1174
+ export {
1175
+ Button,
1176
+ Card,
1177
+ Chat,
1178
+ Command,
1179
+ List,
1180
+ Prompt,
1181
+ Stream,
1182
+ Threads,
1183
+ Widgets,
1184
+ cn,
1185
+ getThemeScript,
1186
+ mockMessages,
1187
+ mockThreads,
1188
+ mockWidgets
1189
+ };
1190
+ //# sourceMappingURL=index.mjs.map