Move DnD shared prompt assets into helper package

This commit is contained in:
2026-07-06 17:15:27 +00:00
parent 68b426cdb0
commit 524f2ffb8e
11 changed files with 107 additions and 31 deletions

View File

@@ -16,7 +16,6 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/modules/merge/appendorder"
"gitea.maximumdirect.net/eric/notarius/internal/modules/normalize/noop"
jsonoutput "gitea.maximumdirect.net/eric/notarius/internal/modules/output/json"
"gitea.maximumdirect.net/eric/notarius/internal/modules/sharedassets"
)
func productionRegistries() (pipeline.Registries, error) {
@@ -63,9 +62,6 @@ func productionCatalog() (pipeline.ModuleCatalog, error) {
func productionPromptAssets() (*llm.AssetRegistry, error) {
registry := llm.NewAssetRegistry()
if err := sharedassets.Register(registry); err != nil {
return nil, fmt.Errorf("register shared dnd prompt assets: %w", err)
}
if err := scenes.RegisterPromptAssets(registry); err != nil {
return nil, fmt.Errorf("register dnd scenes prompt assets: %w", err)
}

View File

@@ -191,9 +191,6 @@ func TestProductionPromptAssetsRegisterAndPrepareDndPrompts(t *testing.T) {
t.Fatalf("PromptFS() error = %v, want nil", err)
}
for _, name := range []string{
"common-dnd-system.md",
"common-dnd-transcript.md",
"common-dnd-references.md",
"dnd.scenes/dnd.scenes.yaml",
"dnd.scenes/task.md",
"dnd.scenes/instructions.md",

View File

@@ -9,16 +9,17 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/framework/llm"
"gitea.maximumdirect.net/eric/notarius/internal/modules/sharedassets"
"gitea.maximumdirect.net/eric/notarius/internal/modules/sharedassets/dnd"
)
const scriptoriumPromptRoot = "assets/prompts"
func RegisterPromptAssets(registry *llm.AssetRegistry) error {
promptFS, err := sharedassets.ModulePromptFS("dnd.scenes", embeddedAssets, []sharedassets.ModulePromptFile{
promptFS, err := dnd.ModulePromptFS("dnd.scenes", embeddedAssets, []sharedassets.ModulePromptFile{
{Name: "dnd.scenes.yaml", Path: "assets/prompts/dnd.scenes.yaml"},
{Name: "task.md", Path: "assets/prompts/task.md"},
{Name: "instructions.md", Path: "assets/prompts/instructions.md"},
}, sharedassets.SharedPromptFiles()...)
})
if err != nil {
return fmt.Errorf("prepare scene prompt assets: %w", err)
}
@@ -64,7 +65,7 @@ func scriptoriumPromptMetadata() (string, error) {
{FS: embeddedAssets, Path: "assets/prompts/dnd.scenes.yaml"},
{FS: embeddedAssets, Path: "assets/prompts/task.md"},
{FS: embeddedAssets, Path: "assets/prompts/instructions.md"},
}, append(sharedassets.CommonHashParts(), sharedassets.ReferenceHashParts()...)...)
}, append(dnd.CommonHashParts(), dnd.ReferenceHashParts()...)...)
scriptoriumPromptHash, scriptoriumPromptHashErr = llm.HashAssets(parts)
})
return scriptoriumPromptHash, scriptoriumPromptHashErr

View File

@@ -8,7 +8,6 @@ import (
"time"
"gitea.maximumdirect.net/eric/notarius/internal/framework/llm"
"gitea.maximumdirect.net/eric/notarius/internal/modules/sharedassets"
"gitea.maximumdirect.net/eric/scriptorium"
)
@@ -90,9 +89,6 @@ func TestScriptoriumPromptDiagnosticsOmitRawMaterials(t *testing.T) {
func prepareScenesPrompt(t *testing.T, transcript []byte, players string, party string, glossary string) *scriptorium.PreparedRun {
t.Helper()
registry := llm.NewAssetRegistry()
if err := sharedassets.Register(registry); err != nil {
t.Fatalf("register shared prompt assets: %v", err)
}
if err := RegisterPromptAssets(registry); err != nil {
t.Fatalf("register scene prompt assets: %v", err)
}

View File

@@ -9,16 +9,17 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/framework/llm"
"gitea.maximumdirect.net/eric/notarius/internal/modules/sharedassets"
"gitea.maximumdirect.net/eric/notarius/internal/modules/sharedassets/dnd"
)
const scriptoriumPromptRoot = "assets/prompts"
func RegisterPromptAssets(registry *llm.AssetRegistry) error {
promptFS, err := sharedassets.ModulePromptFS("dnd.spells", embeddedAssets, []sharedassets.ModulePromptFile{
promptFS, err := dnd.ModulePromptFS("dnd.spells", embeddedAssets, []sharedassets.ModulePromptFile{
{Name: "dnd.spells.yaml", Path: "assets/prompts/dnd.spells.yaml"},
{Name: "task.md", Path: "assets/prompts/task.md"},
{Name: "instructions.md", Path: "assets/prompts/instructions.md"},
}, sharedassets.SharedPromptFiles()...)
})
if err != nil {
return fmt.Errorf("prepare spell prompt assets: %w", err)
}
@@ -64,7 +65,7 @@ func scriptoriumPromptMetadata() (string, error) {
{FS: embeddedAssets, Path: "assets/prompts/dnd.spells.yaml"},
{FS: embeddedAssets, Path: "assets/prompts/task.md"},
{FS: embeddedAssets, Path: "assets/prompts/instructions.md"},
}, append(sharedassets.CommonHashParts(), sharedassets.ReferenceHashParts()...)...)
}, append(dnd.CommonHashParts(), dnd.ReferenceHashParts()...)...)
scriptoriumPromptHash, scriptoriumPromptHashErr = llm.HashAssets(parts)
})
return scriptoriumPromptHash, scriptoriumPromptHashErr

View File

@@ -9,7 +9,6 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/framework/llm"
"gitea.maximumdirect.net/eric/notarius/internal/modules/sharedassets"
"gitea.maximumdirect.net/eric/scriptorium"
)
@@ -140,9 +139,6 @@ func TestScriptoriumPromptDiagnosticsOmitRawMaterials(t *testing.T) {
func prepareSpellsPrompt(t *testing.T, transcript []byte, players string, party string, glossary string) *scriptorium.PreparedRun {
t.Helper()
registry := llm.NewAssetRegistry()
if err := sharedassets.Register(registry); err != nil {
t.Fatalf("register shared prompt assets: %v", err)
}
if err := RegisterPromptAssets(registry); err != nil {
t.Fatalf("register spell prompt assets: %v", err)
}

View File

@@ -1,28 +1,26 @@
package sharedassets
package dnd
import (
"embed"
"io/fs"
"gitea.maximumdirect.net/eric/notarius/internal/framework/llm"
"gitea.maximumdirect.net/eric/notarius/internal/modules/sharedassets"
)
//go:embed assets/prompts/*.md
var embeddedAssets embed.FS
var commonDNDPromptFiles = []string{
var sharedPromptFiles = []string{
"common-dnd-system.md",
"common-dnd-transcript.md",
"common-dnd-references.md",
}
func Register(registry *llm.AssetRegistry) error {
return registry.RegisterPromptFS(embeddedAssets, "assets/prompts")
}
func SharedPromptFiles() []SharedPromptFile {
files := make([]SharedPromptFile, 0, len(commonDNDPromptFiles))
for _, name := range commonDNDPromptFiles {
files = append(files, SharedPromptFile{
func SharedPromptFiles() []sharedassets.SharedPromptFile {
files := make([]sharedassets.SharedPromptFile, 0, len(sharedPromptFiles))
for _, name := range sharedPromptFiles {
files = append(files, sharedassets.SharedPromptFile{
Name: name,
FS: embeddedAssets,
Path: "assets/prompts/" + name,
@@ -43,3 +41,7 @@ func ReferenceHashParts() []llm.AssetHashPart {
{FS: embeddedAssets, Path: "assets/prompts/common-dnd-references.md"},
}
}
func ModulePromptFS(moduleDir string, moduleFS fs.FS, files []sharedassets.ModulePromptFile) (fs.FS, error) {
return sharedassets.ModulePromptFS(moduleDir, moduleFS, files, SharedPromptFiles()...)
}

View File

@@ -0,0 +1,87 @@
package dnd
import (
"io/fs"
"testing"
"testing/fstest"
"gitea.maximumdirect.net/eric/notarius/internal/framework/llm"
"gitea.maximumdirect.net/eric/notarius/internal/modules/sharedassets"
)
func TestSharedPromptFilesReturnsNewSlice(t *testing.T) {
first := SharedPromptFiles()
second := SharedPromptFiles()
if len(first) != 3 || len(second) != 3 {
t.Fatalf("SharedPromptFiles() lengths = %d and %d, want 3", len(first), len(second))
}
first[0].Name = "changed.md"
if second[0].Name != "common-dnd-system.md" {
t.Fatalf("SharedPromptFiles() reused descriptor slice: %#v", second)
}
}
func TestSharedPromptFilesReferenceEmbeddedAssets(t *testing.T) {
for _, file := range SharedPromptFiles() {
if file.FS == nil {
t.Fatalf("SharedPromptFiles() descriptor %q has nil FS", file.Name)
}
if _, err := fs.ReadFile(file.FS, file.Path); err != nil {
t.Fatalf("ReadFile(%q) error = %v, want nil", file.Path, err)
}
}
}
func TestHashPartsReferenceSharedPrompts(t *testing.T) {
assertHashParts(t, "common", CommonHashParts(), []string{
"assets/prompts/common-dnd-system.md",
"assets/prompts/common-dnd-transcript.md",
})
assertHashParts(t, "reference", ReferenceHashParts(), []string{
"assets/prompts/common-dnd-references.md",
})
for _, part := range append(CommonHashParts(), ReferenceHashParts()...) {
if _, err := fs.ReadFile(part.FS, part.Path); err != nil {
t.Fatalf("ReadFile(%q) error = %v, want nil", part.Path, err)
}
}
}
func assertHashParts(t *testing.T, name string, parts []llm.AssetHashPart, want []string) {
t.Helper()
if len(parts) != len(want) {
t.Fatalf("%s hash parts length = %d, want %d", name, len(parts), len(want))
}
for i, part := range parts {
if part.Path != want[i] {
t.Fatalf("%s hash part %d path = %q, want %q", name, i, part.Path, want[i])
}
if part.FS == nil {
t.Fatalf("%s hash part %d has nil FS", name, i)
}
}
}
func TestModulePromptFSMountsDNDSharedPrompts(t *testing.T) {
fsys, err := ModulePromptFS("dnd.test", fstest.MapFS{
"assets/prompts/dnd.test.yaml": {Data: []byte("id: dnd.test")},
}, []sharedassets.ModulePromptFile{
{Name: "dnd.test.yaml", Path: "assets/prompts/dnd.test.yaml"},
})
if err != nil {
t.Fatalf("ModulePromptFS() error = %v, want nil", err)
}
for _, path := range []string{
"assets/prompts/dnd.test/dnd.test.yaml",
"assets/prompts/dnd.test/sharedassets/common-dnd-system.md",
"assets/prompts/dnd.test/sharedassets/common-dnd-transcript.md",
"assets/prompts/dnd.test/sharedassets/common-dnd-references.md",
} {
if _, err := fs.ReadFile(fsys, path); err != nil {
t.Fatalf("ReadFile(%q) error = %v, want nil", path, err)
}
}
}