🧩 JavaScript API
Since v0.75.0
📖 概述
Tavo JavaScript API 是面向玩家及创作者提供的一套 JavaScript 接口,以方便用户在开启 JavaScript 支持时可以获得强大的功能和高可玩性。
✨ 氛围编程 (Vibe Coding) 友好
对于非专业编程玩家,我们建议将此文档复制给 AI ,然后让 AI 生成与 Tavo 结合紧密的高可玩性代码!
导入辅助角色卡
我们建议初学者使用以下角色卡,以便快速查看各 API 的使用例子。
可以直接在 “从 URL 导入角色” 处粘贴此URL:
https://type.tavo.cc/static/images/Tavo_JS_API_v0_7.png
或是下载以下角色卡图片,并通过文件导入:
⚙️ 变量
变量用于存储数据,JavaScript 本身的变量只能存活于页面中,一旦刷新就会丢失,因此我们提供一组变量 API 来协助用户长期存储数据。
获取变量
tavo.get(<name>[, <scope>])
例如:
let age = tavo.get('age') // 获取聊天变量中的 age
let bestScore = tavo.get('bestScore', 'global') // 获取全局最高分
let lover = tavo.get('lover', 'character') // 获取当前角色的爱人
作用域 (scope)
作用域是变量可用范围,我们暂时支持:
- chat: 聊天作用域,这是默认的作用域。变量仅在当前聊天内可访问,你应该总是优先考虑此作用域(可随聊天导出)
- global: 全局作用域。变量将可以跨对话访问与保存(因此也需要格外小心命名冲突)
设置变量
tavo.set(<name>, <value>[, <scope>])
例如:
tavo.set('age', 16) // 设置聊天变量 age = 16
tavo.set('Lily_lover', 'Colin', 'global') // 设置全局变量,Lily 的爱人为 Colin
tavo.set('status', { hp: 100, mp: 32, location: 'Cave' }) // 设置当前聊天的状态为:生命值 100,魔法值 32,地点 洞穴
删除变量
tavo.unset(<name>[, <scope>])
例如:
tavo.set('age', 16) // age = 16
tavo.unset('age') // age = null
变量路径
当操作变量时,我们支持路径形式,例如:
tavo.set('status', { hp: 100, mp: 50 })
tavo.get('status.hp') // 100
tavo.unset('status.hp') // status = { mp: 50 }
在提示词中使用变量
可以通过提示词将变量发给模型,只需要在提示词中使用 宏 (macros) 即可:
{{getvar::<name>}} 获取变量(作用域为 chat,当前聊天)
{{getglobalvar::<name>}} 获取变量(作用域为 chat,全局)
例如:
{{char}} 有了一个新名字 {{getvar::name}}
{{user}} 当前生命值 {{getvar::status.hp}}
全局历史最高分 {{getglobalvar::highestScore}}
更多的变量宏请参考
💬 消息
Since v0.78.0
可以通过此接口读取或改变消息,所有消息接口均为 tavo.message.<method>(...)
查找消息
await tavo.message.find(<indexRange>[, <filter>])
按照楼层范围 indexRange 和过滤器 filter 查找消息,返回值为数组,其中:
indexRange 类型 number | array: 楼层范围
- 当为
number类型时:- 获取指定楼层消息
- 楼层从 0 开始,第一条消息为 0,第二条消息为 1……以此类推
- 支持负数从尾部开始计算楼层, -1 为最后一条,-2 为倒数第二条……以此类推
- 当为
array类型时:[start, end]例如[2, 4],会取出第 2、3、4 条记录(双侧闭区间)[start]代表从start开始到最后[0, end]代表从第 0 条开始到end[] | null | undefined代表全部楼层
- 无论何种参数,总是返回数组,若指定楼层不存在,返回空数组
[]
filter 类型 object: 过滤条件
role类型string按角色过滤,可选值(默认为所有):'system'系统消息'assistant'角色消息'user'用户消息
hidden类型boolean是否包含隐藏消息,可选值(默认为所有):true仅包含隐藏消息false仅包含非隐藏消息
characters类型array角色 ID 数组,仅过滤传入的角色发出的消息
消息格式为:
{
id: 2338, // 消息 ID
characterId: 34, // 角色 ID(仅 assistant 消息会有)
content: 'Hello!', // 消息内容
hidden: false, // 是否是隐藏消息
role: 'assistant' // 消息角色
}
例如:
await tavo.message.find(2) // 获取第 3 层的消息
await tavo.message.find([3, 100]) // 获取第 3-100 条消息,若总共只有 50 层,则返回 3-50 层
await tavo.message.find(-1, { role: 'user' }) // 用户发的最后一层消息
await tavo.message.find([10], { hidden: false }) // 未隐藏的消息,楼层 >= 10 的所有消息
获取单条消息
await tavo.message.get(<messageId>)
按消息 ID 获取单条消息,若 ID 无效或消息不存在则返回 null。
let msg = await tavo.message.get(2338) // 获取 ID 为 2338 的消息
获取当前消息
await tavo.message.current()
获取执行此代码所在的那条消息对象,字段与上文「消息格式」及 tavo.message.get 一致。
典型用途:读取本条消息上的角色信息(tavo.character.get(currentMessage.characterId)),或是修改本条消息(调用 tavo.message.update 写回)。
const self = await tavo.message.current()
console.log(self)
获取消息总数
await tavo.message.count()
获取当前聊天中的消息总数(包含隐藏消息)。一般用来定位最后一条的楼层,第一条楼层为 0,最后一条楼层为 消息总数 - 1。
let lastIndex = await tavo.message.count() - 1
console.log(lastIndex)
追加消息
await tavo.message.append(<message>)
在当前聊天末尾追加一条消息,成功返回新消息 ID,失败返回 null。
message 类型 object,常见字段:
content类型string:消息内容(必填)role类型string:'assistant' | 'user'(默认按'assistant'处理),角色消息还是用户消息characterId类型number:当role = 'assistant'时可指定发言角色 ID(单聊中可不传,群聊必传)hidden类型boolean:是否为隐藏消息(默认false)
注意:
- 当
role = 'assistant'且未传characterId时,会按当前会话上下文自动推断角色- 若无法推断角色,或角色不属于当前聊天,会创建失败并返回
null
例如:
let newId = await tavo.message.append({
role: 'assistant',
characterId: 34,
content: '这是追加的一条消息',
hidden: false,
})
单聊中创建非隐藏消息时,可简化为:
let newId = await tavo.message.append({
content: '这是追加的一条消息。role 默认为 assistant ,即角色消息;单聊时自动推断角色;hidden 默认为 false',
})
更新消息
await tavo.message.update(<message>)
按消息 ID 更新一条已有消息,成功返回消息 ID,失败返回 null。
message 类型 object,常见字段:
id类型number:要更新的消息 ID(必填)content类型string:更新后的消息内容(必填)reasoning类型string:推理内容(可选,传空字符串会清空)hidden类型boolean:是否隐藏(可选,默认按false处理)
const lastMessage = (await tavo.message.find(-1))[0] // 获得最后一层的消息 (参见 tavo.message.find 说明)
lastMessage.content = '更新后的内容'
lastMessage.reasoning = '可选推理内容'
lastMessage.hidden = true // 改为隐藏消息
await tavo.message.update(lastMessage) // 更新最后一条消息
删除消息
await tavo.message.delete(<messageId>)
按消息 ID 删除消息,成功返回被删除的消息 ID,失败返回 null。
const count = await tavo.message.count(); // 获得总消息数
const midIndex = Math.floor(count / 2);
const midMessage = (await tavo.message.find(midIndex))[0] // 获得中间一条消息
await tavo.message.delete(midMessage.id) // 删除中间那条消息
🗨️ 聊天
可以通过此接口获取当前聊天信息,所有聊天接口均为 tavo.chat.<method>(...)
获取当前聊天
await tavo.chat.current()
获取当前正在进行的聊天信息,若当前没有聊天则返回 null。
例如:
let chat = await tavo.chat.current()
console.log(chat.name) // 打印当前聊天名称
console.log(chat.characters[0]?.name) // 打印第一个角色名称
console.log(chat.persona?.name) // 打印当前用户身份名称(若有)
异步 await/async
Tavo JS API 中,除变量操作外,几乎所有的 API 接口都需要使用异步调用。
异步调用就是调用时在前面写上 await,例如 let chat = await tavo.chat.current(),如果你忘了 await 写成了 let chat = tavo.chat.current(),就会出错(可以在侧边栏的 JavaScript 控制台中查看日志)。
而 await 只能在 async 函数(或模块顶层)中使用,比如:
async function demo() {
let chat = await tavo.chat.current();
}
同样如果忘了在 function 前写 async 但函数内部又调用了 await 也会报错噢!
简言之:除变量操作外,所有 Tavo JS API 调用前面必须加 await,而调用的函数要用 async 声明。
更新当前聊天
await tavo.chat.update(<chat>)
更新当前聊天。
可更新字段:
name:聊天标题characters:角色 ID 数组(会直接替换当前聊天角色列表)persona:用户身份 ID
await tavo.chat.update({
name: '新的聊天标题',
characters: [12, 34],
persona: 5,
})
注意:该接口仅更新“当前聊天”,不支持按聊天 ID 更新其他会话。
聊天对象字段
聊天对象(current 返回)包含以下常见字段:
{
id: 1, // 聊天 ID
name: '与爱丽丝的对话', // 聊天名称
characters: [ // 聊天中的角色概要列表
{
id: 12,
name: 'Alice',
avatar: 'alice.png'
},
{
id: 7,
name: 'Lee',
avatar: 'lee.png'
},
],
persona: { // 当前使用的用户身份概要(可能为 null)
id: 5,
name: '默认用户身份',
},
preset: { // 当前使用的预设概要
id: 9,
name: '默认预设',
},
lorebooks: [{
id: 17,
name: '不夜城',
}],
regexes: [{ // 当前启用的正则概要列表
id: 3,
name: '移除舞台提示',
}],
}
🧙 角色
可以通过此接口管理角色,所有角色接口均为 tavo.character.<method>(...)
获取所有角色概要
await tavo.character.all()
返回角色概要对象数组(每项仅包含 id、name、avatar 等概要信息):
let chars = await tavo.character.all()
console.log(chars[0].id) // 例如 12
console.log(chars[0].avatar) // 例如 "chara/alice.png"
console.log(chars[0].name) // 例如 "Alice"
获取单个角色
await tavo.character.get(<characterId>)
按角色 ID 获取角色对象,不存在时返回 null。
let char = await tavo.character.get(12)
if (char) {
console.log(char.name)
}
按名称查找角色
await tavo.character.find(<name>[, <options>])
按名称查找角色,返回角色对象数组。options.match 可选:'exact' | 'prefix' | 'suffix' | 'contains'(默认 'exact')
let chars = await tavo.character.find('Alice')
let chars2 = await tavo.character.find('Ali', { match: 'prefix' })
console.log(chars.length)
新建角色
await tavo.character.create(<character>)
创建角色并返回新角色 ID。character.name 和 character.first_mes 为必填项。
let id = await tavo.character.create({
name: 'Alice',
first_mes: '你好,我是 Alice。',
description: '一位温柔的向导',
})
更新角色
await tavo.character.update(<character>)
更新角色并返回角色 ID。character.id、character.name 和 character.first_mes 为必填项。
await tavo.character.update({
id: 12,
name: 'Alice',
first_mes: '你好,我是 Alice。',
personality: '耐心、细致',
})
删除角色
await tavo.character.delete(<characterId>)
按角色 ID 删除角色:
await tavo.character.delete(12)
await tavo.character.delete(char) // char 需要时带 id 的角色对象
角色对象字段
角色对象(get / find 返回)包含以下常见字段:
{
id: 12, // 角色的唯一ID
avatar: 'xxx.png', // 角色头像图片URL或路径
name: 'Alice', // 角色名称(必填)
description: '...', // 角色简介/描述
first_mes: '...', // 角色打招呼内容(必填)
personality: '...', // 角色性格描述
scenario: '...', // 适用场景或使用场景描述
mes_example: '...', // 消息示例,以 <START> 分割
creator_notes: '...', // 创建者注释或补充说明
system_prompt: '...', // 系统提示词
post_history_instructions: '...', // 信息上下文历史后的额外提示或说明
alternate_greetings: ['...'], // 角色可用的备用打招呼
tags: ['guide'], // 角色标签,用于分类或检索
creator: 'Colin', // 创建者用户名或昵称
character_version: '1.0', // 角色版本号
nickname: 'Ali', // 角色昵称或别名,如果填写了将替代 name 作为 {{char}} 的输出
group_only_greetings: ['...'], // 仅限群聊使用的特定打招呼语
creation_date: new Date('2026-03-05T10:20:30.000Z'), // 创建时间(Date对象)
modification_date: new Date('2026-03-05T11:30:00.000Z'), // 最后修改时间(Date对象)
}
说明:创建、更新、删除角色时会弹出确认框,用户取消后操作不会生效。
🎭 用户身份
可以通过此接口管理用户身份,所有用户身份接口均为 tavo.persona.<method>(...)
获取所有用户身份概要
await tavo.persona.all()
返回用户身份概要对象数组(每项包含 id、name):
let personas = await tavo.persona.all()
console.log(personas[0].id) // 例如 5
console.log(personas[0].name) // 例如 "默认用户身份"
获取单个用户身份
await tavo.persona.get(<personaId>)
按用户身份 ID 获取用户身份对象,不存在时返回 null:
let persona = await tavo.persona.get(5)
if (persona) {
console.log(persona.name)
console.log(persona.description)
}
按名称查找用户身份
await tavo.persona.find(<name>[, <options>])
按名称查找用户身份,返回用户身份对象数组。options.match 可选:'exact' | 'prefix' | 'suffix' | 'contains' (默认 'exact')
let personas = await tavo.persona.find('默认')
let personas2 = await tavo.persona.find('默', { match: 'prefix' })
console.log(personas.length)
新建用户身份
await tavo.persona.create(<persona>)
创建用户身份并返回新用户身份 ID。persona.name 和 persona.description 为必填项。
let id = await tavo.persona.create({
name: '侦探用户身份',
description: '注重细节,擅长结构化推理。',
avatar: 'chara/persona-detective.png',
})
更新用户身份
await tavo.persona.update(<persona>)
更新用户身份。persona.id、persona.name 和 persona.description 为必填项。
await tavo.persona.update({
id: 5,
name: '默认用户身份',
description: '语气更简洁,优先给出可执行结论。',
avatar: 'chara/persona-default.png',
active: true,
})
删除用户身份
await tavo.persona.delete(<personaId>)
按用户身份 ID 删除用户身份:
await tavo.persona.delete(5)
await tavo.persona.delete(persona) // persona 需要是带 id 的用户身份对象
用户身份对象字段
用户身份对象(get 返回)包含以下常见字段:
{
id: 5, // 用户身份唯一 ID
name: '默认用户身份', // 用户身份名称(必填)
description: '...', // 用户身份描述(必填)
avatar: 'xxx.png', // 用户身份头像 URL 或路径(可选)
active: true, // 是否为默认用户身份
sortIndex: 12, // 排序索引
}
🎛️ 预设
可以通过此接口管理预设,所有预设接口均为 tavo.preset.<method>(...)
获取所有预设(摘要)
await tavo.preset.all()
返回预设摘要对象数组(每项包含 id、name):
let presets = await tavo.preset.all()
console.log(presets[0].id) // 例如 1
console.log(presets[0].name) // 例如 "Default"
获取单个预设
await tavo.preset.get(<presetId>)
按预设 ID 获取完整预设对象,不存在时返回 null:
let preset = await tavo.preset.get(1)
if (preset) {
console.log(preset.name)
console.log(preset.entries.length)
console.log(preset.basicPrompts.chatStart)
}
按名称查找预设
await tavo.preset.find(<name>[, <options>])
按名称查找预设,返回完整预设对象数组。options.match 可选:'exact' | 'prefix' | 'suffix' | 'contains' (默认 'exact')
let presets = await tavo.preset.find('Default')
let presets2 = await tavo.preset.find('Def', { match: 'prefix' })
console.log(presets.length)
新建预设
await tavo.preset.create(<preset>)
创建预设并返回新预设 ID。preset.name 为必填项,其余字段可选;preset.basicPrompts 与 preset.entries 中缺失的部分将自动填充默认值。
let id = await tavo.preset.create({
name: '我的预设',
basicPrompts: {
continueNudge: '[继续你的上一条消息,不要重复原有内容。]',
},
entries: [
{
identifier: 'abc123',
name: '🌸 文风控制',
content: '采用精致优雅的叙事风格,类似晋江、长佩等平台受欢迎的高质量女性向作品。',
},
],
})
更新预设
await tavo.preset.update(<preset>)
更新预设。preset.id 为必填项。传入的 entries 会直接覆盖原有的 entries,典型用法是先 get 取出,修改后再 update 写回。
const preset = await tavo.preset.get(33);
preset.entries.find(e => e.identifier == 'main').content = '请用中文回复 {{user}} 的所有问题。';
await tavo.preset.update(preset)
删除预设
await tavo.preset.delete(<presetId>)
按预设 ID 删除预设:
await tavo.preset.delete(1)
await tavo.preset.delete(preset) // preset 需要是带 id 的预设对象
预设对象字段
完整预设对象(get / find 返回)包含以下字段:
{
id: 1, // 预设唯一 ID
name: 'Default', // 预设名称(必填)
basicPrompts: { /* BasicPrompts,见下 */ },
entries: [], // PresetEntry[] 提词条目列表(见下)
}
基础提词字段(BasicPrompts)
basicPrompts 包含各类系统提词模板,所有字段均可选,缺省时使用内置默认值:
{
persona: '{{persona}}', // 用户身份描述的格式模板
description: '{{description}}', // 角色描述的格式模板
personality: '{{personality}}', // 角色性格的格式模板(用 {{personality}} 标记插入位置)
scenario: '{{scenario}}', // 场景的格式模板(用 {{scenario}} 标记插入位置)
exampleMessageStart: '[Example Chat]', // 示例对话起始标记
chatStart: '[Start a new Chat]', // 聊天历史起始标记
groupChatStart: '[Start a new group chat. Group members: {{group}}]', // 群聊起始标记
groupNudge: '[Write the next reply only as {{char}}.]', // 群聊中催促指定角色回复的提词
continueNudge: '[Continue your last message without repeating its original content.]', // 续写按钮的提词
impersonation: '[Write your next reply from the point of view of {{user}}...]', // 扮演用户时的提词
lorebook: '{0}', // 世界书条目的包装模板(用 {0} 标记内容插入位置)
}
提词条目字段(PresetEntry)
entries 数组中每一项的结构:
{
// ── 基本信息 ──────────────────────────────────
identifier: 'main', // 条目唯一标识(内置条目有固定 identifier,见下表)
name: 'Main Prompt', // 条目显示名称
content: '...', // 提词正文(marker 类型无此字段)
enabled: true, // 是否启用此条目(在激活列表中是否生效)
active: true, // 是否加入激活列表(false 时条目仅存档,不参与提示词构建)
// ── 类型 ──────────────────────────────────────
type: 'custom', // 条目类型:
// 'builtin' - 内置提词(固定 identifier,如 main / jailbreak)
// 'marker' - 位置标记(无内容,仅标记其他内容的插入位置)
// 'custom' - 自定义提词
// ── 角色与注入(custom 类型可配置)──────────────
role: 'system', // 消息角色:'system' | 'user' | 'assistant'
injectionPosition: 'relative', // 注入位置:
// 'relative' - 相对位置(跟随预设列表顺序)
// 'absolute' - 绝对位置(插入到聊天历史的特定深度)
injectionDepth: 4, // 注入深度,仅 injectionPosition 为 'absolute' 时生效
// 0 = 最后一条消息之后,1 = 最后一条消息之前,以此类推
}
内置条目 identifier 列表
以下 identifier 对应系统内置的固定提词或位置标记,创建 / 更新时可直接引用:
📚 世界书
可以通过此接口管理世界书,所有世界书接口均为 tavo.lorebook.<method>(...)
获取所有世界书概要
await tavo.lorebook.all()
返回世界书概要对象数组(每项包含 id、name、entries):
let lorebooks = await tavo.lorebook.all()
console.log(lorebooks[0].id) // 例如 3
console.log(lorebooks[0].name) // 例如 "城市设定"
console.log(lorebooks[0].entries) // 例如 12(条目数量)
获取单个世界书
await tavo.lorebook.get(<lorebookId>)
按世界书 ID 获取对象,不存在时返回 null:
let lorebook = await tavo.lorebook.get(3)
if (lorebook) {
console.log(lorebook.name)
console.log(lorebook.entries.length)
}
按名称查找世界书
await tavo.lorebook.find(<name>[, <options>])
按名称查找世界书,返回世界书对象数组。options.match 可选:'exact' | 'prefix' | 'suffix' | 'contains' (默认 'exact')
let lorebooks = await tavo.lorebook.find('城市')
let lorebooks2 = await tavo.lorebook.find('城市', { match: 'suffix' })
console.log(lorebooks.length)
新建世界书
await tavo.lorebook.create(<lorebook>)
创建世界书并返回新世界书 ID。lorebook.name 为必填项。
let id = await tavo.lorebook.create({
name: '城市设定',
entries: [],
})
更新世界书
await tavo.lorebook.update(<lorebook>)
更新世界书。lorebook.id 和 lorebook.name 为必填项。
await tavo.lorebook.update({
id: 3,
name: '城市设定(重制)',
entries: [],
})
删除世界书
await tavo.lorebook.delete(<lorebookId>)
按世界书 ID 删除世界书:
await tavo.lorebook.delete(3)
await tavo.lorebook.delete(lorebook) // lorebook 需要是带 id 的世界书对象
世界书对象字段
世界书对象(get / find 返回)包含以下字段:
{
id: 3, // 世界书唯一 ID
name: '城市设定', // 世界书名称(必填)
entries: [], // LorebookEntry[] 条目列表(见下)
}
条目对象字段(LorebookEntry)
entries 数组中每一项的结构:
{
// ── 基本信息 ──────────────────────────────────
identifier: 'entry-uuid', // 条目唯一标识(字符串)
name: '城市总览', // 条目名称(仅供显示和搜索)
content: '这是一座临海城市,夜间常有浓雾。', // 注入到提示词的正文内容
enabled: true, // 是否启用此条目
strategy: 'constant', // 触发策略:'constant'(常驻)| 'keyword'(关键词触发)
// ── 关键词 ─────────────────────────────────────
keywords: ['城市', '港口'], // 主关键词列表(strategy 为 'keyword' 时生效)
secondaryKeywords: ['夜晚', '雾'], // 次级关键词列表
secondaryKeywordStrategy: 'none', // 次级关键词匹配策略:
// 'none' - 不启用次级关键词
// 'andAny' - 主词命中且任意次级词命中(默认)
// 'andAll' - 主词命中且全部次级词命中
// 'notAny' - 主词命中且没有次级词命中
// 'notAll' - 主词命中且不是全部次级词命中
scanDepth: 2, // 关键词扫描的消息深度(默认 2,最大 1000)
caseSensitive: false, // 关键词是否区分大小写
matchWholeWord: true, // 是否全词匹配
// ── 注入位置 ───────────────────────────────────
injectionPosition: 'lorebookBefore', // 注入位置:
// 'lorebookBefore' - 角色描述上方(↑Char)
// 'lorebookAfter' - 角色描述下方(↓Char)
// 'topOfExampleMessages' - 示例对话之前
// 'bottomOfExampleMessages'- 示例对话之后
// 'atDepth' - 聊天历史的绝对深度位置
injectionDepth: 4, // 注入深度,仅 injectionPosition 为 'atDepth' 时生效
injectionRole: 'system', // 注入角色:'system' | 'user' | 'assistant'
// ── 概率与行为 ─────────────────────────────────
probability: 100, // 激活概率(0–100,默认 100)
sticky: 0, // 激活后持续保持的消息轮数(0 表示不持续)
cooldown: 0, // 激活一次后的冷却轮数(0 表示无冷却)
delay: 0, // 延迟激活的消息轮数(0 表示立即)
}
🎨 正则
可以通过此接口管理正则组(一组查找/替换规则),所有正则接口均为 tavo.regex.<method>(...)
获取所有正则(摘要)
await tavo.regex.all()
返回正则摘要对象数组(每项包含 id、name、entries,其中 entries 为规则条数,不是条目数组):
let list = await tavo.regex.all()
console.log(list[0].id) // 例如 2
console.log(list[0].name) // 例如 "我的正则"
console.log(list[0].entries) // 例如 5(条规则数量)
获取单个正则
await tavo.regex.get(<regexId>)
按 ID 获取完整正则对象,不存在时返回 null:
let r = await tavo.regex.get(2)
if (r) {
console.log(r.name)
console.log(r.entries.length)
}
按名称查找正则
await tavo.regex.find(<name>[, <options>])
按名称查找正则,返回完整正则对象数组。options.match 可选:'exact' | 'prefix' | 'suffix' | 'contains' (默认 'exact')
let found = await tavo.regex.find('我的')
let found2 = await tavo.regex.find('我的', { match: 'contains' })
console.log(found.length)
新建正则
await tavo.regex.create(<regex>)
创建正则并返回新 ID。regex.name 为必填;regex.entries 为规则数组,可省略(视为空列表)。创建 / 更新前会弹出确认对话框。
let id = await tavo.regex.create({
name: 'Demo 正则',
entries: [
{
name: '状态栏',
findRegex: '/<status>(.*?)<\/status>/gim',
replaceString: '<pre>$1</pre>',
placements: ['char'],
timing: 'display',
},
],
})
更新正则
await tavo.regex.update(<regex>)
更新正则。regex.id 与 regex.name 均为必填(前端封装会校验)。典型用法:get → 修改 → update。
const r = await tavo.regex.get(2)
r.entries[0].enabled = false
await tavo.regex.update(r)
删除正则
await tavo.regex.delete(<regexId>)
按 ID 删除;也可传入带 id 的正则对象:
await tavo.regex.delete(2)
await tavo.regex.delete({ id: 2 })
正则对象字段
完整对象(get / find 返回)结构:
{
id: 2,
name: '我的正则',
entries: [ /* RegexEntry[],见下 */ ],
}
规则条目字段(RegexEntry)
entries 中每一项:
{
name: '规则显示名', // 必填(字符串),否则解析可能失败
findRegex: 'pattern', // 查找用正则(可支持 JavaScript 正则类似的 `/pattern/flags` 写法)
replaceString: '', // 替换为的字符串
trimStrings: [], // 额外要裁剪的字符串列表
placements: ['char'], // 作用位置,可多选:
// 'user' - 用户输入
// 'char' - AI 输出
// 'reasoning' - 推理内容
// 'lorebook' - 世界书注入内容
timing: 'display', // 执行时机:
// 'display' - 仅显示时(不写入持久消息,类似 ST markdownOnly)
// 'send' - 仅发送进模型前
// 'sendAndDisplay' - 显示与发送都执行
// 'receive' - 收到回复后持久化(仅输入/输出相关)
// 'editAndReceive' - 收到与编辑消息时都会持久化改写
substitution: 'none', // 宏替换方式:'none' | 'raw' | 'escaped'
minDepth: null, // 可选,消息深度下限(整数)
maxDepth: null, // 可选,消息深度上限(整数)
enabled: true, // 是否启用该条规则
}
省略字段时,端侧会为 findRegex、replaceString、trimStrings、placements、timing、substitution、enabled 等填入合理默认值(例如 placements: ['char']、timing: 'display')。
🧠 长记忆
可以通过此接口读取或修改当前聊天的长期记忆(Long-term Memory),所有接口均为 tavo.memory.<method>(...)
获取当前记忆
await tavo.memory.current()
获取当前聊天记忆对象:
const memory = await tavo.memory.current()
console.log(memory.enabled) // true / false
console.log(memory.memories.length) // 记忆条数
更新记忆
await tavo.memory.update(<memory>)
更新当前聊天记忆并返回更新后的对象。可更新字段:
enabled:是否启用记忆memories:记忆文本数组(string[])
const memory = await tavo.memory.current()
memory.enabled = true
memory.memories = [
'用户喜欢简洁、结论先行的回答风格',
'用户倾向于让角色保持冷静和专业',
]
const updated = await tavo.memory.update(memory)
console.log(updated)
记忆对象字段
current / update 返回对象结构:
{
id: 12, // 记忆记录 ID
enabled: true, // 是否启用长期记忆
memories: [ // 记忆条目列表(字符串数组)
'用户偏好简洁回复',
'避免重复解释已确认信息'
],
}
✨ 生成请求
可以通过此接口直接触发一次文本生成,所有生成接口均为 tavo.generate(...)。
发起生成
await tavo.generate(<prompt>, <options>)
prompt类型string:本次生成的用户输入内容options类型object:生成选项(若无额外配置,传空对象{})
返回值类型为 string,即模型生成的文本内容。
const result = await tavo.generate('请用一句话总结今天发生的事情', {})
console.log(result)
options 字段
options 支持以下字段:
context类型boolean(默认false):true:带当前对话上下文生成(沿用当前聊天状态)false:与当前对话无关的AI生成请求(默认)
preset类型number | object(可选):- 直接传预设 ID,例如
12 - 传对象时仅识别
id,例如{ id: 12 }
- 直接传预设 ID,例如
settings类型object(可选):覆盖本次请求的模型参数
示例:
const text = await tavo.generate(
'根据最近对话,给我 3 条行动建议',
{
context: true,
preset: { id: 8 },
settings: {
temperature: 0.7,
topP: 0.9,
maxCompletionTokens: 300,
},
},
)
console.log(text)
注意事项
- 该接口为一次性请求,返回完整文本,不返回流式分片
- 生成请求会使用当前聊天绑定的模型端点;若当前聊天无可用端点,则返回
null
使用示例
将以下内容复制到气泡中,以观察效果:
<h3>生成请求 API 演示</h3>
<pre id="log" style="background: #0006; font-size: 12px; padding: 1em 1.5em; min-height: 80px; max-height: 300px; overflow-y: auto;"></pre>
<button id="btn-generate" onclick="generate()">生成角色卡</button>
<p id="status"></p>
<div id="actions" style="display:none; gap:8px;">
<button onclick="downloadJson()">下载 JSON 文件</button>
<button onclick="createCharacter()">直接创建角色卡</button>
</div>
<script>
let generatedCard = null;
const log = (...args) => {
const text = args.map(v => typeof v === 'string' ? v : JSON.stringify(v, null, 2)).join(' ');
document.getElementById('log').textContent = text + '\n\n';
};
function setUi(loading, status, showActions = false) {
document.getElementById('btn-generate').disabled = loading;
document.getElementById('status').textContent = status;
document.getElementById('actions').style.display = showActions ? 'flex' : 'none';
}
async function generate() {
const p = prompt('请输入想要生成的角色特点');
if (!p) return;
setUi(true, '生成中...');
try {
let text = await tavo.generate(`根据以下信息生成一张角色卡,输出符合 Character Card Spec V3 规范的JSON格式\n${p}`);
log(text)
text = text.trim();
if (text.startsWith('```') && text.endsWith('```')) {
text = text.replace(/^```[a-zA-Z]*\n?/, '').replace(/```$/, '');
}
generatedCard = JSON.parse(text);
if (generatedCard.mes_example instanceof Array) generatedCard.mes_example = generatedCard.mes_example.join('\n')
setUi(false, `角色卡 《${generatedCard.name}》 已生成`, true);
} catch (e) {
log(e);
console.log(e);
setUi(false, `角色卡生成失败`, false)
}
}
function downloadJson() {
tavo.utils.export(`${generatedCard.name}.json`, JSON.stringify(generatedCard));
}
async function createCharacter() {
await tavo.character.create(generatedCard);
}
</script>
⌨️ 输入框
可以通过此接口读取或操作聊天输入框,所有输入框接口均为 tavo.input.<method>(...)
读取输入框
await tavo.input.get()
获取当前输入框中的文本内容:
let text = await tavo.input.get() // 获取当前输入框内容
写入输入框
tavo.input.set(<text>)
覆盖写入输入框内容(会清除原有内容):
tavo.input.set('你好!') // 将输入框内容替换为"你好!"
追加到输入框
tavo.input.append(<text>)
在输入框现有内容末尾追加文本:
tavo.input.append(' 继续聊吧') // 在原有内容后追加文字
清空输入框
tavo.input.clear()
清空输入框内容:
tavo.input.clear()
发送消息
tavo.input.send()
触发发送当前输入框中的消息:
tavo.input.set('今天天气不错')
tavo.input.send() // 自动发送
🛠️ 工具
通用工具接口,所有工具接口均为 tavo.utils.<method>(...)
轻量提示
tavo.utils.toast(<text>)
显示一个轻量 toast 提示,数秒后自动消失
打开链接
tavo.utils.openUrl(<url>)
在外部浏览器中打开一个 URL:
tavo.utils.openUrl('https://example.com')
导出文件
tavo.utils.export(<name>, <data>)
将数据导出为文件并触发系统分享/保存。data 可以是 Base64 编码的内容(推荐)或普通文本字符串:
tavo.utils.export('叶离角色卡', btoa('这是一段文本或二进制,调用 btoa 转化为 base64')) // 传 base64 数据(推荐)
tavo.utils.export('record.txt', '这是一段文本内容') // 普通文本
📱 App
可以通过此接口读取或操作一些应用属性,所有接口均为 tavo.app.<method>(...)
获得当前 app 版本
await tavo.app.version(); // 字符串:0.77.0
await tavo.app.versionNumber(); // 数字: 770
⌛ 持续更新中
Tavo JavaScript API 现在还处于早期的 beta 阶段,我们仍在持续建设中,如果你有疑问或好的想法,欢迎到社区中进行反馈。