feat: delete tool use messages tool (#2158)

This commit is contained in:
yetone
2025-06-05 02:51:46 +08:00
committed by GitHub
parent af8d373f22
commit 801adc4692
8 changed files with 313 additions and 222 deletions

View File

@@ -1955,6 +1955,15 @@ local _save_history = Utils.debounce(function(self) Path.history.save(self.code.
local save_history = vim.schedule_wrap(_save_history)
---@param uuids string[]
function Sidebar:delete_history_messages(uuids)
local history_messages = Utils.get_history_messages(self.chat_history)
for _, msg in ipairs(history_messages) do
if vim.list_contains(uuids, msg.uuid) then msg.is_deleted = true end
end
Path.history.save(self.code.bufnr, self.chat_history)
end
---@param messages avante.HistoryMessage | avante.HistoryMessage[]
function Sidebar:add_history_messages(messages)
local history_messages = Utils.get_history_messages(self.chat_history)
@@ -1978,7 +1987,6 @@ function Sidebar:add_history_messages(messages)
end
end
self.chat_history.messages = history_messages
-- 历史消息变更时,标记缓存失效
self._history_cache_invalidated = true
save_history(self)
if
@@ -1987,15 +1995,6 @@ function Sidebar:add_history_messages(messages)
and messages[1].just_for_display ~= true
and messages[1].state == "generated"
then
-- self.chat_history.title = "generating..."
-- Llm.summarize_chat_thread_title(messages[1].message.content, function(title)
-- if title then
-- self.chat_history.title = title
-- else
-- self.chat_history.title = "untitled"
-- end
-- save_history(self)
-- end)
local first_msg_text = Utils.message_to_text(messages[1], messages)
local lines_ = vim.split(first_msg_text, "\n")
if #lines_ > 0 then
@@ -2190,24 +2189,219 @@ end
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)
-- 重新加载历史时,标记缓存失效
self._history_cache_invalidated = true
end
---@param opts? {all?: boolean}
---@return avante.HistoryMessage[]
function Sidebar:get_history_messages_for_api()
local history_messages = Utils.get_history_messages(self.chat_history)
self.chat_history.messages = history_messages
function Sidebar:get_history_messages_for_api(opts)
opts = opts or {}
local history_messages0 = Utils.get_history_messages(self.chat_history)
self.chat_history.messages = history_messages0
if self.chat_history.memory then
history_messages = {}
for i = #self.chat_history.messages, 1, -1 do
local message = self.chat_history.messages[i]
if message.uuid == self.chat_history.memory.last_message_uuid then break end
table.insert(history_messages, 1, message)
history_messages0 = vim
.iter(history_messages0)
:filter(function(message) return not message.just_for_display and not message.is_compacted end)
:totable()
if opts.all then return history_messages0 end
local tool_id_to_tool_name = {}
local tool_id_to_path = {}
local tool_id_to_start_line = {}
local tool_id_to_end_line = {}
local viewed_files = {}
local last_modified_files = {}
local history_messages = {}
local failed_edit_tool_ids = {}
for idx, message in ipairs(history_messages0) do
if Utils.is_tool_result_message(message) then
local tool_use_message = Utils.get_tool_use_message(message, history_messages0)
local is_edit_func_call, _, _, path = Utils.is_edit_func_call_message(tool_use_message)
if is_edit_func_call and message.message.content[1].is_error then
failed_edit_tool_ids[message.message.content[1].tool_use_id] = true
end
if is_edit_func_call and path and not message.message.content[1].is_error then
local uniformed_path = Utils.uniform_path(path)
last_modified_files[uniformed_path] = idx
end
end
end
return vim.iter(history_messages):filter(function(message) return not message.just_for_display end):totable()
for idx, message in ipairs(history_messages0) do
if Utils.is_tool_use_message(message) and failed_edit_tool_ids[message.message.content[1].id] then
goto continue
end
table.insert(history_messages, message)
if Utils.is_tool_result_message(message) then
local tool_use_message = Utils.get_tool_use_message(message, history_messages0)
local is_edit_func_call, is_str_replace_editor_func_call, is_str_replace_based_edit_tool_func_call, path =
Utils.is_edit_func_call_message(tool_use_message)
--- For models like gpt-4o, the input parameter of replace_in_file is treated as the latest file content, so here we need to insert a fake view tool call to ensure it uses the latest file content
if is_edit_func_call and path and not message.message.content[1].is_error then
local uniformed_path = Utils.uniform_path(path)
local view_result, view_error = require("avante.llm_tools.view").func({ path = path }, nil, nil, nil)
if view_error then view_result = "Error: " .. view_error end
local get_diagnostics_tool_use_id = Utils.uuid()
local view_tool_use_id = Utils.uuid()
local view_tool_name = "view"
local view_tool_input = { path = path }
if is_str_replace_editor_func_call then
view_tool_name = "str_replace_editor"
view_tool_input = { command = "view", path = path }
end
if is_str_replace_based_edit_tool_func_call then
view_tool_name = "str_replace_based_edit_tool"
view_tool_input = { command = "view", path = path }
end
history_messages = vim.list_extend(history_messages, {
HistoryMessage:new({
role = "assistant",
content = string.format("Viewing file %s to get the latest content", path),
}, {
is_dummy = true,
}),
HistoryMessage:new({
role = "assistant",
content = {
{
type = "tool_use",
id = view_tool_use_id,
name = view_tool_name,
input = view_tool_input,
},
},
}, {
is_dummy = true,
}),
HistoryMessage:new({
role = "user",
content = {
{
type = "tool_result",
tool_use_id = view_tool_use_id,
content = view_result,
is_error = view_error ~= nil,
},
},
}, {
is_dummy = true,
}),
})
if last_modified_files[uniformed_path] == idx then
local diagnostics = Utils.lsp.get_diagnostics_from_filepath(path)
history_messages = vim.list_extend(history_messages, {
HistoryMessage:new({
role = "assistant",
content = string.format(
"The file %s has been modified, let me check if there are any errors in the changes.",
path
),
}, {
is_dummy = true,
}),
HistoryMessage:new({
role = "assistant",
content = {
{
type = "tool_use",
id = get_diagnostics_tool_use_id,
name = "get_diagnostics",
input = { path = path },
},
},
}, {
is_dummy = true,
}),
HistoryMessage:new({
role = "user",
content = {
{
type = "tool_result",
tool_use_id = get_diagnostics_tool_use_id,
content = vim.json.encode(diagnostics),
is_error = false,
},
},
}, {
is_dummy = true,
}),
})
end
end
end
::continue::
end
for _, message in ipairs(history_messages) do
local content = message.message.content
if type(content) ~= "table" then goto continue end
for _, item in ipairs(content) do
if type(item) ~= "table" then goto continue1 end
if item.type ~= "tool_use" then goto continue1 end
local tool_name = item.name
if tool_name ~= "view" then goto continue1 end
local path = item.input.path
tool_id_to_tool_name[item.id] = tool_name
if path then
local uniform_path = Utils.uniform_path(path)
tool_id_to_path[item.id] = uniform_path
tool_id_to_start_line[item.id] = item.input.start_line
tool_id_to_end_line[item.id] = item.input.end_line
viewed_files[uniform_path] = item.id
end
::continue1::
end
::continue::
end
for _, message in ipairs(history_messages) do
local content = message.message.content
if type(content) == "table" then
for _, item in ipairs(content) do
if type(item) ~= "table" then goto continue end
if item.type ~= "tool_result" then goto continue end
local tool_name = tool_id_to_tool_name[item.tool_use_id]
if tool_name ~= "view" then goto continue end
if item.is_error then goto continue end
local path = tool_id_to_path[item.tool_use_id]
local latest_tool_id = viewed_files[path]
if not latest_tool_id then goto continue end
if latest_tool_id ~= item.tool_use_id then
item.content = string.format("The file %s has been updated. Please use the latest `view` tool result!", path)
else
local start_line = tool_id_to_start_line[item.tool_use_id]
local end_line = tool_id_to_end_line[item.tool_use_id]
local view_result, view_error = require("avante.llm_tools.view").func(
{ path = path, start_line = start_line, end_line = end_line },
nil,
nil,
nil
)
if view_error then view_result = "Error: " .. view_error end
item.content = view_result
item.is_error = view_error ~= nil
end
::continue::
end
end
end
local final_history_messages = {}
for _, msg in ipairs(history_messages) do
local tool_result_message
if Utils.is_tool_use_message(msg) then
tool_result_message = Utils.get_tool_result_message(msg, history_messages)
if not tool_result_message then goto continue end
end
if Utils.is_tool_result_message(msg) then goto continue end
table.insert(final_history_messages, msg)
if tool_result_message then table.insert(final_history_messages, tool_result_message) end
::continue::
end
return final_history_messages
end
---@param request string
@@ -2292,8 +2486,6 @@ function Sidebar:get_generate_prompts_options(request, cb)
history_messages = history_messages,
code_lang = filetype,
selected_code = selected_code,
disable_compact_history_messages = true,
-- instructions = request,
tools = tools,
}
@@ -2409,8 +2601,6 @@ function Sidebar:create_input_container()
self:render_state()
end
local save_history = Utils.debounce(function() Path.history.save(self.code.bufnr, self.chat_history) end, 3000)
---@param tool_id string
---@param tool_name string
---@param log string
@@ -2434,7 +2624,7 @@ function Sidebar:create_input_container()
local content = string.format("[%s]: %s", tool_name, log)
table.insert(tool_use_logs, content)
tool_use_message.tool_use_logs = tool_use_logs
save_history()
save_history(self)
self:update_content("")
end
@@ -2502,7 +2692,7 @@ function Sidebar:create_input_container()
on_tool_log = on_tool_log,
on_messages_add = on_messages_add,
on_state_change = on_state_change,
get_history_messages = function() return self:get_history_messages_for_api() end,
get_history_messages = function(opts) return self:get_history_messages_for_api(opts) end,
session_ctx = {},
})