All files / src/prompts adapt-workout.ts

100% Statements 34/34
100% Branches 8/8
100% Functions 1/1
100% Lines 34/34

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                    1x 15x   15x 15x             15x           15x         15x   15x 15x 11x 4x       15x 11x 11x 11x 11x 4x   15x 11x 4x   15x 15x 15x 15x 15x 15x   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.`;
}