fix(agent): prevent Anthropic stale-stream SQLite corruption via _abort_anthropic_client (#67142) - #67270
Conversation
…rt_anthropic_client (NousResearch#67142) Root cause: 4 watchdog locations in chat_completion_helpers.py called agent._anthropic_client.close() from the polling thread (stranger thread). The kernel recycled the freed TLS socket FD to a SQLite database, and the still-live SSL BIO on the worker thread wrote TLS record bytes into the SQLite header — same FD-reuse race as NousResearch#29507. Fix: - Added _abort_anthropic_client(reason) to run_agent.py — calls force_close_tcp_sockets() (shutdown SHUT_RDWR only, never close()) then _rebuild_anthropic_client() to preserve NousResearch#28161 pool-cleanup guarantee - Added _close_anthropic_client(reason) for owner-thread full cleanup - Replaced 4 watchdog sites: .close()+_rebuild → _abort_anthropic_client() + _rebuild_anthropic_client() - Worker-thread retry paths still use full _close_anthropic_client Closes NousResearch#67142
Competing with #67210 and #67238 for #67142: this patch centralizes socket abort/rebuild, while #67210 defers close/rebuild to the owner thread and #67238 makes Anthropic request clients local. These are materially different lifecycle mechanisms, so maintainer selection is needed. |
|
Closing as superseded by #67238 (merged), which already lands the fix for #67142: request-local Anthropic clients so the stale/interrupt watchdog never closes a shared client from the poll thread and corrupts SQLite via TLS FD reuse. Thanks for the parallel work — please reopen if you believe there's a remaining gap on current |
|
Thanks for the focused stale-stream investigation. This is an automated hermes-sweeper review; the requested behavioral guarantee is already implemented on current
The maintainer comment identified competing lifecycle mechanisms; main has now selected and merged the request-local implementation. |
Closes #67142