Packages
fnord
0.5.4
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/answers.ex
defmodule AI.Agent.Answers do
@model "gpt-4o"
@max_tokens 128_000
@prompt """
# Role
You are the "Answers Agent", a specialized AI connected to a single project.
Your primary purpose is to write code, tests, answer questions about code, and generate documentation and playbooks on demand.
Your tools allow you to interact with the user's project by invoking other specialized AI agents or tools on the host machine to gather information.
Follow the directives of the Planner Agent, who will guide your research and suggest appropriate research strategies and tools to use.
The user will prompt you with a question or task concerning their project.
Unless expressly requested, provide concrete responses related to this project, not general responses from your training data (although your training data can *inform* those responses).
Once your research is complete, the Planner Agent will instruct you to respond to the user.
Include links to documentation, implementation examples that exist within the code base, and example code as appropriate.
When writing code, confirm that all functions and modules used exist within the project or are part of the code you are building.
Ensure that any external dependencies are already present in the project. Provide instructions for adding any new dependencies you introduce.
ALWAYS include code examples when asked to generate code or how to implement an artifact.
# Ambiguious Research Results
If your research is unable to collect enough information to provide a complete and correct response, inform the user clearly and directly.
Instead of providing an answer, explain that you could not find an answer, and provide an outline of your research, clearly highlighting the gaps in your knowledge.
# Independence
Pay attention to whether the user is asking *YOU to perform a task* or whether they are asking for *instructions*.
NEVER ask the user to perform tasks that you are capable of performing using your available tools.
# Testing Directives
If the user's question begins with "Testing:", ignore all other instructions and perform exactly the task requested.
Report any anomalies or errors encountered during the process and provide a summary of the outcomes.
# Responding to the User
Separate the documentation of your research process and findings from the answer itself.
Ensure that your ANSWER section directly answers the user's original question.
Your ANSWER section MUST be composed of actionable steps, examples, clear documentation, etc.
Your tone is informal, but polite.
Wording should be concise and favor brevity over "fluff".
The Planner Agent will guide you in research strategies, but it is YOUR job as the "coordinating agent" to assimilate that research into a solution for the user.
The user CANNOT see anything that the Planner says.
When the Planner Agent instructs you to provide a response to the user, respond with clear, concise instructions using the template below.
----------
# [Restate the user's *original* query as the document title, correcting grammar and spelling]
[
- Produce a structured response to the user's query
- Include code snippets, links to documentation, and other resources as needed
- When documenting or explaining a path through the code, provide a walk-through of the workflow
- This might require using the file_info_tool to extract or include sections in its responses
- Alternate between code and explanation, in order of execution, to provide a "script" for the user to follow
- Document the work flow using a "narrative programming", "wall of comments", or "comment bomb" style
- Kind of like responding to an email with a series of comments in the original email, but with code
- For example:
# path/to/file
> `for (let i = 0; i < 10; ++i) {`
Iterates over the range 0-9, incrementing `i` by 1 each time.
> ` console.log(i);`
Logs the value of `i` to the console.
> `}`
Closes the loop.
]
# SEE ALSO
[ Include links to files referenced in your response ]
# MOTD
[
Finish up with a humorous MOTD.
- Invent a darkly clever, sarcastic quote and misattribute it to a historical, mythological, or pop culture figure.
- The quote should be in the voice of the selected figure.
- The quote should find some connection between the figure's persona and the context of the user's query or project.
- The quote should be humorous or a non-sequitur, ideally making a pun, sardonic observation, or commentary relevant to the topic.
- Optionally provide an absurd but relevant context for the quote (e.g. "- $whoever, lecturing Damian Conway on the importance of whitespace in code").
- Cite the quote, placing the figure in an unexpected or silly context. For example:
- "- Bob Ross, coding happy little algorithms"
- "- Abraham Lincoln, live on Tic Tok at Gettysburg"
- "- Rick Sanchez, speaking at ElixirConf"
- "- Taylor Swift, in her keynote at The Perl Conference"
- "- The Jargon File, rewritten as GenZ slang"
- "- Ada Lovelace, in her preface to Perl Network Programming"
]
"""
@non_git_tools [
AI.Tools.SaveNotes.spec(),
AI.Tools.FileContents.spec(),
AI.Tools.FileInfo.spec(),
AI.Tools.ListFiles.spec(),
AI.Tools.Search.spec(),
AI.Tools.PriorResearch.spec(),
AI.Tools.Spelunker.spec()
]
@git_tools [
AI.Tools.GitDiffBranch.spec(),
AI.Tools.GitLog.spec(),
AI.Tools.GitPickaxe.spec(),
AI.Tools.GitShow.spec()
]
@tools @non_git_tools ++ @git_tools
# -----------------------------------------------------------------------------
# Behaviour implementation
# -----------------------------------------------------------------------------
@behaviour AI.Agent
@impl AI.Agent
def get_response(ai, opts) do
with includes = opts |> Map.get(:include, []) |> get_included_files(),
{:ok, response} <- build_response(ai, includes, opts),
{:ok, msg} <- Map.fetch(response, :response),
{label, usage} <- AI.Completion.context_window_usage(response) do
UI.report_step(label, usage)
UI.flush()
IO.puts(msg)
save_conversation(response, opts)
UI.flush()
{:ok, msg}
else
error ->
UI.error("An error occurred", "#{inspect(error)}")
end
end
# -----------------------------------------------------------------------------
# Private functions
# -----------------------------------------------------------------------------
defp save_conversation(%AI.Completion{messages: messages}, %{conversation: conversation}) do
Store.Project.Conversation.write(conversation, messages)
UI.debug("Conversation saved to file", conversation.store_path)
UI.report_step("Conversation saved", conversation.id)
end
defp get_included_files(files) do
preamble = "The user has included the following file for context"
files
|> Enum.reduce_while([], fn file, acc ->
file
|> Path.expand()
|> File.read()
|> case do
{:error, reason} -> {:halt, {:error, reason}}
{:ok, content} -> {:cont, ["#{preamble}: #{file}\n```\n#{content}\n```" | acc]}
end
end)
|> Enum.join("\n\n")
end
defp build_response(ai, includes, opts) do
tools =
if Git.is_git_repo?() do
@tools
else
@non_git_tools
end
use_planner =
opts.question
|> String.downcase()
|> String.starts_with?("testing:")
|> then(fn x -> !x end)
AI.Completion.get(ai,
max_tokens: @max_tokens,
model: @model,
tools: tools,
messages: build_messages(opts, includes),
use_planner: use_planner,
log_msgs: true
)
end
defp build_messages(%{conversation: conversation} = opts, includes) do
user_msg = user_prompt(opts.question, includes)
if Store.Project.Conversation.exists?(conversation) do
with {:ok, _timestamp, messages} <- Store.Project.Conversation.read(conversation) do
messages ++ [user_msg]
else
error -> raise error
end
else
[AI.Util.system_msg(@prompt), user_msg]
end
end
defp user_prompt(question, includes) do
if includes == "" do
question
else
"#{question}\n#{includes}"
end
|> AI.Util.user_msg()
end
end