Stop Blocking Virtual Threads: Building Asynchronous Human-in-the-Loop AI Agents with Spring AI A developer has built an asynchronous human-in-the-loop AI agent system using Spring AI that avoids blocking virtual threads during approval workflows. The approach serializes the agent's ReAct loop state—including token history, tool call IDs, and pending variables—to a Redis-backed persistent store, terminates the active thread immediately, and hydrates a new agent instance when a human decision webhook fires. The implementation uses a custom `ChatMemory` adapter that supports snapshotting at specific message indices and a resume endpoint that injects the human's decision as a `ToolResponseMessage` to continue the ReAct loop. In 2026, letting autonomous AI agents execute high-risk enterprise tools without human oversight is a production liability, but blocking platform threads—or even Project Loom’s virtual threads—for hours waiting for a manager's Slack approval is absolute architectural malpractice. We must transition from synchronous execution loops to stateless, event-driven agent hydration where the LLM's reasoning state is serialized and persisted during human-in-the-loop HITL interrupts. VirtualThreadExecutor solve the wait problem—they do not; holding resources open for a 4-hour human coffee break destroys system scalability and ruins connection pools. ChatMemory or agent context in local heap memory, making your system highly vulnerable to redeployments and node failures. CompletableFuture or busy-waiting database polling loops to check if a human has clicked "Approve" on an external UI.The clean solution is to serialize the agent's execution state—the ReAct loop token history, tool call IDs, and pending variables—to a persistent store, terminate the active thread immediately, and hydrate a brand-new agent instance when the approval webhook fires. AgentSuspensionException containing the serialized stateId and tool execution metadata when a high-risk tool is triggered. ChatClient with a custom Redis-backed ChatMemory implementation that supports snapshotting at specific message indices. /api/v1/agent/resume that accepts the human decision, merges it into the serialized history as a ToolResponseMessage , and triggers the next step of the ReAct loop. @PostMapping "/agent/resume" public ResponseEntity