fix: more fixes to AI chat

This commit is contained in:
2026-05-01 22:13:21 +02:00
parent c25720bf6e
commit 391a7f216f
4 changed files with 139 additions and 1 deletions

View File

@@ -479,10 +479,44 @@ defmodule BDS.AI.Chat do
case Catalog.decode_nullable_json(message.tool_calls) do
nil -> base
tool_calls -> Map.put(base, "tool_calls", tool_calls)
tool_calls -> Map.put(base, "tool_calls", tool_calls_for_runtime(tool_calls))
end
end
defp tool_calls_for_runtime(tool_calls) when is_list(tool_calls) do
Enum.map(tool_calls, &tool_call_for_runtime/1)
end
defp tool_calls_for_runtime(tool_calls), do: tool_calls
defp tool_call_for_runtime(%{"type" => "function", "function" => %{} = _function} = tool_call) do
tool_call
end
defp tool_call_for_runtime(%{"id" => id, "name" => name} = tool_call) do
%{
"id" => id,
"type" => "function",
"function" => %{
"name" => name,
"arguments" => Jason.encode!(tool_call["arguments"] || %{})
}
}
end
defp tool_call_for_runtime(%{id: id, name: name} = tool_call) do
%{
"id" => id,
"type" => "function",
"function" => %{
"name" => name,
"arguments" => Jason.encode!(Map.get(tool_call, :arguments) || %{})
}
}
end
defp tool_call_for_runtime(tool_call), do: tool_call
defp truncate_chat_messages(messages, model, tools) do
context_window = model_context_window(model)
reserve = min(@default_max_output_tokens, max(div(context_window, 4), 512))

View File

@@ -62,6 +62,16 @@ defmodule BDS.Desktop.ShellLive.ChatEditor.MessageBuild do
next_turn_index = turn_index + 1
{entries, start_entry(message, next_turn_index, assigns), next_turn_index}
:assistant ->
next_entry = start_entry(message, turn_index, assigns)
if tool_only_assistant_entry?(current_entry) do
{entries, merge_tool_only_entry(current_entry, next_entry), turn_index}
else
entries = finalize_entry(entries, current_entry)
{entries, next_entry, turn_index}
end
_other ->
entries = finalize_entry(entries, current_entry)
{entries, start_entry(message, turn_index, assigns), turn_index}
@@ -99,6 +109,22 @@ defmodule BDS.Desktop.ShellLive.ChatEditor.MessageBuild do
end
end
defp tool_only_assistant_entry?(%{role: :assistant, content: content} = entry) do
String.trim(content || "") == "" and
(entry.tool_markers != [] or entry.inline_surfaces != [] or entry.tool_surfaces != [])
end
defp tool_only_assistant_entry?(_entry), do: false
defp merge_tool_only_entry(tool_entry, assistant_entry) do
%{
assistant_entry
| tool_markers: tool_entry.tool_markers ++ assistant_entry.tool_markers,
inline_surfaces: tool_entry.inline_surfaces ++ assistant_entry.inline_surfaces,
tool_surfaces: tool_entry.tool_surfaces ++ assistant_entry.tool_surfaces
}
end
defp pending_user_message(_messages, nil), do: nil
defp pending_user_message(messages, %{message: message}) when is_binary(message) do