Skip to content

v1.20.9 — ReAct mode draft HITL parity (ADR-070 amendment)

Choose a tag to compare

@jgouviergmail jgouviergmail released this 20 May 20:12

ReAct mode now confirms before acting — no more false "Done!" (ADR-070 amendment)

What was wrong

In ReAct mode (⚡), asking LIA to create / modify / reply / forward / delete (events, emails, contacts, tasks, files, labels) could answer "C'est fait." while nothing was actually performed. These mutation tools don't execute directly — they prepare a draft that must be confirmed via HITL before the real action runs. The default Pipeline mode wired this through task_orchestrator → hitl_dispatch (draft_critique) → response, but the ReAct loop had no equivalent: the prepared draft was collected into a dead, never-consumed wrapper field and the loop continued, so the model treated "draft prepared" as completion. Only hitl_required tools (e.g. delegate_to_sub_agent) reached an interrupt().

The fix (reuses existing nodes — no new HITL machinery)

  • react_execute_tools_node detects a prepared draft (tool_metadata.requires_confirmation), extracts the executable payload from the draft's registry item, and always sets pending_draft_critique / pending_drafts_queue (None/[] when no draft) so a stale value can never mis-route the loop.
  • New route_from_react_execute_tools routes a pending draft → hitl_dispatch (the shared draft_critique node), otherwise loops back to react_call_model. The existing hitl_dispatch → initiative → response_node path then runs the confirm/edit/cancel HITL and executes the confirmed draft via execute_draft_if_confirmed.
  • Confirmation lives downstream of react_execute_tools, so resume re-enters hitl_dispatch only — the draft tool is never re-run (no duplicate drafts).
  • ReAct completion metrics preserved on the draft path (react_agent_executions_total{status="draft"}).
  • Removed the now-redundant and previously-broken _accumulated_drafts collector from ReactToolWrapper (it read draft_content from tool_metadata, where it is empty rather than from the registry payload).
  • Reminder creation executes directly (no draft) and stays ungated — unchanged in both modes.

Quality

Backend (Ruff, Black, MyPy, 8266 unit tests) and frontend (ESLint, TypeScript) green; i18n parity preserved across 6 languages. Added 4 routing tests + 7 draft-detection tests; removed the obsolete test_collects_draft_metadata wrapper test.

Docs: ADR-070 amendment, ARCHITECTURE_LANGRAPH, REACT_EXECUTION_MODE, ADR_INDEX, knowledge/02_chat. In-app FAQ changelog v1.20.9 added in all 6 languages.

Full changelog: CHANGELOG.md