Skip to documentation

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.