Skip to content

fix(delegation): update live-transcript manifest on async completion - #72771

Closed
plcunha wants to merge 1 commit into
NousResearch:mainfrom
plcunha:fix/delegation-manifest-async-update
Closed

fix(delegation): update live-transcript manifest on async completion#72771
plcunha wants to merge 1 commit into
NousResearch:mainfrom
plcunha:fix/delegation-manifest-async-update

Conversation

@plcunha

@plcunha plcunha commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Summary

Keep live-transcript manifests synchronized when background delegate_task workers finish. Both single-child and batch finalization now write terminal per-task statuses through update_manifest_statuses(), so Desktop/status consumers no longer see completed children as perpetually running.

The manifest update is best-effort and intentionally occurs after completion delivery; a filesystem/logging failure cannot suppress the result returning to the parent conversation.

RED proof

The regression tests were copied onto unfixed origin/main (cff972858) and run there:

$ HERMES_TEST_FILE_RETRIES=0 scripts/run_tests.sh \
    tests/tools/test_async_delegation.py -q \
    -k 'single_async_finalization_updates_live_manifest or batch_async_finalization_updates_live_manifest'

FAILED ...::test_single_async_finalization_updates_live_manifest
  AssertionError: assert [] == [('deleg_...', [result])]
FAILED ...::test_batch_async_finalization_updates_live_manifest
  AssertionError: assert [] == [('deleg_...', results)]
2 failed, 40 deselected

After the fix:

2 passed, 40 deselected

Code path trace

  1. Symptom: background children finish and deliver their summaries, but cache/delegation/live/<id>/manifest.json can remain status=running indefinitely.
  2. Intermediate: the synchronous aggregation path calls update_manifest_statuses(), while _finalize() and _finalize_batch() only publish completion events and durable state.
  3. Root cause: the async finalization rail never bridged its terminal result back into the live-transcript manifest owned by delegation_live_log.

Widening audit

  • Single background delegation: affected → updates the manifest with [result].
  • Background fan-out batch: affected → updates the manifest with combined.results.
  • Synchronous delegation: already updates manifests; unchanged.
  • Empty batch results: no update, preserving the manifest rather than fabricating terminal entries.
  • Completion delivery: remains authoritative and occurs before the best-effort manifest write.
  • Manifest filesystem/import failure: logged at debug and cannot lose the user-facing completion event.
  • Stalled/interrupted async finalization: shares the same finalizers and therefore gets terminal manifest propagation.

Verification

$ HERMES_TEST_FILE_RETRIES=0 scripts/run_tests.sh \
    tests/tools/test_async_delegation.py \
    tests/tools/test_delegation_live_log.py -q
75 passed

$ ruff check tools/async_delegation.py tests/tools/test_async_delegation.py
All checks passed!

$ python3 -m py_compile tools/async_delegation.py tests/tools/test_async_delegation.py
$ git diff --check

Validated on PR head d3f89eb0c. GitHub reports the branch mergeable with all required checks passing against the current base.

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/tools Tool registry, model_tools, toolsets tool/delegate Subagent delegation labels Jul 27, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Related to #67479: that merged live-transcript infrastructure updates manifest statuses on synchronous aggregation, while this focused follow-up adds the missing async-finalization updates.

@plcunha
plcunha force-pushed the fix/delegation-manifest-async-update branch from 9126109 to d941c42 Compare July 29, 2026 15:22
The synchronous subagent path in delegate_tool calls
update_manifest_statuses() after every batch aggregates, so the
cache/delegation/live/<id>/manifest.json always reflects the final
per-task statuses.  The background-pool path (_finalize for single
subagents and _finalize_batch for fan-out batches) was missing this
call, so completed tasks appeared as 'running' forever even after
their .log files recorded 'final | status=completed'.

The Desktop and status-bar subagent indicators read manifest.json
directly, so this gap caused the UI to show '1 Background' /
'Thinking' indefinitely for every async delegation, even when all
work had already finished.

Add update_manifest_statuses to both _finalize and _finalize_batch,
wrapped in best-effort try/except so a manifest write failure never
blocks delivery of the completion event to the chat.
@plcunha
plcunha force-pushed the fix/delegation-manifest-async-update branch from d941c42 to d3f89eb Compare July 29, 2026 18:48
@teknium1

Copy link
Copy Markdown
Contributor

Thanks for the focused investigation and regression coverage.

Automated hermes-sweeper review found this behavior is already implemented on current main:

  • tools/delegate_tool.py:3146 calls update_manifest_statuses(live_deleg_id, results) after finalizing child results.
  • The production background path uses that same aggregation function through _batch_runner at tools/delegate_tool.py:3270-3273, then dispatches it with the matching live-transcript ID at tools/delegate_tool.py:3318-3336.
  • The existing implementation arrived with 299e409f15aa5615a8a64be488580be92cda351e (feat(delegation): live-viewable subagent transcripts — tail your subagents while they work (#67479)).

The proposed tests invoke dispatch_async_delegation* directly, whereas live manifests are created and owned by the delegate_task aggregation path. Closing as already implemented on main.

@teknium1 teknium1 closed this Jul 30, 2026
@teknium1 teknium1 added the sweeper:implemented-on-main Sweeper: behavior already present on current main label Jul 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/tools Tool registry, model_tools, toolsets P2 Medium — degraded but workaround exists sweeper:implemented-on-main Sweeper: behavior already present on current main tool/delegate Subagent delegation type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants