Skip to main content
Tier 2 is the whole reasoning cycle composed as one dspy.Module. The current React app drives the loop from App.tsx click handlers; here forward() is the loop:
Every LM call inside forward() is a sub-module, so the entire engine is compilable and evaluable as a unit. With dspy.Flex, even the loop structure itself can be optimized by GEPA.

Router

qlaw/router.py picks the lens for a given node and decides whether to stop the recursion. Both are DSPy modules; a deterministic heuristic covers the case where no router is configured.

Reasoning engine

qlaw/engine.py composes ReasoningEngine + ReasoningLoop + SeedFlow — the whole cycle as one program.
  • SeedFlow — the composition SemanticInterpreter → Decomposer that produces the initial ROOT node plus its first decomposition layer.
  • ReasoningEngine — one step of the cycle: Selection → Routing → Invocation → Expansion → Critic gate. lens_batch() maps every lens output to a NodeBatch.
  • ReasoningLoop — recursion with Terminator. max_depth is a constructor argument, not a request field.
The invariant across all three: the LM never mutates the graph. Every lens emits a NodeBatch; GraphState.apply() does the wiring deterministically.

One reasoning step

ReasoningEngine.forward(graph, active_node_id, action=None) returns a Prediction with:

Recursion depth is a constructor argument

ReasoningLoop.max_depth and ReasoningEngine.max_depth are set at construction time. They are not accepted on the /engine request body. This is one of the DSPy 3.3.0 gotchas — see Gotchas.

Why the engine is optimizable

Because the whole loop is a single dspy.Module:
  • dspy.MIPROv2 or dspy.BootstrapFewShot can compile the engine from full-session trajectories in qlaw/datasets.py::engine_trainset().
  • dspy.Evaluate can score full sessions with any subset of the six metrics in qlaw/metrics.py.
  • dspy.Flex (experimental) starts from a signature, not a composed module. A future signature-first rewrite of the loop can be optimizer-authored inside a CodeInterpreter sandbox.
Last modified on August 9, 2026