Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 15 additions & 12 deletions example/convex/example.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,20 +270,23 @@ export const t = action({
},
}),
},
maxSteps: 5,
maxSteps: 20,
});

const { threadId, thread } = await fastAgent.createThread(ctx, {});
// eslint-disable-next-line @typescript-eslint/no-floating-promises
const s = await thread.streamText({
prompt:
"Do something four times, then do something else, then do something else again",
});
console.log("s", s);

for await (const chunk of s.textStream) {
console.log(chunk);
}
// // eslint-disable-next-line @typescript-eslint/no-floating-promises
await Promise.all(
Array.from({ length: 10 }).map(async (i) => {
const { threadId, thread } = await fastAgent.createThread(ctx, {
userId: "123",
});
const s = await thread.streamText({
prompt: "Do something twice",
});
console.log("agent", i);
await s.response;
}),
);
console.log("done");
// return result.text;
},
});
3 changes: 1 addition & 2 deletions example/convex/http.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { httpRouter } from "convex/server";
import { httpAction } from "./_generated/server";
import { streamHttpAction } from "./example";

const http = httpRouter();

http.route({
path: "/streamText",
method: "GET",
method: "POST",
handler: streamHttpAction,
});

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"email": "support@convex.dev",
"url": "https://github.com/get-convex/agent/issues"
},
"version": "0.0.4",
"version": "0.0.5-alpha.1",
"license": "Apache-2.0",
"keywords": [
"convex",
Expand Down
40 changes: 21 additions & 19 deletions src/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import type {
ToolChoice,
ToolExecutionOptions,
ToolSet,
Message as UIMessage,
} from "ai";
import {
generateObject,
Expand All @@ -38,6 +37,7 @@ import {
VectorDimension,
} from "../component/vector/tables";
import {
AIMessageWithoutId,
promptOrMessagesToCoreMessages,
serializeMessageWithId,
serializeNewMessagesInStep,
Expand Down Expand Up @@ -288,17 +288,14 @@ export class Agent<AgentTools extends ToolSet> {
included = new Set(searchMessages.map((m) => m._id));
contextMessages.push(...searchMessages.map((m) => m.message!));
}
if (args.threadId) {
if (args.threadId && opts.recentMessages !== 0) {
const { page } = await ctx.runQuery(
this.component.messages.getThreadMessages,
{
threadId: args.threadId,
isTool: args.includeToolCalls ?? false,
paginationOpts: {
numItems:
args.recentMessages ??
this.options.contextOptions?.recentMessages ??
DEFAULT_RECENT_MESSAGES,
numItems: opts.recentMessages ?? DEFAULT_RECENT_MESSAGES,
cursor: null,
},
parentMessageId: args.parentMessageId,
Expand Down Expand Up @@ -555,7 +552,7 @@ export class Agent<AgentTools extends ToolSet> {
async saveMessagesAndFetchContext<
T extends {
prompt?: string;
messages?: CoreMessage[] | Omit<UIMessage, "id">[];
messages?: CoreMessage[] | AIMessageWithoutId[];
system?: string;
},
>(
Expand Down Expand Up @@ -834,7 +831,7 @@ export class Agent<AgentTools extends ToolSet> {
...rest,
schema: jsonSchema(schema),
} as unknown as OurStreamObjectArgs<unknown>);
for await (const chunk of value.fullStream) {
for await (const _ of value.fullStream) {
// no-op, just consume the stream
}
return value.object;
Expand All @@ -859,23 +856,28 @@ export class Agent<AgentTools extends ToolSet> {
args: Validator<unknown, "required", string>;
contextOptions?: ContextOptions;
maxSteps?: number;
provideMessageHistory?: boolean;
}) {
return createTool({
...spec,
handler: async (ctx, args) => {
handler: async (ctx, args, options) => {
const maxSteps = spec.maxSteps ?? this.options.maxSteps;
const contextOptions =
spec.contextOptions && this.mergedContextOptions(spec.contextOptions);
const value = await this.generateText(
ctx,
{ userId: ctx.userId, threadId: ctx.threadId },
{
prompt: JSON.stringify(args),
parentMessageId: ctx.messageId,
maxSteps,
...contextOptions,
}
);
const { thread } = await this.createThread(ctx, {
parentThreadIds: ctx.threadId ? [ctx.threadId] : undefined,
userId: ctx.userId,
});
const messages = spec.provideMessageHistory ? options.messages : [];
messages.push({
role: "user",
content: JSON.stringify(args),
});
const value = await thread.generateText({
messages,
maxSteps,
...contextOptions,
});
return value.text;
},
});
Expand Down
2 changes: 0 additions & 2 deletions src/component/_generated/api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
* @module
*/

import type * as lib from "../lib.js";
import type * as messages from "../messages.js";
import type * as vector_index from "../vector/index.js";
import type * as vector_tables from "../vector/tables.js";
Expand All @@ -28,7 +27,6 @@ import type {
* ```
*/
declare const fullApi: ApiFromModules<{
lib: typeof lib;
messages: typeof messages;
"vector/index": typeof vector_index;
"vector/tables": typeof vector_tables;
Expand Down
2 changes: 0 additions & 2 deletions src/component/lib.ts

This file was deleted.

File renamed without changes.
11 changes: 2 additions & 9 deletions src/component/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export const getThreadsByUserId = query({
handler: async (ctx, args) => {
const threads = await paginator(ctx.db, schema)
.query("threads")
.withIndex("userId_order", (q) => q.eq("userId", args.userId))
.withIndex("userId", (q) => q.eq("userId", args.userId))
.order(args.order ?? "desc")
.paginate(args.paginationOpts ?? { cursor: null, numItems: 100 });
return threads;
Expand All @@ -68,15 +68,8 @@ const vThread = schema.tables.threads.validator;
export const createThread = mutation({
args: omit(vThread.fields, ["order", "status"]),
handler: async (ctx, args) => {
const latestThread = await ctx.db
.query("threads")
.withIndex("userId_order", (q) => q.eq("userId", args.userId))
.order("desc")
.first();
const order = (latestThread?.order ?? -1) + 1;
const threadId = await ctx.db.insert("threads", {
...args,
order,
status: "active",
});
return (await ctx.db.get(threadId))!;
Expand Down Expand Up @@ -207,7 +200,7 @@ async function deletePageForUserId(
): Promise<DeleteAllReturns> {
const threads = await paginator(ctx.db, schema)
.query("threads")
.withIndex("userId_order", (q) => q.eq("userId", args.userId))
.withIndex("userId", (q) => q.eq("userId", args.userId))
.order("desc")
.paginate({
numItems: 100,
Expand Down
5 changes: 3 additions & 2 deletions src/component/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import vectorTables, { vVectorId } from "./vector/tables";
export const schema = defineSchema({
threads: defineTable({
userId: v.optional(v.string()), // Unset for anonymous
order: v.optional(v.number()), // within a domain
// TODO: is this bubbling up in continue?
defaultSystemPrompt: v.optional(v.string()),
title: v.optional(v.string()),
Expand All @@ -17,7 +16,9 @@ export const schema = defineSchema({
// the parent thread(s). There are multiple if the thread is a merging of
// multiple threads.
parentThreadIds: v.optional(v.array(v.id("threads"))),
}).index("userId_order", ["userId", "order"]),
// DEPRECATED
order: /*DEPRECATED*/ v.optional(v.number()),
}).index("userId", ["userId"]),
// TODO: text search on title/ summary
messages: defineTable({
id: v.optional(v.string()), // external id, e.g. from Vercel AI SDK
Expand Down
9 changes: 5 additions & 4 deletions src/mapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ import {
type AssistantContent,
type CoreMessage,
type DataContent,
type GenerateTextResult,
type StepResult,
type ToolContent,
type ToolSet,
type Message as UIMessage,
type Message as AIMessage,
type UserContent,
} from "ai";
import { assert } from "convex-helpers";
Expand All @@ -19,6 +18,8 @@ import {
StepWithMessagesWithFileAndId,
} from "./validators";

export type AIMessageWithoutId = Omit<AIMessage, "id">;

export type SerializeUrlsAndUint8Arrays<T> = T extends URL
? string
: T extends Uint8Array | ArrayBufferLike
Expand Down Expand Up @@ -195,7 +196,7 @@ function deserializeUrl(urlOrString: string | ArrayBuffer): URL | DataContent {
export function promptOrMessagesToCoreMessages(args: {
system?: string;
prompt?: string;
messages?: CoreMessage[] | Omit<UIMessage, "id">[];
messages?: CoreMessage[] | AIMessageWithoutId[];
}): CoreMessage[] {
const messages: CoreMessage[] = [];
if (args.system) {
Expand All @@ -214,7 +215,7 @@ export function promptOrMessagesToCoreMessages(args: {
"experimental_attachments" in m)
)
) {
messages.push(...convertToCoreMessages(args.messages as UIMessage[]));
messages.push(...convertToCoreMessages(args.messages as AIMessage[]));
} else {
messages.push(...coreMessageSchema.array().parse(args.messages));
}
Expand Down