diff --git a/lua/CopilotChat/client.lua b/lua/CopilotChat/client.lua index e2801844..e8383b8c 100644 --- a/lua/CopilotChat/client.lua +++ b/lua/CopilotChat/client.lua @@ -445,12 +445,22 @@ function Client:ask(opts) if out.tool_calls then for _, tool_call in ipairs(out.tool_calls) do - local key = tool_call.id or tool_call.index - local val = tool_calls:get(key) - if not val then + local key = tool_call.id or tool_call.index or tool_call.name or (#tool_calls:values() + 1) + local existing = tool_calls:get(key) + + if not existing then tool_calls:set(key, tool_call) else - val.arguments = val.arguments .. tool_call.arguments + existing.arguments = existing.arguments .. tool_call.arguments + if tool_call.id then + existing.id = tool_call.id + end + if tool_call.index then + existing.index = tool_call.index + end + if tool_call.name then + existing.name = tool_call.name + end end end end @@ -597,12 +607,17 @@ function Client:ask(opts) response_reasoning = response_reasoning_buffer:tostring() end + -- Filter out tool calls that don't have names (streaming deltas used only for accumulation) + local final_tool_calls = vim.tbl_filter(function(tc) + return tc.name ~= nil + end, tool_calls:values()) + return { message = { role = constants.ROLE.ASSISTANT, content = response_text, reasoning = response_reasoning, - tool_calls = #tool_calls:values() > 0 and tool_calls:values() or nil, + tool_calls = #final_tool_calls > 0 and final_tool_calls or nil, model = out_model, }, token_count = token_count, diff --git a/lua/CopilotChat/config/providers.lua b/lua/CopilotChat/config/providers.lua index c817f6f8..548f6abd 100644 --- a/lua/CopilotChat/config/providers.lua +++ b/lua/CopilotChat/config/providers.lua @@ -397,14 +397,12 @@ local function prepare_responses_output(output) content = output.delta.text end elseif output.type == 'response.output_item.done' then - -- Complete output item (including tool calls) local item = output.item if item and item.type == 'function_call' then - local index = output.output_index or (#tool_calls + 1) table.insert(tool_calls, { - id = item.call_id or ('tooluse_' .. index), - index = index, - name = item.name or '', + id = item.call_id, + index = output.output_index, + name = item.name, arguments = item.arguments or '', }) end @@ -436,9 +434,9 @@ local function prepare_responses_output(output) if msg.tool_calls then for i, tool_call in ipairs(msg.tool_calls) do table.insert(tool_calls, { - id = tool_call.call_id or ('tooluse_' .. i), + id = tool_call.call_id, index = i, - name = tool_call.name or '', + name = tool_call.name, arguments = tool_call.arguments or '', }) end @@ -481,11 +479,9 @@ local function prepare_chat_output(output) for i, tool_call in ipairs(message.tool_calls) do local fn = tool_call['function'] if fn then - local index = tool_call.index or i - local id = utils.empty(tool_call.id) and ('tooluse_' .. index) or tool_call.id table.insert(tool_calls, { - id = id, - index = index, + id = tool_call.id, + index = tool_call.index or i, name = fn.name, arguments = fn.arguments or '', }) diff --git a/lua/CopilotChat/init.lua b/lua/CopilotChat/init.lua index 9cea5d2d..1b7d0570 100644 --- a/lua/CopilotChat/init.lua +++ b/lua/CopilotChat/init.lua @@ -546,6 +546,7 @@ function M.ask(prompt, config) M.chat:add_message(response, true) M.chat.token_count = token_count M.chat.token_max_count = token_max_count + finish() end end))