JSONL 看起来简单,因为好像每个换行就分隔出一个对象。一份活着的编码 Agent 会话记录会加上更硬的约束:最后一条记录可能不完整,负载可能异常地大,事件可能重复,而一次旧的完成可能被之后的活动作废
解析之前先给读取加界
用流式读取,并写明行策略。不要把一份无界的会话记录整个读成一个字符串。Agent Island v1.7.1 采用各平台各自的保护:macOS 的 Claude 读取器有 64 MiB 的兜底上限,Windows 读取器则在 JSON 解析前跳过超过 1,000,000 字符的行
这两条策略并不相同,不该被说成同一个共享上限。它们反映的是两份不同的已发布实现。两条策略都让畸形或残缺记录不至于把文件其余部分拖垮
只解析能改变状态的字段
大范围反序列化会造出对无关负载的意外依赖。状态监控需要一个更小的投影
对 Claude 事件,有用的字段包括 type、uuid、timestamp、message.stop_reason、isSidechain、isApiErrorMessage 和 toolEndsTurn。对 Codex 事件,已发布的读取器检查的是 type、payload.type、payload.turn_id、role、timestamp、completed_at 和 started_at 这类字段
read bounded line
-> parse JSON
-> project provider-specific state fields
-> attach event identity and semantic time
-> reduce ordered events into session state
完成是一个候选,不是一条永久事实
一个长得像完成的事件只属于某一个回合。之后出现的用户消息或开始事件意味着会话已经往前走了。因此归约器必须比较语义顺序,允许之后的活动取代更早的完成
这条规则阻止一次过期的完成在下一回合已经开始之后还把监控钉住。它也解释了为什么单看最新的文件时间戳不够:同一份记录里住着多个回合
拒绝假的完成信封
限流和 API 错误的助手信封不是成功完成。sidechain 或子 Agent 的完成不自动等于一次主线程交接。工具活动也可能在模型的终止标记之后继续
服务商特有的闸门应该跑在通用完成归约器之前。否则一行语法完全合法的记录,也能产生一次语义上错误的闹钟
让文件变化触发一次新的归约
Agent Island 监听 .jsonl 文件的变化,同时保留轮询作为兜底。事件驱动的观测降低延迟,轮询则防住漏掉的监听通知。此刻被跳过的一行残行,可以在下一次变化后重新考虑
用路径、大小和修改时间这类稳定指纹缓存未变化的文件,但源变化时必须让缓存失效。缓存是优化,不能把一个更早的状态冻住
能抓到真实解析错误的测试
- 一行空行或畸形行不会中断之后的合法记录
- 一条不完整的末行,在之后的追加之后变得可读
- 超大行遵循写明的平台策略
- 重复事件不会产生第二次闹钟
- 之后的用户或开始事件取代更早的完成
- API 错误信封不会变成已完成
- sidechain 的结束不会为父会话呼叫用户
- 漏掉的监听事件能由轮询补回
安全的 JSONL 解析不只是「合法 JSON 处理」。它是有界 I/O,加上理解服务商语义的事件处理、排序、去重和刷新行为
