Skip to content

AgnesCode ACP WebSocket 协议分析报告

协议端点: Renderer (React) ↔ agnesd (Rust Backend)
通信方式: WebSocket (JSON-RPC 2.0)
报告日期: 2026-07-25
分析版本: v1.0.17


1. 协议概述

ACP (Agent Client Protocol) 是 AgnesCode 的核心 AI 交互协议, 基于 JSON-RPC 2.0 标准, 运行于 WebSocket 之上。

┌─────────────────────────────────────────────────┐
│  Renderer (React)                               │
│  ┌───────────────────────────────────────────┐  │
│  │  $3 class (ACP Client)                    │  │
│  │  ├── initialize()     → 会话初始化         │  │
│  │  ├── newSession()     → 创建新会话         │  │
│  │  ├── prompt()         → 发送提示词(核心)   │  │
│  │  ├── cancel()         → 取消请求           │  │
│  │  └── setSessionMode() → 设置模式           │  │
│  └──────────────────┬────────────────────────┘  │
│                     │ WebSocket (JSON-RPC 2.0)   │
│  ┌──────────────────▼────────────────────────┐  │
│  │  Z3 class (Transport Layer)               │  │
│  │  ├── sendRequest()   → 请求+等待响应       │  │
│  │  └── sendNotification() → 通知(无响应)     │  │
│  └──────────────────┬────────────────────────┘  │
│                     │ Stream                    │
│  ┌──────────────────▼────────────────────────┐  │
│  │  x8() WebSocket Stream                    │  │
│  │  ├── ReadableStream (接收 JSON 消息)       │  │
│  │  └── WritableStream (发送 JSON 消息)        │  │
│  └───────────────────────────────────────────┘  │
└─────────────────────────────────────────────────┘

2. 连接建立

2.1 WebSocket URL

wss://127.0.0.1:{port}/acp?token={secretKey}

构造函数 (从 main.js 提取):

javascript
function Vj(baseUrl, token) {
    const r = new URL(baseUrl);
    r.pathname = `${r.pathname.replace(/\/+$/, "")}/acp`;
    r.protocol = r.protocol === "https:" ? "wss:" : "ws:";
    r.searchParams.set("token", token);
    return r.toString();
}

2.2 连接生命周期

1. Renderer 调用 window.electron.getAcpUrl() 获取 WS URL
2. 创建 WebSocket 连接
3. 发送 JSON-RPC 2.0 initialize 请求
4. 收到 initialize 响应, 连接就绪
5. 开始会话交互 (session/new → session/prompt)
6. 断开时自动重连

2.3 WebSocket Stream 实现

从 renderer 代码提取的底层实现:

javascript
function x8(url) {
    const t = new window.WebSocket(url);
    const o = [];  // 接收队列
    const a = [];  // 等待队列

    t.addEventListener("message", M => {
        if (typeof M.data == "string")
            o.push(JSON.parse(M.data));  // 解析 JSON
    });

    const readable = new ReadableStream({
        async pull(M) {
            await waitForData();
            while (o.length > 0) M.enqueue(o.shift());
            if (closed && o.length === 0) M.close();
        }
    });

    const writable = new WritableStream({
        async write(M) {
            await connectionReady;
            t.send(JSON.stringify(M));  // 序列化 JSON
        },
        close() { t.close(); },
        abort() { t.close(); }
    });

    return { stream: { readable, writable }, isAlive };
}

3. 消息格式 (JSON-RPC 2.0)

3.1 Request 消息

json
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "session/prompt",
    "params": { ... }
}

3.2 Response 消息

json
{
    "jsonrpc": "2.0",
    "id": 1,
    "result": { ... }
}

3.3 Error 消息

json
{
    "jsonrpc": "2.0",
    "id": 1,
    "error": {
        "code": -32601,
        "message": "Method not found: xxx",
        "data": { "method": "xxx" }
    }
}

3.4 Notification 消息 (无响应)

json
{
    "jsonrpc": "2.0",
    "method": "session/cancel",
    "params": { ... }
}

4. 标准 ACP 方法

4.1 方法清单

方法类型方向描述
initializeRequestC→S初始化连接, 协商能力
authenticateRequestC→S认证
logoutRequestC→S登出
session/newRequestC→S创建新会话
session/promptRequestC→S发送提示词 (核心方法)
session/cancelNotificationC→S取消当前请求
session/closeRequestC→S关闭会话
session/forkRequestC→S分叉会话
session/listRequestC→S列出会话
session/loadRequestC→S加载会话
session/resumeRequestC→S恢复会话
session/set_modeRequestC→S设置模式 (smart/expert)
session/set_modelRequestC→S设置模型
session/set_config_optionRequestC→S设置配置项
session/request_permissionRequestS→C请求权限
session/updateNotificationS→C会话更新推送
document/didChangeNotificationC→S文档变更
document/didCloseNotificationC→S文档关闭
document/didFocusNotificationC→S文档聚焦
document/didOpenNotificationC→S文档打开
document/didSaveNotificationC→S文档保存
nes/startRequestC→S启动 NES (Nested Expert System)
nes/suggestRequestC→S建议
nes/acceptNotificationC→S接受
nes/rejectNotificationC→S拒绝
nes/closeRequestC→S关闭 NES
terminal/createRequestC→S创建终端
terminal/killRequestC→S终止终端
terminal/outputRequestC→S终端输出
terminal/releaseRequestC→S释放终端
terminal/wait_for_exitRequestC→S等待终端退出
fs/read_text_fileRequestC→S读取文本文件
fs/write_text_fileRequestC→S写入文本文件
elicitation/createRequestC→S创建引导
elicitation/completeNotificationC→S引导完成

4.2 协议能力协商 (initialize)

Request:

json
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
        "protocolVersion": 1,
        "clientInfo": {
            "name": "AgnesCode",
            "version": "1.0.17"
        },
        "clientCapabilities": {
            "auth": { "terminal": false },
            "fs": { "readTextFile": false, "writeTextFile": false },
            "terminal": false,
            "audio": false,
            "embeddedContext": false,
            "image": false,
            "nes": null,
            "positionEncodings": [],
            "elicitation": { "form": {} },
            "_meta": {
                "agnes": {
                    "mcpHostCapabilities": {},
                    "customNotifications": true,
                    "recipeParameterRequests": true
                }
            }
        }
    }
}

Response:

json
{
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
        "protocolVersion": 1,
        "serverInfo": { "name": "agnesd", "version": "1.0.17" },
        "capabilities": {
            "experimental": {},
            "logging": {},
            "prompts": { "listChanged": true },
            "resources": { "listChanged": true, "subscribe": true },
            "tools": { "listChanged": true },
            "completions": {},
            "sampling": {},
            "fs": { "readTextFile": true, "writeTextFile": true },
            "terminal": true,
            "auth": { "terminal": false },
            "audio": false,
            "image": false,
            "embeddedContext": false,
            "nes": null
        }
    }
}

5. 核心方法: session/prompt

5.1 请求格式

json
{
    "jsonrpc": "2.0",
    "id": 3,
    "method": "session/prompt",
    "params": {
        "sessionId": "uuid-v4",
        "prompt": [
            {
                "role": "user",
                "content": [
                    { "type": "text", "text": "Hello, how are you?" }
                ],
                "id": "msg-uuid",
                "createdAt": 1234567890
            }
        ],
        "expectedRunId": "run-uuid"
    }
}

5.2 响应格式

json
{
    "jsonrpc": "2.0",
    "id": 3,
    "result": {
        "sessionId": "uuid-v4",
        "runId": "run-uuid",
        "messageId": "msg-uuid",
        "message": {
            "role": "assistant",
            "content": [
                { "type": "text", "text": "Hello! I'm doing well." }
            ]
        },
        "stopReason": "endTurn",
        "model": "agnes-2.5-flash",
        "usage": {
            "inputTokens": 15,
            "outputTokens": 10,
            "totalTokens": 25,
            "cacheReadTokens": 0,
            "cacheWriteTokens": 0,
            "cost": 0.0001,
            "costSource": "provider_reported",
            "elapsedMs": 1500,
            "timeToFirstTokenMs": 500,
            "isCompaction": false
        },
        "userMessageId": "user-msg-uuid"
    }
}

5.3 ContentBlock 类型

typescript
type ContentBlock =
    | { type: "text", text: string, annotations?: Annotations, _meta?: any }
    | { type: "image", data: string, mimeType: string, annotations?: Annotations, _meta?: any }
    | { type: "audio", data: string, mimeType: string, annotations?: Annotations, _meta?: any }
    | { type: "resource", resource: Resource, annotations?: Annotations, _meta?: any }
    | { type: "resource_link", resource: Resource, annotations?: Annotations, _meta?: any }
    | { type: "tool_use", name: string, id: string, input: any }
    | { type: "tool_result", toolUseId: string, content: ContentBlock[], isError?: boolean }

5.4 停止原因

typescript
type StopReason = "endTurn" | "stopSequence" | "maxTokens" | "toolUse";

6. 其他会话方法

6.1 session/new

json
{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "session/new",
    "params": {
        "sessionId": "uuid-v4",
        "cwd": "/Users/user/Documents/AgnesCode",
        "additionalDirectories": [],
        "title": "My Project",
        "updatedAt": "2026-07-25T12:00:00Z",
        "_meta": {}
    }
}

6.2 session/list

json
{
    "jsonrpc": "2.0",
    "id": 4,
    "result": {
        "sessions": [{
            "sessionId": "uuid-v4",
            "cwd": "/Users/user/project",
            "additionalDirectories": [],
            "title": "Project Analysis",
            "updatedAt": "2026-07-25T12:00:00Z",
            "_meta": {}
        }]
    }
}

6.3 session/set_mode

json
{
    "jsonrpc": "2.0",
    "id": 5,
    "method": "session/set_mode",
    "params": { "sessionId": "uuid-v4", "modeId": "smart" }
}

6.4 session/set_model

json
{
    "jsonrpc": "2.0",
    "id": 6,
    "method": "session/set_model",
    "params": { "sessionId": "uuid-v4", "modelId": "agnes-2.5-flash" }
}

7. 扩展方法 (110+)

所有扩展方法以 _agnes/unstable/ 为前缀, 分为以下子系统:

7.1 会话管理

  • session/info, session/export, session/import
  • session/history/load, session/extensions/*
  • session/system-prompt/set, session/working-dir/update
  • session/steer, session/archive, session/unarchive, session/rename
  • session/share/nostr, session/conversation/truncate
  • session/recipe/request-params, session/project/update

7.2 工具系统

  • tools/list, tools/call, tools/permissions/set
  • resources/read

7.3 提供商配置

  • providers/list, providers/config/*, providers/secrets/*
  • providers/catalog/*, providers/setup/catalog/*
  • providers/custom/*, providers/supported-models/list
  • providers/canonical-model-info, providers/inventory/refresh

7.4 配方系统

  • recipes/list, recipes/delete, recipes/encode, recipes/decode
  • recipes/parse, recipes/save, recipes/scan, recipes/schedule
  • recipes/slash-command, recipes/to-yaml

7.5 配置

  • config/read, config/read-all, config/upsert, config/remove
  • config/prompts/*, config/extensions/*

7.6 扩展

  • extensions/available

7.7 本地推理

  • local-inference/models/*, local-inference/huggingface/*
  • local-inference/chat-templates/builtin/list

7.8 听写

  • dictation/config, dictation/transcribe, dictation/models/*
  • dictation/secret/*

7.9 其他

  • side-chat/start, side-chat/cancel, side-chat/dispose
  • sources/*, apps/*, capabilities/list
  • diagnostics/get, defaults/*, preferences/*
  • onboarding/import/*, scheduled-tasks/*, schedules/*
  • agent-mentions/list, slash-commands/list

8. 错误码

代码名称描述
-32700Parse ErrorJSON 解析错误
-32600Invalid Request无效请求
-32601Method Not Found方法不存在
-32602Invalid Params无效参数
-32603Internal Error内部错误
-32000Auth Required需要认证
-32002Resource Not Found资源不存在
-32800URL Elicitation Required需要 URL 引导

9. 传输层实现

9.1 消息序列化

javascript
// 发送: JSON.stringify
// 接收: JSON.parse
// 使用 WebSocket 原生文本帧

9.2 请求-响应匹配

javascript
class Z3 {
    #pending = new Map();  // id → { resolve, reject }
    #nextId = 0;

    async sendRequest(method, params) {
        const id = this.#nextId++;
        const promise = new Promise((resolve, reject) => {
            this.#pending.set(id, { resolve, reject });
        });
        await this.#send({ jsonrpc: "2.0", id, method, params });
        return promise;
    }

    #handleResponse(message) {
        if (message.id !== undefined) {
            const handler = this.#pending.get(message.id);
            if (handler) {
                if ("result" in message) handler.resolve(message.result);
                else if ("error" in message) handler.reject(new Error(message.error.message));
            }
        }
    }
}

9.3 流式传输 (SSE)

ACP 支持通过 HTTP SSE (Server-Sent Events) 进行流式传输:

GET /acp
Accept: text/event-stream
Acp-Connection-Id: {connectionId}
GET /acp
Accept: text/event-stream
Acp-Connection-Id: {connectionId}
Acp-Session-Id: {sessionId}

基于 MIT 协议发布