Packages
fnord
0.4.22
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/agent/clarify.ex
defmodule AI.Agent.Clarify do
@model "gpt-4o"
@prompt """
You are the Clarification Agent. Your job is to determine what exactly the
user is asking for when they provide a vague or ambiguous question to help
the Answers Agent in its research.
You cannot directly interact with the user. Instead, you must rely on your
tools to analyze the code base and attempt to gain enough context to
understand the user's question.
Pay special attention to ambigious terms or phrases that could have multiple
meanings. Ensure that you clarify these ambiguities through research, and use
the other terms in the user's question to ensure that your answer correlates
with both the user's intent and the code itself.
# Tools
- List Files Tool: Use this tool to list all files in the project database.
- Search Tool: Use this tool to identify relevant files using semantic queries.
- File Info Tool: Use this tool to ask specialized questions about the contents of a specific file.
# Response
Respond with a detailed explanation of the user's question, along with a
summary of your research, citing specific files or code snippets that support
your understanding of the user's query. Ensure to clarify that ambiguities
you discovered (for example, two unrelated entities that have similar names)
to ensure that the Answers Agent is aware of the potential for confusion.
"""
defstruct [
:ai,
:opts,
:tool_calls,
:messages,
:response
]
def new(ai, opts) do
%__MODULE__{
ai: ai,
opts: opts,
tool_calls: [],
messages: [
AI.Util.system_msg(@prompt),
AI.Util.user_msg(opts.question)
],
response: nil
}
end
def perform(agent) do
agent
|> send_request()
|> then(fn agent -> {:ok, agent.response} end)
end
defp send_request(agent) do
agent
|> build_request()
|> get_response(agent)
|> handle_response(agent)
end
defp build_request(agent) do
request =
OpenaiEx.Chat.Completions.new(
model: @model,
tool_choice: "auto",
messages: agent.messages,
tools: [
AI.Tools.Search.spec(),
AI.Tools.ListFiles.spec(),
AI.Tools.FileInfo.spec(),
AI.Tools.Planner.spec()
]
)
request
end
defp get_response(request, agent) do
completion = OpenaiEx.Chat.Completions.create(agent.ai.client, request)
with {:ok, %{"choices" => [event]}} <- completion do
event
end
end
defp handle_response(%{"finish_reason" => "stop"} = response, agent) do
with %{"message" => %{"content" => content}} <- response do
%__MODULE__{agent | response: content}
end
end
defp handle_response(%{"finish_reason" => "tool_calls"} = response, agent) do
with %{"message" => %{"tool_calls" => tool_calls}} <- response do
%__MODULE__{agent | tool_calls: tool_calls}
|> handle_tool_calls()
|> send_request()
end
end
defp handle_response({:error, %OpenaiEx.Error{message: "Request timed out."}}, agent) do
IO.puts(:stderr, "Request timed out. Retrying in 500 ms.")
Process.sleep(500)
send_request(agent)
end
defp handle_response({:error, %OpenaiEx.Error{message: msg}}, agent) do
%__MODULE__{
agent
| response: """
I encountered an error while processing your request. Please try again.
The error message was:
#{msg}
"""
}
end
# -----------------------------------------------------------------------------
# Tool calls
# -----------------------------------------------------------------------------
defp handle_tool_calls(%{tool_calls: tool_calls} = agent) do
{:ok, queue} =
Queue.start_link(agent.opts.concurrency, fn tool_call ->
handle_tool_call(agent, tool_call)
end)
outputs =
tool_calls
|> Queue.map(queue)
|> Enum.reduce([], fn
{:ok, msgs}, acc -> acc ++ msgs
_, acc -> acc
end)
Queue.shutdown(queue)
Queue.join(queue)
%__MODULE__{
agent
| tool_calls: [],
messages: agent.messages ++ outputs
}
end
def handle_tool_call(
agent,
%{
"id" => id,
"function" => %{
"name" => func,
"arguments" => args_json
}
}
) do
with {:ok, args} <- Jason.decode(args_json),
{:ok, output} <- perform_tool_call(agent, func, args) do
request = AI.Util.assistant_tool_msg(id, func, args_json)
response = AI.Util.tool_msg(id, func, output)
{:ok, [request, response]}
else
error ->
IO.puts(:stderr, "Error handling tool call | #{func} -> #{args_json} | #{inspect(error)}")
error
end
end
# -----------------------------------------------------------------------------
# Tool call outputs
# -----------------------------------------------------------------------------
defp perform_tool_call(agent, func, args_json) when is_binary(args_json) do
with {:ok, args} <- Jason.decode(args_json) do
perform_tool_call(agent, func, args)
end
end
defp perform_tool_call(agent, "search_tool", args), do: AI.Tools.Search.call(agent, args)
defp perform_tool_call(agent, "list_files_tool", args), do: AI.Tools.ListFiles.call(agent, args)
defp perform_tool_call(agent, "file_info_tool", args), do: AI.Tools.FileInfo.call(agent, args)
defp perform_tool_call(_agent, func, _args), do: {:error, :unhandled_tool_call, func}
end