/** * Planungs-KI Phase D: strukturierter Kontext für suggestExerciseAi. */ export function buildPickerPlanningContextForAi({ planningContextSummary = null, planningContext = null, searchQuery = '', } = {}) { if (!planningContextSummary && !planningContext) return null const ctx = { source: 'planning_picker', search_query: (searchQuery || '').trim() || null, unit_title: planningContextSummary?.unit_title || null, group_name: planningContextSummary?.group_name || null, section_title: planningContextSummary?.section_title || planningContext?.sectionTitle || null, section_guidance_notes: planningContext?.sectionGuidanceNotes || null, section_exercise_count: planningContextSummary?.section_exercise_count ?? null, last_section_exercise_title: planningContextSummary?.last_section_exercise_title || planningContext?.lastExerciseTitle || null, anchor_title: planningContextSummary?.anchor_title || null, progression_graph_name: planningContextSummary?.progression_graph_name || null, planned_count: planningContextSummary?.planned_count ?? null, intent_resolved: planningContextSummary?.intent_resolved || planningContext?.intentHint || null, } return Object.fromEntries(Object.entries(ctx).filter(([, v]) => v != null && v !== '')) } export function buildPathGapPlanningContextForAi({ goalQuery = '', semanticBrief = null, offer = null, graphId = null, pathSteps = [], editableMajorSteps = [], progressionRoadmap = null, } = {}) { const afterIdx = Number(offer?.insert_after_index) const stepA = Number.isFinite(afterIdx) && afterIdx >= 0 ? pathSteps[afterIdx] : null const stepB = Number.isFinite(afterIdx) && afterIdx >= 0 ? pathSteps[afterIdx + 1] : null const majorIdxRaw = offer?.roadmap_major_step_index ?? offer?.gap?.roadmap_major_step_index const majorIdx = majorIdxRaw != null && Number.isFinite(Number(majorIdxRaw)) ? Number(majorIdxRaw) : null const majorStep = majorIdx != null && editableMajorSteps[majorIdx] ? editableMajorSteps[majorIdx] : null const ctx = { source: 'progression_path_gap_fill', goal_query: (goalQuery || '').trim() || null, primary_topic: semanticBrief?.primary_topic || null, progression_graph_id: graphId != null ? Number(graphId) : null, gap_source: offer?.source || null, gap_phase: offer?.phase || offer?.gap?.expected_phase || null, roadmap_major_step_index: majorIdx, roadmap_phase: majorStep?.phase || offer?.phase || null, roadmap_learning_goal: (majorStep?.learning_goal || offer?.title_hint || offer?.gap?.learning_goal || '').trim() || null, neighbor_before_title: stepA?.exerciseTitle || offer?.from_title || null, neighbor_after_title: stepB?.exerciseTitle || offer?.to_title || null, path_step_count: Array.isArray(pathSteps) ? pathSteps.length : 0, major_step_count: editableMajorSteps?.length || progressionRoadmap?.major_step_count || progressionRoadmap?.roadmap?.major_steps?.length || null, } return Object.fromEntries(Object.entries(ctx).filter(([, v]) => v != null && v !== '')) }