streaming, markdown, model selecting, and lots more
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
import { Schema as S } from '@triplit/client';
|
||||
|
||||
export const authSchema = S.Collections({
|
||||
users: {
|
||||
schema: S.Schema({
|
||||
id: S.Id(),
|
||||
name: S.String(),
|
||||
email: S.String(),
|
||||
emailVerified: S.Boolean({ default: false }),
|
||||
image: S.Optional(S.String()),
|
||||
createdAt: S.Date({ default: S.Default.now() }),
|
||||
updatedAt: S.Date({ default: S.Default.now() }),
|
||||
}),
|
||||
relationships: {
|
||||
sessions: S.RelationMany('sessions', {
|
||||
where: [['userId', '=', '$id']],
|
||||
}),
|
||||
accounts: S.RelationMany('accounts', {
|
||||
where: [['userId', '=', '$id']],
|
||||
}),
|
||||
},
|
||||
permissions: {
|
||||
authenticated: {
|
||||
read: {
|
||||
filter: [['id', '=', '$token.sub']],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
sessions: {
|
||||
schema: S.Schema({
|
||||
id: S.Id(),
|
||||
userId: S.String(),
|
||||
token: S.String(),
|
||||
expiresAt: S.Date(),
|
||||
ipAddress: S.Optional(S.String()),
|
||||
userAgent: S.Optional(S.String()),
|
||||
createdAt: S.Date({ default: S.Default.now() }),
|
||||
updatedAt: S.Date({ default: S.Default.now() }),
|
||||
}),
|
||||
relationships: {
|
||||
user: S.RelationById('users', '$userId'),
|
||||
},
|
||||
permissions: {
|
||||
authenticated: {
|
||||
read: {
|
||||
filter: [['userId', '=', '$token.sub']],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
accounts: {
|
||||
schema: S.Schema({
|
||||
id: S.Id(),
|
||||
userId: S.String(),
|
||||
accountId: S.String(),
|
||||
providerId: S.String(),
|
||||
accessToken: S.Optional(S.String()),
|
||||
refreshToken: S.Optional(S.String()),
|
||||
accessTokenExpiresAt: S.Optional(S.Date()),
|
||||
refreshTokenExpiresAt: S.Optional(S.Date()),
|
||||
scope: S.Optional(S.String()),
|
||||
idToken: S.Optional(S.String()),
|
||||
password: S.Optional(S.String()),
|
||||
createdAt: S.Date({ default: S.Default.now() }),
|
||||
updatedAt: S.Date({ default: S.Default.now() }),
|
||||
}),
|
||||
relationships: {
|
||||
user: S.RelationById('users', '$userId'),
|
||||
},
|
||||
permissions: {
|
||||
authenticated: {
|
||||
read: {
|
||||
filter: [['userId', '=', '$token.sub']],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
verifications: {
|
||||
schema: S.Schema({
|
||||
id: S.Id(),
|
||||
identifier: S.String(),
|
||||
value: S.String(),
|
||||
expiresAt: S.Date(),
|
||||
createdAt: S.Date({ default: S.Default.now() }),
|
||||
updatedAt: S.Date({ default: S.Default.now() }),
|
||||
}),
|
||||
permissions: {},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,312 @@
|
||||
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']],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user