fix: still fighting crashes on close and weird AI chat behaviou

This commit is contained in:
2026-05-02 08:40:36 +02:00
parent 7db8f6d36b
commit 631ceb0521
5 changed files with 93 additions and 11 deletions

View File

@@ -385,12 +385,19 @@ defmodule BDS.AI.Chat do
cond do
chat_user_message_count(conversation_id) < 1 ->
Logger.debug("Chat title generation skipped reason=:no_user_messages")
{:ok, reply}
not generated_chat_title?(conversation.title, conversation.model) ->
Logger.debug(
"Chat title generation skipped reason=:conversation_already_titled title=#{inspect(conversation.title)}"
)
{:ok, reply}
true ->
Logger.debug("Chat title generation requested conversation_id=#{conversation_id}")
case generate_chat_title(user_content, opts) do
{:ok, title} when is_binary(title) and title != "" ->
now = Persistence.now_ms()

View File

@@ -1,6 +1,8 @@
defmodule BDS.AI.OpenAICompatibleRuntime do
@moduledoc false
require Logger
alias BDS.AI.HttpClient
def list_models(endpoint, opts \\ []) when is_map(endpoint) and is_list(opts) do
@@ -39,6 +41,10 @@ defmodule BDS.AI.OpenAICompatibleRuntime do
|> maybe_disable_thinking(request.model)
|> maybe_put_tools(Map.get(request, :tools, []))
Logger.debug(
"AI OpenAI-compatible request operation=#{inspect(Map.get(request, :operation))} model=#{inspect(request.model)} url=#{url} tools=#{payload |> Map.get("tools", []) |> length()}"
)
with {:ok, response} <- HttpClient.post(url, headers, Jason.encode!(payload)),
200 <- response.status do
normalize_response(response.body)

View File

@@ -66,13 +66,33 @@ defmodule BDS.Desktop.Shutdown do
defp start_shutdown_task do
Task.start(fn ->
MainWindow.persist_now()
maybe_hide_window()
Process.sleep(50)
quit_module().quit()
end)
:ok
end
defp maybe_hide_window do
module = window_module()
if function_exported?(module, :hide, 1) do
module.hide(MainWindow.window_id())
end
:ok
rescue
_error -> :ok
catch
:exit, _reason -> :ok
end
defp quit_module do
Application.get_env(:bds, :desktop_window_quit_module, Window)
end
defp window_module do
Application.get_env(:bds, :desktop_window_module, Window)
end
end

View File

@@ -1,7 +1,9 @@
defmodule BDS.AITest do
use ExUnit.Case, async: false
import ExUnit.CaptureLog
import Ecto.Query
require Logger
alias BDS.Media.Media
alias BDS.Persistence
@@ -342,17 +344,28 @@ defmodule BDS.AITest do
{:ok, {_address, port}} = ThousandIsland.listener_info(server)
assert {:ok, %{content: "Short Title"}} =
BDS.AI.OpenAICompatibleRuntime.generate(
%{url: "http://127.0.0.1:#{port}/v1", api_key: nil},
%{
operation: :chat_title,
model: "qwen3.5-122b",
messages: [%{"role" => "user", "content" => "Topic: posts per month"}],
max_output_tokens: 20
},
[]
)
previous_level = Logger.level()
Logger.configure(level: :debug)
log =
capture_log(fn ->
assert {:ok, %{content: "Short Title"}} =
BDS.AI.OpenAICompatibleRuntime.generate(
%{url: "http://127.0.0.1:#{port}/v1", api_key: nil},
%{
operation: :chat_title,
model: "qwen3.5-122b",
messages: [%{"role" => "user", "content" => "Topic: posts per month"}],
max_output_tokens: 20
},
[]
)
end)
Logger.configure(level: previous_level)
assert log =~ "AI OpenAI-compatible request operation=:chat_title"
assert log =~ ~s(model="qwen3.5-122b")
assert_received {:completion_payload, payload}
assert payload["model"] == "qwen3.5-122b"

View File

@@ -23,6 +23,18 @@ defmodule BDS.DesktopTest do
end
end
defmodule FakeWindowLifecycle do
def hide(window_id) do
send(Application.fetch_env!(:bds, :desktop_shutdown_test_pid), {:window_hide_requested, window_id})
:ok
end
def quit do
send(Application.fetch_env!(:bds, :desktop_shutdown_test_pid), :window_quit_requested)
:ok
end
end
test "desktop configuration no longer uses a pending adapter" do
assert Application.get_env(:bds, BDS.Application)[:desktop_adapter] == :desktop
end
@@ -191,6 +203,30 @@ defmodule BDS.DesktopTest do
assert_receive :window_quit_requested
end
test "app-owned shutdown hides the window before hard quit" do
previous_module = Application.get_env(:bds, :desktop_shutdown_module)
previous_quit_module = Application.get_env(:bds, :desktop_window_quit_module)
previous_window_module = Application.get_env(:bds, :desktop_window_module)
previous_pid = Application.get_env(:bds, :desktop_shutdown_test_pid)
Application.put_env(:bds, :desktop_shutdown_module, BDS.Desktop.Shutdown)
Application.put_env(:bds, :desktop_window_quit_module, FakeWindowLifecycle)
Application.put_env(:bds, :desktop_window_module, FakeWindowLifecycle)
Application.put_env(:bds, :desktop_shutdown_test_pid, self())
expected_window_id = BDS.Desktop.MainWindow.window_id()
on_exit(fn ->
restore_env(:desktop_shutdown_module, previous_module)
restore_env(:desktop_window_quit_module, previous_quit_module)
restore_env(:desktop_window_module, previous_window_module)
restore_env(:desktop_shutdown_test_pid, previous_pid)
end)
assert :ok = BDS.Desktop.Shutdown.request_quit()
assert_receive {:window_hide_requested, ^expected_window_id}
assert_receive :window_quit_requested
end
test "desktop root html is a LiveView shell and references only the live bootstrap assets" do
conn = conn(:get, "/?k=#{Desktop.Auth.login_key()}")
conn = BDS.Desktop.Endpoint.call(conn, BDS.Desktop.Endpoint.init([]))