@convex-dev/agent 0.5.0-alpha.1 → 0.6.0-alpha.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.
Files changed (235) hide show
  1. package/MIGRATION.md +153 -0
  2. package/README.md +32 -27
  3. package/dist/UIMessages.d.ts +46 -0
  4. package/dist/UIMessages.d.ts.map +1 -0
  5. package/dist/UIMessages.js +546 -0
  6. package/dist/UIMessages.js.map +1 -0
  7. package/dist/client/createTool.d.ts +126 -27
  8. package/dist/client/createTool.d.ts.map +1 -1
  9. package/dist/client/createTool.js +67 -12
  10. package/dist/client/createTool.js.map +1 -1
  11. package/dist/client/defaultComponent.d.ts +11 -0
  12. package/dist/client/defaultComponent.d.ts.map +1 -0
  13. package/dist/client/defaultComponent.js +7 -0
  14. package/dist/client/defaultComponent.js.map +1 -0
  15. package/dist/client/definePlaygroundAPI.d.ts +1335 -204
  16. package/dist/client/definePlaygroundAPI.d.ts.map +1 -1
  17. package/dist/client/definePlaygroundAPI.js +52 -28
  18. package/dist/client/definePlaygroundAPI.js.map +1 -1
  19. package/dist/client/files.d.ts +20 -7
  20. package/dist/client/files.d.ts.map +1 -1
  21. package/dist/client/files.js +68 -11
  22. package/dist/client/files.js.map +1 -1
  23. package/dist/client/index.d.ts +1116 -978
  24. package/dist/client/index.d.ts.map +1 -1
  25. package/dist/client/index.js +332 -747
  26. package/dist/client/index.js.map +1 -1
  27. package/dist/client/messages.d.ts +461 -0
  28. package/dist/client/messages.d.ts.map +1 -0
  29. package/dist/client/messages.js +106 -0
  30. package/dist/client/messages.js.map +1 -0
  31. package/dist/client/mockModel.d.ts +42 -0
  32. package/dist/client/mockModel.d.ts.map +1 -0
  33. package/dist/client/mockModel.js +182 -0
  34. package/dist/client/mockModel.js.map +1 -0
  35. package/dist/client/saveInputMessages.d.ts +20 -0
  36. package/dist/client/saveInputMessages.d.ts.map +1 -0
  37. package/dist/client/saveInputMessages.js +58 -0
  38. package/dist/client/saveInputMessages.js.map +1 -0
  39. package/dist/client/search.d.ts +350 -39
  40. package/dist/client/search.d.ts.map +1 -1
  41. package/dist/client/search.js +350 -39
  42. package/dist/client/search.js.map +1 -1
  43. package/dist/client/start.d.ts +84 -0
  44. package/dist/client/start.d.ts.map +1 -0
  45. package/dist/client/start.js +185 -0
  46. package/dist/client/start.js.map +1 -0
  47. package/dist/client/streamText.d.ts +46 -0
  48. package/dist/client/streamText.d.ts.map +1 -0
  49. package/dist/client/streamText.js +117 -0
  50. package/dist/client/streamText.js.map +1 -0
  51. package/dist/client/streaming.d.ts +3716 -32
  52. package/dist/client/streaming.d.ts.map +1 -1
  53. package/dist/client/streaming.js +161 -59
  54. package/dist/client/streaming.js.map +1 -1
  55. package/dist/client/threads.d.ts +46 -0
  56. package/dist/client/threads.d.ts.map +1 -0
  57. package/dist/client/threads.js +49 -0
  58. package/dist/client/threads.js.map +1 -0
  59. package/dist/client/types.d.ts +266 -128
  60. package/dist/client/types.d.ts.map +1 -1
  61. package/dist/client/utils.d.ts +4 -0
  62. package/dist/client/utils.d.ts.map +1 -0
  63. package/dist/client/utils.js +21 -0
  64. package/dist/client/utils.js.map +1 -0
  65. package/dist/component/_generated/api.d.ts +24 -2178
  66. package/dist/component/_generated/api.d.ts.map +1 -1
  67. package/dist/component/_generated/api.js +10 -1
  68. package/dist/component/_generated/api.js.map +1 -1
  69. package/dist/component/_generated/component.d.ts +3120 -0
  70. package/dist/component/_generated/component.d.ts.map +1 -0
  71. package/dist/component/_generated/component.js +11 -0
  72. package/dist/component/_generated/component.js.map +1 -0
  73. package/dist/component/_generated/dataModel.d.ts +4 -18
  74. package/dist/component/_generated/dataModel.d.ts.map +1 -0
  75. package/dist/component/_generated/dataModel.js +11 -0
  76. package/dist/component/_generated/dataModel.js.map +1 -0
  77. package/dist/component/_generated/server.d.ts +10 -38
  78. package/dist/component/_generated/server.d.ts.map +1 -1
  79. package/dist/component/_generated/server.js +9 -5
  80. package/dist/component/_generated/server.js.map +1 -1
  81. package/dist/component/files.d.ts +16 -10
  82. package/dist/component/files.d.ts.map +1 -1
  83. package/dist/component/files.js +10 -2
  84. package/dist/component/files.js.map +1 -1
  85. package/dist/component/messages.d.ts +2578 -366
  86. package/dist/component/messages.d.ts.map +1 -1
  87. package/dist/component/messages.js +397 -154
  88. package/dist/component/messages.js.map +1 -1
  89. package/dist/component/schema.d.ts +5697 -3584
  90. package/dist/component/schema.d.ts.map +1 -1
  91. package/dist/component/schema.js +18 -41
  92. package/dist/component/schema.js.map +1 -1
  93. package/dist/component/streams.d.ts +39 -339
  94. package/dist/component/streams.d.ts.map +1 -1
  95. package/dist/component/streams.js +114 -73
  96. package/dist/component/streams.js.map +1 -1
  97. package/dist/component/threads.d.ts +13 -13
  98. package/dist/component/users.d.ts +7 -7
  99. package/dist/component/vector/index.d.ts +1 -1
  100. package/dist/component/vector/index.d.ts.map +1 -1
  101. package/dist/component/vector/index.js +1 -3
  102. package/dist/component/vector/index.js.map +1 -1
  103. package/dist/deltas.d.ts +43 -0
  104. package/dist/deltas.d.ts.map +1 -0
  105. package/dist/deltas.js +446 -0
  106. package/dist/deltas.js.map +1 -0
  107. package/dist/mapping.d.ts +38 -20
  108. package/dist/mapping.d.ts.map +1 -1
  109. package/dist/mapping.js +365 -97
  110. package/dist/mapping.js.map +1 -1
  111. package/dist/react/SmoothText.d.ts +5 -0
  112. package/dist/react/SmoothText.d.ts.map +1 -0
  113. package/dist/react/SmoothText.js +6 -0
  114. package/dist/react/SmoothText.js.map +1 -0
  115. package/dist/react/index.d.ts +5 -77
  116. package/dist/react/index.d.ts.map +1 -1
  117. package/dist/react/index.js +6 -160
  118. package/dist/react/index.js.map +1 -1
  119. package/dist/react/optimisticallySendMessage.d.ts +36 -3
  120. package/dist/react/optimisticallySendMessage.d.ts.map +1 -1
  121. package/dist/react/optimisticallySendMessage.js +35 -9
  122. package/dist/react/optimisticallySendMessage.js.map +1 -1
  123. package/dist/react/types.d.ts +4 -18
  124. package/dist/react/types.d.ts.map +1 -1
  125. package/dist/react/useDeltaStreams.d.ts +10 -0
  126. package/dist/react/useDeltaStreams.d.ts.map +1 -0
  127. package/dist/react/useDeltaStreams.js +106 -0
  128. package/dist/react/useDeltaStreams.js.map +1 -0
  129. package/dist/react/useSmoothText.d.ts +13 -12
  130. package/dist/react/useSmoothText.d.ts.map +1 -1
  131. package/dist/react/useSmoothText.js +32 -15
  132. package/dist/react/useSmoothText.js.map +1 -1
  133. package/dist/react/useStreamingUIMessages.d.ts +22 -0
  134. package/dist/react/useStreamingUIMessages.d.ts.map +1 -0
  135. package/dist/react/useStreamingUIMessages.js +92 -0
  136. package/dist/react/useStreamingUIMessages.js.map +1 -0
  137. package/dist/react/useThreadMessages.d.ts +104 -0
  138. package/dist/react/useThreadMessages.d.ts.map +1 -0
  139. package/dist/react/useThreadMessages.js +148 -0
  140. package/dist/react/useThreadMessages.js.map +1 -0
  141. package/dist/react/useUIMessages.d.ts +96 -0
  142. package/dist/react/useUIMessages.d.ts.map +1 -0
  143. package/dist/react/useUIMessages.js +108 -0
  144. package/dist/react/useUIMessages.js.map +1 -0
  145. package/dist/shared.d.ts +20 -4
  146. package/dist/shared.d.ts.map +1 -1
  147. package/dist/shared.js +45 -8
  148. package/dist/shared.js.map +1 -1
  149. package/dist/validators.d.ts +22981 -5666
  150. package/dist/validators.d.ts.map +1 -1
  151. package/dist/validators.js +245 -137
  152. package/dist/validators.js.map +1 -1
  153. package/package.json +101 -51
  154. package/src/UIMessages.combineUIMessages.test.ts +239 -0
  155. package/src/UIMessages.test.ts +273 -0
  156. package/src/UIMessages.ts +739 -0
  157. package/src/client/approval.test.ts +350 -0
  158. package/src/client/createTool.ts +291 -76
  159. package/src/client/defaultComponent.ts +17 -0
  160. package/src/client/definePlaygroundAPI.ts +67 -31
  161. package/src/client/files.ts +100 -20
  162. package/src/client/index.test.ts +40 -85
  163. package/src/client/index.ts +638 -1289
  164. package/src/client/messages.ts +237 -0
  165. package/src/client/mockModel.ts +252 -0
  166. package/src/client/saveInputMessages.test.ts +583 -0
  167. package/src/client/saveInputMessages.ts +101 -0
  168. package/src/client/search.test.ts +1207 -0
  169. package/src/client/search.ts +581 -70
  170. package/src/client/start.ts +327 -0
  171. package/src/client/streamText.ts +187 -0
  172. package/src/client/streaming.test.ts +186 -0
  173. package/src/client/streaming.ts +241 -97
  174. package/src/client/threads.ts +83 -0
  175. package/src/client/types.ts +370 -219
  176. package/src/client/utils.ts +27 -0
  177. package/src/component/_generated/api.ts +64 -0
  178. package/src/component/_generated/component.ts +4902 -0
  179. package/src/component/_generated/{server.d.ts → server.ts} +33 -21
  180. package/src/component/files.ts +11 -2
  181. package/src/component/messages.test.ts +195 -51
  182. package/src/component/messages.ts +500 -201
  183. package/src/component/schema.ts +20 -46
  184. package/src/component/setup.test.ts +7 -0
  185. package/src/component/streams.ts +184 -83
  186. package/src/component/users.test.ts +0 -1
  187. package/src/component/vector/index.ts +1 -3
  188. package/src/deltas.test.ts +626 -0
  189. package/src/deltas.ts +569 -0
  190. package/src/fromUIMessages.test.ts +497 -0
  191. package/src/mapping.test.ts +180 -6
  192. package/src/mapping.ts +479 -162
  193. package/src/react/SmoothText.tsx +9 -0
  194. package/src/react/index.ts +10 -230
  195. package/src/react/optimisticallySendMessage.ts +55 -12
  196. package/src/react/types.ts +6 -39
  197. package/src/react/useDeltaStreams.ts +160 -0
  198. package/src/react/useSmoothText.ts +56 -36
  199. package/src/react/useStreamingUIMessages.ts +143 -0
  200. package/src/react/useThreadMessages.ts +262 -0
  201. package/src/react/useUIMessages.test.ts +255 -0
  202. package/src/react/useUIMessages.ts +195 -0
  203. package/src/shared.ts +88 -12
  204. package/src/test.ts +18 -0
  205. package/src/toUIMessages.test.ts +1269 -0
  206. package/src/validators.test.ts +18 -19
  207. package/src/validators.ts +325 -185
  208. package/dist/client/_generated/_ignore.d.ts +0 -1
  209. package/dist/client/_generated/_ignore.d.ts.map +0 -1
  210. package/dist/client/_generated/_ignore.js +0 -3
  211. package/dist/client/_generated/_ignore.js.map +0 -1
  212. package/dist/client/listMessages.d.ts +0 -22
  213. package/dist/client/listMessages.d.ts.map +0 -1
  214. package/dist/client/listMessages.js +0 -25
  215. package/dist/client/listMessages.js.map +0 -1
  216. package/dist/package.json +0 -3
  217. package/dist/react/deltas.d.ts +0 -26
  218. package/dist/react/deltas.d.ts.map +0 -1
  219. package/dist/react/deltas.js +0 -384
  220. package/dist/react/deltas.js.map +0 -1
  221. package/dist/react/toUIMessages.d.ts +0 -15
  222. package/dist/react/toUIMessages.d.ts.map +0 -1
  223. package/dist/react/toUIMessages.js +0 -211
  224. package/dist/react/toUIMessages.js.map +0 -1
  225. package/src/client/listMessages.ts +0 -38
  226. package/src/component/_generated/api.d.ts +0 -2202
  227. package/src/component/_generated/api.js +0 -23
  228. package/src/component/_generated/server.js +0 -90
  229. package/src/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
  230. package/src/react/deltas.test.ts +0 -315
  231. package/src/react/deltas.ts +0 -478
  232. package/src/react/toUIMessages.test.ts +0 -420
  233. package/src/react/toUIMessages.ts +0 -253
  234. package/src/vitest.config.ts +0 -7
  235. /package/src/component/_generated/{dataModel.d.ts → dataModel.ts} +0 -0
@@ -0,0 +1,106 @@
1
+ "use client";
2
+ import { sorted } from "../shared.js";
3
+ import { useQuery } from "convex/react";
4
+ import { useState } from "react";
5
+ import { assert } from "convex-helpers";
6
+ export function useDeltaStreams(query, args, options) {
7
+ // We hold onto and modify state directly to avoid re-running unnecessarily.
8
+ const [state] = useState({
9
+ startOrder: options?.startOrder ?? 0,
10
+ deltaStreams: undefined,
11
+ threadId: args === "skip" ? undefined : args.threadId,
12
+ });
13
+ const [cursors, setCursors] = useState({});
14
+ if (args !== "skip" && state.threadId !== args.threadId) {
15
+ state.threadId = args.threadId;
16
+ state.deltaStreams = undefined;
17
+ state.startOrder = options?.startOrder ?? 0;
18
+ setCursors({});
19
+ }
20
+ if (state.deltaStreams?.length ||
21
+ (options?.startOrder && options.startOrder < state.startOrder)) {
22
+ const cacheFriendlyStartOrder = options?.startOrder
23
+ ? // round down to the nearest 10 for some cache benefits
24
+ options.startOrder - (options.startOrder % 10)
25
+ : 0;
26
+ if (cacheFriendlyStartOrder !== state.startOrder) {
27
+ state.startOrder = cacheFriendlyStartOrder;
28
+ }
29
+ }
30
+ // Get all the active streams
31
+ const streamList = useQuery(query, args === "skip"
32
+ ? args
33
+ : {
34
+ ...args,
35
+ streamArgs: {
36
+ kind: "list",
37
+ startOrder: state.startOrder,
38
+ },
39
+ });
40
+ const streamMessages = args === "skip"
41
+ ? undefined
42
+ : !streamList
43
+ ? state.deltaStreams?.map(({ streamMessage }) => streamMessage)
44
+ : sorted(streamList.streams.messages.filter(({ streamId, order }) => !options?.skipStreamIds?.includes(streamId) &&
45
+ (!options?.startOrder || order >= options.startOrder)));
46
+ // When no active streams remain, clear the stale state so we stop
47
+ // returning old streaming UIMessages.
48
+ if (streamMessages !== undefined && streamMessages.length === 0) {
49
+ state.deltaStreams = undefined;
50
+ }
51
+ // Get the deltas for all the active streams, if any.
52
+ const cursorQuery = useQuery(query, args === "skip" || !streamMessages?.length
53
+ ? "skip"
54
+ : {
55
+ ...args,
56
+ streamArgs: {
57
+ kind: "deltas",
58
+ cursors: streamMessages.map(({ streamId }) => ({
59
+ streamId,
60
+ cursor: cursors[streamId] ?? 0,
61
+ })),
62
+ },
63
+ });
64
+ const newDeltas = cursorQuery?.streams.deltas;
65
+ if (newDeltas?.length && streamMessages) {
66
+ const newDeltasByStreamId = new Map();
67
+ for (const delta of newDeltas) {
68
+ const oldCursor = cursors[delta.streamId];
69
+ if (oldCursor && delta.start < oldCursor)
70
+ continue;
71
+ const existing = newDeltasByStreamId.get(delta.streamId);
72
+ if (existing) {
73
+ const previousEnd = existing.at(-1).end;
74
+ assert(previousEnd === delta.start, `Gap found in deltas for ${delta.streamId} jumping to ${delta.start} from ${previousEnd}`);
75
+ existing.push(delta);
76
+ }
77
+ else {
78
+ assert(!oldCursor || oldCursor === delta.start, `Gap found - first delta after ${oldCursor} is ${delta.start} for stream ${delta.streamId}`);
79
+ newDeltasByStreamId.set(delta.streamId, [delta]);
80
+ }
81
+ }
82
+ const newCursors = {};
83
+ for (const { streamId } of streamMessages) {
84
+ const cursor = newDeltasByStreamId.get(streamId)?.at(-1)?.end ?? cursors[streamId];
85
+ if (cursor !== undefined) {
86
+ newCursors[streamId] = cursor;
87
+ }
88
+ }
89
+ setCursors(newCursors);
90
+ // we defensively create a new object so object identity matches contents
91
+ state.deltaStreams = streamMessages.map((streamMessage) => {
92
+ const streamId = streamMessage.streamId;
93
+ const old = state.deltaStreams?.find((ds) => ds.streamMessage.streamId === streamId);
94
+ const newDeltas = newDeltasByStreamId.get(streamId);
95
+ if (!newDeltas && streamMessage === old?.streamMessage) {
96
+ return old;
97
+ }
98
+ return {
99
+ streamMessage,
100
+ deltas: [...(old?.deltas ?? []), ...(newDeltas ?? [])],
101
+ };
102
+ });
103
+ }
104
+ return state.deltaStreams;
105
+ }
106
+ //# sourceMappingURL=useDeltaStreams.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDeltaStreams.js","sourceRoot":"","sources":["../../src/react/useDeltaStreams.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,4 @@
1
- /**
2
- * A hook that smoothly displays text as it is streamed.
3
- *
4
- * @param text The text to display. Pass in the full text each time.
5
- * @param charsPerSec The number of characters to display per second.
6
- * @returns A tuple of the visible text and the state of the smooth text,
7
- * including the current cursor position and whether it's still streaming.
8
- * This allows you to decide if it's too far behind and you want to adjust
9
- * the charsPerSec or just prefer the full text.
10
- */
11
- export declare function useSmoothText(text: string, { charsPerSec, startStreaming, }?: {
1
+ export type SmoothTextOptions = {
12
2
  /**
13
3
  * The number of characters to display per second.
14
4
  */
@@ -19,7 +9,18 @@ export declare function useSmoothText(text: string, { charsPerSec, startStreamin
19
9
  * This will start streaming the first value it sees.
20
10
  */
21
11
  startStreaming?: boolean;
22
- }): [string, {
12
+ };
13
+ /**
14
+ * A hook that smoothly displays text as it is streamed.
15
+ *
16
+ * @param text The text to display. Pass in the full text each time.
17
+ * @param charsPerSec The number of characters to display per second.
18
+ * @returns A tuple of the visible text and the state of the smooth text,
19
+ * including the current cursor position and whether it's still streaming.
20
+ * This allows you to decide if it's too far behind and you want to adjust
21
+ * the charsPerSec or just prefer the full text.
22
+ */
23
+ export declare function useSmoothText(text: string, { charsPerSec, startStreaming, }?: SmoothTextOptions): [string, {
23
24
  cursor: number;
24
25
  isStreaming: boolean;
25
26
  }];
@@ -1 +1 @@
1
- {"version":3,"file":"useSmoothText.d.ts","sourceRoot":"","sources":["../../src/react/useSmoothText.ts"],"names":[],"mappings":"AAKA;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,EACE,WAAiB,EACjB,cAAsB,GACvB,GAAE;IACD;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CACrB,GACL,CAAC,MAAM,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,CAAC,CAsDpD"}
1
+ {"version":3,"file":"useSmoothText.d.ts","sourceRoot":"","sources":["../../src/react/useSmoothText.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;AACF;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,EACE,WAAmC,EACnC,cAAsB,GACvB,GAAE,iBAAsB,GACxB,CAAC,MAAM,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,CAAC,CAwEpD"}
@@ -1,7 +1,7 @@
1
1
  import { useEffect, useRef, useState } from "react";
2
2
  const FPS = 20;
3
3
  const MS_PER_FRAME = 1000 / FPS;
4
- const MAX_TIME_JUMP_MS = 250;
4
+ const INITIAL_CHARS_PER_SEC = 128;
5
5
  /**
6
6
  * A hook that smoothly displays text as it is streamed.
7
7
  *
@@ -12,34 +12,51 @@ const MAX_TIME_JUMP_MS = 250;
12
12
  * This allows you to decide if it's too far behind and you want to adjust
13
13
  * the charsPerSec or just prefer the full text.
14
14
  */
15
- export function useSmoothText(text, { charsPerSec = 256, startStreaming = false, } = {}) {
16
- const [visibleText, setVisibleText] = useState(startStreaming ? "" : text);
15
+ export function useSmoothText(text, { charsPerSec = INITIAL_CHARS_PER_SEC, startStreaming = false, } = {}) {
16
+ const [visibleText, setVisibleText] = useState(startStreaming ? "" : text || "");
17
17
  const smoothState = useRef({
18
- tick: Date.now() + (visibleText.length * 1000) / charsPerSec,
18
+ tick: Date.now(),
19
19
  cursor: visibleText.length,
20
- start: Date.now(),
21
- initialLength: visibleText.length,
20
+ lastUpdate: Date.now(),
21
+ lastUpdateLength: text.length,
22
22
  charsPerMs: charsPerSec / 1000,
23
+ initial: true,
23
24
  });
24
25
  const isStreaming = smoothState.current.cursor < text.length;
25
26
  useEffect(() => {
26
27
  if (!isStreaming) {
27
28
  return;
28
29
  }
29
- const latestCharsPerMs = (text.length - smoothState.current.initialLength) /
30
- (Date.now() - smoothState.current.start);
31
- // Smooth out the charsPerSec by averaging it with the previous value.
32
- smoothState.current.charsPerMs = Math.min((2 * latestCharsPerMs + smoothState.current.charsPerMs) / 3, smoothState.current.charsPerMs * 2);
33
- smoothState.current.tick = Math.max(smoothState.current.tick, Date.now() - 2 * MS_PER_FRAME);
30
+ if (smoothState.current.lastUpdateLength !== text.length) {
31
+ const timeSinceLastUpdate = Date.now() - smoothState.current.lastUpdate;
32
+ const latestCharsPerMs = (text.length - smoothState.current.lastUpdateLength) /
33
+ timeSinceLastUpdate;
34
+ // Is the rate increasing?
35
+ const rateError = latestCharsPerMs - smoothState.current.charsPerMs;
36
+ // Is our visible text falling behind what it could show?
37
+ const charLag = smoothState.current.lastUpdateLength - smoothState.current.cursor;
38
+ const lagRate = charLag / timeSinceLastUpdate;
39
+ const charsPerMs = latestCharsPerMs +
40
+ (smoothState.current.initial
41
+ ? 0
42
+ : Math.max(0, (rateError + lagRate) / 2));
43
+ smoothState.current.initial = false;
44
+ // Smooth out the charsPerSec by weighting it with the previous value.
45
+ smoothState.current.charsPerMs = Math.min((2 * charsPerMs + smoothState.current.charsPerMs) / 3, smoothState.current.charsPerMs * 2);
46
+ }
47
+ smoothState.current.tick = Math.max(smoothState.current.tick, Date.now() - MS_PER_FRAME);
48
+ smoothState.current.lastUpdate = Date.now();
49
+ smoothState.current.lastUpdateLength = text.length;
34
50
  function update() {
35
51
  if (smoothState.current.cursor >= text.length) {
36
52
  return;
37
53
  }
38
54
  const now = Date.now();
39
- const timeSinceLastUpdate = Math.min(MAX_TIME_JUMP_MS, now - smoothState.current.tick);
40
- const chars = Math.floor(timeSinceLastUpdate * smoothState.current.charsPerMs);
41
- smoothState.current.cursor = Math.min(smoothState.current.cursor + chars, text.length);
42
- smoothState.current.tick = now;
55
+ const timeSinceLastUpdate = now - smoothState.current.tick;
56
+ const charsSinceLastUpdate = Math.floor(timeSinceLastUpdate * smoothState.current.charsPerMs);
57
+ const chars = Math.min(charsSinceLastUpdate, text.length - smoothState.current.cursor);
58
+ smoothState.current.cursor += chars;
59
+ smoothState.current.tick += chars / smoothState.current.charsPerMs;
43
60
  setVisibleText(text.slice(0, smoothState.current.cursor));
44
61
  }
45
62
  update();
@@ -1 +1 @@
1
- {"version":3,"file":"useSmoothText.js","sourceRoot":"","sources":["../../src/react/useSmoothText.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useSmoothText.js","sourceRoot":"","sources":["../../src/react/useSmoothText.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEpD,MAAM,GAAG,GAAG,EAAE,CAAC;AACf,MAAM,YAAY,GAAG,IAAI,GAAG,GAAG,CAAC;AAChC,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAclC;;;;;;;;;GASG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAY,EACZ,EACE,WAAW,GAAG,qBAAqB,EACnC,cAAc,GAAG,KAAK,MACD,EAAE;IAEzB,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAC5C,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CACjC,CAAC;IACF,MAAM,WAAW,GAAG,MAAM,CAAC;QACzB,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE;QAChB,MAAM,EAAE,WAAW,CAAC,MAAM;QAC1B,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE;QACtB,gBAAgB,EAAE,IAAI,CAAC,MAAM;QAC7B,UAAU,EAAE,WAAW,GAAG,IAAI;QAC9B,OAAO,EAAE,IAAI;KACd,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,WAAW,CAAC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IAE7D,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO;QACT,CAAC;QACD,IAAI,WAAW,CAAC,OAAO,CAAC,gBAAgB,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;YACzD,MAAM,mBAAmB,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC;YACxE,MAAM,gBAAgB,GACpB,CAAC,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,gBAAgB,CAAC;gBACpD,mBAAmB,CAAC;YACtB,0BAA0B;YAC1B,MAAM,SAAS,GAAG,gBAAgB,GAAG,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC;YACpE,yDAAyD;YACzD,MAAM,OAAO,GACX,WAAW,CAAC,OAAO,CAAC,gBAAgB,GAAG,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC;YACpE,MAAM,OAAO,GAAG,OAAO,GAAG,mBAAmB,CAAC;YAC9C,MAAM,UAAU,GACd,gBAAgB;gBAChB,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO;oBAC1B,CAAC,CAAC,CAAC;oBACH,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC9C,WAAW,CAAC,OAAO,CAAC,OAAO,GAAG,KAAK,CAAC;YACpC,sEAAsE;YACtE,WAAW,CAAC,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CACvC,CAAC,CAAC,GAAG,UAAU,GAAG,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EACrD,WAAW,CAAC,OAAO,CAAC,UAAU,GAAG,CAAC,CACnC,CAAC;QACJ,CAAC;QACD,WAAW,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CACjC,WAAW,CAAC,OAAO,CAAC,IAAI,EACxB,IAAI,CAAC,GAAG,EAAE,GAAG,YAAY,CAC1B,CAAC;QACF,WAAW,CAAC,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC5C,WAAW,CAAC,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,MAAM,CAAC;QAEnD,SAAS,MAAM;YACb,IAAI,WAAW,CAAC,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAC9C,OAAO;YACT,CAAC;YACD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvB,MAAM,mBAAmB,GAAG,GAAG,GAAG,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC;YAC3D,MAAM,oBAAoB,GAAG,IAAI,CAAC,KAAK,CACrC,mBAAmB,GAAG,WAAW,CAAC,OAAO,CAAC,UAAU,CACrD,CAAC;YACF,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CACpB,oBAAoB,EACpB,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,MAAM,CACzC,CAAC;YACF,WAAW,CAAC,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC;YACpC,WAAW,CAAC,OAAO,CAAC,IAAI,IAAI,KAAK,GAAG,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC;YACnE,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;QAC5D,CAAC;QACD,MAAM,EAAE,CAAC;QACT,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QACnD,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IACvC,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC;IAErC,OAAO,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;AAC5E,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { type UIDataTypes, type UITools } from "ai";
2
+ import type { StreamQuery, StreamQueryArgs } from "./types.js";
3
+ import { type UIMessage } from "../UIMessages.js";
4
+ /**
5
+ * A hook that fetches streaming messages from a thread and converts them to UIMessages
6
+ * using AI SDK's readUIMessageStream.
7
+ * This ONLY returns streaming UIMessages. To get both full and streaming messages,
8
+ * use `useUIMessages`.
9
+ *
10
+ * @param query The query to use to fetch messages.
11
+ * It must take as arguments `{ threadId, paginationOpts, streamArgs }` and
12
+ * return a `streams` object returned from `agent.syncStreams`.
13
+ * @param args The arguments to pass to the query other than `paginationOpts`
14
+ * and `streamArgs`. So `{ threadId }` at minimum, plus any other arguments that
15
+ * you want to pass to the query.
16
+ * @returns The streaming UIMessages.
17
+ */
18
+ export declare function useStreamingUIMessages<METADATA = unknown, DATA_PARTS extends UIDataTypes = UIDataTypes, TOOLS extends UITools = UITools, Query extends StreamQuery<any> = StreamQuery<object>>(query: Query, args: StreamQueryArgs<Query> | "skip", options?: {
19
+ startOrder?: number;
20
+ skipStreamIds?: string[];
21
+ }): UIMessage<METADATA, DATA_PARTS, TOOLS>[] | undefined;
22
+ //# sourceMappingURL=useStreamingUIMessages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStreamingUIMessages.d.ts","sourceRoot":"","sources":["../../src/react/useStreamingUIMessages.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,WAAW,EAAuB,KAAK,OAAO,EAAE,MAAM,IAAI,CAAC;AACzE,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC/D,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAiBlD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,GAAG,OAAO,EAClB,UAAU,SAAS,WAAW,GAAG,WAAW,EAC5C,KAAK,SAAS,OAAO,GAAG,OAAO,EAC/B,KAAK,SAAS,WAAW,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC,EAEpD,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,eAAe,CAAC,KAAK,CAAC,GAAG,MAAM,EACrC,OAAO,CAAC,EAAE;IACR,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B,GAEA,SAAS,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,CAAC,EAAE,GAAG,SAAS,CA8FtD"}
@@ -0,0 +1,92 @@
1
+ "use client";
2
+ import { useMemo, useState, useEffect } from "react";
3
+ import {} from "ai";
4
+ import {} from "../UIMessages.js";
5
+ import { blankUIMessage, getParts, updateFromUIMessageChunks, deriveUIMessagesFromTextStreamParts, } from "../deltas.js";
6
+ import { useDeltaStreams } from "./useDeltaStreams.js";
7
+ // Polyfill structuredClone to support readUIMessageStream on ReactNative
8
+ if (!("structuredClone" in globalThis)) {
9
+ void import("@ungap/structured-clone").then(({ default: structuredClone }) => (globalThis.structuredClone = structuredClone));
10
+ }
11
+ /**
12
+ * A hook that fetches streaming messages from a thread and converts them to UIMessages
13
+ * using AI SDK's readUIMessageStream.
14
+ * This ONLY returns streaming UIMessages. To get both full and streaming messages,
15
+ * use `useUIMessages`.
16
+ *
17
+ * @param query The query to use to fetch messages.
18
+ * It must take as arguments `{ threadId, paginationOpts, streamArgs }` and
19
+ * return a `streams` object returned from `agent.syncStreams`.
20
+ * @param args The arguments to pass to the query other than `paginationOpts`
21
+ * and `streamArgs`. So `{ threadId }` at minimum, plus any other arguments that
22
+ * you want to pass to the query.
23
+ * @returns The streaming UIMessages.
24
+ */
25
+ export function useStreamingUIMessages(query, args, options) {
26
+ const [messageState, setMessageState] = useState({});
27
+ const streams = useDeltaStreams(query, args, options);
28
+ const threadId = args === "skip" ? undefined : args.threadId;
29
+ useEffect(() => {
30
+ if (!streams)
31
+ return;
32
+ // return if there are no new deltas beyond the cursors
33
+ let noNewDeltas = true;
34
+ for (const stream of streams) {
35
+ const lastDelta = stream.deltas.at(-1);
36
+ const cursor = messageState[stream.streamMessage.streamId]?.cursor;
37
+ if (!cursor) {
38
+ noNewDeltas = false;
39
+ break;
40
+ }
41
+ if (lastDelta && lastDelta.start >= cursor) {
42
+ noNewDeltas = false;
43
+ break;
44
+ }
45
+ }
46
+ if (noNewDeltas) {
47
+ return;
48
+ }
49
+ const abortController = new AbortController();
50
+ void (async () => {
51
+ const newMessageState = Object.fromEntries(await Promise.all(streams.map(async ({ deltas, streamMessage }) => {
52
+ const { parts, cursor } = getParts(deltas, 0);
53
+ if (streamMessage.format === "UIMessageChunk") {
54
+ // Unfortunately this can't handle resuming from a UIMessage and
55
+ // adding more chunks, so we re-create it from scratch each time.
56
+ const uiMessage = await updateFromUIMessageChunks(blankUIMessage(streamMessage, threadId), parts);
57
+ return [
58
+ streamMessage.streamId,
59
+ {
60
+ uiMessage,
61
+ cursor,
62
+ },
63
+ ];
64
+ }
65
+ else {
66
+ const [uiMessages] = deriveUIMessagesFromTextStreamParts(threadId, [streamMessage], [], deltas);
67
+ return [
68
+ streamMessage.streamId,
69
+ {
70
+ uiMessage: uiMessages[0],
71
+ cursor,
72
+ },
73
+ ];
74
+ }
75
+ })));
76
+ if (abortController.signal.aborted)
77
+ return;
78
+ setMessageState(newMessageState);
79
+ })();
80
+ return () => {
81
+ abortController.abort();
82
+ };
83
+ }, [messageState, streams, threadId]);
84
+ return useMemo(() => {
85
+ if (!streams)
86
+ return undefined;
87
+ return streams
88
+ .map(({ streamMessage }) => messageState[streamMessage.streamId]?.uiMessage)
89
+ .filter((uiMessage) => uiMessage !== undefined);
90
+ }, [messageState, streams]);
91
+ }
92
+ //# sourceMappingURL=useStreamingUIMessages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStreamingUIMessages.js","sourceRoot":"","sources":["../../src/react/useStreamingUIMessages.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,104 @@
1
+ import { type BetterOmit, type ErrorMessage, type Expand } from "convex-helpers";
2
+ import { type UsePaginatedQueryResult } from "convex/react";
3
+ import type { FunctionArgs, FunctionReference, PaginationOptions, PaginationResult } from "convex/server";
4
+ import type { SyncStreamsReturnValue } from "../client/types.js";
5
+ import type { Message, MessageDoc, MessageStatus, StreamArgs } from "../validators.js";
6
+ import type { StreamQueryArgs, StreamQuery } from "./types.js";
7
+ export type MessageDocLike = {
8
+ order: number;
9
+ stepOrder: number;
10
+ status: MessageStatus | "streaming";
11
+ message?: Message;
12
+ };
13
+ export type ThreadMessagesQuery<Args = unknown, M extends MessageDocLike = MessageDocLike> = FunctionReference<"query", "public", {
14
+ threadId: string;
15
+ paginationOpts: PaginationOptions;
16
+ /**
17
+ * If { stream: true } is passed, it will also query for stream deltas.
18
+ * In order for this to work, the query must take as an argument streamArgs.
19
+ */
20
+ streamArgs?: StreamArgs;
21
+ } & Args, PaginationResult<M> & {
22
+ streams?: SyncStreamsReturnValue;
23
+ }>;
24
+ export type ThreadMessagesArgs<Query extends ThreadMessagesQuery<unknown, MessageDocLike>> = Query extends ThreadMessagesQuery<unknown, MessageDocLike> ? Expand<BetterOmit<FunctionArgs<Query>, "paginationOpts" | "streamArgs">> : never;
25
+ export type ThreadMessagesResult<Query extends ThreadMessagesQuery<unknown, MessageDocLike>> = Query extends ThreadMessagesQuery<unknown, infer M> ? M : never;
26
+ /**
27
+ * A hook that fetches messages from a thread.
28
+ *
29
+ * This hook is a wrapper around `usePaginatedQuery` and `useStreamingThreadMessages`.
30
+ * It will fetch both full messages and streaming messages, and merge them together.
31
+ *
32
+ * The query must take as arguments `{ threadId, paginationOpts }` and return a
33
+ * pagination result of objects that extend `MessageDoc`.
34
+ *
35
+ * For streaming, it should look like this:
36
+ * ```ts
37
+ * export const listThreadMessages = query({
38
+ * args: {
39
+ * threadId: v.string(),
40
+ * paginationOpts: paginationOptsValidator,
41
+ * streamArgs: vStreamArgs,
42
+ * ... other arguments you want
43
+ * },
44
+ * handler: async (ctx, args) => {
45
+ * // await authorizeThreadAccess(ctx, threadId);
46
+ * // NOTE: listMessages returns MessageDocs, not UIMessages.
47
+ * const paginated = await listMessages(ctx, components.agent, args);
48
+ * const streams = await syncStreams(ctx, components.agent, args);
49
+ * // Here you could filter out / modify the documents & stream deltas.
50
+ * return { ...paginated, streams };
51
+ * },
52
+ * });
53
+ * ```
54
+ *
55
+ * Then the hook can be used like this:
56
+ * ```ts
57
+ * const { results, status, loadMore } = useThreadMessages(
58
+ * api.myModule.listThreadMessages,
59
+ * { threadId },
60
+ * { initialNumItems: 10, stream: true }
61
+ * );
62
+ * ```
63
+ *
64
+ * @param query The query to use to fetch messages.
65
+ * It must take as arguments `{ threadId, paginationOpts }` and return a
66
+ * pagination result of objects that extend `MessageDoc`.
67
+ * To support streaming, it must also take in `streamArgs: vStreamArgs` and
68
+ * return a `streams` object returned from `agent.syncStreams`.
69
+ * @param args The arguments to pass to the query other than `paginationOpts`
70
+ * and `streamArgs`. So `{ threadId }` at minimum, plus any other arguments that
71
+ * you want to pass to the query.
72
+ * @param options The options for the query. Similar to usePaginatedQuery.
73
+ * To enable streaming, pass `stream: true`.
74
+ * @returns The messages. If stream is true, it will return a list of messages
75
+ * that includes both full messages and streaming messages.
76
+ */
77
+ export declare function useThreadMessages<Query extends ThreadMessagesQuery<any, any>>(query: Query, args: ThreadMessagesArgs<Query> | "skip", options: {
78
+ initialNumItems: number;
79
+ stream?: Query extends StreamQuery ? boolean : ErrorMessage<"To enable streaming, your query must take in streamArgs: vStreamArgs and return a streams object returned from syncStreams. See docs.">;
80
+ }): UsePaginatedQueryResult<ThreadMessagesResult<Query> & {
81
+ streaming: boolean;
82
+ key: string;
83
+ }>;
84
+ /**
85
+ * @deprecated FYI `useStreamingUIMessages` is likely better for you.
86
+ * A hook that fetches streaming messages from a thread.
87
+ * This ONLY returns streaming messages. To get both, use `useThreadMessages`.
88
+ *
89
+ * @param query The query to use to fetch messages.
90
+ * It must take as arguments `{ threadId, paginationOpts, streamArgs }` and
91
+ * return a `streams` object returned from `agent.syncStreams`.
92
+ * @param args The arguments to pass to the query other than `paginationOpts`
93
+ * and `streamArgs`. So `{ threadId }` at minimum, plus any other arguments that
94
+ * you want to pass to the query.
95
+ * @returns The streaming messages.
96
+ */
97
+ export declare function useStreamingThreadMessages<Query extends StreamQuery<any>>(query: Query, args: (StreamQueryArgs<Query> & {
98
+ /** @deprecated Pass startOrder to the next argument (third argument). */
99
+ startOrder?: number;
100
+ }) | "skip", options?: {
101
+ startOrder?: number;
102
+ skipStreamIds?: string[];
103
+ }): Array<MessageDoc> | undefined;
104
+ //# sourceMappingURL=useThreadMessages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useThreadMessages.d.ts","sourceRoot":"","sources":["../../src/react/useThreadMessages.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,MAAM,EACZ,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EACV,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EACjB,MAAM,eAAe,CAAC;AAEvB,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAGjE,OAAO,KAAK,EACV,OAAO,EACP,UAAU,EACV,aAAa,EACb,UAAU,EACX,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG/D,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,aAAa,GAAG,WAAW,CAAC;IACpC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,mBAAmB,CAC7B,IAAI,GAAG,OAAO,EACd,CAAC,SAAS,cAAc,GAAG,cAAc,IACvC,iBAAiB,CACnB,OAAO,EACP,QAAQ,EACR;IACE,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,iBAAiB,CAAC;IAClC;;;OAGG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB,GAAG,IAAI,EACR,gBAAgB,CAAC,CAAC,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,sBAAsB,CAAA;CAAE,CAC3D,CAAC;AAEF,MAAM,MAAM,kBAAkB,CAC5B,KAAK,SAAS,mBAAmB,CAAC,OAAO,EAAE,cAAc,CAAC,IAE1D,KAAK,SAAS,mBAAmB,CAAC,OAAO,EAAE,cAAc,CAAC,GACtD,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,gBAAgB,GAAG,YAAY,CAAC,CAAC,GACxE,KAAK,CAAC;AAEZ,MAAM,MAAM,oBAAoB,CAC9B,KAAK,SAAS,mBAAmB,CAAC,OAAO,EAAE,cAAc,CAAC,IACxD,KAAK,SAAS,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAEpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,SAAS,mBAAmB,CAAC,GAAG,EAAE,GAAG,CAAC,EAC3E,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,kBAAkB,CAAC,KAAK,CAAC,GAAG,MAAM,EACxC,OAAO,EAAE;IACP,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,KAAK,SAAS,WAAW,GAC9B,OAAO,GACP,YAAY,CAAC,uIAAuI,CAAC,CAAC;CAC3J,GACA,uBAAuB,CACxB,oBAAoB,CAAC,KAAK,CAAC,GAAG;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAClE,CA4EA;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,SAAS,WAAW,CAAC,GAAG,CAAC,EACvE,KAAK,EAAE,KAAK,EACZ,IAAI,EACA,CAAC,eAAe,CAAC,KAAK,CAAC,GAAG;IACxB,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC,GACF,MAAM,EACV,OAAO,CAAC,EAAE;IACR,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B,GACA,KAAK,CAAC,UAAU,CAAC,GAAG,SAAS,CA6B/B"}
@@ -0,0 +1,148 @@
1
+ "use client";
2
+ import { omit, } from "convex-helpers";
3
+ import { usePaginatedQuery } from "convex-helpers/react";
4
+ import {} from "convex/react";
5
+ import { useMemo, useState, useEffect, useRef } from "react";
6
+ import { sorted } from "../shared.js";
7
+ import { fromUIMessages } from "../UIMessages.js";
8
+ import { useStreamingUIMessages } from "./useStreamingUIMessages.js";
9
+ /**
10
+ * A hook that fetches messages from a thread.
11
+ *
12
+ * This hook is a wrapper around `usePaginatedQuery` and `useStreamingThreadMessages`.
13
+ * It will fetch both full messages and streaming messages, and merge them together.
14
+ *
15
+ * The query must take as arguments `{ threadId, paginationOpts }` and return a
16
+ * pagination result of objects that extend `MessageDoc`.
17
+ *
18
+ * For streaming, it should look like this:
19
+ * ```ts
20
+ * export const listThreadMessages = query({
21
+ * args: {
22
+ * threadId: v.string(),
23
+ * paginationOpts: paginationOptsValidator,
24
+ * streamArgs: vStreamArgs,
25
+ * ... other arguments you want
26
+ * },
27
+ * handler: async (ctx, args) => {
28
+ * // await authorizeThreadAccess(ctx, threadId);
29
+ * // NOTE: listMessages returns MessageDocs, not UIMessages.
30
+ * const paginated = await listMessages(ctx, components.agent, args);
31
+ * const streams = await syncStreams(ctx, components.agent, args);
32
+ * // Here you could filter out / modify the documents & stream deltas.
33
+ * return { ...paginated, streams };
34
+ * },
35
+ * });
36
+ * ```
37
+ *
38
+ * Then the hook can be used like this:
39
+ * ```ts
40
+ * const { results, status, loadMore } = useThreadMessages(
41
+ * api.myModule.listThreadMessages,
42
+ * { threadId },
43
+ * { initialNumItems: 10, stream: true }
44
+ * );
45
+ * ```
46
+ *
47
+ * @param query The query to use to fetch messages.
48
+ * It must take as arguments `{ threadId, paginationOpts }` and return a
49
+ * pagination result of objects that extend `MessageDoc`.
50
+ * To support streaming, it must also take in `streamArgs: vStreamArgs` and
51
+ * return a `streams` object returned from `agent.syncStreams`.
52
+ * @param args The arguments to pass to the query other than `paginationOpts`
53
+ * and `streamArgs`. So `{ threadId }` at minimum, plus any other arguments that
54
+ * you want to pass to the query.
55
+ * @param options The options for the query. Similar to usePaginatedQuery.
56
+ * To enable streaming, pass `stream: true`.
57
+ * @returns The messages. If stream is true, it will return a list of messages
58
+ * that includes both full messages and streaming messages.
59
+ */
60
+ export function useThreadMessages(query, args, options) {
61
+ // These are full messages
62
+ const paginated = usePaginatedQuery(query, args, { initialNumItems: options.initialNumItems });
63
+ let startOrder = paginated.results.at(-1)?.order ?? 0;
64
+ for (let i = paginated.results.length - 1; i >= 0; i--) {
65
+ const m = paginated.results[i];
66
+ if (!m.streaming && m.status === "pending") {
67
+ // round down to the nearest 10 for some cache benefits
68
+ startOrder = m.order - (m.order % 10);
69
+ break;
70
+ }
71
+ }
72
+ // These are streaming messages that will not include full messages.
73
+ const streamMessages = useStreamingThreadMessages(query, !options.stream ||
74
+ args === "skip" ||
75
+ paginated.status === "LoadingFirstPage"
76
+ ? "skip"
77
+ : { ...args, paginationOpts: { cursor: null, numItems: 0 } }, { startOrder });
78
+ const threadId = args === "skip" ? undefined : args.threadId;
79
+ const merged = useMemo(() => {
80
+ const streamListMessages = streamMessages?.map((m) => ({
81
+ ...m,
82
+ streaming: !m.status || m.status === "pending",
83
+ })) ?? [];
84
+ return {
85
+ ...paginated,
86
+ results: sorted(paginated.results
87
+ .map((m) => ({ ...m, streaming: false }))
88
+ // Note: this is intentionally after paginated results.
89
+ .concat(streamListMessages)).reduce((msgs, msg) => {
90
+ msg.key = `${threadId}-${msg.order}-${msg.stepOrder}`;
91
+ const last = msgs.at(-1);
92
+ if (!last) {
93
+ return [msg];
94
+ }
95
+ if (last.order !== msg.order || last.stepOrder !== msg.stepOrder) {
96
+ return [...msgs, msg];
97
+ }
98
+ if (last.status === "pending" &&
99
+ (msg.streaming || msg.status !== "pending")) {
100
+ // Let's prefer a streaming or finalized message over a pending
101
+ // one.
102
+ return [...msgs.slice(0, -1), msg];
103
+ }
104
+ // skip the new one if the previous one (listed) was finalized
105
+ return msgs;
106
+ }, []),
107
+ };
108
+ }, [paginated, streamMessages, threadId]);
109
+ return merged;
110
+ }
111
+ /**
112
+ * @deprecated FYI `useStreamingUIMessages` is likely better for you.
113
+ * A hook that fetches streaming messages from a thread.
114
+ * This ONLY returns streaming messages. To get both, use `useThreadMessages`.
115
+ *
116
+ * @param query The query to use to fetch messages.
117
+ * It must take as arguments `{ threadId, paginationOpts, streamArgs }` and
118
+ * return a `streams` object returned from `agent.syncStreams`.
119
+ * @param args The arguments to pass to the query other than `paginationOpts`
120
+ * and `streamArgs`. So `{ threadId }` at minimum, plus any other arguments that
121
+ * you want to pass to the query.
122
+ * @returns The streaming messages.
123
+ */
124
+ export function useStreamingThreadMessages(query, args, options) {
125
+ const queryArgs = args === "skip"
126
+ ? args
127
+ : omit(args, ["startOrder"]);
128
+ const startOrder = args === "skip" ? undefined : (args.startOrder ?? undefined);
129
+ const queryOptions = { startOrder, ...options };
130
+ const uiMessages = useStreamingUIMessages(query, queryArgs, queryOptions);
131
+ const [messages, setMessages] = useState();
132
+ const generationRef = useRef(0);
133
+ useEffect(() => {
134
+ if (args === "skip" || !uiMessages) {
135
+ setMessages(undefined);
136
+ return;
137
+ }
138
+ const currentGeneration = ++generationRef.current;
139
+ (async () => {
140
+ const nested = await Promise.all(uiMessages.map((m) => fromUIMessages([m], { threadId: args.threadId })));
141
+ if (generationRef.current === currentGeneration) {
142
+ setMessages(nested.flat());
143
+ }
144
+ })();
145
+ }, [uiMessages, args === "skip" ? undefined : args.threadId]);
146
+ return messages;
147
+ }
148
+ //# sourceMappingURL=useThreadMessages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useThreadMessages.js","sourceRoot":"","sources":["../../src/react/useThreadMessages.ts"],"names":[],"mappings":"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"}