fix: better sidebar (#1603)

* fix: better sidebar

* feat: better msg history

* fix: tests
This commit is contained in:
yetone
2025-03-17 01:40:05 +08:00
committed by GitHub
parent f60f150a21
commit 6e77da83c1
17 changed files with 870 additions and 319 deletions

View File

@@ -43,6 +43,7 @@ local Sidebar = {}
---@field selected_files_container NuiSplit | nil
---@field input_container NuiSplit | nil
---@field file_selector FileSelector
---@field chat_history avante.ChatHistory | nil
---@param id integer the tabpage id retrieved from api.nvim_get_current_tabpage()
function Sidebar:new(id)
@@ -61,6 +62,7 @@ function Sidebar:new(id)
input_container = nil,
file_selector = FileSelector:new(id),
is_generating = false,
chat_history = nil,
}, { __index = self })
end
@@ -397,6 +399,7 @@ local function transform_result_content(selected_files, result_content, prev_fil
elseif line_content == "<think>" then
is_thinking = true
last_think_tag_start_line = i
last_think_tag_end_line = 0
elseif line_content == "</think>" then
is_thinking = false
last_think_tag_end_line = i
@@ -1810,6 +1813,7 @@ function Sidebar:on_mount(opts)
group = self.augroup,
callback = function(args)
local closed_winid = tonumber(args.match)
if closed_winid == self.winids.selected_files_container then return end
if not self:is_focused_on(closed_winid) then return end
self:close()
end,
@@ -1838,6 +1842,7 @@ function Sidebar:refresh_winids()
local function switch_windows()
local current_winid = api.nvim_get_current_win()
winids = vim.iter(winids):filter(function(winid) return api.nvim_win_is_valid(winid) end):totable()
local current_idx = Utils.tbl_indexof(winids, current_winid) or 1
if current_idx == #winids then
current_idx = 1
@@ -1906,6 +1911,8 @@ function Sidebar:initialize()
self.file_selector:reset()
self.file_selector:add_selected_file(filepath)
self:reload_chat_history()
return self
end
@@ -2095,6 +2102,7 @@ end
function Sidebar:render_history_content(history)
local content = ""
for idx, entry in ipairs(history.entries) do
if entry.visible == false then goto continue end
if entry.reset_memory then
content = content .. "***MEMORY RESET***\n\n"
if idx < #history.entries then content = content .. "-------\n\n" end
@@ -2180,7 +2188,7 @@ end
function Sidebar:new_chat(args, cb)
Path.history.new(self.code.bufnr)
Sidebar.reload_chat_history()
self:reload_chat_history()
self:update_content(
"New chat",
{ ignore_history = true, focus = false, scroll = false, callback = function() self:focus_input() end }
@@ -2188,6 +2196,26 @@ function Sidebar:new_chat(args, cb)
if cb then cb(args) end
end
---@param message AvanteLLMMessage
---@param options {visible?: boolean}
function Sidebar:add_chat_history(message, options)
local timestamp = get_timestamp()
self:reload_chat_history()
table.insert(self.chat_history.entries, {
timestamp = timestamp,
provider = Config.provider,
model = Config.get_provider_config(Config.provider).model,
request = message.role == "user" and message.content or "",
response = message.role == "assistant" and message.content or "",
original_response = "",
selected_filepaths = nil,
selected_code = nil,
reset_memory = false,
visible = options.visible,
})
Path.history.save(self.code.bufnr, self.chat_history)
end
function Sidebar:reset_memory(args, cb)
local chat_history = Path.history.load(self.code.bufnr)
if next(chat_history) ~= nil then
@@ -2203,7 +2231,7 @@ function Sidebar:reset_memory(args, cb)
reset_memory = true,
})
Path.history.save(self.code.bufnr, chat_history)
Sidebar.reload_chat_history()
self:reload_chat_history()
local history_content = self:render_history_content(chat_history)
self:update_content(history_content, {
focus = false,
@@ -2212,7 +2240,7 @@ function Sidebar:reset_memory(args, cb)
})
if cb then cb(args) end
else
Sidebar.reload_chat_history()
self:reload_chat_history()
self:update_content(
"Chat history is already empty",
{ focus = false, scroll = false, callback = function() self:focus_input() end }
@@ -2321,46 +2349,18 @@ local generating_text = "**Generating response ...**\n"
local hint_window = nil
function Sidebar:reload_chat_history()
if not self.code.bufnr or not api.nvim_buf_is_valid(self.code.bufnr) then return end
self.chat_history = Path.history.load(self.code.bufnr)
end
---@param opts AskOptions
function Sidebar:create_input_container(opts)
if self.input_container then self.input_container:unmount() end
if not self.code.bufnr or not api.nvim_buf_is_valid(self.code.bufnr) then return end
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",
description = "Add a file to the context",
---@type AvanteLLMToolFunc<{ rel_path: string }>
func = function(input)
self.file_selector:add_selected_file(input.rel_path)
return "Added file to context", nil
end,
param = {
type = "table",
fields = { { name = "rel_path", description = "Relative path to the file", type = "string" } },
},
returns = {},
})
table.insert(tools, {
name = "remove_file_from_context",
description = "Remove a file from the context",
---@type AvanteLLMToolFunc<{ rel_path: string }>
func = function(input)
self.file_selector:remove_selected_file(input.rel_path)
return "Removed file from context", nil
end,
param = {
type = "table",
fields = { { name = "rel_path", description = "Relative path to the file", type = "string" } },
},
returns = {},
})
if self.chat_history == nil then self:reload_chat_history() end
---@param request string
---@param summarize_memory boolean
@@ -2399,17 +2399,48 @@ function Sidebar:create_input_container(opts)
end
end
local entries = Utils.history.filter_active_entries(chat_history.entries)
local entries = Utils.history.filter_active_entries(self.chat_history.entries)
if chat_history.memory then
if self.chat_history.memory then
entries = vim
.iter(entries)
:filter(function(entry) return entry.timestamp > chat_history.memory.last_summarized_timestamp end)
:filter(function(entry) return entry.timestamp > self.chat_history.memory.last_summarized_timestamp end)
:totable()
end
local history_messages = Utils.history.entries_to_llm_messages(entries)
local tools = vim.deepcopy(LLMTools.get_tools(request, history_messages))
table.insert(tools, {
name = "add_file_to_context",
description = "Add a file to the context",
---@type AvanteLLMToolFunc<{ rel_path: string }>
func = function(input)
self.file_selector:add_selected_file(input.rel_path)
return "Added file to context", nil
end,
param = {
type = "table",
fields = { { name = "rel_path", description = "Relative path to the file", type = "string" } },
},
returns = {},
})
table.insert(tools, {
name = "remove_file_from_context",
description = "Remove a file from the context",
---@type AvanteLLMToolFunc<{ rel_path: string }>
func = function(input)
self.file_selector:remove_selected_file(input.rel_path)
return "Removed file from context", nil
end,
param = {
type = "table",
fields = { { name = "rel_path", description = "Relative path to the file", type = "string" } },
},
returns = {},
})
---@type AvanteGeneratePromptsOptions
local prompts_opts = {
ask = opts.ask or true,
@@ -2425,7 +2456,7 @@ function Sidebar:create_input_container(opts)
tools = tools,
}
if chat_history.memory then prompts_opts.memory = chat_history.memory.content end
if self.chat_history.memory then prompts_opts.memory = self.chat_history.memory.content end
if not summarize_memory or #history_messages < 8 then
cb(prompts_opts)
@@ -2434,7 +2465,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, chat_history, function(memory)
Llm.summarize_memory(self.code.bufnr, self.chat_history, function(memory)
if memory then prompts_opts.memory = memory.content end
cb(prompts_opts)
end)
@@ -2628,8 +2659,8 @@ function Sidebar:create_input_container(opts)
end, 0)
-- Save chat history
chat_history.entries = chat_history.entries or {}
table.insert(chat_history.entries, {
self.chat_history.entries = self.chat_history.entries or {}
table.insert(self.chat_history.entries, {
timestamp = timestamp,
provider = Config.provider,
model = model,
@@ -2638,8 +2669,9 @@ function Sidebar:create_input_container(opts)
original_response = original_response,
selected_filepaths = selected_filepaths,
selected_code = selected_code,
tool_histories = stop_opts.tool_histories,
})
Path.history.save(self.code.bufnr, chat_history)
Path.history.save(self.code.bufnr, self.chat_history)
end
get_generate_prompts_options(request, true, function(generate_prompts_options)