fix(discord): preserve title retry thread rename

Fixes #127667.
This commit is contained in:
Angello Picasso
2026-09-29 08:51:49 +00:00
committed by kshitij
parent 47676981f5
commit ee559ccb3b
2 changed files with 89 additions and 0 deletions

View File

@@ -871,6 +871,35 @@ class TurnRunner:
session_id = getattr(agent, "session_id", None)
source = ctx.source
runner = self._runner
# Native Discord only stamps auto-thread markers on the opening parent-channel event. A
# title retry arrives as an ordinary in-thread event; when the agent was rebuilt, there
# is no first-turn callback left to rename it. Recover only those immutable markers from
# this same thread's persisted origin, while keeping the live source's transport owner.
if (
getattr(source, "platform", None) == Platform.DISCORD
and getattr(source, "chat_type", None) == "thread"
and getattr(source, "thread_id", None)
and getattr(source, "delivered_via_upstream_relay", False) is not True
and not runner._is_discord_auto_thread_lane(source)
):
with suppress(Exception):
row = agent._session_db.get_session(session_id)
origin = json.loads((row or {}).get("origin_json") or "{}")
initial_name = origin.get("auto_thread_initial_name")
if (
origin.get("platform") == Platform.DISCORD.value
and origin.get("chat_type") == "thread"
and str(origin.get("thread_id") or "") == str(source.thread_id)
and origin.get("auto_thread_created") is True
and isinstance(initial_name, str)
and initial_name.strip()
):
from gateway.session_identity import replace_source
source = replace_source(
source,
auto_thread_created=True,
auto_thread_initial_name=initial_name,
)
# Both lanes spend a rate-limited platform call per title, so they use the model's title
# only (TitleCallback); renaming twice burns Discord's 2-per-10-min budget on a throwaway.
# Relay Discord predicate is shape-only: whether the connector auto-threaded our reply is

View File

@@ -9,6 +9,7 @@ ten minutes, so the throwaway can be the one that survives.
from __future__ import annotations
import json
import types
import weakref
@@ -58,6 +59,65 @@ def test_the_rename_waits_for_the_model_title(lane):
assert renames == ["Fix flaky auth test"]
def test_discord_title_retry_recovers_auto_thread_origin():
"""A fresh agent on a later thread turn still wires the semantic rename."""
scheduled = []
current = SessionSource(
platform=Platform.DISCORD,
chat_id="thread-1",
chat_type="thread",
thread_id="thread-1",
message_id="follow-up",
)
origin = SessionSource(
platform=Platform.DISCORD,
chat_id="thread-1",
chat_type="thread",
thread_id="thread-1",
message_id="opening-message",
auto_thread_created=True,
auto_thread_initial_name="Opening words",
)
session_db = types.SimpleNamespace(
get_session=lambda session_id: {
"origin_json": json.dumps(origin.to_dict()),
}
)
runner = types.SimpleNamespace(
_is_telegram_topic_lane=lambda source: False,
_is_discord_auto_thread_lane=lambda source: (
source.platform == Platform.DISCORD
and source.chat_type == "thread"
and source.auto_thread_created is True
and bool(source.thread_id)
and bool(source.auto_thread_initial_name)
),
_is_relay_discord_channel_lane=lambda source: False,
_schedule_discord_semantic_thread_rename=(
lambda source, session_id, title: scheduled.append(
(source, session_id, title)
)
),
)
holder = types.SimpleNamespace(
_runner=runner,
_attach_session_title_callback=TurnRunner._attach_session_title_callback,
)
agent = types.SimpleNamespace(session_id="sess-1", _session_db=session_db)
holder._attach_session_title_callback(
holder, agent, types.SimpleNamespace(source=current)
)
agent._on_session_title("Recovered semantic title", "llm")
recovered, session_id, title = scheduled[0]
assert recovered.message_id == "follow-up"
assert recovered.auto_thread_created is True
assert recovered.auto_thread_initial_name == "Opening words"
assert session_id == "sess-1"
assert title == "Recovered semantic title"
@pytest.mark.anyio
async def test_native_thread_rename_passes_only_the_initial_name_guard():
"""The shared rename lane must honor the strict native adapter contract."""