refactor(history): move message rendering into history module
Move code related to converting history messages into UI representation from utils into history/render.lua for better code organization and clean up the implementation.
This commit is contained in:
171
lua/avante/history/render.lua
Normal file
171
lua/avante/history/render.lua
Normal file
@@ -0,0 +1,171 @@
|
||||
local Helpers = require("avante.history.helpers")
|
||||
local Line = require("avante.ui.line")
|
||||
local Utils = require("avante.utils")
|
||||
|
||||
local M = {}
|
||||
|
||||
---Converts text into format suitable for UI
|
||||
---@param text string
|
||||
---@return avante.ui.Line[]
|
||||
local function text_to_lines(text)
|
||||
local text_lines = vim.split(text, "\n")
|
||||
local lines = {}
|
||||
for _, text_line in ipairs(text_lines) do
|
||||
table.insert(lines, Line:new({ { text_line } }))
|
||||
end
|
||||
return lines
|
||||
end
|
||||
|
||||
---Converts "thinking" item into format suitable for UI
|
||||
---@param item AvanteLLMMessageContentItem
|
||||
---@return avante.ui.Line[]
|
||||
local function thinking_to_lines(item)
|
||||
local text = item.thinking or item.data or ""
|
||||
local text_lines = vim.split(text, "\n")
|
||||
local ui_lines = {}
|
||||
table.insert(ui_lines, Line:new({ { Utils.icon("🤔 ") .. "Thought content:" } }))
|
||||
table.insert(ui_lines, Line:new({ { "" } }))
|
||||
for _, text_line in ipairs(text_lines) do
|
||||
table.insert(ui_lines, Line:new({ { "> " .. text_line } }))
|
||||
end
|
||||
return ui_lines
|
||||
end
|
||||
|
||||
---Converts logs generated by a tool during execution into format suitable for UI
|
||||
---@param tool_name string
|
||||
---@param logs string[]
|
||||
---@return avante.ui.Line[]
|
||||
local function tool_logs_to_lines(tool_name, logs)
|
||||
local ui_lines = {}
|
||||
local num_logs = #logs
|
||||
|
||||
for log_idx = 1, num_logs do
|
||||
local log_lines = vim.split(logs[log_idx]:gsub("^%[" .. tool_name .. "%]: ", "", 1), "\n")
|
||||
local num_lines = #log_lines
|
||||
|
||||
for line_idx = 1, num_lines do
|
||||
local decoration = (log_idx == num_logs and line_idx == num_lines) and "╰─ " or "│ "
|
||||
table.insert(ui_lines, Line:new({ { decoration }, { " " .. log_lines[line_idx] } }))
|
||||
end
|
||||
end
|
||||
return ui_lines
|
||||
end
|
||||
|
||||
local STATE_TO_HL = {
|
||||
generating = "AvanteStateSpinnerToolCalling",
|
||||
failed = "AvanteStateSpinnerFailed",
|
||||
succeeded = "AvanteStateSpinnerSucceeded",
|
||||
}
|
||||
|
||||
---Converts a tool invocation into format suitable for UI
|
||||
---@param item AvanteLLMMessageContentItem
|
||||
---@param messages avante.HistoryMessage[]
|
||||
---@param logs string[]|nil
|
||||
---@return avante.ui.Line[]
|
||||
local function tool_to_lines(item, messages, logs)
|
||||
local lines = {}
|
||||
|
||||
local result = Helpers.get_tool_result(item.id, messages)
|
||||
local state
|
||||
if not result then
|
||||
state = "generating"
|
||||
elseif result.is_error then
|
||||
state = "failed"
|
||||
else
|
||||
state = "succeeded"
|
||||
end
|
||||
table.insert(
|
||||
lines,
|
||||
Line:new({
|
||||
{ "╭─ " },
|
||||
{ " " .. item.name .. " ", STATE_TO_HL[state] },
|
||||
{ " " .. state },
|
||||
})
|
||||
)
|
||||
if logs then vim.list_extend(lines, tool_logs_to_lines(item.name, logs)) end
|
||||
return lines
|
||||
end
|
||||
|
||||
---Converts a message item into representation suitable for UI
|
||||
---@param item AvanteLLMMessageContentItem
|
||||
---@param message avante.HistoryMessage
|
||||
---@param messages avante.HistoryMessage[]
|
||||
---@return avante.ui.Line[]
|
||||
local function message_content_item_to_lines(item, message, messages)
|
||||
if type(item) == "string" then
|
||||
return text_to_lines(item)
|
||||
elseif type(item) == "table" then
|
||||
if item.type == "thinking" or item.type == "redacted_thinking" then
|
||||
return thinking_to_lines(item.thinking or item.data or "")
|
||||
elseif item.type == "text" then
|
||||
return text_to_lines(item.text)
|
||||
elseif item.type == "image" then
|
||||
return { Line:new({ { "" } }) }
|
||||
elseif item.type == "tool_use" then
|
||||
local ok, llm_tool = pcall(require, "avante.llm_tools." .. item.name)
|
||||
if ok then
|
||||
local tool_result_message = Helpers.get_tool_result_message(message, messages)
|
||||
---@cast llm_tool AvanteLLMTool
|
||||
if llm_tool.on_render then
|
||||
return llm_tool.on_render(item.input, {
|
||||
logs = message.tool_use_logs,
|
||||
state = message.state,
|
||||
store = message.tool_use_store,
|
||||
result_message = tool_result_message,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
return tool_to_lines(item, messages, message.tool_use_logs)
|
||||
end
|
||||
end
|
||||
return {}
|
||||
end
|
||||
|
||||
---Converts a message into representation suitable for UI
|
||||
---@param message avante.HistoryMessage
|
||||
---@param messages avante.HistoryMessage[]
|
||||
---@return avante.ui.Line[]
|
||||
function M.message_to_lines(message, messages)
|
||||
if message.displayed_content then return text_to_lines(message.displayed_content) end
|
||||
local content = message.message.content
|
||||
if type(content) == "string" then return text_to_lines(content) end
|
||||
if vim.islist(content) then
|
||||
local lines = {}
|
||||
for _, item in ipairs(content) do
|
||||
local item_lines = message_content_item_to_lines(item, message, messages)
|
||||
lines = vim.list_extend(lines, item_lines)
|
||||
end
|
||||
return lines
|
||||
end
|
||||
return {}
|
||||
end
|
||||
|
||||
---Converts a message item into text representation
|
||||
---@param item AvanteLLMMessageContentItem
|
||||
---@param message avante.HistoryMessage
|
||||
---@param messages avante.HistoryMessage[]
|
||||
---@return string
|
||||
local function message_content_item_to_text(item, message, messages)
|
||||
local lines = message_content_item_to_lines(item, message, messages)
|
||||
return vim.iter(lines):map(function(line) return tostring(line) end):join("\n")
|
||||
end
|
||||
|
||||
---Converts a message into text representation
|
||||
---@param message avante.HistoryMessage
|
||||
---@param messages avante.HistoryMessage[]
|
||||
---@return string
|
||||
function M.message_to_text(message, messages)
|
||||
local content = message.message.content
|
||||
if type(content) == "string" then return content end
|
||||
if vim.islist(content) then
|
||||
return vim
|
||||
.iter(content)
|
||||
:map(function(item) return message_content_item_to_text(item, message, messages) end)
|
||||
:filter(function(text) return text ~= "" end)
|
||||
:join("\n")
|
||||
end
|
||||
return ""
|
||||
end
|
||||
|
||||
return M
|
||||
Reference in New Issue
Block a user