@convex-dev/agent 0.2.4 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/definePlaygroundAPI.d.ts +85 -0
- package/dist/client/definePlaygroundAPI.d.ts.map +1 -1
- package/dist/client/index.d.ts +85 -23
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +52 -51
- package/dist/client/index.js.map +1 -1
- package/dist/client/messages.d.ts +17 -0
- package/dist/client/messages.d.ts.map +1 -1
- package/dist/client/messages.js +5 -5
- package/dist/client/messages.js.map +1 -1
- package/dist/client/mockModel.d.ts +30 -0
- package/dist/client/mockModel.d.ts.map +1 -0
- package/dist/client/mockModel.js +153 -0
- package/dist/client/mockModel.js.map +1 -0
- package/dist/client/search.d.ts +17 -0
- package/dist/client/search.d.ts.map +1 -1
- package/dist/client/streaming.d.ts +190 -2
- package/dist/client/streaming.d.ts.map +1 -1
- package/dist/client/streaming.js +10 -8
- package/dist/client/streaming.js.map +1 -1
- package/dist/component/_generated/api.d.ts +176 -0
- package/dist/component/messages.d.ts +187 -0
- package/dist/component/messages.d.ts.map +1 -1
- package/dist/component/messages.js +1 -1
- package/dist/component/messages.js.map +1 -1
- package/dist/component/schema.d.ts +496 -3
- package/dist/component/schema.d.ts.map +1 -1
- package/dist/mapping.d.ts.map +1 -1
- package/dist/mapping.js +5 -0
- package/dist/mapping.js.map +1 -1
- package/dist/react/toUIMessages.d.ts.map +1 -1
- package/dist/react/toUIMessages.js +29 -19
- package/dist/react/toUIMessages.js.map +1 -1
- package/dist/validators.d.ts +1183 -8
- package/dist/validators.d.ts.map +1 -1
- package/dist/validators.js +19 -1
- package/dist/validators.js.map +1 -1
- package/package.json +3 -3
- package/src/client/index.ts +91 -82
- package/src/client/messages.ts +6 -6
- package/src/client/mockModel.ts +195 -0
- package/src/client/streaming.ts +8 -7
- package/src/component/_generated/api.d.ts +176 -0
- package/src/component/messages.ts +1 -1
- package/src/mapping.ts +7 -0
- package/src/react/toUIMessages.ts +36 -19
- package/src/validators.ts +24 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
LanguageModelV2,
|
|
3
|
+
LanguageModelV2StreamPart,
|
|
4
|
+
} from "@ai-sdk/provider";
|
|
5
|
+
import type { ReasoningPart, TextPart } from "@ai-sdk/provider-utils";
|
|
6
|
+
import { simulateReadableStream } from "ai";
|
|
7
|
+
|
|
8
|
+
const longDefaultText = `
|
|
9
|
+
A A A A A A A A A A A A A A A
|
|
10
|
+
B B B B B B B B B B B B B B B
|
|
11
|
+
C C C C C C C C C C C C C C C
|
|
12
|
+
D D D D D D D D D D D D D D D
|
|
13
|
+
`;
|
|
14
|
+
const defaultUsage = { outputTokens: 10, inputTokens: 3, totalTokens: 13 };
|
|
15
|
+
|
|
16
|
+
export type MockModelArgs = {
|
|
17
|
+
provider?: LanguageModelV2["provider"];
|
|
18
|
+
modelId?: LanguageModelV2["modelId"];
|
|
19
|
+
supportedUrls?:
|
|
20
|
+
| LanguageModelV2["supportedUrls"]
|
|
21
|
+
| (() => LanguageModelV2["supportedUrls"]);
|
|
22
|
+
chunkDelayInMs?: number;
|
|
23
|
+
initialDelayInMs?: number;
|
|
24
|
+
// provide either content or doGenerate & doStream
|
|
25
|
+
content?: (TextPart | ReasoningPart)[];
|
|
26
|
+
doGenerate?: LanguageModelV2["doGenerate"];
|
|
27
|
+
doStream?: LanguageModelV2["doStream"];
|
|
28
|
+
fail?:
|
|
29
|
+
| boolean
|
|
30
|
+
| {
|
|
31
|
+
probability?: number;
|
|
32
|
+
error?: string;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export function mockModel(args?: MockModelArgs): LanguageModelV2 {
|
|
37
|
+
return new MockLanguageModel(args ?? {});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export class MockLanguageModel implements LanguageModelV2 {
|
|
41
|
+
readonly specificationVersion = "v2";
|
|
42
|
+
|
|
43
|
+
private _supportedUrls: () => LanguageModelV2["supportedUrls"];
|
|
44
|
+
|
|
45
|
+
readonly provider: LanguageModelV2["provider"];
|
|
46
|
+
readonly modelId: LanguageModelV2["modelId"];
|
|
47
|
+
|
|
48
|
+
doGenerate: LanguageModelV2["doGenerate"];
|
|
49
|
+
doStream: LanguageModelV2["doStream"];
|
|
50
|
+
|
|
51
|
+
doGenerateCalls: Parameters<LanguageModelV2["doGenerate"]>[0][] = [];
|
|
52
|
+
doStreamCalls: Parameters<LanguageModelV2["doStream"]>[0][] = [];
|
|
53
|
+
|
|
54
|
+
constructor(args: MockModelArgs) {
|
|
55
|
+
this.provider = args.provider || "mock-provider";
|
|
56
|
+
this.modelId = args.modelId || "mock-model-id";
|
|
57
|
+
const {
|
|
58
|
+
content = [{ type: "text", text: longDefaultText }],
|
|
59
|
+
chunkDelayInMs = 200,
|
|
60
|
+
initialDelayInMs = 1000,
|
|
61
|
+
supportedUrls = {},
|
|
62
|
+
} = args;
|
|
63
|
+
const fail =
|
|
64
|
+
args.fail &&
|
|
65
|
+
(args.fail === true ||
|
|
66
|
+
!args.fail.probability ||
|
|
67
|
+
Math.random() < args.fail.probability);
|
|
68
|
+
const error =
|
|
69
|
+
(typeof args.fail === "object" && args.fail.error) ||
|
|
70
|
+
"Mock error message";
|
|
71
|
+
|
|
72
|
+
const chunks: LanguageModelV2StreamPart[] = [
|
|
73
|
+
{ type: "stream-start", warnings: [] },
|
|
74
|
+
];
|
|
75
|
+
chunks.push(
|
|
76
|
+
...content.flatMap((c, ci) => {
|
|
77
|
+
const deltas = c.text.split(" ");
|
|
78
|
+
let parts: LanguageModelV2StreamPart[] = [];
|
|
79
|
+
if (c.type === "reasoning") {
|
|
80
|
+
parts.push({
|
|
81
|
+
type: "reasoning-start",
|
|
82
|
+
id: `${ci}-reasoning-start`,
|
|
83
|
+
});
|
|
84
|
+
parts.push(
|
|
85
|
+
...deltas.map(
|
|
86
|
+
(delta, di) =>
|
|
87
|
+
({
|
|
88
|
+
type: "reasoning-delta",
|
|
89
|
+
delta,
|
|
90
|
+
id: `${ci}-reasoning-${di}`,
|
|
91
|
+
providerMetadata: {
|
|
92
|
+
mockProvider: { mock: { reasoningDetails: null } },
|
|
93
|
+
},
|
|
94
|
+
}) satisfies LanguageModelV2StreamPart,
|
|
95
|
+
),
|
|
96
|
+
);
|
|
97
|
+
parts.push({
|
|
98
|
+
type: "reasoning-end",
|
|
99
|
+
id: `${ci}-reasoning-end`,
|
|
100
|
+
});
|
|
101
|
+
} else if (c.type === "text") {
|
|
102
|
+
parts.push({
|
|
103
|
+
type: "text-start",
|
|
104
|
+
id: `${ci}-text-start`,
|
|
105
|
+
});
|
|
106
|
+
parts = deltas.map((delta, di) => ({
|
|
107
|
+
type: "text-delta",
|
|
108
|
+
delta,
|
|
109
|
+
id: `${ci}-text-${di}`,
|
|
110
|
+
}));
|
|
111
|
+
parts.push({
|
|
112
|
+
type: "text-end",
|
|
113
|
+
id: `${ci}-text-end`,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
return parts;
|
|
117
|
+
}),
|
|
118
|
+
);
|
|
119
|
+
if (fail) {
|
|
120
|
+
chunks.push({
|
|
121
|
+
type: "error",
|
|
122
|
+
error,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
chunks.push({
|
|
126
|
+
type: "finish",
|
|
127
|
+
finishReason: fail ? "error" : "stop",
|
|
128
|
+
usage: defaultUsage,
|
|
129
|
+
providerMetadata: {
|
|
130
|
+
mockProvider: { mock: "mock metadata" },
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
this.doGenerate = async (options) => {
|
|
134
|
+
this.doGenerateCalls.push(options);
|
|
135
|
+
|
|
136
|
+
if (fail) {
|
|
137
|
+
throw new Error(error);
|
|
138
|
+
}
|
|
139
|
+
if (typeof args.doGenerate === "function") {
|
|
140
|
+
return args.doGenerate(options);
|
|
141
|
+
} else if (Array.isArray(args.doGenerate)) {
|
|
142
|
+
return args.doGenerate[this.doGenerateCalls.length];
|
|
143
|
+
} else if (content) {
|
|
144
|
+
return {
|
|
145
|
+
content,
|
|
146
|
+
finishReason: "stop",
|
|
147
|
+
usage: defaultUsage,
|
|
148
|
+
providerMetadata: { mockProvider: { mock: "mock metadata" } },
|
|
149
|
+
warnings: [],
|
|
150
|
+
};
|
|
151
|
+
} else {
|
|
152
|
+
throw new Error("Unexpected: no content or doGenerate");
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
this._supportedUrls =
|
|
156
|
+
typeof supportedUrls === "function"
|
|
157
|
+
? supportedUrls
|
|
158
|
+
: async () => supportedUrls;
|
|
159
|
+
this.doStream = async (options) => {
|
|
160
|
+
this.doStreamCalls.push(options);
|
|
161
|
+
|
|
162
|
+
if (typeof args.doStream === "function") {
|
|
163
|
+
return args.doStream(options);
|
|
164
|
+
} else if (Array.isArray(args.doStream)) {
|
|
165
|
+
return args.doStream[this.doStreamCalls.length];
|
|
166
|
+
} else if (content) {
|
|
167
|
+
const stream = simulateReadableStream({
|
|
168
|
+
chunks,
|
|
169
|
+
initialDelayInMs,
|
|
170
|
+
chunkDelayInMs,
|
|
171
|
+
});
|
|
172
|
+
if (options.abortSignal) {
|
|
173
|
+
throw new Error("abortSignal in mock model");
|
|
174
|
+
}
|
|
175
|
+
return {
|
|
176
|
+
stream,
|
|
177
|
+
request: { body: {} },
|
|
178
|
+
response: { headers: {} },
|
|
179
|
+
};
|
|
180
|
+
} else if (args.doStream) {
|
|
181
|
+
return args.doStream;
|
|
182
|
+
} else {
|
|
183
|
+
throw new Error("Provide either content or doStream");
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
this._supportedUrls =
|
|
187
|
+
typeof supportedUrls === "function"
|
|
188
|
+
? supportedUrls
|
|
189
|
+
: async () => supportedUrls;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
get supportedUrls() {
|
|
193
|
+
return this._supportedUrls();
|
|
194
|
+
}
|
|
195
|
+
}
|
package/src/client/streaming.ts
CHANGED
|
@@ -197,6 +197,7 @@ export class DeltaStreamer {
|
|
|
197
197
|
public readonly component: AgentComponent,
|
|
198
198
|
public readonly ctx: RunActionCtx,
|
|
199
199
|
options: true | StreamingOptions,
|
|
200
|
+
private onAsyncAbort: (reason: string) => Promise<void>,
|
|
200
201
|
public readonly metadata: {
|
|
201
202
|
threadId: string;
|
|
202
203
|
userId?: string;
|
|
@@ -210,21 +211,22 @@ export class DeltaStreamer {
|
|
|
210
211
|
},
|
|
211
212
|
) {
|
|
212
213
|
this.options =
|
|
213
|
-
|
|
214
|
+
options === true
|
|
214
215
|
? DEFAULT_STREAMING_OPTIONS
|
|
215
216
|
: { ...DEFAULT_STREAMING_OPTIONS, ...options };
|
|
216
217
|
this.#nextParts = [];
|
|
217
218
|
this.abortController = new AbortController();
|
|
218
219
|
if (metadata.abortSignal) {
|
|
219
220
|
metadata.abortSignal.addEventListener("abort", async () => {
|
|
221
|
+
if (this.abortController.signal.aborted) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
220
224
|
if (this.streamId) {
|
|
221
225
|
this.abortController.abort();
|
|
222
|
-
const finalDelta = this.#createDelta();
|
|
223
226
|
await this.#ongoingWrite;
|
|
224
227
|
await this.ctx.runMutation(this.component.streams.abort, {
|
|
225
228
|
streamId: this.streamId,
|
|
226
229
|
reason: "abortSignal",
|
|
227
|
-
finalDelta,
|
|
228
230
|
});
|
|
229
231
|
}
|
|
230
232
|
});
|
|
@@ -265,9 +267,12 @@ export class DeltaStreamer {
|
|
|
265
267
|
delta,
|
|
266
268
|
);
|
|
267
269
|
if (!success) {
|
|
270
|
+
await this.onAsyncAbort("async abort");
|
|
268
271
|
this.abortController.abort();
|
|
272
|
+
return;
|
|
269
273
|
}
|
|
270
274
|
} catch (e) {
|
|
275
|
+
await this.onAsyncAbort(e instanceof Error ? e.message : "unknown error");
|
|
271
276
|
this.abortController.abort();
|
|
272
277
|
throw e;
|
|
273
278
|
}
|
|
@@ -302,11 +307,9 @@ export class DeltaStreamer {
|
|
|
302
307
|
if (!this.streamId) {
|
|
303
308
|
return;
|
|
304
309
|
}
|
|
305
|
-
const finalDelta = this.#createDelta();
|
|
306
310
|
await this.#ongoingWrite;
|
|
307
311
|
await this.ctx.runMutation(this.component.streams.finish, {
|
|
308
312
|
streamId: this.streamId,
|
|
309
|
-
finalDelta,
|
|
310
313
|
});
|
|
311
314
|
}
|
|
312
315
|
|
|
@@ -318,12 +321,10 @@ export class DeltaStreamer {
|
|
|
318
321
|
if (!this.streamId) {
|
|
319
322
|
return;
|
|
320
323
|
}
|
|
321
|
-
const finalDelta = this.#createDelta();
|
|
322
324
|
await this.#ongoingWrite;
|
|
323
325
|
await this.ctx.runMutation(this.component.streams.abort, {
|
|
324
326
|
streamId: this.streamId,
|
|
325
327
|
reason,
|
|
326
|
-
finalDelta,
|
|
327
328
|
});
|
|
328
329
|
}
|
|
329
330
|
}
|
|
@@ -260,6 +260,31 @@ export type Mounts = {
|
|
|
260
260
|
toolName: string;
|
|
261
261
|
type: "tool-result";
|
|
262
262
|
}
|
|
263
|
+
| {
|
|
264
|
+
id: string;
|
|
265
|
+
providerMetadata?: Record<
|
|
266
|
+
string,
|
|
267
|
+
Record<string, any>
|
|
268
|
+
>;
|
|
269
|
+
providerOptions?: Record<string, Record<string, any>>;
|
|
270
|
+
sourceType: "url";
|
|
271
|
+
title: string;
|
|
272
|
+
type: "source";
|
|
273
|
+
url: string;
|
|
274
|
+
}
|
|
275
|
+
| {
|
|
276
|
+
filename?: string;
|
|
277
|
+
id: string;
|
|
278
|
+
mediaType: string;
|
|
279
|
+
providerMetadata?: Record<
|
|
280
|
+
string,
|
|
281
|
+
Record<string, any>
|
|
282
|
+
>;
|
|
283
|
+
providerOptions?: Record<string, Record<string, any>>;
|
|
284
|
+
sourceType: "document";
|
|
285
|
+
title: string;
|
|
286
|
+
type: "source";
|
|
287
|
+
}
|
|
263
288
|
>;
|
|
264
289
|
providerOptions?: Record<string, Record<string, any>>;
|
|
265
290
|
role: "assistant";
|
|
@@ -469,6 +494,31 @@ export type Mounts = {
|
|
|
469
494
|
toolName: string;
|
|
470
495
|
type: "tool-result";
|
|
471
496
|
}
|
|
497
|
+
| {
|
|
498
|
+
id: string;
|
|
499
|
+
providerMetadata?: Record<
|
|
500
|
+
string,
|
|
501
|
+
Record<string, any>
|
|
502
|
+
>;
|
|
503
|
+
providerOptions?: Record<string, Record<string, any>>;
|
|
504
|
+
sourceType: "url";
|
|
505
|
+
title: string;
|
|
506
|
+
type: "source";
|
|
507
|
+
url: string;
|
|
508
|
+
}
|
|
509
|
+
| {
|
|
510
|
+
filename?: string;
|
|
511
|
+
id: string;
|
|
512
|
+
mediaType: string;
|
|
513
|
+
providerMetadata?: Record<
|
|
514
|
+
string,
|
|
515
|
+
Record<string, any>
|
|
516
|
+
>;
|
|
517
|
+
providerOptions?: Record<string, Record<string, any>>;
|
|
518
|
+
sourceType: "document";
|
|
519
|
+
title: string;
|
|
520
|
+
type: "source";
|
|
521
|
+
}
|
|
472
522
|
>;
|
|
473
523
|
providerOptions?: Record<string, Record<string, any>>;
|
|
474
524
|
role: "assistant";
|
|
@@ -687,6 +737,25 @@ export type Mounts = {
|
|
|
687
737
|
toolName: string;
|
|
688
738
|
type: "tool-result";
|
|
689
739
|
}
|
|
740
|
+
| {
|
|
741
|
+
id: string;
|
|
742
|
+
providerMetadata?: Record<string, Record<string, any>>;
|
|
743
|
+
providerOptions?: Record<string, Record<string, any>>;
|
|
744
|
+
sourceType: "url";
|
|
745
|
+
title: string;
|
|
746
|
+
type: "source";
|
|
747
|
+
url: string;
|
|
748
|
+
}
|
|
749
|
+
| {
|
|
750
|
+
filename?: string;
|
|
751
|
+
id: string;
|
|
752
|
+
mediaType: string;
|
|
753
|
+
providerMetadata?: Record<string, Record<string, any>>;
|
|
754
|
+
providerOptions?: Record<string, Record<string, any>>;
|
|
755
|
+
sourceType: "document";
|
|
756
|
+
title: string;
|
|
757
|
+
type: "source";
|
|
758
|
+
}
|
|
690
759
|
>;
|
|
691
760
|
providerOptions?: Record<string, Record<string, any>>;
|
|
692
761
|
role: "assistant";
|
|
@@ -918,6 +987,31 @@ export type Mounts = {
|
|
|
918
987
|
toolName: string;
|
|
919
988
|
type: "tool-result";
|
|
920
989
|
}
|
|
990
|
+
| {
|
|
991
|
+
id: string;
|
|
992
|
+
providerMetadata?: Record<
|
|
993
|
+
string,
|
|
994
|
+
Record<string, any>
|
|
995
|
+
>;
|
|
996
|
+
providerOptions?: Record<string, Record<string, any>>;
|
|
997
|
+
sourceType: "url";
|
|
998
|
+
title: string;
|
|
999
|
+
type: "source";
|
|
1000
|
+
url: string;
|
|
1001
|
+
}
|
|
1002
|
+
| {
|
|
1003
|
+
filename?: string;
|
|
1004
|
+
id: string;
|
|
1005
|
+
mediaType: string;
|
|
1006
|
+
providerMetadata?: Record<
|
|
1007
|
+
string,
|
|
1008
|
+
Record<string, any>
|
|
1009
|
+
>;
|
|
1010
|
+
providerOptions?: Record<string, Record<string, any>>;
|
|
1011
|
+
sourceType: "document";
|
|
1012
|
+
title: string;
|
|
1013
|
+
type: "source";
|
|
1014
|
+
}
|
|
921
1015
|
>;
|
|
922
1016
|
providerOptions?: Record<string, Record<string, any>>;
|
|
923
1017
|
role: "assistant";
|
|
@@ -1121,6 +1215,25 @@ export type Mounts = {
|
|
|
1121
1215
|
toolName: string;
|
|
1122
1216
|
type: "tool-result";
|
|
1123
1217
|
}
|
|
1218
|
+
| {
|
|
1219
|
+
id: string;
|
|
1220
|
+
providerMetadata?: Record<string, Record<string, any>>;
|
|
1221
|
+
providerOptions?: Record<string, Record<string, any>>;
|
|
1222
|
+
sourceType: "url";
|
|
1223
|
+
title: string;
|
|
1224
|
+
type: "source";
|
|
1225
|
+
url: string;
|
|
1226
|
+
}
|
|
1227
|
+
| {
|
|
1228
|
+
filename?: string;
|
|
1229
|
+
id: string;
|
|
1230
|
+
mediaType: string;
|
|
1231
|
+
providerMetadata?: Record<string, Record<string, any>>;
|
|
1232
|
+
providerOptions?: Record<string, Record<string, any>>;
|
|
1233
|
+
sourceType: "document";
|
|
1234
|
+
title: string;
|
|
1235
|
+
type: "source";
|
|
1236
|
+
}
|
|
1124
1237
|
>;
|
|
1125
1238
|
providerOptions?: Record<string, Record<string, any>>;
|
|
1126
1239
|
role: "assistant";
|
|
@@ -1317,6 +1430,25 @@ export type Mounts = {
|
|
|
1317
1430
|
toolName: string;
|
|
1318
1431
|
type: "tool-result";
|
|
1319
1432
|
}
|
|
1433
|
+
| {
|
|
1434
|
+
id: string;
|
|
1435
|
+
providerMetadata?: Record<string, Record<string, any>>;
|
|
1436
|
+
providerOptions?: Record<string, Record<string, any>>;
|
|
1437
|
+
sourceType: "url";
|
|
1438
|
+
title: string;
|
|
1439
|
+
type: "source";
|
|
1440
|
+
url: string;
|
|
1441
|
+
}
|
|
1442
|
+
| {
|
|
1443
|
+
filename?: string;
|
|
1444
|
+
id: string;
|
|
1445
|
+
mediaType: string;
|
|
1446
|
+
providerMetadata?: Record<string, Record<string, any>>;
|
|
1447
|
+
providerOptions?: Record<string, Record<string, any>>;
|
|
1448
|
+
sourceType: "document";
|
|
1449
|
+
title: string;
|
|
1450
|
+
type: "source";
|
|
1451
|
+
}
|
|
1320
1452
|
>;
|
|
1321
1453
|
providerOptions?: Record<string, Record<string, any>>;
|
|
1322
1454
|
role: "assistant";
|
|
@@ -1527,6 +1659,31 @@ export type Mounts = {
|
|
|
1527
1659
|
toolName: string;
|
|
1528
1660
|
type: "tool-result";
|
|
1529
1661
|
}
|
|
1662
|
+
| {
|
|
1663
|
+
id: string;
|
|
1664
|
+
providerMetadata?: Record<
|
|
1665
|
+
string,
|
|
1666
|
+
Record<string, any>
|
|
1667
|
+
>;
|
|
1668
|
+
providerOptions?: Record<string, Record<string, any>>;
|
|
1669
|
+
sourceType: "url";
|
|
1670
|
+
title: string;
|
|
1671
|
+
type: "source";
|
|
1672
|
+
url: string;
|
|
1673
|
+
}
|
|
1674
|
+
| {
|
|
1675
|
+
filename?: string;
|
|
1676
|
+
id: string;
|
|
1677
|
+
mediaType: string;
|
|
1678
|
+
providerMetadata?: Record<
|
|
1679
|
+
string,
|
|
1680
|
+
Record<string, any>
|
|
1681
|
+
>;
|
|
1682
|
+
providerOptions?: Record<string, Record<string, any>>;
|
|
1683
|
+
sourceType: "document";
|
|
1684
|
+
title: string;
|
|
1685
|
+
type: "source";
|
|
1686
|
+
}
|
|
1530
1687
|
>;
|
|
1531
1688
|
providerOptions?: Record<string, Record<string, any>>;
|
|
1532
1689
|
role: "assistant";
|
|
@@ -1661,6 +1818,25 @@ export type Mounts = {
|
|
|
1661
1818
|
toolName: string;
|
|
1662
1819
|
type: "tool-result";
|
|
1663
1820
|
}
|
|
1821
|
+
| {
|
|
1822
|
+
id: string;
|
|
1823
|
+
providerMetadata?: Record<string, Record<string, any>>;
|
|
1824
|
+
providerOptions?: Record<string, Record<string, any>>;
|
|
1825
|
+
sourceType: "url";
|
|
1826
|
+
title: string;
|
|
1827
|
+
type: "source";
|
|
1828
|
+
url: string;
|
|
1829
|
+
}
|
|
1830
|
+
| {
|
|
1831
|
+
filename?: string;
|
|
1832
|
+
id: string;
|
|
1833
|
+
mediaType: string;
|
|
1834
|
+
providerMetadata?: Record<string, Record<string, any>>;
|
|
1835
|
+
providerOptions?: Record<string, Record<string, any>>;
|
|
1836
|
+
sourceType: "document";
|
|
1837
|
+
title: string;
|
|
1838
|
+
type: "source";
|
|
1839
|
+
}
|
|
1664
1840
|
>;
|
|
1665
1841
|
providerOptions?: Record<string, Record<string, any>>;
|
|
1666
1842
|
role: "assistant";
|
|
@@ -351,7 +351,7 @@ export const finalizeMessage = mutation({
|
|
|
351
351
|
return;
|
|
352
352
|
}
|
|
353
353
|
// See if we can add any in-progress data
|
|
354
|
-
if (message.message
|
|
354
|
+
if (!message.message?.content.length) {
|
|
355
355
|
const messages = await getStreamingMessagesWithMetadata(
|
|
356
356
|
ctx,
|
|
357
357
|
message,
|
package/src/mapping.ts
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
} from "ai";
|
|
21
21
|
import {
|
|
22
22
|
vMessageWithMetadata,
|
|
23
|
+
type vSourcePart,
|
|
23
24
|
type Message,
|
|
24
25
|
type MessageWithMetadata,
|
|
25
26
|
type Usage,
|
|
@@ -31,6 +32,7 @@ import {
|
|
|
31
32
|
type vTextPart,
|
|
32
33
|
type vToolCallPart,
|
|
33
34
|
type vToolResultPart,
|
|
35
|
+
type SourcePart,
|
|
34
36
|
} from "./validators.js";
|
|
35
37
|
import type { ActionCtx, AgentComponent } from "./client/types.js";
|
|
36
38
|
import type { RunMutationCtx } from "./client/types.js";
|
|
@@ -335,6 +337,9 @@ export async function serializeContent(
|
|
|
335
337
|
...metadata,
|
|
336
338
|
} satisfies Infer<typeof vRedactedReasoningPart>;
|
|
337
339
|
}
|
|
340
|
+
case "source": {
|
|
341
|
+
return part satisfies Infer<typeof vSourcePart>;
|
|
342
|
+
}
|
|
338
343
|
default:
|
|
339
344
|
return part satisfies Infer<typeof vContent>;
|
|
340
345
|
}
|
|
@@ -431,6 +436,8 @@ export function deserializeContent(
|
|
|
431
436
|
}
|
|
432
437
|
: undefined,
|
|
433
438
|
} satisfies ReasoningPart;
|
|
439
|
+
case "source":
|
|
440
|
+
return part satisfies SourcePart;
|
|
434
441
|
default:
|
|
435
442
|
return part satisfies Content;
|
|
436
443
|
}
|
|
@@ -12,8 +12,9 @@ import type {
|
|
|
12
12
|
} from "ai";
|
|
13
13
|
import { extractText, type MessageDoc } from "../client/index.js";
|
|
14
14
|
import { deserializeMessage, toUIFilePart } from "../mapping.js";
|
|
15
|
-
import type { MessageStatus } from "../validators.js";
|
|
15
|
+
import type { MessageStatus, SourcePart, vSource } from "../validators.js";
|
|
16
16
|
import { sorted } from "../shared.js";
|
|
17
|
+
import type { Infer } from "convex/values";
|
|
17
18
|
|
|
18
19
|
export type UIMessage<
|
|
19
20
|
METADATA = unknown,
|
|
@@ -388,29 +389,23 @@ function createAssistantUIMessage<
|
|
|
388
389
|
}
|
|
389
390
|
break;
|
|
390
391
|
}
|
|
392
|
+
default: {
|
|
393
|
+
const maybeSource = contentPart as SourcePart;
|
|
394
|
+
if (maybeSource.type === "source") {
|
|
395
|
+
allParts.push(toSourcePart(maybeSource));
|
|
396
|
+
} else {
|
|
397
|
+
console.warn(
|
|
398
|
+
"Unknown content part type for assistant",
|
|
399
|
+
contentPart,
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
391
403
|
}
|
|
392
404
|
}
|
|
393
405
|
|
|
394
406
|
// Add source parts
|
|
395
407
|
for (const source of message.sources ?? []) {
|
|
396
|
-
|
|
397
|
-
allParts.push({
|
|
398
|
-
type: "source-url",
|
|
399
|
-
url: source.url!,
|
|
400
|
-
sourceId: source.id,
|
|
401
|
-
providerMetadata: message.providerMetadata,
|
|
402
|
-
title: source.title,
|
|
403
|
-
} satisfies SourceUrlUIPart);
|
|
404
|
-
} else {
|
|
405
|
-
allParts.push({
|
|
406
|
-
type: "source-document",
|
|
407
|
-
mediaType: source.mediaType,
|
|
408
|
-
sourceId: source.id,
|
|
409
|
-
title: source.title,
|
|
410
|
-
filename: source.filename,
|
|
411
|
-
providerMetadata: message.providerMetadata,
|
|
412
|
-
} satisfies SourceDocumentUIPart);
|
|
413
|
-
}
|
|
408
|
+
allParts.push(toSourcePart(source));
|
|
414
409
|
}
|
|
415
410
|
}
|
|
416
411
|
|
|
@@ -422,3 +417,25 @@ function createAssistantUIMessage<
|
|
|
422
417
|
parts: allParts,
|
|
423
418
|
};
|
|
424
419
|
}
|
|
420
|
+
|
|
421
|
+
function toSourcePart(
|
|
422
|
+
part: SourcePart | Infer<typeof vSource>,
|
|
423
|
+
): SourceUrlUIPart | SourceDocumentUIPart {
|
|
424
|
+
if (part.sourceType === "url") {
|
|
425
|
+
return {
|
|
426
|
+
type: "source-url",
|
|
427
|
+
url: part.url,
|
|
428
|
+
sourceId: part.id,
|
|
429
|
+
providerMetadata: part.providerMetadata,
|
|
430
|
+
title: part.title,
|
|
431
|
+
} satisfies SourceUrlUIPart;
|
|
432
|
+
}
|
|
433
|
+
return {
|
|
434
|
+
type: "source-document",
|
|
435
|
+
mediaType: part.mediaType,
|
|
436
|
+
sourceId: part.id,
|
|
437
|
+
title: part.title,
|
|
438
|
+
filename: part.filename,
|
|
439
|
+
providerMetadata: part.providerMetadata,
|
|
440
|
+
} satisfies SourceDocumentUIPart;
|
|
441
|
+
}
|
package/src/validators.ts
CHANGED
|
@@ -87,6 +87,29 @@ export const vReasoningDetails = v.array(
|
|
|
87
87
|
),
|
|
88
88
|
);
|
|
89
89
|
|
|
90
|
+
export const vSourcePart = v.union(
|
|
91
|
+
v.object({
|
|
92
|
+
type: v.literal("source"),
|
|
93
|
+
sourceType: v.literal("url"),
|
|
94
|
+
id: v.string(),
|
|
95
|
+
url: v.string(),
|
|
96
|
+
title: v.string(),
|
|
97
|
+
providerOptions,
|
|
98
|
+
providerMetadata,
|
|
99
|
+
}),
|
|
100
|
+
v.object({
|
|
101
|
+
type: v.literal("source"),
|
|
102
|
+
sourceType: v.literal("document"),
|
|
103
|
+
id: v.string(),
|
|
104
|
+
mediaType: v.string(),
|
|
105
|
+
title: v.string(),
|
|
106
|
+
filename: v.optional(v.string()),
|
|
107
|
+
providerOptions,
|
|
108
|
+
providerMetadata,
|
|
109
|
+
}),
|
|
110
|
+
);
|
|
111
|
+
export type SourcePart = Infer<typeof vSourcePart>;
|
|
112
|
+
|
|
90
113
|
export const vToolCallPart = v.object({
|
|
91
114
|
type: v.literal("tool-call"),
|
|
92
115
|
toolCallId: v.string(),
|
|
@@ -136,6 +159,7 @@ export const vAssistantContent = v.union(
|
|
|
136
159
|
vRedactedReasoningPart,
|
|
137
160
|
vToolCallPart,
|
|
138
161
|
vToolResultPart,
|
|
162
|
+
vSourcePart,
|
|
139
163
|
),
|
|
140
164
|
),
|
|
141
165
|
);
|