Wire config loading into CLI setup

This commit is contained in:
2026-05-06 16:46:33 +00:00
parent 2a40dc1030
commit 0fca5611d6
2 changed files with 284 additions and 18 deletions

View File

@@ -14,6 +14,7 @@ import (
httpadapter "gitea.maximumdirect.net/eric/scriptorium/internal/adapter/http"
artifactadapter "gitea.maximumdirect.net/eric/scriptorium/internal/artifact"
appconfig "gitea.maximumdirect.net/eric/scriptorium/internal/config"
"gitea.maximumdirect.net/eric/scriptorium/internal/defaults"
"gitea.maximumdirect.net/eric/scriptorium/internal/domain"
renderformat "gitea.maximumdirect.net/eric/scriptorium/internal/format"
@@ -32,6 +33,8 @@ const (
)
type runConfig struct {
configPath string
promptDir string
profileDir string
promptID string
@@ -48,6 +51,8 @@ type runConfig struct {
schemaDir string
timeout time.Duration
defaultRenderFormat renderformat.PreparedRunOutputFormat
llmBaseURLSet bool
apiKeyEnvSet bool
modelSet bool
@@ -63,6 +68,8 @@ type renderConfig struct {
}
type serveConfig struct {
configPath string
addr string
promptDir string
profileDir string
@@ -230,8 +237,9 @@ func parseRunArgs(args []string) (*runConfig, error) {
fs := flag.NewFlagSet("run", flag.ContinueOnError)
fs.SetOutput(io.Discard)
registerConfigPathFlag(fs, &cfg.configPath)
registerExecutionRequestFlags(fs, cfg)
fs.StringVar(&cfg.schemaDir, "schema-dir", defaults.SchemaDirDefault, "base directory for validation schemas")
fs.StringVar(&cfg.schemaDir, "schema-dir", "", "base directory for validation schemas")
if err := fs.Parse(args); err != nil {
return nil, err
@@ -251,10 +259,11 @@ func parseRenderArgs(args []string) (*renderConfig, error) {
fs := flag.NewFlagSet("render", flag.ContinueOnError)
fs.SetOutput(io.Discard)
registerConfigPathFlag(fs, &cfg.configPath)
registerExecutionRequestFlags(fs, &cfg.runConfig)
var rawFormat string
fs.StringVar(&rawFormat, "format", string(renderformat.DefaultPreparedRunOutputFormat), "render output format (text|json)")
fs.StringVar(&rawFormat, "format", "", "render output format (text|json)")
if err := fs.Parse(args); err != nil {
return nil, err
@@ -263,11 +272,15 @@ func parseRenderArgs(args []string) (*renderConfig, error) {
return nil, err
}
format, err := renderformat.ParsePreparedRunOutputFormat(rawFormat)
if err != nil {
return nil, err
if flagWasSet(fs, "format") {
format, err := renderformat.ParsePreparedRunOutputFormat(rawFormat)
if err != nil {
return nil, err
}
cfg.outputFormat = format
} else {
cfg.outputFormat = cfg.defaultRenderFormat
}
cfg.outputFormat = format
return cfg, nil
}
@@ -276,10 +289,11 @@ func parseServeArgs(args []string) (*serveConfig, error) {
fs := flag.NewFlagSet("serve", flag.ContinueOnError)
fs.SetOutput(io.Discard)
fs.StringVar(&cfg.addr, "addr", defaults.HTTPAddrDefault, "HTTP listen address")
registerConfigPathFlag(fs, &cfg.configPath)
fs.StringVar(&cfg.addr, "addr", "", "HTTP listen address")
fs.StringVar(&cfg.promptDir, "prompt-dir", "", "directory containing prompt definition YAML files")
fs.StringVar(&cfg.profileDir, "profile-dir", "", "directory containing execution profile YAML files")
fs.StringVar(&cfg.schemaDir, "schema-dir", defaults.SchemaDirDefault, "base directory for validation schemas")
fs.StringVar(&cfg.schemaDir, "schema-dir", "", "base directory for validation schemas")
if err := fs.Parse(args); err != nil {
return nil, err
@@ -288,6 +302,21 @@ func parseServeArgs(args []string) (*serveConfig, error) {
return nil, fmt.Errorf("unexpected positional args: %v", fs.Args())
}
settings, err := resolveAppSettings(fs, cfg.configPath, appconfig.CLIOverrides{
PromptDir: cfg.promptDirIfSet(fs),
ProfileDir: cfg.profileDirIfSet(fs),
SchemaDir: cfg.schemaDirIfSet(fs),
ServerAddr: cfg.addrIfSet(fs),
})
if err != nil {
return nil, err
}
cfg.promptDir = settings.PromptDir
cfg.profileDir = settings.ProfileDir
cfg.schemaDir = settings.SchemaDir
cfg.addr = settings.ServerAddr
if strings.TrimSpace(cfg.promptDir) == "" {
return nil, errors.New("--prompt-dir is required")
}
@@ -325,6 +354,20 @@ func finalizeExecutionRequestConfig(fs *flag.FlagSet, cfg *runConfig) error {
return fmt.Errorf("unexpected positional args: %v", fs.Args())
}
settings, err := resolveAppSettings(fs, cfg.configPath, appconfig.CLIOverrides{
PromptDir: cfg.promptDirIfSet(fs),
ProfileDir: cfg.profileDirIfSet(fs),
SchemaDir: cfg.schemaDirIfSet(fs),
})
if err != nil {
return err
}
cfg.promptDir = settings.PromptDir
cfg.profileDir = settings.ProfileDir
cfg.schemaDir = settings.SchemaDir
cfg.defaultRenderFormat = settings.DefaultRenderFormat
if strings.TrimSpace(cfg.promptDir) == "" {
return errors.New("--prompt-dir is required")
}
@@ -352,6 +395,73 @@ func finalizeExecutionRequestConfig(fs *flag.FlagSet, cfg *runConfig) error {
return nil
}
func (c *runConfig) promptDirIfSet(fs *flag.FlagSet) string {
if flagWasSet(fs, "prompt-dir") {
return c.promptDir
}
return ""
}
func (c *runConfig) profileDirIfSet(fs *flag.FlagSet) string {
if flagWasSet(fs, "profile-dir") {
return c.profileDir
}
return ""
}
func (c *runConfig) schemaDirIfSet(fs *flag.FlagSet) string {
if flagWasSet(fs, "schema-dir") {
return c.schemaDir
}
return ""
}
func (c *serveConfig) promptDirIfSet(fs *flag.FlagSet) string {
if flagWasSet(fs, "prompt-dir") {
return c.promptDir
}
return ""
}
func (c *serveConfig) profileDirIfSet(fs *flag.FlagSet) string {
if flagWasSet(fs, "profile-dir") {
return c.profileDir
}
return ""
}
func (c *serveConfig) schemaDirIfSet(fs *flag.FlagSet) string {
if flagWasSet(fs, "schema-dir") {
return c.schemaDir
}
return ""
}
func (c *serveConfig) addrIfSet(fs *flag.FlagSet) string {
if flagWasSet(fs, "addr") {
return c.addr
}
return ""
}
func registerConfigPathFlag(fs *flag.FlagSet, target *string) {
fs.StringVar(target, "config", "", fmt.Sprintf("application config path (default %s)", appconfig.DefaultConfigPath))
}
func resolveAppSettings(fs *flag.FlagSet, configPath string, overrides appconfig.CLIOverrides) (appconfig.AppSettings, error) {
settings, err := appconfig.LoadConfig(configPath, flagWasSet(fs, "config"))
if err != nil {
return appconfig.AppSettings{}, fmt.Errorf("application config error: %w", err)
}
merged, err := appconfig.ApplyCLIOverrides(settings, overrides)
if err != nil {
return appconfig.AppSettings{}, fmt.Errorf("application config error: %w", err)
}
return merged, nil
}
func buildRunRequestFromConfig(cfg *runConfig) (domain.RunRequest, error) {
inputMappings, err := parseMappings(cfg.inputRaw, false)
if err != nil {
@@ -482,7 +592,7 @@ func printSummary(stderr io.Writer, res *domain.RunResult) {
func printUsage(w io.Writer) {
fmt.Fprintln(w, "usage: scriptorium <run|render|serve> ...")
fmt.Fprintln(w, " run: scriptorium run --prompt-dir DIR --profile-dir DIR --prompt ID --input name=path [--input ...] [--profile ID] [--llm-base-url URL] [--model NAME] [--api-key-env ENV] [--temperature N] [--max-tokens N] [--top-p N] [--var k=v] [--out path] [--timeout 10m]")
fmt.Fprintln(w, " render: scriptorium render --prompt-dir DIR --profile-dir DIR --prompt ID --input name=path [--input ...] [--profile ID] [--llm-base-url URL] [--model NAME] [--api-key-env ENV] [--temperature N] [--max-tokens N] [--top-p N] [--var k=v] [--format text|json] [--out path] [--timeout 10m]")
fmt.Fprintf(w, " serve: scriptorium serve --addr %s --prompt-dir DIR --profile-dir DIR [--schema-dir DIR]\n", defaults.HTTPAddrDefault)
fmt.Fprintln(w, " run: scriptorium run [--config PATH] --prompt-dir DIR --profile-dir DIR --prompt ID --input name=path [--input ...] [--profile ID] [--llm-base-url URL] [--model NAME] [--api-key-env ENV] [--temperature N] [--max-tokens N] [--top-p N] [--var k=v] [--out path] [--timeout 10m]")
fmt.Fprintln(w, " render: scriptorium render [--config PATH] --prompt-dir DIR --profile-dir DIR --prompt ID --input name=path [--input ...] [--profile ID] [--llm-base-url URL] [--model NAME] [--api-key-env ENV] [--temperature N] [--max-tokens N] [--top-p N] [--var k=v] [--format text|json] [--out path] [--timeout 10m]")
fmt.Fprintf(w, " serve: scriptorium serve [--config PATH] --addr %s --prompt-dir DIR --profile-dir DIR [--schema-dir DIR]\n", defaults.HTTPAddrDefault)
}