Index and validate identified resources
This commit is contained in:
@@ -299,6 +299,13 @@ Validation: target tests cover a root resource, namespaced resources sharing a
|
||||
local ID, and partial-profile completion. Upstream duplicates must fail before
|
||||
an execution map can silently overwrite a record.
|
||||
|
||||
Completion: final backend, profile, and prompt IDs and references are validated
|
||||
at list-entry paths; backend and profile runtime indexes use full identities.
|
||||
Added root and independent namespace target coverage and converted the strict
|
||||
duplicate fixture to identified lists. The focused tests remain deferred because
|
||||
prompt materialization and remaining configuration fixtures have not yet been
|
||||
migrated. Formatting and `git diff --check` passed.
|
||||
|
||||
## Stage 6: Materialize Prompts From Effective List Entries
|
||||
|
||||
Scope: prompt resolution/capture in `internal/configuration/prompts.go` and
|
||||
|
||||
@@ -194,8 +194,8 @@ func indexedResourceID(namespace, localKey string) string {
|
||||
func indexedBackends(config *document) map[string]backendConfig {
|
||||
backends := make(map[string]backendConfig)
|
||||
for _, resources := range resourceSets(config) {
|
||||
for localKey, definition := range resources.backends {
|
||||
backends[indexedResourceID(resources.namespace, localKey)] = definition
|
||||
for _, definition := range resources.backends {
|
||||
backends[indexedResourceID(resources.namespace, definition.ID)] = definition
|
||||
}
|
||||
}
|
||||
return backends
|
||||
@@ -204,8 +204,8 @@ func indexedBackends(config *document) map[string]backendConfig {
|
||||
func indexedProfiles(config *document) map[string]profileConfig {
|
||||
profiles := make(map[string]profileConfig)
|
||||
for _, resources := range resourceSets(config) {
|
||||
for localKey, definition := range resources.profiles {
|
||||
profiles[indexedResourceID(resources.namespace, localKey)] = definition
|
||||
for _, definition := range resources.profiles {
|
||||
profiles[indexedResourceID(resources.namespace, definition.ID)] = definition
|
||||
}
|
||||
}
|
||||
return profiles
|
||||
@@ -476,16 +476,15 @@ func validateEffective(config *document, validation *configkit.Validation) {
|
||||
if resources.isCollection && !domain.IsValidResourceNamespace(resources.namespace) {
|
||||
validation.Error(configkit.Keys("collections", resources.namespace), "collection namespace must be nonblank and contain no slash")
|
||||
}
|
||||
for localKey := range resources.backends {
|
||||
backendIDs[indexedResourceID(resources.namespace, localKey)] = struct{}{}
|
||||
for _, backend := range resources.backends {
|
||||
backendIDs[indexedResourceID(resources.namespace, backend.ID)] = struct{}{}
|
||||
}
|
||||
}
|
||||
for _, resources := range sets {
|
||||
for _, id := range sortedKeys(resources.backends) {
|
||||
backend := resources.backends[id]
|
||||
base := resources.bases.backends.Key(id)
|
||||
if !domain.IsValidLocalResourceKey(id) {
|
||||
validation.Error(base, "backend key must be a nonblank local key without a slash")
|
||||
for index, backend := range resources.backends {
|
||||
base := resources.bases.backends.Index(index)
|
||||
if !domain.IsValidLocalResourceKey(backend.ID) {
|
||||
validation.Error(base.Key("id"), "backend ID must be a nonblank local key without a slash")
|
||||
}
|
||||
if backend.Endpoint == nil || *backend.Endpoint == "" {
|
||||
validation.Error(base.Key("endpoint"), "endpoint is required")
|
||||
@@ -526,11 +525,10 @@ func validateEffective(config *document, validation *configkit.Validation) {
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, id := range sortedKeys(resources.profiles) {
|
||||
profile := resources.profiles[id]
|
||||
base := resources.bases.profiles.Key(id)
|
||||
if !domain.IsValidLocalResourceKey(id) {
|
||||
validation.Error(base, "profile key must be a nonblank local key without a slash")
|
||||
for index, profile := range resources.profiles {
|
||||
base := resources.bases.profiles.Index(index)
|
||||
if !domain.IsValidLocalResourceKey(profile.ID) {
|
||||
validation.Error(base.Key("id"), "profile ID must be a nonblank local key without a slash")
|
||||
}
|
||||
if profile.Backend != nil && *profile.Backend != "" {
|
||||
if !domain.IsValidResourceID(*profile.Backend) {
|
||||
@@ -564,11 +562,10 @@ func validateEffective(config *document, validation *configkit.Validation) {
|
||||
}
|
||||
validateExtraParams(profile.ExtraParams, base.Key("extra_params"), false, validation)
|
||||
}
|
||||
for _, id := range sortedKeys(resources.prompts) {
|
||||
prompt := resources.prompts[id]
|
||||
base := resources.bases.prompts.Key(id)
|
||||
if !domain.IsValidLocalResourceKey(id) {
|
||||
validation.Error(base, "prompt key must be a nonblank local key without a slash")
|
||||
for index, prompt := range resources.prompts {
|
||||
base := resources.bases.prompts.Index(index)
|
||||
if !domain.IsValidLocalResourceKey(prompt.ID) {
|
||||
validation.Error(base.Key("id"), "prompt ID must be a nonblank local key without a slash")
|
||||
}
|
||||
if prompt.DefaultProfile != nil && *prompt.DefaultProfile != "" && !domain.IsValidResourceID(*prompt.DefaultProfile) {
|
||||
validation.Error(base.Key("default_profile"), "default profile reference is malformed")
|
||||
|
||||
@@ -440,8 +440,8 @@ func TestLoadCapturesProfilePresence(t *testing.T) {
|
||||
|
||||
func TestLoadRejectsStrictGroupConflict(t *testing.T) {
|
||||
_, err := load(configkit.Input{Source: configkit.NoSource()}, []configkit.Underlay{{Inputs: []configkit.Input{
|
||||
mapping("first", map[string]any{"profiles": map[string]any{"shared": map[string]any{"model": "one"}}}),
|
||||
mapping("second", map[string]any{"profiles": map[string]any{"shared": map[string]any{"model": "one"}}}),
|
||||
mapping("first", map[string]any{"profiles": []any{map[string]any{"id": "shared", "model": "one"}}}),
|
||||
mapping("second", map[string]any{"profiles": []any{map[string]any{"id": "shared", "model": "one"}}}),
|
||||
}}})
|
||||
var loadError *configkit.LoadError
|
||||
if !errors.As(err, &loadError) {
|
||||
|
||||
@@ -15,30 +15,55 @@ import (
|
||||
profilepkg "gitea.maximumdirect.net/eric/promptkit/internal/profile"
|
||||
)
|
||||
|
||||
func TestLoadIndexesIdentifiedTargets(t *testing.T) {
|
||||
values := map[string]any{
|
||||
"backends": []any{map[string]any{"id": "local", "endpoint": "https://root.example/v1"}},
|
||||
"profiles": []any{map[string]any{"id": "partial", "backend": "local"}},
|
||||
"collections": map[string]any{},
|
||||
}
|
||||
collections := values["collections"].(map[string]any)
|
||||
for _, namespace := range []string{"north", "south"} {
|
||||
collections[namespace] = map[string]any{
|
||||
"backends": []any{map[string]any{"id": "local", "endpoint": "https://" + namespace + ".example/v1"}},
|
||||
"profiles": []any{map[string]any{"id": "partial", "backend": namespace + "/local"}},
|
||||
}
|
||||
}
|
||||
state, err := load(mapping("identified targets", values), nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for id, backendID := range map[string]string{"partial": "local", "north/partial": "north/local", "south/partial": "south/local"} {
|
||||
profile, err := state.GetProfile(context.Background(), id)
|
||||
if err != nil || profile.ID != id || profile.ResolvedTarget == nil || profile.ResolvedTarget.Model != "" || profile.ResolvedTarget.BackendID != backendID {
|
||||
t.Fatalf("partial profile %q = %+v, %v", id, profile, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadBuildsEffectiveTargetsAfterInheritance(t *testing.T) {
|
||||
state, err := load(mapping("effective-targets", map[string]any{
|
||||
"backends": map[string]any{
|
||||
"first": map[string]any{"endpoint": "https://first.example/v1", "api_key_env": "FIRST_KEY",
|
||||
"backends": []any{
|
||||
map[string]any{"id": "first", "endpoint": "https://first.example/v1", "api_key_env": "FIRST_KEY",
|
||||
"extra_params": map[string]any{"source": "first", "nested": map[string]any{"old": true}}},
|
||||
"second": map[string]any{"endpoint": "https://second.example/v1", "api_key_env": "SECOND_KEY",
|
||||
map[string]any{"id": "second", "endpoint": "https://second.example/v1", "api_key_env": "SECOND_KEY",
|
||||
"concurrency_limit": 2, "queue_capacity": 0,
|
||||
"extra_params": map[string]any{"source": "second", "nested": map[string]any{"backend": true}}},
|
||||
},
|
||||
"profiles": map[string]any{
|
||||
"base": map[string]any{"backend": "first", "model": "model", "temperature": 0.8,
|
||||
"profiles": []any{
|
||||
map[string]any{"id": "base", "backend": "first", "model": "model", "temperature": 0.8,
|
||||
"top_p": 0.9, "max_tokens": 100, "timeout_seconds": 30, "api_key_required": true,
|
||||
"extra_params": map[string]any{"nested": map[string]any{"profile": true}}},
|
||||
"child": map[string]any{"extends": "base", "backend": "second", "temperature": 0.0,
|
||||
map[string]any{"id": "child", "extends": map[string]any{"id": "base"}, "backend": "second", "temperature": 0.0,
|
||||
"top_p": nil, "max_tokens": 0, "timeout_seconds": nil, "api_key_env": nil,
|
||||
"api_key_required": false,
|
||||
"extra_params": map[string]any{"nested": map[string]any{"child": nil}}},
|
||||
"direct-key": map[string]any{"backend": "second", "api_key_required": true},
|
||||
"named-key": map[string]any{"backend": "second", "api_key_required": true, "api_key_env": "CUSTOM_KEY"},
|
||||
"no-provider-map": map[string]any{"backend": "second", "extra_params": nil},
|
||||
"no-timeout": map[string]any{"backend": "second", "timeout_seconds": 0},
|
||||
"partial": map[string]any{},
|
||||
"endpoint-only": map[string]any{"endpoint": "https://standalone.example/v1"},
|
||||
"cleared-endpoint": map[string]any{"extends": "base", "endpoint": nil},
|
||||
map[string]any{"id": "direct-key", "backend": "second", "api_key_required": true},
|
||||
map[string]any{"id": "named-key", "backend": "second", "api_key_required": true, "api_key_env": "CUSTOM_KEY"},
|
||||
map[string]any{"id": "no-provider-map", "backend": "second", "extra_params": nil},
|
||||
map[string]any{"id": "no-timeout", "backend": "second", "timeout_seconds": 0},
|
||||
map[string]any{"id": "partial"},
|
||||
map[string]any{"id": "endpoint-only", "endpoint": "https://standalone.example/v1"},
|
||||
map[string]any{"id": "cleared-endpoint", "extends": map[string]any{"id": "base"}, "endpoint": nil},
|
||||
},
|
||||
}), nil)
|
||||
if err != nil {
|
||||
@@ -133,9 +158,9 @@ func TestLoadedZeroControlsReachBuiltInRequest(t *testing.T) {
|
||||
}))
|
||||
defer server.Close()
|
||||
state, err := load(mapping("wire-controls", map[string]any{
|
||||
"backends": map[string]any{"local": map[string]any{"endpoint": server.URL + "/v1"}},
|
||||
"profiles": map[string]any{"direct": map[string]any{
|
||||
"backend": "local", "model": "example", "temperature": 0.0, "max_tokens": 0, "top_p": nil,
|
||||
"backends": []any{map[string]any{"id": "local", "endpoint": server.URL + "/v1"}},
|
||||
"profiles": []any{map[string]any{
|
||||
"id": "direct", "backend": "local", "model": "example", "temperature": 0.0, "max_tokens": 0, "top_p": nil,
|
||||
}},
|
||||
}), nil)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user