# `PhoenixAI.Pipeline`
[🔗](https://github.com/franciscpd/phoenix-ai/blob/main/lib/phoenix_ai/pipeline.ex#L1)

Sequential railway pipeline.

Steps execute in order. Each step receives the previous step's unwrapped
`{:ok, value}` result. The pipeline halts on the first `{:error, reason}`.

## Ad-hoc usage

    Pipeline.run([
      fn query -> AI.chat([msg(query)], provider: :openai) end,
      fn %Response{content: text} -> String.upcase(text) end
    ], "Hello")

## DSL usage

    defmodule MyPipeline do
      use PhoenixAI.Pipeline

      step :search do
        fn query -> AI.chat([msg(query)], provider: :openai) end
      end
    end

    MyPipeline.run("Hello")

# `step`

```elixir
@type step() :: (term() -&gt; {:ok, term()} | {:error, term()} | term())
```

# `run`

```elixir
@spec run([step()], term(), keyword()) :: {:ok, term()} | {:error, term()}
```

Executes a list of step functions sequentially.

Each step receives the unwrapped value from the previous step's `{:ok, value}`.
Halts on first `{:error, reason}`. Raw (non-tuple) returns are auto-wrapped
in `{:ok, value}`.

# `step`
*macro* 

Defines a named step in a pipeline module.

The block must return a function `fn input -> {:ok, result} | {:error, reason} | term() end`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
