架构决策研究 下载完整 Markdown

NullClaw
还是 Infinity?

不是比较谁的功能清单更长,
而是找到离目标更近的执行模型。

面向本地优先、海量长期会话与低常驻内存的源码级选型。执行、存储、队列、故障恢复、安全与迁移成本,放在同一张工程图里看。

结论先行

长期 Agent 平台,倾向 Infinity step;近期多渠道助手,倾向 NullClaw。两者都需要有界上下文与可靠持久化。

查看决策依据

评估目标沿用此前 Infinity 研究的工作假设,并非本轮重新确认的产品规格。报告明确区分源码事实、本轮实测、上游样本与设计建议。

执行结论

若核心目标是“本地优先 + 大量长期会话 + 低常驻内存 + 异步任务可恢复”,建议选 Infinity 的 step 内核做二次开发,而不是直接把 Infinity Code daemon 当作成品服务。若首要目标是尽快交付一个多渠道个人/小团队助手,选当前 NullClaw 更合适。两者都不能原样满足前一个目标。

这不是 Rust 对 Zig 的偏好:关键在于 能否把一次 Agent 执行拆成可持久化、可重入的事件切片。Infinity 已把输入、工具结果、子线程报告和订阅事件纳入这一模型;NullClaw 的主路径则是持有 Agent 的 session,在一次同步 turn 内循环调用模型与工具。为前者补本地 durable substrate 是基础设施开发;把后者改成同等语义,往往触及执行器、工具接口与恢复协议。[I01] [I02] [N01] [N06]

同时,必须否定三个容易导致错误选型的说法:

  • “Infinity 本地模式等工具也完全不驻留”不准确。 当前 local driver 在 awaiting_tool_result() 时走 AwaitInput,保留 driver;订阅存续但没有未决工具时才可退出。真正允许工具派发后结束整个执行宿主的是 step embedding。[I03] [I04]
  • “NullClaw 永不回收 session”不准确。 它有 idle eviction 和持久化恢复;但 TTL 不是硬字节上限,daemon 的回收又由处理计数触发,不能等同于定时到点释放。[N02] [N03]
  • “接 SQLite 就能让全部历史不进 RAM”不准确。 NullClaw 恢复仍全量读取历史;Infinity 当前 daemon 的 JSON 持久化也把已加载历史留在内存 store。二者都需要真正有预算的 prompt-context 读取与缓存治理。[N04] [I05] [I06]

建议决策:Infinity step 为长期运行时主线;NullClaw 保留为近期产品交付或边缘入口的候选,而不是默认同时运行两套 Agent loop。先做两周以内的可证伪 PoC,再决定正式迁移。 本文后面给出足以推翻这个建议的条件、改动位置和验收方法。

目标、假设与边界

“我们的目标”在本次提示里没有重新定义。本报告从 Rex 中同一 Infinity 项目的既有研究稿提取以下工作假设,它们不是本轮新确认的产品规格:本地/私有部署优先;长期保留大量会话;内存主要随活跃量而非全部历史量增长;工具可异步等待;重启不丢已接受的工作;模型位置与状态存储位置可以分别选择。该既有报告是上下文线索,不被当成本轮结论的证据。

NullClaw 仓库还存在另一条明确但不同的目标线:Telegram topic 路由、nullboiler 工作流编排、nulltickets 任务流。它出现在 2026-03-13 的集成路线图和分析中,不能自动替代上述运行时目标,也不能把路线图中的 Planned 当成现成功能。本报告将其作为“多渠道/业务编排优先”的独立场景。[N18]

目标维度本报告采用的含义必须另行确认的规格
本地优先worker、会话、队列可全部留在本机;不强制 AWS是否要求断网推理;模型权重是否计入内存
海量长期会话已归档会话数 N 很大,活跃切片数 C 可限流N、每日事件数、活跃率、历史体积及附件分布
低内存idle 之后不保留无界执行态、热历史和队列RSS 上限、采样周期、子进程/cgroup 计量口径
可靠恢复先 durable accept 再确认;崩溃后重放且可审计进程崩溃还是断电;可接受 RPO/RTO
多 Agent父子任务、异步报告、订阅与调度固定 DAG、动态协作还是一次性模型委派
产品可用可配置渠道、身份与权限、可观测和运维首批必须支持的渠道、租户、UI 与管理员能力

如果“< 1 MB 二进制、< 5 MB 整个生产系统 RSS”是不能松动的硬门槛,先暂停选型:本轮没有证明任何一个项目在目标负载下达标。NullClaw 的工程目标不能直接当作所有功能组合的实测承诺。

研究方法与证据等级

比较基于相同研究日期的本地源码快照,并用 git ls-remote 只读核对远端 HEAD/main;两者与本地 SHA 相同,没有拉分支、修改上游或把旧版本当最新。

项目锁定 commit最近提交日期本轮定位
NullClaw5f1cade05c19b6ecdfb9565ae3305e892e484da92026-10-05当前工作区
Hydro Infinity1abc6fcff1f186124f924b56aa92c3a3684c90c52026-10-28Rex 标签页的 Infinity 工作区

证据分为四类,阅读时应保持区分:

  1. 源码事实:可沿文中 N/I 编号打开固定 commit 的具体文件与起始行。负面结论限定在被审计的默认路径,而非声称所有部署都没有某能力。
  2. 本轮验证:明确列出命令、环境、通过/失败/跳过项;没有跑过的压测绝不写成实测。
  3. 上游样本:例如 Infinity 内存图表的原始数据,标明机器、负载和采样点,不冒充本机复现。
  4. 工程判断/设计提案:选型、工期、架构与验收目标都属于这一类,不是上游现成保证。

本轮重点读取 session 生命周期、Agent turn、store 契约、local router、step commit/dispatch、持久化实现、入出站队列、父子线程、工具执行、安全边界、模型适配、部署与测试脚本。这是源码级架构评估,不是完整安全审计、同负载性能竞赛或所有渠道的端到端验收。

产品层级:一个助手产品与一个运行时框架

NullClaw 更靠近“可直接部署的助手”:渠道入口、配对、配置、模型路由、工具、安全策略、记忆检索、cron 与 daemon 都在同一产品边界内。其扩展骨架是 Zig ptr + vtable 与 factory;扩展现有渠道、工具、provider 的路径相对清楚。[N07] [N08] [N09]

Infinity 更靠近“可嵌入的 Agent 执行基础”:ConversationStore、StateStore、InputSender、model provider、observer、thread config 等契约与执行器解耦;Infinity Code daemon/Web UI 和 AWS Lambda/CDK 都是 embedding,不是框架必选的宿主。可本地运行不等于当前本地宿主已适合海量会话。 [I01] [I07] [I08]

层级NullClaw 默认路径Infinity 当前仓库对二次开发的含义
用户产品多渠道助手、CLI/daemon、内置工具Infinity Code、Web/TUI、Slack 示例前者离通用助手交付近;后者离协作编码体验近
执行内核session-owned Agent;同步 turn looplocal actor router 或外部驱动 step后者更容易把等待变成持久化事件边界
长期状态SessionStore 与 Memory 分离ConversationStore 与 StateStore 分离两边都要分清 transcript、记忆、执行状态
平台设施有界 bus、渠道出站 outbox、策略与观测RAP、MCP bridge、回调、serverless embedding产品适配多不等于 durable scheduling 完成
宿主选择本地/容器/运行时适配器本地进程或 Lambda 等不能把接口名推断成部署能力与资源保证

因此,“功能数更多”“二进制更小”“Rust 更安全”都不是充分的选型理由。要比较的是目标所缺能力会落在扩展接口外层还是要求改动核心时序。

NullClaw:一条消息如何完成一轮工作

channel / gateway
  → inbound bus
  → daemon 分片队列 → 固定 worker
  → SessionManager.getOrCreate(session_key)
      → 新 session 时从 SessionStore 恢复历史
      → session 持有 Agent、provider 所有权与 history
  → 同一 session 的 mutex 串行化 turn
  → 模型请求 → 解析 tool calls → 同步逐个 execute → 再请求模型
  → persistTurn:用户/最终助手文本、usage
  → outbound bus → 渠道发送 / 最终消息 outbox

Session 直接拥有 Agent,不只是一个 ID。getOrCreate 在 manager 锁内完成查找、创建和历史恢复;session mutex 防止同一会话并发 turn,不同会话可并行。daemon 默认 4 个分片 worker,每分片入站容量 256;因此慢模型/慢工具会占住对应 worker,同分片其他会话可能遭遇队头阻塞。这不代表所有 gateway 路径都只有四并发,只描述 daemon channel dispatch 这条路径。 [N01] [N03]

普通 tool call 在 agent/root.zig 的 for (parsed_calls) 中直接调用 executeTool,Tool.VTable.execute 返回最终 ToolResult。这给小规模本地助手带来简单、直接、较容易推理的行为;代价是工具等待仍属于当前 turn 的生命周期。[N06] [N09]

一个值得开发者警惕的细节是 agent.parallel_tools:本轮全仓搜索只找到声明、解析、序列化与配置测试,未发现执行循环消费它;主路径依然逐个执行。不能把配置 round-trip 测试当成并行执行已实现的证据。 即使未来加上线程并行,也只是单轮工具并行,不会自然得到 durable callback 与进程重启续跑。[N10] [N06]

Infinity:必须区分 local 与 step

local 模式

InputSender 的进程内 channel
  → router 按 thread_id 路由
  → 按需构建 driver / Thread / HistoryManager
  → driver pool:FuturesUnordered
  → 模型完成 → sync history → dispatch tool
  → 无事可做且无未决 tool:退出 driver,移除 worker entry
  → 等未决 tool result:AwaitInput,driver 仍留在 pool

router 自己持有 driver futures,而非为每个历史 thread 永久留下 spawned task;已退出 driver 的内存与 worker entry 可以回收。新消息到达时再构建 driver。但这里的“idle”有精确定义:check_before_idle 若发现 thread.awaiting_tool_result(),返回 AwaitInput,不是 Exit;active subscriptions 本身则不要求 driver 常驻。[I02] [I03]

这修正了既有 Infinity 研究稿中过于宽泛的叙述:不能仅凭“工具异步”就断言 local daemon 在每次等工具时都释放执行态。 当前 local 模式仍可能保留一份 history view;底层内存 store 本身还保存规范历史。

step 模式

durable inbox → claim 有限批次
  → system.step(inputs, observer, deferral)
  → Thread::load:读取历史、状态、去重与配置
  → 执行一个有边界的模型/同步工具切片
  → sync:提交可持久化历史
  → dispatch 异步工具;后续结果作为新的 InputMessage
  → step 返回;宿主可释放 Thread 或退出整个进程

step 对输入按 thread 分组,先加载/过滤,再用 join_all 并行执行各组。它不是调度器:传入多少组,就可能同时持有多少组上下文;批次上限、全局并发、租户配额与 queue lease 要由 embedding 负责。另外,分组使用顺序 Vec 查找,大批不同 thread 的批次不宜无节制放大;外层小批处理比急着改内核更优先。[I04] [I09]

本地化的正确入口是这套 step API,而不是把 daemon JSON store 换成 SQLite 后继续默认常驻 local router,就宣称完成了规模化改造。

内存:应该比较什么,而不是比较什么

先定义变量:N 是历史会话总数,H 是历史总字节,C 是同时执行切片数,W 是等待工具的 thread 数,K 是热缓存字节,Q 是排队字节,P 是每个活跃上下文及请求缓冲。

目标模型:RSS ≈ runtime_base + C × P + K_max + Q_ram_max + DB_client_buffers
          持久化历史 H 与 durable backlog 放磁盘,不随 N 全量镜像进 RAM

NullClaw 当前:共享运行时 + 仍驻留的 session/Agent + 活跃 worker 栈与缓冲
              + 恢复历史的瞬时峰值 + 子任务/出站积压

Infinity local + 内存 stores:runtime + H + dedup/metadata/subscriptions
              + C 的执行视图 + 等未决工具的 W 个 driver + 无界 channel 积压

Infinity step + 真正磁盘 store:更接近目标式;但有界读、限并发和 durable queue 必须补齐

公式是架构分析,不是经压测拟合的预测模型。N 不出现在目标式中也不意味着数据库索引、文件描述符、缓存管理和去重表没有成本;这些成本必须外置或有明确上界。

NullClaw 已有回收,但不是硬上界

默认 session_idle_timeout_secs = 1800。evictIdle 扫描 map 并跳过运行中的 turn;daemon 在每 100 次计数触发时调用,不是独立定时器。其他 channel loop 也有调用点,但不改变“TTL ≠ 全局字节预算”的判断。停止流量后不能据此承诺准确 30 分钟内回落;短时间涌入大量不同会话仍可能形成高水位。[N02] [N03] [N10]

此外,恢复是在 manager 锁内调用 loadMessages,SQLite 实现是无 LIMIT 的 ORDER BY id ASC;即使后续 compaction 缩小 history,也已付出了全量读取、分配和锁持有成本。极长历史唤醒可能影响无关 session 的创建延迟。[N04]

Infinity 当前持久化也不是有界缓存

PersistentConversationStore 包装核心 InMemoryConversationStore,使用 loaded 集合追踪已读取 thread;正常读取路径没有按字节/TTL 卸载这些历史。该 wrapper 的 delete/remove 操作与热缓存淘汰不是一回事。store 中的规范历史、driver 中的历史 view 也可能同时占用内存。[I05] [I06]

StateStore 的 processed IDs、metadata、subscriptions 是另一份长期状态;只替换 ConversationStore 而让 StateStore 仍无界,不能做到 RSS 与 lifetime event 数解耦。[I10]

性能证据:本轮实测与上游样本

本轮可以复现的结果

环境:macOS Darwin / arm64;Zig 0.16.0;rustc 1.97.1、cargo 1.97.1。未使用真实 LLM 压测,未启动业务渠道。以下数字不代表同工作负载的横向性能。

项目/命令结果能证明什么不能证明什么
NullClaw zig build -Doptimize=ReleaseSmall成功;默认构建二进制 4,889,528 B,约 4.66 MiB当前宿主/默认功能集可构建不证明全部发布裁剪组合都大于 1 MB
NullClaw --help,/usr/bin/time -lexit 0;max RSS 2,441,216 B,约 2.33 MiB极短 CLI 路径开销不是 daemon、会话并发、工具子进程或模型内存
NullClaw 全套测试,清除进程代理后7,490 通过、9 跳过、0 失败;无泄漏报告当前测试可通过;详见验证章节不是目标负载已达标
Infinity core 单元测试108 通过、0 失败核心状态机与现有回归测试通过不是 daemon、云设施或目标平台全验收
Infinity RAP bridge 单元测试15 通过、0 失败现有 callback 映射/bridge 测试通过不证明公网鉴权与重放防护已产品化

NullClaw 主测试进程的构建摘要给出 MaxRSS 249M,高于 AGENTS 中“test well under 50 MB”的工程期望。必须分开理解:这不是生产 runtime 的 RSS,也不是可忽略的“已满足协议”——它说明该测试预算在本次环境下没有达成。

Infinity 上游 80k 样本的准确解读

仓库 MemoryChart.tsx 指向 agent_scale.rs:AMD EPYC 9R14 单线程;AGENTS=80000 TURNS=20 WAVE=4000;内存 stores、进程内 scripted model;每个合成 turn 两轮 completion 加一次异步工具回环;每波完成并 idle 后采样 RSS。[I11]

累计 Agent上游记录 RSS(十进制字节)
05,304,320
4,000692,879,360
8,0001,101,406,208
12,0001,507,291,136
40,0004,348,772,352
80,0008,406,446,080

全区间平均增量 (8,406,446,080 − 5,304,320) / 80,000 = 105,014.272 B/agent,约 102.55 KiB/agent。这不是固定常数;前几波并非严格线性。样本说明 idle driver 开销可以回收,也同时说明内存 store 中的历史仍随会话数增长。不能用该图证明 80k 个真实活跃 Agent 能在几 MB 内存中运行。

本轮没有把 Linux /proc RSS 采样脚本硬套到 macOS,更没有用 NullClaw 的 --help 与 Infinity 的 80k 历史样本作速度/内存排行榜。两者的真实胜负要用本文的统一 workload 验证。

历史、记忆与恢复:三件不同的事

NullClaw 的 Memory 提供语义/关键词记忆操作,SessionStore 则提供 transcript 与 usage。向量检索、FTS、衰减、rerank 等很有价值,但不会自动变成可恢复的执行日志。SQLite/Redis/Postgres 等 backend 名称也不保证都支持 session store:registry 用 capability 显式区分。[N05] [N11]

Infinity 的 ConversationStore 保存消息、祖先线程关系与 compaction;StateStore 保存 processed IDs、metadata、订阅、待选项等。它更接近执行语义所需的状态分解,但 trait 被拆开不等于跨 trait 写入天然原子。[I01] [I10]

语义NullClawInfinity规模化改造要求
完整 transcript主 turn persistence 保存用户与最终助手文本带类型消息、tool call/result、thread 关系定义规范日志,不能把 UI 渲染文本当执行状态
在途工具普通同步 turn,spawn 另走进程内任务step 历史先 commit 再 dispatch还要有持久化 dispatch intent 和恢复扫描
去重有局部/渠道专用能力,非统一入站 durable inboxprocessed IDs;工具结果可对历史 tail 去重稳定 ID、唯一约束、保留窗口与事务
compaction活跃 history 压缩与 trimsummary / thread cutoff / ancestor context摘要必须持久化、有版本且可重建
记忆检索内置检索体系更完整本轮未发现同级通用检索产品层单独实现授权过滤、索引一致性和 token 预算

NullClaw persistTurn 当前逐项写 user/assistant/usage 并 catch {};不会返回“持久化失败”。因此成功生成回复不等于会话已 durable。且这一条主路径没有保存整个逐工具执行日志,重启恢复不等价于从任意 tool 中间点续跑。[N12]

Infinity HistoryManager.sync 先 append messages,再调用 StateStore 保存需显式去重的 ID;后者结果被忽略。daemon 的 save_thread* 则直接 std::fs::write(...).ok()。这两个事实都要求正式本地后端重新设计错误传播与事务边界,不能因 Rust 类型系统而跳过。[I12] [I13]

Prompt-context:真正的低内存必修课

NullClaw 默认 max_history_messages = 100,有 token threshold、compaction、保留最近消息和 hard trimming;Infinity 有 compaction summary、祖先 cutoff 和 fresh-context 子线程。这些是有效的上下文治理机制,但发生在读取之后的压缩,不保证读取峰值有界。[N10] [N13] [I14]

Infinity load_history_up_to(start_from, up_to) 主要是消息序号范围,不是 byte/token 限制;load_history_with_ancestors 返回完整 Vec。NullClaw 虽有分页的 loadMessagesDetailed,session restore 使用的仍是无界 loadMessages。所以两边都不能只靠已有分页 UI API 宣称执行器已 bounded。[I06] [N04] [N05]

建议新增的能力不是泛化的“数据库层”,而是一个有具体调用者的读取契约:

loadPromptContext(thread_id, budget)
  输入:max_bytes、目标 token budget、snapshot/version、tenant
  输出:system/config + durable summary + recent closed messages
       + 必需的未决 tool-call/result 闭合片段 + 受限检索结果
  约束:单消息也有尺寸上限;超长工具输出落 blob;不先全量加载再截断

消息条数只是辅助限制,单条工具输出就可能是几十 MB。祖先线程继承还会放大读取;fresh context 能切断继承,但不能代替统一预算。工具调用与结果必须保持协议配对,summary cutoff 必须与快照版本一致。完整审计回放另用分页流式接口,不必塞进模型 prompt。

队列、背压与调度公平性

NullClaw bus 是容量 100 的 BoundedQueue;daemon 分片队列容量 256、固定 worker 4。这是实在的条目级背压,不应被忽略。但容量按条目而非字节;模型、工具和媒体 payload 仍可能让小数量消息变大。bus 和分片队列在进程内,没有统一 durable inbound accept/claim/ack 语义。[N14] [N03]

Infinity local 的入口、每线程输入、订阅请求和 lifecycle 通知使用 unbounded channels;router 没有在本轮审计路径中提供全局 semaphore。异步 future 比 OS 线程轻,但无界生产者仍能把内存填满。step API 也不是自动限流层。[I02] [I09]

风险NullClawInfinity必须实施的控制
突发新会话未淘汰 session 增长driver/store/输入 channel 增长admission control、磁盘 backlog、字节预算
同会话顺序session mutex / 分片路径local router 或外层 queue 保证同 thread 单 lease + fencing,不同 thread 公平调度
长工具阻塞占住 turn / 分片 workerlocal 保留待结果 driver;step 可退出durable tool intent、callback 唤醒、超时核对
过载进程内 bounded 等待/timeoutembedding 自定;local 可无界堆积明确 429/503 或等待策略,不静默丢弃
大租户挤占本轮未证明完整租户调度本轮未证明完整租户调度每租户并发/字节/模型成本额度

更合理的调度单位是“有限成本的切片”,而不是一个直到完成才归还 worker 的整段任务。每 thread 可串行,跨 thread 用轮转/公平队列;不要因为同一个 hash 分片恰好碰到慢工具而阻塞所有邻居。

故障模型:可重放不等于 exactly-once

Infinity 的 step_no_defer 明确把 history sync 放在工具 dispatch 前,这避免结果比 tool-call 记录更早抵达。但“历史有记录”和“外部工具一定执行”之间仍存在跨进程窗口;它不是分布式事务。[I04]

NullClaw 已有渠道最终消息 outbox:enqueue 会持久化,支持 claim、失败退避、最多 5 次尝试与 delivered 记录。它有实际价值,但它是 outbound delivery,不是任意工具执行的 durable outbox,也没有自动与 turn persistence 共用一次事务。该实现将 jobs 放在 ArrayList 中并重写 JSON,积压很大时仍需磁盘队列化。[N15]

故障窗口当前实现能依赖的部分仍需补的机制
接到用户输入后、写日志前崩溃都不能仅凭内存入口保证恢复inbox 落盘后才返回 accepted;外部平台 ack 时序审查
历史已 commit、tool 尚未发出Infinity 历史保留意图线索durable dispatch intent、lease 到期重扫、幂等 call ID
tool 已执行、回包前网络断开两边都不能猜测外部副作用是否发生幂等重试或状态查询;无法确定时标 unknown
callback 已到、ack 前崩溃Infinity 有 dedup 契约基础callback inbox 原子落盘、稳定 event ID、重复投递测试
历史写成功、dedup 写失败Infinity 两个 trait 写入分开且后者忽略错误同库事务/UoW,或可证明的 replay-safe 提交协议
回复发送成功、delivered 记账前崩溃NullClaw outbox 可重试但可能重复发送下游幂等 key 或明确 at-least-once 用户语义
磁盘满/权限错误/JSON 半写默认 wrapper 部分错误被吞掉错误向上传播、durable health、原子写/事务与故障注入

语义底线应是:已接受的输入不静默消失;内部可重放;对外副作用幂等或可核对;不确定状态可见。 不要承诺一个本地 SQLite 事务就能让邮件、支付、shell、第三方 API 全部 exactly-once。

另一个具体细节:Infinity RAP bridge 为 tool result 使用稳定 call ID,但对 subscription event 生成新的 UUID,因为协议事件本身没有逐事件身份。网络重投若携带同一业务事件,不能凭这个新 UUID 自动去重;需要在业务 envelope 中补 stable source-event ID。它不表示相同内容的两次合法事件应该被错误合并。[I15]

多 Agent:不能只看有没有 spawn

NullClaw 既有 delegate 也有 spawn,不能把它说成单 Agent 项目。delegate 主要对命名 agent/provider 发起模型请求;spawn 通过 SubagentManager 创建后台任务与 OS 线程、返回 task ID,并把完成结果路由回来源 session/channel。默认子任务并发 4,单任务工具迭代 15。[N16] [N17]

但 SubagentManager.tasks 是进程内 map。本轮在正常完成/通知路径没有发现持久化任务状态或已完成 task 的淘汰;notified 标志不会释放结果与线程 handle,最终由 manager deinit 统一回收。这限制长期后台服务;并发上限限制的是 running 数,不等于 lifetime 完成结果有界。[N17]

Infinity 把 parent-child thread、继承/fresh context、report、订阅和 compaction 纳入核心会话语义。RAP 让工具结果、流事件和订阅回调重新进入输入通道,而不是一定让父 turn 一直等待。step 模式适合低活跃率的大量长期任务;local 模式的等待保留行为仍要单独计量。[I14] [I16]

协作需求NullClaw 二次开发Infinity 二次开发
换模型做一次子任务已有 delegate,改动少配 thread/model source,也可完成
少量后台工具 Agent已有 spawn,需清理与任务恢复已有线程/报告机制,需宿主配额与持久化
数万长期等待任务线程/turn/任务 map 语义需要显著改造step 生命周期合适;durable scheduler 仍需开发
固定业务 DAG/人工审批/票据 FSMnullboiler/nulltickets 是候选集成,不是本仓库证明核心 thread 不是完整业务工作流引擎,仍要独立控制面
协作编码与分支隔离需要较多产品层补充Infinity Code 的 stacked sandboxes/终端/Web 资产更相关

多 Agent 工具只是执行原语;预算分配、重试策略、审批、租户隔离和业务结果归档都是产品职责,不会因支持 spawn 自动出现。

工具、模型与渠道的复用成本

工具协议

NullClaw 的本地 tool vtable 简洁、直接,输入 JSON args、输出 ToolResult;安全策略与运行时上下文可在工具层落地。要加一个普通工具通常是实现结构体并 factory 注册;但把工具改成“已受理、未来回调”会影响调用结果、会话状态和调度,不是单个 adapter 即可解决。[N09]

Infinity Tool<M> 与 InputSender、RAP/MCP bridge 的边界更贴合异步执行;需要把本地进程工具变成受控 runner/服务,完成后发事件。MCP 兼容层降低接入成本,但不会把所有同步 MCP 工具自动变成跨重启可续跑服务;持有连接的 bridge/runner 也必须计入资源账本。[I16] [I17]

模型适配

NullClaw 拥有更丰富的 product-level provider factory、API key 解析、兼容 endpoint、fallback/router、不同工具格式与错误处理经验。Infinity 的 ModelProvider 协议独立,Bedrock 和 rig bridge 是具体实现,不强制 Bedrock;但已有 NullClaw 特有 provider 行为不能直接按文件拷贝到 Rust。[N07] [I18]

迁移要验证 streaming delta、tool-call ID/JSON 增量、thinking blocks、取消、context overflow、rate limit、timeout 与 usage。Infinity 文档明确 runtime 不统一设置 provider timeout,provider 应自行实现;这应纳入我们自己的 deadline 契约,不能无限等待。[I18]

渠道与业务

当前 NullClaw 的 Telegram、Discord、Slack、飞书/企业微信/钉钉等渠道及路由资产,对近期助手落地更有价值;Infinity 仓库中的 Slack embedding 不等于覆盖整套渠道。反过来 Infinity Code 的 Web/终端、diff 与 sandbox 工作区是另一类产品资产,不能因 NullClaw 渠道多就忽略。[N08] [I08]

渠道迁移最易低估的不是发送 API,而是:thread/topic/account 映射、重试去重、流式草稿转最终回复、附件大小、交互按钮、用户身份/allowlist、主动推送和配对权限。应按真实用户路径验收,而非以“可以发一条消息”作为迁移完成。

安全与多租户:两边都需要明确威胁模型

这是高风险设计评估,不是漏洞利用或完整审计。NullClaw 已有 PairingGuard、bearer 校验、公网绑定的鉴权判断、工具策略、路径/命令限制、SSRF 处理、脱敏与多种 sandbox。相对成熟的产品边界有复用价值,但配置、例外与实际调用链仍要验证。[N19] [N20]

例如 http_request 的空 allowed_domains 并非“拒绝全部外网”,而是允许安全检查通过的外部域;显式 allowlist 的域可访问私网,并跳过相应 SSRF/DNS pinning。这是可信操作者配置的能力边界,不能在报告里泛化成“永远禁止私网”或“全系统默认 deny all”。[N20]

Infinity daemon 默认 WebSocket 绑定 loopback;本轮审阅的 HTTP upgrade 路径没有看到配套 bearer/Origin 验证,因此不能把 INFINITY_WS_BIND=0.0.0.0 当作安全的公网服务开关。RAP 规范将认证交给具体实现,并明确 callback 应认证;loopback callback 也不是多租户授权体系。[I19] [I20]

Infinity local sandbox 默认启用 macOS sandbox-exec / Linux bwrap,但策略重点限制写入目录;macOS 规则包含 allow default,Linux 有 read-only root 等设置。这不是“任何文件都不可读、网络自动全隔离、可运行敌对租户”的证明。工作区隔离和安全沙箱应分别评估。[I21]

威胁/边界需要的产品控制验收示例
伪造 callback 唤醒 Agent短期 scoped token/HMAC 或 mTLS;call 与 tenant 绑定别的租户的 call ID 即使存在也必须拒绝
callback 重放与洪泛stable event ID、有效期、大小限制、速率/字节预算重复合法回调不重复执行;过期签名不能注入
prompt injection 导致越权工具工具能力授权独立于模型文本;敏感操作审批tool description/结果无法提升权限
工作区或密钥泄漏最小环境变量、文件/网络隔离、日志脱敏非授权目录读取和跨会话检索必须失败
多租户资源挤占tenant-aware scheduler、DB 查询与 cache key 强制分域恶意大租户不能饿死其他租户
任意代码执行容器/OS 沙箱、进程树限额、kill deadlineshell 超时后子进程与后代一并回收

NullClaw 的内存安全依赖所有权约定与测试;Infinity 的 Rust 能降低悬垂/数据竞争风险,但不能消除业务鉴权、无限队列、落盘失败和外部副作用重复。语言安全不能代替系统安全。

部署、依赖与工程维护

NullClaw 的 vtable/factory 架构适合保持模块边界,运行产物较集中;当前默认 build 包含 vendored SQLite、外部 Zig websocket/wasm3 依赖,实际 provider/tool 路径还可能调用 curl 或平台命令。因此“零依赖”应解释为具体裁剪配置的运行形态,不是仓库没有构建依赖与外部可选工具。[N21]

Infinity core 的 Cargo.toml 不要求 AWS SDK,但包含 Tokio、RAP、Rhai 等;完整 workspace 的 Lambda、CDK、Web UI 与 sandbox 工具链更重。core 可裁剪、daemon 完整产品栈、AWS 示例栈应分开计成本。 Rc、LocalSet、spawn_local 出现在 local embedding;不能把 Tokio 直接理解为所有工作自动分摊多核,多核扩展可以先用多 worker 进程与 thread lease。[I02] [I07] [I22]

维度NullClawInfinity
仓库源码统计src/**/*.zig 293 文件、289,734 行crates/**/*.rs 168 文件、57,187 行
测试声明粗计^test " 7,565 块#[test] / #[tokio::test] 匹配 373 处
正确解释更大产品表面、更多集成回归负担核心更集中,但另有 TS/Web/CDK 表面
错误解释不能据行数断言可靠性更高不能据声明数推断缺乏覆盖或更低维护成本
工具链风险固定 Zig 0.16.0;allocator/vtable 生命周期要严守Rust/async trait/LocalSet 学习成本;SDK/前端依赖面
许可证观察MITApache-2.0,含 NOTICE 与 THIRD-PARTY

统计包含测试且不代表可比“业务逻辑量”;编译条件、宏、文档测试使声明数与实际执行数不同。许可证这里只记录仓库文件,正式分发仍应做依赖和修改通知合规审查,不构成法律意见。[N22] [I23]

在本轮没有修改任何 Zig/Rust 生产代码、没有版本升级、没有 commit/tag,也没有把已有 Infinity 报告目录作为待覆盖的输出。最终报告是单独的静态站;部署报告本身不意味着两个 Agent runtime 适合跑在 Pages。

决策矩阵:先过硬门槛,再谈权重

不提供伪精确的“总分 8.7 对 7.9”。权重未知时,数字只能把假设藏起来。先用场景与硬门槛决策:

场景/硬门槛更合适的基础选择理由会推翻结论的条件
近期多渠道个人/团队助手,少量后台任务NullClaw渠道、配置、工具、策略与现成产品价值高真正负载以大量长工具等待为主,session/worker 模型成为瓶颈
大 N、小 C、本地持久化、低 idle RAMInfinity step执行切片可退出,输入/状态契约已有有界 store + queue PoC 仍达不到预算,或必需渠道移植成本压倒优势
海量长工具/订阅、动态子线程协作Infinity step结果重新作为事件,线程语义内生全部工具实际同步且可在短 turn 内完成
首发强依赖 Telegram topic/nullboiler/nulltickets倾向 NullClaw目标与现有产品边界更贴近先核实外部仓库能力;不能仅信旧路线图估工期
协作编码、Web/终端、sandbox diff倾向 Infinity Code仓库已有相关宿主资产我们的场景与其会话/文件/权限模型不匹配
严格 < 1 MB 默认二进制、全系统 < 5 MB当前均未证明本轮默认 NullClaw 产物已超 1 MB;未做极限裁剪对测专项裁剪与目标硬件 workload 证明可达
零基础设施开发、生产级 durable exactly-once当前均不能直接给出两边都有故障/事务窗口缩小语义或引入经过验证的外部执行基础

若需要正式加权,由业务先确认优先级,再对“已实现 / 可外层补齐 / 需改核心 / 未验证”打分。核心目标下,生命周期匹配、持久化边界、上下文有界性应优先于 provider 数量或宣传基准;短期助手目标则可能反过来。

推荐架构:本地 durable substrate + Infinity step

以下全是建议架构,尚未在本轮实现。可以不依赖云服务,初期一个本机服务与 SQLite 即可,但接口要按可恢复的执行边界设计。

渠道 / CLI / Web
  │ 鉴权、大小限制、tenant/thread 标识、stable event ID
  ▼
local durable inbox ── lease / fencing / fair scheduling ──┐
  │ 已落盘才确认                                          │ C ≤ 上限
  ▼                                                       ▼
SQLite / PostgreSQL ◄── bounded Conversation/State ── Infinity step workers
  │                    + prompt-context budget            │
  │ messages / summaries / dedup / leases                 │ commit intent
  │                                                       ▼
  ├── tool outbox → 受控 runner / RAP tool → authenticated callback → inbox
  └── delivery outbox → 渠道 sender → 最终回复 / 状态事件

blobs:大工具输出/附件原文;有授权的引用和摘要进入会话
observability:queue bytes、active slices、RSS、lease age、unknown effects

三个存储语义不能混用:inbox 表示输入已被接受;tool outbox 表示计划执行的外部动作;delivery outbox 表示发给用户/渠道的输出。可以同库,但必须独立状态机与指标。历史和去重也不应变成所有 thread 常驻内存的 mirror。

SQLite WAL 支持读写并行但同时只有一个 writer;适合单机起步,不承诺无限吞吐/多机多主,也不应把 WAL 当网络共享磁盘上的分布式协调层。若写并发或 HA 超出单机边界,再迁移自管 PostgreSQL/队列,而不是为了 Infinity 被迫上 AWS。[E01]

“数据库本地”“worker 本地”“模型本地”是三条独立轴:远程模型 API 不要求会话上云;本地模型的权重/KV cache 也不能藏在 runtime 的几 MB 指标之外。

数据模型与事务时序

建议最小持久化实体如下。它们是设计草案,不是新增配置项或承诺的稳定 API:

实体关键字段/约束为什么需要
threads(tenant_id, thread_id)、parent、status、context_version权限分域、线程关系、快照一致性
messagesthread、sequence、message_id、typed payload/blob ref;唯一约束可重放日志、去重、分页与审计
summariessource cutoff、version、模型/格式、content重启后恢复同一上下文,而非丢掉压缩成果
inboxevent_id 唯一、payload、status、attempt、available_at接收确认、可重试与延迟唤醒
thread_leasesowner、lease_until、单调 fencing token同 thread 串行;过期 worker 不得覆盖新结果
tool_calls / tool_outboxcall_id、intent、state、idempotency key、deadline重发派发、回调匹配、unknown 状态核对
delivery_outboxoutput_id、channel/topic/account、attempt、receipt用户回复独立重试,不反向重跑整个 Agent
dedup / retained IDssource、stable ID、保留窗口/唯一索引重放可吸收,且 lifetime ID 集合不无限进 RAM

建议切片时序:

  1. 接收事务:鉴权通过,把 event_id 与 payload 写 inbox;commit 后才向入口确认。重复 event 返回原 receipt。
  2. claim 短事务:选 ready 输入、持有 thread lease/fencing;取有限 batch。不要在模型 HTTP 期间一直持有 SQLite 写锁。
  3. 执行切片:读取有界快照;调用模型/安全的同步工具;构建待提交 typed messages 与 action intent。设置 wall-clock、模型 token、工具输出预算。
  4. 提交短事务:确认 fencing/version 仍有效,写 messages/summary/processed IDs/outbox 并推进 inbox。跨 store 的 commit unit 是当前 trait 使用方式需要补齐的点。
  5. 异步 dispatch:从 tool outbox 领取,带稳定 call_id;成功、失败或未知结果分别记账。callback 先落 inbox 再 ack。
  6. 终态投递/恢复:输出进入 delivery outbox;worker 崩溃释放 lease 后重试,超期 action 查询外部状态或标 unknown,不猜成功。

不能只是把三个 trait 分别连到同一个 SQLite connection,就声称具备上面的原子性:当前 step 过程中有多次 store 调用与外部派发,必须在 embedding/提交 hook 中显式表达事务单元、错误传播和恢复边界。不要用一个跨 LLM 的大事务掩盖时序问题。

改造清单:具体改哪里

如果选择 Infinity

优先级改动位置最小改动/新增组件不应顺手做的事
P0traits.rs、HistoryManager.syncdurable 本地 Conversation/State store;明确统一提交单元;dedup 失败显式报错继续复用吞错的 daemon JSON wrapper 作为权威数据源
P0ConversationStore 读取与 Thread::load有界 prompt context、summary cutoff、blob refs先 SELECT 全量再按 token 截断
P0InputSender + 新 local schedulerdurable inbox、claim/lease/fencing、限批/限并发将 local unbounded channel 当 durable queue
P0step_no_defer dispatch 边界outbox intent、恢复扫描、回调稳定 ID把 commit-before-dispatch 误当 exactly-once
P0callback/runner 边界scoped auth、尺寸/速率限制、deadline、租户隔离直接公网暴露 daemon websocket
P1provider / observer / ThreadConfigSource模型期限、成本/租户配额、指标与审计默认引入全部 AWS workspace 与 Code UI
P1渠道 adapter / 记忆检索服务首发渠道、回包路由、最小可用记忆检索一口气移植所有 NullClaw provider/channel
P2运行宿主视负载加多进程、自管 Postgres、备份与升级工具未证实单机不足就上分布式系统

核心接口已匹配目标,但错误传播、统一事务、有界读取与 scheduler 是实质性开发,不是“加一个 SQLite 文件”两天即可完成。源码导览对应 [I01] [I04] [I09] [I12]。

如果选择 NullClaw

目标层级具体改动是否触及核心
保持当前助手模型、先止内存增长session entry/byte 上限、真正定时 eviction;恢复用有界 summary+窗口;缩短 manager 锁内 I/O中等:session/restore/daemon
长期运行的 spawn任务结果 TTL/字节预算、已完成线程回收;任务与完成通知持久化中高:SubagentManager 与 bus
可靠交付persistTurn 错误向上传播;事务化 transcript;durable inbox 与 delivery outbox 对齐高:session/turn/gateway/渠道 ack
同轮工具并行明确消费 parallel_tools;限制并发与输出;可取消中高,但仍不是 durable async
达到 Infinity step 的执行语义ToolResult 增加 pending/dispatch 概念;拆 turn 状态机;序列化未决工具、恢复点、父子报告;引入统一事件入口高:跨执行器与 vtable/工具协议,不是普通插件

vtable/factory 是 NullClaw 的稳定骨架,应优先沿扩展点做外层增强;但工具等待和 turn 重入语义超出当前简单工具接口。若为了追求目标重写一套 step engine,原先“现成功能多、启动快”的优势会被核心改造成本削弱。[N01] [N06] [N09] [N17]

混合方案:可行,但不要默认双内核

“NullClaw 接渠道,Infinity 执行长期任务”有现实价值,前提是边界单一:谁是 conversation/执行状态的唯一权威,谁就拥有 Agent loop。另一边只做受限 ingress/egress 或独立工具服务。

推荐的最小跨进程 envelope:

{
  "version": 1,
  "event_id": "source-stable-event-id",
  "tenant_id": "tenant_a",
  "thread_id": "thread_a",
  "type": "user.message",
  "payload_ref": "local-blob-reference",
  "reply_target": {"channel": "telegram", "account": "bot_a", "topic": "topic_a"},
  "trace_id": "trace_a"
}

这是提议的 envelope,不是当前 /api/send、/api/worker、/api/callback 的现成实现。本轮没有在 gateway 找到这三个旧路线图端点;已有 /a2a、/webhook 等 API 也不能自动提供相同鉴权、租户、持久化确认和回包语义。先写契约测试,再决定复用哪个入口。[N18] [N23]

本机优先用 Unix socket 或带认证的 loopback RPC,不共享内存指针/vtable,也不在两个进程间各自维护一份可独立修改的 transcript。跨主机通信按仓库要求使用 HTTPS;跨语言 in-process FFI 会增加 allocator、panic/错误、ABI 与线程约束,不建议作为首版捷径。

混合方案增加两套升级、配置、日志、权限与排障面;若首发只需要一个渠道,直接在 Infinity embedding 做 adapter 可能更便宜。只有必需的 NullClaw 产品资产复用收益明显时,才用混合,而不是为了“取两边优点”无条件拼接。

工作量、人员与阶段验收

以下是工程估算,不是上游承诺,也不是固定报价。假设两名熟悉 Rust/Zig 与数据库的开发者;首发单机、一个主渠道、一类异步工具;不包含完整 UI 重做、多租户商业化、跨机 HA 或移植全部 provider。

方案粗略投入区间最大不确定性
NullClaw 助手加固,不改执行范式4–7 人周恢复历史、spawn 清理、现有渠道语义与故障行为
Infinity step 本地 durable MVP10–16 人周事务边界接入、上下文读取、runner 恢复、首发渠道
NullClaw 改成同等级 durable step 内核14–24 人周工具/turn 协议重构、跨子系统回归面、兼容性
双运行时混合在选定主线之外额外预算RPC/身份/回包映射/双运维,不能假设为零

这些区间不能直接除以人数得到日历时间;PoC 的结果可能大幅调整它们。真正的成本判断是“改契约/核心时序还是补适配器”,不是只看语言上手速度。

首先做能推翻结论的 PoC

阶段 A:1–2 周内完成选型验证,而非声称完成生产版。

  • 一个真实磁盘 Conversation/State store,summary+窗口读取有 byte 上限;不使用 full-history mirror。
  • 一个 durable inbox、单 thread lease、全局有限 worker;接入 Infinity step;一个可延迟/可重复回调的假工具。
  • 相同 fixture 驱动 NullClaw 基线路径;测冷启动、长历史唤醒与 burst 后回收;不调用真实收费模型。
  • 做 kill/replay、重复 callback、disk-full 三项故障注入;若关键语义必须大改引擎而超预算,重新评估。

阶段 B:可靠本地 MVP。 工具/回复 outbox、错误传播、deadline、备份恢复、指标;首发渠道走完整端到端,保留回滚通道。

阶段 C:迁移与扩展。 分批转换 typed transcript/summary,校验条数、顺序、工具配对和租户;小比例新流量 canary,旧运行时只读或停写,避免双主;达到单机瓶颈后再引入多 worker/自管数据库。

停止条件:目标 workload 的 RSS 无法平台化;无法定义可审计的副作用恢复;渠道迁移成本超过预算;或产品优先级已变成“近期助手交付”。出现任一项,应调整方案,而不是维护既定结论。

统一压测与故障注入规范

本节是建议验收方案,尚未执行的数据不得作为达标结果。先由产品确认数值门槛,再跑同机、同 provider stub、同 fixture、同活跃率、同完整进程树的 A/B。

场景建议负载矩阵观察点/通过条件
大 N、小 CN 取 1k / 10k / 100k;C 固定 8 / 32RSS 不随归档 N 线性常驻增长;DB 大小增长可解释
长历史唤醒每会话 10 / 1k / 100k 条历史prompt 读取字节、峰值 RSS 与延迟有界;不先全量读
长工具等待延迟 1s / 60s / 模拟小时;固定完成流量分开看 local/step 的 driver 数、W 对 RSS 的影响
突发输入10 倍短时流入,包含新 threadbacklog 到磁盘;有过载信号;队列字节受限
大输出/附件1 KiB / 64 KiB / 10 MiB 工具结果大对象落 blob;prompt/context 严格限额
父子与订阅高 fan-out、重复/乱序/迟到事件fan-out quota、稳定去重、关闭 thread 后行为可解释
crash/replay在 accept/claim/commit/dispatch/ack 每点 kill -9已确认事件可恢复;重复副作用有幂等/核对机制
磁盘/网络故障disk full、权限拒绝、损坏记录、429/断流不静默成功;重试有上限;unknown 状态与告警
长时运行持续 24–72 小时的创建/完成/淘汰task/result/dedup/连接数不过 lifetime 单调增长
隔离与公平恶意大租户 + 正常租户授权边界、p95 饥饿、缓存/队列/模型成本隔离

至少记录:进程及子进程 RSS/PSS、活跃/等待 driver、worker 数、缓存/队列条目与字节、每次历史读取条数/字节、DB/WAL/blob 大小、冷/热 p50/p95/p99、模型 token 与工具成本、retry/lease age/dead-letter、磁盘 fsync 延迟。

把“空闲”“已归档”“等待工具”“有订阅”“正在模型请求”分别计量。RSS 还会受 allocator 保留与 OS 页面回收影响,不能只看对象数;测稳定窗口与峰值,并注明是否 trim allocator。关闭内存 store 的合成基准和真实磁盘方案也不应混作一个系列。

本轮验证台账与限制

验证命令/处置结果
项目定位Rex window ls / block ls / 只读 pwd找到已打开 Infinity 项目;未向其他运行中终端发送输入
版本核对两仓 git rev-parse HEAD 与 git ls-remote ... HEAD refs/heads/main本地与远端 SHA 一致;未 fetch/改分支
NullClaw 初次测试zig build test --summary all最初依赖 git 传输失败;从同 commit 官方归档填充 Zig cache 后恢复,不改 manifest
NullClaw 代理环境测试同上,原有代理环境7,489 通过、9 跳过、1 失败;本地 curl resolve fixture 走代理导致 GET exit 22
NullClaw 隔离代理重跑env -u http_proxy -u https_proxy -u HTTP_PROXY -u HTTPS_PROXY -u ALL_PROXY -u all_proxy zig build test --summary all7,490 通过、9 跳过、0 失败;无泄漏报告;没有修改失败测试或产品代码
NullClaw releasezig build -Doptimize=ReleaseSmall --summary all成功;产物大小与 --help RSS 见性能章节
Infinity 离线尝试cargo test -p infinity-agent-core --lib --offline缓存缺 strkind,未进入测试;不把它写成代码失败
Infinity corecargo test -p infinity-agent-core --lib --locked108 通过、0 失败;测试执行约 5.06s,不含编译时间
Infinity RAPcargo test -p rap-protocol -p infinity-rap-bridge --lib --lockedbridge 15 通过;rap-protocol 此命令下 0 项,不可加成覆盖数
Infinity 全量脚本./check.bashprerequisite 阶段缺 jj,未跑完整脚本;未宣称 workspace/daemon/e2e 全通过
官方规则Cloudflare Pages limits/pricing、SQLite WAL 官方文档2026-10-31 抓取核对;仅作为部署/存储规则来源

未做:真实渠道发送、真实 LLM 负载、跨进程生产恢复演练、Infinity daemon/Web e2e、全 workspace/云环境测试、同负载 A/B RSS、目标硬件极限裁剪、安全渗透与依赖供应链全审计。上游 80k 数据没有在本机重跑。

测试输出中的故障注入 warning 不是实际生产故障;统计以最终 summary 为准。仓库说明中的源文件/测试数量快照已过时,本文用当前源码统计和实际测试结果,不沿用“245 文件 / 5,640+ tests”当作当前精确规模。

报告交付、免费部署与隐私

本报告作为纯静态文件部署到 Cloudflare Pages:HTML、CSS、浏览器原生 JS、Markdown 下载和机器可读证据清单;不启用 Functions、D1、R2、Worker 或收费模型服务。Cloudflare 官方说明静态资源请求免费且不限次数;Free plan 当前文件数上限 20,000,单文件 25 MiB。本产物远低于限制。免费描述仅针对该报告站点,不包含未来 Agent 系统、模型调用或云存储成本。[E02] [E03]

部署使用已登录的 cf CLI 创建独立 Pages 项目、取得短期 upload token、提交 production manifest;当前 CLI 目录参数本身不会自动上传文件,因此上传资源步骤由脚本调用同一官方 Pages Direct Upload API。不使用 Wrangler,不读取/打印长期 OAuth token,不更改已有报告站点,不开通付费资源。 upload token 仅在进程内使用,不进入站点或 git。

公开内容只包含开源源码、固定 commit 引用、环境类型、验证汇总与设计建议;没有 Rex session/block ID、用户名、机器名、本机绝对路径、终端原文、账号标识、密钥或私有项目列表。Pages 是公开发布,若未来加入业务目标细节或私有测试样本,应先重新审查发布边界。

最终建议与下一步

本地优先的长期 Agent 平台:选 Infinity step,但把 durable store、队列、上下文预算和安全控制作为首发必做项。短期多渠道助手:选 NullClaw,先补 session/任务清理与持久化错误,不贸然重构内核。

对开发团队而言,最重要的不是“采用哪个项目”这一句话,而是下面五件可检查的事:

  1. 锁定目标:首发到底是海量长期 runtime,还是 Telegram/多渠道助手;把 N、C、RSS、历史和恢复口径写成验收规格。
  2. 锁定宿主:Infinity 选择 step embedding,不把 local daemon 的宣传能力当 step 的生命周期保证。
  3. 锁定权威状态:所有 accept/commit/dispatch/ack 的故障窗口可审计;不做两个 Agent loop 的双主会话。
  4. 锁定资源预算:不仅控制 worker 数,还限制 history、tool output、cache、queue、dedup 和完成任务结果的字节。
  5. 用 PoC 决定而非维护偏好:两周内证明有界 RSS、冷恢复、重复/崩溃语义;不通过就调整主线。

报告结论的置信度:执行模型/默认源码路径为高;目标产品适配为中,依赖目标假设;真实吞吐/长期 RSS/总体迁移工期为待验证。 这是一个可被测试推翻的工程决策,不是项目宣传。

固定版本证据索引

以下引用由构建脚本从 evidence.json 生成;N 是 NullClaw,I 是 Infinity,E 是官方外部规则。所有 GitHub 代码引用固定到本报告的 commit,不随 main 分支漂移。

  • N01 — Session 直接持有 Agent;getOrCreate、mutex 与恢复路径;src/session.zig:204
  • N02 — evictIdle 扫描、跳过 active turn 与销毁 session;src/session.zig:2243
  • N03 — 分片队列容量、worker 数、每 100 次处理触发回收;src/daemon.zig:1193
  • N04 — loadMessages 无界历史读取;session.zig:1488 为调用点;src/memory/engines/sqlite.zig:835
  • N05 — SessionStore 与分页详细消息契约;Memory 另有独立 vtable;src/memory/root.zig:208
  • N06 — 主 turn 的逐工具同步执行循环;src/agent/root.zig:2708
  • N07 — Provider 契约、factory 与配置/兼容层导出;src/providers/root.zig:1
  • N08 — Channel 契约与渠道产品边界;src/channels/root.zig:1
  • N09 — Tool.VTable.execute 同步返回 ToolResult;src/tools/root.zig:182
  • N10 — Agent 配置默认值、parallel_tools 与 session TTL;src/config_types.zig:406
  • N11 — 后端 capability:session store、事务、outbox 支持独立;src/memory/engines/registry.zig:23
  • N12 — persistTurn 保存 user/assistant/usage;错误被忽略;src/agent/turn_persistence.zig:18
  • N13 — 按消息数/token 触发的上下文压缩;src/agent/compaction.zig:78
  • N14 — BoundedQueue.publish 与容量 100 的 bus;src/bus.zig:409
  • N15 — 最终消息出站 outbox、claim、持久化与重试;src/channels/outbox.zig:164
  • N16 — 命名 provider/model 子任务委派与 completeAgentPrompt;src/tools/delegate.zig:33
  • N17 — 后台 task map、OS 线程、结果通知与 deinit 回收;src/subagent.zig:99
  • N18 — 2026-03-13 业务集成目标与 Planned 端点,非现成能力证明;docs/integration-roadmap.md:1
  • N19 — Webhook/public-bind bearer 鉴权与配对边界;src/gateway.zig:719
  • N20 — HTTP 工具 allowed_domains 与 SSRF/DNS pinning 例外;src/tools/http_request.zig:14
  • N21 — Zig 版本及 SQLite/websocket/wasm3 构建依赖;build.zig.zon:1
  • N22 — NullClaw MIT 许可证;LICENSE:1
  • N23 — 已有 webhook/A2A API 与鉴权;不等于路线图端点;docs/en/gateway-api.md:24
  • I01 — ConversationStore、StateStore、InputSender 的平台契约;crates/infinity-agent-core/src/traits.rs:27
  • I02 — FuturesUnordered、worker 移除、unbounded channels 与 spawn_local;crates/infinity-agent-core/src/system/local/router.rs:241
  • I03 — check_before_idle:未决工具 AwaitInput,订阅本身不保活;crates/infinity-agent-core/src/system/local/driver.rs:331
  • I04 — step_no_defer、sync-before-dispatch 与可退出切片;crates/infinity-agent-core/src/system/thread.rs:414
  • I05 — daemon 持久化 wrapper、core 内存 store 与 loaded 集合;crates/infinity-daemon/src/memory_store.rs:46
  • I06 — history/ancestor API 返回完整 Vec,范围不等于字节预算;crates/infinity-agent-core/src/traits.rs:49
  • I07 — core 包依赖,不要求完整 AWS embedding;crates/infinity-agent-core/Cargo.toml:1
  • I08 — Runtime、RAP、Infinity Code 的产品定位;README.md:1
  • I09 — step 的 Vec 分组、load、join_all;外层需限批;crates/infinity-agent-core/src/system/builder.rs:452
  • I10 — StateStore processed IDs/subscriptions/metadata 的长期内存状态;crates/infinity-agent-core/src/stores.rs:409
  • I11 — 80k 上游内存样本的负载、环境与原始 RSS 数据;docs/src/components/MemoryChart.tsx:3
  • I12 — HistoryManager.sync 先 append;processed ID 写入结果被忽略;crates/infinity-agent-core/src/event_processor.rs:627
  • I13 — JSON save_thread / save_thread_metadata 忽略文件写失败;crates/infinity-daemon/src/memory_store.rs:350
  • I14 — spawn_thread、fresh_context、父子报告与线程工具;crates/infinity-agent-core/src/tools/thread.rs:14
  • I15 — callback dedup ID:tool result 稳定,subscription event 新 UUID;crates/infinity-rap-bridge/src/lib.rs:41
  • I16 — RAP tool 适配与回调执行原语;crates/infinity-agent-core/src/tools/rap_tool.rs:1
  • I17 — MCP bridge:协议接入不等于工具重启续跑;crates/infinity-mcp-bridge/src/lib.rs:1
  • I18 — ModelProvider、rig/Bedrock、provider 自有 timeout 与错误分类;docs/docs/infinity-runtime/model-providers.md:8
  • I19 — daemon HTTP/WebSocket upgrade 路径;需额外公网授权审查;crates/infinity-daemon/src/ws_handler.rs:41
  • I20 — RAP 安全:认证由 embedding 实现,callback 应认证;docs/docs/rap/spec/overview.md:88
  • I21 — macOS/Linux sandbox 命令及具体写限制策略;crates/sandbox-local/src/backend.rs:277
  • I22 — workspace 核心、daemon、provider、sandbox、AWS 的独立包边界;Cargo.toml:1
  • I23 — Infinity Apache-2.0;分发另查 NOTICE 与 THIRD-PARTY;LICENSE.txt:1
  • I24 — 全量验证前置条件、clippy、tests、doctests、Web e2e;check.bash:13
  • I25 — 内存基准驱动、合成工具与 idle 后采样;crates/infinity-agent-core/examples/agent_scale.rs:1
  • E01 — SQLite 官方 WAL:单 writer 与同机共享内存边界
  • E02 — Cloudflare Pages 官方静态资源请求定价
  • E03 — Cloudflare Pages 官方 Free plan 文件数/大小限制
  • E04 — Cloudflare Pages 官方 Direct Upload 部署方式