> ## Documentation Index
> Fetch the complete documentation index at: https://agno-v2-codex-docs-audit-20260719-0149.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# AG-UI Showcase

> Single server exposing all AG-UI Dojo demo endpoints.

Single server exposing all AG-UI Dojo demo endpoints. Run this to test AG-UI integration with the Dojo frontend at localhost:3000.

```python showcase.py theme={null}
"""
AG-UI Showcase
==============

Single server exposing all AG-UI Dojo demo endpoints.
Run this to test AG-UI integration with the Dojo frontend at localhost:3000.

Imports agents from individual files and mounts them at Dojo-compatible paths.
"""

from agent_with_media import media_agent
from agentic_chat import agentic_chat_agent
from agno.os import AgentOS
from agno.os.interfaces.agui import AGUI
from backend_feedback import backend_feedback_agent
from backend_tool_rendering import backend_tool_agent
from human_in_the_loop import hitl_agent
from reasoning_agent import chat_agent as reasoning_agent
from shared_state import shared_state_agent
from tool_based_generative_ui import generative_ui_agent
from tool_confirmation import tool_confirmation_agent
from user_input import user_input_agent

agent_os = AgentOS(
    agents=[
        agentic_chat_agent,
        backend_tool_agent,
        hitl_agent,
        generative_ui_agent,
        shared_state_agent,
        reasoning_agent,
        media_agent,
        tool_confirmation_agent,
        user_input_agent,
        backend_feedback_agent,
    ],
    interfaces=[
        AGUI(agent=agentic_chat_agent, prefix="/agentic_chat"),
        AGUI(agent=backend_tool_agent, prefix="/backend_tool_rendering"),
        AGUI(agent=hitl_agent, prefix="/human_in_the_loop"),
        AGUI(agent=generative_ui_agent, prefix="/tool_based_generative_ui"),
        AGUI(agent=shared_state_agent, prefix="/shared_state"),
        AGUI(agent=reasoning_agent, prefix="/agentic_chat_reasoning"),
        AGUI(agent=media_agent, prefix="/agentic_chat_multimodal"),
        AGUI(agent=tool_confirmation_agent, prefix="/tool_confirmation"),
        AGUI(agent=user_input_agent, prefix="/user_input"),
        AGUI(agent=backend_feedback_agent, prefix="/backend_feedback"),
    ],
)
app = agent_os.get_app()

if __name__ == "__main__":
    print("AG-UI Showcase Server")
    print("Endpoints:")
    print("  /agentic_chat — Chat, Tools, Streaming")
    print("  /backend_tool_rendering — Backend tool rendering")
    print("  /human_in_the_loop — Task planning with step selection")
    print("  /tool_based_generative_ui — Generative UI (action), Tools")
    print("  /shared_state — Agent State, Collaborating")
    print("  /agentic_chat_reasoning — Chat, Tools, Streaming, Reasoning")
    print("  /agentic_chat_multimodal — Chat, Multimodal, Streaming")
    print("  /tool_confirmation — Email/delete with confirmation")
    print("  /user_input — Text/secret input collection")
    print("  /backend_feedback — Multiple choice selection")
    agent_os.serve(app="showcase:app", reload=True, port=9001)
```

The example imports these helper modules from the same directory:

```python agent_with_media.py theme={null}
"""
Agent With Media
================
AG-UI agent that accepts multimodal input (images, audio, video, documents).

Uses Google Gemini to analyze attached files. Set GOOGLE_API_KEY env var.
"""

from agno.agent.agent import Agent
from agno.db.sqlite import SqliteDb
from agno.models.google import Gemini
from agno.os import AgentOS
from agno.os.interfaces.agui import AGUI

# ---------------------------------------------------------------------------
# Create Example
# ---------------------------------------------------------------------------

media_agent = Agent(
    name="Media Agent",
    model=Gemini(id="gemini-2.5-flash"),
    db=SqliteDb(db_file="/tmp/agui_agent_with_media.db"),
    instructions="Analyze any image, audio, video, or document the user sends and answer their question about it.",
    add_datetime_to_context=True,
    markdown=True,
)

# Setup your AgentOS app
# Dojo expects: http://localhost:9001/agentic_chat_multimodal/agui
agent_os = AgentOS(
    agents=[media_agent],
    interfaces=[AGUI(agent=media_agent, prefix="/agentic_chat_multimodal")],
)
app = agent_os.get_app()


# ---------------------------------------------------------------------------
# Run Example
# ---------------------------------------------------------------------------
if __name__ == "__main__":
    agent_os.serve(app="agent_with_media:app", port=9001, reload=True)
```

```python agentic_chat.py theme={null}
"""
Agentic Chat — Dojo Demo
========================

Frontend tool: change_background (external_execution)
Backend tool: get_weather (renders as card via useRenderTool)

Dojo expects:
- change_background(background: str) -> changes CSS background
- get_weather(location: str) -> dict with city, temperature, humidity, wind_speed, conditions
"""

from agno.agent.agent import Agent
from agno.db.sqlite import SqliteDb
from agno.models.openai import OpenAIResponses
from agno.tools import tool


@tool(external_execution=True, external_execution_silent=True)
def change_background(background: str) -> str:
    """Change the background color of the chat. Can be anything that the CSS background attribute accepts. Regular colors, linear or radial gradients etc."""
    return f"Background changed to {background}"


@tool
def get_weather(location: str) -> dict:
    """Get the current weather for a location."""
    data = {
        "San Francisco": {
            "city": "San Francisco",
            "temperature": 18,
            "humidity": 65,
            "wind_speed": 12,
            "conditions": "Sunny",
        },
        "New York": {
            "city": "New York",
            "temperature": 22,
            "humidity": 55,
            "wind_speed": 8,
            "conditions": "Cloudy",
        },
        "Tokyo": {
            "city": "Tokyo",
            "temperature": 26,
            "humidity": 70,
            "wind_speed": 5,
            "conditions": "Rainy",
        },
        "London": {
            "city": "London",
            "temperature": 15,
            "humidity": 80,
            "wind_speed": 15,
            "conditions": "Overcast",
        },
        "Paris": {
            "city": "Paris",
            "temperature": 20,
            "humidity": 60,
            "wind_speed": 10,
            "conditions": "Partly cloudy",
        },
    }
    return data.get(
        location,
        {
            "city": location,
            "temperature": 20,
            "humidity": 60,
            "wind_speed": 10,
            "conditions": "Partly cloudy",
        },
    )


agentic_chat_agent = Agent(
    name="agentic_chat",
    model=OpenAIResponses(id="gpt-5.5"),
    db=SqliteDb(db_file="/tmp/agentic_chat.db"),
    tools=[change_background, get_weather],
    instructions="""You are a helpful assistant with frontend and backend capabilities.

Tools available:
- change_background: Changes the page background. Accepts CSS values (colors, gradients). Only use when explicitly asked.
- get_weather: Gets weather for a location. Returns temperature, humidity, wind speed, and conditions.

Be helpful and use tools when appropriate.""",
    markdown=True,
)
```

```python backend_feedback.py theme={null}
"""
Backend Feedback — Dojo Demo
============================

Frontend-provided tool: get_user_choice (via useHumanInTheLoop)

The frontend defines this tool for presenting multiple choices to the user.
When called, it renders a card with radio buttons for selection.
"""

from agno.agent.agent import Agent
from agno.db.sqlite import SqliteDb
from agno.models.openai import OpenAIResponses

backend_feedback_agent = Agent(
    name="backend_feedback",
    model=OpenAIResponses(id="gpt-5.5"),
    db=SqliteDb(db_file="/tmp/agui_backend_feedback.db"),
    instructions="""You are an assistant that helps users make decisions.

When you need the user to choose from options:
- Call get_user_choice with: question, options (array of strings)
- Wait for user to select an option

Example get_user_choice call:
{
  "question": "What type of cuisine would you prefer for dinner?",
  "options": ["Italian", "Japanese", "Mexican", "Indian", "Thai"]
}

After receiving the selection:
- Acknowledge their choice
- Provide relevant recommendations or next steps based on their selection
- Ask follow-up questions if needed using get_user_choice again""",
    markdown=True,
)
```

```python backend_tool_rendering.py theme={null}
"""
Backend Tool Rendering — Dojo Demo
===================================

Backend tool: get_weather (renders as weather card via useRenderTool)

Dojo expects get_weather(location: str) with detailed return:
- city, temperature, humidity, wind_speed, conditions
- Rendered as a styled weather card in the frontend
"""

from agno.agent.agent import Agent
from agno.db.sqlite import SqliteDb
from agno.models.openai import OpenAIResponses
from agno.tools import tool


@tool
def get_weather(location: str) -> dict:
    """Get detailed weather for a location. Returns structured data for frontend rendering."""
    data = {
        "San Francisco": {
            "city": "San Francisco",
            "temperature": 18,
            "humidity": 65,
            "wind_speed": 12,
            "conditions": "Sunny",
        },
        "New York": {
            "city": "New York",
            "temperature": 22,
            "humidity": 55,
            "wind_speed": 8,
            "conditions": "Cloudy",
        },
        "Tokyo": {
            "city": "Tokyo",
            "temperature": 26,
            "humidity": 70,
            "wind_speed": 5,
            "conditions": "Rainy",
        },
        "London": {
            "city": "London",
            "temperature": 15,
            "humidity": 80,
            "wind_speed": 15,
            "conditions": "Overcast",
        },
        "Paris": {
            "city": "Paris",
            "temperature": 20,
            "humidity": 60,
            "wind_speed": 10,
            "conditions": "Partly cloudy",
        },
    }
    return data.get(
        location,
        {
            "city": location,
            "temperature": 20,
            "humidity": 60,
            "wind_speed": 10,
            "conditions": "Partly cloudy",
        },
    )


backend_tool_agent = Agent(
    name="backend_tool_rendering",
    model=OpenAIResponses(id="gpt-5.5"),
    db=SqliteDb(db_file="/tmp/agui_backend_tool_rendering.db"),
    tools=[get_weather],
    instructions="""You help users check weather. When asked about weather, always use the get_weather tool.

The tool returns structured data that the frontend will render as a weather card.""",
    markdown=True,
)
```

```python human_in_the_loop.py theme={null}
"""
Human in the Loop — Dojo Demo
==============================

Frontend-provided tool: generate_task_steps (external_execution)

The frontend defines this tool via useHumanInTheLoop hook. The agent calls it,
and the frontend renders an interactive step-selector UI where the user can
toggle steps on/off and confirm.

Backend does NOT define the tool — it comes from the frontend in the request.
"""

from agno.agent.agent import Agent
from agno.db.sqlite import SqliteDb
from agno.models.openai import OpenAIResponses

hitl_agent = Agent(
    name="human_in_the_loop",
    model=OpenAIResponses(id="gpt-5.5"),
    db=SqliteDb(db_file="/tmp/agui_human_in_the_loop.db"),
    instructions="""You are a task planning assistant. When asked to plan something:

1. **IMMEDIATELY call the generate_task_steps tool** with a list of steps
2. Generate exactly 10 clear, actionable steps
3. Each step must be an object with:
   - description: Brief imperative form (e.g., "Research travel options")
   - status: Set to "enabled" initially

Example tool call for "plan a trip to Mars":
{
  "steps": [
    {"description": "Research Mars travel options", "status": "enabled"},
    {"description": "Prepare necessary equipment", "status": "enabled"},
    {"description": "Complete health screenings", "status": "enabled"},
    ...
  ]
}

After calling the tool:
- Briefly confirm: "I've created a 10-step plan for you!"
- Don't repeat the steps (they're visible in the UI)
- Ask the user to review and select which steps to perform

When user provides feedback (after clicking "Perform Steps"):
- Acknowledge which steps were approved
- Provide a brief summary of next actions""",
    markdown=True,
)
```

```python reasoning_agent.py theme={null}
"""
Reasoning Agent
===============

Demonstrates reasoning agent.
"""

from agno.agent.agent import Agent
from agno.db.sqlite import SqliteDb
from agno.models.openai import OpenAIResponses
from agno.os import AgentOS
from agno.os.interfaces.agui import AGUI
from agno.tools.websearch import WebSearchTools

# ---------------------------------------------------------------------------
# Create Example
# ---------------------------------------------------------------------------

chat_agent = Agent(
    name="Assistant",
    model=OpenAIResponses(id="o4-mini"),
    db=SqliteDb(db_file="/tmp/agui_reasoning_agent.db"),
    instructions="You are a helpful AI assistant.",
    add_datetime_to_context=True,
    add_history_to_context=True,
    add_location_to_context=True,
    timezone_identifier="Etc/UTC",
    markdown=True,
    tools=[WebSearchTools()],
)

# Setup your AgentOS app
agent_os = AgentOS(
    agents=[chat_agent],
    interfaces=[AGUI(agent=chat_agent)],
)
app = agent_os.get_app()


# ---------------------------------------------------------------------------
# Run Example
# ---------------------------------------------------------------------------

if __name__ == "__main__":
    """Run your AgentOS.

    You can see the configuration and available apps at:
    http://localhost:9001/config

    """
    agent_os.serve(app="reasoning_agent:app", reload=True, port=9001)
```

```python shared_state.py theme={null}
"""
Shared State — Dojo Demo
=========================

Agent with session state that syncs with frontend.

Dojo expects state structure:
{
    "recipe": {
        "title": str,
        "skill_level": "Beginner" | "Intermediate" | "Advanced",
        "cooking_time": "5 min" | "15 min" | "30 min" | "45 min" | "60+ min",
        "special_preferences": List[str],  # "High Protein", "Low Carb", "Spicy", etc.
        "ingredients": List[{icon: str, name: str, amount: str}],
        "instructions": List[str]
    }
}

The agent uses update_session_state tool to modify state, which triggers
STATE_DELTA events that the frontend uses to update the recipe UI.
"""

from agno.agent.agent import Agent
from agno.db.sqlite import SqliteDb
from agno.models.openai import OpenAIResponses

shared_state_agent = Agent(
    name="shared_state",
    model=OpenAIResponses(id="gpt-5.5"),
    db=SqliteDb(db_file="/tmp/agui_shared_state.db"),
    session_state={
        "recipe": {
            "title": "Make Your Recipe",
            "skill_level": "Intermediate",
            "cooking_time": "45 min",
            "special_preferences": [],
            "ingredients": [
                {"icon": "🥕", "name": "Carrots", "amount": "3 large, grated"},
                {"icon": "🌾", "name": "All-Purpose Flour", "amount": "2 cups"},
            ],
            "instructions": ["Preheat oven to 350°F (175°C)"],
        }
    },
    add_session_state_to_context=True,
    enable_agentic_state=True,
    instructions="""You are a recipe assistant. The current recipe state is shown in <session_state>.

Use update_session_state to modify the recipe. The structure is:
- title: Recipe name (string)
- skill_level: "Beginner", "Intermediate", or "Advanced"
- cooking_time: "5 min", "15 min", "30 min", "45 min", or "60+ min"
- special_preferences: List of strings like "High Protein", "Low Carb", "Spicy", "Budget-Friendly", "One-Pot Meal", "Vegetarian", "Vegan"
- ingredients: List of objects with {icon: emoji, name: string, amount: string}
- instructions: List of step strings

When modifying:
1. Read the current state from <session_state>
2. Use update_session_state with the fields you want to change
3. Preserve existing values for fields you don't change

Example: To add an ingredient, include the existing ingredients plus the new one.""",
    markdown=True,
)
```

```python tool_based_generative_ui.py theme={null}
"""
Tool Based Generative UI — Dojo Demo
=====================================

Frontend tool: generate_haiku (external_execution)

Dojo expects generate_haiku with:
- japanese: List[str] - 3 lines of haiku in Japanese
- english: List[str] - 3 lines translated to English
- image_name: str - One of the valid image names
- gradient: str - CSS gradient for background

Valid image names (from Dojo):
- Osaka_Castle_Turret_Stone_Wall_Pine_Trees_Daytime.jpg
- Tokyo_Skyline_Night_Tokyo_Tower_Mount_Fuji_View.jpg
- Itsukushima_Shrine_Miyajima_Floating_Torii_Gate_Sunset_Long_Exposure.jpg
- Takachiho_Gorge_Waterfall_River_Lush_Greenery_Japan.jpg
- Bonsai_Tree_Potted_Japanese_Art_Green_Foliage.jpeg
- Shirakawa-go_Gassho-zukuri_Thatched_Roof_Village_Aerial_View.jpg
- Ginkaku-ji_Silver_Pavilion_Kyoto_Japanese_Garden_Pond_Reflection.jpg
- Senso-ji_Temple_Asakusa_Cherry_Blossoms_Kimono_Umbrella.jpg
- Cherry_Blossoms_Sakura_Night_View_City_Lights_Japan.jpg
- Mount_Fuji_Lake_Reflection_Cherry_Blossoms_Sakura_Spring.jpg
"""

from typing import List

from agno.agent.agent import Agent
from agno.db.sqlite import SqliteDb
from agno.models.openai import OpenAIResponses
from agno.tools import tool

VALID_IMAGE_NAMES = [
    "Osaka_Castle_Turret_Stone_Wall_Pine_Trees_Daytime.jpg",
    "Tokyo_Skyline_Night_Tokyo_Tower_Mount_Fuji_View.jpg",
    "Itsukushima_Shrine_Miyajima_Floating_Torii_Gate_Sunset_Long_Exposure.jpg",
    "Takachiho_Gorge_Waterfall_River_Lush_Greenery_Japan.jpg",
    "Bonsai_Tree_Potted_Japanese_Art_Green_Foliage.jpeg",
    "Shirakawa-go_Gassho-zukuri_Thatched_Roof_Village_Aerial_View.jpg",
    "Ginkaku-ji_Silver_Pavilion_Kyoto_Japanese_Garden_Pond_Reflection.jpg",
    "Senso-ji_Temple_Asakusa_Cherry_Blossoms_Kimono_Umbrella.jpg",
    "Cherry_Blossoms_Sakura_Night_View_City_Lights_Japan.jpg",
    "Mount_Fuji_Lake_Reflection_Cherry_Blossoms_Sakura_Spring.jpg",
]


@tool(external_execution=True, external_execution_silent=True)
def generate_haiku(
    japanese: List[str], english: List[str], image_name: str, gradient: str
) -> str:
    """Generate and display a haiku with image and styling.

    Args:
        japanese: 3 lines of haiku in Japanese
        english: 3 lines of haiku translated to English
        image_name: One relevant image name from the valid list
        gradient: CSS gradient color for the background (e.g., "linear-gradient(135deg, #667eea 0%, #764ba2 100%)")
    """
    return "Haiku generated and displayed in frontend"


generative_ui_agent = Agent(
    name="tool_based_generative_ui",
    model=OpenAIResponses(id="gpt-5.5"),
    db=SqliteDb(db_file="/tmp/agui_tool_based_generative_ui.db"),
    tools=[generate_haiku],
    instructions=f"""You are a haiku poet. When asked to create a haiku:

1. Create a beautiful haiku in both English (5-7-5 syllables) and Japanese
2. Choose a relevant image from: {", ".join(VALID_IMAGE_NAMES)}
3. Choose a beautiful CSS gradient for the background
4. Use the generate_haiku tool with all parameters

Example gradient: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)"

The frontend will render your haiku with the image and gradient as a beautiful card.""",
    markdown=True,
)
```

```python tool_confirmation.py theme={null}
"""
Tool Confirmation — Dojo Demo
=============================

Frontend-provided tools: send_email, delete_files (via useHumanInTheLoop)

The frontend defines these tools as requiring confirmation before execution.
When the agent calls them, the frontend renders a confirmation card.
User can approve or reject the action.
"""

from agno.agent.agent import Agent
from agno.db.sqlite import SqliteDb
from agno.models.openai import OpenAIResponses

tool_confirmation_agent = Agent(
    name="tool_confirmation",
    model=OpenAIResponses(id="gpt-5.5"),
    db=SqliteDb(db_file="/tmp/agui_tool_confirmation.db"),
    instructions="""You are an assistant that can send emails and delete files.
Both actions require user confirmation before execution.

When asked to send an email:
- Call the send_email tool with: to, subject, body
- Wait for user confirmation

When asked to delete files:
- Call the delete_files tool with: action, description, details
- Wait for user confirmation

Example email tool call:
{
  "to": "alice@example.com",
  "subject": "Hello!",
  "body": "Just wanted to say hi."
}

Example delete tool call:
{
  "action": "Delete temporary files",
  "description": "Remove all .tmp files from the project",
  "details": {"count": "15 files", "size": "2.3 MB"}
}

After user confirms or rejects:
- Acknowledge the decision
- If confirmed, confirm the action was taken
- If rejected, acknowledge and ask if there's anything else""",
    markdown=True,
)
```

```python user_input.py theme={null}
"""
User Input — Dojo Demo
======================

Frontend-provided tools: get_user_text, get_secret_input (via useHumanInTheLoop)

The frontend defines these tools for collecting user input inline.
- get_user_text: Shows a text input field
- get_secret_input: Shows a password-style input for sensitive data
"""

from agno.agent.agent import Agent
from agno.db.sqlite import SqliteDb
from agno.models.openai import OpenAIResponses

user_input_agent = Agent(
    name="user_input",
    model=OpenAIResponses(id="gpt-5.5"),
    db=SqliteDb(db_file="/tmp/agui_user_input.db"),
    instructions="""You are an assistant that can request input from the user.

When you need text input from the user:
- Call get_user_text with: prompt, placeholder (optional)
- Wait for user to provide input

When you need sensitive input (API keys, passwords):
- Call get_secret_input with: prompt, service (optional)
- Wait for user to provide input

Example get_user_text call:
{
  "prompt": "What would you like to search for?",
  "placeholder": "Enter search term..."
}

Example get_secret_input call:
{
  "prompt": "Please enter your OpenAI API key",
  "service": "OpenAI"
}

After receiving input:
- Acknowledge what was provided (don't echo secrets)
- Use the input to complete the user's request""",
    markdown=True,
)
```

## Run the Example

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

  <Step title="Install dependencies">
    ```bash theme={null}
    uv pip install -U "agno[agui,os]" ddgs google-genai openai requests
    ```
  </Step>

  <Step title="Export your API keys">
    <CodeGroup>
      ```bash Mac/Linux theme={null}
      export GOOGLE_API_KEY="your_google_api_key_here"
      export OPENAI_API_KEY="your_openai_api_key_here"
      ```

      ```bash Windows theme={null}
      $Env:GOOGLE_API_KEY="your_google_api_key_here"
      $Env:OPENAI_API_KEY="your_openai_api_key_here"
      ```
    </CodeGroup>
  </Step>

  <Step title="Run the example">
    Save the code blocks above as `showcase.py`, `agent_with_media.py`, `agentic_chat.py`, `backend_feedback.py`, `backend_tool_rendering.py`, `human_in_the_loop.py`, `reasoning_agent.py`, `shared_state.py`, `tool_based_generative_ui.py`, `tool_confirmation.py`, `user_input.py` in the same directory, then run:

    ```bash theme={null}
    python showcase.py
    ```
  </Step>
</Steps>

Full source: [cookbook/05\_agent\_os/interfaces/agui/showcase.py](https://github.com/agno-agi/agno/blob/v2.7.4/cookbook/05_agent_os/interfaces/agui/showcase.py)
