Updated AI tac_tac_toe agent

This commit is contained in:
ShubhamSaboo 2025-02-25 21:51:38 -06:00
parent 81b75cf72c
commit aa49a0dcc9
8 changed files with 320 additions and 657 deletions

View file

@ -1,32 +1,23 @@
# 🎮 Agent X vs Agent O: Tic-Tac-Toe Game
An interactive Tic-Tac-Toe game where two AI agents powered by different language models compete against each other built on Agno Agent Framework and Streamlit as UI. Watch as GPT-4O battles against either DeepSeek V3 or Google's Gemini 1.5 Flash in this classic game.
An interactive Tic-Tac-Toe game where two AI agents powered by different language models compete against each other built on Agno Agent Framework and Streamlit as UI.
This example shows how to build an interactive Tic Tac Toe game where AI agents compete against each other. The application showcases how to:
- Coordinate multiple AI agents in a turn-based game
- Use different language models for different players
- Create an interactive web interface with Streamlit
- Handle game state and move validation
- Display real-time game progress and move history
## Features
- Multiple AI models support (GPT-4, Claude, Gemini, etc.)
- Real-time game visualization
- Move history tracking with board states
- Interactive player selection
- Game state management
- Move validation and coordination
### Multi-Agent System
- Player X: OpenAI's Gemini Flash 2.0
- Player O: DeepSeek v3
- Judge: GPT-4o for game outcome validation
### Interactive Interface
- Real-time game board visualization
- Move-by-move analysis
- Agent response tracking
- Clear game status updates
### Strategic Gameplay
- AI-powered move decisions
- Winning strategy implementation
- Opponent move blocking
- Victory condition monitoring
## Prerequisites
- Python 3.8+
- OpenAI API key
- Either DeepSeek API key or Google API key (for Player O)
## How to Run
## How to Run?
1. **Setup Environment**
```bash
@ -38,40 +29,78 @@ An interactive Tic-Tac-Toe game where two AI agents powered by different languag
pip install -r requirements.txt
```
2. **Configure API Keys**
- Get OpenAI API key from [OpenAI Platform](https://platform.openai.com)
- Get Google API key from [Google AI Studio](https://aistudio.google.com) (if using Gemini)
- Get DeepSeek API key from DeepSeek platform [Deepseek platform](https://www.deepseek.com) (if using DeepSeek v3 model)
### 2. Install dependencies
4. **Run the Application**
```bash
streamlit run ai_tic_tac_toe_agent.py
```
```shell
pip install -r requirements.txt
```
5. **Using the Interface**
- Enter your API keys in the sidebar
- Click "Start Game" to begin
- Watch as the AI agents battle it out!
- Monitor the game progress and final results
### 3. Export API Keys
## Game Components
The game supports multiple AI models. Export the API keys for the models you want to use:
- **Game Board**
- 3x3 interactive grid
- Real-time move visualization
- Clear symbol placement (X/O)
```shell
# Required for OpenAI models
export OPENAI_API_KEY=***
- **AI Agent Players**
- Player X: Strategic offensive moves
- Player O: Defensive countermoves since this agent started later
- AI Judge: Game outcome validation
# Optional - for additional models
export ANTHROPIC_API_KEY=*** # For Claude models
export GOOGLE_API_KEY=*** # For Gemini models
export GROQ_API_KEY=*** # For Groq models
```
- **Game Flow**
- Alternating turns between AIs
- Move validation and error handling
- Winner determination
- Draw detection
### 4. Run the Game
## Disclaimer ⚠️
```shell
streamlit run app.py
```
This is a demonstration project showcasing AI capabilities in game playing. API costs will apply based on your usage of the OpenAI, DeepSeek, or Google APIs.
- Open [localhost:8501](http://localhost:8501) to view the game interface
## How It Works
The game consists of three agents:
1. **Master Agent (Referee)**
- Coordinates the game
- Validates moves
- Maintains game state
- Determines game outcome
2. **Two Player Agents**
- Make strategic moves
- Analyze board state
- Follow game rules
- Respond to opponent moves
## Available Models
The game supports various AI models:
- GPT-4o (OpenAI)
- GPT-o3-mini (OpenAI)
- Gemini (Google)
- Llama 3 (Groq)
- Claude (Anthropic)
## Game Features
1. **Interactive Board**
- Real-time updates
- Visual move tracking
- Clear game status display
2. **Move History**
- Detailed move tracking
- Board state visualization
- Player action timeline
3. **Game Controls**
- Start/Pause game
- Reset board
- Select AI models
- View game history
4. **Performance Analysis**
- Move timing
- Strategy tracking
- Game statistics

View file

@ -1,259 +0,0 @@
import re
import streamlit as st
from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.models.deepseek import DeepSeek
from agno.models.google import Gemini
# Streamlit App Title
st.title("🎮 Agent X vs Agent O: Tic-Tac-Toe Game")
# Enhanced Welcome Message
with st.chat_message("assistant"):
st.markdown("""
**Welcome to the Tic-Tac-Toe AI Battle!** 🎮
This project pits two advanced AI agents against each other in a classic game of Tic-Tac-Toe.
Here's what you need to know:
""")
st.info("""
- **Player X**: Powered by Google's Gemini Flash 2.0.
- **Player O**: Powered by DeepSeek v3.
- **How to Play**: Enter your API keys in the sidebar, click **Start Game**, and watch the AI battle it out!
- **Goal**: The first player to get three of their symbols in a row (horizontally, vertically, or diagonally) wins.
- **Draw**: If the board fills up without a winner, the game ends in a draw.
""")
st.markdown("Ready to see who wins? Click the **Start Game** button below! 🚀")
# Initialize the game board in session state
if 'board' not in st.session_state:
st.session_state.board = [[None, None, None],
[None, None, None],
[None, None, None]]
# Function to display the board with better styling
def display_board(board):
st.markdown("""
<style>
.board {
display: grid;
grid-template-columns: repeat(3, 50px);
grid-template-rows: repeat(3, 50px);
gap: 5px;
margin-bottom: 20px;
}
.cell {
display: flex;
align-items: center;
justify-content: center;
border: 1px solid #ccc;
font-size: 20px;
font-weight: bold;
}
</style>
""", unsafe_allow_html=True)
st.write("Current Board:")
board_html = '<div class="board">'
for row in board:
for cell in row:
cell_value = cell if cell is not None else "&nbsp;"
board_html += f'<div class="cell">{cell_value}</div>'
board_html += '</div>'
st.markdown(board_html, unsafe_allow_html=True)
# Function to get the board state as a string
def get_board_state(board):
rows = []
for i, row in enumerate(board):
row_str = " | ".join([f"({i},{j}) {cell or ' '}" for j, cell in enumerate(row)])
rows.append(f"Row {i}: {row_str}")
return "\n".join(rows)
# Function to check for a winner
def check_winner(board):
# Check rows
for row in board:
if row[0] == row[1] == row[2] and row[0] is not None:
return row[0]
# Check columns
for col in range(3):
if board[0][col] == board[1][col] == board[2][col] and board[0][col] is not None:
return board[0][col]
# Check diagonals
if board[0][0] == board[1][1] == board[2][2] and board[0][0] is not None:
return board[0][0]
if board[0][2] == board[1][1] == board[2][0] and board[0][2] is not None:
return board[0][2]
# Check for draw
if all(cell is not None for row in board for cell in row):
return "Draw"
return None
# Sidebar for API keys
st.sidebar.header("API Keys")
openai_api_key = st.sidebar.text_input("Enter your OpenAI API Key", type="password")
deepseek_api_key = st.sidebar.text_input("Enter your DeepSeek API Key", type="password")
google_api_key = st.sidebar.text_input("Enter your Google API Key (for Gemini)", type="password")
if openai_api_key:
st.session_state.openai_api_key = openai_api_key
if deepseek_api_key:
st.session_state.deepseek_api_key = deepseek_api_key
if google_api_key:
st.session_state.google_api_key = google_api_key
# Initialize agents if API keys are provided
if 'openai_api_key' in st.session_state:
player_x = Agent(
name="Player X",
model=Gemini(id="gemini-2.0-flash-exp", api_key=st.session_state.google_api_key),
instructions=[
"You are a Tic-Tac-Toe player using the symbol 'X'.",
"Your opponent is using the symbol 'O'. Block their potential winning moves.",
"Make your move in the format 'row, col' based on the current board state.",
"Strategize to win by placing your symbol in a way that blocks your opponent from forming a straight line.",
"Do not include any explanations or extra text. Only provide the move.",
"Row and column indices start from 0.",
],
markdown=True,
)
# Initialize Player O with DeepSeek or Google Gemini
if 'deepseek_api_key' in st.session_state:
player_o = Agent(
name="Player O",
model=DeepSeek(id="deepseek-chat", api_key=st.session_state.deepseek_api_key),
instructions=[
"You are a Tic-Tac-Toe player using the symbol 'O'.",
"Your opponent is using the symbol 'X'. Block their potential winning moves.",
"Make your move in the format 'row, col' based on the current board state.",
"Strategize to win by placing your symbol in a way that blocks your opponent from forming a straight line.",
"Do not include any explanations or extra text. Only provide the move.",
"Row and column indices start from 0.",
],
markdown=True,
)
else:
st.warning("Please provide either a DeepSeek API key or a Google API key for Player O.")
judge = Agent(
name="Judge",
model=OpenAIChat(id="gpt-4o", temperature=0.1, api_key=st.session_state.openai_api_key),
instructions=[
"You are the judge of a Tic-Tac-Toe game.",
"The board is presented as rows with positions separated by '|'.",
"Rows are labeled from 0 to 2, and columns from 0 to 2.",
"Example board state:",
"Row 0: (0,0) X | (0,1) | (0,2) O",
"Row 1: (1,0) O | (1,1) X | (1,2) X",
"Row 2: (2,0) X | (2,1) O | (2,2) O",
"Determine the winner based on this board state.",
"The winner is the player with three of their symbols in a straight line (row, column, or diagonal).",
"If the board is full and there is no winner, declare a draw.",
"Provide only the result (e.g., 'Player X wins', 'Player O wins', 'Draw').",
],
markdown=True,
)
# Function to extract the move from the agent's response
def extract_move(response):
content = response.content.strip()
match = re.search(r'\d\s*,\s*\d', content)
if match:
move = match.group().replace(' ', '')
return move
numbers = re.findall(r'\d+', content)
if len(numbers) >= 2:
row = int(numbers[0])
col = int(numbers[1])
return f"{row},{col}"
return None
# Game loop
def play_game():
if 'current_player' not in st.session_state:
st.session_state.current_player = player_x
if 'symbol' not in st.session_state:
st.session_state.symbol = "X"
if 'move_count' not in st.session_state:
st.session_state.move_count = 0
max_moves = 9
winner = None # Initialize winner variable
while st.session_state.move_count < max_moves:
# Display the board
display_board(st.session_state.board)
# Prepare the board state for the agent
board_state = get_board_state(st.session_state.board)
move_prompt = (
f"Current board state:\n{board_state}\n"
f"{st.session_state.current_player.name}'s turn. Make your move in the format 'row, col'."
)
# Get the current player's move
with st.chat_message("assistant"):
st.write(f"**{st.session_state.current_player.name}'s turn:**")
move_response = st.session_state.current_player.run(move_prompt)
st.code(f"Agent {st.session_state.current_player.name} response:\n{move_response.content}", language="markdown")
move = extract_move(move_response)
st.write(f"**Extracted move:** {move}")
if move is None:
st.error("Invalid move! Please use the format 'row, col'.")
continue
try:
row, col = map(int, move.split(','))
if st.session_state.board[row][col] is not None:
st.error("Invalid move! Cell already occupied.")
continue
st.session_state.board[row][col] = st.session_state.symbol
except (ValueError, IndexError):
st.error("Invalid move! Please use the format 'row, col'.")
continue
# Check for a winner or draw
winner = check_winner(st.session_state.board)
if winner:
break # Exit the loop if there's a winner
# Switch players
st.session_state.current_player = player_o if st.session_state.current_player == player_x else player_x
st.session_state.symbol = "O" if st.session_state.symbol == "X" else "X"
st.session_state.move_count += 1
# After the game loop, display the final board and involve the judge agent
st.write("**Final Board:**")
display_board(st.session_state.board)
if winner:
st.success(f"**Result:** {winner}")
else:
st.success("**Result:** Draw")
# Judge's announcement
st.write("\n**Game Over. Judge is determining the result...**")
st.write("**Final board state passed to judge:**")
st.code(get_board_state(st.session_state.board), language="markdown")
judge_prompt = (
f"Final board state:\n{get_board_state(st.session_state.board)}\n"
f"Determine the winner and announce the result."
)
judge_response = judge.run(judge_prompt)
st.code(f"Judge's raw response:\n{judge_response.content}", language="markdown")
announcement = judge_response.content.strip()
st.success(f"**Judge's Announcement:** {announcement}")
# Start Game Button
if st.button("Start Game"):
st.session_state.board = [[None, None, None],
[None, None, None],
[None, None, None]]
st.session_state.current_player = player_x
st.session_state.symbol = "X"
st.session_state.move_count = 0
play_game()
else:
st.warning("Please enter your OpenAI API key and either Deepseek/Gemini API key to start the game.")

View file

@ -1,4 +1,238 @@
streamlit==1.41.1
agno
openai==1.58.1
google-generativeai==0.8.3
# This file was autogenerated by uv via the following command:
# ./generate_requirements.sh
agno==1.1.6
# via -r cookbook/examples/apps/tic_tac_toe/requirements.in
altair==5.5.0
# via streamlit
annotated-types==0.7.0
# via pydantic
anthropic==0.47.1
# via -r cookbook/examples/apps/tic_tac_toe/requirements.in
anyio==4.8.0
# via
# anthropic
# groq
# httpx
# openai
attrs==25.1.0
# via
# jsonschema
# referencing
blinker==1.9.0
# via streamlit
build==1.2.2.post1
# via pip-tools
cachetools==5.5.2
# via
# google-auth
# streamlit
certifi==2025.1.31
# via
# httpcore
# httpx
# requests
charset-normalizer==3.4.1
# via requests
click==8.1.8
# via
# pip-tools
# streamlit
# typer
distro==1.9.0
# via
# anthropic
# groq
# openai
docstring-parser==0.16
# via agno
gitdb==4.0.12
# via gitpython
gitpython==3.1.44
# via
# agno
# streamlit
google-auth==2.38.0
# via google-genai
google-genai==1.3.0
# via -r cookbook/examples/apps/tic_tac_toe/requirements.in
groq==0.18.0
# via -r cookbook/examples/apps/tic_tac_toe/requirements.in
h11==0.14.0
# via httpcore
httpcore==1.0.7
# via httpx
httpx==0.28.1
# via
# agno
# anthropic
# google-genai
# groq
# ollama
# openai
idna==3.10
# via
# anyio
# httpx
# requests
jinja2==3.1.5
# via
# altair
# pydeck
jiter==0.8.2
# via
# anthropic
# openai
jsonschema==4.23.0
# via altair
jsonschema-specifications==2024.10.1
# via jsonschema
markdown-it-py==3.0.0
# via rich
markupsafe==3.0.2
# via jinja2
mdurl==0.1.2
# via markdown-it-py
narwhals==1.28.0
# via altair
nest-asyncio==1.6.0
# via -r cookbook/examples/apps/tic_tac_toe/requirements.in
numpy==2.2.3
# via
# pandas
# pydeck
# streamlit
ollama==0.4.7
# via -r cookbook/examples/apps/tic_tac_toe/requirements.in
openai==1.64.0
# via -r cookbook/examples/apps/tic_tac_toe/requirements.in
packaging==24.2
# via
# altair
# build
# streamlit
pandas==2.2.3
# via streamlit
pathlib==1.0.1
# via -r cookbook/examples/apps/tic_tac_toe/requirements.in
pillow==11.1.0
# via
# -r cookbook/examples/apps/tic_tac_toe/requirements.in
# streamlit
pip==25.0.1
# via pip-tools
pip-tools==7.4.1
# via -r cookbook/examples/apps/tic_tac_toe/requirements.in
protobuf==5.29.3
# via streamlit
pyarrow==19.0.1
# via streamlit
pyasn1==0.6.1
# via
# pyasn1-modules
# rsa
pyasn1-modules==0.4.1
# via google-auth
pydantic==2.10.6
# via
# agno
# anthropic
# google-genai
# groq
# ollama
# openai
# pydantic-settings
pydantic-core==2.27.2
# via pydantic
pydantic-settings==2.8.0
# via agno
pydeck==0.9.1
# via streamlit
pygments==2.19.1
# via rich
pyproject-hooks==1.2.0
# via
# build
# pip-tools
python-dateutil==2.9.0.post0
# via pandas
python-dotenv==1.0.1
# via
# -r cookbook/examples/apps/tic_tac_toe/requirements.in
# agno
# pydantic-settings
python-multipart==0.0.20
# via agno
pytz==2025.1
# via pandas
pyyaml==6.0.2
# via agno
referencing==0.36.2
# via
# jsonschema
# jsonschema-specifications
requests==2.32.3
# via
# google-genai
# streamlit
rich==13.9.4
# via
# -r cookbook/examples/apps/tic_tac_toe/requirements.in
# agno
# streamlit
# typer
rpds-py==0.23.1
# via
# jsonschema
# referencing
rsa==4.9
# via google-auth
setuptools==75.8.0
# via pip-tools
shellingham==1.5.4
# via typer
six==1.17.0
# via python-dateutil
smmap==5.0.2
# via gitdb
sniffio==1.3.1
# via
# anthropic
# anyio
# groq
# openai
streamlit==1.42.2
# via -r cookbook/examples/apps/tic_tac_toe/requirements.in
tenacity==9.0.0
# via streamlit
toml==0.10.2
# via streamlit
tomli==2.2.1
# via agno
tornado==6.4.2
# via streamlit
tqdm==4.67.1
# via openai
typer==0.15.1
# via agno
typing-extensions==4.12.2
# via
# agno
# altair
# anthropic
# anyio
# google-genai
# groq
# openai
# pydantic
# pydantic-core
# referencing
# streamlit
# typer
tzdata==2025.1
# via pandas
urllib3==2.3.0
# via requests
websockets==14.2
# via google-genai
wheel==0.45.1
# via pip-tools

View file

@ -1,103 +0,0 @@
# Agent Tic Tac Toe
This example shows how to build an interactive Tic Tac Toe game where AI agents compete against each other. The application showcases how to:
- Coordinate multiple AI agents in a turn-based game
- Use different language models for different players
- Create an interactive web interface with Streamlit
- Handle game state and move validation
- Display real-time game progress and move history
## Features
- Multiple AI models support (GPT-4, Claude, Gemini, etc.)
- Real-time game visualization
- Move history tracking with board states
- Interactive player selection
- Game state management
- Move validation and coordination
### 1. Create a virtual environment
```shell
python3 -m venv .venv
source .venv/bin/activate
```
### 2. Install dependencies
```shell
pip install -r ai_agent_tutorials/ai_tic_tac_toe_game/requirements.txt
```
### 3. Export API Keys
The game supports multiple AI models. Export the API keys for the models you want to use:
```shell
# Required for OpenAI models
export OPENAI_API_KEY=***
# Optional - for additional models
export ANTHROPIC_API_KEY=*** # For Claude models
export GOOGLE_API_KEY=*** # For Gemini models
export GROQ_API_KEY=*** # For Groq models
```
### 4. Run the Game
```shell
streamlit run ai_agent_tutorials/ai_tic_tac_toe_game/app.py
```
- Open [localhost:8501](http://localhost:8501) to view the game interface
## How It Works
The game consists of three agents:
1. **Master Agent (Referee)**
- Coordinates the game
- Validates moves
- Maintains game state
- Determines game outcome
2. **Two Player Agents**
- Make strategic moves
- Analyze board state
- Follow game rules
- Respond to opponent moves
## Available Models
The game supports various AI models:
- GPT-4o (OpenAI)
- GPT-o3-mini (OpenAI)
- Gemini (Google)
- Llama 3 (Groq)
- Claude (Anthropic)
## Game Features
1. **Interactive Board**
- Real-time updates
- Visual move tracking
- Clear game status display
2. **Move History**
- Detailed move tracking
- Board state visualization
- Player action timeline
3. **Game Controls**
- Start/Pause game
- Reset board
- Select AI models
- View game history
4. **Performance Analysis**
- Move timing
- Strategy tracking
- Game statistics
## Support
Join our [Discord community](https://agno.link/discord) for help and discussions.

View file

@ -1,238 +0,0 @@
# This file was autogenerated by uv via the following command:
# ./generate_requirements.sh
agno==1.1.6
# via -r cookbook/examples/apps/tic_tac_toe/requirements.in
altair==5.5.0
# via streamlit
annotated-types==0.7.0
# via pydantic
anthropic==0.47.1
# via -r cookbook/examples/apps/tic_tac_toe/requirements.in
anyio==4.8.0
# via
# anthropic
# groq
# httpx
# openai
attrs==25.1.0
# via
# jsonschema
# referencing
blinker==1.9.0
# via streamlit
build==1.2.2.post1
# via pip-tools
cachetools==5.5.2
# via
# google-auth
# streamlit
certifi==2025.1.31
# via
# httpcore
# httpx
# requests
charset-normalizer==3.4.1
# via requests
click==8.1.8
# via
# pip-tools
# streamlit
# typer
distro==1.9.0
# via
# anthropic
# groq
# openai
docstring-parser==0.16
# via agno
gitdb==4.0.12
# via gitpython
gitpython==3.1.44
# via
# agno
# streamlit
google-auth==2.38.0
# via google-genai
google-genai==1.3.0
# via -r cookbook/examples/apps/tic_tac_toe/requirements.in
groq==0.18.0
# via -r cookbook/examples/apps/tic_tac_toe/requirements.in
h11==0.14.0
# via httpcore
httpcore==1.0.7
# via httpx
httpx==0.28.1
# via
# agno
# anthropic
# google-genai
# groq
# ollama
# openai
idna==3.10
# via
# anyio
# httpx
# requests
jinja2==3.1.5
# via
# altair
# pydeck
jiter==0.8.2
# via
# anthropic
# openai
jsonschema==4.23.0
# via altair
jsonschema-specifications==2024.10.1
# via jsonschema
markdown-it-py==3.0.0
# via rich
markupsafe==3.0.2
# via jinja2
mdurl==0.1.2
# via markdown-it-py
narwhals==1.28.0
# via altair
nest-asyncio==1.6.0
# via -r cookbook/examples/apps/tic_tac_toe/requirements.in
numpy==2.2.3
# via
# pandas
# pydeck
# streamlit
ollama==0.4.7
# via -r cookbook/examples/apps/tic_tac_toe/requirements.in
openai==1.64.0
# via -r cookbook/examples/apps/tic_tac_toe/requirements.in
packaging==24.2
# via
# altair
# build
# streamlit
pandas==2.2.3
# via streamlit
pathlib==1.0.1
# via -r cookbook/examples/apps/tic_tac_toe/requirements.in
pillow==11.1.0
# via
# -r cookbook/examples/apps/tic_tac_toe/requirements.in
# streamlit
pip==25.0.1
# via pip-tools
pip-tools==7.4.1
# via -r cookbook/examples/apps/tic_tac_toe/requirements.in
protobuf==5.29.3
# via streamlit
pyarrow==19.0.1
# via streamlit
pyasn1==0.6.1
# via
# pyasn1-modules
# rsa
pyasn1-modules==0.4.1
# via google-auth
pydantic==2.10.6
# via
# agno
# anthropic
# google-genai
# groq
# ollama
# openai
# pydantic-settings
pydantic-core==2.27.2
# via pydantic
pydantic-settings==2.8.0
# via agno
pydeck==0.9.1
# via streamlit
pygments==2.19.1
# via rich
pyproject-hooks==1.2.0
# via
# build
# pip-tools
python-dateutil==2.9.0.post0
# via pandas
python-dotenv==1.0.1
# via
# -r cookbook/examples/apps/tic_tac_toe/requirements.in
# agno
# pydantic-settings
python-multipart==0.0.20
# via agno
pytz==2025.1
# via pandas
pyyaml==6.0.2
# via agno
referencing==0.36.2
# via
# jsonschema
# jsonschema-specifications
requests==2.32.3
# via
# google-genai
# streamlit
rich==13.9.4
# via
# -r cookbook/examples/apps/tic_tac_toe/requirements.in
# agno
# streamlit
# typer
rpds-py==0.23.1
# via
# jsonschema
# referencing
rsa==4.9
# via google-auth
setuptools==75.8.0
# via pip-tools
shellingham==1.5.4
# via typer
six==1.17.0
# via python-dateutil
smmap==5.0.2
# via gitdb
sniffio==1.3.1
# via
# anthropic
# anyio
# groq
# openai
streamlit==1.42.2
# via -r cookbook/examples/apps/tic_tac_toe/requirements.in
tenacity==9.0.0
# via streamlit
toml==0.10.2
# via streamlit
tomli==2.2.1
# via agno
tornado==6.4.2
# via streamlit
tqdm==4.67.1
# via openai
typer==0.15.1
# via agno
typing-extensions==4.12.2
# via
# agno
# altair
# anthropic
# anyio
# google-genai
# groq
# openai
# pydantic
# pydantic-core
# referencing
# streamlit
# typer
tzdata==2025.1
# via pandas
urllib3==2.3.0
# via requests
websockets==14.2
# via google-genai
wheel==0.45.1
# via pip-tools