Imported from zai-org/Synapse (
packages/remote-agent-daemon/AGENTS.md). Install upstream withnpx skills add zai-org/Synapse --skill remote-agent-daemon. Copyright stays with the author.
remote-agent-daemon
机器侧守护进程:把外部 coding agent(Claude Code、Codex,未来可加其他 Agent SDK)桥接进 Synapse conversation。
架构约定
- per-(remote_agent, conversation) runtime session:一个 remote_agent 在不同 Synapse conversation 中必须对应不同的 CC/Codex session,不允许复用同一个
session_id/threadId。运行时状态在 server 端落remote_agent_conversation_contexts(含runtime_session_id、runtime_state等列),daemon 端按Map<conversationId, ConversationRuntime>管理。不要再把 sessionId 挂在 binding 上。 - driver 抽象:所有 runtime(CC、Codex、未来新增 SDK)实现
drivers/types.ts的AgentDriver/AgentSession接口,集中在drivers/registry.ts注册。新增 runtime 只新增一个 driver 文件 + 注册一行;不要在 supervisor 里写 runtime-specific 分支。 - Claude Code 走
@anthropic-ai/claude-agent-sdk(不直接 spawnclaudeCLI 解析 stream-json)。Permission / AskUserQuestion / ExitPlanMode 通过 SDK 的canUseTool回调路由。 - Codex 沿用
codex app-serverJSON-RPC v2 over stdio(v2 typed schema 由codex app-server generate-ts --out src/codex/generated/生成、提交进 git;与本地codex二进制版本绑定,升级 codex 时需要重生成)。运行时配置approval_policy=never+sandbox_mode=workspace-write,绝大多数 approval RPC 不再到达 driver。 - 反向 MCP:daemon 不再托管自己的 stdio MCP server。Synapse 在
/api/v1/internal/remote-agents/:id/mcp/:conversationId暴露 Streamable HTTP MCP server(IM 工具 + conversation 授权的 plugin/device 工具);MCP server 的 URL + Bearer 在 session 创建时经createSession({ mcpServers })注入(claude SDK 的mcpServers选项 / codex 的-c mcp_servers.*flags),没有运行时setMcpServers(driver 接口不再暴露它)。
提交章法(refactor 进行中)
整改分 7 个 phase 提交,每个 phase 完成后保证 npm run build + 涉及 workspace 的 npm test 通过:
chore(remote-agent): baseline before refactorfeat(remote-agent): per-conversation runtime sessions + connection fencingfeat(remote-agent): reliable delivery retry with exponential backoffrefactor(remote-agent): introduce AgentDriver abstraction + claude-agent-sdkrefactor(remote-agent): codex app-server v2 typed schema + slimmer approvalsfeat(remote-agent): expose per-conversation MCP server to remote agentstest(remote-agent): isolated docker-compose stack for e2e verification
部署/兼容公告(changelog)
- 2026-07 trace 整改 Phase 3(fail-deliveries 清洁断裂,与 api 同车发布):
POST /api/v1/internal/remote-agents/:id/fail-deliveries的请求体从{delivery_ids: [...]}重塑为 per-delivery 携带 trace 上下文的{deliveries: [{delivery_id, traceparent?, tracestate?}], reason}(无双轨兼容, 旧 shape 直接 400 —— device-protocol schema 有测试钉死拒绝行为)。升级顺序: api 与 daemon 作为同一 release train 发布;未升级的旧 daemon 在该路由上收到 400 直至升级——期间 deliveries 保持 pending,由 api 侧 retry worker 重新 notify,不丢数据(仅失去 daemon 主动上报失败的时效性)。同批次变更: daemon→api 的 machine message(ready/runtime:catalog/agent:session/agent:status,不含 heartbeat)按当前 carrier scope 附带{traceparent, tracestate?}wire 字段;spawn-env 传递 traceparent 的旧约定 (SYNAPSE_TRACEPARENT)已全仓退役,无任何 reader/writer 残留。
E2E 验证
合入 dev 后,使用 dev 分支的独立部署测试容器(packages/api/tests/integration/ 下的 docker-compose.test.yaml 等)进行验证。
子进程的外发流量由部署环境的代理配置决定。如果需要让 CC/Codex 子进程走 HTTPS 代理,可以通过 --proxy-url(或环境变量 SYNAPSE_AGENT_PROXY_URL)注入,driver 内部由 drivers/proxy-env.ts:buildAgentChildEnv() 统一展开为 HTTPS_PROXY / HTTP_PROXY / NO_PROXY 系列变量。默认不开启代理。