Yes — that is exactly the direction I’m taking.
The emotion/state layer is not meant to be a fixed hardcoded enum, but it also should not be completely free-form.
The user can dynamically add the emotions or vessel states they want, and then the runtime treats that loaded preset set as the current contract. The LLM can choose from that allowed state space, but it should not invent new executable states outside of it.
So the flow is roughly:
- User defines or adds emotion presets
- Runtime loads the available preset set
- The model selects from those existing states
- Missing, malformed, or unknown tags fail closed or fall back to neutral
That way the vessel stays customizable, but the model’s output is still schema-bound instead of arbitrary free text.
The output contract splitting each reply into dialogue, data, and action planes is the interesting idea here, more than the avatar itself. Making the model emit an explicit [confirm] before an irreversible step and blocking on the keypress is a nice structured way to keep a human in the loop without bolting on a separate approval UI. The one thing I would test is what happens when the model emits a malformed or missing action tag, since the safety of the whole scheme rests on that tag being present and correct, which is a structured-output validation problem at heart.