feat: step 5 claimed done
This commit is contained in:
@@ -13,6 +13,31 @@ defmodule BDS.Desktop.ShellLive.ChatEditor do
|
||||
assign(socket, :chat_editor, build(socket.assigns))
|
||||
end
|
||||
|
||||
def toggle_model_selector(socket, reload) do
|
||||
%{id: conversation_id} = socket.assigns.current_tab
|
||||
current = Map.get(socket.assigns.chat_model_selectors_open, conversation_id, false)
|
||||
|
||||
socket
|
||||
|> assign(:chat_model_selectors_open, Map.put(socket.assigns.chat_model_selectors_open, conversation_id, not current))
|
||||
|> reload.(socket.assigns.workbench)
|
||||
end
|
||||
|
||||
def set_model(socket, model_id, reload, append_output) do
|
||||
%{id: conversation_id} = socket.assigns.current_tab
|
||||
|
||||
case AI.set_conversation_model(conversation_id, model_id) do
|
||||
{:ok, _conversation} ->
|
||||
socket
|
||||
|> assign(:chat_model_selectors_open, Map.put(socket.assigns.chat_model_selectors_open, conversation_id, false))
|
||||
|> reload.(socket.assigns.workbench)
|
||||
|
||||
{:error, reason} ->
|
||||
socket
|
||||
|> append_output.(translated("Chat"), inspect(reason), nil, "error")
|
||||
|> reload.(socket.assigns.workbench)
|
||||
end
|
||||
end
|
||||
|
||||
def update_input(socket, value, reload) do
|
||||
%{id: conversation_id} = socket.assigns.current_tab
|
||||
|
||||
@@ -53,10 +78,12 @@ defmodule BDS.Desktop.ShellLive.ChatEditor do
|
||||
%ChatConversation{} = conversation ->
|
||||
%{
|
||||
id: conversation.id,
|
||||
title: conversation.title || translated("New Chat"),
|
||||
title: conversation.title || translated("chat.newChat"),
|
||||
model: conversation.model,
|
||||
available_models: AI.available_chat_models(conversation.model),
|
||||
model_selector_open?: Map.get(assigns.chat_model_selectors_open, conversation.id, false),
|
||||
input: Map.get(assigns.chat_editor_inputs, conversation.id, ""),
|
||||
messages: AI.list_chat_messages(conversation.id),
|
||||
messages: build_entries(AI.list_chat_messages(conversation.id)),
|
||||
offline?: Map.get(assigns, :offline_mode, true)
|
||||
}
|
||||
end
|
||||
@@ -64,5 +91,89 @@ defmodule BDS.Desktop.ShellLive.ChatEditor do
|
||||
|
||||
def build(_assigns), do: nil
|
||||
|
||||
def message_role_label(:user), do: translated("chat.role.you")
|
||||
def message_role_label(_role), do: translated("chat.role.assistant")
|
||||
|
||||
def tool_call_name(tool_call) when is_map(tool_call) do
|
||||
Map.get(tool_call, "name") || Map.get(tool_call, :name) || "tool"
|
||||
end
|
||||
|
||||
def tool_surface_type(surface), do: Map.get(surface, :type, "json")
|
||||
|
||||
defp build_entries(messages) do
|
||||
{entries, current_entry} =
|
||||
Enum.reduce(messages, {[], nil}, fn message, {entries, current_entry} ->
|
||||
case message.role do
|
||||
:tool ->
|
||||
if current_entry && current_entry.role == :assistant do
|
||||
{entries, append_tool_surface(current_entry, message)}
|
||||
else
|
||||
{entries, current_entry}
|
||||
end
|
||||
|
||||
:system ->
|
||||
{entries, current_entry}
|
||||
|
||||
_other ->
|
||||
entries = finalize_entry(entries, current_entry)
|
||||
{entries, start_entry(message)}
|
||||
end
|
||||
end)
|
||||
|
||||
entries
|
||||
|> finalize_entry(current_entry)
|
||||
|> Enum.reverse()
|
||||
end
|
||||
|
||||
defp finalize_entry(entries, nil), do: entries
|
||||
defp finalize_entry(entries, entry), do: [entry | entries]
|
||||
|
||||
defp start_entry(message) do
|
||||
%{
|
||||
id: message.id,
|
||||
role: message.role,
|
||||
content: message.content || "",
|
||||
tool_markers: normalize_tool_calls(message.tool_calls),
|
||||
tool_surfaces: []
|
||||
}
|
||||
end
|
||||
|
||||
defp append_tool_surface(entry, message) do
|
||||
case normalize_tool_surface(message.content) do
|
||||
nil -> entry
|
||||
surface -> update_in(entry.tool_surfaces, &(&1 ++ [surface]))
|
||||
end
|
||||
end
|
||||
|
||||
defp normalize_tool_calls(tool_calls) when is_list(tool_calls) do
|
||||
Enum.map(tool_calls, fn tool_call ->
|
||||
%{
|
||||
name: tool_call_name(tool_call),
|
||||
arguments: Map.get(tool_call, "arguments") || Map.get(tool_call, :arguments) || Map.get(tool_call, "args") || Map.get(tool_call, :args) || %{}
|
||||
}
|
||||
end)
|
||||
end
|
||||
|
||||
defp normalize_tool_calls(_tool_calls), do: []
|
||||
|
||||
defp normalize_tool_surface(content) when is_binary(content) do
|
||||
case Jason.decode(content) do
|
||||
{:ok, %{"type" => type} = decoded} ->
|
||||
%{
|
||||
type: type,
|
||||
title: decoded["title"],
|
||||
columns: List.wrap(decoded["columns"]),
|
||||
rows: Enum.map(List.wrap(decoded["rows"]), &List.wrap/1),
|
||||
fields: List.wrap(decoded["fields"]),
|
||||
data: decoded
|
||||
}
|
||||
|
||||
_other ->
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
defp normalize_tool_surface(_content), do: nil
|
||||
|
||||
def translated(text, bindings \\ %{}), do: ShellData.translate(text, bindings, Process.get(:bds_ui_locale))
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user