@convex-dev/agent 0.1.9-alpha.2 → 0.1.9-alpha.4
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 +3 -3
- package/dist/commonjs/client/index.d.ts.map +1 -1
- package/dist/commonjs/client/index.js +1 -1
- package/dist/commonjs/client/index.js.map +1 -1
- package/dist/commonjs/client/streaming.d.ts.map +1 -1
- package/dist/commonjs/client/streaming.js +7 -1
- package/dist/commonjs/client/streaming.js.map +1 -1
- package/dist/commonjs/client/types.d.ts +0 -2
- package/dist/commonjs/client/types.d.ts.map +1 -1
- package/dist/commonjs/component/_generated/api.d.ts +18 -4
- package/dist/commonjs/component/schema.d.ts +36 -6
- package/dist/commonjs/component/schema.d.ts.map +1 -1
- package/dist/commonjs/component/schema.js +3 -0
- package/dist/commonjs/component/schema.js.map +1 -1
- package/dist/commonjs/component/streams.d.ts +5 -0
- package/dist/commonjs/component/streams.d.ts.map +1 -1
- package/dist/commonjs/component/streams.js +35 -7
- package/dist/commonjs/component/streams.js.map +1 -1
- package/dist/commonjs/component/threads.d.ts +8 -2
- package/dist/commonjs/component/threads.d.ts.map +1 -1
- package/dist/commonjs/component/threads.js +44 -18
- package/dist/commonjs/component/threads.js.map +1 -1
- package/dist/commonjs/react/index.d.ts +3 -1
- package/dist/commonjs/react/index.d.ts.map +1 -1
- package/dist/commonjs/react/index.js +14 -3
- package/dist/commonjs/react/index.js.map +1 -1
- package/dist/commonjs/validators.d.ts +5 -2
- package/dist/commonjs/validators.d.ts.map +1 -1
- package/dist/commonjs/validators.js +1 -0
- package/dist/commonjs/validators.js.map +1 -1
- package/dist/commonjs.tsbuildinfo +1 -1
- package/dist/esm/client/index.d.ts.map +1 -1
- package/dist/esm/client/index.js +1 -1
- package/dist/esm/client/index.js.map +1 -1
- package/dist/esm/client/streaming.d.ts.map +1 -1
- package/dist/esm/client/streaming.js +7 -1
- package/dist/esm/client/streaming.js.map +1 -1
- package/dist/esm/client/types.d.ts +0 -2
- package/dist/esm/client/types.d.ts.map +1 -1
- package/dist/esm/component/_generated/api.d.ts +18 -4
- package/dist/esm/component/schema.d.ts +36 -6
- package/dist/esm/component/schema.d.ts.map +1 -1
- package/dist/esm/component/schema.js +3 -0
- package/dist/esm/component/schema.js.map +1 -1
- package/dist/esm/component/streams.d.ts +5 -0
- package/dist/esm/component/streams.d.ts.map +1 -1
- package/dist/esm/component/streams.js +35 -7
- package/dist/esm/component/streams.js.map +1 -1
- package/dist/esm/component/threads.d.ts +8 -2
- package/dist/esm/component/threads.d.ts.map +1 -1
- package/dist/esm/component/threads.js +44 -18
- package/dist/esm/component/threads.js.map +1 -1
- package/dist/esm/react/index.d.ts +3 -1
- package/dist/esm/react/index.d.ts.map +1 -1
- package/dist/esm/react/index.js +14 -3
- package/dist/esm/react/index.js.map +1 -1
- package/dist/esm/validators.d.ts +5 -2
- package/dist/esm/validators.d.ts.map +1 -1
- package/dist/esm/validators.js +1 -0
- package/dist/esm/validators.js.map +1 -1
- package/dist/esm.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/client/index.ts +1 -2
- package/src/client/streaming.ts +7 -1
- package/src/client/types.ts +0 -2
- package/src/component/_generated/api.d.ts +18 -4
- package/src/component/schema.ts +4 -0
- package/src/component/streams.ts +43 -8
- package/src/component/threads.ts +48 -26
- package/src/react/index.ts +15 -4
- package/src/validators.ts +1 -0
package/src/component/streams.ts
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
vStreamMessage,
|
|
7
7
|
} from "../validators.js";
|
|
8
8
|
import { api, internal } from "./_generated/api.js";
|
|
9
|
-
import type { Id } from "./_generated/dataModel.js";
|
|
9
|
+
import type { Doc, Id } from "./_generated/dataModel.js";
|
|
10
10
|
import {
|
|
11
11
|
internalMutation,
|
|
12
12
|
mutation,
|
|
@@ -102,13 +102,17 @@ export const create = mutation({
|
|
|
102
102
|
export const list = query({
|
|
103
103
|
args: {
|
|
104
104
|
threadId: v.id("threads"),
|
|
105
|
+
startOrder: v.optional(v.number()),
|
|
105
106
|
},
|
|
106
107
|
returns: v.array(vStreamMessage),
|
|
107
108
|
handler: async (ctx, args) => {
|
|
108
109
|
return ctx.db
|
|
109
110
|
.query("streamingMessages")
|
|
110
111
|
.withIndex("threadId_state_order_stepOrder", (q) =>
|
|
111
|
-
q
|
|
112
|
+
q
|
|
113
|
+
.eq("threadId", args.threadId)
|
|
114
|
+
.eq("state.kind", "streaming")
|
|
115
|
+
.gte("order", args.startOrder ?? 0)
|
|
112
116
|
)
|
|
113
117
|
.order("desc")
|
|
114
118
|
.take(100)
|
|
@@ -129,6 +133,42 @@ export const list = query({
|
|
|
129
133
|
},
|
|
130
134
|
});
|
|
131
135
|
|
|
136
|
+
export const abort = mutation({
|
|
137
|
+
args: {
|
|
138
|
+
streamId: v.id("streamingMessages"),
|
|
139
|
+
reason: v.string(),
|
|
140
|
+
},
|
|
141
|
+
returns: v.null(),
|
|
142
|
+
handler: async (ctx, args) => {
|
|
143
|
+
const stream = await ctx.db.get(args.streamId);
|
|
144
|
+
if (!stream) {
|
|
145
|
+
throw new Error(`Stream not found: ${args.streamId}`);
|
|
146
|
+
}
|
|
147
|
+
if (stream.state.kind !== "streaming") {
|
|
148
|
+
console.warn(
|
|
149
|
+
`Stream trying to abort but not currently streaming (${stream.state.kind}): ${args.streamId}`
|
|
150
|
+
);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
await cleanupTimeoutFn(ctx, stream);
|
|
154
|
+
await ctx.db.patch(args.streamId, {
|
|
155
|
+
state: { kind: "aborted", reason: args.reason },
|
|
156
|
+
});
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
async function cleanupTimeoutFn(
|
|
161
|
+
ctx: MutationCtx,
|
|
162
|
+
stream: Doc<"streamingMessages">
|
|
163
|
+
) {
|
|
164
|
+
if (stream.state.kind === "streaming" && stream.state.timeoutFnId) {
|
|
165
|
+
const timeoutFn = await ctx.db.system.get(stream.state.timeoutFnId);
|
|
166
|
+
if (timeoutFn?.state.kind === "pending") {
|
|
167
|
+
await ctx.scheduler.cancel(stream.state.timeoutFnId);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
132
172
|
export const finish = mutation({
|
|
133
173
|
args: {
|
|
134
174
|
streamId: v.id("streamingMessages"),
|
|
@@ -149,12 +189,7 @@ export const finish = mutation({
|
|
|
149
189
|
);
|
|
150
190
|
return;
|
|
151
191
|
}
|
|
152
|
-
|
|
153
|
-
const timeoutFn = await ctx.db.system.get(stream.state.timeoutFnId);
|
|
154
|
-
if (timeoutFn?.state.kind === "pending") {
|
|
155
|
-
await ctx.scheduler.cancel(stream.state.timeoutFnId);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
192
|
+
await cleanupTimeoutFn(ctx, stream);
|
|
158
193
|
await ctx.db.patch(args.streamId, {
|
|
159
194
|
state: { kind: "finished", endedAt: Date.now() },
|
|
160
195
|
});
|
package/src/component/threads.ts
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
} from "./_generated/server.js";
|
|
17
17
|
import { deleteMessage } from "./messages.js";
|
|
18
18
|
import { schema, v } from "./schema.js";
|
|
19
|
+
import { deleteStreamsPageForThreadId } from "./streams.js";
|
|
19
20
|
|
|
20
21
|
function publicThreadOrNull(thread: Doc<"threads"> | null): ThreadDoc | null {
|
|
21
22
|
if (thread === null) {
|
|
@@ -100,29 +101,17 @@ export const updateThread = mutation({
|
|
|
100
101
|
|
|
101
102
|
// TODO: delete thread
|
|
102
103
|
|
|
103
|
-
const deleteThreadArgs = {
|
|
104
|
-
threadId: v.id("threads"),
|
|
105
|
-
cursor: v.optional(v.string()),
|
|
106
|
-
limit: v.optional(v.number()),
|
|
107
|
-
};
|
|
108
|
-
type DeleteThreadArgs = ObjectType<typeof deleteThreadArgs>;
|
|
109
|
-
const deleteThreadReturns = {
|
|
110
|
-
cursor: v.string(),
|
|
111
|
-
isDone: v.boolean(),
|
|
112
|
-
};
|
|
113
|
-
type DeleteThreadReturns = ObjectType<typeof deleteThreadReturns>;
|
|
114
|
-
|
|
115
104
|
/**
|
|
116
105
|
* Use this to delete a thread and everything it contains.
|
|
117
106
|
* It will try to delete all pages synchronously.
|
|
118
107
|
* If it times out or fails, you'll have to run it again.
|
|
119
108
|
*/
|
|
120
109
|
export const deleteAllForThreadIdSync = action({
|
|
121
|
-
args:
|
|
110
|
+
args: { threadId: v.id("threads"), limit: v.optional(v.number()) },
|
|
122
111
|
handler: async (ctx, args) => {
|
|
123
|
-
let cursor =
|
|
112
|
+
let cursor: string | undefined = undefined;
|
|
124
113
|
while (true) {
|
|
125
|
-
const result = await ctx.runMutation(
|
|
114
|
+
const result: DeleteThreadReturns = await ctx.runMutation(
|
|
126
115
|
internal.threads._deletePageForThreadId,
|
|
127
116
|
{ threadId: args.threadId, cursor, limit: args.limit }
|
|
128
117
|
);
|
|
@@ -138,6 +127,22 @@ export const deleteAllForThreadIdSync = action({
|
|
|
138
127
|
returns: v.null(),
|
|
139
128
|
});
|
|
140
129
|
|
|
130
|
+
const deleteThreadArgs = {
|
|
131
|
+
threadId: v.id("threads"),
|
|
132
|
+
cursor: v.optional(v.string()),
|
|
133
|
+
messagesDone: v.optional(v.boolean()),
|
|
134
|
+
streamsDone: v.optional(v.boolean()),
|
|
135
|
+
streamOrder: v.optional(v.number()),
|
|
136
|
+
deltaCursor: v.optional(v.string()),
|
|
137
|
+
limit: v.optional(v.number()),
|
|
138
|
+
};
|
|
139
|
+
type DeleteThreadArgs = ObjectType<typeof deleteThreadArgs>;
|
|
140
|
+
const deleteThreadReturns = {
|
|
141
|
+
cursor: v.string(),
|
|
142
|
+
isDone: v.boolean(),
|
|
143
|
+
};
|
|
144
|
+
type DeleteThreadReturns = ObjectType<typeof deleteThreadReturns>;
|
|
145
|
+
|
|
141
146
|
export const _deletePageForThreadId = internalMutation({
|
|
142
147
|
args: deleteThreadArgs,
|
|
143
148
|
handler: deletePageForThreadIdHandler,
|
|
@@ -151,22 +156,39 @@ export const _deletePageForThreadId = internalMutation({
|
|
|
151
156
|
export const deleteAllForThreadIdAsync = mutation({
|
|
152
157
|
args: deleteThreadArgs,
|
|
153
158
|
handler: async (ctx, args) => {
|
|
154
|
-
|
|
155
|
-
|
|
159
|
+
let messagesResult = {
|
|
160
|
+
isDone: args.messagesDone ?? false,
|
|
161
|
+
cursor: args.cursor,
|
|
162
|
+
};
|
|
163
|
+
if (!args.messagesDone) {
|
|
164
|
+
messagesResult = await deletePageForThreadIdHandler(ctx, args);
|
|
165
|
+
}
|
|
166
|
+
let streamResult = {
|
|
167
|
+
isDone: args.streamsDone ?? false,
|
|
168
|
+
streamOrder: args.streamOrder,
|
|
169
|
+
deltaCursor: args.deltaCursor,
|
|
170
|
+
};
|
|
171
|
+
if (!args.streamsDone) {
|
|
172
|
+
streamResult = await deleteStreamsPageForThreadId(ctx, {
|
|
173
|
+
threadId: args.threadId,
|
|
174
|
+
streamOrder: args.streamOrder,
|
|
175
|
+
deltaCursor: args.deltaCursor,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
const isDone = messagesResult.isDone && streamResult.isDone;
|
|
179
|
+
if (!isDone) {
|
|
156
180
|
await ctx.scheduler.runAfter(0, api.threads.deleteAllForThreadIdAsync, {
|
|
157
181
|
threadId: args.threadId,
|
|
158
|
-
cursor:
|
|
182
|
+
cursor: messagesResult.cursor,
|
|
183
|
+
messagesDone: messagesResult.isDone,
|
|
184
|
+
streamsDone: streamResult.isDone,
|
|
185
|
+
streamOrder: streamResult.streamOrder,
|
|
186
|
+
deltaCursor: streamResult.deltaCursor,
|
|
159
187
|
});
|
|
160
188
|
}
|
|
161
|
-
|
|
162
|
-
await ctx.scheduler.runAfter(
|
|
163
|
-
0,
|
|
164
|
-
api.streams.deleteAllStreamsForThreadIdSync,
|
|
165
|
-
{ threadId: args.threadId }
|
|
166
|
-
);
|
|
167
|
-
return result;
|
|
189
|
+
return { isDone };
|
|
168
190
|
},
|
|
169
|
-
returns:
|
|
191
|
+
returns: v.object({ isDone: v.boolean() }),
|
|
170
192
|
});
|
|
171
193
|
|
|
172
194
|
async function deletePageForThreadIdHandler(
|
package/src/react/index.ts
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from "convex/react";
|
|
8
8
|
import { usePaginatedQuery } from "convex-helpers/react";
|
|
9
9
|
import type { FunctionArgs } from "convex/server";
|
|
10
|
-
import { useMemo, useState } from "react";
|
|
10
|
+
import { useMemo, useRef, useState } from "react";
|
|
11
11
|
import type { MessageDoc } from "../client/index.js";
|
|
12
12
|
import type { SyncStreamsReturnValue } from "../client/types.js";
|
|
13
13
|
import type { StreamArgs } from "../validators.js";
|
|
@@ -103,7 +103,11 @@ export function useThreadMessages<
|
|
|
103
103
|
ThreadMessagesArgs<Query>,
|
|
104
104
|
ThreadMessagesResult<Query>
|
|
105
105
|
>,
|
|
106
|
-
!options.stream
|
|
106
|
+
!options.stream ||
|
|
107
|
+
args === "skip" ||
|
|
108
|
+
paginated.status === "LoadingFirstPage"
|
|
109
|
+
? "skip"
|
|
110
|
+
: { ...args, startOrder: paginated.results.at(0)?.order }
|
|
107
111
|
);
|
|
108
112
|
|
|
109
113
|
const merged = useMemo(() => {
|
|
@@ -150,7 +154,7 @@ export function useStreamingThreadMessages<
|
|
|
150
154
|
Query extends ThreadStreamQuery<any, any>,
|
|
151
155
|
>(
|
|
152
156
|
query: Query,
|
|
153
|
-
args: ThreadMessagesArgs<Query> | "skip"
|
|
157
|
+
args: (ThreadMessagesArgs<Query> & { startOrder?: number }) | "skip"
|
|
154
158
|
): Array<ThreadMessagesResult<Query>> | undefined {
|
|
155
159
|
// Invariant: streamMessages[streamId] is comprised of all deltas up to the
|
|
156
160
|
// cursor. There can be multiple messages in the same stream, e.g. for tool
|
|
@@ -158,6 +162,10 @@ export function useStreamingThreadMessages<
|
|
|
158
162
|
const [streams, setStreams] = useState<
|
|
159
163
|
Array<{ streamId: string; cursor: number; messages: MessageDoc[] }>
|
|
160
164
|
>([]);
|
|
165
|
+
const startOrderRef = useRef<number>(0);
|
|
166
|
+
if (args !== "skip" && !startOrderRef.current && args.startOrder) {
|
|
167
|
+
startOrderRef.current = args.startOrder;
|
|
168
|
+
}
|
|
161
169
|
// Get all the active streams
|
|
162
170
|
const streamList = useQuery(
|
|
163
171
|
query,
|
|
@@ -166,7 +174,10 @@ export function useStreamingThreadMessages<
|
|
|
166
174
|
: ({
|
|
167
175
|
...args,
|
|
168
176
|
paginationOpts: { cursor: null, numItems: 0 },
|
|
169
|
-
streamArgs: {
|
|
177
|
+
streamArgs: {
|
|
178
|
+
kind: "list",
|
|
179
|
+
startOrder: startOrderRef.current,
|
|
180
|
+
} as StreamArgs,
|
|
170
181
|
} as FunctionArgs<Query>)
|
|
171
182
|
) as
|
|
172
183
|
| { streams: Extract<SyncStreamsReturnValue, { kind: "list" }> }
|