ACP_Protocol_Specification.md 23 KB

ACP (Agent Client Protocol) 协议详细描述文档

基于 vscode-acp 项目源码分析提取,SDK 版本:@agentclientprotocol/sdk ^0.21.1


1. 协议概述

ACP (Agent Client Protocol) 是一种用于 AI 编程代理(Agent)与客户端(Client/IDE)之间通信 的标准化协议。它定义了客户端如何启动、管理和与 AI 代理交互的完整生命周期,类似于 LSP (Language Server Protocol) 的设计理念,但专门面向 AI 代理场景。

1.1 核心设计理念

  • 进程隔离:Agent 以独立子进程方式运行,通过 stdin/stdout 与客户端通信
  • 协议版本化:每次连接通过 initialize 握手交换 protocolVersion
  • 能力协商:客户端和代理通过初始化阶段声明各自支持的能力
  • 会话管理:支持创建、加载、恢复、列举会话
  • 双向通信:代理可以向客户端发起请求(如文件读写、终端操作、权限请求)

1.2 传输层

属性 描述
传输方式 子进程的 stdin(写入)/ stdout(读取)
序列化格式 ND-JSON(Newline Delimited JSON)
流适配 Node.js Stream → Web Streams API (ReadableStream / WritableStream)
SDK 入口 ndJsonStream(writable, readable) 创建双向流

2. 连接生命周期

2.1 Agent 进程启动

Client                                          Agent Process
  |                                                  |
  |--- spawn(command, args, {stdio: pipe}) --------->|
  |                                                  |
  |<========= stdin/stdout pipe established ========>|

Agent 配置结构:

interface AgentConfigEntry {
  command: string;       // 启动命令,如 "npx"
  args?: string[];       // 命令行参数
  env?: Record<string, string>;  // 环境变量
  displayName?: string;  // 显示名称
}

2.2 初始化握手(Initialize)

连接建立后,客户端必须发送 initialize 请求:

请求方向:Client → Agent

// 客户端发送的初始化参数
{
  protocolVersion: PROTOCOL_VERSION,   // 协议版本号
  clientInfo: {
    name: 'vscode-acp-client',         // 客户端名称
    version: '0.2.0',                  // 客户端版本
  },
  clientCapabilities: {
    fs: {
      readTextFile: true,              // 支持文件读取
      writeTextFile: true,             // 支持文件写入
    },
    terminal: true,                    // 支持终端操作
  },
}

响应结构 (InitializeResponse):

interface InitializeResponse {
  agentInfo?: {
    name: string;         // Agent 名称
    title?: string;       // Agent 显示标题
    version?: string;     // Agent 版本
  };
  agentCapabilities?: AgentCapabilities;  // Agent 能力声明
  authMethods?: AuthMethod[];              // 支持的认证方式
}

interface AgentCapabilities {
  sessionCapabilities?: {
    list?: boolean;    // 是否支持 session/list
    resume?: boolean;  // 是否支持 session/resume
  };
  loadSession?: boolean;  // 是否支持 session/load
}

interface AuthMethod {
  id: string;           // 认证方式 ID
  name: string;         // 认证方式名称
  description?: string; // 认证方式描述
}

2.3 认证流程(Authentication)

当 Agent 需要认证时(错误码 -32000),客户端启动认证流程:

Client                                Agent
  |                                     |
  |-- newSession() ------------------->|
  |<-- Error: auth required (-32000) --|
  |                                     |
  |-- authenticate({methodId}) ------->|
  |<-- success ------------------------|
  |                                     |
  |-- newSession() (retry) ----------->|
  |<-- NewSessionResponse -------------|

认证请求:

{ methodId: string }  // 用户选择的认证方式 ID

3. 会话管理(Session Management)

3.1 创建新会话(session/new)

请求方向:Client → Agent

// 请求参数
interface NewSessionRequest {
  cwd: string;              // 工作目录路径
  mcpServers: any[];        // MCP 服务器列表(当前为空数组)
}

// 响应
interface NewSessionResponse {
  sessionId: string;                       // 会话唯一标识
  modes?: SessionModeState;                // 可用模式(legacy)
  models?: SessionModelState;              // 可用模型(experimental)
  configOptions?: SessionConfigOption[];   // 通用配置选项(新版,优先级高于 modes/models)
}

3.2 列举会话(session/list)

前提:Agent 在初始化时声明 sessionCapabilities.list = true

// 请求参数
interface ListSessionsRequest {
  cwd?: string;      // 按工作目录过滤
  cursor?: string;   // 分页游标
}

// 响应
interface ListSessionsResponse {
  sessions: SessionInfo[];   // 会话列表
  nextCursor?: string;       // 下一页游标(分页)
}

interface SessionInfo {
  sessionId: string;
  title?: string;
  createdAt?: string;
  updatedAt?: string;
}

3.3 加载会话(session/load)

前提:Agent 声明 loadSession = true

重量级操作,完整重放会话历史:

// 请求参数
interface LoadSessionRequest {
  sessionId: string;
  cwd: string;
  mcpServers: any[];
}

// 响应(同 NewSessionResponse)
interface LoadSessionResponse {
  modes?: SessionModeState;
  models?: SessionModelState;
  configOptions?: SessionConfigOption[];
}

加载过程中 Agent 会通过 session/update 通知回放所有历史消息。

3.4 恢复会话(session/resume)

前提:Agent 声明 sessionCapabilities.resume = true

轻量级操作,不回放历史:

// 请求参数
interface ResumeSessionRequest {
  sessionId: string;
  cwd: string;
  mcpServers: any[];
}

// 响应
interface ResumeSessionResponse {
  modes?: SessionModeState;
  models?: SessionModelState;
  configOptions?: SessionConfigOption[];
}

4. 对话交互(Prompt/Response)

4.1 发送提示(prompt)

请求方向:Client → Agent

// 请求参数
interface PromptRequest {
  sessionId: string;
  prompt: ContentBlock[];    // 内容块数组
}

interface ContentBlock {
  type: 'text';              // 内容类型
  text: string;              // 文本内容
}

// 响应
interface PromptResponse {
  stopReason: string;   // 停止原因:"end_turn" | "error" | "cancelled" 等
  usage?: {             // Token 用量统计(可选)
    // 具体字段取决于 Agent 实现
  };
}

4.2 取消当前轮次(cancel)

请求方向:Client → Agent

interface CancelRequest {
  sessionId: string;
}

5. 会话实时通知(Session Notifications)

Agent 通过 session/update 向客户端推送实时状态更新。这是 ACP 协议中最丰富的通知机制。

通知方向:Agent → Client

interface SessionNotification {
  sessionId: string;
  update: SessionUpdate;  // 更新内容(以下各种类型之一)
}

5.1 消息流(Streaming)

agent_message_chunk — Agent 文本流式输出

{
  sessionUpdate: 'agent_message_chunk',
  content: {
    type: 'text',
    text: string     // 增量文本片段
  }
}

user_message_chunk — 用户消息回放(仅 session/load 使用)

{
  sessionUpdate: 'user_message_chunk',
  content: {
    type: 'text',
    text: string
  }
}

agent_thought_chunk — Agent 思维过程流式输出

{
  sessionUpdate: 'agent_thought_chunk',
  content: {
    type: 'text',
    text: string     // 思考过程增量文本
  }
}

5.2 工具调用(Tool Calls)

tool_call — 新工具调用

{
  sessionUpdate: 'tool_call',
  toolCallId: string,        // 工具调用唯一ID
  title: string,             // 工具调用标题/描述
  status: 'pending' | 'running' | 'completed' | 'failed'
}

tool_call_update — 工具调用状态更新

{
  sessionUpdate: 'tool_call_update',
  toolCallId: string,        // 对应的工具调用ID
  status: 'pending' | 'running' | 'completed' | 'failed',
  title?: string             // 可选的标题更新
}

5.3 计划(Plan)

plan — Agent 执行计划

{
  sessionUpdate: 'plan',
  entries: PlanEntry[]
}

interface PlanEntry {
  title?: string;
  description?: string;
  content?: string;
  status: 'pending' | 'in_progress' | 'completed'
}

5.4 会话配置更新

current_mode_update — 模式变更通知

{
  sessionUpdate: 'current_mode_update',
  currentModeId: string     // 新的当前模式 ID
}

config_option_update — 配置选项全量更新

{
  sessionUpdate: 'config_option_update',
  configOptions: SessionConfigOption[]   // 完整的配置选项数组
}

available_commands_update — 可用命令更新

{
  sessionUpdate: 'available_commands_update',
  availableCommands: AvailableCommand[]
}

interface AvailableCommand {
  name: string;              // 命令名(用于 /slash 命令)
  description: string;       // 命令描述
  input?: {
    hint?: string;           // 输入提示文字
  };
}

session_info_update — 会话元信息更新

{
  sessionUpdate: 'session_info_update',
  title?: string | null,     // 会话标题(null 表示清除)
  updatedAt?: string | null  // 最后更新时间(ISO 格式)
}

6. Agent → Client 请求(反向调用)

Agent 可以向客户端发起以下请求,由客户端实现 Client 接口来处理。

6.1 文件系统操作

readTextFile — 读取文本文件

// 请求
interface ReadTextFileRequest {
  path: string;        // 文件绝对路径
  line?: number;       // 起始行号(1-based)
  limit?: number;      // 读取行数限制
}

// 响应
interface ReadTextFileResponse {
  content: string;     // 文件内容
}

实现特性:

  • 优先读取编辑器中未保存的内容(dirty buffer)
  • 支持行范围读取(line + limit)

writeTextFile — 写入文本文件

// 请求
interface WriteTextFileRequest {
  path: string;        // 文件绝对路径
  content: string;     // 要写入的内容
}

// 响应
interface WriteTextFileResponse {}  // 空响应表示成功

实现特性:

  • 自动创建父目录
  • 写入后在编辑器中打开文件

6.2 终端操作

createTerminal — 创建终端

// 请求
interface CreateTerminalRequest {
  command: string;             // 要执行的命令
  args?: string[];             // 命令参数
  cwd?: string;               // 工作目录
  env?: EnvVar[];              // 环境变量列表
  outputByteLimit?: number;    // 输出缓冲区大小限制(默认 1MB)
}

interface EnvVar {
  name: string;
  value: string;
}

// 响应
interface CreateTerminalResponse {
  terminalId: string;          // 终端唯一标识
}

terminalOutput — 获取终端输出

// 请求
interface TerminalOutputRequest {
  terminalId: string;
}

// 响应
interface TerminalOutputResponse {
  output: string;              // 累积的输出内容
  truncated: boolean;          // 是否因超出限制被截断
  exitStatus?: {               // 进程已退出时提供
    exitCode: number | null;
    signal: string | null;
  };
}

waitForTerminalExit — 等待终端退出

// 请求
interface WaitForTerminalExitRequest {
  terminalId: string;
}

// 响应
interface WaitForTerminalExitResponse {
  exitCode: number | null;
  signal: string | null;
}

killTerminal — 终止终端

// 请求
interface KillTerminalRequest {
  terminalId: string;
}

// 响应
interface KillTerminalResponse {}  // 空响应

releaseTerminal — 释放终端资源

// 请求
interface ReleaseTerminalRequest {
  terminalId: string;
}

// 响应
interface ReleaseTerminalResponse {}  // 空响应

实现特性:

  • 如果进程仍在运行,先发送 SIGTERM
  • VS Code 终端保持可见(不自动关闭),符合 ACP 规范

6.3 权限请求

requestPermission — 请求用户授权

// 请求
interface RequestPermissionRequest {
  toolCall?: {
    title?: string;            // 权限请求标题
  };
  options: PermissionOption[]; // Agent 提供的选项列表
}

interface PermissionOption {
  optionId: string;            // 选项唯一 ID
  name: string;                // 选项显示名称
  kind: 'allow_once' | 'allow_always' | 'deny' | string;  // 选项类型
}

// 响应
interface RequestPermissionResponse {
  outcome: {
    outcome: 'selected' | 'cancelled';
    optionId?: string;         // 用户选择的选项 ID
  };
}

7. 会话配置系统

7.1 Session Mode(模式 — Legacy)

interface SessionModeState {
  currentModeId: string;
  availableModes: SessionMode[];
}

interface SessionMode {
  id: string;
  name: string;
  description?: string;
}

设置模式:Client → Agent

// setSessionMode 请求
{ sessionId: string; modeId: string; }

7.2 Session Model(模型 — Experimental)

interface SessionModelState {
  currentModelId: string;
  availableModels: SessionModel[];
}

interface SessionModel {
  modelId: string;
  name: string;
  description?: string;
}

设置模型:Client → Agent(unstable API)

// unstable_setSessionModel 请求
{ sessionId: string; modelId: string; }

7.3 Session Config Options(通用配置选项 — 推荐)

这是取代 modes/models 的新统一 API。当 Agent 同时提供 configOptions 和 modes 时,客户端必须仅使用 configOptions。

interface SessionConfigOption {
  id: string;                              // 配置项唯一 ID
  type: 'select';                          // 配置类型(目前仅支持 select)
  name: string;                            // 配置项名称
  description?: string;                    // 配置项描述
  category: 'mode' | 'model' | 'thought_level' | string;  // 分类
  currentValue: string;                    // 当前值
  options: SelectOption[] | GroupedOptions[];  // 可选值列表
}

interface SelectOption {
  value: string;
  name: string;
  description?: string;
}

interface GroupedOptions {
  group: string;
  name?: string;
  options: SelectOption[];
}

设置配置选项:Client → Agent

// setSessionConfigOption 请求
{
  sessionId: string;
  configId: string;
  value: string;
}

// 响应 — 包含更新后的完整 configOptions(级联更新)
{
  configOptions: SessionConfigOption[];
}

8. 协议错误码

错误码 含义 触发场景
-32000 需要认证 (Auth Required) newSession / listSessions 调用时 Agent 需要认证

错误通过 RequestError 类传递:

class RequestError extends Error {
  code: number;
  message: string;
}

9. 完整交互流程示例

┌─────────┐                                    ┌─────────┐
│  Client │                                    │  Agent  │
└────┬────┘                                    └────┬────┘
     │                                              │
     │──── spawn process (stdin/stdout pipe) ──────>│
     │                                              │
     │──── initialize ─────────────────────────────>│
     │<─── InitializeResponse (agentInfo, caps) ────│
     │                                              │
     │──── newSession({cwd, mcpServers}) ──────────>│
     │<─── NewSessionResponse {sessionId, modes} ───│
     │                                              │
     │<─── session/update: available_commands ───────│
     │<─── session/update: config_option_update ────│
     │                                              │
     │──── prompt({sessionId, prompt}) ────────────>│
     │                                              │
     │<─── session/update: agent_thought_chunk ─────│ (思考过程)
     │<─── session/update: agent_thought_chunk ─────│
     │                                              │
     │<─── session/update: tool_call ───────────────│ (工具调用)
     │                                              │
     │<─── requestPermission ───────────────────────│ (请求权限)
     │──── {outcome: 'selected', optionId} ────────>│
     │                                              │
     │<─── readTextFile({path}) ────────────────────│ (读取文件)
     │──── {content} ──────────────────────────────>│
     │                                              │
     │<─── writeTextFile({path, content}) ──────────│ (写入文件)
     │──── {} ─────────────────────────────────────>│
     │                                              │
     │<─── createTerminal({command, args}) ─────────│ (创建终端)
     │──── {terminalId} ───────────────────────────>│
     │                                              │
     │<─── waitForTerminalExit({terminalId}) ───────│
     │──── {exitCode} ────────────────────────────>│
     │                                              │
     │<─── session/update: tool_call_update ────────│ (工具完成)
     │<─── session/update: agent_message_chunk ─────│ (回复内容)
     │<─── session/update: agent_message_chunk ─────│
     │                                              │
     │<─── PromptResponse {stopReason: 'end_turn'}──│
     │                                              │
     │<─── session/update: session_info_update ─────│ (标题更新)
     │                                              │
     │──── cancel({sessionId}) ────────────────────>│ (可选:取消)
     │                                              │
     │──── [kill process] ─────────────────────────>│ (断开连接)
     │                                              │

10. Agent 注册表

ACP 提供了公共的 Agent 注册表服务:

  • 注册表地址:https://cdn.agentclientprotocol.com/registry/v1/latest/registry.json
  • 缓存策略:客户端缓存 5 分钟

注册表数据结构:

interface Registry {
  agents: RegistryAgent[];
}

interface RegistryAgent {
  name: string;
  description?: string;
  command: string;
  args?: string[];
  homepage?: string;
}

11. 已知兼容的 ACP Agent

Agent 名称 命令 参数
GitHub Copilot npx @github/copilot-language-server@latest --acp
Claude Code npx @agentclientprotocol/claude-agent-acp@latest
Gemini CLI npx @google/gemini-cli@latest --experimental-acp
Qwen Code npx @qwen-code/qwen-code@latest --acp --experimental-skills
Auggie CLI npx @augmentcode/auggie@latest --acp
Qoder CLI npx @qoder-ai/qodercli@latest --acp
Codex CLI npx @zed-industries/codex-acp@latest
OpenCode npx opencode-ai@latest acp
OpenClaw npx openclaw acp
Kiro CLI kiro-cli acp
Hermes Agent hermes acp

12. 客户端能力声明(Client Capabilities)

客户端在 initialize 时声明支持的能力:

interface ClientCapabilities {
  fs?: {
    readTextFile?: boolean;   // 支持 Agent 读取文件
    writeTextFile?: boolean;  // 支持 Agent 写入文件
  };
  terminal?: boolean;          // 支持 Agent 操作终端
}

Agent 据此判断可以向客户端发起哪些反向请求。


13. 协议设计特点总结

  1. 基于 JSON-RPC 风格:请求-响应模式 + 通知模式
  2. ND-JSON 传输:轻量级,易于解析和调试
  3. 流式输出:通过 *_chunk 通知实现实时流式展示
  4. 双向通信:Agent 既接收指令,也可主动向客户端发起操作请求
  5. 能力协商:初始化时双方声明能力,避免调用不支持的功能
  6. 认证集成:支持多种认证方式,认证失败后自动重试
  7. 会话持久化:支持会话的创建、列举、加载(回放历史)和轻量恢复
  8. 配置灵活性:从 legacy modes/models 到统一的 configOptions,平滑演进
  9. 权限控制:Agent 操作需要用户授权,支持自动批准策略
  10. 版本化设计:通过 protocolVersion 确保客户端和代理的兼容性

14. 附录:消息流方向汇总

方法 方向 类型 说明
initialize Client → Agent Request 协议握手
authenticate Client → Agent Request 认证
newSession Client → Agent Request 创建会话
listSessions Client → Agent Request 列举会话
loadSession Client → Agent Request 加载会话(重放历史)
resumeSession Client → Agent Request 恢复会话(无重放)
prompt Client → Agent Request 发送提示
cancel Client → Agent Request 取消当前轮次
setSessionMode Client → Agent Request 设置模式
setSessionConfigOption Client → Agent Request 设置配置选项
unstable_setSessionModel Client → Agent Request 设置模型
session/update Agent → Client Notification 会话状态推送
readTextFile Agent → Client Request 读取文件
writeTextFile Agent → Client Request 写入文件
createTerminal Agent → Client Request 创建终端
terminalOutput Agent → Client Request 获取终端输出
waitForTerminalExit Agent → Client Request 等待终端退出
killTerminal Agent → Client Request 终止终端
releaseTerminal Agent → Client Request 释放终端
requestPermission Agent → Client Request 请求用户授权