``Task`` adapter for ``in_process_teammate`` entries. Polymorphic dispatch target for ``stop_task`` (Phase 5). Setting ``abort_event`` propagates the kill signal; the teammate's run loop sees ``TeammateAbortedError`` at its next yield and unwinds the lifecycle.
| 321 | |
| 322 | |
| 323 | class InProcessTeammateTask: |
| 324 | """``Task`` adapter for ``in_process_teammate`` entries. |
| 325 | |
| 326 | Polymorphic dispatch target for ``stop_task`` (Phase 5). Setting |
| 327 | ``abort_event`` propagates the kill signal; the teammate's run |
| 328 | loop sees ``TeammateAbortedError`` at its next yield and |
| 329 | unwinds the lifecycle. |
| 330 | """ |
| 331 | |
| 332 | name: str = "InProcessTeammateTask" |
| 333 | type: Literal["in_process_teammate"] = "in_process_teammate" |
| 334 | |
| 335 | async def kill( |
| 336 | self, task_id: str, registry: "RuntimeTaskRegistry" |
| 337 | ) -> None: |
| 338 | aborted_event: asyncio.Event | None = None |
| 339 | |
| 340 | def _kill(prev: TaskStateBase) -> TaskStateBase: |
| 341 | nonlocal aborted_event |
| 342 | if not isinstance(prev, InProcessTeammateTaskState): |
| 343 | return prev |
| 344 | if is_terminal_task_status(prev.status): |
| 345 | return prev |
| 346 | aborted_event = prev.abort_event |
| 347 | return replace(prev, status="killed") |
| 348 | |
| 349 | registry.update(task_id, _kill) |
| 350 | # Set the event OUTSIDE the registry lock — same defense-in-depth |
| 351 | # pattern as kill_async_agent. asyncio.Event is thread-safe for |
| 352 | # ``set()`` (it dispatches via the loop's call_soon_threadsafe |
| 353 | # internally), but we don't want a misbehaving subclass to |
| 354 | # deadlock the registry. |
| 355 | if aborted_event is not None: |
| 356 | try: |
| 357 | aborted_event.set() |
| 358 | except Exception: |
| 359 | import logging |
| 360 | logging.getLogger(__name__).exception( |
| 361 | "failed to set abort event for killed teammate %s", task_id |
| 362 | ) |
| 363 | |
| 364 | |
| 365 | __all__ = [ |
no outgoing calls