如何让T3 Code连接AI智能体:ACP协议对接与effect-acp包完整解析
【免费下载链接】t3code项目地址: https://gitcode.com/GitHub_Trending/t3/t3code
T3 Code 通过Agent Client Protocol(ACP,智能体客户端协议)与各类 AI 编码智能体对接,核心实现就藏在 packages/effect-acp/ 这个effect-acp包里。本文带你读懂 ACP 是什么、effect-acp 如何基于 Effect 框架设计双向通信,以及它如何从上游 JSON Schema 一键生成 TypeScript 类型——一篇看懂这套"协议对接 + 代码生成"的完整机制。
一、先搞懂 ACP:AI 智能体与客户端之间的"通用插口"
ACP(Agent Client Protocol)是一个开放的通信标准:AI 智能体(Agent)和编码客户端(Client)通过JSON-RPC 消息走标准输入/输出(stdio)管道对话。双方各守一方:
- Agent 端(如 Cursor Agent、Grok 等命令行智能体)负责思考与执行,可主动向客户端发起请求:申请权限、读写文件、创建终端、推送会话更新;
- Client 端(如 T3 Code 的服务端运行时)负责管理会话生命周期:初始化、新建/加载/分叉/恢复会话、切换模型与配置。
上图:T3 Code 界面中,AI 编码智能体正在执行工具调用并汇报进度——这些交互在底层都由 ACP 消息驱动
没有 ACP 这类协议,每接一个智能体就要写一套私有适配层;有了它,客户端只需要实现一次协议,就能"即插即用"所有遵循 ACP 的智能体。
二、effect-acp 包在 T3 Code 中的定位
在 T3 Code 的 monorepo 中,docs/internals/workspace-layout.md 对它的定位非常明确:packages/effect-acp是基于 Effect 框架的 ACP 客户端与智能体实现,专门供"会说 ACP 的供应商驱动"使用。
该包通过 package.json 暴露 7 个细分入口,职责清晰分层:
| 入口 | 职责 |
|---|---|
./client | 客户端角色:调用 Agent 的会话方法 |
./agent | 智能体角色:调用 Client 的权限/文件/终端方法 |
./protocol | 底层协议层:stdio 上的双向 RPC 通道 |
./schema | 生成的全部消息 Schema |
./rpc、./terminal、./errors | RPC 封装、终端流、结构化错误 |
这种"客户端/智能体双视角"的设计意味着同一个包既能驱动外部智能体(T3 Code 的用法),也能把 T3 Code 自身暴露成 ACP 服务端。
三、生成原理:从上游 Schema 到 TypeScript 的一键管线
这是 effect-acp 最巧妙的部分。ACP 的消息格式由上游以 JSON Schema 形式发布,effect-acp 不手写任何消息类型,而是用一条生成管线同步过来。整个入口是 scripts/generate.ts,流程分 5 步:
- 版本钉住(Pin):脚本顶部声明
CURRENT_SCHEMA_RELEASE = "v0.11.3",生成过程只会拉取该固定版本发布的schema.unstable.json与meta.unstable.json,保证类型定义可复现; - Schema 归一化:
normalizeNullableTypes函数递归遍历 Schema,把"type": ["string", "null"]这类联合类型改写成anyOf结构,让下游生成器产出更地道的可空类型; - 调用 Effect 官方生成器:使用
@effect/openapi-generator的JsonSchemaGenerator,把每个$defs条目按字母序逐个转成Schema.Struct定义; - 落盘两个生成文件(位于 src/_generated/):
- schema.gen.ts:上万行的全量消息类型,每个类型同时导出 TS 接口和 Effect Schema 双份定义,兼顾编译期类型与运行时校验;
- meta.gen.ts:导出
AGENT_METHODS、CLIENT_METHODS两个方法名常量表和PROTOCOL_VERSION,如session_prompt: "session/prompt"、fs_read_text_file: "fs/read_text_file"——运行时所有方法名都引用常量而非裸字符串;
- 自动格式化:生成完毕直接调用
oxfmt格式化目录,失败则整体报错。
文件头会写入// This file is generated by the effect-acp package. Do not edit manually.与当前 ACP 版本号,防止误改。升级 ACP 协议 = 改一行版本号 + 重新运行生成,这就是它"生成原理"的核心。
上图:T3 Code 的会话与差异视图——这些状态同步依赖 ACP 的 session/update 通知机制
四、协议层设计:在 stdio 上跑双向 RPC
真正的通信逻辑集中在 src/protocol.ts,它基于 Effect 实验性 RPC 模块(RpcClient/RpcServer)+ND-JSON 序列化器(每行一条 JSON)构建。设计上有三个值得注意的点:
- 五路队列分流:入站消息按类型分流——标准 Agent 方法请求进
serverQueue交给 RPC 服务端处理;session/update、session/elicitation/complete等通知经 Schema 校验后汇入notificationQueue;未识别的扩展方法走onExtRequest回调。出站则统一汇入outgoing队列写入 stdout; - 扩展请求的 Deferred 挂起机制:Agent/Client 都可以发起协议未定义的"扩展请求"。发送时分配自增请求 ID 并挂一个
Deferred(Effect 的一次性承诺),响应到达时按 ID 匹配完成它——相当于在 RPC 之上自己实现了 Promise 语义; - 结构化错误与可观测日志:所有失败都收敛为 errors.ts 中的
AcpError(解析错误、传输错误、流意外结束等),并支持按"原始/解码后/解码失败"三阶段记录协议日志,方便排查线上问题。
在此之上,src/agent.ts 和 src/client.ts 把裸通道包装成带文档的服务:AcpAgent暴露requestPermission、readTextFile、createTerminal、sessionUpdate等方法,AcpClient暴露initialize、createSession、forkSession、setSessionModel等——调用方拿到的全是类型安全、文档注释齐全的 Effect 函数,完全感知不到底层 JSON-RPC 的存在。
五、实战:T3 Code 如何用它接入 Cursor 与 Grok
在 apps/server/src/provider/acp/ 下,每个 ACP 供应商一个适配器。以 CursorAcpSupport.ts 为例,接线步骤只有三步:
- 构造 spawn 参数——命令
cursor-agent acp(可用设置里的binaryPath覆盖),由 T3 Code 进程直接拉起智能体子进程; - 通过 AcpSessionRuntime.ts 建立 effect-acp 客户端层,传入认证方式与客户端能力声明;
- 初始化协商能力后即可调用
session/prompt发消息、订阅session/update流——你在界面上看到的进度与差异视图,全部来自这条消息流。
Grok(X AI)供应商同样复用这套运行时,仅扩展点不同,可见协议抽象确实做到了"换智能体不换协议"。
六、快速上手:本地重新生成 ACP Schema
想跟进 ACP 上游新版本?只需两步(以 pnpm workspace 为例):
- 修改 scripts/generate.ts 中的
CURRENT_SCHEMA_RELEASE为新版本号; - 运行包的
generate脚本(等价于node scripts/generate.ts,详见 package.json 的scripts.generate)。
生成器会重新下载对应版本的 schema/meta 资产、重写src/_generated/下两个文件并完成格式化。全程无需手写一行消息类型。
小结
effect-acp 包展示了现代 AI 编码工具链对接智能体的标准姿势:
- 协议即契约:用 ACP 统一 Agent 与 Client 的通信,stdio + JSON-RPC,任何语言可实现;
- 类型即生成:Schema 版本钉住 + 生成器管线,协议升级零手写、可复现;
- 框架即保障:基于 Effect 的队列、Deferred 与 Scope,让双向通信的错误处理与资源回收天然可控。
读懂这套设计,你基本就能看懂 T3 Code 如何"即插即用"接入任意 ACP 智能体了。
【免费下载链接】t3code项目地址: https://gitcode.com/GitHub_Trending/t3/t3code
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考