Skill Resolution Standards
Overview
Every skill in MelodyArc must conclude with an entity controller — the point responsible for resolving the current skill entity and activating the next one when appropriate.
The entity controller forms the bridge between a skill’s execution logic and the operator’s state management, ensuring that progress, messages, and state updates are handled in a consistent, reliable way.
1️⃣ Purpose of an Entity Controller
The entity controller is the final step in a skill’s lifecycle. Its job is to:
- Resolve the current skill entity (mark it as completed or “done”).
- Activate the next entity in the sequence (mark it as “ready” when applicable).
- Update operator state with any information produced or transformed by the skill.
- Send user-facing messages through the MelodyArc Chat Service (MCS) when required.
This keeps each skill self-contained while allowing the operator to progress smoothly from one skill to the next.
2️⃣ Resolution Responsibilities
When a skill resolves, its entity controller should:
-
Mark the entity as complete
- Set the current entity’s
statusto"done".
- Set the current entity’s
-
Activate the next skill (if applicable)
- Locate the next entity with
status: "waiting"and mark it"ready".
- Locate the next entity with
-
Update the operator state
- Add or modify relevant key/value pairs in
operator_state. - Use prefix-based key mapping defined in the
saveStatesobject (see below).
- Add or modify relevant key/value pairs in
-
Send outgoing messages to the user via the MelodyArc Chat Service
- Use
sendMcsUpdateto provide confirmation, results, or contextual messages to the user via MCS.
- Use
-
Return a structured object that merges these results for the next execution stage.
3️⃣ Using the generic_controller
generic_controllerIn most cases, you do not need to write a custom controller.
The standard generic_controller is designed to handle the full lifecycle for 90% of skills.
What the generic_controller handles:
generic_controller handles:- Resolves the current entity (
status: "done"). - Prepares and activates the next skill entity (
status: "ready"). - Sends messages to the user through
_mcs.appendMessage(). - Updates operator state using mappings defined in
saveStates. - Returns a fully structured output for downstream processing.
When to use it:
Use the generic controller unless:
- The skill needs custom sequencing or branching logic.
- You must process or format complex data before sending a user message.
- You need to trigger non-standard integrations beyond MCS and state update behavior.
If one of those conditions applies, you can use the generic controller’s logic as a base and extend it.
4️⃣ Key Configuration Parameters
Both saveStates and sendMcsUpdate are defined as attributes of the invoke that calls the generic_controller.
They provide declarative control over how the controller updates state and communicates with the user.
Additional configuration keys may be introduced in the future to support expanded behaviors and advanced resolution logic.
🗂️ saveStates
saveStatesThe saveStates object defines how to map values from the current entity into the operator state.
Keys are prefix mappings: any field in _this (the current entity) that begins with the prefix will be copied into operator_state under the new destination path.
Example:
"saveStates": {
"_this.result.": "operator_state.skill_results.",
"_this.formData.": "operator_state.last_submission."
}This allows the controller to dynamically persist relevant data between skills without hardcoding field paths.
💬 sendMcsUpdate
sendMcsUpdatesendMcsUpdate defines the message that should be sent to the user at the end of the skill resolution step.
It can be defined either:
- At the entity level (
_this.sendMcsUpdate), or - In the invoke context (
_token.sendMcsUpdate).
The controller uses the first available source and automatically expands dynamic placeholders through the fill_text function before sending the message via MCS.
Example:
"sendMcsUpdate": "Your request for [[_this.formData.item_name]] has been submitted successfully."5️⃣ Data Contexts
| Context | Source | Description |
|---|---|---|
_this | Entity data | Contains the live skill entity being resolved (fields, status, message templates, etc.). |
_token | Invocation context | Holds task-level and operator-level parameters injected when the controller runs (conversation details, metadata, integration name, etc.). |
6️⃣ Example Resolution Flow (Generic Controller)
-
Controller starts
- Reads entity type (
_this._entity.type). - Loads entity list from
_token[entityType].
- Reads entity type (
-
Finds the current and next entities
- Marks the current entity as
"done". - Marks the next waiting entity as
"ready", if one exists.
- Marks the current entity as
-
Sends user message
- Expands
sendMcsUpdatetext withfill_text(). - Sends it through
_mcs.appendMessage()with proper sender and metadata.
- Expands
-
Updates operator state
- Reads
_token.saveStatesand maps_thisvalues accordingly.
- Reads
-
Returns structured output
- Includes entity status changes, updated operator state, and any message results.
9️⃣ Best Practices
✅ Prefer the generic_controller whenever possible — it handles 90% of use cases.
✅ Use saveStates for clean, declarative operator state mapping.
✅ Always include a sendMcsUpdate message when user confirmation or summary is expected.
✅ Keep skill data lightweight — avoid deeply nested objects that complicate key mapping.
✅ Define new configuration keys thoughtfully and document them in future revisions of this standard.
🧠 Summary
An entity controller is how a skill finalizes itself.
It:
- Resolves the current skill,
- Activates the next,
- Updates operator state,
- And communicates with the user.
Most of the time, you can achieve this simply by using the generic controller, configured through an invoke using the attributes saveStates and sendMcsUpdate.
This ensures all skills resolve consistently, share data cleanly, and maintain synchronized state across the operator workflow.
Maintained by: MelodyArc Platform Engineering
Applies to: All skill entity controllers
Version: 1.1
Updated about 17 hours ago
