@harmonyos-arkts/opencode-acp
v0.0.13
Published
Enhanced ACP (Agent Client Protocol) server for OpenCode with subagent visibility
Downloads
1,226
Readme
Harmony-ACP
OpenCode 的增强版 ACP(Agent Client Protocol)服务器。以独立进程运行,提供 OpenCode 内置 ACP 所缺少的 子代理可见性 和 全量流量日志。
为什么需要它
OpenCode 内置的 ACP 有两个关键限制:
- 子代理不可见:当代理通过 Task 工具派生子代理时,子 session 的事件——工具调用、文本输出、权限请求——对 ACP 客户端(如 Zed、VSCode)完全不可见。原因是内置的
SessionManager只注册顶层 session,来自子 session 的事件会被静默丢弃。 - 无法进行问题回答:当大模型有问题需要用户回答时,opencode acp没有监听,ACP客户端(如Zed/ VSCode)无法感知
Harmony-ACP 在不修改任何 OpenCode 源码的前提下解决了这两个问题。
工作原理
┌─────────────────────────┐
│ 编辑器 (Zed / VSCode) │
└────────────┬────────────┘
│ stdio (JSON-RPC)
┌────────────▼────────────┐
│ Harmony-ACP │ ← 独立进程
│ - 自动发现子 session │
│ - 子 session 拥有独立 │
│ sessionId │
│ - 记录全量流量日志 │
│ - 自动拼接消息碎片 │
└────────────┬────────────
│ HTTP / SSE
┌────────────▼────────────┐
│ opencode serve │ ← 未修改的 OpenCode
└─────────────────────────┘子代理可见性
每个子 session 作为独立虚拟 session 公告,拥有自己的 sessionId:
// Harmony-ACP:子 session 获得独立身份
await sendToClient({
sessionId: childSessionId,
update: {
sessionUpdate: "session_info_update",
title: "Explore project structure (@explore subagent)",
_meta: { parentSessionId, isSubagent: true },
},
});客户端通过 sessionId 区分父/子消息,通过 _meta.parentSessionId 展示层级关系。
消息拼装
OpenCode 以许多小 delta 碎片发送文本/推理内容。Harmony-ACP 在内存中累积这些碎片,遇到边界事件时刷新为完整消息:
[delta] "你" → [delta] "好" → [delta] "!" → [边界: tool_call]
↓
[日志] agent_message_complete: "你好!"边界触发条件:tool_call 开始、新 messageID、session 切换、进程停止。
快速开始
前置条件
- Node.js >= 18
- 已安装 OpenCode(
npm i -g opencode)
安装
git clone <repo-url> harmony-acp
cd harmony-acp
npm install
npm run build运行
# 1. 启动 OpenCode 服务
opencode serve --port 4096
# 2. 启动 Harmony-ACP
node dist/index.cjs --server http://localhost:4096编辑器配置
Zed(~/.config/zed/settings.json):
{
"agent_servers": {
"Harmony-ACP": {
"command": "node",
"args": ["/path/to/harmony-acp/dist/index.cjs", "--server", "http://localhost:4096"]
}
}
}VSCode(配合 ACP 插件):
将代理服务器命令配置为指向 dist/index.cjs,并传入 --server 参数。
命令行选项
用法:harmony-acp [选项]
选项:
--server, -s <url> OpenCode 服务器地址(默认:http://localhost:4096)
--cwd, -c <目录> 工作目录(默认:当前目录)
--help, -h 显示帮助信息流量日志
所有通信记录到 ~/.harmony-acp/logs/ 目录下的 JSONL 文件(自动轮转,最多保留 30 个文件)。
日志分类
| 分类 | 方向 | 说明 |
| ---------- | ---------------------- | ----------------------------------------------------------- |
| acp.in | 编辑器 → Harmony-ACP | 收到的 ACP 请求(initialize、prompt、newSession 等) |
| acp.out | Harmony-ACP → 编辑器 | 发出的 ACP 响应和 session 更新 |
| oc.call | Harmony-ACP → OpenCode | 对 OpenCode SDK 的调用(session.create、session.prompt 等) |
| oc.event | OpenCode → Harmony-ACP | SSE 事件(session.created、permission.asked 等) |
| system | 内部 | 生命周期事件(启动、停止、错误) |
日志查看器
# 查看最新日志(彩色、摘要化)
npm run logs
# 展示拼装后的完整消息文本
node scripts/view-log.mjs --content
# 按分类或动作过滤
node scripts/view-log.mjs --filter acp.out
node scripts/view-log.mjs --filter prompt
# 原始 JSONL 输出
node scripts/view-log.mjs --raw
# 列出可用日志文件
node scripts/view-log.mjs --list拼装消息日志
使用 --content 参数时,拼装消息以完整文本展示:
14:23:01.456 acp.out MSG[142chars] session=a1b2c3d4e5f6
项目使用 TypeScript 和 Effect 框架。
关键文件位于 src/ 目录...架构
| 文件 | 职责 |
| ------------------------------ | ---------------------------------------------------------------- |
| src/index.ts | 入口:参数解析、stdio 设置、服务器连接 |
| src/agent.ts | ACP 代理:实现 Agent 接口、session 管理、prompt 转发、日志包装 |
| src/session-manager.ts | 增强版 session 管理,维护父子关系索引 |
| src/event-handler.ts | SSE 事件订阅、路由和消息 delta 拼装 |
| src/logger.ts | JSONL 结构化日志,支持消息拼装 |
| src/types.ts | 共享类型定义 |
| src/utils.ts | 工具函数(toolKind 映射等) |
| scripts/view-log.mjs | 彩色日志查看器 |
| scripts/test-integration.mjs | 全链路集成测试 |
各文件的详细分析见 docs/codebase-overview.md。
SessionManager 增强
与 OpenCode 内置的 ACPSessionManager 只感知显式创建的 session 不同,Harmony-ACP 的 SessionManager:
- 自动发现子 session——通过
session.createdSSE 事件 - 维护父子关系索引——
children: Map<parentID, Set<childID>> - 解析根 session——通过
findRootSession()将子 session 事件路由到正确的 ACP 客户端
EventHandler 增强
EventHandler 订阅 OpenCode 的全局 SSE 事件流并处理:
| 事件 | 行为 |
| ---------------------- | ----------------------------------------------------- |
| session.created | 自动注册子 session,作为虚拟 session 公告给客户端 |
| permission.asked | 转发权限请求,包括来自子 session 的请求 |
| message.part.updated | 路由子 session 的工具执行状态更新 |
| message.part.delta | 累积文本/推理 delta,流式转发给客户端,拼装后写入日志 |
开发
npm run build # esbuild → dist/index.cjs
npm run typecheck # TypeScript 类型检查
npm test # 单元测试(Vitest,无需外部依赖)
npm run test:watch # 单元测试 watch 模式
npm run test:integration # 全链路集成测试(需运行 OpenCode 服务器)与内置 ACP 对比
| 特性 | OpenCode 内置 ACP | Harmony-ACP | | ---------------------- | ---------------------- | ---------------------- | | Session 管理 | 仅顶层 session | 顶层 + 子 session | | 子代理工具调用可见 | 否 | 是 | | 子代理文本输出可见 | 否 | 是 | | 子代理权限请求转发 | 否 | 是 | | 流量日志 | 无 | 有(JSONL,分类记录) | | 消息碎片拼装 | N/A | 有(delta → 完整消息) | | 是否修改 OpenCode 源码 | — | 否 | | 运行方式 | 集成在 OpenCode 进程内 | 独立进程 |
许可证
MIT
