Update public configuration and inventory contracts
This commit is contained in:
@@ -40,7 +40,7 @@ func TestCollectionInputLoadsNativeImportsAndLaterOverride(t *testing.T) {
|
||||
if err := os.WriteFile(mainPath, []byte("config:\n imports:\n - path: defaults.yaml\n required: true\n"), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(defaultsPath, []byte("prompts:\n greeting:\n version: imported\n messages:\n - role: user\n content: Hello\n output:\n format: text\n validation_mode: none\n"), 0o600); err != nil {
|
||||
if err := os.WriteFile(defaultsPath, []byte("prompts:\n - id: greeting\n messages:\n - role: user\n content: Hello\n output:\n format: text\n validation_mode: none\n"), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
input, err := promptkit.CollectionInput("docs", configkit.File(mainPath))
|
||||
@@ -50,7 +50,7 @@ func TestCollectionInputLoadsNativeImportsAndLaterOverride(t *testing.T) {
|
||||
engine, err := promptkit.NewEngine(promptkit.Config{Sources: promptkit.ConfigurationSources{
|
||||
Underlays: []configkit.Underlay{{Inputs: []configkit.Input{input}}},
|
||||
Main: &configkit.Input{
|
||||
Source: configkit.Mapping("later collection override", map[string]any{"prompts": map[string]any{"greeting": map[string]any{"version": "overridden"}}}),
|
||||
Source: configkit.Mapping("later collection override", map[string]any{"prompts": []any{map[string]any{"id": "greeting", "inputs": []any{map[string]any{"name": "overridden"}}, "messages": []any{map[string]any{"role": "user", "content": "Updated"}}, "output": map[string]any{"format": "text", "validation_mode": "none"}}}}),
|
||||
Destination: configkit.Keys("collections", "docs"),
|
||||
},
|
||||
}})
|
||||
@@ -58,7 +58,7 @@ func TestCollectionInputLoadsNativeImportsAndLaterOverride(t *testing.T) {
|
||||
t.Fatalf("construct engine with native collection import: %v", err)
|
||||
}
|
||||
inspection, err := engine.InspectPrompt(context.Background(), "docs/greeting")
|
||||
if err != nil || inspection.PromptVersion == nil || *inspection.PromptVersion != "overridden" {
|
||||
if err != nil || inspection.PromptID != "docs/greeting" || len(inspection.Inputs) != 1 || inspection.Inputs[0].Name != "overridden" {
|
||||
t.Fatalf("inspect imported and overlaid prompt = (%+v, %v)", inspection, err)
|
||||
}
|
||||
}
|
||||
@@ -66,7 +66,7 @@ func TestCollectionInputLoadsNativeImportsAndLaterOverride(t *testing.T) {
|
||||
func TestCollectionInputLoadsEmbeddedImportsAndLaterOverride(t *testing.T) {
|
||||
files := fstest.MapFS{
|
||||
"collection.yaml": {Data: []byte("config:\n imports:\n - path: defaults.yaml\n required: true\n")},
|
||||
"defaults.yaml": {Data: []byte("prompts:\n greeting:\n version: imported\n messages:\n - role: user\n content: Hello\n output:\n format: text\n validation_mode: none\n")},
|
||||
"defaults.yaml": {Data: []byte("prompts:\n - id: greeting\n messages:\n - role: user\n content: Hello\n output:\n format: text\n validation_mode: none\n")},
|
||||
}
|
||||
filesystem := configkit.NewFilesystem("embedded collection", files)
|
||||
input, err := promptkit.CollectionInput("docs", filesystem.File("collection.yaml"))
|
||||
@@ -77,7 +77,7 @@ func TestCollectionInputLoadsEmbeddedImportsAndLaterOverride(t *testing.T) {
|
||||
engine, err := promptkit.NewEngine(promptkit.Config{Sources: promptkit.ConfigurationSources{
|
||||
Underlays: []configkit.Underlay{{Inputs: []configkit.Input{input}}},
|
||||
Main: &configkit.Input{
|
||||
Source: configkit.Mapping("later collection override", map[string]any{"prompts": map[string]any{"greeting": map[string]any{"version": "overridden"}}}),
|
||||
Source: configkit.Mapping("later collection override", map[string]any{"prompts": []any{map[string]any{"id": "greeting", "inputs": []any{map[string]any{"name": "overridden"}}, "messages": []any{map[string]any{"role": "user", "content": "Updated"}}, "output": map[string]any{"format": "text", "validation_mode": "none"}}}}),
|
||||
Destination: configkit.Keys("collections", "docs"),
|
||||
},
|
||||
}})
|
||||
@@ -85,7 +85,7 @@ func TestCollectionInputLoadsEmbeddedImportsAndLaterOverride(t *testing.T) {
|
||||
t.Fatalf("construct engine with embedded collection import: %v", err)
|
||||
}
|
||||
inspection, err := engine.InspectPrompt(context.Background(), "docs/greeting")
|
||||
if err != nil || inspection.PromptVersion == nil || *inspection.PromptVersion != "overridden" {
|
||||
if err != nil || inspection.PromptID != "docs/greeting" || len(inspection.Inputs) != 1 || inspection.Inputs[0].Name != "overridden" {
|
||||
t.Fatalf("inspect imported and overlaid prompt = (%+v, %v)", inspection, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,8 +73,8 @@ func TestProfileEnvironmentLookupAcceptsNonShellNames(t *testing.T) {
|
||||
func TestPublicConstructionWithLocalBackendAndProgrammaticProfile(t *testing.T) {
|
||||
backendID, model := "workstation", "offline-model"
|
||||
prompt := configkit.Input{Source: configkit.Mapping("prompt", map[string]any{
|
||||
"prompts": map[string]any{"hello": map[string]any{
|
||||
"version": "1",
|
||||
"prompts": []any{map[string]any{
|
||||
"id": "hello",
|
||||
"default_profile": "offline",
|
||||
"messages": []any{map[string]any{"role": "user", "content": "Hello"}},
|
||||
"output": map[string]any{"format": "text", "validation_mode": "none"},
|
||||
@@ -143,12 +143,11 @@ func TestPublicConstructionCombinesEmbeddedOperatorAndProgrammaticInputs(t *test
|
||||
embedded, err := promptkit.FilesystemInputs("embedded defaults", fstest.MapFS{
|
||||
"config/default.yaml": &fstest.MapFile{Data: []byte(`
|
||||
profiles:
|
||||
application:
|
||||
- id: application
|
||||
endpoint: https://example.invalid/v1
|
||||
model: default-model
|
||||
prompts:
|
||||
hello:
|
||||
version: "1"
|
||||
- id: hello
|
||||
default_profile: application
|
||||
messages:
|
||||
- role: user
|
||||
@@ -162,16 +161,16 @@ prompts:
|
||||
t.Fatalf("select embedded defaults: %v", err)
|
||||
}
|
||||
operatorDirectory := t.TempDir()
|
||||
if err := os.WriteFile(filepath.Join(operatorDirectory, "override.yaml"), []byte("profiles:\n application:\n model: operator-model\n"), 0o644); err != nil {
|
||||
if err := os.WriteFile(filepath.Join(operatorDirectory, "override.yaml"), []byte("profiles:\n - id: application\n endpoint: https://example.invalid/v1\n model: operator-model\n"), 0o644); err != nil {
|
||||
t.Fatalf("write operator input: %v", err)
|
||||
}
|
||||
operator, err := promptkit.DirectoryInputs(operatorDirectory)
|
||||
if err != nil {
|
||||
t.Fatalf("select operator inputs: %v", err)
|
||||
}
|
||||
programmaticModel := "programmatic-model"
|
||||
programmaticModel, programmaticEndpoint := "programmatic-model", "https://example.invalid/v1"
|
||||
programmatic := configkit.Input{Source: promptkit.ProfileSource("programmatic settings", []promptkit.ProfileConfig{
|
||||
{ID: "application", Model: &programmaticModel},
|
||||
{ID: "application", Endpoint: &programmaticEndpoint, Model: &programmaticModel},
|
||||
})}
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
@@ -207,7 +206,7 @@ prompts:
|
||||
|
||||
func TestPublicConstructionPreservesConfigKitLoadError(t *testing.T) {
|
||||
engine, err := promptkit.NewEngine(promptkit.Config{Sources: promptkit.ConfigurationSources{Main: &configkit.Input{
|
||||
Source: configkit.Mapping("invalid", map[string]any{"profiles": map[string]any{"broken": map[string]any{"unknown": true}}}),
|
||||
Source: configkit.Mapping("invalid", map[string]any{"profiles": []any{map[string]any{"id": "broken", "unknown": true}}}),
|
||||
}}})
|
||||
var loadErr *configkit.LoadError
|
||||
if engine != nil || !errors.Is(err, promptkit.ErrInvalidConfig) || !errors.As(err, &loadErr) {
|
||||
@@ -291,7 +290,7 @@ func TestBackendSourceOwnsSmokeTestValuesAndDefersDefaultLookup(t *testing.T) {
|
||||
"https://backend.example/v1",
|
||||
"not-yet-listed",
|
||||
"https://probe.example/ready?check=1",
|
||||
"openrouter_key",
|
||||
" OPENROUTER_KEY ",
|
||||
"https://probe.example/key?scope=current",
|
||||
} {
|
||||
if !strings.Contains(contents, want) {
|
||||
|
||||
@@ -701,6 +701,13 @@ inspection, listing, and namespace contract tests.
|
||||
Validation: run the affected external-package contract tests using real ConfigKit
|
||||
composition and offline sources. Do not add index/list-position guarantees.
|
||||
|
||||
Completion: public source, construction, profile inheritance/inspection,
|
||||
namespace, and inventory fixtures now use explicit-ID lists and identity
|
||||
inheritance. Layered replacements supply complete records, and configuration
|
||||
inspection assertions reflect composed values. Focused offline contract tests
|
||||
passed on Go 1.27.0. Tests depending on the shared legacy execution fixture and
|
||||
the full root package remain assigned to subsequent fixture migrations.
|
||||
|
||||
## Stage 16: Migrate Internal Execution And Rendering Fixtures
|
||||
|
||||
Scope: remaining `internal/usecase`, `internal/prompt`, `internal/domain`, and
|
||||
|
||||
@@ -17,8 +17,8 @@ import (
|
||||
func TestListIdentitiesBasicContract(t *testing.T) {
|
||||
engine, err := promptkit.NewEngine(promptkit.Config{Sources: promptkit.ConfigurationSources{Main: &configkit.Input{
|
||||
Source: configkit.Mapping("listing", map[string]any{
|
||||
"profiles": map[string]any{"configured-profile": map[string]any{"model": "example-model"}},
|
||||
"prompts": map[string]any{"example-prompt": promptDefinitionWithVersion("10", listingContractPrompt())},
|
||||
"profiles": []any{map[string]any{"id": "configured-profile", "model": "example-model"}},
|
||||
"prompts": []any{listingContractPrompt("example-prompt")},
|
||||
}),
|
||||
}}})
|
||||
if err != nil {
|
||||
@@ -38,13 +38,13 @@ func TestListIdentitiesBasicContract(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
want := []promptkit.PromptIdentity{
|
||||
{ID: "example-prompt", Version: stringPointerForTest("10")},
|
||||
{ID: "example-prompt"},
|
||||
}
|
||||
if len(prompts) != len(want) {
|
||||
t.Fatalf("prompt listing = %#v, want %#v", prompts, want)
|
||||
}
|
||||
for i := range want {
|
||||
if prompts[i].ID != want[i].ID || prompts[i].Version == nil || *prompts[i].Version != *want[i].Version {
|
||||
if prompts[i].ID != want[i].ID {
|
||||
t.Fatalf("prompt listing = %#v, want %#v", prompts, want)
|
||||
}
|
||||
}
|
||||
@@ -54,8 +54,7 @@ func TestListIdentitiesBasicContract(t *testing.T) {
|
||||
t.Fatalf("listed profile could not be inspected: (%+v, %v)", profile, err)
|
||||
}
|
||||
prompt, err := engine.InspectPrompt(context.Background(), prompts[0].ID)
|
||||
if err != nil || prompt == nil || prompt.PromptID != prompts[0].ID || prompt.PromptVersion == nil ||
|
||||
*prompt.PromptVersion != *prompts[0].Version {
|
||||
if err != nil || prompt == nil || prompt.PromptID != prompts[0].ID {
|
||||
t.Fatalf("listed prompt could not be inspected: (%+v, %v)", prompt, err)
|
||||
}
|
||||
}
|
||||
@@ -135,16 +134,15 @@ func TestScopedIdentityListingsApplyNamespaceFilters(t *testing.T) {
|
||||
}
|
||||
|
||||
prompts, err := scoped.ListPrompts(context.Background(), promptkit.NamespaceFilter{Mode: promptkit.NamespaceNamed, Name: "team"})
|
||||
if err != nil || len(prompts) != 1 || prompts[0].ID != "team/prompt" || prompts[0].Version == nil || *prompts[0].Version != "team-v1" {
|
||||
if err != nil || len(prompts) != 1 || prompts[0].ID != "team/prompt" {
|
||||
t.Fatalf("named prompt identity = %#v, %v", prompts, err)
|
||||
}
|
||||
if _, err := scoped.InspectPrompt(context.Background(), prompts[0].ID); err != nil {
|
||||
t.Fatalf("listed full prompt ID did not round trip: %v", err)
|
||||
}
|
||||
*prompts[0].Version = "caller change"
|
||||
prompts[0].ID = "caller change"
|
||||
prompts, err = scoped.ListPrompts(context.Background(), promptkit.NamespaceFilter{Mode: promptkit.NamespaceNamed, Name: "team"})
|
||||
if err != nil || len(prompts) != 1 || prompts[0].ID != "team/prompt" || prompts[0].Version == nil || *prompts[0].Version != "team-v1" {
|
||||
if err != nil || len(prompts) != 1 || prompts[0].ID != "team/prompt" {
|
||||
t.Fatalf("mutating filtered prompt inventory escaped: %#v, %v", prompts, err)
|
||||
}
|
||||
profiles, err := scoped.ListProfiles(context.Background(), promptkit.NamespaceFilter{Mode: promptkit.NamespaceNamed, Name: "team"})
|
||||
@@ -214,9 +212,9 @@ func newNamespaceListingEngine(t *testing.T) *promptkit.Engine {
|
||||
t.Helper()
|
||||
collection := func(namespace string) map[string]any {
|
||||
return map[string]any{
|
||||
"backends": map[string]any{"backend": map[string]any{"endpoint": "https://example.test/v1"}},
|
||||
"profiles": map[string]any{"profile": map[string]any{"backend": namespace + "/backend", "model": "example-model"}},
|
||||
"prompts": map[string]any{"prompt": promptDefinitionWithVersion("team-v1", listingContractPrompt())},
|
||||
"backends": []any{map[string]any{"id": "backend", "endpoint": "https://example.test/v1"}},
|
||||
"profiles": []any{map[string]any{"id": "profile", "backend": namespace + "/backend", "model": "example-model"}},
|
||||
"prompts": []any{listingContractPrompt("prompt")},
|
||||
}
|
||||
}
|
||||
input := configkit.Input{Source: configkit.Mapping("namespaced listing", map[string]any{
|
||||
@@ -224,9 +222,9 @@ func newNamespaceListingEngine(t *testing.T) *promptkit.Engine {
|
||||
"team": collection("team"),
|
||||
"team-blue": collection("team-blue"),
|
||||
},
|
||||
"backends": map[string]any{"root-backend": map[string]any{"endpoint": "https://root.example.test/v1"}},
|
||||
"profiles": map[string]any{"root-profile": map[string]any{"backend": "root-backend", "model": "root-model"}},
|
||||
"prompts": map[string]any{"root-prompt": promptDefinitionWithVersion("root-v1", listingContractPrompt())},
|
||||
"backends": []any{map[string]any{"id": "root-backend", "endpoint": "https://root.example.test/v1"}},
|
||||
"profiles": []any{map[string]any{"id": "root-profile", "backend": "root-backend", "model": "root-model"}},
|
||||
"prompts": []any{listingContractPrompt("root-prompt")},
|
||||
})}
|
||||
engine, err := promptkit.NewEngine(promptkit.Config{Sources: promptkit.ConfigurationSources{Main: &input}})
|
||||
if err != nil {
|
||||
@@ -241,18 +239,18 @@ func newNamespaceListingEngine(t *testing.T) *promptkit.Engine {
|
||||
|
||||
func TestResourceAndCollectionInventories(t *testing.T) {
|
||||
underlay := configkit.Input{Source: configkit.Mapping("inventory defaults", map[string]any{
|
||||
"backends": map[string]any{"root-backend": map[string]any{"endpoint": "https://root.example.test/v1"}},
|
||||
"profiles": map[string]any{"root-profile": map[string]any{"endpoint": "https://root.example.test/v1", "model": "root-model"}},
|
||||
"prompts": map[string]any{"root-prompt": listingContractPrompt()},
|
||||
"backends": []any{map[string]any{"id": "root-backend", "endpoint": "https://root.example.test/v1"}},
|
||||
"profiles": []any{map[string]any{"id": "root-profile", "endpoint": "https://root.example.test/v1", "model": "root-model"}},
|
||||
"prompts": []any{listingContractPrompt("root-prompt")},
|
||||
"collections": map[string]any{
|
||||
"alpha": map[string]any{
|
||||
"backends": map[string]any{"api": map[string]any{"endpoint": "https://alpha.example.test/v1"}},
|
||||
"profiles": map[string]any{"profile": map[string]any{"backend": "alpha/api", "model": "alpha-model"}},
|
||||
"prompts": map[string]any{"prompt": listingContractPrompt()},
|
||||
"backends": []any{map[string]any{"id": "api", "endpoint": "https://alpha.example.test/v1"}},
|
||||
"profiles": []any{map[string]any{"id": "profile", "backend": "alpha/api", "model": "alpha-model"}},
|
||||
"prompts": []any{listingContractPrompt("prompt")},
|
||||
},
|
||||
"alpha-beta": map[string]any{"prompts": map[string]any{"prompt": listingContractPrompt()}},
|
||||
"beta": map[string]any{"backends": map[string]any{"api": map[string]any{"endpoint": "https://beta.example.test/v1"}}},
|
||||
"resource-only": map[string]any{"profiles": map[string]any{"profile": map[string]any{"endpoint": "https://resource.example.test/v1", "model": "resource-model"}}},
|
||||
"alpha-beta": map[string]any{"prompts": []any{listingContractPrompt("prompt")}},
|
||||
"beta": map[string]any{"backends": []any{map[string]any{"id": "api", "endpoint": "https://beta.example.test/v1"}}},
|
||||
"resource-only": map[string]any{"profiles": []any{map[string]any{"id": "profile", "endpoint": "https://resource.example.test/v1", "model": "resource-model"}}},
|
||||
"metadata-only": map[string]any{"release_version": "v1"},
|
||||
"empty-label": map[string]any{"release_version": ""},
|
||||
"null-label": map[string]any{"release_version": nil},
|
||||
@@ -363,8 +361,8 @@ func TestListIdentitiesInvalidEngine(t *testing.T) {
|
||||
func TestListIdentitiesPreserveContextErrorsWithoutPartialResults(t *testing.T) {
|
||||
engine, err := promptkit.NewEngine(promptkit.Config{Sources: promptkit.ConfigurationSources{Main: &configkit.Input{
|
||||
Source: configkit.Mapping("listing", map[string]any{
|
||||
"profiles": map[string]any{"profile": map[string]any{}},
|
||||
"prompts": map[string]any{"example": promptDefinitionWithVersion("v1", listingContractPrompt())},
|
||||
"profiles": []any{map[string]any{"id": "profile"}},
|
||||
"prompts": []any{listingContractPrompt("example")},
|
||||
}),
|
||||
}}})
|
||||
if err != nil {
|
||||
@@ -399,26 +397,20 @@ func TestListIdentitiesPreserveContextErrorsWithoutPartialResults(t *testing.T)
|
||||
func TestListIdentitiesUseEffectiveLayeredMembership(t *testing.T) {
|
||||
underlay := configkit.Input{Source: configkit.Mapping("consumer defaults", map[string]any{
|
||||
"collections": map[string]any{"shared": map[string]any{
|
||||
"profiles": map[string]any{
|
||||
"base": map[string]any{"endpoint": "https://example.test/v1", "model": "base-model"},
|
||||
"child": map[string]any{"extends": "base"},
|
||||
"overlay": map[string]any{"endpoint": "https://example.test/v1", "model": "old-model"},
|
||||
},
|
||||
"prompts": map[string]any{
|
||||
"prompt": promptDefinitionWithVersion("v1", listingContractPrompt()),
|
||||
"profiles": []any{
|
||||
map[string]any{"id": "base", "endpoint": "https://example.test/v1", "model": "base-model"},
|
||||
map[string]any{"id": "child", "extends": map[string]any{"id": "base"}},
|
||||
map[string]any{"id": "overlay", "endpoint": "https://example.test/v1", "model": "old-model"},
|
||||
},
|
||||
"prompts": []any{listingContractPrompt("prompt")},
|
||||
}},
|
||||
"prompts": map[string]any{
|
||||
"underlay-only": promptDefinitionWithVersion("v1", listingContractPrompt()),
|
||||
},
|
||||
"prompts": []any{listingContractPrompt("underlay-only")},
|
||||
})}
|
||||
main := configkit.Input{Source: configkit.Mapping("application overlay", map[string]any{
|
||||
"collections": map[string]any{"shared": map[string]any{"profiles": map[string]any{
|
||||
"overlay": map[string]any{"model": "effective-model"},
|
||||
"collections": map[string]any{"shared": map[string]any{"profiles": []any{
|
||||
map[string]any{"id": "overlay", "model": "effective-model"},
|
||||
}}},
|
||||
"prompts": map[string]any{
|
||||
"main-only": promptDefinitionWithVersion("v3", listingContractPrompt()),
|
||||
},
|
||||
"prompts": []any{listingContractPrompt("main-only")},
|
||||
})}
|
||||
engine, err := promptkit.NewEngine(promptkit.Config{Sources: promptkit.ConfigurationSources{
|
||||
Underlays: []configkit.Underlay{{Inputs: []configkit.Input{underlay}}},
|
||||
@@ -459,14 +451,14 @@ func TestListIdentitiesUseEffectiveLayeredMembership(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
wantPrompts := []promptkit.PromptIdentity{
|
||||
{ID: "main-only", Version: stringPointerForTest("v3")},
|
||||
{ID: "shared/prompt", Version: stringPointerForTest("v1")},
|
||||
{ID: "underlay-only", Version: stringPointerForTest("v1")},
|
||||
{ID: "main-only"},
|
||||
{ID: "shared/prompt"},
|
||||
{ID: "underlay-only"},
|
||||
}
|
||||
if !reflect.DeepEqual(prompts, wantPrompts) {
|
||||
t.Fatalf("effective prompt identities = %#v, want %#v", prompts, wantPrompts)
|
||||
}
|
||||
if got := countListingPrompt(prompts, "shared/prompt", "v1"); got != 1 {
|
||||
if got := countListingPrompt(prompts, "shared/prompt"); got != 1 {
|
||||
t.Fatalf("overlaid prompt identity appears %d times, want 1", got)
|
||||
}
|
||||
}
|
||||
@@ -488,8 +480,8 @@ func TestListIdentitiesEmptyEffectiveConfiguration(t *testing.T) {
|
||||
|
||||
func TestListIdentitiesAreOwnedAndSafeForConcurrentUse(t *testing.T) {
|
||||
engine, err := newListingContractEngine(t, map[string]any{
|
||||
"profiles": map[string]any{"profile": map[string]any{"model": "partial-model"}},
|
||||
"prompts": map[string]any{"prompt": promptDefinitionWithVersion("v1", listingContractPrompt())},
|
||||
"profiles": []any{map[string]any{"id": "profile", "model": "partial-model"}},
|
||||
"prompts": []any{listingContractPrompt("prompt")},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -511,9 +503,6 @@ func TestListIdentitiesAreOwnedAndSafeForConcurrentUse(t *testing.T) {
|
||||
for i := range prompts {
|
||||
if prompts[i].ID == "prompt" {
|
||||
prompts[i].ID = "caller mutation"
|
||||
if prompts[i].Version != nil {
|
||||
*prompts[i].Version = "caller mutation"
|
||||
}
|
||||
}
|
||||
}
|
||||
profiles, err = engine.ListProfiles(context.Background())
|
||||
@@ -521,7 +510,7 @@ func TestListIdentitiesAreOwnedAndSafeForConcurrentUse(t *testing.T) {
|
||||
t.Fatalf("profile result mutation escaped into engine: %#v, %v", profiles, err)
|
||||
}
|
||||
prompts, err = engine.ListPrompts(context.Background())
|
||||
if err != nil || countListingPrompt(prompts, "prompt", "v1") != 1 {
|
||||
if err != nil || countListingPrompt(prompts, "prompt") != 1 {
|
||||
t.Fatalf("prompt result mutation escaped into engine: %#v, %v", prompts, err)
|
||||
}
|
||||
|
||||
@@ -557,9 +546,6 @@ func TestListIdentitiesAreOwnedAndSafeForConcurrentUse(t *testing.T) {
|
||||
return
|
||||
}
|
||||
prompts[0].ID = "worker mutation"
|
||||
if prompts[0].Version != nil {
|
||||
*prompts[0].Version = "worker mutation"
|
||||
}
|
||||
|
||||
if _, err := engine.InspectProfile(context.Background(), "profile"); err != nil {
|
||||
results <- fmt.Errorf("inspect profile: %w", err)
|
||||
@@ -582,7 +568,7 @@ func TestListIdentitiesAreOwnedAndSafeForConcurrentUse(t *testing.T) {
|
||||
|
||||
func TestListIdentitiesUseCapturedSourcesWithoutExecutionWork(t *testing.T) {
|
||||
files := fstest.MapFS{
|
||||
"config/listing.yaml": &fstest.MapFile{Data: []byte("profiles:\n captured-partial:\n model: partial-model\nprompts:\n captured-prompt:\n version: v1\n messages:\n - role: user\n content: Hello.\n output:\n format: text\n validation_mode: basic\n")},
|
||||
"config/listing.yaml": &fstest.MapFile{Data: []byte("profiles:\n - id: captured-partial\n model: partial-model\nprompts:\n - id: captured-prompt\n messages:\n - role: user\n content: Hello.\n output:\n format: text\n validation_mode: basic\n")},
|
||||
}
|
||||
inputs, err := promptkit.FilesystemInputs("application listing", files, "config")
|
||||
if err != nil {
|
||||
@@ -594,20 +580,21 @@ func TestListIdentitiesUseCapturedSourcesWithoutExecutionWork(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
files["config/listing.yaml"].Data = []byte("profiles:\n replacement-profile: {}\nprompts:\n replacement-prompt:\n version: v2\n messages:\n - role: user\n content: Changed.\n output:\n format: text\n validation_mode: basic\n")
|
||||
files["config/listing.yaml"].Data = []byte("profiles:\n - id: replacement-profile\nprompts:\n - id: replacement-prompt\n messages:\n - role: user\n content: Changed.\n output:\n format: text\n validation_mode: basic\n")
|
||||
|
||||
profiles, err := engine.ListProfiles(context.Background())
|
||||
if err != nil || !containsListingProfile(profiles, "captured-partial") || containsListingProfile(profiles, "replacement-profile") {
|
||||
t.Fatalf("profile listing did not use captured source: %#v, %v", profiles, err)
|
||||
}
|
||||
prompts, err := engine.ListPrompts(context.Background())
|
||||
if err != nil || countListingPrompt(prompts, "captured-prompt", "v1") != 1 || countListingPrompt(prompts, "replacement-prompt", "v2") != 0 {
|
||||
if err != nil || countListingPrompt(prompts, "captured-prompt") != 1 || countListingPrompt(prompts, "replacement-prompt") != 0 {
|
||||
t.Fatalf("prompt listing did not use captured source: %#v, %v", prompts, err)
|
||||
}
|
||||
}
|
||||
|
||||
func listingContractPrompt() map[string]any {
|
||||
func listingContractPrompt(id string) map[string]any {
|
||||
return map[string]any{
|
||||
"id": id,
|
||||
"messages": []any{map[string]any{"role": "user", "content": "Hello."}},
|
||||
"output": map[string]any{"format": "text", "validation_mode": "basic"},
|
||||
}
|
||||
@@ -632,10 +619,10 @@ func countListingProfile(profiles []string, id string) int {
|
||||
return count
|
||||
}
|
||||
|
||||
func countListingPrompt(prompts []promptkit.PromptIdentity, id, version string) int {
|
||||
func countListingPrompt(prompts []promptkit.PromptIdentity, id string) int {
|
||||
count := 0
|
||||
for _, prompt := range prompts {
|
||||
if prompt.ID == id && prompt.Version != nil && *prompt.Version == version {
|
||||
if prompt.ID == id {
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,12 +268,11 @@ func newNamespacedContractEngine(t *testing.T, client promptkit.LLMClient) *prom
|
||||
for _, namespace := range []string{"alpha", "beta"} {
|
||||
endpoint := "https://" + namespace + ".example/v1"
|
||||
input, err := promptkit.CollectionInput(namespace, configkit.Mapping(namespace+" resources", map[string]any{
|
||||
"backends": map[string]any{"backend": map[string]any{"endpoint": endpoint}},
|
||||
"profiles": map[string]any{"shared": map[string]any{
|
||||
"backends": []any{map[string]any{"id": "backend", "endpoint": endpoint}},
|
||||
"profiles": []any{map[string]any{"id": "shared",
|
||||
"backend": namespace + "/backend", "model": namespace + "-model",
|
||||
}},
|
||||
"prompts": map[string]any{"shared": map[string]any{
|
||||
"version": "1",
|
||||
"prompts": []any{map[string]any{"id": "shared",
|
||||
"default_profile": "root-only",
|
||||
"messages": []any{map[string]any{"role": "user", "content": "Hello"}},
|
||||
"output": map[string]any{"format": "text", "validation_mode": "none"},
|
||||
@@ -286,11 +285,10 @@ func newNamespacedContractEngine(t *testing.T, client promptkit.LLMClient) *prom
|
||||
inputs = append(inputs, input)
|
||||
}
|
||||
inputs = append(inputs, configkit.Input{Source: configkit.Mapping("root resources", map[string]any{
|
||||
"profiles": map[string]any{"root-only": map[string]any{
|
||||
"profiles": []any{map[string]any{"id": "root-only",
|
||||
"endpoint": "https://root.example/v1", "model": "root-model",
|
||||
}},
|
||||
"prompts": map[string]any{"root-only": map[string]any{
|
||||
"version": "1",
|
||||
"prompts": []any{map[string]any{"id": "root-only",
|
||||
"messages": []any{map[string]any{"role": "user", "content": "Root prompt"}},
|
||||
"output": map[string]any{"format": "text", "validation_mode": "none"},
|
||||
}},
|
||||
|
||||
@@ -61,7 +61,7 @@ func TestProfileInheritanceConfiguredBaseAliasWorkflow(t *testing.T) {
|
||||
|
||||
func TestProfileInheritanceYAMLAliasOfConfiguredProfile(t *testing.T) {
|
||||
inputs, err := promptkit.FilesystemInputs("profile alias", fstest.MapFS{
|
||||
"config/alias.yaml": &fstest.MapFile{Data: []byte("profiles:\n base:\n model: synthetic-model\n yaml-alias:\n extends: base\n")},
|
||||
"config/alias.yaml": &fstest.MapFile{Data: []byte("profiles:\n - id: base\n model: synthetic-model\n - id: yaml-alias\n extends: {id: base}\n")},
|
||||
}, "config")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -79,12 +79,12 @@ func TestProfileInheritanceYAMLAliasOfConfiguredProfile(t *testing.T) {
|
||||
func TestProfileInheritanceRetainsRequiredCredentialBehavior(t *testing.T) {
|
||||
engine, err := promptkit.NewEngine(promptkit.Config{Sources: promptkit.ConfigurationSources{Main: &configkit.Input{
|
||||
Source: configkit.Mapping("credentials", map[string]any{
|
||||
"backends": map[string]any{"credential-backend": map[string]any{
|
||||
"backends": []any{map[string]any{"id": "credential-backend",
|
||||
"endpoint": "https://credential.example/v1", "api_key_env": "OPTIONAL_BACKEND_KEY",
|
||||
}},
|
||||
"profiles": map[string]any{
|
||||
"credential-base": map[string]any{"backend": "credential-backend", "model": "model", "api_key_required": true},
|
||||
"credential-child": map[string]any{"extends": "credential-base"},
|
||||
"profiles": []any{
|
||||
map[string]any{"id": "credential-base", "backend": "credential-backend", "model": "model", "api_key_required": true},
|
||||
map[string]any{"id": "credential-child", "extends": map[string]any{"id": "credential-base"}},
|
||||
},
|
||||
}),
|
||||
}}})
|
||||
@@ -106,8 +106,8 @@ func TestProfileInheritancePreservesPublicErrorIdentities(t *testing.T) {
|
||||
t.Fatalf("missing profile = (%+v, %v)", inspection, err)
|
||||
}
|
||||
for _, document := range []map[string]any{
|
||||
{"profiles": map[string]any{"child": map[string]any{"extends": "missing"}}},
|
||||
{"profiles": map[string]any{"a": map[string]any{"extends": "b"}, "b": map[string]any{"extends": "a"}}},
|
||||
{"profiles": []any{map[string]any{"id": "child", "extends": map[string]any{"id": "missing"}}}},
|
||||
{"profiles": []any{map[string]any{"id": "a", "extends": map[string]any{"id": "b"}}, map[string]any{"id": "b", "extends": map[string]any{"id": "a"}}}},
|
||||
} {
|
||||
invalid, err := promptkit.NewEngine(promptkit.Config{Sources: promptkit.ConfigurationSources{Main: &configkit.Input{
|
||||
Source: configkit.Mapping("invalid inheritance", document),
|
||||
@@ -120,7 +120,7 @@ func TestProfileInheritancePreservesPublicErrorIdentities(t *testing.T) {
|
||||
|
||||
func TestProfileInheritanceFreezesPreparedExecution(t *testing.T) {
|
||||
profiles := &mutableInheritanceProfileFS{files: fstest.MapFS{
|
||||
"config/profiles.yaml": &fstest.MapFile{Data: []byte("profiles:\n base:\n endpoint: https://base.example/v1\n model: first-model\n child:\n extends: base\n")},
|
||||
"config/profiles.yaml": &fstest.MapFile{Data: []byte("profiles:\n - id: base\n endpoint: https://base.example/v1\n model: first-model\n - id: child\n extends: {id: base}\n")},
|
||||
}}
|
||||
inputs, err := promptkit.FilesystemInputs("profiles", profiles, "config")
|
||||
if err != nil {
|
||||
@@ -138,7 +138,7 @@ func TestProfileInheritanceFreezesPreparedExecution(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
profiles.set("config/profiles.yaml", "profiles:\n base:\n endpoint: https://base.example/v1\n model: second-model\n child:\n extends: base\n")
|
||||
profiles.set("config/profiles.yaml", "profiles:\n - id: base\n endpoint: https://base.example/v1\n model: second-model\n - id: child\n extends: {id: base}\n")
|
||||
result, err := engine.RunPrepared(context.Background(), prepared)
|
||||
if err != nil || result == nil || client.model != "first-model" {
|
||||
t.Fatalf("prepared execution = (%+v, %v), model %q", result, err, client.model)
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
func TestInspectProfileUsesLiteralFileKeyForPreparation(t *testing.T) {
|
||||
profiles, err := promptkit.FilesystemInputs("literal profile", fstest.MapFS{
|
||||
"config/profile.yaml": &fstest.MapFile{Data: []byte("profiles:\n ' literal ':\n endpoint: https://example.test/v1\n model: model\n")},
|
||||
"config/profile.yaml": &fstest.MapFile{Data: []byte("profiles:\n - id: ' literal '\n endpoint: https://example.test/v1\n model: model\n")},
|
||||
}, "config")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -20,8 +20,8 @@ func TestInspectProfileUsesLiteralFileKeyForPreparation(t *testing.T) {
|
||||
engine, err := promptkit.NewEngine(promptkit.Config{Sources: promptkit.ConfigurationSources{
|
||||
Underlays: []configkit.Underlay{{Inputs: profiles}},
|
||||
Main: &configkit.Input{Source: configkit.Mapping("prompt", map[string]any{
|
||||
"prompts": map[string]any{"prompt": map[string]any{
|
||||
"version": "1",
|
||||
"prompts": []any{map[string]any{
|
||||
"id": "prompt",
|
||||
"default_profile": " literal ",
|
||||
"messages": []any{map[string]any{"role": "user", "content": "hello"}},
|
||||
"output": map[string]any{"format": "text", "validation_mode": "none"},
|
||||
@@ -50,8 +50,8 @@ func TestInspectProfileUsesLiteralFileKeyForPreparation(t *testing.T) {
|
||||
func TestInspectProfileIsIndependentAndDoesNotInvokeProvider(t *testing.T) {
|
||||
client := &fakeLLMClient{response: &promptkit.GenerateResponse{Content: "unexpected"}}
|
||||
engine, err := promptkit.NewEngine(promptkit.Config{Sources: promptkit.ConfigurationSources{Main: &configkit.Input{
|
||||
Source: configkit.Mapping("inspection", map[string]any{"profiles": map[string]any{
|
||||
"profile": map[string]any{
|
||||
Source: configkit.Mapping("inspection", map[string]any{"profiles": []any{
|
||||
map[string]any{"id": "profile",
|
||||
"endpoint": "https://example.test/v1", "model": "model", "api_key_required": true,
|
||||
"extra_params": map[string]any{"nested": map[string]any{"value": "original"}},
|
||||
},
|
||||
@@ -77,7 +77,7 @@ func TestInspectProfilePublicErrorsAndPartialTarget(t *testing.T) {
|
||||
t.Fatalf("nil engine: %v", err)
|
||||
}
|
||||
engine, err := promptkit.NewEngine(promptkit.Config{Sources: promptkit.ConfigurationSources{Main: &configkit.Input{
|
||||
Source: configkit.Mapping("partial", map[string]any{"profiles": map[string]any{"profile": map[string]any{"model": "model"}}}),
|
||||
Source: configkit.Mapping("partial", map[string]any{"profiles": []any{map[string]any{"id": "profile", "model": "model"}}}),
|
||||
}}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
Reference in New Issue
Block a user