Assemble collection resources by qualified ID

This commit is contained in:
2026-10-17 06:03:28 +00:00
parent a10a9053b7
commit 473fc1f6d7
12 changed files with 387 additions and 154 deletions

View File

@@ -17,10 +17,18 @@ import (
)
type document struct {
Version *string `yaml:"version"`
Backends map[string]backendConfig `yaml:"backends"`
Profiles map[string]profileConfig `yaml:"profiles"`
Prompts map[string]promptConfig `yaml:"prompts"`
Version *string `yaml:"version"`
Backends map[string]backendConfig `yaml:"backends"`
Profiles map[string]profileConfig `yaml:"profiles"`
Prompts map[string]promptConfig `yaml:"prompts"`
Collections map[string]collectionConfig `yaml:"collections"`
}
type collectionConfig struct {
ReleaseVersion *string `yaml:"release_version"`
Backends map[string]backendConfig `yaml:"backends"`
Profiles map[string]profileConfig `yaml:"profiles"`
Prompts map[string]promptConfig `yaml:"prompts"`
}
type backendConfig struct {
@@ -126,6 +134,15 @@ type resourceBases struct {
prompts configkit.Path
}
type resourceSet struct {
isCollection bool
namespace string
bases resourceBases
backends map[string]backendConfig
profiles map[string]profileConfig
prompts map[string]promptConfig
}
func rootResourceBases() resourceBases {
return resourceBases{
backends: configkit.Keys("backends"),
@@ -134,6 +151,61 @@ func rootResourceBases() resourceBases {
}
}
func resourceSets(config *document) []resourceSet {
sets := make([]resourceSet, 0, len(config.Collections)+1)
sets = append(sets, resourceSet{
bases: rootResourceBases(), backends: config.Backends, profiles: config.Profiles, prompts: config.Prompts,
})
for _, namespace := range sortedKeys(config.Collections) {
collection := config.Collections[namespace]
base := configkit.Keys("collections", namespace)
sets = append(sets, resourceSet{
isCollection: true,
namespace: namespace,
bases: resourceBases{
backends: base.Key("backends"),
profiles: base.Key("profiles"),
prompts: base.Key("prompts"),
},
backends: collection.Backends,
profiles: collection.Profiles,
prompts: collection.Prompts,
})
}
return sets
}
func indexedResourceID(namespace, localKey string) string {
qualified, valid := domain.QualifyLocalResourceID(namespace, localKey)
if valid {
return qualified
}
if namespace == "" {
return localKey
}
return namespace + "/" + localKey
}
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
}
}
return backends
}
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
}
}
return profiles
}
var envName = regexp.MustCompile(`^[A-Za-z_][A-Za-z0-9_]*$`)
var backendFields = []string{"endpoint", "api_key_env", "concurrency_limit", "queue_capacity", "extra_params", "smoke_tests"}
@@ -146,7 +218,6 @@ func Load(main configkit.Input, underlays []configkit.Underlay) (*loaded, error)
// load performs one ConfigKit lifecycle over the selected source tiers.
func load(main configkit.Input, underlays []configkit.Underlay) (*loaded, error) {
bases := rootResourceBases()
state := &loaded{
backends: make(map[string]map[string]fieldState),
profiles: make(map[string]map[string]fieldState),
@@ -162,16 +233,18 @@ func load(main configkit.Input, underlays []configkit.Underlay) (*loaded, error)
},
Secret: secretProviderPath,
Resolve: func(config *document, resolution *configkit.Resolution) error {
captureFields(config.Backends, bases.backends, backendFields, resolution, state.backends)
captureFields(config.Profiles, bases.profiles, profileFields, resolution, state.profiles)
capturePromptMetadata(config.Prompts, bases.prompts, resolution, state.promptMetadata)
resolveBackends(config.Backends, bases.backends, resolution)
resolveProfiles(config.Profiles, bases.profiles, resolution)
resolvePrompts(config.Prompts, bases.prompts, resolution)
for _, resources := range resourceSets(config) {
captureFields(resources.backends, resources.bases.backends, resources.namespace, backendFields, resolution, state.backends)
captureFields(resources.profiles, resources.bases.profiles, resources.namespace, profileFields, resolution, state.profiles)
capturePromptMetadata(resources.prompts, resources.bases.prompts, resources.namespace, resolution, state.promptMetadata)
resolveBackends(resources.backends, resources.bases.backends, resolution)
resolveProfiles(resources.profiles, resources.bases.profiles, resolution)
resolvePrompts(resources.prompts, resources.bases.prompts, resolution)
}
return nil
},
Validate: func(config *document, validation *configkit.Validation) {
validateEffective(config, bases, validation)
validateEffective(config, validation)
},
},
})
@@ -179,8 +252,10 @@ func load(main configkit.Input, underlays []configkit.Underlay) (*loaded, error)
return nil, fmt.Errorf("load configuration: %w", err)
}
state.result = result
if err := state.materializePrompts(result.Config.Prompts, bases.prompts); err != nil {
return nil, fmt.Errorf("load configuration: %w", err)
for _, resources := range resourceSets(&result.Config) {
if err := state.materializePrompts(resources.prompts, resources.bases.prompts, resources.namespace); err != nil {
return nil, fmt.Errorf("load configuration: %w", err)
}
}
if err := state.buildExecutionProfiles(); err != nil {
return nil, fmt.Errorf("load configuration: %w", err)
@@ -207,7 +282,7 @@ type promptInputPresence struct {
description fieldState
}
func capturePromptMetadata(prompts map[string]promptConfig, basePath configkit.Path, resolution *configkit.Resolution, destination map[string][]promptInputPresence) {
func capturePromptMetadata(prompts map[string]promptConfig, basePath configkit.Path, namespace string, resolution *configkit.Resolution, destination map[string][]promptInputPresence) {
for _, id := range sortedKeys(prompts) {
inputs := prompts[id].Inputs
states := make([]promptInputPresence, len(inputs))
@@ -219,7 +294,7 @@ func capturePromptMetadata(prompts map[string]promptConfig, basePath configkit.P
description: captureFieldState(path.Key("description"), resolution),
}
}
destination[id] = states
destination[indexedResourceID(namespace, id)] = states
}
}
@@ -235,7 +310,7 @@ func captureFieldState(path configkit.Path, resolution *configkit.Resolution) fi
}
}
func captureFields[T any](entries map[string]T, basePath configkit.Path, fields []string, resolution *configkit.Resolution, destination map[string]map[string]fieldState) {
func captureFields[T any](entries map[string]T, basePath configkit.Path, namespace string, fields []string, resolution *configkit.Resolution, destination map[string]map[string]fieldState) {
for id := range entries {
states := make(map[string]fieldState, len(fields))
for _, field := range fields {
@@ -249,7 +324,7 @@ func captureFields[T any](entries map[string]T, basePath configkit.Path, fields
states[field] = fieldValue
}
}
destination[id] = states
destination[indexedResourceID(namespace, id)] = states
}
}
@@ -355,83 +430,111 @@ func resolveProfiles(profiles map[string]profileConfig, basePath configkit.Path,
}
}
func validateEffective(config *document, bases resourceBases, validation *configkit.Validation) {
for _, id := range sortedKeys(config.Backends) {
backend := config.Backends[id]
base := bases.backends.Key(id)
if strings.TrimSpace(id) == "" {
validation.Error(base, "backend ID must not be blank")
func validateEffective(config *document, validation *configkit.Validation) {
sets := resourceSets(config)
backendIDs := make(map[string]struct{})
for _, resources := range sets {
if resources.isCollection && !domain.IsValidResourceNamespace(resources.namespace) {
validation.Error(configkit.Keys("collections", resources.namespace), "collection namespace must be nonblank and contain no slash")
}
if backend.Endpoint == nil || *backend.Endpoint == "" {
validation.Error(base.Key("endpoint"), "endpoint is required")
for localKey := range resources.backends {
backendIDs[indexedResourceID(resources.namespace, localKey)] = struct{}{}
}
if backend.APIKeyEnv != nil && *backend.APIKeyEnv != "" && !envName.MatchString(*backend.APIKeyEnv) {
validation.Error(base.Key("api_key_env"), "environment variable name is invalid")
}
if backend.ConcurrencyLimit != nil && *backend.ConcurrencyLimit < 0 {
validation.Error(base.Key("concurrency_limit"), "concurrency limit must not be negative")
}
if backend.QueueCapacity != nil {
if *backend.QueueCapacity < 0 {
validation.Error(base.Key("queue_capacity"), "queue capacity must not be negative")
}
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")
}
if backend.ConcurrencyLimit == nil || *backend.ConcurrencyLimit <= 0 {
validation.Error(base.Key("queue_capacity"), "queue capacity requires a positive concurrency limit")
} else if *backend.QueueCapacity > int(^uint(0)>>1)-*backend.ConcurrencyLimit {
validation.Error(base.Key("queue_capacity"), "total capacity overflows int")
if backend.Endpoint == nil || *backend.Endpoint == "" {
validation.Error(base.Key("endpoint"), "endpoint is required")
}
}
validateExtraParams(backend.ExtraParams, base.Key("extra_params"), true, validation)
if smokeTests := backend.SmokeTests; smokeTests != nil {
smokePath := base.Key("smoke_tests")
if smokeTests.DefaultProfile != nil && strings.TrimSpace(*smokeTests.DefaultProfile) == "" {
validation.Error(smokePath.Key("default_profile"), "default profile must not be blank")
if backend.APIKeyEnv != nil && *backend.APIKeyEnv != "" && !envName.MatchString(*backend.APIKeyEnv) {
validation.Error(base.Key("api_key_env"), "environment variable name is invalid")
}
if authentication := smokeTests.Authentication; authentication != nil {
kindPath := smokePath.Key("authentication").Key("kind")
if authentication.Kind == nil {
validation.Error(kindPath, "authentication kind is required")
} else if *authentication.Kind != "none" && *authentication.Kind != "openrouter_key" {
validation.Error(kindPath, "authentication kind must be none or openrouter_key")
if backend.ConcurrencyLimit != nil && *backend.ConcurrencyLimit < 0 {
validation.Error(base.Key("concurrency_limit"), "concurrency limit must not be negative")
}
if backend.QueueCapacity != nil {
if *backend.QueueCapacity < 0 {
validation.Error(base.Key("queue_capacity"), "queue capacity must not be negative")
}
if backend.ConcurrencyLimit == nil || *backend.ConcurrencyLimit <= 0 {
validation.Error(base.Key("queue_capacity"), "queue capacity requires a positive concurrency limit")
} else if *backend.QueueCapacity > int(^uint(0)>>1)-*backend.ConcurrencyLimit {
validation.Error(base.Key("queue_capacity"), "total capacity overflows int")
}
}
validateExtraParams(backend.ExtraParams, base.Key("extra_params"), true, validation)
if smokeTests := backend.SmokeTests; smokeTests != nil {
smokePath := base.Key("smoke_tests")
if smokeTests.DefaultProfile != nil {
if strings.TrimSpace(*smokeTests.DefaultProfile) == "" {
validation.Error(smokePath.Key("default_profile"), "default profile must not be blank")
} else if !domain.IsValidResourceID(*smokeTests.DefaultProfile) {
validation.Error(smokePath.Key("default_profile"), "default profile reference is malformed")
}
}
if authentication := smokeTests.Authentication; authentication != nil {
kindPath := smokePath.Key("authentication").Key("kind")
if authentication.Kind == nil {
validation.Error(kindPath, "authentication kind is required")
} else if *authentication.Kind != "none" && *authentication.Kind != "openrouter_key" {
validation.Error(kindPath, "authentication kind must be none or openrouter_key")
}
}
}
}
}
for _, id := range sortedKeys(config.Profiles) {
profile := config.Profiles[id]
base := bases.profiles.Key(id)
if strings.TrimSpace(id) == "" {
validation.Error(base, "profile ID must not be blank")
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")
}
if profile.Backend != nil && *profile.Backend != "" {
if !domain.IsValidResourceID(*profile.Backend) {
validation.Error(base.Key("backend"), "backend reference is malformed")
} else if _, exists := backendIDs[*profile.Backend]; !exists {
validation.Error(base.Key("backend"), "backend is not defined")
}
}
if profile.Model != nil && *profile.Model != "" && strings.TrimSpace(*profile.Model) == "" {
validation.Error(base.Key("model"), "model must not be blank")
}
if profile.Temperature != nil {
if err := domain.ValidateExecutionTargetSettings(domain.ExecutionTarget{Temperature: *profile.Temperature}); err != nil {
validation.Error(base.Key("temperature"), err.Error())
}
}
if profile.TopP != nil {
if err := domain.ValidateExecutionTargetSettings(domain.ExecutionTarget{TopP: *profile.TopP}); err != nil {
validation.Error(base.Key("top_p"), err.Error())
}
}
if profile.MaxTokens != nil {
if err := domain.ValidateExecutionTargetSettings(domain.ExecutionTarget{MaxTokens: *profile.MaxTokens}); err != nil {
validation.Error(base.Key("max_tokens"), err.Error())
}
}
if profile.TimeoutSeconds != nil {
if err := domain.ValidateExecutionTargetSettings(domain.ExecutionTarget{TimeoutSeconds: *profile.TimeoutSeconds}); err != nil {
validation.Error(base.Key("timeout_seconds"), err.Error())
}
}
validateExtraParams(profile.ExtraParams, base.Key("extra_params"), false, validation)
}
if profile.Backend != nil && *profile.Backend != "" {
if _, exists := config.Backends[*profile.Backend]; !exists {
validation.Error(base.Key("backend"), "backend is not defined")
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")
}
if prompt.DefaultProfile != nil && *prompt.DefaultProfile != "" && !domain.IsValidResourceID(*prompt.DefaultProfile) {
validation.Error(base.Key("default_profile"), "default profile reference is malformed")
}
}
if profile.Model != nil && *profile.Model != "" && strings.TrimSpace(*profile.Model) == "" {
validation.Error(base.Key("model"), "model must not be blank")
}
if profile.Temperature != nil {
if err := domain.ValidateExecutionTargetSettings(domain.ExecutionTarget{Temperature: *profile.Temperature}); err != nil {
validation.Error(base.Key("temperature"), err.Error())
}
}
if profile.TopP != nil {
if err := domain.ValidateExecutionTargetSettings(domain.ExecutionTarget{TopP: *profile.TopP}); err != nil {
validation.Error(base.Key("top_p"), err.Error())
}
}
if profile.MaxTokens != nil {
if err := domain.ValidateExecutionTargetSettings(domain.ExecutionTarget{MaxTokens: *profile.MaxTokens}); err != nil {
validation.Error(base.Key("max_tokens"), err.Error())
}
}
if profile.TimeoutSeconds != nil {
if err := domain.ValidateExecutionTargetSettings(domain.ExecutionTarget{TimeoutSeconds: *profile.TimeoutSeconds}); err != nil {
validation.Error(base.Key("timeout_seconds"), err.Error())
}
}
validateExtraParams(profile.ExtraParams, base.Key("extra_params"), false, validation)
}
}