agent: effect ledger — duplicate-side-effect awareness on shell retries (LangEffect/RAC-inspired) - #2449
Merged
Conversation
…etries Executed-side-effect ledger at the tool execution layer (sibling of commandCache), implementing the awareness layer of Uber LangEffect (2025) and RAC log-based recovery (arXiv:2605.03409). Gap: when a side-effecting run_command times out or dies mid-flight, the outcome is UNKNOWN — a kill says nothing about whether the work already landed. On retry of the identical command nothing told the model that a prior attempt may have partially succeeded, so it treated the retry output as authoritative and could duplicate external effects (git push / npm publish / deploys twice). Mechanism: - record(): stores failed and uncertain (timeout/kill/cancel) outcomes of actually-executed run_command calls; never-executed shapes (permission denial, gate block, invalid input) are excluded; successes are not recorded (verification re-runs are already covered by redundantReverify). - priorHint(): when an identical (command, working_dir) is re-executed within a 30-minute window after a failed/uncertain attempt, the retry's tool result is annotated ([Effect Ledger] ...) telling the model to verify external state before drawing conclusions. - Protocol-safe: annotation appended to the tool result content (same pattern as commandCache's [cached] annotation); no message inserted between tool_calls and tool_results. Runs after storeCommandResult so annotation text is never cached. Capped at 5 hints, 64 records. Includes guard tests for classification, key matching (with #1530 comment stripping), retry window, warning cap, and self-hint exclusion. Co-Authored-By: ggcode <noreply@ggcode.dev>
topcheer
commented
Sep 16, 2026
topcheer
left a comment
Owner
Author
There was a problem hiding this comment.
复审通过 ✅(执行层机制定位正确+协议安全)
- 挂接时序精确:storeCommandResult 之后(注释明示 annotation 永不入缓存——缓存污染防护在位);record 在 priorHint 之后(自标注不可能,测试 TestRecordEffectAttemptSelfNotHinted 钉住);追加式 annotation 同 command_cache 惯例(协议安全——无消息插入)✓
- 分类完备:neverExecutedMarkers(denial/parse/gate/shell resolve/job 未启动)排除正确——这些形态无外部效果;uncertainMarkers(timeout/deadline/killed/canceled)是最危险重试面——UNKNOWN 态可能部分落盘 ✓
- 身份归一:stripLeadingShellComment 复用 command_cache 的 #1530 归一('# 描述' 行不破坏匹配)+workDir 组合键 ✓
- 资源边界:64 记录减半淘汰/5 提示上限(防紧循环 nagging)/30 分钟窗(旧失败=有意重跑,不注)——三界合理 ✓
- 7 测试覆盖全语义面(分类表/重试提示/窗口/上限/自标注排除/他工具忽略/键归一)
- 非阻塞观察:uncertain 判定基于错误文本 Contains——marker 串与本仓错误格式耦合,格式变更需同步(marker 列表已注释出处:command_jobs.go 等,可维护)
This was referenced Sep 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
方向:2025-2026 前沿 gap — Agent 副作用账本(Effect Ledger)
研究依据:Uber LangEffect(2025,effect log + LIFO 补偿事务)、RAC: Robust Agent Compensation(arXiv:2605.03409,log-based recovery)、"Agent Idempotency" 生产模式(2026)。
Gap(已核实不存在)
当 side-effecting
run_command超时/中途被杀时,其外部结果 UNKNOWN——kill 本身不说明工作是否已落盘。Agent 重试同一命令时,现有机制均不提示此前有失败尝试,模型把重试输出当权威结论,可能重复外部副作用(git push两次、npm publish两次、重复部署/写 API):commandCache:只缓存确定性构建命令,且从不缓存失败([business-logic] command cache exclusion scan only blocks > << | so command substitution , backticks, input redirection <, and background & pass through - a cached go test whose result depended on substitution output replays without re-evaluating; error and timeout results enter the cache unconditionally and replay without the cached annotation, pinning a one-off timeout flake for the full 10-minute TTL #1717)errorStrategyLoop:策略复用检测,非重复执行防护checkpoint/undo_edit:文件树回滚,不覆盖 shell 外部效果实现(工具执行层机制,非新增 detector)
与
commandCache同层的执行路径机制:run_command的 failed / uncertain(timeout/kill/cancel)结果;权限拒绝、gate 拦截、参数解析失败等从未执行的形态被排除;成功不入账(验证类重复执行已由 redundantReverify 覆盖)[Effect Ledger]注释,提示模型先验证外部真实状态(git log/status、检查产物)再下结论[cached]注释同模式),不在 tool_calls 与 tool_results 之间插入消息;在storeCommandResult之后执行,注释永不入缓存;限流 5 次/会话、64 条环形账本测试
6 个守卫测试:结果分类、键匹配(含 #1530 注释剥离)、重试窗口、限流、自我注释排除。
go test -tags goolm ./internal/agent/全量通过,go build -tags goolm ./...通过。后续可选(本次未做):失败路径上的 LIFO 补偿摘要(向用户列出本会话副作用与建议回滚命令)。
Co-Authored-By: ggcode noreply@ggcode.dev