General Advice
- Read the output link after the agent's output phase but before the next decision cycle's input phase.
- Excercise care if you save commands (or other working memory elements on the output-link) to use later and return control back to Soar.
- Be careful not to dereference working memory elements you have disconnected with DestroyWME.
Events During Which Output May Be Read
Recommended: Register for the Update event smlEVENT_AFTER_ALL_OUTPUT_PHASES.
Run Events (agent-specific):
Code:
# Register using Agent::RegisterForRunEvent smlEVENT_AFTER_OUTPUT_PHASE # All three of these are essentially equivalent smlEVENT_AFTER_DECISION_PHASE smlEVENT_AFTER_DECISION_CYCLE
Code:
# Register using Kernel::RegisterForUpdateEvent smlEVENT_AFTER_ALL_OUTPUT_PHASES # Fires after all agents' output phases are done smlEVENT_AFTER_ALL_GENERATED_OUTPUT # Fires as above but only after all agents also have output or reached max-nil-output-cycles
Reading the Output Link
There are a number of different ways to read information from the output link, each with pros and cons. Choose whichever method seems easiest to you.
Examine In Detail
- Use GetOutputLink, GetNumberChildren, GetChild, and other similar methods to examine working memory in its raw state.
- Can't use IsJustAdded and AreChildrenModified -- these require SetTrackOutputLinkChanges true
- Most flexible.
- Can disable change tracking Agent::SetTrackOutputLinkChanges(false)
- Most verbose.
- Use Commands, GetCommand, and GetParamValue to get top level WMEs that have been added since the last cycle.
Pros:
- Easiest.
- Do not save identifiers and return control back to Soar--they could be deleted.
- Not good for commands that span multiple decision cycles, retained so that ^status complete can be added.
- Must follow "command" format: top level identifier.
Code:
# "Command" format <s> ^io.output-link <ol> <ol> ^move <c> # Command name "move" <c> ^direction north # Parameter "direction" # Not "Command" format <s> ^io.output-link <ol> <ol> ^move north
- Use GetNumberOutputLinkChanges, GetOutputLinkChange, and IsOutputLinkChangeAdd to get the list of all WMEs added and removed since the last decision cycle.
Pros:
- Full access to output link.
- Output link removals can be detected using IsOutputLinkChangeAdd() == false
- Great for commands that can span multiple decision cycles because of removal notification.
- Need to parse changes to figure out what's attached to what.
Code:
# This structure: <s> ^io.output-link <ol> <ol> ^move <c> # Command name "move" <c> ^direction north # Parameter "direction" # ... generates these two separate changes: (I3 ^move M1) (M1 ^direction north)
- Use AddOutputHandler to register functions that are called when a specific attributes are added to the output link.
Pros:
- Other update events do not need to be registered (such as smlEVENT_AFTER_ALL_OUTPUT_PHASES)
- Event handling model, can be very clear.
- Full command set needs to be known before hand (only get events when identifiers with registered attributes are added to the output link).
- Do not save identifiers and return control back to Soar--they could be deleted.
- Not good for commands that span multiple decision cycles, retained so that ^status complete can be added.
- Must follow "command" format: top level identifier. See Command Interface above.
Not recommended. Reading the output link without event registration is possible. Generalized steps for this are:
Set the stop phase to before-input.
Call RunTillOutput or Run (one step only--multiple steps will lose tracked changes).
Read the output link.