Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 38 additions & 2 deletions basics/hitl/overview.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
---
title: Human-in-the-Loop in Agents
description: Learn how to control the flow of an agent's execution in Agno.
sidebarTitle: Overview
description: Learn how to control the flow of an agent's execution in Agno with human oversight and input.
keywords: [human-in-the-loop, HITL, user confirmation, user input, external execution, control flow]
mode: wide
---

Human-in-the-Loop (HITL) in Agno enable you to implement patterns where human oversight and input are required during agent execution. This is crucial for:
Expand Down Expand Up @@ -404,8 +407,41 @@ if run_response.is_paused:
2. **Error Handling**: Implement proper error handling for user input and external calls
3. **Input Validation**: Validate user input before processing

## Learn More

<CardGroup cols={2}>
<Card
title="User Confirmation Examples"
icon="circle-check"
href="/examples/basics/agent/hitl/confirmation-required"
>
Require explicit user approval before executing tool calls
</Card>
<Card
title="User Input Examples"
icon="keyboard"
href="/examples/basics/agent/hitl/user-input-required"
>
Gather specific information from users during execution
</Card>
<Card
title="Dynamic User Input Examples"
icon="comments"
href="/examples/basics/agent/hitl/agentic-user-input"
>
Let agents request user input dynamically when needed
</Card>
<Card
title="External Tool Execution Examples"
icon="plug"
href="/examples/basics/agent/hitl/external-tool-execution"
>
Execute tools outside of the agent's control
</Card>
</CardGroup>

## Developer Resources

- View more [Examples](/examples/basics/agent/human_in_the_loop/)
- View more [Examples](/examples/basics/agent/hitl/)
- View [Cookbook](https://github.com/agno-agi/agno/tree/main/cookbook/agents/human_in_the_loop)

55 changes: 33 additions & 22 deletions docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -1310,29 +1310,40 @@
"pages": [
"basics/hitl/overview",
{
"group": "Examples",
"group": "Usage",
"pages": [
"examples/basics/agent/human_in_the_loop/agentic_user_input",
"examples/basics/agent/human_in_the_loop/confirmation_required",
"examples/basics/agent/human_in_the_loop/confirmation_required_async",
"examples/basics/agent/human_in_the_loop/confirmation_required_mixed_tools",
"examples/basics/agent/human_in_the_loop/confirmation_required_multiple_tools",
"examples/basics/agent/human_in_the_loop/confirmation_required_stream",
"examples/basics/agent/human_in_the_loop/confirmation_required_stream_async",
"examples/basics/agent/human_in_the_loop/confirmation_required_toolkit",
"examples/basics/agent/human_in_the_loop/confirmation_required_with_history",
"examples/basics/agent/human_in_the_loop/confirmation_required_with_run_id",
"examples/basics/agent/human_in_the_loop/external_tool_execution",
"examples/basics/agent/human_in_the_loop/external_tool_execution_async",
"examples/basics/agent/human_in_the_loop/external_tool_execution_async_responses",
"examples/basics/agent/human_in_the_loop/external_tool_execution_stream",
"examples/basics/agent/human_in_the_loop/external_tool_execution_stream_async",
"examples/basics/agent/human_in_the_loop/external_tool_execution_toolkit",
"examples/basics/agent/human_in_the_loop/user_input_required",
"examples/basics/agent/human_in_the_loop/user_input_required_all_fields",
"examples/basics/agent/human_in_the_loop/user_input_required_async",
"examples/basics/agent/human_in_the_loop/user_input_required_stream",
"examples/basics/agent/human_in_the_loop/user_input_required_stream_async"
"examples/basics/agent/hitl/agentic-user-input",
{
"group": "Confirmation Required",
"pages": [
"examples/basics/agent/hitl/confirmation-required",
"examples/basics/agent/hitl/confirmation-required-async",
"examples/basics/agent/hitl/confirmation-required-mixed-tools",
"examples/basics/agent/hitl/confirmation-required-multiple-tools",
"examples/basics/agent/hitl/confirmation-required-stream-async",
"examples/basics/agent/hitl/confirmation-required-toolkit",
"examples/basics/agent/hitl/confirmation-required-with-history",
"examples/basics/agent/hitl/confirmation-required-with-run-id"
]
},
{
"group": "User Input Required",
"pages": [
"examples/basics/agent/hitl/user-input-required",
"examples/basics/agent/hitl/user-input-required-all-fields",
"examples/basics/agent/hitl/user-input-required-async",
"examples/basics/agent/hitl/user-input-required-stream-async"
]
},
{
"group": "External Tool Execution",
"pages": [
"examples/basics/agent/hitl/external-tool-execution",
"examples/basics/agent/hitl/external-tool-execution-async",
"examples/basics/agent/hitl/external-tool-execution-stream-async",
"examples/basics/agent/hitl/external-tool-execution-toolkit"
]
}
]
}
]
Expand Down
182 changes: 182 additions & 0 deletions examples/basics/agent/hitl/agentic-user-input.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
---
title: Agentic User Input with Control Flow
sidebarTitle: Agentic User Input
keywords: [UserControlFlowTools, dynamic user input, agentic input, form-like interaction, control flow]
description: This example demonstrates how to use UserControlFlowTools to allow agents to dynamically request user input when they need additional information to complete tasks.
mode: wide
---

<Steps>

<Step title="Create a Python file">
Create a Python file for the example.
```bash
touch agentic_user_input.py
```
</Step>

<Step title="Add the following code to your Python file">
```python agentic_user_input.py
from typing import Any, Dict, List

from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.tools import Toolkit
from agno.tools.function import UserInputField
from agno.tools.user_control_flow import UserControlFlowTools
from agno.utils import pprint


class EmailTools(Toolkit):
def __init__(self, *args, **kwargs):
super().__init__(
name="EmailTools", tools=[self.send_email, self.get_emails], *args, **kwargs
)

def send_email(self, subject: str, body: str, to_address: str) -> str:
"""Send an email to the given address with the given subject and body.

Args:
subject (str): The subject of the email.
body (str): The body of the email.
to_address (str): The address to send the email to.
"""
return f"Sent email to {to_address} with subject {subject} and body {body}"

def get_emails(self, date_from: str, date_to: str) -> list[dict[str, str]]:
"""Get all emails between the given dates.

Args:
date_from (str): The start date (in YYYY-MM-DD format).
date_to (str): The end date (in YYYY-MM-DD format).
"""
return [
{
"subject": "Hello",
"body": "Hello, world!",
"to_address": "test@test.com",
"date": date_from,
},
{
"subject": "Random other email",
"body": "This is a random other email",
"to_address": "john@doe.com",
"date": date_to,
},
]


agent = Agent(
model=OpenAIChat(id="gpt-5-mini"),
tools=[EmailTools(), UserControlFlowTools()],
markdown=True,
)

run_response = agent.run("Send an email with the body 'What is the weather in Tokyo?'")

# We use a while loop to continue the running until the agent is satisfied with the user input
while run_response.is_paused:
for tool in run_response.tools_requiring_user_input:
input_schema: List[UserInputField] = tool.user_input_schema # type: ignore

for field in input_schema:
# Get user input for each field in the schema
field_type = field.field_type # type: ignore
field_description = field.description # type: ignore

# Display field information to the user
print(f"\nField: {field.name}") # type: ignore
print(f"Description: {field_description}")
print(f"Type: {field_type}")

# Get user input
if field.value is None: # type: ignore
user_value = input(f"Please enter a value for {field.name}: ") # type: ignore
else:
print(f"Value: {field.value}") # type: ignore
user_value = field.value # type: ignore

# Update the field value
field.value = user_value # type: ignore

run_response = agent.continue_run(run_response=run_response)
if not run_response.is_paused:
pprint.pprint_run_response(run_response)
break


run_response = agent.run("Get me all my emails")

while run_response.is_paused:
for tool in run_response.tools_requiring_user_input:
input_schema: Dict[str, Any] = tool.user_input_schema # type: ignore

for field in input_schema:
# Get user input for each field in the schema
field_type = field.field_type # type: ignore
field_description = field.description # type: ignore

# Display field information to the user
print(f"\nField: {field.name}") # type: ignore
print(f"Description: {field_description}")
print(f"Type: {field_type}")

# Get user input
if field.value is None: # type: ignore
user_value = input(f"Please enter a value for {field.name}: ") # type: ignore
else:
print(f"Value: {field.value}") # type: ignore
user_value = field.value # type: ignore

# Update the field value
field.value = user_value # type: ignore

run_response = agent.continue_run(run_response=run_response)
if not run_response.is_paused:
pprint.pprint_run_response(run_response)
break
```
</Step>

<Snippet file="create-venv-step.mdx" />

<Step title="Install libraries">
```bash
pip install -U agno openai
```
</Step>

<Step title="Export your OpenAI API key">

<CodeGroup>

```bash Mac/Linux
export OPENAI_API_KEY="your_openai_api_key_here"
```

```bash Windows
$Env:OPENAI_API_KEY="your_openai_api_key_here"
```
</CodeGroup>
</Step>

<Step title="Run Agent">
<CodeGroup>
```bash Mac
python agentic_user_input.py
```

```bash Windows
python agentic_user_input.py
```
</CodeGroup>
</Step>

<Step title="Find All Cookbooks">
Explore all the available cookbooks in the Agno repository. Click the link below to view the code on GitHub:

<Link href="https://github.com/agno-agi/agno/tree/main/cookbook/agents/human_in_the_loop" target="_blank">
Agno Cookbooks on GitHub
</Link>
</Step>
</Steps>
Loading