fix(responses): propagate aclose through MCPEnhancedStreamingIterator and type test helpers

Greptile review: the MCP wrapper stores its upstream-owning iterator in
base_iterator, so the inherited response-based aclose was a no-op there.
Delegate to the base iterator's aclose when it has one. Also add the
missing parameter and return annotations on the new passthrough test
helpers
This commit is contained in:
vivekvar-dl 2026-08-08 13:57:22 +05:30
parent e8e7db248b
commit 62ca98a3f7
3 changed files with 34 additions and 3 deletions

View file

@ -326,6 +326,11 @@ class MCPEnhancedStreamingIterator(BaseResponsesAPIStreamingIterator):
self._error_event_emitted = False
self._last_sequence_number = 0
async def aclose(self) -> None:
base_aclose: Final = getattr(self.base_iterator, "aclose", None)
if base_aclose is not None:
await base_aclose()
def _extract_mcp_headers_from_params(self) -> None:
"""Extract MCP headers from original request params to pass to tool calls"""

View file

@ -3,7 +3,7 @@ when the stream ends, including on client disconnect (generator aclose), so
the provider connection is released and backends like vLLM stop generating.
"""
from collections.abc import AsyncIterator
from collections.abc import AsyncIterator, Coroutine
from datetime import datetime, timezone
from typing import Final
from unittest.mock import MagicMock, patch
@ -51,7 +51,7 @@ def _logging_obj_stub() -> MagicMock:
return logging_obj
def _chunk_processor(response: httpx.Response):
def _chunk_processor(response: httpx.Response) -> AsyncIterator[bytes]:
return PassThroughStreamingHandler.chunk_processor(
response=response,
request_body={"model": "claude-sonnet-4-5"},
@ -63,7 +63,7 @@ def _chunk_processor(response: httpx.Response):
)
def _drop_scheduled_coroutine(async_coroutine) -> None:
def _drop_scheduled_coroutine(async_coroutine: Coroutine[object, object, object]) -> None:
async_coroutine.close()

View file

@ -257,3 +257,29 @@ async def test_initial_call_failure_is_stashed_for_eager_reraise(monkeypatch):
assert iterator._initial_creation_error is not None
assert "initial boom" in str(iterator._initial_creation_error)
@pytest.mark.asyncio
async def test_aclose_closes_base_iterator():
class _ClosableStream:
def __init__(self):
self.aclose_called = False
async def aclose(self) -> None:
self.aclose_called = True
iterator = _make_iterator([])
closable = _ClosableStream()
iterator.base_iterator = closable
await iterator.aclose()
assert closable.aclose_called
@pytest.mark.asyncio
async def test_aclose_is_a_noop_without_base_iterator():
iterator = _make_iterator([])
iterator.base_iterator = None
await iterator.aclose()