@agents24/chat-react 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -1
- package/dist/index.cjs +79 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -2
- package/dist/index.d.ts +15 -2
- package/dist/index.js +78 -16
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -405,6 +405,7 @@ type FetchChatTransportOptions = {
|
|
|
405
405
|
};
|
|
406
406
|
declare const createFetchChatTransport: ({ routes, fetchImpl, headers, streamBody, }: FetchChatTransportOptions) => ChatTransport;
|
|
407
407
|
|
|
408
|
+
type LatestFollowState = "following" | "detached";
|
|
408
409
|
declare const isScrollable: (element: Pick<HTMLDivElement, "scrollHeight" | "clientHeight">) => boolean;
|
|
409
410
|
declare const isAtTimelineLatestEdge: (element: Pick<HTMLDivElement, "scrollHeight" | "clientHeight" | "scrollTop">, isTopOrigin: boolean) => boolean;
|
|
410
411
|
declare const shouldPrefetchOlder: (element: Pick<HTMLDivElement, "scrollHeight" | "clientHeight" | "scrollTop">) => boolean;
|
|
@@ -414,6 +415,11 @@ declare const shouldUseTopOriginTimeline: ({ hasOlder, itemCount, topOriginMaxIt
|
|
|
414
415
|
itemCount: number;
|
|
415
416
|
topOriginMaxItems?: number;
|
|
416
417
|
}) => boolean;
|
|
418
|
+
declare const nextLatestFollowStateOnScroll: ({ atLatest, current, isProgrammatic, }: {
|
|
419
|
+
atLatest: boolean;
|
|
420
|
+
current: LatestFollowState;
|
|
421
|
+
isProgrammatic: boolean;
|
|
422
|
+
}) => LatestFollowState;
|
|
417
423
|
type UseLatestThreadViewportOptions = {
|
|
418
424
|
itemCount: number;
|
|
419
425
|
hasOlder: boolean;
|
|
@@ -426,15 +432,22 @@ type UseLatestThreadViewportOptions = {
|
|
|
426
432
|
type LatestThreadViewportState = {
|
|
427
433
|
scrollContainerRef: RefObject<HTMLDivElement | null>;
|
|
428
434
|
isAtLatest: boolean;
|
|
435
|
+
isFollowingLatest: boolean;
|
|
429
436
|
isTopOrigin: boolean;
|
|
430
437
|
shouldShowLatestButton: boolean;
|
|
431
438
|
handleScroll: (event: UIEvent<HTMLDivElement>) => void;
|
|
432
|
-
|
|
439
|
+
handleUserScrollIntent: () => void;
|
|
440
|
+
scrollToLatest: (options?: {
|
|
441
|
+
reattach?: boolean;
|
|
442
|
+
}) => void;
|
|
443
|
+
detachFromLatest: () => void;
|
|
444
|
+
reattachToLatest: () => void;
|
|
433
445
|
preserveIntrinsicResize: () => void;
|
|
434
446
|
};
|
|
435
447
|
declare function useLatestThreadViewport({ itemCount, hasOlder, isLoadingOlder, onLoadOlder, activeStreamKey, shouldAutoFollow, topOriginMaxItems, }: UseLatestThreadViewportOptions): LatestThreadViewportState;
|
|
436
448
|
type LatestThreadViewportRenderContext = {
|
|
437
449
|
preserveIntrinsicResize: () => void;
|
|
450
|
+
isFollowingLatest: boolean;
|
|
438
451
|
isTopOrigin: boolean;
|
|
439
452
|
};
|
|
440
453
|
type LatestThreadViewportProps<T> = {
|
|
@@ -450,4 +463,4 @@ type LatestThreadViewportProps<T> = {
|
|
|
450
463
|
};
|
|
451
464
|
declare function LatestThreadViewport<T>({ items, hasOlder, isLoadingOlder, onLoadOlder, activeStreamKey, className, latestSpacer, trailingSpacer, renderItem, }: LatestThreadViewportProps<T>): react.JSX.Element;
|
|
452
465
|
|
|
453
|
-
export { type Agents24ChatRenderOptions, type ChatActiveRun, type ChatApprovalPart, type ChatAttachment, type ChatCitation, type ChatContextWindow, type ChatController, type ChatDataPart, type ChatErrorPart, type ChatMessage, type ChatPart, type ChatReasoningPart, type ChatReasoningStep, type ChatRunStatus, type ChatRuntimeEvent, type ChatStorageAdapter, type ChatStreamResult, type ChatTextPart, type ChatThreadDetail, type ChatThreadSummary, type ChatThreadTurn, type ChatToolPart, type ChatToolState, type ChatTransport, type ChatUiBlocksPart, DEFAULT_THREAD_PAGE_SIZE, DefaultChatPart, DefaultToolPart, type FetchChatTransportOptions, type FetchChatTransportRoutes, LatestThreadViewport, type LatestThreadViewportProps, type LatestThreadViewportRenderContext, type LatestThreadViewportState, type StoredChatThread, type StreamingTextCache, type StreamingTextMode, type ToolPresentation, type ToolRenderer, type UseAgents24ChatControllerOptions, type UseLatestThreadViewportOptions, type UseStreamingTextOptions, type UseStreamingTextResult, activeRunIdFromThread, activeRunIdFromThreadDetail, assistantTextFromParts, assistantTextFromResponseBlocks, consumeSseResponse, createChatId, createFetchChatTransport, getActiveStreamingTextPartId, getLatestScrollTop, hasStaleUnfinishedAssistantCache, hasUnfinishedAssistantMessage, isActiveStreamingTextPart, isAtTimelineLatestEdge, isRunningThreadStatus, isScrollable, latestContextWindowFromThread, mergeReasoningSteps, parseSseBlock, partsFromResponseBlocks, reasoningStepsFromParts, renderChatPart, shouldPrefetchOlder, shouldUseTopOriginTimeline, textFromFinalOutput, threadActivityDate, threadDetailToMessages, threadPaging, titleFromMessage, toolStateFromStatus, useAgents24ChatController, useLatestThreadViewport, useStreamingText };
|
|
466
|
+
export { type Agents24ChatRenderOptions, type ChatActiveRun, type ChatApprovalPart, type ChatAttachment, type ChatCitation, type ChatContextWindow, type ChatController, type ChatDataPart, type ChatErrorPart, type ChatMessage, type ChatPart, type ChatReasoningPart, type ChatReasoningStep, type ChatRunStatus, type ChatRuntimeEvent, type ChatStorageAdapter, type ChatStreamResult, type ChatTextPart, type ChatThreadDetail, type ChatThreadSummary, type ChatThreadTurn, type ChatToolPart, type ChatToolState, type ChatTransport, type ChatUiBlocksPart, DEFAULT_THREAD_PAGE_SIZE, DefaultChatPart, DefaultToolPart, type FetchChatTransportOptions, type FetchChatTransportRoutes, type LatestFollowState, LatestThreadViewport, type LatestThreadViewportProps, type LatestThreadViewportRenderContext, type LatestThreadViewportState, type StoredChatThread, type StreamingTextCache, type StreamingTextMode, type ToolPresentation, type ToolRenderer, type UseAgents24ChatControllerOptions, type UseLatestThreadViewportOptions, type UseStreamingTextOptions, type UseStreamingTextResult, activeRunIdFromThread, activeRunIdFromThreadDetail, assistantTextFromParts, assistantTextFromResponseBlocks, consumeSseResponse, createChatId, createFetchChatTransport, getActiveStreamingTextPartId, getLatestScrollTop, hasStaleUnfinishedAssistantCache, hasUnfinishedAssistantMessage, isActiveStreamingTextPart, isAtTimelineLatestEdge, isRunningThreadStatus, isScrollable, latestContextWindowFromThread, mergeReasoningSteps, nextLatestFollowStateOnScroll, parseSseBlock, partsFromResponseBlocks, reasoningStepsFromParts, renderChatPart, shouldPrefetchOlder, shouldUseTopOriginTimeline, textFromFinalOutput, threadActivityDate, threadDetailToMessages, threadPaging, titleFromMessage, toolStateFromStatus, useAgents24ChatController, useLatestThreadViewport, useStreamingText };
|
package/dist/index.js
CHANGED
|
@@ -1274,6 +1274,14 @@ var shouldUseTopOriginTimeline = ({
|
|
|
1274
1274
|
itemCount,
|
|
1275
1275
|
topOriginMaxItems = 4
|
|
1276
1276
|
}) => !hasOlder && itemCount > 0 && itemCount <= topOriginMaxItems;
|
|
1277
|
+
var nextLatestFollowStateOnScroll = ({
|
|
1278
|
+
atLatest,
|
|
1279
|
+
current,
|
|
1280
|
+
isProgrammatic
|
|
1281
|
+
}) => {
|
|
1282
|
+
if (isProgrammatic) return current;
|
|
1283
|
+
return atLatest ? "following" : "detached";
|
|
1284
|
+
};
|
|
1277
1285
|
function useLatestThreadViewport({
|
|
1278
1286
|
itemCount,
|
|
1279
1287
|
hasOlder,
|
|
@@ -1287,12 +1295,19 @@ function useLatestThreadViewport({
|
|
|
1287
1295
|
const olderPagePreserveRef = useRef3(null);
|
|
1288
1296
|
const olderPageRequestInFlightRef = useRef3(false);
|
|
1289
1297
|
const intrinsicResizePreserveRef = useRef3(null);
|
|
1290
|
-
const
|
|
1298
|
+
const followStateRef = useRef3("following");
|
|
1291
1299
|
const programmaticScrollRef = useRef3(false);
|
|
1292
1300
|
const programmaticScrollTimeoutRef = useRef3(null);
|
|
1293
1301
|
const activeStreamKeyRef = useRef3(null);
|
|
1302
|
+
const observedScrollHeightRef = useRef3(null);
|
|
1294
1303
|
const [isAtLatest, setIsAtLatest] = useState3(true);
|
|
1304
|
+
const [followState, setFollowState] = useState3("following");
|
|
1295
1305
|
const isTopOrigin = shouldUseTopOriginTimeline({ hasOlder, itemCount, topOriginMaxItems });
|
|
1306
|
+
const setLatestFollowState = useCallback2((next) => {
|
|
1307
|
+
if (followStateRef.current === next) return;
|
|
1308
|
+
followStateRef.current = next;
|
|
1309
|
+
setFollowState(next);
|
|
1310
|
+
}, []);
|
|
1296
1311
|
const markProgrammaticScroll = useCallback2(() => {
|
|
1297
1312
|
programmaticScrollRef.current = true;
|
|
1298
1313
|
if (programmaticScrollTimeoutRef.current) clearTimeout(programmaticScrollTimeoutRef.current);
|
|
@@ -1301,13 +1316,26 @@ function useLatestThreadViewport({
|
|
|
1301
1316
|
programmaticScrollTimeoutRef.current = null;
|
|
1302
1317
|
}, 80);
|
|
1303
1318
|
}, []);
|
|
1304
|
-
const scrollToLatest = useCallback2(() => {
|
|
1319
|
+
const scrollToLatest = useCallback2((options) => {
|
|
1305
1320
|
const element = scrollContainerRef.current;
|
|
1306
1321
|
if (!element) return;
|
|
1322
|
+
if (options?.reattach !== false) setLatestFollowState("following");
|
|
1307
1323
|
markProgrammaticScroll();
|
|
1308
1324
|
element.scrollTop = getLatestScrollTop(element, isTopOrigin);
|
|
1309
1325
|
setIsAtLatest(true);
|
|
1310
|
-
|
|
1326
|
+
observedScrollHeightRef.current = element.scrollHeight;
|
|
1327
|
+
}, [isTopOrigin, markProgrammaticScroll, setLatestFollowState]);
|
|
1328
|
+
const detachFromLatest = useCallback2(() => {
|
|
1329
|
+
setLatestFollowState("detached");
|
|
1330
|
+
}, [setLatestFollowState]);
|
|
1331
|
+
const reattachToLatest = useCallback2(() => {
|
|
1332
|
+
scrollToLatest({ reattach: true });
|
|
1333
|
+
}, [scrollToLatest]);
|
|
1334
|
+
const handleUserScrollIntent = useCallback2(() => {
|
|
1335
|
+
const element = scrollContainerRef.current;
|
|
1336
|
+
if (!activeStreamKey || !element) return;
|
|
1337
|
+
if (!isAtTimelineLatestEdge(element, isTopOrigin)) detachFromLatest();
|
|
1338
|
+
}, [activeStreamKey, detachFromLatest, isTopOrigin]);
|
|
1311
1339
|
useEffect3(() => {
|
|
1312
1340
|
return () => {
|
|
1313
1341
|
if (programmaticScrollTimeoutRef.current) clearTimeout(programmaticScrollTimeoutRef.current);
|
|
@@ -1319,6 +1347,7 @@ function useLatestThreadViewport({
|
|
|
1319
1347
|
const element = scrollContainerRef.current;
|
|
1320
1348
|
const preserve = olderPagePreserveRef.current;
|
|
1321
1349
|
if (!element) return;
|
|
1350
|
+
observedScrollHeightRef.current = element.scrollHeight;
|
|
1322
1351
|
if (!preserve) {
|
|
1323
1352
|
setIsAtLatest(isAtTimelineLatestEdge(element, isTopOrigin));
|
|
1324
1353
|
return;
|
|
@@ -1335,7 +1364,13 @@ function useLatestThreadViewport({
|
|
|
1335
1364
|
const element = event.currentTarget;
|
|
1336
1365
|
const atLatest = isAtTimelineLatestEdge(element, isTopOrigin);
|
|
1337
1366
|
setIsAtLatest(atLatest);
|
|
1338
|
-
|
|
1367
|
+
setLatestFollowState(
|
|
1368
|
+
nextLatestFollowStateOnScroll({
|
|
1369
|
+
atLatest,
|
|
1370
|
+
current: followStateRef.current,
|
|
1371
|
+
isProgrammatic: programmaticScrollRef.current
|
|
1372
|
+
})
|
|
1373
|
+
);
|
|
1339
1374
|
if (isTopOrigin || !hasOlder || isLoadingOlder || olderPageRequestInFlightRef.current || !shouldPrefetchOlder(element)) {
|
|
1340
1375
|
return;
|
|
1341
1376
|
}
|
|
@@ -1352,7 +1387,7 @@ function useLatestThreadViewport({
|
|
|
1352
1387
|
});
|
|
1353
1388
|
});
|
|
1354
1389
|
},
|
|
1355
|
-
[hasOlder, isLoadingOlder, isTopOrigin, onLoadOlder]
|
|
1390
|
+
[hasOlder, isLoadingOlder, isTopOrigin, onLoadOlder, setLatestFollowState]
|
|
1356
1391
|
);
|
|
1357
1392
|
const preserveIntrinsicResize = useCallback2(() => {
|
|
1358
1393
|
const element = scrollContainerRef.current;
|
|
@@ -1389,31 +1424,54 @@ function useLatestThreadViewport({
|
|
|
1389
1424
|
activeStreamKeyRef.current = key;
|
|
1390
1425
|
return;
|
|
1391
1426
|
}
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
activeStreamKeyRef.current = key;
|
|
1395
|
-
return;
|
|
1396
|
-
}
|
|
1397
|
-
const frame = requestAnimationFrame(scrollToLatest);
|
|
1427
|
+
setLatestFollowState("following");
|
|
1428
|
+
const frame = requestAnimationFrame(() => scrollToLatest());
|
|
1398
1429
|
activeStreamKeyRef.current = key;
|
|
1399
1430
|
return () => cancelAnimationFrame(frame);
|
|
1400
|
-
}, [activeStreamKey,
|
|
1431
|
+
}, [activeStreamKey, scrollToLatest, setLatestFollowState]);
|
|
1401
1432
|
useLayoutEffect(() => {
|
|
1402
|
-
if (
|
|
1403
|
-
if (!activeStreamKey || !shouldAutoFollow || !autoFollowLatestRef.current) return;
|
|
1433
|
+
if (!activeStreamKey || !shouldAutoFollow || followStateRef.current !== "following") return;
|
|
1404
1434
|
if (isLoadingOlder || olderPageRequestInFlightRef.current) return;
|
|
1405
1435
|
const frame = requestAnimationFrame(() => {
|
|
1406
|
-
if (
|
|
1436
|
+
if (followStateRef.current === "following" && !isLoadingOlder && !olderPageRequestInFlightRef.current) {
|
|
1437
|
+
scrollToLatest({ reattach: false });
|
|
1438
|
+
}
|
|
1407
1439
|
});
|
|
1408
1440
|
return () => cancelAnimationFrame(frame);
|
|
1409
|
-
}, [activeStreamKey, isLoadingOlder,
|
|
1441
|
+
}, [activeStreamKey, isLoadingOlder, itemCount, scrollToLatest, shouldAutoFollow]);
|
|
1442
|
+
useEffect3(() => {
|
|
1443
|
+
if (!activeStreamKey) {
|
|
1444
|
+
observedScrollHeightRef.current = scrollContainerRef.current?.scrollHeight ?? null;
|
|
1445
|
+
return;
|
|
1446
|
+
}
|
|
1447
|
+
let frame = null;
|
|
1448
|
+
const watchStreamResize = () => {
|
|
1449
|
+
const element = scrollContainerRef.current;
|
|
1450
|
+
if (!element) return;
|
|
1451
|
+
const previousHeight = observedScrollHeightRef.current;
|
|
1452
|
+
const nextHeight = element.scrollHeight;
|
|
1453
|
+
observedScrollHeightRef.current = nextHeight;
|
|
1454
|
+
if (previousHeight !== null && Math.abs(nextHeight - previousHeight) >= 1 && shouldAutoFollow && followStateRef.current === "following" && !isLoadingOlder && !olderPageRequestInFlightRef.current) {
|
|
1455
|
+
scrollToLatest({ reattach: false });
|
|
1456
|
+
}
|
|
1457
|
+
frame = requestAnimationFrame(watchStreamResize);
|
|
1458
|
+
};
|
|
1459
|
+
frame = requestAnimationFrame(watchStreamResize);
|
|
1460
|
+
return () => {
|
|
1461
|
+
if (frame !== null) cancelAnimationFrame(frame);
|
|
1462
|
+
};
|
|
1463
|
+
}, [activeStreamKey, isLoadingOlder, scrollToLatest, shouldAutoFollow]);
|
|
1410
1464
|
return {
|
|
1411
1465
|
scrollContainerRef,
|
|
1412
1466
|
isAtLatest,
|
|
1467
|
+
isFollowingLatest: followState === "following",
|
|
1413
1468
|
isTopOrigin,
|
|
1414
1469
|
shouldShowLatestButton: !isAtLatest,
|
|
1415
1470
|
handleScroll,
|
|
1471
|
+
handleUserScrollIntent,
|
|
1416
1472
|
scrollToLatest,
|
|
1473
|
+
detachFromLatest,
|
|
1474
|
+
reattachToLatest,
|
|
1417
1475
|
preserveIntrinsicResize
|
|
1418
1476
|
};
|
|
1419
1477
|
}
|
|
@@ -1441,7 +1499,10 @@ function LatestThreadViewport({
|
|
|
1441
1499
|
{
|
|
1442
1500
|
ref: viewport.scrollContainerRef,
|
|
1443
1501
|
className,
|
|
1502
|
+
onKeyDown: viewport.handleUserScrollIntent,
|
|
1444
1503
|
onScroll: viewport.handleScroll,
|
|
1504
|
+
onTouchMove: viewport.handleUserScrollIntent,
|
|
1505
|
+
onWheel: viewport.handleUserScrollIntent,
|
|
1445
1506
|
role: "log",
|
|
1446
1507
|
style: { overflowAnchor: "none" },
|
|
1447
1508
|
children: [
|
|
@@ -1474,6 +1535,7 @@ export {
|
|
|
1474
1535
|
isScrollable,
|
|
1475
1536
|
latestContextWindowFromThread,
|
|
1476
1537
|
mergeReasoningSteps,
|
|
1538
|
+
nextLatestFollowStateOnScroll,
|
|
1477
1539
|
parseSseBlock,
|
|
1478
1540
|
partsFromResponseBlocks,
|
|
1479
1541
|
reasoningStepsFromParts,
|