Skip to main content
Fleet Reasoner (qlaw-dspy) is the Qlaw reasoning engine re-implemented on DSPy 3.3.0 as a compilable, evaluable program. Qlaw’s agents become typed dspy.Signature + dspy.Module lenses over a pydantic graph state. The reasoning cycle is the forward() of a single ReasoningEngine module, and the Co-Pilot and Enrich researcher are dspy.ReActV2 tool agents. Because everything is a DSPy module, every layer is optimizable (MIPROv2 / BootstrapFewShot / GEPA), evaluable (dspy.Evaluate), and Refine-validated.

Three tiers

Key facts from DSPy 3.3.0

  • dspy.ReActV2 — native tool calling, reserved submit tool, parallel tool calls, and prompt-cache reuse. Used for the Co-Pilot and Enrich agents.
  • dspy.Flex — GEPA can discover the engine’s structure itself, as an optional upgrade path for the loop.
  • Assertions retired. dspy.Assert, Suggest, constrain, and SoftAssert are removed in 3.x. Validation is done through dspy.Refine.
  • One model everywhere: deepseek-v4-flash addressed as openai/<model> via the OpenAI-compatible endpoint (OPENAI_BASE_URL / OPENAI_API_KEY / OPENAI_MODEL).
  • API conventions: metric on the optimizer constructor, trainset= keyword-only, module(...) not module.forward(...), super().__init__() mandatory.
  • 3.3.0 breaking changes handled: numpy optional (dspy[numpy]), GEPA result shapes, dspy.LMError normalization.

Layout

  • qlaw/graph.py — pure pydantic graph state (GraphState, NodeContext, NodeBatch, lens DTOs). apply() is deterministic — the LM never mutates the graph.
  • qlaw/signatures.py — 10 typed signatures (7 lenses + router, termination, chat).
  • qlaw/lenses/ — one dspy.Module per agent, Refine-validated via the reward functions in _validators.py.
  • qlaw/router.pyLensRouter, Terminator, and the deterministic default_lens_for() fallback.
  • qlaw/engine.pyReasoningEngine + ReasoningLoop + SeedFlow; lens_batch() maps every lens output to a NodeBatch.
  • qlaw/chat.py — multi-turn Qlaw chat: stateful GraphSession, make_chat_tools(), SSE status provider.
  • qlaw/tools.py — pluggable search tool (a NotImplementedError stub; inject a real backend via DI).
  • qlaw/config.py — one model across all tiers: deepseek_flash() + startup configure_research().
  • qlaw/datasets.py — per-lens and engine trainsets and devsets (30 examples per lens, train/val/test split).
  • qlaw/metrics.py — taxonomy adherence, node validity, conciseness, novelty, coverage, grounding.
  • qlaw/optimize.py — compile pipeline (compile_lens / compile_engine / load_program).
  • qlaw/evaluate.pydspy.Evaluate harness, writes eval_results.json.
  • qlaw/omni.py — GEPA “omni” meta-optimizer composition (optimize_omni, optimize_parallel, …).
  • qlaw/serve.py — FastAPI + SSE server.
  • scripts/ — CLIs: compile.py, evaluate.py, optimize_lenses.py (plus the optimize wrapper).
  • web/ — tldraw frontend (React 19 + Tailwind 4).

Setup

Nothing auto-loads .env. Run LM-hitting commands with uv run --env-file .env. One model is used across all tiers: deepseek-v4-flash via the OpenAI-compatible endpoint. Any OpenAI-compatible model id works via OPENAI_MODEL.

Commands

For bounded GEPA prompt optimization of the core lenses (default strategy --strategy omni — explore all engines on a small slice, continue from the validation winner), use the wrapper:
The wrapper installs the unreleased gepa OA API at run time (DSPy pins gepa 0.1.1). By default the gepa engine’s proposals and evaluation both use the .env model — pass --codex-model to switch to the native Codex agent proposer.

API

  • POST /seed — prompt → graph with ROOT plus first decomposition layer.
  • POST /engine — one reasoning step: (graph, active_node_id, action) → expanded graph.
  • POST /chat/stream — SSE: status and tool events, then done with the answer plus post-chat graph.
  • GET /config — the active model id (no credentials) for the web client.
Two DSPy 3.3.0 gotchas: /engine outputs use Prediction.toDict() (no model_dump() in DSPy 3.3.0), and max_depth is a constructor argument, not a request field.

Web frontend

The tldraw canvas sits over the engine: web/src/state/graphStore.ts (zustand) holds the canonical GraphState, and web/src/canvas/sync.ts is the only writer of qlaw shapes and arrows. web/src/api/client.ts is the fetch + SSE client.
Set VITE_API_BASE in web/.env.local if the API port differs from http://localhost:8000.

Testing

The stub-LM strategy needs no API key: tests/helpers.py provides a StubLM that returns canned JSON responses, proving signatures coerce, Refine loops, and ReActV2 submits. Build responses with field_response(...) (ChatAdapter format). Every output field must be present, including reasoning (ChainOfThought adds it).

Learn more

Quickstart

Install with uv, run the FastAPI service, and open the tldraw frontend.

Architecture

The three tiers and the DSPy 3.3.0 primitives that power them.

Lenses

Seven optimizable modules with Refine-validated output contracts.

Engine and router

The reasoning cycle composed as one dspy.Module.

Chat and tools

Multi-turn ReActV2 Co-Pilot with lenses as tools.

API and streaming

FastAPI endpoints, SSE frames, and error mapping.

Optimization and evaluation

Compile pipeline, trainsets, metrics, and bounded GEPA.

Gotchas

DSPy 3.3.0 pitfalls that will cost you time.
Source: github.com/Qredence/fleet-reasoner.
Last modified on August 9, 2026