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:
Dmitry Torokhov
2025-07-15 14:30:00 -07:00
committed by yetone
parent 06d9d8cec3
commit 966eef743b
4 changed files with 177 additions and 153 deletions

View File

@@ -1520,155 +1520,6 @@ function M.is_edit_func_call_tool_use(tool_use)
return is_replace_func_call, is_str_replace_editor_func_call, is_str_replace_based_edit_tool_func_call, path
end
---@param text string
---@param hl string | nil
---@return avante.ui.Line[]
function M.text_to_lines(text, hl)
local Line = require("avante.ui.line")
local text_lines = vim.split(text, "\n")
local lines = {}
for _, text_line in ipairs(text_lines) do
local piece = { text_line }
if hl then table.insert(piece, hl) end
table.insert(lines, Line:new({ piece }))
end
return lines
end
---@param thinking_text string
---@param hl string | nil
---@return avante.ui.Line[]
function M.thinking_to_lines(thinking_text, hl)
local Line = require("avante.ui.line")
local text_lines = vim.split(thinking_text, "\n")
local lines = {}
table.insert(lines, Line:new({ { M.icon("🤔 ") .. "Thought content:" } }))
table.insert(lines, Line:new({ { "" } }))
for _, text_line in ipairs(text_lines) do
local piece = { "> " .. text_line }
if hl then table.insert(piece, hl) end
table.insert(lines, Line:new({ piece }))
end
return lines
end
---@param item AvanteLLMMessageContentItem
---@param message avante.HistoryMessage
---@param messages avante.HistoryMessage[]
---@return avante.ui.Line[]
function M.message_content_item_to_lines(item, message, messages)
local Line = require("avante.ui.line")
local HistoryHelpers = require("avante.history.helpers")
if type(item) == "string" then return M.text_to_lines(item) end
if type(item) == "table" then
if item.type == "thinking" or item.type == "redacted_thinking" then
return M.thinking_to_lines(item.thinking or item.data or "")
end
if item.type == "text" then return M.text_to_lines(item.text) end
if item.type == "image" then
return { Line:new({ { "![image](" .. item.source.media_type .. ": " .. item.source.data .. ")" } }) }
end
if item.type == "tool_use" then
local tool_result_message = HistoryHelpers.get_tool_result_message(message, messages)
local lines = {}
local state = "generating"
local hl = "AvanteStateSpinnerToolCalling"
local ok, llm_tool = pcall(require, "avante.llm_tools." .. item.name)
if ok then
---@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
if tool_result_message then
local tool_result = tool_result_message.message.content[1]
if tool_result.is_error then
state = "failed"
hl = "AvanteStateSpinnerFailed"
else
state = "succeeded"
hl = "AvanteStateSpinnerSucceeded"
end
end
table.insert(
lines,
Line:new({ { "╭─" }, { " " }, { string.format(" %s ", item.name), hl }, { string.format(" %s", state) } })
)
if message.tool_use_logs then
for idx, log in ipairs(message.tool_use_logs) do
local log_ = M.trim(log, { prefix = string.format("[%s]: ", item.name) })
local lines_ = vim.split(log_, "\n")
if idx ~= #(message.tool_use_logs or {}) then
for _, line_ in ipairs(lines_) do
table.insert(lines, Line:new({ { "" }, { string.format(" %s", line_) } }))
end
else
for idx_, line_ in ipairs(lines_) do
if idx_ ~= #lines_ then
table.insert(lines, Line:new({ { "" }, { string.format(" %s", line_) } }))
else
table.insert(lines, Line:new({ { "╰─" }, { string.format(" %s", line_) } }))
end
end
end
end
end
return lines
end
end
return {}
end
---@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 M.text_to_lines(message.displayed_content) end
local content = message.message.content
if type(content) == "string" then return M.text_to_lines(content) end
if vim.islist(content) then
local lines = {}
for _, item in ipairs(content) do
local lines_ = M.message_content_item_to_lines(item, message, messages)
lines = vim.list_extend(lines, lines_)
end
return lines
end
return {}
end
---@param item AvanteLLMMessageContentItem
---@param message avante.HistoryMessage
---@param messages avante.HistoryMessage[]
---@return string
function M.message_content_item_to_text(item, message, messages)
local lines = M.message_content_item_to_lines(item, message, messages)
if #lines == 0 then return "" end
return table.concat(vim.tbl_map(function(line) return tostring(line) end, lines), "\n")
end
---@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
local pieces = {}
for _, item in ipairs(content) do
local text = M.message_content_item_to_text(item, message, messages)
if text ~= "" then table.insert(pieces, text) end
end
return table.concat(pieces, "\n")
end
return ""
end
---Counts number of strings in text, accounting for possibility of a trailing newline
---@param str string | nil
---@return integer