All files / src/prompts generate-workout.ts

100% Statements 55/55
100% Branches 20/20
100% Functions 2/2
100% Lines 55/55

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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                  1x 29x 29x 29x 29x 29x 29x 29x 29x 29x 29x 29x 29x 29x 29x   29x 1x             28x   29x 29x 2x     2x 27x   29x 1x             28x   29x 29x 29x 17x 12x   29x 29x     29x 17x   29x 29x 17x 12x   29x 29x 17x 12x   29x     29x 29x 29x 29x 29x     29x       29x     29x     29x 29x                                                 29x  
import type { WorkoutGenerationContext } from '../model-provider.js';
 
/**
 * System prompt for workout generation.
 *
 * Guides Claude to produce creative, personalised programming within
 * periodisation constraints (deload behavior, movement pattern balance,
 * rep ranges, time caps, equipment availability).
 */
export function generateWorkoutPrompt(context: WorkoutGenerationContext): string {
  const {
    session_type,
    time_cap_minutes,
    rep_range_low,
    rep_range_high,
    rest_seconds_target,
    is_deload,
    available_equipment,
    movement_pattern_history,
    familiar_exercises,
    constraints,
    previous_violations,
    is_sparse_profile,
  } = context;
 
  const deloadGuidance = is_deload
    ? `
## Deload Week
This is a DELOAD session. Reduce training stress significantly:
- Use 2 working sets per exercise (not 3+)
- Target weights approximately 40-60% of normal working weights
- Keep RPE below 7 on all sets
- Prioritise movement quality and recovery`
    : '';
 
  const violationWarning =
    previous_violations && previous_violations.length > 0
      ? `
## Previous Violations to Avoid
The previous workout generation attempt had these violations. Do NOT repeat them:
${previous_violations.map((v) => `- ${v.rule}: ${v.message}`).join('\n')}`
      : '';
 
  const sparseProfileGuidance = is_sparse_profile
    ? `
## Sparse Profile Note
This athlete has a minimal profile with system-assigned defaults. Programme conservatively:
- Stick to foundational, well-known exercises
- Prefer moderate intensity (RPE 6-7)
- Include clear form cues in exercise notes
- Keep the session straightforward — this may be their first structured programme`
    : '';
 
  const historyEntries = Object.entries(movement_pattern_history);
  const patternHistoryText =
    historyEntries.length > 0
      ? historyEntries.map(([pattern, count]) => `- ${pattern}: ${count} recent sets`).join('\n')
      : '- No recent history available';
 
  const equipmentText =
    available_equipment.length > 0 ? available_equipment.join(', ') : 'bodyweight only';
 
  // Sanitize athlete-editable constraint text to prevent prompt injection
  const sanitizeConstraint = (c: string) =>
    c.replace(/#{1,6}\s/g, '').replace(/\n{2,}/g, '\n').slice(0, 200);
 
  const constraintsText =
    constraints.length > 0
      ? constraints.map((c) => `- ${sanitizeConstraint(c)}`).join('\n')
      : '- No special constraints';
 
  const familiarText =
    familiar_exercises.length > 0
      ? familiar_exercises.join(', ')
      : 'No exercise history available';
 
  return `You are an expert strength and conditioning coach generating a personalised workout session.
 
## Session Parameters
- Session type: ${session_type}
- Time cap: ${time_cap_minutes} minutes
- Rep range: ${rep_range_low}–${rep_range_high} reps per set
- Rest target: ${rest_seconds_target} seconds between sets
${deloadGuidance}
 
## Available Equipment
${equipmentText}
 
## Movement Pattern Balance
Balance training across movement patterns (squat, hinge, push, pull). Avoid over-concentrating on one pattern. Recent training history:
${patternHistoryText}
 
## Athlete Familiarity
Exercises the athlete knows well (prioritise these): ${familiarText}
 
## Constraints
${constraintsText}
${violationWarning}${sparseProfileGuidance}
 
## Output Requirements
Use the submit_workout_plan tool to return the final workout. Do NOT output JSON directly.
 
Before building the plan, call lookup_exercises for each movement pattern you intend to programme.
Use only the id values returned by lookup_exercises as exercise_id — never invent exercise_id values.
Lookups are scoped to the athlete's available equipment (listed above).
 
Each prescribed exercise must include:
- exercise_id: UUID returned by lookup_exercises — must be from the library, not invented
- exercise_name: human-readable name (from the lookup_exercises result)
- order: sequence number (1-based)
- sets: array of SetPrescription objects with target_weight_kg, target_reps, target_rpe, rest_seconds
- is_warmup: false for working sets
- is_backup: true for exercises that can substitute if equipment is unavailable
- notes: optional coaching cue or null
- movement_patterns: array of patterns this exercise trains
 
## Validation Rules
Before submitting, use validate_session to check your workout passes safety checks:
1. No single movement pattern should exceed 45% of total set count
2. Estimated workout time must not exceed the time cap by more than 3 minutes
 
Use estimate_workout_time to check timing. If validate_session returns violations, redesign and re-check before submitting.`;
}