ALLM.Pipeline.Step behaviour (allm_pipeline v0.1.0)

Copy Markdown View Source

Behavior for pipeline steps with strongly-typed inputs and outputs.

Each step declares its input/output types and produces artifacts. Steps are the atomic units of work in the scraping pipeline.

Input/Output Schemas

Input and output schemas are plain Elixir structs with typespecs. Use @enforce_keys for required fields and @derive Jason.Encoder for output schemas that need JSON serialization.

Example Implementation

defmodule MyStep do
  @behaviour ALLM.Pipeline.Step

  defmodule Input do
    @enforce_keys [:url]
    defstruct [:url]
    @type t :: %__MODULE__{url: String.t()}
  end

  defmodule Output do
    @derive Jason.Encoder
    @enforce_keys [:result]
    defstruct [:result]
    @type t :: %__MODULE__{result: String.t()}
  end

  @impl true
  def step_type, do: :my_step

  @impl true
  def input_schema, do: __MODULE__.Input

  @impl true
  def output_schema, do: __MODULE__.Output

  @impl true
  def execute(_context, %Input{} = input) do
    # Process input and return output
    {:ok, %Output{result: "processed"}}
  end

  # Optional: Store artifacts
  @impl true
  def artifact_content_type, do: "text/html"

  @impl true
  def artifact_content(%Output{html: html}), do: html
end

Summary

Types

What a step receives as its first argument: an ALLM.Pipeline.Context struct.

Callbacks

Optional: extract artifact content from output for storage

Optional: artifact content type for storage (e.g., 'text/html', 'application/json')

Execute the step with validated input, return validated output

The struct module for input (plain Elixir struct with typespecs)

The struct module for output (plain Elixir struct with typespecs)

The step type identifier (e.g., :scrape_committee_list)

Functions

Check if a module implements the Step behavior.

Check if a step module produces artifacts.

Types

context()

@type context() :: ALLM.Pipeline.Context.t()

What a step receives as its first argument: an ALLM.Pipeline.Context struct.

Widened from a bare map in Phase 4 (D5). It always WAS that struct — ALLM.Pipeline.Executor.run_with_step_log/5 has only ever built one — but the type said %{pipeline_run: …, step_log: …}, which is both weaker and, since step_log became nilable for escape-hatch bodies, wrong. A struct is a map, so this narrows nothing at runtime and is dialyzer-visible only.

execute_result()

@type execute_result() :: {:ok, output :: struct()} | {:error, reason :: term()}

Callbacks

artifact_content(output)

(optional)
@callback artifact_content(output :: struct()) :: binary() | nil

Optional: extract artifact content from output for storage

artifact_content_type()

(optional)
@callback artifact_content_type() :: String.t()

Optional: artifact content type for storage (e.g., 'text/html', 'application/json')

execute(context, input)

@callback execute(context(), input :: struct()) :: execute_result()

Execute the step with validated input, return validated output

input_schema()

@callback input_schema() :: module()

The struct module for input (plain Elixir struct with typespecs)

output_schema()

@callback output_schema() :: module()

The struct module for output (plain Elixir struct with typespecs)

step_type()

@callback step_type() :: atom()

The step type identifier (e.g., :scrape_committee_list)

Functions

implements?(module)

@spec implements?(module()) :: boolean()

Check if a module implements the Step behavior.

produces_artifact?(module)

@spec produces_artifact?(module()) :: boolean()

Check if a step module produces artifacts.