OpenClaw 24h 更新快报(2026-11-05):会话权限与恢复、压缩归档流式读取、Cron 调度与工具策略

内容管家 其他评论0字数 4377阅读14分35秒阅读模式
OpenClaw 24h 更新快报(2026-11-05):会话权限与恢复、压缩归档流式读取、Cron 调度与工具策略

OpenClaw 24h 更新快报(2026-11-05):会话权限与恢复、压缩归档流式读取、Cron 调度与工具策略

过去 24 小时,OpenClaw 合并了超过 400 个 PR,实际影响用户的有两条主线。其一是会话权限与恢复链路被系统性重写:渠道发起的会话创建第一次拿到与可见 spawn 同等的授权,无角色 Gateway 上的登录用户在重启后也能继续跑任务,而可见 spawn 不再被套用 subagent 的工具禁用清单。其二是会话归档读取从"整块解压"改成流式解码,过去因压缩比超限而被拒绝的归档有 56% 重新可读。同时,Cron 停止轮次不再误报失败,OpenRouter 的 reasoning summary 也不再让 /compact 卡死。

下面按主题梳理其中值得开发者与运维人员关注的改动。

会话权限:渠道创建、跨重启恢复与工具策略

PR #192037(P1,size XL,+708/-583)移除了 sessions_create 上独立的 operator/session-write 闸门。此前自 #164304 起,显式的会话创建请求被路由到 sessions_create,而它自己的准入判定会拒绝所有缺少 operator 授权的渠道轮次——即便调用方通过 sessions_spawn(visible: true) 已经能正常工作。生产环境的 Discord 请求因此直接返回 "sessions_create requires current session write authority…"。修复方式不是放宽成匿名开放,而是让创建路径复用已有的可见 spawn 归属者,并给出一个独立模式:调用方归属、准入、共享限制、沙箱与工具策略继承、权限模式全部沿用同一条链路,独立性只体现在"不建立完成归属、不注册子运行、不要求 yield",开场简报原样投递。共享会话的访客限制依然由 Gateway 权威判定,取消 operator 闸门并没有绕过它。

PR #192444(P1,security-boundary,+687/-14)修掉了一个更隐蔽的断点:在没有配置 gateway.roles 的 Gateway 上,登录用户的会话在优雅重启后永远不恢复。其重启时捕获的排队消息被丢弃,会话内的宿主事件则报 "Session principal has no current run authority.",受影响范围包括 exec 完成唤醒、插件运行时事件和 system-event 唤醒。根因是 #185730 引入的会话主体工作按"当前权限"准入,而当前权限在无角色场景下只来自 profile 本身;profile 自身没有权限,权限来自配对设备的 scopes 与 identityScopes,于是所有非 owner profile 全被拒绝。直接给 admin 会造成越权,因此这次改为复用定时任务已在使用的"操作源重验证"路径:用户输入被接受后,准入运行的 recoverySnapshot 会被保存,重启后据此重建会话。写权限设备依然保持写权限,不会因为登录就升权。

PR #192369(+248/-108)修正了工具策略的一处误伤。sessions_spawn 以 visible: true 创建的会话是用户在侧边栏里持续对话的交互式会话,却一直被当作 subagent 信封处理,因此默认套用 SUBAGENT_TOOL_DENY_ALWAYS(原本只豁免 message),在叶子深度还会叠加 SUBAGENT_TOOL_DENY_LEAF。在 Codex harness 上后果被放大:sessions_send、conversations_* 以及叶子层的 sessions_*/subagents 都不在 CODEX_TOOL_POLICY_SAFE_DENY_NAMES 白名单里,于是整轮变成 policy-restricted,Codex 原生的 shell 与文件能力被整体关闭;若部署同时排除了 Gateway 本地兜底工具,这类会话将彻底没有 shell 和文件工具,而同一 agent 的普通仪表盘会话仍然保留 bash/apply_patch。修复后可见 spawn 保留 subagent 信封与继承策略(受限父会话派生出的可见 spawn 依然受限),但不再被默认禁用清单波及,后台 exec 的退出通知也重新送达。

PR #192501(+480/-145)处理了关机预算耗尽时的会话丢失:关停在写入部分重启标记后耗尽准备预算时,被中断的根对话会失去自动恢复。原因是标记存储被串行处理、subagent 结算排在根取消之前、任一部分标记失败会禁用全部存储的恢复,而强制停止的引导记录又会阻止未完成运行的接管。修复后各存储批次并行写入、每个准备阶段在既有关机截止内被限制为 10 秒,并在 join subagent 结算之前先发出已捕获工作的信号;部分标记不再否决其他未完成的根会话。

会话归档:从"整块解压"到流式解码

PR #192743(P1,size XL,+851/-466)也许是这一轮最有工程含量的一项。#190690 之前规定:只要压缩归档的明文体积超过存储体积加 1 MiB 就直接拒绝。在 team-metal 环境下,这导致 16,806 个归档中有 9,461 个(56%)被拒;生产环境压缩比 p50 为 6.5 倍、p90 为 11.7 倍、p99 为 33.6 倍、最高 114 倍,且 45% 的帧根本不声明内容大小——任何固定倍率上限都不安全。而每一次拒绝都会中止整个 Usage 刷新批次,导致 /usage 长期停留在 "Partial results"(上线 51 小时内出现 167 次刷新失败,上线前为 0),重置/删除归档的历史、CLI 历史、会话结束时的记录读取以及 memory 会话索引器全部受影响。修复分两步:openSessionArchiveDecodedStream 以流的方式做 read → zstd 解码,内存占用维持在一个分块量级,4 GiB 上限只用于约束恶意构造帧;Usage 侧改为直接以不可变的 .zst 文件为新鲜度与身份依据,不再解压出副本——此前副本位于按日清理的临时缓存中,每次清理都会把所有归档标记为过期并触发全量重新解压扫描,而 team-metal 的 /tmp 是内存盘,全部归档明文合计 70.3 GB。

与之配套,PR #192732(+87/-7)解决了 usage 清单的另一处开销:sessions.usage 在 team-metal 上 15 秒预算中的绝大部分耗在 sessions.usage.inventory,每次请求从 SQLite 读取约 850 MB(journal readBytes 最高 1.27 GB,约 13 秒)。原因是 session_transcript_archives 表把 archive_blob 排在 archive_name 与 created_at 之前,而归档列表需要按 created_at 排序,SQLite 因此必须遍历每个命中 blob 的溢出链(2,912 行上约 782 MB)。修复后 usage 走独立的身份查询入口,只读取 blob 之前的身份列,排序与历史/SDK 列表行为不变。

PostgreSQL 侧,PR #192849(+151/-10)给维护期年龄查询加了边界:此前会把整个查询结果传回,而调度方只需要第一个符合条件的会话。考虑到受保护键需要先被跳过、单纯限制行数并不正确,查询改为按最多 64 行的分页惰性拉取并按既有的升序时间戳/降序原始键顺序续取,SQLite 保留原生流式查询。PR #192645(+434/-28)则为滚动发布候选提供了只读 PostgreSQL 备库检视能力:只读选择贯穿既有数据库与 worker 属主,读写连接复用被拆分,读者语句被强制在 PostgreSQL 只读事务内执行,并用单语句扩展查询避免一个批次提前结束受保护事务。这是原生滚动交接的第一块拼图,而非"滚动发布已可用"的宣告。

Agent 与模型调用:授权等待、失败恢复与上下文开销

PR #192906(+239/-24)解决多 run 共享同一 OAuth 账号时的竞态:一个 run 在刷新即将过期的 token,另一个 run 恰好在刷新期间发起下一次模型请求,于是直接以 MCP_AUTHORIZATION_UNAVAILABLE 失败,整轮运行终止。修复新增 assertSettledAuthProfileAuthorization:先执行既有的 assertCurrent,仅在授权暂不可用这一种错误上以 25 ms 轮询等待对端刷新落定,上界复用 OAuth manager 已有的 OAUTH_REFRESH_CALL_TIMEOUT_MS;其余错误立即抛出。两处授权检查现在都被纳入既有的凭据解析截止时间(withAuthDeadline)内,因此等待对端发布的上界由 run 自身的授权预算约束,而不是额外的独立配额。已退役、已重连、已关闭或已中止的授权仍然立即失败。

PR #187117(P1,+115/-109)修复了一个"一次失败毁掉整段对话"的问题:Claude CLI 启动失败(例如替换期间可执行文件暂时缺失)之后,同一对话后续轮次会一直保留并重复最初的启动错误,即使用户已经把可执行文件恢复。根因是会话句柄在进程启动前注册,清理 join 此前会把每一次启动拒绝都重新抛出,使活跃会话注册表里留下一个被拒绝的清理 promise。现在普通启动失败只影响自己那一轮,下一轮即可创建新的 Claude CLI 进程,无需重启 Gateway、修改配置或另开会话;只有清理无法确认(OwnedStdioCleanupError)时才阻止替换。

PR #192793(+10/-5)是一个很小但很实用的修复:OpenRouter 在其文档化的 summary 字段中返回非空的 reasoning.summary 进度,而非 text,导致手动 /compact 在 3 秒静默窗口后超时。修复后在既有的非空字符串判定之前先选取文档化的 summary 字段,复用隐藏思考的增量路径,不暴露推理内容、不调整超时值、不削弱用户取消。实测中主线程在 3.128 秒取消,而该修复版本在 4.209 / 4.249 秒完成两个压缩阶段。

上下文开销方面有两项可量化的改进。PR #192697(+7/-1)让工具密集的重放复用同一个 occurrence 队列:在 500 轮、每轮两个调用(2000 条消息、重复 provider ID)的基准下,重放加传输的 CPU 中位数从 929.91 µs 降到 727.67 µs,单次操作分配从 3,686,151 B 降到 2,855,993 B,repair 路径 CPU 从 239.69 µs 降到 148.86 µs。PR #192702(+125/-44)针对 OpenAI Responses 的长工具对话,避免为已被转换逻辑冻结的历史反复分配归一化副本,改为先比对生产者已有的不可变条目身份,再决定是否重建 owner map 与 JSON 投影,生产代码净增 18 行,wire 差异、response ID 与工具结果归属不变。

此外 PR #192447(P1)把内联 GIF 在发往 xAI 前投影为首帧 JPEG(质量 85,最长边 1200),避免一个合法 GIF 让 xAI 拒绝该图像轮次以及之后所有重放它的纯文本轮次。PR #191840 与 PR #192927 则修正了 Bedrock 目录:前者隐藏那些 AWS 明确声明不支持 ON_DEMAND 的自动发现裸模型行,后者把 Grok 4.6 的上下文窗口从保守的 32K 改为文档化的 500K。

Cron 调度与自动化

PR #192550(+241/-12)修掉了定时任务里最扰人的一类误报:通过会话手动停止一个调度轮次,会被计为失败并触发不必要的修复或告警。原因是会话事件属主把取消记录成一个字符串,而 cron 检查的是另一条仍然存活的调用方信号。现在会在异步结算与清理之前先固化规范的终态结论,再把分类结果交给 cron;被停止、被重启、被取代的轮次走既有的中断策略,真正的超时与卡死执行仍保留失败语义。

PR #192399(size L,+531/-25)让调度轮次能挺过无关的 MCP 配置改动。此前一次 mcp.servers.* 配置补丁会让调度轮次在准备阶段失败,并丢失已接受的 next_check 节奏,直到下一个整点才恢复。修复后准入判定改用上游已选定的运行时事实:OpenClaw 自持连接保留精确实例撤销,CLI 等接收原始 MCP 配置的原生运行时维持原有检查;cron 属主会保留一个到期节奏轮次直到它成功或被禁用,因此失败的节奏检查在正常错误退避与 Gateway 重启后依然存在。

另外两条面向使用体验:PR #192211(+79/-65)修复了失败修复轮次在 WebChat 里回答 NO_REPLY 却在属主聊天里发出 "Your request couldn't be completed." 假错误的缺陷;PR #192796(+9/-8)让 cron add 及其别名不再剥离 agent prompt 的前导缩进与结尾换行,新建的自动化提示词与 cron edit 行为一致。

渠道集成:Telegram、Discord 与飞书

PR #191646(+190/-116)让 Telegram 真正支持消息特效:共享的 message 工具早就接受 effectId(别名 effect),但 Telegram 在发送前直接丢弃,私聊消息因此在没有任何报错的情况下缺少原生特效元数据。修复把该参数贯穿旧版与 prepared 两条载荷路径进入文本、富文本、媒体与位置发送属主,并借助已解析的 chat 事实避免把私聊专属字段发给群组;对群组、频道、未解析的用户名目标和非数字特效名,一律省略特效而不是引入新的失败。

PR #192932(+214/-26)处理了 Discord 语音录制泄漏:当说话者停止或离开却没有发出 speaking-end 事件,或接收流报错但未关闭时,partial 录制会被无限期保留。原因是 speaking-start 取消了唯一的收尾定时器,而数据包活动从未重新设置它。现在音频 worker 在收到数据包时刷新自己持有的空闲截止时间、在 speaking-start 时恢复它,并关闭失败的输入;物理订阅关闭仍是移除占用的属主,与延迟解码或录制工作解耦。

PR #192482(+35/-19)修掉了飞书完成态流式卡片重复末块的问题:当累计预览与完成块流式同时开启时,成品卡片会把最后一块再追加一遍。修复后调度器按源顺序在既有助手消息边界内消费完成块,先在消费偏移处尝试精确匹配,再允许句子分块省略的分隔空白;真正重复且超出已消费预览的块仍然保留,不做后缀重叠猜测。

控制台、CLI 与运维可见性

这一轮有相当多工作用于把"泛化失败"变成"可诊断的具体原因"。PR #192478 让 openclaw gateway restart 在传入冲突参数组合(--skip-deferral 不带 --safe、--safe 与 --force 并用等)时给出具体原因,而不是只打印 "The CLI command failed."。PR #193000 让 openclaw models accounts 系列命令在 Gateway 未启动时输出统一的"网关不可达"指引,而不是裸的 connect ECONNREFUSED。PR #192919 修复了更新失败时错误信息被吞掉的问题:此前只显示 "Update <run> has unfinished recovery; reconcile it before starting another update.",真正导致失败的错误完全丢失,现在会打印首个失败原因,并在可修复时提示 openclaw update repair。

PR #192585(P1,+77/-55)解决了日常使用中一个明显不合理的交互:在回复进行中执行 /status 会以 transcript 冲突取消正在生成的回复,导致待发答案丢失。修复后只读状态命令的分类被保留下来,状态交换仍然出现在历史中但不进入模型上下文。PR #192934 则让 templates dev 与 templates add --agent-id "" 不再静默丢弃显式的空覆盖并自动编号,而是返回既有的 invalid_agent_id 校验错误并以状态码 1 退出。

运行环境方面,PR #192872(+278/-42)解决了 Podman 清理无关容器时沙箱启动变慢的问题:每次容器准备都会重复执行 podman info,而该命令会盘点全部容器并等待它们的状态锁,即使使用了窄输出格式。现在运行时会复用 Gateway 进程已发现的事实,并发首次调用共享同一次发现,失败的发现可重试;修改 Podman 连接、引擎模式或可执行文件后需重启 Gateway。PR #193010 则为 Kubernetes 模板请求 OnRootMismatch,避免在卷根目录已匹配时 kubelet 反复做权限遍历,同时在文档中区分了"预防权限扩大"与"修复既有数据"。

结构变化:Skill Workshop 迁出核心

PR #192471(size XL,+4519/-2857)把 Skill Workshop 从核心代码搬进捆绑插件 extensions/skill-workshop。此前约 20 个核心模块直接引用它,核心还为它特化了工具、提示词区块、/learn、CLI、Gateway 方法与 Doctor 检查,其他实现方无法在受支持契约上重建同样的东西。迁移基于已经落地的通用 SDK 接口(forked turns、completed-turn anchor、run_stopped、session notices、skill authoring、tool availability、skill usage、/learn contributions、personal-library split)。用户可见行为不变:skill_workshop 工具、带 Undo 的后台评审与通知、每日维护、/learn 的草稿与撤销、openclaw skills workshop ... 命令,以及 8 个 skills.workshop.* Gateway 方法的名称、载荷与 scope 均保持一致。

小结

这一天的基调是"把权限与恢复的边界讲清楚":渠道、OAuth、Gateway 重启、子代理策略与定时任务各自的责任方被重新划界,多处错误提示从泛化失败变成可执行的具体指引。性能侧最显著的收益来自会话归档改为流式解码与按身份列读取,绕开了此前让过半归档无法读取的压缩比上限。

常用链接

 
内容管家

发表评论