Skip to content

feat: Add AsyncSSEClient with aiohttp-based async/await support#58

Open
keelerm84 wants to merge 7 commits intomainfrom
mk/sdk-1400/async
Open

feat: Add AsyncSSEClient with aiohttp-based async/await support#58
keelerm84 wants to merge 7 commits intomainfrom
mk/sdk-1400/async

Conversation

@keelerm84
Copy link
Member

@keelerm84 keelerm84 commented Mar 11, 2026

Adds AsyncSSEClient as a purely additive new public API alongside the
existing SSEClient. Async users install with the [async] extra to get
aiohttp; sync users have no new dependencies. All existing tests pass
unchanged.


Note

Medium Risk
Adds a new async public client and optional aiohttp dependency plus new CI/contract-test coverage; while largely additive, it introduces new concurrency and connection-handling code paths that could surface runtime issues for async users.

Overview
Adds a new AsyncSSEClient API for consuming SSE streams with asyncio, including async parsing/iteration, retry/backoff handling, and an AsyncConnectStrategy.http() implementation backed by optional aiohttp.

Updates packaging/docs to expose the async client without forcing aiohttp on sync users (lazy import via ld_eventsource.__getattr__, new async extra, Sphinx mocking), and standardizes header typing via a new Headers alias used across sync/async actions and errors.

Extends test/CI coverage with pytest-asyncio, new unit tests for async reader/client/HTTP strategy, and a separate async contract-test service and CI steps/Makefile targets to run the shared contract test harness against the async implementation.

Written by Cursor Bugbot for commit cda95c0. This will update automatically on new commits. Configure here.

Adds AsyncSSEClient as a purely additive new public API alongside the
existing SSEClient. Async users install with the [async] extra to get
aiohttp; sync users have no new dependencies. All existing tests pass
unchanged.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@keelerm84 keelerm84 marked this pull request as ready for review March 11, 2026 19:52
@keelerm84 keelerm84 requested a review from a team as a code owner March 11, 2026 19:52
keelerm84 and others added 2 commits March 11, 2026 16:44
Removes make_stream, retry_for_status, and no_delay from async_helpers.py
as they were either unused or duplicates of the same functions in helpers.py.
Updates async test files to import these from helpers.py consistently.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>

request_options = {}
if self.options.get("readTimeoutMs") is not None:
request_options["timeout"] = aiohttp.ClientTimeout(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think, even without a read timeout, we need to customize the ClientTimeout.
image

The timeout uses a non-default ClientTimeout.

But if we do set it to anything, then the total will get set to None. https://docs.aiohttp.org/en/stable/client_reference.html#aiohttp.ClientTimeout.total

But if we set a ClientTimeout, we would get the default total=None.

error = e
self.__connection_result = None
finally:
self.__last_event_id = reader.last_event_id
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we close the result in finally out of an abundance of caution? By the docs you normally don't need to close it if it completes normally, and it would be closed on a network error, but the exception here here could also potentially be a decoding error, in which maybe we wouldn't close it?


async def close(self):
# Only close the session if we created it ourselves
if self.__external_session is None and self.__session is not None:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the non-async version does this wrong?

self.__should_close_pool = params.pool is not None

self.__should_close_pool = params.pool is not None

Not a problem with this PR, but maybe worth checking.

Copy link
Member

@kinyoklion kinyoklion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requests in comments.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

@keelerm84 keelerm84 requested a review from kinyoklion March 17, 2026 19:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants