> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agno.com/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:3002.

```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:3002.

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_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

agent_os = AgentOS(
    agents=[
        agentic_chat_agent,
        backend_tool_agent,
        hitl_agent,
        generative_ui_agent,
        shared_state_agent,
        reasoning_agent,
        media_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"),
    ],
)
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 — Agent State, Collaborating")
    print("  /human_in_the_loop — HITL, Interactivity")
    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")
    agent_os.serve(app="showcase:app", reload=True, port=9001)
```

The example imports this 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.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"),
    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_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.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"),
    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
==============================

HITL tool: generate_task_steps (requires_confirmation)

Dojo expects generate_task_steps that returns:
- steps: list of {description: str, status: "enabled"|"disabled"|"executing"}

The frontend renders a step selector UI where user can toggle steps and confirm/reject.
"""

from typing import List

from agno.agent.agent import Agent
from agno.models.openai import OpenAIResponses
from agno.tools import tool
from pydantic import BaseModel, Field


class TaskStep(BaseModel):
    description: str = Field(description="Description of the step")
    status: str = Field(
        default="enabled", description="Status: enabled, disabled, or executing"
    )


@tool(requires_confirmation=True)
def generate_task_steps(steps: List[TaskStep]) -> str:
    """Generate a list of task steps for the user to review and confirm.

    The frontend will display these steps with checkboxes.
    User can enable/disable steps before confirming execution.
    """
    enabled_steps = [s for s in steps if s.status == "enabled"]
    return f"Executing {len(enabled_steps)} steps: " + ", ".join(
        s.description for s in enabled_steps
    )


hitl_agent = Agent(
    name="human_in_the_loop",
    model=OpenAIResponses(id="gpt-5.5"),
    tools=[generate_task_steps],
    instructions="""You help users plan tasks that require confirmation.

When asked to plan something (trip, recipe, project, etc.):
1. Break it down into clear steps (5-10 steps typically)
2. Use the generate_task_steps tool with a list of steps
3. Each step should have a description and status="enabled"

Example: For "plan a trip to Paris", create steps like:
- Book flights
- Reserve hotel
- Plan activities
- Pack luggage
- etc.

The user will review and confirm which steps to execute.""",
    markdown=True,
)
```

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

Demonstrates reasoning agent.
"""

from agno.agent.agent import Agent
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"),
    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.models.openai import OpenAIResponses

shared_state_agent = Agent(
    name="shared_state",
    model=OpenAIResponses(id="gpt-5.5"),
    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.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"),
    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,
)
```

## 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 fastmcp google-genai openai starlette
    ```
  </Step>

  <Step title="Export your API keys">
    <CodeGroup>
      ```bash Mac/Linux theme={null}
      export GOOGLE_API_KEY="your_google_api_key_here"
      export JWT_VERIFICATION_KEY="your_jwt_verification_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:JWT_VERIFICATION_KEY="your_jwt_verification_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_tool_rendering.py`, `human_in_the_loop.py`, `reasoning_agent.py`, `shared_state.py`, `tool_based_generative_ui.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/main/cookbook/05_agent_os/interfaces/agui/showcase.py)
