Skip to main content
When a task has to pass through several milestones in a fixed order, and each milestone must be accepted before the next one starts, developers can write it as a standard operating procedure (SOP) with the agentscope.sop module. The procedure says which steps exist and what each must prove; how a step gets there is left to the agent doing it. The module is made of the following parts: Compared with the Goal Pipeline, an SOP is a sequence of ordered milestones, each with its own verifier and attempt budget, and its run state can be written to disk and picked up again any time later.
The SOP module is experimental, and its interfaces may change in later releases.
Two questions tell whether something should be an SOP. Without running it, can you say how many steps there are and who does each one? If not, it is not an SOP. Does someone actually check the step when it finishes? If not, it should not be a step of its own.

Define a Procedure

The following example defines a two-step procedure: write an outline that a reviewer agent accepts, then write the article from that outline:
sop_quickstart.py
SOPStep takes the following arguments: Executors and verifiers only need to satisfy the AgentLike protocol, which Agent does out of the box. Reusing one agent across several steps carries its context through those steps; giving each step its own agent keeps their contexts apart.
Judging belongs to the verifier; do not write it as a step of its own. A refusal sends back the step that was refused. If “check the outline” were its own step, a refusal would only rerun the check, which reaches the same conclusion every time until the attempts run out.

Advance Steps

The engine advances through the steps in order and skips those already completed. Each attempt at a step has two halves, work and judgement:
1

The executor works

The executor receives the step’s description and what the previous step handed over. When done, it returns a handover through structured output: the account the following steps will read.
2

The verifier judges

The verifier sees the step’s description, the input the step received, and the executor’s handover, and answers with passed and message through structured output.
3

Pass and move on

A passed step is marked completed, and its handover becomes the next step’s input.
4

Refuse and retry

A refusal clears the handover and sends message back to the executor, together with which attempt this is. Once refusals reach max_attempts, the step and the whole run are marked failed.
Only handovers cross between steps; files and conversations do not. The first step receives the run’s input, and every later step receives the previous step’s handover wrapped in a <handover from="previous step name"> tag. An executor should therefore write its handover for someone who has seen none of its work. The following cases also count as a refusal and spend max_attempts in the same way: While running, the engine emits a CustomEvent before and after each attempt, which developers can use to show progress:

Check the Run Phase

Steps and the run as a whole share one set of phases, SOPPhase: The run’s phase is derived from its steps, by these rules in order: PENDING when no step has started, FAILED when any step failed, COMPLETED when every step completed, AWAITING when any step is parked, and RUNNING otherwise. Read it from engine.phase or engine.state.phase.

Park and Resume

When an executor or verifier stops on a tool confirmation or an external execution, the step enters AWAITING and reply_stream ends, holding no coroutine and no lock. Once developers have the answer, calling reply_stream again carries on:
Resume after parking
reply_stream accepts the following inputs:

Persist the Run State

SOPRunState is a Pydantic model holding the run’s inputs and each step’s phase, handover, and verdicts. Developers can store it and rebuild the engine at any later time, even in another process, to carry on:
Save and restore the run state
SOPRunState covers only the procedure’s own state. Executors and verifiers are Agents with their own context, which developers save and restore the way they would for any agent, before building the SOP from them. If steps were added or removed after the state was saved, the step count no longer matches and SOPEngine raises ValueError.

Customize Steps

When a step does not fit the “one works, one judges” shape, developers can subclass SOPStepBase and implement reply_stream. The engine never looks inside a step; it only requires that one call is one attempt, and that the attempt either parks or records a verdict on the state it was handed:
Custom step
SOPStepBase provides the following interfaces:

Debug in the Terminal

SOPEngine satisfies the pipeline PipelineProtocol, so it can be handed to the terminal UI just like an agent, with tool confirmations and interruptions handled by the UI:
Run an SOP in the terminal

Further Reading

SOP Service

Store procedures in the agent service, start runs, and have people sign off on steps online.

Goal Pipeline

When there is a single goal, close in on it with an executor and verifier loop.