fix(telegram): restore model-switch success path + author map

The cherry-picked PR over-indented the edit_message_text block for
the mm: (model selected → switch) success path so the confirmation
edit lived inside the preceding 'except Exception as exc' branch and
only fired when the callback raised. Dedent the try/except back to
12-space indent so it runs after the callback succeeds, restoring
the original flow that removes the inline buttons and shows the
'Switched to ...' confirmation.

Add a regression test (test_model_selected_edits_message_on_success)
that asserts edit_message_text is awaited and the result text is
routed through format_message (MARKDOWN_V2 + backtick survival).

Add phuongvm to scripts/release.py AUTHOR_MAP.
This commit is contained in:
teknium1 2026-05-14 07:42:24 -07:00 committed by Teknium
parent a694040520
commit 26deeea830
3 changed files with 56 additions and 11 deletions

View file

@ -2534,22 +2534,22 @@ class TelegramAdapter(BasePlatformAdapter):
result_text = f"Error switching model: {exc}" result_text = f"Error switching model: {exc}"
# Edit message to show confirmation, remove buttons # Edit message to show confirmation, remove buttons
try:
await query.edit_message_text(
text=self.format_message(result_text),
parse_mode=ParseMode.MARKDOWN_V2,
reply_markup=None,
)
except Exception:
# Markdown parse failure — retry as plain text
try: try:
await query.edit_message_text( await query.edit_message_text(
text=self.format_message(result_text), text=result_text,
parse_mode=ParseMode.MARKDOWN_V2, parse_mode=None,
reply_markup=None, reply_markup=None,
) )
except Exception: except Exception:
# Markdown parse failure — retry as plain text pass
try:
await query.edit_message_text(
text=result_text,
parse_mode=None,
reply_markup=None,
)
except Exception:
pass
await query.answer(text="Model switched!") await query.answer(text="Model switched!")
# Clean up state # Clean up state

View file

@ -715,6 +715,7 @@ AUTHOR_MAP = {
"tangyuanjc@JCdeAIfenshendeMac-mini.local": "tangyuanjc", "tangyuanjc@JCdeAIfenshendeMac-mini.local": "tangyuanjc",
"harryplusplus@gmail.com": "harryplusplus", "harryplusplus@gmail.com": "harryplusplus",
"anthhub@163.com": "anthhub", "anthhub@163.com": "anthhub",
"vmphuongit@gmail.com": "phuongvm",
"allard.quek@singtel.com": "AllardQuek", "allard.quek@singtel.com": "AllardQuek",
"shenuu@gmail.com": "shenuu", "shenuu@gmail.com": "shenuu",
"xiayh17@gmail.com": "xiayh0107", "xiayh17@gmail.com": "xiayh0107",

View file

@ -102,6 +102,50 @@ class TestTelegramModelPicker:
assert "provider\\_one" in edit_kwargs["text"] assert "provider\\_one" in edit_kwargs["text"]
assert "`model_1`" in edit_kwargs["text"] assert "`model_1`" in edit_kwargs["text"]
@pytest.mark.asyncio
async def test_model_selected_edits_message_on_success(self):
"""Regression: the mm: (model selected → switch) success path must
edit the picker message to show the confirmation and remove the
buttons. An earlier revision of this PR over-indented the
edit_message_text block so it lived inside the except branch and
only fired when the callback raised."""
adapter = _make_adapter()
callback = AsyncMock(return_value="Switched to `gpt-5`")
adapter._model_picker_state["12345"] = {
"providers": [
{"slug": "openai", "name": "OpenAI", "total_models": 1, "is_current": True}
],
"current_model": "model_1",
"current_provider": "openai",
"session_key": "s",
"on_model_selected": callback,
"selected_provider": "openai",
"model_list": ["gpt-5"],
"msg_id": 42,
}
query = AsyncMock()
query.data = "mm:0"
query.message = MagicMock()
query.message.chat_id = 12345
query.answer = AsyncMock()
query.edit_message_text = AsyncMock()
await adapter._handle_model_picker_callback(query, "mm:0", "12345")
# The callback was invoked with the selected model
callback.assert_awaited_once()
# edit_message_text MUST be called on the success path (this is the
# regression we're guarding).
query.edit_message_text.assert_awaited()
edit_kwargs = query.edit_message_text.call_args[1]
assert "MARKDOWN_V2" in repr(edit_kwargs["parse_mode"])
# The dynamic result text was routed through format_message
# (backtick code blocks survive escaping).
assert "`gpt-5`" in edit_kwargs["text"]
# State is cleaned up after a successful switch.
assert "12345" not in adapter._model_picker_state
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_retries_without_thread_when_thread_not_found(self): async def test_retries_without_thread_when_thread_not_found(self):
adapter = _make_adapter() adapter = _make_adapter()