Packages
fnord
0.9.31
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/self_help/docs.ex
defmodule AI.Tools.SelfHelp.Docs do
@moduledoc """
Searches fnord's published documentation to answer questions about features,
configuration, and usage patterns. Uses a web-search-capable model scoped to
fnord's canonical documentation sites.
"""
@behaviour AI.Tools
# Build canonical URL lists from docs/user/ at compile time so adding a
# new user-facing guide automatically expands the search scope without
# editing this module. Dev docs under docs/dev/ are intentionally out
# of scope: they're architecture notes for contributors/LLMs working
# on fnord itself, not answers to end-user questions.
#
# docs/user/README.md is NOT in hexdocs extras (see mix.exs - it's
# excluded to avoid a `readme.html` filename collision with the top-level
# README.md), so a URL for it would 404. The root README is already
# represented as the hardcoded `readme.html` entry below; drop the
# docs/user/README.md duplicate from the glob before building URLs.
@doc_paths Path.wildcard("docs/user/*.md")
|> Enum.reject(&(&1 == "docs/user/README.md"))
|> Enum.sort()
for path <- @doc_paths, do: @external_resource(path)
@hexdocs_urls [
"- https://hexdocs.pm/fnord/readme.html"
| Enum.map(@doc_paths, fn path ->
"- https://hexdocs.pm/fnord/#{Path.basename(path, ".md")}.html"
end)
]
|> Enum.join("\n")
@github_urls [
"- https://github.com/sysread/fnord/blob/main/README.md"
| Enum.map(@doc_paths, fn path ->
"- https://github.com/sysread/fnord/blob/main/#{path}"
end)
]
|> Enum.join("\n")
@system_prompt """
You are a documentation lookup tool for fnord, an AI-powered CLI for codebase research and editing.
Start with these canonical sources.
Hexdocs (preferred):
#{@hexdocs_urls}
GitHub (fallback):
#{@github_urls}
Follow links from these pages when the answer requires it.
GitHub's web UI URLs sometimes fail to load. When fetching content from GitHub,
convert to raw URLs. For example:
https://github.com/sysread/fnord/blob/main/docs/user/README.md
becomes:
https://raw.githubusercontent.com/sysread/fnord/refs/heads/main/docs/user/README.md
Provide a direct, concise answer based on the documentation content.
Include inline citations (page titles or URLs) when referencing specific information.
If the documentation does not cover the question, say so explicitly.
"""
@impl AI.Tools
def async?(), do: true
@impl AI.Tools
def is_available?(), do: true
@impl AI.Tools
def ui_note_on_request(%{"question" => q}), do: {"Researching fnord docs", q}
def ui_note_on_request(_), do: "Researching fnord docs"
@impl AI.Tools
def ui_note_on_result(_, _), do: nil
@impl AI.Tools
def tool_call_failure_message(_, _), do: :default
@impl AI.Tools
def spec do
%{
type: "function",
function: %{
name: "fnord_help_docs_tool",
description: """
Search fnord's published documentation to answer questions about features, configuration, and usage.
Use this tool when the user asks about how fnord works, what a feature does, or how to configure something.
For CLI structure questions (flags, subcommands, command tree), prefer fnord_help_cli_tool instead.
""",
parameters: %{
type: "object",
additionalProperties: false,
required: ["question"],
properties: %{
"question" => %{
type: "string",
description: "The question to research in fnord's documentation."
}
}
}
}
}
end
@impl AI.Tools
def read_args(args), do: {:ok, args}
@impl AI.Tools
def call(args) do
with {:ok, question} <- AI.Tools.get_arg(args, "question") do
search_docs(question)
end
end
defp search_docs(question) do
AI.Completion.get(
model: AI.Model.web_search(),
messages: [
AI.Util.system_msg(@system_prompt),
AI.Util.user_msg(question)
]
)
|> case do
{:ok, %{response: response}} ->
{:ok, response}
# Completion exposes the usage count alongside :context_length_exceeded;
# collapsing it to an :error with a descriptive reason keeps the tool
# caller contract single-shaped without dropping signal for logs.
{:error, :context_length_exceeded, _usage} ->
{:error, "documentation research exceeded the context window"}
{:error, reason} ->
{:error, reason}
end
end
end