Skip to content

Commit 5bd2da7

Browse files
committed
fix: check cancel signal inside aiter_bytes() loop and clarify docstrings
1 parent 02313af commit 5bd2da7

2 files changed

Lines changed: 27 additions & 6 deletions

File tree

strands-py/src/strands/vended_tools/web_fetch/web_fetch.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ def make_web_fetch(
6464
5 MiB.
6565
client: Optional ``httpx.AsyncClient`` to use for requests. When
6666
provided, the tool uses it directly and will not close it.
67-
When ``None``, a new client is created per request with httpx
68-
defaults.
67+
When ``None``, a new client is created per request with
68+
``follow_redirects=True`` and httpx's default timeout (5s).
6969
model: Optional model for the summarizer. Resolution order when
7070
``prompt`` is non-empty: this model, then the host agent's model,
7171
then ``ValueError`` if neither is available.
@@ -88,8 +88,7 @@ async def web_fetch_tool(
8888
"""Fetches an HTTP(S) URL and returns readable content.
8989
9090
Only ``http://`` and ``https://`` URLs are accepted. Raises
91-
``TimeoutError`` if the request does not complete within the
92-
configured timeout.
91+
``TimeoutError`` if the request exceeds the client's timeout.
9392
9493
Args:
9594
url: The URL to fetch. Must be ``http://`` or ``https://``.
@@ -125,8 +124,7 @@ async def web_fetch_tool(
125124
effective_model = summarizer_model or getattr(agent_obj, "model", None)
126125
if effective_model is None:
127126
raise ValueError(
128-
"web_fetch: prompt requires a model. Pass model= to make_web_fetch "
129-
"or call the tool from an agent."
127+
"web_fetch: prompt requires a model. Pass model= to make_web_fetch or call the tool from an agent."
130128
)
131129
# Fresh agent per call — no history from one fetch bleeds into the next.
132130
summarizer = Agent(
@@ -180,6 +178,7 @@ async def _fetch_once(
180178
chunks: list[bytes] = []
181179
total = 0
182180
async for chunk in response.aiter_bytes():
181+
_check_cancelled(cancel_signal)
183182
total += len(chunk)
184183
if total > max_bytes:
185184
raise ValueError(f"Response body exceeded {max_bytes} bytes. Refusing to buffer more.")

strands-py/tests/strands/vended_tools/test_web_fetch.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,28 @@ def handler(_request: httpx.Request) -> httpx.Response:
208208
with pytest.raises(asyncio.CancelledError):
209209
await tool(url="https://example.com/", tool_context=ctx)
210210

211+
@pytest.mark.asyncio
212+
async def test_mid_flight_cancel_aborts_between_chunks(self):
213+
cancel = threading.Event()
214+
215+
def handler(_request: httpx.Request) -> httpx.Response:
216+
async def body():
217+
yield b"chunk-one"
218+
cancel.set() # signal mid-stream
219+
yield b"chunk-two"
220+
221+
return httpx.Response(200, headers={"content-type": "text/plain"}, content=body())
222+
223+
agent = SimpleNamespace(_cancel_signal=cancel)
224+
from strands.types.tools import ToolContext, ToolUse
225+
226+
tool_use = ToolUse(toolUseId="wf_2", name="web_fetch", input={})
227+
ctx = ToolContext(tool_use=tool_use, agent=agent, invocation_state={})
228+
229+
tool = make_web_fetch(client=_client(handler))
230+
with pytest.raises(asyncio.CancelledError):
231+
await tool(url="https://example.com/", tool_context=ctx)
232+
211233

212234
class TestSummarizer:
213235
"""Summarizer agent is called when model + prompt are both provided."""

0 commit comments

Comments
 (0)