@convex-dev/agent 0.0.1 → 0.0.3-alpha.0

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 (64) hide show
  1. package/README.md +27 -0
  2. package/dist/commonjs/client/index.d.ts +792 -83
  3. package/dist/commonjs/client/index.d.ts.map +1 -1
  4. package/dist/commonjs/client/index.js +119 -155
  5. package/dist/commonjs/client/index.js.map +1 -1
  6. package/dist/commonjs/component/messages.d.ts +11 -3
  7. package/dist/commonjs/component/messages.d.ts.map +1 -1
  8. package/dist/commonjs/component/messages.js +2 -1
  9. package/dist/commonjs/component/messages.js.map +1 -1
  10. package/dist/commonjs/component/schema.d.ts +18 -12
  11. package/dist/commonjs/component/schema.d.ts.map +1 -1
  12. package/dist/commonjs/component/schema.js +1 -0
  13. package/dist/commonjs/component/schema.js.map +1 -1
  14. package/dist/commonjs/component/vector/index.d.ts.map +1 -1
  15. package/dist/commonjs/component/vector/index.js +1 -1
  16. package/dist/commonjs/component/vector/index.js.map +1 -1
  17. package/dist/commonjs/logging.d.ts +18 -0
  18. package/dist/commonjs/logging.d.ts.map +1 -0
  19. package/dist/commonjs/logging.js +78 -0
  20. package/dist/commonjs/logging.js.map +1 -0
  21. package/dist/commonjs/mapping.d.ts +3 -6
  22. package/dist/commonjs/mapping.d.ts.map +1 -1
  23. package/dist/commonjs/mapping.js +46 -20
  24. package/dist/commonjs/mapping.js.map +1 -1
  25. package/dist/commonjs/validators.d.ts +2736 -76
  26. package/dist/commonjs/validators.d.ts.map +1 -1
  27. package/dist/commonjs/validators.js +72 -7
  28. package/dist/commonjs/validators.js.map +1 -1
  29. package/dist/esm/client/index.d.ts +792 -83
  30. package/dist/esm/client/index.d.ts.map +1 -1
  31. package/dist/esm/client/index.js +119 -155
  32. package/dist/esm/client/index.js.map +1 -1
  33. package/dist/esm/component/messages.d.ts +11 -3
  34. package/dist/esm/component/messages.d.ts.map +1 -1
  35. package/dist/esm/component/messages.js +2 -1
  36. package/dist/esm/component/messages.js.map +1 -1
  37. package/dist/esm/component/schema.d.ts +18 -12
  38. package/dist/esm/component/schema.d.ts.map +1 -1
  39. package/dist/esm/component/schema.js +1 -0
  40. package/dist/esm/component/schema.js.map +1 -1
  41. package/dist/esm/component/vector/index.d.ts.map +1 -1
  42. package/dist/esm/component/vector/index.js +1 -1
  43. package/dist/esm/component/vector/index.js.map +1 -1
  44. package/dist/esm/logging.d.ts +18 -0
  45. package/dist/esm/logging.d.ts.map +1 -0
  46. package/dist/esm/logging.js +78 -0
  47. package/dist/esm/logging.js.map +1 -0
  48. package/dist/esm/mapping.d.ts +3 -6
  49. package/dist/esm/mapping.d.ts.map +1 -1
  50. package/dist/esm/mapping.js +46 -20
  51. package/dist/esm/mapping.js.map +1 -1
  52. package/dist/esm/validators.d.ts +2736 -76
  53. package/dist/esm/validators.d.ts.map +1 -1
  54. package/dist/esm/validators.js +72 -7
  55. package/dist/esm/validators.js.map +1 -1
  56. package/package.json +7 -7
  57. package/src/client/index.ts +277 -193
  58. package/src/component/_generated/api.d.ts +5 -0
  59. package/src/component/messages.ts +2 -1
  60. package/src/component/schema.ts +1 -0
  61. package/src/component/vector/index.ts +1 -7
  62. package/src/logging.ts +103 -0
  63. package/src/mapping.ts +61 -29
  64. package/src/validators.ts +102 -9
@@ -169,6 +169,7 @@ export type Mounts = {
169
169
  | string
170
170
  | string
171
171
  | string;
172
+ error?: string;
172
173
  fileId?: string;
173
174
  id?: string;
174
175
  message?:
@@ -293,6 +294,7 @@ export type Mounts = {
293
294
  | string
294
295
  | string
295
296
  | string;
297
+ error?: string;
296
298
  fileId?: string;
297
299
  id?: string;
298
300
  message?:
@@ -1058,6 +1060,7 @@ export type Mounts = {
1058
1060
  | string
1059
1061
  | string
1060
1062
  | string;
1063
+ error?: string;
1061
1064
  fileId?: string;
1062
1065
  id?: string;
1063
1066
  message?:
@@ -1230,6 +1233,7 @@ export type Mounts = {
1230
1233
  | string
1231
1234
  | string
1232
1235
  | string;
1236
+ error?: string;
1233
1237
  fileId?: string;
1234
1238
  id?: string;
1235
1239
  message?:
@@ -1359,6 +1363,7 @@ export type Mounts = {
1359
1363
  | string
1360
1364
  | string
1361
1365
  | string;
1366
+ error?: string;
1362
1367
  fileId?: string;
1363
1368
  id?: string;
1364
1369
  message?:
@@ -401,6 +401,7 @@ async function addMessagesHandler(
401
401
  ...rest
402
402
  } = args;
403
403
  const parent = parentMessageId && (await ctx.db.get(parentMessageId));
404
+ // TODO: I think this is a bug - parent will be pending always?
404
405
  if (failPendingSteps && parent?.status !== "pending") {
405
406
  assert(args.threadId, "threadId is required to fail pending steps");
406
407
  const pendingMessages = await ctx.db
@@ -594,7 +595,7 @@ export const rollbackMessage = mutation({
594
595
  }
595
596
  await ctx.db.patch(messageId, {
596
597
  status: "failed",
597
- text: error ?? message.text,
598
+ error: error,
598
599
  });
599
600
  },
600
601
  });
@@ -27,6 +27,7 @@ export const schema = defineSchema({
27
27
  stepId: v.optional(v.id("steps")),
28
28
  agentName: v.optional(v.string()),
29
29
  message: v.optional(vMessage),
30
+ error: v.optional(v.string()),
30
31
  model: v.optional(v.string()),
31
32
  text: v.optional(v.string()),
32
33
  embeddingId: v.optional(vVectorId),
@@ -1,12 +1,6 @@
1
1
  import { paginator } from "convex-helpers/server/pagination";
2
2
  import { v } from "convex/values";
3
- import {
4
- ActionCtx,
5
- mutation,
6
- MutationCtx,
7
- query,
8
- QueryCtx,
9
- } from "../_generated/server";
3
+ import { ActionCtx, mutation, MutationCtx, query } from "../_generated/server";
10
4
  import {
11
5
  EmbeddingsWithoutDenormalizedFields,
12
6
  getVectorTableName,
package/src/logging.ts ADDED
@@ -0,0 +1,103 @@
1
+ import { v, Infer } from "convex/values";
2
+
3
+ export const DEFAULT_LOG_LEVEL: LogLevel = "WARN";
4
+
5
+ // NOTE: the ordering here is important! A config level of "INFO" will log
6
+ // "INFO", "REPORT", "WARN",and "ERROR" events.
7
+ export const logLevel = v.union(
8
+ v.literal("DEBUG"),
9
+ v.literal("TRACE"),
10
+ v.literal("INFO"),
11
+ v.literal("REPORT"),
12
+ v.literal("WARN"),
13
+ v.literal("ERROR"),
14
+ );
15
+ export type LogLevel = Infer<typeof logLevel>;
16
+
17
+ export type Logger = {
18
+ debug: (...args: unknown[]) => void;
19
+ info: (...args: unknown[]) => void;
20
+ log: (...args: unknown[]) => void;
21
+ warn: (...args: unknown[]) => void;
22
+ error: (...args: unknown[]) => void;
23
+ time: (label: string) => void;
24
+ timeEnd: (label: string) => void;
25
+ event: (event: string, payload: Record<string, unknown>) => void;
26
+ logLevel: LogLevel;
27
+ };
28
+
29
+ const logLevelOrder = logLevel.members.map((l) => l.value);
30
+ const logLevelByName = logLevelOrder.reduce(
31
+ (acc, l, i) => {
32
+ acc[l] = i;
33
+ return acc;
34
+ },
35
+ {} as Record<LogLevel, number>,
36
+ );
37
+ export function shouldLog(config: LogLevel, level: LogLevel) {
38
+ return logLevelByName[config] <= logLevelByName[level];
39
+ }
40
+ const DEBUG = logLevelByName["DEBUG"];
41
+ const TRACE = logLevelByName["TRACE"];
42
+ const INFO = logLevelByName["INFO"];
43
+ const REPORT = logLevelByName["REPORT"];
44
+ const WARN = logLevelByName["WARN"];
45
+ const ERROR = logLevelByName["ERROR"];
46
+
47
+ export function createLogger(level?: LogLevel): Logger {
48
+ const logLevel = level ?? DEFAULT_LOG_LEVEL;
49
+ const levelIndex = logLevelByName[logLevel];
50
+ if (levelIndex === undefined) {
51
+ throw new Error(`Invalid log level: ${logLevel}`);
52
+ }
53
+ return {
54
+ logLevel,
55
+ debug: (...args: unknown[]) => {
56
+ if (levelIndex <= DEBUG) {
57
+ console.debug(...args);
58
+ }
59
+ },
60
+ log: (...args: unknown[]) => {
61
+ if (levelIndex <= INFO) {
62
+ console.log(...args);
63
+ }
64
+ },
65
+ info: (...args: unknown[]) => {
66
+ if (levelIndex <= INFO) {
67
+ console.info(...args);
68
+ }
69
+ },
70
+ warn: (...args: unknown[]) => {
71
+ if (levelIndex <= WARN) {
72
+ console.warn(...args);
73
+ }
74
+ },
75
+ error: (...args: unknown[]) => {
76
+ if (levelIndex <= ERROR) {
77
+ console.error(...args);
78
+ }
79
+ },
80
+ time: (label: string) => {
81
+ if (levelIndex <= TRACE) {
82
+ console.time(label);
83
+ }
84
+ },
85
+ timeEnd: (label: string) => {
86
+ if (levelIndex <= TRACE) {
87
+ console.timeEnd(label);
88
+ }
89
+ },
90
+ event: (event: string, payload: Record<string, unknown>) => {
91
+ const fullPayload = {
92
+ component: "workflow",
93
+ event,
94
+ ...payload,
95
+ };
96
+ if (levelIndex === REPORT && event === "report") {
97
+ console.info(JSON.stringify(fullPayload));
98
+ } else if (levelIndex <= INFO) {
99
+ console.info(JSON.stringify(fullPayload));
100
+ }
101
+ },
102
+ };
103
+ }
package/src/mapping.ts CHANGED
@@ -1,10 +1,9 @@
1
1
  import {
2
2
  convertToCoreMessages,
3
3
  coreMessageSchema,
4
+ GenerateObjectResult,
4
5
  type AssistantContent,
5
- type CoreAssistantMessage,
6
6
  type CoreMessage,
7
- type CoreToolMessage,
8
7
  type DataContent,
9
8
  type GenerateTextResult,
10
9
  type StepResult,
@@ -13,8 +12,12 @@ import {
13
12
  type Message as UIMessage,
14
13
  type UserContent,
15
14
  } from "ai";
16
- import { MessageWithFileAndId, Step } from "./validators";
17
15
  import { assert } from "convex-helpers";
16
+ import {
17
+ MessageWithFileAndId,
18
+ Step,
19
+ StepWithMessagesWithFileAndId,
20
+ } from "./validators";
18
21
 
19
22
  export type SerializeUrlsAndUint8Arrays<T> = T extends URL
20
23
  ? string
@@ -66,15 +69,6 @@ export function serializeContent(content: Content): SerializedContent {
66
69
  return serialized as SerializedContent;
67
70
  }
68
71
 
69
- export function serializeResponse<TOOLS extends ToolSet, OUTPUT>(
70
- response: GenerateTextResult<TOOLS, OUTPUT>["response"]
71
- ): { message: SerializedMessage; id?: string }[] {
72
- const { id, timestamp, modelId, headers, messages, body } = response;
73
- // TODO: what to do about all the rest?
74
- // Store body?
75
- return messages.map((m) => serializeMessageWithId(m));
76
- }
77
-
78
72
  export function serializeStep<TOOLS extends ToolSet>(
79
73
  step: StepResult<TOOLS>
80
74
  ): Step {
@@ -86,7 +80,7 @@ export function serializeStep<TOOLS extends ToolSet>(
86
80
  ...step.response,
87
81
  messages: content,
88
82
  timestamp,
89
- headers: {},
83
+ headers: {}, // these are large and low value
90
84
  };
91
85
  return {
92
86
  ...step,
@@ -115,6 +109,41 @@ export function serializeNewMessagesInStep<TOOLS extends ToolSet>(
115
109
  return messages;
116
110
  }
117
111
 
112
+ export function serializeObjectResult(
113
+ result: GenerateObjectResult<unknown>
114
+ ): StepWithMessagesWithFileAndId {
115
+ const text = JSON.stringify(result.object);
116
+ const serializedMessage = serializeMessageWithId({
117
+ role: "assistant" as const,
118
+ content: text,
119
+ id: result.response.id,
120
+ });
121
+
122
+ const messages = [serializedMessage];
123
+
124
+ return {
125
+ messages,
126
+ step: {
127
+ text,
128
+ isContinued: false,
129
+ stepType: "initial",
130
+ toolCalls: [],
131
+ toolResults: [],
132
+ usage: result.usage,
133
+ warnings: result.warnings,
134
+ finishReason: result.finishReason,
135
+ request: result.request,
136
+ response: {
137
+ ...result.response,
138
+ timestamp: result.response.timestamp.getTime(),
139
+ messages,
140
+ },
141
+ providerMetadata: result.providerMetadata,
142
+ experimental_providerMetadata: result.experimental_providerMetadata,
143
+ },
144
+ };
145
+ }
146
+
118
147
  export function deserializeContent(content: SerializedContent): Content {
119
148
  if (typeof content === "string") {
120
149
  return content;
@@ -172,23 +201,26 @@ export function promptOrMessagesToCoreMessages(args: {
172
201
  if (args.system) {
173
202
  messages.push({ role: "system", content: args.system });
174
203
  }
175
- if (!args.messages) {
176
- assert(args.prompt, "messages or prompt is required");
204
+ assert(args.prompt || args.messages, "messages or prompt is required");
205
+ if (args.messages) {
206
+ if (
207
+ args.messages.some(
208
+ (m) =>
209
+ typeof m === "object" &&
210
+ m !== null &&
211
+ (m.role === "data" || // UI-only role
212
+ "toolInvocations" in m || // UI-specific field
213
+ "parts" in m || // UI-specific field
214
+ "experimental_attachments" in m)
215
+ )
216
+ ) {
217
+ messages.push(...convertToCoreMessages(args.messages as UIMessage[]));
218
+ } else {
219
+ messages.push(...coreMessageSchema.array().parse(args.messages));
220
+ }
221
+ }
222
+ if (args.prompt) {
177
223
  messages.push({ role: "user", content: args.prompt });
178
- } else if (
179
- args.messages.some(
180
- (m) =>
181
- typeof m === "object" &&
182
- m !== null &&
183
- (m.role === "data" || // UI-only role
184
- "toolInvocations" in m || // UI-specific field
185
- "parts" in m || // UI-specific field
186
- "experimental_attachments" in m)
187
- )
188
- ) {
189
- messages.push(...convertToCoreMessages(args.messages as UIMessage[]));
190
- } else {
191
- messages.push(...coreMessageSchema.array().parse(args.messages));
192
224
  }
193
225
  assert(messages.length > 0, "Messages must contain at least one message");
194
226
  return messages;
package/src/validators.ts CHANGED
@@ -1,10 +1,12 @@
1
- import { Infer, v } from "convex/values";
1
+ import { Infer, ObjectType, v } from "convex/values";
2
2
  import { vVectorDimension } from "./component/vector/tables";
3
3
 
4
4
  // const deprecated = v.optional(v.any()) as unknown as VNull<unknown, "optional">;
5
5
 
6
6
  const providerOptions = v.optional(v.record(v.string(), v.any()));
7
+ export type ProviderOptions = Infer<typeof providerOptions>;
7
8
  const experimental_providerMetadata = providerOptions;
9
+ export type ProviderMetadata = Infer<typeof experimental_providerMetadata>;
8
10
 
9
11
  export const vThreadStatus = v.union(
10
12
  v.literal("active"),
@@ -186,6 +188,14 @@ export const vResponse = v.object({
186
188
  body: v.optional(v.any()),
187
189
  });
188
190
 
191
+ export const vResponseWithoutMessages = v.object({
192
+ id: v.string(),
193
+ timestamp: v.number(),
194
+ modelId: v.string(),
195
+ headers: v.optional(v.record(v.string(), v.string())), // clear these?
196
+ body: v.optional(v.any()),
197
+ });
198
+
189
199
  export const vFinishReason = v.union(
190
200
  v.literal("stop"),
191
201
  v.literal("length"),
@@ -250,6 +260,18 @@ export const vStepWithMessages = v.object({
250
260
  });
251
261
  export type StepWithMessagesWithFileAndId = Infer<typeof vStepWithMessages>;
252
262
 
263
+ export const vObjectResult = v.object({
264
+ request: vRequest,
265
+ response: vResponseWithoutMessages,
266
+ finishReason: vFinishReason,
267
+ usage: v.optional(v.any()),
268
+ object: v.any(),
269
+ error: v.optional(v.string()),
270
+ warnings: v.optional(v.array(vLanguageModelV1CallWarning)),
271
+ providerMetadata: providerOptions,
272
+ experimental_providerMetadata,
273
+ });
274
+ export type ObjectResult = Infer<typeof vObjectResult>;
253
275
  export const vSearchOptions = v.object({
254
276
  vector: v.optional(v.array(v.number())),
255
277
  vectorModel: v.optional(v.string()),
@@ -279,18 +301,89 @@ export const vStorageOptions = v.object({
279
301
  saveAllOutputMessages: v.optional(v.boolean()),
280
302
  });
281
303
 
282
- export const vThreadArgs = v.object({
283
- maxSteps: v.optional(v.number()),
304
+ const vPromptFields = {
305
+ system: v.optional(v.string()),
284
306
  prompt: v.optional(v.string()),
285
307
  messages: v.optional(v.array(vMessage)),
286
- });
308
+ };
309
+
310
+ export const vCallSettingsFields = {
311
+ maxTokens: v.optional(v.number()),
312
+ temperature: v.optional(v.number()),
313
+ topP: v.optional(v.number()),
314
+ topK: v.optional(v.number()),
315
+ presencePenalty: v.optional(v.number()),
316
+ frequencyPenalty: v.optional(v.number()),
317
+ seed: v.optional(v.number()),
318
+ maxRetries: v.optional(v.number()),
319
+ headers: v.optional(v.record(v.string(), v.string())),
320
+ };
321
+ export type CallSettings = ObjectType<typeof vCallSettingsFields>;
287
322
 
288
- export const vObjectArgs = v.object({
289
- output: v.optional(v.any()),
290
- mode: v.optional(v.literal("json")),
291
- prompt: v.optional(v.string()),
292
- messages: v.optional(v.array(vMessage)),
323
+ export const vTextArgs = v.object({
324
+ ...vCallSettingsFields,
325
+ ...vPromptFields,
326
+ toolChoice: v.optional(
327
+ v.union(
328
+ v.literal("auto"),
329
+ v.literal("none"),
330
+ v.literal("required"),
331
+ v.object({
332
+ type: v.literal("tool"),
333
+ toolName: v.string(),
334
+ })
335
+ )
336
+ ),
337
+ maxSteps: v.optional(v.number()),
338
+ experimental_continueSteps: v.optional(v.boolean()),
339
+ providerOptions,
340
+ experimental_providerMetadata,
293
341
  });
342
+ export type TextArgs = Infer<typeof vTextArgs>;
343
+
344
+ const objectArgsCommonFields = {
345
+ ...vCallSettingsFields,
346
+ ...vPromptFields,
347
+ providerOptions,
348
+ experimental_providerMetadata,
349
+ };
350
+
351
+ export const vSafeObjectArgs = v.union(
352
+ v.object({
353
+ ...objectArgsCommonFields,
354
+ output: v.optional(v.literal("object")),
355
+ schema: v.any(), // JSON schema
356
+ schemaName: v.optional(v.string()),
357
+ schemaDescription: v.optional(v.string()),
358
+ mode: v.optional(
359
+ v.union(v.literal("auto"), v.literal("json"), v.literal("tool"))
360
+ ),
361
+ }),
362
+ v.object({
363
+ ...objectArgsCommonFields,
364
+ output: v.optional(v.literal("array")),
365
+ schema: v.any(), // JSON schema
366
+ schemaName: v.optional(v.string()),
367
+ schemaDescription: v.optional(v.string()),
368
+ mode: v.optional(
369
+ v.union(v.literal("auto"), v.literal("json"), v.literal("tool"))
370
+ ),
371
+ }),
372
+ v.object({
373
+ ...objectArgsCommonFields,
374
+ output: v.optional(v.literal("enum")),
375
+ enum: v.array(v.string()),
376
+ mode: v.optional(
377
+ v.union(v.literal("auto"), v.literal("json"), v.literal("tool"))
378
+ ),
379
+ }),
380
+ v.object({
381
+ ...objectArgsCommonFields,
382
+ output: v.literal("no-schema"),
383
+ mode: v.optional(v.literal("json")),
384
+ })
385
+ );
386
+ export type SafeObjectArgs = Infer<typeof vSafeObjectArgs>;
294
387
 
295
388
  export const vEmbeddingsWithMetadata = v.object({
296
389
  vectors: v.array(v.union(v.array(v.number()), v.null())),