Skip to content

Length recovery

Length recovery is BMO’s same-run continuation path for three pressure cases:

  • the model stops with MaxOutputTokens
  • prompt-budget preflight says the next turn will not fit
  • the provider returns a context-length error

When recovery is enabled, BMO summarizes the current session state and queues a bounded continuation instead of letting the run stop on length alone. The runtime records each attempt as metadata-only recovery evidence so operators can tell whether recovery queued another turn, hit the continuation cap, failed to summarize, or was suppressed by config or cancellation.

flowchart TD
    trigger["Length pressure"] --> lane{"Shared recovery lane"}
    lane --> summary["Summarize or compact current context"]
    summary --> outcome{"Terminal outcome"}
    outcome --> queued["continuation_queued"]
    outcome --> capped["cap_reached"]
    outcome --> failed["summarize_failed"]
    outcome --> suppressed["suppressed or cancel_suppressed"]

All three triggers use the same recovery lane:

TriggerMeaning
max_output_tokensThe provider stopped because the response hit its output cap.
prompt_budget_preflight_exceededBMO predicted the next turn would overflow before sending it.
context_length_exceededThe provider rejected the request for context length.

The recovery policy is intentionally bounded. BMO does not keep queuing continuations forever; it stops at the configured continuation cap and records that outcome explicitly.

Each recovery attempt is captured as one bounded lengthrecovery.Episode:

  • wall-clock time
  • hashed session identifier
  • trigger
  • continuation number and continuation cap
  • summarization engine (streaming_compaction, legacy_summarize, or none)
  • terminal outcome
  • optional bounded reason (summarization_disabled, context_canceled, context_deadline_exceeded)

The episode record is strictly metadata-only. It never stores prompt text, summary text, tool payloads, raw provider error bodies, or full session IDs.

OutcomeMeaning
continuation_queuedRecovery succeeded and BMO queued the next continuation turn.
cap_reachedRecovery would have continued, but the configured continuation cap was already reached.
summarize_failedThe summarization step failed, so no continuation was queued.
suppressedRecovery was intentionally skipped or a deadline suppressed queueing before another continuation could be added.
cancel_suppressedA cancellation or interruption won before BMO could queue the continuation.

When streaming compaction is enabled, the recorded engine is streaming_compaction. Otherwise BMO records legacy_summarize. Suppressed attempts that never summarize record none.

Every operator surface reads the same shared status family:

SurfacePurpose
bmo config show-length-recoveryConfig-first summary of the recovery lane.
bmo config show-length-recovery --format=jsonSame snapshot as machine-parseable JSON.
/length-recovery (aliases /lr, /length_recovery)In-process operator report with current config, ring stats, and latest recorded episode.
GET /v1/length-recovery/statusAuthenticated HTTP route for the shared JSON snapshot.
get_length_recovery_statusNative agent tool exposing the same status family.
bmo_get_length_recovery_statusMCP twin of the native tool.

The snapshot includes:

  • summarization enablement
  • continuation cap
  • whether streaming compaction is enabled
  • custom continuation-message or template-path overrides
  • recent-evidence scope (process_local)
  • recent recovery ring capacity, count, saturation, and episode tail

Detached CLI reads stay truthful about authority. They report local config and defaults, but they do not pretend to replay another process’s in-memory recent-episode ring.

The TUI sidebar exposes the latest live runtime outcome as a short label:

  • queued
  • capped
  • failed
  • cancelled
  • suppressed

The full /length-recovery report renders the same shared status snapshot used by the agent tool, MCP tool, and HTTP route.

Length recovery keeps the existing structured log vocabulary:

  • length_recovery.fired
  • length_recovery.action

The recent episode ring complements those logs. Use the logs when you want the chronological event stream; use the status family when you want the bounded current posture plus the newest process-local recovery outcomes in one call.

  • This feature does not redesign summarization or compaction policy.
  • It does not persist raw summaries or transcript fragments in the recovery ring.
  • It does not create a second recovery route family; the shared length_recovery status family remains the canonical inspect surface.
  • Prompt-budget preflight overflow may still interact with broader context-pressure handling, but the length-recovery status family only reports the bounded summarize-and-continue lane described here.