TauriTavern/docs/API/Agent.md
Darkatse 48aa5c7242 refactor(agent): remove round and tool call budgets
Remove the profile limits, runtime counters, quota errors, and extra-round resume flow. Keep tool authorization stateless and give protocol drift recovery its own 20-attempt limit, reset on resume.

Migrate profiles to schema 5 and discard retired fields at the existing profile, draft, and checkpoint decoding boundaries. Route shared Session profile migration and persistence through AgentProfileService.

Validation: pnpm run check; focused profile and runtime tests; macOS profile migration, JSON save, export dialog, and old checkpoint reads.
2026-10-22 01:48:30 -04:00

18 KiB
Raw Permalink Blame History

Agent API

window.__TAURITAVERN__.api.agent 提供 Chat 与 Session 运行、历史读取和 Profile 管理。框架说明从 Agent 开始,完整 TypeScript 类型见 src/types.d.ts。

启动一次运行

await (window.__TAURITAVERN__?.ready ?? window.__TAURITAVERN_MAIN_READY__);
const agent = window.__TAURITAVERN__.api.agent;

const run = await agent.startRunFromLegacyGenerate({ profileId: 'default-writer' });
const unsubscribe = agent.subscribe(run.runId, event => {
  console.log(event.seq, event.type, event.payload);
}, { onError: console.error });

// 离开当前视图时调用 unsubscribe()。

该入口从当前聊天捕获生成输入,适用于 OpenAI/chat-completion 路径。普通发送、/trigger、regenerate 和生成新 swipe 在 Agent Mode 开启时使用同一套运行机制。

启动方法 输入
startRunFromLegacyGenerate(input?) 当前聊天与 Legacy Generate 选项
startRunWithPromptSnapshot(input) 调用方已经组装好的 promptSnapshot 与 chatRef

共同选项有 profileId、generationType、stableChatId、presentation 和 options.stream。稳定聊天 ID 省略时由 Host API 解析。options.stream 省略时使用各 Invocation 的 Profile 设置,显式值覆盖整次 Run。

两种 Chat 方法返回 { runId, status, workspaceId, stableChatId, generationType }。Snapshot 使用 { contextPolicy, messages, generationParameters, acceptsImages? },消息为 AgentModelMessage[];Legacy chatCompletionPayload 在入口适配,Chat 输入不能注入外部工具回合。冻结输入与组装规则见 Prompt assembly。

acceptsImages 的公开默认值为 false;判定与 Invocation 生命周期见 Prompt assembly。

canonical snapshot 的指令消息以 Text part 保存正文,并携带 providerMetadata.promptComponent: "agentSystemPrompt",供 runtime 追加目录。旧 Chat 输入仍接受字符串 content 与 _tauritavern_prompt_component: "agentSystemPrompt"。共同 PromptManager 自动提供标记,标记不会发送给模型。

手工 snapshot 需要委派或交接时须携带 frozenRunInputSnapshot,当前预设及其 Skill 作用域都从中取得。

持续 Session

Session 独立于角色聊天和写作 Agent Mode。使用前通过 sessions.profile.save() 保存共享配置,此后每次发送读取最新配置。

方法 返回内容
sessions.profile.load() { profile };尚未配置时为 { profile: null }
sessions.profile.save(profile) 保存共享的 AgentProfileDefinition
sessions.create() { session };元数据为 { id, createdAt, title, lastUsedAt }
sessions.list() { sessions, activeRuns };仅会话元数据目录与活动 Run handles
sessions.rename({ sessionId, title }) { session };标题 trim 后为 1–120 字符
sessions.delete({ sessionId }) 删除会话数据;活动会话拒绝删除,目标已不存在时成功
sessions.read({ sessionId, beforeSeq?, limit? }) { session, messages, lastSeq, nextBeforeSeq, activeRun }
sessions.send({ sessionId, text, variables? }) { sessionId, runId, status, createdAt };执行在原生端继续
sessions.compact({ sessionId }) 同上;这次 Run 只压缩上下文,不回复
// 已配置 Session Profile;agent 的取得方式同上。
const { session } = await agent.sessions.create();
const run = await agent.sessions.send({ sessionId: session.id, text: '查看 work/ 中的文件。' });

variables.local 是本次宏求值的局部变量,省略时为空;全局变量在 send 开始时复制。宏写入只影响本次工作副本,详见宏求值 API。

保存 session.id 供后续读取和发送。send 返回后执行仍在继续,通过 subscribe(run.runId, ...) 观察终态,再发送下一条。忙碌或准备输入过期时 reject,不自动重试。

title、lastUsedAt 未设置或旧数据缺字段时为 null。用户消息落盘时更新 lastUsedAt,未命名时生成短标题。目录按 lastUsedAt ?? createdAt 降序排列;改名不改变排序。

历史由后端保存;收到 session_message_appended 后可调用 sessions.read() 更新界面,实时进度沿用 subscribeLiveProjection()。历史页按 seq 升序返回,每项为 { seq, runId, createdAt, message, origin?, compaction? };nextBeforeSeq 用于向前翻页,activeRun 为活动 handle 或 null。

origin: { invocationId, round } 关联 assistant/tool 消息及压缩记录所属的回合,不进入模型消息;用户自己的消息没有 origin,旧历史也可缺少它。Session seq 标识持久消息。压缩记录为 user 角色,两个 Text part 分别保存说明和摘要,并带 compaction: { keptFromSeq: number | null, tokensBefore: number, tokensAfter: number };它不是用户发言,不更新标题或 lastUsedAt,也不替代同 origin 的模型回复。keptFromSeq 指向保留的完整组起点,null 表示没有保留组。

Session 的 snapshot 另带 contextLimits: { context, response, tokenizerModel },由组装时的有效模型设置提供。压缩的规则见运行循环,状态与事件见运行日志。常见失败码:

错误码 含义
agent.session_history_window_unsupported Session Profile 的历史窗口不是 -1
agent.session_context_limits_missing 快照缺少有效的 contextLimits
agent.session_context_limits_invalid contextLimits.context 不大于 contextLimits.response
agent.context_full 上下文无法通过压缩降到压缩点以下
agent.nothing_to_compact 手动压缩时,较早部分都在保留范围内
agent.compaction_failed 模型未按要求产出摘要、回复截断或输入无法缩小到可摘要的范围
model.context_overflow 服务商报告超窗;本轮压缩恢复后仍失败时传播

Session 的结束与恢复边界见 运行循环,文件保留规则见 Workspace。

控制与订阅

方法 行为
cancel(runId) 请求取消,返回 Chat handle 或 { sessionId, runId, status, createdAt };终态通过事件观察
readCheckpoint(runId) 读取保存状态及可恢复性信息
resume({ runId, revisionGuidance? }) 续接同一 Run,或根据新要求修订已完成输出;返回含订阅游标 afterSeq 的 Run handle
submitGuidance({ runId, text, clientGuidanceId? }) 向活跃 Run 补充指令,返回 guidanceId 与 status: 'queued'
subscribe(runId, handler, options?) 订阅持久事件,返回可重复调用的 unsubscribe
subscribeLiveProjection(runId, handler, options?) 订阅当前正文、推理文字及文件工具参数预览,返回 unsubscribe

Chat 补充指令在下一次前台模型请求前加入上下文,已经发出的请求保持原样。尚未消费的指令随续接保留。该接口不创建聊天消息。

subscribe 的选项是 afterSeq、limit、intervalMs、onError,默认从起点读取。实时预览只接受 onError;历史过程从持久事件读取。退订后不再交付回调,包括在途请求的结果与错误。

实时通道使用以下共同协议(不写入持久 journal):

update.type 内容
snapshot { calls, responses },替换当前投影
responseReplace { response },新的模型回合或重试
responseAppend { invocationId, text, reasoning, toolIds },三个字段分别追加
responseRemove { invocationId },移除本次临时响应
replace / append / remove 既有文件工具参数投影

response 包含 invocationId、invocationExitPolicy、round、attempt、text、reasoning、toolIds。正文与思考共用回合/尝试身份,完成快照不重复发送增量。正式 assistant 按 runId + invocationId + round 接替对应 attempt 的预览,须处理事件与 Channel 的任意到达顺序。失败、取消及终态清除预览,不将其写入历史。写作 Timeline 只消费 reasoning,Chat 正文仍走文件提交。

resume 保留原始输入与已确认结果,要求当前聊天及消息仍属于原 Run;普通重新生成仍创建新 Run。续接订阅使用返回的 afterSeq,恢复条件见 运行循环。

传入 revisionGuidance 时,从已完成的 checkpoint 开始新的前台 Invocation,继承上下文与原 Profile。聊天命令 /fix 修改要求 使用这一入口,原地修改最后一条 Agent 回复的当前 swipe,以当前已保存的正文为基准。

v1 checkpoint 仅支持查看状态和修订已完成的 Run;首次修订时转换,范围见 运行循环。

历史与详情

const page = await agent.listRuns({ stableChatId, limit: 20 });
const nextPage = page.nextCursor
  ? await agent.listRuns({ stableChatId, before: page.nextCursor, limit: 20 })
  : null;

const { events, timelineProjection } = await agent.readEvents({
  runId,
  afterSeq: 0,
  limit: 100,
  includeTimelineProjection: true,
});
方法 返回内容
listRuns({ chatRef?, stableChatId?, statuses?, before?, limit? }) { runs, nextCursor? },按创建时间倒序;before 为 { createdAt, runId },最多 200 条
readEvents({ runId, afterSeq?, beforeSeq?, limit?, invocationId?, includeTimelineProjection? }) { events, timelineProjection? },事件按序号升序,单页最多 500 条
readWorkspaceFile({ runId, path }) { path, text, chars, words, sha256 }
readWorkspaceBytes({ runId, path }) Uint8Array;上限 1,000,000 字节,用于读取工具结果图片
readModelTurn({ runId, invocationId?, round, maxChars? }) assistant 文本、可见 reasoning、工具调用与 provider 摘要
readTaskDetail({ runId, taskId, includeResult? }) 任务说明、当前状态及按需读取的结果

listRuns 保持 Chat 历史范围;Session 对话使用 sessions.read,按 runId 的事件、模型回合及工作区详情读取可用于两种 Run。beforeSeq 读取该序号之前最近的一页,afterSeq 用于向前追新。invocationId 先筛选归属再分页,适合子 Agent 的局部 Timeline。timelineProjection 包含整个 Run 的 Invocation 和委派关系,独立于当前事件页。

readModelTurn 的 round 从 1 开始,省略 invocationId 时读取根 Agent。maxChars 限制展示文本,字词总数仍对应完整内容。

readTaskDetail 把委派的 task 和交接的 handoff 统一放在返回值的 task 字段,保留自定义字段。状态是读取时的状态。includeResult 默认 false;设为 true 时,若有结果则返回 { summary, summaryRef, output },否则 result 为 null。

模型回合、任务详情、工具目录与 Timeline 关系属于随项目演进的 UI 投影(Project Contract)。界面通过这些 API 读取内容,具体类型集中在 src/types.d.ts。日志语义见 运行日志。

Profile、提示词与工具目录

方法 用途
profiles.list() 返回 Profile 列表及文件诊断
profiles.load(profileId) 返回 { profile }
profiles.save(profile) / delete(profileId) 保存或删除配置
profiles.diagnose(profileId) 检查预设、模型、工具等引用
profiles.resolveSystemPrompt({ profileId? }) 返回 { agentSystemPrompt }
profiles.repairFile({ profileId, action }) 删除损坏配置或规范化身份;action 为 delete、normalizeIdentity
profiles.retargetPresetRefs({ from, to }) 预设重命名后更新普通 Profile 和共享 Session Profile 的匹配引用;两端都是 { apiId, name }
promptAssembly.prepare(input) 解析 Profile 与冻结输入,返回组装模式及请求
promptAssembly.buildSnapshot(request) 在前端运行 PromptManager,生成 snapshot
promptAssembly.buildCurrentModelConnectionSnapshot(input) 根据当前设置生成连接快照
promptAssembly.applyCurrentModelConnectionSnapshot(input) 把连接快照应用到组装设置
tools.list({ context? }?) 返回 { tools, diagnostics },包含内置、可用 MCP 及已注册扩展工具;context 可为 chat 或 session
tools.register(definition, execute) 注册普通 JS 工具函数,返回 Promise<void>
tools.setEnabled(toolId, enabled) 启用或关闭已注册的扩展工具,不删除函数或改写 Profile

Profile 的用法见 配置指南。tools.list() 返回稳定工具 ID、描述和参数 schema;模型调用名称属于 Invocation 快照。

profiles.retargetPresetRefs 返回 { updated, profileIds, sessionProfileUpdated };总数 updated 包含共享配置,profileIds 只列普通 Profile。

profiles.resolveSystemPrompt 返回 Profile 指令正文;运行时目录的追加规则见 Prompt assembly。

注册扩展工具

在扩展启动入口注册普通 JS 函数,可直接使用模块引用和闭包。稳定 ID 为 extension/<extensionId>:<name>,重复注册报错;注册持续到主页面 reload,与面板开关无关。

await agent.tools.register({
    extensionId: 'my-extension',
    name: 'read_auto_reply_settings',
    description: '读取自动回复的启用状态。',
    inputSchema: { type: 'object', properties: {} },
    contexts: ['chat', 'session'],
    enabled: true,
}, async () => {
    return { enabled: true };
});

await agent.tools.setEnabled('extension/my-extension:read_auto_reply_settings', false);

模型以 name 为调用名称基础,命名与结果表达遵循 工具契约。description 说明用途与必要限制,返回值和错误说明实际结果或具体问题。

contexts 必填且非空,enabled 默认 true;注册后仍需在 Profile 中选择工具。关闭后不再接受新调用,已开始的调用继续执行,list() 仍包含关闭条目。开关持久化由扩展自己的设置或 api.extension.store 负责,页面 reload 后按保存的值重新注册。

回调接收 JSON 对象参数与执行上下文,其中 target 指向本次 Run 所属的 Chat 或 Session,与当前 UI 无关;signal: AbortSignal 提供合作式取消,不回滚已发生的操作。完整字段见 类型定义。

图片通过 context.attachImage(blob) 附加,函数的 JSON 返回值描述结果。规范化、存储和上下文留存见 工具结果。

returnsImages 默认 false;声明和绑定规则见 扩展工具。

函数可异步返回 JSON 值,顶层 undefined 按 null 返回;抛错或无法通过 JSON IPC 传输时报告工具错误。60 秒无回执时请求取消该调用,将“执行结果未知”作为工具错误交给模型继续处理,不自动重发;脚本可能仍在运行,后续操作应先核查状态。用户主动取消仍结束 Run。

保留策略

const settings = await agent.retention.readSettings();
const plan = await agent.retention.planPrune({ detailLimit: 20 });
方法 行为
retention.readSettings() 返回自动清理开关及两个保留数量
retention.updateSettings(patch) 保存部分设置
retention.planPrune({ retention?, detailLimit? }) 预览清理范围和统计
retention.applyPrune({ retention?, detailLimit? }) 重新计算并执行清理,返回结果和 afterPlan

此清理范围为 Chat Run,不包含 Session。设置包括 autoPruneEnabled、keepRecentTerminalRuns、keepFullRecentRuns。完整保留数量不得大于核心历史数量;自动清理默认关闭。一次性 retention 参数只覆盖本次操作的保留数量。

预览区分缩减材料和整次删除,并返回不能清理的 Run。执行结果中的 failedRuns 表示未完成的项目。detailLimit 只控制返回明细数量,不改变执行范围或总计。

宿主生命周期

聊天提交由 runtime 与宿主协作完成;模型用 workspace.commit 请求提交。宿主调用 settleChatPresentation({ runId }) 等待消息呈现与 checkpoint 保存;失败后可重试,已完成的消息写入不会重复执行。

聊天分叉时,copyChatPersistentStates({ sourceChatRef, sourceStableChatId, targetChatRef, targetStableChatId }) 复制持久版本。删除消息或 swipe 后,pruneChatPersistentStates({ chatRef?, stableChatId?, candidateStateIds }) 清理明确列出的、已不再被当前聊天引用的版本;该清理入口目前支持角色聊天。

approveToolCall() 是未实现的预留入口,调用会抛错。当前没有通用 rollback API。

错误与实现

异步方法失败时 reject;订阅错误通过 onError 传递。运行失败原因保存在日志,错误发生在已有确认提交之后时,Run 会保留输出并以 partial_success 结束。