@convex-dev/agent 0.2.6-alpha.1 → 0.2.7

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 (101) hide show
  1. package/dist/client/createTool.js +1 -1
  2. package/dist/client/createTool.js.map +1 -1
  3. package/dist/client/definePlaygroundAPI.d.ts +6 -4
  4. package/dist/client/definePlaygroundAPI.d.ts.map +1 -1
  5. package/dist/client/definePlaygroundAPI.js +15 -6
  6. package/dist/client/definePlaygroundAPI.js.map +1 -1
  7. package/dist/client/index.d.ts +55 -122
  8. package/dist/client/index.d.ts.map +1 -1
  9. package/dist/client/index.js +47 -371
  10. package/dist/client/index.js.map +1 -1
  11. package/dist/client/messages.d.ts +1 -1
  12. package/dist/client/messages.d.ts.map +1 -1
  13. package/dist/client/mockModel.d.ts +5 -3
  14. package/dist/client/mockModel.d.ts.map +1 -1
  15. package/dist/client/mockModel.js +33 -24
  16. package/dist/client/mockModel.js.map +1 -1
  17. package/dist/client/saveInputMessages.d.ts +20 -0
  18. package/dist/client/saveInputMessages.d.ts.map +1 -0
  19. package/dist/client/saveInputMessages.js +57 -0
  20. package/dist/client/saveInputMessages.js.map +1 -0
  21. package/dist/client/search.d.ts +110 -9
  22. package/dist/client/search.d.ts.map +1 -1
  23. package/dist/client/search.js +271 -39
  24. package/dist/client/search.js.map +1 -1
  25. package/dist/client/start.d.ts +84 -0
  26. package/dist/client/start.d.ts.map +1 -0
  27. package/dist/client/start.js +171 -0
  28. package/dist/client/start.js.map +1 -0
  29. package/dist/client/streaming.d.ts +8 -8
  30. package/dist/client/streaming.d.ts.map +1 -1
  31. package/dist/client/streaming.js +2 -1
  32. package/dist/client/streaming.js.map +1 -1
  33. package/dist/client/textStreamParts.d.ts.map +1 -1
  34. package/dist/client/textStreamParts.js +2 -9
  35. package/dist/client/textStreamParts.js.map +1 -1
  36. package/dist/client/threads.d.ts +1 -1
  37. package/dist/client/threads.d.ts.map +1 -1
  38. package/dist/client/types.d.ts +147 -17
  39. package/dist/client/types.d.ts.map +1 -1
  40. package/dist/component/_generated/api.d.ts +11 -3
  41. package/dist/component/messages.d.ts +13 -4
  42. package/dist/component/messages.d.ts.map +1 -1
  43. package/dist/component/messages.js +67 -25
  44. package/dist/component/messages.js.map +1 -1
  45. package/dist/component/schema.d.ts +2 -1643
  46. package/dist/component/schema.d.ts.map +1 -1
  47. package/dist/component/schema.js +0 -24
  48. package/dist/component/schema.js.map +1 -1
  49. package/dist/mapping.d.ts +5 -8
  50. package/dist/mapping.d.ts.map +1 -1
  51. package/dist/mapping.js +72 -6
  52. package/dist/mapping.js.map +1 -1
  53. package/dist/react/deltas.d.ts.map +1 -1
  54. package/dist/react/deltas.js +1 -0
  55. package/dist/react/deltas.js.map +1 -1
  56. package/dist/react/fromUIMessages.d.ts +13 -0
  57. package/dist/react/fromUIMessages.d.ts.map +1 -0
  58. package/dist/react/fromUIMessages.js +75 -0
  59. package/dist/react/fromUIMessages.js.map +1 -0
  60. package/dist/react/toUIMessages.d.ts +5 -2
  61. package/dist/react/toUIMessages.d.ts.map +1 -1
  62. package/dist/react/toUIMessages.js +3 -0
  63. package/dist/react/toUIMessages.js.map +1 -1
  64. package/dist/shared.d.ts +10 -0
  65. package/dist/shared.d.ts.map +1 -1
  66. package/dist/shared.js +26 -0
  67. package/dist/shared.js.map +1 -1
  68. package/dist/validators.d.ts +1640 -0
  69. package/dist/validators.d.ts.map +1 -1
  70. package/dist/validators.js +41 -0
  71. package/dist/validators.js.map +1 -1
  72. package/package.json +4 -4
  73. package/src/client/createTool.ts +1 -1
  74. package/src/client/definePlaygroundAPI.ts +16 -7
  75. package/src/client/index.test.ts +11 -46
  76. package/src/client/index.ts +128 -573
  77. package/src/client/messages.ts +1 -1
  78. package/src/client/mock.json +68 -0
  79. package/src/client/mockModel.ts +47 -31
  80. package/src/client/saveInputMessages.test.ts +576 -0
  81. package/src/client/saveInputMessages.ts +100 -0
  82. package/src/client/search.test.ts +1017 -0
  83. package/src/client/search.ts +446 -68
  84. package/src/client/start.ts +315 -0
  85. package/src/client/stream.json +48 -0
  86. package/src/client/streaming.ts +3 -3
  87. package/src/client/textStreamParts.ts +2 -11
  88. package/src/client/threads.ts +1 -1
  89. package/src/client/types.ts +153 -22
  90. package/src/component/_generated/api.d.ts +11 -3
  91. package/src/component/messages.ts +73 -27
  92. package/src/component/schema.ts +1 -29
  93. package/src/mapping.ts +83 -6
  94. package/src/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  95. package/src/react/deltas.ts +1 -0
  96. package/src/react/fromUIMessages.test.ts +467 -0
  97. package/src/react/fromUIMessages.ts +90 -0
  98. package/src/react/toUIMessages.ts +21 -13
  99. package/src/shared.ts +33 -0
  100. package/src/validators.test.ts +13 -2
  101. package/src/validators.ts +48 -0
@@ -0,0 +1,315 @@
1
+ import {
2
+ stepCountIs,
3
+ type CallSettings,
4
+ type GenerateObjectResult,
5
+ type IdGenerator,
6
+ type LanguageModel,
7
+ type ModelMessage,
8
+ type StepResult,
9
+ type StopCondition,
10
+ type ToolSet,
11
+ } from "ai";
12
+ import {
13
+ serializeNewMessagesInStep,
14
+ serializeObjectResult,
15
+ } from "../mapping.js";
16
+ import { embedMessages, fetchContextWithPrompt } from "./search.js";
17
+ import type {
18
+ ActionCtx,
19
+ AgentComponent,
20
+ Config,
21
+ Options,
22
+ UserActionCtx,
23
+ } from "./types.js";
24
+ import { saveMessages } from "./messages.js";
25
+ import type { Message, MessageDoc } from "../validators.js";
26
+ import {
27
+ getModelName,
28
+ getProviderName,
29
+ type ModelOrMetadata,
30
+ } from "../shared.js";
31
+ import { wrapTools, type ToolCtx } from "./createTool.js";
32
+ import type { Agent } from "./index.js";
33
+ import { omit } from "convex-helpers";
34
+ import { saveInputMessages } from "./saveInputMessages.js";
35
+
36
+ export async function start<
37
+ T,
38
+ Tools extends ToolSet = ToolSet,
39
+ CustomCtx extends object = object,
40
+ >(
41
+ ctx: ActionCtx & CustomCtx,
42
+ component: AgentComponent,
43
+ /**
44
+ * These are the arguments you'll pass to the LLM call such as
45
+ * `generateText` or `streamText`. This function will look up the context
46
+ * and provide functions to save the steps, abort the generation, and more.
47
+ * The type of the arguments returned infers from the type of the arguments
48
+ * you pass here.
49
+ */
50
+ args: T & {
51
+ /**
52
+ * If provided, this message will be used as the "prompt" for the LLM call,
53
+ * instead of the prompt or messages.
54
+ * This is useful if you want to first save a user message, then use it as
55
+ * the prompt for the LLM call in another call.
56
+ */
57
+ promptMessageId?: string;
58
+ /**
59
+ * The model to use for the LLM calls. This will override the model specified
60
+ * in the Agent constructor.
61
+ */
62
+ model?: LanguageModel;
63
+ /**
64
+ * The tools to use for the tool calls. This will override tools specified
65
+ * in the Agent constructor or createThread / continueThread.
66
+ */
67
+ tools?: Tools;
68
+ /**
69
+ * The single prompt message to use for the LLM call. This will be the
70
+ * last message in the context. If it's a string, it will be a user role.
71
+ */
72
+ prompt?: string | (ModelMessage | Message)[];
73
+ /**
74
+ * If provided alongside prompt, the ordering will be:
75
+ * 1. system prompt
76
+ * 2. search context
77
+ * 3. recent messages
78
+ * 4. these messages
79
+ * 5. prompt messages, including those already on the same `order` as
80
+ * the promptMessageId message, if provided.
81
+ */
82
+ messages?: (ModelMessage | Message)[];
83
+ /**
84
+ * The abort signal to be passed to the LLM call. If triggered, it will
85
+ * mark the pending message as failed. If the generation is asynchronously
86
+ * aborted, it will trigger this signal when detected.
87
+ */
88
+ abortSignal?: AbortSignal;
89
+ stopWhen?: StopCondition<Tools> | Array<StopCondition<Tools>>;
90
+ _internal?: { generateId?: IdGenerator };
91
+ },
92
+ {
93
+ threadId,
94
+ ...opts
95
+ }: Options &
96
+ Config & {
97
+ userId?: string | null;
98
+ threadId?: string;
99
+ languageModel: LanguageModel;
100
+ agentName: string;
101
+ agentForToolCtx?: Agent;
102
+ },
103
+ ): Promise<{
104
+ args: T & {
105
+ system?: string;
106
+ model: LanguageModel;
107
+ messages: ModelMessage[];
108
+ prompt?: never;
109
+ tools?: Tools;
110
+ } & CallSettings;
111
+ order: number;
112
+ stepOrder: number;
113
+ userId: string | undefined;
114
+ promptMessageId: string | undefined;
115
+ updateModel: (model: ModelOrMetadata | undefined) => void;
116
+ save: <TOOLS extends ToolSet>(
117
+ toSave:
118
+ | { step: StepResult<TOOLS> }
119
+ | { object: GenerateObjectResult<unknown> },
120
+ createPendingMessage?: boolean,
121
+ ) => Promise<void>;
122
+ fail: (reason: string) => Promise<void>;
123
+ getSavedMessages: () => MessageDoc[];
124
+ }> {
125
+ const userId =
126
+ opts.userId ??
127
+ (threadId &&
128
+ (await ctx.runQuery(component.threads.getThread, { threadId }))
129
+ ?.userId) ??
130
+ undefined;
131
+
132
+ const context = await fetchContextWithPrompt(ctx, component, {
133
+ ...opts,
134
+ userId,
135
+ threadId,
136
+ messages: args.messages,
137
+ prompt: args.prompt,
138
+ promptMessageId: args.promptMessageId,
139
+ });
140
+
141
+ const saveMessages = opts.storageOptions?.saveMessages ?? "promptAndOutput";
142
+ const { promptMessageId, pendingMessage, savedMessages } =
143
+ threadId && saveMessages !== "none"
144
+ ? await saveInputMessages(ctx, component, {
145
+ ...opts,
146
+ userId,
147
+ threadId,
148
+ prompt: args.prompt,
149
+ messages: args.messages,
150
+ promptMessageId: args.promptMessageId,
151
+ storageOptions: { saveMessages },
152
+ })
153
+ : {
154
+ promptMessageId: args.promptMessageId,
155
+ pendingMessage: undefined,
156
+ savedMessages: [] as MessageDoc[],
157
+ };
158
+
159
+ const order = pendingMessage?.order ?? context.order;
160
+ const stepOrder = pendingMessage?.stepOrder ?? context.stepOrder;
161
+ let pendingMessageId = pendingMessage?._id;
162
+
163
+ const model = args.model ?? opts.languageModel;
164
+ let activeModel: ModelOrMetadata = model;
165
+
166
+ const fail = async (reason: string) => {
167
+ if (pendingMessageId) {
168
+ await ctx.runMutation(component.messages.finalizeMessage, {
169
+ messageId: pendingMessageId,
170
+ result: { status: "failed", error: reason },
171
+ });
172
+ }
173
+ };
174
+ if (args.abortSignal) {
175
+ const abortSignal = args.abortSignal;
176
+ abortSignal.addEventListener(
177
+ "abort",
178
+ async () => {
179
+ await fail(abortSignal.reason?.toString() ?? "abortSignal");
180
+ },
181
+ { once: true },
182
+ );
183
+ }
184
+ const toolCtx = {
185
+ ...(ctx as UserActionCtx & CustomCtx),
186
+ userId,
187
+ threadId,
188
+ promptMessageId,
189
+ agent: opts.agentForToolCtx,
190
+ } satisfies ToolCtx;
191
+ const tools = wrapTools(toolCtx, args.tools) as Tools;
192
+ const aiArgs = {
193
+ ...opts.callSettings,
194
+ providerOptions: opts.providerOptions,
195
+ ...omit(args, ["promptMessageId", "messages", "prompt"]),
196
+ model,
197
+ messages: context.messages,
198
+ stopWhen:
199
+ args.stopWhen ?? (opts.maxSteps ? stepCountIs(opts.maxSteps) : undefined),
200
+ tools,
201
+ } as T & {
202
+ model: LanguageModel;
203
+ messages: ModelMessage[];
204
+ prompt?: never;
205
+ tools?: Tools;
206
+ _internal?: { generateId?: IdGenerator };
207
+ } & CallSettings;
208
+ if (pendingMessageId) {
209
+ if (!aiArgs._internal?.generateId) {
210
+ aiArgs._internal = {
211
+ ...aiArgs._internal,
212
+ generateId: pendingMessageId
213
+ ? () => pendingMessageId ?? crypto.randomUUID()
214
+ : undefined,
215
+ };
216
+ }
217
+ }
218
+ return {
219
+ args: aiArgs,
220
+ order: order ?? 0,
221
+ stepOrder: stepOrder ?? 0,
222
+ userId,
223
+ promptMessageId,
224
+ getSavedMessages: () => savedMessages,
225
+ updateModel: (model: ModelOrMetadata | undefined) => {
226
+ if (model) {
227
+ activeModel = model;
228
+ }
229
+ },
230
+ fail,
231
+ save: async <TOOLS extends ToolSet>(
232
+ toSave:
233
+ | { step: StepResult<TOOLS> }
234
+ | { object: GenerateObjectResult<unknown> },
235
+ createPendingMessage?: boolean,
236
+ ) => {
237
+ if (threadId && saveMessages !== "none") {
238
+ const serialized =
239
+ "object" in toSave
240
+ ? await serializeObjectResult(
241
+ ctx,
242
+ component,
243
+ toSave.object,
244
+ activeModel,
245
+ )
246
+ : await serializeNewMessagesInStep(
247
+ ctx,
248
+ component,
249
+ toSave.step,
250
+ activeModel,
251
+ );
252
+ const embeddings = await embedMessages(
253
+ ctx,
254
+ { threadId, ...opts, userId },
255
+ serialized.messages.map((m) => m.message),
256
+ );
257
+ if (createPendingMessage) {
258
+ serialized.messages.push({
259
+ message: { role: "assistant", content: [] },
260
+ status: "pending",
261
+ });
262
+ embeddings?.vectors.push(null);
263
+ }
264
+ const saved = await ctx.runMutation(component.messages.addMessages, {
265
+ userId,
266
+ threadId,
267
+ agentName: opts.agentName,
268
+ promptMessageId,
269
+ pendingMessageId,
270
+ messages: serialized.messages,
271
+ embeddings,
272
+ failPendingSteps: false,
273
+ });
274
+ const lastMessage = saved.messages.at(-1)!;
275
+ if (createPendingMessage) {
276
+ if (lastMessage.status === "failed") {
277
+ pendingMessageId = undefined;
278
+ savedMessages.push(...saved.messages);
279
+ await fail(
280
+ lastMessage.error ??
281
+ "Aborting - the pending message was marked as failed",
282
+ );
283
+ } else {
284
+ pendingMessageId = lastMessage._id;
285
+ savedMessages.push(...saved.messages.slice(0, -1));
286
+ }
287
+ } else {
288
+ pendingMessageId = undefined;
289
+ savedMessages.push(...saved.messages);
290
+ }
291
+ }
292
+ const output = "object" in toSave ? toSave.object : toSave.step;
293
+ if (opts.rawRequestResponseHandler) {
294
+ await opts.rawRequestResponseHandler(ctx, {
295
+ userId,
296
+ threadId,
297
+ agentName: opts.agentName,
298
+ request: output.request,
299
+ response: output.response,
300
+ });
301
+ }
302
+ if (opts.usageHandler && output.usage) {
303
+ await opts.usageHandler(ctx, {
304
+ userId,
305
+ threadId,
306
+ agentName: opts.agentName,
307
+ model: getModelName(activeModel),
308
+ provider: getProviderName(activeModel),
309
+ usage: output.usage,
310
+ providerMetadata: output.providerMetadata,
311
+ });
312
+ }
313
+ },
314
+ };
315
+ }
@@ -0,0 +1,48 @@
1
+ [
2
+ { "type": "start" },
3
+ { "type": "start-step" },
4
+ { "type": "reasoning-start", "id": "reasoning-0" },
5
+ { "type": "reasoning-delta", "id": "reasoning-0", "delta": "Okay" },
6
+ {
7
+ "type": "reasoning-delta",
8
+ "id": "reasoning-0",
9
+ "delta": ", the user is asking, \"What is the best flavor of ice cream?\" I need to figure out how to respond. Let me check the tools provided. The only tool available is the \"say\" function, which allows me to ask a friend for their favorite ice cream flavor. The function requires a \"question\" parameter.\n\nSo, since I don't have any other functions, I can't look up information or calculate the answer. The best approach is to use the \"say\" function to ask a friend. I should formulate the question to match the friend's parameters. The user is asking for the \"best\" flavor, which is subjective. Therefore, asking a friend's favorite makes sense.\n\nI need to structure the function call correctly. The function name is \"say\" and the argument is the question. The question should be, \"What is your favorite flavor of ice cream?\" That's the parameter required. Let me make sure the JSON is properly formatted with the arguments as a JSON object. Yep, that should work. I'll output the tool_call with the function name and the question argument.\n"
10
+ },
11
+ { "type": "tool-input-start", "toolCallId": "0ychh9k6f", "toolName": "say" },
12
+ {
13
+ "type": "tool-input-delta",
14
+ "toolCallId": "0ychh9k6f",
15
+ "inputTextDelta": "{\"question\":\"What is your favorite flavor of ice cream?\"}"
16
+ },
17
+ {
18
+ "type": "tool-input-available",
19
+ "toolCallId": "0ychh9k6f",
20
+ "toolName": "say",
21
+ "input": { "question": "What is your favorite flavor of ice cream?" }
22
+ },
23
+ {
24
+ "type": "tool-output-available",
25
+ "toolCallId": "0ychh9k6f",
26
+ "output": "I'm sorry I can't help you. Stop asking me questions."
27
+ },
28
+ { "type": "reasoning-end", "id": "reasoning-0" },
29
+ { "type": "finish-step" },
30
+ { "type": "start-step" },
31
+ { "type": "reasoning-start", "id": "reasoning-0" },
32
+ { "type": "reasoning-delta", "id": "reasoning-0", "delta": "Okay" },
33
+ {
34
+ "type": "reasoning-delta",
35
+ "id": "reasoning-0",
36
+ "delta": ", the user initially asked for the best ice cream flavor. I tried using the 'say' function to ask a friend, but the friend didn't help. Now I need to respond. Since I can't get an answer from the friend, I should tell the user that I can't determine the best flavor because it's subjective. Maybe suggest they try different ones. Keep the response friendly and helpful.\n"
37
+ },
38
+ { "type": "text-start", "id": "txt-0" },
39
+ {
40
+ "type": "text-delta",
41
+ "id": "txt-0",
42
+ "delta": "The \"best\" ice cream flavor is subjective—it depends on personal taste! Some people love classic vanilla, while others might prefer adventurous options like matcha or salted caramel. Why not try a few and see which one you like most? 🍦"
43
+ },
44
+ { "type": "reasoning-end", "id": "reasoning-0" },
45
+ { "type": "text-end", "id": "txt-0" },
46
+ { "type": "finish-step" },
47
+ { "type": "finish" }
48
+ ]
@@ -10,13 +10,12 @@ import {
10
10
  } from "../validators.js";
11
11
  import type {
12
12
  AgentComponent,
13
- RunActionCtx,
14
13
  RunMutationCtx,
15
14
  RunQueryCtx,
16
15
  SyncStreamsReturnValue,
17
16
  } from "./types.js";
18
17
  import { v } from "convex/values";
19
- import { vMessageDoc } from "../component/schema.js";
18
+ import { vMessageDoc } from "../validators.js";
20
19
 
21
20
  export const vStreamMessagesReturnValue = v.object({
22
21
  ...vPaginationResult(vMessageDoc).fields,
@@ -175,7 +174,7 @@ export class DeltaStreamer<T> {
175
174
 
176
175
  constructor(
177
176
  public readonly component: AgentComponent,
178
- public readonly ctx: RunActionCtx,
177
+ public readonly ctx: RunMutationCtx,
179
178
  config: {
180
179
  stream: true | StreamingOptions;
181
180
  onAsyncAbort: (reason: string) => Promise<void>;
@@ -299,6 +298,7 @@ export class DeltaStreamer<T> {
299
298
  return;
300
299
  }
301
300
  await this.#ongoingWrite;
301
+ await this.#sendDelta();
302
302
  await this.ctx.runMutation(this.component.streams.finish, {
303
303
  streamId: this.streamId,
304
304
  });
@@ -23,21 +23,12 @@ export function serializeTextStreamingPartsV5(
23
23
  ) {
24
24
  last.text += part.text;
25
25
  } else {
26
- if (
27
- part.type === "start-step" ||
28
- part.type === "finish-step" ||
29
- part.type === "start" ||
30
- part.type === "finish"
31
- ) {
32
- continue;
33
- }
34
26
  if (part.type === "file") {
35
27
  compressed.push({
36
28
  type: "file",
37
29
  file: {
38
- mediaType: part.file.mediaType,
39
- base64: part.file.base64,
40
- uint8Array: new Uint8Array([]),
30
+ ...part.file,
31
+ uint8Array: undefined as unknown as Uint8Array,
41
32
  },
42
33
  });
43
34
  }
@@ -1,5 +1,5 @@
1
1
  import type { WithoutSystemFields } from "convex/server";
2
- import type { ThreadDoc } from "../component/schema.js";
2
+ import type { ThreadDoc } from "../validators.js";
3
3
  import type { AgentComponent, RunMutationCtx, RunQueryCtx } from "./types.js";
4
4
 
5
5
  /**
@@ -1,10 +1,12 @@
1
1
  import type {
2
2
  InferSchema,
3
+ ModelMessage,
3
4
  ProviderOptions,
4
5
  Schema,
5
6
  } from "@ai-sdk/provider-utils";
6
7
  import type { JSONValue } from "@ai-sdk/provider";
7
8
  import type {
9
+ EmbeddingModel,
8
10
  GenerateObjectResult,
9
11
  generateText,
10
12
  GenerateTextResult,
@@ -36,16 +38,96 @@ import type {
36
38
  } from "convex/server";
37
39
  import type { GenericId } from "convex/values";
38
40
  import type { Mounts } from "../component/_generated/api.js";
39
- import type { MessageDoc, ThreadDoc } from "../component/schema.js";
40
41
  import type {
42
+ MessageDoc,
41
43
  ProviderMetadata,
42
44
  StreamDelta,
43
45
  StreamMessage,
46
+ ThreadDoc,
44
47
  } from "../validators.js";
45
48
  import type { StreamingOptions } from "./streaming.js";
46
49
  import type * as z3 from "zod/v3";
47
50
  import type * as z4 from "zod/v4";
48
51
 
52
+ export type Config = {
53
+ /**
54
+ * The LLM model to use for generating / streaming text and objects.
55
+ * e.g.
56
+ * import { openai } from "@ai-sdk/openai"
57
+ * const myAgent = new Agent(components.agent, {
58
+ * languageModel: openai.chat("gpt-4o-mini"),
59
+ */
60
+ languageModel?: LanguageModel;
61
+ /**
62
+ * The model to use for text embeddings. Optional.
63
+ * If specified, it will use this for generating vector embeddings
64
+ * of chats, and can opt-in to doing vector search for automatic context
65
+ * on generateText, etc.
66
+ * e.g.
67
+ * import { openai } from "@ai-sdk/openai"
68
+ * const myAgent = new Agent(components.agent, {
69
+ * ...
70
+ * textEmbeddingModel: openai.embedding("text-embedding-3-small")
71
+ */
72
+ textEmbeddingModel?: EmbeddingModel<string>;
73
+ /**
74
+ * Options to determine what messages are included as context in message
75
+ * generation. To disable any messages automatically being added, pass:
76
+ * { recentMessages: 0 }
77
+ */
78
+ contextOptions?: ContextOptions;
79
+ /**
80
+ * Determines whether messages are automatically stored when passed as
81
+ * arguments or generated.
82
+ */
83
+ storageOptions?: StorageOptions;
84
+ /**
85
+ * The usage handler to use for this agent.
86
+ */
87
+ usageHandler?: UsageHandler;
88
+ /**
89
+ * By default, messages are ordered with context in `fetchContextWithPrompt`,
90
+ * but you can override this by providing a context handler. Here you can
91
+ * filter, modify, or enrich the context messages. If provided, the default
92
+ * ordering will not apply. This excludes the system message / instructions.
93
+ */
94
+ contextHandler?: ContextHandler;
95
+ /**
96
+ * Called for each LLM request/response, so you can do things like
97
+ * log the raw request body or response headers to a table, or logs.
98
+ */
99
+ rawRequestResponseHandler?: RawRequestResponseHandler;
100
+ /**
101
+ * @deprecated Reach out if you use this. Otherwise will be removed soon.
102
+ * Default provider options to pass for the LLM calls.
103
+ * This can be overridden at each generate/stream callsite on a per-field
104
+ * basis. To clear a default setting, you'll need to pass `undefined`.
105
+ */
106
+ providerOptions?: ProviderOptions;
107
+ /**
108
+ * The default settings to use for the LLM calls.
109
+ * This can be overridden at each generate/stream callsite on a per-field
110
+ * basis. To clear a default setting, you'll need to pass `undefined`.
111
+ */
112
+ callSettings?: CallSettings;
113
+ /**
114
+ * The maximum number of steps to allow for a single generation.
115
+ *
116
+ * For example, if an agent wants to call a tool, that call and tool response
117
+ * will be one step. Generating a response based on the tool call & response
118
+ * will be a second step.
119
+ * If it runs out of steps, it will return the last step result, which may
120
+ * not be an assistant message.
121
+
122
+ * This becomes the default value when `stopWhen` is not specified in the
123
+ * Agent or generation callsite.
124
+ * AI SDK v5 removed the `maxSteps` argument, but this is kept here for
125
+ * convenience and backwards compatibility.
126
+ * Defaults to 1.
127
+ */
128
+ maxSteps?: number;
129
+ };
130
+
49
131
  /**
50
132
  * Options to configure what messages are fetched as context,
51
133
  * automatically with thread.generateText, or directly via search.
@@ -153,6 +235,50 @@ export type UsageHandler = (
153
235
  },
154
236
  ) => void | Promise<void>;
155
237
 
238
+ /**
239
+ * By default, messages are ordered with context in `fetchContextWithPrompt`,
240
+ * but you can override this by providing a context handler. Here you can filter
241
+ * out, add in, or reorder messages.
242
+ */
243
+ export type ContextHandler = (
244
+ ctx: RunActionCtx,
245
+ args: {
246
+ /**
247
+ * The messages fetched from search.
248
+ */
249
+ search: ModelMessage[];
250
+ /**
251
+ * The recent messages already in the thread history,
252
+ * excluding any messages that came after promptMessageId.
253
+ */
254
+ recent: ModelMessage[];
255
+ /**
256
+ * The messages passed as the `messages` argument to e.g. generateText.
257
+ */
258
+ inputMessages: ModelMessage[];
259
+ /**
260
+ * The message(s) passed as the `prompt` argument to e.g. generateText.
261
+ * Otherwise, if `promptMessageId` was provided, the message at that id.
262
+ * `prompt` will override the message at `promptMessageId`.
263
+ */
264
+ inputPrompt: ModelMessage[];
265
+ /**
266
+ * Any messages on the same `order` as the promptMessageId message after the
267
+ * prompt message. These are presumably existing responses to the prompt
268
+ * message.
269
+ */
270
+ existingResponses: ModelMessage[];
271
+ /**
272
+ * The user associated with the generation, if any.
273
+ */
274
+ userId: string | undefined;
275
+ /**
276
+ * The thread associated with the generation, if any.
277
+ */
278
+ threadId: string | undefined;
279
+ },
280
+ ) => ModelMessage[] | Promise<ModelMessage[]>;
281
+
156
282
  export type RawRequestResponseHandler = (
157
283
  ctx: ActionCtx,
158
284
  args: {
@@ -262,7 +388,7 @@ export type GenerateObjectArgs<
262
388
  ? Array<InferSchema<SCHEMA>>
263
389
  : InferSchema<SCHEMA>,
264
390
  > = Omit<CallSettings, "stopSequences"> &
265
- Prompt & {
391
+ Partial<Prompt> & {
266
392
  /**
267
393
  * If provided, this message will be used as the "prompt" for the LLM call,
268
394
  * instead of the prompt or messages.
@@ -429,7 +555,15 @@ export interface Thread<DefaultTools extends ToolSet> {
429
555
  TOOLS,
430
556
  OUTPUT,
431
557
  OUTPUT_PARTIAL
432
- >,
558
+ > & {
559
+ /**
560
+ * If provided, this message will be used as the "prompt" for the LLM call,
561
+ * instead of the prompt or messages.
562
+ * This is useful if you want to first save a user message, then use it as
563
+ * the prompt for the LLM call in another call.
564
+ */
565
+ promptMessageId?: string;
566
+ },
433
567
  options?: Options,
434
568
  ): Promise<
435
569
  GenerateTextResult<TOOLS extends undefined ? DefaultTools : TOOLS, OUTPUT> &
@@ -456,7 +590,15 @@ export interface Thread<DefaultTools extends ToolSet> {
456
590
  TOOLS,
457
591
  OUTPUT,
458
592
  PARTIAL_OUTPUT
459
- >,
593
+ > & {
594
+ /**
595
+ * If provided, this message will be used as the "prompt" for the LLM call,
596
+ * instead of the prompt or messages.
597
+ * This is useful if you want to first save a user message, then use it as
598
+ * the prompt for the LLM call in another call.
599
+ */
600
+ promptMessageId?: string;
601
+ },
460
602
  options?: Options & {
461
603
  /**
462
604
  * Whether to save incremental data (deltas) from streaming responses.
@@ -504,15 +646,6 @@ export interface Thread<DefaultTools extends ToolSet> {
504
646
  * the prompt for the LLM call in another call.
505
647
  */
506
648
  promptMessageId?: string;
507
- /**
508
- * The model to use for the LLM calls. This will override the model specified
509
- * in the Agent constructor.
510
- */
511
- model?: LanguageModel;
512
- /**
513
- * The tools to use for the tool calls. This will override tools specified
514
- * in the Agent constructor or createThread / continueThread.
515
- */
516
649
  },
517
650
  options?: Options,
518
651
  ): Promise<GenerateObjectResult<RESULT> & ThreadOutputMetadata>;
@@ -546,15 +679,6 @@ export interface Thread<DefaultTools extends ToolSet> {
546
679
  * the prompt for the LLM call in another call.
547
680
  */
548
681
  promptMessageId?: string;
549
- /**
550
- * The model to use for the LLM calls. This will override the model specified
551
- * in the Agent constructor.
552
- */
553
- model?: LanguageModel;
554
- /**
555
- * The tools to use for the tool calls. This will override tools specified
556
- * in the Agent constructor or createThread / continueThread.
557
- */
558
682
  },
559
683
  options?: Options,
560
684
  ): Promise<
@@ -577,6 +701,13 @@ export type Options = {
577
701
  * set in the agent constructor.
578
702
  */
579
703
  usageHandler?: UsageHandler;
704
+ /**
705
+ * By default, messages are ordered with context in `fetchContextWithPrompt`,
706
+ * but you can override this by providing a context handler. Here you can
707
+ * filter, modify, or enrich the context messages. If provided, the default
708
+ * ordering will not apply. This excludes the system message / instructions.
709
+ */
710
+ contextHandler?: ContextHandler;
580
711
  };
581
712
 
582
713
  export type SyncStreamsReturnValue =