@hef2024/llmasaservice-ui 0.22.11 → 0.23.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hef2024/llmasaservice-ui",
3
- "version": "0.22.11",
3
+ "version": "0.23.1",
4
4
  "description": "Prebuilt UI components for LLMAsAService.io",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -1956,7 +1956,6 @@ const AIAgentPanel = React.forwardRef<AIAgentPanelHandle, AIAgentPanelProps>(({
1956
1956
  toggleCollapse();
1957
1957
  }
1958
1958
  }}
1959
- title="Click to expand"
1960
1959
  >
1961
1960
  {/* Expand button at top for discoverability */}
1962
1961
  <Tooltip content="Expand Panel" side="left">
@@ -2013,58 +2012,58 @@ const AIAgentPanel = React.forwardRef<AIAgentPanelHandle, AIAgentPanelProps>(({
2013
2012
  const hasActiveConversation = !!activeConvForAgent;
2014
2013
 
2015
2014
  return (
2016
- <Tooltip key={agent.id} content={agent.name} side="left">
2017
- <Button
2018
- variant={agent.id === currentAgentId ? 'secondary' : 'ghost'}
2019
- size="icon"
2020
- onClick={() => {
2021
- // Expand panel in controlled or uncontrolled mode
2022
- if (!isControlled) {
2023
- setUncontrolledIsCollapsed(false);
2015
+ <Button
2016
+ key={agent.id}
2017
+ variant={agent.id === currentAgentId ? 'secondary' : 'ghost'}
2018
+ size="icon"
2019
+ title={agent.name}
2020
+ onClick={() => {
2021
+ // Expand panel in controlled or uncontrolled mode
2022
+ if (!isControlled) {
2023
+ setUncontrolledIsCollapsed(false);
2024
+ }
2025
+ onCollapsedChange?.(false);
2026
+ if (hasActiveConversation && activeConvForAgent) {
2027
+ // Switch to the existing conversation
2028
+ setCurrentConversationId(activeConvForAgent.conversationId);
2029
+ setCurrentAgentId(agent.id);
2030
+ if (onConversationChange) {
2031
+ onConversationChange(activeConvForAgent.conversationId);
2024
2032
  }
2025
- onCollapsedChange?.(false);
2026
- if (hasActiveConversation && activeConvForAgent) {
2027
- // Switch to the existing conversation
2028
- setCurrentConversationId(activeConvForAgent.conversationId);
2029
- setCurrentAgentId(agent.id);
2030
- if (onConversationChange) {
2031
- onConversationChange(activeConvForAgent.conversationId);
2032
- }
2033
- } else {
2034
- // Start a new conversation with this agent
2035
- const tempId = `new-${Date.now()}`;
2036
- setActiveConversations(prev => {
2037
- const next = new Map(prev);
2038
- next.set(tempId, {
2039
- conversationId: tempId,
2040
- stableKey: tempId, // Stable key never changes
2041
- agentId: agent.id,
2042
- history: {},
2043
- isLoading: false,
2044
- title: 'New conversation',
2045
- });
2046
- return next;
2033
+ } else {
2034
+ // Start a new conversation with this agent
2035
+ const tempId = `new-${Date.now()}`;
2036
+ setActiveConversations(prev => {
2037
+ const next = new Map(prev);
2038
+ next.set(tempId, {
2039
+ conversationId: tempId,
2040
+ stableKey: tempId, // Stable key never changes
2041
+ agentId: agent.id,
2042
+ history: {},
2043
+ isLoading: false,
2044
+ title: 'New conversation',
2047
2045
  });
2048
- setCurrentConversationId(tempId);
2049
- setCurrentAgentId(agent.id);
2050
- }
2051
- }}
2052
- className={`ai-agent-panel__agent-icon ${hasActiveConversation ? 'ai-agent-panel__agent-icon--active' : ''}`}
2053
- >
2054
- {agent.avatarUrl ? (
2055
- <img
2056
- src={agent.avatarUrl}
2057
- alt={agent.name}
2058
- className="ai-agent-panel__agent-avatar"
2059
- />
2060
- ) : (
2061
- agent.name.charAt(0).toUpperCase()
2062
- )}
2063
- {hasActiveConversation && (
2064
- <span className="ai-agent-panel__agent-active-indicator" />
2065
- )}
2066
- </Button>
2067
- </Tooltip>
2046
+ return next;
2047
+ });
2048
+ setCurrentConversationId(tempId);
2049
+ setCurrentAgentId(agent.id);
2050
+ }
2051
+ }}
2052
+ className={`ai-agent-panel__agent-icon ${hasActiveConversation ? 'ai-agent-panel__agent-icon--active' : ''}`}
2053
+ >
2054
+ {agent.avatarUrl ? (
2055
+ <img
2056
+ src={agent.avatarUrl}
2057
+ alt={agent.name}
2058
+ className="ai-agent-panel__agent-avatar"
2059
+ />
2060
+ ) : (
2061
+ agent.name.charAt(0).toUpperCase()
2062
+ )}
2063
+ {hasActiveConversation && (
2064
+ <span className="ai-agent-panel__agent-active-indicator" />
2065
+ )}
2066
+ </Button>
2068
2067
  );
2069
2068
  })}
2070
2069
 
@@ -2105,7 +2104,6 @@ const AIAgentPanel = React.forwardRef<AIAgentPanelHandle, AIAgentPanelProps>(({
2105
2104
  toggleHistoryCollapse();
2106
2105
  }
2107
2106
  }}
2108
- title="Click to expand history"
2109
2107
  >
2110
2108
  {/* Expand button at top for discoverability */}
2111
2109
  <Tooltip content="Expand History" side={sidebarPosition === 'left' ? 'right' : 'left'}>
@@ -2140,53 +2138,53 @@ const AIAgentPanel = React.forwardRef<AIAgentPanelHandle, AIAgentPanelProps>(({
2140
2138
  const hasActiveConversation = !!activeConvForAgent;
2141
2139
 
2142
2140
  return (
2143
- <Tooltip key={agent.id} content={agent.name} side={sidebarPosition === 'left' ? 'right' : 'left'}>
2144
- <Button
2145
- variant={agent.id === currentAgentId ? 'secondary' : 'ghost'}
2146
- size="icon"
2147
- onClick={() => {
2148
- if (hasActiveConversation && activeConvForAgent) {
2149
- // Switch to the existing conversation
2150
- setCurrentConversationId(activeConvForAgent.conversationId);
2151
- setCurrentAgentId(agent.id);
2152
- if (onConversationChange) {
2153
- onConversationChange(activeConvForAgent.conversationId);
2154
- }
2155
- } else {
2156
- // Start a new conversation with this agent
2157
- const tempId = `new-${Date.now()}`;
2158
- setActiveConversations(prev => {
2159
- const next = new Map(prev);
2160
- next.set(tempId, {
2161
- conversationId: tempId,
2162
- stableKey: tempId, // Stable key never changes
2163
- agentId: agent.id,
2164
- history: {},
2165
- isLoading: false,
2166
- title: 'New conversation',
2167
- });
2168
- return next;
2169
- });
2170
- setCurrentConversationId(tempId);
2171
- setCurrentAgentId(agent.id);
2141
+ <Button
2142
+ key={agent.id}
2143
+ variant={agent.id === currentAgentId ? 'secondary' : 'ghost'}
2144
+ size="icon"
2145
+ title={agent.name}
2146
+ onClick={() => {
2147
+ if (hasActiveConversation && activeConvForAgent) {
2148
+ // Switch to the existing conversation
2149
+ setCurrentConversationId(activeConvForAgent.conversationId);
2150
+ setCurrentAgentId(agent.id);
2151
+ if (onConversationChange) {
2152
+ onConversationChange(activeConvForAgent.conversationId);
2172
2153
  }
2173
- }}
2174
- className={`ai-agent-panel__agent-icon ${hasActiveConversation ? 'ai-agent-panel__agent-icon--active' : ''}`}
2175
- >
2176
- {agent.avatarUrl ? (
2177
- <img
2178
- src={agent.avatarUrl}
2179
- alt={agent.name}
2180
- className="ai-agent-panel__agent-avatar"
2181
- />
2182
- ) : (
2183
- agent.name.charAt(0).toUpperCase()
2184
- )}
2185
- {hasActiveConversation && (
2186
- <span className="ai-agent-panel__agent-active-indicator" />
2187
- )}
2188
- </Button>
2189
- </Tooltip>
2154
+ } else {
2155
+ // Start a new conversation with this agent
2156
+ const tempId = `new-${Date.now()}`;
2157
+ setActiveConversations(prev => {
2158
+ const next = new Map(prev);
2159
+ next.set(tempId, {
2160
+ conversationId: tempId,
2161
+ stableKey: tempId, // Stable key never changes
2162
+ agentId: agent.id,
2163
+ history: {},
2164
+ isLoading: false,
2165
+ title: 'New conversation',
2166
+ });
2167
+ return next;
2168
+ });
2169
+ setCurrentConversationId(tempId);
2170
+ setCurrentAgentId(agent.id);
2171
+ }
2172
+ }}
2173
+ className={`ai-agent-panel__agent-icon ${hasActiveConversation ? 'ai-agent-panel__agent-icon--active' : ''}`}
2174
+ >
2175
+ {agent.avatarUrl ? (
2176
+ <img
2177
+ src={agent.avatarUrl}
2178
+ alt={agent.name}
2179
+ className="ai-agent-panel__agent-avatar"
2180
+ />
2181
+ ) : (
2182
+ agent.name.charAt(0).toUpperCase()
2183
+ )}
2184
+ {hasActiveConversation && (
2185
+ <span className="ai-agent-panel__agent-active-indicator" />
2186
+ )}
2187
+ </Button>
2190
2188
  );
2191
2189
  })}
2192
2190
 
@@ -2352,4 +2352,369 @@
2352
2352
 
2353
2353
  .dark-theme .ai-chat-email-edit-button:hover {
2354
2354
  background-color: #374151;
2355
+ }
2356
+
2357
+ /* ============================================================================
2358
+ Streaming Thinking Blocks - New Collapsible Design
2359
+ ============================================================================ */
2360
+
2361
+ /* Word Fade-In Animation */
2362
+ .word-fade-in {
2363
+ animation: wordFadeIn 150ms ease-out forwards;
2364
+ }
2365
+
2366
+ @keyframes wordFadeIn {
2367
+ from {
2368
+ opacity: 0;
2369
+ transform: translateY(2px);
2370
+ }
2371
+ to {
2372
+ opacity: 1;
2373
+ transform: translateY(0);
2374
+ }
2375
+ }
2376
+
2377
+ /* Streaming Text Chunk Animation - for text appearing as it streams */
2378
+ .streaming-text-chunk {
2379
+ animation: streamingFadeIn var(--fade-duration, 400ms) ease-out forwards;
2380
+ }
2381
+
2382
+ @keyframes streamingFadeIn {
2383
+ 0% {
2384
+ opacity: 0;
2385
+ background-color: rgba(99, 102, 241, 0.2);
2386
+ border-radius: 2px;
2387
+ }
2388
+ 30% {
2389
+ opacity: 0.8;
2390
+ background-color: rgba(99, 102, 241, 0.15);
2391
+ }
2392
+ 100% {
2393
+ opacity: 1;
2394
+ background-color: transparent;
2395
+ }
2396
+ }
2397
+
2398
+ /* Dark theme streaming highlight */
2399
+ .dark-theme .streaming-text-chunk {
2400
+ animation: streamingFadeInDark var(--fade-duration, 400ms) ease-out forwards;
2401
+ }
2402
+
2403
+ @keyframes streamingFadeInDark {
2404
+ 0% {
2405
+ opacity: 0;
2406
+ background-color: rgba(129, 140, 248, 0.25);
2407
+ border-radius: 2px;
2408
+ }
2409
+ 30% {
2410
+ opacity: 0.8;
2411
+ background-color: rgba(129, 140, 248, 0.15);
2412
+ }
2413
+ 100% {
2414
+ opacity: 1;
2415
+ background-color: transparent;
2416
+ }
2417
+ }
2418
+
2419
+ /* Thinking Block Container */
2420
+ .thinking-block {
2421
+ margin-bottom: 12px;
2422
+ border-radius: 8px;
2423
+ overflow: hidden;
2424
+ background-color: var(--ai-chat-thinking-bg);
2425
+ border: 1px solid var(--ai-chat-thinking-border);
2426
+ transition: all 0.2s ease-out;
2427
+ }
2428
+
2429
+ /* Type-specific themes */
2430
+ .thinking-block--thinking {
2431
+ --thinking-block-accent: #8b5cf6;
2432
+ --thinking-block-bg: #f5f3ff;
2433
+ --thinking-block-text: #5b21b6;
2434
+ background-color: var(--thinking-block-bg);
2435
+ border-color: var(--thinking-block-accent);
2436
+ }
2437
+
2438
+ .thinking-block--reasoning {
2439
+ --thinking-block-accent: #3b82f6;
2440
+ --thinking-block-bg: #eff6ff;
2441
+ --thinking-block-text: #1d4ed8;
2442
+ background-color: var(--thinking-block-bg);
2443
+ border-color: var(--thinking-block-accent);
2444
+ }
2445
+
2446
+ .thinking-block--searching {
2447
+ --thinking-block-accent: #22c55e;
2448
+ --thinking-block-bg: #f0fdf4;
2449
+ --thinking-block-text: #166534;
2450
+ background-color: var(--thinking-block-bg);
2451
+ border-color: var(--thinking-block-accent);
2452
+ }
2453
+
2454
+ /* Dark theme type-specific */
2455
+ .dark-theme .thinking-block--thinking {
2456
+ --thinking-block-bg: #1e1b2e;
2457
+ --thinking-block-accent: #a78bfa;
2458
+ --thinking-block-text: #c4b5fd;
2459
+ }
2460
+
2461
+ .dark-theme .thinking-block--reasoning {
2462
+ --thinking-block-bg: #0c1929;
2463
+ --thinking-block-accent: #60a5fa;
2464
+ --thinking-block-text: #93c5fd;
2465
+ }
2466
+
2467
+ .dark-theme .thinking-block--searching {
2468
+ --thinking-block-bg: #052e16;
2469
+ --thinking-block-accent: #4ade80;
2470
+ --thinking-block-text: #86efac;
2471
+ }
2472
+
2473
+ /* Header (clickable toggle) */
2474
+ .thinking-block__header {
2475
+ display: flex;
2476
+ align-items: center;
2477
+ justify-content: space-between;
2478
+ width: 100%;
2479
+ padding: 10px 12px;
2480
+ background: none;
2481
+ border: none;
2482
+ cursor: pointer;
2483
+ font-family: inherit;
2484
+ text-align: left;
2485
+ transition: background-color 0.15s;
2486
+ }
2487
+
2488
+ .thinking-block__header:hover {
2489
+ background-color: rgba(0, 0, 0, 0.03);
2490
+ }
2491
+
2492
+ .dark-theme .thinking-block__header:hover {
2493
+ background-color: rgba(255, 255, 255, 0.03);
2494
+ }
2495
+
2496
+ .thinking-block__header-left {
2497
+ display: flex;
2498
+ align-items: center;
2499
+ gap: 8px;
2500
+ }
2501
+
2502
+ /* Icon */
2503
+ .thinking-block__icon {
2504
+ width: 16px;
2505
+ height: 16px;
2506
+ color: var(--thinking-block-accent, var(--ai-chat-thinking-icon));
2507
+ flex-shrink: 0;
2508
+ }
2509
+
2510
+ /* Title */
2511
+ .thinking-block__title {
2512
+ font-weight: 600;
2513
+ font-size: 13px;
2514
+ color: var(--thinking-block-text, var(--ai-chat-thinking-text));
2515
+ }
2516
+
2517
+ /* Chevron (collapse indicator) */
2518
+ .thinking-block__chevron {
2519
+ width: 16px;
2520
+ height: 16px;
2521
+ color: var(--thinking-block-text, var(--ai-chat-thinking-text));
2522
+ opacity: 0.6;
2523
+ transition: transform 0.2s ease-out;
2524
+ flex-shrink: 0;
2525
+ }
2526
+
2527
+ .thinking-block__chevron--collapsed {
2528
+ transform: rotate(-90deg);
2529
+ }
2530
+
2531
+ /* Streaming Indicator (three pulsing dots) */
2532
+ .thinking-block__streaming-indicator {
2533
+ display: flex;
2534
+ align-items: center;
2535
+ gap: 3px;
2536
+ margin-left: 4px;
2537
+ }
2538
+
2539
+ .thinking-block__streaming-dot {
2540
+ width: 4px;
2541
+ height: 4px;
2542
+ border-radius: 50%;
2543
+ background-color: var(--thinking-block-accent, var(--ai-chat-thinking-icon));
2544
+ animation: streamingDotPulse 1.4s ease-in-out infinite;
2545
+ }
2546
+
2547
+ .thinking-block__streaming-dot:nth-child(1) {
2548
+ animation-delay: 0s;
2549
+ }
2550
+
2551
+ .thinking-block__streaming-dot:nth-child(2) {
2552
+ animation-delay: 0.2s;
2553
+ }
2554
+
2555
+ .thinking-block__streaming-dot:nth-child(3) {
2556
+ animation-delay: 0.4s;
2557
+ }
2558
+
2559
+ @keyframes streamingDotPulse {
2560
+ 0%, 60%, 100% {
2561
+ opacity: 0.3;
2562
+ transform: scale(0.8);
2563
+ }
2564
+ 30% {
2565
+ opacity: 1;
2566
+ transform: scale(1);
2567
+ }
2568
+ }
2569
+
2570
+ /* Blinking cursor for streaming content */
2571
+ .thinking-block__cursor {
2572
+ display: inline;
2573
+ color: var(--thinking-block-accent, var(--ai-chat-thinking-icon));
2574
+ animation: cursorBlink 0.8s step-end infinite;
2575
+ font-weight: bold;
2576
+ margin-left: 1px;
2577
+ }
2578
+
2579
+ @keyframes cursorBlink {
2580
+ 0%, 100% { opacity: 1; }
2581
+ 50% { opacity: 0; }
2582
+ }
2583
+
2584
+ /* Thinking In Progress Indicator - shown during pauses between blocks */
2585
+ .thinking-in-progress {
2586
+ padding: 12px 16px;
2587
+ margin: 8px 0;
2588
+ background: linear-gradient(135deg,
2589
+ rgba(139, 92, 246, 0.08) 0%,
2590
+ rgba(99, 102, 241, 0.08) 100%
2591
+ );
2592
+ border: 1px solid rgba(139, 92, 246, 0.2);
2593
+ border-radius: 8px;
2594
+ animation: thinkingPulse 2s ease-in-out infinite;
2595
+ }
2596
+
2597
+ .thinking-in-progress__content {
2598
+ display: flex;
2599
+ align-items: center;
2600
+ gap: 8px;
2601
+ }
2602
+
2603
+ .thinking-in-progress__icon {
2604
+ width: 16px;
2605
+ height: 16px;
2606
+ color: var(--ai-chat-thinking-icon, #8b5cf6);
2607
+ animation: iconSpin 2s linear infinite;
2608
+ }
2609
+
2610
+ .thinking-in-progress__text {
2611
+ color: var(--ai-chat-text, #374151);
2612
+ font-size: 14px;
2613
+ font-weight: 500;
2614
+ }
2615
+
2616
+ .thinking-in-progress__dots {
2617
+ display: flex;
2618
+ gap: 3px;
2619
+ margin-left: 2px;
2620
+ }
2621
+
2622
+ .thinking-in-progress__dot {
2623
+ width: 4px;
2624
+ height: 4px;
2625
+ border-radius: 50%;
2626
+ background-color: var(--ai-chat-thinking-icon, #8b5cf6);
2627
+ animation: dotPulse 1.4s ease-in-out infinite;
2628
+ }
2629
+
2630
+ .thinking-in-progress__dot:nth-child(1) { animation-delay: 0s; }
2631
+ .thinking-in-progress__dot:nth-child(2) { animation-delay: 0.2s; }
2632
+ .thinking-in-progress__dot:nth-child(3) { animation-delay: 0.4s; }
2633
+
2634
+ @keyframes thinkingPulse {
2635
+ 0%, 100% {
2636
+ opacity: 1;
2637
+ border-color: rgba(139, 92, 246, 0.2);
2638
+ }
2639
+ 50% {
2640
+ opacity: 0.85;
2641
+ border-color: rgba(139, 92, 246, 0.4);
2642
+ }
2643
+ }
2644
+
2645
+ @keyframes iconSpin {
2646
+ from { transform: rotate(0deg); }
2647
+ to { transform: rotate(360deg); }
2648
+ }
2649
+
2650
+ @keyframes dotPulse {
2651
+ 0%, 60%, 100% {
2652
+ opacity: 0.3;
2653
+ transform: scale(0.8);
2654
+ }
2655
+ 30% {
2656
+ opacity: 1;
2657
+ transform: scale(1.1);
2658
+ }
2659
+ }
2660
+
2661
+ /* Dark theme */
2662
+ .dark-theme .thinking-in-progress {
2663
+ background: linear-gradient(135deg,
2664
+ rgba(139, 92, 246, 0.12) 0%,
2665
+ rgba(99, 102, 241, 0.12) 100%
2666
+ );
2667
+ border-color: rgba(139, 92, 246, 0.3);
2668
+ }
2669
+
2670
+ .dark-theme .thinking-in-progress__text {
2671
+ color: var(--ai-chat-text, #e5e7eb);
2672
+ }
2673
+
2674
+ /* Content Wrapper (for collapse animation) */
2675
+ .thinking-block__content-wrapper {
2676
+ display: grid;
2677
+ grid-template-rows: 1fr;
2678
+ transition: grid-template-rows 0.2s ease-out;
2679
+ }
2680
+
2681
+ .thinking-block--collapsed .thinking-block__content-wrapper {
2682
+ grid-template-rows: 0fr;
2683
+ }
2684
+
2685
+ /* Content */
2686
+ .thinking-block__content {
2687
+ overflow: hidden;
2688
+ padding: 0 12px 12px 12px;
2689
+ font-size: 13px;
2690
+ line-height: 1.6;
2691
+ color: var(--thinking-block-text, var(--ai-chat-thinking-text));
2692
+ white-space: pre-wrap;
2693
+ word-break: break-word;
2694
+ }
2695
+
2696
+ .thinking-block--collapsed .thinking-block__content {
2697
+ padding-top: 0;
2698
+ padding-bottom: 0;
2699
+ }
2700
+
2701
+ /* Streaming state - subtle left border glow */
2702
+ .thinking-block:not(.thinking-block--collapsed) {
2703
+ border-left-width: 3px;
2704
+ }
2705
+
2706
+ /* Animation when block first appears */
2707
+ .thinking-block {
2708
+ animation: thinkingBlockAppear 0.2s ease-out;
2709
+ }
2710
+
2711
+ @keyframes thinkingBlockAppear {
2712
+ from {
2713
+ opacity: 0;
2714
+ transform: translateY(-4px);
2715
+ }
2716
+ to {
2717
+ opacity: 1;
2718
+ transform: translateY(0);
2719
+ }
2355
2720
  }