@copilotz/chat-adapter 0.3.2 → 0.3.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/dist/index.d.ts CHANGED
@@ -44,6 +44,15 @@ type RestMessage = {
44
44
  createdAt?: string;
45
45
  updatedAt?: string;
46
46
  };
47
+ type RestMessagePageInfo = {
48
+ hasMoreBefore: boolean;
49
+ oldestMessageId: string | null;
50
+ newestMessageId: string | null;
51
+ };
52
+ type RestMessagePage = {
53
+ data: RestMessage[];
54
+ pageInfo: RestMessagePageInfo;
55
+ };
47
56
  type StreamCallbacks = {
48
57
  onToken?: (token: string, isComplete: boolean, raw?: any, options?: {
49
58
  isReasoning?: boolean;
@@ -95,6 +104,10 @@ declare class CopilotzRequestError extends Error {
95
104
  declare function runCopilotzStream(options: RunOptions): Promise<CopilotzStreamResult>;
96
105
  declare function fetchThreads(userId: string, getRequestHeaders?: RequestHeadersProvider): Promise<RestThread[]>;
97
106
  declare function fetchThreadMessages(threadId: string, getRequestHeaders?: RequestHeadersProvider): Promise<RestMessage[]>;
107
+ declare function fetchThreadMessagesPage(threadId: string, options?: {
108
+ limit?: number;
109
+ before?: string | null;
110
+ }, getRequestHeaders?: RequestHeadersProvider): Promise<RestMessagePage>;
98
111
  declare function updateThread(threadId: string, updates: Partial<RestThread>, getRequestHeaders?: RequestHeadersProvider): Promise<any>;
99
112
  declare function deleteThread(threadId: string, getRequestHeaders?: RequestHeadersProvider): Promise<boolean>;
100
113
  declare const copilotzService: {
@@ -187,6 +200,8 @@ interface UseCopilotzOptions {
187
200
  declare function useCopilotz({ userId, initialContext, bootstrap, defaultThreadName, onToolOutput, preferredAgentName, participants, targetAgentName, getRequestHeaders, eventInterceptor, runErrorInterceptor, }: UseCopilotzOptions): {
188
201
  messages: ChatMessage[];
189
202
  isMessagesLoading: boolean;
203
+ isLoadingOlderMessages: boolean;
204
+ messagePageInfo: RestMessagePageInfo;
190
205
  threads: ChatThread[];
191
206
  currentThreadId: string | null;
192
207
  isStreaming: boolean;
@@ -202,6 +217,7 @@ declare function useCopilotz({ userId, initialContext, bootstrap, defaultThreadN
202
217
  stopGeneration: () => void;
203
218
  fetchAndSetThreadsState: (uid: string, preferredExternalId?: string | null) => Promise<string | null | undefined>;
204
219
  loadThreadMessages: (threadId: string) => Promise<void>;
220
+ loadOlderMessages: () => Promise<void>;
205
221
  reset: () => void;
206
222
  };
207
223
 
@@ -281,4 +297,4 @@ type WithMetadata = {
281
297
  };
282
298
  declare function resolveAssetsInMessages<T extends WithMetadata>(messages: T[]): Promise<T[]>;
283
299
 
284
- export { CopilotzChat, CopilotzRequestError, type CopilotzStreamResult, type EventInterceptor, type EventInterceptorResult, type RenderSpecialState, type RequestHeadersProvider, type RunErrorInterceptor, type SpecialChatState, type SpecialStateControls, type UrlParamsConfig, type UrlState, type UseUrlStateReturn, copilotzService, deleteThread, fetchThreadMessages, fetchThreads, getAssetDataUrl, resolveAssetsInMessages, runCopilotzStream, updateThread, useCopilotz, useUrlState };
300
+ export { CopilotzChat, CopilotzRequestError, type CopilotzStreamResult, type EventInterceptor, type EventInterceptorResult, type RenderSpecialState, type RequestHeadersProvider, type RestMessagePage, type RestMessagePageInfo, type RunErrorInterceptor, type SpecialChatState, type SpecialStateControls, type UrlParamsConfig, type UrlState, type UseUrlStateReturn, copilotzService, deleteThread, fetchThreadMessages, fetchThreadMessagesPage, fetchThreads, getAssetDataUrl, resolveAssetsInMessages, runCopilotzStream, updateThread, useCopilotz, useUrlState };
package/dist/index.js CHANGED
@@ -130,6 +130,11 @@ var withAuthHeaders = async (headers = {}, getRequestHeaders) => {
130
130
  }
131
131
  return headers;
132
132
  };
133
+ var buildFallbackPageInfo = (data) => ({
134
+ hasMoreBefore: false,
135
+ oldestMessageId: data[0]?.id ?? null,
136
+ newestMessageId: data[data.length - 1]?.id ?? null
137
+ });
133
138
  var CopilotzRequestError = class extends Error {
134
139
  status;
135
140
  code;
@@ -549,8 +554,15 @@ async function fetchThreads(userId, getRequestHeaders) {
549
554
  return data;
550
555
  }
551
556
  async function fetchThreadMessages(threadId, getRequestHeaders) {
557
+ const page = await fetchThreadMessagesPage(threadId, void 0, getRequestHeaders);
558
+ return page.data;
559
+ }
560
+ async function fetchThreadMessagesPage(threadId, options, getRequestHeaders) {
552
561
  const params = new URLSearchParams();
553
- params.set("limit", "500");
562
+ params.set("limit", String(options?.limit ?? 50));
563
+ if (options?.before) {
564
+ params.set("before", options.before);
565
+ }
554
566
  const res = await fetch(
555
567
  apiUrl(`/v1/threads/${threadId}/messages?${params.toString()}`),
556
568
  {
@@ -566,14 +578,33 @@ async function fetchThreadMessages(threadId, getRequestHeaders) {
566
578
  errorText || `Failed to load thread messages (${res.status})`
567
579
  );
568
580
  }
569
- const data = await res.json();
570
- if (Array.isArray(data)) {
571
- return data;
581
+ const payload = await res.json();
582
+ if (Array.isArray(payload)) {
583
+ return {
584
+ data: payload,
585
+ pageInfo: buildFallbackPageInfo(payload)
586
+ };
572
587
  }
573
- if (Array.isArray(data?.data)) {
574
- return data.data;
588
+ if (Array.isArray(payload?.data)) {
589
+ const data = payload.data;
590
+ const rawPageInfo = payload?.pageInfo;
591
+ return {
592
+ data,
593
+ pageInfo: {
594
+ hasMoreBefore: rawPageInfo?.hasMoreBefore === true,
595
+ oldestMessageId: typeof rawPageInfo?.oldestMessageId === "string" ? rawPageInfo.oldestMessageId : data[0]?.id ?? null,
596
+ newestMessageId: typeof rawPageInfo?.newestMessageId === "string" ? rawPageInfo.newestMessageId : data[data.length - 1]?.id ?? null
597
+ }
598
+ };
575
599
  }
576
- return [];
600
+ return {
601
+ data: [],
602
+ pageInfo: {
603
+ hasMoreBefore: false,
604
+ oldestMessageId: null,
605
+ newestMessageId: null
606
+ }
607
+ };
577
608
  }
578
609
  async function updateThread(threadId, updates, getRequestHeaders) {
579
610
  const res = await fetch(apiUrl(`/v1/threads/${threadId}`), {
@@ -787,6 +818,7 @@ var hasVisibleAssistantOutput = (message) => {
787
818
  if (Array.isArray(message.toolCalls) && message.toolCalls.length > 0) return true;
788
819
  return false;
789
820
  };
821
+ var isInternalMessageMetadata = (metadata) => metadata?.visibility === "internal";
790
822
  var normalizeAgentIdentity = (agent) => {
791
823
  const senderAgentId = typeof agent?.id === "string" && agent.id.length > 0 ? agent.id : void 0;
792
824
  const senderName = typeof agent?.name === "string" && agent.name.length > 0 ? agent.name : senderAgentId;
@@ -799,6 +831,12 @@ var messageAgentKey = (message) => {
799
831
  if (message.role !== "assistant") return null;
800
832
  return message.senderAgentId ?? message.senderName ?? null;
801
833
  };
834
+ var THREAD_MESSAGES_PAGE_SIZE = 50;
835
+ var createEmptyMessagePageInfo = () => ({
836
+ hasMoreBefore: false,
837
+ oldestMessageId: null,
838
+ newestMessageId: null
839
+ });
802
840
  var normalizeToolStatus = (status) => {
803
841
  if (status === "pending") return "pending";
804
842
  if (status === "running" || status === "processing") return "running";
@@ -916,6 +954,18 @@ var mergePersistedToolResults = (messages, updates) => {
916
954
  }
917
955
  return nextMessages;
918
956
  };
957
+ var prependUniqueMessages = (olderMessages, currentMessages) => {
958
+ if (olderMessages.length === 0) return currentMessages;
959
+ if (currentMessages.length === 0) return olderMessages;
960
+ const seen = /* @__PURE__ */ new Set();
961
+ const combined = [];
962
+ for (const message of [...olderMessages, ...currentMessages]) {
963
+ if (seen.has(message.id)) continue;
964
+ seen.add(message.id);
965
+ combined.push(message);
966
+ }
967
+ return combined;
968
+ };
919
969
  var convertServerMessage = (msg) => {
920
970
  const timestamp = msg.createdAt ? new Date(msg.createdAt).getTime() : nowTs();
921
971
  const metadata = msg.metadata ?? void 0;
@@ -1003,6 +1053,8 @@ function useCopilotz({
1003
1053
  const [currentThreadExternalId, setCurrentThreadExternalId] = useState2(null);
1004
1054
  const [messages, setMessages] = useState2([]);
1005
1055
  const [isMessagesLoading, setIsMessagesLoading] = useState2(false);
1056
+ const [isLoadingOlderMessages, setIsLoadingOlderMessages] = useState2(false);
1057
+ const [messagePageInfo, setMessagePageInfo] = useState2(createEmptyMessagePageInfo);
1006
1058
  const [isStreaming, setIsStreaming] = useState2(false);
1007
1059
  const [specialState, setSpecialState] = useState2(null);
1008
1060
  const [userContextSeed, setUserContextSeed] = useState2(initialContext || {});
@@ -1015,12 +1067,17 @@ function useCopilotz({
1015
1067
  const currentThreadIdRef = useRef2(currentThreadId);
1016
1068
  const currentThreadExternalIdRef = useRef2(currentThreadExternalId);
1017
1069
  const userContextSeedRef = useRef2(userContextSeed);
1070
+ const messagePageInfoRef = useRef2(messagePageInfo);
1071
+ const isLoadingOlderMessagesRef = useRef2(isLoadingOlderMessages);
1072
+ const persistedToolUpdatesRef = useRef2([]);
1018
1073
  threadsRef.current = threads;
1019
1074
  threadMetadataMapRef.current = threadMetadataMap;
1020
1075
  threadExternalIdMapRef.current = threadExternalIdMap;
1021
1076
  currentThreadIdRef.current = currentThreadId;
1022
1077
  currentThreadExternalIdRef.current = currentThreadExternalId;
1023
1078
  userContextSeedRef.current = userContextSeed;
1079
+ messagePageInfoRef.current = messagePageInfo;
1080
+ isLoadingOlderMessagesRef.current = isLoadingOlderMessages;
1024
1081
  preferredAgentRef.current = preferredAgentName ?? null;
1025
1082
  participantsRef.current = participants ?? null;
1026
1083
  targetAgentNameRef.current = targetAgentName ?? null;
@@ -1071,6 +1128,10 @@ function useCopilotz({
1071
1128
  const handleStreamMessageEvent = useCallback2((event) => {
1072
1129
  const payload = getEventPayload(event);
1073
1130
  if (!payload) return;
1131
+ const liveMetadata = event?.metadata && typeof event.metadata === "object" ? event.metadata : payload?.metadata;
1132
+ if (isInternalMessageMetadata(liveMetadata)) {
1133
+ return;
1134
+ }
1074
1135
  const senderType = getEventSenderType(payload);
1075
1136
  if (senderType === "tool") {
1076
1137
  const metadata = payload.metadata ?? event.metadata ?? {};
@@ -1145,7 +1206,7 @@ function useCopilotz({
1145
1206
  timestamp: nowTs(),
1146
1207
  isStreaming: false,
1147
1208
  isComplete: true,
1148
- metadata: payload.metadata ?? void 0,
1209
+ metadata: liveMetadata,
1149
1210
  ...agentSenderId ? { senderAgentId: agentSenderId } : {},
1150
1211
  ...agentSenderName ? { senderName: agentSenderName } : {}
1151
1212
  }
@@ -1205,47 +1266,105 @@ function useCopilotz({
1205
1266
  return null;
1206
1267
  }
1207
1268
  }, [updateThreadsState, getRequestHeaders]);
1269
+ const prepareThreadMessages = useCallback2(async (rawMessages) => {
1270
+ const resolvedMessages = await resolveAssetsInMessages(rawMessages);
1271
+ resolvedMessages.forEach((msg) => {
1272
+ if (msg.senderType === "tool") {
1273
+ const metadata = msg.metadata;
1274
+ const output = metadata?.output ?? metadata;
1275
+ if (output) processToolOutput(output);
1276
+ }
1277
+ });
1278
+ const toolResultUpdates = resolvedMessages.map((msg) => extractToolResultUpdateFromMessage(msg)).filter((update) => update !== null);
1279
+ const viewMessages = resolvedMessages.filter((msg) => {
1280
+ const meta = msg.metadata ?? {};
1281
+ if (isInternalMessageMetadata(meta)) {
1282
+ return false;
1283
+ }
1284
+ const text = (typeof msg.content === "string" ? msg.content : "").trim();
1285
+ const hasText = text.length > 0;
1286
+ const hasToolCalls = extractToolCallsFromServerMessage(msg).length > 0;
1287
+ const hasAttachments = Array.isArray(meta.attachments) && meta.attachments.length > 0;
1288
+ if (msg.senderType === "tool") {
1289
+ return hasAttachments;
1290
+ }
1291
+ return hasText || hasToolCalls || hasAttachments;
1292
+ }).map(convertServerMessage);
1293
+ return {
1294
+ viewMessages,
1295
+ toolResultUpdates
1296
+ };
1297
+ }, [processToolOutput]);
1208
1298
  const loadThreadMessages = useCallback2(async (threadId) => {
1209
1299
  const requestId = messagesRequestRef.current + 1;
1210
1300
  messagesRequestRef.current = requestId;
1211
1301
  setIsMessagesLoading(true);
1302
+ setIsLoadingOlderMessages(false);
1303
+ setMessagePageInfo(createEmptyMessagePageInfo());
1304
+ persistedToolUpdatesRef.current = [];
1212
1305
  try {
1213
- const rawMessages = await fetchThreadMessages(threadId, getRequestHeaders);
1214
- const resolvedMessages = await resolveAssetsInMessages(rawMessages);
1306
+ const page = await fetchThreadMessagesPage(
1307
+ threadId,
1308
+ { limit: THREAD_MESSAGES_PAGE_SIZE },
1309
+ getRequestHeaders
1310
+ );
1311
+ const { viewMessages, toolResultUpdates } = await prepareThreadMessages(page.data);
1215
1312
  if (messagesRequestRef.current !== requestId) return;
1216
- resolvedMessages.forEach((msg) => {
1217
- if (msg.senderType === "tool") {
1218
- const metadata = msg.metadata;
1219
- const output = metadata?.output ?? metadata;
1220
- if (output) processToolOutput(output);
1221
- }
1222
- });
1223
- const toolResultUpdates = resolvedMessages.map((msg) => extractToolResultUpdateFromMessage(msg)).filter((update) => update !== null);
1224
- const viewMessages = resolvedMessages.filter((msg) => {
1225
- const text = (typeof msg.content === "string" ? msg.content : "").trim();
1226
- const hasText = text.length > 0;
1227
- const hasToolCalls = extractToolCallsFromServerMessage(msg).length > 0;
1228
- const meta = msg.metadata ?? {};
1229
- const hasAttachments = Array.isArray(meta.attachments) && meta.attachments.length > 0;
1230
- if (msg.senderType === "tool") {
1231
- return hasAttachments;
1232
- }
1233
- return hasText || hasToolCalls || hasAttachments;
1234
- }).map(convertServerMessage);
1235
- const hydratedMessages = mergePersistedToolResults(viewMessages, toolResultUpdates);
1313
+ persistedToolUpdatesRef.current = toolResultUpdates;
1314
+ const hydratedMessages = mergePersistedToolResults(viewMessages, persistedToolUpdatesRef.current);
1236
1315
  setMessages(hydratedMessages);
1316
+ setMessagePageInfo(page.pageInfo);
1237
1317
  } catch (error) {
1238
1318
  if (isAbortError(error)) return;
1239
1319
  console.error(`Error loading messages for thread ${threadId}`, error);
1320
+ persistedToolUpdatesRef.current = [];
1321
+ setMessagePageInfo(createEmptyMessagePageInfo());
1240
1322
  } finally {
1241
1323
  if (messagesRequestRef.current === requestId) {
1242
1324
  setIsMessagesLoading(false);
1243
1325
  }
1244
1326
  }
1245
- }, [processToolOutput, getRequestHeaders]);
1327
+ }, [getRequestHeaders, prepareThreadMessages]);
1328
+ const loadOlderMessages = useCallback2(async () => {
1329
+ const threadId = currentThreadIdRef.current;
1330
+ const pageInfo = messagePageInfoRef.current;
1331
+ const before = pageInfo.oldestMessageId;
1332
+ if (!threadId || !before || !pageInfo.hasMoreBefore || isLoadingOlderMessagesRef.current) {
1333
+ return;
1334
+ }
1335
+ const requestId = messagesRequestRef.current;
1336
+ setIsLoadingOlderMessages(true);
1337
+ try {
1338
+ const page = await fetchThreadMessagesPage(
1339
+ threadId,
1340
+ { limit: THREAD_MESSAGES_PAGE_SIZE, before },
1341
+ getRequestHeaders
1342
+ );
1343
+ const { viewMessages, toolResultUpdates } = await prepareThreadMessages(page.data);
1344
+ if (messagesRequestRef.current !== requestId) return;
1345
+ persistedToolUpdatesRef.current = [
1346
+ ...toolResultUpdates,
1347
+ ...persistedToolUpdatesRef.current
1348
+ ];
1349
+ setMessages((prev) => mergePersistedToolResults(
1350
+ prependUniqueMessages(viewMessages, prev),
1351
+ persistedToolUpdatesRef.current
1352
+ ));
1353
+ setMessagePageInfo(page.pageInfo);
1354
+ } catch (error) {
1355
+ if (isAbortError(error)) return;
1356
+ console.error(`Error loading older messages for thread ${threadId}`, error);
1357
+ } finally {
1358
+ if (messagesRequestRef.current === requestId) {
1359
+ setIsLoadingOlderMessages(false);
1360
+ }
1361
+ }
1362
+ }, [getRequestHeaders, prepareThreadMessages]);
1246
1363
  const handleSelectThread = useCallback2(async (threadId) => {
1247
1364
  setCurrentThreadId(threadId);
1248
1365
  setMessages([]);
1366
+ setMessagePageInfo(createEmptyMessagePageInfo());
1367
+ persistedToolUpdatesRef.current = [];
1249
1368
  const extMap = threadExternalIdMapRef.current;
1250
1369
  setCurrentThreadExternalId(extMap[threadId] ?? null);
1251
1370
  await loadThreadMessages(threadId);
@@ -1253,6 +1372,7 @@ function useCopilotz({
1253
1372
  const handleCreateThread = useCallback2((title) => {
1254
1373
  messagesRequestRef.current += 1;
1255
1374
  setIsMessagesLoading(false);
1375
+ setIsLoadingOlderMessages(false);
1256
1376
  const id = generateId();
1257
1377
  const now = nowTs();
1258
1378
  const newThread = {
@@ -1269,6 +1389,8 @@ function useCopilotz({
1269
1389
  setCurrentThreadId(id);
1270
1390
  setCurrentThreadExternalId(id);
1271
1391
  setMessages([]);
1392
+ setMessagePageInfo(createEmptyMessagePageInfo());
1393
+ persistedToolUpdatesRef.current = [];
1272
1394
  }, []);
1273
1395
  const handleRenameThread = useCallback2(async (threadId, newTitle) => {
1274
1396
  const trimmedTitle = newTitle.trim();
@@ -1338,6 +1460,8 @@ function useCopilotz({
1338
1460
  setCurrentThreadId(null);
1339
1461
  setCurrentThreadExternalId(null);
1340
1462
  setMessages([]);
1463
+ setMessagePageInfo(createEmptyMessagePageInfo());
1464
+ persistedToolUpdatesRef.current = [];
1341
1465
  }
1342
1466
  }
1343
1467
  if (!isPlaceholder) {
@@ -1526,6 +1650,10 @@ function useCopilotz({
1526
1650
  }
1527
1651
  if (type === "MESSAGE" || type === "NEW_MESSAGE") {
1528
1652
  const senderType = payload?.senderType || payload?.sender?.type;
1653
+ const liveMetadata = event?.metadata && typeof event.metadata === "object" ? event.metadata : payload?.metadata;
1654
+ if (isInternalMessageMetadata(liveMetadata)) {
1655
+ return null;
1656
+ }
1529
1657
  if (senderType !== "agent") {
1530
1658
  return null;
1531
1659
  }
@@ -1538,7 +1666,7 @@ function useCopilotz({
1538
1666
  threadId: curThreadId ?? "",
1539
1667
  senderType: "agent",
1540
1668
  content,
1541
- metadata: payload?.metadata ?? {}
1669
+ metadata: liveMetadata ?? {}
1542
1670
  };
1543
1671
  }
1544
1672
  if (type === "ASSET_CREATED") {
@@ -1886,6 +2014,8 @@ function useCopilotz({
1886
2014
  setThreadExternalIdMap((prev) => ({ ...prev, [bootstrapThreadExternalId]: bootstrapThreadExternalId }));
1887
2015
  setThreadMetadataMap((prev) => ({ ...prev, [bootstrapThreadExternalId]: {} }));
1888
2016
  setMessages([]);
2017
+ setMessagePageInfo(createEmptyMessagePageInfo());
2018
+ persistedToolUpdatesRef.current = [];
1889
2019
  setSpecialState(null);
1890
2020
  try {
1891
2021
  await sendCopilotzMessage({
@@ -1931,7 +2061,10 @@ function useCopilotz({
1931
2061
  setMessages([]);
1932
2062
  setUserContextSeed({});
1933
2063
  setIsMessagesLoading(false);
2064
+ setIsLoadingOlderMessages(false);
1934
2065
  setIsStreaming(false);
2066
+ setMessagePageInfo(createEmptyMessagePageInfo());
2067
+ persistedToolUpdatesRef.current = [];
1935
2068
  setSpecialState(null);
1936
2069
  abortControllerRef.current?.abort();
1937
2070
  }, []);
@@ -1972,6 +2105,8 @@ function useCopilotz({
1972
2105
  return {
1973
2106
  messages,
1974
2107
  isMessagesLoading,
2108
+ isLoadingOlderMessages,
2109
+ messagePageInfo,
1975
2110
  threads,
1976
2111
  currentThreadId,
1977
2112
  isStreaming,
@@ -1987,6 +2122,7 @@ function useCopilotz({
1987
2122
  stopGeneration: handleStop,
1988
2123
  fetchAndSetThreadsState,
1989
2124
  loadThreadMessages,
2125
+ loadOlderMessages,
1990
2126
  reset
1991
2127
  };
1992
2128
  }
@@ -2035,6 +2171,8 @@ var CopilotzChat = ({
2035
2171
  const {
2036
2172
  messages,
2037
2173
  isMessagesLoading,
2174
+ isLoadingOlderMessages,
2175
+ messagePageInfo,
2038
2176
  threads,
2039
2177
  currentThreadId,
2040
2178
  isStreaming,
@@ -2047,7 +2185,8 @@ var CopilotzChat = ({
2047
2185
  renameThread,
2048
2186
  archiveThread,
2049
2187
  deleteThread: deleteThread2,
2050
- stopGeneration
2188
+ stopGeneration,
2189
+ loadOlderMessages
2051
2190
  } = useCopilotz({
2052
2191
  userId,
2053
2192
  initialContext,
@@ -2148,6 +2287,9 @@ var CopilotzChat = ({
2148
2287
  {
2149
2288
  messages,
2150
2289
  isMessagesLoading,
2290
+ isLoadingOlderMessages,
2291
+ hasMoreMessagesBefore: messagePageInfo.hasMoreBefore,
2292
+ onLoadOlderMessages: loadOlderMessages,
2151
2293
  threads,
2152
2294
  currentThreadId,
2153
2295
  config: mergedConfig,
@@ -2176,6 +2318,7 @@ export {
2176
2318
  copilotzService,
2177
2319
  deleteThread,
2178
2320
  fetchThreadMessages,
2321
+ fetchThreadMessagesPage,
2179
2322
  fetchThreads,
2180
2323
  getAssetDataUrl,
2181
2324
  resolveAssetsInMessages,