fix(session): persist profile_name and route batch key by profile
Two follow-ups observed after deploying profile routing:
1. sessions.profile_name was NULL even when the agent ran inside the
routed profile scope. _insert_session_row never wrote it,
get_or_create_session / reset_session never passed it through, and
the agent-side _ensure_db_session fallback had no way to read it.
- Declare profile_name TEXT in SCHEMA_SQL so _reconcile_columns
auto-adds it on existing DBs.
- _insert_session_row takes profile_name and writes it.
- SessionStore passes source.profile (or old_entry.origin.profile
on reset) into db_create_kwargs.
- _ensure_db_session reads the active profile via
get_active_profile_name() inside _profile_runtime_scope.
2. DiscordAdapter._text_batch_key called build_session_key without
profile=, so the batch key always landed in agent:main even when
the routed profile differed — diverging from the agent session
key namespace (agent:crypto-trader, agent:ai-expert, ...).
Pass event.source.profile through so both namespaces agree.
Live verification (jth-server-2, 2026-06-28): a test message in a
routed #coin thread produced agent:crypto-trader:discord🧵...
in the batch log and profile_name=crypto-trader in the sessions
row. Default-routed chat still produced agent:main / NULL.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
d7993ab178
commit
e8b7ce8c19
|
|
@ -1993,6 +1993,7 @@ class SessionStore:
|
||||||
"chat_id": source.chat_id,
|
"chat_id": source.chat_id,
|
||||||
"chat_type": source.chat_type,
|
"chat_type": source.chat_type,
|
||||||
"thread_id": source.thread_id,
|
"thread_id": source.thread_id,
|
||||||
|
"profile_name": source.profile,
|
||||||
}
|
}
|
||||||
|
|
||||||
if _needs_save:
|
if _needs_save:
|
||||||
|
|
@ -2273,6 +2274,7 @@ class SessionStore:
|
||||||
"chat_id": old_entry.origin.chat_id if old_entry.origin else None,
|
"chat_id": old_entry.origin.chat_id if old_entry.origin else None,
|
||||||
"chat_type": old_entry.origin.chat_type if old_entry.origin else None,
|
"chat_type": old_entry.origin.chat_type if old_entry.origin else None,
|
||||||
"thread_id": old_entry.origin.thread_id if old_entry.origin else None,
|
"thread_id": old_entry.origin.thread_id if old_entry.origin else None,
|
||||||
|
"profile_name": old_entry.origin.profile if old_entry.origin else None,
|
||||||
}
|
}
|
||||||
|
|
||||||
if self._db and db_end_session_id:
|
if self._db and db_end_session_id:
|
||||||
|
|
|
||||||
|
|
@ -791,6 +791,7 @@ CREATE TABLE IF NOT EXISTS sessions (
|
||||||
compression_failure_cooldown_until REAL,
|
compression_failure_cooldown_until REAL,
|
||||||
compression_failure_error TEXT,
|
compression_failure_error TEXT,
|
||||||
compression_fallback_streak INTEGER NOT NULL DEFAULT 0,
|
compression_fallback_streak INTEGER NOT NULL DEFAULT 0,
|
||||||
|
profile_name TEXT,
|
||||||
rewind_count INTEGER NOT NULL DEFAULT 0,
|
rewind_count INTEGER NOT NULL DEFAULT 0,
|
||||||
archived INTEGER NOT NULL DEFAULT 0,
|
archived INTEGER NOT NULL DEFAULT 0,
|
||||||
FOREIGN KEY (parent_session_id) REFERENCES sessions(id)
|
FOREIGN KEY (parent_session_id) REFERENCES sessions(id)
|
||||||
|
|
@ -1759,6 +1760,7 @@ class SessionDB:
|
||||||
thread_id: str = None,
|
thread_id: str = None,
|
||||||
parent_session_id: str = None,
|
parent_session_id: str = None,
|
||||||
cwd: str = None,
|
cwd: str = None,
|
||||||
|
profile_name: str = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Insert a session row, enriching NULL metadata on conflict.
|
"""Insert a session row, enriching NULL metadata on conflict.
|
||||||
|
|
||||||
|
|
@ -1782,9 +1784,9 @@ class SessionDB:
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"""INSERT INTO sessions (
|
"""INSERT INTO sessions (
|
||||||
id, source, user_id, session_key, chat_id, chat_type, thread_id,
|
id, source, user_id, session_key, chat_id, chat_type, thread_id,
|
||||||
model, model_config, system_prompt, parent_session_id, cwd, started_at
|
model, model_config, system_prompt, parent_session_id, cwd, profile_name, started_at
|
||||||
)
|
)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
ON CONFLICT(id) DO UPDATE SET
|
ON CONFLICT(id) DO UPDATE SET
|
||||||
model = COALESCE(sessions.model, excluded.model),
|
model = COALESCE(sessions.model, excluded.model),
|
||||||
model_config = COALESCE(sessions.model_config, excluded.model_config),
|
model_config = COALESCE(sessions.model_config, excluded.model_config),
|
||||||
|
|
@ -1794,7 +1796,8 @@ class SessionDB:
|
||||||
chat_type = COALESCE(sessions.chat_type, excluded.chat_type),
|
chat_type = COALESCE(sessions.chat_type, excluded.chat_type),
|
||||||
thread_id = COALESCE(sessions.thread_id, excluded.thread_id),
|
thread_id = COALESCE(sessions.thread_id, excluded.thread_id),
|
||||||
parent_session_id = COALESCE(sessions.parent_session_id, excluded.parent_session_id),
|
parent_session_id = COALESCE(sessions.parent_session_id, excluded.parent_session_id),
|
||||||
cwd = COALESCE(sessions.cwd, excluded.cwd)""",
|
cwd = COALESCE(sessions.cwd, excluded.cwd),
|
||||||
|
profile_name = COALESCE(sessions.profile_name, excluded.profile_name)""",
|
||||||
(
|
(
|
||||||
session_id,
|
session_id,
|
||||||
source,
|
source,
|
||||||
|
|
@ -1808,6 +1811,7 @@ class SessionDB:
|
||||||
system_prompt,
|
system_prompt,
|
||||||
parent_session_id,
|
parent_session_id,
|
||||||
cwd,
|
cwd,
|
||||||
|
profile_name,
|
||||||
time.time(),
|
time.time(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -6612,12 +6612,20 @@ class DiscordAdapter(BasePlatformAdapter):
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
|
|
||||||
def _text_batch_key(self, event: MessageEvent) -> str:
|
def _text_batch_key(self, event: MessageEvent) -> str:
|
||||||
"""Session-scoped key for text message batching."""
|
"""Session-scoped key for text message batching.
|
||||||
|
|
||||||
|
Passes ``event.source.profile`` through so routed messages batch
|
||||||
|
under the same namespace the agent run will use (e.g.
|
||||||
|
``agent:crypto-trader`` instead of ``agent:main``). Without this,
|
||||||
|
the batch key would always land in ``agent:main`` even when the
|
||||||
|
routed profile differs.
|
||||||
|
"""
|
||||||
from gateway.session import build_session_key
|
from gateway.session import build_session_key
|
||||||
return build_session_key(
|
return build_session_key(
|
||||||
event.source,
|
event.source,
|
||||||
group_sessions_per_user=self.config.extra.get("group_sessions_per_user", True),
|
group_sessions_per_user=self.config.extra.get("group_sessions_per_user", True),
|
||||||
thread_sessions_per_user=self.config.extra.get("thread_sessions_per_user", False),
|
thread_sessions_per_user=self.config.extra.get("thread_sessions_per_user", False),
|
||||||
|
profile=event.source.profile,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _enqueue_text_event(self, event: MessageEvent) -> None:
|
def _enqueue_text_event(self, event: MessageEvent) -> None:
|
||||||
|
|
|
||||||
|
|
@ -599,6 +599,13 @@ class AIAgent:
|
||||||
return
|
return
|
||||||
source = _session_source_for_agent(self.platform)
|
source = _session_source_for_agent(self.platform)
|
||||||
try:
|
try:
|
||||||
|
try:
|
||||||
|
from hermes_cli.profiles import get_active_profile_name
|
||||||
|
_profile_for_session = get_active_profile_name()
|
||||||
|
if _profile_for_session == "default":
|
||||||
|
_profile_for_session = None
|
||||||
|
except Exception:
|
||||||
|
_profile_for_session = None
|
||||||
self._session_db.create_session(
|
self._session_db.create_session(
|
||||||
session_id=self.session_id,
|
session_id=self.session_id,
|
||||||
source=source,
|
source=source,
|
||||||
|
|
@ -608,6 +615,7 @@ class AIAgent:
|
||||||
user_id=None,
|
user_id=None,
|
||||||
parent_session_id=self._parent_session_id,
|
parent_session_id=self._parent_session_id,
|
||||||
cwd=_launch_cwd_for_session(source),
|
cwd=_launch_cwd_for_session(source),
|
||||||
|
profile_name=_profile_for_session,
|
||||||
)
|
)
|
||||||
self._session_db_created = True
|
self._session_db_created = True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue