refactor: summarize memory (#1508)
This commit is contained in:
@@ -2073,11 +2073,11 @@ function Sidebar:get_layout()
|
||||
return vim.tbl_contains({ "left", "right" }, calculate_config_window_position()) and "vertical" or "horizontal"
|
||||
end
|
||||
|
||||
---@param history avante.ChatHistoryEntry[]
|
||||
---@param history avante.ChatHistory
|
||||
---@return string
|
||||
function Sidebar:render_history_content(history)
|
||||
local content = ""
|
||||
for idx, entry in ipairs(history) do
|
||||
for idx, entry in ipairs(history.entries) do
|
||||
if entry.reset_memory then
|
||||
content = content .. "***MEMORY RESET***\n\n"
|
||||
if idx < #history then content = content .. "-------\n\n" end
|
||||
@@ -2146,11 +2146,11 @@ end
|
||||
function Sidebar:clear_history(args, cb)
|
||||
local chat_history = Path.history.load(self.code.bufnr)
|
||||
if next(chat_history) ~= nil then
|
||||
chat_history = {}
|
||||
chat_history.entries = {}
|
||||
Path.history.save(self.code.bufnr, chat_history)
|
||||
self:update_content(
|
||||
"Chat history cleared",
|
||||
{ focus = false, scroll = false, callback = function() self:focus_input() end }
|
||||
{ ignore_history = true, focus = false, scroll = false, callback = function() self:focus_input() end }
|
||||
)
|
||||
if cb then cb(args) end
|
||||
else
|
||||
@@ -2161,6 +2161,16 @@ function Sidebar:clear_history(args, cb)
|
||||
end
|
||||
end
|
||||
|
||||
function Sidebar:new_chat(args, cb)
|
||||
Path.history.new(self.code.bufnr)
|
||||
Sidebar.reload_chat_history()
|
||||
self:update_content(
|
||||
"New chat",
|
||||
{ ignore_history = true, focus = false, scroll = false, callback = function() self:focus_input() end }
|
||||
)
|
||||
if cb then cb(args) end
|
||||
end
|
||||
|
||||
function Sidebar:reset_memory(args, cb)
|
||||
local chat_history = Path.history.load(self.code.bufnr)
|
||||
if next(chat_history) ~= nil then
|
||||
@@ -2176,6 +2186,7 @@ function Sidebar:reset_memory(args, cb)
|
||||
reset_memory = true,
|
||||
})
|
||||
Path.history.save(self.code.bufnr, chat_history)
|
||||
Sidebar.reload_chat_history()
|
||||
local history_content = self:render_history_content(chat_history)
|
||||
self:update_content(history_content, {
|
||||
focus = false,
|
||||
@@ -2184,6 +2195,7 @@ function Sidebar:reset_memory(args, cb)
|
||||
})
|
||||
if cb then cb(args) end
|
||||
else
|
||||
Sidebar.reload_chat_history()
|
||||
self:update_content(
|
||||
"Chat history is already empty",
|
||||
{ focus = false, scroll = false, callback = function() self:focus_input() end }
|
||||
@@ -2191,7 +2203,7 @@ function Sidebar:reset_memory(args, cb)
|
||||
end
|
||||
end
|
||||
|
||||
---@alias AvanteSlashCommandType "clear" | "help" | "lines" | "reset" | "commit"
|
||||
---@alias AvanteSlashCommandType "clear" | "help" | "lines" | "reset" | "commit" | "new"
|
||||
---@alias AvanteSlashCommandCallback fun(args: string, cb?: fun(args: string): nil): nil
|
||||
---@alias AvanteSlashCommand {description: string, command: AvanteSlashCommandType, details: string, shorthelp?: string, callback?: AvanteSlashCommandCallback}
|
||||
---@return AvanteSlashCommand[]
|
||||
@@ -2211,6 +2223,7 @@ function Sidebar:get_commands()
|
||||
{ description = "Show help message", command = "help" },
|
||||
{ description = "Clear chat history", command = "clear" },
|
||||
{ description = "Reset memory", command = "reset" },
|
||||
{ description = "New chat", command = "new" },
|
||||
{
|
||||
shorthelp = "Ask a question about specific lines",
|
||||
description = "/lines <start>-<end> <question>",
|
||||
@@ -2228,6 +2241,7 @@ function Sidebar:get_commands()
|
||||
end,
|
||||
clear = function(args, cb) self:clear_history(args, cb) end,
|
||||
reset = function(args, cb) self:reset_memory(args, cb) end,
|
||||
new = function(args, cb) self:new_chat(args, cb) end,
|
||||
lines = function(args, cb)
|
||||
if cb then cb(args) end
|
||||
end,
|
||||
@@ -2298,6 +2312,8 @@ function Sidebar:create_input_container(opts)
|
||||
|
||||
local chat_history = Path.history.load(self.code.bufnr)
|
||||
|
||||
Sidebar.reload_chat_history = function() chat_history = Path.history.load(self.code.bufnr) end
|
||||
|
||||
local tools = vim.deepcopy(LLMTools.get_tools())
|
||||
table.insert(tools, {
|
||||
name = "add_file_to_context",
|
||||
@@ -2330,8 +2346,9 @@ function Sidebar:create_input_container(opts)
|
||||
})
|
||||
|
||||
---@param request string
|
||||
---@return AvanteGeneratePromptsOptions
|
||||
local function get_generate_prompts_options(request)
|
||||
---@param summarize_memory boolean
|
||||
---@param cb fun(opts: AvanteGeneratePromptsOptions): nil
|
||||
local function get_generate_prompts_options(request, summarize_memory, cb)
|
||||
local filetype = api.nvim_get_option_value("filetype", { buf = self.code.bufnr })
|
||||
|
||||
local selected_code_content = nil
|
||||
@@ -2355,40 +2372,19 @@ function Sidebar:create_input_container(opts)
|
||||
end
|
||||
end
|
||||
|
||||
local history_messages = {}
|
||||
for i = #chat_history, 1, -1 do
|
||||
local entry = chat_history[i]
|
||||
if entry.reset_memory then break end
|
||||
if
|
||||
entry.request == nil
|
||||
or entry.original_response == nil
|
||||
or entry.request == ""
|
||||
or entry.original_response == ""
|
||||
then
|
||||
break
|
||||
end
|
||||
table.insert(
|
||||
history_messages,
|
||||
1,
|
||||
{ role = "assistant", content = Utils.trim_think_content(entry.original_response) }
|
||||
)
|
||||
local user_content = ""
|
||||
if entry.selected_file ~= nil then
|
||||
user_content = user_content .. "SELECTED FILE: " .. entry.selected_file.filepath .. "\n\n"
|
||||
end
|
||||
if entry.selected_code ~= nil then
|
||||
user_content = user_content
|
||||
.. "SELECTED CODE:\n\n```"
|
||||
.. entry.selected_code.filetype
|
||||
.. "\n"
|
||||
.. entry.selected_code.content
|
||||
.. "\n```\n\n"
|
||||
end
|
||||
user_content = user_content .. "USER PROMPT:\n\n" .. entry.request
|
||||
table.insert(history_messages, 1, { role = "user", content = user_content })
|
||||
local entries = Utils.history.filter_active_entries(chat_history.entries)
|
||||
|
||||
if chat_history.memory then
|
||||
entries = vim
|
||||
.iter(entries)
|
||||
:filter(function(entry) return entry.timestamp > chat_history.memory.last_summarized_timestamp end)
|
||||
:totable()
|
||||
end
|
||||
|
||||
return {
|
||||
local history_messages = Utils.history.entries_to_llm_messages(entries)
|
||||
|
||||
---@type AvanteGeneratePromptsOptions
|
||||
local prompts_opts = {
|
||||
ask = opts.ask or true,
|
||||
project_context = vim.json.encode(project_context),
|
||||
selected_files = selected_files_contents,
|
||||
@@ -2400,6 +2396,20 @@ function Sidebar:create_input_container(opts)
|
||||
mode = Config.behaviour.enable_cursor_planning_mode and "cursor-planning" or "planning",
|
||||
tools = tools,
|
||||
}
|
||||
|
||||
if chat_history.memory then prompts_opts.memory = chat_history.memory.content end
|
||||
|
||||
if not summarize_memory or #history_messages < 8 then
|
||||
cb(prompts_opts)
|
||||
return
|
||||
end
|
||||
|
||||
prompts_opts.history_messages = vim.list_slice(prompts_opts.history_messages, 5)
|
||||
|
||||
Llm.summarize_memory(self.code.bufnr, chat_history, function(memory)
|
||||
if memory then prompts_opts.memory = memory.content end
|
||||
cb(prompts_opts)
|
||||
end)
|
||||
end
|
||||
|
||||
---@param request string
|
||||
@@ -2584,7 +2594,8 @@ function Sidebar:create_input_container(opts)
|
||||
end, 0)
|
||||
|
||||
-- Save chat history
|
||||
table.insert(chat_history or {}, {
|
||||
chat_history.entries = chat_history.entries or {}
|
||||
table.insert(chat_history.entries, {
|
||||
timestamp = timestamp,
|
||||
provider = Config.provider,
|
||||
model = model,
|
||||
@@ -2597,17 +2608,18 @@ function Sidebar:create_input_container(opts)
|
||||
Path.history.save(self.code.bufnr, chat_history)
|
||||
end
|
||||
|
||||
local generate_prompts_options = get_generate_prompts_options(request)
|
||||
---@type AvanteLLMStreamOptions
|
||||
---@diagnostic disable-next-line: assign-type-mismatch
|
||||
local stream_options = vim.tbl_deep_extend("force", generate_prompts_options, {
|
||||
on_start = on_start,
|
||||
on_chunk = on_chunk,
|
||||
on_stop = on_stop,
|
||||
on_tool_log = on_tool_log,
|
||||
})
|
||||
get_generate_prompts_options(request, true, function(generate_prompts_options)
|
||||
---@type AvanteLLMStreamOptions
|
||||
---@diagnostic disable-next-line: assign-type-mismatch
|
||||
local stream_options = vim.tbl_deep_extend("force", generate_prompts_options, {
|
||||
on_start = on_start,
|
||||
on_chunk = on_chunk,
|
||||
on_stop = on_stop,
|
||||
on_tool_log = on_tool_log,
|
||||
})
|
||||
|
||||
Llm.stream(stream_options)
|
||||
Llm.stream(stream_options)
|
||||
end)
|
||||
end
|
||||
|
||||
local function get_position()
|
||||
@@ -2762,37 +2774,43 @@ function Sidebar:create_input_container(opts)
|
||||
local hint_text = (fn.mode() ~= "i" and Config.mappings.submit.normal or Config.mappings.submit.insert)
|
||||
.. ": submit"
|
||||
|
||||
if Config.behaviour.enable_token_counting then
|
||||
local input_value = table.concat(api.nvim_buf_get_lines(self.input_container.bufnr, 0, -1, false), "\n")
|
||||
local generate_prompts_options = get_generate_prompts_options(input_value)
|
||||
local tokens = Llm.calculate_tokens(generate_prompts_options)
|
||||
hint_text = "Tokens: " .. tostring(tokens) .. "; " .. hint_text
|
||||
local function show()
|
||||
local buf = api.nvim_create_buf(false, true)
|
||||
api.nvim_buf_set_lines(buf, 0, -1, false, { hint_text })
|
||||
api.nvim_buf_add_highlight(buf, 0, "AvantePopupHint", 0, 0, -1)
|
||||
|
||||
-- Get the current window size
|
||||
local win_width = api.nvim_win_get_width(self.input_container.winid)
|
||||
local width = #hint_text
|
||||
|
||||
-- Set the floating window options
|
||||
local win_opts = {
|
||||
relative = "win",
|
||||
win = self.input_container.winid,
|
||||
width = width,
|
||||
height = 1,
|
||||
row = get_float_window_row(),
|
||||
col = math.max(win_width - width, 0), -- Display in the bottom right corner
|
||||
style = "minimal",
|
||||
border = "none",
|
||||
focusable = false,
|
||||
zindex = 100,
|
||||
}
|
||||
|
||||
-- Create the floating window
|
||||
hint_window = api.nvim_open_win(buf, false, win_opts)
|
||||
end
|
||||
|
||||
local buf = api.nvim_create_buf(false, true)
|
||||
api.nvim_buf_set_lines(buf, 0, -1, false, { hint_text })
|
||||
api.nvim_buf_add_highlight(buf, 0, "AvantePopupHint", 0, 0, -1)
|
||||
|
||||
-- Get the current window size
|
||||
local win_width = api.nvim_win_get_width(self.input_container.winid)
|
||||
local width = #hint_text
|
||||
|
||||
-- Set the floating window options
|
||||
local win_opts = {
|
||||
relative = "win",
|
||||
win = self.input_container.winid,
|
||||
width = width,
|
||||
height = 1,
|
||||
row = get_float_window_row(),
|
||||
col = math.max(win_width - width, 0), -- Display in the bottom right corner
|
||||
style = "minimal",
|
||||
border = "none",
|
||||
focusable = false,
|
||||
zindex = 100,
|
||||
}
|
||||
|
||||
-- Create the floating window
|
||||
hint_window = api.nvim_open_win(buf, false, win_opts)
|
||||
if Config.behaviour.enable_token_counting then
|
||||
local input_value = table.concat(api.nvim_buf_get_lines(self.input_container.bufnr, 0, -1, false), "\n")
|
||||
get_generate_prompts_options(input_value, false, function(generate_prompts_options)
|
||||
local tokens = Llm.calculate_tokens(generate_prompts_options)
|
||||
hint_text = "Tokens: " .. tostring(tokens) .. "; " .. hint_text
|
||||
show()
|
||||
end)
|
||||
else
|
||||
show()
|
||||
end
|
||||
end
|
||||
|
||||
api.nvim_create_autocmd({ "TextChanged", "TextChangedI", "VimResized" }, {
|
||||
|
||||
Reference in New Issue
Block a user