From 0b38258d6cfec6bb3d68d28d000f3c3aea68f14e Mon Sep 17 00:00:00 2001 From: Alessandro <155005371+3clyp50@users.noreply.github.com> Date: Sun, 28 Jun 2026 18:46:58 +0200 Subject: [PATCH] Show Utility Model rename failures Notify users when automatic chat renaming cannot reach the Utility Model, while keeping the rename task best-effort. Normalize saved generated titles, mark WebUI state dirty after successful saves, and cover the success and failure paths with focused tests. --- extensions/python/monologue_start/AGENTS.md | 3 +- .../python/monologue_start/_60_rename_chat.py | 31 ++++++++-- tests/test_chat_rename_extension.py | 61 +++++++++++++++++++ 3 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 tests/test_chat_rename_extension.py diff --git a/extensions/python/monologue_start/AGENTS.md b/extensions/python/monologue_start/AGENTS.md index 93615ed68..3c4b32c48 100644 --- a/extensions/python/monologue_start/AGENTS.md +++ b/extensions/python/monologue_start/AGENTS.md @@ -12,10 +12,11 @@ - Keep automatic rename behavior bounded and non-destructive. - Do not override explicit user chat names without the intended guard conditions. +- Surface Utility Model rename failures with one scoped error notification per chat. ## Work Guidance -- Coordinate rename behavior with chat persistence and WebUI refresh. +- Coordinate rename behavior with chat persistence and WebUI refresh after successful saves. ## Verification diff --git a/extensions/python/monologue_start/_60_rename_chat.py b/extensions/python/monologue_start/_60_rename_chat.py index c23486b94..ee2361cf6 100644 --- a/extensions/python/monologue_start/_60_rename_chat.py +++ b/extensions/python/monologue_start/_60_rename_chat.py @@ -1,5 +1,7 @@ from helpers import persist_chat, tokens from helpers.extension import Extension +from helpers.notification import NotificationManager, NotificationPriority, NotificationType +from helpers.state_monitor_integration import mark_dirty_all from agent import LoopData import asyncio @@ -29,16 +31,35 @@ class RenameChat(Extension): "fw.rename_chat.msg.md", current_name=current_name, history=history_text ) # call utility model - new_name = await self.agent.call_utility_model( - system=system, message=message, background=True - ) + try: + new_name = await self.agent.call_utility_model( + system=system, message=message, background=True + ) + except Exception: + NotificationManager.send_notification( + type=NotificationType.ERROR, + priority=NotificationPriority.NORMAL, + title="Chat Rename Failed", + message="Automatic chat renaming failed because the Utility Model was not reachable.", + detail=( + "Automatic chat renaming uses the Utility Model. Check Settings > Models > " + "Utility Model, provider/API key, and network reachability." + ), + display_time=10, + group="chat_rename", + id=f"chat_rename_failed_{self.agent.context.id}", + ) + return # update name if new_name: - # trim name to max length if needed + new_name = " ".join(str(new_name).split()) if len(new_name) > 40: new_name = new_name[:40] + "..." + if not new_name: + return # apply to context and save self.agent.context.name = new_name persist_chat.save_tmp_chat(self.agent.context) - except Exception as e: + mark_dirty_all(reason="monologue_start.RenameChat.change_name") + except Exception: pass # non-critical diff --git a/tests/test_chat_rename_extension.py b/tests/test_chat_rename_extension.py new file mode 100644 index 000000000..abc02887a --- /dev/null +++ b/tests/test_chat_rename_extension.py @@ -0,0 +1,61 @@ +from types import SimpleNamespace + +import pytest + +from extensions.python.monologue_start import _60_rename_chat as rename_chat +from plugins._model_config.helpers import model_config + + +pytestmark = pytest.mark.asyncio + + +class _History: + def output_text(self) -> str: + return "User: Please help me plan the launch." + + +class _Agent: + def __init__(self, *, response: str | None = None, error: Exception | None = None): + self.context = SimpleNamespace(id="ctx-rename", name="") + self.history = _History() + self._response = response + self._error = error + + def read_prompt(self, name: str, **kwargs) -> str: + return name + + async def call_utility_model(self, **kwargs) -> str: + if self._error: + raise self._error + return self._response or "" + + +async def test_rename_failure_sends_utility_model_error_notification(monkeypatch): + sent: list[dict] = [] + + monkeypatch.setattr(model_config, "get_utility_model_config", lambda agent: {"ctx_length": 1000}) + monkeypatch.setattr(rename_chat.NotificationManager, "send_notification", lambda **kwargs: sent.append(kwargs)) + + await rename_chat.RenameChat(agent=_Agent(error=RuntimeError("offline"))).change_name() + + assert len(sent) == 1 + assert sent[0]["type"] == rename_chat.NotificationType.ERROR + assert sent[0]["title"] == "Chat Rename Failed" + assert "Utility Model was not reachable" in sent[0]["message"] + assert sent[0]["id"] == "chat_rename_failed_ctx-rename" + + +async def test_successful_rename_saves_clean_name_and_marks_state_dirty(monkeypatch): + saved_names: list[str] = [] + dirty_reasons: list[str | None] = [] + + monkeypatch.setattr(model_config, "get_utility_model_config", lambda agent: {"ctx_length": 1000}) + monkeypatch.setattr(rename_chat.persist_chat, "save_tmp_chat", lambda context: saved_names.append(context.name)) + monkeypatch.setattr(rename_chat, "mark_dirty_all", lambda *, reason=None: dirty_reasons.append(reason)) + + agent = _Agent(response="\n\nLaunch Readiness Notes\n") + await rename_chat.RenameChat(agent=agent).change_name() + + assert agent.context.name == "Launch Readiness Notes" + assert saved_names == ["Launch Readiness Notes"] + assert dirty_reasons == ["monologue_start.RenameChat.change_name"]