Packages
nous
0.13.3
0.17.0
0.16.6
0.16.5
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.8
0.15.7
0.15.6
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.3
0.13.2
0.13.1
0.13.0
0.12.17
0.12.16
0.12.15
0.12.14
0.12.13
0.12.12
0.12.11
0.12.9
0.12.7
0.12.6
0.12.5
0.12.3
0.12.2
0.12.0
0.11.3
0.11.0
0.10.1
0.10.0
0.9.0
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.5.0
AI agent framework for Elixir with multi-provider LLM support
Current section
Files
Jump to
Current section
Files
lib/nous/workflow/node.ex
defmodule Nous.Workflow.Node do
@moduledoc """
A node in a workflow graph.
Nodes represent discrete execution steps: running agents, executing tools,
branching on conditions, parallel fan-out, data transformation, and
human-in-the-loop checkpoints.
## Node Types
| Type | Purpose |
|------|---------|
| `:agent_step` | Run a `Nous.Agent` via `AgentRunner.run/3` |
| `:tool_step` | Execute a single tool via `ToolExecutor.execute/3` |
| `:branch` | Conditional routing based on state predicates |
| `:parallel` | Static fan-out to named branches, fan-in with merge |
| `:parallel_map` | Dynamic fan-out over a runtime-computed list |
| `:transform` | Pure function on workflow state |
| `:human_checkpoint` | Pause for human review/approval |
| `:subworkflow` | Nested workflow invocation |
## Examples
Nous.Workflow.Node.new(%{
id: "fetch_data",
type: :agent_step,
label: "Fetch research data",
config: %{agent: researcher_agent, prompt: "Find data on..."}
})
"""
@type node_type ::
:agent_step
| :tool_step
| :branch
| :parallel
| :parallel_map
| :transform
| :human_checkpoint
| :subworkflow
@type error_strategy ::
:fail_fast
| {:retry, max :: pos_integer(), delay_ms :: non_neg_integer()}
| :skip
| {:fallback, node_id :: String.t()}
@type t :: %__MODULE__{
id: String.t(),
type: node_type(),
label: String.t(),
config: map(),
error_strategy: error_strategy(),
timeout: non_neg_integer() | nil,
metadata: map()
}
defstruct [
:id,
:type,
:label,
:timeout,
config: %{},
error_strategy: :fail_fast,
metadata: %{}
]
@valid_types ~w(agent_step tool_step branch parallel parallel_map transform human_checkpoint subworkflow)a
@doc """
Create a new workflow node.
Required: `:id`, `:type`, and `:label`.
## Examples
iex> node = Nous.Workflow.Node.new(%{id: "step1", type: :transform, label: "Clean data"})
iex> node.type
:transform
iex> node.error_strategy
:fail_fast
"""
@spec new(map()) :: t()
def new(attrs) when is_map(attrs) do
type = Map.fetch!(attrs, :type)
unless type in @valid_types do
raise ArgumentError,
"invalid node type: #{inspect(type)}, must be one of #{inspect(@valid_types)}"
end
%__MODULE__{
id: attrs |> Map.fetch!(:id) |> to_string(),
type: type,
label: Map.fetch!(attrs, :label),
config: Map.get(attrs, :config, %{}),
error_strategy: Map.get(attrs, :error_strategy, :fail_fast),
timeout: Map.get(attrs, :timeout),
metadata: Map.get(attrs, :metadata, %{})
}
end
@doc """
Returns the list of valid node types.
"""
@spec valid_types() :: [node_type()]
def valid_types, do: @valid_types
end