NVIDIANVIDIA-Certified Professional: Agentic AI2026-1010.1 Build intuitive UIs with user-in-the-loop interaction.
Keep review in session or park it as a task
Completed by the knowledge check
Learning objective
Choose synchronous versus asynchronous user-in-the-loop interactions.
Core idea
Choose synchronous interaction when the person can make the decision within the active session’s time budget. Choose asynchronous interaction when the task must wait independently of that session and the person needs to return later. The distinction is who waits for whom, not whether the Python function uses async def.
See 1.1.1 for task-inbox surfaces and 10.1.1 for review controls. Here, decide how long the waiting task must survive. See 5.4.2 for checkpoint implementation and replay-safe side effects.
How it works
Bound the live interaction
NeMo Agent Toolkit’s UserInteractionManager pauses a workflow through await user_input_manager.prompt_user_input(prompt). The function processes the returned response before proceeding. This supports a live clarification or review exchange, even though its implementation is an asynchronous Python call.
For the Toolkit’s supplied frontend, enable WebSocket mode. The server sends system_interaction_message, and the client answers with user_interaction_message. A bidirectional connection carries the exchange; it does not decide whether the business task survives a later process restart.
The WebSocket schema gives each prompt an optional timeout, expressed in seconds. Its default is null, meaning no timeout. A configured timeout makes the frontend show a countdown and dismiss an expired prompt; server enforcement raises TimeoutError to the workflow. Set the value from the remaining session budget rather than assuming the person can always respond in time.
For example, if a hypothetical application allows 60 seconds end to end, spends 8 seconds preparing a proposal, and reserves 12 seconds for execution and response, at most 40 seconds remain for synchronous review. These are application budgets, not Toolkit limits. A 5-minute human response cannot satisfy that design merely by enabling streaming or increasing model throughput.
Match waiting to the required lifetime
Toolkit HTTP Interactive Execution carries human prompts without an open WebSocket. In polling mode, an interaction returns 202 Accepted with status: "interaction_required", status_url containing the execution ID, interaction_id, prompt, and response_url. A client can disconnect and later poll GET /executions/{execution_id} or post its answer to POST /executions/{execution_id}/interactions/{interaction_id}/response while the execution waits on the server. See 2.5.2–2.5.3 for client recovery and resolved-interaction handling.
Interactive extensions are enabled by default on /v1/workflow and /v1/chat. For /v1/chat/completions, enable general.front_end.enable_interactive_extensions: true; its default is false. This path transports the same interactive prompts, but the HTTP Interactive Execution reference documents no persistence of a pending execution across a server restart or redeploy.
When review must survive a server restart, use a durable waiting task. LangGraph’s interrupt() surfaces a JSON-serializable payload to the caller while a checkpointer saves graph state. Production use requires a durable checkpointer and a stable configurable.thread_id. The graph waits until it receives a resume response.
With the default invoke() API, pending interrupts appear in result["__interrupt__"]. A service can turn that payload into a review task and later invoke the graph with Command(resume=...) using the same thread ID. The resume value becomes the return value of interrupt(). This is a framework-level mechanism; the application’s task inbox, notification delivery, authorization, and review deadline remain separate service responsibilities.
NeMo Agent Toolkit integrates existing LangGraph agents through workflow._type: langgraph_wrapper and a graph value in module_path:variable_name form. It requires nvidia-nat-langchain. The documented graph is a CompiledStateGraph or a callable returning one from RunnableConfig; complex state management can require additional configuration or code changes. Keep the framework resume service explicit in your design instead of assuming that importing a graph automatically exposes an inbox or a Command-accepting public route.
An application-owned review record can carry task_id, thread_id, proposal_revision, review_status, and review_deadline. Retrieve that pending proposal before accepting a decision.
Give the wait a business outcome
LangGraph’s documented interrupt wait is indefinite. That is a persistence behavior, not a business policy for how long approval remains valid. Define a deadline in the review task and have the response service check it before issuing Command(resume=...). If the proposal has expired, show the expired outcome and regenerate or close it according to the workflow’s decision rule.
A notification tells the person that work is waiting; it is not the authoritative proposal. When the person opens it, load the pending task and its revision. If another response has already resolved it, display that outcome rather than offering a second actionable form. The review service owns that acceptance check, while the graph owns continuation.
Resume also restarts the interrupted node from its beginning. Keep that fact in mind when placing the review step, and use the replay-safe design in 5.4.2 for external writes. A durable review task can outlive the browser without making every operation around it safe to repeat.
Key distinctions and trade-offs
Compare the interaction choices against the human wait:
| Choice | Required lifetime | Mechanism | Main cost | Owner |
|---|---|---|---|---|
| Synchronous review | The active session | Toolkit prompt_user_input over WebSocket or HTTP with a bounded timeout | Session occupancy and timeout risk | Interactive workflow team |
| Asynchronous review on the running server | Client disconnect and return | Toolkit HTTP polling with execution_id and interaction_id | Status retrieval, expiry, and response coordination | HTTP client and workflow teams |
| Durable asynchronous review | Server restart or redeploy | LangGraph interrupt(), durable checkpointer, stable thread_id, and Command(resume=...) | Persistent storage and a review service | Workflow and review-service teams |
Transport and interaction are different dimensions. HTTP polling lets a person return without keeping a connection open; durable checkpoints address server restarts. Setting timeout: null only removes the prompt deadline.
Asynchronous review adds a return journey and potentially stale proposals. Measure completion time as well as acknowledgment; fast acceptance can hide review backlog.
Architecture / decision scenario
A publishing company’s research assistant prepares campaign briefs. In this hypothetical service, source retrieval and drafting take 8 seconds. An editor’s short clarification takes a median of 10 seconds, while brand review takes a median of 20 minutes. The interactive application has a 60-second completion budget and reserves 12 seconds after the decision to validate and deliver the brief.
One proposal keeps every decision inside the WebSocket conversation with no prompt timeout. That avoids a review-service implementation, but the 20-minute brand review exceeds the 40-second remaining synchronous allowance. Closing the browser would also leave the editor without a durable review-task return path in that design.
The product owner chooses a mixed workflow. Short clarifications use prompt_user_input with an application-selected 40-second timeout. An unanswered clarification produces an expired interaction and an option to restart it. For brand review, the team assumes the 4-hour review window spans a server redeploy. It therefore chooses a durable graph interrupt and stable thread ID behind the task inbox rather than relying on HTTP polling alone.
The review service stores an application-selected 4-hour deadline and proposal revision. When brand review finishes, it verifies that the task is still pending and unexpired, then resumes the graph with Command(resume=...). An expired brief returns for refreshed source checks rather than publishing from a stale approval. The team measures clarification timeouts separately from review age, so it can distinguish a poor live interaction from an understaffed review queue.
Common exam traps
- Assuming Toolkit human-in-the-loop interaction requires an open WebSocket.
- Calling an interaction asynchronous solely because it uses
await. - Equating streamed progress with durable background execution.
- Holding a live interaction open for a reviewer whose response exceeds the session budget.
- Treating
timeout: nullas persistent task storage. - Resuming with a different
configurable.thread_idand expecting the pending checkpoint. - Assuming a graph wrapper creates the review service, notification channel, and business expiry policy.
Where the exam guide differs
The study guide lists “NVIDIA Agent Intelligence Toolkit” among its suggested readings. NVIDIA documents the integration as NeMo Agent Toolkit’s langgraph_wrapper. For the guide’s “user-in-the-loop” objective, Toolkit prompts support WebSocket or HTTP polling. A durable checkpoint is a separate framework-level choice when the required waiting lifetime spans server restarts.
What to remember
Fit synchronous review inside the remaining session budget. Use HTTP polling for client return and durable checkpoints for restart survival. Give the task an identity, an expiry rule, and a controlled resume path. Measure human wait separately from model execution; faster inference cannot remove review backlog.
Knowledge check
A NeMo Agent Toolkit assistant needs a yes/no clarification from the person who asked. The hypothetical application allows 60 seconds end to end, spends 8 seconds preparing the question, and reserves 12 seconds after the answer. Users answer such questions in a median of 6 seconds and stay in the session. Which design meets the budget with the least added infrastructure?
prompt_user_input and leave timeout at its null defaultprompt_user_input with a 40-second timeout and handle expiryasync def function so the wait is asynchronousnull timeout leaves the session waiting past its budget whenever nobody answers. A durable interrupt also works but adds a review service and storage this wait does not need, and async def describes the Python call, not who waits for whom.Contract approvals in a Toolkit-served assistant take two to six hours. Reviewers close their browsers meanwhile, and the platform team redeploys the server most afternoons. A pending approval must survive a redeploy. Which design fits that lifetime?
thread_idexecution_id and interaction_idtimeout: null and a notification to the reviewerlanggraph_wrapper workflow that relies on the wrapper’s review inboxthread_id lets a review service resume it with Command(resume=...) . A null timeout only removes the prompt deadline, and the wrapper integrates a graph without creating a review inbox.A durable LangGraph interrupt holds a campaign brief for brand review. The review service stores an application-selected 4-hour review_deadline with the task. Approval is available through both a notification link and a task inbox that opens the pending task independently of that link. Two days later, a reviewer submits Approve from the inbox. Which control should enforce the deadline for either entry path?
timeout set on the original review promptCommand(resume=...)In a LangGraph node, the code sends a “review requested” email and then calls interrupt(). The service later resumes once with Command(resume=...) on the same thread_id. Reviewers receive the email twice: when review starts and again just after they approve. A “draft ready” email sent by an earlier node arrives only once. What explains the duplicate?
interrupt()interrupt() was called from its beginning, so any side effect placed before the interrupt in that node repeats. Earlier nodes do not rerun, and the interrupt does not expire on its own. Place the notification where it runs once, or make it replay-safe as 5.4.2 describes.