Symptom: CI hangs for 19 minutes after tests finish. Process never exits.
Root cause: _cleanup_portal() only fires on natural stream exhaustion (StopAsyncIteration). Exception, break, or abandoned streams leak the BlockingPortal thread.
Fix: Replace __iter__ returning self + __next__ with a generator-based __iter__. Python guarantees generator finally blocks run on exhaustion, break, exception, and GC.
Also fixes Pydantic V2.11 deprecation warning: tool.model_fields → type(tool).model_fields in 4 tool mapper files.
Files:
src/celeste/streaming.py
src/celeste/protocols/openresponses/tools.py
src/celeste/providers/google/generate_content/tools.py
src/celeste/providers/groq/chat/tools.py
src/celeste/providers/moonshot/chat/tools.py
Symptom: CI hangs for 19 minutes after tests finish. Process never exits.
Root cause:
_cleanup_portal()only fires on natural stream exhaustion (StopAsyncIteration). Exception,break, or abandoned streams leak theBlockingPortalthread.Fix: Replace
__iter__returningself+__next__with a generator-based__iter__. Python guarantees generatorfinallyblocks run on exhaustion, break, exception, and GC.Also fixes Pydantic V2.11 deprecation warning:
tool.model_fields→type(tool).model_fieldsin 4 tool mapper files.Files:
src/celeste/streaming.pysrc/celeste/protocols/openresponses/tools.pysrc/celeste/providers/google/generate_content/tools.pysrc/celeste/providers/groq/chat/tools.pysrc/celeste/providers/moonshot/chat/tools.py