package promptkit import "go.maximumdirect.net/configkit" // ProfileConfig is a presence-aware convenience value for an identified execution // profile. Nil fields are omitted; non-nil pointers preserve zero and blank // values. A nil ExtraParams map is omitted; a non-nil empty map supplies an // empty mapping, not a clear operation. Raw ConfigKit Mapping inputs can // express explicit null. ProfileConfig has no stable JSON representation. // Extends, when supplied, names a sibling profile in the same resource list. type ProfileConfig struct { // ID is the local profile identity within its resource list. ID string Extends, Backend, Endpoint, Model *string Temperature, TopP *float64 MaxTokens, TimeoutSeconds *int ServiceTier, ReasoningEffort *string APIKeyEnv *string APIKeyRequired *bool ExtraParams map[string]any } // ProfileSource creates a labeled ConfigKit mapping containing profile records // in caller order. IDs are explicit and duplicates are left for loading to reject. // It encodes fields without validating them; NewEngine validates the final // effective configuration after all selected source layers are combined. // Mapping captures a copy of supported input values at creation; unsupported // values fail when the source is loaded. func ProfileSource(label string, profiles []ProfileConfig) configkit.Source { definitions := make([]any, 0, len(profiles)) for _, config := range profiles { fields := map[string]any{"id": config.ID} if config.Extends != nil { fields["extends"] = map[string]any{"id": *config.Extends} } if config.Backend != nil { fields["backend"] = *config.Backend } if config.Endpoint != nil { fields["endpoint"] = *config.Endpoint } if config.Model != nil { fields["model"] = *config.Model } if config.Temperature != nil { fields["temperature"] = *config.Temperature } if config.TopP != nil { fields["top_p"] = *config.TopP } if config.MaxTokens != nil { fields["max_tokens"] = *config.MaxTokens } if config.TimeoutSeconds != nil { fields["timeout_seconds"] = *config.TimeoutSeconds } if config.ServiceTier != nil { fields["service_tier"] = *config.ServiceTier } if config.ReasoningEffort != nil { fields["reasoning_effort"] = *config.ReasoningEffort } if config.APIKeyEnv != nil { fields["api_key_env"] = *config.APIKeyEnv } if config.APIKeyRequired != nil { fields["api_key_required"] = *config.APIKeyRequired } if config.ExtraParams != nil { fields["extra_params"] = providerMapForMapping(config.ExtraParams) } definitions = append(definitions, fields) } return configkit.Mapping(label, map[string]any{"profiles": definitions}) }