OpenClaw 24h 更新快报(2026-11-10):OpenClaw ID 节点接入、Gateway 会话恢复、沙箱容器回收

内容管家 新闻 AI领域评论2字数 4873阅读16分14秒阅读模式
OpenClaw 24h 更新快报(2026-11-10):OpenClaw ID 节点接入、Gateway 会话恢复、沙箱容器回收

OpenClaw 24h 更新快报(2026-11-10):OpenClaw ID 节点接入、Gateway 会话恢复、沙箱容器回收

过去 24 小时,OpenClaw 主仓库合并了 261 个 PR。改动的主线集中在三处:节点接入流程重做,OpenClaw ID 节点现在可以凭链接自助入网;网关启动不再被会话恢复阻塞;沙箱与容器的空闲资源开始被主动回收。此外还有一批工具调用、配置写入与子代理协作上的静默错误被修正。

节点接入:从命令行链接到设备码确认

无头节点此前没有一条不依赖用户账号、也不依赖 Gateway token 的入网路径,这一层被 PR #193993 补齐。新增 openclaw node join <openclaw-node-link>,openclaw connect 也会发送同一种链接;节点侧会显示一个六位数字码和一份带签名的命令清单,所有者在 Access 页面对照数字码后批准,节点随后自行确认已被准入,再以前台方式连接,或用 --service 装成用户级服务。发现来源由 --discovery-url 指定或复用节点目标里已保存的值,代码里没有任何生产默认值的推导逻辑。

入网之后的服务端密钥轮转是配套问题。PR #194459 让节点在每次连接前刷新并校验 claw 当前的签名服务端授权与成员关系,因此网关如实轮换服务端密钥时,节点会跟着走而不必重新入网;反过来,若连接对端的密钥已被替换,节点会主动断开。访问权限被移除时节点停止并给出重新入网提示,其他拒绝原因也只打印一次具体理由,而不是抛一个笼统的连接失败。

移动端要接上这条链路,还差一层原生传输。PR #194174 新增 openclaw-iroh-ffi crate 的 uniffi 绑定,为 OpenClaw ID 隧道提供 Swift/Kotlin 传输,QUIC keep-alive 与 openclaw/tunnel/1 的精确数字关闭码都在这一层实现。这次合并本身没有用户可见变化,Android 与 Apple 侧的接入 PR 尚未落地,默认 App 构建也不变;UniFFI、attohttpc 及 MPL 覆盖依赖的许可声明属于发布环节的门槛,不构成合并门槛。

网关启动:让就绪读不再等会话恢复

这一轮体量最大的改动是 PR #195987。过去网关的就绪判定和启动期读取,要等所有被中断会话的恢复输入全部入队才放行,于是控制台在明明已经连上的情况下反复收到 UNAVAILABLE。现在就绪检查与 models.list、mentions.list、sessions.github.options 这些 owner-ready 方法可以在会话恢复的同时正常推进,无关会话照常接收新回合;正在恢复的那个会话的新输入会排在它已恢复的回合和保留的 FIFO 输入之后。整个改动不需要用户改配置,也不动 schema。

与重启相关的还有 PR #195661:停在 sessions_yield 上的 dashboard 与 operator root 原先会在网关重启中丢掉生命周期。现在已记录的 yield 等待会原地保留,不会因为重启触发一次额外的启动模型回合;当重启确实停掉了请求方自己的子执行时,root 会收到常规恢复输入去核对工作,而不是干等旧执行或直接失败。永久性的交接失败会走既有分类后的运行失败通知,明确告知子结果无法投递但对话已保留,便于用户检查已保存的子工作并重试。

退出路径则由 PR #196067 收紧。此前一次干净的网关关闭,在句柄所有者已经收工之后仍可能再等上数秒;运行时插件编译还会留下常驻的 esbuild 服务与同步 API worker,终止编译 worker 时可能既留下活着的服务也留下僵尸进程。现在 POSIX 上的干净退出把残余句柄的上限压到 1000 毫秒(终态器、文件日志与输出管道收敛之后),编译路径也不再残留常驻服务。

前端配套的 PR #195142 处理的是网关重启期间后台动态 import 失败的情况:旧逻辑把"服务器不可达"当成"构建已更新",重连后直接替换整个文档,正好打断用户正在写的回复。现在同一构建版本的短暂不可用只会等待服务文档并重试 import,不再触发导航;真正的构建变更仍然走原有的受保护的 stale-build 恢复路径,草稿保护和单次重载守卫都保留。

PR #196206 顺手收紧了项目会话的工作目录纪律:新项目会话如果省略了 worktree 或显式设为 false,构建与克隆的临时目录就会堆在共享克隆里。现在由 OpenClaw 克隆的项目,新会话一律拿到托管 worktree,仅给仓库 URL 的会话和旧的 pending URL 会话重试同样适用,项目选择器也会提供新建 worktree 的入口;已登记的本地目录和已配置的 agent 工作区仍保留"当前检出"选项。已有会话的工作目录不变,想离开共享克隆就新开一个会话。

沙箱与容器:空闲 tmpfs 被主动回收

闲置的 Docker 与 Podman 工具容器在干完活之后仍长时间保留 tmpfs 页面,冷数据持续吃掉宿主机 swap,而原有的 24 小时清理策略只负责删除容器,并不约束容器在运行态能活多久。PR #196064 补上了这一段:距上一次沙箱准入超过 15 分钟的非活跃工具容器会被停止,复用既有的 5 分钟巡检周期;每轮最多顺序尝试停止 32 个空闲容器(失败的尝试同样计入),并在 state-root 生命周期里记录一个游标,下次从上次尝试过的名字之后继续,避免个别失败反复占用名额把后面的容器饿死,积压会在多轮巡检中自然排空。进行中的回合、被跟踪的后台命令和被保留的持久执行都在保护名单里;工作区绑定挂载、可写容器层和已准备好的依赖模板都会保留,下一个回合直接重启容器即可,不必重跑准备流程。

另一侧的模板准备由 PR #195713 修复。网关优雅关闭打断沙箱模板校验或准备之后,同源依赖会被迫重装;而一次被打断的增量刷新,甚至可能在替代品就绪之前就改动了已经发布的那一代模板。现在同源的恢复会话会保留上一份完好的已准备模板,新源输入仍需各自安装;旧实现留下的已失效模板仍然需要重建一次,这个版本不会把可能被改动过的内容重新标为可用。

同类的稳定性修补还有 PR #195409:NFS 留下被占用的 SQLite 快照清理目录时,Doctor 和网关启动会直接失败。现在已验证的快照在 NFS 保留忙目录时以清理告警结束,Doctor 与网关的预检和严格快照调用方仍然会暴露真正的清理失败,候选版本检查则把清理小插曲单独记录,不影响它原本成功的结果或原始读错误。

配置写入与账号诊断:从静默变更到可解释

PR #191326 处理的是一个不产生任何提示的计费变更:配置写入如果把某个模型从 Claude CLI 登录态或订阅档位移到按量的 API key 计费(或者反向切回),此前是静默成功的。现在 config.set、config.patch 与 config.apply 在成功返回里带上 billingRouteWarnings 并写入网关日志,agent 默认值、agent 条目、subagent 默认值、heartbeat 以及其他被引用的模型配置每一个受影响的消费方都会得到一条提示;运行中的网关提交写入时,openclaw config 与 openclaw setup 会把同样的警告打印到 stderr。Doctor 原有的计费告警也从"仅有目录路由行的 provider"扩展到全部 provider。写入本身永远不会被拦截。

定时任务里的账号问题由 PR #195905 负责暴露。旧的定时 CLI 任务如果选中了一个已存储的账号,在第一次被拒之前没有任何预警,而使用配置密钥的任务反倒会收到一条 Doctor 也修不了的启动告警。现在 Doctor 和 lint 会点名每一个受影响的 CLI 任务,给出它使用的运行时、模型、所选 profile 以及确切的改用命令;启动阶段还有一轮后台扫描提供同样的指引,它不会阻塞 cron 的就绪与运行,总预算 5 秒,并对仍未勾选的任务给出一份汇总。定时 CLI 任务仍然必须显式指定账号,建议的 --model 修改同时会把主模型一并设上。

工具调用正确性:占位参数、静默改签与循环

PR #196083 修的是一个看起来毫无关联的线上故障:经 ClawRouter 的 OpenAI Responses 路由访问的 GPT 模型,会把所有可选工具参数填满占位值,导致 strict 工具直接拒绝每一次调用。修复前,GPT-6 Astra、Luna 与 Sol 会把每个工具的每个属性都发过去,process 收到空字符串和空数组,github_publish 收到 title 为 "x"、SHA 与 UUID 全为零的值,在一个生产网关上两周内 130 次调用全被拒绝,报的还是毫不相干的 workspacePath 错误。根因是 OpenAI Responses 把没有 strict 键的 function 工具当作严格模式处理,于是要求每个属性都必须出现。现在 openai/\* 走 OpenAI Responses 时可选输入重新保持可选,无论模型来自实时目录还是配置里的 models.providers.clawrouter.models。

MCP 的 OAuth 刷新也有类似的脆弱点。PR #196055 指出,刷新边界在真正发出 token 请求之前就把这次刷新标记为已下发,于是任何传输层错误——包括根本没离开主机的 DNS 解析失败——都被记成结果不确定,持久化的刷新声明因此一直被围栏拦住,之后每次尝试都只能报"刷新结果不确定,请重新登录",哪怕只是一次网络抖动。现在瞬时故障会正常上报失败,下一次启动用已保存的授权重试刷新即可。

Code Mode 的失败循环由 PR #195754 收敛。反复出现的相同错误此前会让一个回合一直挂着,后续消息在控制台里干等且没有任何说明。现在既有的三次错误恢复守卫能通过仅分类的钩子识别出内容未变的 Code Mode 失败,模型会收到一条恢复提示;再次尝试被拦截的动作会结束当前回合并留下可见、可记录的诊断信息,排队的后续消息得以继续推进。控制台也把服务端已准入的后续消息明确标注为"Queued behind the current turn"。

可观测性方向上,PR #194353 让采集到的 OTel 内容在多行场景下也走一致的脱敏:此前当结构化模型内容或工具内容里的赋值出现在换行之后时,多行字符串的脱敏会漏掉一部分。现在多行字符串在被编码成 JSON 属性之前会先经过同样的文本脱敏,整体大小上限、按导出记忆、聚合脱敏与截断行为都保持不变。

子代理协作与团队聊天:不该回复的回复与重复投递

PR #196034 修的是一类会重复发消息的假失败:子协调回合在同一批工具调用里同时发起 sessions_send 和 message(action=send) 时,dispatch_action 会报出 SQLite transcript changed while preparing rewrite,尽管它其实已经执行完了。根因是嵌套的工具活动行在写入前可能已经被另一次发送推前了转录。现在这类 dispatch_action 调用会返回真实结果,Agent 不再把已投递的消息当成失败而反复重试——过去的重复投递正是这么来的。

与之配套的 PR #196033 处理的是可见性:当一个回合由某个子会话的回报启动时,Agent 用 message(action=send) 发出的更新此前根本不会出现在控制台里,因为可见性投影会连同该回合的行一起隐藏。现在父会话的这条可见回复会实时显示,刷新后依然在;子会话的回报与父会话的私有协调文本仍按原样隐藏。

内置 Goal 曾在收集完子会话结果后停止推进。PR #196213 指出,历史的 spawn 回执并不等于一项尚未完成的交付义务,之前的判定把两者混为一谈。现在已被收集的子会话不会拖住下一个 Goal 回合,而仍欠完成交付的子会话依旧保有优先级;Stop/Pause、错误、审批、预算与权限检查的行为均未改变。

团队聊天里的冒名回复则由 PR #196124 拦下:一条只 @ 了别人(例如 @nonconsensus 这些贴纸挺可爱)的消息,此前 Agent 也会接话。现在这条消息照常进入转录、被 @ 到的人照常收到收件箱条目,但 Agent 保持安静——不回复、不抢话、不打断进行中的回合,也不会排队;它会在下一回合把这条消息当作上下文读到。要让 Agent 参与同一条消息,需要在正文里点名。

语音与移动端:静音不必挂断

Talk 模式此前把"静音麦克风"和"结束通话"混为一谈,两端分别补上了独立的静音入口。iOS 侧由 PR #192648 加入 Talk 麦克风静音按钮;Android 侧由 PR #187722 允许在不结束通话、不打断助手工作与回复音频的前提下暂停输入。静音状态在 App 进程内的 Talk 重启后保持,直到用户显式取消静音,结束 Talk 之后独立按住说话依然可用。实时静音的实现方式是发送静音帧而保持录音会话打开,因此 Android 的麦克风使用指示灯可能仍然亮起;原生 Talk 会先把已经识别出的词说完再暂停识别。这一改动不需要新增权限、配置、依赖或协议变更。

语音侧的另一个错误在 PR #191950。Google Live 取消 openclaw_agent_consult 调用、OpenClaw 中止运行之后,实时 Talk 仍会先报告任务进行中、再报告任务已完成。现在语音模型会被明确告知请求已中断且结果未知,于是它不再声称工作已经做完,而是先核对已经执行到哪一步再决定是否重跑——因为取消之前跑过的步骤并不会被自动撤销。

记忆与会话存储:大转录不再压垮 worker

压缩 worker 在超大转录面前会直接被撑爆。PR #194536 指出,完整压缩会有意关闭有界重放限制,而旧的选择器会把每个被选中的载荷都解析并保留在 worker 侧的 Map 里,于是在下一个 Agent 回合到来前内存先耗尽。现在选择器产出的是一份不含载荷的压缩计划,只保留祖先与选择元数据以及至多两个完整锚点,被选中的载荷通过既有的已确认水合通道在同一个读快照下流式传输,由宿主校验完整性并重建语义。转录再长也不会在 worker 里留下完整副本。

记忆索引的导出有类似问题。PR #196158 指出,单个大会话会耗尽带上限的导出 worker,因为它同时持有着投影后的转录、脱敏后的字符串底层存储、渲染后的行以及最终拼接结果。导出分组与确认原本已经限制了批量大小,但没有在单次导出内部释放这些中间物。现在渲染器只从私有且不缓存的 worker 快照消费记录,并按组展平渲染后的文本;被判定为迟到生成会话的记录会同时清空缓冲文本、已刷出文本以及与之对齐的元数据。

记忆插件在 CLI 后端回合上则一直是完全静默的。PR #194454 指出,走 claude-cli 这类 CLI 后端的回合,其插件钩子拿不到 memory audience,于是自动召回与自动留存被整体跳过。现在在 before_prompt_build、llm_input、llm_output、before_agent_run 与 agent_end 里读取 ctx.memoryAudience 的记忆插件,在 CLI 后端回合上与内嵌回合行为一致,包括继承父会话记忆的定时 cron 运行。不使用 audience 的插件不受影响。

还有一个容易被忽略的时钟陷阱。PR #196093 指出,memory_search 遇到真实的服务方失败(例如 openai embeddings 429 insufficient_quota)后会进入 60 秒失败暂停,此时系统时钟若向后跳一步,暂停永远不会到期——之后每次调用都直接返回缓存的不可用结果,继续告诉模型去重试 memory_search,却一次真实搜索都没发起,直到蔷钟追上,可能要等几分钟甚至几小时;时钟前跳则是镜像的伤害,暂停瞬间失效,又去打刚刚已经耗尽配额的 provider。现在暂停改用 performance.now 度量经过时间。

渠道与网关就绪:断线不等于不健康

Discord 的 op-7/resume 与 X 的流重连属于常规恢复,此前却会让整个网关对 /readyz 返回 503。PR #195437 让已连接的渠道在既有的两分钟重连窗口内保持就绪,受影响的渠道 ID 会出现在详细响应的 degraded 字段里,状态保留断连/恢复中并标记为 reconnect-grace,重连与恢复日志照旧可见;而真正没有恢复的传输、阻塞与鉴权失败、以及耗尽网关重启阶梯的账号,仍然判定为未就绪。

Matrix 的长消息则被 PR #196167 修好:超过 4000 字符、且带 ``` 代码块的回复在切分点落在围栏内部时,第一条消息会以未闭合的围栏结束,第二条把剩余代码降级成普通段落丢掉缩进,最后那条孤立的闭合围栏还会在结尾正文外再开一个空代码块。现在切分会避开围栏内部,每个事件都能渲染出完整且高亮正确的代码块,同时仍满足 4000 字符的事件上限。

这一天的改动没有大张旗鼓的新功能,但把节点接入、网关启动、容器回收、工具调用这几条主链路的稳定性都往前推了一步。

常用链接

 
内容管家

发表评论