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

@@ -259,9 +259,20 @@ func (client *enemyEventLLMClient) CompleteStructured(ctx context.Context, reque
content = []byte(`{"combat_turns":[{"actor":"Kesh","turn_kind":"turn","source_refs":[{"start_unit_id":8,"end_unit_id":8}]}]}`)
case npcinteractions.PromptID:
if combatScene {
content = []byte(`{"interactions":[{"name":"Kesh","kind":"combat_opponent","source_refs":[{"start_unit_id":7,"end_unit_id":7}]}]}`)
var registry struct {
NPCs []struct {
ID string `json:"id"`
} `json:"npcs"`
}
if err := json.Unmarshal(request.Inputs["npc_registry"].Content, &registry); err != nil {
return contracts.StructuredCompletionResponse{}, fmt.Errorf("decode generated NPC registry: %w", err)
}
if len(registry.NPCs) == 0 {
return contracts.StructuredCompletionResponse{}, fmt.Errorf("generated NPC registry has no NPCs")
}
content = []byte(fmt.Sprintf(`{"occurrences":[{"npc_id":%q,"name":"Kesh","kind":"combat_opponent","source_refs":[{"start_unit_id":7,"end_unit_id":7}]}]}`, registry.NPCs[0].ID))
} else {
content = []byte(`{"interactions":[]}`)
content = []byte(`{"occurrences":[]}`)
}
case locationoccurrences.PromptID:
var registry struct {

View File

@@ -25,7 +25,7 @@ func TestProductionNPCInteractionPipelineResolvesAndPrepares(t *testing.T) {
t.Fatalf("resolved pipeline = %#v", resolved)
}
lane := resolved.Steps[1].ArtifactLanes[0]
if lane.ArtifactKind != dnd.NPCInteractionListKind || lane.Extract.Module != interactionextract.Key || lane.Normalize.Module != interactionnormalize.Key {
if lane.ArtifactKind != dnd.NPCOccurrenceListKind || lane.Extract.Module != interactionextract.Key || lane.Normalize.Module != interactionnormalize.Key {
t.Fatalf("interaction lane = %#v", lane)
}
for _, bindings := range [][]pipeline.ReferenceBinding{lane.ExtractReferences.Bindings, lane.NormalizeReferences.Bindings} {
@@ -38,7 +38,7 @@ func TestProductionNPCInteractionPipelineResolvesAndPrepares(t *testing.T) {
}
catalog := catalogFromRegistries(components.registries)
codecSpec, ok := catalog.ArtifactCodecs.Spec(dnd.NPCInteractionListKind)
codecSpec, ok := catalog.ArtifactCodecs.Spec(dnd.NPCOccurrenceListKind)
if !ok || codecSpec.Schema.ID != interactioncodec.SchemaID || codecSpec.Schema.Version != interactioncodec.SchemaVersion {
t.Fatalf("NPC interaction codec spec = %#v", codecSpec)
}