fix: tool use id sometimes will be the same (#1982)

This commit is contained in:
yetone
2025-05-04 02:43:33 +08:00
committed by GitHub
parent fcf6e8617e
commit 0f7fb35e6d
4 changed files with 128 additions and 41 deletions

View File

@@ -182,7 +182,8 @@ function M.generate_prompts(opts)
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)
item.content =
string.format("The file %s has been updated. Please use the latest `view` tool result!", path)
else
local lines, error = Utils.read_file_from_buf_or_disk(path)
if error ~= nil then Utils.error("error reading file: " .. error) end
@@ -288,18 +289,20 @@ function M.generate_prompts(opts)
dropped_history_messages = vim.list_extend(dropped_history_messages, opts.prompt_opts.dropped_history_messages)
end
local cleaned_history_messages = opts.history_messages
local final_history_messages = {}
if opts.history_messages then
if cleaned_history_messages then
if opts.disable_compact_history_messages then
final_history_messages = vim.list_extend(final_history_messages, opts.history_messages)
final_history_messages = vim.list_extend(final_history_messages, cleaned_history_messages)
else
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]
for i = #cleaned_history_messages, 1, -1 do
local message = cleaned_history_messages[i]
local tokens = Utils.tokens.calculate_tokens(message.message.content)
remaining_tokens = remaining_tokens - tokens
if remaining_tokens > 0 then
@@ -310,10 +313,12 @@ function M.generate_prompts(opts)
end
if #history_messages == 0 then
history_messages = vim.list_slice(opts.history_messages, #opts.history_messages - 1, #opts.history_messages)
history_messages =
vim.list_slice(cleaned_history_messages, #cleaned_history_messages - 1, #cleaned_history_messages)
end
dropped_history_messages = vim.list_slice(opts.history_messages, 1, #opts.history_messages - #history_messages)
dropped_history_messages =
vim.list_slice(cleaned_history_messages, 1, #cleaned_history_messages - #history_messages)
-- prepend the history messages to the messages table
vim.iter(history_messages):each(function(msg) table.insert(final_history_messages, msg) end)

View File

@@ -38,6 +38,7 @@ One or more SEARCH/REPLACE blocks following this exact format:
\`\`\`
Critical rules:
1. SEARCH content must match the associated file section to find EXACTLY:
* Do not refer to the `diff` argument of the previous `replace_in_file` function call for SEARCH content matching, as it may have been modified. Always match from the latest file content in <selected_files> or from the `view` function call result.
* Match character-for-character including whitespace, indentation, line endings
* Include all comments, docstrings, etc.
2. SEARCH/REPLACE blocks will ONLY replace the first match occurrence.

View File

@@ -2311,22 +2311,23 @@ function Sidebar:create_input_container()
---@param state AvanteLLMToolUseState
local function on_tool_log(tool_id, tool_name, log, state)
if state == "generating" then on_state_change("tool calling") end
local tool_message = vim.iter(self.chat_history.messages):find(function(message)
if message.message.role ~= "assistant" then return false end
local tool_use_message = nil
for idx = #self.chat_history.messages, 1, -1 do
local message = self.chat_history.messages[idx]
local content = message.message.content
if type(content) ~= "table" then return false end
if content[1].type ~= "tool_use" then return false end
if content[1].id ~= tool_id then return false end
return true
end)
if not tool_message then
Utils.debug("tool_message not found", tool_id, tool_name)
if type(content) == "table" and content[1].type == "tool_use" and content[1].id == tool_id then
tool_use_message = message
break
end
end
if not tool_use_message then
Utils.debug("tool_use message not found", tool_id, tool_name)
return
end
local tool_use_logs = tool_message.tool_use_logs or {}
local tool_use_logs = tool_use_message.tool_use_logs or {}
local content = string.format("[%s]: %s", tool_name, log)
table.insert(tool_use_logs, content)
tool_message.tool_use_logs = tool_use_logs
tool_use_message.tool_use_logs = tool_use_logs
save_history()
self:update_content("")
end

View File

@@ -1413,6 +1413,66 @@ function M.uuid()
end)
end
---@param message avante.HistoryMessage
---@return boolean
function M.is_tool_use_message(message)
local content = message.message.content
if type(content) == "string" then return false end
if vim.islist(content) then
for _, item in ipairs(content) do
if item.type == "tool_use" then return true end
end
end
return false
end
---@param message avante.HistoryMessage
---@return boolean
function M.is_tool_result_message(message)
local content = message.message.content
if type(content) == "string" then return false end
if vim.islist(content) then
for _, item in ipairs(content) do
if item.type == "tool_result" then return true end
end
end
return false
end
---@param message avante.HistoryMessage
---@param messages avante.HistoryMessage[]
---@return avante.HistoryMessage | nil
function M.get_tool_use_message(message, messages)
local content = message.message.content
if type(content) == "string" then return nil end
if vim.islist(content) then
local tool_id = nil
for _, item in ipairs(content) do
if item.type == "tool_result" then
tool_id = item.tool_use_id
break
end
end
if not tool_id then return nil end
local idx = nil
for idx_, message_ in ipairs(messages) do
if message_.uuid == message.uuid then
idx = idx_
break
end
end
if not idx then return nil end
for idx_ = idx - 1, 1, -1 do
local message_ = messages[idx_]
local content_ = message_.message.content
if type(content_) == "table" and content_[1].type == "tool_use" and content_[1].id == tool_id then
return message_
end
end
end
return nil
end
---@param message avante.HistoryMessage
---@param messages avante.HistoryMessage[]
---@return avante.HistoryMessage | nil
@@ -1428,7 +1488,15 @@ function M.get_tool_result_message(message, messages)
end
end
if not tool_id then return nil end
for _, message_ in ipairs(messages) do
local idx = nil
for idx_, message_ in ipairs(messages) do
if message_.uuid == message.uuid then
idx = idx_
break
end
end
if not idx then return nil end
for _, message_ in ipairs(vim.list_slice(messages, idx + 1, #messages)) do
local content_ = message_.message.content
if type(content_) == "table" and content_[1].type == "tool_result" and content_[1].tool_use_id == tool_id then
return message_
@@ -1469,36 +1537,48 @@ function M.message_content_item_to_lines(item, message, messages)
local lines = {}
local state = "generating"
local hl = "AvanteStateSpinnerToolCalling"
if message.state == "generated" then
local tool_result_message = M.get_tool_result_message(message, messages)
if tool_result_message then
local tool_result = tool_result_message.message.content[1]
if tool_result.is_error then
state = "failed"
hl = "AvanteStateSpinnerFailed"
else
state = "succeeded"
hl = "AvanteStateSpinnerSucceeded"
end
local tool_result_message = M.get_tool_result_message(message, messages)
if tool_result_message then
local tool_result = tool_result_message.message.content[1]
if tool_result.is_error then
state = "failed"
hl = "AvanteStateSpinnerFailed"
else
state = "succeeded"
hl = "AvanteStateSpinnerSucceeded"
end
end
table.insert(
lines,
Line:new({ { "╭─" }, { " " }, { string.format(" %s ", item.name), hl }, { string.format(" %s", state) } })
)
for idx, log in ipairs(message.tool_use_logs or {}) do
local log_ = M.trim(log, { prefix = string.format("[%s]: ", item.name) })
local lines_ = vim.split(log_, "\n")
if idx ~= #(message.tool_use_logs or {}) then
for _, line_ in ipairs(lines_) do
table.insert(lines, Line:new({ { "" }, { string.format(" %s", line_) } }))
end
else
for idx_, line_ in ipairs(lines_) do
if idx_ ~= #lines_ then
if message.tool_use_logs then
for idx, log in ipairs(message.tool_use_logs) do
local log_ = M.trim(log, { prefix = string.format("[%s]: ", item.name) })
local lines_ = vim.split(log_, "\n")
if idx ~= #(message.tool_use_logs or {}) then
for _, line_ in ipairs(lines_) do
table.insert(lines, Line:new({ { "" }, { string.format(" %s", line_) } }))
end
else
for idx_, line_ in ipairs(lines_) do
if idx_ ~= #lines_ then
table.insert(lines, Line:new({ { "" }, { string.format(" %s", line_) } }))
else
table.insert(lines, Line:new({ { "╰─" }, { string.format(" %s", line_) } }))
end
end
end
end
elseif tool_result_message then
local tool_result = tool_result_message.message.content[1]
if tool_result.content then
local result_lines = vim.split(tool_result.content, "\n")
for idx, line in ipairs(result_lines) do
if idx ~= #result_lines then
table.insert(lines, Line:new({ { "" }, { string.format(" %s", line) } }))
else
table.insert(lines, Line:new({ { "╰─" }, { string.format(" %s", line_) } }))
table.insert(lines, Line:new({ { "╰─" }, { string.format(" %s", line) } }))
end
end
end