feat(qoder): integrate Qoder CLI as a built-in agent - #514
Merged
Conversation
Qoder (Alibaba), driven by the `@qoder-ai/qodercli` npm package pinned to 1.1.23 and launched as `qoder --acp`, joins the built-in roster. The ACP server is the CLI's own first-party implementation — no community bridge — and the verified handshake advertises loadSession plus the full sessionCapabilities set (list/resume/fork/close/delete), image and embeddedContext prompts, and MCP http+sse, so the resume rung and the codeg-mcp companion work with nothing in between. Auth is the qoder account (`qoder login` / the IDE's qoder-browser flow); there is no API-key env, so the agent stays off the model-provider credential cascade and the settings auth panel keys stay empty rather than misreporting off generic OPENAI_*/API_KEY values. History comes from `~/.qoder/projects/<encoded-cwd>/<sessionId>.jsonl` (relocatable via `QODER_CONFIG_DIR`), written in the Claude-Code-style chunk-log envelope: uuid/parentUuid-chained user/assistant records with thinking/text/tool_use/tool_result blocks, interleaved with metadata records (`workspace-directories`, `runtime-config`, `active-leaf`, `last-prompt`) that repeat at the file tail. The parser merges assistant fragments that share one `message.id` (one API response streams as thinking, tool_use and final-text records), pairs tool results by tool_use_id, excludes `isSidechain` sub-agent internals, and derives titles from the plaintext transcript — the sibling `state.json` keeps its titles encrypted (AES-GCM under the machine key), so it cannot be the source. The exact byte length read becomes `transcript_watermark`. MCP rides qoder's own config: the CLI reads `mcpServers` out of `~/.qoder/settings.json` (gemini-schema settings file, alongside securityScan/permissions/security/model keys), so codeg's MCP settings writes go there as read-modify-write merges that preserve every other key, and Qoder joins the ACP forward skip list with Hermes/Kimi/Grok/ Cursor — forwarding the same servers over `session/new.mcpServers` would double-mount them. Unlike Codex/DeepSeek there is no SSE refusal: the handshake advertises http+sse and stdio entries are gemini-shaped. Skills: directory bundles only (`<id>/SKILL.md`, no flat markdown), roots `~/.agents/skills` (home) plus per-workspace `skills/` and `.agents/skills` — there is no qoder-owned home skills directory. `McpAppType::Qoder` serializes as `qoder`, pinned against `AgentType::as_wire` by the existing wire-name test, and a `qoder-cli` custom-agent entry registered before this integration is rejected at hydration as a built-in registry-id collision.
Owner
|
黎总666 |
xintaofei
added a commit
that referenced
this pull request
Aug 19, 2026
Fixes on top of #514, verified against the published bundle. Parser: read everything the Claude and Qoder envelopes share through parsers::claude's own extractors instead of a second spelling of the same rules — block-array content (which every ACP-entrypoint prompt uses, so the whole user turn and the title were being dropped), images, isMeta injections, synthetic API-error turns, slash-command tags, and per-message.id usage de-duplication. On top of that, the parts that are Qoder's own: * The transcript is an append-only message GRAPH walked back from active-leaf, not a list — reading it in file order splices abandoned rewind branches into the conversation and double-counts their tokens. * compact_boundary records write parentUuid: null on purpose and stash the real predecessor in logicalParentUuid; following only parentUuid hid every message sent before a compaction. * A parallel tool batch is one assistant record and one user record PER call, each result parented to its own call, so the results are siblings and an ancestor walk kept just one of them — the rest vanished and left their tool cards looking like calls that never returned. * active-leaf with leafUuid: null means the branch is EMPTY (the user rewound the first prompt); treating it as malformed resurrected the conversation they had just cleared. * custom-title / ai-title / token-stats / runtime-config.contextWindow are plaintext records, so titles and the context gauge no longer have to be guessed. Wiring: resolve the config dir the way Qoder does (QODER_CONFIG_DIR, else QODER_CLI_HOME / GEMINI_CLI_HOME joined with QODER_CONFIG_DIR_NAME) so codeg and the CLI it launches agree on one directory; read skills from the roots Qoder actually scans; authenticate with QODER_PERSONAL_ACCESS_TOKEN, the only credential a headless install can use (QODER_API_KEY was never read, and the empty slots wrote an env var literally named "undefined"); and alias the upstream registry id so the picker stops offering an entry that cannot be added. Also serializes the tests that contend on the process-global IMPORT_GUARD, a pre-existing race that failed CI intermittently.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概述
在现有 13 个内置 agent 之外,新增第 14 个内置 agent:Qoder(阿里巴巴的编码 agent CLI)。
与需要桥接的方案不同,
qoder --acp是 CLI 官方自带的第一方 ACP 服务端,无需任何适配层。实测 handshake 能力:支持
loadSession与完整sessionCapabilities(list / resume / fork /close / delete / additionalDirectories),prompt 接受图片与 embeddedContext,MCP 走 http+sse
——会话恢复、MCP、tool 轨迹全部走原生 ACP,没有能力缺口。npx 分发
@qoder-ai/qodercli@1.1.23(node ≥ 20),安装、启动、更新由 registry 统一管理。改动内容
AgentType::Qoder(wire 名qoder,registry idqoder-cli),registry、MCP skip list、文件系统 root slots、委派 tool_schema、conversations / experts / office_tools、
import_service 等枚举触点全部同步
parsers/qoder:读取~/.qoder/projects/<encoded-cwd>/<sessionId>.jsonl(Claude-Code 风格 chunk-log 信封),复用 claude 的 turn 分组;sidechain 子代理记录与
尾部元数据记录排除在外;assistant 分片按
message.id合并;transcript 水印契约与claude 解析器一致
~/.qoder/settings.json顶层mcpServers(gemini schema),codeg 的 MCP 设置页直接管理该文件(读改写合并,保留 CLI 自有的其他键),并加入 ACP
forward skip list 防止双重挂载
qoder login/ IDE 的 qoder-browser 流程),无 API-key 环境变量;模型、权限模式、推理力度走标准 ACP
configOptions<id>/SKILL.md),根为共享~/.agents/skills与项目skills/、.agents/skills/BuiltinAgentType类型、标签、颜色、图标(ACP registry 官方 glyph)、展示顺序、MCP 应用选项、委派默认值
验证结果
cargo clippy --all-targets --features test-utils -- -D warnings与 server / codeg-mcp模式 clippy 均无告警
cargo test --features test-utils全过:含 qoder 解析器 6 个测试(真实 1.1.23 会话fixture、sidechain 排除、尾部元数据不污染时间戳、水印契约)与 MCP 写入器往返测试
(保留
settings.json无关键、跳过非法条目、精准删除)pnpm eslint ./pnpm test(4168 用例)/pnpm build全过Rust 2695 个单测 + 全部集成测试、前端 4252 个用例、clippy 双模式全部通过
已知限制(Qoder 上游设计所致)
state.json中为 AES-GCM 加密存储,解析器从明文 transcript 的首条 humanprompt 推导标题