Packages
fnord
0.7.23
0.9.40
0.9.39
0.9.38
0.9.37
0.9.36
0.9.35
0.9.34
0.9.33
0.9.32
0.9.31
0.9.30
0.9.29
0.9.28
0.9.27
0.9.26
0.9.25
0.9.24
0.9.23
0.9.22
0.9.21
0.9.20
0.9.19
0.9.18
0.9.17
0.9.16
0.9.15
0.9.14
0.9.13
0.9.12
0.9.11
0.9.10
0.9.9
0.9.8
0.9.7
0.9.6
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.99
0.8.98
0.8.97
0.8.96
0.8.95
0.8.94
0.8.93
0.8.92
0.8.91
0.8.90
0.8.89
0.8.88
0.8.87
0.8.86
0.8.85
0.8.84
0.8.83
0.8.82
0.8.81
0.8.80
0.8.79
0.8.78
0.8.77
0.8.76
0.8.75
0.8.74
0.8.73
0.8.72
0.8.71
0.8.70
0.8.69
0.8.68
0.8.67
0.8.66
0.8.65
0.8.64
0.8.63
0.8.62
0.8.61
0.8.60
0.8.59
0.8.58
0.8.57
0.8.56
0.8.55
0.8.54
0.8.53
0.8.52
0.8.51
0.8.50
0.8.49
0.8.48
0.8.47
0.8.46
0.8.45
0.8.44
0.8.43
0.8.42
0.8.41
0.8.40
0.8.39
0.8.38
0.8.37
0.8.36
0.8.35
0.8.34
0.8.33
0.8.32
0.8.31
0.8.30
0.8.29
0.8.27
0.8.26
0.8.25
0.8.24
0.8.23
0.8.22
0.8.21
0.8.20
0.8.19
0.8.18
0.8.17
0.8.16
0.8.15
0.8.14
0.8.13
0.8.12
0.8.11
0.8.1
0.8.0
0.7.24
0.7.23
0.7.22
0.7.21
0.7.20
0.7.19
0.7.18
0.7.17
0.7.16
0.7.15
0.7.14
0.7.13
0.7.12
0.7.11
0.7.10
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.3
0.7.2
0.7.1
0.7.0
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.1
0.6.0
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.44
0.4.43
0.4.42
0.4.41
0.4.40
0.4.39
0.4.38
0.4.37
0.4.36
0.4.35
0.4.34
0.4.33
0.4.32
0.4.30
0.4.29
0.4.28
0.4.27
0.4.26
0.4.25
0.4.24
0.4.23
0.4.22
0.4.21
0.4.20
0.4.19
0.4.18
0.4.17
0.4.16
0.4.15
0.4.14
0.4.13
0.4.12
0.4.11
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.0
0.2.0
0.1.0
AI code archaeology
Current section
Files
Jump to
Current section
Files
lib/ai/tools/file/info.ex
defmodule AI.Tools.File.Info do
@behaviour AI.Tools
@impl AI.Tools
def is_available?, do: true
@impl AI.Tools
def ui_note_on_request(%{"files" => files, "question" => question}) do
{"Considering #{Enum.join(files, ", ")}", question}
end
def ui_note_on_request(args) do
{"file_info_tool", "invalid arguments: #{inspect(args)}"}
end
@impl AI.Tools
def ui_note_on_result(%{"files" => files, "question" => question}, _result) do
{"Answered", "#{Enum.join(files, ", ")}: #{question}"}
end
def ui_note_on_result(_args, _result) do
nil
end
@impl AI.Tools
def read_args(args) do
with {:ok, files} <- get_files(args),
{:ok, question} <- get_question(args) do
{:ok, %{"files" => files, "question" => question}}
end
end
defp get_files(%{"files" => files}), do: {:ok, files}
defp get_files(_args), do: AI.Tools.required_arg_error("files")
defp get_question(%{"question" => question}), do: {:ok, question}
defp get_question(_args), do: AI.Tools.required_arg_error("question")
@impl AI.Tools
def spec() do
%{
type: "function",
function: %{
name: "file_info_tool",
description: """
Requests information about a file or files. An LLM will use your
question to extract relevant information from each of the specified
file, preserving your own context window so you can focus on answering
the user's questions. Specify exactly how you want the response
formatted (e.g. exact code sections, interfaces, explanations, yes/no,
etc.). File paths must match the ones provided by the file_list_tool or
file_search_tool to avoid enoent errors. This tool can use git to
provide context about its history and differences from earlier version.
""",
parameters: %{
type: "object",
required: ["question", "files"],
properties: %{
question: %{
type: "string",
description: "A complete prompt for the LLM to respond to."
},
files: %{
type: "array",
items: %{type: "string"},
description: """
A list of file paths that the LLM should process. Each file will
be delegated to the LLM in parallel, allowing you to perform the
same inquiry over many files at once.
This is extremely useful when the user has asked you to identify
complex patterns across multiple files, such as "find all
functions that call this function" or "find all methods that
return a value of this type".
"""
}
}
}
}
}
end
@impl AI.Tools
def call(args) do
with {:ok, question} <- Map.fetch(args, "question"),
{:ok, files} <- Map.fetch(args, "files") do
files
|> Util.async_stream(&process_file(&1, question))
|> Stream.map(&format_response/1)
|> Enum.join("\n\n-----\n\n")
|> then(&{:ok, &1})
end
end
@spec process_file(String.t(), String.t()) :: {String.t(), String.t()}
defp process_file(file, question) do
response =
with {:ok, content} <- AI.Tools.get_file_contents(file),
{:ok, response} <- get_agent_response(file, question, content) do
response
else
{:error, reason} ->
"""
Unable to read the file contents for the requested file.
- If the file name is correct, verify the path using the search or the file listing tool.
- It may have been added since the most recent reindexing of the project.
- If the file is only present in a topic branch that has not yet been merged, it may not be visible to this tool.
FILE: #{file}
ERROR: #{inspect(reason)}
"""
end
{file, response}
end
@spec get_agent_response(String.t(), String.t(), String.t()) ::
{:ok, String.t()}
| {:error, any()}
defp get_agent_response(file, question, content) do
AI.Agent.FileInfo.get_response(%{
file: file,
question: question,
content: content
})
end
@spec format_response({atom, {String.t(), String.t() | atom}}) :: String.t()
defp format_response({:ok, {file, result}}) do
"""
## File
#{file}
## Result
#{result}
"""
end
defp format_response({:error, {file, reason}}) do
"""
## File
#{file}
## Error
An error occurred while processing the file:
#{inspect(reason, pretty: true)}
"""
end
end