@convex-dev/agent
Version:
A agent component for Convex.
127 lines (115 loc) • 3.87 kB
text/typescript
import { omit } from "convex-helpers";
import { literals } from "convex-helpers/validators";
import {
defineTable,
type GenericTableSearchIndexes,
type SchemaDefinition,
type TableDefinition,
} from "convex/server";
import {
type GenericId,
type Infer,
type ObjectType,
v,
type VId,
type VObject,
type VUnion,
} from "convex/values";
import type { QueryCtx } from "../_generated/server.js";
// We only generate embeddings for non-tool, non-system messages
const embeddings = {
model: v.string(),
// What table it's stored in. (usually messages or memories)
table: v.string(),
userId: v.optional(v.string()),
threadId: v.optional(v.string()),
// not set for private threads
model_table_userId: v.optional(v.array(v.string())),
model_table_threadId: v.optional(v.array(v.string())),
vector: v.array(v.number()),
};
export const vEmbeddingsWithoutDenormalizedFields = v.object(
omit(embeddings, ["model_table_userId", "model_table_threadId"]),
);
export type EmbeddingsWithoutDenormalizedFields = Infer<
typeof vEmbeddingsWithoutDenormalizedFields
>;
function table<D extends number>(dimensions: D): VectorTable<D> {
return defineTable(embeddings)
.vectorIndex("vector", {
vectorField: "vector",
dimensions,
filterFields: ["model_table_userId", "model_table_threadId"],
})
.index("model_table_threadId", ["model", "table", "threadId"]);
}
type VectorTable<D extends number> = TableDefinition<
VObject<ObjectType<typeof embeddings>, typeof embeddings>,
{ model_table_threadId: ["model", "table", "threadId", "_creationTime"] },
GenericTableSearchIndexes,
VectorIndex<D>
>;
type VectorIndex<D extends number> = {
vector: {
vectorField: "vector";
dimensions: D;
filterFields: "model_table_userId" | "model_table_threadId";
};
};
export type VectorSchema = SchemaDefinition<
{ [key in VectorTableName]: VectorTable<128> },
true
>;
export const VectorDimensions = [
128, 256, 512, 768, 1024, 1408, 1536, 2048, 3072, 4096,
] as const;
export function validateVectorDimension(
dimension: number,
): asserts dimension is VectorDimension {
if (!VectorDimensions.includes(dimension as VectorDimension)) {
throw new Error(
`Unsupported vector dimension${dimension}. Supported: ${VectorDimensions.join(", ")}`,
);
}
}
export type VectorDimension = (typeof VectorDimensions)[number];
export const VectorTableNames = VectorDimensions.map(
(d) => `embeddings_${d}`,
) as `embeddings_${(typeof VectorDimensions)[number]}`[];
export type VectorTableName = (typeof VectorTableNames)[number];
export type VectorTableId = GenericId<(typeof VectorTableNames)[number]>;
export const vVectorDimension = literals(...VectorDimensions);
export const vVectorTableName = literals(...VectorTableNames);
export const vVectorId = v.union(
...VectorTableNames.map((name) => v.id(name)),
) as VUnion<
GenericId<(typeof VectorTableNames)[number]>,
VId<(typeof VectorTableNames)[number]>[]
>;
export function getVectorTableName(dimension: VectorDimension) {
return `embeddings_${dimension}` as VectorTableName;
}
export function getVectorIdInfo(ctx: QueryCtx, id: VectorTableId) {
for (const dimension of VectorDimensions) {
const tableName = getVectorTableName(dimension);
if (ctx.db.normalizeId(tableName, id)) {
return { tableName, dimension };
}
}
throw new Error(`Unknown vector table id: ${id}`);
}
const tables: {
[K in keyof typeof VectorDimensions &
number as `embeddings_${(typeof VectorDimensions)[K]}`]: VectorTable<
(typeof VectorDimensions)[K]
>;
} = Object.fromEntries(
VectorDimensions.map((dimensions) => [
`embeddings_${dimensions}`,
table(dimensions),
]),
) as Record<
`embeddings_${(typeof VectorDimensions)[number]}`,
VectorTable<(typeof VectorDimensions)[number]>
>;
export default tables;