Pass effective paths through configuration loading

This commit is contained in:
2026-10-17 05:33:03 +00:00
parent 5e58b6944b
commit 0cd833513c
5 changed files with 90 additions and 32 deletions

View File

@@ -119,6 +119,20 @@ type loaded struct {
promptIDs []domain.PromptIdentity
}
type resourceBases struct {
backends configkit.Path
profiles configkit.Path
prompts configkit.Path
}
func rootResourceBases() resourceBases {
return resourceBases{
backends: configkit.Keys("backends"),
profiles: configkit.Keys("profiles"),
prompts: configkit.Keys("prompts"),
}
}
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"}
@@ -131,6 +145,7 @@ 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),
@@ -141,22 +156,24 @@ func load(main configkit.Input, underlays []configkit.Underlay) (*loaded, error)
Definition: configkit.Definition[document]{
Secret: secretProviderPath,
Resolve: func(config *document, resolution *configkit.Resolution) error {
captureFields(config.Backends, "backends", backendFields, resolution, state.backends)
captureFields(config.Profiles, "profiles", profileFields, resolution, state.profiles)
capturePromptMetadata(config.Prompts, resolution, state.promptMetadata)
resolveBackends(config.Backends, resolution)
resolveProfiles(config.Profiles, resolution)
resolvePrompts(config.Prompts, resolution)
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)
return nil
},
Validate: validateEffective,
Validate: func(config *document, validation *configkit.Validation) {
validateEffective(config, bases, validation)
},
},
})
if err != nil {
return nil, fmt.Errorf("load configuration: %w", err)
}
state.result = result
if err := state.materializePrompts(); err != nil {
if err := state.materializePrompts(result.Config.Prompts, bases.prompts); err != nil {
return nil, fmt.Errorf("load configuration: %w", err)
}
if err := state.buildExecutionProfiles(); err != nil {
@@ -176,7 +193,7 @@ type promptInputPresence struct {
description fieldState
}
func capturePromptMetadata(prompts map[string]map[string]promptConfig, resolution *configkit.Resolution, destination map[string]map[string][]promptInputPresence) {
func capturePromptMetadata(prompts map[string]map[string]promptConfig, basePath configkit.Path, resolution *configkit.Resolution, destination map[string]map[string][]promptInputPresence) {
for _, id := range sortedKeys(prompts) {
if destination[id] == nil {
destination[id] = make(map[string][]promptInputPresence, len(prompts[id]))
@@ -184,7 +201,7 @@ func capturePromptMetadata(prompts map[string]map[string]promptConfig, resolutio
for _, version := range sortedKeys(prompts[id]) {
inputs := prompts[id][version].Inputs
states := make([]promptInputPresence, len(inputs))
base := configkit.Keys("prompts", id, version, "inputs")
base := basePath.Key(id).Key(version).Key("inputs")
for index := range inputs {
path := base.Index(index)
states[index] = promptInputPresence{
@@ -209,11 +226,11 @@ func captureFieldState(path configkit.Path, resolution *configkit.Resolution) fi
}
}
func captureFields[T any](entries map[string]T, collection string, fields []string, resolution *configkit.Resolution, destination map[string]map[string]fieldState) {
func captureFields[T any](entries map[string]T, basePath configkit.Path, 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 {
info, exists := resolution.InputInfo(configkit.Keys(collection, id, field))
info, exists := resolution.InputInfo(basePath.Key(id).Key(field))
switch {
case !exists || !info.Explicit:
states[field] = fieldAbsent
@@ -244,10 +261,10 @@ func normalizeString(value **string, path configkit.Path, resolution *configkit.
return false
}
func resolveBackends(backends map[string]backendConfig, resolution *configkit.Resolution) {
func resolveBackends(backends map[string]backendConfig, basePath configkit.Path, resolution *configkit.Resolution) {
for _, id := range sortedKeys(backends) {
backend := backends[id]
base := configkit.Keys("backends", id)
base := basePath.Key(id)
if backend.Endpoint != nil {
endpoint, err := domain.NormalizeOpenAICompatibleBaseEndpoint(*backend.Endpoint)
if err != nil {
@@ -301,10 +318,10 @@ func normalizeDiagnosticEndpoint(value **string, path configkit.Path, resolution
normalizeString(value, path, resolution, normalized)
}
func resolveProfiles(profiles map[string]profileConfig, resolution *configkit.Resolution) {
func resolveProfiles(profiles map[string]profileConfig, basePath configkit.Path, resolution *configkit.Resolution) {
for _, id := range sortedKeys(profiles) {
profile := profiles[id]
base := configkit.Keys("profiles", id)
base := basePath.Key(id)
if profile.Endpoint != nil && *profile.Endpoint != "" {
endpoint, err := domain.NormalizeOpenAICompatibleBaseEndpoint(*profile.Endpoint)
if err != nil {
@@ -329,10 +346,10 @@ func resolveProfiles(profiles map[string]profileConfig, resolution *configkit.Re
}
}
func validateEffective(config *document, validation *configkit.Validation) {
func validateEffective(config *document, bases resourceBases, validation *configkit.Validation) {
for _, id := range sortedKeys(config.Backends) {
backend := config.Backends[id]
base := configkit.Keys("backends", id)
base := bases.backends.Key(id)
if strings.TrimSpace(id) == "" {
validation.Error(base, "backend ID must not be blank")
}
@@ -373,7 +390,7 @@ func validateEffective(config *document, validation *configkit.Validation) {
}
for _, id := range sortedKeys(config.Profiles) {
profile := config.Profiles[id]
base := configkit.Keys("profiles", id)
base := bases.profiles.Key(id)
if strings.TrimSpace(id) == "" {
validation.Error(base, "profile ID must not be blank")
}