Skip to content

fix(gateway): keep multiplexed profiles in their own workspaces - #84584

Closed
fangliquanflq wants to merge 1 commit into
NousResearch:mainfrom
fangliquanflq:fix/gateway-profile-session-cwd
Closed

fangliquanflq wants to merge 1 commit into
NousResearch:mainfrom
fangliquanflq:fix/gateway-profile-session-cwd

Conversation

@fangliquanflq

Copy link
Copy Markdown

What does this PR do?

Multiplexed Discord profiles now start each routed session in that profile's configured terminal.cwd instead of inheriting the gateway launch profile's directory. This prevents terminal and file operations from running against another profile's workspace while preserving the session's later cd changes and existing conversation identity.

Symptom

When one gateway multiplexes profiles with different terminal.cwd values, a correctly routed profile can report and use the launch profile's working directory. The same profile behaves correctly when used outside the multiplexed gateway path.

Impact

Affected multiplexed sessions can run terminal commands and resolve relative file paths in another profile's workspace. Profile routing, credentials, skills, memory, and transcript isolation remain correct, but workspace isolation is lost.

Bug Cause

Trigger: gateway/run.py / GatewayRunner._set_session_env() when gateway.multiplex_profiles routes a message to a secondary profile.

Causal chain:

  1. The gateway resolves the incoming Discord message to the correct profile and enters that profile's runtime scope.
  2. _set_session_env() binds the routed profile and session key but does not bind the profile's configured working directory.
  3. Runtime cwd resolution falls back to the process-wide TERMINAL_CWD set by the launch profile, so terminal and relative file operations use the wrong workspace.

Why it is wrong: A process-global cwd fallback cannot represent multiple concurrently routed profiles. Mutating it per message would also introduce a cross-session race.

Working sibling / contrast: Single-profile and TUI launches load their own profile configuration at process startup, so their process-level fallback already points at the intended workspace.

Ruled out: Session-key routing was not the cause. The multiplexed path already selected the correct profile, credentials, skills, memory, and transcript; exact-base verification reproduced the cwd mismatch after routing succeeded.

Fix

The gateway now resolves the routed profile's explicit terminal.cwd, seeds the existing per-session cwd record only when that session has no live cwd, and binds it through the existing cwd ContextVar. Concurrent profiles remain isolated, while a later session-local cd stays authoritative on subsequent turns. Placeholder and absent cwd values retain the legacy fallback behavior.

Related Issue

Closes #84517

Type of Change

  • Bug fix (non-breaking change that fixes an issue)

Changes Made

  • gateway/run.py - resolve routed profile cwd and bind it into multiplexed session context without mutating process-global state.
  • tests/gateway/test_multiplex_profile_cwd.py - cover concurrent profile isolation, runtime/file cwd consistency, and later cd persistence.

How to Test

  1. Configure two multiplexed profiles with distinct terminal.cwd directories and route a Discord session to each profile.
  2. Confirm each session's runtime cwd and relative file resolution stay in its configured directory, then cd one session and confirm the new directory persists without affecting the other profile.
  3. Run the related automated tests:
scripts/run_tests.sh tests/gateway/test_multiplex_profile_cwd.py tests/gateway/test_session_context.py

The related suite passed locally: 22 tests passed. Exact-base REAL_ENV comparison reproduced the original cross-profile cwd inheritance; the committed tip isolated concurrent routed profile terminal/runtime/file paths and preserved later cd state.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run the repository test entry on the relevant tests and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested the multiplexed runtime path on Windows 10

Documentation & Housekeeping

  • Relevant documentation update: N/A - no user-facing configuration or behavior contract changed
  • cli-config.yaml.example update: N/A - no configuration keys changed
  • CONTRIBUTING.md or AGENTS.md update: N/A - no architecture or workflow contract changed
  • Cross-platform impact considered - path expansion preserves remote SSH tilde handling and uses existing local path semantics
  • Tool descriptions/schemas update: N/A - no tool schema changed

Screenshots / Logs

N/A - the regression is covered by exact-base runtime verification and automated tests.

@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/terminal Terminal execution and process management area/config Config system, migrations, profiles area/sessions Session lifecycle, resume, persistence, history area/profiles Multi-profile isolation, HERMES_HOME scoping 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 sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Aug 12, 2026
@Enough1122

Copy link
Copy Markdown

AI code review — automated review for reference, author can ignore or act on any point.

fix(gateway): keep multiplexed profiles in their own workspaces

  1. Seeded cwd is not validated to exist — _profile_terminal_cwd (gateway/run.py:9-47) resolves and returns terminal.cwd from a profile's config without checking that the directory actually exists, and _set_session_env then record_session_cwds it. If a profile's config points at a deleted/moved path, the session is seeded with a dead cwd and file tools resolve against it with no fallback to the process-level TERMINAL_CWD. Suggest Path(raw).is_dir() check → None so the existing fallback stays intact.

  2. Non-multiplexed path passes cwd="" — when multiplex_profiles is false, _session_cwd stays "" and is passed to set_session_vars. Worth verifying set_session_vars treats an empty cwd as "no override" (not an actual chdir target), since other callers of the gateway path now hit this argument too.

  3. Test couples to a private module global — the regression test monkeypatches terminal_tool._session_cwd directly (tests/gateway/test_multiplex_profile_cwd.py:143). Acceptable for a regression test, but if the cwd store ever moves to a per-session structure the test silently stops exercising the real path.

@teknium1

teknium1 commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Thanks for this PR. Merged via #101242 (4a7f228) on current main — routed multiplex profiles get their own terminal cwd/backend/docker config; container boot honors config multiplex_profiles.

#101242 won as the consolidated fix because it covers the whole multiplex-profile bug class in one change (with tests) rather than the single symptom addressed here; this PR is superseded by it.
Your PR is referenced in #101242's body as prior work on this bug.

If anything from your original change is still missing on main >= 4a7f228, please open a fresh PR/issue against main and tag it. Thanks again.

@teknium1 teknium1 closed this Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/config Config system, migrations, profiles area/profiles Multi-profile isolation, HERMES_HOME scoping 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 P2 Medium — degraded but workaround exists 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/terminal Terminal execution and process management type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[]

4 participants