Packages
fnord
0.7.7
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/notes_consolidator.ex
defmodule AI.Agent.NotesConsolidator do
@model AI.Model.fast()
@prompt """
#{AI.Util.note_format_prompt()}
You are an AI agent responsible for analyzing a list of facts and consolidating them.
You will be presented with a mess of individual facts and documents.
Input may include mixed formats. It is your job to organize them into a coherent structure.
Break down all the information into discrete facts, then reorganize them by topic.
Your goal is to reorgnaize facts under a small number of broad topics.
Try to reorganize and categorize all of the facts under a maximum of 20 topics.
If required, broaden the scope of topics to make this possible.
- DO *combine* ALL of the facts from similar topics under a SINGLE topic.
- DO *merge* IDENTICAL facts.
- DO NOT *merge* facts that are similar but not identical.
**It is ESSENTIAL that no facts are lost.**
"""
@invalid_format_prompt """
The fact-checked note was not in the expected format.
Please correct the format. Respond ONLY with the expected note format.
"""
@invalid_format_error "the LLM responded with the incorrect format after 3 attempts"
@missing_arg_error "missing required argument: notes"
@type note :: String.t()
@type ai :: AI.t()
# -----------------------------------------------------------------------------
# Behaviour implementation
# -----------------------------------------------------------------------------
@behaviour AI.Agent
@impl AI.Agent
def get_response(ai, opts) do
with {:ok, notes} <- Map.fetch(opts, :notes),
{:ok, notes} <- consolidate_notes(notes, ai) do
{:ok, notes}
else
{:error, :invalid_format} -> {:error, @invalid_format_error}
:error -> {:error, @missing_arg_error}
end
end
@spec consolidate_notes([note], ai) :: {:ok, note} | {:error, :invalid_format}
defp consolidate_notes(notes, ai) do
1..3
|> Enum.reduce_while(nil, fn _attempt, acc ->
notes
|> get_completion(ai, acc)
|> process_response()
|> AI.Util.validate_notes_string()
|> case do
{:ok, notes} -> {:halt, Enum.join(notes, "\n")}
{:error, :invalid_format} -> {:cont, :invalid_format}
end
end)
|> case do
:invalid_format -> {:error, :invalid_format}
valid_notes when is_binary(valid_notes) -> {:ok, valid_notes}
end
end
@spec get_completion([note], ai, nil | :invalid_format) :: note
defp get_completion(notes, ai, prior_failure) do
notes_msg = Enum.join(notes, "\n")
messages = [AI.Util.system_msg(@prompt), AI.Util.user_msg(notes_msg)]
messages =
case prior_failure do
nil -> messages
:invalid_format -> messages ++ [AI.Util.system_msg(@invalid_format_prompt)]
end
AI.Completion.get(ai,
log_msgs: false,
log_tool_calls: false,
model: @model,
messages: messages
)
|> then(fn {:ok, %{response: response}} ->
response
end)
end
@spec process_response(note) :: note
defp process_response(response) do
response
|> String.split("\n")
|> Enum.map(fn line ->
line
|> String.trim()
|> String.trim_leading("-")
|> String.trim()
end)
|> Enum.join("\n")
end
end