Skip to content

fix(gateway): route multiplex clarify replies by profile - #83346

Open
Burningiron wants to merge 1 commit into
NousResearch:mainfrom
Burningiron:codex/fix-multiplex-clarify-routing
Open

fix(gateway): route multiplex clarify replies by profile#83346
Burningiron wants to merge 1 commit into
NousResearch:mainfrom
Burningiron:codex/fix-multiplex-clarify-routing

Conversation

@Burningiron

@Burningiron Burningiron commented Aug 10, 2026

Copy link
Copy Markdown

What does this PR do?

Routes active-session clarify replies through a profile-aware session key.

Under gateway multiplexing, the adapter busy guard remains adapter-local and uses the legacy agent:main key, while a pending clarify request for a named profile is stored under agent:<profile>. The previous clarify bypass reused the adapter-local key, so replies for secondary profiles missed the pending clarify and fell through to the busy interrupt path.

The fix builds a canonical clarify lookup key from the inbound event, including event.source.profile, while leaving adapter-local active-session bookkeeping unchanged. This preserves default-profile behavior and routes secondary-profile replies to the existing clarify resolver.

Related Issue

Fixes #83345

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Security fix
  • Documentation update
  • Tests (adding or improving test coverage)
  • Refactor (no behavior change)
  • New skill (bundled or hub)

Changes Made

  • gateway/platforms/base.py: build the pending-clarify lookup key with the routed source profile.
  • tests/gateway/test_clarify_active_session_bypass.py: add a behavioral regression test covering an adapter busy key under agent:main and pending clarify under agent:research.

How to Test

  1. Configure one gateway process with gateway.multiplex_profiles: true, a default profile, and a named secondary profile.
  2. Start a task through the secondary profile that invokes clarify, then reply with a choice such as 1.
  3. Verify that the reply reaches the clarify resolver, the same agent turn continues, and the busy interrupt handler is not invoked.

Focused automated verification:

scripts/run_tests.sh tests/gateway/test_clarify_active_session_bypass.py tests/gateway/test_clarify_thread_followup_not_swallowed.py tests/gateway/test_multiplex_adapter_registry.py -q
3 files, 18 tests passed, 0 failed
ruff check gateway/platforms/base.py tests/gateway/test_clarify_active_session_bypass.py
All checks passed

The original behavior was reproduced on a Linux gateway. The focused regression suite was run on Linux with Python 3.11.

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 (no unrelated commits)
  • I've run the complete test suite locally; focused affected tests pass and the full repository suite is pending CI
  • I've added tests for my changes
  • I've tested on my platform: Linux, Python 3.11

Documentation & Housekeeping

  • Documentation update: N/A — no public interface or configuration changes
  • cli-config.yaml.example update: N/A — no configuration keys changed
  • CONTRIBUTING.md / AGENTS.md update: N/A — no architecture or workflow changes
  • Cross-platform impact considered: the change only affects profile-aware session-key construction and introduces no OS-specific behavior
  • Tool descriptions/schemas update: N/A — no tool contract changed

Screenshots / Logs

No deployment screenshots or private gateway logs are attached because they may contain messaging identifiers. The minimal reproduction, focused test output, and regression test contain no account or peer data.

@neurosovereign

Copy link
Copy Markdown

Independent production confirmation of the root cause this PR fixes — same mechanism, different platform (Matrix, not Telegram).

We hit this on 2026-08-10 in a multiplexed gateway (gateway.multiplex_profiles: true, default profile + named profile kernel, each served by its own Matrix adapter instance). Timeline from gateway.log:

  • Runner registers the pending clarify under the profile-namespaced key agent:kernel:matrix:dm:!... (via ctx.session_key)
  • The adapter busy-guard bypass in BasePlatformAdapter.handle_message checks get_pending_for_session() with the adapter-local agent:main:matrix:dm:!... key
  • Lookup misses → user replies are queued behind the very turn waiting for them → clarify hangs until timeout

Our interim downstream mitigation (adapter-side override in our plugin, since we don't patch core): neurosovereign/hermes-matrix-tng@5e7aaab — resolves the reply at ingress against the profile-namespaced key. Verified in production after gateway restart: clarify replies now bind instantly while the turn is busy.

On this PR's approach (profile-namespaced key for the clarify lookup only, adapter-local busy bookkeeping left in agent:main): semantically equivalent to our workaround but at the right layer — fixes all platforms at once and routes to the runner's own intercept instead of duplicating its semantics. The regression test asserts the right invariant (busy key != clarify key; reply reaches the normal handler, busy handler untouched). +1 from a production multiplex deployment.

One note for reviewers: when event.source.profile is None (non-multiplex), the lookup key falls back to agent:main — byte-identical to today's behavior, so no regression surface for single-profile gateways.

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/gateway Gateway runner, session dispatch, delivery area/profiles Multi-profile isolation, HERMES_HOME scoping duplicate This issue or pull request already exists labels Aug 10, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Duplicate of #82980: both repair the profile-namespaced clarify lookup in gateway/platforms/base.py. #82980 is the earlier focused open PR.

ayushnangia added a commit to ayushnangia/hermes-agent that referenced this pull request Aug 14, 2026
One xfail per open member of the class mapped on NousResearch#82936: profile-scoped
state resolved from ambient process state at use time instead of bound
to the owning profile/session at creation. Test-only; fixes nothing;
flips to XPASS as per-site fixes land.

Members: NousResearch#82936 (multiplex terminal env), NousResearch#81952 (corrupt config silent
fallback), NousResearch#83346 (ambient session-key profile), NousResearch#80318 (profile scope
hides root MoA presets), NousResearch#83197/NousResearch#83557 (cron delivery scope reset before
delivery).
@Enough1122

Copy link
Copy Markdown
Contributor

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

fix(gateway): route multiplex clarify replies by profile

  1. Backward compatibility: the clarify lookup key now includes profile=event.source.profile. In single-profile (non-multiplexed) operation, event.source.profile should be None — confirm build_session_key(..., profile=None) reproduces the exact legacy key; if it doesn't, existing single-profile clarify replies would silently miss the lookup and fall into busy handling. A regression test asserting build_session_key(source, profile=None) == build_session_key(source) (no profile arg) would lock this.
  2. The group_sessions_per_user / thread_sessions_per_user config is re-read and re-applied here, duplicating the adapter's own key construction (gateway/platforms/base.py ~L6048). If the adapter's key-building logic evolves, this copy drifts silently; consider exposing the adapter's own builder parameterized by profile.
  3. The test covers the multiplex case only. Given the deliberate asymmetry (busy guards keep agent:main, clarify lookup is profile-routed), also cover the fallback: a clarify registered under the legacy key while event.source.profile is set should still route to the runner (or be explicitly documented as not found).

@alt-glitch alt-glitch added 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 and removed duplicate This issue or pull request already exists labels Aug 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/profiles Multi-profile isolation, HERMES_HOME scoping comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists 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 type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: clarify replies interrupt secondary profiles under gateway multiplexing

4 participants