feat: ReAct tool calling (#2104)
This commit is contained in:
@@ -576,7 +576,7 @@ end
|
||||
--- remove indentation from code: spaces or tabs
|
||||
function M.remove_indentation(code)
|
||||
if not code then return code end
|
||||
return code:gsub("^%s*", ""):gsub("%s*$", "")
|
||||
return code:gsub("%s*", "")
|
||||
end
|
||||
|
||||
function M.relative_path(absolute)
|
||||
@@ -1056,12 +1056,12 @@ function M.update_buffer_lines(ns_id, bufnr, old_lines, new_lines)
|
||||
if #diffs == 0 then return end
|
||||
for _, diff in ipairs(diffs) do
|
||||
local lines = diff.content
|
||||
-- M.debug("lines", lines)
|
||||
local text_lines = vim.tbl_map(function(line) return tostring(line) end, lines)
|
||||
vim.api.nvim_buf_set_lines(bufnr, diff.start_line - 1, diff.end_line - 1, false, text_lines)
|
||||
for i, line in ipairs(lines) do
|
||||
line:set_highlights(ns_id, bufnr, diff.start_line + i - 2)
|
||||
end
|
||||
vim.cmd("redraw")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1467,6 +1467,23 @@ function M.text_to_lines(text, hl)
|
||||
return lines
|
||||
end
|
||||
|
||||
---@param thinking_text string
|
||||
---@param hl string | nil
|
||||
---@return avante.ui.Line[]
|
||||
function M.thinking_to_lines(thinking_text, hl)
|
||||
local Line = require("avante.ui.line")
|
||||
local text_lines = vim.split(thinking_text, "\n")
|
||||
local lines = {}
|
||||
table.insert(lines, Line:new({ { M.icon("🤔 ") .. "Thought content:" } }))
|
||||
table.insert(lines, Line:new({ { "" } }))
|
||||
for _, text_line in ipairs(text_lines) do
|
||||
local piece = { "> " .. text_line }
|
||||
if hl then table.insert(piece, hl) end
|
||||
table.insert(lines, Line:new({ piece }))
|
||||
end
|
||||
return lines
|
||||
end
|
||||
|
||||
---@param item AvanteLLMMessageContentItem
|
||||
---@param message avante.HistoryMessage
|
||||
---@param messages avante.HistoryMessage[]
|
||||
@@ -1475,6 +1492,9 @@ function M.message_content_item_to_lines(item, message, messages)
|
||||
local Line = require("avante.ui.line")
|
||||
if type(item) == "string" then return M.text_to_lines(item) end
|
||||
if type(item) == "table" then
|
||||
if item.type == "thinking" or item.type == "redacted_thinking" then
|
||||
return M.thinking_to_lines(item.thinking or item.data or "")
|
||||
end
|
||||
if item.type == "text" then return M.text_to_lines(item.text) end
|
||||
if item.type == "image" then
|
||||
return { Line:new({ { "" } }) }
|
||||
@@ -1520,18 +1540,6 @@ function M.message_content_item_to_lines(item, message, messages)
|
||||
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) } }))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return lines
|
||||
end
|
||||
|
||||
144
lua/avante/utils/prompts.lua
Normal file
144
lua/avante/utils/prompts.lua
Normal file
@@ -0,0 +1,144 @@
|
||||
local M = {}
|
||||
|
||||
---@param provider_conf AvanteDefaultBaseProvider
|
||||
---@param opts AvantePromptOptions
|
||||
---@return string
|
||||
function M.get_ReAct_system_prompt(provider_conf, opts)
|
||||
local system_prompt = opts.system_prompt
|
||||
local disable_tools = provider_conf.disable_tools or false
|
||||
if not disable_tools and opts.tools then
|
||||
local tools_prompts = [[
|
||||
====
|
||||
|
||||
TOOL USE
|
||||
|
||||
You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
|
||||
|
||||
# Tool Use Formatting
|
||||
|
||||
Tool use is formatted using XML-style tags. The tool name is enclosed in opening and closing tags, and each parameter is similarly enclosed within its own set of tags. Here's the structure:
|
||||
|
||||
<tool_name>
|
||||
<parameter1_name>value1</parameter1_name>
|
||||
<parameter2_name>value2</parameter2_name>
|
||||
...
|
||||
</tool_name>
|
||||
|
||||
For example:
|
||||
|
||||
<view>
|
||||
<path>src/main.js</path>
|
||||
</view>
|
||||
|
||||
Always adhere to this format for the tool use to ensure proper parsing and execution.
|
||||
|
||||
# Tools
|
||||
|
||||
]]
|
||||
for _, tool in ipairs(opts.tools) do
|
||||
local tool_prompt = ([[
|
||||
## {{name}}
|
||||
Description: {{description}}
|
||||
Parameters:
|
||||
]]):gsub("{{name}}", tool.name):gsub(
|
||||
"{{description}}",
|
||||
tool.get_description and tool.get_description() or (tool.description or "")
|
||||
)
|
||||
for _, field in ipairs(tool.param.fields) do
|
||||
if field.optional then
|
||||
tool_prompt = tool_prompt .. string.format(" - %s: %s\n", field.name, field.description)
|
||||
else
|
||||
tool_prompt = tool_prompt
|
||||
.. string.format(
|
||||
" - %s: (required) %s\n",
|
||||
field.name,
|
||||
field.get_description and field.get_description() or (field.description or "")
|
||||
)
|
||||
end
|
||||
end
|
||||
if tool.param.usage then
|
||||
tool_prompt = tool_prompt
|
||||
.. ("Usage:\n<{{name}}>\n"):gsub("{{([%w_]+)}}", function(name) return tool[name] end)
|
||||
for k, v in pairs(tool.param.usage) do
|
||||
tool_prompt = tool_prompt .. "<" .. k .. ">" .. tostring(v) .. "</" .. k .. ">\n"
|
||||
end
|
||||
tool_prompt = tool_prompt .. ("</{{name}}>\n"):gsub("{{([%w_]+)}}", function(name) return tool[name] end)
|
||||
end
|
||||
tools_prompts = tools_prompts .. tool_prompt .. "\n"
|
||||
end
|
||||
|
||||
system_prompt = system_prompt .. tools_prompts
|
||||
|
||||
system_prompt = system_prompt
|
||||
.. [[
|
||||
# Tool Use Examples
|
||||
|
||||
## Example 1: Requesting to execute a command
|
||||
|
||||
<bash>
|
||||
<path>./src</path>
|
||||
<command>npm run dev</command>
|
||||
</bash>
|
||||
|
||||
## Example 2: Requesting to create a new file
|
||||
|
||||
<write_to_file>
|
||||
<path>src/frontend-config.json</path>
|
||||
<content>
|
||||
{
|
||||
"apiEndpoint": "https://api.example.com",
|
||||
"theme": {
|
||||
"primaryColor": "#007bff",
|
||||
"secondaryColor": "#6c757d",
|
||||
"fontFamily": "Arial, sans-serif"
|
||||
},
|
||||
"features": {
|
||||
"darkMode": true,
|
||||
"notifications": true,
|
||||
"analytics": false
|
||||
},
|
||||
"version": "1.0.0"
|
||||
}
|
||||
</content>
|
||||
</write_to_file>
|
||||
|
||||
## Example 3: Requesting to make targeted edits to a file
|
||||
|
||||
<replace_in_file>
|
||||
<path>src/components/App.tsx</path>
|
||||
<diff>
|
||||
<<<<<<< SEARCH
|
||||
import React from 'react';
|
||||
=======
|
||||
import React, { useState } from 'react';
|
||||
>>>>>>> REPLACE
|
||||
|
||||
<<<<<<< SEARCH
|
||||
function handleSubmit() {
|
||||
saveData();
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
=======
|
||||
>>>>>>> REPLACE
|
||||
|
||||
<<<<<<< SEARCH
|
||||
return (
|
||||
<div>
|
||||
=======
|
||||
function handleSubmit() {
|
||||
saveData();
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
>>>>>>> REPLACE
|
||||
</diff>
|
||||
</replace_in_file>
|
||||
]]
|
||||
end
|
||||
return system_prompt
|
||||
end
|
||||
|
||||
return M
|
||||
Reference in New Issue
Block a user