Pausing the Agent for Input

Pause an agent run mid-tool, hand control to a custom React component, and resume with the user's answer.


"""ADK scheduling agent backing the gen-ui-interrupt demo (Strategy-B).In langgraph-python the gen-ui-interrupt demo relies on the native`interrupt()` primitive with checkpoint/resume. ADK has no such primitive,so we adapt with the same "Strategy B" pattern used by the agno andms-agent-framework ports: the agent's instruction tells Gemini to call the`schedule_meeting` tool, but NO backend tool is registered. CopilotKit's`AGUIToolset()` injects the frontend-registered `schedule_meeting`(`useHumanInTheLoop` in src/app/demos/gen-ui-interrupt/page.tsx) into themodel's tool list; the model's call is routed to the frontend, which rendersthe time-picker inline and resolves the call once the user picks a slot —equivalent to `interrupt()` in the LangGraph reference.`after_model_callback=stop_on_terminal_text` is the canonical ADK terminalguard (see shared_chat.py): without it the configured Gemini model(from `get_model()`) re-issues the same tool call indefinitely after thefrontend tool resolves."""from __future__ import annotations# region: setupfrom google.adk.agents import LlmAgentfrom ag_ui_adk import AGUIToolsetfrom agents.shared_chat import get_model, stop_on_terminal_text_INSTRUCTION = (    "You are a scheduling assistant. Whenever the user asks you to book a "    "call or schedule a meeting, you MUST call the `schedule_meeting` tool. "    "Pass a short `topic` describing the purpose of the meeting and, if "    "known, an `attendee` describing who the meeting is with.\n\n"    "The `schedule_meeting` tool is implemented on the client: it surfaces a "    "time-picker UI and returns the user's selection. After the tool "    "returns, briefly confirm whether the meeting was scheduled and at what "    "time, or note that the user cancelled. Do NOT ask for approval "    "yourself — always call the tool and let the picker handle the decision. "    "Keep responses short and friendly, and always send a brief final "    "assistant message summarising what happened so it persists.")interrupt_agent = LlmAgent(    name="InterruptAgent",    model=get_model(),    instruction=_INSTRUCTION,    # No backend tools. `schedule_meeting` is registered on the frontend via    # useHumanInTheLoop; AGUIToolset() exposes CopilotKit's frontend-tool    # channel to the model.    tools=[AGUIToolset()],    after_model_callback=stop_on_terminal_text,)# endregion

What is this?#

useInterrupt lets your agent pause mid-run, hand control to the user through a custom React component, and resume with whatever the user returns. How that pause is implemented depends on the framework's runtime.

Not available on this framework. useInterrupt is only meaningful when the underlying runtime exposes either a native interrupt(...) primitive (LangGraph) or a Promise-resolving frontend tool path (Microsoft Agent Framework). For all other integrations, use useHumanInTheLoop instead — it's the standard hook for tool-call-based pause/resume flows and works on every framework that supports tool calls.

When should I use this?#

Reach for useInterrupt when the pause is a graph-enforced checkpoint where the code path must stop and wait for a human, not an LLM-initiated tool call. Typical cases:

  • A sensitive action (payments, irreversible writes) must be approved
  • A required piece of state isn't known and can only be collected from the user
  • The agent explicitly reaches an approval node in a longer workflow
  • You want the server-side contract to be interrupt(...) and resume with a payload

For LLM-initiated pauses where the model decides on the fly to ask the user, prefer useHumanInTheLoop.

Going further#