From 772220118b0f0a211d5782d493aa479be4c1b741 Mon Sep 17 00:00:00 2001 From: joaopluigi Date: Tue, 13 Jan 2026 09:59:25 -0300 Subject: [PATCH 1/2] handle implicit manual approval flow --- lua/eca/approve.lua | 12 +++++++----- lua/eca/sidebar.lua | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/lua/eca/approve.lua b/lua/eca/approve.lua index 5c5f5d8..fc94f7a 100644 --- a/lua/eca/approve.lua +++ b/lua/eca/approve.lua @@ -2,14 +2,16 @@ local M = {} ---@param tool_call eca.ToolCallRun function M.get_preview_lines(tool_call) - if not tool_call.details then - local arguments = vim.split(vim.inspect(tool_call.arguments), "\n") + -- If no details or details without diff, show tool call info + if not tool_call.details or not tool_call.details.diff then + local arguments_text = tool_call.arguments or "" + local arguments = vim.split(vim.inspect(arguments_text), "\n") local messages = {} if tool_call.summary then table.insert(messages, "Summary: " .. tool_call.summary) end - table.insert(messages, "Tool Name: " .. tool_call.name) - table.insert(messages, "Tool Type: " .. tool_call.origin) + table.insert(messages, "Tool Name: " .. (tool_call.name or "unknown")) + table.insert(messages, "Tool Type: " .. (tool_call.origin or "unknown")) table.insert(messages, "Tool Arguments: ") for _, v in pairs(arguments) do table.insert(messages, v) @@ -17,7 +19,7 @@ function M.get_preview_lines(tool_call) return messages end local lines = vim.split(tool_call.details.diff, "\n") - return { tool_call.details.path, unpack(lines) } + return { tool_call.details.path or "", unpack(lines) } end ---@param lines string[] diff --git a/lua/eca/sidebar.lua b/lua/eca/sidebar.lua index b64804b..37d34d9 100644 --- a/lua/eca/sidebar.lua +++ b/lua/eca/sidebar.lua @@ -1205,6 +1205,9 @@ function M:handle_chat_content_received(params) if content.state == "finished" then self:_finalize_streaming_response() self:_update_input_display() + elseif content.text == "Waiting for tool call approval" then + -- Handle implicit approval flow when toolCallPrepare was already received + self:render_tool_call(content, chat_id) end elseif content.type == "toolCallPrepare" then self:_finalize_streaming_response() @@ -1375,6 +1378,7 @@ function M:handle_chat_content_received(params) end function M:render_tool_call(tool_content, chat_id) + -- Handle explicit manual approval (toolCallRun with manualApproval flag) if tool_content.type == "toolCallRun" and tool_content.manualApproval then return require("eca.approve").approve_tool_call(tool_content, function() self.mediator:send("chat/toolCallApprove", { chatId = chat_id, toolCallId = tool_content.id }, nil) @@ -1382,6 +1386,37 @@ function M:render_tool_call(tool_content, chat_id) self.mediator:send("chat/toolCallReject", { chatId = chat_id, toolCallId = tool_content.id }, nil) end) end + + -- Handle implicit approval flow: progress message "Waiting for tool call approval" + -- with a previously prepared tool call (toolCallPrepare stored in _current_tool_call) + if tool_content.type == "progress" + and tool_content.text == "Waiting for tool call approval" + and self._current_tool_call + and self._current_tool_call.id + and not self._current_tool_call.approval_shown then + -- Mark as shown to avoid duplicate approval dialogs + self._current_tool_call.approval_shown = true + + -- Store the tool call id in a local variable to avoid closure issues + local tool_call_id = self._current_tool_call.id + + -- Build tool content from the prepared tool call for the approval dialog + -- Using field names expected by approve.lua + local prepared_tool_call = { + id = tool_call_id, + name = self._current_tool_call.name or "Tool call", + summary = self._current_tool_call.summary, + arguments = self._current_tool_call.arguments or "", + origin = "eca", -- default origin for implicit approval + details = self._current_tool_call.details, + } + + return require("eca.approve").approve_tool_call(prepared_tool_call, function() + self.mediator:send("chat/toolCallApprove", { chatId = chat_id, toolCallId = tool_call_id }, nil) + end, function() + self.mediator:send("chat/toolCallReject", { chatId = chat_id, toolCallId = tool_call_id }, nil) + end) + end end ---@param text string @@ -1811,6 +1846,7 @@ function M:_handle_tool_call_prepare(content) arguments = "", details = {}, outputs = "", + approval_shown = false, } end From 73f8c9c0a405f538b6791034dc98277ae697ac54 Mon Sep 17 00:00:00 2001 From: joaopluigi Date: Tue, 13 Jan 2026 10:41:46 -0300 Subject: [PATCH 2/2] fix displaying two tool calls approval at once --- lua/eca/sidebar.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lua/eca/sidebar.lua b/lua/eca/sidebar.lua index 37d34d9..c50f112 100644 --- a/lua/eca/sidebar.lua +++ b/lua/eca/sidebar.lua @@ -1380,6 +1380,10 @@ end function M:render_tool_call(tool_content, chat_id) -- Handle explicit manual approval (toolCallRun with manualApproval flag) if tool_content.type == "toolCallRun" and tool_content.manualApproval then + -- Mark as shown to prevent duplicate approval dialogs from implicit flow + if self._current_tool_call then + self._current_tool_call.approval_shown = true + end return require("eca.approve").approve_tool_call(tool_content, function() self.mediator:send("chat/toolCallApprove", { chatId = chat_id, toolCallId = tool_content.id }, nil) end, function()