110 lines
4.2 KiB
Go
110 lines
4.2 KiB
Go
package config
|
|
|
|
import (
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
|
"gitea.maximumdirect.net/eric/scriptorium/internal/defaults"
|
|
renderformat "gitea.maximumdirect.net/eric/scriptorium/internal/format"
|
|
)
|
|
|
|
// Document is Scriptorium's ConfigKit-native application configuration shape.
|
|
type Document struct {
|
|
PromptDir string `yaml:"prompt_dir"`
|
|
ProfileDir string `yaml:"profile_dir"`
|
|
SchemaDir string `yaml:"schema_dir"`
|
|
TransientRetries *int `yaml:"transient_retries"`
|
|
Server ServerDocument `yaml:"server"`
|
|
Defaults DefaultsDocument `yaml:"defaults"`
|
|
Backends map[string]BackendDocument `yaml:"backends"`
|
|
}
|
|
|
|
type BackendDocument struct {
|
|
Endpoint string `yaml:"endpoint"`
|
|
APIKeyEnv string `yaml:"api_key_env"`
|
|
ExtraParams map[string]any `yaml:"extra_params"`
|
|
ConcurrencyLimit int `yaml:"concurrency_limit"`
|
|
QueueCapacity *int `yaml:"queue_capacity"`
|
|
}
|
|
|
|
type ServerDocument struct {
|
|
Addr string `yaml:"addr"`
|
|
ArtifactRoot string `yaml:"artifact_root"`
|
|
MaxRequestBytes int64 `yaml:"max_request_bytes"`
|
|
MaxArtifactBytes int64 `yaml:"max_artifact_bytes"`
|
|
MaxResponseBytes int64 `yaml:"max_response_bytes"`
|
|
}
|
|
|
|
type DefaultsDocument struct {
|
|
RenderFormat string `yaml:"render_format"`
|
|
}
|
|
|
|
func documentDefinition() configkit.Definition[Document] {
|
|
return configkit.Definition[Document]{
|
|
Defaults: documentDefaults,
|
|
Resolve: resolveDocument,
|
|
Validate: validateDocument,
|
|
}
|
|
}
|
|
|
|
func documentDefaults() Document {
|
|
return Document{
|
|
SchemaDir: defaults.SchemaDirDefault,
|
|
Server: ServerDocument{
|
|
Addr: defaults.HTTPAddrDefault,
|
|
MaxRequestBytes: defaults.HTTPMaxRequestBytesDefault,
|
|
MaxArtifactBytes: defaults.HTTPMaxArtifactBytesDefault,
|
|
MaxResponseBytes: defaults.HTTPMaxResponseBytesDefault,
|
|
},
|
|
Defaults: DefaultsDocument{RenderFormat: string(renderformat.DefaultPreparedRunOutputFormat)},
|
|
}
|
|
}
|
|
|
|
func resolveDocument(document *Document, resolution *configkit.Resolution) error {
|
|
normalizePath := func(path configkit.Path, value *string) {
|
|
cleaned := strings.TrimSpace(*value)
|
|
if cleaned != "" {
|
|
cleaned = filepath.Clean(cleaned)
|
|
}
|
|
if cleaned != *value {
|
|
configkit.Normalize(resolution, path, value, cleaned, "normalized application path")
|
|
}
|
|
}
|
|
normalizeString := func(path configkit.Path, value *string, normalized, reason string) {
|
|
if normalized != *value {
|
|
configkit.Normalize(resolution, path, value, normalized, reason)
|
|
}
|
|
}
|
|
|
|
normalizePath(configkit.Keys("prompt_dir"), &document.PromptDir)
|
|
normalizePath(configkit.Keys("profile_dir"), &document.ProfileDir)
|
|
normalizePath(configkit.Keys("schema_dir"), &document.SchemaDir)
|
|
normalizePath(configkit.Keys("server", "artifact_root"), &document.Server.ArtifactRoot)
|
|
normalizeString(configkit.Keys("server", "addr"), &document.Server.Addr,
|
|
strings.TrimSpace(document.Server.Addr), "trimmed server address")
|
|
normalizeString(configkit.Keys("defaults", "render_format"), &document.Defaults.RenderFormat,
|
|
strings.ToLower(strings.TrimSpace(document.Defaults.RenderFormat)), "normalized render format")
|
|
return nil
|
|
}
|
|
|
|
func validateDocument(document *Document, validation *configkit.Validation) {
|
|
if document.TransientRetries != nil && *document.TransientRetries < 0 {
|
|
validation.Error(configkit.Keys("transient_retries"), "must be greater than or equal to zero")
|
|
}
|
|
if document.Server.MaxRequestBytes < 0 {
|
|
validation.Error(configkit.Keys("server", "max_request_bytes"), "must be greater than or equal to zero")
|
|
}
|
|
if document.Server.MaxArtifactBytes < 0 {
|
|
validation.Error(configkit.Keys("server", "max_artifact_bytes"), "must be greater than or equal to zero")
|
|
}
|
|
if document.Server.MaxResponseBytes < 0 {
|
|
validation.Error(configkit.Keys("server", "max_response_bytes"), "must be greater than or equal to zero")
|
|
}
|
|
switch document.Defaults.RenderFormat {
|
|
case string(renderformat.OutputFormatText), string(renderformat.OutputFormatJSON):
|
|
default:
|
|
validation.Error(configkit.Keys("defaults", "render_format"), "must be text or json")
|
|
}
|
|
}
|