()
| 513 | ) |
| 514 | |
| 515 | async def _background_lifecycle() -> None: |
| 516 | tracker = ProgressTracker() |
| 517 | messages: list[Any] = [] |
| 518 | transcript: TranscriptWriter | None = None |
| 519 | if transcript_path: |
| 520 | try: |
| 521 | transcript = TranscriptWriter(transcript_path) |
| 522 | except OSError: |
| 523 | # Transcript open failure must not abort the run — |
| 524 | # downstream Chunk D / Chunk F will degrade |
| 525 | # gracefully (no outputFile content / no auto-resume |
| 526 | # source) rather than crash. |
| 527 | logger.exception( |
| 528 | "transcript open failed for %s; continuing without disk persistence", |
| 529 | agent_id, |
| 530 | ) |
| 531 | transcript = None |
| 532 | try: |
| 533 | try: |
| 534 | async for message in run_agent(run_params): |
| 535 | messages.append(message) |
| 536 | # Live progress accounting — feeds the post-hoc |
| 537 | # ``finalize_agent_tool`` token total via the |
| 538 | # ``progress`` keyword (WI-2.4 fallback also |
| 539 | # works if the tracker is somehow empty). |
| 540 | try: |
| 541 | update_progress_from_message(tracker, message) |
| 542 | except Exception: |
| 543 | logger.exception( |
| 544 | "progress tracker update failed for %s", agent_id |
| 545 | ) |
| 546 | # Persist to disk per WI-2.2. Synchronous IO |
| 547 | # outside the registry lock — A6/C5 contract is |
| 548 | # preserved (no ``await`` under the registry's |
| 549 | # RLock). |
| 550 | if transcript is not None: |
| 551 | try: |
| 552 | transcript.append(message) |
| 553 | except OSError: |
| 554 | logger.exception( |
| 555 | "transcript append failed for %s; further appends will be skipped", |
| 556 | agent_id, |
| 557 | ) |
| 558 | transcript.close() |
| 559 | transcript = None |
| 560 | |
| 561 | metadata = { |
| 562 | "start_time": time.time(), |
| 563 | "agent_type": agent_type, |
| 564 | } |
| 565 | result = finalize_agent_tool( |
| 566 | messages, agent_id, metadata, progress=tracker |
| 567 | ) |
| 568 | result_text = "\n".join( |
| 569 | block.get("text", "") |
| 570 | for block in result.content |
| 571 | if isinstance(block, dict) and block.get("type") == "text" |
| 572 | ).strip() |
no test coverage detected