Add LLM-backed planning agent (A4/A11/A13) — step 5a #11

Merged
dongar merged 3 commits from llm-planning into main 2026-09-07 16:15:47 +00:00
3 Commits
Author SHA1 Message Date
dongarandClaude Opus 5 fb35ca774d Trigger CI to pick up the NISSE_LIVE_PLANNER_MODEL secret
CI / checks (push) Successful in 20s
CI / checks (pull_request) Successful in 18s
Empty commit: Gitea 1.27 exposes no rerun API endpoint, and Actions
secrets are read at run start, so a new run is needed to exercise the
live planning test.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 16:02:56 +00:00
dongarandClaude Opus 5 6c17f2bf57 Enable the live planning test against claude-haiku-4-5
CI / checks (push) Successful in 13s
CI / checks (pull_request) Successful in 12s
The virtual key now reaches a Haiku-class route, which holds the
tool-call contract llama3.2 could not: a real planning turn returns a
well-formed submit_plan call with an explicit, low-inference plan.

Wires NISSE_LIVE_PLANNER_MODEL through the CI workflow (add the
matching Actions secret to run it there) and records the finding in
.env.example.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 16:01:18 +00:00
dongarandClaude Opus 5 cf85648719 Add LLM-backed planning agent (A4/A11/A13) — step 5a
CI / checks (push) Successful in 12s
CI / checks (pull_request) Successful in 11s
- planner.py: LLMPlanningAgent offers exactly two tools, submit_plan
  and ask_human, so gating stays structural at the tool layer; no
  proceed tool exists. System prompt requires explicit, low-inference
  plans because a weaker model executes them (A13)
- Model output is appended to the canonical log as it arrives, before
  being interpreted, so a crash mid-planning leaves a truthful
  transcript
- A bad turn (prose instead of a tool call, malformed arguments, or a
  failed call) retries once, then raises PlanningError; the
  orchestrator gates to AWAIT_INPUT rather than inventing a plan
- Orchestrator: appends every operator message, plan_submitted, and
  gate_opened to the transcript, so re-planning sees rejection
  feedback as conversation rather than out-of-band parameters; pins
  the A11 role mapping at task start
- llm.py: non-JSON or non-object tool arguments now raise LLMError
  instead of escaping as JSONDecodeError — observed from llama3.2,
  which emits truncated argument strings
- Live planning test is opt-in on NISSE_LIVE_PLANNER_MODEL: planning
  escalates unconditionally (A12) and the local model does not hold
  the tool-call contract, so it awaits a frontier route

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 14:47:12 +00:00