@hef2024/llmasaservice-ui 0.22.0 → 0.22.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.
- package/dist/index.js +23 -6
- package/dist/index.mjs +23 -6
- package/package.json +1 -1
- package/src/AIChatPanel.tsx +36 -7
package/dist/index.js
CHANGED
|
@@ -3894,6 +3894,7 @@ var AIChatPanel = ({
|
|
|
3894
3894
|
const lastScrollTopRef = (0, import_react12.useRef)(0);
|
|
3895
3895
|
const scrollRAFRef = (0, import_react12.useRef)(null);
|
|
3896
3896
|
const lastScrollTimeRef = (0, import_react12.useRef)(0);
|
|
3897
|
+
const prevResponseLengthRef = (0, import_react12.useRef)(0);
|
|
3897
3898
|
const prevIdleRef = (0, import_react12.useRef)(true);
|
|
3898
3899
|
const hasNotifiedCompletionRef = (0, import_react12.useRef)(true);
|
|
3899
3900
|
const latestHistoryRef = (0, import_react12.useRef)(initialHistory);
|
|
@@ -4334,11 +4335,22 @@ var AIChatPanel = ({
|
|
|
4334
4335
|
thumbsDownClick(callId);
|
|
4335
4336
|
}
|
|
4336
4337
|
}), [thumbsDownClick, interactionClicked]);
|
|
4337
|
-
const scrollToBottom = (0, import_react12.useCallback)(() => {
|
|
4338
|
+
const scrollToBottom = (0, import_react12.useCallback)((force = false) => {
|
|
4338
4339
|
var _a2;
|
|
4339
4340
|
if (scrollRAFRef.current) {
|
|
4340
4341
|
cancelAnimationFrame(scrollRAFRef.current);
|
|
4341
4342
|
}
|
|
4343
|
+
if (!force && responseAreaRef.current) {
|
|
4344
|
+
const scrollViewport = responseAreaRef.current.querySelector("[data-radix-scroll-area-viewport]");
|
|
4345
|
+
const scrollElement = scrollViewport || responseAreaRef.current;
|
|
4346
|
+
const scrollTop = scrollElement.scrollTop;
|
|
4347
|
+
const scrollHeight = scrollElement.scrollHeight;
|
|
4348
|
+
const clientHeight = scrollElement.clientHeight;
|
|
4349
|
+
const isNearBottom = scrollHeight - scrollTop - clientHeight < 100;
|
|
4350
|
+
if (!isNearBottom) {
|
|
4351
|
+
return;
|
|
4352
|
+
}
|
|
4353
|
+
}
|
|
4342
4354
|
const now = Date.now();
|
|
4343
4355
|
if (now - lastScrollTimeRef.current < 100) {
|
|
4344
4356
|
scrollRAFRef.current = requestAnimationFrame(() => {
|
|
@@ -4357,6 +4369,7 @@ var AIChatPanel = ({
|
|
|
4357
4369
|
setCurrentThinkingIndex(0);
|
|
4358
4370
|
setError(null);
|
|
4359
4371
|
setUserHasScrolled(false);
|
|
4372
|
+
prevResponseLengthRef.current = 0;
|
|
4360
4373
|
setResponse("");
|
|
4361
4374
|
if (!idle) {
|
|
4362
4375
|
stop(lastController);
|
|
@@ -4382,7 +4395,7 @@ var AIChatPanel = ({
|
|
|
4382
4395
|
setLastPrompt(promptToSend.trim());
|
|
4383
4396
|
setLastKey(promptKey);
|
|
4384
4397
|
setTimeout(() => {
|
|
4385
|
-
scrollToBottom();
|
|
4398
|
+
scrollToBottom(true);
|
|
4386
4399
|
}, 0);
|
|
4387
4400
|
console.log("AIChatPanel.continueChat - about to call ensureConversation");
|
|
4388
4401
|
ensureConversation().then((convId) => {
|
|
@@ -4557,12 +4570,16 @@ var AIChatPanel = ({
|
|
|
4557
4570
|
}
|
|
4558
4571
|
if (!isNowIdle && hasNotifiedCompletionRef.current) {
|
|
4559
4572
|
hasNotifiedCompletionRef.current = false;
|
|
4573
|
+
prevResponseLengthRef.current = 0;
|
|
4560
4574
|
}
|
|
4561
4575
|
}, [idle]);
|
|
4562
4576
|
(0, import_react12.useEffect)(() => {
|
|
4577
|
+
const currentResponseLength = response.length;
|
|
4578
|
+
const responseGotLonger = currentResponseLength > prevResponseLengthRef.current;
|
|
4579
|
+
prevResponseLengthRef.current = currentResponseLength;
|
|
4563
4580
|
const shouldAutoScroll = scrollToEnd || !userHasScrolled;
|
|
4564
|
-
if (!idle && shouldAutoScroll && response) {
|
|
4565
|
-
scrollToBottom();
|
|
4581
|
+
if (!idle && shouldAutoScroll && response && responseGotLonger) {
|
|
4582
|
+
scrollToBottom(false);
|
|
4566
4583
|
}
|
|
4567
4584
|
}, [response, scrollToBottom, idle, userHasScrolled, scrollToEnd]);
|
|
4568
4585
|
const idleRef = (0, import_react12.useRef)(idle);
|
|
@@ -4722,7 +4739,7 @@ var AIChatPanel = ({
|
|
|
4722
4739
|
const AgentSuggestionCard = import_react12.default.memo(({ agentId, agentName, reason }) => {
|
|
4723
4740
|
(0, import_react12.useEffect)(() => {
|
|
4724
4741
|
const timer = setTimeout(() => {
|
|
4725
|
-
scrollToBottom();
|
|
4742
|
+
scrollToBottom(true);
|
|
4726
4743
|
}, 100);
|
|
4727
4744
|
return () => clearTimeout(timer);
|
|
4728
4745
|
}, []);
|
|
@@ -4769,7 +4786,7 @@ var AIChatPanel = ({
|
|
|
4769
4786
|
onClick: () => {
|
|
4770
4787
|
onAgentChange(agentId);
|
|
4771
4788
|
setTimeout(() => {
|
|
4772
|
-
scrollToBottom();
|
|
4789
|
+
scrollToBottom(true);
|
|
4773
4790
|
}, 100);
|
|
4774
4791
|
}
|
|
4775
4792
|
},
|
package/dist/index.mjs
CHANGED
|
@@ -3861,6 +3861,7 @@ var AIChatPanel = ({
|
|
|
3861
3861
|
const lastScrollTopRef = useRef5(0);
|
|
3862
3862
|
const scrollRAFRef = useRef5(null);
|
|
3863
3863
|
const lastScrollTimeRef = useRef5(0);
|
|
3864
|
+
const prevResponseLengthRef = useRef5(0);
|
|
3864
3865
|
const prevIdleRef = useRef5(true);
|
|
3865
3866
|
const hasNotifiedCompletionRef = useRef5(true);
|
|
3866
3867
|
const latestHistoryRef = useRef5(initialHistory);
|
|
@@ -4301,11 +4302,22 @@ var AIChatPanel = ({
|
|
|
4301
4302
|
thumbsDownClick(callId);
|
|
4302
4303
|
}
|
|
4303
4304
|
}), [thumbsDownClick, interactionClicked]);
|
|
4304
|
-
const scrollToBottom = useCallback2(() => {
|
|
4305
|
+
const scrollToBottom = useCallback2((force = false) => {
|
|
4305
4306
|
var _a2;
|
|
4306
4307
|
if (scrollRAFRef.current) {
|
|
4307
4308
|
cancelAnimationFrame(scrollRAFRef.current);
|
|
4308
4309
|
}
|
|
4310
|
+
if (!force && responseAreaRef.current) {
|
|
4311
|
+
const scrollViewport = responseAreaRef.current.querySelector("[data-radix-scroll-area-viewport]");
|
|
4312
|
+
const scrollElement = scrollViewport || responseAreaRef.current;
|
|
4313
|
+
const scrollTop = scrollElement.scrollTop;
|
|
4314
|
+
const scrollHeight = scrollElement.scrollHeight;
|
|
4315
|
+
const clientHeight = scrollElement.clientHeight;
|
|
4316
|
+
const isNearBottom = scrollHeight - scrollTop - clientHeight < 100;
|
|
4317
|
+
if (!isNearBottom) {
|
|
4318
|
+
return;
|
|
4319
|
+
}
|
|
4320
|
+
}
|
|
4309
4321
|
const now = Date.now();
|
|
4310
4322
|
if (now - lastScrollTimeRef.current < 100) {
|
|
4311
4323
|
scrollRAFRef.current = requestAnimationFrame(() => {
|
|
@@ -4324,6 +4336,7 @@ var AIChatPanel = ({
|
|
|
4324
4336
|
setCurrentThinkingIndex(0);
|
|
4325
4337
|
setError(null);
|
|
4326
4338
|
setUserHasScrolled(false);
|
|
4339
|
+
prevResponseLengthRef.current = 0;
|
|
4327
4340
|
setResponse("");
|
|
4328
4341
|
if (!idle) {
|
|
4329
4342
|
stop(lastController);
|
|
@@ -4349,7 +4362,7 @@ var AIChatPanel = ({
|
|
|
4349
4362
|
setLastPrompt(promptToSend.trim());
|
|
4350
4363
|
setLastKey(promptKey);
|
|
4351
4364
|
setTimeout(() => {
|
|
4352
|
-
scrollToBottom();
|
|
4365
|
+
scrollToBottom(true);
|
|
4353
4366
|
}, 0);
|
|
4354
4367
|
console.log("AIChatPanel.continueChat - about to call ensureConversation");
|
|
4355
4368
|
ensureConversation().then((convId) => {
|
|
@@ -4524,12 +4537,16 @@ var AIChatPanel = ({
|
|
|
4524
4537
|
}
|
|
4525
4538
|
if (!isNowIdle && hasNotifiedCompletionRef.current) {
|
|
4526
4539
|
hasNotifiedCompletionRef.current = false;
|
|
4540
|
+
prevResponseLengthRef.current = 0;
|
|
4527
4541
|
}
|
|
4528
4542
|
}, [idle]);
|
|
4529
4543
|
useEffect7(() => {
|
|
4544
|
+
const currentResponseLength = response.length;
|
|
4545
|
+
const responseGotLonger = currentResponseLength > prevResponseLengthRef.current;
|
|
4546
|
+
prevResponseLengthRef.current = currentResponseLength;
|
|
4530
4547
|
const shouldAutoScroll = scrollToEnd || !userHasScrolled;
|
|
4531
|
-
if (!idle && shouldAutoScroll && response) {
|
|
4532
|
-
scrollToBottom();
|
|
4548
|
+
if (!idle && shouldAutoScroll && response && responseGotLonger) {
|
|
4549
|
+
scrollToBottom(false);
|
|
4533
4550
|
}
|
|
4534
4551
|
}, [response, scrollToBottom, idle, userHasScrolled, scrollToEnd]);
|
|
4535
4552
|
const idleRef = useRef5(idle);
|
|
@@ -4689,7 +4706,7 @@ var AIChatPanel = ({
|
|
|
4689
4706
|
const AgentSuggestionCard = React12.memo(({ agentId, agentName, reason }) => {
|
|
4690
4707
|
useEffect7(() => {
|
|
4691
4708
|
const timer = setTimeout(() => {
|
|
4692
|
-
scrollToBottom();
|
|
4709
|
+
scrollToBottom(true);
|
|
4693
4710
|
}, 100);
|
|
4694
4711
|
return () => clearTimeout(timer);
|
|
4695
4712
|
}, []);
|
|
@@ -4736,7 +4753,7 @@ var AIChatPanel = ({
|
|
|
4736
4753
|
onClick: () => {
|
|
4737
4754
|
onAgentChange(agentId);
|
|
4738
4755
|
setTimeout(() => {
|
|
4739
|
-
scrollToBottom();
|
|
4756
|
+
scrollToBottom(true);
|
|
4740
4757
|
}, 100);
|
|
4741
4758
|
}
|
|
4742
4759
|
},
|
package/package.json
CHANGED
package/src/AIChatPanel.tsx
CHANGED
|
@@ -846,6 +846,7 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
|
|
|
846
846
|
const lastScrollTopRef = useRef<number>(0);
|
|
847
847
|
const scrollRAFRef = useRef<number | null>(null);
|
|
848
848
|
const lastScrollTimeRef = useRef<number>(0);
|
|
849
|
+
const prevResponseLengthRef = useRef<number>(0);
|
|
849
850
|
|
|
850
851
|
// === NEW: Clean history management refs ===
|
|
851
852
|
// Track previous idle state to detect transitions (false→true = completion)
|
|
@@ -1470,12 +1471,28 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
|
|
|
1470
1471
|
}, [thumbsDownClick, interactionClicked]);
|
|
1471
1472
|
|
|
1472
1473
|
// Scroll to bottom - throttled using RAF to prevent layout thrashing
|
|
1473
|
-
const scrollToBottom = useCallback(() => {
|
|
1474
|
+
const scrollToBottom = useCallback((force: boolean = false) => {
|
|
1474
1475
|
// Cancel any pending scroll
|
|
1475
1476
|
if (scrollRAFRef.current) {
|
|
1476
1477
|
cancelAnimationFrame(scrollRAFRef.current);
|
|
1477
1478
|
}
|
|
1478
1479
|
|
|
1480
|
+
// Check if we should scroll - only if user is near bottom or force is true
|
|
1481
|
+
if (!force && responseAreaRef.current) {
|
|
1482
|
+
const scrollViewport = responseAreaRef.current.querySelector('[data-radix-scroll-area-viewport]') as HTMLElement;
|
|
1483
|
+
const scrollElement = scrollViewport || responseAreaRef.current;
|
|
1484
|
+
|
|
1485
|
+
const scrollTop = scrollElement.scrollTop;
|
|
1486
|
+
const scrollHeight = scrollElement.scrollHeight;
|
|
1487
|
+
const clientHeight = scrollElement.clientHeight;
|
|
1488
|
+
const isNearBottom = scrollHeight - scrollTop - clientHeight < 100;
|
|
1489
|
+
|
|
1490
|
+
// If user is not near bottom, don't scroll (prevents scroll on layout changes like toast)
|
|
1491
|
+
if (!isNearBottom) {
|
|
1492
|
+
return;
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1479
1496
|
// Throttle to max once per 100ms to prevent performance issues during streaming
|
|
1480
1497
|
const now = Date.now();
|
|
1481
1498
|
if (now - lastScrollTimeRef.current < 100) {
|
|
@@ -1505,6 +1522,7 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
|
|
|
1505
1522
|
|
|
1506
1523
|
// Reset scroll tracking for new message - enable auto-scroll
|
|
1507
1524
|
setUserHasScrolled(false);
|
|
1525
|
+
prevResponseLengthRef.current = 0;
|
|
1508
1526
|
|
|
1509
1527
|
// IMPORTANT: Clear the response BEFORE setting new lastKey
|
|
1510
1528
|
// This prevents the old response from being written to the new history entry
|
|
@@ -1551,8 +1569,9 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
|
|
|
1551
1569
|
|
|
1552
1570
|
// Scroll to bottom immediately to show the new prompt
|
|
1553
1571
|
// Use setTimeout to ensure the DOM has updated
|
|
1572
|
+
// Force scroll since this is a user-initiated action
|
|
1554
1573
|
setTimeout(() => {
|
|
1555
|
-
scrollToBottom();
|
|
1574
|
+
scrollToBottom(true);
|
|
1556
1575
|
}, 0);
|
|
1557
1576
|
|
|
1558
1577
|
// Now proceed with API calls in the background (conversation creation + LLM call)
|
|
@@ -1797,18 +1816,26 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
|
|
|
1797
1816
|
// Reset notification flag when starting a new stream
|
|
1798
1817
|
if (!isNowIdle && hasNotifiedCompletionRef.current) {
|
|
1799
1818
|
hasNotifiedCompletionRef.current = false;
|
|
1819
|
+
// Reset response length tracking for new stream
|
|
1820
|
+
prevResponseLengthRef.current = 0;
|
|
1800
1821
|
}
|
|
1801
1822
|
}, [idle]); // ONLY depends on idle - no history, no callbacks in deps
|
|
1802
|
-
|
|
1823
|
+
|
|
1803
1824
|
// Auto-scroll to bottom - only while streaming and user hasn't manually scrolled
|
|
1804
1825
|
useEffect(() => {
|
|
1805
1826
|
// Only auto-scroll if:
|
|
1806
1827
|
// 1. We're actively streaming (!idle)
|
|
1807
1828
|
// 2. User hasn't manually scrolled up during this response (or scrollToEnd prop is true)
|
|
1808
1829
|
// 3. We have content to show (response exists)
|
|
1830
|
+
// 4. The response actually got longer (not just a re-render from layout change)
|
|
1831
|
+
const currentResponseLength = response.length;
|
|
1832
|
+
const responseGotLonger = currentResponseLength > prevResponseLengthRef.current;
|
|
1833
|
+
prevResponseLengthRef.current = currentResponseLength;
|
|
1834
|
+
|
|
1809
1835
|
const shouldAutoScroll = scrollToEnd || !userHasScrolled;
|
|
1810
|
-
if (!idle && shouldAutoScroll && response) {
|
|
1811
|
-
|
|
1836
|
+
if (!idle && shouldAutoScroll && response && responseGotLonger) {
|
|
1837
|
+
// Use non-forced scroll - will only scroll if near bottom
|
|
1838
|
+
scrollToBottom(false);
|
|
1812
1839
|
}
|
|
1813
1840
|
}, [response, scrollToBottom, idle, userHasScrolled, scrollToEnd]); // Removed history dependency
|
|
1814
1841
|
|
|
@@ -2037,8 +2064,9 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
|
|
|
2037
2064
|
// Auto-scroll when the agent suggestion card appears
|
|
2038
2065
|
useEffect(() => {
|
|
2039
2066
|
// Small delay to ensure the card is fully rendered in the DOM
|
|
2067
|
+
// Force scroll since this is new content being added
|
|
2040
2068
|
const timer = setTimeout(() => {
|
|
2041
|
-
scrollToBottom();
|
|
2069
|
+
scrollToBottom(true);
|
|
2042
2070
|
}, 100);
|
|
2043
2071
|
return () => clearTimeout(timer);
|
|
2044
2072
|
}, []); // Empty deps - only run on mount
|
|
@@ -2158,8 +2186,9 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
|
|
|
2158
2186
|
onClick={() => {
|
|
2159
2187
|
onAgentChange(agentId);
|
|
2160
2188
|
// Scroll to bottom after a brief delay to let React re-render
|
|
2189
|
+
// Force scroll since this is a user-initiated action
|
|
2161
2190
|
setTimeout(() => {
|
|
2162
|
-
scrollToBottom();
|
|
2191
|
+
scrollToBottom(true);
|
|
2163
2192
|
}, 100);
|
|
2164
2193
|
}}
|
|
2165
2194
|
>
|