fix(gateway): keep /model + /reasoning overrides on topic recovery & compression splits
Session-scoped /model and /reasoning overrides were silently lost on Telegram DM/forum topics and after compression session splits (#30479). Root cause: _handle_message_with_agent rewrites source.thread_id via _recover_telegram_topic_thread_id (lobby/stripped reply -> the user's bound topic) before deriving the session key. The /model and /reasoning handlers derived their override key from the raw inbound event.source, skipping that recovery, so the override was stored under one key and the next message turn read a different key. Fix: add _normalize_source_for_session_key (applies the same recovery a message turn does) and use it in both handlers before deriving the key. session_id rotation on compression was never the cause — overrides are keyed by the durable session_key; the split path preserves it. Author: teknium1 <127238744+teknium1@users.noreply.github.com>
This commit is contained in:
+38
-1
@@ -2618,6 +2618,34 @@ class GatewayRunner:
|
||||
return None
|
||||
return None
|
||||
|
||||
def _normalize_source_for_session_key(
|
||||
self,
|
||||
source: SessionSource,
|
||||
) -> SessionSource:
|
||||
"""Apply Telegram DM topic recovery to a source for session-key purposes.
|
||||
|
||||
``_handle_message_with_agent`` rewrites ``source.thread_id`` via
|
||||
``_recover_telegram_topic_thread_id`` *before* deriving the session
|
||||
key for a normal message turn (a lobby/stripped reply gets pinned to
|
||||
the user's last-active topic). Session-scoped command handlers like
|
||||
``/model`` and ``/reasoning`` derive their override key from the raw
|
||||
inbound ``event.source``, which skips that recovery — so the override
|
||||
is stored under a different key than the next message turn reads,
|
||||
and the override is silently dropped on Telegram forum topics and
|
||||
after compression session splits (#30479).
|
||||
|
||||
Returns a recovery-normalized copy when a rewrite applies, otherwise
|
||||
the original source unchanged. Always derive the override storage key
|
||||
from the result so storage and read use an identical key.
|
||||
"""
|
||||
try:
|
||||
recovered = self._recover_telegram_topic_thread_id(source)
|
||||
except Exception:
|
||||
return source
|
||||
if recovered is None:
|
||||
return source
|
||||
return dataclasses.replace(source, thread_id=recovered)
|
||||
|
||||
def _resolve_session_agent_runtime(
|
||||
self,
|
||||
*,
|
||||
@@ -11175,6 +11203,11 @@ class GatewayRunner:
|
||||
|
||||
# Check for session override
|
||||
source = event.source
|
||||
# Normalize the source the same way a normal message turn does
|
||||
# (Telegram DM topic recovery) before deriving the override key, so
|
||||
# the override is stored under the key the next message turn reads
|
||||
# (#30479).
|
||||
source = self._normalize_source_for_session_key(source)
|
||||
session_key = self._session_key_for_source(source)
|
||||
override = self._session_model_overrides.get(session_key, {})
|
||||
if override:
|
||||
@@ -12923,7 +12956,11 @@ class GatewayRunner:
|
||||
raw_args = event.get_command_args().strip()
|
||||
args, persist_global = self._parse_reasoning_command_args(raw_args)
|
||||
config_path = _hermes_home / "config.yaml"
|
||||
session_key = self._session_key_for_source(event.source)
|
||||
# Normalize the source (Telegram DM topic recovery) before deriving
|
||||
# the override key so storage matches the key the next message turn
|
||||
# reads — same fix as /model (#30479).
|
||||
_reasoning_source = self._normalize_source_for_session_key(event.source)
|
||||
session_key = self._session_key_for_source(_reasoning_source)
|
||||
self._show_reasoning = self._load_show_reasoning()
|
||||
self._reasoning_config = self._resolve_session_reasoning_config(
|
||||
source=event.source,
|
||||
|
||||
Reference in New Issue
Block a user