v1.20.6 — ADR-084 Indexable vs Semantic + Gemini 3.x compat + Vagues 1-5 timeout centralization
Highlights
Three independent hardening fronts shipped in one release.
🛡️ ADR-084 — Indexable vs Semantic Criteria (universal planning principle)
Repeated diagnostics of "mes deux prochains rdv médicaux" surfaced a class of failures invisible to the existing validator: the planner was passing semantic qualifiers (medical, urgent, important) as the query of literal-text-search tools (Calendar / Gmail / Notion-style stores) which then returned 0 hits or false positives.
4-layer defense:
- Universal prompt section in
smart_planner_prompt.txt(370 tokens, prompt-cached after first call) - Structured
semantic_filter_termshint emitted by the query analyzer - Universal
PlanValidator._check_semantic_leakgated byPLANNER_SEMANTIC_LEAK_MODE(off/observe/autocorrect, defaultobserve) ToolManifest.text_search_modedeclarative opt-out for native semantic-search backends
Ships in observe mode this release: zero plan mutation, only telemetry. Phase 2 promotion to autocorrect gated on operational metrics. Tests: 19 cases including French apostrophe regression and required-param protection.
🔧 Gemini 3.x response.content shape fix
Switching query_analyzer / planner to gemini-3.1-pro-preview exposed smart_planner_panic_failed with a JSON parse error: langchain_google_genai wraps the response as list[dict] for Gemini 3.x specifically while every other provider keeps str.
33 sites across 26 files migrated to the LangChain Core 1.2+ BaseMessage.text property which handles both shapes:
- Planner ×2, response node, compaction ×3, memory extraction + reference resolution ×4
- HITL classification + question generation streams ×6
- Voice TTS, broadcast notifications
- Journals extraction + consolidation ×3, interests ×3, psyche ×2, heartbeat
- MCP service, llm_cache key serialization
End-to-end Gemini 3.1 Pro Preview pipeline now runs cleanly. Test mocks for compaction, draft_modifier, item_filter and psyche updated to mirror .content on .text.
⏱️ Vagues 1-5 timeout centralization
Audit inventoried ~80 backend timeouts and surfaced:
- 28 hardcoded values used in production paths but never operator-tunable
- 2 inline magic numbers in
parallel_executor - 1 orphan field (
task_orchestrator_execution_timeout_seconds) declared but never read - 2 dead constants, 1 duplicated Field (currency API)
- 1 cascade inversion bug (Brave enrichment 3 s wrapper firing before its own 5 s HTTP call → raised to 8 s)
All 28 hardcoded values exposed as Pydantic Fields with operator-validated ranges and matching .env.example / .env.prod.example entries. Two new config modules: LocksSettings (OAuth refresh lock) and SchedulerSettings (scheduled-actions executor). The orphan global timeout was wired in parallel_executor.execute_plan_parallel as a soft cap on multi-wave plans + new Prometheus counter lia_parallel_execution_global_timeout_total{plan_outcome}.
Single source of doc truth: docs/technical/TIMEOUT_REGISTRY.md — 12 sections + Annex A (LLM out-of-scope), Annex B (frontend timing.ts mirror), Annex C (gaps tracked for future Vague 6).
Pydantic ranges fully aligned with scripts/validate_config.py end-to-end; 4 legacy gt=0-only Fields tightened (http_timeout_oauth/token/external_api, apple_connection_timeout).
What changed for users
See the in-app FAQ changelog (v1.20.6 entry) — 4 user/admin items in 6 languages:
- Web search (Brave) response enrichment more reliable
- Gemini 3.x LLM fully compatible end-to-end
- 28 timeouts now operator-tunable via
.env+ newTIMEOUT_REGISTRY.md - Preventive defense layer on the planner (in observe mode)
Documentation
- ADR-084 created
- TIMEOUT_REGISTRY.md created
PLANNER.md,SMART_SERVICES.md,OBSERVABILITY_AGENTS.mdupdated- README banner bumped (v1.20.5 demoted)
GETTING_STARTED.mdcompatibility line updated- Blog article
execution-plansenriched with an "Indexable vs Semantic criteria distinction" section in 6 languages
Commit
91eb2ad — see CHANGELOG.md for the full diff narrative.