Packages
fnord
0.4.25
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/code_mapper.ex
defmodule AI.Agent.CodeMapper do
defstruct [
:ai,
:file_path,
:splitter,
:outline
]
@model "gpt-4o-mini"
# It's actually 128k for this model, but this gives us a little bit of
# wiggle room in case the tokenizer we are using falls behind.
@max_tokens 100_000
@chunk_prompt """
You are the Code Mapper Agent. You will receive the contents of a code file.
You will generate an outline of the code in the file, identifying symbols like ctags, but in a human-readable format.
For every function, include a list of other functions it calls, including notes about the conditions under which a function calls other functions.
Your organization is hierarchical, and depends on the programming language(s) in the file.
If there is no higher-level organization, use "GLOBAL" as the top-level.
If the example below does not match the terminology of the language in the file being processed, please adapt it to match the language's terminology (for example, the example uses Python, which does not have a <constant> but C does).
Do not respond with any explanation or context, just the outline, in text format with no special formatting (just list markers).
For example, for a Python module, organize the code first by class, then by method:
```
# Accumulated Outline
- <file> $file_path
- <namespace> GLOBAL
- <variable> DEFAULT_X
- <variable> DEFAULT_Y
- <class> Point
- <attribute> x
- <attribute> y
- <method> __init__(x=None, y=None)
- <reference> DEFAULT_X - when x is None
- <reference> DEFAULT_Y - when y is None
- <method> get_slope(point)
- <call> calculate_slope(point_a, point_b)
- <method> move_to(x, y)
- <call> __init__(x, y) - when (x, y) is not the current position
- <class method> from_string(string)
```
You are processing file chunks in sequence, each paired with an "accumulator" string to update, in the following format:
```
# Accumulated Outline
$your_accumulated_outline
-----
file path: $file_path
$current_file_chunk
```
Guidelines for updating the accumulator:
1. Add Relevant Content: Update the accumulator with the symbols found in the current chunk
2. Continuity: Build on the existing outline, preserving its structure
3. Handle Incompletes: If a chunk is incomplete, mark it (e.g., `<partial>`) to complete later
4. Consistent Format: Append new content in list format under "Accumulated Outline"
Respond ONLY with the `Accumulated Outline` section, formatted as an outline in list format, including your updates from the current chunk.
"""
@final_prompt """
You have processed a file in chunks and have collected an outline of the code in the file.
Please review the outline and ensure that it is coherent and consistent.
Your input will be in the format:
```
# Accumulated Outline
$your_accumulated_outline
```
Respond ONLY with your cleaned up `Accumulated Outline` section, formatted as a text outline.
"""
def new(ai, file_path, file_content) do
%__MODULE__{
ai: ai,
file_path: file_path,
splitter: AI.TokenSplitter.new(file_content, @max_tokens),
outline: ""
}
end
def get_outline(agent) do
reduce(agent)
end
defp reduce(%{splitter: %{done: true}} = agent) do
finish(agent)
end
defp reduce(%{splitter: %{done: false}} = agent) do
with {:ok, agent} <- process_chunk(agent) do
reduce(agent)
end
end
defp finish(agent) do
AI.get_completion(agent.ai,
model: @model,
system_prompt: @final_prompt,
user_prompt: get_prompt(agent)
)
|> case do
{:ok, %{"message" => %{"content" => outline}}} -> {:ok, outline}
{:error, reason} -> {:error, reason}
end
end
defp process_chunk(agent) do
prompt = get_prompt(agent)
{chunk, splitter} = AI.TokenSplitter.next_chunk(agent.splitter, prompt)
agent = %{agent | splitter: splitter}
message = prompt <> chunk
AI.get_completion(agent.ai,
model: @model,
system_prompt: @chunk_prompt,
user_prompt: message
)
|> case do
{:ok, %{"message" => %{"content" => outline}}} ->
{:ok, %__MODULE__{agent | splitter: splitter, outline: outline}}
{:error, reason} ->
{:error, inspect(reason)}
end
end
defp get_prompt(agent) do
"""
# Accumulated Outline
#{agent.outline}
-----
file path: #{agent.file_path}
"""
end
end