Spaces:
Running
Running
""" | |
Main fitness agent implementation. | |
""" | |
from typing import Optional | |
from agents import Agent | |
from dotenv import load_dotenv | |
from .models import FitnessPlan, AgentConfig | |
from .providers import ModelProvider | |
load_dotenv() | |
class FitnessAgent(Agent): | |
""" | |
A helpful assistant for general fitness guidance and handoffs to a plan-building agent. | |
Supports multiple AI providers via LiteLLM (as of January 2025): | |
Anthropic models: | |
- Claude-4: claude-opus-4-20250514, claude-sonnet-4-20250514 (Premium) | |
- Claude-3.7: claude-3-7-sonnet-20250219 (Extended thinking) | |
- Claude-3.5: claude-3-5-sonnet-20241022 (latest), claude-3-5-sonnet-20240620 (stable), claude-3-5-haiku-20241022 (fast) | |
- Claude-3: claude-3-haiku-20240307 (legacy but reliable) | |
OpenAI models: | |
- GPT-4o: gpt-4o, gpt-4o-mini (Vision + latest capabilities) | |
- GPT-4: gpt-4-turbo (Legacy but stable) | |
- GPT-3.5: gpt-3.5-turbo (Cost-effective) | |
- Reasoning: o1-preview, o1-mini, o3-mini (Advanced reasoning) | |
Note: Some older models may be deprecated. Always check provider documentation. | |
""" | |
def __init__(self, model_name: Optional[str] = None, config: Optional[AgentConfig] = None): | |
""" | |
Initialize the Fitness Agent with configurable AI model (Anthropic or OpenAI). | |
Args: | |
model_name: Name of the AI model to use. Can be a key from SUPPORTED_MODELS | |
or a full model identifier. Defaults to gpt-4o-mini if not specified. | |
Can also be set via AI_MODEL, ANTHROPIC_MODEL, or OPENAI_MODEL environment variables. | |
config: Optional AgentConfig for additional configuration | |
""" | |
# Resolve model name | |
resolved_model_name = ModelProvider.resolve_model_name(model_name) | |
final_model = ModelProvider.get_final_model_identifier(resolved_model_name) | |
# Store the model information for debugging | |
self.model_name = resolved_model_name | |
self.full_model_name = ModelProvider.SUPPORTED_MODELS.get(resolved_model_name, resolved_model_name) | |
self.final_model = final_model | |
self.provider = ModelProvider.get_provider(resolved_model_name, self.full_model_name) | |
self.config = config | |
# Create fitness plan agent with model-specific configuration | |
# Check if this is a Groq model that might struggle with structured output | |
is_groq_model = "groq" in final_model.lower() or resolved_model_name in [ | |
"llama-3.3-70b-versatile", "llama-3.1-8b-instant", "llama3-8b-8192", | |
"llama3-70b-8192", "gemma2-9b-it", | |
"mixtral-8x7b-32768", "qwen3-32b", "kimi-k2-instruct" | |
] | |
if is_groq_model: | |
# For Groq models, use simpler instructions without strict structured output | |
fitness_plan_agent = Agent( | |
name="Fitness Plan Assistant", | |
instructions="""You are an expert fitness plan creation specialist. Create detailed fitness plans. | |
IMPORTANT: Respond directly with the fitness plan. Do not use <think> tags or internal reasoning. | |
When responding, always provide: | |
1. A clear plan name | |
2. A complete training plan with specific exercises, sets, and reps | |
3. A detailed meal plan with specific foods and portions | |
Format your response clearly and include all three components above. Be specific and actionable. | |
Example response format: | |
**Plan Name:** Intermediate Muscle Building Program | |
**Training Plan:** | |
Day 1: Upper Body | |
- Bench Press: 4 sets × 8-10 reps | |
- Pull-ups: 3 sets × 6-8 reps | |
- Overhead Press: 3 sets × 10-12 reps | |
Day 2: Lower Body | |
- Squats: 4 sets × 8-10 reps | |
- Deadlifts: 3 sets × 5-6 reps | |
**Meal Plan:** | |
Breakfast: 3 whole eggs + 2 egg whites, 1 cup oatmeal, 1 banana | |
Lunch: 6oz chicken breast, 1.5 cups brown rice, mixed vegetables | |
Dinner: 6oz salmon, 1 cup quinoa, steamed broccoli | |
Now create a comprehensive fitness plan based on the user's request.""", | |
model=final_model | |
# Note: No output_type for Groq models to avoid structured output issues | |
) | |
else: | |
# For OpenAI and Anthropic models, use structured output | |
fitness_plan_agent = Agent( | |
name="Fitness Plan Assistant", | |
instructions="""You are an expert fitness plan creation specialist. Create detailed fitness plans with the following structure: | |
CRITICAL: You must respond with a valid FitnessPlan object containing exactly these three fields: | |
- name: A descriptive title for the plan | |
- training_plan: Complete workout program with exercises, sets, and reps | |
- meal_plan: Detailed nutrition plan with specific foods and portions | |
TRAINING PLAN REQUIREMENTS: | |
- Organize by days (Day 1, Day 2, etc.) or muscle groups | |
- Include specific exercises with sets × reps (e.g., "Push-ups: 3 sets × 10 reps") | |
- Mention rest periods and progression tips | |
- Consider the user's fitness level and available equipment | |
MEAL PLAN REQUIREMENTS: | |
- Provide specific meals for breakfast, lunch, dinner, and snacks | |
- Include portion sizes and macronutrient balance | |
- Consider the user's goals (muscle gain, weight loss, etc.) | |
- Make it practical and achievable | |
IMPORTANT: Always fill in ALL three fields (name, training_plan, meal_plan) with detailed, specific content. Never leave any field empty or use placeholder text. | |
Example format: | |
- name: "Intermediate Muscle Building Program" | |
- training_plan: "Day 1: Upper Body\n- Bench Press: 4 sets × 8-10 reps\n- Pull-ups: 3 sets × 6-8 reps\n\nDay 2: Lower Body\n- Squats: 4 sets × 8-10 reps" | |
- meal_plan: "Breakfast: 3 whole eggs + 2 egg whites, 1 cup oatmeal, 1 banana\nLunch: 6oz chicken breast, 1.5 cups brown rice" | |
Now create a comprehensive fitness plan based on the user's request.""", | |
model=final_model, | |
output_type=FitnessPlan | |
) | |
# Initialize parent Agent with improved instructions | |
super().__init__( | |
name="Fitness Assistant", | |
model=final_model, | |
instructions="""You are a professional fitness and nutrition assistant with expertise in creating personalized fitness programs. | |
CORE CAPABILITIES: | |
- Fitness program design and workout planning | |
- Nutrition guidance and meal planning | |
- Exercise technique and form advice | |
- Goal setting and progress tracking | |
- Injury prevention and modification strategies | |
WHEN TO TRANSFER TO FITNESS PLAN ASSISTANT: | |
Transfer immediately when users request: | |
- "Create a workout plan" or "design a program" | |
- "I need a fitness plan" or "help me with a routine" | |
- "Build a meal plan" or nutrition planning | |
- Any structured fitness or nutrition program creation | |
CONVERSATION GUIDELINES: | |
- Be encouraging and supportive | |
- Ask clarifying questions about fitness level, goals, and preferences | |
- Provide evidence-based advice | |
- Consider individual limitations and equipment availability | |
- Always prioritize safety and proper form | |
For detailed fitness plan creation, immediately transfer to the Fitness Plan Assistant who will create comprehensive, structured programs.""", | |
handoffs=[fitness_plan_agent] | |
) | |
def list_supported_models(cls) -> dict: | |
"""Return a dictionary of supported model names and their full identifiers.""" | |
return ModelProvider.SUPPORTED_MODELS.copy() | |
def get_model_info(cls, model_name: str) -> str: | |
"""Get information about a specific model.""" | |
return ModelProvider.get_model_info(model_name) | |
def get_recommended_models(cls) -> list: | |
"""Get a list of recommended models that are most likely to be available.""" | |
return ModelProvider.get_recommended_models() | |
def get_models_by_provider(cls) -> dict: | |
"""Get models organized by provider.""" | |
return ModelProvider.get_models_by_provider() | |
def get_models_table_data(cls) -> list: | |
"""Get model data formatted for table display.""" | |
return ModelProvider.get_models_table_data() | |
def validate_model_name(cls, model_name: str) -> tuple[bool, str]: | |
""" | |
Validate if a model name is in our supported list and provide helpful feedback. | |
Returns: | |
tuple: (is_valid, message) | |
""" | |
return ModelProvider.validate_model_name(model_name) | |