refactor: llm tools (#1675)
This commit is contained in:
118
lua/avante/llm_tools/dispatch_agent.lua
Normal file
118
lua/avante/llm_tools/dispatch_agent.lua
Normal file
@@ -0,0 +1,118 @@
|
||||
local Providers = require("avante.providers")
|
||||
local Config = require("avante.config")
|
||||
local Utils = require("avante.utils")
|
||||
local Base = require("avante.llm_tools.base")
|
||||
|
||||
---@class AvanteLLMTool
|
||||
local M = setmetatable({}, Base)
|
||||
|
||||
M.name = "dispatch_agent"
|
||||
|
||||
M.description =
|
||||
[[Launch a new agent that has access to the following tools: `glob`, `grep`, `ls`, `read_file`. When you are searching for a keyword or file and are not confident that you will find the right match on the first try, use the Agent tool to perform the search for you. For example:
|
||||
|
||||
- If you are searching for a keyword like "config" or "logger", the Agent tool is appropriate
|
||||
- If you want to read a specific file path, use the `read_file` or `glob` tool instead of the `dispatch_agent` tool, to find the match more quickly
|
||||
- If you are searching for a specific class definition like "class Foo", use the `glob` tool instead, to find the match more quickly
|
||||
|
||||
Usage notes:
|
||||
1. Launch multiple agents concurrently whenever possible, to maximize performance
|
||||
2. When the agent is done, it will return a single message back to you
|
||||
3. Each agent invocation is stateless
|
||||
4. The agent's outputs should generally be trusted]]
|
||||
|
||||
---@type AvanteLLMToolParam
|
||||
M.param = {
|
||||
type = "table",
|
||||
fields = {
|
||||
{
|
||||
name = "prompt",
|
||||
description = "The task for the agent to perform",
|
||||
type = "string",
|
||||
},
|
||||
},
|
||||
required = { "prompt" },
|
||||
}
|
||||
|
||||
---@type AvanteLLMToolReturn[]
|
||||
M.returns = {
|
||||
{
|
||||
name = "result",
|
||||
description = "The result of the agent",
|
||||
type = "string",
|
||||
},
|
||||
{
|
||||
name = "error",
|
||||
description = "The error message if the agent fails",
|
||||
type = "string",
|
||||
optional = true,
|
||||
},
|
||||
}
|
||||
|
||||
local function get_available_tools()
|
||||
return {
|
||||
require("avante.llm_tools.ls"),
|
||||
require("avante.llm_tools.grep"),
|
||||
require("avante.llm_tools.glob"),
|
||||
require("avante.llm_tools.read_file"),
|
||||
}
|
||||
end
|
||||
|
||||
---@type AvanteLLMToolFunc<{ prompt: string }>
|
||||
function M.func(opts, on_log, on_complete)
|
||||
local Llm = require("avante.llm")
|
||||
if not on_complete then return false, "on_complete not provided" end
|
||||
local prompt = opts.prompt
|
||||
local tools = get_available_tools()
|
||||
local start_time = os.date("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
if on_log then on_log("prompt: " .. prompt) end
|
||||
|
||||
local system_prompt = ([[You are a helpful assistant with access to various tools.
|
||||
Your task is to help the user with their request: "${prompt}"
|
||||
Be thorough and use the tools available to you to find the most relevant information.
|
||||
When you're done, provide a clear and concise summary of what you found.]]):gsub("${prompt}", prompt)
|
||||
|
||||
local total_tokens = 0
|
||||
local final_response = ""
|
||||
Llm._stream({
|
||||
ask = true,
|
||||
code_lang = "unknown",
|
||||
provider = Providers[Config.provider],
|
||||
prompt_opts = {
|
||||
system_prompt = system_prompt,
|
||||
tools = tools,
|
||||
messages = {
|
||||
{ role = "user", content = prompt },
|
||||
},
|
||||
},
|
||||
on_start = function(_) end,
|
||||
on_chunk = function(chunk)
|
||||
if not chunk then return end
|
||||
final_response = final_response .. chunk
|
||||
total_tokens = total_tokens + (#vim.split(chunk, " ") * 1.3)
|
||||
end,
|
||||
on_stop = function(stop_opts)
|
||||
if stop_opts.error ~= nil then
|
||||
local err = string.format("dispatch_agent failed: %s", vim.inspect(stop_opts.error))
|
||||
on_complete(err, nil)
|
||||
return
|
||||
end
|
||||
local end_time = os.date("%Y-%m-%d %H:%M:%S")
|
||||
local elapsed_time = Utils.datetime_diff(tostring(start_time), tostring(end_time))
|
||||
local tool_use_count = stop_opts.tool_histories and #stop_opts.tool_histories or 0
|
||||
local summary = "Done ("
|
||||
.. (tool_use_count <= 1 and "1 tool use" or tool_use_count .. " tool uses")
|
||||
.. " · "
|
||||
.. math.ceil(total_tokens)
|
||||
.. " tokens · "
|
||||
.. elapsed_time
|
||||
.. "s)"
|
||||
Utils.debug("summary", summary)
|
||||
local response = string.format("Final response:\n%s\n\nSummary:\n%s", summary, final_response)
|
||||
on_complete(response, nil)
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
return M
|
||||
Reference in New Issue
Block a user