Packages
fnord
0.9.21
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/skill.ex
defmodule AI.Agent.Skill do
@moduledoc """
Generic agent implementation for executing a `%Skills.Skill{}`.
The coordinator (or another agent) provides:
- the skill to run, and
- an input prompt.
This agent resolves the skill's runtime configuration:
- model preset (via `Skills.Runtime.model_from_string/1`)
- tool tags (via `Skills.Runtime.toolbox_from_tags/1`)
- response_format (via `Skills.Runtime.validate_response_format/1`)
It then performs a single completion using the resolved model, toolbox, and
messages.
"""
@behaviour AI.Agent
@type error ::
Skills.Runtime.model_error()
| Skills.Runtime.toolbox_error()
| Skills.Runtime.response_format_error()
| {:missing_arg, atom}
@impl AI.Agent
@spec get_response(map) :: {:ok, any} | {:error, any}
def get_response(opts) do
with {:ok, agent} <- fetch_arg(opts, :agent),
{:ok, skill} <- fetch_arg(opts, :skill),
{:ok, prompt} <- fetch_arg(opts, :prompt),
:ok <- enforce_rw_gating(skill),
{:ok, model} <- Skills.Runtime.model_from_string(skill.model),
{:ok, toolbox} <- Skills.Runtime.toolbox_from_tags(skill.tools),
{:ok, response_format} <- Skills.Runtime.validate_response_format(skill.response_format) do
UI.report_from(agent.name, "[skill #{skill.name}] #{prompt}")
# When at max skill nesting depth, strip the run_skill tool so the skill
# can still execute but cannot recurse further (mirrors researcher pattern).
toolbox =
case Map.get(opts, :strip_skills?, false) do
true -> Map.drop(toolbox, ["run_skill"])
false -> toolbox
end
# Prepend the shared reasoning preamble to the skill's own system prompt
# so all skill agents inherit baseline reasoning discipline.
system_prompt = Skills.Runtime.reasoning_preamble() <> "\n" <> skill.system_prompt
AI.Agent.get_completion(agent,
model: model,
toolbox: toolbox,
response_format: response_format,
log_msgs: true,
messages: [
AI.Util.system_msg(AI.Util.project_context()),
AI.Util.system_msg(system_prompt),
AI.Util.user_msg(prompt)
]
)
|> case do
{:ok, %{response: response}} -> {:ok, response}
{:error, %{response: response}} -> {:error, response}
{:error, reason} -> {:error, reason}
end
else
{:error, reason} -> {:error, reason}
end
end
# RW skills require --edit mode. Enforced here so direct callers (not just
# the RunSkill tool) cannot bypass the gate.
defp enforce_rw_gating(%Skills.Skill{tools: tools}) do
if Enum.member?(tools, "rw") and not Settings.get_edit_mode() do
{:error, "Cannot run rw skills; the user did not pass --edit."}
else
:ok
end
end
defp fetch_arg(opts, key) do
case Map.fetch(opts, key) do
{:ok, value} -> {:ok, value}
:error -> {:error, {:missing_arg, key}}
end
end
end