HumanInTheLoopMiddleware: Opt-In Per-Call Interrupts With Typed Response_schema
Current batched HITL interrupts force approval UIs to infer tool action context from positional lists and skip response validation, leading to fragile integrations and potential stuck threads. This change adds per-call interrupts with typed tool_approval values and per-tool response_schema validation.
HumanInTheLoopMiddleware batches all pending tool call approvals into a single interrupt and provides allowed decisions in a separate review_configs list matched by position. This design removes per-tool context and omits response_schema validation, so approval UIs must parse arrays manually and malformed edit/approve payloads can be persisted, blocking thread progress.
1. Configure HumanInTheLoopMiddleware with a model that produces multiple tool calls in one turn.
2. Observe a single interrupt containing a list of actions and a parallel review_configs list.
3. Submit an approval with a malformed edit for one of the tools.
4. Notice the invalid answer is saved and the thread becomes stuck because no validation rejects it before the tool runs.
The per-call mode interrupts individually from wrap_tool_call, using LangGraph's typed interrupt with a response_schema that restricts decisions to the tool's allowed set and pins tool_call_id. The edit branch includes the tool's args schema, so LangGraph validates edits before resuming, and rename is impossible because tool_call_id is const.
Edge Case Audit
This fix is opt-in; batched remains default until the next major. Rolling back requires setting interrupt_mode back to 'batched'. Concurrency/multiple interrupts per turn increases UI round trips; ensure approval UIs can handle multiple simultaneous interrupts. Response schema changes may reject previously accepted malformed payloads, potentially breaking existing integrations. Test with langgraph>=1.2.12; earlier versions lack typed interrupt support.