Assemble resolved parts into role-faithful messages, coalescing adjacent same-role.
ProtectedcoerceProtectedgetCandidate parts for a prompt: same PromptID + resolvable Status. Override to widen/narrow.
ProtectedisIs this part compatible with the run scope? (cascading: a part may only require dims the run has)
ProtectedorderFinal assembly order: Sort ASC, then Priority DESC, then Name.
ProtectedparseResolve the included, ordered parts for promptID under scope.
ProtectedscoreSpecificity score: SecondaryScopes match (+4) > PrimaryScopeRecord (+2) > Global (+1).
ProtectedselectFrom in-scope candidates, decide inclusion per Name:
Priority;MergeBehavior governs the group — 'Override' keeps only the top,
'Append' keeps all (additive within the Name).
Distinct names always coexist (additive across names).
PromptComponentResolver — decides which
MJ: Scoped Prompt Partsare included for a given prompt under a given scope, and assembles them into a role-faithfulChatMessage[].Pluggable (ClassFactory) + metadata-driven (template method). The public Resolve / AssembleMessages fix the orchestration; the protected hooks (getCandidates, isInScope, score, selectIncluded, order) are the extension points. MJ core obtains the resolver via
MJGlobal.Instance.ClassFactory.CreateInstance(PromptComponentResolver), which returns this base by default (no registration ⇒ base instance) or the highest-priority registered subclass. So any downstream consumer can plug in custom inclusion logic with no core change:Base (metadata-driven) defaults:
Names — distinct names all survive.Name, the row'sMergeBehaviordecides:'Override'(default) ⇒ the most-specific part wins (replace),'Append'⇒ all in-scope same-named parts are included.Priority.SortASC, thenPriorityDESC.