Skip to main content
GoalPipeline is a pipeline of two agents: an executor produces a result, a verifier judges it against the goal, and a refusal goes back to the executor with its reason, until the work passes or the attempts run out. The loop runs like this:
The verifier is an ordinary Agent, not a special kind of object. Its verdict comes back as structured output, so a check that has to read files, run commands or ask a person goes through exactly the machinery the executor does.

Running a Pipeline

The example below has two agents collaborate on a programming task: the executor writes the code, the verifier checks it.
goal_pipeline.py

Constructor Arguments

GoalPipeline takes the following arguments:
The goal is not given at construction. It arrives with the task: the first message the pipeline receives is both what the executor is asked to do and what the verifier judges against.

Verification and Retries

Both agents hand their results to the pipeline as structured output: message reaches the executor verbatim, so it has to say what is missing rather than that something is. A full round goes:
1

The executor works

The executor takes the task, leaves its output in the shared workspace, and hands back a report.
2

The verifier judges

The verifier checks the output against the goal and returns result and message.
3

Passing ends the run

On pass or impossible the pipeline finishes and the event stream closes.
4

A refusal goes back

message is wrapped in a reminder and handed to the executor, which starts the round again.
Two kinds of retry are counted differently, and only the first spends an attempt: The second is a malfunction rather than a judgement; charging it would quietly cost the executor attempts. Once max_iters is reached the pipeline stops, the stream ends, and the last message stays in the verifier’s conversation.

Interruption and Resuming

When either agent stops for tool authorization, reply_stream simply ends: no coroutine pinned, no lock held, no polling. Feed the result back in to carry on:
Resuming after an interruption
Resuming does not require saying who to resume. The event carries the reply_id of whichever agent parked, and the pipeline routes the result there. reply_stream accepts these inputs:
The attempt budget lives on the pipeline instance rather than inside reply_stream, so resuming does not hand the run a fresh set of attempts.

Debugging in the Terminal

The quickest way to watch a pipeline is to hand the whole thing to the console, with no adapter code:
Running a pipeline in the terminal
Once it is running, the parts divide up like this: Answering an authorization prompt with Ctrl+D sends a UserInterruptEvent: the parked agent closes its pending tool calls and the pipeline ends with it. An interruption abandons the run rather than continuing it.