Add D&D extraction fallback profile

This commit is contained in:
2026-08-03 16:39:45 +00:00
parent b05634ee86
commit a3bd0c1867
16 changed files with 145 additions and 16 deletions

View File

@@ -201,6 +201,76 @@ func TestDefaultCLICompositionValidatesRepresentativeConfiguration(t *testing.T)
}
}
func TestProductionAssetsResolveDNDExtractionProfile(t *testing.T) {
components := productionTestComponents(t)
newEngine := func(profileFile string) (*promptkit.Engine, error) {
t.Helper()
options, err := components.assets.PromptKitOptions()
if err != nil {
return nil, err
}
if profileFile != "" {
options = append(options, promptkit.WithProfileFile(profileFile))
}
return promptkit.NewEngine(promptkit.Config{}, options...)
}
t.Run("fallback", func(t *testing.T) {
engine, err := newEngine("")
if err != nil {
t.Fatal(err)
}
inspection, err := engine.InspectProfile(context.Background(), "dnd-extraction")
if err != nil {
t.Fatalf("InspectProfile() error = %v, want fallback profile", err)
}
params := inspection.EffectiveModelParams
if params.BackendID != "openrouter" || params.Model != "openai/gpt-5.6-luna" || params.TimeoutSeconds != 240 || params.ServiceTier != "flex" {
t.Fatalf("fallback profile parameters = %#v", params)
}
if params.ReasoningEffort != "" || params.Temperature != 0 || params.MaxTokens != 0 || params.TopP != 0 {
t.Fatalf("fallback profile selected optional provider controls: %#v", params)
}
})
t.Run("valid operator profile wins", func(t *testing.T) {
profilePath := filepath.Join(t.TempDir(), "profiles.yaml")
if err := os.WriteFile(profilePath, []byte(`id: dnd-extraction
endpoint: http://operator.example.test/v1
model: operator-model
timeout_seconds: 75
`), 0o600); err != nil {
t.Fatal(err)
}
engine, err := newEngine(profilePath)
if err != nil {
t.Fatal(err)
}
inspection, err := engine.InspectProfile(context.Background(), "dnd-extraction")
if err != nil {
t.Fatalf("InspectProfile() error = %v, want operator profile", err)
}
params := inspection.EffectiveModelParams
if params.BackendID != "" || params.Endpoint != "http://operator.example.test/v1" || params.Model != "operator-model" || params.TimeoutSeconds != 75 || params.ServiceTier != "" {
t.Fatalf("operator profile parameters = %#v, want complete replacement", params)
}
})
t.Run("invalid operator profile does not fall through", func(t *testing.T) {
profilePath := filepath.Join(t.TempDir(), "profiles.yaml")
if err := os.WriteFile(profilePath, []byte("id: dnd-extraction\nendpoint: http://operator.example.test/v1\nmodel: operator-model\nunknown: value\n"), 0o600); err != nil {
t.Fatal(err)
}
engine, err := newEngine(profilePath)
if err == nil {
_, err = engine.InspectProfile(context.Background(), "dnd-extraction")
}
if err == nil {
t.Fatal("operator profile error = nil, want failure instead of fallback")
}
})
}
func TestProductionPromptAssetsPrepareWithoutProviderCredentials(t *testing.T) {
components := productionTestComponents(t)
cfg := config.Default()

View File

@@ -1,6 +1,6 @@
id: dnd.scenes
version: "v1"
default_profile: gemini-2-flash
default_profile: dnd-extraction
inputs:
- name: transcript
required: true

View File

@@ -1,6 +1,6 @@
id: dnd.combat_turns
version: "v1"
default_profile: gemini-2-flash
default_profile: dnd-extraction
inputs:
- name: transcript
required: true

View File

@@ -1,6 +1,6 @@
id: dnd.item_events
version: "v1"
default_profile: gemini-2-flash
default_profile: dnd-extraction
inputs:
- name: transcript
required: true

View File

@@ -1,6 +1,6 @@
id: dnd.npc_interactions
version: "v1"
default_profile: gemini-2-flash
default_profile: dnd-extraction
inputs:
- name: transcript
required: true

View File

@@ -1,6 +1,6 @@
id: dnd.npcs
version: "v1"
default_profile: gemini-2-flash
default_profile: dnd-extraction
inputs:
- name: transcript
required: true

View File

@@ -1,6 +1,6 @@
id: dnd.scene_descriptions
version: "v1"
default_profile: gemini-2-flash
default_profile: dnd-extraction
inputs:
- name: transcript
required: true

View File

@@ -1,6 +1,6 @@
id: dnd.spells
version: "v1"
default_profile: gemini-2-flash
default_profile: dnd-extraction
inputs:
- name: transcript
required: true

View File

@@ -1,6 +1,6 @@
id: dnd.npcs.normalize
version: "v1"
default_profile: gemini-2-flash
default_profile: dnd-extraction
inputs:
- name: candidates
required: true

View File

@@ -0,0 +1,5 @@
id: dnd-extraction
backend: openrouter
model: openai/gpt-5.6-luna
timeout_seconds: 240
service_tier: flex

View File

@@ -0,0 +1,14 @@
package register
import (
"embed"
"gitea.maximumdirect.net/eric/notarius/internal/framework/llm"
)
//go:embed assets/profiles/*.yaml
var embeddedProfileAssets embed.FS
func registerFallbackProfiles(assets *llm.AssetRegistry) error {
return assets.RegisterFallbackProfileFS(embeddedProfileAssets, "assets/profiles")
}

View File

@@ -30,6 +30,9 @@ func Register(registries pipeline.Registries, assets *llm.AssetRegistry) error {
if err := registerPromptAssets(assets); err != nil {
return err
}
if err := registerFallbackProfiles(assets); err != nil {
return err
}
return registerDefaultChains(registries.ValidatorChains)
}

View File

@@ -39,6 +39,31 @@ func TestRegisterAddsDNDFamily(t *testing.T) {
if _, err := fs.ReadFile(promptFS, "dnd.npcs.normalize/dnd.npcs.normalize.yaml"); err != nil {
t.Fatalf("normalization prompt asset = %v, want registered private prompt", err)
}
for _, name := range []string{
"dnd.scenes/dnd.scenes.yaml",
"dnd.spells/dnd.spells.yaml",
"dnd.npcs/dnd.npcs.yaml",
"dnd.combat_turns/dnd.combat_turns.yaml",
"dnd.item_events/dnd.item_events.yaml",
"dnd.npc_interactions/dnd.npc_interactions.yaml",
"dnd.scene_descriptions/dnd.scene_descriptions.yaml",
"dnd.npcs.normalize/dnd.npcs.normalize.yaml",
} {
content, err := fs.ReadFile(promptFS, name)
if err != nil {
t.Fatalf("read prompt asset %q: %v", name, err)
}
if !strings.Contains(string(content), "default_profile: dnd-extraction") {
t.Fatalf("prompt asset %q does not select dnd-extraction", name)
}
}
fallbackFS, err := assets.FallbackProfileFS()
if err != nil {
t.Fatalf("FallbackProfileFS() error = %v", err)
}
if _, err := fs.ReadFile(fallbackFS, "dnd-extraction.yaml"); err != nil {
t.Fatalf("fallback profile asset = %v, want registered D&D profile", err)
}
schemaFS, err := assets.SchemaFS()
if err != nil {
t.Fatalf("SchemaFS() error = %v", err)