Files
veridian/triplit/schema.ts
T

313 lines
11 KiB
TypeScript

import { Schema as S } from '@triplit/client';
import { authSchema } from './auth-schema';
import { Providers } from '../app/types/model';
export const schema = S.Collections({
...authSchema,
agents: {
schema: S.Schema({
id: S.Id(),
userId: S.String(),
name: S.String(),
systemPrompt: S.String({ nullable: true }),
imageUrl: S.String({ nullable: true }),
defaultModelId: S.String({ nullable: true }),
createdAt: S.Date({ default: S.Default.now() }),
}),
relationships: {
topics: S.RelationMany('topics', {
where: [['agentId', '=', '$1.id']],
}),
model: S.RelationOne('models', {
where: [['id', '=', '$defaultModelId']],
}),
},
permissions: {
authenticated: {
read: {
filter: [['userId', '=', '$token.sub']],
},
insert: {
filter: [['userId', '=', '$token.sub']],
},
update: {
filter: [['userId', '=', '$token.sub']],
},
delete: {
filter: [['userId', '=', '$token.sub']],
},
},
},
},
topics: {
schema: S.Schema({
id: S.Id(),
userId: S.String(),
agentId: S.String(),
name: S.String(),
createdAt: S.Date({ default: S.Default.now() }),
}),
relationships: {
agent: S.RelationOne('agents', {
where: [['id', '=', '$agentId']],
}),
messages: S.RelationMany('messages', {
where: [['topicId', '=', '$id']],
}),
generations: S.RelationMany('generations', {
where: [['topicId', '=', '$id']],
}),
},
permissions: {
authenticated: {
read: {
filter: [['userId', '=', '$token.sub']],
},
insert: {
filter: [['userId', '=', '$token.sub']],
},
update: {
filter: [['userId', '=', '$token.sub']],
},
delete: {
filter: [['userId', '=', '$token.sub']],
},
},
},
},
message_parts: {
schema: S.Schema({
id: S.Id(),
messageId: S.String(),
toolCallId: S.String({ nullable: true }),
type: S.String({ enum: ['reasoning', 'text', 'tool-call', 'file'] }),
content: S.String(),
providerOptions: S.Json({ nullable: true }),
finished: S.Boolean({ default: false }),
createdAt: S.Date({ default: S.Default.now() }),
lastUpdatedAt: S.Date({ default: S.Default.now() }),
}),
relationships: {
message: S.RelationOne('messages', {
where: [['id', '=', '$messageId']],
}),
toolCall: S.RelationOne('tool_calls', {
where: [['id', '=', '$toolCallId']],
}),
},
permissions: {
authenticated: {
read: {
filter: [['message.topic.userId', '=', '$token.sub']],
},
insert: {
// blank means it can only be inserted by the service token (ie the server)
},
update: {
filter: [['message.topic.userId', '=', '$token.sub']],
},
delete: {
filter: [['message.topic.userId', '=', '$token.sub']],
},
},
},
},
tool_calls: {
schema: S.Schema({
id: S.Id(),
userId: S.String(),
toolName: S.String(),
status: S.String({
enum: ['pending', 'completed', 'failed', 'cancelled'],
}),
input: S.Record({ type: S.String({ enum: ['text', 'json'] }), value: S.String() }, { nullable: true }),
output: S.Record({ type: S.String({ enum: ['text', 'json'] }), value: S.String() }, { nullable: true }),
error: S.Record({ type: S.String({ enum: ['text', 'json'] }), value: S.String() }, { nullable: true }),
createdAt: S.Date({ default: S.Default.now() }),
}),
relationships: {
message_part: S.RelationOne('message_parts', {
where: [['id', '=', '$messagePartId']],
}),
},
permissions: {
authenticated: {
read: { filter: [['userId', '=', '$token.sub']] },
insert: {},
update: {},
delete: { filter: [['userId', '=', '$token.sub']] },
},
},
},
messages: {
schema: S.Schema({
id: S.Id(),
topicId: S.String(),
role: S.String({ enum: ['user', 'assistant'] }),
content: S.String(),
generationId: S.String({ nullable: true, default: null }),
// a message has a "children" relationship that points to these messages.
// For each child, if its topicId matches the parent topicId, it will be a
// regeneration, but if the topicId is different, it will be a branching
// message, basically making a sub-thread of the parent topic.
parentMessageId: S.String({ nullable: true, default: null }),
createdAt: S.Date({ default: S.Default.now() }),
}),
relationships: {
topic: S.RelationOne('topics', {
where: [['id', '=', '$topicId']],
}),
parts: S.RelationMany('message_parts', {
where: [['messageId', '=', '$id']],
}),
generation: S.RelationOne('generations', {
where: [['id', '=', '$generationId']],
}),
parentMessage: S.RelationOne('messages', {
where: [['id', '=', '$parentMessageId']],
}),
children: S.RelationMany('messages', {
where: [['parentMessageId', '=', '$id']],
}),
},
permissions: {
authenticated: {
read: {
filter: [['topic.userId', '=', '$token.sub']],
},
insert: {
filter: [['topic.userId', '=', '$token.sub']],
},
update: {
filter: [['topic.userId', '=', '$token.sub']],
},
delete: {
filter: [['topic.userId', '=', '$token.sub']],
},
},
},
},
generations: {
schema: S.Schema({
id: S.Id(),
status: S.String({
enum: ['pending', 'cancelled', 'completed', 'failed'],
}),
topicId: S.String(),
messageId: S.String(),
modelId: S.String(),
tokens: S.Record({
input: S.Number({ nullable: true }),
cache: S.Record({
read: S.Number({ nullable: true }),
write: S.Number({ nullable: true }),
}, { nullable: true }),
output: S.Number({ nullable: true }),
thinking: S.Number({ nullable: true }),
}, { nullable: true }),
error: S.String({ nullable: true, default: null }),
}),
relationships: {
message: S.RelationOne('messages', {
where: [['id', '=', '$messageId']],
}),
topic: S.RelationOne('topics', {
where: [['id', '=', '$topicId']],
}),
},
permissions: {
authenticated: {
read: {
filter: [
['message.topic.userId', '=', '$token.sub'],
['topic.userId', '=', '$token.sub'],
],
},
insert: {},
update: {},
delete: {
filter: [
['message.topic.userId', '=', '$token.sub'],
['topic.userId', '=', '$token.sub'],
],
},
},
},
},
providers: {
schema: S.Schema({
id: S.Id(),
userId: S.String(),
type: S.String({ enum: Providers }),
name: S.String(),
enabled: S.Boolean({ default: true }),
config: S.Json(),
createdAt: S.Date({ default: S.Default.now() }),
updatedAt: S.Date({ default: S.Default.now() }),
}),
relationships: {
models: S.RelationMany('models', {
where: [['providerId', '=', '$id']],
}),
},
permissions: {
authenticated: {
read: {
filter: [['userId', '=', '$token.sub']],
},
insert: {
filter: [['userId', '=', '$token.sub']],
},
update: {
filter: [['userId', '=', '$token.sub']],
},
delete: {
filter: [['userId', '=', '$token.sub']],
},
},
}
},
models: {
schema: S.Schema({
id: S.Id(),
userId: S.String(),
externalId: S.String(),// e.g. "x-ai/grok-4.1-fast"
providerId: S.String(),
name: S.String(),
attributes: S.Record({
inputModalities: S.Set(S.String({ enum: ['text', 'image'] })),
outputModalities: S.Set(S.String({ enum: ['text', 'image'] })),
capabilities: S.Set(S.String({ enum: ['reasoning', 'tools'] })),
contextWindow: S.Number({ nullable: true }),
supported_parameters: S.Set(S.String(), { nullable: true }),
}), // From models.dev (context window, etc)
isCustom: S.Boolean({ default: false }),
enabled: S.Boolean({ default: true }),
releasedAt: S.Date({ nullable: true }),
createdAt: S.Date({ default: S.Default.now() }),
updatedAt: S.Date({ default: S.Default.now() }),
}),
relationships: {
provider: S.RelationOne('providers', {
where: [['id', '=', '$providerId']],
}),
},
permissions: {
authenticated: {
read: {
filter: [['userId', '=', '$token.sub'], ['provider.userId', '=', '$token.sub']],
},
insert: {
filter: [['userId', '=', '$token.sub'], ['provider.userId', '=', '$token.sub']],
},
update: {
filter: [['userId', '=', '$token.sub'], ['provider.userId', '=', '$token.sub']],
},
delete: {
filter: [['userId', '=', '$token.sub'], ['provider.userId', '=', '$token.sub']],
},
},
},
}
});