From 6ebeb39268ad362ca43a449c1233fdcd4cfa0178 Mon Sep 17 00:00:00 2001 From: Hermes Date: Sun, 24 May 2026 22:52:57 -0400 Subject: [PATCH] feat: support multi-user Discord threads via context var - Add contextvars.ContextVar to carry resolved peer name from pre_gateway_dispatch to Honcho session init without modifying event.user_id (auth uses raw Discord snowflake) - _pre_gateway_dispatch: now stores resolved peer in context var - _patched_do_session_init: reads context var first, falls back to kanban resolution, then to existing user_id Requires thread_sessions_per_user: true in profile config.yaml (added to ashley, claire, finn, matt, paul) --- __init__.py | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/__init__.py b/__init__.py index d344780..ef497ea 100644 --- a/__init__.py +++ b/__init__.py @@ -10,6 +10,7 @@ Config: /opt/data/identity-config.json (persistent volume) from __future__ import annotations +import contextvars import json import logging import os @@ -23,6 +24,12 @@ logger = logging.getLogger(__name__) CONFIG_PATH = Path("/opt/data/identity-config.json") +# Context var to carry resolved peer name from pre_gateway_dispatch +# to Honcho's _do_session_init without modifying event.user_id. +_resolved_peer_var: contextvars.ContextVar[str | None] = contextvars.ContextVar( + "identity_resolved_peer", default=None +) + # ── Config ────────────────────────────────────────────────────────────────── @@ -161,10 +168,22 @@ _original_init: Callable | None = None def _patched_do_session_init(self, cfg, session_id: str, **kwargs): """Wrapper around Honcho's _do_session_init. - If no user_id was provided by the gateway (kanban worker / CLI context), - resolve one from the identity config and inject it. + Priority for user_id: + 1. _resolved_peer_var from pre_gateway_dispatch (gateway multi-user) + 2. get_peer_name() for kanban workers + 3. kwargs.get("user_id") as-is (existing Discord snowflake fallback) """ - if not kwargs.get("user_id"): + # Check context var first (set by _pre_gateway_dispatch for + # gateway-originated messages — peer name already resolved) + resolved = _resolved_peer_var.get() + if resolved: + logger.info( + "identity: Honcho peer '%s' from gateway dispatch (was %s)", + resolved, kwargs.get("user_id", "(none)"), + ) + kwargs["user_id"] = resolved + elif not kwargs.get("user_id"): + # Kanban worker / CLI — no user_id set by gateway resolved = get_peer_name() if resolved: logger.info( @@ -222,13 +241,17 @@ def _apply_honcho_patch(): def _pre_gateway_dispatch(event: Any, gateway: Any, session_store: Any, **kw) -> dict | None: - """Log resolved peer identity before dispatch.""" + """Resolve peer identity and store it for Honcho session init.""" platform = getattr(event, "platform", "unknown") user_id = getattr(event, "user_id", "unknown") resolved = resolve_peer(platform, user_id) if resolved: - logger.debug("identity: gateway platform=%s user_id=%s → peer=%s", platform, user_id, resolved) + logger.debug( + "identity: gateway platform=%s user_id=%s → peer=%s", + platform, user_id, resolved, + ) + _resolved_peer_var.set(resolved) else: logger.info("identity: unmapped gateway user platform=%s user_id=%s", platform, user_id) return None