fix(sessions): protect canonical Bot Chat from auto-title
This commit is contained in:
+17
-15
@@ -10866,8 +10866,8 @@ class SessionDB(SessionSearchMixin, SessionSchemaMixin, SessionPortabilityMixin)
|
||||
# Bot Mode's forever-chat registry: the session titled exactly this, on a
|
||||
# bot's profile, IS the bot's canonical chat — resolved by exact-title
|
||||
# lookup on every open (no session-id pointer exists). The title is the
|
||||
# identity, which is why _set_session_title refuses user renames of a
|
||||
# hidden row holding it (#92473).
|
||||
# identity, which is why _set_session_title refuses renames of a hidden
|
||||
# row holding it (#92473).
|
||||
CANONICAL_BOT_CHAT_TITLE = "Bot Chat"
|
||||
|
||||
@classmethod
|
||||
@@ -10979,12 +10979,13 @@ class SessionDB(SessionSearchMixin, SessionSchemaMixin, SessionPortabilityMixin)
|
||||
"""Write a title, enforcing provenance precedence.
|
||||
|
||||
``source`` is one of ``TITLE_SOURCE_{DERIVED,LLM,USER}``. A ``user``
|
||||
write always lands — an explicit rename is authoritative. An automatic
|
||||
write (``derived``/``llm``) lands only when the row is untitled or the
|
||||
stored title has strictly lower authority, so the instant ``derived``
|
||||
title upgrades to ``llm`` exactly once and neither can ever overwrite a
|
||||
name the user typed. Re-running the titler on an already-``llm`` row is
|
||||
a no-op, which is what stops a session renaming itself.
|
||||
write is authoritative except for a canonical Bot Chat identity. An
|
||||
automatic write (``derived``/``llm``) lands only when the row is
|
||||
untitled or the stored title has strictly lower authority, so the
|
||||
instant ``derived`` title upgrades to ``llm`` exactly once and neither
|
||||
can ever overwrite a name the user typed. Re-running the titler on an
|
||||
already-``llm`` row is a no-op, which is what stops a session renaming
|
||||
itself.
|
||||
|
||||
The read and the write are one compare-and-swap inside a single
|
||||
transaction, so a manual ``/title`` racing an in-flight generation
|
||||
@@ -11011,16 +11012,17 @@ class SessionDB(SessionSearchMixin, SessionSchemaMixin, SessionPortabilityMixin)
|
||||
# born hidden; an ordinary visible session a user happens to call
|
||||
# "Bot Chat" stays freely renameable.
|
||||
if (
|
||||
is_user
|
||||
and (current["title"] or "") == self.CANONICAL_BOT_CHAT_TITLE
|
||||
(current["title"] or "") == self.CANONICAL_BOT_CHAT_TITLE
|
||||
and bool(current["hidden"])
|
||||
and title != self.CANONICAL_BOT_CHAT_TITLE
|
||||
):
|
||||
raise ValueError(
|
||||
"This is the bot's canonical Bot Chat — its name is its "
|
||||
"identity, and renaming it would orphan the conversation. "
|
||||
"To start fresh, create a new bot instead."
|
||||
)
|
||||
if is_user:
|
||||
raise ValueError(
|
||||
"This is the bot's canonical Bot Chat — its name is its "
|
||||
"identity, and renaming it would orphan the conversation. "
|
||||
"To start fresh, create a new bot instead."
|
||||
)
|
||||
return 0
|
||||
if not is_user and current["title"] is not None:
|
||||
if self._title_rank(current["title_source"]) >= new_rank:
|
||||
return 0
|
||||
|
||||
@@ -69,3 +69,38 @@ def test_auto_titler_still_cannot_touch_the_canonical_row(db):
|
||||
assert not db.set_auto_title(sid, "Chat about groceries", source=SessionDB.TITLE_SOURCE_LLM)
|
||||
row = db.get_session_by_title(SessionDB.CANONICAL_BOT_CHAT_TITLE)
|
||||
assert row and row["id"] == sid
|
||||
|
||||
|
||||
def test_auto_titler_cannot_rename_derived_canonical_bot_chat(db):
|
||||
db.create_session("derived", source="desktop")
|
||||
assert db._set_session_title(
|
||||
"derived",
|
||||
SessionDB.CANONICAL_BOT_CHAT_TITLE,
|
||||
source=SessionDB.TITLE_SOURCE_DERIVED,
|
||||
)
|
||||
assert db.set_session_hidden("derived", True)
|
||||
|
||||
assert not db.set_auto_title(
|
||||
"derived",
|
||||
"Renamed by titler",
|
||||
source=SessionDB.TITLE_SOURCE_LLM,
|
||||
)
|
||||
row = db.get_session("derived")
|
||||
assert row["title"] == SessionDB.CANONICAL_BOT_CHAT_TITLE
|
||||
assert row["title_source"] == SessionDB.TITLE_SOURCE_DERIVED
|
||||
|
||||
|
||||
def test_auto_titler_can_rename_visible_derived_bot_chat(db):
|
||||
db.create_session("visible", source="desktop")
|
||||
assert db._set_session_title(
|
||||
"visible",
|
||||
SessionDB.CANONICAL_BOT_CHAT_TITLE,
|
||||
source=SessionDB.TITLE_SOURCE_DERIVED,
|
||||
)
|
||||
|
||||
assert db.set_auto_title(
|
||||
"visible",
|
||||
"Renamed by titler",
|
||||
source=SessionDB.TITLE_SOURCE_LLM,
|
||||
)
|
||||
assert db.get_session("visible")["title"] == "Renamed by titler"
|
||||
|
||||
Reference in New Issue
Block a user