Skip to content

docs: proposal — loops and iteration in Open Agent Spec#93

Draft
sgriffiths wants to merge 4 commits into
mainfrom
docs/proposal-loops
Draft

docs: proposal — loops and iteration in Open Agent Spec#93
sgriffiths wants to merge 4 commits into
mainfrom
docs/proposal-loops

Conversation

@sgriffiths

Copy link
Copy Markdown
Contributor

What changed

Adds docs/proposals/loops.md — a position doc on whether/how OA should incorporate "loops", following the same decide-the-boundary format as markdown-interop.md. Docs-only; no schema or runtime change. Opening as a draft to get the direction agreed before any code.

The core argument

"Add loops to OA" is really three different features wearing one word, and they land very differently against OA's boundaries (no orchestration, no conditionals, depends_on acyclicity):

Loop Termination Verdict
A. Tool-calling loop Bounded cap, structured error Already runs (_MAX_TOOL_ITERATIONS) — just surface it
B. Bounded map / fan-out Fixed by array length + ceiling 🟡 Compatible if bounded — own design
C. Conditional / until-good Runtime predicate 🔴 Out — belongs above the spec (BCE)

Bright line proposed: OA iterates over data it can see before the first token; it never loops on a condition it can only evaluate at runtime.

That line is drawn on determinism of termination, and it stays consistent with the deterministic-pipeline framing already in the 1.6 spec (§7 / §7.3 pre-flight checks) and the markdown-interop precedent.

Recommendations in the doc

  • A (near-term, small): promote the hardcoded tool-iteration cap to a declared, schema-validated intelligence.config.max_iterations. Names existing behaviour; no new semantics.
  • B (real design work): a bounded map — run task T per array element, ordered results, fail-closed by default, with a validated fan-out ceiling enforced as a pre-flight error (§7). Ships as its own proposal + schema PR if this direction is accepted.
  • C (hold the line): conditional/until-good loops stay out of the schema; the supported pattern is "the orchestrator loops and calls an OA spec each pass" — a BCE/caller concern, keeping OA the deterministic unit.

For discussion

  • Is the A/B/C split the right cut, and is "determinism of termination" the right dividing principle?
  • Should B (bounded map) proceed to its own design proposal, or stay out for now?
  • Anything in the "explicitly refuse" list that's too strict / not strict enough?

Type of change

  • Documentation

Checklist

  • Self-review completed
  • No schema/runtime change (proposal only)

Adds docs/proposals/loops.md. Frames "add loops to OA" as three distinct
features (tool-calling loop / bounded map / conditional-until-good) and
draws the boundary by determinism of termination:

- A. tool-calling loop — already runs, bounded; recommend surfacing the
  existing cap as a declared max_iterations field.
- B. bounded map / fan-out — compatible if bounded (ordered results,
  fail-closed, validated ceiling); gets its own schema proposal.
- C. conditional / until-good — refused in-spec; belongs to the
  orchestrator (BCE) that calls OA specs each pass.

Bright line: OA iterates over data it can see before the first token; it
never loops on a condition only knowable at runtime. Consistent with the
markdown-interop boundary, no-orchestration, and depends_on acyclicity.

Status: Proposed — docs-only; any schema change is a separate follow-up.
@vercel

vercel Bot commented Jul 23, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
open-agent-spec Ready Ready Preview, Comment Jul 23, 2026 11:24pm

Request Review

Incorporates maintainer review on the loops proposal:

- Replace the private-constant reference with normative language (the
  tool-call loop and its mandatory iteration cap are §12.3; reference
  implementation uses 10). Keeps the doc runtime-agnostic.
- Recommendation A now flags the two schema-PR decisions: field placement
  (tool loops are per-task, intelligence.config is spec-global) and naming
  (prefer max_tool_iterations — examples/multi-agent/loop.py already uses
  max_iterations for an orchestration loop).
- B: add a paragraph clarifying bounded map is a NEW construct (a single
  DAG node iterating over data), not a loosening of §7.3's parallel-fan-out
  refusal, which is scoped to depends_on. Add a cost-vs-count note: the
  ceiling bounds iteration count, not per-element tool-loop cost.
- C: tie to §7.3's existing permanent exclusions (conditional execution,
  loop control, retry semantics) and point at examples/multi-agent/loop.py
  as the in-repo orchestrator-loops pattern.
- Refuse list: add retry-with-backoff and run-until-confidence explicitly.
- A: name the working field (max_tool_iterations) once inline for
  scan-ability, naming still formally deferred to the schema PR.
- Future: note parallel fan-out would still be capped by the same fan-out
  ceiling and must preserve input order — preempts "parallel = unbounded".
- How we manage it: record two on-acceptance follow-ups — a README /
  AGENTS.md pointer when this moves to Accepted, and npm-runtime parity +
  a conformance case in the schema PR for A. Both are later PRs.

@aswhitehouse aswhitehouse left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strong proposal — same quality bar as the markdown-interop write-up, and the bright line is the right one:

OA iterates over data it can see before the first token. It never loops on a condition it can only evaluate at runtime.

A / B / C sorting by determinism of termination is teachable and defensible. Naming the tool-call loop OA already has (A), fencing bounded map as its own construct rather than loosening depends_on (B), and refusing until-good with a pointer at examples/multi-agent/loop.py (C) all land correctly against every boundary we've drawn.

Agree, ship as Proposed

  • Docs-only, status Proposed, schema deferred — right shape for a direction-setting PR.
  • max_tool_iterations naming (vs bare max_iterations) is a good catch given the orchestration loop in loop.py.
  • "Bounding count is not bounding cost" is an important honesty note; keep that when B is designed.
  • Fail-closed default for map failures matches OA's posture.
  • C joining "no orchestration" / "no skills task type" as a cited boundary is exactly how we should manage it.

Tighten before / as Accepted

1. Clarify "before the first token" for B when the array is upstream-produced.
If the map input arrives via depends_on merge from an LLM task, its length is not known at chain entry — only after that dep completes. The fan-out ceiling is still enforceable before the mapped task spends tokens, but it is not a §7.1 stage-1–5 static error for the whole chain. Spell that out so nobody reads "statically detectable" as "knowable from the YAML alone". Suggested gloss: ceiling is validated against the resolved input at the start of the mapped task (after merge), before any per-element invocation.

2. A's "npm parity" obligation is larger than a field.
The npm runtime still refuses tools: (UNSUPPORTED_FEATURE). A schema PR that adds max_tool_iterations and requires npm parity either needs to land tools on npm first, or to state that A is capability-scoped (tools) — declare it, enforce it where tools exist, and keep the honesty rule for runtimes that don't. Don't let the follow-up paint us into "field exists in schema, only Python honours it".

3. B canary to watch.
The slope from bounded map → filter/map → map-reduce → conditional fan-out is the same slope depends_on had toward orchestration. When the B design PR arrives, the hard wall should stay: no predicates on which elements run, no early-exit based on element output, no reduce-as-control-flow. Collect-partial as explicit opt-in (as you have) is the right default posture.

4. Tiny: on Proposed → Accepted, yes — README blurb + AGENTS.md pointer, same as markdown-interop. Not this PR.

No blocking changes for a docs-only Proposed document. Happy to mark Accepted once you've weighed (1) and (2), or leave them as notes for the follow-up PRs — either works.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants