Spaces:
Running
Running
File size: 8,440 Bytes
3a07545 e687096 3a07545 e687096 3a07545 e687096 3a07545 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
"""
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]
)
@classmethod
def list_supported_models(cls) -> dict:
"""Return a dictionary of supported model names and their full identifiers."""
return ModelProvider.SUPPORTED_MODELS.copy()
@classmethod
def get_model_info(cls, model_name: str) -> str:
"""Get information about a specific model."""
return ModelProvider.get_model_info(model_name)
@classmethod
def get_recommended_models(cls) -> list:
"""Get a list of recommended models that are most likely to be available."""
return ModelProvider.get_recommended_models()
@classmethod
def get_models_by_provider(cls) -> dict:
"""Get models organized by provider."""
return ModelProvider.get_models_by_provider()
@classmethod
def get_models_table_data(cls) -> list:
"""Get model data formatted for table display."""
return ModelProvider.get_models_table_data()
@classmethod
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)
|