@convex-dev/agent 0.0.1-alpha.1 → 0.0.1-alpha.3
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/README.md +293 -6
- package/dist/commonjs/client/index.d.ts +520 -96
- package/dist/commonjs/client/index.d.ts.map +1 -1
- package/dist/commonjs/client/index.js +210 -131
- package/dist/commonjs/client/index.js.map +1 -1
- package/dist/commonjs/client/types.d.ts +3 -0
- package/dist/commonjs/client/types.d.ts.map +1 -1
- package/dist/commonjs/component/messages.d.ts +57 -56
- package/dist/commonjs/component/messages.d.ts.map +1 -1
- package/dist/commonjs/component/messages.js +184 -147
- package/dist/commonjs/component/messages.js.map +1 -1
- package/dist/commonjs/component/schema.d.ts +260 -256
- package/dist/commonjs/component/schema.d.ts.map +1 -1
- package/dist/commonjs/component/schema.js +25 -18
- package/dist/commonjs/component/schema.js.map +1 -1
- package/dist/commonjs/component/vector/index.d.ts +4 -4
- package/dist/commonjs/component/vector/index.d.ts.map +1 -1
- package/dist/commonjs/component/vector/index.js +12 -10
- package/dist/commonjs/component/vector/index.js.map +1 -1
- package/dist/commonjs/component/vector/tables.d.ts +3 -3
- package/dist/commonjs/component/vector/tables.js +6 -6
- package/dist/commonjs/component/vector/tables.js.map +1 -1
- package/dist/commonjs/mapping.d.ts +6 -1
- package/dist/commonjs/mapping.d.ts.map +1 -1
- package/dist/commonjs/mapping.js +25 -0
- package/dist/commonjs/mapping.js.map +1 -1
- package/dist/commonjs/validators.d.ts +1376 -1
- package/dist/commonjs/validators.d.ts.map +1 -1
- package/dist/commonjs/validators.js +28 -1
- package/dist/commonjs/validators.js.map +1 -1
- package/dist/esm/client/index.d.ts +520 -96
- package/dist/esm/client/index.d.ts.map +1 -1
- package/dist/esm/client/index.js +210 -131
- package/dist/esm/client/index.js.map +1 -1
- package/dist/esm/client/types.d.ts +3 -0
- package/dist/esm/client/types.d.ts.map +1 -1
- package/dist/esm/component/messages.d.ts +57 -56
- package/dist/esm/component/messages.d.ts.map +1 -1
- package/dist/esm/component/messages.js +184 -147
- package/dist/esm/component/messages.js.map +1 -1
- package/dist/esm/component/schema.d.ts +260 -256
- package/dist/esm/component/schema.d.ts.map +1 -1
- package/dist/esm/component/schema.js +25 -18
- package/dist/esm/component/schema.js.map +1 -1
- package/dist/esm/component/vector/index.d.ts +4 -4
- package/dist/esm/component/vector/index.d.ts.map +1 -1
- package/dist/esm/component/vector/index.js +12 -10
- package/dist/esm/component/vector/index.js.map +1 -1
- package/dist/esm/component/vector/tables.d.ts +3 -3
- package/dist/esm/component/vector/tables.js +6 -6
- package/dist/esm/component/vector/tables.js.map +1 -1
- package/dist/esm/mapping.d.ts +6 -1
- package/dist/esm/mapping.d.ts.map +1 -1
- package/dist/esm/mapping.js +25 -0
- package/dist/esm/mapping.js.map +1 -1
- package/dist/esm/validators.d.ts +1376 -1
- package/dist/esm/validators.d.ts.map +1 -1
- package/dist/esm/validators.js +28 -1
- package/dist/esm/validators.js.map +1 -1
- package/package.json +3 -3
- package/src/client/index.ts +384 -276
- package/src/client/types.ts +4 -0
- package/src/component/_generated/api.d.ts +54 -53
- package/src/component/messages.ts +219 -177
- package/src/component/schema.ts +25 -18
- package/src/component/vector/index.ts +13 -11
- package/src/component/vector/tables.ts +6 -6
- package/src/mapping.ts +46 -11
- package/src/validators.test.ts +9 -0
- package/src/validators.ts +36 -1
package/src/component/schema.ts
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
import { defineSchema, defineTable } from "convex/server";
|
|
2
2
|
import { v } from "convex/values";
|
|
3
|
-
import {
|
|
3
|
+
import { vThreadStatus, vMessage, vMessageStatus, vStep } from "../validators";
|
|
4
4
|
import { typedV } from "convex-helpers/validators";
|
|
5
5
|
import vectorTables, { vVectorId } from "./vector/tables";
|
|
6
6
|
|
|
7
7
|
export const schema = defineSchema({
|
|
8
|
-
|
|
8
|
+
threads: defineTable({
|
|
9
9
|
userId: v.optional(v.string()), // Unset for anonymous
|
|
10
10
|
order: v.optional(v.number()), // within a domain
|
|
11
11
|
// TODO: is this bubbling up in continue?
|
|
12
12
|
defaultSystemPrompt: v.optional(v.string()),
|
|
13
13
|
title: v.optional(v.string()),
|
|
14
14
|
summary: v.optional(v.string()),
|
|
15
|
-
status:
|
|
16
|
-
// If this is a
|
|
17
|
-
// the parent
|
|
18
|
-
// multiple
|
|
19
|
-
|
|
15
|
+
status: vThreadStatus,
|
|
16
|
+
// If this is a thread continuation, we can use this to find context from
|
|
17
|
+
// the parent thread(s). There are multiple if the thread is a merging of
|
|
18
|
+
// multiple threads.
|
|
19
|
+
parentThreadIds: v.optional(v.array(v.id("threads"))),
|
|
20
20
|
}).index("status_userId_order", ["status", "userId", "order"]),
|
|
21
21
|
// TODO: text search on title/ summary
|
|
22
22
|
messages: defineTable({
|
|
23
23
|
id: v.optional(v.string()), // external id, e.g. from Vercel AI SDK
|
|
24
24
|
userId: v.optional(v.string()), // useful for future indexes (text search)
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
threadId: v.optional(v.id("threads")),
|
|
26
|
+
parentMessageId: v.optional(v.id("messages")),
|
|
27
27
|
stepId: v.optional(v.id("steps")),
|
|
28
28
|
agentName: v.optional(v.string()),
|
|
29
29
|
message: v.optional(vMessage),
|
|
@@ -33,7 +33,7 @@ export const schema = defineSchema({
|
|
|
33
33
|
// TODO: add sub-messages back in? or be able to skip them?
|
|
34
34
|
tool: v.boolean(),
|
|
35
35
|
// Repeats until a non-tool message.
|
|
36
|
-
//
|
|
36
|
+
// Unset if it's not in a thread.
|
|
37
37
|
order: v.number(),
|
|
38
38
|
stepOrder: v.optional(v.number()),
|
|
39
39
|
fileId: v.optional(v.id("files")),
|
|
@@ -41,8 +41,15 @@ export const schema = defineSchema({
|
|
|
41
41
|
})
|
|
42
42
|
// Allows finding successful visible messages in order
|
|
43
43
|
// Also surface pending messages separately to e.g. stream
|
|
44
|
-
.index("
|
|
45
|
-
"
|
|
44
|
+
.index("threadId_status_tool_order_stepOrder", [
|
|
45
|
+
"threadId",
|
|
46
|
+
"status",
|
|
47
|
+
"tool",
|
|
48
|
+
"order",
|
|
49
|
+
"stepOrder",
|
|
50
|
+
])
|
|
51
|
+
.index("userId_status_tool_order_stepOrder", [
|
|
52
|
+
"userId",
|
|
46
53
|
"status",
|
|
47
54
|
"tool",
|
|
48
55
|
"order",
|
|
@@ -50,22 +57,22 @@ export const schema = defineSchema({
|
|
|
50
57
|
])
|
|
51
58
|
// Allows finding all threaded messages in order
|
|
52
59
|
// Allows finding all failed messages to evaluate
|
|
53
|
-
// .index("
|
|
60
|
+
// .index("status_parentMessageId_order_stepOrder", [
|
|
54
61
|
// "status",
|
|
55
|
-
// "
|
|
62
|
+
// "parentMessageId",
|
|
56
63
|
// "order",
|
|
57
64
|
// "stepOrder",
|
|
58
65
|
// ])
|
|
59
66
|
// Allows text search on message content
|
|
60
67
|
.searchIndex("text_search", {
|
|
61
68
|
searchField: "text",
|
|
62
|
-
filterFields: ["userId", "
|
|
69
|
+
filterFields: ["userId", "threadId"],
|
|
63
70
|
})
|
|
64
71
|
// Allows finding messages by vector embedding id
|
|
65
72
|
.index("embeddingId", ["embeddingId"]),
|
|
66
73
|
|
|
67
74
|
steps: defineTable({
|
|
68
|
-
|
|
75
|
+
threadId: v.id("threads"),
|
|
69
76
|
// Could be different from the order if we fail.
|
|
70
77
|
parentMessageId: v.id("messages"),
|
|
71
78
|
order: v.number(), // parent message order
|
|
@@ -73,9 +80,9 @@ export const schema = defineSchema({
|
|
|
73
80
|
step: vStep,
|
|
74
81
|
status: vMessageStatus,
|
|
75
82
|
})
|
|
76
|
-
.index("
|
|
83
|
+
.index("status_threadId_order_stepOrder", [
|
|
77
84
|
"status",
|
|
78
|
-
"
|
|
85
|
+
"threadId",
|
|
79
86
|
"order",
|
|
80
87
|
"stepOrder",
|
|
81
88
|
])
|
|
@@ -23,7 +23,7 @@ export const paginate = query({
|
|
|
23
23
|
const vectors = await paginator(ctx.db, schema)
|
|
24
24
|
.query(tableName)
|
|
25
25
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
26
|
-
.withIndex("
|
|
26
|
+
.withIndex("model_kind_threadId" as any, (q) =>
|
|
27
27
|
q.eq("model", args.targetModel)
|
|
28
28
|
)
|
|
29
29
|
.paginate({
|
|
@@ -39,11 +39,11 @@ export const paginate = query({
|
|
|
39
39
|
},
|
|
40
40
|
});
|
|
41
41
|
|
|
42
|
-
export const
|
|
42
|
+
export const deleteBatchForThread = mutation({
|
|
43
43
|
args: {
|
|
44
44
|
vectorDimension: vVectorDimension,
|
|
45
45
|
model: v.string(),
|
|
46
|
-
|
|
46
|
+
threadId: v.string(),
|
|
47
47
|
cursor: v.optional(v.string()),
|
|
48
48
|
limit: v.number(),
|
|
49
49
|
},
|
|
@@ -54,18 +54,18 @@ export const deleteBatchForChat = mutation({
|
|
|
54
54
|
handler: async (ctx, args) => {
|
|
55
55
|
const tableName = getVectorTableName(args.vectorDimension);
|
|
56
56
|
const vectors = await mergedStream(
|
|
57
|
-
["
|
|
57
|
+
["thread", "memory"].map((kind) =>
|
|
58
58
|
stream(ctx.db, schema)
|
|
59
59
|
.query(tableName)
|
|
60
60
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
61
|
-
.withIndex("
|
|
61
|
+
.withIndex("model_kind_threadId" as any, (q) =>
|
|
62
62
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
63
63
|
(q.eq("model", args.model) as any)
|
|
64
64
|
.eq("kind", kind)
|
|
65
|
-
.eq("
|
|
65
|
+
.eq("threadId", args.threadId)
|
|
66
66
|
)
|
|
67
67
|
),
|
|
68
|
-
["
|
|
68
|
+
["threadId"]
|
|
69
69
|
).paginate({
|
|
70
70
|
cursor: args.cursor ?? null,
|
|
71
71
|
numItems: args.limit,
|
|
@@ -85,9 +85,9 @@ export const insertBatch = mutation({
|
|
|
85
85
|
vectors: v.array(
|
|
86
86
|
v.object({
|
|
87
87
|
model: v.string(),
|
|
88
|
-
kind: v.union(v.literal("
|
|
88
|
+
kind: v.union(v.literal("thread"), v.literal("memory")),
|
|
89
89
|
userId: v.optional(v.string()),
|
|
90
|
-
|
|
90
|
+
threadId: v.optional(v.string()),
|
|
91
91
|
vector: v.array(v.number()),
|
|
92
92
|
})
|
|
93
93
|
),
|
|
@@ -100,10 +100,12 @@ export const insertBatch = mutation({
|
|
|
100
100
|
model: v.model,
|
|
101
101
|
kind: v.kind,
|
|
102
102
|
userId: v.userId,
|
|
103
|
-
|
|
103
|
+
threadId: v.threadId,
|
|
104
104
|
vector: v.vector,
|
|
105
105
|
model_kind_userId: v.userId ? [v.model, v.kind, v.userId] : undefined,
|
|
106
|
-
|
|
106
|
+
model_kind_threadId: v.threadId
|
|
107
|
+
? [v.model, v.kind, v.threadId]
|
|
108
|
+
: undefined,
|
|
107
109
|
})
|
|
108
110
|
)
|
|
109
111
|
);
|
|
@@ -10,12 +10,12 @@ import { QueryCtx } from "../_generated/server";
|
|
|
10
10
|
// We only generate embeddings for non-tool, non-system messages
|
|
11
11
|
const embeddings = {
|
|
12
12
|
model: v.string(),
|
|
13
|
-
kind: v.union(v.literal("
|
|
13
|
+
kind: v.union(v.literal("thread"), v.literal("memory")),
|
|
14
14
|
userId: v.optional(v.string()),
|
|
15
|
-
|
|
16
|
-
// not set for private
|
|
15
|
+
threadId: v.optional(v.string()),
|
|
16
|
+
// not set for private threads
|
|
17
17
|
model_kind_userId: v.optional(v.array(v.string())),
|
|
18
|
-
|
|
18
|
+
model_kind_threadId: v.optional(v.array(v.string())),
|
|
19
19
|
vector: v.array(v.number()),
|
|
20
20
|
};
|
|
21
21
|
|
|
@@ -24,9 +24,9 @@ function table<D extends number>(dimensions: D): Table<D> {
|
|
|
24
24
|
.vectorIndex("vector", {
|
|
25
25
|
vectorField: "vector",
|
|
26
26
|
dimensions,
|
|
27
|
-
filterFields: ["model_kind_userId", "
|
|
27
|
+
filterFields: ["model_kind_userId", "model_kind_threadId"],
|
|
28
28
|
})
|
|
29
|
-
.index("
|
|
29
|
+
.index("model_kind_threadId", ["model", "kind", "threadId"]);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
export const VectorDimensions = [
|
package/src/mapping.ts
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
import {
|
|
2
|
+
convertToCoreMessages,
|
|
3
|
+
coreMessageSchema,
|
|
4
|
+
type AssistantContent,
|
|
5
|
+
type CoreAssistantMessage,
|
|
6
|
+
type CoreMessage,
|
|
7
|
+
type CoreToolMessage,
|
|
8
|
+
type DataContent,
|
|
9
|
+
type GenerateTextResult,
|
|
10
|
+
type StepResult,
|
|
11
|
+
type ToolContent,
|
|
12
|
+
type ToolSet,
|
|
13
|
+
type Message as UIMessage,
|
|
14
|
+
type UserContent,
|
|
12
15
|
} from "ai";
|
|
13
16
|
import { MessageWithFileAndId, Step } from "./validators";
|
|
17
|
+
import { assert } from "convex-helpers";
|
|
14
18
|
|
|
15
19
|
export type SerializeUrlsAndUint8Arrays<T> = T extends URL
|
|
16
20
|
? string
|
|
@@ -158,3 +162,34 @@ function deserializeUrl(urlOrString: string | ArrayBuffer): URL | DataContent {
|
|
|
158
162
|
}
|
|
159
163
|
return urlOrString;
|
|
160
164
|
}
|
|
165
|
+
|
|
166
|
+
export function promptOrMessagesToCoreMessages(args: {
|
|
167
|
+
system?: string;
|
|
168
|
+
prompt?: string;
|
|
169
|
+
messages?: CoreMessage[] | Omit<UIMessage, "id">[];
|
|
170
|
+
}): CoreMessage[] {
|
|
171
|
+
const messages: CoreMessage[] = [];
|
|
172
|
+
if (args.system) {
|
|
173
|
+
messages.push({ role: "system", content: args.system });
|
|
174
|
+
}
|
|
175
|
+
if (!args.messages) {
|
|
176
|
+
assert(args.prompt, "messages or prompt is required");
|
|
177
|
+
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
|
+
}
|
|
193
|
+
assert(messages.length > 0, "Messages must contain at least one message");
|
|
194
|
+
return messages;
|
|
195
|
+
}
|
package/src/validators.test.ts
CHANGED
|
@@ -3,11 +3,13 @@ import { expectTypeOf, test } from "vitest";
|
|
|
3
3
|
import {
|
|
4
4
|
vAssistantContent,
|
|
5
5
|
vAssistantMessage,
|
|
6
|
+
vContextOptions,
|
|
6
7
|
vFilePart,
|
|
7
8
|
vImagePart,
|
|
8
9
|
vMessage,
|
|
9
10
|
vReasoningPart,
|
|
10
11
|
vRedactedReasoningPart,
|
|
12
|
+
vStorageOptions,
|
|
11
13
|
vSystemMessage,
|
|
12
14
|
vTextPart,
|
|
13
15
|
vToolCallPart,
|
|
@@ -31,6 +33,7 @@ import {
|
|
|
31
33
|
UserContent,
|
|
32
34
|
} from "ai";
|
|
33
35
|
import { SerializeUrlsAndUint8Arrays } from "./mapping";
|
|
36
|
+
import { ContextOptions, StorageOptions } from "./client";
|
|
34
37
|
|
|
35
38
|
// type assertion
|
|
36
39
|
type OurUserContent = SerializeUrlsAndUint8Arrays<UserContent>;
|
|
@@ -98,4 +101,10 @@ type OurMessage = SerializeUrlsAndUint8Arrays<CoreMessage>;
|
|
|
98
101
|
expectTypeOf<OurMessage>().toExtend<Infer<typeof vMessage>>();
|
|
99
102
|
expectTypeOf<Infer<typeof vMessage>>().toExtend<OurMessage>();
|
|
100
103
|
|
|
104
|
+
expectTypeOf<Infer<typeof vContextOptions>>().toExtend<ContextOptions>();
|
|
105
|
+
expectTypeOf<ContextOptions>().toExtend<Infer<typeof vContextOptions>>();
|
|
106
|
+
|
|
107
|
+
expectTypeOf<Infer<typeof vStorageOptions>>().toExtend<StorageOptions>();
|
|
108
|
+
expectTypeOf<StorageOptions>().toExtend<Infer<typeof vStorageOptions>>();
|
|
109
|
+
|
|
101
110
|
test("noop", () => { });
|
package/src/validators.ts
CHANGED
|
@@ -5,7 +5,10 @@ import { Infer, v } from "convex/values";
|
|
|
5
5
|
const providerOptions = v.optional(v.record(v.string(), v.any()));
|
|
6
6
|
const experimental_providerMetadata = providerOptions;
|
|
7
7
|
|
|
8
|
-
export const
|
|
8
|
+
export const vThreadStatus = v.union(
|
|
9
|
+
v.literal("active"),
|
|
10
|
+
v.literal("archived")
|
|
11
|
+
);
|
|
9
12
|
export const vMessageStatus = v.union(
|
|
10
13
|
v.literal("pending"),
|
|
11
14
|
v.literal("success"),
|
|
@@ -256,3 +259,35 @@ export const vSearchOptions = v.object({
|
|
|
256
259
|
messageRange: v.optional(v.object({ before: v.number(), after: v.number() })),
|
|
257
260
|
});
|
|
258
261
|
export type SearchOptions = Infer<typeof vSearchOptions>;
|
|
262
|
+
|
|
263
|
+
export const vContextOptionsSearchOptions = v.object({
|
|
264
|
+
limit: v.number(),
|
|
265
|
+
textSearch: v.optional(v.boolean()),
|
|
266
|
+
vectorSearch: v.optional(v.boolean()),
|
|
267
|
+
messageRange: v.optional(v.object({ before: v.number(), after: v.number() })),
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
export const vContextOptions = v.object({
|
|
271
|
+
includeToolCalls: v.optional(v.boolean()),
|
|
272
|
+
recentMessages: v.optional(v.number()),
|
|
273
|
+
searchOptions: v.optional(vContextOptionsSearchOptions),
|
|
274
|
+
searchOtherThreads: v.optional(v.boolean()),
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
export const vStorageOptions = v.object({
|
|
278
|
+
saveAllInputMessages: v.optional(v.boolean()),
|
|
279
|
+
saveAllOutputMessages: v.optional(v.boolean()),
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
export const vThreadArgs = v.object({
|
|
283
|
+
maxSteps: v.optional(v.number()),
|
|
284
|
+
prompt: v.optional(v.string()),
|
|
285
|
+
messages: v.optional(v.array(vMessage)),
|
|
286
|
+
});
|
|
287
|
+
|
|
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)),
|
|
293
|
+
});
|