flowdit-chatbot-library 1.0.0 → 1.0.2

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.
@@ -24,8 +24,32 @@ export const FullScreenChat = () => {
24
24
  // =========================================
25
25
  // State Definitions
26
26
  // =========================================
27
- // Stores the list of chat messages (user and assistant)
28
- const [messages, setMessages] = useState([]);
27
+ // -- Session states --
28
+ const [sessions, setSessions] = useState([
29
+ { id: uuidv4(), title: 'New Chat', messages: [], createdAt: Date.now() }
30
+ ]);
31
+ const [activeSessionId, setActiveSessionId] = useState(sessions[0].id);
32
+ const [isSidebarOpen, setIsSidebarOpen] = useState(true);
33
+ // Sync messages with active session
34
+ const activeSession = sessions.find(s => s.id === activeSessionId) || sessions[0];
35
+ const messages = activeSession?.messages || [];
36
+ const setMessages = (updateFn) => {
37
+ setSessions(prev => prev.map(s => {
38
+ if (s.id === activeSessionId) {
39
+ const newMessages = typeof updateFn === 'function' ? updateFn(s.messages) : updateFn;
40
+ // Auto-generate title if it's the first user message
41
+ let newTitle = s.title;
42
+ if (s.title === 'New Chat' && newMessages.length > 0) {
43
+ const firstUserMsg = newMessages.find(m => m.role === 'user');
44
+ if (firstUserMsg) {
45
+ newTitle = firstUserMsg.content.slice(0, 30) + (firstUserMsg.content.length > 30 ? '...' : '');
46
+ }
47
+ }
48
+ return { ...s, messages: newMessages, title: newTitle };
49
+ }
50
+ return s;
51
+ }));
52
+ };
29
53
  // Current value of the input textarea
30
54
  const [input, setInput] = useState("");
31
55
  // Flag indicating if a response is currently being streamed from the API
@@ -53,8 +77,8 @@ export const FullScreenChat = () => {
53
77
  const animationFrameRef = useRef(null);
54
78
  // Timestamp of the last character added for animation timing control
55
79
  const lastCharTimeRef = useRef(0);
56
- // Unique ID for the current conversation session
57
- const conversationIdRef = useRef(uuidv4());
80
+ // Unique ID for the current conversation session (synced with activeSessionId)
81
+ const conversationIdRef = useRef(activeSessionId);
58
82
  // Reference to the textarea element for auto-resizing
59
83
  const textareaRef = useRef(null);
60
84
  // Tracks the previous animation ID to detect message switches
@@ -71,6 +95,13 @@ export const FullScreenChat = () => {
71
95
  // =========================================
72
96
  // Effects
73
97
  // =========================================
98
+ /**
99
+ * Effect: Sync conversationIdRef with activeSessionId.
100
+ */
101
+ useEffect(() => {
102
+ conversationIdRef.current = activeSessionId;
103
+ console.log("Active session changed, synced conversationIdRef:", activeSessionId);
104
+ }, [activeSessionId]);
74
105
  /**
75
106
  * Effect: Handle clicks outside of dropdowns to close them.
76
107
  */
@@ -346,61 +377,154 @@ export const FullScreenChat = () => {
346
377
  setStreamingComplete
347
378
  });
348
379
  };
349
- return (React.createElement("div", { className: "chat-gpt-interface" },
350
- React.createElement("div", { className: "chat-scroll-area", ref: chatContainerRef, onScroll: handleScroll },
351
- messages.length === 0 ? (React.createElement("div", { className: "empty-state-container" },
352
- React.createElement("div", { className: "empty-state-content" },
353
- React.createElement("div", { className: "logo-placeholder" },
354
- React.createElement("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5" },
355
- React.createElement("path", { d: "M12 2a10 10 0 1 0 10 10A10 10 0 0 0 12 2zm0 18a8 8 0 1 1 8-8 8 8 0 0 1-8 8z" }),
356
- React.createElement("path", { d: "M12 6v6l4 2" }))),
357
- React.createElement("h2", null, "How can I help you today?"),
358
- React.createElement("div", { className: "capabilities-grid" },
359
- React.createElement("div", { className: "capability-card" }, "Generate a checklist for a project"),
360
- React.createElement("div", { className: "capability-card" }, "Analyze this data set"),
361
- React.createElement("div", { className: "capability-card" }, "Translate text to Spanish"))))) : (messages.map((m) => {
362
- const isUser = m.role === "user";
363
- return (React.createElement("div", { key: m.id, className: `message-row ${m.role}` },
364
- React.createElement("div", { className: "message-content-container" },
365
- React.createElement("div", { className: `avatar ${isUser ? 'user-avatar' : 'assistant-avatar'}` }, isUser ? (React.createElement("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" },
380
+ /**
381
+ * Retries the last failed message generation.
382
+ * Finds the last user message and re-sends it after removing the failed assistant message.
383
+ */
384
+ const handleRetry = () => {
385
+ // 1. Find the last user message
386
+ const userMessages = messages.filter(m => m.role === 'user');
387
+ if (userMessages.length === 0)
388
+ return;
389
+ const lastUserMessage = userMessages[userMessages.length - 1];
390
+ // 2. Remove the failed assistant message AND the last user message
391
+ // (handleSend will re-add the user message, so this prevents duplication)
392
+ setMessages(prev => {
393
+ const reversedIdx = [...prev].reverse().findIndex(m => m.id === lastUserMessage.id);
394
+ if (reversedIdx === -1)
395
+ return prev.filter(m => !m.hasError);
396
+ const actualIdx = prev.length - 1 - reversedIdx;
397
+ return prev.filter((m, idx) => !m.hasError && idx !== actualIdx);
398
+ });
399
+ // 3. Clear any animation state
400
+ setAnimatingMessageId(null);
401
+ setDisplayedChars("");
402
+ charBufferRef.current = "";
403
+ // 4. Re-send
404
+ handleSend(lastUserMessage.content);
405
+ };
406
+ const createNewChat = () => {
407
+ const newId = uuidv4();
408
+ setSessions(prev => [
409
+ { id: newId, title: 'New Chat', messages: [], createdAt: Date.now() },
410
+ ...prev
411
+ ]);
412
+ setActiveSessionId(newId);
413
+ charBufferRef.current = "";
414
+ setDisplayedChars("");
415
+ setStreamingComplete(false);
416
+ setAnimatingMessageId(null);
417
+ setUserScrolledUp(false);
418
+ conversationIdRef.current = newId;
419
+ };
420
+ const deleteSession = (id, e) => {
421
+ e.stopPropagation();
422
+ if (sessions.length === 1) {
423
+ const newId = uuidv4();
424
+ setSessions([{ id: newId, title: 'New Chat', messages: [], createdAt: Date.now() }]);
425
+ setActiveSessionId(newId);
426
+ }
427
+ else {
428
+ const newSessions = sessions.filter(s => s.id !== id);
429
+ setSessions(newSessions);
430
+ if (activeSessionId === id) {
431
+ setActiveSessionId(newSessions[0].id);
432
+ }
433
+ }
434
+ };
435
+ return (React.createElement("div", { className: `chat-gpt-interface ${isSidebarOpen ? 'sidebar-open' : 'sidebar-closed'}` },
436
+ isSidebarOpen && React.createElement("div", { className: "sidebar-overlay", onClick: () => setIsSidebarOpen(false) }),
437
+ React.createElement("aside", { className: `chat-sidebar ${isSidebarOpen ? 'open' : ''}` },
438
+ React.createElement("div", { className: "sidebar-header" },
439
+ React.createElement("button", { className: "new-chat-sidebar-btn", onClick: createNewChat },
440
+ React.createElement("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" },
441
+ React.createElement("path", { d: "M12 5v14M5 12h14" })),
442
+ React.createElement("span", null, "New Chat")),
443
+ React.createElement("button", { className: "sidebar-toggle-mobile", onClick: () => setIsSidebarOpen(false) },
444
+ React.createElement("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2" },
445
+ React.createElement("path", { d: "M18 6L6 18M6 6l12 12" })))),
446
+ React.createElement("div", { className: "sidebar-history" },
447
+ React.createElement("div", { className: "history-label" }, "Recent Chats"),
448
+ sessions.map(s => (React.createElement("div", { key: s.id, className: `history-item ${s.id === activeSessionId ? 'active' : ''}`, onClick: () => {
449
+ setActiveSessionId(s.id);
450
+ if (window.innerWidth < 768)
451
+ setIsSidebarOpen(false);
452
+ } },
453
+ React.createElement("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "item-icon" },
454
+ React.createElement("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" })),
455
+ React.createElement("span", { className: "item-title" }, s.title),
456
+ React.createElement("button", { className: "delete-btn", onClick: (e) => deleteSession(s.id, e) },
457
+ React.createElement("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2" },
458
+ React.createElement("path", { d: "M3 6h18M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2" }))))))),
459
+ React.createElement("div", { className: "sidebar-footer" },
460
+ React.createElement("div", { className: "user-profile" },
461
+ React.createElement("div", { className: "user-avatar-small" },
462
+ React.createElement("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2" },
366
463
  React.createElement("path", { d: "M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" }),
367
- React.createElement("circle", { cx: "12", cy: "7", r: "4" }))) : (React.createElement("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" },
368
- React.createElement("rect", { x: "3", y: "11", width: "18", height: "10", rx: "2" }),
369
- React.createElement("circle", { cx: "12", cy: "5", r: "2" }),
370
- React.createElement("path", { d: "M12 7v4" }),
371
- React.createElement("line", { x1: "8", y1: "16", x2: "8", y2: "16" }),
372
- React.createElement("line", { x1: "16", y1: "16", x2: "16", y2: "16" })))),
373
- React.createElement("div", { className: "text-content" }, isUser ? (React.createElement("p", { style: { whiteSpace: 'pre-wrap' } }, m.content)) : (React.createElement(React.Fragment, null,
374
- !m.content && !m.status && (React.createElement("div", { className: "typing-indicator", style: {
375
- display: 'flex',
376
- gap: '4px',
377
- padding: '8px 0'
378
- } },
379
- React.createElement("span", { className: "dot", style: {
380
- width: '8px',
381
- height: '8px',
382
- backgroundColor: '#94a3b8',
383
- borderRadius: '50%',
384
- animation: 'typingDot 1.4s infinite ease-in-out',
385
- animationDelay: '0s'
386
- } }),
387
- React.createElement("span", { className: "dot", style: {
388
- width: '8px',
389
- height: '8px',
390
- backgroundColor: '#94a3b8',
391
- borderRadius: '50%',
392
- animation: 'typingDot 1.4s infinite ease-in-out',
393
- animationDelay: '0.2s'
394
- } }),
395
- React.createElement("span", { className: "dot", style: {
396
- width: '8px',
397
- height: '8px',
398
- backgroundColor: '#94a3b8',
399
- borderRadius: '50%',
400
- animation: 'typingDot 1.4s infinite ease-in-out',
401
- animationDelay: '0.4s'
402
- } }),
403
- React.createElement("style", null, `
464
+ React.createElement("circle", { cx: "12", cy: "7", r: "4" }))),
465
+ React.createElement("span", { className: "user-name" }, "Ibaa Ibrahim")))),
466
+ React.createElement("main", { className: "chat-main" },
467
+ React.createElement("header", { className: "chat-header" },
468
+ React.createElement("button", { className: "sidebar-toggle-btn", onClick: () => setIsSidebarOpen(!isSidebarOpen) },
469
+ React.createElement("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" },
470
+ React.createElement("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
471
+ React.createElement("line", { x1: "9", y1: "3", x2: "9", y2: "21" }))),
472
+ React.createElement("div", { className: "header-title" }, activeSession.title),
473
+ React.createElement("div", { className: "header-actions" })),
474
+ React.createElement("div", { className: "chat-scroll-area", ref: chatContainerRef, onScroll: handleScroll },
475
+ messages.length === 0 ? (React.createElement("div", { className: "empty-state-container" },
476
+ React.createElement("div", { className: "empty-state-content" },
477
+ React.createElement("div", { className: "logo-placeholder" },
478
+ React.createElement("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5" },
479
+ React.createElement("path", { d: "M12 2a10 10 0 1 0 10 10A10 10 0 0 0 12 2zm0 18a8 8 0 1 1 8-8 8 8 0 0 1-8 8z" }),
480
+ React.createElement("path", { d: "M12 6v6l4 2" }))),
481
+ React.createElement("h2", null, "How can I help you today?"),
482
+ React.createElement("div", { className: "capabilities-grid" },
483
+ React.createElement("div", { className: "capability-card" }, "Generate a checklist for a project"),
484
+ React.createElement("div", { className: "capability-card" }, "Analyze this data set"),
485
+ React.createElement("div", { className: "capability-card" }, "Translate text to Spanish"))))) : (messages.map((m) => {
486
+ const isUser = m.role === "user";
487
+ return (React.createElement("div", { key: m.id, className: `message-row ${m.role}` },
488
+ React.createElement("div", { className: "message-content-container" },
489
+ React.createElement("div", { className: `avatar ${isUser ? 'user-avatar' : 'assistant-avatar'}` }, isUser ? (React.createElement("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" },
490
+ React.createElement("path", { d: "M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" }),
491
+ React.createElement("circle", { cx: "12", cy: "7", r: "4" }))) : (React.createElement("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" },
492
+ React.createElement("rect", { x: "3", y: "11", width: "18", height: "10", rx: "2" }),
493
+ React.createElement("circle", { cx: "12", cy: "5", r: "2" }),
494
+ React.createElement("path", { d: "M12 7v4" }),
495
+ React.createElement("line", { x1: "8", y1: "16", x2: "8", y2: "16" }),
496
+ React.createElement("line", { x1: "16", y1: "16", x2: "16", y2: "16" })))),
497
+ React.createElement("div", { className: "text-content" }, isUser ? (React.createElement("p", { style: { whiteSpace: 'pre-wrap' } }, m.content)) : (React.createElement(React.Fragment, null,
498
+ !m.content && !m.status && !m.hasError && (React.createElement("div", { className: "typing-indicator", style: {
499
+ display: 'flex',
500
+ gap: '4px',
501
+ padding: '8px 0'
502
+ } },
503
+ React.createElement("span", { className: "dot", style: {
504
+ width: '8px',
505
+ height: '8px',
506
+ backgroundColor: '#94a3b8',
507
+ borderRadius: '50%',
508
+ animation: 'typingDot 1.4s infinite ease-in-out',
509
+ animationDelay: '0s'
510
+ } }),
511
+ React.createElement("span", { className: "dot", style: {
512
+ width: '8px',
513
+ height: '8px',
514
+ backgroundColor: '#94a3b8',
515
+ borderRadius: '50%',
516
+ animation: 'typingDot 1.4s infinite ease-in-out',
517
+ animationDelay: '0.2s'
518
+ } }),
519
+ React.createElement("span", { className: "dot", style: {
520
+ width: '8px',
521
+ height: '8px',
522
+ backgroundColor: '#94a3b8',
523
+ borderRadius: '50%',
524
+ animation: 'typingDot 1.4s infinite ease-in-out',
525
+ animationDelay: '0.4s'
526
+ } }),
527
+ React.createElement("style", null, `
404
528
  @keyframes typingDot {
405
529
  0%, 60%, 100% {
406
530
  transform: translateY(0);
@@ -412,158 +536,179 @@ export const FullScreenChat = () => {
412
536
  }
413
537
  }
414
538
  `))),
415
- React.createElement(ReactMarkdown, null, m.content),
416
- m.role === 'assistant' && (() => {
417
- console.log(`🔍 Button visibility for message ${m.id}:`, {
418
- hasToolCalls: !!m.toolCalls,
419
- toolCallsLength: m.toolCalls?.length || 0,
420
- toolCalls: m.toolCalls,
421
- animationComplete: m.animationComplete,
422
- shouldShow: !!(m.toolCalls && m.toolCalls.length > 0 && m.animationComplete)
423
- });
424
- return null;
425
- })(),
426
- m.toolCalls && m.toolCalls.length > 0 && m.animationComplete && (React.createElement("div", { className: "tool-actions", style: { marginTop: '12px', display: 'flex', gap: '8px', flexWrap: 'wrap' } }, m.toolCalls.map((tool, idx) => (React.createElement("button", { key: idx, onClick: () => {
427
- const handler = TOOL_HANDLERS[tool.tool];
428
- if (handler && tool.data)
429
- handler(tool.data);
430
- }, style: {
431
- background: 'linear-gradient(135deg, #6366f1 0%, #4f46e5 100%)',
432
- border: 'none',
433
- padding: '8px 16px',
434
- borderRadius: '8px',
435
- color: 'white',
436
- fontSize: '0.85rem',
437
- fontWeight: 500,
438
- cursor: 'pointer',
439
- display: 'flex',
440
- alignItems: 'center',
441
- gap: '6px',
442
- boxShadow: '0 4px 6px -1px rgba(99, 102, 241, 0.3)',
443
- transition: 'transform 0.2s, box-shadow 0.2s'
444
- }, onMouseOver: (e) => { e.currentTarget.style.transform = 'translateY(-1px)'; }, onMouseOut: (e) => { e.currentTarget.style.transform = 'translateY(0)'; } },
445
- React.createElement("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" },
446
- React.createElement("path", { d: "M22 11.08V12a10 10 0 1 1-5.93-9.14" }),
447
- React.createElement("polyline", { points: "22 4 12 14.01 9 11.01" })),
448
- "View ",
449
- tool.tool === 'generate_checklist' ? 'Checklist' : 'Result'))))),
450
- m.status && (React.createElement("div", { className: "agent-status-indicator", style: {
451
- marginTop: '8px',
452
- fontSize: '0.8rem',
453
- color: '#64748b',
454
- display: 'flex',
455
- alignItems: 'center',
456
- gap: '6px',
457
- fontStyle: 'italic'
458
- } },
459
- React.createElement("span", { className: "pulsing-dot", style: {
460
- width: '6px',
461
- height: '6px',
462
- backgroundColor: '#6366f1',
463
- borderRadius: '50%',
464
- display: 'inline-block',
465
- animation: 'pulse 1.5s infinite'
466
- } }),
467
- m.status,
468
- React.createElement("style", null, `
539
+ m.hasError && (React.createElement("div", { className: "error-message-container", style: {
540
+ display: 'flex',
541
+ flexDirection: 'column',
542
+ gap: '12px',
543
+ padding: '12px',
544
+ background: 'rgba(239, 68, 68, 0.1)',
545
+ border: '1px solid rgba(239, 68, 68, 0.2)',
546
+ borderRadius: '12px',
547
+ marginTop: '8px'
548
+ } },
549
+ React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: '8px', color: '#ef4444', fontSize: '0.9rem' } },
550
+ React.createElement("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" },
551
+ React.createElement("circle", { cx: "12", cy: "12", r: "10" }),
552
+ React.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
553
+ React.createElement("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })),
554
+ React.createElement("span", null, "Failed to get a response. Please try again.")),
555
+ React.createElement("button", { onClick: () => handleRetry(), style: {
556
+ alignSelf: 'flex-start',
557
+ background: '#ef4444',
558
+ color: 'white',
559
+ border: 'none',
560
+ padding: '6px 14px',
561
+ borderRadius: '6px',
562
+ fontSize: '0.85rem',
563
+ fontWeight: 500,
564
+ cursor: 'pointer',
565
+ display: 'flex',
566
+ alignItems: 'center',
567
+ gap: '6px',
568
+ transition: 'background 0.2s'
569
+ }, onMouseOver: (e) => { e.currentTarget.style.background = '#dc2626'; }, onMouseOut: (e) => { e.currentTarget.style.background = '#ef4444'; } },
570
+ React.createElement("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" },
571
+ React.createElement("path", { d: "M21 2v6h-6" }),
572
+ React.createElement("path", { d: "M3 12a9 9 0 0 1 15-6.7L21 8M3 12a9 9 0 0 0 15 6.7L21 16" }),
573
+ React.createElement("path", { d: "M3 22v-6h6" })),
574
+ "Retry"))),
575
+ React.createElement(ReactMarkdown, null, m.content),
576
+ m.role === 'assistant' && (() => {
577
+ console.log(`🔍 Button visibility for message ${m.id}:`, {
578
+ hasToolCalls: !!m.toolCalls,
579
+ toolCallsLength: m.toolCalls?.length || 0,
580
+ toolCalls: m.toolCalls,
581
+ animationComplete: m.animationComplete,
582
+ shouldShow: !!(m.toolCalls && m.toolCalls.length > 0 && m.animationComplete)
583
+ });
584
+ return null;
585
+ })(),
586
+ m.toolCalls && m.toolCalls.length > 0 && m.animationComplete && (React.createElement("div", { className: "tool-actions", style: { marginTop: '12px', display: 'flex', gap: '8px', flexWrap: 'wrap' } }, m.toolCalls.map((tool, idx) => (React.createElement("button", { key: idx, onClick: () => {
587
+ const handler = TOOL_HANDLERS[tool.tool];
588
+ if (handler && tool.data)
589
+ handler(tool.data);
590
+ }, style: {
591
+ background: 'linear-gradient(135deg, #6366f1 0%, #4f46e5 100%)',
592
+ border: 'none',
593
+ padding: '8px 16px',
594
+ borderRadius: '8px',
595
+ color: 'white',
596
+ fontSize: '0.85rem',
597
+ fontWeight: 500,
598
+ cursor: 'pointer',
599
+ display: 'flex',
600
+ alignItems: 'center',
601
+ gap: '6px',
602
+ boxShadow: '0 4px 6px -1px rgba(99, 102, 241, 0.3)',
603
+ transition: 'transform 0.2s, box-shadow 0.2s'
604
+ }, onMouseOver: (e) => { e.currentTarget.style.transform = 'translateY(-1px)'; }, onMouseOut: (e) => { e.currentTarget.style.transform = 'translateY(0)'; } },
605
+ React.createElement("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round" },
606
+ React.createElement("path", { d: "M20 6L9 17l-5-5" })),
607
+ "View ",
608
+ tool.tool === 'generate_checklist' ? 'Checklist' : 'Result'))))),
609
+ m.status && (React.createElement("div", { className: "agent-status-indicator", style: {
610
+ marginTop: '8px',
611
+ fontSize: '0.8rem',
612
+ color: '#64748b',
613
+ display: 'flex',
614
+ alignItems: 'center',
615
+ gap: '6px',
616
+ fontStyle: 'italic'
617
+ } },
618
+ React.createElement("span", { className: "pulsing-dot", style: {
619
+ width: '6px',
620
+ height: '6px',
621
+ backgroundColor: '#6366f1',
622
+ borderRadius: '50%',
623
+ display: 'inline-block',
624
+ animation: 'pulse 1.5s infinite'
625
+ } }),
626
+ m.status,
627
+ React.createElement("style", null, `
469
628
  @keyframes pulse {
470
629
  0% { transform: scale(0.95); opacity: 0.7; }
471
630
  50% { transform: scale(1.15); opacity: 1; }
472
631
  100% { transform: scale(0.95); opacity: 0.7; }
473
632
  }
474
633
  `)))))))));
475
- })),
476
- React.createElement("div", { ref: scrollEndRef })),
477
- React.createElement("div", { className: "input-area-container" },
478
- userScrolledUp && messages.length > 0 && (React.createElement("button", { className: "scroll-bottom-btn", onClick: handleScrollToBottom },
479
- React.createElement("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" },
480
- React.createElement("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
481
- React.createElement("polyline", { points: "19 12 12 19 5 12" })))),
482
- messages.length > 0 && (React.createElement("div", { className: "new-chat-floater" },
483
- React.createElement("button", { className: "new-chat-btn", onClick: () => {
484
- setMessages([]);
485
- charBufferRef.current = "";
486
- setDisplayedChars("");
487
- setStreamingComplete(false);
488
- setAnimatingMessageId(null);
489
- setUserScrolledUp(false);
490
- conversationIdRef.current = uuidv4();
491
- }, title: "Start new chat" },
492
- React.createElement("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" },
493
- React.createElement("path", { d: "M12 5v14M5 12h14" })),
494
- React.createElement("span", null, "New Chat")))),
495
- React.createElement("div", { className: "input-wrapper" },
496
- React.createElement("div", { className: "input-box user-specific-design" },
497
- React.createElement("div", { className: "input-top-row" },
498
- React.createElement("textarea", { ref: textareaRef, rows: 1, placeholder: "Ask anything (Ctrl+L), @ to mention, / for workflows", value: input, onChange: (e) => setInput(e.target.value), disabled: isStreaming || animatingMessageId !== null, onKeyDown: (e) => {
499
- if (e.key === "Enter" && !e.shiftKey && !isStreaming && !animatingMessageId) {
500
- e.preventDefault();
501
- handleSend(input);
502
- }
503
- } })),
504
- React.createElement("div", { className: "input-bottom-row" },
505
- React.createElement("div", { className: "left-controls" },
506
- React.createElement("div", { className: "tools-section" },
507
- React.createElement("div", { className: `tools-menu custom-dropdown-menu ${activeDropdown === 'tools' ? 'show' : ''}` },
508
- React.createElement("div", { className: "tool-option", onClick: () => setActiveDropdown(null) },
509
- React.createElement("span", { className: "icon-box purple" },
510
- React.createElement("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2" },
511
- React.createElement("path", { d: "M9 11l3 3L22 4" }),
512
- React.createElement("path", { d: "M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11" }))),
513
- React.createElement("div", { className: "text" },
514
- React.createElement("span", { className: "title" }, "Checklist"))),
515
- React.createElement("div", { className: "tool-option", onClick: () => setActiveDropdown(null) },
516
- React.createElement("span", { className: "icon-box blue" },
517
- React.createElement("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2" },
518
- React.createElement("circle", { cx: "12", cy: "12", r: "10" }),
519
- React.createElement("line", { x1: "2", y1: "12", x2: "22", y2: "12" }),
520
- React.createElement("path", { d: "M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" }))),
521
- React.createElement("div", { className: "text" },
522
- React.createElement("span", { className: "title" }, "Translate"))),
523
- React.createElement("div", { className: "tool-option", onClick: () => setActiveDropdown(null) },
524
- React.createElement("div", { className: "text", style: { paddingLeft: '4px', fontSize: '11px', color: '#666' } }, "More coming soon..."))),
525
- React.createElement("button", { className: `control-btn plus-btn dropdown-trigger ${activeDropdown === 'tools' ? 'active' : ''}`, onClick: () => setActiveDropdown(activeDropdown === 'tools' ? null : 'tools'), title: "Add attachment / Tools" },
526
- React.createElement("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" },
527
- React.createElement("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
528
- React.createElement("line", { x1: "5", y1: "12", x2: "19", y2: "12" })))),
529
- React.createElement("div", { className: "tools-section" },
530
- React.createElement("div", { className: `tools-menu custom-dropdown-menu ${activeDropdown === 'mode' ? 'show' : ''}`, style: { width: '120px' } },
531
- React.createElement("div", { className: "tool-option", onClick: () => setActiveDropdown(null) },
532
- React.createElement("div", { className: "text" },
533
- React.createElement("span", { className: "title" }, "Fast"))),
534
- React.createElement("div", { className: "tool-option", onClick: () => setActiveDropdown(null) },
535
- React.createElement("div", { className: "text" },
536
- React.createElement("span", { className: "title" }, "Balanced")))),
537
- React.createElement("button", { className: `mode-pill-btn dropdown-trigger ${activeDropdown === 'mode' ? 'active-mode' : ''}`, onClick: () => setActiveDropdown(activeDropdown === 'mode' ? null : 'mode') },
538
- React.createElement("span", { className: "chevron" },
539
- React.createElement("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" },
540
- React.createElement("polyline", { points: "18 15 12 9 6 15" }))),
541
- React.createElement("span", null, "Fast"))),
542
- React.createElement("div", { className: "tools-section" },
543
- React.createElement("div", { className: `tools-menu custom-dropdown-menu ${activeDropdown === 'model' ? 'show' : ''}`, style: { width: '200px' } },
544
- React.createElement("div", { className: "tool-option", onClick: () => setActiveDropdown(null) },
545
- React.createElement("div", { className: "text" },
546
- React.createElement("span", { className: "title" }, "GPT 4o-mini"))),
547
- React.createElement("div", { className: "tool-option", onClick: () => setActiveDropdown(null) },
548
- React.createElement("div", { className: "text" },
549
- React.createElement("span", { className: "title" }, "GPT 4o"))),
550
- React.createElement("div", { className: "tool-option", onClick: () => setActiveDropdown(null) },
551
- React.createElement("div", { className: "text" },
552
- React.createElement("span", { className: "title" }, "Gemini Pro 1.5")))),
553
- React.createElement("button", { className: `mode-pill-btn active-mode dropdown-trigger ${activeDropdown === 'model' ? 'active-mode' : ''}`, onClick: () => setActiveDropdown(activeDropdown === 'model' ? null : 'model') },
554
- React.createElement("span", { className: "chevron" },
555
- React.createElement("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" },
556
- React.createElement("polyline", { points: "18 15 12 9 6 15" }))),
557
- React.createElement("span", null, "GPT 4o-mini (High)")))),
558
- React.createElement("div", { className: "right-controls" },
559
- React.createElement("button", { className: `send-btn-circle ${input.trim() || isStreaming || animatingMessageId ? 'active' : ''}`, onClick: (isStreaming || animatingMessageId) ? handleStop : () => handleSend(input), disabled: (!input.trim() && !isStreaming && !animatingMessageId) }, (isStreaming || animatingMessageId) ? (
560
- // Stop Square
561
- React.createElement("svg", { viewBox: "0 0 24 24", fill: "currentColor" },
562
- React.createElement("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }))) : (
563
- // Right Arrow
564
- React.createElement("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" },
565
- React.createElement("line", { x1: "5", y1: "12", x2: "19", y2: "12" }),
566
- React.createElement("polyline", { points: "12 5 19 12 12 19" })))))))),
567
- React.createElement("div", { className: "footer-text" }, "Allowed to generate up to 2000 tokens per request."))));
634
+ })),
635
+ React.createElement("div", { ref: scrollEndRef })),
636
+ React.createElement("div", { className: "input-area-container" },
637
+ userScrolledUp && messages.length > 0 && (React.createElement("button", { className: "scroll-bottom-btn", onClick: handleScrollToBottom },
638
+ React.createElement("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" },
639
+ React.createElement("polyline", { points: "7 13 12 18 17 13" }),
640
+ React.createElement("polyline", { points: "7 6 12 11 17 6" })))),
641
+ React.createElement("div", { className: "input-wrapper" },
642
+ React.createElement("div", { className: "input-box user-specific-design" },
643
+ React.createElement("div", { className: "input-top-row" },
644
+ React.createElement("textarea", { ref: textareaRef, rows: 1, placeholder: "Ask anything (Ctrl+L), @ to mention, / for workflows", value: input, onChange: (e) => setInput(e.target.value), disabled: isStreaming || animatingMessageId !== null, onKeyDown: (e) => {
645
+ if (e.key === "Enter" && !e.shiftKey && !isStreaming && !animatingMessageId) {
646
+ e.preventDefault();
647
+ handleSend(input);
648
+ }
649
+ } })),
650
+ React.createElement("div", { className: "input-bottom-row" },
651
+ React.createElement("div", { className: "left-controls" },
652
+ React.createElement("div", { className: "tools-section" },
653
+ React.createElement("div", { className: `tools-menu custom-dropdown-menu ${activeDropdown === 'tools' ? 'show' : ''}` },
654
+ React.createElement("div", { className: "tool-option", onClick: () => setActiveDropdown(null) },
655
+ React.createElement("span", { className: "icon-box purple" },
656
+ React.createElement("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" },
657
+ React.createElement("path", { d: "M9 11l3 3L22 4" }),
658
+ React.createElement("path", { d: "M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11" }))),
659
+ React.createElement("div", { className: "text" },
660
+ React.createElement("span", { className: "title" }, "Checklist"))),
661
+ React.createElement("div", { className: "tool-option", onClick: () => setActiveDropdown(null) },
662
+ React.createElement("span", { className: "icon-box blue" },
663
+ React.createElement("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" },
664
+ React.createElement("circle", { cx: "12", cy: "12", r: "10" }),
665
+ React.createElement("line", { x1: "2", y1: "12", x2: "22", y2: "12" }),
666
+ React.createElement("path", { d: "M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" }))),
667
+ React.createElement("div", { className: "text" },
668
+ React.createElement("span", { className: "title" }, "Translate"))),
669
+ React.createElement("div", { className: "tool-option", onClick: () => setActiveDropdown(null) },
670
+ React.createElement("div", { className: "text", style: { paddingLeft: '4px', fontSize: '11px', color: '#666' } }, "More coming soon..."))),
671
+ React.createElement("button", { className: `control-btn plus-btn dropdown-trigger ${activeDropdown === 'tools' ? 'active' : ''}`, onClick: () => setActiveDropdown(activeDropdown === 'tools' ? null : 'tools'), title: "Add attachment / Tools" },
672
+ React.createElement("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" },
673
+ React.createElement("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
674
+ React.createElement("line", { x1: "5", y1: "12", x2: "19", y2: "12" })))),
675
+ React.createElement("div", { className: "tools-section" },
676
+ React.createElement("div", { className: `tools-menu custom-dropdown-menu ${activeDropdown === 'mode' ? 'show' : ''}`, style: { width: '120px' } },
677
+ React.createElement("div", { className: "tool-option", onClick: () => setActiveDropdown(null) },
678
+ React.createElement("div", { className: "text" },
679
+ React.createElement("span", { className: "title" }, "Fast"))),
680
+ React.createElement("div", { className: "tool-option", onClick: () => setActiveDropdown(null) },
681
+ React.createElement("div", { className: "text" },
682
+ React.createElement("span", { className: "title" }, "Balanced")))),
683
+ React.createElement("button", { className: `mode-pill-btn dropdown-trigger ${activeDropdown === 'mode' ? 'active-mode' : ''}`, onClick: () => setActiveDropdown(activeDropdown === 'mode' ? null : 'mode') },
684
+ React.createElement("span", { className: "chevron" },
685
+ React.createElement("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" },
686
+ React.createElement("polyline", { points: "18 15 12 9 6 15" }))),
687
+ React.createElement("span", null, "Fast"))),
688
+ React.createElement("div", { className: "tools-section" },
689
+ React.createElement("div", { className: `tools-menu custom-dropdown-menu ${activeDropdown === 'model' ? 'show' : ''}`, style: { width: '200px' } },
690
+ React.createElement("div", { className: "tool-option", onClick: () => setActiveDropdown(null) },
691
+ React.createElement("div", { className: "text" },
692
+ React.createElement("span", { className: "title" }, "GPT 4o-mini"))),
693
+ React.createElement("div", { className: "tool-option", onClick: () => setActiveDropdown(null) },
694
+ React.createElement("div", { className: "text" },
695
+ React.createElement("span", { className: "title" }, "GPT 4o"))),
696
+ React.createElement("div", { className: "tool-option", onClick: () => setActiveDropdown(null) },
697
+ React.createElement("div", { className: "text" },
698
+ React.createElement("span", { className: "title" }, "Gemini Pro 1.5")))),
699
+ React.createElement("button", { className: `mode-pill-btn active-mode dropdown-trigger ${activeDropdown === 'model' ? 'active-mode' : ''}`, onClick: () => setActiveDropdown(activeDropdown === 'model' ? null : 'model') },
700
+ React.createElement("span", { className: "chevron" },
701
+ React.createElement("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" },
702
+ React.createElement("polyline", { points: "18 15 12 9 6 15" }))),
703
+ React.createElement("span", null, "GPT 4o-mini (High)")))),
704
+ React.createElement("div", { className: "right-controls" },
705
+ React.createElement("button", { className: `send-btn-circle ${input.trim() || isStreaming || animatingMessageId ? 'active' : ''}`, onClick: (isStreaming || animatingMessageId) ? handleStop : () => handleSend(input), disabled: (!input.trim() && !isStreaming && !animatingMessageId) }, (isStreaming || animatingMessageId) ? (
706
+ // Stop Square
707
+ React.createElement("svg", { viewBox: "0 0 24 24", fill: "currentColor" },
708
+ React.createElement("rect", { x: "7", y: "7", width: "10", height: "10", rx: "1.5" }))) : (
709
+ // Up Arrow (ChatGPT style)
710
+ React.createElement("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round" },
711
+ React.createElement("path", { d: "M12 19V5M5 12l7-7 7 7" })))))))),
712
+ React.createElement("div", { className: "footer-text" }, "Token budget and context are managed automatically.")))));
568
713
  };
569
714
  //# sourceMappingURL=index.js.map