import 'models.dart'; /// Combines strict local matching with an advisory semantic AI result. /// /// Progress is deliberately permissive: a strict local match can continue if /// AI is unavailable or disagrees. Mastery evidence is conservative: a free /// scene produces independent evidence only when local and AI agree and the /// learner received no answer-level help. DialogueTurnDecision resolveDialogueTurnDecision({ required LocalDialogueVerdict local, required DialogueAiIntervention? ai, required bool aiWasAttempted, required bool isFreeScene, required DialogueSupportLevel supportLevel, }) { if (local == LocalDialogueVerdict.rejected) { return const DialogueTurnDecision( canAdvance: false, evidenceOutcome: EvidenceKind.languageError, validationSource: DialogueValidationSource.local, supportLevel: DialogueSupportLevel.none, feedback: '请输入一个有效的英文回答。', ); } final aiAccepted = ai?.accepted == true && ai?.goalSatisfied == true && ai?.verdict == DialogueAiVerdict.accepted; final assisted = switch (supportLevel) { DialogueSupportLevel.hint || DialogueSupportLevel.translation || DialogueSupportLevel.correction || DialogueSupportLevel.skipped => true, _ => false, }; if (local == LocalDialogueVerdict.accepted && aiAccepted) { return DialogueTurnDecision( canAdvance: true, evidenceOutcome: !isFreeScene ? (assisted ? EvidenceKind.assisted : EvidenceKind.pending) : (assisted ? EvidenceKind.assisted : EvidenceKind.independentSuccess), validationSource: DialogueValidationSource.localAndAi, supportLevel: supportLevel, feedback: ai?.explanation, ); } if (aiAccepted) { return DialogueTurnDecision( canAdvance: true, evidenceOutcome: assisted ? EvidenceKind.assisted : EvidenceKind.pending, validationSource: DialogueValidationSource.ai, supportLevel: supportLevel == DialogueSupportLevel.none ? DialogueSupportLevel.validationOnly : supportLevel, feedback: ai?.explanation, ); } if (local == LocalDialogueVerdict.accepted) { final aiExplicitlyRejected = ai?.verdict == DialogueAiVerdict.correctable || ai?.verdict == DialogueAiVerdict.offTopic; if (aiExplicitlyRejected) { return DialogueTurnDecision( canAdvance: false, evidenceOutcome: assisted ? EvidenceKind.assisted : EvidenceKind.pending, validationSource: DialogueValidationSource.disagreement, supportLevel: supportLevel, feedback: ai?.explanation, suggestion: ai?.suggestion, ); } final source = aiWasAttempted ? (ai == null ? DialogueValidationSource.unavailable : DialogueValidationSource.disagreement) : DialogueValidationSource.local; return DialogueTurnDecision( canAdvance: true, evidenceOutcome: assisted ? EvidenceKind.assisted : aiWasAttempted ? EvidenceKind.pending : isFreeScene ? EvidenceKind.independentSuccess : EvidenceKind.pending, validationSource: source, supportLevel: supportLevel, feedback: ai?.explanation, ); } return DialogueTurnDecision( canAdvance: false, evidenceOutcome: assisted ? EvidenceKind.assisted : EvidenceKind.pending, validationSource: aiWasAttempted ? (ai == null ? DialogueValidationSource.unavailable : DialogueValidationSource.localAndAi) : DialogueValidationSource.local, supportLevel: supportLevel, feedback: ai?.explanation ?? '暂时无法确认这句是否完成本轮任务,请换一种说法。', suggestion: ai?.suggestion, ); }