fix(relay): avoid concurrent turn scope corruption - #74864
Conversation
Related to #73746 and merged #73493, but this is not a duplicate: #73493 repairs scope cleanup, while this PR prevents overlapping turns from opening non-LIFO Relay scopes. Current CI has one failing Python test: an existing mock lacks the new relay_enabled attribute. |
|
Thanks for isolating the overlap from the earlier logical-call cleanup work. The current-main premise is verified: Problems
Suggested changes
Automated hermes-sweeper review. |
|
Addressed Teknium's LIFO-regression feedback in The direct-runtime fake now maintains a context-local scope stack and rejects any pop whose handle is not at the top, matching the native Relay contract and error ( The overlapping-turn regression now runs against that strict fake, finishes the first turn while the second still overlaps, and asserts that no Validation on the branch's Relay 0.6 environment: |
SummaryOne PR addresses #73746. #74864 prevents overlapping turns in one Relay session from interleaving scopes by instrumenting only the first active turn; this directly removes the tested non-LIFO overlap path, but does not cover other cleanup-ordering causes or the separately reported stale-session gateway deadlock. Related pull requests
Suggested consolidationKeep #74864 open with a salvage path: retain the single-instrumented-turn guard and LIFO-enforcing regression as the focused fix for the demonstrated overlap mechanism, and track other cleanup causes and stale-session gateway recovery separately because they are outside this diff. There are no listed duplicate PRs to close. Complex graphflowchart LR
classDef open fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
classDef merged fill:#dcfce7,stroke:#15803d,color:#14532d
classDef closed fill:#e5e7eb,stroke:#6b7280,color:#1f2937
classDef unverified fill:#f3f4f6,stroke:#9ca3af,color:#374151
classDef best stroke-width:3px,stroke:#b45309
classDef target stroke-width:3px,stroke:#4338ca
I73746(["issue #73746 (open)"])
P74864["PR #74864 (open)"]
P74864 -->|best fix| I73746
class I73746 open
class P74864 open
class P74864 best
class P74864 target
click I73746 "https://github.com/NousResearch/hermes-agent/issues/73746"
click P74864 "https://github.com/NousResearch/hermes-agent/pull/74864"
Graph: solid arrow = fixes / best fix, dashed arrow = partial or unverified (see edge label); boxed group = PRs duplicating each other; amber border = best fix; indigo border = target; gray node = closed (state tag in the node label). Cross-PR triage: Reviewed 1 pull request and 1 issue in this complex. Each diff was read against this issue; Assessment working set: 11 kB of PR diffs, 7 kB of issue/PR text, 3 kB of discussion (3 comments), 2 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch. |
af30b39 to
fd18dc8
Compare
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
fd18dc8 to
e1caa61
Compare
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
|
@bbednarski9 one quick item: Success-path task_finished = True
if task_started:
finish_task_run(**task_context, result=result) |
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
|
@jquesnelle thanks for that. Addressed in 80c7ccf |
…urrent-turn-scopes fix(relay): avoid concurrent turn scope corruption
…urrent-turn-scopes fix(relay): avoid concurrent turn scope corruption
What does this PR do?
Fixes the NeMo Relay non-LIFO scope failure when two Hermes turns overlap for the same session. Relay 0.6 gives a session one physical LIFO scope stack; opening a scope for both turns lets turn B sit above turn A, so finishing A first attempts to pop a non-top handle.
Hermes now admits only one instrumented turn per shared session. An overlapping turn remains a normal Hermes turn but is marked
relay_enabled=False, so it cannot create turn, task, model, tool, logical-call, or shared-metrics Relay scopes. The context-local skipped state is preserved until that turn ends—even if the first turn ends while the skipped turn is current—and stale copied contexts remain fail-closed instead of falling back to the session handle.Relay version compatibility
This is the conservative path for Hermes's current
nemo-relay>=0.6.0,<0.7dependency. It is forward-compatible with Relay 0.7.x as written, but still deliberately instruments only one overlapping turn. A follow-up can capability-detect Relay 0.7.x's publicuse_scope_stack()API and give every turn an isolated stack while retaining this admission guard as the Relay 0.6 fallback.Related Issue
Fixes #73746
Type of Change
Changes Made
agent/relay_runtime.pyContextVartoken resets with an explicit predecessor chain, so ending turn A cannot erase current turn B;hermes_cli/observability/relay_shared_metrics.pyrun_agent.pytests/hermes_cli/test_relay_shared_metrics_runtime.pypre_api_request, ending A before continuing B, copied contexts, and subagent parent restoration.How to Test
Current macOS arm64 validation against the pinned Relay 0.6 binding:
57 passed;All checks passed!;non_lifo_errors=0;1895 passedbefore an unrelated order-dependenttest_file_safetyfailure that passes in isolation on both rebased branches. The full-suite checkbox remains unchecked pending CI's isolated slices.Checklist
Code
fix(scope):,feat(scope):, etc.)pytest tests/ -qand all tests passDocumentation & Housekeeping
docs/, docstrings) — or N/Acli-config.yaml.exampleif I added/changed config keys — or N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — or N/AFor New Skills
Not applicable.
Screenshots / Logs
Real Relay 0.6 overlap result: