std.agent_loop
std.agent_loop provides loop_until — the functional form of Sema’s
declarative loop … until construct. It runs a pure step function over an
immutable state until a done predicate holds or a max_iters bound is reached.
The termination policy is data, not a tangle of breaks.
from std.agent_loop import loop_untilWhy it exists
Section titled “Why it exists”The agentic loop — “keep taking a step until you are confident enough or you run
out of budget” — is the backbone of every agent, and it is usually a long,
hand-rolled while (a _run_deep loop can run ~300 lines). loop_until
distills it to one combinator whose step and done are ordinary lambdas, so the
loop’s structure is fixed and correct while its policy is a parameter.
loop_until
Section titled “loop_until”def loop_until(init: any, max_iters: int, step: fn, done: fn) -> any !{}init is the starting state; step: state -> state advances it; done: state -> bool decides when to stop; max_iters caps the iterations. It returns the final
state (whether it stopped because done held or the cap was hit):
from std.agent_loop import loop_untilfrom std.belief import prior
# Gather evidence until we are confident, or after at most 8 rounds.final = loop_until( prior(), max_iters=8, step=(b => b.bumped(next_observation())), done=(b => b.confidence() > 0.9),)Immutable state keeps it parallel-safe
Section titled “Immutable state keeps it parallel-safe”step and done are pure functions over an immutable state. Sema forbids a
lambda from mutating captured state, which is why std.belief offers bumped
(returns a new belief) alongside update (mutates in place): inside a
loop_until step you thread state functionally rather than mutating it. This
discipline is what keeps the loop safe to reason about and parallelize.
See the exact signature and effect row in the generated std.agent_loop API reference.