first commit
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
// Package config implements pigo's optional user config file at
|
||||
// ~/.config/pigo/config.toml (honoring $XDG_CONFIG_HOME when set) plus the
|
||||
// provider-agnostic base-url env-var name derivation. Values in the file
|
||||
// replace pigo's built-in defaults, but an explicit command-line flag always
|
||||
// wins over the file:
|
||||
//
|
||||
// command-line flag > config.toml > built-in default
|
||||
//
|
||||
// A missing file is not an error (defaults apply); a malformed file is surfaced
|
||||
// to the caller so it can warn rather than silently ignore user intent.
|
||||
//
|
||||
// The package is intentionally free of any cliOptions/run-assembly concern: it
|
||||
// only loads and decodes the file and derives env-var names. Overlaying a
|
||||
// FileConfig onto the parsed CLI options lives in cmd/pigo, alongside the
|
||||
// options struct it mutates.
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
)
|
||||
|
||||
// FileConfig is the on-disk shape of config.toml. Every field is optional; an
|
||||
// absent (zero-value) field leaves the corresponding default/flag untouched.
|
||||
// Keys are snake_case to read naturally in TOML.
|
||||
type FileConfig struct {
|
||||
Model string `toml:"model"`
|
||||
BaseURL string `toml:"base_url"`
|
||||
APIKey string `toml:"api_key"`
|
||||
Protocol string `toml:"protocol"`
|
||||
Provider string `toml:"provider"`
|
||||
ThinkingLevel string `toml:"thinking_level"`
|
||||
OutputFormat string `toml:"output_format"`
|
||||
NoTools bool `toml:"no_tools"`
|
||||
NoSkills bool `toml:"no_skills"`
|
||||
Approve bool `toml:"approve"`
|
||||
SystemPrompt string `toml:"system_prompt"`
|
||||
// AllowedTools and DisallowedTools are the tool-level admission boundary:
|
||||
// the config-file tier of --allowed-tools / --disallowed-tools. Names match
|
||||
// case-insensitively and DisallowedTools wins when a name appears in both.
|
||||
// A CLI flag replaces the file value wholesale rather than merging with it,
|
||||
// so passing --allowed-tools can widen a boundary the file narrowed.
|
||||
AllowedTools []string `toml:"allowed_tools"`
|
||||
DisallowedTools []string `toml:"disallowed_tools"`
|
||||
// Prompts is the config.toml `prompts` array: paths (files or dirs) to load
|
||||
// prompt templates from at the settings tier (mirrors pi's settings prompts).
|
||||
Prompts []string `toml:"prompts"`
|
||||
// Memory, Checkpoint, and Compaction are nested TOML tables for the
|
||||
// persistent-memory / infinite-context feature. They are pure config
|
||||
// plumbing here; defaults/parsing live in memory.go (Resolve* helpers) and
|
||||
// the overlay into runtime options lives in cmd/pigo. See
|
||||
// tasks/spec-persistent-memory-infinite-context.md §3/§4/§5.2.
|
||||
Memory MemoryConfig `toml:"memory"`
|
||||
Checkpoint CheckpointConfig `toml:"checkpoint"`
|
||||
Compaction CompactionConfig `toml:"compaction"`
|
||||
// Dream is the [dream] TOML table for the /dream memory-consolidation
|
||||
// feature. Pure config plumbing here; defaults/normalization live in
|
||||
// internal/dream (Config). See tasks/spec-dream-memory-consolidation.md
|
||||
// §3.3.
|
||||
Dream DreamConfig `toml:"dream"`
|
||||
}
|
||||
|
||||
// DreamConfig is the [dream] TOML table for /dream memory consolidation.
|
||||
// Enabled is a pointer so an absent key (nil) is distinguishable from an
|
||||
// explicit false: nil is treated as true, only enabled = false disables
|
||||
// auto-trigger. IntervalDays and RecentSessions use zero as "apply default"
|
||||
// (7 and 20 respectively); normalization lives in dream.Config.
|
||||
type DreamConfig struct {
|
||||
Enabled *bool `toml:"enabled"`
|
||||
IntervalDays int `toml:"interval_days"`
|
||||
RecentSessions int `toml:"recent_sessions"`
|
||||
}
|
||||
|
||||
// FileConfigPath returns the path to the user config file:
|
||||
// $XDG_CONFIG_HOME/pigo/config.toml, or ~/.config/pigo/config.toml by default.
|
||||
// It returns "" when neither can be resolved, so the caller treats the file as
|
||||
// absent.
|
||||
func FileConfigPath() string {
|
||||
if dir := os.Getenv("XDG_CONFIG_HOME"); dir != "" {
|
||||
return filepath.Join(dir, "pigo", "config.toml")
|
||||
}
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return filepath.Join(home, ".config", "pigo", "config.toml")
|
||||
}
|
||||
|
||||
// LoadFileConfig reads and decodes config.toml. A missing file (or an empty
|
||||
// path) returns a zero config with no error; a malformed file is an error.
|
||||
func LoadFileConfig(path string) (FileConfig, error) {
|
||||
if path == "" {
|
||||
return FileConfig{}, nil
|
||||
}
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return FileConfig{}, nil
|
||||
}
|
||||
return FileConfig{}, fmt.Errorf("read config %s: %w", path, err)
|
||||
}
|
||||
var cfg FileConfig
|
||||
if err := toml.Unmarshal(data, &cfg); err != nil {
|
||||
return FileConfig{}, fmt.Errorf("parse config %s: %w", path, err)
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// GenericBaseURLEnvVar derives the generic base-url override env var name for a
|
||||
// provider: the provider name uppercased with hyphens rewritten to underscores,
|
||||
// suffixed with _BASE_URL. For example "zai-coding-cn" → "ZAI_CODING_CN_BASE_URL"
|
||||
// and "deepseek" → "DEEPSEEK_BASE_URL". An empty provider name yields "".
|
||||
//
|
||||
// It lives here (not with ResolveBaseURL) because it is a pure name derivation
|
||||
// with no dependency on the provider registry — the provider-agnostic part of
|
||||
// base-url resolution. ResolveBaseURL itself lives in internal/provider.
|
||||
func GenericBaseURLEnvVar(providerName string) string {
|
||||
n := strings.TrimSpace(providerName)
|
||||
if n == "" {
|
||||
return ""
|
||||
}
|
||||
n = strings.ReplaceAll(n, "-", "_")
|
||||
return strings.ToUpper(n) + "_BASE_URL"
|
||||
}
|
||||
Reference in New Issue
Block a user