Skip to content

Commit 61f8753

Browse files
committed
fix(ui): show error details in title generation error dialog
Include the exception message in the title generation error dialog, matching completion, transcription, and save error handling. Change generate_title to return (title, error) so the presenter can display the real error.
1 parent 8e730ce commit 61f8753

File tree

4 files changed

+32
-17
lines changed

4 files changed

+32
-17
lines changed

basilisk/presenters/conversation_presenter.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,7 @@ def generate_conversation_title(self):
452452
model = self.view.current_model
453453
if not model:
454454
return
455-
title = self.service.generate_title(
455+
title, error = self.service.generate_title(
456456
engine=self.view.current_engine,
457457
conversation=self.conversation,
458458
provider_id=self.view.current_account.provider.id,
@@ -463,10 +463,13 @@ def generate_conversation_title(self):
463463
stream=self.view.stream_mode.GetValue(),
464464
)
465465
if title is None and self.conversation.messages:
466+
message = (
467+
_("An error occurred during title generation: %s") % error
468+
if error
469+
else _("An error occurred during title generation")
470+
)
466471
self.view.show_enhanced_error(
467-
_("An error occurred during title generation"),
468-
_("Title Generation Error"),
469-
is_completion_error=True,
472+
message, _("Title Generation Error"), is_completion_error=True
470473
)
471474
return title
472475

basilisk/services/conversation_service.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ def generate_title(
209209
top_p: float,
210210
max_tokens: int,
211211
stream: bool = True,
212-
) -> Optional[str]:
212+
) -> tuple[Optional[str], Optional[Exception]]:
213213
"""Generate a conversation title using the AI model.
214214
215215
Streaming is used by default; some providers (e.g. Anthropic) require
@@ -228,7 +228,8 @@ def generate_title(
228228
models that do not support streaming.
229229
230230
Returns:
231-
The generated title string, or None on failure.
231+
A tuple of (title, error). On success: (title_string, None).
232+
On failure: (None, exception).
232233
"""
233234
play_sound("progress", loop=True)
234235
try:
@@ -254,13 +255,13 @@ def generate_title(
254255
for chunk in engine.completion_response_with_stream(response):
255256
if isinstance(chunk, str):
256257
content_parts.append(chunk)
257-
return "".join(content_parts).strip()
258+
return "".join(content_parts).strip(), None
258259
new_block = engine.completion_response_without_stream(
259260
response=response, **completion_kw
260261
)
261-
return new_block.response.content
262-
except Exception:
262+
return new_block.response.content, None
263+
except Exception as e:
263264
log.error("Title generation failed", exc_info=True)
264-
return None
265+
return None, e
265266
finally:
266267
stop_sound()

tests/presenters/test_conversation_presenter.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ def test_returns_title_on_success(
404404
model=AIModelInfo(provider_id="openai", model_id="test"),
405405
)
406406
presenter.conversation.add_block(block, None)
407-
mock_service.generate_title.return_value = "My Conversation"
407+
mock_service.generate_title.return_value = ("My Conversation", None)
408408

409409
mocker.patch.object(
410410
presenter.completion_handler, "is_running", return_value=False
@@ -416,14 +416,19 @@ def test_returns_title_on_success(
416416
def test_shows_error_when_title_none_but_messages_exist(
417417
self, presenter, mock_view, mock_service, mocker
418418
):
419-
"""Shows enhanced error dialog when service returns None but messages exist."""
419+
"""Shows enhanced error dialog with error details when service fails."""
420420
block = MessageBlock(
421421
request=Message(role=MessageRoleEnum.USER, content="Hi"),
422422
response=Message(role=MessageRoleEnum.ASSISTANT, content="Hello"),
423423
model=AIModelInfo(provider_id="openai", model_id="test"),
424424
)
425425
presenter.conversation.add_block(block, None)
426-
mock_service.generate_title.return_value = None
426+
mock_service.generate_title.return_value = (
427+
None,
428+
ValueError(
429+
"Streaming is required for operations that may take longer than 10 minutes."
430+
),
431+
)
427432

428433
mocker.patch.object(
429434
presenter.completion_handler, "is_running", return_value=False
@@ -432,3 +437,5 @@ def test_shows_error_when_title_none_but_messages_exist(
432437

433438
assert result is None
434439
mock_view.show_enhanced_error.assert_called_once()
440+
call_args = mock_view.show_enhanced_error.call_args
441+
assert "Streaming is required" in call_args[0][0]

tests/services/test_conversation_service.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ def test_returns_content(self, service):
189189
model=AIModelInfo(provider_id="openai", model_id="test"),
190190
)
191191
)
192-
title = service.generate_title(
192+
title, error = service.generate_title(
193193
engine=mock_engine,
194194
conversation=conv,
195195
provider_id="openai",
@@ -199,6 +199,7 @@ def test_returns_content(self, service):
199199
max_tokens=100,
200200
)
201201
assert title == "My Title"
202+
assert error is None
202203

203204
def test_returns_content_without_stream(self, service):
204205
"""generate_title with stream=False should use non-streaming path."""
@@ -221,7 +222,7 @@ def test_returns_content_without_stream(self, service):
221222
model=AIModelInfo(provider_id="openai", model_id="test"),
222223
)
223224
)
224-
title = service.generate_title(
225+
title, error = service.generate_title(
225226
engine=mock_engine,
226227
conversation=conv,
227228
provider_id="openai",
@@ -232,14 +233,15 @@ def test_returns_content_without_stream(self, service):
232233
stream=False,
233234
)
234235
assert title == "Non-Stream Title"
236+
assert error is None
235237

236238
def test_returns_none_on_error(self, service):
237-
"""generate_title should return None on exception."""
239+
"""generate_title should return (None, exception) on exception."""
238240
mock_engine = MagicMock()
239241
mock_engine.completion.side_effect = RuntimeError("API down")
240242

241243
conv = Conversation()
242-
title = service.generate_title(
244+
title, error = service.generate_title(
243245
engine=mock_engine,
244246
conversation=conv,
245247
provider_id="openai",
@@ -249,3 +251,5 @@ def test_returns_none_on_error(self, service):
249251
max_tokens=100,
250252
)
251253
assert title is None
254+
assert error is not None
255+
assert str(error) == "API down"

0 commit comments

Comments
 (0)