Files
sift/internal/config/config.go
T
kyle d7873403ff p3: search API, pinned sources, cache, CLI
POST /v1/search and /v2/search fan in SearXNG, Brave LLM Context, and
Tavily from config-fixed endpoints. Public sources refuse private A
records; SearXNG is a loopback-only client, not the fetch guard.

Cache keys include caller class. Restricted callers search like the
fleet; logs omit query, hosts, URLs, and upstream errors. Degraded
results are not stored. Tavily sends search_depth=basic and drops
answer. Missing keys surface in /healthz.

Default-on sources stay off until the bake-off. Query harvest is not
in this commit.
2026-09-23 12:17:51 -07:00

111 lines
2.5 KiB
Go

package config
import (
"os"
"time"
"github.com/pelletier/go-toml/v2"
)
// File is the on-disk /etc/sift/config.toml.
type File struct {
Listen string `toml:"listen"`
UserAgent string `toml:"user_agent"`
DenyPrefixes []string `toml:"deny_prefixes"`
SelfIP SelfIP `toml:"self_ip"`
Dixie Dixie `toml:"dixie"`
Digest Digest `toml:"digest"`
Context Context `toml:"context"`
Search Search `toml:"search"`
}
type Dixie struct {
Chat string `toml:"chat"`
Embed string `toml:"embed"`
EmbedModel string `toml:"embed_model"`
MaxInflight int `toml:"max_inflight"`
QueueDepth int `toml:"queue_depth"`
QueueWait string `toml:"queue_wait"`
}
type Digest struct {
Model string `toml:"model"`
Thinking bool `toml:"thinking"`
Cache string `toml:"cache"`
}
type Context struct {
Honcho string `toml:"honcho"`
Workspaces []string `toml:"workspaces"`
PermitRestricted []string `toml:"permit_restricted"`
}
// Search is the [search] block. Sources default off; bake-off picks defaults.
type Search struct {
K int `toml:"k"`
Timeout string `toml:"timeout"`
Rerank *bool `toml:"rerank"`
Digest bool `toml:"digest"`
CacheTTL string `toml:"cache_ttl"`
SearxNG SearchSource `toml:"searxng"`
BraveLLM SearchSource `toml:"brave_llm"`
Tavily TavilySource `toml:"tavily"`
}
type SearchSource struct {
Enabled bool `toml:"enabled"`
URL string `toml:"url"`
}
type TavilySource struct {
Enabled bool `toml:"enabled"`
URL string `toml:"url"`
DailyCreditCap int `toml:"daily_credit_cap"`
}
func (s Search) RerankOn() bool {
if s.Rerank == nil {
return true
}
return *s.Rerank
}
func (s Search) AnyEnabled() bool {
return s.SearxNG.Enabled || s.BraveLLM.Enabled || s.Tavily.Enabled
}
// SelfIP is the [self_ip] block.
type SelfIP struct {
Sources []string `toml:"sources"`
Interval string `toml:"interval"`
KeepPrevious string `toml:"keep_previous"`
Path string `toml:"path"`
}
// Load reads path. A missing file returns a zero File and a nil error.
func Load(path string) (File, error) {
var f File
b, err := os.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
return f, nil
}
return f, err
}
if err := toml.Unmarshal(b, &f); err != nil {
return File{}, err
}
return f, nil
}
func ParseDuration(s string, def time.Duration) time.Duration {
if s == "" {
return def
}
d, err := time.ParseDuration(s)
if err != nil {
return def
}
return d
}