Skip to content

Reasoning Algorithms as Versioned Graph Topologies

Concept: CONCEPT:AU-ORCH.planning.reasoning-graph-topologies — CoT, self-consistent CoT, ToT (BFS/DFS), GoT, ReAct, and RAP are graph topologies (node contracts + edge/routing functions) over ONE shared state, not separate agent frameworks.

Related: CONCEPT:AU-ORCH.planning.rap-mcts-backpropagation (real MCTS backprop) · CONCEPT:AU-AHE.evaluation.reasoning-topology-benchmark (the unified benchmark harness) · CONCEPT:AU-ORCH.routing.topology-escalation-policy (cheapest-adequate-first router) · agent_utilities/graph/reasoning/.

Why

"Graph Engineering: A Unified Framework for Language Agent System Design" (arXiv:2505.24354) observes that CoT / ToT / GoT / ReAct / RAP are usually implemented as separate, incompatible frameworks, when they are actually the same primitive — a DAG of typed thought nodes, a set of edge/routing functions that drive dynamic branching and loops, and a shared state store that carries frontier/visited/candidate/MCTS statistics (including tree-search backpropagation). agent_utilities/graph/reasoning/ ports that thesis: one ReasoningState substrate (state.py), six topology implementations that read/write it, a versioned/content-addressed topology resource (topology.py), a budget+termination contract every topology obeys (budgets.py), a unified benchmark harness (benchmark.py), and a cost-aware escalation policy (policy.py).

Prior art (survey — don't duplicate)

Before this package, none of the six topologies existed as a named, reusable resource. The closest existing building blocks, reused rather than reimplemented:

Existing capability Reused by
agent_utilities.graph.test_time_diversity (VPO diverse fan-out + MMR best-of-k) .cot's self-consistent variant (diversity-aware pruning seam)
agent_utilities.harness.graph_search_evolution.GraphSearchEvolver (real UCT + backprop MCTS for code/ML-algorithm evolution search, MLEvolve arXiv:2606.06473) .rap's algorithmic shape (UCT selection + full-path backprop), generalized off the code-evolution specifics
agent_utilities.security.execution_stability_engine.DoomLoopDetector .react's grounding/termination detection
agent_utilities.graph.reactive.budget.BudgetGuard (time/token/cost) .budgets.BudgetTracker (adds loop-count + tool-call-count, the two axes it doesn't cover)
agent_utilities.graph.topology_engine.TopologyEngine (KG-tracked team-topology resource + EMA outcome update) .topology's register_topology/record_topology_outcome (same pattern, reasoning-topology resource kind)
agent_utilities.models.knowledge_graph.ArtifactVersionNode (content-addressed, versioned, evolvable artifact — the same contract skills/prompts/specs already use) ReasoningTopologyVersionNode, the KG-modeled topology resource

The shared-state thesis

flowchart TB
    subgraph State["ReasoningState (one shared substrate)"]
        Nodes["nodes: dict[id, ThoughtNode]<br/>(DAG — multi-parent = merge provenance)"]
        Frontier["frontier / visited<br/>(ToT BFS/DFS)"]
        MCTS["visits / total_reward<br/>(RAP backprop targets)"]
        Cand["candidates: CandidateVote<br/>(self-consistency vote)"]
        Tools["tool_calls: ToolCallRecord<br/>(ReAct grounding/retry)"]
        Rationale["rationale_summary<br/>(CoT, append-only, summary-only)"]
    end

    CoT["cot.py — linear generate chain"] --> State
    SC["cot.py — self-consistent fan-out + vote"] --> State
    ToT["tot.py — generate/score/frontier/prune (BFS or DFS)"] --> State
    GoT["got.py — generate/transform/aggregate/refine DAG"] --> State
    ReAct["react.py — thought/action/observation loop"] --> State
    RAP["rap.py — select/expand/simulate/backpropagate (real MCTS)"] --> State

    State --> Budget["budgets.BudgetTracker<br/>loop/tool/token/cost/time"]
    Budget -->|exhausted| Proof["TerminationProof<br/>(degraded=True, never a fabricated success)"]
    State -->|goal / converged| Proof

    Proof --> Benchmark["benchmark.BenchmarkHarness<br/>accuracy/pass-rate/grounding/tokens/<br/>wall-time/tool-calls/cache-reuse/cost/reliability"]
    Benchmark --> Policy["policy.EscalationPolicy<br/>cheapest adequate → escalate on<br/>measured low-confidence/unreliability"]
    Policy -->|chooses next run's topology| CoT

The versioned topology resource

Each topology module publishes exactly one TopologySpec (topology.py): a content-addressed digest over its name/version/node-contracts/state-schema/budgets/termination-conditions, a topology_id (topology:<name>:<digest>), and to_node() — the same content-addressed, versioned-artifact contract this repo already uses for skills and specs (ArtifactVersionNode → ReasoningTopologyVersionNode). register_topology/ record_topology_outcome write/update it in the KG with the exact best-effort, engine-optional pattern TopologyEngine already uses for team-composition topologies (an add_node at registration, an EMA reward update after each run) — reused, not duplicated. Checkpoint (memento) semantics are uniform across all six: ReasoningState.to_memento() / from_memento() serializes the whole run, so a budget-stopped run resumes exactly where it stopped rather than losing partial progress.

RAP: real backpropagation, not an approximation

rap.py's _backpropagate walks the full parent chain (ReasoningState.path_to_root) from the simulated node to the root, incrementing visits and total_reward on every ancestor. A common "simplified" MCTS/RAP port credits only the immediate parent (or only the leaf), which silently breaks UCT above the first level — a deep, high-value line never changes selection at the root or mid-tree, and the search degenerates into flat rollouts. tests/unit/graph/reasoning/test_rap.py:: test_backpropagation_updates_every_ancestor builds a 3-level chain, backpropagates a reward from the depth-3 leaf, and asserts every one of the four ancestors (leaf → root) was credited — not just the immediate parent.

Truthfulness contract

Every run_* entry point returns (ReasoningState, TerminationProof). TerminationProof. as_report() reports success as False whenever degraded=True — a budget-halted, truncated run is never reported as a clean success, and the partial ReasoningState is always returned rather than discarded. BenchmarkHarness.stats().accuracy and .reliability apply the same rule at the aggregate level: a degraded-but-correct run still counts toward the looser pass_rate but never toward accuracy/reliability.

Deferred

See reports/deferred/waves1-5-gate.md (D-W15-1..3) for the recorded dependency on the parallel budget/repair lane and the not-yet-built MCP/REST live entrypoint for this package.