Documentation
¶
Overview ¶
Package config loads, defaults, persists, and redacts Factor's configuration.
Index ¶
- Constants
- func ChangedSections(a, b *Config) []string
- func DefaultPath() string
- func EnsureWorkspace(workspace string) error
- func Home() string
- func Update(path string, fn func(*Config) error) error
- func Watch(ctx context.Context, baseline *Config, every time.Duration, ...)
- type AgentConfig
- type BrowserConfig
- type BudgetConfig
- type Candidate
- type Config
- func (c *Config) ApplyLogLevel()
- func (c *Config) FilterSecrets(s string) string
- func (c *Config) Get(dottedKey string) (any, error)
- func (c *Config) Path() string
- func (c *Config) RedactedMap() (map[string]any, error)
- func (c *Config) Save() error
- func (c *Config) SecretValues() []string
- func (c *Config) Set(dottedKey string, value any) error
- type CostConfig
- type DesktopConfig
- type GatewayConfig
- type HeartbeatConfig
- type MCPConfig
- type MCPServer
- type MemoryConfig
- type Price
- type ProviderConfig
- type ReasoningConfig
- type ToolsConfig
- type UpgradeConfig
Constants ¶
const Version = 1
Variables ¶
This section is empty.
Functions ¶
func ChangedSections ¶ added in v0.26.0
ChangedSections names the top-level sections whose content differs — "provider", "channels.voice" — which is what the reload log and the "config change applied" notice report back.
func EnsureWorkspace ¶
EnsureWorkspace creates the workspace layout and default bootstrap files.
Bootstrap files belong to the user, so an upgrade must not clobber a persona or an instruction set someone wrote by hand. It may, however, carry an improved default to an install that never edited the old one: a file whose bytes still match a superseded default is replaced, everything else is left exactly as it is.
func Update ¶
Update atomically load-modifies-saves the config FILE. The live in-memory Config is deliberately immutable after startup (concurrent turns read it lock-free); durable changes go through here, and the gateway's Watch is what turns the saved file back into running state — by reloading the process, not by mutating what concurrent readers hold.
func Watch ¶ added in v0.26.0
func Watch(ctx context.Context, baseline *Config, every time.Duration, onChange func(*Config, []string))
Watch polls the file baseline was loaded from and calls onChange with the freshly loaded configuration — and the names of the sections that differ — whenever its content changes into something loadable. A file that cannot be loaded (a half-saved edit, a syntax error) is warned about once and retried on the next tick, so a bad save never takes the running config down. Blocks until ctx ends; run it on its own goroutine.
Types ¶
type AgentConfig ¶
type AgentConfig struct {
Workspace string `json:"workspace" env:"FACTOR_WORKSPACE"`
MaxToolIterations int `json:"max_tool_iterations" env:"FACTOR_MAX_TOOL_ITERATIONS"`
MaxConcurrentTurns int `json:"max_concurrent_turns"`
// ContextWindowTokens caps the window compaction budgets against. 0 means
// auto: the model catalog answers per model. A set value can only shrink
// what the catalog says, and stands alone for models it does not carry.
ContextWindowTokens int `json:"context_window_tokens"`
SummarizeAtPercent int `json:"summarize_at_percent"`
// MaxContextTokens is the working ceiling for one assembled request,
// independent of what the model would accept. Quality falls off long
// before a window is full, so a model with a huge window still answers
// better from a small context than a large one — and a percentage of a
// million-token window is not a budget at all. 0 means the default.
MaxContextTokens int `json:"max_context_tokens"`
KeepRecentMessages int `json:"keep_recent_messages"`
ExtraInstructions string `json:"extra_instructions,omitempty"`
}
type BrowserConfig ¶
type BrowserConfig struct {
Enabled bool `json:"enabled"`
AttachURL string `json:"attach_url,omitempty" env:"FACTOR_BROWSER_ATTACH_URL"`
Command string `json:"command,omitempty"`
Headless bool `json:"headless"`
NoSandbox bool `json:"no_sandbox"` // needed as root, in containers, and where user namespaces are restricted
UserDataDir string `json:"user_data_dir,omitempty"`
// FastPath adds a second, much lighter engine that only reads pages.
// Off unless asked for: it is a whole extra browser to install, and the
// full suite already reads pages perfectly well.
FastPath bool `json:"fast_path"`
FastCommand string `json:"fast_command,omitempty"`
}
BrowserConfig controls the CDP browser integration. With AttachURL empty, Factor probes the standard DevTools port and falls back to launching a managed instance (visible unless Headless).
type BudgetConfig ¶ added in v0.19.0
type BudgetConfig struct {
SessionUSD float64 `json:"session_usd" env:"FACTOR_BUDGET_SESSION_USD"`
GlobalUSD float64 `json:"global_usd" env:"FACTOR_BUDGET_GLOBAL_USD"`
Period string `json:"period"` // day | month | total
}
BudgetConfig caps spend. Zero is no cap, on both scopes: a budget that starts refusing turns is something you ask for, never something you inherit. Period says what "global" counts — this day, this month, or everything Factor has ever spent.
func (BudgetConfig) Off ¶ added in v0.19.0
func (b BudgetConfig) Off() bool
Off reports that neither cap is set.
type Candidate ¶
type Candidate struct {
Type string `json:"type"`
APIKey string `json:"api_key,omitempty"`
APIBase string `json:"api_base,omitempty"`
Model string `json:"model"`
Reasoning *ReasoningConfig `json:"reasoning,omitempty"`
}
Candidate identifies one provider+model combination in the failover chain. A nil Reasoning inherits the provider-level setting.
type Config ¶
type Config struct {
ConfigVersion int `json:"version"`
Agent AgentConfig `json:"agent"`
Provider ProviderConfig `json:"provider"`
Memory MemoryConfig `json:"memory"`
Channels map[string]json.RawMessage `json:"channels,omitempty"`
MCP MCPConfig `json:"mcp"`
Tools ToolsConfig `json:"tools"`
Desktop DesktopConfig `json:"desktop"`
Browser BrowserConfig `json:"browser"`
Heartbeat HeartbeatConfig `json:"heartbeat"`
Gateway GatewayConfig `json:"gateway"`
Upgrade UpgradeConfig `json:"upgrade"`
Cost CostConfig `json:"cost"`
// LogLevel is the lowest severity that reaches the log: "debug", "info"
// (the default), "warn", or "error". Debug is where the per-decision
// detail lives — which profile a voice matched and how closely, how long
// an utterance was, a memory write that was dropped — too noisy for a
// normal run and the first thing wanted when one goes wrong.
LogLevel string `json:"log_level,omitempty" env:"FACTOR_LOG_LEVEL"`
// contains filtered or unexported fields
}
Config is the root configuration. Channel sections stay raw JSON so connectors can define and decode their own config without touching core.
func Load ¶
Load reads the config file (DefaultPath when path is empty), overlays it on defaults, then applies FACTOR_* environment overrides.
func ReadFile ¶
ReadFile returns a fresh file-backed copy (no env overlay), for introspection consistent with what Update sees.
func (*Config) ApplyLogLevel ¶ added in v0.26.0
func (c *Config) ApplyLogLevel()
ApplyLogLevel installs log_level process-wide. It moves the default handler's threshold rather than replacing the handler, so the log keeps the format every other line is already written in — and so Factor's slog.Debug calls, which Go's default drops on the floor, become reachable at all. An unrecognized name is reported and left at info rather than silencing the log over a typo.
func (*Config) FilterSecrets ¶
FilterSecrets replaces occurrences of secret values in s with a placeholder.
func (*Config) Get ¶
Get returns the (secret-redacted) value at a dotted path, e.g. "provider.model" or "" for the whole config.
func (*Config) RedactedMap ¶
RedactedMap returns the config as a generic map with secret-looking values masked.
func (*Config) SecretValues ¶
SecretValues returns every configured secret worth filtering out of output.
type CostConfig ¶ added in v0.19.0
type CostConfig struct {
Track bool `json:"track"`
Budget BudgetConfig `json:"budget"`
Prices map[string]Price `json:"prices,omitempty"` // model id -> USD per million tokens
PricesURL string `json:"prices_url,omitempty"`
RefreshHours int `json:"refresh_hours"`
}
CostConfig turns token counts into money. Tracking is on by default because it costs nothing — every provider already reports the counts, and a spend you cannot see is one you find out about on an invoice. Prices are fetched from the model catalog and cached; an entry here overrides one for a model the catalog does not carry (a private endpoint, a negotiated rate).
type DesktopConfig ¶
type DesktopConfig struct {
Enabled *bool `json:"enabled,omitempty"`
ScreenshotDir string `json:"screenshot_dir,omitempty"`
}
DesktopConfig controls the desktop-control tools (windows, screenshots, mouse, keyboard, clipboard, notifications). Enabled is a tri-state: unset means "register them when a graphical session is detected", which keeps a headless server's prompt free of tools that could never work there.
func (DesktopConfig) Register ¶
func (d DesktopConfig) Register(hasDisplay bool) bool
Register reports whether the desktop tools should be registered.
type GatewayConfig ¶
type HeartbeatConfig ¶
type MCPServer ¶
type MemoryConfig ¶
type MemoryConfig struct {
Mode string `json:"mode" env:"FACTOR_MEMORY_MODE"` // sidecar | external | off
URL string `json:"url,omitempty" env:"FACTOR_MEMORY_URL"`
Command string `json:"command"`
AutoInstall bool `json:"auto_install"` // install smrti (uv/pipx/pip/venv) when missing
KeepAlive bool `json:"keep_alive"` // sidecar outlives Factor; later runs adopt it warm
Host string `json:"host"`
Port int `json:"port" env:"FACTOR_MEMORY_PORT"`
DBPath string `json:"db_path"`
Tenant string `json:"tenant"`
Space string `json:"space"`
SpaceStrategy string `json:"space_strategy"` // origin: conversations write to `space`, cron/job turns to `system_space`, each reading the other as an overlay (needs a smrti with space routing; older engines fall back to single). single: everything in `space`.
SystemSpace string `json:"system_space"`
Personality string `json:"personality" env:"FACTOR_MEMORY_PERSONALITY"`
APIKey string `json:"api_key,omitempty" env:"FACTOR_MEMORY_API_KEY"`
RecallTopK int `json:"recall_top_k"`
RecallMinConfidence float64 `json:"recall_min_confidence"`
QueryContextMsgs int `json:"query_context_msgs"`
QueryMaxChars int `json:"query_max_chars"`
InjectMaxChars int `json:"inject_max_chars"`
ReflectIntervalSecs int `json:"reflect_interval_secs"`
ExtractMode string `json:"extract_mode,omitempty" env:"FACTOR_MEMORY_EXTRACT_MODE"` // hybrid | llm | local | "" = auto
ExtractURL string `json:"extract_url,omitempty" env:"FACTOR_MEMORY_EXTRACT_URL"`
ExtractModel string `json:"extract_model,omitempty" env:"FACTOR_MEMORY_EXTRACT_MODEL"`
ExtractAPIKey string `json:"extract_api_key,omitempty" env:"FACTOR_MEMORY_EXTRACT_API_KEY"`
IgnorePatterns []string `json:"ignore_patterns,omitempty"`
StartupTimeoutSecs int `json:"startup_timeout_secs"`
}
func (MemoryConfig) BaseURL ¶
func (m MemoryConfig) BaseURL() string
BaseURL returns the effective smrti endpoint.
type Price ¶ added in v0.19.0
Price is what one model charges, in USD per million tokens — the unit model pages quote, so a hand-written override reads the way it was copied.
type ProviderConfig ¶
type ProviderConfig struct {
Type string `json:"type" env:"FACTOR_PROVIDER_TYPE"`
APIKey string `json:"api_key,omitempty" env:"FACTOR_PROVIDER_API_KEY"`
APIBase string `json:"api_base,omitempty" env:"FACTOR_PROVIDER_API_BASE"`
Model string `json:"model" env:"FACTOR_PROVIDER_MODEL"`
Reasoning ReasoningConfig `json:"reasoning"`
MaxTokens int `json:"max_tokens"`
Temperature float64 `json:"temperature,omitempty"`
Fallbacks []Candidate `json:"fallbacks,omitempty"`
MaxRetries int `json:"max_retries"`
RetryBackoffSecs int `json:"retry_backoff_secs"`
}
func (ProviderConfig) Candidates ¶
func (p ProviderConfig) Candidates() []Candidate
Candidates returns the primary candidate followed by the fallbacks, each carrying the reasoning settings it should use.
type ReasoningConfig ¶
type ReasoningConfig struct {
Effort string `json:"effort"` // xhigh | high | medium | low | minimal | none
MaxTokens int `json:"max_tokens"` // explicit thinking budget; wins over effort
Exclude bool `json:"exclude"` // think, but keep the reasoning out of the reply
}
ReasoningConfig asks the model to think before answering. Each backend spells this differently (OpenRouter takes a reasoning object, OpenAI and Groq take reasoning_effort, Anthropic takes a thinking budget); Factor translates one setting into whichever the active provider understands. The fields are written even when empty: the section is overlaid on top of the defaults at load time, so an omitted "effort" would silently restore the default xhigh instead of the "off" the user asked for.
func (ReasoningConfig) IsZero ¶
func (r ReasoningConfig) IsZero() bool
IsZero reports that nothing was configured (no reasoning parameters sent).
type ToolsConfig ¶
type ToolsConfig struct {
Disabled []string `json:"disabled,omitempty"`
RestrictToWorkspace bool `json:"restrict_to_workspace"`
AllowReadOutsideWorkspace bool `json:"allow_read_outside_workspace"`
AllowPaths []string `json:"allow_paths,omitempty"`
ExecTimeoutSecs int `json:"exec_timeout_secs"`
EnableDenyPatterns bool `json:"enable_deny_patterns"`
CustomDenyPatterns []string `json:"custom_deny_patterns,omitempty"`
AllowInstall bool `json:"allow_install"`
// SkillRegistryURL points skill_find and skill_install at something other
// than skills.sh: a mirror, a private index, a stub in a test.
SkillRegistryURL string `json:"skill_registry_url,omitempty" env:"FACTOR_SKILL_REGISTRY_URL"`
}
func (ToolsConfig) IsToolEnabled ¶
func (t ToolsConfig) IsToolEnabled(name string) bool
IsToolEnabled reports whether a tool name survives the user's disabled list.
type UpgradeConfig ¶ added in v0.5.0
type UpgradeConfig struct {
Check bool `json:"check"`
CheckIntervalHours int `json:"check_interval_hours"`
}
UpgradeConfig controls the release check. The gateway only ever reports a newer version — installing it stays an explicit `factor upgrade` or a request to the agent, so a daemon never swaps its own binary out from under a live conversation.