Pass effective paths through configuration loading
This commit is contained in:
@@ -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")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user