Fix #276: WebFetch/WebSearch honor abort_controller (ESC-cancel)#307
Open
ericleepi314 wants to merge 1 commit into
Open
Fix #276: WebFetch/WebSearch honor abort_controller (ESC-cancel)#307ericleepi314 wants to merge 1 commit into
ericleepi314 wants to merge 1 commit into
Conversation
ESC during a slow fetch blocked the agent until the urllib socket timeout (15-20s) — the longest interactive stall left in the tool set. New src/utils/abortable_net.py primitives: - call_with_abort: blocking call on a daemon worker thread, abort polled at 50ms; the caller unblocks immediately on ESC while the worker dies at its (bounded) socket timeout - abortable_read: chunked body read with an abort listener that shuts the socket down (close() alone does not interrupt a recv blocked on another thread) so mid-body stalls cancel instantly WebFetch threads the signal through the redirect loop, the open, the body read, and the Cloudflare-UA retry; WebSearch wraps the Tavily request. Both raise AbortError, which dispatch already renders as the user-cancel message. Closes #276, closes #170 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This was referenced Jun 12, 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.
Closes #276
Closes #170 (duplicate)
Summary
ESC during a slow WebFetch/WebSearch blocked the agent until the urllib socket timeout (15–20s), while Bash/Read/Grep already cancel in ~50–100ms.
urllibhas no cancellation primitive, so this builds it from two mechanisms in a newsrc/utils/abortable_net.py:call_with_abort(fn, signal)— runs the blocking call on a daemon worker thread and polls the abort signal every 50ms. On ESC the caller unblocks immediately (raisesAbortError); the worker dies at its bounded socket timeout, and a late-arriving response is closed rather than leaked.abortable_read(resp, max_bytes, signal)— chunked 64KB body read with an abort listener that shuts the socket down (SHUT_RDWR) before closing. Empirically necessary:resp.close()alone does not interrupt arecvblocked on another thread — the first version of the test stalled the full 8s timeout until the shutdown was added.Wiring:
opener.open, the body read, and the Cloudflare-UA retry recursion. Cached results skip fetching entirely.urlopen+readruns undercall_with_abort.Both raise
AbortError, which the dispatch layer already converts to the user-cancel REJECT_MESSAGE (same path as grep/ripgrep cancellation).Test plan
tests/test_web_abort.py: unit coverage for both primitives (pre-aborted short-circuit, abort-mid-call <2s, worker exception relay, late-result close, listener cleanup) plus integration against a real local stalling HTTP server — WebFetch mid-body abort and Tavily abort both unblock in ~0.2s while the server is still stalling (3s) and the socket timeout is 8s+🤖 Generated with Claude Code