@@ -1223,27 +1223,41 @@ function M:_handle_server_content(params)
12231223 -- IMPORTANT: Return immediately - do NOT display anything for toolCallPrepare
12241224 return
12251225 elseif content .type == " toolCalled" then
1226+ local tool_text = nil
1227+
12261228 -- Add diff to current tool call if present in toolCalled content
12271229 if self ._current_tool_call and content .details then
12281230 self ._current_tool_call .details = content .details
12291231 end
12301232
12311233 -- Show the final accumulated tool call if we have one
12321234 if self ._is_tool_call_streaming and self ._current_tool_call then
1233- self :_display_tool_call ()
1235+ tool_text = self :_display_tool_call ()
12341236 end
12351237
12361238 -- Show the tool result
1237- local tool_text = string.format (" ✅ **Tool Result**: %s" , content .name or " unknown" )
1239+ local tool_log = string.format (" **Tool Result**: %s" , content .name or " unknown" )
12381240 if content .outputs and # content .outputs > 0 then
12391241 for _ , output in ipairs (content .outputs ) do
12401242 if output .type == " text" and output .content then
1241- tool_text = tool_text .. " \n " .. output .content
1243+ tool_log = tool_log .. " \n " .. output .content
12421244 end
12431245 end
12441246 end
1245- self :_add_message (" assistant" , tool_text )
1246-
1247+ Logger .debug (tool_log )
1248+
1249+ local tool_text_completed = " ✅ "
1250+
1251+ if content .error then
1252+ tool_text_completed = " ❌ "
1253+ end
1254+
1255+ tool_text_completed = tool_text_completed .. (content .summary or content .name or " Tool call completed" )
1256+
1257+ if tool_text == nil or not self :_replace_text (tool_text or " " , tool_text_completed ) then
1258+ self :_add_message (" assistant" , tool_text_completed )
1259+ end
1260+
12471261 -- Clean up tool call state
12481262 self :_finalize_tool_call ()
12491263 end
@@ -1519,15 +1533,21 @@ function M:_handle_tool_call_prepare(content)
15191533 self ._is_tool_call_streaming = true
15201534 self ._current_tool_call = {
15211535 name = " " ,
1522- arguments = " "
1536+ summary = " " ,
1537+ arguments = " " ,
1538+ details = {}
15231539 }
15241540 end
1525-
1541+
15261542 -- Accumulate tool call data
15271543 if content .name then
15281544 self ._current_tool_call .name = content .name
15291545 end
1530-
1546+
1547+ if content .summary then
1548+ self ._current_tool_call .summary = content .summary
1549+ end
1550+
15311551 if content .argumentsText then
15321552 self ._current_tool_call .arguments = (self ._current_tool_call .arguments or " " ) .. content .argumentsText
15331553 end
@@ -1537,26 +1557,90 @@ function M:_handle_tool_call_prepare(content)
15371557 end
15381558end
15391559
1560+ --- @return string tool text
15401561function M :_display_tool_call ()
1541- if not self ._current_tool_call then return end
1542-
1543- local tool_text = string.format (" 🔧 **Tool Call**: %s" , self ._current_tool_call .name or " unknown" )
1544-
1562+ if not self ._current_tool_call then return nil end
1563+
1564+ local diff = " "
1565+ local tool_text = " 🔧 " .. (self ._current_tool_call .summary or " Tool call prepared" )
1566+ local tool_log = string.format (" **Tool Call**: %s" , self ._current_tool_call .name or " unknown" )
1567+
15451568 if self ._current_tool_call .arguments and self ._current_tool_call .arguments ~= " " then
1546- tool_text = tool_text .. " \n ```json\n " .. self ._current_tool_call .arguments .. " \n ```"
1569+ tool_log = tool_log .. " \n ```json\n " .. self ._current_tool_call .arguments .. " \n ```"
15471570 end
1548-
15491571
15501572 if self ._current_tool_call .details and self ._current_tool_call .details .diff then
1551- tool_text = tool_text .. " \n\n **Diff**:\n ```diff\n " .. self ._current_tool_call .details .diff .. " \n ```"
1573+ diff = " \n\n **Diff**:\n ```diff\n " .. self ._current_tool_call .details .diff .. " \n ```"
15521574 end
15531575
1554- self :_add_message (" assistant" , tool_text )
1576+ Logger .debug (tool_log .. diff )
1577+ self :_add_message (" assistant" , tool_text .. diff )
1578+
1579+ return tool_text
15551580end
15561581
15571582function M :_finalize_tool_call ()
15581583 self ._current_tool_call = nil
15591584 self ._is_tool_call_streaming = false
15601585end
15611586
1587+ --- @param target string
1588+ --- @param replacement string
1589+ --- @param opts ? table | nil Optional search options : { max_search_lines = number , start_line = number }
1590+ --- @return boolean changed True if any replacement was made
1591+ function M :_replace_text (target , replacement , opts )
1592+ local chat = self .containers .chat
1593+
1594+ if not chat or not vim .api .nvim_buf_is_valid (chat .bufnr ) then
1595+ Logger .warn (" Cannot replace message: chat buffer not available" )
1596+ return false
1597+ end
1598+
1599+ if not target or target == " " then
1600+ Logger .warn (" Cannot replace message: empty target" )
1601+ return false
1602+ end
1603+
1604+ if not replacement or replacement == " " then
1605+ Logger .warn (" Cannot replace message: empty replacement" )
1606+ return false
1607+ end
1608+
1609+ local changed = false
1610+
1611+ self :_safe_buffer_update (chat .bufnr , function ()
1612+ local total_lines = vim .api .nvim_buf_line_count (chat .bufnr )
1613+ opts = opts or {}
1614+
1615+ -- Limit how many lines to search for performance with large buffers
1616+ local max_search_lines = tonumber (opts .max_search_lines ) or 500
1617+
1618+ -- If a start line is provided, start searching from there (useful for targeted replacement)
1619+ local start_line = tonumber (opts .start_line ) or total_lines
1620+ if start_line < 1 then start_line = 1 end
1621+ if start_line > total_lines then start_line = total_lines end
1622+
1623+ -- Determine the search window [end_line, start_line]
1624+ local end_line = math.max (1 , start_line - max_search_lines + 1 )
1625+
1626+ -- Fetch only the relevant range once (0-based indices for nvim API)
1627+ local range_lines = vim .api .nvim_buf_get_lines (chat .bufnr , end_line - 1 , start_line , false )
1628+
1629+ -- Iterate from bottom to top within the range
1630+ for idx = # range_lines , 1 , - 1 do
1631+ local line = range_lines [idx ] or " "
1632+ local s_idx , e_idx = line :find (target , 1 , true )
1633+ if s_idx then
1634+ local new_line = (line :sub (1 , s_idx - 1 )) .. replacement .. (line :sub (e_idx + 1 ))
1635+ local absolute_line = end_line + idx - 1 -- convert to absolute 1-based line
1636+ vim .api .nvim_buf_set_lines (chat .bufnr , absolute_line - 1 , absolute_line , false , { new_line })
1637+ changed = true
1638+ break
1639+ end
1640+ end
1641+ end )
1642+
1643+ return changed
1644+ end
1645+
15621646return M
0 commit comments