AutoTutor Explanation with Example or Figure Production Rule
This modern agent-selected production starts work on an expectation by offering an explanation, a worked example or teaching figure, and a question about an analogous case. Here, expectation means an authored idea the learner should understand. Expectancy is the model's estimate of the learner's knowledge, expressed as a logit for selection.
The teaching decision in plain English
The numbered comments connect the pseudocode to objects in the annotated rule below. The competition step belongs to the selector; it is shown between eligibility and execution so the whole instructional decision is visible.
CONSIDER: Explain this expectation, support it, then ask an analogous question.
WHEN
The learner's answer has been evaluated. # [1] interface-event + instructional.assessmentSnapshot
Feedback for that answer has already been produced. # [2] dialogue.utterance with action instruction.feedback
More instruction remains, and no move has been chosen yet. # [3] controller.completionState + absence of instructional.decision
It is time to start a target cycle, rather than continue one. # [3] instructional.cycleStatus.continuable = false
This is the highest-ranked expectation still eligible. # [3] instructional.candidate: eligible + isMaximumWithinKind
No eligible misconception needs priority. # [4] absence of an eligible misconception candidate
ENTER THIS MOVE INTO COMPETITION
Compare learner expectancy + this move's assistance
with the desired instructional target, all in logit units. # [5] expectancyLogit + assistance versus oetLogit
Give closer matches higher selection probability.
Sample one move using the Boltzmann temperature. # [5] selector behavior; enabled by the competition module
IF THIS PRODUCTION IS SELECTED, THEN
Save the target, chosen move, and selection evidence. # [6] instructional.decision
Record the chosen action and begin teaching this expectation. # [7] controller.selectedAction + instructional.activeCycle
Invoke its component primitives. # [8] invoke-action: autotutor.generate-move
Obtain a worked example OR teaching figure.
Generate an explanation aligned with that support.
Generate a question about an analogous case.
Present: explanation, support, question. # [8] generation action's behavior, not extra rule fields
This is one alternative, not a command to supply this much assistance whenever its conditions match. Other instructional moves compete for the same expectation. Target ranking and move competition are separate decisions. The figure-versus-worked-example choice is made inside the rich-content primitive after the composite move is selected.
The same production, annotated
These are the current runtime fields and values, with explanatory comments added. A factType names a kind of information available to the tutor; slots contains that information. literal requires a specified value, bind gives a matched value a name, and bound requires the same previously named value. That is how the rule keeps the answer, assessment, and expectation aligned.
This block is JSONC for reading. Comments are not valid in TutorScript's plain JSON; the expandable copy below contains the identical production without comments. The rule is supplied by the dynamic controller, not pasted into an AutoTutor lesson's authored rule array.
{
"id": "instruction.dynamic.agent.expectation.start.instruction.dynamic.explanation-rich-question",
// [5] The selector compares this instructional alternative with other eligible moves for ONE target.
"module": "dialogue.instructional-competition",
"when": [
// [1] Start with a submitted answer. Remember its event ID so later conditions use the same assessment.
{
"factType": "interface-event",
"slots": {
"eventType": {"type":"literal","value":"response-submitted"},
"eventId": {"type":"bind","variable":"snapshotId"}
}
},
// [1] That answer must already have been evaluated.
{
"factType": "instructional.assessmentSnapshot",
"slots": {"snapshotId":{"type":"bound","variable":"snapshotId"}}
},
// [2] Its tutor feedback must already exist before this move can be selected.
{
"factType": "dialogue.utterance",
"slots": {
"eventId": {"type":"bound","variable":"snapshotId"},
"action": {"type":"literal","value":"instruction.feedback"},
"speaker": {"type":"literal","value":"tutor"}
}
},
// [3] There is still instruction to do.
{"factType":"controller.completionState","slots":{"completed":{"type":"literal","value":false}}},
// [3] Do not make a second instructional decision for this assessment.
{
"type": "not",
"pattern": {"factType":"instructional.decision","slots":{"snapshotId":{"type":"bound","variable":"snapshotId"}}}
},
// [3] This is a START rule: the previous target cycle cannot continue. A separate rule handles continuation.
{
"factType": "instructional.cycleStatus",
"slots": {"snapshotId":{"type":"bound","variable":"snapshotId"},"continuable":{"type":"literal","value":false}}
},
// [3] Choose the highest-ranked eligible expectation at this boundary.
// An expectation is an authored idea the learner should understand, not a probability.
// isMaximumWithinKind refers to target-policy ranking, not simply the highest knowledge score.
{
"factType": "instructional.candidate",
"slots": {
"snapshotId": {"type":"bound","variable":"snapshotId"},
"targetKind": {"type":"literal","value":"expectation"},
"targetId": {"type":"bind","variable":"targetId"},
"targetKey": {"type":"bind","variable":"targetKey"},
"currentValue": {"type":"bind","variable":"currentValue"},
"eligible": {"type":"literal","value":true},
"isMaximumWithinKind": {"type":"literal","value":true}
}
},
// [4] An eligible misconception takes priority, so this expectation rule must wait.
{
"type": "not",
"pattern": {
"factType": "instructional.candidate",
"slots": {
"snapshotId": {"type":"bound","variable":"snapshotId"},
"targetKind": {"type":"literal","value":"misconception"},
"eligible": {"type":"literal","value":true}
}
}
},
// [5] For that SAME expectation, retrieve learner expectancy and the instructional target (OET), in logits.
{
"factType": "instructional.candidate",
"slots": {
"snapshotId": {"type":"bound","variable":"snapshotId"},
"targetKind": {"type":"literal","value":"expectation"},
"targetId": {"type":"bound","variable":"targetId"},
"eligible": {"type":"literal","value":true},
"expectancyLogit": {"type":"bind","variable":"expectancyLogit"},
"oetLogit": {"type":"bind","variable":"oetLogit"}
}
},
// [5] Retrieve the assistance assigned to this composite move, also in logit units.
// The rule can compete; these conditions do not guarantee it will win.
{
"factType": "instructional.move",
"slots": {
"action": {"type":"literal","value":"instruction.dynamic.explanation-rich-question"},
"assistance": {"type":"bind","variable":"assistance"}
}
},
{"factType":"session.turnState","slots":{"turnCount":{"type":"bind","variable":"turnNumber"}}}
],
"then": [
// [6] If selected, save what was chosen, for which target, and why. persist makes the decision durable.
{
"type": "assert-fact",
"persist": true,
"identitySlots": ["snapshotId"],
"fact": {
"factType": "instructional.decision",
"slots": {
"snapshotId": {"type":"variable","name":"snapshotId"},
"targetKind": {"type":"literal","value":"expectation"},
"targetId": {"type":"variable","name":"targetId"},
"targetKey": {"type":"variable","name":"targetKey"},
"action": {"type":"literal","value":"instruction.dynamic.explanation-rich-question"},
"transition": {"type":"literal","value":"start"},
"sourceRuleId": {
"type": "literal",
"value": "instruction.dynamic.agent.expectation.start.instruction.dynamic.explanation-rich-question"
},
"reason": {"type":"literal","value":"oet-distance"},
"expectancyLogit": {"type":"variable","name":"expectancyLogit"},
"assistance": {"type":"variable","name":"assistance"},
"oetLogit": {"type":"variable","name":"oetLogit"},
// [6] The selector supplies these three values. They record the competition, not an AI wording choice.
// utility = -abs(expectancyLogit + assistance - oetLogit); temperature controls sampling.
"utility": {"type":"variable","name":"utility"},
"temperature": {"type":"variable","name":"temperature"},
// Chance of selecting this move among eligible alternatives; NOT the learner's probability of success.
"selectionProbability": {"type":"variable","name":"selectionProbability"}
}
}
},
// [7] Tell the generation action which move and expectation were selected.
{
"type": "assert-fact",
"persist": true,
"identitySlots": [],
"fact": {
"factType": "controller.selectedAction",
"slots": {
"targetType": {"type":"literal","value":"expectation"},
"targetId": {"type":"variable","name":"targetId"},
"targetKey": {"type":"variable","name":"targetKey"},
"action": {"type":"literal","value":"instruction.dynamic.explanation-rich-question"},
"sourceRuleId": {
"type": "literal",
"value": "instruction.dynamic.agent.expectation.start.instruction.dynamic.explanation-rich-question"
},
"snapshotId": {"type":"variable","name":"snapshotId"}
}
}
},
// [7] Retain this expectation as the active teaching focus for subsequent turns.
// priorValue stores its current evaluated coverage for later progress comparisons.
{
"type": "assert-fact",
"persist": true,
"identitySlots": [],
"fact": {
"factType": "instructional.activeCycle",
"slots": {
"cycleId": {"type":"variable","name":"snapshotId"},
"targetKind": {"type":"literal","value":"expectation"},
"targetId": {"type":"variable","name":"targetId"},
"targetKey": {"type":"variable","name":"targetKey"},
"stage": {"type":"literal","value":"DYNAMIC"},
"priorValue": {"type":"variable","name":"currentValue"},
"startedAtTurn": {"type":"variable","name":"turnNumber"},
"cycleTurnCount": {"type":"literal","value":0},
"status": {"type":"literal","value":"active"}
}
}
},
// [8] Invoke the action that carries out the selected move using component primitives.
// Learner-facing order: explanation, worked example OR teaching figure, then an analogous question.
// The rich-content primitive chooses the support form; this rule does not require an image every time.
{"type":"invoke-action","actionId":"autotutor.generate-move"}
]
}
Uncommented JSON — exact current runtime production
{
"id": "instruction.dynamic.agent.expectation.start.instruction.dynamic.explanation-rich-question",
"module": "dialogue.instructional-competition",
"when": [
{
"factType": "interface-event",
"slots": {
"eventType": {
"type": "literal",
"value": "response-submitted"
},
"eventId": {
"type": "bind",
"variable": "snapshotId"
}
}
},
{
"factType": "instructional.assessmentSnapshot",
"slots": {
"snapshotId": {
"type": "bound",
"variable": "snapshotId"
}
}
},
{
"factType": "dialogue.utterance",
"slots": {
"eventId": {
"type": "bound",
"variable": "snapshotId"
},
"action": {
"type": "literal",
"value": "instruction.feedback"
},
"speaker": {
"type": "literal",
"value": "tutor"
}
}
},
{
"factType": "controller.completionState",
"slots": {
"completed": {
"type": "literal",
"value": false
}
}
},
{
"type": "not",
"pattern": {
"factType": "instructional.decision",
"slots": {
"snapshotId": {
"type": "bound",
"variable": "snapshotId"
}
}
}
},
{
"factType": "instructional.cycleStatus",
"slots": {
"snapshotId": {
"type": "bound",
"variable": "snapshotId"
},
"continuable": {
"type": "literal",
"value": false
}
}
},
{
"factType": "instructional.candidate",
"slots": {
"snapshotId": {
"type": "bound",
"variable": "snapshotId"
},
"targetKind": {
"type": "literal",
"value": "expectation"
},
"targetId": {
"type": "bind",
"variable": "targetId"
},
"targetKey": {
"type": "bind",
"variable": "targetKey"
},
"currentValue": {
"type": "bind",
"variable": "currentValue"
},
"eligible": {
"type": "literal",
"value": true
},
"isMaximumWithinKind": {
"type": "literal",
"value": true
}
}
},
{
"type": "not",
"pattern": {
"factType": "instructional.candidate",
"slots": {
"snapshotId": {
"type": "bound",
"variable": "snapshotId"
},
"targetKind": {
"type": "literal",
"value": "misconception"
},
"eligible": {
"type": "literal",
"value": true
}
}
}
},
{
"factType": "instructional.candidate",
"slots": {
"snapshotId": {
"type": "bound",
"variable": "snapshotId"
},
"targetKind": {
"type": "literal",
"value": "expectation"
},
"targetId": {
"type": "bound",
"variable": "targetId"
},
"eligible": {
"type": "literal",
"value": true
},
"expectancyLogit": {
"type": "bind",
"variable": "expectancyLogit"
},
"oetLogit": {
"type": "bind",
"variable": "oetLogit"
}
}
},
{
"factType": "instructional.move",
"slots": {
"action": {
"type": "literal",
"value": "instruction.dynamic.explanation-rich-question"
},
"assistance": {
"type": "bind",
"variable": "assistance"
}
}
},
{
"factType": "session.turnState",
"slots": {
"turnCount": {
"type": "bind",
"variable": "turnNumber"
}
}
}
],
"then": [
{
"type": "assert-fact",
"persist": true,
"identitySlots": [
"snapshotId"
],
"fact": {
"factType": "instructional.decision",
"slots": {
"snapshotId": {
"type": "variable",
"name": "snapshotId"
},
"targetKind": {
"type": "literal",
"value": "expectation"
},
"targetId": {
"type": "variable",
"name": "targetId"
},
"targetKey": {
"type": "variable",
"name": "targetKey"
},
"action": {
"type": "literal",
"value": "instruction.dynamic.explanation-rich-question"
},
"transition": {
"type": "literal",
"value": "start"
},
"sourceRuleId": {
"type": "literal",
"value": "instruction.dynamic.agent.expectation.start.instruction.dynamic.explanation-rich-question"
},
"reason": {
"type": "literal",
"value": "oet-distance"
},
"expectancyLogit": {
"type": "variable",
"name": "expectancyLogit"
},
"assistance": {
"type": "variable",
"name": "assistance"
},
"oetLogit": {
"type": "variable",
"name": "oetLogit"
},
"utility": {
"type": "variable",
"name": "utility"
},
"temperature": {
"type": "variable",
"name": "temperature"
},
"selectionProbability": {
"type": "variable",
"name": "selectionProbability"
}
}
}
},
{
"type": "assert-fact",
"persist": true,
"identitySlots": [],
"fact": {
"factType": "controller.selectedAction",
"slots": {
"targetType": {
"type": "literal",
"value": "expectation"
},
"targetId": {
"type": "variable",
"name": "targetId"
},
"targetKey": {
"type": "variable",
"name": "targetKey"
},
"action": {
"type": "literal",
"value": "instruction.dynamic.explanation-rich-question"
},
"sourceRuleId": {
"type": "literal",
"value": "instruction.dynamic.agent.expectation.start.instruction.dynamic.explanation-rich-question"
},
"snapshotId": {
"type": "variable",
"name": "snapshotId"
}
}
}
},
{
"type": "assert-fact",
"persist": true,
"identitySlots": [],
"fact": {
"factType": "instructional.activeCycle",
"slots": {
"cycleId": {
"type": "variable",
"name": "snapshotId"
},
"targetKind": {
"type": "literal",
"value": "expectation"
},
"targetId": {
"type": "variable",
"name": "targetId"
},
"targetKey": {
"type": "variable",
"name": "targetKey"
},
"stage": {
"type": "literal",
"value": "DYNAMIC"
},
"priorValue": {
"type": "variable",
"name": "currentValue"
},
"startedAtTurn": {
"type": "variable",
"name": "turnNumber"
},
"cycleTurnCount": {
"type": "literal",
"value": 0
},
"status": {
"type": "literal",
"value": "active"
}
}
}
},
{
"type": "invoke-action",
"actionId": "autotutor.generate-move"
}
]
}
The production is generated by createSparcDynamicInstructionRules. Competition is implemented by selectCompetitiveActivation; component composition is defined in sparcMoveDefinitions.ts. See TutorScript's selection cycle for the surrounding flow.