Skip to content

v0.3.0 — LLM-driven replanning on step failure

Choose a tag to compare

@a-radwan-20 a-radwan-20 released this 01 Jun 09:00
· 45 commits to main since this release

Highlights

Missions can now survive step failures. Configure a Replanner on
your Supervisor and a failing step triggers a recovery prompt instead
of terminating the whole mission. The default missionruntime
LLM-backed replanner calls your existing model adapter with a strict
JSON-output prompt, parses a replacement step sequence, persists it,
and the supervisor continues from there. Up to MaxReplans attempts
per mission (default 3).

This is categorically new behaviour — v0.2.x missions had exactly one
shot at every step. Existing missions without a configured Replanner
keep the v0.2.x fail-fast behaviour unchanged.

Added — LLM-driven replanning on step failure

supervisor.Replanner interface + Supervisor.Replanner / MaxReplans fields

When a step fails in sequential mode, the supervisor consults the
configured Replanner for a replacement step sequence and continues
from there instead of failing the mission. Each mission may be
replanned up to MaxReplans times (default 3).

The Replanner can return ErrReplanRejected to opt out of recovery
for a specific failure (mission fails immediately, no replan attempt
consumed). Any other non-nil error is treated as an implementation
failure and surfaced in the mission.failed reason for diagnostics.

Existing missions without a configured Replanner keep the v0.2.x
fail-fast behaviour — purely additive.

supervisor.NoopReplanner

A Replanner that always returns ErrReplanRejected. Same semantics as
leaving Replanner nil; useful in tests and as documentation.

mission.Manager.Replan(missionID, fromStepID, newSteps, reason)

Persistence-layer replanning. Appends replacement steps after the
failed one, marks every still-unstarted original step that came after
as cancelled (error: "superseded by replan"), rewrites
Mission.PlanJSON to the union, and emits one mission.replanned
event with payload {from_step_id, new_step_count, superseded_step_ids, reason}.

The failed step itself stays in state=failed for the audit log —
replanning never rewrites history. Plans set with
SetPlanParallel keep their parallel=true flag across replans.

missionruntime.NewLLMReplanner(LLMReplannerConfig)

An LLM-backed supervisor.Replanner. Calls a configured
agent.ModelAdapter directly with a strict JSON-output prompt — no
tools, no nested agent loop, so the cost is one Complete call per
attempt and the output schema is enforceable. Retries on malformed
output up to MaxRetries (default 1) with a corrective user turn
appended each retry. Strips common LLM noise (markdown code fences,
leading/trailing prose) before parsing. Empty steps array →
ErrReplanRejected. Per-call timeout Timeout (default 30s).

missionruntime.Options.Replanner / Options.MaxReplans / Runtime.SetReplanner

The runtime passes the configured Replanner to every spawned
Supervisor. SetReplanner mirrors SetExecutor for hot-swap at app
startup once the model adapter is resolved.

Scope notes

  • Sequential mode only. Parallel dispatch (SetPlanParallel)
    still fails the whole mission on the first step failure; in-flight
    peers complete naturally but no replan attempt is made. Parallel-
    mode replanning has its own design problem (what to do with
    in-flight peers whose results are partway done) and is a separate
    follow-up.
  • Bounded scope. The Replanner sees the goal, completed step
    outputs, the failed step + error, and the remaining unstarted steps.
    It does NOT see the mission's running event log or per-step
    telemetry. A richer audit-trail integration is a clearly-scoped
    follow-up.

Tests

10 new tests across three layers:

  • internal/agent/supervisor (5 tests) — recovery via replacement
    steps, ErrReplanRejected short-circuit, MaxReplans cap
    enforcement, nil Replanner preserves old fail-fast behavior,
    NoopReplanner behaves like no Replanner.
  • internal/mission (4 tests) — full happy-path persistence contract
    including event payload + supersede semantics, state guard,
    ID validation, empty-input validation.
  • internal/agent/missionruntime (6 tests) — clean JSON happy path,
    empty-steps → ErrReplanRejected, malformed-then-recovers retry
    flow, markdown-fenced parses anyway, retries-exhausted error,
    model error propagation.

Full repo go test -race -count=1 ./... passes across all 127
packages.

Compatibility

No breaking changes. The new fields on Supervisor and
missionruntime.Options are optional; zero values preserve v0.2.x
behaviour exactly. No mission schema, plan, or wire-format change.


Full changelog: v0.2.3...v0.3.0