feat: per-user profile routing via config.yaml (#33548) - #33892
feat: per-user profile routing via config.yaml (#33548)#33892ousiaresearch wants to merge 1 commit into
Conversation
Adds profile_routing config section mapping user identity strings (Telegram UID, Discord snowflake) to Hermes profile names. When matched, the gateway switches to the target profile for message processing and restores afterward. Includes MessageEvent.target_profile field and _load_profile_routing/_resolve_profile_for_user helpers.
Design notes — config.yaml vs env var approachThis PR implements per-user profile routing through a ```yaml Why config.yaml over env var (#33558):
Both approaches solve #33548. The env var approach (#33558) is simpler for single-user setups; the config.yaml approach is better for multi-user routing (which is the actual use case — different humans hitting the same gateway instance). |
|
Agreed @ousiaresearch - @alt-glitch are we good to merge here? |
|
Would love to see this implemented! |
Competing-PR cluster for #33548 (per-user profile routing). This PR uses a |
|
👍 for the config.yaml approach over env vars — the version-controlled audit trail and clean multi-user scaling matter for real deployments. Our use case: single BlueBubbles (iMessage) instance on a Mac Mini serving three household users, each with their own Hermes profile (separate SOUL, AGENTS, memory banks, model config). Phone number → profile routing via profile_routing in config.yaml is exactly what we need — one gateway, one BlueBubbles server, three fully isolated agent identities. Would love to see this (or #33558) merged. Either approach unblocks multi-user iMessage without custom middleware. |
teknium1
left a comment
There was a problem hiding this comment.
Thanks for pursuing the config.yaml route; the current gateway has the profile-scoping primitives needed for this feature, but this patch is not yet connected to them.
Problems
gateway/run.py:6917in this PR storesevent.target_profile, while current execution resolves the profile solely fromsource.profileingateway/run.py:16977-16987. There is no current gateway consumer oftarget_profile, so a matched map does not switch the turn.- The mapping runs after the authorization/pairing return path. Current authorization and adapter lookup use
SessionSource.profile(gateway/authz_mixin.py:39-70), so the target profile cannot govern intake or reply delivery. - Main rejects duplicate same-platform credentials in multiplex mode (
gateway/run.py:8586-8600); the single-ingress adapter must remain the reply transport while the turn runs in the mapped profile's scope.
Suggested changes
- Resolve and apply the mapped profile at the
SessionSource.profileingress seam before authorization and session creation, then exercise the existing_profile_runtime_scopepath. - Add integration tests covering mapped/unmapped users, profile-local session/config isolation, authorization, and replies through the ingress adapter.
Automated hermes-sweeper review.
| _routed_profile, | ||
| self._active_profile_name(), | ||
| ) | ||
| event.target_profile = _routed_profile |
There was a problem hiding this comment.
target_profile is not consumed by the gateway execution path. Current main scopes the turn from source.profile (gateway/run.py:16977-16987) and resolves the response adapter from that same field (gateway/authz_mixin.py:61-70), so this assignment does not route the message. Apply the resolved profile at the source/profile ingress seam before authorization and session-key creation.
Related to #65571. Current main now has the richer |
What does this PR do?
Adds per-user profile routing via config.yaml. Maps user identity strings to Hermes profiles — the gateway switches profiles for individual users.
Fixes #33548
Type of Change
Changes Made
gateway/platforms/base.py: Addedtarget_profilefield to MessageEventgateway/run.py: Added_load_profile_routing,_resolve_profile_for_user, routing block in_handle_messageHow to Test
profile_routing: {"<user_id>": "<profile>"}to config.yamlChecklist