fix: memory (#1718)

This commit is contained in:
yetone
2025-03-26 00:45:54 +08:00
committed by GitHub
parent d82eb8534e
commit 39787969c7
6 changed files with 58 additions and 11 deletions

View File

@@ -345,6 +345,7 @@ M._defaults = {
},
history = {
max_tokens = 4096,
carried_entry_count = nil,
storage_path = vim.fn.stdpath("state") .. "/avante",
paste = {
extension = "png",

View File

@@ -60,10 +60,11 @@ end
---@param bufnr integer
---@param history avante.ChatHistory
---@param entries? avante.ChatHistoryEntry[]
---@param cb fun(memory: avante.ChatMemory | nil): nil
function M.summarize_memory(bufnr, history, cb)
function M.summarize_memory(bufnr, history, entries, cb)
local system_prompt = [[You are a helpful AI assistant tasked with summarizing conversations.]]
local entries = Utils.history.filter_active_entries(history.entries)
if not entries then entries = Utils.history.filter_active_entries(history.entries) end
if #entries == 0 then
cb(nil)
return
@@ -202,9 +203,7 @@ function M.generate_prompts(opts)
if memory ~= "" then table.insert(messages, { role = "user", content = memory }) end
end
if instructions then
table.insert(messages, { role = "user", content = string.format("<question>%s</question>", instructions) })
end
if instructions then table.insert(messages, { role = "user", content = instructions }) end
local remaining_tokens = max_tokens - Utils.tokens.calculate_tokens(system_prompt)
@@ -212,20 +211,29 @@ function M.generate_prompts(opts)
remaining_tokens = remaining_tokens - Utils.tokens.calculate_tokens(message.content)
end
local dropped_history_messages = {}
if opts.history_messages then
if Config.history.max_tokens > 0 then remaining_tokens = math.min(Config.history.max_tokens, remaining_tokens) end
-- Traverse the history in reverse, keeping only the latest history until the remaining tokens are exhausted and the first message role is "user"
local history_messages = {}
for i = #opts.history_messages, 1, -1 do
local message = opts.history_messages[i]
local tokens = Utils.tokens.calculate_tokens(message.content)
remaining_tokens = remaining_tokens - tokens
if remaining_tokens > 0 then
if Config.history.carried_entry_count ~= nil then
if #history_messages > Config.history.carried_entry_count then break end
table.insert(history_messages, message)
else
break
local tokens = Utils.tokens.calculate_tokens(message.content)
remaining_tokens = remaining_tokens - tokens
if remaining_tokens > 0 then
table.insert(history_messages, message)
else
break
end
end
end
dropped_history_messages = vim.list_slice(opts.history_messages, 1, #opts.history_messages - #history_messages)
-- prepend the history messages to the messages table
vim.iter(history_messages):each(function(msg) table.insert(messages, 1, msg) end)
if #messages > 0 and messages[1].role == "assistant" then table.remove(messages, 1) end
@@ -254,6 +262,7 @@ Merge all changes from the <update> snippet into the <code> below.
image_paths = image_paths,
tools = opts.tools,
tool_histories = opts.tool_histories,
dropped_history_messages = dropped_history_messages,
}
end
@@ -493,6 +502,15 @@ function M._stream(opts)
local prompt_opts = M.generate_prompts(opts)
if
prompt_opts.dropped_history_messages
and #prompt_opts.dropped_history_messages > 0
and opts.on_memory_summarize
then
opts.on_memory_summarize(prompt_opts.dropped_history_messages)
return
end
local resp_headers = {}
---@type AvanteHandlerOptions

View File

@@ -2578,7 +2578,7 @@ function Sidebar:create_input_container(opts)
prompts_opts.history_messages = vim.list_slice(prompts_opts.history_messages, 5)
Llm.summarize_memory(self.code.bufnr, self.chat_history, function(memory)
Llm.summarize_memory(self.code.bufnr, self.chat_history, nil, function(memory)
if memory then prompts_opts.memory = memory.content end
cb(prompts_opts)
end)
@@ -2815,6 +2815,28 @@ function Sidebar:create_input_container(opts)
session_ctx = {},
})
local function on_memory_summarize(dropped_history_messages)
local entries = Utils.history.filter_active_entries(self.chat_history.entries)
if self.chat_history.memory then
entries = vim
.iter(entries)
:filter(function(entry) return entry.timestamp > self.chat_history.memory.last_summarized_timestamp end)
:totable()
end
entries = vim.list_slice(entries, 1, #dropped_history_messages)
Llm.summarize_memory(self.code.bufnr, self.chat_history, entries, function(memory)
if memory then stream_options.memory = memory.content end
stream_options.history_messages =
vim.list_slice(stream_options.history_messages, #dropped_history_messages + 1)
Llm.stream(stream_options)
end)
end
stream_options.on_memory_summarize = on_memory_summarize
Llm.stream(stream_options)
end)
end

View File

@@ -95,7 +95,7 @@ L5: pass
},
{
role = "user",
content = '<question>{"insertSpaces":true,"tabSize":4,"indentSize":4,"position":{"row":1,"col":7}}</question>',
content = '{"insertSpaces":true,"tabSize":4,"indentSize":4,"position":{"row":1,"col":7}}',
},
{
role = "assistant",

View File

@@ -4,6 +4,8 @@ Respect and use existing conventions, libraries, etc that are already present in
Make sure code comments are in English when generating them.
Memory is crucial, you must follow the instructions in <memory>!
{% include "_tools-guidelines.avanterules" %}
{% if system_info -%}

View File

@@ -96,6 +96,7 @@ vim.g.avante_login = vim.g.avante_login
---@field image_paths? string[]
---@field tools? AvanteLLMTool[]
---@field tool_histories? AvanteLLMToolHistory[]
---@field dropped_history_messages? AvanteLLMMessage[]
---
---@class AvanteGeminiMessage
---@field role "user"
@@ -331,11 +332,14 @@ vim.g.avante_login = vim.g.avante_login
---@field tool_result? AvanteLLMToolResult
---@field tool_use? AvanteLLMToolUse
---
---@alias AvanteLLMMemorySummarizeCallback fun(dropped_history_messages: AvanteLLMMessage[]): nil
---
---@class AvanteLLMStreamOptions: AvanteGeneratePromptsOptions
---@field session_ctx? table
---@field on_start AvanteLLMStartCallback
---@field on_chunk AvanteLLMChunkCallback
---@field on_stop AvanteLLMStopCallback
---@field on_memory_summarize? AvanteLLMMemorySummarizeCallback
---@field on_tool_log? function(tool_name: string, log: string): nil
---
---@alias AvanteLLMToolFunc<T> fun(