这是什么
ACP(Agent Client Protocol)是一种标准化的 stdio 协议:编辑器 / IDE 作为客户端,
通过进程的 stdin / stdout 收发 NDJSON 消息来驱动一个 AI agent。
千手大师实现了完整的 agent 端,因此任何支持 ACP 的客户端(Zed、Cursor 等)都能直接调用它。
入口是一条快速路径:当首个参数为 --acp 时,CLI 跳过完整 REPL 启动流程,
直接加载 runAcpAgent()。读取端把 Node 流包成 ACP 的 Stream,
再用 AgentSideConnection 驱动 AcpAgent 实现。
| 文件 | 职责 |
|---|---|
src/services/acp/entry.ts |
入口:创建 stdio → NDJSON 流,启动 AgentSideConnection;把 console 重定向到 stderr |
src/services/acp/agent.ts |
Barrel,装配 AcpAgent 类(拆分为 agent/ 子模块) |
src/services/acp/bridge.ts |
把内部 SDKMessage 转换为 ACP SessionUpdate(文本 / 思考 / 工具 / 用量 / 编辑 diff) |
src/services/acp/permissions.ts |
权限桥接:ACP requestPermission() ↔ 内部 CanUseToolFn |
src/services/acp/utils.ts |
Pushable / 流转换 / 权限模式解析 / session fingerprint / 路径显示 |
AcpAgent 的角色是 ACP Agent 接口的实现体,负责会话 CRUD
(新建 / 恢复 / 加载 / 分叉 / 关闭 / 列出)、发送 prompt、取消、以及运行时切换权限模式与模型。
它在会话内部复用千手大师的 QueryEngine 完成真正的对话执行。
ACP 由 feature flag ACP 控制(build 与 dev 模式默认启用)。
该 flag 未启用时,--acp 快速路径不会生效。
前置条件
- 已在 Zed、Cursor 或自建 ACP 客户端中配置好以子进程方式启动
qsdashi --acp的能力。 - 已通过
/login配置好 API 供应商,或准备了QS_BASE_URL/QS_AUTH_TOKEN等凭证。 - 运行 ACP agent 的机器上已安装千手大师(
qsdashi,英文命令别名qs-master)。 - 使用
acp-link远程接入时,需能运行仓库内packages/acp-link或已安装其acp-link可执行文件。
ACP agent 启动时会调用 applySafeConfigEnvironmentVariables(),
自动把 settings.json 中的环境变量(QS_BASE_URL、QS_AUTH_TOKEN、模型覆盖等)
注入 process.env。这一点很关键:由 Zed 拉起的进程默认拿不到这些变量。
安装与启用
1直接以 ACP 模式启动
标准输入输出即协议通道,不要在其中混入其他输出。
qsdashi --acp
2在 Zed 中注册为 Agent Server
编辑 Zed 的 settings.json(Cmd+, → Open Settings)。
{
"agent_servers": {
"qsdashi": {
"type": "custom",
"command": "qsdashi",
"args": ["--acp"]
}
}
}
3可选:用 acp-link 提供 WebSocket 入口
让远程 / 浏览器客户端也能接入同一个 ACP agent。
# 源码目录内运行(monorepo)
bun packages/acp-link/src/cli/bin.ts qsdashi -- --acp
# 或使用安装后的 acp-link 可执行文件,指定端口与主机
acp-link --port 9000 --host 0.0.0.0 qsdashi -- --acp
--
acp-link 之后的第一个位置参数是要启动的 agent 命令,再往后的参数需用
-- 分隔才能传给 agent 本身。例如
acp-link qsdashi -- --acp。
配置
acp-link 命令行参数
| 参数 | 默认值 | 说明 |
|---|---|---|
--port |
9315 |
监听端口 |
--host |
localhost |
绑定主机;远程访问用 0.0.0.0 |
--debug |
关闭 | 开启调试日志并写入文件 |
--no-auth |
关闭 | 关闭认证(危险,仅开发用) |
--https |
关闭 | 使用自动生成的自签名证书启用 HTTPS |
--manager |
关闭 | 仅启动管理 Web UI,不启动代理;浏览器访问 http://localhost:<port> |
--group |
无 | RCS 注册用的频道组 ID(仅字母、数字、连字符、下划线) |
环境变量
| 变量 | 作用域 | 说明 |
|---|---|---|
ACP_AUTH_TOKEN |
acp-link | 固定认证 token;未设置时启动会随机生成 |
ACP_PERMISSION_MODE |
acp-link / agent | 默认权限模式的兜底来源 |
ACP_RCS_URL |
acp-link | RCS 服务器地址,设置后启用 RCS 集成 |
ACP_RCS_TOKEN |
acp-link | RCS API token |
ACP_RCS_GROUP |
acp-link | RCS 频道组 ID;--group 优先于该变量 |
权限模式与 fallback 链
支持的权限模式:default、auto、acceptEdits、plan、dontAsk、bypassPermissions。当客户端未显式传入 permissionMode 时,按以下顺序兜底:
# 客户端传值 > config.permissionMode > ACP_PERMISSION_MODE 环境变量
ACP_PERMISSION_MODE=auto acp-link qsdashi -- --acp
在 acp-link 层,客户端要请求 bypassPermissions,必须先令
ACP_PERMISSION_MODE=bypassPermissions,否则会报
bypassPermissions requires local ACP_PERMISSION_MODE=bypassPermissions。
在 agent 层,该模式还会做可用性检测,仅在非 root 或 sandbox 环境中启用。
认证传递
默认连接端点为 ws://localhost:9315/ws,token 不放在 URL 中。
无法发送 Authorization 头的 WebSocket 客户端,需通过
rcs.auth.<base64url-token> 子协议传递 token。
常用命令与参数
| 命令 | 行为 |
|---|---|
qsdashi --acp |
以 ACP agent 模式启动,stdin/stdout 走 NDJSON |
acp-link qsdashi -- --acp |
启动 WebSocket → stdio 代理(默认 localhost:9315) |
acp-link --https qsdashi -- --acp |
启用自签名 HTTPS |
acp-link --manager |
仅启动 Manager Web UI,可创建 / 停止 / 删除多个 acp-link 实例并查看日志 |
ACP 协议方法支持
| 方法 | 说明 |
|---|---|
initialize | 返回 agent 信息与能力 |
authenticate | 自托管场景无需认证 |
newSession / resumeSession / loadSession | 新建 / 恢复 / 加载会话,后两者含历史回放 |
listSessions / forkSession / closeSession | 列出 / 分叉 / 关闭会话 |
prompt / cancel | 发送消息(支持排队)与取消 |
setSessionMode / setSessionModel / setSessionConfigOption | 运行时切换权限模式 / 模型 / 配置 |
SessionUpdate 类型(节选):agent_message_chunk、agent_thought_chunk、user_message_chunk(历史回放)、tool_call、tool_call_update、usage_update、plan、available_commands_update、current_mode_update、config_option_update。
实战示例
带环境变量在 Zed 中启动(进程由 Zed 拉起、拿不到 shell 环境时):
{
"agent_servers": {
"qsdashi": {
"command": "qsdashi",
"args": ["--acp"],
"env": {
"QS_BASE_URL": "https://api.example.com/v1",
"QS_AUTH_TOKEN": "sk-xxx"
}
}
}
}
接入 RCS,通过 Web UI 远程操控:
ACP_RCS_URL=http://localhost:3000 \
ACP_RCS_TOKEN=sk-rcs-your-key \
acp-link qsdashi -- --acp
注册分两步:先通过 REST POST /v1/environments/bridge 向 RCS 注册环境并拿到
agentId,再建立 WebSocket 后发送 identify 消息(携带
agentId)完成标识。RCS 的 ACP WebSocket 不接受 URL query token,
acp-link 会用 rcs.auth.<base64url-token> 子协议发送
ACP_RCS_TOKEN。
Plan 可视化:当会话使用 TodoWrite 时,bridge 会把待办映射为 ACP 的
session/update 中 sessionUpdate: "plan" 消息,
每个条目带 content、归一化后的 status 与 priority。
支持 ACP Plan 视图的客户端会直接渲染为带进度与状态图标的清单。
自建 ACP 客户端(用 @agentclientprotocol/sdk):
import { ClientSideConnection, ndJsonStream } from '@agentclientprotocol/sdk'
// 将 qsdashi --acp 作为子进程启动,接通 stdio
const child = spawn('qsdashi', ['--acp'])
const stream = ndJsonStream(
Writable.toWeb(child.stdin),
Readable.toWeb(child.stdout),
)
const client = new ClientSideConnection(stream)
await client.initialize({ clientCapabilities: {} })
const { sessionId } = await client.newSession({ cwd: '/path/to/project' })
await client.prompt({
sessionId,
prompt: [{ type: 'text', text: '解释一下这个项目' }],
})
常见问题排错
由 IDE 拉起的进程默认没有 shell 里的环境变量。ACP 启动时会读取
settings.json 中的环境变量,因此先确保已通过 /login 配置;
或在 agent_servers 的 env 中显式传入
QS_BASE_URL / QS_AUTH_TOKEN。
token 不能放在 URL 中。能发 header 的客户端请用 Authorization;
否则通过 rcs.auth.<base64url-token> 子协议传递。绑定远程地址时记得
--host 0.0.0.0,并优先用 ACP_AUTH_TOKEN 固定 token 而非
--no-auth。
这属于安全设计。acp-link 侧需要 ACP_PERMISSION_MODE=bypassPermissions;
agent 侧还需要非 root 或 sandbox 环境。两个条件缺一不可。
ACP 用 stdout 传协议消息。agent 启动时已把 console.log/info/warn/debug
重定向到 stderr;自定义代码也不要往 stdout 打印。否则 NDJSON 流会被破坏。
默认端口为 9315。被占用时用 --port 指定其他端口即可。