fix(bot-mode): backfill follow-profile contract for legacy canonical Bot Chats
Bot Chats created before the follow_profile_config marker existed carry no contract in model_config, so they would stay pinned to a stale stored provider until deleted — the exact shape of the live reports (#89497, #94818). Mirror the plugin's own identity rule (the profile's session titled exactly 'Bot Chat') as a legacy fallback in _stored_session_runtime_overrides, matching the room-plumbing legacy 'Group:' title fallback. Follow-up to the salvaged #90343 (@curator8888) and #96111 (@lorzl).
This commit is contained in:
@@ -0,0 +1 @@
|
||||
curator8888
|
||||
@@ -621,6 +621,43 @@ class TestFollowProfileConfigRuntimeOverrides:
|
||||
assert overrides["model_override"]["model"] == "openai/gpt-5.6-luna-pro"
|
||||
assert overrides["model_override"]["provider"] == "nous"
|
||||
|
||||
def test_legacy_bot_chat_title_backfills_contract(self):
|
||||
"""Canonical Bot Chats created BEFORE the marker existed carry no
|
||||
follow_profile_config, but they are still the plugin-owned forever-DM
|
||||
(identified by the exact title "Bot Chat"). They must also rebuild
|
||||
from the profile's CURRENT config — the live-report shape where every
|
||||
pre-existing Bot Chat stayed pinned to a deleted provider."""
|
||||
from tui_gateway.server import _stored_session_runtime_overrides
|
||||
|
||||
for hidden in (0, 1):
|
||||
row = {
|
||||
"title": "Bot Chat",
|
||||
"hidden": hidden,
|
||||
"model": "openai/gpt-5.6-luna-pro",
|
||||
"billing_provider": "nous",
|
||||
"model_config": json.dumps(
|
||||
{"model": "openai/gpt-5.6-luna-pro", "provider": "nous"}
|
||||
),
|
||||
}
|
||||
assert _stored_session_runtime_overrides(row) == {}
|
||||
|
||||
def test_bot_chat_prefix_title_is_not_backfilled(self):
|
||||
"""Only the EXACT canonical title matches the legacy backfill — a
|
||||
user chat that merely mentions bots keeps its stored runtime."""
|
||||
from tui_gateway.server import _stored_session_runtime_overrides
|
||||
|
||||
row = {
|
||||
"title": "Bot Chat ideas for my app",
|
||||
"hidden": 0,
|
||||
"model": "glm-5.1",
|
||||
"billing_provider": "ollama-cloud",
|
||||
"model_config": json.dumps(
|
||||
{"model": "glm-5.1", "provider": "ollama-cloud"}
|
||||
),
|
||||
}
|
||||
overrides = _stored_session_runtime_overrides(row)
|
||||
assert overrides["model_override"]["model"] == "glm-5.1"
|
||||
|
||||
def test_ensure_db_row_persists_contract_marker(self, monkeypatch):
|
||||
"""_ensure_session_db_row stamps follow_profile_config into the row's
|
||||
model_config when the session carries the contract."""
|
||||
|
||||
@@ -5318,6 +5318,16 @@ def _stored_session_runtime_overrides(row: dict | None) -> dict:
|
||||
_follow_marker = None
|
||||
if _follow_marker:
|
||||
return {}
|
||||
# Legacy backfill: canonical Bot Chats created BEFORE the
|
||||
# follow_profile_config contract existed carry no marker, yet they are
|
||||
# still the plugin-owned forever-DM. The plugin's own identity rule is
|
||||
# "the profile's session titled exactly 'Bot Chat'" (UNIQUE(title) makes
|
||||
# that an exact registry, and pre-policy rows may be visible OR hidden),
|
||||
# so mirror that rule here. Without this, every Bot Chat that already
|
||||
# exists in the field stays pinned to its stale stored provider until
|
||||
# the user deletes it — the exact live-report shape (#89497 / #94818).
|
||||
if _row_title == "Bot Chat":
|
||||
return {}
|
||||
|
||||
raw_config = row.get("model_config")
|
||||
model_config: dict = {}
|
||||
|
||||
Reference in New Issue
Block a user