Skip to content

Commit 9aad4e3

Browse files
committed
fix(teams): track wait_until invocation explicitly to detect deduped messages
The previous fix (17009a9) used ``processing_done.done()`` to detect whether a chat task was scheduled, but ``_resolve_processing`` registers a ``done_callback`` on the task that fires only on task COMPLETION — not at the moment ``wait_until`` is invoked. So my check prematurely resolved ``processing_done`` immediately after ``process_message`` returned (before the task had a chance to run), which broke 2 tests: - test_caller_wait_until_raise_does_not_kill_native_streaming - test_same_thread_concurrent_handlers_clobber_active_stream Fix: track a separate ``wait_until_invoked`` flag inside ``_chained_wait_until``. After ``process_message`` returns, only resolve ``processing_done`` if ``wait_until`` was NEVER called — that's the true signal that no chat task was scheduled (deduped/dropped). 23 native-streaming tests pass; full suite passes (modulo the pre-existing unrelated github_webhook failure). https://claude.ai/code/session_01FyMxQn2BEAzmwKS1GZczKj
1 parent 17009a9 commit 9aad4e3

1 file changed

Lines changed: 12 additions & 1 deletion

File tree

src/chat_sdk/adapters/teams/adapter.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,8 +458,15 @@ def _on_done(_t: asyncio.Task[Any]) -> None:
458458
processing_done.set_result(None)
459459

460460
upstream_wait_until = options.wait_until if options is not None else None
461+
# Track whether the chained wait_until fired synchronously during
462+
# ``process_message``. Used below to detect deduped/dropped
463+
# messages where no chat task was scheduled and we'd otherwise
464+
# hang on ``await processing_done``.
465+
wait_until_invoked = False
461466

462467
def _chained_wait_until(task: Awaitable[Any]) -> None:
468+
nonlocal wait_until_invoked
469+
wait_until_invoked = True
463470
# Resolve our own gate FIRST, before invoking the upstream
464471
# ``wait_until`` callback. This way, even if the upstream
465472
# callback raises, blocks, or never fires, ``processing_done``
@@ -494,7 +501,11 @@ def _chained_wait_until(task: Awaitable[Any]) -> None:
494501
# message wasn't admitted for handling). Resolve the gate
495502
# immediately so ``await processing_done`` doesn't hang
496503
# forever — there is no in-flight handler to wait on.
497-
if not processing_done.done():
504+
# Note: we check ``wait_until_invoked`` rather than
505+
# ``processing_done.done()`` because the latter is set via
506+
# an ``add_done_callback`` on task COMPLETION; the task is
507+
# scheduled but has not run yet at this point.
508+
if not wait_until_invoked and not processing_done.done():
498509
processing_done.set_result(None)
499510
try:
500511
await processing_done

0 commit comments

Comments
 (0)