MonitorSteeringInjection posts the trace to POST /monitors/evaluate each step; when a monitor fires, the server returns steering text that the middleware appends to the system message as the [REASONBLOCKS] block.
Earlier SDK versions shipped a local pure-Python monitor suite (
reasonblocks.monitors.suite.evaluate_all, DEFAULT_WEIGHTS). That suite has been removed — monitor evaluation now runs server-side only. If you need a local trajectory signal (for example, to drive TokenSavingMiddleware’s early-exit nudge), supply your own signals_fn; see token saving.How monitor steering works
MonitorSteeringInjection.retrieve posts the current trace to POST /monitors/evaluate with the model identifier, task_profile, and any explicit weight overrides. The server runs the six monitors, applies its injection gate, optionally falls back to an E2 pattern lookup, and returns:
inject is True and the text is new (different from the last firing), the middleware queues a PendingInjection carrying that text plus monitors_fired and failure_type. Per-run guardrails are enforced client-side after the server’s decision:
- Hard cap of 5 monitor injections per run.
- Cooldowns by FSM state: every 2 steps in
SLOW/SKIP, every 3 inNORMAL, every 5 inFAST. - Duplicate suppression: the same intervention text is not re-queued back-to-back.
task_profile argument selects the server-side weight preset (coding, pr_review, qa). See Monitor weights and profiles for the per-profile weight tables and how to override individual weights.
The six monitors
Scores are in[0, 1] where 1 is maximum badness. The weighted sum is the composite; the coding weights are shown below (other profiles redistribute them).
claim_contradiction — self-contradictory conclusions (weight: 0.30)
claim_contradiction — self-contradictory conclusions (weight: 0.30)
Examines what the agent has concluded, not what it called, and flags when its stated claims contradict each other or earlier findings. It carries the highest weight because it’s the only detector that looks at the agent’s reasoning output rather than its tool-call pattern.
semantic_loop — reworded repetition (weight: 0.25)
semantic_loop — reworded repetition (weight: 0.25)
Detects the same action or search repeated with reworded inputs. It is embedding-based, so it recognizes that “session timeout”, “session expiry”, and “session token expiration” are the same loop — something edit-distance similarity would miss.
verification_skip — concluding without checking (weight: 0.15)
verification_skip — concluding without checking (weight: 0.15)
Fires when the agent reaches a conclusion without verifying its work — no test run, no re-read of the file it changed, no confirmation step before declaring done.
cyclic_compression — context churn (weight: 0.10)
cyclic_compression — context churn (weight: 0.10)
Detects repeated re-summarization cycles: the agent compresses its context, re-derives the same state, and churns without making forward progress.
late_sprawl — late scope creep (weight: 0.10)
late_sprawl — late scope creep (weight: 0.10)
Fires when a run that should be converging instead sprawls — new tools and tangents introduced deep into the trajectory.
silent_topic_drift — quiet off-task drift (weight: 0.10)
silent_topic_drift — quiet off-task drift (weight: 0.10)
Detects the agent quietly drifting away from the original task without acknowledging the change of direction.
How monitor results gate E1 retrieval
The middleware consumes the server-side evaluation to gate E1 retrieval, so vector search stays off healthy steps. A two-step lookback keeps the gate open across consecutive at-risk steps.MonitorSteeringInjection is not configured at all, E1 is allowed unconditionally for backward compatibility.

