fix: more work on A2UI
This commit is contained in:
@@ -135,6 +135,7 @@ defmodule BDS.Desktop.ShellLive do
|
||||
|> assign(:chat_editor_request_refs, %{})
|
||||
|> assign(:chat_editor_surface_data, %{})
|
||||
|> assign(:chat_editor_surface_tabs, %{})
|
||||
|> assign(:chat_editor_dismissed_surfaces, MapSet.new())
|
||||
|> assign(:chat_editor_action_errors, %{})
|
||||
|> assign(:import_editor_analysis_states, %{})
|
||||
|> assign(:import_editor_analysis_task_refs, %{})
|
||||
@@ -948,6 +949,10 @@ defmodule BDS.Desktop.ShellLive do
|
||||
ChatEditor.select_surface_tab(socket, surface_id, parse_integer(index), &reload_shell/2)}
|
||||
end
|
||||
|
||||
def handle_event("dismiss_chat_surface", %{"surface-id" => surface_id}, socket) do
|
||||
{:noreply, ChatEditor.dismiss_surface(socket, surface_id, &reload_shell/2)}
|
||||
end
|
||||
|
||||
def handle_event("chat_surface_action", params, socket) do
|
||||
{:noreply,
|
||||
ChatSurface.handle_action(socket, params, %{
|
||||
|
||||
@@ -59,6 +59,16 @@ defmodule BDS.Desktop.ShellLive.ChatEditor do
|
||||
|> reload.(socket.assigns.workbench)
|
||||
end
|
||||
|
||||
@spec dismiss_surface(term(), term(), term()) :: term()
|
||||
def dismiss_surface(socket, surface_id, reload) when is_binary(surface_id) do
|
||||
socket
|
||||
|> assign(
|
||||
:chat_editor_dismissed_surfaces,
|
||||
MapSet.put(socket.assigns.chat_editor_dismissed_surfaces, surface_id)
|
||||
)
|
||||
|> reload.(socket.assigns.workbench)
|
||||
end
|
||||
|
||||
@spec current_surface_data(term(), term()) :: term()
|
||||
def current_surface_data(socket, surface_id) when is_binary(surface_id) do
|
||||
Map.get(socket.assigns.chat_editor_surface_data, surface_id, %{})
|
||||
@@ -314,13 +324,23 @@ defmodule BDS.Desktop.ShellLive.ChatEditor do
|
||||
<%= if @markers != [] do %>
|
||||
<div class="chat-tool-markers">
|
||||
<%= for marker <- @markers do %>
|
||||
<div class={["chat-tool-marker", if(marker.complete?, do: "completed", else: "pending")]} data-testid="chat-tool-marker">
|
||||
<span class="chat-tool-marker-icon"><%= if marker.complete?, do: "✓", else: "●" %></span>
|
||||
<span class="chat-tool-marker-name"><%= marker.name %></span>
|
||||
<%= if marker.args_preview not in [nil, ""] do %>
|
||||
<span class="chat-tool-marker-args">(<%= marker.args_preview %>)</span>
|
||||
<% end %>
|
||||
</div>
|
||||
<details class={["chat-tool-marker", if(marker.complete?, do: "completed", else: "pending")]} data-testid="chat-tool-marker">
|
||||
<summary>
|
||||
<span class="chat-tool-marker-icon"><%= if marker.complete?, do: "✓", else: "●" %></span>
|
||||
<span class="chat-tool-marker-name"><%= marker.name %></span>
|
||||
<%= if marker.args_preview not in [nil, ""] do %>
|
||||
<span class="chat-tool-marker-args">(<%= marker.args_preview %>)</span>
|
||||
<% end %>
|
||||
</summary>
|
||||
<div class="chat-tool-marker-details" data-testid="chat-tool-marker-details">
|
||||
<div class="chat-tool-marker-detail-label"><%= translated("chat.toolArguments") %></div>
|
||||
<pre><%= Jason.encode!(marker.arguments || %{}, pretty: true) %></pre>
|
||||
<%= if marker.result not in [nil, ""] do %>
|
||||
<div class="chat-tool-marker-detail-label"><%= translated("chat.toolResult") %></div>
|
||||
<pre><%= marker.result %></pre>
|
||||
<% end %>
|
||||
</div>
|
||||
</details>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
@@ -332,7 +352,13 @@ defmodule BDS.Desktop.ShellLive.ChatEditor do
|
||||
@spec chat_surface(term()) :: term()
|
||||
def chat_surface(assigns) do
|
||||
~H"""
|
||||
<article class={["chat-inline-surface", "chat-inline-surface-#{@surface.type}"]} data-testid="chat-inline-surface">
|
||||
<details id={@surface.id} class={["chat-inline-surface", "chat-inline-surface-#{@surface.type}"]} data-testid="chat-inline-surface" open={Map.get(@surface, :expanded?, false)}>
|
||||
<summary class="chat-inline-surface-header">
|
||||
<span class="chat-inline-surface-icon"><%= surface_icon(@surface.type) %></span>
|
||||
<span class="chat-inline-surface-title"><%= surface_title(@surface) %></span>
|
||||
<button class="chat-inline-surface-dismiss" type="button" phx-click="dismiss_chat_surface" phx-value-surface-id={@surface.id} aria-label={translated("chat.dismissSurface")} data-testid="chat-inline-surface-dismiss">×</button>
|
||||
</summary>
|
||||
<div class="chat-inline-surface-body">
|
||||
<%= case @surface.type do %>
|
||||
<% "card" -> %>
|
||||
<div class="chat-surface-card">
|
||||
@@ -526,10 +552,28 @@ defmodule BDS.Desktop.ShellLive.ChatEditor do
|
||||
<% _other -> %>
|
||||
<pre class="chat-tool-surface-json"><%= Jason.encode!(@surface.raw || %{}, pretty: true) %></pre>
|
||||
<% end %>
|
||||
</article>
|
||||
</div>
|
||||
</details>
|
||||
"""
|
||||
end
|
||||
|
||||
defp surface_icon("chart"), do: "▥"
|
||||
defp surface_icon("table"), do: "▦"
|
||||
defp surface_icon("form"), do: "▤"
|
||||
defp surface_icon("card"), do: "▣"
|
||||
defp surface_icon("metric"), do: "#"
|
||||
defp surface_icon("list"), do: "☰"
|
||||
defp surface_icon("tabs"), do: "▧"
|
||||
defp surface_icon(_type), do: "■"
|
||||
|
||||
defp surface_title(surface) do
|
||||
cond do
|
||||
present?(Map.get(surface, :title)) -> Map.get(surface, :title)
|
||||
present?(Map.get(surface, :label)) -> Map.get(surface, :label)
|
||||
true -> surface.type |> to_string() |> String.capitalize()
|
||||
end
|
||||
end
|
||||
|
||||
# ── Private helpers ───────────────────────────────────────────────────────
|
||||
|
||||
defp update_request(socket, conversation_id, updater, reload) do
|
||||
|
||||
@@ -31,6 +31,7 @@ defmodule BDS.Desktop.ShellLive.ChatEditor.MessageBuild do
|
||||
is_streaming: not is_nil(request),
|
||||
streaming_content: streaming_content(request),
|
||||
streaming_tool_markers: ToolTracking.tool_markers_from_events(request),
|
||||
streaming_inline_surfaces: streaming_inline_surfaces(conversation.id, request, assigns),
|
||||
offline?: Map.get(assigns, :offline_mode, true),
|
||||
needs_api_key?: ModelSelection.needs_api_key?(Map.get(assigns, :offline_mode, true)),
|
||||
action_error: Map.get(assigns.chat_editor_action_errors, conversation.id),
|
||||
@@ -49,7 +50,7 @@ defmodule BDS.Desktop.ShellLive.ChatEditor.MessageBuild do
|
||||
case message.role do
|
||||
:tool ->
|
||||
if current_entry && current_entry.role == :assistant do
|
||||
{entries, append_tool_surface(current_entry, message), turn_index}
|
||||
{entries, append_tool_result(current_entry, message), turn_index}
|
||||
else
|
||||
{entries, current_entry, turn_index}
|
||||
end
|
||||
@@ -95,18 +96,15 @@ defmodule BDS.Desktop.ShellLive.ChatEditor.MessageBuild do
|
||||
content: message.content || "",
|
||||
turn_index: turn_index,
|
||||
tool_markers: tool_markers,
|
||||
inline_surfaces: ToolSurfaces.build_render_surfaces(tool_markers, message.id, assigns),
|
||||
inline_surfaces:
|
||||
ToolSurfaces.build_render_surfaces(tool_markers, message.id, assigns)
|
||||
|> mark_latest_surface_expanded(assigns),
|
||||
tool_surfaces: []
|
||||
}
|
||||
end
|
||||
|
||||
defp append_tool_surface(entry, message) do
|
||||
entry = ToolTracking.mark_tool_call_completed(entry, message.tool_call_id)
|
||||
|
||||
case ToolSurfaces.normalize_tool_surface(message.content) do
|
||||
nil -> entry
|
||||
surface -> update_in(entry.tool_surfaces, &(&1 ++ [surface]))
|
||||
end
|
||||
defp append_tool_result(entry, message) do
|
||||
ToolTracking.mark_tool_call_completed(entry, message.tool_call_id, message.content)
|
||||
end
|
||||
|
||||
defp tool_only_assistant_entry?(%{role: :assistant, content: content} = entry) do
|
||||
@@ -125,6 +123,17 @@ defmodule BDS.Desktop.ShellLive.ChatEditor.MessageBuild do
|
||||
}
|
||||
end
|
||||
|
||||
defp mark_latest_surface_expanded([], _assigns), do: []
|
||||
|
||||
defp mark_latest_surface_expanded(surfaces, assigns) do
|
||||
dismissed = Map.get(assigns, :chat_editor_dismissed_surfaces, MapSet.new())
|
||||
|
||||
surfaces
|
||||
|> Enum.reject(&MapSet.member?(dismissed, &1.id))
|
||||
|> Enum.with_index()
|
||||
|> Enum.map(fn {surface, index} -> Map.put(surface, :expanded?, index == length(surfaces) - 1) end)
|
||||
end
|
||||
|
||||
defp pending_user_message(_messages, nil), do: nil
|
||||
|
||||
defp pending_user_message(messages, %{message: message}) when is_binary(message) do
|
||||
@@ -140,6 +149,15 @@ defmodule BDS.Desktop.ShellLive.ChatEditor.MessageBuild do
|
||||
defp streaming_content(%{content: content}) when is_binary(content), do: content
|
||||
defp streaming_content(_request), do: ""
|
||||
|
||||
defp streaming_inline_surfaces(_conversation_id, nil, _assigns), do: []
|
||||
|
||||
defp streaming_inline_surfaces(conversation_id, request, assigns) do
|
||||
request
|
||||
|> ToolTracking.tool_markers_from_events()
|
||||
|> ToolSurfaces.build_render_surfaces("streaming-#{conversation_id}", assigns)
|
||||
|> mark_latest_surface_expanded(assigns)
|
||||
end
|
||||
|
||||
defp translated(text, bindings \\ %{}),
|
||||
do: ShellData.translate(text, bindings, BDS.Desktop.UILocale.current())
|
||||
end
|
||||
|
||||
@@ -22,6 +22,7 @@ defmodule BDS.Desktop.ShellLive.ChatEditor.ToolTracking do
|
||||
name: tool_call_name(tool_call),
|
||||
arguments: arguments,
|
||||
args_preview: tool_arguments_preview(arguments),
|
||||
result: nil,
|
||||
complete?: false
|
||||
}
|
||||
end)
|
||||
@@ -39,11 +40,19 @@ defmodule BDS.Desktop.ShellLive.ChatEditor.ToolTracking do
|
||||
@spec tool_arguments_preview(term()) :: term()
|
||||
def tool_arguments_preview(_arguments), do: ""
|
||||
|
||||
@spec mark_tool_call_completed(term(), term()) :: term()
|
||||
def mark_tool_call_completed(entry, tool_call_id) when is_binary(tool_call_id) do
|
||||
mark_tool_call_completed(entry, tool_call_id, nil)
|
||||
end
|
||||
|
||||
def mark_tool_call_completed(entry, _tool_call_id), do: entry
|
||||
|
||||
@spec mark_tool_call_completed(term(), term(), term()) :: term()
|
||||
def mark_tool_call_completed(entry, tool_call_id, result) when is_binary(tool_call_id) do
|
||||
update_in(entry.tool_markers, fn markers ->
|
||||
Enum.map(markers, fn marker ->
|
||||
if marker.id == tool_call_id do
|
||||
%{marker | complete?: true}
|
||||
%{marker | complete?: true, result: result}
|
||||
else
|
||||
marker
|
||||
end
|
||||
@@ -51,8 +60,7 @@ defmodule BDS.Desktop.ShellLive.ChatEditor.ToolTracking do
|
||||
end)
|
||||
end
|
||||
|
||||
@spec mark_tool_call_completed(term(), term()) :: term()
|
||||
def mark_tool_call_completed(entry, _tool_call_id), do: entry
|
||||
def mark_tool_call_completed(entry, _tool_call_id, _result), do: entry
|
||||
|
||||
@spec tool_markers_from_events(term()) :: term()
|
||||
def tool_markers_from_events(nil), do: []
|
||||
@@ -68,6 +76,7 @@ defmodule BDS.Desktop.ShellLive.ChatEditor.ToolTracking do
|
||||
name: event.name,
|
||||
arguments: event.arguments,
|
||||
args_preview: tool_arguments_preview(event.arguments || %{}),
|
||||
result: nil,
|
||||
complete?: false
|
||||
}
|
||||
]
|
||||
|
||||
@@ -109,40 +109,6 @@
|
||||
<.chat_surface surface={surface} />
|
||||
<% end %>
|
||||
|
||||
<%= for surface <- message.tool_surfaces do %>
|
||||
<article class="chat-tool-surface" data-testid="chat-tool-surface">
|
||||
<%= if surface.title do %>
|
||||
<h3><%= surface.title %></h3>
|
||||
<% end %>
|
||||
|
||||
<%= case tool_surface_type(surface) do %>
|
||||
<% "table" -> %>
|
||||
<div class="chat-tool-surface-table-wrap">
|
||||
<table class="chat-tool-surface-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<%= for column <- surface.columns do %>
|
||||
<th><%= column %></th>
|
||||
<% end %>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<%= for row <- surface.rows do %>
|
||||
<tr>
|
||||
<%= for value <- row do %>
|
||||
<td><%= value %></td>
|
||||
<% end %>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<% _other -> %>
|
||||
<pre class="chat-tool-surface-json"><%= Jason.encode!(surface.data, pretty: true) %></pre>
|
||||
<% end %>
|
||||
</article>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<%= if @chat_editor.is_streaming and (@chat_editor.streaming_content != "" or @chat_editor.streaming_tool_markers != []) do %>
|
||||
@@ -160,6 +126,10 @@
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= for surface <- @chat_editor.streaming_inline_surfaces do %>
|
||||
<.chat_surface surface={surface} />
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<%= if @chat_editor.is_streaming and @chat_editor.streaming_content == "" and @chat_editor.streaming_tool_markers == [] do %>
|
||||
|
||||
@@ -109,6 +109,9 @@
|
||||
"chat.role.assistant": "Assistent",
|
||||
"chat.inputPlaceholder": "Nachricht eingeben...",
|
||||
"chat.stop": "Stopp",
|
||||
"chat.toolArguments": "Argumente",
|
||||
"chat.toolResult": "Ergebnis",
|
||||
"chat.dismissSurface": "Ansicht schließen",
|
||||
"chat.cancelledSuffix": "(abgebrochen)",
|
||||
"gitDiff.changedFiles": "Geänderte Dateien",
|
||||
"sidebar.tags": "Schlagwörter",
|
||||
|
||||
@@ -109,6 +109,9 @@
|
||||
"chat.role.assistant": "Assistant",
|
||||
"chat.inputPlaceholder": "Type a message...",
|
||||
"chat.stop": "Stop",
|
||||
"chat.toolArguments": "Arguments",
|
||||
"chat.toolResult": "Result",
|
||||
"chat.dismissSurface": "Dismiss surface",
|
||||
"chat.cancelledSuffix": "(cancelled)",
|
||||
"gitDiff.changedFiles": "Changed files",
|
||||
"sidebar.tags": "Tags",
|
||||
|
||||
@@ -109,6 +109,9 @@
|
||||
"chat.role.assistant": "Asistente",
|
||||
"chat.inputPlaceholder": "Escribe un mensaje...",
|
||||
"chat.stop": "Detener",
|
||||
"chat.toolArguments": "Argumentos",
|
||||
"chat.toolResult": "Resultado",
|
||||
"chat.dismissSurface": "Cerrar superficie",
|
||||
"chat.cancelledSuffix": "(cancelado)",
|
||||
"gitDiff.changedFiles": "Archivos modificados",
|
||||
"sidebar.tags": "Etiquetas",
|
||||
|
||||
@@ -109,6 +109,9 @@
|
||||
"chat.role.assistant": "Assistant IA",
|
||||
"chat.inputPlaceholder": "Saisissez un message...",
|
||||
"chat.stop": "Arrêter",
|
||||
"chat.toolArguments": "Arguments",
|
||||
"chat.toolResult": "Résultat",
|
||||
"chat.dismissSurface": "Fermer la surface",
|
||||
"chat.cancelledSuffix": "(annulé)",
|
||||
"gitDiff.changedFiles": "Fichiers modifiés",
|
||||
"sidebar.tags": "Étiquettes",
|
||||
|
||||
@@ -109,6 +109,9 @@
|
||||
"chat.role.assistant": "Assistente",
|
||||
"chat.inputPlaceholder": "Scrivi un messaggio...",
|
||||
"chat.stop": "Ferma",
|
||||
"chat.toolArguments": "Argomenti",
|
||||
"chat.toolResult": "Risultato",
|
||||
"chat.dismissSurface": "Chiudi superficie",
|
||||
"chat.cancelledSuffix": "(annullato)",
|
||||
"gitDiff.changedFiles": "File modificati",
|
||||
"sidebar.tags": "Tag",
|
||||
|
||||
@@ -5558,13 +5558,45 @@ button svg * {
|
||||
}
|
||||
|
||||
.chat-tool-marker {
|
||||
font-size: 12px;
|
||||
color: var(--vscode-descriptionForeground, inherit);
|
||||
}
|
||||
|
||||
.chat-tool-marker summary {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.chat-tool-marker summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.chat-tool-marker-details {
|
||||
margin: 6px 0 2px 20px;
|
||||
padding: 8px;
|
||||
border: 1px solid var(--vscode-editorGroup-border, var(--line, #3c3c3c));
|
||||
border-radius: 6px;
|
||||
background-color: var(--vscode-editor-background, rgba(0, 0, 0, 0.18));
|
||||
}
|
||||
|
||||
.chat-tool-marker-detail-label {
|
||||
margin: 0 0 4px;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
color: var(--vscode-descriptionForeground, inherit);
|
||||
}
|
||||
|
||||
.chat-tool-marker-details pre {
|
||||
margin: 0 0 8px;
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: anywhere;
|
||||
font: 11px/1.45 "SFMono-Regular", Menlo, Monaco, Consolas, monospace;
|
||||
}
|
||||
|
||||
.chat-tool-marker.completed .chat-tool-marker-icon {
|
||||
color: var(--vscode-testing-iconPassed, #89d185);
|
||||
}
|
||||
@@ -5581,13 +5613,60 @@ button svg * {
|
||||
.chat-tool-surface {
|
||||
width: min(720px, calc(100% - 44px));
|
||||
margin-left: 44px;
|
||||
padding: 14px;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid var(--vscode-editorGroup-border, var(--line, #3c3c3c));
|
||||
border-radius: 12px;
|
||||
background-color: var(--vscode-sideBar-background, var(--panel-2, #252526));
|
||||
}
|
||||
|
||||
.chat-inline-surface {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.chat-inline-surface-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 12px;
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
background-color: var(--vscode-textBlockQuote-background, rgba(127, 127, 127, 0.1));
|
||||
}
|
||||
|
||||
.chat-inline-surface-header::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.chat-inline-surface-title {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.chat-inline-surface-dismiss {
|
||||
border: 0;
|
||||
border-radius: 4px;
|
||||
padding: 2px 7px;
|
||||
background: transparent;
|
||||
color: var(--vscode-descriptionForeground, inherit);
|
||||
cursor: pointer;
|
||||
font-size: 15px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.chat-inline-surface-dismiss:hover {
|
||||
background-color: var(--vscode-toolbar-hoverBackground, rgba(255, 255, 255, 0.08));
|
||||
color: var(--vscode-foreground, inherit);
|
||||
}
|
||||
|
||||
.chat-inline-surface-body {
|
||||
padding: 14px;
|
||||
}
|
||||
|
||||
.chat-inline-surface h3,
|
||||
.chat-tool-surface h3 {
|
||||
margin: 0 0 12px;
|
||||
|
||||
@@ -2149,7 +2149,7 @@ defmodule BDS.Desktop.ShellLiveTest do
|
||||
assert css =~ "position: static;"
|
||||
end
|
||||
|
||||
test "chat editor renders legacy model controls, tool markers, and structured tool surfaces" do
|
||||
test "chat editor renders legacy model controls, collapsed tool pills, and dismissible A2UI surfaces" do
|
||||
assert {:ok, conversation} = AI.start_chat(%{title: "Editor Chat", model: "gpt-4.1"})
|
||||
|
||||
now = Persistence.now_ms()
|
||||
@@ -2209,11 +2209,21 @@ defmodule BDS.Desktop.ShellLiveTest do
|
||||
assert html =~ ~s(data-testid="chat-model-selector-button")
|
||||
assert html =~ "gpt-4.1"
|
||||
assert html =~ ~s(data-testid="chat-tool-marker")
|
||||
assert html =~ ~s(data-testid="chat-tool-marker-details")
|
||||
assert html =~ "render_table"
|
||||
assert html =~ ~s(data-testid="chat-tool-surface")
|
||||
refute html =~ ~s(data-testid="chat-tool-surface")
|
||||
assert html =~ ~s(data-testid="chat-inline-surface")
|
||||
assert html =~ ~s(data-testid="chat-inline-surface-dismiss")
|
||||
assert html =~ "Blog Stats"
|
||||
assert html =~ "Metric"
|
||||
assert html =~ "Posts"
|
||||
|
||||
dismissed_html =
|
||||
render_click(view, "dismiss_chat_surface", %{
|
||||
"surface-id" => Regex.run(~r/id="([^"]+-surface-0)"/, html) |> Enum.at(1)
|
||||
})
|
||||
|
||||
refute dismissed_html =~ ~s(data-testid="chat-inline-surface")
|
||||
end
|
||||
|
||||
test "chat editor folds tool-only assistant steps into the final assistant answer" do
|
||||
@@ -2647,6 +2657,25 @@ defmodule BDS.Desktop.ShellLiveTest do
|
||||
assert assistant_index < user_index
|
||||
assert html =~ ~r/<textarea[^>]*class="chat-input chat-surface-input"[^>]*disabled/
|
||||
|
||||
send(view.pid, {
|
||||
:chat_tool_call,
|
||||
conversation.id,
|
||||
%{
|
||||
id: "call-streaming-chart",
|
||||
name: "render_chart",
|
||||
arguments: %{
|
||||
"title" => "Streaming Chart",
|
||||
"chartType" => "bar",
|
||||
"series" => [%{"label" => "Posts", "value" => 3}]
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
html = render(view)
|
||||
assert html =~ ~s(data-testid="chat-streaming-message")
|
||||
assert html =~ ~s(data-testid="chat-inline-surface")
|
||||
assert html =~ "Streaming Chart"
|
||||
|
||||
html =
|
||||
view
|
||||
|> element("[data-testid='chat-abort-button']")
|
||||
|
||||
Reference in New Issue
Block a user