loop · A Cyclic Workflow (guess-the-number)
How a workflow graph forms a cycle: two executors feed each other until one yields an output — the workflow analogue of a while-loop.
What this lesson demonstrates
A workflow graph is not a DAG — edges may form a cycle. Here two executors, GuessNumber and Judge, are wired to feed each other: GuessNumber → Judge → GuessNumber. Judge compares each guess against a hidden target and sends Above/Below back; GuessNumber binary-searches the range in response. The loop runs until Judge finds the target and yields an output, which ends the run.
Where human_in_the_loop_basic closed its cycle through a human at a RequestPort, this lesson closes the cycle between two pure executors — the state and the exit condition both live in code.
The real code
The cycle is just two edges; the second one closes the loop:
return workflow.NewBuilder(guess).
AddEdge(guess, judge). // a guess flows forward to the judge
AddEdge(judge, guess). // the judge's verdict flows back — this edge closes the loop
WithOutputFrom(judge). // the run ends when Judge yields its output
Build()
GuessNumber keeps a mutable [lower, upper] range in its closure and sends the midpoint each turn; Judge counts tries and either ctx.YieldOutput(...) (exit) or ctx.SendMessage("", Below/Above) (keep looping).
What to notice
- Convergence is the only exit. Nothing bounds the loop except Judge yielding an output. A buggy predicate or a guess that never narrows would spin forever — this is the workflow you must reason about for termination, not just wiring.
- State lives in the executor closure.
lower, upper := low, highandvar tries intare captured per node. That’s why each executor also declares aResetFuncin itsExtendblock — so the range and counter can be restored if the workflow is reset or reused. - Protocol is declared, not inferred. Each executor’s
Extendblock callsConfigureProtocol—rb.SendsMessageType(...),rb.YieldsOutputType(...)— so the builder knowsGuessNumbersends anintandJudgesends aNumberSignaland yields astring. RunStreamingseeds the cycle. The initialInitmessage kicksGuessNumber; from then on the two trade messages until Judge exits.
How it maps to the Agent Framework
In the Microsoft Agent Framework Go SDK, cyclic workflows are how you build iterative refinement — a writer/critic loop, a plan/execute/replan agent, retry-until-valid. The framework doesn’t forbid cycles the way a strict DAG engine would; it relies on an executor eventually calling YieldOutput. This binary-search game is the smallest self-contained cycle, so it’s the right place to internalize “the loop ends when someone yields” before you wrap agents in it. No model or credentials required.
Run it
go run ./tutorial/03-workflows/loop
Fully offline — no model, no provider, pure in-process orchestration. The test both asserts the two-edge cycle and runs it end-to-end.
Next: observability · Workflow as an Agent