@agents24/chat-react 0.1.3 → 0.1.4
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 +6 -1
- package/dist/index.cjs +161 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +25 -1
- package/dist/index.d.ts +25 -1
- package/dist/index.js +152 -15
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1035,6 +1035,140 @@ var consumeSseResponse = async (response, onEvent) => {
|
|
|
1035
1035
|
return { threadId, runId };
|
|
1036
1036
|
};
|
|
1037
1037
|
|
|
1038
|
+
// src/streaming-text.ts
|
|
1039
|
+
import { useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
1040
|
+
var DEFAULT_COMPLETED_TEXT_CACHE_SIZE = 200;
|
|
1041
|
+
var defaultCompletedTextCache = /* @__PURE__ */ new Map();
|
|
1042
|
+
var defaultStreamingTextCache = {
|
|
1043
|
+
get: (id) => defaultCompletedTextCache.get(id),
|
|
1044
|
+
set: (id, text) => {
|
|
1045
|
+
defaultCompletedTextCache.set(id, text);
|
|
1046
|
+
if (defaultCompletedTextCache.size > DEFAULT_COMPLETED_TEXT_CACHE_SIZE) {
|
|
1047
|
+
const firstKey = defaultCompletedTextCache.keys().next().value;
|
|
1048
|
+
if (firstKey) defaultCompletedTextCache.delete(firstKey);
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
};
|
|
1052
|
+
var getActiveStreamingTextPartId = (message, streamingMessageId) => {
|
|
1053
|
+
if (message.role !== "assistant" || streamingMessageId !== message.id) return null;
|
|
1054
|
+
return message.parts.slice().reverse().find((part) => part.kind === "text")?.id || null;
|
|
1055
|
+
};
|
|
1056
|
+
var isActiveStreamingTextPart = (message, part, streamingMessageId) => part.kind === "text" && part.id === getActiveStreamingTextPartId(message, streamingMessageId);
|
|
1057
|
+
function useStreamingText({
|
|
1058
|
+
id,
|
|
1059
|
+
isStreaming,
|
|
1060
|
+
text,
|
|
1061
|
+
cache = defaultStreamingTextCache,
|
|
1062
|
+
charsPerSecond = 72,
|
|
1063
|
+
catchupThreshold = 40,
|
|
1064
|
+
maxCatchupChars = 20
|
|
1065
|
+
}) {
|
|
1066
|
+
const cacheAdapter = cache === false ? null : cache;
|
|
1067
|
+
const [displayedText, setDisplayedText] = useState2(() => {
|
|
1068
|
+
const cachedText = cacheAdapter?.get(id);
|
|
1069
|
+
return isStreaming && cachedText !== text ? "" : text;
|
|
1070
|
+
});
|
|
1071
|
+
const targetRef = useRef2(text);
|
|
1072
|
+
const displayedRef = useRef2(displayedText);
|
|
1073
|
+
const rafRef = useRef2(null);
|
|
1074
|
+
const lastFrameAtRef = useRef2(null);
|
|
1075
|
+
const idRef = useRef2(id);
|
|
1076
|
+
const shouldAnimateRef = useRef2(isStreaming);
|
|
1077
|
+
useEffect2(() => {
|
|
1078
|
+
if (isStreaming || !text) return;
|
|
1079
|
+
cacheAdapter?.set(id, text);
|
|
1080
|
+
}, [cacheAdapter, id, isStreaming, text]);
|
|
1081
|
+
useEffect2(() => {
|
|
1082
|
+
targetRef.current = text;
|
|
1083
|
+
}, [text]);
|
|
1084
|
+
useEffect2(() => {
|
|
1085
|
+
if (idRef.current === id) return;
|
|
1086
|
+
idRef.current = id;
|
|
1087
|
+
const cachedText = cacheAdapter?.get(id);
|
|
1088
|
+
const initial = isStreaming && cachedText !== text ? "" : text;
|
|
1089
|
+
shouldAnimateRef.current = isStreaming && initial !== text;
|
|
1090
|
+
displayedRef.current = initial;
|
|
1091
|
+
setDisplayedText(initial);
|
|
1092
|
+
if (rafRef.current !== null) {
|
|
1093
|
+
cancelAnimationFrame(rafRef.current);
|
|
1094
|
+
rafRef.current = null;
|
|
1095
|
+
}
|
|
1096
|
+
lastFrameAtRef.current = null;
|
|
1097
|
+
}, [cacheAdapter, id, isStreaming, text]);
|
|
1098
|
+
useEffect2(() => {
|
|
1099
|
+
if (typeof window === "undefined") {
|
|
1100
|
+
displayedRef.current = text;
|
|
1101
|
+
setDisplayedText(text);
|
|
1102
|
+
return;
|
|
1103
|
+
}
|
|
1104
|
+
const reduceMotion = typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
1105
|
+
if (reduceMotion) {
|
|
1106
|
+
displayedRef.current = text;
|
|
1107
|
+
setDisplayedText(text);
|
|
1108
|
+
shouldAnimateRef.current = false;
|
|
1109
|
+
return;
|
|
1110
|
+
}
|
|
1111
|
+
const cachedText = cacheAdapter?.get(id);
|
|
1112
|
+
if (cachedText === text) {
|
|
1113
|
+
displayedRef.current = text;
|
|
1114
|
+
setDisplayedText(text);
|
|
1115
|
+
shouldAnimateRef.current = false;
|
|
1116
|
+
return;
|
|
1117
|
+
}
|
|
1118
|
+
if (isStreaming) {
|
|
1119
|
+
shouldAnimateRef.current = true;
|
|
1120
|
+
}
|
|
1121
|
+
if (!shouldAnimateRef.current) {
|
|
1122
|
+
displayedRef.current = text;
|
|
1123
|
+
setDisplayedText(text);
|
|
1124
|
+
return;
|
|
1125
|
+
}
|
|
1126
|
+
if (!text.startsWith(displayedRef.current)) {
|
|
1127
|
+
displayedRef.current = "";
|
|
1128
|
+
setDisplayedText("");
|
|
1129
|
+
}
|
|
1130
|
+
const tick = (timestamp) => {
|
|
1131
|
+
const previousTimestamp = lastFrameAtRef.current ?? timestamp;
|
|
1132
|
+
lastFrameAtRef.current = timestamp;
|
|
1133
|
+
const target = targetRef.current;
|
|
1134
|
+
const current = displayedRef.current;
|
|
1135
|
+
if (current.length >= target.length) {
|
|
1136
|
+
shouldAnimateRef.current = false;
|
|
1137
|
+
rafRef.current = null;
|
|
1138
|
+
return;
|
|
1139
|
+
}
|
|
1140
|
+
const elapsedMs = Math.max(8, timestamp - previousTimestamp);
|
|
1141
|
+
const charsFromTime = Math.max(1, Math.floor(elapsedMs / 1e3 * charsPerSecond));
|
|
1142
|
+
const gap = target.length - current.length;
|
|
1143
|
+
const catchupStep = gap > catchupThreshold ? Math.min(maxCatchupChars, Math.ceil(gap / 10)) : charsFromTime;
|
|
1144
|
+
const nextLength = Math.min(
|
|
1145
|
+
target.length,
|
|
1146
|
+
current.length + Math.max(charsFromTime, catchupStep)
|
|
1147
|
+
);
|
|
1148
|
+
const next = target.slice(0, nextLength);
|
|
1149
|
+
displayedRef.current = next;
|
|
1150
|
+
setDisplayedText(next);
|
|
1151
|
+
rafRef.current = window.requestAnimationFrame(tick);
|
|
1152
|
+
};
|
|
1153
|
+
if (rafRef.current === null && displayedRef.current.length < text.length) {
|
|
1154
|
+
rafRef.current = window.requestAnimationFrame(tick);
|
|
1155
|
+
}
|
|
1156
|
+
return () => {
|
|
1157
|
+
if (rafRef.current !== null) {
|
|
1158
|
+
cancelAnimationFrame(rafRef.current);
|
|
1159
|
+
rafRef.current = null;
|
|
1160
|
+
}
|
|
1161
|
+
lastFrameAtRef.current = null;
|
|
1162
|
+
};
|
|
1163
|
+
}, [cacheAdapter, catchupThreshold, charsPerSecond, id, isStreaming, maxCatchupChars, text]);
|
|
1164
|
+
return {
|
|
1165
|
+
displayedText,
|
|
1166
|
+
isAnimating: isStreaming,
|
|
1167
|
+
mode: isStreaming ? "streaming" : "static",
|
|
1168
|
+
parseIncompleteMarkdown: isStreaming
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1038
1172
|
// src/transport.ts
|
|
1039
1173
|
var jsonHeaders = (headers) => ({
|
|
1040
1174
|
...headers || {},
|
|
@@ -1118,11 +1252,11 @@ var createFetchChatTransport = ({
|
|
|
1118
1252
|
// src/viewport.tsx
|
|
1119
1253
|
import {
|
|
1120
1254
|
useCallback as useCallback2,
|
|
1121
|
-
useEffect as
|
|
1255
|
+
useEffect as useEffect3,
|
|
1122
1256
|
useLayoutEffect,
|
|
1123
1257
|
useMemo as useMemo2,
|
|
1124
|
-
useRef as
|
|
1125
|
-
useState as
|
|
1258
|
+
useRef as useRef3,
|
|
1259
|
+
useState as useState3
|
|
1126
1260
|
} from "react";
|
|
1127
1261
|
import { jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1128
1262
|
var LATEST_EDGE_THRESHOLD_PX = 2;
|
|
@@ -1149,15 +1283,15 @@ function useLatestThreadViewport({
|
|
|
1149
1283
|
shouldAutoFollow = true,
|
|
1150
1284
|
topOriginMaxItems = 4
|
|
1151
1285
|
}) {
|
|
1152
|
-
const scrollContainerRef =
|
|
1153
|
-
const olderPagePreserveRef =
|
|
1154
|
-
const olderPageRequestInFlightRef =
|
|
1155
|
-
const intrinsicResizePreserveRef =
|
|
1156
|
-
const autoFollowLatestRef =
|
|
1157
|
-
const programmaticScrollRef =
|
|
1158
|
-
const programmaticScrollTimeoutRef =
|
|
1159
|
-
const activeStreamKeyRef =
|
|
1160
|
-
const [isAtLatest, setIsAtLatest] =
|
|
1286
|
+
const scrollContainerRef = useRef3(null);
|
|
1287
|
+
const olderPagePreserveRef = useRef3(null);
|
|
1288
|
+
const olderPageRequestInFlightRef = useRef3(false);
|
|
1289
|
+
const intrinsicResizePreserveRef = useRef3(null);
|
|
1290
|
+
const autoFollowLatestRef = useRef3(true);
|
|
1291
|
+
const programmaticScrollRef = useRef3(false);
|
|
1292
|
+
const programmaticScrollTimeoutRef = useRef3(null);
|
|
1293
|
+
const activeStreamKeyRef = useRef3(null);
|
|
1294
|
+
const [isAtLatest, setIsAtLatest] = useState3(true);
|
|
1161
1295
|
const isTopOrigin = shouldUseTopOriginTimeline({ hasOlder, itemCount, topOriginMaxItems });
|
|
1162
1296
|
const markProgrammaticScroll = useCallback2(() => {
|
|
1163
1297
|
programmaticScrollRef.current = true;
|
|
@@ -1174,7 +1308,7 @@ function useLatestThreadViewport({
|
|
|
1174
1308
|
element.scrollTop = getLatestScrollTop(element, isTopOrigin);
|
|
1175
1309
|
setIsAtLatest(true);
|
|
1176
1310
|
}, [isTopOrigin, markProgrammaticScroll]);
|
|
1177
|
-
|
|
1311
|
+
useEffect3(() => {
|
|
1178
1312
|
return () => {
|
|
1179
1313
|
if (programmaticScrollTimeoutRef.current) clearTimeout(programmaticScrollTimeoutRef.current);
|
|
1180
1314
|
const preserve = intrinsicResizePreserveRef.current;
|
|
@@ -1249,7 +1383,7 @@ function useLatestThreadViewport({
|
|
|
1249
1383
|
};
|
|
1250
1384
|
intrinsicResizePreserveRef.current.frame = requestAnimationFrame(preserveFrame);
|
|
1251
1385
|
}, [isTopOrigin, markProgrammaticScroll]);
|
|
1252
|
-
|
|
1386
|
+
useEffect3(() => {
|
|
1253
1387
|
const key = activeStreamKey || null;
|
|
1254
1388
|
if (!key || activeStreamKeyRef.current === key) {
|
|
1255
1389
|
activeStreamKeyRef.current = key;
|
|
@@ -1330,9 +1464,11 @@ export {
|
|
|
1330
1464
|
consumeSseResponse,
|
|
1331
1465
|
createChatId,
|
|
1332
1466
|
createFetchChatTransport,
|
|
1467
|
+
getActiveStreamingTextPartId,
|
|
1333
1468
|
getLatestScrollTop,
|
|
1334
1469
|
hasStaleUnfinishedAssistantCache,
|
|
1335
1470
|
hasUnfinishedAssistantMessage,
|
|
1471
|
+
isActiveStreamingTextPart,
|
|
1336
1472
|
isAtTimelineLatestEdge,
|
|
1337
1473
|
isRunningThreadStatus,
|
|
1338
1474
|
isScrollable,
|
|
@@ -1351,6 +1487,7 @@ export {
|
|
|
1351
1487
|
titleFromMessage,
|
|
1352
1488
|
toolStateFromStatus,
|
|
1353
1489
|
useAgents24ChatController,
|
|
1354
|
-
useLatestThreadViewport
|
|
1490
|
+
useLatestThreadViewport,
|
|
1491
|
+
useStreamingText
|
|
1355
1492
|
};
|
|
1356
1493
|
//# sourceMappingURL=index.js.map
|