planning: fix LLM-output failure modes that killed every plan
Production planning_logs showed three ways a plan silently dies:

1. glm-5.3-flash wraps the whole answer in a structured envelope
   (response:unknown{value:...}<tool_call|>) — the planner only knew the
   gemma4 thought<channel|> artifact, so the wrapped analysis/plan failed
   to parse. The stripper now unwraps response:<type>{value:...} envelopes,
   including a truncated (unbalanced) one.
2. Empty content with spent completion tokens: glm on ollama-cloud puts
   the whole answer in the thinking channel on some calls. Both planning
   phases now fall back to thinking when content is empty; the debug log
   records which channel served (source: content|thinking).
3. phase3_timeout at the shared 120s LLM_COMPLETE_TIMEOUT: planning now
   has its own PLANNING_LLM_TIMEOUT_SEC (default 240).

Unit tests cover the envelope unwrap (balanced/truncated/inner braces),
the thinking fallback in both phases, and the clean-fail path.
1 parent ea9e4fe commit 8d4665144a68a283d1f1c9f4a4637d866a1709ec
@Eugene Sukhodolskiy Eugene Sukhodolskiy authored 12 hours ago
Showing 4 changed files
View
docs/config.md
View
navi/config.py
View
navi/core/planning.py
View
tests/unit/core/test_planning.py