跳到主要内容

通信协议参考手册

Ante 在客户端(Client)与守护进程(Daemon)之间采用强类型的消息传递协议。同进程客户端使用有界操作通道和无界事件通道;外部客户端则通过 JSON Lines 或 WebSocket 帧交换相同消息。

传输协议格式​

外部客户端使用 JSON Lines (JSONL) 与守护进程通信 —— 通过 stdin/stdout 每行传输一个 JSON 对象。

  • 客户端 → 守护进程(Client → Daemon):向 stdin 写入 OpMsg 对象(每行一个 JSON)
  • 守护进程 → 客户端(Daemon → Client):从 stdout 读取 EventMsg 对象(每行一个 JSON)

OpMsg 消息封装​

每个操作指令均封装在 OpMsg 中:

{
"op": { "StartSession": { "model": "claude-sonnet-5-5", "provider": "anthropic" } },
"id": "op_01ARZ3NDEKTSV4RRFFQ69G5FAV"
}

EventMsg 消息封装​

每个状态事件均封装在 EventMsg 中:

{
"timestamp": "2025-06-01T12:00:00Z",
"id": "evt_01ARZ3NDEKTSV4RRFFQ69G5FAV",
"event": { "AgentMessage": "这是生成的代码..." },
"parent": "op_01ARZ3NDEKTSV4RRFFQ69G5FAV"
}

parent 字段用于关联触发该事件的操作指令 ID。在不适用时为 null。

消息 ID​

每个消息都拥有强类型的 Id,由前缀(最多 4 字节)与 ULID 组成。字符串格式为 {prefix}_{ulid}。

前缀用途
op_操作指令(客户端 → 守护进程)
evt_状态事件(守护进程 → 客户端)
ses_会话唯一标识符
step_模型单步调用标识符

示例:op_01J5A3B7C9D0E1F2G3H4J5K6M7

操作指令(客户端 → 守护进程)​

StartSession​

初始化新会话,并替换任何正在运行的会话。客户端提供的字段会被固定;省略或设为 null 的字段会在当前会话边界从主机设置解析,设置不存在时再使用 Ante 内置默认值。

{
"op": {
"StartSession": {
"model": "claude-sonnet-5-5",
"provider": "anthropic",
"credential": null,
"permission_mode": null,
"system_prompt": null,
"append_system_prompt": null,
"tools": null,
"include_tools": null,
"exclude_tools": null,
"cwd": null,
"effort": null,
"enable_auto_memory": null,
"short_prompt": null,
"no_skills": null,
"include_skills": null,
"exclude_skills": null,
"save_session": null,
"unattended": null,
"title": null
}
},
"id": "op_..."
}

SessionRequest 字段说明:

字段类型说明
modelstring?模型名称(如 "claude-sonnet-5-5");null 使用主机默认值
providerstring?提供商名称(如 "anthropic"、"openai"、"gemini"、"xai"、"openrouter"、"local");null 使用主机默认值
credentialstring?从首次请求起固定一个凭据引用,例如在 anthropic-subscription 上使用 "oauth:anthropic/work"。引用格式无效、不可用或不被提供商接受时,启动会被拒绝。省略或为 null 时按已配置的凭据优先级选择。自 v0.3.1 起可用
permission_modePermissionMode?工具审批模式:"strict"、"auto" 或 "yolo";null 使用主机默认值
system_promptstring?完全覆盖默认系统提示词
append_system_promptstring?向默认系统提示词末尾追加内容
toolsstring[]?精确指定的基础工具集,替换默认工具集。同时约束动态注册的(MCP)工具
include_toolsstring[]?在基础工具集(tools 或默认集)之上额外引入的工具列表
exclude_toolsstring[]?从会话中剔除的工具列表;优先级高于 tools 和 include_tools
cwdstring?工作目录。默认采用守护进程所在的进程目录
effortEffort?思考深度(Effort)覆盖值:"min"、"low"、"medium"、"high"、"xhigh" 或 "max"。null 时从目录中解析
enable_auto_memorybool?智能体是否记录并唤起自动记忆(auto-memory)。null 时采用守护进程默认值(交互式会话开启)
short_promptbool?使用更短的内置工具描述;系统指令保持不变。null 时采用配置默认值
no_skillsbool?为 true 时跳过所有技能发现,不声明或调用任何技能。null 时采用会话默认值
include_skillsstring[]?添加到会话基础集的精确技能名称。提供列表时替换主机的 include_skills 设置;no_skills 为 true 时不会重新启用技能发现
exclude_skillsstring[]?从会话移除的精确技能名称。提供列表时替换主机的 exclude_skills 设置,且优先级高于 include_skills
save_sessionbool?是否写入对话记录与可恢复快照。null 保留主机的会话保存默认值
unattendedbool?声明没有客户端可以回答审批提示。为 true 时,需要审批的调用会被拒绝而不是暂停;省略或设为 null 表示 false
titlestring?会话的展示名称,在恢复选择器中替代首条消息显示。文本两端会被裁剪,裁剪后为空即视为无标题。null 表示会话以无标题启动

SessionRequest 在 v0.preview.92 中取代旧名称 SessionOverrides。JSON 字段名保持不变,但对 StartSession 而言,缺省值现在只有一个明确含义:立即解析主机默认值,而不是“保留上一会话不变”。实现 /clear 的客户端应自行保留并重新发送其请求,同时合并用户做过的模型或权限模式变更;协议中没有独立的重启操作。

使用 ante auth list --json 可查看已存储的凭据引用及接受它们的提供商。固定凭据仅作用于当前会话,不随对话保存;恢复时需再次传入引用。引用被拒绝时不会回退到其他凭据。

UpdateSession​

在不重启的情况下原地更新活跃会话(例如在会话中切换提供商、模型或权限模式)。每个字段均为可选;省略的字段保持不变。权限模式的变更(如 TUI 中按 Shift+Tab 循环切换)会立即生效,适用于当前正在运行以及后续的轮次;提供商或模型变更在下一轮 Turn 开始时生效。title 变更立即生效,并通过 SessionUpdated 事件回传。其他会话选项必须在 StartSession 时设定。

provider 变更会在指定的目录提供商上继续当前对话,保留会话 ID、消息、标题与权限状态。此时 model 指定该提供商上的模型;省略时使用该提供商的默认模型。指定当前提供商不视为切换。若提供商 ID 未知,或在有 Turn 正在运行时请求切换到其他提供商,整个更新将被拒绝——以 Error 而非 SessionUpdated 回应;会话绝不会被自动改路由到其他提供商。如需从故障或触发限流的提供商切走,请先中断正在运行的 Turn。自 v0.2.5 起可用。

{
"op": {
"UpdateSession": {
"provider": "openai",
"model": { "id": "gpt-6.1-sol", "temperature": 0.2, "effort": "high" },
"permission_mode": "auto",
"title": "auth refactor"
}
},
"id": "op_..."
}

SessionUpdate 字段说明:

字段类型说明
providerstring?要切换到的目录提供商 ID(例如 "openai"),保留当前对话。提供商 ID 未知或有 Turn 正在运行时以 Error 拒绝
modelModelSpec?要使用的新模型规格。携带完整请求参数(包含 effort):设置的 effort 将覆盖目录默认值;未设置的字段从目录中解析。在会话的提供商上解析——同时设置 provider 时即为其指定的提供商
permission_modePermissionMode?新的权限模式("strict"、"auto" 或 "yolo")
titlestring?重命名会话。文本两端会被裁剪;传入空字符串或仅含空白的字符串即清除标题
credentialstring?在切换后的提供商上为本会话固定一个凭据引用,例如 "oauth:openai/work"。若提供商不接受该引用、引用没有值或有轮次正在运行,则拒绝。缺省时沿用当前提供商的选择;切换到其他提供商时按其配置顺序重新开始。自 v0.3.0 起可用

ResumeSession​

根据会话 ID 恢复此前持久化保存的会话。守护进程会还原已保存的对话以及固定的模型、提供商与思考深度;快照未固定的配置从主机当前默认值解析。随后重新发现扩展项并回放完整的持久化对话,以便客户端重建视图。

已保存的系统提示词及提示词模式按原样恢复,包括替换内容、追加指令和 short_prompt。当前启动的提示词参数仅作用于全新会话。本地日期、操作系统或 Shell 改变时,会在下一轮用一条通知告知模型;环境未变则不通知。

权限模式始终从主机的当前设置解析。旧版快照仍可加载,但其中保存的权限模式会被忽略,且下次保存时不再写入。

{ "op": { "ResumeSession": { "session_id": "ses_01ARZ...", "unattended": false } }, "id": "op_..." }
字段类型说明
session_idId要恢复的会话标识符
unattendedbool恢复后的当前会话是否无人可回答审批提示。省略时默认为 false;为 true 时,原本需要提示的调用会在准入阶段被拒绝
toolsstring[]?本次恢复的基础工具集,替换默认集合,同时限制 MCP 工具。省略或为 null 时使用当前设置。自 v0.3.1 起可用
include_toolsstring[]?本次恢复时添加到基础集合的工具。省略或为 null 时不添加。自 v0.3.1 起可用
exclude_toolsstring[]?本次恢复时移除的工具,优先于 tools 和 include_tools。省略或为 null 时不移除。自 v0.3.1 起可用
credentialstring?首次恢复请求前固定的凭据引用,校验规则与 StartSession.credential 相同。省略或为 null 时按已配置的优先级选择。自 v0.3.1 起可用

例如,使用 work 账户和受限工具集恢复一个保存在 anthropic-subscription 提供商上的对话:

{
"op": {
"ResumeSession": {
"session_id": "ses_01ARZ3NDEKTSV4RRFFQ69G5FAV",
"credential": "oauth:anthropic/work",
"tools": ["Read", "Glob", "Grep"]
}
},
"id": "op_01ARZ3NDEKTSV4RRFFQ69G5FAV"
}

除非本次请求提供了 tools,否则基础工具集由当前 tools 设置决定;已保存的对话不会还原旧工具集。添加和排除项仅作用于本次恢复。

成功时守护进程会针对当前会话(若有)触发 SessionEnd,随后为恢复的会话触发 SessionStart 和 ExtensionRefreshed,随后按顺序回放完整持久化事件日志,跳过会话生命周期事件和格式错误的行,不再限制为 200 条。失败时触发 Error 事件。

RewindSession​

将活跃会话的对话和可见历史恢复到输入 to 之前。该 ID 是输入对应的 TurnStart.turn_id(对于用户输入,即提交该输入的操作 ID)。所选输入及其后的内容会移除;不会开始新轮次,也不会撤销文件修改或其他外部操作。

{ "op": { "RewindSession": { "to": "op_input_1" } }, "id": "op_rewind_1" }

会话必须启用保存,且没有运行或排队的轮次、活动目标或运行中的后台任务。输入必须仍可恢复:保存的输入边界在恢复会话后保留,并复制到分叉会话中;成功替换历史的压缩或切换提供商会使之前的边界失效,压缩失败则保留它们。请求被拒绝时发出 Error,不改变对话;成功时发出 SessionRewound。

ForkSession​

从活跃对话保存一个新会话。at 指定仍可恢复的输入 ID 时,复制该输入之前的对话,切点与 RewindSession 相同;省略 at(或传 null)则复制完整对话。

{ "op": { "ForkSession": {} }, "id": "op_fork_1" }

来源会话必须启用保存,且没有运行或排队的轮次及活动目标;它本身保持不变。新会话只保存,不启动:SessionForked 返回其 ID,客户端再发送 ResumeSession 才会切换到它。请求被拒绝时发出 Error,不创建新会话。分叉复制对话状态,不复制文件、Git 工作树或运行中的进程。

Steer​

在当前活跃轮次执行期间向智能体提供额外指导,而无需开启新轮次。

{ "op": { "Steer": "先重点处理 auth 鉴权模块" }, "id": "op_..." }

UserInput​

向智能体提交用户文本提示词。

{ "op": { "UserInput": "解释这个项目的作用" }, "id": "op_..." }

ShellInput​

在守护进程端执行 Shell 命令而不启动轮次 —— 对应 TUI 中的 !command 路径。守护进程通过 ShellOutput 事件进行响应,并将输出排队注入智能体下一轮 Turn 的上下文中。

{ "op": { "ShellInput": "git status" }, "id": "op_..." }

ApprovalResponse​

响应工具审批请求(在收到原因类型为 Approval 的 TurnPause 事件后发送)。

{
"op": {
"ApprovalResponse": {
"turn_id": "step_01ARZ...",
"responses": [
{ "tool_use_id": "tool_use_abc123", "decision": "Accept" },
{
"tool_use_id": "tool_use_def456",
"decision": "Deny",
"message": "请改用只读端点"
}
]
}
},
"id": "op_..."
}

ToolDecision 字段说明:

字段类型说明
tool_use_idstring正在裁决的工具调用 ID(与 ToolStart.id 对应)
decisionReviewDecision取值如下表所示
messagestring?拒绝时返回的反馈理由。对于其他裁决类型请省略

ReviewDecision 裁决类型取值:

裁决取值说明
Accept允许本次单次工具调用
Deny拒绝本次工具调用。智能体将收到失败结果 —— 附带 message 时返回 Tool call denied by user: <message>,否则返回 Tool call denied by user and was not executed.
AcceptForSession在当前会话生命周期内始终允许(具备作用域泛化 —— 参见会话临时授权)
AcceptAlways在当前会话中允许,并将规则持久化写入 settings.json(“始终允许”)

QuestionResponse​

响应并解决挂起的提问暂停(TurnPauseReason::Question)。由客户端在用户回答、跳过或发起讨论 AskUser 提出的结构化问题后发送。

{
"op": {
"QuestionResponse": {
"turn_id": "step_01ARZ...",
"tool_use_id": "toolu_1",
"reply": {
"Answered": [
{ "selected": ["JWT (Recommended)"], "note": null }
]
}
}
},
"id": "op_..."
}
字段类型说明
turn_idId处于暂停状态的轮次 ID
tool_use_idstring对应提问的工具调用 ID
replyQuestionReplyAnswered(QuestionAnswer[])、Dismissed 或 Discuss { message? }

Answered 数组按问题顺序逐项对应 TurnPause.reason.Question.questions。每个 QuestionAnswer 包含:

字段类型说明
selectedstring[]选中选项的完整标签,不是索引;只输入自由文本时为空数组
notestring?补充说明,或 selected 为空时的回答正文;未提供文字时可省略

selected 为空且没有 note 表示该问题未回答。跳过整个提示时发送 "reply": "Dismissed";请求讨论时发送 "reply": { "Discuss": { "message": "先说明这些选项" } }。Discuss.message 可以省略。

SlashCommand​

按名称调用 Skill 技能。

{ "op": { "SlashCommand": { "name": "commit", "args": "-m 'fix bug'" } }, "id": "op_..." }

Compact​

在活跃会话上手动触发对话历史压缩(对应 /compact 命令)。可选 instructions 可引导替换摘要强调或保留哪些内容;如果仅清除工具结果就能释放足够空间,则无需摘要,指令也不会生效。守护进程会在操作前后分别触发 CompactStart 和 CompactEnd。

{ "op": { "Compact": {} }, "id": "op_..." }
{ "op": { "Compact": { "instructions": "重点保留 API 变更" } }, "id": "op_..." }

Compact 自 v0.preview.90 起为结构体变体;没有指令时客户端也必须发送空对象,不能再发送旧的裸字符串形式。

ContextReport​

请求活跃会话上下文窗口占用的分类明细(对应 /context 命令)。守护进程会回复 ContextReport 事件。

{ "op": "ContextReport", "id": "op_..." }

Goal​

在当前会话上设置、清除或查询目标导向型执行循环。设置目标后,会话将持续自主迭代 —— 在每轮 Turn 结束后由评估器裁决条件 —— 直至目标达成、判定不可达或手动清除。

{ "op": { "Goal": { "Set": "所有测试通过" } }, "id": "op_..." }
{ "op": { "Goal": "Clear" }, "id": "op_..." }
{ "op": { "Goal": "Status" }, "id": "op_..." }

AmbientPhrase / AmbientSuggestion​

在主对话关键路径之外调用轻量廉价模型进行异步预测:AmbientPhrase 为正在键入的草稿预测加载状态语;AmbientSuggestion 根据最近对话预测下一轮提示词建议。两者均通过 Ambient 事件响应;单调递增的 req_id 允许客户端丢弃过期的响应。

{ "op": { "AmbientPhrase": { "draft": "重构解析器以支持...", "req_id": 3 } }, "id": "op_..." }
{ "op": { "AmbientSuggestion": { "recent_user": "修复该 bug", "recent_agent": "已修复 — 原因是...", "req_id": 7 } }, "id": "op_..." }

Interrupt​

中断当前正在运行的操作。

{ "op": "Interrupt", "id": "op_..." }

Shutdown​

请求优雅关闭守护进程。

{ "op": "Shutdown", "id": "op_..." }

RegisterLocalProvider​

将运行中的本地推理端点(例如 Ante 托管的 llama serve 路由器,或外部运行的 llama-server)注册为此守护进程的 local 提供商。模型参数为可选 —— 提供时将本地提供商锁定为特定的 ModelSpec;否则本地提供商托管该端点提供的任意模型。

{
"op": {
"RegisterLocalProvider": {
"port": 8080,
"model": null
}
},
"id": "op_..."
}
字段类型说明
portu16本地推理服务器或路由器监听的端口号
modelModelSpec?可选的模型规格,用于锁定提供商

RestoreLocalProvider​

在会话级提供商切换后恢复此前注册的本地提供商配置。当守护进程需要还原到之前注册的本地服务端而无需重新提供端口和模型时非常有用。

{ "op": "RestoreLocalProvider", "id": "op_..." }

状态事件(守护进程 → 客户端)​

会话事件​

SessionStart​

在会话初始化完成后触发。它会声明会话身份、可变设置,以及当前会话已装备的 Skills 和子智能体。ExtensionRefreshed 会立即重复这些能力列表,并附带 MCP 状态,方便客户端通过单一事件整体替换扩展状态。

{
"event": {
"SessionStart": {
"model": { "id": "claude-sonnet-5-5", "max_tokens": 8192 },
"provider": {
"id": "anthropic",
"display_name": "Anthropic",
"base_url": "https://api.anthropic.com/v1"
},
"session_id": "ses_01ARZ...",
"cwd": "/home/user/project",
"permission_mode": "strict",
"skills": [],
"subagents": []
}
}
}

SessionInfo 字段说明:

字段类型说明
modelModelSpec当前活跃的模型规格
providerProviderSpec当前活跃的提供商规格(见下表)
session_idId唯一会话标识符
cwdstring工作目录路径
permission_modePermissionMode当前活跃的权限模式("strict"、"auto" 或 "yolo")
skillsSkillMetadata[]用户可在此会话中调用的 Skills;缺省时为兼容旧版本默认空列表
subagentsSubagentMetadata[]此会话可委派的子智能体;缺省时为兼容旧版本默认空列表
titlestring?已设置时为会话的标题 —— 由用户或客户端指定,绝不会从对话内容中推断。未设置时该字段整体从载荷中省略
forked_fromId?分叉来源会话的 ID。普通会话省略;不表示子智能体的父级关系

其中的 ModelSpec 使用目录参考手册列出的模型字段。自 v0.preview.92 起,可选字段 supported_efforts 用于携带自定义模型接受的思考深度档位,并取代旧的仅输出字段 effort_options。

ProviderSpec 字段说明:

字段类型说明
idstring提供商 Key,例如 "anthropic"(兼容支持历史别名 name)
display_namestring展示名称
base_urlstring当前会话实际使用的端点地址 —— 环境变量覆盖可能会使其不同于目录默认值
credentialstring?会话显式选定的凭据,以引用形式给出,例如 "oauth:antix/work",绝不包含令牌本身。提供商使用其配置顺序时省略。自 v0.3.0 起可用

该载荷类型在 v0.preview.94 之前名为 SessionInitialized,现已更名为 SessionInfo。这仅是 Rust 类型名称的变更 —— 事件名(SessionStart、SessionUpdated)与 JSON 均保持不变,客户端无需适配。

ProviderSpec 有意仅传递客户端无法自行查询的信息。提供商的模型列表不包含在协议消息中;它对每个会话完全相同,并通过 ante catalog 发布。未知字段会被忽略,因此仍会发送 preferred_models 的旧版守护进程载荷能够正常兼容解码。

SessionRewound​

确认活跃对话及其持久化历史现已恢复到 to 之前。该确认事件绝不会包含在恢复会话的回放中。客户端收到后应从对话视图移除所选输入及其后的条目。

{ "event": { "SessionRewound": { "to": "op_input_1" } }, "parent": "op_rewind_1" }

SessionForked​

确认已从 forked_from 保存新会话 session_id;存在 at 时从该输入之前复制,否则复制完整对话。这不表示新会话已经运行;需恢复返回的 ID 才能使用它。

{ "event": { "SessionForked": { "forked_from": "ses_parent", "session_id": "ses_child" } }, "parent": "op_fork_1" }

SessionUpdated​

当活跃会话原地更新(如通过 UpdateSession 切换模型)时触发。携带与 SessionStart 相同的字段。

{
"event": {
"SessionUpdated": {
"model": { "id": "gpt-6.1-sol" },
"provider": {
"id": "openai",
"display_name": "OpenAI",
"base_url": "https://api.openai.com/v1"
},
"session_id": "ses_01ARZ...",
"cwd": "/home/user/project",
"permission_mode": "strict",
"skills": [],
"subagents": []
}
}
}

SessionEnd​

在会话生命周期跨度结束时触发。类似于 TurnEnd:携带会话标识、结束原因及最终的 Token 消耗核算。

{
"event": {
"SessionEnd": {
"session_id": "ses_01ARZ...",
"reason": "Shutdown",
"usage": { "input_tokens": 15000, "output_tokens": 3000 }
}
}
}

SessionEndReason 取值变体:

变体说明
Replaced会话被新的或恢复的会话所替换
Shutdown守护进程正在关闭退出

轮次生命周期事件​

TurnStart​

新轮次开始处理时触发。

{ "event": { "TurnStart": { "turn_id": "step_01ARZ..." } } }

TurnPause​

当轮次暂停以等待用户输入(例如工具审批)时触发。

{
"event": {
"TurnPause": {
"turn_id": "step_01ARZ...",
"reason": {
"Approval": {
"tools": [
{ "id": "tool_use_abc123", "name": "Bash", "input": { "command": "ls -la" } }
],
"message": "是否允许运行 Shell 命令?"
}
}
}
}
}

TurnPauseReason 取值变体:

变体字段说明
Approvaltools: ToolUse[], message: string正在等待工具调用审批
Questiontool_use_id: string, questions: QuestionSpec[]正在等待用户回答 AskUser 提出的结构化问题

QuestionSpec 字段:

字段类型说明
headerstring问题的短标签
questionstring完整问题正文
multi_selectbool是否允许多选;省略时为 false。注意协议字段是 multi_select,工具输入字段为 multiSelect
optionsQuestionOption[]提供的选项;“其他”自由文本入口由客户端添加

每个 QuestionOption 包含 label 和 description 字符串,以及可选的 preview 字符串(代码、示意或配置片段)。提问暂停期间,同一批次中的其他工具仍可能运行;客户端应持续读取事件,并在收到 TurnResume 或 TurnEnd 时清除未回答的提示。

TurnResume​

在 TurnPause 后恢复执行时触发(例如审批得到响应或收到实时引导指令),客户端无需从下一个工具事件反推恢复状态。

{ "event": { "TurnResume": { "turn_id": "step_01ARZ..." } } }

TurnEnd​

轮次完成时触发。steps 为轮次结束前尝试的单步循环次数。

{ "event": { "TurnEnd": { "turn_id": "step_01ARZ...", "status": "Completed", "steps": 4 } } }

TurnEndStatus 取值变体:

变体字段说明
Completed—轮次成功执行完毕
Interruptedreason?: string轮次被中断
Errorkind?: string, headline: string, details: string[]轮次异常结束。kind 为机器可读的稳定 LLM 错误类型(如 "oauth" 表示提供商登录缺失、过期或被撤销)。headline 为单行摘要;details 为详细错误原因行

消息流式事件​

AgentMessage​

从流中汇总的完整智能体文本回复。已展示增量内容的客户端应避免再次渲染相同文字。

{ "event": { "AgentMessage": "该项目是一个 Web 服务器..." } }

Thinking​

从流中汇总的完整推理块。已展示推理增量的客户端应避免再次渲染相同文字。

{ "event": { "Thinking": "让我先分析一下代码库的结构..." } }

MessageDelta​

智能体回复的增量流式片段。拼接所有 delta 片段即可构建完整消息。

{ "event": { "MessageDelta": "该项目" } }

ThinkingDelta​

智能体思考推理过程的增量流式片段。

{ "event": { "ThinkingDelta": "让我" } }

工具事件​

ToolStart​

工具开始调用时触发。

{
"event": {
"ToolStart": {
"id": "tool_use_abc123",
"name": "Read",
"input": { "file_path": "/src/main.rs" }
}
}
}

ToolUpdate​

工具执行期间的进度更新。

{
"event": {
"ToolUpdate": {
"tool_use_id": "tool_use_abc123",
"seq": 0,
"message": "正在读取文件..."
}
}
}
字段类型说明
tool_use_idstring工具调用标识符(与 ToolStart.id 对应)
sequ64单调递增的序列号
messagestring进度提示信息

ToolEnd​

工具执行完成时触发。

{
"event": {
"ToolEnd": {
"tool_use_id": "tool_use_abc123",
"tool_name": "Read",
"status": "Completed",
"result_json": { "content": "fn main() { ... }" }
}
}
}

ToolEndStatus 取值变体:

变体说明
Completed工具成功执行完成
Cancelled工具执行被取消
Denied工具调用被用户拒绝
Failed工具执行发生错误失败

即使工具尚未开始执行,tool_name 也会填充,因此客户端无需从前置事件重建名称,即可展示被拒绝、取消或参数异常的调用。旧事件反序列化时该字段可能为空字符串。协议中没有单独的 is_error 字段:可根据 status 推导(只有 Completed 不是错误)。每个已接受的工具调用都会收到终态 ToolEnd;并发调用会在各自完成时独立发送。

TaskEnd​

工具移交的受跟踪任务完成时触发,例如超过内联等待窗口的 Bash 命令。自 v0.2.3 起可用。先前的 ToolEnd 表示工具调用已完成并返回后台句柄,并不表示进程已退出。

{ "event": { "TaskEnd": { "tool_use_id": "tool_use_abc123", "exit_code": 0 } } }

tool_use_id 标识原始调用。exit_code 是进程退出码(信号终止时为 128 + signal);无法观测退出结果时为 null。客户端可据此更新原始运行任务的显示状态。此事件会持久化,并在恢复会话时回放。

上下文压缩事件​

CompactStart​

对话历史压缩开始时触发。

{ "event": "CompactStart" }

CompactEnd​

对话历史压缩完成时触发。summary 非 null 时,表示该文本已提交为压缩历史的替代内容,并作为后续上下文保留;客户端应使之前的回退与分叉目标失效。null 表示未提交历史替换,原有目标仍然有效。不要仅因收到 CompactStart 就清除目标。

{ "event": { "CompactEnd": { "summary": "用户要求进行..." } } }

扩展事件​

ExtensionRefreshed​

Skills 技能、子智能体或 MCP 服务器刷新时触发。SessionStart 后会立即发送一次,其中 Skills 与子智能体和启动事件相同,mcp_servers: []。配置了 MCP 服务器时,后台预热完成后会再发送第二次,带上发现的服务器与工具;未配置 MCP 时只有首次事件。

{
"event": {
"ExtensionRefreshed": {
"session_id": "ses_01ARZ...",
"skills": [
{ "name": "commit", "description": "创建 Git commit", "scope": "user", "argument_hint": "-m 'message'" }
],
"subagents": [
{ "name": "explore", "description": "探索代码库", "scope": "project" }
],
"mcp_servers": [
{
"name": "filesystem",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
"tools": [
{
"name": "read_text_file",
"qualified_name": "mcp__filesystem__read_text_file",
"description": "读取文本文件内容",
"parameters": [
{ "name": "path", "param_type": "string", "required": true, "description": "文件路径" }
]
}
]
}
]
}
}
}

mcp_servers 中的每个条目描述一个已配置的服务端及其发现的工具。本地服务通过 command 和 args 描述;远程服务包含 url,其 command 为空字符串、args 为空列表。可选字段 url 在 v0.2.12 中加入,本地服务会省略该字段。连接失败或未暴露工具的服务端,其 tools 列表为空;qualified_name 是智能体调用该工具时使用的 mcp__<server>__<tool> 形式。

提示与信息事件​

UsageUpdate​

会话的 Token 消耗统计。在首条回复前、模型上下文限制未知或用量来自子智能体时省略 context。客户端应将每个 usage 累加进总计,但在 context 缺失时保留最后一次根会话上下文快照;委派任务不得覆盖根会话指示器。存在的 context 仅包含原始测量数据 —— used_tokens(包含缓存的窗口占用)与 limit_tokens(模型原始上下文限制);百分比由客户端自行计算。在提供商支持时,usage 还包含 cache_read_tokens 与 cache_creation_tokens。

{
"event": {
"UsageUpdate": {
"usage": { "input_tokens": 1500, "output_tokens": 300 },
"context": { "used_tokens": 1800, "limit_tokens": 200000 }
}
}
}

ContextReport​

响应 ContextReport 操作:请求时刻会话上下文窗口占用的按类别细分明细。

{
"event": {
"ContextReport": {
"system_prompt_tokens": 3200,
"system_tools_tokens": 4100,
"mcp_tools_tokens": 900,
"memory_tokens": 600,
"skills_tokens": 450,
"messages_tokens": 12000,
"used_tokens": 21250,
"limit_tokens": 200000,
"compact_buffer_tokens": 20000
}
}
}
字段类型说明
system_prompt_tokensu32系统提示词(不含单独计数的技能与记忆部分)
system_tools_tokensu32内置工具 Schema 定义
mcp_tools_tokensu32MCP 工具 Schema 定义
memory_tokensu32项目/全局指引文件及自动记忆提示词
skills_tokensu32可用技能列表描述
messages_tokensu32对话消息内容 —— 未归入上述类别的全部内容
used_tokensu32上下文窗口总占用 Token 数
limit_tokensu32?模型上下文上限;未验证时为 null
compact_buffer_tokensu32窗口顶部预留的缓冲 Token;一旦占用进入该预留区将触发自动压缩

Info​

通用信息提示。

{ "event": { "Info": "正在压缩对话历史记录..." } }

InfoBlockStart​

开启带标题的分组信息块。后续具有相同 id 的 InfoBlockAppend 事件会作为树状缩进的子行展示 —— 适用于多阶段后台通知(如 MCP 预热)。当 loading 为 true 时,在收到首条 InfoBlockAppend 之前标题会展示 ./../... 加载动画。

{
"event": {
"InfoBlockStart": {
"id": "mcp-warmup-ses_01ARZ...",
"header": "正在后台预热 4 个 MCP 服务 — 工具将在连接建立后就绪。",
"loading": true
}
}
}

InfoBlockAppend​

向相同 id 的 InfoBlockStart 追加一行子详情。若对应 block 不存在则静默忽略。

{
"event": {
"InfoBlockAppend": {
"id": "mcp-warmup-ses_01ARZ...",
"detail": "MCP 就绪: 4/4 服务已连接,已注册 60 个工具。"
}
}
}

Error​

错误提示信息。

{ "event": { "Error": "认证失败: API 密钥无效" } }

Goodbye​

守护进程断开前的最终消息。收到此消息后不会再发送任何事件。

{ "event": "Goodbye" }

UserInput​

为会话回放记录的用户输入。此变体写入持久化的事件日志,但不会在实时会话中发出 —— 仅在 ResumeSession 历史回放时可见。

{ "event": { "UserInput": "解释这个项目的作用" } }

ShellOutput​

响应 ShellInput 操作:执行的命令及输出结果。

{
"event": {
"ShellOutput": {
"command": "git status",
"stdout": "On branch main...",
"stderr": "",
"exit_code": 0
}
}
}

Ambient​

由轻量模型在主对话外生成的即时预测提示 —— 正在键入草稿的预测加载状态语,或作为输入虚字展示的下一轮提示词建议。通过 AmbientPhrase / AmbientSuggestion 请求;req_id 便于客户端丢弃过期响应。不写入持久化事件日志。

{ "event": { "Ambient": { "kind": "PromptSuggestion", "req_id": 7, "text": "运行测试" } } }

离线模式与协议边界​

本地模型管理(引擎安装、模型发现及本地路由器生命周期)属于客户端侧职责。它是通过进程内的 OfflineSubsystem API 驱动的,而非通过守护进程协议。离线模式面向守护进程的唯一接口是 RegisterLocalProvider / RestoreLocalProvider —— 客户端启动托管的 llama serve 路由器(或连接外部服务器),随后向守护进程注册其端口号及可选的 ModelSpec。

关于面向用户的工作流及 --offline-model CLI 参数,请参阅离线模式。

传输层​

进程内通道​

当客户端与守护进程运行在同一进程内(TUI 或无头模式)时,通过 Tokio 异步 mpsc 通道通信:

通道方向容量
Op 操作指令通道客户端 → 守护进程256 条消息
Event 事件通道守护进程 → 客户端无界;待处理积压达到 4096 条时发出警告,并在排空时记录恢复

事件不会因同进程客户端读取缓慢而丢失或阻塞。停止读取的客户端会累积内存积压,因此消费者即使在处理其他工作时也应持续排空事件接收器。

Stdio 传输(JSONL)​

对于使用 ante serve(或 ante serve --stdio)的外部客户端,StdioTransport 将 stdin/stdout 桥接到内部通道:

  • stdin → 逐行解析为 OpMsg → 转发至守护进程
  • 守护进程事件 → 序列化为 JSON → 逐行写入 stdout
  • stdin EOF → 自动发送 Op::Shutdown
  • 收到 Evt::Goodbye → 传输层退出
  • JSON 解析失败 → 向 stdout 回复 Evt::Error

Unix 套接字传输​

对于需要连入他人已启动宿主的客户端,ante serve --sock [PATH] 会监听一个 Unix 域套接字(默认为 Ante 主目录下的 run/serve.sock),并在该字节流上交换同样的 JSONL 协议:

  • 每个客户端在共享主机上拥有独立连接以及最多一个活跃会话
  • Op::Shutdown 只结束该连接;宿主继续接受新连接
  • 宿主进程在收到 SIGINT 或 SIGTERM 时退出
  • 所有权由套接字旁 .lock 文件上的排他锁表示,因此同一路径上的第二个宿主会拒绝启动,而不会顶替正在运行的宿主;崩溃遗留的陈旧套接字文件不持有锁,会在下次启动时被替换

WebSocket 传输​

对于网络或基于浏览器的客户端(ante serve --ws <ADDR>),WsTransport 在 WebSocket 帧上交换相同的 JSONL 协议:

  • 每个 WebSocket 客户端在共享主机上拥有独立连接与会话
  • 消息通过文本帧传输相同的 OpMsg 与 EventMsg JSON 对象
  • 客户端断开连接 → 当前连接与会话关闭,其他客户端与宿主继续运行
  • 收到 Op::Shutdown → 仅关闭该连接
  • 宿主并发接受客户端,直到收到 SIGINT 或 SIGTERM
  • 即使事件写入阻塞也会继续读取输入;每次写入的期限为 30 秒,响应队列溢出只会断开违规对端

完整交互生命周期示例​

从启动到关闭的完整会话生命周期时序:

Client (客户端) Daemon (守护进程)
│ │
│─── OpMsg { StartSession(...) } ──────────────▶│
│◀── EventMsg { SessionStart(...) } ────────────│
│ │
│─── OpMsg { UserInput("修复该 bug") } ─────────▶│
│◀── EventMsg { TurnStart { turn_id } } ────────│
│◀── EventMsg { ThinkingDelta("...") } ─────────│
│◀── EventMsg { ThinkingDelta("...") } ─────────│
│◀── EventMsg { Thinking("...") } ──────────────│
│◀── EventMsg { MessageDelta("...") } ──────────│
│◀── EventMsg { ToolStart(ToolUse) } ───────────│
│◀── EventMsg { TurnPause(Approval) } ──────────│
│ │
│─── OpMsg { ApprovalResponse(...) } ──────────▶│
│◀── EventMsg { ToolUpdate(...) } ──────────────│
│◀── EventMsg { ToolEnd(...) } ─────────────────│
│◀── EventMsg { MessageDelta("...") } ──────────│
│◀── EventMsg { AgentMessage("...") } ──────────│
│◀── EventMsg { UsageUpdate(...) } ─────────────│
│◀── EventMsg { TurnEnd(Completed) } ───────────│
│ │
│─── OpMsg { Shutdown } ───────────────────────▶│
│◀── EventMsg { SessionEnd } ───────────────────│
│◀── EventMsg { Goodbye } ──────────────────────│
│ │