Adopt registry-backed NPC occurrence artifacts

This commit is contained in:
2026-08-05 18:55:58 +00:00
parent 3f4a1f2647
commit 5e2ccffc0f
42 changed files with 676 additions and 528 deletions

View File

@@ -71,7 +71,7 @@ func referenceSlots() []contracts.ReferenceSlot {
Description: "Required NPC-interaction artifact used only as source-free enemy-event grounding.",
Required: true,
AcceptedMediaTypes: []string{interactioncodec.MediaType},
AcceptedArtifactKinds: []contracts.ArtifactKind{dnd.NPCInteractionListKind},
AcceptedArtifactKinds: []contracts.ArtifactKind{dnd.NPCOccurrenceListKind},
MaxBytes: ReferenceMaxBytes,
},
)
@@ -223,7 +223,7 @@ func prepareNPCInteractionInput(references contracts.ReferenceSet) (*contracts.L
}
content, err := json.Marshal(struct {
Interactions []npcInteractionProjection `json:"npc_interactions"`
}{Interactions: projectNPCInteractions(value.Interactions)})
}{Interactions: projectNPCInteractions(value.Occurrences)})
if err != nil {
return nil, fmt.Errorf("encode NPC-interaction grounding: %w", err)
}
@@ -272,15 +272,15 @@ func projectCombatTurns(turns []dnd.CombatTurn) []combatTurnProjection {
}
type npcInteractionProjection struct {
Name string `json:"name"`
Kind dnd.NPCInteractionKind `json:"kind"`
Name string `json:"name"`
Kind dnd.NPCOccurrenceKind `json:"kind"`
}
func projectNPCInteractions(interactions []dnd.NPCInteraction) []npcInteractionProjection {
projection := make([]npcInteractionProjection, 0, len(interactions))
for _, interaction := range interactions {
if interaction.Kind == dnd.NPCInteractionKindCombatOpponent {
projection = append(projection, npcInteractionProjection{Name: interaction.Name, Kind: interaction.Kind})
func projectNPCInteractions(occurrences []dnd.NPCOccurrence) []npcInteractionProjection {
projection := make([]npcInteractionProjection, 0, len(occurrences))
for _, occurrence := range occurrences {
if occurrence.Kind == dnd.NPCOccurrenceKindCombatOpponent {
projection = append(projection, npcInteractionProjection{Name: occurrence.Name, Kind: occurrence.Kind})
}
}
return projection

View File

@@ -36,7 +36,7 @@ func TestReferenceSlotsDescribeRequiredTypedArtifacts(t *testing.T) {
{NPCRegistryReferenceSlot, dnd.NPCRegistryKind},
{SceneDescriptionReferenceSlot, dnd.SceneDescriptionListKind},
{CombatTurnReferenceSlot, dnd.CombatTurnListKind},
{NPCInteractionReferenceSlot, dnd.NPCInteractionListKind},
{NPCInteractionReferenceSlot, dnd.NPCOccurrenceListKind},
} {
slot, ok := byName[want.name]
if !ok || !slot.Required || slot.MaxBytes != ReferenceMaxBytes || len(slot.AcceptedMediaTypes) != 1 || slot.AcceptedMediaTypes[0] != "application/json" || len(slot.AcceptedArtifactKinds) != 1 || slot.AcceptedArtifactKinds[0] != want.kind {
@@ -220,9 +220,9 @@ func groundingReferences(t *testing.T, enemy string, sceneKind dnd.SceneKind) co
if err != nil {
t.Fatal(err)
}
interactionContent, err := interactioncodec.New().Encode(dnd.NPCInteractionList{Interactions: []dnd.NPCInteraction{
{Name: enemy, Kind: dnd.NPCInteractionKindCombatOpponent, SourceRefs: []source.SourceRef{{SourceID: "combat-session", StartUnitID: 1, EndUnitID: 1}}},
{Name: "Aria", Kind: dnd.NPCInteractionKindCombatAlly, SourceRefs: []source.SourceRef{{SourceID: "combat-session", StartUnitID: 2, EndUnitID: 2}}},
interactionContent, err := interactioncodec.New().Encode(dnd.NPCOccurrenceList{Occurrences: []dnd.NPCOccurrence{
{NPCID: identity.DeriveID(enemy), Name: enemy, Kind: dnd.NPCOccurrenceKindCombatOpponent, SourceRefs: []source.SourceRef{{SourceID: "combat-session", StartUnitID: 1, EndUnitID: 1}}},
{NPCID: identity.DeriveID("Aria"), Name: "Aria", Kind: dnd.NPCOccurrenceKindCombatAlly, SourceRefs: []source.SourceRef{{SourceID: "combat-session", StartUnitID: 2, EndUnitID: 2}}},
}})
if err != nil {
t.Fatal(err)