Files
sillytavern-repalice/shared/types

共享类型系统文档

概述

本目录包含项目的完整类型系统,采用双格式兼容设计:

  1. SillyTavern 原生格式 - 用于导入导出兼容
  2. 扩展内部格式 - 用于增强功能和自定义特性

目录结构

shared/types/
├── sillytavern/          # SillyTavern 原生格式(从官方文档读取)
│   ├── character.types.ts    # 角色卡 V2 规范
│   ├── chat.types.ts         # 聊天记录JSONL
│   ├── world.types.ts        # 世界书 / Lorebook
│   └── preset.types.ts       # 生成预设
│
├── extended/             # 您的自定义扩展
│   ├── chat-ext.types.ts     # 扩展聊天(动态表头)
│   ├── preset-ext.types.ts   # 扩展预设(位置锚点)
│   └── world-ext.types.ts    # 统一触发器系统
│
├── adapters/             # 导入导出适配器
│   └── import-export.types.ts # 适配器接口
│
├── common.types.ts       # 通用工具类型
└── index.ts              # 主导出文件

核心设计原则

1. 双格式系统

每个数据实体都有两种表示形式

  • ST 格式:精确的 SillyTavern 规范(用于兼容性)
  • 扩展格式:增强了您的自定义功能

示例:

// SillyTavern 格式(导入/导出)
interface STChatMessage {
  name: string;
  is_user: boolean;
  mes: string;
  // ... ST 字段
}

// 扩展格式(内部使用)
interface ExtendedChatMessage {
  senderName: string;
  senderRole: 'user' | 'assistant';
  mes: string;
  reasoning?: string;      // 您的自定义字段
  image?: string;          // 您的自定义字段
  audio?: string;          // 您的自定义字段
  dynamicData?: Record<string, any>; // 动态表头
}

2. 适配器模式

适配器处理格式之间的转换:

interface ChatAdapter {
  importFromST(jsonlContent: string): InternalChatSession;
  exportToST(chat: InternalChatSession): string;
}

3. 保留原始数据

内部模型保留原始 ST 数据:

interface InternalCharacter {
  // ... 您的字段
  stData?: STCharacterCardV2; // 保留原始数据
}

Data Models

Chat History (JSONL)

Metadata (First line):

  • characterName: Character name
  • dynamicHeaders: User-defined dynamic table headers
  • characterDescription: Character description
  • systemPrompt: System prompt
  • firstMessages: Alternate first messages

Messages (Subsequent lines):

  • senderName: Who sent the message
  • senderRole: user/assistant/system/narrator
  • mes: Message content
  • swipes: Alternative responses
  • reasoning: Chain of thought
  • image/audio: Media attachments
  • dynamicData: Custom dynamic header values

预设系统

固定占位符位置(顺序必须保持):

  1. system - 系统提示词(来自角色卡)
  2. world_info_before - 世界书(前置)
  3. persona_description - 角色设定描述
  4. char_description - 角色详细描述
  5. world_info_after - 世界书(后置)
  6. history - 聊天记录(对话历史)
  7. user_input - 用户当前输入

核心参数:

  • temperature: 温度(创造性)
  • maxReplyLength: 最大回复长度
  • topP, topK: 采样参数
  • repetitionPenalty: 重复惩罚系数
  • entryOrder: 预设条目名称的有序列表
  • maxContextTokens: 最大上下文 token 数
  • streaming: 是否流式传输

API 配置:

interface ApiConfig {
  apiUrl: string;      // API 地址
  apiKey: string;      // API 密钥
  apiType: 'primary' | 'secondary' | 'image_gen' | 'rag'; // API 类型
  model: string;       // 模型名称
}

世界书(统一触发器系统)

将原有的 keyconstant 整合为统一的四元素字典:

interface TriggerConfig {
  permanent: PermanentTrigger;   // 永久激活(无需触发器)
  keyword: KeywordTrigger;       // 关键词触发
  rag: RagTrigger;              // RAG/数据库触发
  variable: VariableTrigger;    // 变量比较触发
}

触发器类型详解:

  1. 永久触发器 (permanent)

    • enabled: 是否永久激活
    • 无其他条件,始终生效
  2. 关键词触发器 (keyword)

    • enabled: 是否启用
    • keywords: 关键词数组
    • useRegex: 是否使用正则表达式
    • matchWholeWords: 是否匹配完整单词
    • caseSensitive: 是否区分大小写
  3. RAG 触发器 (rag)

    • enabled: 是否启用
    • databaseName: 关联的数据库/集合名称
    • threshold: 相似度阈值0-1
    • topK: 检索的相似条目数量
  4. 变量触发器 (variable)

    • enabled: 是否启用
    • variableA: 变量 A
    • operator: 运算符(>, <, =, contains, <=, >=, !=
    • variableB: 变量 B可选
    • constantA: 常量值(可选,替代 variableB

其他字段:

  • content: 条目内容
  • position: 插入位置(before_char / after_char
  • scanDepth: 扫描深度(扫描多少条消息)
  • priority: 优先级(同位置的先后顺序)

使用示例

导入角色卡

import { CharacterAdapter, STCharacterCardV2 } from '@shared/types';

const adapter: CharacterAdapter = new CharacterAdapterImpl();

// 从 ST 格式导入
const stCard: STCharacterCardV2 = parsePNG('character.png');
const internalChar = adapter.importFromST(stCard);

// 导出为 ST 格式
const stExport = adapter.exportToST(internalChar);

聊天会话管理

import { ChatAdapter } from '@shared/types';

const adapter: ChatAdapter = new ChatAdapterImpl();

// 导入 JSONL
const jsonlContent = await readFile('chat.jsonl');
const chat = adapter.importFromST(jsonlContent);

// 添加带自定义字段的消息
chat.messages.push({
  senderName: '用户',
  senderRole: 'user',
  mes: '你好!',
  reasoning: undefined,
  dynamicData: { mood: 'happy' }
});

// 导出回 JSONL
const exported = adapter.exportToST(chat);

世界书统一触发器

import { ExtendedWorldInfoEntry, TriggerConfig } from '@shared/types';

const entry: ExtendedWorldInfoEntry = {
  id: '1',
  content: '魔法剑发出蓝色光芒。',
  position: 'after_char',
  scanDepth: 5,
  priority: 1,
  triggers: {
    permanent: { enabled: false },
    keyword: {
      enabled: true,
      keywords: ['剑', '武器'],
      useRegex: false,
      matchWholeWords: true,
      caseSensitive: false
    },
    rag: { enabled: false },
    variable: { enabled: false }
  },
  enabled: true
};

兼容性说明

SillyTavern V2 规范

  • 完全兼容 Character Card V2
  • 支持 PNG 嵌入tEXt 数据块)
  • 支持 JSON 格式

聊天记录

  • JSONL 格式(每行一个 JSON 对象)
  • 第一行:元数据
  • 后续行:消息
  • 支持完整性哈希校验

世界书

  • 兼容 ST Lorebook 格式
  • 扩展触发器系统可转换为 keys + constant

预设

  • 支持所有标准 ST 参数
  • 固定占位符位置用于提示词构建
  • 保留条目顺序

迁移指南

从 SillyTavern 到内部格式

  1. 解析 ST 格式PNG/JSON/JSONL
  2. 使用适配器转换为内部格式
  3. 原始 ST 数据保存在 stData 字段中
  4. 根据需要添加自定义字段

从内部格式到 SillyTavern 格式

  1. 使用适配器将内部格式转换为 ST 格式
  2. 不在 ST 规范中的自定义字段会被排除
  3. 如果可用,使用原始 ST 数据
  4. 以所需格式导出PNG/JSON/JSONL

类型安全

所有类型都使用 TypeScript 完整定义:

  • 核心模型中不使用 any 类型
  • 严格的空值检查
  • 基于枚举的常量
  • 全面的接口定义

下一步计划

  1. 实现适配器类
  2. 创建验证函数
  3. 为转换逻辑添加单元测试
  4. 构建导入导出 UI 组件