Skip to content

feat(delegation): route ready children between turns - #76229

Open
Xipong wants to merge 2 commits into
NousResearch:mainfrom
Xipong:feat/delegation-ready-set
Open

feat(delegation): route ready children between turns#76229
Xipong wants to merge 2 commits into
NousResearch:mainfrom
Xipong:feat/delegation-ready-set

Conversation

@Xipong

@Xipong Xipong commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Note

This PR is stacked on #76228. GitHub temporarily shows the foundation commit because a fork branch cannot be used as the upstream base. The code owned by this PR is the single commit b2c9c3e24; after #76228 merges, this branch will be rebased onto main and the ancestor diff will disappear.

Decision summary

This is the independently useful after_turn improvement requested in #74378's close review: completed children become visible at the next existing between-turn boundary without waiting for unfinished siblings.

If only #76228 and this PR merge, Hermes still has no same-turn injection mode and no active-loop carrier.

Stack navigation

PR Owned commit Responsibility Standalone behavior
#76228 778dcaab3 durable child identity and settlement existing between-turn delivery
#76229 (this PR) b2c9c3e24 snapshot and route the current ready set faster after_turn, no active-loop change
#76230 9a6293b89 opt-in tool-result carrier dependent results may affect the active turn

The behavior change

Old batch behavior effectively joined every sibling before publishing the aggregate. A fast child could therefore remain invisible behind a slow or stuck sibling.

The new invariant is boundary-based rather than batch-finalization-based:

  • if only task:0 is ready at a boundary, deliver task:0 then;
  • if task:1 and task:2 become ready before a later boundary, deliver them together then;
  • if all children are ready at one boundary, deliver one grouped envelope;
  • never wait for an unfinished sibling merely to form an aggregate.

The envelope is transient. Durable ownership remains child-scoped in #76228.

Why this is one routing policy, not another delivery system

CLI, gateway, TUI, and API-server consumers all use the same:

  • child rows;
  • claim/lease/ack/release API;
  • ready-set coalescer;
  • deferred live-lease scheduler;
  • retry/drop state.

The bounded routing reservation covers only dequeue → coalesce → ownership/classification → requeue. Formatting, adapter I/O, and model work stay outside the lock.

This gives competing consumers an atomic answer to “who owns this ready set?” without serializing slow work.

Failure and race contracts

  • a child is published as soon as its own execution completes;
  • one ready-set claim owns every included row or none of them;
  • busy gateway/TUI sessions return a re-coalescible envelope;
  • children that finish while an envelope is deferred may join the next boundary;
  • claim loss cannot leave a TUI session marked busy;
  • a transient queue put failure is rescheduled rather than losing the only RAM copy;
  • live claims use one heap/condition scheduler, not immediate-requeue spin;
  • terminal/delivered siblings are pruned before a grouped retry.

Intentional exclusions

This PR adds no:

  • result_delivery option;
  • same-turn carrier;
  • synthetic user message;
  • provider-specific transport behavior;
  • wait, poll, or extra model iteration;
  • config/UI/model-tool surface.

Review focus

The reviewable question in commit b2c9c3e24 is:

Does every existing between-turn consumer expose exactly the currently ready durable children without loss, duplication, sibling blocking, or routing races?

The ancestor ledger is reviewed in #76228. The model-facing inject policy is reviewed in #76230.

Verification

  • affected async/CLI/gateway/TUI matrix: 604 passed, 0 failed;
  • GitHub regression found one lightweight ProcessRegistry.__new__ fixture missing the new lock; fixed by initializing the production-required field in that fixture;
  • full GitHub CI: 27 successful checks, 0 failures;
  • Ruff, py_compile, and git diff --check: passed;
  • current head (rebased): b2c9c3e24dd43d990a4eb62c114df2e8b295be01.

Coordination graph

Hermes triage dashboard graph

Live dashboard neighbourhood: https://hermes-triage.gottz.de/?node=76229

flowchart LR
    classDef focus fill:#fef3c7,stroke:#b45309,stroke-width:3px,color:#451a03
    classDef issue fill:#ede9fe,stroke:#6d28d9,color:#2e1065
    classDef open fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
    classDef closed fill:#e5e7eb,stroke:#6b7280,color:#1f2937
    P76229["PR #76229 (open)"]
    I85647(["issue #85647 (open)"])
    P46101["PR #46101 (open)"]
    P60863["PR #60863 (merged)"]
    P63133["PR #63133 (open)"]
    P68950["PR #68950 (open)"]
    P71898["PR #71898 (open)"]
    P72301["PR #72301 (open)"]
    P72620["PR #72620 (closed)"]
    P74378["PR #74378 (closed)"]
    P76228["PR #76228 (open)"]
    P76230["PR #76230 (open)"]
    P76229 -->|closes| I85647
    P76229 -->|related| I85647
    P76228 -.->|duplicate of 0.77| P76229
    P74378 -.->|duplicate of 0.69| P76229
    P76229 -.->|duplicate of 0.67| P76230
    P68950 -.->|duplicate of 0.65| P76229
    P63133 -.->|duplicate of 0.63| P76229
    P72620 -.->|duplicate of 0.63| P76229
    P71898 -.->|duplicate of 0.63| P76229
    P60863 -.->|duplicate of 0.63| P76229
    P46101 -.->|duplicate of 0.62| P76229
    P72301 -.->|duplicate of 0.62| P76229
    class P76229 focus
    click P76229 "https://github.com/NousResearch/hermes-agent/pull/76229"
    class I85647 issue
    click I85647 "https://github.com/NousResearch/hermes-agent/issues/85647"
    class P46101 open
    click P46101 "https://github.com/NousResearch/hermes-agent/pull/46101"
    class P60863 merged
    click P60863 "https://github.com/NousResearch/hermes-agent/pull/60863"
    class P63133 open
    click P63133 "https://github.com/NousResearch/hermes-agent/pull/63133"
    class P68950 open
    click P68950 "https://github.com/NousResearch/hermes-agent/pull/68950"
    class P71898 open
    click P71898 "https://github.com/NousResearch/hermes-agent/pull/71898"
    class P72301 open
    click P72301 "https://github.com/NousResearch/hermes-agent/pull/72301"
    class P72620 closed
    click P72620 "https://github.com/NousResearch/hermes-agent/pull/72620"
    class P74378 closed
    click P74378 "https://github.com/NousResearch/hermes-agent/pull/74378"
    class P76228 open
    click P76228 "https://github.com/NousResearch/hermes-agent/pull/76228"
    class P76230 open
    click P76230 "https://github.com/NousResearch/hermes-agent/pull/76230"
Loading

Dashboard interpretation:

  • solid edges are structural GitHub links (closes / related);
  • dashed edges are embedding-discovery candidates and show the dashboard score;
  • the fold thresholds reported by the dashboard are embedding 0.88 and file overlap 0.75;
  • a dashed duplicate of edge below the fold threshold is a similarity lead for review, not an accepted duplicate or merge-order edge;
  • the gold node is this PR; purple nodes are issues; blue/gray nodes are open/closed neighbouring PRs.

This graph is additive to the hand-audited coordination block above: the dashboard supplies discovery neighbourhoods, while the declared dependency, collision, ownership, and merge-order edges remain the reviewed coordination contract.

@Xipong
Xipong force-pushed the feat/delegation-ready-set branch from bcb6482 to 1d595c0 Compare August 1, 2026 14:57
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/cli CLI entry point, hermes_cli/, setup wizard comp/gateway Gateway runner, session dispatch, delivery comp/tui Terminal UI (ui-tui/ + tui_gateway/) tool/delegate Subagent delegation sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages labels Aug 1, 2026
@Xipong Xipong changed the title feat(delegation): deliver ready batch children after turns feat(delegation): route ready children between turns Aug 1, 2026
@teknium1

teknium1 commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Thanks for splitting the between-turn delivery work out of the rejected mid-loop injection direction. No blocking issue was found in this review.

Current main still has the reported behavior: dispatch_async_delegation_batch() documents one completion after every child finishes (tools/async_delegation.py:896-910), and its worker only calls _finalize_batch() after runner() returns its aggregate (tools/async_delegation.py:965-988). The PR changes that mechanism by publishing completed children (tools/delegate_tool.py:2983-3002) and coalescing only the ready child rows into a transient delivery envelope (tools/async_delegation.py:442-517 at 1d595c0cc). This keeps delivery at an existing turn boundary and does not introduce a synthetic mid-loop user message.

The #74378 maintainer discussion specifically invited this after-turn ready-set extraction and the child-level durable ledger. The implementation depends on the declared foundation commit in #76228; with that stack preserved, the PR is a high-value salvage candidate.

Automated hermes-sweeper review.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Aug 1, 2026
@Xipong
Xipong force-pushed the feat/delegation-ready-set branch 2 times, most recently from a7f8a89 to 9fcc3ee Compare August 7, 2026 20:22
@Xipong

Xipong commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto current main (a8c50eb1d) and re-stacked on the updated #76228. Test goals padded to >=10 chars (upstream _MIN_BATCH_GOAL_LEN validation), with the result-text assertions updated to match.

Verification: tests/tools/test_async_delegation.py + tests/tools/test_delegate_apiserver_background.py 24/24, py_compile clean.

@Xipong
Xipong force-pushed the feat/delegation-ready-set branch 3 times, most recently from 4d01304 to 5fa6180 Compare August 13, 2026 20:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard comp/gateway Gateway runner, session dispatch, delivery comp/tui Terminal UI (ui-tui/ + tui_gateway/) P3 Low — cosmetic, nice to have sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state tool/delegate Subagent delegation type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Delegation routing: deliver ready batch children without waiting for siblings

3 participants