showcase.py
"""
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)
agent_with_media.py
"""
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)
agentic_chat.py
"""
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,
)
backend_tool_rendering.py
"""
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,
)
human_in_the_loop.py
"""
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,
)
reasoning_agent.py
"""
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)
shared_state.py
"""
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,
)
tool_based_generative_ui.py
"""
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
Set up your virtual environment
uv venv --python 3.12
source .venv/bin/activate
uv venv --python 3.12
.venv\Scripts\activate
Export your API keys
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"
$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"