Files
veridian/drizzle/schema.ts
T
zoeissleeping a836082de8 feat: per-agent tools toggle and better python scratchpad
Add ToolSelector for enabling sandboxed python per agent, drop unsafe
filesystem/bash tools, bundle fetchUrl with web search, and return
Monty's last expression value so agents need not print.
2026-07-29 14:18:37 -05:00

324 lines
12 KiB
TypeScript

import {
pgTable,
text,
timestamp,
boolean,
integer,
jsonb,
pgEnum,
vector,
index
} from 'drizzle-orm/pg-core';
import { nanoid } from 'nanoid';
// Always use timestamptz. Drizzle treats naive `timestamp` values as UTC on read
// (via textToDateWithTz), which shifts displayed times by the server offset
// (e.g. -5h in America/Chicago).
const timestamptz = (name: string) => timestamp(name, { withTimezone: true });
export const roleEnum = pgEnum('role', ['user', 'assistant']);
export const partTypeEnum = pgEnum('part_type', ['reasoning', 'text', 'tool-call', 'file']);
export const statusEnum = pgEnum('status', ['pending', 'completed', 'failed', 'cancelled']);
export enum ToolCallType {
Text = 'text',
Json = 'json',
}
export const settings = pgTable('settings', {
id: text('id').primaryKey().$defaultFn(nanoid),
userId: text('user_id').notNull(),
systemAssistants: jsonb('system_assistants').$type<{
rename: {
enabled: boolean;
modelId: string | null;
};
rerank: {
enabled: boolean;
modelId: string | null;
};
}>().notNull().default({} as any),
appearance: jsonb('appearance').$type<{
colorScheme?: 'light' | 'dark' | 'system';
accent?: string;
neutral?: string;
hinting?: number;
fontSize?: string;
}>(),
}, (table) => [
index('settings_userId_idx').on(table.userId),
]);
export const providers = pgTable('providers', {
id: text('id').primaryKey().$defaultFn(nanoid),
userId: text('user_id').notNull(),
type: text('type').notNull(),
name: text('name').notNull(),
enabled: boolean('enabled').notNull().default(true),
config: jsonb('config').notNull().$type<{
apiKey?: string;
apiProxyUrl?: string;
}>().default({}),
createdAt: timestamptz('created_at').notNull().defaultNow(),
updatedAt: timestamptz('updated_at').notNull().defaultNow().$onUpdate(() => /* @__PURE__ */ new Date()),
}, (table) => [
index('providers_userId_idx').on(table.userId),
]);
export const models = pgTable('models', {
id: text('id').primaryKey().$defaultFn(nanoid),
userId: text('user_id').notNull(),
externalId: text('external_id').notNull(),
providerId: text('provider_id').notNull().references(() => providers.id, { onDelete: 'cascade' }),
name: text('name').notNull(),
cost: jsonb('cost').notNull().$type<{
prompt?: string;
completion?: string;
request?: string;
image?: string;
imageTokens?: string;
imageOutput?: string;
audio?: string;
audioOutput?: string;
inputAudioCache?: string;
webSearch?: string;
internalReasoning?: string;
inputCacheRead?: string;
inputCacheWrite?: string;
discount?: string;
}>().default({}),
inputModalities: text('input_modalities').array().notNull().default([]),
outputModalities: text('output_modalities').array().notNull().default([]),
capabilities: text('capabilities').array().notNull().default([]),
contextWindow: integer('context_window'),
supportedParameters: text('supported_parameters').array(),
isCustom: boolean('is_custom').notNull().default(false),
enabled: boolean('enabled').notNull().default(true),
releasedAt: timestamptz('released_at'),
}, (table) => [
index('models_providerId_idx').on(table.providerId),
index('models_userId_idx').on(table.userId),
]);
export const agents = pgTable('agents', {
id: text('id').primaryKey().$defaultFn(nanoid),
userId: text('user_id').notNull(),
name: text('name').notNull(),
systemPrompt: text('system_prompt'),
imageUrl: text('image_url'),
defaultModelId: text('default_model_id').references(() => models.id, { onDelete: 'set null' }),
config: jsonb('config').$type<{
search?: {
enabled: boolean;
rerank: boolean;
maxResults: number;
};
tools?: {
python?: boolean;
};
}>().default({}),
createdAt: timestamptz('created_at').notNull().defaultNow(),
}, (table) => [
index('agents_userId_idx').on(table.userId),
]);
export const topics = pgTable('topics', {
id: text('id').primaryKey().$defaultFn(nanoid),
userId: text('user_id').notNull(),
agentId: text('agent_id').notNull().references(() => agents.id, { onDelete: 'cascade' }),
name: text('name').notNull(),
renaming: boolean('renaming').default(false),
createdAt: timestamptz('created_at').notNull().defaultNow(),
}, (table) => [
index('topics_agentId_idx').on(table.agentId),
index('topics_userId_idx').on(table.userId),
]);
export const messages = pgTable('messages', {
id: text('id').primaryKey().$defaultFn(nanoid),
userId: text('user_id').notNull(),
topicId: text('topic_id').notNull().references(() => topics.id, { onDelete: 'cascade' }),
parentMessageId: text('parent_message_id'),
generationId: text('generation_id').references(() => generations.id, { onDelete: 'cascade' }),
role: roleEnum('role').notNull(),
content: text('content'),
activeChildId: text('active_child_id'),
deleted: boolean('deleted').default(false),
updatedAt: timestamptz('updated_at').notNull().defaultNow().$onUpdate(() => /* @__PURE__ */ new Date()),
createdAt: timestamptz('created_at').notNull().defaultNow(),
}, (table) => [
index('messages_topicId_idx').on(table.topicId),
index('messages_parentMessageId_idx').on(table.parentMessageId),
index('messages_userId_idx').on(table.userId),
]);
export const messageParts = pgTable('message_parts', {
id: text('id').primaryKey().$defaultFn(nanoid),
userId: text('user_id').notNull(),
topicId: text('topic_id').notNull().references(() => topics.id, { onDelete: 'cascade' }),
messageId: text('message_id').notNull().references(() => messages.id, { onDelete: 'cascade' }),
toolCallId: text('tool_call_id').references(() => toolCalls.id, { onDelete: 'cascade' }),
type: partTypeEnum('type').notNull(),
content: text('content'),
providerOptions: jsonb('provider_options'),
finished: boolean('finished').notNull().default(false),
createdAt: timestamptz('created_at').notNull().defaultNow(),
lastUpdatedAt: timestamptz('last_updated_at').notNull().defaultNow().$onUpdate(() => /* @__PURE__ */ new Date()),
}, (table) => [
index('message_parts_topicId_idx').on(table.topicId),
index('message_parts_messageId_idx').on(table.messageId),
index('message_parts_userId_idx').on(table.userId),
]);
export const toolCalls = pgTable('tool_calls', {
id: text('id').primaryKey().$defaultFn(nanoid),
userId: text('user_id').notNull(),
toolName: text('tool_name').notNull(),
status: statusEnum('status').notNull().default('pending'),
input: jsonb('input').$type<{
type: ToolCallType;
value: string;
}>(),
output: jsonb('output').$type<{
type: ToolCallType;
value: string;
}>(),
error: jsonb('error').$type<{
type: ToolCallType;
value: string;
}>(),
createdAt: timestamptz('created_at').notNull().defaultNow(),
}, (table) => [
index('tool_calls_userId_idx').on(table.userId),
]);
export const generations = pgTable('generations', {
id: text('id').primaryKey().$defaultFn(nanoid),
userId: text('user_id').notNull(),
topicId: text('topic_id').notNull().references(() => topics.id, { onDelete: 'cascade' }),
modelId: text('model_id').notNull(),
status: statusEnum('status').notNull(),
tokens: jsonb('tokens').$type<{
input?: number;
cache?: {
read?: number;
write?: number;
};
output?: number;
thinking?: number;
ttft?: number;
tps?: number;
}>(),
error: text('error'),
}, (table) => [
index('generations_topicId_idx').on(table.topicId),
index('generations_userId_idx').on(table.userId),
]);
export const files = pgTable('files', {
id: text('id').primaryKey().$defaultFn(nanoid),
userId: text('user_id').notNull(),
name: text('name').notNull(),
mimeType: text('mime_type').notNull(),
size: integer('size').notNull().default(0),
url: text('url').notNull(),
createdAt: timestamptz('created_at').notNull().defaultNow(),
}, (table) => [
index('files_userId_idx').on(table.userId),
]);
export const embeddings = pgTable('embeddings', {
id: text('id').primaryKey().$defaultFn(nanoid),
fileId: text('file_id').notNull().references(() => files.id, { onDelete: 'cascade' }),
content: text('content').notNull(),
embedding: vector('embedding', { dimensions: 1536 }),
metadata: jsonb('metadata'),
}, (table) => [
index('embeddings_fileId_idx').on(table.fileId),
]);
export const attachments = pgTable('attachments', {
id: text('id').primaryKey().$defaultFn(nanoid),
userId: text('user_id').notNull(),
topicId: text('topic_id').notNull().references(() => topics.id, { onDelete: 'cascade' }),
messageId: text('message_id').notNull().references(() => messages.id, { onDelete: 'cascade' }),
fileId: text('file_id').notNull().references(() => files.id, { onDelete: 'cascade' }),
createdAt: timestamptz('created_at').notNull().defaultNow(),
}, (table) => [
index('attachments_topicId_idx').on(table.topicId),
index('attachments_messageId_idx').on(table.messageId),
index('attachments_userId_idx').on(table.userId),
]);
export const users = pgTable("users", {
id: text("id").primaryKey(),
name: text("name").notNull(),
email: text("email").notNull().unique(),
emailVerified: boolean("email_verified").default(false).notNull(),
image: text("image"),
createdAt: timestamptz("created_at").defaultNow().notNull(),
updatedAt: timestamptz("updated_at")
.defaultNow()
.$onUpdate(() => /* @__PURE__ */ new Date())
.notNull(),
});
export const sessions = pgTable(
"sessions",
{
id: text("id").primaryKey(),
expiresAt: timestamptz("expires_at").notNull(),
token: text("token").notNull().unique(),
createdAt: timestamptz("created_at").defaultNow().notNull(),
updatedAt: timestamptz("updated_at")
.$onUpdate(() => /* @__PURE__ */ new Date())
.notNull(),
ipAddress: text("ip_address"),
userAgent: text("user_agent"),
userId: text("user_id")
.notNull()
.references(() => users.id, { onDelete: "cascade" }),
},
(table) => [index("sessions_userId_idx").on(table.userId)],
);
export const accounts = pgTable(
"accounts",
{
id: text("id").primaryKey(),
accountId: text("account_id").notNull(),
providerId: text("provider_id").notNull(),
userId: text("user_id")
.notNull()
.references(() => users.id, { onDelete: "cascade" }),
accessToken: text("access_token"),
refreshToken: text("refresh_token"),
idToken: text("id_token"),
accessTokenExpiresAt: timestamptz("access_token_expires_at"),
refreshTokenExpiresAt: timestamptz("refresh_token_expires_at"),
scope: text("scope"),
password: text("password"),
createdAt: timestamptz("created_at").defaultNow().notNull(),
updatedAt: timestamptz("updated_at")
.$onUpdate(() => /* @__PURE__ */ new Date())
.notNull(),
},
(table) => [index("accounts_userId_idx").on(table.userId)],
);
export const verifications = pgTable(
"verifications",
{
id: text("id").primaryKey(),
identifier: text("identifier").notNull(),
value: text("value").notNull(),
expiresAt: timestamptz("expires_at").notNull(),
createdAt: timestamptz("created_at").defaultNow().notNull(),
updatedAt: timestamptz("updated_at")
.defaultNow()
.$onUpdate(() => /* @__PURE__ */ new Date())
.notNull(),
},
(table) => [index("verifications_identifier_idx").on(table.identifier)],
);