Launch an agent in the background and return immediately. Chapter-10 layered story: * Chunk B / WI-1.5 — state on ``context.runtime_tasks`` as a typed ``LocalAgentTaskState`` (no more ``context.tasks`` / ``metadata._internal=True`` workaround). * Chunk C
(
*,
run_params: RunAgentParams,
context: ToolContext,
agent_id: str,
description: str,
prompt: str,
agent_type: str,
agent_name: str | None = None,
)
| 430 | ) |
| 431 | |
| 432 | def _launch_async_agent( |
| 433 | *, |
| 434 | run_params: RunAgentParams, |
| 435 | context: ToolContext, |
| 436 | agent_id: str, |
| 437 | description: str, |
| 438 | prompt: str, |
| 439 | agent_type: str, |
| 440 | agent_name: str | None = None, |
| 441 | ) -> ToolResult: |
| 442 | """Launch an agent in the background and return immediately. |
| 443 | |
| 444 | Chapter-10 layered story: |
| 445 | * Chunk B / WI-1.5 — state on ``context.runtime_tasks`` as a |
| 446 | typed ``LocalAgentTaskState`` (no more ``context.tasks`` / |
| 447 | ``metadata._internal=True`` workaround). |
| 448 | * Chunk C / WI-2.2 (gate-zero) — sidechain JSONL transcript |
| 449 | opened for the lifetime of the agent run; ``output_file`` is |
| 450 | its absolute path. |
| 451 | * Chunk C / WI-2.3 — lifecycle goes through the named helpers |
| 452 | (``register_async_agent`` / ``complete_agent_task`` / |
| 453 | ``fail_agent_task``) so the registry mutations are atomic |
| 454 | and consistent across spawn / kill / completion paths. |
| 455 | * Chunk C / WI-2.4 — token accounting via ``ProgressTracker``; |
| 456 | ``finalize_agent_tool`` reads its accumulated totals instead |
| 457 | of reporting ``total_tokens=0``. |
| 458 | * Chunk F / WI-6.1 — optional ``agent_name`` registers the |
| 459 | spawn under ``context.agent_name_registry`` so SendMessage |
| 460 | can resolve ``to: <name>``. Collision-on-running raises; |
| 461 | collision-on-terminal silently overwrites. |
| 462 | """ |
| 463 | # Local imports defer the cycle: ``src.tasks.local_agent`` |
| 464 | # reaches back into ``src.task_registry`` which is fine, but |
| 465 | # importing them at module scope would tangle with |
| 466 | # ``defaults.py``'s tool-construction order. |
| 467 | from src.agent.transcript import TranscriptWriter |
| 468 | from src.tasks.local_agent import ( |
| 469 | LocalAgentTaskState, |
| 470 | complete_agent_task, |
| 471 | fail_agent_task, |
| 472 | register_async_agent, |
| 473 | ) |
| 474 | from src.tasks.progress import ( |
| 475 | ProgressTracker, |
| 476 | update_progress_from_message, |
| 477 | ) |
| 478 | from src.services.swarm.agent_name_registry import ( |
| 479 | AgentNameAlreadyClaimedError, |
| 480 | ) |
| 481 | from src.utils.task_notification import enqueue_agent_notification |
| 482 | |
| 483 | # WI-6.1 + critic C1 (Phase-7 fix): atomic check-and-claim |
| 484 | # under the typed registry's RLock. The previous Phase-6 |
| 485 | # implementation had a TOCTOU window between the read and |
| 486 | # the write; the typed ``claim_or_raise`` closes it. We do |
| 487 | # the claim BEFORE the runtime_tasks write so a refused |
| 488 | # spawn doesn't leak a half-constructed agent_id into the |
| 489 | # runtime registry. |
no test coverage detected