Documentation
¶
Overview ¶
Package configuration: command categorization and force-flag detection. (split from config_risk_subagent.go)
Package configuration: git-command classification and risk-pattern matching. (split from config_risk_subagent.go)
Package configuration: heredoc / quoted-string stripping for risk classifiers. (split from config_risk_subagent.go)
Package configuration: risk-profile resolution and rule factory. (split from config_risk_subagent.go)
Package configuration: core risk-level and risk-profile types. (split from config_risk_subagent.go)
Package configuration: SubagentType struct, IsCriticalOperation, and risk evaluation. (split from config_risk_subagent.go)
Package configuration: SP-125 low-context mode (LCM) abstraction.
ContextProfile is the resolved shape every downstream call site reads when it needs to know whether sprout is operating in full-context mode (default) or low-context mode. The profile is computed once at agent creation by ResolveContextProfile and stored on the Agent — call sites must never re-derive it (see SP-125 R5 / "Resolution is centralized" in the roadmap).
The split between Config.ContextMode (the user-facing selector) and ContextProfile (the resolved lever values) mirrors the existing Config.RiskProfile / AutoApproveRules split: a small user-facing knob expands into a struct full of concrete preset values. A future medium mode is one new preset value, not a new config field.
Package configuration provides high-level configuration and credential resolution for providers, including support for custom providers and stored credentials.
Index ¶
- Constants
- func AllowedSkillsPath(projectRoot string) string
- func BootstrapIsolatedConfig(configDir string) error
- func CanonicalizeCustomProviderName(name string) (string, error)
- func DebugPrintConfig(config *Config, apiKeys *APIKeys)
- func DeleteCustomProvider(name string) error
- func EffectiveContextCapErrorf(got int) error
- func EnsureProviderAPIKey(provider string, apiKeys *APIKeys) error
- func GetAPIKeysPath() (string, error)
- func GetAvailableProviders() []string
- func GetConfigDir() (string, error)
- func GetConfigPath() (string, error)
- func GetCustomProviderPath(name string) (string, error)
- func GetEnv(sproutKey, legacyKey string) string
- func GetEnvSimple(suffix string) string
- func GetProviderDisplayName(provider string) string
- func GetProviderEnvVarName(provider string) string
- func GetProvidersDir() (string, error)
- func GetWorkspaceConfigPath(workspaceRoot string) string
- func HasProviderAuth(provider string) bool
- func Initialize() (*Config, *APIKeys, error)
- func IsConfigConflict(err error) bool
- func IsCriticalOperation(command string) bool
- func IsValidRiskProfile(s string) bool
- func IsWorkspaceConfigPresent(workspaceRoot string) bool
- func KnownProviderNames() []string
- func LoadCustomProviders() (map[string]CustomProviderConfig, error)
- func LoadCustomProvidersFromDir(providersDir string) (map[string]CustomProviderConfig, error)
- func LookupEnv(suffix string) (string, bool)
- func MapProviderStringToClientType(cfg *Config, raw string) (api.ClientType, error)
- func MigrateCommandPolicies(cfg *Config)
- func MigrateConfig(raw map[string]interface{}, targetVersion string) (map[string]interface{}, error)
- func MigrateConfigFileAPIKeys(configPath string) error
- func MigrateEmbeddedAPIKeys(providers map[string]CustomProviderConfig) error
- func MigrateLegacyCustomProviders(cfg *Config) (map[string]CustomProviderConfig, error)
- func PromptForAPIKey(provider string) (string, error)
- func ReadAllowedSkills(projectRoot string) map[string]bool
- func RegisterMigration(from, to string, fn MigrationFunc)deprecated
- func RequiresAPIKey(provider string) bool
- func ResolveEffectiveContextCap(cfg *Config, nativeContextWindow int) (int, error)
- func ResolveProviderModel(cfg *Config, explicitProvider, explicitModel string) (api.ClientType, string, error)
- func SaveAPIKeys(keys *APIKeys) error
- func SaveAPIKeysToDir(keys *APIKeys, configDir string) error
- func SaveCustomProvider(cfg CustomProviderConfig) error
- func SelectProvider(currentProvider string, apiKeys *APIKeys) (string, error)
- func SetEnv(suffix, value string) error
- func SetProviderConfigLookup(fn ProviderConfigLookupFunc)
- func SetProviderDisplayNameLookup(fn ProviderDisplayNameLookupFunc)
- func SetProviderNamesLookup(fn ProviderNamesLookupFunc)
- func SetValidateAndSaveAPIKeyValidation(skip bool)
- func ShowNextSteps(provider, configDir string)
- func ShowWelcomeMessage()
- func UnsetEnv(suffix string)
- func ValidateAndSaveAPIKey(provider, key string) (int, error)
- func ValidateCustomProviderEndpoint(raw string) error
- func WriteAllowedSkills(projectRoot string, ids []string) error
- type APIKeys
- func (a APIKeys) Get(provider string) string
- func (keys *APIKeys) GetAPIKey(provider string) string
- func (keys *APIKeys) HasAPIKey(provider string) bool
- func (keys *APIKeys) PopulateFromEnvironment() bool
- func (keys *APIKeys) PopulateFromJSONEnv() bool
- func (a *APIKeys) Set(provider, key string)
- func (keys *APIKeys) SetAPIKey(provider, key string)
- type APITimeoutConfig
- type AutoApproveRules
- type ChangeTrackingConfig
- type CombinedAssessment
- type CommandPolicies
- type CommandPolicyAction
- type CommandRule
- type ComputerUseConfig
- type Config
- func (c *Config) GetAllEnabledSkills() map[string]Skill
- func (c *Config) GetCommitModel() string
- func (c *Config) GetCommitProvider() string
- func (c *Config) GetMCPTimeout() time.Duration
- func (c *Config) GetModelForProvider(provider string) string
- func (c *Config) GetRefreshSystemPromptOnModelChange() bool
- func (c *Config) GetReviewModel() string
- func (c *Config) GetReviewProvider() string
- func (c *Config) GetSkill(id string) *Skill
- func (c *Config) GetSkillPath(id string) string
- func (c *Config) GetSubagentMaxDepth() int
- func (c *Config) GetSubagentMaxParallel() int
- func (c *Config) GetSubagentModel() string
- func (c *Config) GetSubagentParallelEnabled() bool
- func (c *Config) GetSubagentProvider() string
- func (c *Config) GetSubagentType(id string) *SubagentType
- func (c *Config) GetSubagentTypeModel(id string) string
- func (c *Config) GetSubagentTypeProvider(id string) string
- func (c *Config) IsPersonaDisabled(id string) bool
- func (c *Config) Save() error
- func (c *Config) SaveToDir(dir string) error
- func (c *Config) SetCommitModel(model string)
- func (c *Config) SetCommitProvider(provider string)
- func (c *Config) SetModelForProvider(provider, model string)
- func (c *Config) SetPersonaDisabled(id string, disabled bool)
- func (c *Config) SetReviewModel(model string)
- func (c *Config) SetReviewProvider(provider string)
- func (c *Config) SetSubagentModel(model string)
- func (c *Config) SetSubagentProvider(provider string)
- func (c *Config) Validate() error
- type ConfigConflictError
- type ContextMode
- type ContextProfile
- type CustomProviderConfig
- type EditApprovalConfig
- type EmbeddingIndexConfig
- type KnownProviderInfo
- type LanguageServerOverride
- type Manager
- func NewManager() (*Manager, error)
- func NewManagerSilent() (*Manager, error)
- func NewManagerWithConfig(cfg *Config, apiKeys *APIKeys) *Manager
- func NewManagerWithDir(configDir string) (*Manager, error)
- func NewManagerWithLayers(globalDir, workspaceDir string) (*Manager, error)
- func NewTestManager(t *testing.T) (*Manager, func())
- func (m *Manager) AddMCPServer(name string, server mcp.MCPServerConfig) error
- func (m *Manager) EnrichCustomProviders()
- func (m *Manager) EnsureAPIKey(clientType api.ClientType) error
- func (m *Manager) GetAPIKeyForProvider(clientType api.ClientType) string
- func (m *Manager) GetAPIKeys() *APIKeys
- func (m *Manager) GetAvailableProviders() []api.ClientType
- func (m *Manager) GetConfig() *Config
- func (m *Manager) GetConfigDir() string
- func (m *Manager) GetMCPConfig() mcp.MCPConfig
- func (m *Manager) GetModelForProvider(clientType api.ClientType) string
- func (m *Manager) GetProvider() (api.ClientType, error)
- func (m *Manager) HasAPIKey(clientType api.ClientType) bool
- func (m *Manager) MapStringToClientType(s string) (api.ClientType, error)
- func (m *Manager) RefreshAPIKeys() error
- func (m *Manager) Reload() error
- func (m *Manager) ResolveProviderModel(explicitProvider, explicitModel string) (api.ClientType, string, error)
- func (m *Manager) SaveAPIKeys() errordeprecated
- func (m *Manager) SaveConfig() error
- func (m *Manager) SelectNewProvider() (api.ClientType, error)
- func (m *Manager) SetMCPEnabled(enabled bool) error
- func (m *Manager) SetModelForProvider(clientType api.ClientType, model string) error
- func (m *Manager) SetProvider(clientType api.ClientType) error
- func (m *Manager) UpdateConfig(mutator func(*Config) error) error
- func (m *Manager) UpdateConfigNoSave(mutator func(*Config) error) error
- type MigrationFunc
- type NotificationsConfig
- type PersistentContextConfig
- type ProviderAuthMetadata
- type ProviderConfigLookupFunc
- type ProviderDiscoveryModel
- type ProviderDisplayNameLookupFunc
- type ProviderNamesLookupFunc
- type RevisionRetentionConfig
- type RiskLevel
- type RiskProfile
- type SecurityPolicy
- type SecurityPolicyAction
- type SecurityRule
- type ShellConfig
- type ShellPattern
- type Skill
- type SubagentType
- type TrainingConfig
- type VisionConfig
- type WakeupConfig
- type WorkspaceOverlayConfig
Constants ¶
const ( ConfigVersion = "2.0" ConfigDirName = ".sprout" ConfigFileName = "config.json" APIKeysFileName = "api_keys.json" OutputVerbosityCompact = "compact" OutputVerbosityDefault = "default" OutputVerbosityVerbose = "verbose" )
const ContextFloor = 8_000
ContextFloor is the absolute minimum context window at which sprout will start at all, regardless of profile. Below this, even the lite prompt (~1.5K tokens) plus a single read_file call (~2.5K tokens) plus a minimal response leaves no room to operate. ResolveContextProfile hard-errors when the caller reports a known window below this floor so the user gets a clear directive rather than a silent broken session.
Set at 8K: comfortably above the ~4K absolute minimum (prompt + one tool I/O + response) but below the smallest practical model context windows on the market. Models in the 8K–32K band get LCM; below 8K gets refused. Deliberately not user-tunable; the floor is a guardrail, not a knob.
const EffectiveContextCapMinimum = 1024
EffectiveContextCapMinimum (SP-126) is the minimum cap a user may explicitly set via Config.MaxContextTokens. Below this, the agent is not operable: every prompt exceeds the cap on the first iteration, compaction fires immediately, and the model produces nothing user-visible. The minimum matches the value already enforced by the /max-context slash command (max_context.go:64) and the settings validator (settings_defs.go), so users see a consistent message regardless of which surface they used to set the cap.
Set at 1024: enough for a system prompt + one tool round-trip on the most aggressive LCM profile, and small enough that no one accidentally gets a "sprout produces no output" experience.
Nil/zero caps (no cap configured) bypass this minimum and resolve to the native window — only EXPLICITLY SET caps below this minimum trigger the error.
const ProvidersDirName = "providers"
Variables ¶
This section is empty.
Functions ¶
func AllowedSkillsPath ¶
AllowedSkillsPath returns the full path to the allowed_skills file for a given project root.
func BootstrapIsolatedConfig ¶
BootstrapIsolatedConfig initializes an isolated config directory by cloning the user's main config on first use.
Behavior: - Creates configDir if missing. - If configDir/config.json already exists, does nothing. - Otherwise clones default config from the main config location (if present). - Removes command-history fields from the cloned config.
func CanonicalizeCustomProviderName ¶
CanonicalizeCustomProviderName lowercases and trims the input, then rejects anything outside the [a-z0-9_-] character set. Empty input is also rejected.
func DebugPrintConfig ¶
DebugPrintConfig prints current configuration for debugging
func DeleteCustomProvider ¶
func EffectiveContextCapErrorf ¶ added in v0.17.7
EffectiveContextCapErrorf builds the error message returned when a user-configured cap falls below EffectiveContextCapMinimum. The wording matches the existing /max-context and settings_defs validators exactly so users see the same message regardless of which surface they used:
"value must be at least 1024 when setting a cap (got X)"
Centralized here so the three call sites (slash command, settings validator, resolver) stay in sync.
func EnsureProviderAPIKey ¶
EnsureProviderAPIKey ensures the provider has an API key, prompting if needed
func GetAPIKeysPath ¶
GetAPIKeysPath returns the full path to the API keys file
func GetAvailableProviders ¶
func GetAvailableProviders() []string
GetAvailableProviders returns all supported providers
func GetConfigDir ¶
GetConfigDir returns the configuration directory path
func GetConfigPath ¶
GetConfigPath returns the full path to the config file
func GetCustomProviderPath ¶
GetCustomProviderPath returns the path where a custom provider JSON file is stored. Custom providers are a global resource — they are always written to the default (home) providers directory so they're visible across all workspaces. This deliberately ignores SPROUT_CONFIG so that adding a provider from a workspace-scoped session doesn't bury it in a .sprout/providers/ subdirectory that other sessions can't find.
func GetEnv ¶
GetEnv checks for an environment variable using the Sprout (SPROUT_*) name first, falling back to the legacy Ledit (LEDIT_*) name.
Convention: sproutKey should be the SPROUT_* equivalent, legacyKey the LEDIT_* original.
func GetEnvSimple ¶
GetEnvSimple checks SPROUT_* then LEDIT_* for a variable name suffix. E.g., GetEnvSimple("CONFIG") checks SPROUT_CONFIG then LEDIT_CONFIG.
func GetProviderDisplayName ¶ added in v0.16.12
GetProviderDisplayName returns a user-friendly name for the provider. Lookup chain:
- Static display-name map (generated from embedded configs — fastest and the common case for built-ins).
- Runtime factory (covers remote-only providers published to GitHub Pages whose display_name isn't baked into the static map).
- CustomProviders (user-defined local providers in config.json).
- Raw provider ID as a last resort.
func GetProviderEnvVarName ¶
func GetProvidersDir ¶
func GetWorkspaceConfigPath ¶
GetWorkspaceConfigPath returns the path to workspace-level config
func HasProviderAuth ¶
HasProviderAuth checks whether a provider has a configured credential. For providers that don't require an API key (local providers), always returns true.
func Initialize ¶
Initialize loads or creates configuration with first-run setup
func IsConfigConflict ¶
IsConfigConflict is a convenience predicate so callers don't have to type-assert by hand. Returns false for nil errors.
func IsCriticalOperation ¶
IsCriticalOperation reports whether a command matches a pattern that is NEVER allowed regardless of profile, persona, or interactive approval. Reserved for operations that can permanently destroy the system or leave it in an unrecoverable state.
This is the single source of truth for "critical" across every security gate: the static classifier (agent_tools.isCriticalSystemOperation delegates here) and the persona risk cascade (EvaluateOperationRisk) both consult it, so the two gates can't disagree on what's critical.
Covers:
- rm -rf targeting root or the current dir (`/`, `/*`, `~`, `$HOME`, `.`, `*`)
- Classic fork-bomb pattern `:(){:|:&};:`
- Filesystem creation / raw disk overwrite (mkfs, dd to a block device)
- Mass process kills (killall -9 / -KILL)
- chmod 000 on a system root path
- Overwriting critical auth/system files (/etc/shadow, /etc/passwd, …)
Tokenized matching matches invokesCommand semantics so a benign substring inside a path or argument can't trigger a false positive.
func IsValidRiskProfile ¶
IsValidRiskProfile reports whether s names a known profile. User-defined profiles (added via Config.RiskProfiles) are NOT considered "valid" by this predicate — it only covers the baked-in names. Callers that need to accept user-defined profiles should check Config.RiskProfiles directly via ResolveRiskProfileRules.
func IsWorkspaceConfigPresent ¶
IsWorkspaceConfigPresent checks if a workspace config file exists
func KnownProviderNames ¶ added in v0.16.12
func KnownProviderNames() []string
KnownProviderNames returns the union of the compile-time provider list and whatever the runtime factory has registered (which includes embedded + filesystem + remote configs once pkg/factory.init has wired SetProviderNamesLookup). Static entries keep their generated order; runtime-only additions are appended in sorted order so the result is deterministic across calls.
func LoadCustomProviders ¶
func LoadCustomProviders() (map[string]CustomProviderConfig, error)
LoadCustomProviders loads all custom provider configs. It merges providers from the SPROUT_CONFIG-resolved directory and the global home directory (~/.config/sprout/providers/), with the global home directory winning on name conflicts.
This matches the layered manager's effective behavior (which only reads from global) and ensures the factory's /provider switch path resolves the same providers the /provider listing shows. Without the merge, a user running sprout from a project workspace with SPROUT_CONFIG overridden sees custom providers listed (via the layered manager) but receives a "not registered as a custom provider" error when trying to switch to one (via LoadCustomProviders, which would otherwise only see the SPROUT_CONFIG-resolved dir).
func LoadCustomProvidersFromDir ¶
func LoadCustomProvidersFromDir(providersDir string) (map[string]CustomProviderConfig, error)
LoadCustomProvidersFromDir loads all custom provider JSON files from the given directory. Used by LoadCustomProviders for both the SPROUT_CONFIG-resolved dir and the global home dir (see the merge behavior in LoadCustomProviders for context).
func LookupEnv ¶
LookupEnv checks SPROUT_* first, then LEDIT_*. Returns the value and whether it was found.
func MapProviderStringToClientType ¶
func MapProviderStringToClientType(cfg *Config, raw string) (api.ClientType, error)
MapProviderStringToClientType converts a provider string to ClientType, including built-in providers, custom providers from config, and factory-backed dynamic providers.
Inputs accepted in priority order:
- Built-in ClientType IDs ("openai", "ollama-local", "zai-coding", ...)
- Custom providers from cfg.CustomProviders
- Factory-loaded embedded provider configs
- Display names ("OpenAI", "Ollama (Local)", ...) — reverse lookup against api.GetProviderName output. Provided for backward compatibility with sessions that persisted display names before the SP-034-fix.
func MigrateCommandPolicies ¶ added in v0.17.5
func MigrateCommandPolicies(cfg *Config)
MigrateCommandPolicies converts legacy approved_shell_commands and approved_shell_command_patterns fields into the unified CommandPolicies format. It is a no-op when cfg.CommandPolicies is already non-nil.
After migration, the old fields remain in the config for backward compatibility but are no longer consulted by the policy engine.
func MigrateConfig ¶
func MigrateConfig(raw map[string]interface{}, targetVersion string) (map[string]interface{}, error)
MigrateConfig applies all necessary migration steps to bring raw config up to the target version. It takes a raw JSON map, determines the current version, and runs each step in order. Returns the migrated raw config or an error if a step fails or the chain cannot reach the target.
func MigrateConfigFileAPIKeys ¶
MigrateConfigFileAPIKeys migrates any api_key values found in config.json's custom_providers entries into the unified credential store, then strips the keys from the config file. Called on every Load() but exits immediately if the migration marker exists.
This is necessary because the CustomProviderConfig struct no longer has an APIKey field, so json.Unmarshal would silently drop these values.
func MigrateEmbeddedAPIKeys ¶
func MigrateEmbeddedAPIKeys(providers map[string]CustomProviderConfig) error
MigrateEmbeddedAPIKeys moves any api_key values found in custom provider JSON files into the unified credential store, then strips the key from the file. Called on every Load() but exits immediately if the migration marker exists.
func MigrateLegacyCustomProviders ¶
func MigrateLegacyCustomProviders(cfg *Config) (map[string]CustomProviderConfig, error)
MigrateLegacyCustomProviders copies any custom_providers entries that lived inline in config.json into the new file-per-provider format under ~/.config/sprout/providers/. Existing files win — the inline entry is only promoted when no file with the same name already exists.
func PromptForAPIKey ¶
PromptForAPIKey prompts the user for an API key with helpful guidance
func ReadAllowedSkills ¶
ReadAllowedSkills reads the .sprout/allowed_skills file from the given project root (cwd). Returns a set of allowed skill IDs. If the file does not exist, returns nil (meaning all skills are allowed).
func RegisterMigration
deprecated
func RegisterMigration(from, to string, fn MigrationFunc)
RegisterMigration adds a migration step to the global registry. It panics if a migration from the same source version is already registered (at-most-one-step-per-source prevents ambiguous chains).
Deprecated: Use registerMigration (returns an error) for new code. This wrapper is retained for backward compatibility with external callers and tests that expect the panic behavior.
func RequiresAPIKey ¶
RequiresAPIKey checks if a provider requires an API key.
func ResolveEffectiveContextCap ¶ added in v0.17.7
ResolveEffectiveContextCap returns the user's effective context cap for this session — the smaller of (a) the model's native context window and (b) the user's configured MaxContextTokens cap. This is the single source of truth for the cap; every call site in sprout MUST read the value returned here (typically once at agent creation, then stored on the Agent for hot-path access) and MUST NOT re-derive it from Config.MaxContextTokens or call client.GetModelContextLimit() directly — those paths bypass the cap.
Inputs:
- cfg: the user's config. May be nil (no cap, no error).
- nativeContextWindow: the model's native context window in tokens. May be 0 or negative (unknown). When unknown, the cap is the user-configured value alone; if neither is known the return is 0, which callers treat as "no cap".
Output:
- cap: the resolved effective cap in tokens. 0 means "no cap".
Errors:
- Returns an error ONLY when the user explicitly set a cap below EffectiveContextCapMinimum (1024). The nil/zero cap (no cap configured) bypasses the minimum and resolves to the native window — only EXPLICITLY SET caps below the minimum trigger the error. The error message matches the /max-context and settings_defs validators exactly so users see consistent feedback across surfaces.
Precedence (highest first):
- If cfg.MaxContextTokens is non-nil and > 0, AND the native window is known (> 0), return min(native, *cfg.MaxContextTokens).
- If only one of the two is known, return that one.
- If neither is known, return 0. Call sites treat 0 as "unknown" and fall back to whatever default is appropriate (typically the native value reported by the client, or a hardcoded fallback).
Independent of ContextProfile (SP-125): a 1M model can run in full mode with a 300K cap; a 32K model can run in LCM with no cap. Both are valid. The cap and the profile are deliberately separate concerns — the cap is a user cost preference, the profile is a model-size accommodation.
func ResolveProviderModel ¶
func ResolveProviderModel(cfg *Config, explicitProvider, explicitModel string) (api.ClientType, string, error)
ResolveProviderModel resolves provider and model using one canonical precedence path: 1) Explicit provider flag/arg 2) Explicit model in provider:model format (only when prefix is a valid provider) 3) SPROUT_PROVIDER env (with LEDIT_PROVIDER backward-compat) 4) SPROUT_MODEL env (provider:model format only when prefix is a valid provider, LEDIT_MODEL backward-compat) 5) Config last_used_provider 6) Auto-detected provider via DetermineProvider
Model precedence: 1) Explicit model (trimmed to model segment when provider:model format is recognized) 2) SPROUT_MODEL env (same parsing rule, LEDIT_MODEL backward-compat) 3) Config provider model default
func SaveAPIKeys ¶
SaveAPIKeys saves API keys to the active backend. When keyring is active, each key is stored via SetToActiveBackend, keys that are no longer in the map are deleted from the keyring, and keys that are now in the keyring are cleaned from the encrypted file store. When file is active, it uses the existing file-based Save behavior.
Uses GetStorageBackend() (not GetStorageMode()) for consistent resolution.
func SaveAPIKeysToDir ¶
SaveAPIKeysToDir saves API keys to a specific config directory. This is like SaveAPIKeys() but routes file-backend saves through credentials.SaveToDir() instead of credentials.Save().
func SaveCustomProvider ¶
func SaveCustomProvider(cfg CustomProviderConfig) error
func SelectProvider ¶
SelectProvider allows user to select a provider interactively
func SetEnv ¶
SetEnv sets both the SPROUT_* and LEDIT_* versions of an env var for backward compatibility during the transition period.
func SetProviderConfigLookup ¶ added in v0.16.8
func SetProviderConfigLookup(fn ProviderConfigLookupFunc)
SetProviderConfigLookup registers a runtime config lookup. pkg/factory wires this to GlobalFactory().GetProviderConfig in its init() so that GetProviderAuthMetadata sees providers added by refreshFromRemote — not just embedded ones. The pattern mirrors credentials.SetProviderInfoFunc and exists to avoid a configuration → factory import cycle.
func SetProviderDisplayNameLookup ¶ added in v0.16.8
func SetProviderDisplayNameLookup(fn ProviderDisplayNameLookupFunc)
SetProviderDisplayNameLookup registers a runtime display-name lookup. pkg/factory wires this to GlobalFactory().GetProviderConfig in its init(); the callback returns cfg.DisplayName so providers published only to the remote registry surface their friendly label in the onboarding menu, model picker, and other UI surfaces.
func SetProviderNamesLookup ¶ added in v0.16.8
func SetProviderNamesLookup(fn ProviderNamesLookupFunc)
SetProviderNamesLookup registers a runtime provider-names lookup. pkg/factory wires this to GlobalFactory().GetAvailableProviders in its init() so onboarding / credential-enumeration loops surface providers added by refreshFromRemote.
func SetValidateAndSaveAPIKeyValidation ¶ added in v0.16.2
func SetValidateAndSaveAPIKeyValidation(skip bool)
SetValidateAndSaveAPIKeyValidation enables or disables the test-mode skip. Call with true in tests that need to store keys without network validation.
func ShowNextSteps ¶
func ShowNextSteps(provider, configDir string)
ShowNextSteps displays helpful next steps after successful setup
func ShowWelcomeMessage ¶
func ShowWelcomeMessage()
ShowWelcomeMessage displays a comprehensive welcome message for new users
func UnsetEnv ¶
func UnsetEnv(suffix string)
UnsetEnv removes both SPROUT_* and LEDIT_* versions of an env var.
func ValidateAndSaveAPIKey ¶
ValidateAndSaveAPIKey validates a new API key before storing it. If validation fails, the old key is preserved and an error is returned. Returns the number of models available if validation succeeds.
func ValidateCustomProviderEndpoint ¶ added in v0.16.25
ValidateCustomProviderEndpoint checks that raw is a syntactically valid http or https URL with a host. It runs before NormalizeCustomProviderConfig (which auto-appends /v1/chat/completions), so it catches typos that would otherwise produce a config that silently fails model discovery.
Returns nil for empty input — that's allowed at this layer so the wizard can detect "user pressed enter on an empty prompt" separately from "user typed garbage".
func WriteAllowedSkills ¶
WriteAllowedSkills writes the .sprout/allowed_skills file in the given project root. IDs are sorted for deterministic output.
Types ¶
type APIKeys ¶
func LoadAPIKeys ¶
LoadAPIKeys loads API keys from the active backend. When keyring is active, it loads from both keyring (tracked providers) and the file store (for backward compatibility with keys stored before keyring was enabled). When file is active, it uses the existing file-based Load behavior.
Uses GetStorageBackend() (not GetStorageMode()) to ensure consistent resolution on first run — the auto-detection logic runs exactly once and persists the mode, so subsequent Load/Save calls see the same backend.
func LoadAPIKeysFromDir ¶
LoadAPIKeysFromDir loads API keys from a specific config directory. This is like LoadAPIKeys() but takes an explicit config directory instead of reading from environment variables. It's useful for test environments and other scenarios where you want to load from a specific location without mutating process state.
When keyring is active, it loads from both keyring (tracked providers) and the file store at the specified configDir (for backward compatibility with keys stored before keyring was enabled). When file is active, it uses LoadFromDir.
func (*APIKeys) HasAPIKey ¶
HasAPIKey checks if a provider has an API key set. Checks the in-memory map first, then falls back to the active backend (keyring or file store) for credentials not in the map.
func (*APIKeys) PopulateFromEnvironment ¶
PopulateFromEnvironment populates API keys from environment variables This is called on startup only to detect whether environment credentials are available.
func (*APIKeys) PopulateFromJSONEnv ¶
PopulateFromJSONEnv populates API keys from the SPROUT_API_KEYS_JSON environment variable. The value must be a JSON object mapping provider names to API key strings, e.g. {"openrouter":"sk-...","deepinfra":"di-..."}. This is designed for containerized/SaaS environments (e.g. Sprout Foundry) where keys are injected at runtime rather than stored in config files.
type APITimeoutConfig ¶
type APITimeoutConfig struct {
ConnectionTimeoutSec int `json:"connection_timeout_sec,omitempty"` // Time to establish connection (default: 300)
FirstChunkTimeoutSec int `json:"first_chunk_timeout_sec,omitempty"` // Time to receive first response (default: 600)
ChunkTimeoutSec int `json:"chunk_timeout_sec,omitempty"` // Max time between streaming chunks (default: 600)
OverallTimeoutSec int `json:"overall_timeout_sec,omitempty"` // Total request timeout (default: 1800)
CommitMessageTimeoutSec int `json:"commit_message_timeout_sec,omitempty"` // Timeout for commit message generation (default: 300)
}
APITimeoutConfig represents timeout settings for API calls
type AutoApproveRules ¶
type AutoApproveRules struct {
LowRiskOps []string `json:"low_risk,omitempty"` // Operations auto-approved by EA
MediumRiskOps []string `json:"medium_risk,omitempty"` // Operations the EA reasons about
HighRiskNever []string `json:"high_risk_never,omitempty"` // Pattern names always gated (rm_recursive, force_flag, ...)
// DefaultRisk is the level returned for operations that don't
// match any of the above. Default (empty) is "medium" — the
// classic EA behavior. Cautious profiles set this to "high"
// so unrecognized commands route to a prompt. Permissive /
// unrestricted set it to "low" so common operations auto-approve.
DefaultRisk RiskLevel `json:"default_risk,omitempty"`
}
AutoApproveRules controls the EA's sliding risk cascade for operation approvals.
func AutoApproveRulesForProfile ¶
func AutoApproveRulesForProfile(profile RiskProfile) AutoApproveRules
AutoApproveRulesForProfile returns the rules baked into each named profile. Unknown profiles fall back to RiskProfileDefault.
func DefaultAutoApproveRules ¶
func DefaultAutoApproveRules() AutoApproveRules
DefaultAutoApproveRules returns the default risk cascade rules for the EA persona.
func ResolveRiskProfileRules ¶
func ResolveRiskProfileRules(cfg *Config, profile RiskProfile) AutoApproveRules
ResolveRiskProfileRules returns the AutoApproveRules that should apply for the given profile name, honoring user overrides in Config.RiskProfiles before falling back to the baked-in defaults.
Resolution order:
- cfg.RiskProfiles[name] — user override (replaces builtins entirely; the user is the source of truth for any profile name they list, including the five named built-ins).
- AutoApproveRulesForProfile(name) — baked-in defaults for the known profile names. Unknown names fall through to the Default profile here.
cfg may be nil (no config loaded); in that case the baked-in rules are always returned.
type ChangeTrackingConfig ¶
type ChangeTrackingConfig struct {
// Enabled controls whether the change tracking subsystem is active
// at all. When false, no file changes are recorded, no revision
// history is written, and the rollback/recover/view_history tools
// are no-ops.
//
// Defaults to true. The git-awareness guards (IsRevertSafe) now
// prevent the subsystem from reverting committed work, so tracking
// stays on by default. Set to false to disable the entire subsystem.
Enabled *bool `json:"enabled,omitempty"`
// ShellWalkEnabled controls whether the per-shell_command snapshot
// walk runs at all. Disable for workspaces where the walk cost is
// unacceptable (e.g., very-large monorepos with novel bloat
// directories) or for users who don't care about recovering
// shell-deleted untracked files. Direct file-tool tracking is
// unaffected. Default: true. Only meaningful when Enabled is true.
ShellWalkEnabled *bool `json:"shell_walk_enabled,omitempty"`
// MaxFiles caps the number of files visited in a single walk.
// Larger workspaces hit the cap and yield partial coverage with a
// truncation log. Default: 50000.
MaxFiles int `json:"max_files,omitempty"`
// MaxTotalBytes caps cumulative content bytes captured per walk.
// Files past this cap get path-only entries (still appear in
// list_changes / FilesModified, but report recoverable=false).
// Default: 32 MiB (33554432).
MaxTotalBytes int64 `json:"max_total_bytes,omitempty"`
// MaxDurationMs is the wall-clock budget for a single walk, in
// milliseconds. Exceeding it aborts the walk with a partial-
// coverage log. Default: 500 ms.
MaxDurationMs int `json:"max_duration_ms,omitempty"`
// AutoSkipFileCountThreshold is the per-directory immediate child
// file count that triggers adaptive auto-skip. Default: 1500.
AutoSkipFileCountThreshold int `json:"auto_skip_file_count_threshold,omitempty"`
// RevisionRetention controls how the persistent revision store
// (.sprout/revisions/ + .sprout/changes/) is compacted. Quantity-
// based tiering: most recent N revisions are kept verbatim, next M
// drop the conversation transcript, next K collapse to a one-line
// summary, the rest are dropped. Position is by directory mtime,
// so accessing an old revision via view_history / recover_file
// promotes it back toward "hot" automatically.
RevisionRetention *RevisionRetentionConfig `json:"revision_retention,omitempty"`
}
ChangeTrackingConfig gates and tunes the ChangeTracker. When Enabled is false (the default) the entire subsystem is dormant — no file changes are recorded, no revision history is written, and the rollback/recover/view_history tools are no-ops. When Enabled is true the per-shell_command snapshot walk runs (tuned by the remaining fields) and direct file-tool tracking (write_file, edit_file, patch_structured_file) records changes.
func (*ChangeTrackingConfig) Resolve ¶
func (c *ChangeTrackingConfig) Resolve() ChangeTrackingConfig
Resolve fills in defaults for any zero-value fields and returns a fully-populated config. Safe to call on nil — yields all-defaults.
type CombinedAssessment ¶
type CombinedAssessment struct {
ClassifierRisk int // SecurityRisk value (0=safe, 1=caution, 2=dangerous)
ClassifierBlocked bool // ShouldBlock from the classifier
ClassifierPrompt bool // ShouldPrompt from the classifier
ClassifierCategory string // RiskCategory string
PolicyAction SecurityPolicyAction
PolicyRule *SecurityRule // the matched rule, if any
PathAllowed bool
CommandDenied bool
OverrideAction string // reason if policy overrides classifier
}
CombinedAssessment holds the result of combining the security classifier with the workspace security policy.
IMPORTANT: To avoid a circular import (configuration -> agent_tools -> configuration), the ClassifierResult field is a generic map instead of a typed reference to agent_tools.SecurityResult. Callers that need the typed result should use CombinedSecurityAssessmentWithClassifier below.
func CombinedSecurityAssessment ¶
func CombinedSecurityAssessment( toolName string, args map[string]interface{}, policy *SecurityPolicy, classifierRisk int, classifierBlocked bool, classifierPrompt bool, classifierCategory string, ) *CombinedAssessment
CombinedSecurityAssessment evaluates a tool call against the security policy.
classifierRisk is the risk level from the security classifier (0=safe, 1=caution, 2=dangerous). classifierBlocked indicates whether the classifier says the call should be blocked. classifierPrompt indicates whether the classifier says the call should prompt the user. classifierCategory is the risk category string from the classifier (e.g. "read-only", "file-write").
This interface avoids a circular import between configuration and agent_tools.
type CommandPolicies ¶ added in v0.17.5
type CommandPolicies struct {
Rules []CommandRule `json:"rules"`
}
CommandPolicies is the top-level config structure for user command policies (SP-123). Rules are evaluated first-match-wins before the classifier and risk profile. The three actions (allow/ask/deny) override the default approval cascade.
type CommandPolicyAction ¶ added in v0.17.5
type CommandPolicyAction string
CommandPolicyAction determines what happens when a command matches a rule.
const ( // CommandPolicyAllow auto-approves the command, skipping classifier, risk // profile, and interactive prompt. Does not override Critical-tier blocks. CommandPolicyAllow CommandPolicyAction = "allow" // CommandPolicyAsk forces an interactive prompt, skipping allowlist and // classifier auto-approve. Classifier risk is still computed for display. CommandPolicyAsk CommandPolicyAction = "ask" // CommandPolicyDeny hard-blocks the command, returning an error immediately. CommandPolicyDeny CommandPolicyAction = "deny" )
type CommandRule ¶ added in v0.17.5
type CommandRule struct {
// Pattern is a glob pattern (Go path.Match syntax) to match against
// shell commands. For example: "git push*", "rm -rf /tmp/*".
Pattern string `json:"pattern"`
// Action determines the behavior when a command matches this rule.
Action CommandPolicyAction `json:"action"`
// Reason is an optional user note explaining why this rule exists.
Reason string `json:"reason,omitempty"`
}
CommandRule is a single user-defined command policy rule.
type ComputerUseConfig ¶ added in v0.16.12
type ComputerUseConfig struct {
// Enabled is the master switch. When false (default) the computer_user
// persona's mouse/keyboard/screenshot tools are never registered or
// executed. Turning it on is a deliberate, one-time user choice.
Enabled bool `json:"enabled,omitempty"`
// MaxActionsPerMinute caps the action rate as a runaway-loop backstop.
// Default: 60. Set to 0 to disable the cap (not recommended).
MaxActionsPerMinute int `json:"max_actions_per_minute,omitempty"`
// AuditLogDir is where per-session JSONL action logs are written.
// Default: ~/.config/sprout/computer_use_log when empty.
AuditLogDir string `json:"audit_log_dir,omitempty"`
// WorkspaceAllowlist lists workspace roots where computer use is
// auto-approved for the session without the per-session opt-in prompt.
WorkspaceAllowlist []string `json:"workspace_allowlist,omitempty"`
// PanicKeyChord is the key chord that triggers the panic key. Defaults
// to "ctrl+shift+escape". Set to "disabled" to turn off the panic key
// entirely.
PanicKeyChord string `json:"panic_key_chord,omitempty"`
// DestructiveAppGate controls whether the destructive-app denylist gate
// is active. When true (default), actions targeting apps on the
// denylist prompt the user for approval before proceeding.
DestructiveAppGate bool `json:"destructive_app_gate,omitempty"`
// OverrideFilePath is an optional override of the per-user denylist
// override file location. When empty, the default path
// (~/.config/sprout/computer_use_denylist_overrides.json) is used.
OverrideFilePath string `json:"denylist_override_file,omitempty"`
}
ComputerUseConfig gates the computer_user persona's desktop-control tools (SP-063). The feature is categorically more dangerous than file edits — a click can send an email or empty the trash — so it is off by default and every field is a safety lever.
func (*ComputerUseConfig) Resolve ¶ added in v0.16.12
func (c *ComputerUseConfig) Resolve() ComputerUseConfig
Resolve returns a copy with defaults filled in for zero-value fields.
type Config ¶
type Config struct {
Version string `json:"version"`
// Provider and Model Configuration
LastUsedProvider string `json:"last_used_provider"`
ProviderModels map[string]string `json:"provider_models"`
ProviderPriority []string `json:"provider_priority"`
// Language Server Override Configuration
LanguageServers []LanguageServerOverride `json:"language_servers,omitempty"`
// MCP Configuration
MCP mcp.MCPConfig `json:"mcp"`
// Preferences
Preferences map[string]interface{} `json:"preferences,omitempty"`
// DisableCoordinatorAutoActivate opts out of the automatic activation of the
// coordinator persona (formerly Executive Assistant) when sprout starts in
// the user's $HOME directory. When true, no persona is auto-activated and
// the user must select one explicitly. Default false (auto-activate).
DisableCoordinatorAutoActivate bool `json:"disable_coordinator_auto_activate,omitempty"`
// AllowGitHistoryRewrite controls whether commands that can lose commit
// history are accepted via shell_command without going through the git
// tool's approval flow. Specifically: `git reset --hard <commit-ish>`,
// `git rebase`, `git branch -D`, `git tag -d`.
//
// Working-tree-only destructive ops (`git checkout .`, `git restore`,
// `git clean -fd`, `git reset --hard HEAD`, etc.) are always allowed
// because the change tracker captures pre-mutation content and exposes
// recover_file / recover_bulk for restoration. History rewrites can't
// be recovered through the tracker — only via the reflog — so they
// stay gated by default.
//
// Default: false (gated). Set true in environments where the agent
// has tighter feedback loops (e.g. user-facing chat where every step
// is confirmed) and the friction of going through the git tool isn't
// worth it.
AllowGitHistoryRewrite bool `json:"allow_git_history_rewrite,omitempty"`
// UnifiedRiskResolver enables the unified risk resolver (SP-068 Phase 2).
// When true (the default), gating decisions at call sites use a single
// ResolveToolRisk assessment instead of the split Gate 1 (static
// classifier) → Gate 2 (persona risk cascade) path. When false, the
// legacy dual-gate code paths run (retained for compatibility). Set to
// false explicitly to opt out of the unified resolver.
UnifiedRiskResolver bool `json:"unified_risk_resolver,omitempty"`
// DaemonMultiSession enables N concurrent browser windows per user
// when the server runs in service/daemon mode (SPROUT_SERVICE=1).
// When true, the WebSocket dispatcher routes new connections through
// the multi-session path (handleWebSocket_Daemon); each connection
// gets its own chat session and its own agent without colliding
// with sibling windows. When false, the daemon falls back to the
// single-active-session path (handleWebSocket_Agent) and the second
// window triggers session_conflict + takeover — the pre-SP-118
// behavior.
//
// Effective value at the dispatch site is
// effective = (agentEnforceSingleSession == false) && DaemonMultiSession
// i.e. the agent path always uses Mode 1 regardless of this flag,
// and the daemon path uses Mode 2 only when this flag is true.
//
// Default: true (the daemon opens with multi-session on, so three
// browser windows on the same daemon each get their own chat
// without a takeover prompt). Set to false to opt out without
// editing code — useful for rolling forward / back during the
// SP-118 rollout window. SP-118 Phase 4 will flip the rollout so
// this default is the new normal.
DaemonMultiSession bool `json:"daemon_multi_session,omitempty"`
// ResourceDirectory stores captured web/vision resources relative to the current working directory.
// This can be overridden at runtime with --resource-directory.
ResourceDirectory string `json:"resource_directory,omitempty"`
// ReasoningEffort sets a global default reasoning effort for chat requests.
// Valid values: "low", "medium", "high". Empty means automatic selection.
ReasoningEffort string `json:"reasoning_effort,omitempty"`
// DisableThinking disables thinking/reasoning mode for thinking-capable models.
// When true, models like Qwen3, Qwen3.5, GLM models, and Minimax models will
// not use their thinking/reasoning mode. Note: GPT-OSS models do not support
// disabling thinking (they use reasoning_effort instead).
DisableThinking bool `json:"disable_thinking,omitempty"`
// SystemPromptText overrides the main agent system prompt inline.
// Empty means use the embedded default prompt.
SystemPromptText string `json:"system_prompt_text,omitempty"`
// RefreshSystemPromptOnModelChange (Spec B): when true, re-derive the
// agent's system prompt on every provider/model swap instead of
// freezing it at agent-creation time. Different models respond very
// differently to the same prompt — a Claude-tuned prompt sent to
// GPT-4 may be silently ignored. With this on, the agent re-runs
// GetEmbeddedSystemPromptForProfile on each SetProvider / SelectProvider
// so the prompt stays in sync with the active provider and context
// window. Defaults to false so existing sessions are bit-identical.
// Flip to true after observability shows the new behavior lands
// cleanly. The agent's `SystemPromptText` override still wins — only
// the embedded portion is re-derived, the configured override is
// re-applied on top.
RefreshSystemPromptOnModelChange bool `yaml:"refresh_system_prompt_on_model_change,omitempty" json:"refresh_system_prompt_on_model_change,omitempty"`
// SkipPrompt - for non-interactive mode
SkipPrompt bool `json:"skip_prompt,omitempty"`
// RiskProfile selects a named preset for the shell-command risk
// cascade: readonly / cautious / default / permissive /
// unrestricted. Empty or unrecognized values resolve to "default"
// via AutoApproveRulesForProfile. Per-persona AutoApproveRules
// always win over the profile. The CLI's --risk-profile flag and
// a workflow step's "risk_profile" field both override this
// value.
RiskProfile string `json:"risk_profile,omitempty"`
// ContextMode selects a named context-engine preset: "" (full
// default) | "full" | "low_context". Resolved into a ContextProfile
// via ResolveContextProfile at agent creation; call sites read
// fields off the resolved profile rather than this string directly.
// Empty/unrecognized values fall through to auto-detection by the
// resolver (which honors a small enough model window).
ContextMode ContextMode `json:"context_mode,omitempty"`
// RiskProfiles allows the user to override the baked-in rules
// for any named profile. Keys are profile names (readonly,
// cautious, default, permissive, unrestricted, or any
// user-defined name); values replace the built-in rules entirely
// for that name. Useful when the user wants a slightly different
// definition of "cautious" or wants to add their own named
// profile. See docs/SECURITY.md#risk-profiles.
RiskProfiles map[string]AutoApproveRules `json:"risk_profiles,omitempty"`
// ApprovedShellCommands is the user's persistent allowlist of
// literal shell command strings that should auto-approve through
// the high-risk cascade without prompting. Populated by the
// "Always approve this command" choice on the approval dialog
// (SP-058 follow-up). Stored as exact strings — matching is
// command-literal equality, not pattern matching, so allow-listing
// `rm -rf /tmp/build-cache` does NOT allow `rm -rf anything-else`.
// The Critical tier still blocks regardless of this allowlist.
// Users can edit this list directly in config.json to revoke an
// entry, or remove all entries to reset.
ApprovedShellCommands []string `json:"approved_shell_commands,omitempty"`
// ApprovedShellCommandPatterns is the user's persistent allowlist of
// glob patterns for shell commands that should auto-approve through
// the high-risk cascade without prompting. Patterns use Go's path.Match
// syntax: `*` matches any sequence of characters (but NOT `/`),
// `?` matches any single character, `[abc]` matches a character class.
// For example, `rm -rf /tmp/*` matches `rm -rf /tmp/build` but NOT
// `rm -rf /home/x`. The Critical tier still blocks regardless of
// pattern matches — patterns cannot override critical-tier gating,
// which is enforced at the call site before this allowlist is consulted.
// Users can edit this list directly in config.json to revoke an entry,
// or remove all entries to reset.
ApprovedShellCommandPatterns []string `json:"approved_shell_command_patterns,omitempty"`
// CommandPolicies is the unified command policy layer (SP-123) with
// three actions: allow (auto-approve), ask (force prompt), deny
// (hard block). Rules are evaluated before the classifier and risk
// profile, first-match-wins. Replaces the fragmented
// approved_shell_commands / approved_shell_command_patterns /
// security_policy.denied_commands surfaces. Legacy fields remain for
// backward compatibility; MigrateCommandPolicies converts them on load.
CommandPolicies *CommandPolicies `json:"command_policies,omitempty"`
// DismissedPrompts tracks which one-time prompts the user has dismissed.
DismissedPrompts map[string]bool `json:"dismissed_prompts,omitempty"`
// API Timeout Configuration (in seconds)
APITimeouts *APITimeoutConfig `json:"api_timeouts,omitempty"`
// Custom Providers Configuration
CustomProviders map[string]CustomProviderConfig `json:"custom_providers,omitempty"`
// Command History Configuration
CommandHistoryByPath map[string][]string `json:"command_history_by_path,omitempty"`
HistoryIndexByPath map[string]int `json:"history_index_by_path,omitempty"`
// Change History Configuration
HistoryScope string `json:"history_scope,omitempty"` // "project" or "global"
// Subagent Configuration
SubagentProvider string `json:"subagent_provider,omitempty"` // Provider for subagents (defaults to LastUsedProvider)
SubagentModel string `json:"subagent_model,omitempty"` // Model for subagents (defaults to provider's default model)
// SubagentTypes is hydrated from the embedded catalog at config load time.
// It is NOT persisted (json:"-"): personas are catalog-fixed and user
// customization is intentionally not supported. Use DisabledPersonas to
// hide specific personas from /persona list and from subagent spawning.
SubagentTypes map[string]SubagentType `json:"-"`
// DisabledPersonas holds canonical persona IDs the user has hidden via
// `/persona <id> disable`. The catalog entries themselves are never
// mutated; resolution checks this list and treats disabled IDs as absent.
DisabledPersonas []string `json:"disabled_personas,omitempty"`
// DefaultSubagentPersona is the persona ID used when run_subagent is called
// without a persona argument. Defaults to "general" if unset. Setting this
// lets users redirect default spawns without editing the catalog.
DefaultSubagentPersona string `json:"default_subagent_persona,omitempty"`
SubagentMaxParallel int `json:"subagent_max_parallel,omitempty"` // Maximum number of parallel subagents (default: 2)
SubagentParallelEnabled *bool `json:"subagent_parallel_enabled,omitempty"` // Enable/disable parallel subagent execution (default: true)
SubagentMaxDepth int `json:"subagent_max_depth,omitempty"` // Maximum subagent nesting depth (default: 2)
// Commit Configuration
CommitProvider string `json:"commit_provider,omitempty"` // Provider for commit message generation (defaults to LastUsedProvider)
CommitModel string `json:"commit_model,omitempty"` // Model for commit message generation (defaults to provider's default model)
// Review Configuration
ReviewProvider string `json:"review_provider,omitempty"` // Provider for review commands (defaults to LastUsedProvider)
ReviewModel string `json:"review_model,omitempty"` // Model for review commands (defaults to provider's default model)
// Vision Fallback Configuration
// VisionFallbackToOCR enables transparent fallback to the OCR model
// when the primary vision model fails after retries. When true and
// PDFOCRModel is configured, a single OCR attempt is made as a last
// resort. Default: true (enabled). Controlled by VISION_FALLBACK_TO_OCR
// env var (SPROUT_ / LEDIT_ prefixes).
VisionFallbackToOCR bool `json:"vision_fallback_to_ocr,omitempty"`
// PDF OCR Configuration
PDFOCREnabled bool `json:"pdf_ocr_enabled,omitempty"` // Enable PDF OCR processing
PDFOCRProvider string `json:"pdf_ocr_provider,omitempty"` // Provider for PDF OCR (e.g., "ollama", "openai", "deepinfra")
PDFOCRModel string `json:"pdf_ocr_model,omitempty"` // Model for PDF OCR (e.g., "glm-ocr", "llama3.2-vision")
PDFOCRDownloaded bool `json:"pdf_ocr_downloaded,omitempty"` // Whether the model has been downloaded
// Embedding Index Configuration
EmbeddingIndex *EmbeddingIndexConfig `json:"embedding_index,omitempty"`
// Persistent Context Configuration
PersistentContext *PersistentContextConfig `json:"persistent_context,omitempty"`
// Computer Use Configuration (SP-063) — gates the computer_user persona's
// mouse/keyboard/screenshot tools. Off by default; the tools are never
// available unless this is explicitly enabled.
ComputerUse *ComputerUseConfig `json:"computer_use,omitempty"`
// Vision Configuration (SP-103-C3) — controls vision-pipeline runtime
// behavior: parallel worker pool size, global concurrency cap, and
// multi-image batching. All fields have safe defaults via Resolve().
Vision *VisionConfig `json:"vision,omitempty"`
// Change Tracking Configuration — controls the shell-mutation
// snapshot pass. Direct file-tool hooks (write_file, edit_file,
// patch_structured_file) are always tracked; this struct only
// gates the walker that detects shell_command mutations.
ChangeTracking *ChangeTrackingConfig `json:"change_tracking,omitempty"`
// Skills Configuration
Skills map[string]Skill `json:"skills,omitempty"` // Agent Skills that can be loaded into context
// Zsh Command Execution
EnableZshCommandDetection bool `json:"enable_zsh_command_detection"` // Enable zsh-aware command detection (default: true)
AutoExecuteDetectedCommands bool `json:"auto_execute_detected_commands"` // Auto-execute detected commands without prompting (default: true)
// Security Policy Configuration
SecurityPolicy *SecurityPolicy `json:"security_policy,omitempty"`
// Shell Configuration — user-configurable shell permission policy
// (SP-049 Phase 2). Lets users define safe/dangerous command patterns
// and a workspace-overlay mode.
Shell ShellConfig `json:"shell,omitempty"`
// MaxContextTokens caps the effective context window used when building
// requests. When set, the agent acts as if the model has at most this
// many tokens of context, limiting how large an input (and therefore
// completion budget) a single request can claim. Useful as a cost-control
// measure when using models with very large native context windows
// (e.g. 1M-token models billed per input token). Nil or 0 means no cap.
MaxContextTokens *int `json:"max_context_tokens,omitempty"`
// Notifications Configuration (SP-070) — controls how the agent
// notifies the user when long-running turns complete.
Notifications *NotificationsConfig `json:"notifications,omitempty"`
// Edit Approval Configuration (SP-072) — controls the per-hunk
// diff approval gate for agent file writes.
EditApproval *EditApprovalConfig `json:"edit_approval,omitempty"`
// OutputVerbosity controls how much inter-tool-call narration and
// streaming detail the UI shows. Valid values: "compact" (hide
// interim model messages, show only tool results and final text),
// "default" (show tool calls with results, show streaming final
// text), "verbose" (show everything including interim narration).
// Empty defaults to "default".
OutputVerbosity string `json:"output_verbosity,omitempty"`
// ShowToolInvocations controls whether the UI expands per-tool
// invocation details in the conversation output. When false, tool
// calls are collapsed/hidden. Defaults to true.
ShowToolInvocations bool `json:"show_tool_invocations,omitempty"`
// Wakeup controls auto-resume behavior for background task completions
// (SP-108). When enabled, the daemon automatically processes pending
// notifications by calling ProcessQueryWithContinuity so the agent can
// act on completed background tasks without the user sending a manual
// message. Budget controls prevent unattended token burn loops.
Wakeup WakeupConfig `json:"wakeup,omitempty"`
// Training controls opt-in session recording for training data
// collection. When enabled, each saved session is PII-redacted and
// pushed to the configured endpoint as JSON. OFF by default — must
// be explicitly enabled via --train flag, SPROUT_TRAIN_ENABLED env,
// or config.json.
Training TrainingConfig `json:"training,omitempty"`
// Other flags
FromAgent bool `json:"-"` // Internal flag, not persisted
// contains filtered or unexported fields
}
Config represents the unified application configuration
func LoadConfigWithLayers ¶
func LoadConfigWithLayers(globalPath, workspacePath, sessionPath, globalDir string) (*Config, error)
LoadConfigWithLayers loads configuration from three layers: globalPath -> workspacePath -> sessionPath (each overrides previous) Each layer is optional; missing layers are skipped. globalDir is the directory for global providers (used when globalPath is empty but custom providers need loading).
func LoadOrInitConfig ¶
func MergeConfig ¶
MergeConfig merges two configs, with override taking precedence over base. The override config typically contains only changed fields (deltas). Returns a new config without modifying either input.
func NewConfig ¶
func NewConfig() *Config
NewConfig creates a new configuration with sensible defaults
func RedactConfig ¶
RedactConfig returns a copy of the configuration with all credential values redacted. The MCP server configs have their env vars and credentials maps redacted. This should be used for any display/export/diagnostic output where the config is shown to the user or logged.
func (*Config) GetAllEnabledSkills ¶
GetAllEnabledSkills returns all enabled skills
func (*Config) GetCommitModel ¶
GetCommitModel returns the configured model for commit message generation If not explicitly set, falls back to the provider's default model
func (*Config) GetCommitProvider ¶
GetCommitProvider returns the configured provider for commit message generation. Returns an empty string if no explicit commit provider is set; callers should surface this and offer interactive provider selection.
func (*Config) GetMCPTimeout ¶
GetMCPTimeout returns the MCP timeout as a time.Duration
func (*Config) GetModelForProvider ¶
GetModelForProvider returns the configured model for a provider. Returns an empty string if no model is configured for the provider; callers handle this by running model selection against the live provider API.
func (*Config) GetRefreshSystemPromptOnModelChange ¶ added in v0.17.7
GetRefreshSystemPromptOnModelChange (Spec B) reports whether the agent should re-derive its system prompt on every provider/model swap instead of freezing it at agent-creation time.
When false (the default), the prompt is set once in initAgentFromResolvedProvider and never touched on subsequent SetProvider/SetModel calls. This preserves bit-identical behavior for existing sessions that may have observed and relied on a particular prompt composition.
When true, the agent's refreshSystemPrompt() (called from setClient) re-runs GetEmbeddedSystemPromptForProfile against the active provider and context window. The configured SystemPromptText override still wins — only the embedded portion is re-derived.
This getter exists alongside the field so call sites read through a stable accessor (and so future migrations can change the storage shape without touching every read site). A nil-safe return of false matches the field's zero-value default and keeps bare Config literals in tests working without explicit initialization.
func (*Config) GetReviewModel ¶
GetReviewModel returns the configured model for review commands If not explicitly set, falls back to the provider's default model
func (*Config) GetReviewProvider ¶
GetReviewProvider returns the configured provider for review commands. Returns an empty string if no explicit review provider is set; callers should surface this and offer interactive provider selection.
func (*Config) GetSkill ¶
GetSkill retrieves a skill configuration by ID Returns nil if the skill doesn't exist or is disabled
func (*Config) GetSkillPath ¶
GetSkillPath returns the full path to a skill directory
func (*Config) GetSubagentMaxDepth ¶
GetSubagentMaxDepth returns the maximum subagent nesting depth. Defaults to 2 if not configured or set to 0.
func (*Config) GetSubagentMaxParallel ¶
GetSubagentMaxParallel returns the maximum number of parallel subagents Defaults to 2 if not configured or set to 0
func (*Config) GetSubagentModel ¶
GetSubagentModel returns the configured model for subagents If not explicitly set, falls back to the provider's default model
func (*Config) GetSubagentParallelEnabled ¶
GetSubagentParallelEnabled returns whether parallel subagent execution is enabled Defaults to true if not explicitly set (nil pointer)
func (*Config) GetSubagentProvider ¶
GetSubagentProvider returns the configured provider for subagents. Returns an empty string if no explicit subagent provider is set; callers inherit from the parent agent's provider or treat empty as a signal that no explicit subagent provider is configured.
func (*Config) GetSubagentType ¶
func (c *Config) GetSubagentType(id string) *SubagentType
GetSubagentType retrieves a subagent type configuration by ID or alias. Personas are catalog-fixed (loaded from pkg/personas/configs/*.json at startup) — there is no user-override merge path. Returns nil if the persona does not exist or has been disabled via Config.DisabledPersonas.
func (*Config) GetSubagentTypeModel ¶
GetSubagentTypeModel returns the model for a specific subagent type Falls back to the general subagent model if not specified
func (*Config) GetSubagentTypeProvider ¶
GetSubagentTypeProvider returns the provider for a specific subagent type Falls back to the general subagent provider if not specified
func (*Config) IsPersonaDisabled ¶ added in v0.16.4
IsPersonaDisabled reports whether the given persona ID has been disabled by the user (via /persona <id> disable). The canonical ID after alias resolution is matched; a disabled persona is returned as nil by GetSubagentType and filtered from GetAvailablePersonaIDs.
func (*Config) SaveToDir ¶
SaveToDir saves the configuration to a specific directory, bypassing GetConfigPath() (which reads the SPROUT_CONFIG/LEDIT_CONFIG env vars). Use this when a Manager has an explicit configDir so that saves go to the correct location even after the env var has been restored.
func (*Config) SetCommitModel ¶
SetCommitModel sets the model for commit message generation
func (*Config) SetCommitProvider ¶
SetCommitProvider sets the provider for commit message generation
func (*Config) SetModelForProvider ¶
SetModelForProvider sets the model for a specific provider. The test provider is silently rejected to prevent it from leaking into the persisted config via direct Config access.
func (*Config) SetPersonaDisabled ¶ added in v0.16.4
SetPersonaDisabled adds or removes a persona ID from DisabledPersonas. Idempotent; aliases are normalized to the canonical form before storage.
func (*Config) SetReviewModel ¶
SetReviewModel sets the model for review commands
func (*Config) SetReviewProvider ¶
SetReviewProvider sets the provider for review commands
func (*Config) SetSubagentModel ¶
SetSubagentModel sets the model for subagents
func (*Config) SetSubagentProvider ¶
SetSubagentProvider sets the provider for subagents
type ConfigConflictError ¶
type ConfigConflictError struct {
// Path is the absolute path of the config file.
Path string
// LoadedModTime / LoadedSize is what the in-memory Config remembers
// from when it was last loaded.
LoadedModTime time.Time
LoadedSize int64
// CurrentModTime / CurrentSize is what's on disk right now.
CurrentModTime time.Time
CurrentSize int64
}
ConfigConflictError is returned from Config.Save when the on-disk config file has been modified since the in-memory Config was last loaded. Indicates another writer (another agent process, another webui tab, a hand-edit) changed the file out from under us.
SP-034-4b. Callers should surface this to the user with a "Settings changed on disk" prompt and offer to reload before retrying.
func (*ConfigConflictError) Error ¶
func (e *ConfigConflictError) Error() string
Error satisfies the error interface. Format is stable and parsed by the webui's `config_conflict` error mapper — don't reorganize fields without coordinating with `pkg/webui/websocket_message_handlers.go`.
type ContextMode ¶ added in v0.17.7
type ContextMode string
ContextMode is the user-facing context-engine selector. The empty string ("") is treated identically to "full" for resolution — it's the zero value of the field and must be safe to leave unset. Persisted as json:"context_mode,omitempty"; any value that doesn't match one of the two named constants falls through to auto-detection via ResolveContextProfile (so a typo in the config file degrades gracefully to the default rather than becoming a hard error).
const ( // ContextModeFull is the default sprout mode: all 44 tools, the full // orchestrator system prompt, project AGENTS.md injected, proactive // context enabled, and the standard compaction trigger (0.70). // Resolved by passing a zero-value ContextProfile — every lever // reads as empty/zero/false and downstream code already treats that // as "use built-in default". ContextModeFull ContextMode = "full" // ContextModeLowContext activates the LCM levers (curated 8-tool // allowlist, lite prompt, no proactive context, compaction trigger // 0.85, recency 2, repo-map depth 1). AGENTS.md is still injected // (project conventions are mandatory in every mode). Activated // explicitly via config, or auto-detected when the selected model // reports a context window below SubagentMinContext (64K). ContextModeLowContext ContextMode = "low_context" )
type ContextProfile ¶ added in v0.17.7
type ContextProfile struct {
Mode ContextMode `json:"mode,omitempty"`
ToolAllowlist []string `json:"tool_allowlist,omitempty"`
SystemPromptPath string `json:"system_prompt_path,omitempty"`
SkipProactiveContext bool `json:"skip_proactive_context,omitempty"`
CompactionTriggerFraction float64 `json:"compaction_trigger_fraction,omitempty"`
RecentTurnsToPreserve int `json:"recent_turns_to_preserve,omitempty"`
RepoMapDefaultDepth int `json:"repo_map_default_depth,omitempty"`
}
ContextProfile is the resolved shape of every context-engine lever. Constructed exactly once via ResolveContextProfile at agent creation and read downstream at every call site that depends on it. A zero value is intentionally safe and means "use all defaults" — i.e. full mode, no overrides.
Field semantics:
Mode: which preset was selected (Full vs LowContext). Call sites that want to branch on *intent* read this; call sites that want to branch on *behavior* read the boolean/value fields below.
ToolAllowlist: if non-empty, downstream tool registration filters BuildToolDefinitions to only these names. Order is preserved when exposed to the model. Empty means "all tools available" — the zero/full default.
SystemPromptPath: the embedded prompt path to load (relative to pkg/agent/prompts). Empty means use the default full prompt; downstream code maps the path suffix to the right //go:embed variable. The two currently-known values are "prompts/system_prompt.md" (default, empty string equivalent) and "prompts/system_prompt.lite.md" (LCM).
SkipProactiveContext: when true, downstream prompt builders skip the semantically-recalled prior-turn block injected after turn 1. Disables cross-session recall in this session.
CompactionTriggerFraction: when non-zero, overrides the default trigger fraction (1.0 - totalReservedFraction(), 0.70 in full mode). LCM uses 0.85 to push compaction closer to the window edge so the model has more working room per turn.
RecentTurnsToPreserve: when non-zero, overrides the default recent-turn count kept at full fidelity during rollups (default 5 in full mode). LCM uses 2 because LCM sessions are short (2–4 round-trips) and the recency window is almost the whole conversation.
RepoMapDefaultDepth: when non-zero, overrides the default depth passed to repo_map (default 3 in full mode). LCM uses 1 (directory tree only, no symbols) to keep repo_map output under ~800 tokens.
func ResolveContextProfile ¶ added in v0.17.7
func ResolveContextProfile(cfg *Config, modelContextWindow int) (ContextProfile, error)
ResolveContextProfile picks the effective profile from the user's config plus the detected model context window. Called once at agent creation; the result is stored on the Agent and read by every downstream call site.
Precedence (highest first):
Hard floor — if modelContextWindow is a known positive value below ContextFloor (8K), return an error. This is unconditional: even explicit "full" cannot rescue the session because no amount of lever-pulling fits prompt + one tool round-trip + a response below ~4K tokens. The caller is expected to surface the error to the user.
Explicit cfg.ContextMode — "low_context" or "full" both win outright over auto-detection. A user who explicitly sets the field has overridden any window-based guess.
Auto-detect — a known context window below subagentContextThreshold (64K) flips LCM on with a strong warning (callers can detect the auto-detect case by comparing the returned Mode to what cfg requested, or via a future explicit-notice hook).
Default — fullContextProfile. Applies when cfg is nil, when cfg.ContextMode is empty or unrecognized, or when the model context window is unknown (0 / negative).
Both cfg==nil and modelContextWindow<=0 are tolerated — those are the "we don't know yet" inputs and they must not error. They resolve to the full preset (step 4).
type CustomProviderConfig ¶
type CustomProviderConfig struct {
Name string `json:"name"`
Endpoint string `json:"endpoint"`
ModelName string `json:"model_name"`
ContextSize int `json:"context_size"` // Default context size for provider
ModelContextSizes map[string]int `json:"model_context_sizes,omitempty"` // Per-model context sizes (e.g., "my-model": 131072)
ReasoningEffort string `json:"reasoning_effort,omitempty"` // Optional provider-specific reasoning effort override
Temperature *float64 `json:"temperature,omitempty"` // Optional default temperature
TopP *float64 `json:"top_p,omitempty"` // Optional default top_p
Parameters map[string]interface{} `json:"parameters,omitempty"` // Optional provider-specific default parameters
RequiresAPIKey bool `json:"requires_api_key"`
ToolCalls []string `json:"tool_calls,omitempty"` // Optional explicit tool allowlist; when set, only these tools are exposed
EnvVar string `json:"env_var,omitempty"` // Environment variable name for API key
ChunkTimeoutMs int `json:"chunk_timeout_ms,omitempty"` // Streaming chunk timeout in milliseconds
Conversion providers.MessageConversion `json:"message_conversion,omitempty"` // Message conversion configuration
SupportsVision bool `json:"supports_vision,omitempty"` // Whether this provider supports vision requests
VisionModel string `json:"vision_model,omitempty"` // Vision-capable model for this provider
VisionFallbackProvider string `json:"vision_fallback_provider,omitempty"` // Optional fallback provider for vision
VisionFallbackModel string `json:"vision_fallback_model,omitempty"` // Optional fallback model for vision provider
BillingType string `json:"billing_type,omitempty"` // Billing model: pay_per_token (default), subscription, free
}
CustomProviderConfig represents a custom model provider configuration
func NormalizeCustomProviderConfig ¶
func NormalizeCustomProviderConfig(cfg CustomProviderConfig) (CustomProviderConfig, error)
NormalizeCustomProviderConfig fills in defaults, trims whitespace, and rejects ill-formed values. Called by Save and Load paths so a hand-edited JSON file cannot put the runtime into a state where discovery silently fails later.
func (CustomProviderConfig) ModelsEndpoint ¶
func (c CustomProviderConfig) ModelsEndpoint() string
func (CustomProviderConfig) ToProviderConfig ¶
func (c CustomProviderConfig) ToProviderConfig() (*providers.ProviderConfig, error)
type EditApprovalConfig ¶ added in v0.16.12
type EditApprovalConfig struct {
Mode string `json:"mode,omitempty"`
Paths []string `json:"paths,omitempty"`
// ShellCommand enables per-part shell approval prompts (SP-093-2).
// When true, a multi-part shell command is split and each part is
// approved individually via Agent.RequestShellApproval. Default: false,
// which preserves the existing 4-option prompt for the whole command.
ShellCommand bool `json:"shell_command,omitempty" yaml:"shell_command,omitempty"`
}
EditApprovalConfig controls the per-hunk diff approval gate (SP-072).
func (*EditApprovalConfig) Resolve ¶ added in v0.16.12
func (c *EditApprovalConfig) Resolve() EditApprovalConfig
func (*EditApprovalConfig) ShouldGate ¶ added in v0.16.12
func (c *EditApprovalConfig) ShouldGate(path string) bool
type EmbeddingIndexConfig ¶
type EmbeddingIndexConfig struct {
// Enabled controls whether the embedding index is active.
Enabled bool `json:"enabled,omitempty"`
// IndexDir is the directory where the embedding index JSONL files are stored.
// If empty, uses ~/.config/sprout/embeddings/
IndexDir string `json:"index_dir,omitempty"`
// SimilarityThreshold is the cosine similarity threshold for duplicate detection.
// Range: 0.0 to 1.0. Default: 0.90
SimilarityThreshold float32 `json:"similarity_threshold,omitempty"`
// MaxResults is the maximum number of duplicate candidates to return.
// Default: 3
MaxResults int `json:"max_results,omitempty"`
// AutoIndex controls whether the index is built automatically on first use.
// Default: true
AutoIndex bool `json:"auto_index,omitempty"`
// ExcludePaths is a list of additional paths to exclude from indexing.
ExcludePaths []string `json:"exclude_paths,omitempty"`
}
EmbeddingIndexConfig configures the embedding-based duplicate detection and semantic search.
type KnownProviderInfo ¶ added in v0.16.25
type KnownProviderInfo struct {
// Source identifies where the metadata came from.
// "custom" = user's ~/.config/sprout/providers/<name>.json
// "factory" = embedded config in pkg/agent_providers/configs/
// or upserted via refreshFromRemote
Source string
// Name is the canonical provider name (lowercase, trimmed).
Name string
// DisplayName is the friendly label shown in UI surfaces.
DisplayName string
// EnvVar is the environment variable the provider expects for
// authentication (e.g. "OPENAI_API_KEY"). Empty when no auth
// is required.
EnvVar string
// RequiresAPIKey reports whether the provider needs an API key.
RequiresAPIKey bool
// Endpoint is the chat endpoint URL when known.
Endpoint string
// DefaultModel is the configured default model when known.
DefaultModel string
// ContextSize is the configured default context size in tokens.
ContextSize int
}
KnownProviderInfo describes a provider the runtime already knows about, either from the user's custom provider config or the embedded factory. The `sprout custom add` wizard uses this to detect when a user is "registering credentials for an existing provider" rather than "registering a brand-new OpenAI-compatible endpoint".
func LookupKnownProvider ¶ added in v0.16.25
func LookupKnownProvider(name string) (info KnownProviderInfo, ok bool)
LookupKnownProvider returns metadata for a provider the runtime knows about, checking both the user's custom provider config and the embedded factory. Returns ok=false when the name doesn't match any known provider — in which case the wizard should run the full URL/discovery flow.
The factory lookup uses GetProviderAuthMetadata, which the runtime factory populates via SetProviderConfigLookup. This is safe to call from the wizard because configuration init() ensures the package compiles even without a registered factory.
type LanguageServerOverride ¶
type LanguageServerOverride struct {
ID string `json:"id" yaml:"id"` // Unique server ID (e.g. "go", "typescript")
Binary string `json:"binary" yaml:"binary"` // Path to the binary (e.g. "gopls", "typescript-language-server")
Args []string `json:"args,omitempty" yaml:"args,omitempty"` // Command-line arguments (e.g. ["--stdio"])
LanguageIDs []string `json:"language_ids,omitempty" yaml:"language_ids,omitempty"` // Language IDs this server handles (e.g. ["go"])
InstallHint string `json:"install_hint,omitempty" yaml:"install_hint,omitempty"` // Installation instructions
}
LanguageServerOverride allows users to customize or add language server configurations beyond the built-in defaults. When a matching ID exists in the default set, this override replaces it entirely. New IDs are appended to the merged list.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager manages configuration state with safe concurrent access.
func NewManager ¶
NewManager creates a new configuration manager
func NewManagerSilent ¶
NewManagerSilent creates a new configuration manager without showing welcome messages
func NewManagerWithConfig ¶
NewManagerWithConfig creates a new configuration manager from an explicit Config and optional API key set. The manager will persist saves to the same location that config.Save()/Load() would use for the current env (when configDir is empty) or to configDir (when non-empty). Pass nil for apiKeys to skip key loading.
func NewManagerWithDir ¶
NewManagerWithDir creates a configuration Manager fully backed by configDir. If no config file exists in configDir a fresh default one is written so that subsequent Load/Save calls operate deterministically.
This is intended for tests and tooling that need a hermetic config environment without touching the caller's real ~/.config/sprout.
func NewManagerWithLayers ¶
NewManagerWithLayers creates a configuration manager using layered config. globalDir is the directory containing global config (~/.config/sprout/). workspaceDir is the directory containing workspace config ({workspace}/.sprout/). Each layer is optional - missing layers are skipped. Settings writes go to the workspace dir if provided, otherwise global.
func NewTestManager ¶
NewTestManager builds a configuration Manager backed by an isolated temp directory so that tests never read, modify, or create files in the caller's real ~/.config/sprout config. Sets SPROUT_CONFIG + LEDIT_CONFIG to that temp dir via t.Setenv so any code path that uses GetConfigPath() (rather than the Manager) lands in the temp dir too.
Returns the Manager and a cleanup func (no-op today; reserved for future hooks like Layer 5 detection). Callers should defer cleanup unconditionally to keep the contract stable as the helper grows.
Usage:
mgr, cleanup := configuration.NewTestManager(t) defer cleanup()
This helper lives in a non-_test.go file so packages outside `configuration` can import it. Inside the configuration package it is treated like any other helper.
func (*Manager) AddMCPServer ¶
func (m *Manager) AddMCPServer(name string, server mcp.MCPServerConfig) error
AddMCPServer adds an MCP server configuration
func (*Manager) EnrichCustomProviders ¶
func (m *Manager) EnrichCustomProviders()
EnrichCustomProviders loads custom provider files from the global providers directory into the config. This is needed before provider name lookups because config.json never stores custom providers directly.
func (*Manager) EnsureAPIKey ¶
func (m *Manager) EnsureAPIKey(clientType api.ClientType) error
EnsureAPIKey ensures a provider has an API key, prompting if needed
func (*Manager) GetAPIKeyForProvider ¶
func (m *Manager) GetAPIKeyForProvider(clientType api.ClientType) string
GetAPIKeyForProvider returns the API key for a provider
func (*Manager) GetAPIKeys ¶
GetAPIKeys returns the current API keys
func (*Manager) GetAvailableProviders ¶
func (m *Manager) GetAvailableProviders() []api.ClientType
GetAvailableProviders returns all providers that can be used
func (*Manager) GetConfigDir ¶
GetConfigDir returns the stored config directory for this manager. Returns empty string if the manager uses the default (env-based) location.
func (*Manager) GetMCPConfig ¶
GetMCPConfig returns the MCP configuration
func (*Manager) GetModelForProvider ¶
func (m *Manager) GetModelForProvider(clientType api.ClientType) string
GetModelForProvider returns the model for the given provider
func (*Manager) GetProvider ¶
func (m *Manager) GetProvider() (api.ClientType, error)
GetProvider returns the currently selected provider as ClientType
func (*Manager) HasAPIKey ¶
func (m *Manager) HasAPIKey(clientType api.ClientType) bool
HasAPIKey checks if a provider has an API key
func (*Manager) MapStringToClientType ¶
func (m *Manager) MapStringToClientType(s string) (api.ClientType, error)
MapStringToClientType converts string to ClientType, handling custom providers
func (*Manager) RefreshAPIKeys ¶
RefreshAPIKeys reloads API keys from the backend into the in-memory cache. This must be called after any external mutation of the credential backend (e.g., ValidateAndSaveAPIKey) to keep the Manager's in-memory map in sync.
func (*Manager) Reload ¶
Reload re-reads the on-disk configuration and API keys into the in-memory cache. It is intended to be called from a SIGHUP handler so that config changes made externally (e.g., editing config.yaml) take effect without restarting the daemon. Running agents and tools are NOT affected — only subsequent queries will see the new configuration.
func (*Manager) ResolveProviderModel ¶
func (m *Manager) ResolveProviderModel(explicitProvider, explicitModel string) (api.ClientType, string, error)
ResolveProviderModel resolves provider+model selection using canonical precedence.
func (*Manager) SaveAPIKeys
deprecated
SaveAPIKeys saves the API keys to disk.
Deprecated: This performs a blind write with no validation. Use ValidateAndSaveAPIKey instead, which validates the key before saving and preserves the old key on validation failure. This method is retained for backward compatibility only.
func (*Manager) SaveConfig ¶
SaveConfig saves the configuration to disk
func (*Manager) SelectNewProvider ¶
func (m *Manager) SelectNewProvider() (api.ClientType, error)
SelectNewProvider allows interactive provider selection
func (*Manager) SetMCPEnabled ¶
SetMCPEnabled enables or disables MCP
func (*Manager) SetModelForProvider ¶
func (m *Manager) SetModelForProvider(clientType api.ClientType, model string) error
SetModelForProvider sets the model for a provider
func (*Manager) SetProvider ¶
func (m *Manager) SetProvider(clientType api.ClientType) error
SetProvider sets the current provider
func (*Manager) UpdateConfig ¶
UpdateConfig mutates the live config under lock and persists it to disk.
type MigrationFunc ¶
MigrationFunc transforms a raw JSON config from one version to the next. It receives and returns a map[string]interface{} representing the parsed config JSON. The function should set "version" to the target version on success.
type NotificationsConfig ¶ added in v0.16.12
type NotificationsConfig struct {
// CLIBell emits a terminal bell (\a) on completion.
CLIBell bool `json:"cli_bell,omitempty"`
// OSNotify fires an OS-level desktop notification on completion.
OSNotify bool `json:"os_notify,omitempty"`
// Browser fires a browser notification (used by WebUI, SP-070-4).
Browser bool `json:"browser,omitempty"`
// MinSeconds is the minimum turn duration (in seconds) before a
// notification is sent. Default: 10.0. Turns completing in less
// than this are considered too brief to warrant a notification.
MinSeconds float64 `json:"min_seconds,omitempty"`
}
NotificationsConfig controls how the agent notifies the user when long-running turns complete (SP-070).
func (*NotificationsConfig) Resolve ¶ added in v0.16.12
func (c *NotificationsConfig) Resolve() NotificationsConfig
Resolve returns a copy with defaults filled in for zero-value fields.
type PersistentContextConfig ¶
type PersistentContextConfig struct {
// ProactiveContextEnabled controls whether the system primes new sessions with
// relevant past work via semantic retrieval from conversation history.
// Default: true
ProactiveContextEnabled bool `json:"proactiveContextEnabled,omitempty"`
// MaxContextualResults is the maximum number of past turns to retrieve for context.
// Default: 5
MaxContextualResults int `json:"maxContextualResults,omitempty"`
// MinRelevanceScore is the minimum time-decayed cosine similarity score for retrieval.
// Range: 0.0 to 1.0. Results below this score are filtered out.
// Default: 0.50
MinRelevanceScore float64 `json:"minRelevanceScore,omitempty"`
// MaxContextChars is the hard cap on total injected character count for context.
// Default: 4000
MaxContextChars int `json:"maxContextChars,omitempty"`
// WorkspaceScopedRetrieval restricts retrieval to turns from the current workspace only.
// When false (default), retrieval searches across all workspaces.
// Default: false
WorkspaceScopedRetrieval bool `json:"workspaceScopedRetrieval,omitempty"`
// DriftDetectionEnabled controls whether conversational drift detection is active.
// When enabled, the system checks if the conversation has drifted from its original intent.
// Default: true
DriftDetectionEnabled bool `json:"driftDetectionEnabled,omitempty"`
// DriftThreshold is the cosine similarity threshold below which drift is flagged.
// Range: 0.0 to 1.0. Lower values require more divergence before flagging.
// Default: 0.60
DriftThreshold float64 `json:"driftThreshold,omitempty"`
// DriftCheckInterval is the number of turns between drift checks.
// For example, 5 means drift is checked on turns 5, 10, 15, etc.
// Default: 5
DriftCheckInterval int `json:"driftCheckInterval,omitempty"`
// RetentionDays controls how many days to keep persistent context entries.
// Default: 0 (never expire). Set to a positive value to automatically clean
// up entries older than the specified number of days at agent startup.
RetentionDays int `json:"retentionDays,omitempty"`
}
PersistentContextConfig configures persistent conversational context and memory retrieval.
func (*PersistentContextConfig) Resolve ¶
func (c *PersistentContextConfig) Resolve() PersistentContextConfig
Resolve returns a copy of the config with default values filled in for any zero-value fields. Use this after loading from disk to ensure sensible defaults. If the receiver is nil, returns a fully-defaulted config.
type ProviderAuthMetadata ¶
type ProviderAuthMetadata struct {
Provider string
DisplayName string
RequiresAPIKey bool
EnvVar string
AuthType string
}
func GetProviderAuthMetadata ¶
func GetProviderAuthMetadata(provider string) (ProviderAuthMetadata, error)
type ProviderConfigLookupFunc ¶ added in v0.16.8
ProviderConfigLookupFunc returns the env-var and auth-type for a runtime provider config — typically backed by the global provider factory, which merges embedded, filesystem, and remote (GitHub Pages) sources. Returns ok=false when the provider is not present in the runtime view.
type ProviderDiscoveryModel ¶
type ProviderDiscoveryModel struct {
ID string `json:"id"`
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
ContextLength int `json:"context_length,omitempty"`
Tags []string `json:"tags,omitempty"`
}
func DiscoverCustomProviderModels ¶
func DiscoverCustomProviderModels(cfg CustomProviderConfig) ([]ProviderDiscoveryModel, error)
type ProviderDisplayNameLookupFunc ¶ added in v0.16.8
ProviderDisplayNameLookupFunc returns the user-facing label for a provider — sourced from the runtime config's display_name field. Returns ok=false when the provider is unknown to the runtime view or when its display_name is blank (so callers fall through to the static map / raw-id fallback).
type ProviderNamesLookupFunc ¶ added in v0.16.8
type ProviderNamesLookupFunc func() []string
ProviderNamesLookupFunc returns the full set of provider names known to the runtime — typically the global factory's view, which includes embedded, filesystem, and remote (GitHub Pages) registrations.
type RevisionRetentionConfig ¶
type RevisionRetentionConfig struct {
// HotCount: most recent N revisions kept verbatim (full
// conversation.json + instructions + llm_response + all change
// payloads). Fast view_history + full recovery. Default: 200.
HotCount int `json:"hot_count,omitempty"`
// WarmCount: next M revisions after the hot tier. conversation.json
// dropped; instructions + response + change payloads kept. Recovery
// still works; conversation context lost. Default: 500.
WarmCount int `json:"warm_count,omitempty"`
// MaxDirBytes is the long-stop cap on total revisions+changes
// disk usage per workspace. If the count-based tiering still
// leaves the directory over this size, trim oldest warm entries
// until under cap. Default: 1 GiB (1073741824).
MaxDirBytes int64 `json:"max_dir_bytes,omitempty"`
// ArchiveFrozen: if true, dropped revisions are moved to
// .sprout/revisions/_frozen/ instead of being deleted outright.
// Opt-in safety net for users who want a recoverable record of
// long-tail history at the cost of unbounded growth. Default: false.
ArchiveFrozen bool `json:"archive_frozen,omitempty"`
// MaxChangesPerRevision caps the number of change records kept per
// revision in .sprout/changes/. A single runaway session (e.g. an
// agent that `cd`'d into $HOME so a shell walk classified
// pre-existing files as creates) can produce tens of thousands of
// records; without this cap, count bloat persists even when total
// bytes are under MaxDirBytes. Default: 10000.
MaxChangesPerRevision int `json:"max_changes_per_revision,omitempty"`
// MaxChangesAgeDays drops change records older than this number of
// days regardless of their parent revision's tier. Belt-and-
// suspenders against changes/ accumulating inside the hot window.
// Default: 30. Set to a negative value to disable.
MaxChangesAgeDays int `json:"max_changes_age_days,omitempty"`
}
RevisionRetentionConfig controls the quantity-based compaction of the persistent revision history. Two retained tiers plus a drop threshold:
- hot: the most recent N revisions kept verbatim
- warm: the next M revisions with conversation.json dropped
- drop: anything older is removed entirely
The ChangeTracker is a short-horizon stop-gap (recover from a bad sed -i, undo a hasty rm), not a long-term audit log — that's what git is for. Once a revision falls out of warm, the user has either committed the work or wasn't going to recover it anyway, and the disk space is better spent on hot data.
See AGENTS.md "Change Tracking" for context.
func (*RevisionRetentionConfig) Resolve ¶
func (c *RevisionRetentionConfig) Resolve() RevisionRetentionConfig
Resolve fills in defaults for any zero-value fields and returns a fully-populated retention config. Safe to call on nil — yields all-defaults.
type RiskLevel ¶
type RiskLevel string
RiskLevel represents the risk classification of an operation for the EA approval cascade.
const ( RiskLevelLow RiskLevel = "low" // Auto-approve (git status, read operations) RiskLevelMedium RiskLevel = "medium" // Reason and decide (git commit, git push) RiskLevelHigh RiskLevel = "high" // Prompt the user when interactive; reject when not RiskLevelCritical RiskLevel = "critical" // Never approvable: rm -rf root, fork bombs )
func MoreRestrictiveRiskLevel ¶ added in v0.16.7
MoreRestrictiveRiskLevel returns whichever of a or b gates harder. Ties return a. This is the combinator the unified resolver uses to fold multiple risk sources (classifier, persona cascade, git/fs/workspace gates) into one verdict.
func (RiskLevel) IsAtLeast ¶ added in v0.16.7
IsAtLeast reports whether r is at least as severe as other.
func (RiskLevel) Rank ¶ added in v0.16.7
Rank returns the severity ordering of a risk level:
Low(0) < Medium(1) < High(2) < Critical(3)
An empty or unrecognized level ranks as Medium — the same safe default the persona cascade already applies to unmatched operations — so an unknown value can never silently sort below a known one.
type RiskProfile ¶
type RiskProfile string
RiskProfile names a preset risk-cascade configuration. The active profile resolves to an AutoApproveRules via AutoApproveRulesForProfile. Persona-specified rules always take precedence over the profile.
const ( // RiskProfileReadonly — strictest. ONLY read operations (git // status / log / diff, read_file) are permitted. Every write, // edit, shell command, or destructive op is BLOCKED outright // (no prompt path) by promoting to the Critical tier. Use for // audits, code review, or sandboxed inspection where the agent // should never mutate anything. RiskProfileReadonly RiskProfile = "readonly" // RiskProfileCautious — most operations prompt the user. Suitable // for sensitive workspaces or unfamiliar agents. Low-risk reads // auto-approve; everything else gets routed to a prompt. RiskProfileCautious RiskProfile = "cautious" // RiskProfileDefault — sane defaults matching the historical EA // cascade. Reads auto-approve, common edits/commits auto-approve, // destructive operations (force flags, rm -rf, lossy git) prompt. RiskProfileDefault RiskProfile = "default" // RiskProfilePermissive — high trust. Almost everything passes // without prompting; only truly destructive patterns route to a // prompt. Use when the agent is well-trusted and the workspace // is recoverable (clean checkout, throwaway dir). RiskProfilePermissive RiskProfile = "permissive" // RiskProfileUnrestricted — no risk cascade gating at all. Only // the Critical tier (rm -rf root, fork bombs) blocks. Use with // extreme care; intended for sandboxed / disposable environments. RiskProfileUnrestricted RiskProfile = "unrestricted" )
type SecurityPolicy ¶
type SecurityPolicy struct {
DefaultAction string `json:"default_action,omitempty"`
Rules []SecurityRule `json:"rules,omitempty"`
AllowedPaths []string `json:"allowed_paths,omitempty"`
DeniedPaths []string `json:"denied_paths,omitempty"`
DeniedCommands []string `json:"denied_commands,omitempty"`
MaxRiskLevel string `json:"max_risk_level,omitempty"`
}
SecurityPolicy defines workspace-level security rules
func DefaultSecurityPolicy ¶
func DefaultSecurityPolicy() *SecurityPolicy
DefaultSecurityPolicy returns a conservative default policy
func LoadSecurityPolicy ¶
func LoadSecurityPolicy(workspaceRoot string) (*SecurityPolicy, error)
LoadSecurityPolicy reads .sprout/security-policy.json from workspaceRoot. If the file doesn't exist, returns nil, nil (no error). Validates that actions and risk levels are recognized values, and normalizes AllowedPaths and DeniedPaths via filepath.Clean.
func (*SecurityPolicy) Evaluate ¶
func (p *SecurityPolicy) Evaluate(command string) SecurityPolicyAction
Evaluate checks the command against rules in order. For each rule, it first tries matching the full command string, then the base command (first word). First matching rule wins. This means a rule like {Pattern: "git", Action: "deny"} will match "git commit" via base matching before a later rule {Pattern: "git commit*", Action: "allow"} gets evaluated.
Place more specific patterns before broader ones to get the intended behavior. If no rule matches, returns DefaultAction converted to SecurityPolicyAction. If DefaultAction is empty, defaults to "prompt".
func (*SecurityPolicy) IsCommandDenied ¶
func (p *SecurityPolicy) IsCommandDenied(command string) bool
IsCommandDenied checks if the base command (first word) matches any entry in DeniedCommands (case-insensitive).
func (*SecurityPolicy) IsPathAllowed ¶
func (p *SecurityPolicy) IsPathAllowed(path string) bool
IsPathAllowed checks whether the given path is allowed by this policy. If AllowedPaths is empty, returns true (no restrictions). Otherwise checks if the cleaned path starts with any of the allowed paths. Also ensures the path is not in DeniedPaths.
NOTE: This uses filepath.Clean for normalization but does NOT resolve symlinks. A symlink from an allowed path to a system directory could bypass this check.
func (*SecurityPolicy) IsPathDenied ¶
func (p *SecurityPolicy) IsPathDenied(path string) bool
IsPathDenied checks if the cleaned path starts with any of the denied paths. Handles parent traversal: if "/etc" is denied, "/etc/passwd" is also denied.
NOTE: This uses filepath.Clean for normalization but does NOT resolve symlinks. A symlink from an allowed path to a system directory could bypass this check.
func (*SecurityPolicy) MaxAllowedRisk ¶
func (p *SecurityPolicy) MaxAllowedRisk() int
MaxAllowedRisk converts MaxRiskLevel string to SecurityRisk int equivalent. "safe"=0, "caution"=1, "dangerous"=2. Defaults to 0 if empty or unrecognized.
type SecurityPolicyAction ¶
type SecurityPolicyAction string
SecurityPolicyAction represents the action to take when a rule matches
const ( PolicyAllow SecurityPolicyAction = "allow" PolicyDeny SecurityPolicyAction = "deny" PolicyPrompt SecurityPolicyAction = "prompt" )
func (SecurityPolicyAction) IsValid ¶
func (a SecurityPolicyAction) IsValid() bool
IsValid returns true if the action is a recognized SecurityPolicyAction value: "allow", "deny", "prompt", or empty string.
type SecurityRule ¶
type SecurityRule struct {
Pattern string `json:"pattern"`
Action string `json:"action"`
Reason string `json:"reason,omitempty"`
}
SecurityRule defines a pattern-based rule for command evaluation
type ShellConfig ¶ added in v0.16.12
type ShellConfig struct {
UserSafePatterns []ShellPattern `json:"user_safe_patterns,omitempty"`
UserDangerousPatterns []ShellPattern `json:"user_dangerous_patterns,omitempty"`
WorkspaceOverlay WorkspaceOverlayConfig `json:"workspace_overlay,omitempty"`
}
ShellConfig holds user-configurable shell permission policy.
func (*ShellConfig) Validate ¶ added in v0.16.12
func (sc *ShellConfig) Validate() error
Validate checks the ShellConfig values and normalizes invalid ones. Returns an error for values that can't be normalized.
type ShellPattern ¶ added in v0.16.12
type ShellPattern struct {
Match string `json:"match"` // prefix string or regex pattern
Kind string `json:"kind"` // "prefix" or "regex"
Reason string `json:"reason,omitempty"` // optional human-readable note
}
ShellPattern is a single user-defined shell classification pattern.
type Skill ¶
type Skill struct {
ID string `json:"id"` // Unique identifier (e.g., "go-best-practices")
Name string `json:"name"` // Human-readable name
Description string `json:"description"` // What this skill provides and when to use it
Path string `json:"path"` // Relative path to skill directory
Enabled bool `json:"enabled"` // Whether this skill is available
Metadata map[string]string `json:"metadata"` // Optional metadata (author, version, etc.)
AllowedTools string `json:"allowed_tools"` // Optional space-delimited list of pre-approved tools
}
Skill defines an Agent Skill that can be loaded into context
type SubagentType ¶
type SubagentType struct {
ID string `json:"id"` // Unique identifier (e.g., "coder", "tester", "debugger")
Name string `json:"name"` // Human-readable name (e.g., "Coder", "Tester")
Description string `json:"description"` // What this subagent specializes in
Provider string `json:"provider"` // Provider for this subagent type (optional, falls back to SubagentProvider)
Model string `json:"model"` // Model for this subagent type (optional, falls back to SubagentModel)
SystemPrompt string `json:"system_prompt"` // Relative path to system prompt file (e.g., "subagent_prompts/coder.md")
SystemPromptText string `json:"system_prompt_text,omitempty"` // Optional inline system prompt text (replaces base prompt entirely)
SystemPromptAppend string `json:"system_prompt_append,omitempty"` // Optional inline text appended to the base or loaded system prompt (for composition)
AllowedTools []string `json:"allowed_tools,omitempty"` // Optional explicit tool allowlist for focused persona behavior
Aliases []string `json:"aliases,omitempty"` // Optional aliases (e.g., "web-scraper")
Enabled bool `json:"enabled"` // Catalog-only: every shipped persona sets this true. Runtime "is this persona usable?" is determined by Config.DisabledPersonas (user) + LocalOnly (env). Kept for catalog hygiene + defense-in-depth in case a future variant ships with a deliberately-disabled entry.
LocalOnly bool `json:"local_only,omitempty"` // Only available in local mode (not cloud)
Delegatable bool `json:"delegatable,omitempty"` // Whether this persona can be used as a subagent (default: true for worker personas, false for orchestrator personas)
AutoApproveRules *AutoApproveRules `json:"auto_approve_rules,omitempty"` // Risk cascade rules for the runtime auto-approve check
// Capabilities is an explicit list of agency grants this persona holds
// (e.g. "git_write"). Replaces sniffing AutoApproveRules to infer what a
// persona is allowed to do. Use HasCapability to query.
Capabilities []string `json:"capabilities,omitempty"`
// CanSpawnNonDelegatable lists otherwise-undelegatable persona IDs that
// this persona may spawn. Replaces the hardcoded EA-spawn-authority
// special-case. The coordinator carries ["orchestrator"] to enable the
// canonical coordinator→orchestrator→specialist chain.
CanSpawnNonDelegatable []string `json:"can_spawn_non_delegatable,omitempty"`
}
SubagentType defines a specialized subagent persona with its own configuration
func (*SubagentType) EvaluateOperationRisk ¶
func (st *SubagentType) EvaluateOperationRisk(command string) RiskLevel
EvaluateOperationRisk determines the risk level of a shell operation based on the persona's auto-approve rules. Returns RiskLevelCritical for absolute-block patterns, otherwise RiskLevelLow, RiskLevelMedium, or RiskLevelHigh per the rules.
func (*SubagentType) GetAutoApproveRules ¶
func (st *SubagentType) GetAutoApproveRules() AutoApproveRules
GetAutoApproveRules returns the auto-approve rules for this persona, falling back to defaults if none are configured. Callers MUST NOT modify the returned struct's slice fields, as they may share backing arrays with the original config.
func (*SubagentType) HasCapability ¶ added in v0.16.4
func (st *SubagentType) HasCapability(name string) bool
HasCapability reports whether the persona declares the given capability name. Comparison is case-insensitive and whitespace-tolerant.
type TrainingConfig ¶ added in v0.17.5
type TrainingConfig struct {
// Endpoint is the URL to push training data to (e.g. http://localhost:8190).
// Sessions are POSTed to {Endpoint}/sessions as JSON.
Endpoint string `json:"endpoint,omitempty"`
// Enabled controls whether training data is collected and pushed.
// ALWAYS false by default — must be explicitly enabled.
Enabled bool `json:"enabled,omitempty"`
// ExcludePaths is a list of working directory prefixes to exclude from
// training data. Sessions whose working directory starts with any of
// these paths are silently skipped.
ExcludePaths []string `json:"exclude_paths,omitempty"`
}
TrainingConfig controls opt-in session recording for training data collection. When enabled, PII-redacted conversation states are pushed to the configured endpoint after each session save.
type VisionConfig ¶ added in v0.16.19
type VisionConfig struct {
// ParallelWorkers caps concurrent in-flight vision requests per
// session. Vision requests are heavyweight (large payloads, slow
// provider round-trips) so this defaults to 3 — independent of the
// generic request_parallelism setting.
//
// Range: 1..32. Values outside this range are clamped in Resolve().
// Set to 0 to fall back to the default (3).
ParallelWorkers int `json:"parallel_workers,omitempty"`
// MaxParallelRequests caps the global number of in-flight vision
// API calls across the entire process. This is independent of
// ParallelWorkers (which is per-session). Default: 8.
MaxParallelRequests int `json:"max_parallel_requests,omitempty"`
// EnableBatchProcessing toggles the multi-image batching layer
// (VISION-4). Default: true.
EnableBatchProcessing bool `json:"enable_batch_processing,omitempty"`
// MaxBatchSize is the maximum number of images sent to the provider
// in a single batched call. Default: 4. Range: 1..8.
MaxBatchSize int `json:"max_batch_size,omitempty"`
}
VisionConfig controls vision-pipeline runtime behavior (SP-103-C3).
All fields are zero-valued by default; Resolve() fills in safe defaults. VisionConfig is consulted at runtime by the parallel OCR worker pool (pkg/agent_tools/vision_parallel.go::getVisionParallelWorkers).
func GetVisionConfig ¶ added in v0.16.19
func GetVisionConfig() VisionConfig
GetVisionConfig returns the raw VisionConfig from the on-disk configuration file. If the config file can't be loaded or the Vision section is absent, returns a zero-valued VisionConfig (all fields are zero). Callers should use Resolve() on the result to fill in defaults, or check individual fields directly (zero means "not set") for precedence-based lookups.
This is a convenience accessor for callers that don't have a Manager instance (e.g., vision_parallel.go::getVisionParallelWorkers).
func (*VisionConfig) Resolve ¶ added in v0.16.19
func (c *VisionConfig) Resolve() VisionConfig
Resolve returns a copy with defaults filled in for zero-value fields.
type WakeupConfig ¶ added in v0.16.19
type WakeupConfig struct {
Enabled bool `json:"enabled"` // Master switch; default false
MaxTokensPerSession int `json:"max_tokens_per_session"` // Hard cap on auto-resume token spend; default 5000
MaxResumesPerSession int `json:"max_resumes_per_session"` // Max auto-resumes before requiring user input; default 10
}
WakeupConfig controls auto-resume behavior for background task completions (SP-108). Stored in config.json under the "wakeup" key.
func DefaultWakeupConfig ¶ added in v0.16.19
func DefaultWakeupConfig() WakeupConfig
DefaultWakeupConfig returns conservative defaults.
type WorkspaceOverlayConfig ¶ added in v0.16.12
type WorkspaceOverlayConfig struct {
// Mode: "tighten_only" (default — only user_dangerous_patterns honored),
// "trusted" (full overlay honored after `sprout policy trust`), or
// "ignore" (workspace policy never loaded).
Mode string `json:"mode,omitempty"`
}
WorkspaceOverlayConfig controls how workspace-rooted policy files are loaded.
Source Files
¶
- api_keys.go
- config.go
- config_api_timeout.go
- config_command_categorize.go
- config_command_policy.go
- config_commit_review.go
- config_domain.go
- config_git_classify.go
- config_heredoc_strip.go
- config_load_save.go
- config_merge.go
- config_migration.go
- config_paths.go
- config_provider_custom.go
- config_risk_profile.go
- config_risk_subagent.go
- config_shell.go
- config_skills.go
- config_subagent.go
- config_subagent_type.go
- config_system_prompt.go
- context_profile.go
- custom_provider_migration.go
- custom_provider_normalize.go
- custom_provider_registry.go
- env.go
- errors.go
- init.go
- isolated_config.go
- manager.go
- manager_load.go
- manager_mcp.go
- manager_provider.go
- manager_save.go
- provider_auth.go
- provider_ordering.go
- provider_resolution.go
- redact.go
- resolve.go
- risk_level.go
- security_policy.go
- skills_allowlist.go
- status_prefix.go
- testing_isolation.go