All files / src/prompts adapt-workout.ts

100% Statements 8/8
100% Branches 6/6
100% Functions 2/2
100% Lines 8/8

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                      15x   15x                                           15x           15x             15x       15x     15x       15x                                        
import type { WorkoutAdaptationContext } from '../model-provider.js';
 
/**
 * System prompt for workout adaptation.
 *
 * Handles three adaptation kinds:
 * - not_feeling_it: reduce volume/intensity for a low-energy day
 * - exercise_substitution: swap out a specific exercise for equipment/preference reasons
 * - pain_reported: modify or remove exercises that aggravate reported pain
 */
export function adaptWorkoutPrompt(context: WorkoutAdaptationContext): string {
  const { kind, context_description, current_exercises, completed_sets } = context;
 
  const kindGuidance: Record<typeof kind, string> = {
    not_feeling_it: `The athlete is NOT FEELING IT today. This is valid input. Adapt the workout to:
- Reduce total volume by approximately 30-40% (fewer sets, not fewer exercises)
- Lower target weights to approximately 70-80% of prescribed values
- Maintain movement pattern variety — don't cut entire patterns
- Keep the session structure intact but make it more manageable
- Tone is supportive: honour the athlete's intuition`,
 
    exercise_substitution: `The athlete needs to SUBSTITUTE an exercise. Adapt the workout to:
- Replace the problematic exercise with a biomechanically similar alternative
- Maintain the same movement pattern(s) in the replacement
- Match the rep/set/rest structure of the original where possible
- If context describes which exercise to replace, target that specifically`,
 
    pain_reported: `The athlete has REPORTED PAIN. Safety is the absolute priority:
- Remove or significantly modify any exercise that may aggravate the reported area
- Provide a brief safety note in the explanation (recommend consulting a professional if persistent)
- Substitute with pain-free alternatives that maintain training stimulus where possible
- Err on the side of caution — it is better to undertrain than to cause injury`,
  };
 
  const completedNote =
    completed_sets > 0
      ? `The athlete has already completed ${completed_sets} sets. Preserve completed work in the adapted plan.`
      : 'The workout has not yet started.';
 
  // Sanitize athlete-supplied text to prevent prompt injection:
  // strip markdown headings and cap length
  const sanitizedDescription = context_description
    ? context_description
        .replace(/#{1,6}\s/g, '')  // strip markdown headings
        .replace(/\n{2,}/g, '\n')  // collapse multiple newlines
        .slice(0, 500)
    : null;
 
  const descriptionNote = sanitizedDescription
    ? `\n## Athlete's Description\n"${sanitizedDescription}"`
    : '';
 
  const exerciseList = current_exercises
    .map(
      (ex, i) =>
        `${i + 1}. ${ex.exercise_name} (${ex.movement_patterns.join('/')}, ${ex.sets.length} sets)`,
    )
    .join('\n');
 
  return `You are an expert strength and conditioning coach adapting a workout in real time.
 
## Adaptation Type: ${kind.replace(/_/g, ' ').toUpperCase()}
 
${kindGuidance[kind]}
${descriptionNote}
 
## Current Workout (${current_exercises.length} exercises)
${exerciseList}
 
## Completion Status
${completedNote}
 
## Output Requirements
Use the submit_adapted_workout tool to return the adapted workout. Include:
- prescribed_exercises: the full modified exercise list (including already-completed exercises unchanged)
- explanation: a brief, empathetic explanation of what changed and why (1-3 sentences)
 
The explanation will be shown directly to the athlete — keep it supportive and clear.`;
}