You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

79 lines
3.3 KiB

import { sqliteTable, text, integer, index } from "drizzle-orm/sqlite-core";
import { users } from "./auth";
// ============ CharacterCard(角色卡定义表)============
// 独立于 agents 的角色卡体系:以"人设/世界观/开场白/对话示例"为核心,
// 面向角色扮演场景,与 agent 的工具/审批/记忆注入解耦。
export const characterCards = sqliteTable(
"character_cards",
{
id: integer("id").primaryKey({ autoIncrement: true }),
slug: text("slug", { length: 50 }).notNull().unique(),
name: text("name", { length: 100 }).notNull(),
avatar: text("avatar"),
description: text("description"),
personality: text("personality"),
scenario: text("scenario"),
firstMessage: text("first_message"),
exampleDialogue: text("example_dialogue"),
systemPrompt: text("system_prompt").notNull().default(""),
defaultModelId: integer("default_model_id"),
tags: text("tags"),
isPublic: integer("is_public").notNull().default(1),
enabled: integer("enabled").notNull().default(1),
sortOrder: integer("sort_order").notNull().default(0),
createdAt: integer("created_at", { mode: "timestamp_ms" }).defaultNow().notNull(),
updatedAt: integer("updated_at", { mode: "timestamp_ms" })
.defaultNow()
.$onUpdate(() => new Date())
.notNull(),
},
(table) => [
index("character_cards_enabled_idx").on(table.enabled),
index("character_cards_sort_order_idx").on(table.sortOrder),
],
);
// ============ CharacterSession(角色会话表)============
export const characterSessions = sqliteTable(
"character_sessions",
{
id: text("id").primaryKey(),
cardId: integer("card_id").references(() => characterCards.id, { onDelete: "set null" }),
userId: integer("user_id").references(() => users.id, { onDelete: "cascade" }),
tempToken: text("temp_token", { length: 64 }),
title: text("title", { length: 100 }).notNull().default("新对话"),
modelId: integer("model_id"),
lastActiveAt: integer("last_active_at", { mode: "timestamp_ms" }).defaultNow().notNull(),
expiresAt: integer("expires_at", { mode: "timestamp_ms" }),
deletedAt: integer("deleted_at", { mode: "timestamp_ms" }),
createdAt: integer("created_at", { mode: "timestamp_ms" }).defaultNow().notNull(),
updatedAt: integer("updated_at", { mode: "timestamp_ms" })
.defaultNow()
.$onUpdate(() => new Date())
.notNull(),
},
(table) => [
index("idx_character_sessions_user_deleted").on(table.userId, table.deletedAt),
index("idx_character_sessions_temp_token").on(table.tempToken),
index("idx_character_sessions_card").on(table.cardId),
],
);
// ============ CharacterMessage(角色消息表)============
export const characterMessages = sqliteTable(
"character_messages",
{
id: text("id").primaryKey(),
sessionId: text("session_id")
.notNull()
.references(() => characterSessions.id, { onDelete: "cascade" }),
role: text("role", { length: 20 }).notNull(),
content: text("content").notNull().default(""),
sortOrder: integer("sort_order").notNull(),
createdAt: integer("created_at", { mode: "timestamp_ms" }).defaultNow().notNull(),
},
(table) => [
index("idx_character_messages_session_sort").on(table.sessionId, table.sortOrder),
],
);