Packages
AI agent framework for Elixir built on OTP. TEA-based agents with crash isolation, inter-agent messaging, team supervision, and real SSE streaming to Anthropic, OpenAI, Ollama, and more.
Current section
Files
Jump to
Current section
Files
lib/raxol/agent/action/pipeline.ex
defmodule Raxol.Agent.Action.Pipeline do
@moduledoc """
Composes actions into sequential pipelines.
Each action's output is merged into a shared state map that the next
action receives as params. The pipeline short-circuits on error.
## Example
Pipeline.run(
[ReadFile, AnalyzeCode, FormatReport],
%{path: "lib/app.ex"},
%{backend: mock_backend}
)
#=> {:ok, %{path: "lib/app.ex", content: "...", issues: [...], report: "..."}, []}
"""
@type step :: module() | {module(), map()}
@type pipeline :: [step()]
@doc """
Run a pipeline of actions sequentially.
`initial_params` seeds the shared state. Each action's `{:ok, result}`
is merged into the state for the next step. Commands from all steps
are accumulated.
Returns `{:ok, final_state, all_commands}` or `{:error, {step_module, reason}}`.
"""
@spec run(pipeline(), map(), map()) ::
{:ok, map(), [Raxol.Core.Runtime.Command.t()]} | {:error, {module(), term()}}
def run(steps, initial_params, context \\ %{}) do
Enum.reduce_while(steps, {:ok, initial_params, []}, fn step, {:ok, state, cmds} ->
{module, step_params} = normalize_step(step)
merged_params = Map.merge(state, step_params)
case module.call(merged_params, context) do
{:ok, result} ->
{:cont, {:ok, Map.merge(state, result), cmds}}
{:ok, result, new_cmds} ->
{:cont, {:ok, Map.merge(state, result), cmds ++ new_cmds}}
{:error, reason} ->
{:halt, {:error, {module, reason}}}
end
end)
end
defp normalize_step({module, params}) when is_atom(module) and is_map(params),
do: {module, params}
defp normalize_step(module) when is_atom(module),
do: {module, %{}}
end