refactor: history messages (#1934)
This commit is contained in:
@@ -1,87 +0,0 @@
|
||||
local Utils = require("avante.utils")
|
||||
local Config = require("avante.config")
|
||||
|
||||
---@class avante.utils.history
|
||||
local M = {}
|
||||
|
||||
---@param entries avante.ChatHistoryEntry[]
|
||||
---@return avante.ChatHistoryEntry[]
|
||||
function M.filter_active_entries(entries)
|
||||
local entries_ = {}
|
||||
|
||||
for i = #entries, 1, -1 do
|
||||
local entry = entries[i]
|
||||
if entry.reset_memory then break end
|
||||
table.insert(entries_, 1, entry)
|
||||
end
|
||||
|
||||
return entries_
|
||||
end
|
||||
|
||||
---@param entries avante.ChatHistoryEntry[]
|
||||
---@return AvanteLLMMessage[]
|
||||
function M.entries_to_llm_messages(entries)
|
||||
local current_provider_name = Config.provider
|
||||
local messages = {}
|
||||
for _, entry in ipairs(entries) do
|
||||
if entry.selected_filepaths ~= nil and #entry.selected_filepaths > 0 then
|
||||
local user_content = "SELECTED FILES:\n\n"
|
||||
for _, filepath in ipairs(entry.selected_filepaths) do
|
||||
user_content = user_content .. filepath .. "\n"
|
||||
end
|
||||
table.insert(messages, { role = "user", content = user_content })
|
||||
end
|
||||
if entry.selected_code ~= nil then
|
||||
local user_content_ = "SELECTED CODE:\n\n```"
|
||||
.. (entry.selected_code.file_type or "")
|
||||
.. (entry.selected_code.path and ":" .. entry.selected_code.path or "")
|
||||
.. "\n"
|
||||
.. entry.selected_code.content
|
||||
.. "\n```\n\n"
|
||||
table.insert(messages, { role = "user", content = user_content_ })
|
||||
end
|
||||
if entry.request ~= nil and entry.request ~= "" then
|
||||
table.insert(messages, { role = "user", content = entry.request })
|
||||
end
|
||||
if entry.tool_histories ~= nil and #entry.tool_histories > 0 and entry.provider == current_provider_name then
|
||||
for _, tool_history in ipairs(entry.tool_histories) do
|
||||
local assistant_content = {}
|
||||
if tool_history.tool_use ~= nil then
|
||||
if tool_history.tool_use.response_contents ~= nil then
|
||||
for _, response_content in ipairs(tool_history.tool_use.response_contents) do
|
||||
table.insert(assistant_content, { type = "text", text = response_content })
|
||||
end
|
||||
end
|
||||
table.insert(assistant_content, {
|
||||
type = "tool_use",
|
||||
name = tool_history.tool_use.name,
|
||||
id = tool_history.tool_use.id,
|
||||
input = vim.json.decode(tool_history.tool_use.input_json),
|
||||
})
|
||||
end
|
||||
table.insert(messages, {
|
||||
role = "assistant",
|
||||
content = assistant_content,
|
||||
})
|
||||
local user_content = {}
|
||||
if tool_history.tool_result ~= nil and tool_history.tool_result.content ~= nil then
|
||||
table.insert(user_content, {
|
||||
type = "tool_result",
|
||||
tool_use_id = tool_history.tool_result.tool_use_id,
|
||||
content = tool_history.tool_result.content,
|
||||
is_error = tool_history.tool_result.is_error,
|
||||
})
|
||||
end
|
||||
table.insert(messages, {
|
||||
role = "user",
|
||||
content = user_content,
|
||||
})
|
||||
end
|
||||
end
|
||||
local assistant_content = Utils.trim_think_content(entry.original_response or "")
|
||||
if assistant_content ~= "" then table.insert(messages, { role = "assistant", content = assistant_content }) end
|
||||
end
|
||||
return messages
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -6,7 +6,6 @@ local lsp = vim.lsp
|
||||
---@field tokens avante.utils.tokens
|
||||
---@field root avante.utils.root
|
||||
---@field file avante.utils.file
|
||||
---@field history avante.utils.history
|
||||
---@field environment avante.utils.environment
|
||||
---@field lsp avante.utils.lsp
|
||||
local M = {}
|
||||
@@ -415,7 +414,7 @@ function M.debug(...)
|
||||
local caller_source = info.source:match("@(.+)$") or "unknown"
|
||||
local caller_module = caller_source:gsub("^.*/lua/", ""):gsub("%.lua$", ""):gsub("/", ".")
|
||||
|
||||
local timestamp = os.date("%Y-%m-%d %H:%M:%S")
|
||||
local timestamp = M.get_timestamp()
|
||||
local formated_args = {
|
||||
"[" .. timestamp .. "] [AVANTE] [DEBUG] [" .. caller_module .. ":" .. info.currentline .. "]",
|
||||
}
|
||||
@@ -1263,7 +1262,6 @@ function M.get_commands()
|
||||
local builtin_items = {
|
||||
{ description = "Show help message", name = "help" },
|
||||
{ description = "Clear chat history", name = "clear" },
|
||||
{ description = "Reset memory", name = "reset" },
|
||||
{ description = "New chat", name = "new" },
|
||||
{
|
||||
shorthelp = "Ask a question about specific lines",
|
||||
@@ -1281,7 +1279,6 @@ function M.get_commands()
|
||||
if cb then cb(args) end
|
||||
end,
|
||||
clear = function(sidebar, args, cb) sidebar:clear_history(args, cb) end,
|
||||
reset = function(sidebar, args, cb) sidebar:reset_memory(args, cb) end,
|
||||
new = function(sidebar, args, cb) sidebar:new_chat(args, cb) end,
|
||||
lines = function(_, args, cb)
|
||||
if cb then cb(args) end
|
||||
@@ -1310,4 +1307,97 @@ function M.get_commands()
|
||||
return vim.list_extend(builtin_commands, Config.slash_commands)
|
||||
end
|
||||
|
||||
---@param history avante.ChatHistory
|
||||
---@return avante.HistoryMessage[]
|
||||
function M.get_history_messages(history)
|
||||
local HistoryMessage = require("avante.history_message")
|
||||
if history.messages then return history.messages end
|
||||
local messages = {}
|
||||
for _, entry in ipairs(history.entries or {}) do
|
||||
if entry.request and entry.request ~= "" then
|
||||
local message = HistoryMessage:new({
|
||||
role = "user",
|
||||
content = entry.request,
|
||||
}, {
|
||||
timestamp = entry.timestamp,
|
||||
is_user_submission = true,
|
||||
visible = entry.visible,
|
||||
selected_filepaths = entry.selected_filepaths,
|
||||
selected_code = entry.selected_code,
|
||||
})
|
||||
table.insert(messages, message)
|
||||
end
|
||||
if entry.response and entry.response ~= "" then
|
||||
local message = HistoryMessage:new({
|
||||
role = "assistant",
|
||||
content = entry.response,
|
||||
}, {
|
||||
timestamp = entry.timestamp,
|
||||
visible = entry.visible,
|
||||
})
|
||||
table.insert(messages, message)
|
||||
end
|
||||
end
|
||||
history.messages = messages
|
||||
return messages
|
||||
end
|
||||
|
||||
function M.get_timestamp() return tostring(os.date("%Y-%m-%d %H:%M:%S")) end
|
||||
|
||||
---@param history_messages avante.HistoryMessage[]
|
||||
---@return AvanteLLMMessage[]
|
||||
function M.history_messages_to_messages(history_messages)
|
||||
local messages = {}
|
||||
for _, history_message in ipairs(history_messages) do
|
||||
if history_message.just_for_display then goto continue end
|
||||
table.insert(messages, history_message.message)
|
||||
::continue::
|
||||
end
|
||||
return messages
|
||||
end
|
||||
|
||||
function M.uuid()
|
||||
local template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
|
||||
return string.gsub(template, "[xy]", function(c)
|
||||
local v = (c == "x") and math.random(0, 0xf) or math.random(8, 0xb)
|
||||
return string.format("%x", v)
|
||||
end)
|
||||
end
|
||||
|
||||
---@param item AvanteLLMMessageContentItem
|
||||
---@param message avante.HistoryMessage
|
||||
---@return string
|
||||
function M.message_content_item_to_text(item, message)
|
||||
if type(item) == "string" then return item end
|
||||
if type(item) == "table" then
|
||||
if item.type == "text" then return item.text end
|
||||
if item.type == "image" then return "" end
|
||||
if item.type == "tool_use" then
|
||||
local pieces = {}
|
||||
table.insert(pieces, string.format("[%s]: calling", item.name))
|
||||
for _, log in ipairs(message.tool_use_logs or {}) do
|
||||
table.insert(pieces, log)
|
||||
end
|
||||
return table.concat(pieces, "\n")
|
||||
end
|
||||
end
|
||||
return ""
|
||||
end
|
||||
|
||||
---@param message avante.HistoryMessage
|
||||
---@return string
|
||||
function M.message_to_text(message)
|
||||
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)
|
||||
if text ~= "" then table.insert(pieces, text) end
|
||||
end
|
||||
return table.concat(pieces, "\n")
|
||||
end
|
||||
return ""
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
@@ -77,10 +77,24 @@ function StreamingJSONParser:parse(chunk)
|
||||
-- Handle strings specially (they can contain JSON control characters)
|
||||
if self.state.inString then
|
||||
if self.state.escaping then
|
||||
self.state.stringBuffer = self.state.stringBuffer .. char
|
||||
local escapeMap = {
|
||||
['"'] = '"',
|
||||
["\\"] = "\\",
|
||||
["/"] = "/",
|
||||
["b"] = "\b",
|
||||
["f"] = "\f",
|
||||
["n"] = "\n",
|
||||
["r"] = "\r",
|
||||
["t"] = "\t",
|
||||
}
|
||||
local escapedChar = escapeMap[char]
|
||||
if escapedChar then
|
||||
self.state.stringBuffer = self.state.stringBuffer .. escapedChar
|
||||
else
|
||||
self.state.stringBuffer = self.state.stringBuffer .. char
|
||||
end
|
||||
self.state.escaping = false
|
||||
elseif char == "\\" then
|
||||
self.state.stringBuffer = self.state.stringBuffer .. char
|
||||
self.state.escaping = true
|
||||
elseif char == '"' then
|
||||
-- End of string
|
||||
|
||||
Reference in New Issue
Block a user