HTTP Interactive Execution
February 18, 2026 ยท View on GitHub
NeMo Agent Toolkit supports interactive workflows (Human-in-the-Loop and OAuth) over plain HTTP, without requiring a WebSocket connection. This is useful in deployment environments where WebSocket support is limited.
When enabled, the interactive extensions allow HTTP clients to:
- Start a workflow execution and receive an execution ID
- Poll for execution status (running, interaction required, OAuth required, completed, or failed)
- Submit interaction responses (text, binary choice, radio, checkbox, dropdown, or notification acknowledgment)
- Handle OAuth2 authorization code flows through status polling
Two client integration patterns are supported:
- Polling mode: The server returns
202 Acceptedwith an execution ID. The client pollsGET /executions/{execution_id}until the workflow completes or requires interaction. - Streaming mode (SSE): The server streams workflow output as Server-Sent Events. When an interaction or OAuth flow is needed, a typed SSE event is emitted. The client submits its response, and the stream resumes.
Configuration
HTTP interactive extensions are enabled by default on all workflow endpoints except for
OpenAI-compatible endpoints (/v1/chat/completions). To force the interactive extension to work
with OpenAI-compatible endpoints, set enable_interactive_extensions to true in the FastAPI
front-end configuration:
general:
front_end:
_type: fastapi
enable_interactive_extensions: true
The following table describes the relevant configuration parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
enable_interactive_extensions | boolean | false | Enable HTTP interactive execution on OpenAI-compatible endpoints. When true, POST requests to chat and OpenAI-compatible endpoints (/v1/chat/completions) return 202 Accepted if the workflow pauses for interaction or OAuth |
disable_legacy_routes | boolean | false | Disable legacy endpoint paths (/generate, /chat). When true, only versioned paths with interactive support (/v1/workflow, /v1/chat) are registered |
oauth2_callback_path | string | /auth/redirect | Path for the OAuth2 authorization code grant callback endpoint |
:::{note}
Interactive extensions are enabled for versioned workflow and chat endpoints (for example,
/v1/workflow and /v1/chat).
OpenAI-compatible endpoints (/v1/chat/completions) are opt-in only (defaulting to disabled).
:::
Execution Lifecycle
An interactive HTTP execution moves through the following states:
flowchart TD
Start(["Start workflow"])
Running(["Running"])
Interaction(["Interaction Required"])
OAuth(["OAuth Required"])
Completed(["Completed"])
Failed(["Failed"])
Start --> Running
Running -->|Workflow has interaction| Interaction
Running -->|Workflow needs authentication| OAuth
Running -->|Workflow execution completes| Completed
Running -->|Workflow execution failed| Failed
Interaction -->|Client submits response to execution endpoint| Running
Interaction -->|Timeout| Failed
OAuth -->|OAuth redirect resolves token| Running
OAuth -->|Timeout| Failed
style Completed fill:#2e7d32,color:#fff,stroke:#1b5e20
style Failed fill:#c62828,color:#fff,stroke:#b71c1c
style Running fill:#006699,color:#fff,stroke:#003366
Endpoints
Starting an Execution (Polling Mode)
POST requests to versioned endpoints such as /v1/chat return a 202 Accepted response if the
workflow requires interaction or OAuth before it can complete. Interactive support is enabled by
default on these endpoints; the enable_interactive_extensions flag only gates OpenAI-compatible
endpoints (see Configuration).
Request:
curl -X POST http://localhost:8000/v1/chat \
-H "Content-Type: application/json" \
-d '{
"messages": [
{"role": "user", "content": "Analyze the sales data"}
]
}'
Response (202 Accepted, interaction required):
{
"status": "interaction_required",
"status_url": "/executions/550e8400-e29b-41d4-a716-446655440000",
"interaction_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"prompt": {
"input_type": "text",
"text": "Should I include Q4 projections?",
"placeholder": "Type your response...",
"required": true,
"timeout": null,
"error": null
},
"response_url": "/executions/550e8400-e29b-41d4-a716-446655440000/interactions/a1b2c3d4-e5f6-7890-abcd-ef1234567890/response"
}
The error field inside the prompt object is only populated when the prompt times out or becomes
unavailable. Under normal operation it is null.
Response (202 Accepted, OAuth required):
{
"status": "oauth_required",
"status_url": "/executions/550e8400-e29b-41d4-a716-446655440000",
"auth_url": "https://provider.example.com/authorize?client_id=...&state=abc123",
"oauth_state": "abc123"
}
If the workflow completes without requiring interaction, a standard 200 OK response with the
workflow result is returned, identical to the non-interactive behavior.
Getting Execution Status
Poll the execution status endpoint to check progress or retrieve the final result.
- Route:
GET /executions/{execution_id} - Description: Returns the current status of an execution.
Request:
curl http://localhost:8000/executions/550e8400-e29b-41d4-a716-446655440000
Response (running):
{
"status": "running"
}
Response (interaction required):
{
"status": "interaction_required",
"interaction_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"prompt": {
"input_type": "text",
"text": "Should I include Q4 projections?",
"placeholder": "Type your response...",
"required": true,
"timeout": null,
"error": null
},
"response_url": "/executions/550e8400-e29b-41d4-a716-446655440000/interactions/a1b2c3d4-e5f6-7890-abcd-ef1234567890/response"
}
The error field inside the prompt object is only populated when the prompt times out or becomes
unavailable. Under normal operation it is null.
Response (OAuth required):
{
"status": "oauth_required",
"auth_url": "https://provider.example.com/authorize?client_id=...&state=abc123",
"oauth_state": "abc123"
}
Response (completed):
{
"status": "completed",
"result": {
"id": "chatcmpl-abc123",
"object": "chat.completion",
"choices": [
{
"message": {
"content": "The analysis is complete. Q4 projections have been included.",
"role": "assistant"
},
"finish_reason": "stop",
"index": 0
}
]
}
}
Response (failed):
{
"status": "failed",
"error": "Workflow execution timed out after 300 seconds"
}
The following table lists all possible status values:
| Status | Description |
|---|---|
running | The workflow is actively executing |
interaction_required | The workflow is paused waiting for a human response |
oauth_required | The workflow is paused waiting for OAuth2 authorization |
completed | The workflow finished successfully; the result field contains the output |
failed | The workflow failed; the error field contains the error message |
Submitting an Interaction Response
When an execution has status interaction_required, submit a response to resume the workflow.
- Route:
POST /executions/{execution_id}/interactions/{interaction_id}/response - Description: Submit a human response to a pending interaction prompt.
Request (text response):
curl -X POST http://localhost:8000/executions/550e8400-e29b-41d4-a716-446655440000/interactions/a1b2c3d4-e5f6-7890-abcd-ef1234567890/response \
-H "Content-Type: application/json" \
-d '{
"response": {
"input_type": "text",
"text": "Yes, include Q4 projections"
}
}'
Response: 204 No Content
After submitting a response, the execution transitions back to running. Continue polling
GET /executions/{execution_id} to track progress.
Supported Response Types
The response field in the request body is a discriminated union based on input_type. All
prompt types supported by Interactive Workflows
are available:
input_type | Fields | Description |
|---|---|---|
text | text (string) | Free-text response |
binary_choice | selected_option (object) | One of two options (for example, Continue or Cancel) |
radio | selected_option (object) | Single selection from multiple options |
checkbox | selected_options (array of objects) | Multiple selections from a list |
dropdown | selected_option (object) | Single selection from a dropdown |
notification | (none) | Acknowledgment of a notification prompt |
Request (radio response):
curl -X POST http://localhost:8000/executions/550e8400-e29b-41d4-a716-446655440000/interactions/a1b2c3d4-e5f6-7890-abcd-ef1234567890/response \
-H "Content-Type: application/json" \
-d '{
"response": {
"input_type": "radio",
"selected_option": {"id": "email", "label": "Email", "value": "email"}
}
}'
Request (checkbox response):
curl -X POST http://localhost:8000/executions/550e8400-e29b-41d4-a716-446655440000/interactions/a1b2c3d4-e5f6-7890-abcd-ef1234567890/response \
-H "Content-Type: application/json" \
-d '{
"response": {
"input_type": "checkbox",
"selected_options": [
{"id": "email", "label": "Email", "value": "email"},
{"id": "sms", "label": "SMS", "value": "sms"}
]
}
}'
Success Responses
| Status Code | Condition |
|---|---|
204 | Response accepted successfully |
Error Responses
| Status Code | Condition |
|---|---|
400 | Interaction has already been resolved |
404 | Execution or interaction not found |
Streaming Mode with SSE Events
When using streaming endpoints (/v1/chat/stream or /v1/chat/completions with stream: true),
interactive events are delivered as typed Server-Sent Events within the stream.
Interaction Required Event
When the workflow pauses for human interaction, the following SSE event is emitted:
event: interaction_required
data: {"event_type": "interaction_required", "execution_id": "550e8400-...", "interaction_id": "a1b2c3d4-...", "prompt": {"input_type": "text", "text": "Should I proceed?", ...}, "response_url": "/executions/550e8400-.../interactions/a1b2c3d4-.../response"}
After receiving this event, submit the interaction response through the
POST /executions/{execution_id}/interactions/{interaction_id}/response endpoint.
The SSE stream remains open and resumes sending workflow output once the response is submitted.
OAuth Required Event
When the workflow requires OAuth2 authorization, the following SSE event is emitted:
event: oauth_required
data: {"event_type": "oauth_required", "execution_id": "550e8400-...", "auth_url": "https://provider.example.com/authorize?...", "oauth_state": "abc123"}
Direct the user to the auth_url to complete authorization. After the OAuth redirect callback
is processed, the stream resumes automatically.
Client Integration Example
The following Python example demonstrates how to consume the SSE stream and handle interactive events:
import httpx
import json
def stream_with_interactions(base_url: str, messages: list[dict]) -> str:
"""Stream a chat request and handle any interactive events."""
with httpx.Client(base_url=base_url, timeout=300) as client:
with client.stream(
"POST",
"/v1/chat/stream",
json={"messages": messages},
) as response:
lines_iter = response.iter_lines()
for line in lines_iter:
if not line:
continue
# Check for typed SSE events
if line.startswith("event: interaction_required"):
# Next line is the data payload
data_line = next(lines_iter)
event = json.loads(data_line.removeprefix("data: "))
# Prompt the user
print(f"Workflow asks: {event['prompt']['text']}")
user_input = input("> ")
# Submit the response
client.post(
event["response_url"],
json={
"response": {
"input_type": "text",
"text": user_input,
}
},
)
continue
if line.startswith("event: oauth_required"):
data_line = next(lines_iter)
event = json.loads(data_line.removeprefix("data: "))
print(f"Please authorize at: {event['auth_url']}")
input("Press Enter after completing authorization...")
continue
# Regular data chunk
if line.startswith("data: "):
chunk = json.loads(line.removeprefix("data: "))
if "value" in chunk:
return chunk["value"]
return ""
OpenAI Chat Completions API Compatibility
The OpenAI-compatible endpoint (/v1/chat/completions) also supports interactive extensions when
enable_interactive_extensions is true. The behavior is the same as for the chat endpoints:
- Non-streaming (
stream: false): Returns202 Acceptedwith execution details when interaction or OAuth is required - Streaming (
stream: true): Emitsinteraction_requiredoroauth_requiredSSE events within the stream
curl -X POST http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "nvidia/llama-3.1-8b-instruct",
"messages": [
{"role": "user", "content": "Summarize my documents"}
],
"stream": false
}'
If the workflow needs human input, the response is 202 Accepted with the same structure as the
polling mode responses described above.
OAuth2 Flow over HTTP
When a workflow requires OAuth2 authentication (for example, to access a third-party API), the execution pauses and the authorization URL is surfaced through the execution status or SSE event.
The flow works as follows:
- The workflow calls an authenticated tool that requires OAuth2
- The execution status changes to
oauth_requiredwith theauth_url - The client directs the user to the
auth_urlto complete authorization - The OAuth provider redirects the user to the configured callback path (default:
/auth/redirect) - The callback endpoint exchanges the authorization code for a token and resolves the execution
- The execution transitions back to
runningand the workflow continues
:::{note}
The OAuth2 callback endpoint must be reachable by the user's browser. Ensure oauth2_callback_path
is configured correctly for your deployment environment.
:::
Related Documentation
- Interactive Workflows Guide for building workflows with human-in-the-loop interactions
- API Server Endpoints for the full list of HTTP and WebSocket endpoints
- WebSocket Message Schema for the WebSocket-based interactive messaging format