@convex-dev/agent 0.1.6 → 0.1.7-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 (106) hide show
  1. package/README.md +23 -12
  2. package/dist/commonjs/client/_generated/_ignore.d.ts +1 -0
  3. package/dist/commonjs/client/_generated/_ignore.d.ts.map +1 -0
  4. package/dist/commonjs/client/_generated/_ignore.js +3 -0
  5. package/dist/commonjs/client/_generated/_ignore.js.map +1 -0
  6. package/dist/commonjs/client/files.d.ts +57 -0
  7. package/dist/commonjs/client/files.d.ts.map +1 -0
  8. package/dist/commonjs/client/files.js +124 -0
  9. package/dist/commonjs/client/files.js.map +1 -0
  10. package/dist/commonjs/client/index.d.ts +487 -318
  11. package/dist/commonjs/client/index.d.ts.map +1 -1
  12. package/dist/commonjs/client/index.js +652 -550
  13. package/dist/commonjs/client/index.js.map +1 -1
  14. package/dist/commonjs/client/types.d.ts +35 -5
  15. package/dist/commonjs/client/types.d.ts.map +1 -1
  16. package/dist/commonjs/component/_generated/api.d.ts +47 -711
  17. package/dist/commonjs/component/files.d.ts +66 -21
  18. package/dist/commonjs/component/files.d.ts.map +1 -1
  19. package/dist/commonjs/component/files.js +71 -26
  20. package/dist/commonjs/component/files.js.map +1 -1
  21. package/dist/commonjs/component/messages.d.ts +31 -499
  22. package/dist/commonjs/component/messages.d.ts.map +1 -1
  23. package/dist/commonjs/component/messages.js +45 -125
  24. package/dist/commonjs/component/messages.js.map +1 -1
  25. package/dist/commonjs/component/schema.d.ts +949 -3785
  26. package/dist/commonjs/component/schema.d.ts.map +1 -1
  27. package/dist/commonjs/component/schema.js +9 -25
  28. package/dist/commonjs/component/schema.js.map +1 -1
  29. package/dist/commonjs/component/streams.d.ts +3 -3
  30. package/dist/commonjs/mapping.d.ts +28 -19
  31. package/dist/commonjs/mapping.d.ts.map +1 -1
  32. package/dist/commonjs/mapping.js +136 -81
  33. package/dist/commonjs/mapping.js.map +1 -1
  34. package/dist/commonjs/react/toUIMessages.d.ts.map +1 -1
  35. package/dist/commonjs/react/toUIMessages.js +12 -6
  36. package/dist/commonjs/react/toUIMessages.js.map +1 -1
  37. package/dist/commonjs/react/usePaginatedQuery.d.ts.map +1 -1
  38. package/dist/commonjs/react/usePaginatedQuery.js +0 -19
  39. package/dist/commonjs/react/usePaginatedQuery.js.map +1 -1
  40. package/dist/commonjs/validators.d.ts +851 -3388
  41. package/dist/commonjs/validators.d.ts.map +1 -1
  42. package/dist/commonjs/validators.js +11 -37
  43. package/dist/commonjs/validators.js.map +1 -1
  44. package/dist/commonjs.tsbuildinfo +1 -1
  45. package/dist/esm/client/_generated/_ignore.d.ts +1 -0
  46. package/dist/esm/client/_generated/_ignore.d.ts.map +1 -0
  47. package/dist/esm/client/_generated/_ignore.js +3 -0
  48. package/dist/esm/client/_generated/_ignore.js.map +1 -0
  49. package/dist/esm/client/files.d.ts +57 -0
  50. package/dist/esm/client/files.d.ts.map +1 -0
  51. package/dist/esm/client/files.js +124 -0
  52. package/dist/esm/client/files.js.map +1 -0
  53. package/dist/esm/client/index.d.ts +487 -318
  54. package/dist/esm/client/index.d.ts.map +1 -1
  55. package/dist/esm/client/index.js +652 -550
  56. package/dist/esm/client/index.js.map +1 -1
  57. package/dist/esm/client/types.d.ts +35 -5
  58. package/dist/esm/client/types.d.ts.map +1 -1
  59. package/dist/esm/component/_generated/api.d.ts +47 -711
  60. package/dist/esm/component/files.d.ts +66 -21
  61. package/dist/esm/component/files.d.ts.map +1 -1
  62. package/dist/esm/component/files.js +71 -26
  63. package/dist/esm/component/files.js.map +1 -1
  64. package/dist/esm/component/messages.d.ts +31 -499
  65. package/dist/esm/component/messages.d.ts.map +1 -1
  66. package/dist/esm/component/messages.js +45 -125
  67. package/dist/esm/component/messages.js.map +1 -1
  68. package/dist/esm/component/schema.d.ts +949 -3785
  69. package/dist/esm/component/schema.d.ts.map +1 -1
  70. package/dist/esm/component/schema.js +9 -25
  71. package/dist/esm/component/schema.js.map +1 -1
  72. package/dist/esm/component/streams.d.ts +3 -3
  73. package/dist/esm/mapping.d.ts +28 -19
  74. package/dist/esm/mapping.d.ts.map +1 -1
  75. package/dist/esm/mapping.js +136 -81
  76. package/dist/esm/mapping.js.map +1 -1
  77. package/dist/esm/react/toUIMessages.d.ts.map +1 -1
  78. package/dist/esm/react/toUIMessages.js +12 -6
  79. package/dist/esm/react/toUIMessages.js.map +1 -1
  80. package/dist/esm/react/usePaginatedQuery.d.ts.map +1 -1
  81. package/dist/esm/react/usePaginatedQuery.js +0 -19
  82. package/dist/esm/react/usePaginatedQuery.js.map +1 -1
  83. package/dist/esm/validators.d.ts +851 -3388
  84. package/dist/esm/validators.d.ts.map +1 -1
  85. package/dist/esm/validators.js +11 -37
  86. package/dist/esm/validators.js.map +1 -1
  87. package/dist/esm.tsbuildinfo +1 -1
  88. package/package.json +11 -9
  89. package/src/client/_generated/_ignore.ts +1 -0
  90. package/src/client/files.ts +167 -0
  91. package/src/client/index.test.ts +127 -1
  92. package/src/client/index.ts +970 -812
  93. package/src/client/setup.test.ts +29 -0
  94. package/src/client/types.ts +41 -3
  95. package/src/component/_generated/api.d.ts +47 -711
  96. package/src/component/files.test.ts +130 -0
  97. package/src/component/files.ts +83 -27
  98. package/src/component/messages.test.ts +2 -1
  99. package/src/component/messages.ts +47 -137
  100. package/src/component/schema.ts +8 -28
  101. package/src/mapping.test.ts +163 -0
  102. package/src/mapping.ts +173 -103
  103. package/src/react/deltas.test.ts +4 -1
  104. package/src/react/toUIMessages.ts +12 -6
  105. package/src/react/usePaginatedQuery.ts +0 -31
  106. package/src/validators.ts +33 -47
package/README.md CHANGED
@@ -253,22 +253,15 @@ and have them all saved (vs. just the last one), or avoid saving any input
253
253
  or output messages, you can pass in a `storageOptions` object, either to the
254
254
  Agent constructor or per-message.
255
255
 
256
- The usecase for passing multiple messages is if you want to include some extra
257
- messages for context to the LLM, but only the last message is the user's actual
258
- request. e.g. `messages = [...messagesFromRag, messageFromUser]`.
256
+ The usecase for passing in multiple messages but not saving them is if you want
257
+ to include some extra messages for context to the LLM, but only the last message
258
+ is the user's actual request. e.g. `messages = [...messagesFromRag, messageFromUser]`.
259
+ The default is to save the prompt and all output messages.
259
260
 
260
261
  ```ts
261
262
  const result = await thread.generateText({ messages }, {
262
- // The default values are shown below.
263
263
  storageOptions: {
264
- // When false, allows you to pass in arbitrary context that will
265
- // be in addition to automatically fetched content.
266
- // Pass true to have all input messages saved to the thread history.
267
- saveAllInputMessages: false,
268
- // By default it saves the input message, or the last message if multiple are provided.
269
- saveAnyInputMessages: true,
270
- // Save the generated messages to the thread history.
271
- saveOutputMessages: true,
264
+ saveMessages: "all" | "none" | "promptAndOutput";
272
265
  },
273
266
  });
274
267
  ```
@@ -630,6 +623,24 @@ const supportAgent = new Agent(components.agent, {
630
623
  Tip: Define the `usageHandler` within a function where you have more variables
631
624
  available to attribute the usage to a different user, team, project, etc.
632
625
 
626
+ ### Logging the raw request and response
627
+
628
+ You can provide a `rawRequestResponseHandler` to the agent to log the raw request and response from the LLM.
629
+
630
+ You could use this to log the request and response to a table, or use console logs with
631
+ [Log Streaming](https://docs.convex.dev/production/integrations/log-streams/)
632
+ to allow debugging and searching through Axiom or another logging service.
633
+
634
+ ```ts
635
+ const supportAgent = new Agent(components.agent, {
636
+ ...
637
+ rawRequestResponseHandler: async (ctx, { request, response }) => {
638
+ console.log("request", request);
639
+ console.log("response", response);
640
+ },
641
+ });
642
+ ```
643
+
633
644
  ## Troubleshooting
634
645
 
635
646
  ### Circular dependencies
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=_ignore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_ignore.d.ts","sourceRoot":"","sources":["../../../../src/client/_generated/_ignore.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ // This is only here so convex-test can detect a _generated folder
3
+ //# sourceMappingURL=_ignore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_ignore.js","sourceRoot":"","sources":["../../../../src/client/_generated/_ignore.ts"],"names":[],"mappings":";AAAA,kEAAkE"}
@@ -0,0 +1,57 @@
1
+ import type { FilePart, ImagePart } from "ai";
2
+ import type { Id } from "../component/_generated/dataModel.js";
3
+ import type { ActionCtx, AgentComponent, QueryCtx } from "./types.js";
4
+ import type { RunMutationCtx } from "@convex-dev/prosemirror-sync";
5
+ export declare const MAX_FILE_SIZE: number;
6
+ type File = {
7
+ url: string;
8
+ fileId: string;
9
+ storageId: Id<"_storage">;
10
+ hash: string;
11
+ filename: string | undefined;
12
+ };
13
+ /**
14
+ * Store a file in the file storage and return the URL and fileId.
15
+ * @param ctx A ctx object from an action.
16
+ * @param component The agent component.
17
+ * @param blob The blob to store.
18
+ * @param filename The filename to store.
19
+ * @param sha256 The sha256 hash of the file. If not provided, it will be
20
+ * computed. However, to ensure no corruption during transfer, you can
21
+ * calculate this on the client to enforce integrity.
22
+ * @returns The URL, fileId, and storageId of the stored file.
23
+ */
24
+ export declare function storeFile(ctx: ActionCtx | RunMutationCtx, component: AgentComponent, blob: Blob, filename?: string, sha256?: string): Promise<{
25
+ file: File;
26
+ filePart: FilePart;
27
+ imagePart: ImagePart | undefined;
28
+ }>;
29
+ /**
30
+ * Get file metadata from the component.
31
+ * This also returns filePart (and imagePart if the file is an image),
32
+ * which are useful to construct a CoreMessage like
33
+ * ```ts
34
+ * const { filePart, imagePart } = await getFile(ctx, components.agent, fileId);
35
+ * const message: UserMessage = {
36
+ * role: "user",
37
+ * content: [imagePart ?? filePart],
38
+ * };
39
+ * ```
40
+ * @param ctx A ctx object from an action or query.
41
+ * @param component The agent component, usually `components.agent`.
42
+ * @param fileId The fileId of the file to get.
43
+ * @returns The file metadata and content parts.
44
+ */
45
+ export declare function getFile(ctx: ActionCtx | QueryCtx, component: AgentComponent, fileId: string): Promise<{
46
+ file: {
47
+ fileId: string;
48
+ url: string;
49
+ storageId: Id<"_storage">;
50
+ hash: string;
51
+ filename: string | undefined;
52
+ };
53
+ filePart: FilePart;
54
+ imagePart: ImagePart | undefined;
55
+ }>;
56
+ export {};
57
+ //# sourceMappingURL=files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../../src/client/files.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,sCAAsC,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAEnE,eAAO,MAAM,aAAa,QAAY,CAAC;AAEvC,KAAK,IAAI,GAAG;IACV,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;CAC9B,CAAC;AAEF;;;;;;;;;;GAUG;AACH,wBAAsB,SAAS,CAC7B,GAAG,EAAE,SAAS,GAAG,cAAc,EAC/B,SAAS,EAAE,cAAc,EACzB,IAAI,EAAE,IAAI,EACV,QAAQ,CAAC,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC;IACT,IAAI,EAAE,IAAI,CAAC;IACX,QAAQ,EAAE,QAAQ,CAAC;IACnB,SAAS,EAAE,SAAS,GAAG,SAAS,CAAC;CAClC,CAAC,CAiED;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,OAAO,CAC3B,GAAG,EAAE,SAAS,GAAG,QAAQ,EACzB,SAAS,EAAE,cAAc,EACzB,MAAM,EAAE,MAAM;;;;mBAemB,EAAE,CAAC,UAAU,CAAC;;;;cAYrC,QAAQ;eACP,SAAS,GAAG,SAAS;GARjC"}
@@ -0,0 +1,124 @@
1
+ export const MAX_FILE_SIZE = 1024 * 64;
2
+ /**
3
+ * Store a file in the file storage and return the URL and fileId.
4
+ * @param ctx A ctx object from an action.
5
+ * @param component The agent component.
6
+ * @param blob The blob to store.
7
+ * @param filename The filename to store.
8
+ * @param sha256 The sha256 hash of the file. If not provided, it will be
9
+ * computed. However, to ensure no corruption during transfer, you can
10
+ * calculate this on the client to enforce integrity.
11
+ * @returns The URL, fileId, and storageId of the stored file.
12
+ */
13
+ export async function storeFile(ctx, component, blob, filename, sha256) {
14
+ if (!("runAction" in ctx)) {
15
+ throw new Error("You're trying to save a file that's too large in a mutation. " +
16
+ "You can store the file in file storage from an action first, then pass a URL instead. " +
17
+ "To have the agent component track the file, you can use `saveFile` from an action then use the fileId with getFile in the mutation. " +
18
+ "Read more in the docs.");
19
+ }
20
+ const hash = sha256 ||
21
+ Array.from(new Uint8Array(await crypto.subtle.digest("SHA-256", await blob.arrayBuffer())))
22
+ .map((b) => b.toString(16).padStart(2, "0"))
23
+ .join("");
24
+ const reused = await ctx.runMutation(component.files.useExistingFile, {
25
+ hash,
26
+ filename,
27
+ });
28
+ if (reused) {
29
+ const url = (await ctx.storage.getUrl(reused.storageId));
30
+ return {
31
+ ...getParts(url, blob.type, filename),
32
+ file: {
33
+ url,
34
+ fileId: reused.fileId,
35
+ storageId: reused.storageId,
36
+ hash,
37
+ filename,
38
+ },
39
+ };
40
+ }
41
+ const newStorageId = await ctx.storage.store(blob);
42
+ if (sha256) {
43
+ const metadata = await ctx.storage.getMetadata(newStorageId);
44
+ if (metadata?.sha256 !== sha256) {
45
+ throw new Error("Hash mismatch: " + metadata?.sha256 + " != " + sha256);
46
+ }
47
+ }
48
+ const { fileId, storageId } = await ctx.runMutation(component.files.addFile, {
49
+ storageId: newStorageId,
50
+ hash,
51
+ filename,
52
+ mimeType: blob.type,
53
+ });
54
+ const url = (await ctx.storage.getUrl(storageId));
55
+ if (storageId !== newStorageId) {
56
+ // We're re-using another file's storageId
57
+ // Because we try to reuse the file above, this should be very very rare
58
+ // and only in the case of racing to check then store the file.
59
+ await ctx.storage.delete(newStorageId);
60
+ }
61
+ return {
62
+ ...getParts(url, blob.type, filename),
63
+ file: {
64
+ url,
65
+ fileId,
66
+ storageId: storageId,
67
+ hash,
68
+ filename,
69
+ },
70
+ };
71
+ }
72
+ /**
73
+ * Get file metadata from the component.
74
+ * This also returns filePart (and imagePart if the file is an image),
75
+ * which are useful to construct a CoreMessage like
76
+ * ```ts
77
+ * const { filePart, imagePart } = await getFile(ctx, components.agent, fileId);
78
+ * const message: UserMessage = {
79
+ * role: "user",
80
+ * content: [imagePart ?? filePart],
81
+ * };
82
+ * ```
83
+ * @param ctx A ctx object from an action or query.
84
+ * @param component The agent component, usually `components.agent`.
85
+ * @param fileId The fileId of the file to get.
86
+ * @returns The file metadata and content parts.
87
+ */
88
+ export async function getFile(ctx, component, fileId) {
89
+ const file = await ctx.runQuery(component.files.get, { fileId });
90
+ if (!file) {
91
+ throw new Error(`File not found in component: ${fileId}`);
92
+ }
93
+ const url = await ctx.storage.getUrl(file.storageId);
94
+ if (!url) {
95
+ throw new Error(`File not found in storage: ${file.storageId}`);
96
+ }
97
+ return {
98
+ ...getParts(url, file.mimeType, file.filename),
99
+ file: {
100
+ fileId,
101
+ url,
102
+ storageId: file.storageId,
103
+ hash: file.hash,
104
+ filename: file.filename,
105
+ },
106
+ };
107
+ }
108
+ function getParts(url, mimeType, filename) {
109
+ const filePart = {
110
+ type: "file",
111
+ data: new URL(url),
112
+ mimeType,
113
+ filename,
114
+ };
115
+ const imagePart = mimeType.startsWith("image/")
116
+ ? {
117
+ type: "image",
118
+ image: new URL(url),
119
+ mimeType,
120
+ }
121
+ : undefined;
122
+ return { filePart, imagePart };
123
+ }
124
+ //# sourceMappingURL=files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.js","sourceRoot":"","sources":["../../../src/client/files.ts"],"names":[],"mappings":"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"}