Rip out Ollama: direct_route only, no LLM layer

Pete moves to a remote host without Ollama access. Every source must
declare a direct_route channel; the classifier, explainer, semantic
dedup, !explain summaries, feed_hint, and the recent_headlines /
classification_log tables are gone. Deterministic dedup (canonical URL,
headline_norm, per-channel cooldown) remains.
This commit is contained in:
prosolis
2026-05-24 22:07:13 -07:00
parent fbd4b84eaf
commit e88483526d
23 changed files with 146 additions and 1675 deletions

View File

@@ -14,7 +14,6 @@ var envBracketRe = regexp.MustCompile(`\$\{([^}]+)\}`)
type Config struct {
Matrix MatrixConfig `yaml:"matrix"`
Ollama OllamaConfig `yaml:"ollama"`
Posting PostingConfig `yaml:"posting"`
Storage StorageConfig `yaml:"storage"`
Web WebConfig `yaml:"web"`
@@ -40,12 +39,6 @@ type MatrixConfig struct {
Channels map[string]string `yaml:"channels"`
}
type OllamaConfig struct {
BaseURL string `yaml:"base_url"`
Model string `yaml:"model"`
TimeoutSeconds int `yaml:"timeout_seconds"`
}
type PostingConfig struct {
MinIntervalSeconds int `yaml:"min_interval_seconds"`
BurstCapCount int `yaml:"burst_cap_count"`
@@ -58,27 +51,25 @@ type PostingConfig struct {
}
// RoundRobinConfig switches Pete from immediate-on-classify posting to a
// paced rotation: one story per IntervalHours, picking the next source in
// config order that has a postable story (skip-and-advance, newest-first).
// paced rotation: one story per IntervalHours, picking the next channel in
// rotation order that has a postable story (skip-and-advance, newest-first).
type RoundRobinConfig struct {
Enabled bool `yaml:"enabled"`
IntervalHours int `yaml:"interval_hours"`
}
type StorageConfig struct {
DBPath string `yaml:"db_path"`
RecentWindowHours int `yaml:"recent_window_hours"`
ClassificationLogDays int `yaml:"classification_log_days"`
DBPath string `yaml:"db_path"`
RecentWindowHours int `yaml:"recent_window_hours"`
}
type SourceConfig struct {
Name string `yaml:"name"`
FeedURL string `yaml:"feed_url"`
Tier int `yaml:"tier"`
PollIntervalMinutes int `yaml:"poll_interval_minutes"`
FeedHint string `yaml:"feed_hint"`
DirectRoute *string `yaml:"direct_route"`
Enabled bool `yaml:"enabled"`
Name string `yaml:"name"`
FeedURL string `yaml:"feed_url"`
Tier int `yaml:"tier"`
PollIntervalMinutes int `yaml:"poll_interval_minutes"`
DirectRoute string `yaml:"direct_route"`
Enabled bool `yaml:"enabled"`
}
func Load(path string) (*Config, error) {
@@ -125,12 +116,6 @@ func (c *Config) validate() error {
if len(c.Matrix.Channels) == 0 {
return fmt.Errorf("matrix.channels must have at least one entry")
}
if c.Ollama.BaseURL == "" {
return fmt.Errorf("ollama.base_url is required")
}
if c.Ollama.Model == "" {
return fmt.Errorf("ollama.model is required")
}
if c.Storage.DBPath == "" {
return fmt.Errorf("storage.db_path is required")
}
@@ -148,6 +133,15 @@ func (c *Config) validate() error {
if s.PollIntervalMinutes <= 0 {
return fmt.Errorf("sources[%d].poll_interval_minutes must be > 0", i)
}
if !s.Enabled {
continue
}
if s.DirectRoute == "" {
return fmt.Errorf("sources[%d] (%s): direct_route is required for enabled sources", i, s.Name)
}
if _, ok := c.Matrix.Channels[s.DirectRoute]; !ok {
return fmt.Errorf("sources[%d] (%s): direct_route %q is not a configured matrix.channels key", i, s.Name, s.DirectRoute)
}
}
return nil
@@ -163,9 +157,6 @@ func (c *Config) applyDefaults() {
if c.Matrix.PickleKey == "" {
c.Matrix.PickleKey = "pete_pickle_key"
}
if c.Ollama.TimeoutSeconds == 0 {
c.Ollama.TimeoutSeconds = 30
}
if c.Posting.MinIntervalSeconds == 0 {
c.Posting.MinIntervalSeconds = 300
}
@@ -184,9 +175,6 @@ func (c *Config) applyDefaults() {
if c.Storage.RecentWindowHours == 0 {
c.Storage.RecentWindowHours = 24
}
if c.Storage.ClassificationLogDays == 0 {
c.Storage.ClassificationLogDays = 7
}
if c.Web.ListenAddr == "" {
c.Web.ListenAddr = ":8080"
}