Skip to content

fix(delegation): preserve parent session identity across child runs - #74858

Closed
Xipong wants to merge 1 commit into
NousResearch:mainfrom
Xipong:fix/delegation-parent-session-context
Closed

fix(delegation): preserve parent session identity across child runs#74858
Xipong wants to merge 1 commit into
NousResearch:mainfrom
Xipong:fix/delegation-parent-session-context

Conversation

@Xipong

@Xipong Xipong commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Summary

Delegated child construction currently calls set_current_session_id(child.session_id), which publishes the child ID into the process-wide os.environ["HERMES_SESSION_ID"]. The parent continues running in the same process, so later parent terminal/execute-code subprocesses can inherit the last child's identity.

This PR:

  • suppresses the process-wide environment write while inside delegated_child_context();
  • scopes the child ContextVar to construction/execution and restores the parent value on exit;
  • explicitly binds child.session_id during the child run, so child terminal subprocesses still receive the correct identity through the existing subprocess-environment bridge;
  • preserves the existing root CLI/gateway/cron behavior, including the exceptional fallback path.

No new configuration, schema, model-facing tools, or persistence behavior is introduced.

Reproduction

  1. Start a parent agent session.
  2. Dispatch one or more delegate_task children.
  3. Run a terminal command from the parent and inspect HERMES_SESSION_ID.
  4. Before this fix, the environment ID resolves in state.db to a source='subagent' session whose parent_session_id is the real parent.
  5. With this fix, parent subprocesses retain the parent ID; each child subprocess receives only its own child ID through the task-local bridge.

Verification

  • New single/nested/concurrent ContextVar + environment + real build_subprocess_env contracts: 7 passed
  • Expanded session-context, local-env, API-server-background, single/batch delegation, Kanban/toolset/composite/summary/timeout matrix: 99 passed
  • Focused fallback-neighbor matrix after final hardening: 19 passed
  • Ruff and py_compile: passed

Current head: 56b8f3417521c627db605ed4c1060435a08b4ce1.

…cess env

AIAgent.__init__ calls set_current_session_id(self.session_id), which
mutated both the task-local ContextVar and the process-global os.environ.
Because _build_child_agent wraps construction in delegated_child_context(),
the ContextVar write is harmless (task-local), but the os.environ write
clobbered the parent's HERMES_SESSION_ID for the rest of the process —
leaking the child id into parent tools and subprocesses spawned after
the child was built.

Root cause of HermesPRDelegationSessionContext: parent
20260729_212118_5d797e dispatched child 20260730_160515_736ea1; later
parent terminal inherited HERMES_SESSION_ID=the child.

Fix: set_current_session_id() skips the process-global os.environ write
when called from within a delegated_child_context(). The child's own
tools and subprocesses still resolve their id through the ContextVar
(task-local), while the parent's process-wide env keeps the parent's
session identity. Root agents (CLI, gateway, cron) retain both paths.

Adds 7 regression tests covering single child, concurrent children (8
parallel), parent-tool observation after construction, and root-agent
session rotation backward compatibility. All pass; ruff clean.
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/gateway Gateway runner, session dispatch, delivery tool/delegate Subagent delegation sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state needs-decision Awaiting maintainer decision before any implementation labels Jul 30, 2026
@teknium1

Copy link
Copy Markdown
Contributor

Thanks for the focused fix. The premise is confirmed on current main: tools/delegate_tool.py:1503 constructs a child under delegated_child_context(), but agent/agent_init.py:1466 calls set_current_session_id, whose current implementation writes the child ID to process-wide os.environ at gateway/session_context.py:154. The current delegation context at agent/delegation_context.py:34-40 only tracks the child marker and does not restore the parent session ContextVar.

The proposed construction boundary, explicit child execution binding at tools/delegate_tool.py:2179, and subprocess-environment assertions align with the existing ContextVar bridge in tools/environments/local.py:635.

Automated hermes-sweeper review.

@teknium1 teknium1 added sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users area/sessions Session lifecycle, resume, persistence, history labels Jul 30, 2026
@teknium1

teknium1 commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Merged via #75856 — your commit(s) were cherry-picked onto current main with your authorship preserved in git history (rebase merge). Thanks for the contribution!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/sessions Session lifecycle, resume, persistence, history comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/gateway Gateway runner, session dispatch, delivery needs-decision Awaiting maintainer decision before any implementation P2 Medium — degraded but workaround exists sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state 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