172 lines
5.5 KiB
Lua
172 lines
5.5 KiB
Lua
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" and item.name then
|
|
local ok, llm_tool = pcall(require, "avante.llm_tools." .. item.name)
|
|
if ok then
|
|
local tool_result_message = Helpers.get_tool_result_message(item.id, 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
|