fix: error context preservation, WAL checkpoint, hook timeout - #6622
fix: error context preservation, WAL checkpoint, hook timeout#6622aaronlab wants to merge 2 commits into
Conversation
…agent loop reliability ## Summary Found 5 critical bugs in async error handling, context compression, and cron scheduling: **CRITICAL (2):** 1. Role violation after context compression (context_compressor.py:694-728) - Tool message validation missing when merging summary - Causes API crash and data loss after compression 2. Double-execution race condition in cron scheduler (scheduler.py:843-892) - File lock released before job execution completes - Allows duplicate jobs to be executed (DoS, duplicate messages) **HIGH (1):** 3. Unhandled context compression exceptions in main loop (run_agent.py:8204,8262,8338) - Silent crash when summarizer fails during API loop - No graceful degradation **MEDIUM (2):** 4. Error swallowing in auxiliary_client (auxiliary_client.py:2074-2106) - Original error overwritten on retry failure - Lost error context, unreachable fallback logic 5. Session ID change without exception recovery (run_agent.py:6041-6071) - Session state corruption on DB failures - Broken session lineage ## Details Full analysis with code snippets, scenarios, and fixes in: - AUDIT_ITERATION_2.md (400 lines, detailed technical analysis) - AUDIT_ITERATION_2_SUMMARY.txt (visual summary, testing recommendations) ## Recommended Priority 1. Bug NousResearch#1 (Role Violation) - FIX IMMEDIATELY 2. Bug NousResearch#2 (Double Execution) - FIX IMMEDIATELY 3. Bug NousResearch#3 (Unhandled Exceptions) - FIX SOON 4. Bug NousResearch#4 & NousResearch#5 - FIX AFTER critical bugs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…tection - Preserve original error context in call_llm retry chain (agent/auxiliary_client.py): When max_tokens retry fails with a payment error, the original error was silently overwritten via `first_err = retry_err`, losing diagnostic context. Now chains the original error via `__cause__` for proper Python exception chaining. - Guard fallback provider call (agent/auxiliary_client.py): Payment fallback API call at line 2105 had no try/except. If the fallback provider also failed, there was no logging and no indication the fallback was attempted. Added error handling with warning log on fallback failure. - Add WAL checkpoint to holographic memory store (plugins/memory/holographic/store.py): WAL mode was enabled but no checkpoint mechanism existed, causing unbounded WAL file growth over time. Added periodic checkpoint every 50 writes and a final checkpoint on close(), following the same pattern used in hermes_state.py. - Add timeout protection to plugin hook invocation (hermes_cli/plugins.py): Plugin hook callbacks had exception isolation but no timeout protection. A misbehaving plugin could block the agent loop indefinitely. Added 30-second timeout using ThreadPoolExecutor with proper warning logging on timeout. Co-Authored-By: Claude Code <noreply@anthropic.com>
1 similar comment
|
Thanks for the reliability audit and for identifying the hook and holographic-store failure modes. The current patch needs substantial rework before it can be safely salvaged. Problems
Suggested changes
Automated hermes-sweeper review. |
GottZ
left a comment
There was a problem hiding this comment.
This was generated by AI during triage.
Summary
Four open PRs reference this audit-derived reliability complex, but they address distinct causes: #6622 covers error chaining, fallback logging, hook timeouts, and WAL checkpointing; #6627 covers concurrent-tool timeouts, file handling, and RPC decoding; #6629 covers token estimation, context-length diagnostics, and batch durability; #6635 covers Anthropic tool-prefix handling and parse/shutdown observability. Each diff contains superseded, ineffective, incorrect, or incomplete changes, so none currently provides a mergeable consolidation target.
Related pull requests
- #6622
related— (+670/-4) — needs substantial rework: The error-context and fallback diagnostics target code that has since been refactored, the ThreadPoolExecutor context still waits for a timed-out hook, and PASSIVE checkpointing neither truncates the WAL nor covers all write paths. The contributor keep_open review supports salvaging the hook and holographic-store concerns only after rebasing, using genuinely non-blocking timeout dispatch, applying an appropriate checkpoint policy across every committed mutation, and adding tests. - #6627
related— (+639/-4) — narrow salvage only: The concurrent-tool timeout and cwd handle fixes are already present on main, while replacement decoding can silently corrupt structured JSON and still fails for malformed syntax. Consistent with the keep_open review, retain strict UTF-8 and salvage only explicit RPC protocol-error handling with a malformed-response regression test. - #6629
related— (+647/-3) — needs focused rework: The token-estimation correction has already landed, but the fallback diagnostic and fsync durability concerns remain relevant; the proposed Pool.join(timeout=10) calls are invalid and the configuration guidance is inaccurate. Consistent with the keep_open review, remove the landed and unrelated material, use valid worker cleanup, and test fallback logging, durable trajectory writes, and interruption paths before merge. - #6635
related— (+635/-1) — needs focused rework: OAuth prefix stripping already exists on main, the gateway hunk inspects a write-only map rather than the adapters' actual queued follow-ups, and malformed argument logging covers only one of two fallback paths. Consistent with the keep_open review, remove the landed prefix hunk, instrument both parse fallbacks and the real pending-message stores, and add focused regression tests.
Duplicates
#6622, #6627, #6629, and #6635 duplicate the same unrelated AUDIT_ITERATION_2.md and AUDIT_ITERATION_2_SUMMARY.txt additions; their substantive code changes are not duplicates and should not be consolidated into one PR.
Suggested consolidation
Merge none as-is. Keep #6622, #6627, #6629, and #6635 open only for the focused salvage described in their contributor keep_open reviews, remove the duplicated audit documents and already-landed hunks, and split the remaining unrelated fixes into independently tested PRs; no substantive PR can currently be closed as a duplicate of another.
Cross-PR triage: Reviewed 4 pull requests and 0 issues in this complex. Each diff was read against this issue; Assessment working set: 110 kB of PR diffs, 8 kB of issue/PR text, 6 kB of discussion (6 comments), 0 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch.
Summary
This PR addresses three reliability gaps found during iteration #4 of a deep code audit:
Preserve original error context in call_llm retry chain (
agent/auxiliary_client.py): When themax_tokensretry also fails with a payment error, the original error was silently overwritten viafirst_err = retry_err(line 2089), losing the initial diagnostic context. Now usesretry_err.__cause__ = first_errfor proper Python exception chaining, preserving the full error sequence for debugging.Guard payment fallback provider call (
agent/auxiliary_client.py): The fallback API call (line 2105) had no try/except. If the fallback provider also failed, there was zero logging and no indication that a fallback was even attempted. Added error handling with a warning log message identifying which fallback provider failed.Add WAL checkpoint to holographic memory store (
plugins/memory/holographic/store.py): WAL mode was enabled (line 130) but no checkpoint mechanism existed anywhere in the class, unlikehermes_state.pywhich has proper_try_wal_checkpoint(). This causes unbounded WAL file growth over long-running sessions. Added periodic PASSIVE checkpoint every 50 writes and a final checkpoint onclose(), following the established pattern.Add timeout protection to plugin hook invocation (
hermes_cli/plugins.py): Hook callbacks had good exception isolation (try/except per callback) but no timeout protection. A misbehaving plugin could block the agent loop indefinitely with a blocking call. Added a 30-second timeout usingThreadPoolExecutor, with warning logging on timeout.Files Changed
agent/auxiliary_client.pyplugins/memory/holographic/store.pyhermes_cli/plugins.pyTest plan
__cause__time.sleep(60)in pre_llm_call hook → verify 30s timeout warningpytest tests/🤖 Generated with Claude Code