github.com/xiwan/acp-bridge v0.46.0 Python · acp-sdk · uvicorn Agent 不是 daemon

acp-bridge 全解 — 多 Agent 网关的调用、交互与进程生命周期

你在开发机上装了一堆 CLI Agent:Kiro、Claude Code、Codex、Qwen……想让团队其他人和其他机器人也能用,还想让它们互相协作。acp-bridge 做的就是这件事:把本地 CLI Agent 通过 ACP(Agent Client Protocol) 封装成 HTTP 服务,再叠加进程池、pipeline 编排、IM 驱动的异步工作流。本文基于其源码与文档(2026-09 克隆,main 分支)整理,重点回答三个问题:多个 agent 怎么调用、彼此怎么交互、任务过程中 agent 是不是 daemon 常驻。

§00TL;DR

先给三个答案

问题答案
怎么调用多个 agent?所有 agent 在 config.yaml 注册(或自动探测 PATH 里的 CLI),统一挂在 :18010 的 HTTP API 后面。每个 agent 就是一个名字:POST /runs 指定 agent_name 即可调用;多 agent 协作走 POST /pipelines,支持串行 / 并行 / 竞速 / 圆桌讨论四种编排模式。
怎么交互?对外是 HTTP(JSON、SSE 流式、webhook 回调);对内 Bridge 与每个 agent 子进程之间是 stdio 上的换行分隔 JSON-RPC 2.0:initialize 握手 → session/new 建会话 → session/prompt 发 prompt,期间 agent 以通知流回传思考 / 工具调用 / 文本片段,还能反向请求 Bridge(权限批准、代理文件读写)。
agent 是 daemon 吗?不是。唯一常驻的是 acp-bridge 服务本身(systemd 托管)。每个 agent CLI 是按需 fork 的子进程,键为 (agent, session_id):第一次请求时拉起,空闲超过 TTL(默认 24h)、池满 LRU、内存超 80% 或健康检查失联时被整组 kill。这是一种"温池(warm pool)",不是常驻服务。

§01定位

它是什么:一座双向翻译的桥

名字里的 "bridge" 很准确:ACP 协议有两种传输形态——编辑器(如 Zed)与 agent 之间常见的 stdio 形态,和网络服务需要的 HTTP 形态。acp-bridge 站在两者中间:

  • 向上(HTTP 侧):用 acp-sdk 的 Server + uvicorn 起服务(默认 :18010),把每个配置好的 agent 注册为一个 ACP agent——Bridge 自己对外就是一个 ACP agent 提供方,所以 ACP SDK 客户端、OpenClaw 这类支持 ACP 的宿主都能直接接入。
  • 向下(stdio 侧):为每个 (agent, session) 维护一个 CLI 子进程,用 stdio JSON-RPC 与之对话。

在两个形态之间,它补上了 CLI agent 原生没有的东西:进程池复用、会话保活、多 agent 编排、异步任务、IM 推送、鉴权、沙箱与审计。

全栈里的位置

agent 自身还要调 LLM。默认各 CLI 用自己的模型上游;项目还给出一条完整自托管栈(LiteLLM 聚合 + AWS Bedrock Mantle 网关):

# README 给出的全栈拓扑(LLM 链路)
Clients → acp-bridge (:18010)
              ↓ LLM 调用
          litellm (:4000)   # 聚合多模型
              ↓
          mantle-proxy (:4010)  # SigV4 签名转发
              ↓
          bedrock-mantle.{region}.api.aws  # GPT / Claude / 开源模型统一入口

典型场景

团队 AI 网关一台 EC2 跑 Kiro + Claude + Codex,全员走 HTTP 调用,本地零安装
IM 驱动开发Discord / 飞书里发一条消息 → agent 执行 → 结果推送回聊天频道
异步代码任务提交一个重构 / 评审 job,人走开,完成时 webhook 通知
多 agent 编排串行接力、并行对比、竞速取优,或让多个 agent 圆桌辩论
Prompt 即服务预置 prompt 模板,非技术同事填变量即用
Agent 市场同一个 harness-factory 二进制 + 不同 profile = 评审员、DevOps 助手、翻译官……

§02接入

Agent 怎么接进来

任何 CLI agent 只要满足两者之一就能挂上网关。这决定了"调用多个 agent"的第一层含义:异构 agent 被抹平成同一个 HTTP 接口上的不同名字。

ACP 模式推荐

agent 实现标准 ACP 接口(多数现代 CLI 原生支持或经适配器)。享受进程复用、多轮上下文、结构化事件(思考/工具/状态)、SSE 流式——整座进程池只为此模式服务。

例:kiro-cli 直接 acp --trust-all-tools;Claude Code 经 claude-agent-acp 适配器;Qwen Code 加 --acp。

PTY 模式兼容回退

不支持 ACP 的 agent(如 Trae Agent)配置 mode: "pty"。每次请求新起一个子进程,逐行读 stdout——无复用、无上下文、无结构化事件,是功能完整性让路给兼容性。

对比之下更能看清 ACP 模式的价值:进程复用正是会话上下文保留的关键。

零配置自动探测

没有 config.yaml 也能跑:启动时扫描 PATH,发现已知 CLI 就按默认参数注册(src/auto_detect.py 的 KNOWN_AGENTS),并生成随机鉴权 token:

探测到的命令注册名模式启动参数
kiro-clikiroacpacp --trust-all-tools
claude-agent-acpclaudeacp(适配器即 ACP 服务)
codex-acpcodexacp(经 ACP 适配器;也保留 PTY 直跑方式)
qwenqwenacp--acp
opencodeopencodeacpacp
hermeshermesacpacp
trae-clitraepty(无 ACP,逐行读输出)
harness-factoryharness-*acp按 profile 派生多个 agent

AWS DevOps Agent 刻意不参与零配置探测——它的身份、AgentSpace 与调查策略必须显式声明,走 fail-closed 专用启动器。

一体化多面:harness-factory

另一个"多 agent"维度:同一个 Rust/Go 二进制 + 不同 profile = 不同角色 agent(reader / executor / reviewer / analyst / developer…),还能在运行时通过 POST /harness 动态创建。轻量 agent 不必装十套 CLI,一套二进制按 profile 拉起即可。

自己写一个新 agent?

接入面被刻意压到最小——实现三个 JSON-RPC 方法即可:initialize(握手)、session/new(建会话)、session/prompt(收 prompt、流式发通知、返回结果)。仓库提供 examples/echo-agent.py 参考实现和 test/test_agent_compliance.sh 合规测试脚本。

§03调用链

一次调用的完整旅程

以最基础的 POST /runs 为例,从 HTTP 请求到 agent 子进程的完整链路如下(源码:main.py → src/agents.py → src/acp_client.py):

几个值得注意的工程细节:

  • fork 即立进程组:asyncio.create_subprocess_exec(..., start_new_session=True),让 Bridge 能用 os.killpg 一次杀掉 agent 及其全部孙进程(CLI 工具常会再 spawn 语言服务器等子进程)。
  • 握手即认证:initialize 响应里若带 authMethods,Bridge 自动替你完成 authenticate(openai / api-key),agent 无感登录。
  • 流式优先:session/prompt 在 Bridge 内是一个异步生成器——边收通知边往外吐,HTTP 层可以同步汇聚,也可以直接转成 SSE 让前端实时看到 agent 的思考与工具调用。
  • cwd 沙箱前置:如果请求带了自定义工作目录,先过三级信任沙箱校验(防 cwd=/ 越权),不合法直接拒绝。

线上电报长什么样

Bridge → agent(每行一条 JSON,stdio)

→ req{"jsonrpc":"2.0","id":1,"method":"initialize",
        "params":{"protocolVersion":1,
                  "clientCapabilities":{"fs":{"readTextFile":true,"writeTextFile":true}},
                  "clientInfo":{"name":"acp-bridge","version":"0.46.0"}}}
← res{"id":1,"result":{"agentInfo":{"name":"kiro-cli","version":"…"},
        "authMethods":[{"id":"openai"}],"capabilities":{…}}}
→ req{"id":2,"method":"session/new","params":{"cwd":"/tmp","mcpServers":[]}}
→ req{"id":3,"method":"session/prompt",
        "params":{"sessionId":"…","prompt":[{"type":"text","text":"帮我重构这个模块"}]}}
⇠ note{"method":"session/update","params":{"update":{"sessionUpdate":"tool_call",
        "title":"read_file","kind":"read",…}}}   // 思考、工具、文本片段都是通知
← res{"id":3,"result":{"stopReason":"end_turn"}}   // 这一轮结束

§04协议

交互协议细读

线路规则

传输stdio:stdin 收请求,stdout 发响应与通知,一进程一管道
格式换行分隔的 JSON-RPC 2.0,每条消息占一行,UTF-8
缓冲1MB 行缓冲(默认 64KB 不够装 agent 的大响应)
stderr仅调试日志,Bridge 专门开任务排空,不参与协议

正向:通知流

agent 执行期间通过 session/update 通知回传过程,Bridge 按类型分捡(这也是 SSE step_progress 事件的数据源):

sessionUpdate含义对应 SSE kind
agent_message_chunk回复正文片段message.part
agent_thought_chunk思考片段message.thinking
tool_call工具调用开始tool.start
tool_call_update工具调用结束(成功 / 失败)tool.done
plan计划 / 状态摘要status

反向:agent 也能请求 Bridge

JSON-RPC 是双向的,子进程同样可以发带 id 的请求,_read_loop 里有一组自动应答逻辑:

  • session/request_permission → 自动回 proceed_always。工具审批在无人值守的服务端没法等人点按钮;对 Claude 系 agent 这一步是必须的,否则它一直挂起等待批准。这也是"服务化 CLI agent"与"人坐终端前"最本质的交互差异之一。
  • fs/read_text_file / fs/write_text_file → Bridge 代理执行。agent 每次文件读写都以请求形式发给 Bridge,Bridge 先过三级信任沙箱(allowed_roots + 黑名单,连接自己的 cwd 是隐式合法根),再落盘并写审计记录;拒绝时把 EACCES: sandbox denied 当作文件内容回给 agent——让 agent 自己读懂被拒原因。文件 IO 跑在线程池里,大文件不阻塞读循环。

超时与取消

  • session/prompt 带 idle 超时(默认 300s):持续没收到非思考类事件就发 session/cancel 并报 agent_timeout。思考片段故意不重置计时器——防止 agent 陷入无限思考循环拖死会话。
  • 会话管理三兄弟:session/new 建会话、session/load 恢复历史(如 OpenGame --continue)、session/list 列出某 cwd 下可恢复的会话。

§05入口

五个入口与外围

"调用 agent"在 acp-bridge 里不是一个端点,而是五种按交互形态划分的入口(官方文档称 5 Interaction Modes):

入口形态阻塞上下文多 agent适用
POST /runs同步单发(一问一答)是无否一次性快速任务
/chat 会话进入对话后消息透传,/chat end 退出是有(进程复用保上下文)否多轮结对开发
POST /jobs异步后台,立即返回 job id否无否长任务,完成推 webhook / IM
POST /pipelines多 agent 编排(§06)看模式看模式是接力 / 并行 / 竞速 / 圆桌
/run(sessions_spawn)OpenClaw 原生 API,runtime="acp"否有否IM 宿主线程绑定 + 流式

外围还有三条接入路径,殊途同归到同一套 handler:

  • MCP Server(mcp-server/):把 Bridge agent 包成 MCP 工具,让 Claude Desktop、Cursor 等 MCP 客户端也能调用。
  • IM 机器人:Discord / 飞书 bot 收消息 → 调 HTTP API → 结果格式化推回频道,这是 README 里"让龙虾(OpenClaw)和爱马仕(Hermes)沟通"视频演示的主线。
  • Web UI(--ui):自带聊天界面,人直接在浏览器里用。

§06编排

多 Agent 编排:pipelines 四模式

这是"调用多个 agent"的核心答案。POST /pipelines 提交一个编排声明,Bridge 负责调度、传上下文、汇总产物:

sequence串行接力

上游输出注入下游 prompt
评审 agent→测试生成→QA→汇总

典型:代码评审 → 生成测试 → QA 验收,每步吃上一步的结果。

parallel并行扇出

同一 prompt 发多个 agent,汇总
kiroclaudecodex→对比汇总

典型:同一个问题听三家答案,交叉印证。

race竞速

最快者胜,其余取消
abc→第一名 ✓

典型:延迟敏感的一次性任务,谁先完成用谁的。

conversation圆桌讨论

多 agent 轮流发言,互相接话
kiro→claude→harness→kiro …

典型:架构辩论、协作设计,直到说出 DONE 或轮数耗尽。

conversation 是怎么转起来的

圆桌模式的实现(pipeline.py::_run_conversation)最能体现"agent 之间如何交互"——有趣的是,agent 之间从不直接对话,全靠 Bridge 当传话人 + 各自的会话记忆:

  • 每个参与者分到独立 session(conv-{pipeline_id}-{agent}),因此各自的子进程里保留着自己的对话上下文。
  • 发言按参与者数组轮询(round-robin)。某个 agent 的第一轮,收到完整铺垫:主题 + 全体参与者介绍 + A2A 协作规则(按主题语言自动选中/英文模板)+ 共享工作目录;之后的每一轮,prompt 只有一行:[claude]: (claude 刚才说的话)——主题和前文都由它自己的 session 记着,不必重发。(PTY agent 没有记忆,所以每轮都重发全量。)
  • 终止条件:stop_conditions(默认有人说出 DONE)、max_turns(默认 10)、no_progress_threshold(连续两轮无进展)。
  • 共享工作目录 shared_cwd:所有参与者的子进程 cwd 指向同一个目录,讨论产物(代码、文档)直接落在里面,后续步骤接力使用。

跨调用组合:工作区继承 + 自动链

  • workspace 继承:上一个 pipeline 返回 shared_cwd,下一个提交时塞进 context.shared_cwd,多个 API 调用拼成多阶段工作流——比如先让三个 agent 圆桌讨论游戏设计,再并行让 kiro 写前端、claude 写后端。
  • next 自动链:pipeline 完成后自动触发下一个,steps_from_output: true 时从上一段产出的 output.tasks[] 动态生成步骤,配 step_prompt_template 模板填充({shared_cwd}、{module}、{files})。
  • 收敛循环(next.when,v0.44):next 带 when 条件就从"单次接力"升级成"循环到收敛"——比如 QA agent 打分 verdict.overall < 80 就 loop_back_to 修复步重跑,最多 max_rounds 轮。条件表达式走 AST 白名单求值,绝不用 eval:只允许比较、布尔、属性访问和字面量;指标缺失按 False 处理,不会误触发循环。轮次计数通过保留变量 {{_loop_round}} 注入 prompt。
  • 结构化产出:conversation 配 output_schema: true,Bridge 从最后一轮发言里抽取 JSON 块挂到 pipeline.context.output,给下一步当机器可读输入。

人在环路(Human-in-the-Loop)

  • 暂停 / 恢复:POST /pipelines/{id}/pause 在下一轮前挂起,observe 中间产物后再 resume。
  • 插话:POST /pipelines/{id}/inject 把你的消息作为 [Human] 回合塞进记录,下个 agent 回应它;暂停中插话会自动唤醒。
  • 重跑:rerun 支持 prompt_override(以「修正指令」前缀注入)和 from_step 部分重跑,复用原 shared_cwd,跑过的步骤产物原地保留。

§07生命周期

进程池与生命周期:agent 到底是不是 daemon?

结论 · 直接回答

不是 daemon。整个系统里唯一常驻的进程是 acp-bridge 自身(systemd 单元托管,bridge-ctl.sh / stack-ctl.sh 管理)。所有 agent CLI 都是它按需 fork、有生有灭的子进程。

准确的说法是温池(warm pool):进程的存活期 = 会话需要它的时间 + 一段保活窗口。请求来了才拉起(asyncio.create_subprocess_exec),同一会话的后续轮次复用同一进程以保留上下文;空闲超 TTL、池满被 LRU 挤掉、内存吃紧、心跳失联,任何一条触发就整组 SIGKILL。任务执行"过程中"进程当然活着(否则没法保持上下文),但没有任何机制让它在没人用的时候继续常驻——这和"每个 agent 一个 systemd 服务 / 每个 agent 一个容器常驻"是两种完全不同的资源模型。

拿到一条连接的决策路径

每次请求进来,AcpProcessPool.get_or_create()(带 asyncio.Lock 防并发超卖)按下面的顺序决定"复用还是新建":

① 查表精确命中(agent, session_id) 已有存活连接 → 直接复用,上下文原样保留
② 池满时同 agent 复用找同 agent 空闲进程,reset 会话续用,免一次 fork——最快路径
③ 仍不够LRU 逐出挤掉全池最久未用的空闲连接,腾出名额
④ 兜底有界等待后新建全忙则每 2s 轮询(锁外,不挡别人),默认 60s,超时报 pool_exhausted;有名额则 fork 新进程组

进程怎么被回收:五条清理线

机制周期 / 阈值动作
空闲 TTLsession_ttl_hours 默认 24h(可按 agent 覆盖 idle_ttl),清理循环每 60s 扫一遍kill 空闲超时连接,释放名额
健康检查 ping每 60s 对所有 idle 连接发 no-op JSON-RPC(10s 超时)无响应 → kill 摘除
busy 卡死保护busy 超过 busy_timeout(默认 360s)判定卡死,强杀
OOM 保护读 /proc/meminfo,内存用量超 memory_limit_percent(默认 80%)主动逐出 idle 连接,抢在 OS OOM killer 之前
ghost 清理启动时 + 清理循环,对照 pidfile /tmp/acp-bridge-pidsSIGKILL 上一次 Bridge 崩溃遗留的孤儿 agent 进程

另有三道兜底:Bridge 收到关闭信号时 pool.shutdown() 杀光全部子进程;atexit 注册了 killpg 安全网;中途崩掉的连接在下次请求时被识别为 stale,自动重建新进程(上下文会丢,并明确通知用户)。所有 kill 都是 os.killpg 进程组级别——agent 自己拉起的子进程一棵端走,不留僵尸。

连接的四态

idle · 存活待命,可复用 busy · 正在执行 prompt stale · 会话被重置,待重建 dead · 进程已退出,待收割

两个特例(依然不是 daemon)

  • 心跳保温(可选):配置 heartbeat 后,Bridge 会周期性地用一个环境感知 prompt 唤醒 agent,让它"知道"团队环境的变化。这算主动延长保活窗口,但进程仍在池的统一管辖下,同样受 TTL / LRU / OOM 约束。
  • Lambda 突发:pool: lambda 的 agent 把执行甩到 AWS Lambda 上的 harness-factory(应对 100+ 并发),那是 serverless 形态,更谈不上 daemon。

§08追问

能交互吗?能记住吗?——会话与上下文的边界

把 §03 的调用链和 §07 的生命周期合起来,就能正面回答两个最常被追问的问题。

「通过 ACP 能和 agent 交互吗?」——能,全功能且双向

  • Bridge 与 agent 子进程之间是完整的 ACP 对话:initialize → session/new → session/prompt,agent 以通知流实时回传思考片段、工具调用、文本增量。HTTP 侧既能同步拿最终结果,也能走 SSE 实时围观过程。
  • 协议是双向的:agent 执行中可以反过来请求 Bridge——工具权限自动放行、文件读写代理 + 沙箱(§04)。
  • 前提是 agent 支持 ACP;不支持的走 PTY 兼容模式——能调用,但没有上下文、没有结构化事件(§02)。

「多次对话能保留上下文吗?」——能,但上下文是进程内存级的

能,这正是 ACP 模式相对 PTY 的核心优势(process-pool 文档原话)。机制:进程池以 (agent, session_id) 为键,同一 session 的后续请求命中同一条连接、复用同一个子进程,对话上下文由 agent 进程自己持有——/chat 会话、conversation 圆桌(每人独立 session,首轮之后只传一行接话)都依赖这一点。但要清楚:这个上下文不持久化,四种情况会丢:

场景后果
进程被正常回收空闲超 TTL(默认 24h)、池满 LRU 逐出、内存超 80%、busy 卡死 360s——进程一杀,上下文即失(§07 五条清理线)
进程崩溃Bridge 自动重建子进程,但上下文丢失,并明确通知用户
同 agent 进程被复用池满时 Bridge 拿同 agent 的空闲进程 session/new 重置给新会话(_reuse,省一次 fork),旧会话上下文随之清空
PTY 模式每次请求新起进程,完全没有上下文

补救通道:ACP 的 session/load 可按 ID 恢复会话(Bridge 已实现,如 OpenGame 的 --continue),但依赖 agent 侧自己做了会话持久化,并非普遍能力。

实践建议 — 多轮对话在 TTL 窗口内连续进行,上下文稳;隔天或长间隔续聊,要么接受丢上下文重开,要么依赖 agent 自己的持久化恢复。

§09可靠性

熔断、故障转移与断点恢复

进程是短命的,服务却是长期的——可靠性全部内建在池层与编排层,对 agent 零要求:

每个 agent 一个熔断器

  • CLOSED → OPEN → HALF_OPEN → CLOSED:滑动窗口内连续 5 次失败或失败率 50% 即熔断,OPEN 期间该 agent 的调用立即拒绝,持续 30s;之后放 3 个探测请求,成功才恢复。429 限流不计入失败——那是客户端侧问题,不是 agent 的错。

自动 fallback:带评分的替补链

  • agent 调用失败自动沿 fallback 链换人重试(最多 3 次)。替补不是硬编码顺序,而是打分选出来:熔断 OPEN 的直接排除;有空闲连接的 +1.5× 加成;再看近 1 小时成功率、平均响应时长;近 15 分钟成功率下滑还要吃趋势惩罚。pipeline 的步骤 fallback 会把原定 agent 记为 original_agent 并留 fallback_history,可追溯。

pipeline 断点恢复(v0.35)

Bridge 重启后,处于 pending / running / paused 的 pipeline 按 mode 差异化恢复:

sequence保留已完成步骤,从第一个未完成步续跑
parallel只重跑未完成的步
race整体重跑(半截竞速没有有效冠军)
conversation标记失败(对话 session 活在被杀的子进程里,无法续)

生命周期事件落 SQLite,重启后 SSE 迟连接也能重放历史;每类数据(pipeline / 聊天 / prompt 日志 / 用量)各有保留期,由清理循环统一淘汰,防库无限膨胀。

§10横向扩展

A2A Mesh:多台 Bridge 互为peer

单机进程池之上,还可以把多台 acp-bridge 组成去中心化 mesh——"调用多个 agent"的第三层含义:跨机器调用别人的 agent,像调本地一样。设计哲学一句话:不信任任何远端 agent 的自述,只信可验证的输入→输出链路(校验和、hop 上限、token 认证)。

L0
发现每台节点把本地 agent 发布为 A2A skills(/.well-known/agent.json Agent Card);gossip 式 announce(默认 300s)互换节点与 peer 列表,无中心注册表。超过 3× 间隔(900s)没露面的 peer 标记 unhealthy,其 agent 从路由表摘除。
L1
远程被调任何 peer(或 A2A 客户端)可以 POST /a2a 调本节点的 agent,独立 mesh token 鉴权,与全局 API token 分离。
L2
透明路由本机没有的 agent,若某个健康 peer 有,就注册成本地透明 handler——之后 /runs、/jobs、/pipelines 照常按名字调用,Bridge 自动转发到属主节点。接入 mesh 的任一节点,等于用上了全网所有 agent。
L3
跨节点 pipelinepipeline 里某步的 agent 住在对端?该步的 shared_cwd 工作区经 S3 打包往返中继,多步流水线照样跨机跑。混合内网 / 公网部署用 dual 模式,peer 按子网远近自动挑地址。

§11观测

实时观测:三条通道

通道方式适合
SSE 事件流GET /pipelines/{id}/events,事件:pipeline_started / step_started / step_progress / step_completed / step_failed / step_fallback / pipeline_done + 15s 心跳程序化客户端,实时看 agent 思考与工具调用
轮询GET /pipelines/{id} 全量快照;/steps/{i}/live 正在跑的缓冲 + 工具列表Shell 脚本、SSE 被代理缓冲的环境
webhook 推送提交时带 target + channel,每步完成即格式化推送到 IMDiscord / 飞书频道,人只看结论

step_progress 就是 §04 那张通知表的实时投影——agent 子进程每发一条 session/update,观察者几乎同时看到。产物(声明了 steps[].artifact 的文件)完成后可自动传 S3,以预签名链接附在通知里。

§12结语

三条设计取舍

回看全文,acp-bridge 的所有机制都围绕三个判断展开:

  1. 进程边界 = 会话边界 = 信任单位。一个 (agent, session) 一个进程组,上下文天然隔离,kill 干净利落;沙箱、审计、熔断、逐出全都以这个粒度运转。温池模型在"保留上下文"和"不养闲进程"之间取了精确的平衡——这正是"agent 不是 daemon"的工程含义。
  2. 协议面压到最小。接入一个新 agent 只需三个 JSON-RPC 方法;复杂性(进程池、fallback、编排、观测)全部住在 Bridge 侧。agent 保持"傻而纯",平台才能统一演进——v0.18 加池锁、v0.35 加恢复、v0.44 加收敛循环,没有一次要求 agent 侧配合。
  3. 服务化必须回答"人不在场"的问题。权限请求自动放行、文件读写代理 + 沙箱、空闲超时主动 cancel、失败自动换 agent、崩溃自动恢复——每一个都是"终端里人坐着的默认假设"在服务端不再成立后,补上的显式机制。
姊妹篇 — Agent Client Protocol(ACP)全解:本文反复出现的 stdio JSON-RPC、session/update、request_permission 都是 ACP 协议的内容,协议本体在那边有逐条展开。
← 学习站索引