Packages
fnord
0.9.30
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/reviewer.ex
defmodule AI.Tools.Reviewer do
@moduledoc """
Tool entry point for the review agent pipeline. Delegates to
`AI.Agent.Review.Decomposer`, which triages changes by complexity, partitions
large diffs into focused review units, and fans out scoped Reviewers - each
running five specialists (pedantic, acceptance, state flow, no-slop,
breadcrumbs) - before synthesizing a deduplicated final report.
Always available - reviews are read-only operations.
"""
@behaviour AI.Tools
@impl AI.Tools
def async?, do: true
@impl AI.Tools
def is_available?, do: true
@impl AI.Tools
def read_args(args), do: {:ok, args}
@impl AI.Tools
def ui_note_on_request(%{"scope" => scope}) do
{"Starting code review", scope}
end
@impl AI.Tools
def ui_note_on_result(_args, result) do
{"Review complete", result}
end
@impl AI.Tools
def tool_call_failure_message(_args, reason), do: reason
@impl AI.Tools
def spec do
%{
type: "function",
function: %{
name: "reviewer_tool",
description: """
AI-powered, multi-agent code review.
Triages change complexity, decomposes large diffs into focused review
units, and fans out scoped multi-specialist reviewers in parallel.
Produces a unified, deduplicated, severity-grouped report.
The reviewer reads the target via git directly - it does NOT need the
target checked out in your working tree. Always name an explicit
target via `branch`, `pr`, or `range`; the reviewer will fetch refs
as needed.
Use for:
- Post-implementation review of a branch or commit range
- Pre-merge quality checks of a PR
- Comprehensive audit of changes spanning multiple files
NOT for quick, single-file checks - just read the file yourself.
Not safe to run concurrently. Only one active review per fnord
process at a time.
""",
parameters: %{
type: "object",
required: ["scope"],
additionalProperties: false,
properties: %{
scope: %{
type: "string",
description: """
Design context and specific concerns for the review. Free text.
Describe intent, risky areas, what "done" looks like. Do NOT
use this field to specify the target branch or PR - use the
dedicated `branch`, `pr`, or `range` parameters for that.
"""
},
branch: %{
type: "string",
description: """
Branch to review (e.g. "feature-x"). The reviewer fetches the
branch from origin if it is not locally reachable, then reviews
the range `merge-base(branch, base)..branch`. Mutually
exclusive with `pr` and `range`.
"""
},
pr: %{
type: "integer",
description: """
GitHub pull request number. Requires the `gh` CLI to be
installed and authenticated. The reviewer resolves the PR's
head and base via `gh pr view`, fetches both refs, and
reviews the range `merge-base(head, base)..head`. Mutually
exclusive with `branch` and `range`.
"""
},
range: %{
type: "string",
description: """
Explicit git range in `A..B` or `A...B` form (e.g.
`HEAD~3..HEAD`, `abc123..def456`). Use for commit-scoped
reviews that are not tied to a branch or PR. The reviewer
fetches endpoints from origin if they are not locally
reachable. Mutually exclusive with `branch` and `pr`.
"""
},
base: %{
type: "string",
description: """
Override the base branch used to compute merge-base. Default
is the repo's default branch (`main` or `master`). Useful for
stacked branches - set to the parent branch, not `main`.
Ignored when `range` is used.
"""
}
}
}
}
}
end
@impl AI.Tools
def call(args) do
with {:ok, scope} <- AI.Tools.get_arg(args, "scope"),
{:ok, target_args} <- normalize_target_args(args) do
AI.Agent.Review.Decomposer
|> AI.Agent.new()
|> AI.Agent.get_response(Map.put(target_args, :scope, scope))
end
end
# Extract and validate the target-selection params. The LLM may pass any
# subset (or none) of branch / pr / range; at most one is allowed. `base`
# is free-standing and applies only when resolving branch: or falling back
# to the current checkout.
defp normalize_target_args(args) do
branch = Map.get(args, "branch")
pr = Map.get(args, "pr")
range = Map.get(args, "range")
base = Map.get(args, "base")
given = [{:branch, branch}, {:pr, pr}, {:range, range}] |> Enum.filter(fn {_, v} -> v end)
case given do
[] ->
{:ok, %{branch: nil, pr: nil, range: nil, base: base}}
[{_, _}] ->
{:ok, %{branch: branch, pr: pr, range: range, base: base}}
multiple ->
names = multiple |> Enum.map_join(", ", fn {k, _} -> to_string(k) end)
{:error,
"reviewer_tool: pass at most one of branch, pr, range (got: #{names}). " <>
"Use `range` for explicit commit ranges, `pr` for a GitHub PR number, " <>
"`branch` for a branch name."}
end
end
end