This commit is contained in:
2026-08-07 08:33:41 +02:00
parent d088eb0a47
commit 246241fcda
419 changed files with 11924 additions and 203 deletions
+31 -6
View File
@@ -60,6 +60,11 @@ type Config struct {
ArticleResearchPageMaxChars int
ArticleResearchFetchTimeout time.Duration
ArticleResearchAllowPrivate bool
ArticleLanguage string
ResearchDedupeThreshold float64
ResearchDedupeTTL time.Duration
ResearchOllamaMaxInflight int
ResearchOllamaQueueSize int
AutonomousResearchEnabled bool
AutonomousResearchIdleOnly bool
AutonomousResearchInterval time.Duration
@@ -158,17 +163,22 @@ func Load() (Config, error) {
ArticleMinTextChars: integer("BRAIN_ARTICLE_MIN_TEXT_CHARS", 180),
ArticleMinAnswerChars: integer("BRAIN_ARTICLE_MIN_ANSWER_CHARS", 420),
ArticleMaxResearchQueries: integer("BRAIN_ARTICLE_MAX_RESEARCH_QUERIES", 6),
ArticleResearchResults: integer("BRAIN_ARTICLE_RESEARCH_RESULTS", 8),
ArticleResearchResults: integer("BRAIN_ARTICLE_RESEARCH_RESULTS", 12),
ArticleResearchRounds: integer("BRAIN_ARTICLE_RESEARCH_ROUNDS", 3),
ArticleResearchFetchResults: integer("BRAIN_ARTICLE_RESEARCH_FETCH_RESULTS", 4),
ArticleResearchExplorationResults: integer("BRAIN_ARTICLE_RESEARCH_EXPLORATION_RESULTS", 2),
ArticleResearchPrefetchMinRelevance: number("BRAIN_ARTICLE_RESEARCH_PREFETCH_MIN_RELEVANCE", 0.35),
ArticleResearchMinRelevance: number("BRAIN_ARTICLE_RESEARCH_MIN_RELEVANCE", 0.65),
ArticleResearchMinQuality: number("BRAIN_ARTICLE_RESEARCH_MIN_QUALITY", 0.45),
ArticleResearchFetchResults: integer("BRAIN_ARTICLE_RESEARCH_FETCH_RESULTS", 6),
ArticleResearchExplorationResults: integer("BRAIN_ARTICLE_RESEARCH_EXPLORATION_RESULTS", 3),
ArticleResearchPrefetchMinRelevance: number("BRAIN_ARTICLE_RESEARCH_PREFETCH_MIN_RELEVANCE", 0.25),
ArticleResearchMinRelevance: number("BRAIN_ARTICLE_RESEARCH_MIN_RELEVANCE", 0.55),
ArticleResearchMinQuality: number("BRAIN_ARTICLE_RESEARCH_MIN_QUALITY", 0.35),
ArticleResearchPageMaxBytes: int64(integer("BRAIN_ARTICLE_RESEARCH_PAGE_MAX_BYTES", 2097152)),
ArticleResearchPageMaxChars: integer("BRAIN_ARTICLE_RESEARCH_PAGE_MAX_CHARS", 14000),
ArticleResearchFetchTimeout: duration("BRAIN_ARTICLE_RESEARCH_FETCH_TIMEOUT", 20*time.Second),
ArticleResearchAllowPrivate: boolean("BRAIN_ARTICLE_RESEARCH_ALLOW_PRIVATE", false),
ArticleLanguage: strings.TrimSpace(env("BRAIN_ARTICLE_LANGUAGE", "de-DE")),
ResearchDedupeThreshold: number("BRAIN_RESEARCH_DEDUPE_THRESHOLD", 0.92),
ResearchDedupeTTL: duration("BRAIN_RESEARCH_DEDUPE_TTL", 45*time.Minute),
ResearchOllamaMaxInflight: integer("BRAIN_RESEARCH_OLLAMA_MAX_INFLIGHT", 2),
ResearchOllamaQueueSize: integer("BRAIN_RESEARCH_OLLAMA_QUEUE_SIZE", 64),
AutonomousResearchEnabled: boolean("BRAIN_AUTONOMOUS_RESEARCH_ENABLED", false),
AutonomousResearchIdleOnly: boolean("BRAIN_AUTONOMOUS_RESEARCH_IDLE_ONLY", true),
AutonomousResearchInterval: duration("BRAIN_AUTONOMOUS_RESEARCH_INTERVAL", 30*time.Minute),
@@ -290,6 +300,21 @@ func Load() (Config, error) {
if cfg.ArticleResearchFetchTimeout < time.Second || cfg.ArticleResearchFetchTimeout > 2*time.Minute {
return Config{}, fmt.Errorf("BRAIN_ARTICLE_RESEARCH_FETCH_TIMEOUT must be between 1s and 2m")
}
if cfg.ArticleLanguage == "" || len(cfg.ArticleLanguage) > 32 {
return Config{}, fmt.Errorf("BRAIN_ARTICLE_LANGUAGE must be a non-empty language tag")
}
if cfg.ResearchDedupeThreshold < 0.5 || cfg.ResearchDedupeThreshold > 1 {
return Config{}, fmt.Errorf("BRAIN_RESEARCH_DEDUPE_THRESHOLD must be between 0.5 and 1")
}
if cfg.ResearchDedupeTTL < time.Minute || cfg.ResearchDedupeTTL > 24*time.Hour {
return Config{}, fmt.Errorf("BRAIN_RESEARCH_DEDUPE_TTL must be between 1m and 24h")
}
if cfg.ResearchOllamaMaxInflight < 1 || cfg.ResearchOllamaMaxInflight > 32 {
return Config{}, fmt.Errorf("BRAIN_RESEARCH_OLLAMA_MAX_INFLIGHT must be between 1 and 32")
}
if cfg.ResearchOllamaQueueSize < 1 || cfg.ResearchOllamaQueueSize > 4096 {
return Config{}, fmt.Errorf("BRAIN_RESEARCH_OLLAMA_QUEUE_SIZE must be between 1 and 4096")
}
if cfg.AutonomousResearchInterval < time.Minute || cfg.AutonomousResearchInterval > 24*time.Hour {
return Config{}, fmt.Errorf("BRAIN_AUTONOMOUS_RESEARCH_INTERVAL must be between 1m and 24h")
}
+7 -2
View File
@@ -78,11 +78,12 @@ func TestLoadArticleSynthesisQualitySettings(t *testing.T) {
t.Setenv("BRAIN_ARTICLE_MIN_CONFIDENCE", "0.81")
t.Setenv("BRAIN_ARTICLE_MIN_TEXT_CHARS", "220")
t.Setenv("BRAIN_ARTICLE_MIN_ANSWER_CHARS", "500")
t.Setenv("BRAIN_ARTICLE_LANGUAGE", "en-US")
cfg, err := Load()
if err != nil {
t.Fatal(err)
}
if !cfg.ArticleSynthesisEnabled || cfg.ArticleMinSources != 4 || cfg.ArticleMaxSources != 7 || cfg.ArticleMinProductionRatio != 0.8 || cfg.ArticleMaxGenerationDepth != 2 || cfg.ArticleMinConfidence != 0.81 || cfg.ArticleMinTextChars != 220 || cfg.ArticleMinAnswerChars != 500 {
if !cfg.ArticleSynthesisEnabled || cfg.ArticleMinSources != 4 || cfg.ArticleMaxSources != 7 || cfg.ArticleMinProductionRatio != 0.8 || cfg.ArticleMaxGenerationDepth != 2 || cfg.ArticleMinConfidence != 0.81 || cfg.ArticleMinTextChars != 220 || cfg.ArticleMinAnswerChars != 500 || cfg.ArticleLanguage != "en-US" {
t.Fatalf("unexpected article synthesis config: %+v", cfg)
}
}
@@ -101,11 +102,15 @@ func TestLoadIterativeResearchSettings(t *testing.T) {
t.Setenv("BRAIN_ARTICLE_RESEARCH_PAGE_MAX_CHARS", "9000")
t.Setenv("BRAIN_ARTICLE_RESEARCH_FETCH_TIMEOUT", "15s")
t.Setenv("BRAIN_ARTICLE_RESEARCH_ALLOW_PRIVATE", "true")
t.Setenv("BRAIN_RESEARCH_DEDUPE_THRESHOLD", "0.94")
t.Setenv("BRAIN_RESEARCH_DEDUPE_TTL", "30m")
t.Setenv("BRAIN_RESEARCH_OLLAMA_MAX_INFLIGHT", "3")
t.Setenv("BRAIN_RESEARCH_OLLAMA_QUEUE_SIZE", "24")
cfg, err := Load()
if err != nil {
t.Fatal(err)
}
if cfg.ArticleMaxResearchQueries != 5 || cfg.ArticleResearchResults != 10 || cfg.ArticleResearchRounds != 4 || cfg.ArticleResearchFetchResults != 3 || cfg.ArticleResearchExplorationResults != 2 || cfg.ArticleResearchPrefetchMinRelevance != .3 || cfg.ArticleResearchMinRelevance != .7 || cfg.ArticleResearchMinQuality != .6 || cfg.ArticleResearchPageMaxBytes != 1048576 || cfg.ArticleResearchPageMaxChars != 9000 || cfg.ArticleResearchFetchTimeout.String() != "15s" || !cfg.ArticleResearchAllowPrivate {
if cfg.ArticleMaxResearchQueries != 5 || cfg.ArticleResearchResults != 10 || cfg.ArticleResearchRounds != 4 || cfg.ArticleResearchFetchResults != 3 || cfg.ArticleResearchExplorationResults != 2 || cfg.ArticleResearchPrefetchMinRelevance != .3 || cfg.ArticleResearchMinRelevance != .7 || cfg.ArticleResearchMinQuality != .6 || cfg.ArticleResearchPageMaxBytes != 1048576 || cfg.ArticleResearchPageMaxChars != 9000 || cfg.ArticleResearchFetchTimeout.String() != "15s" || !cfg.ArticleResearchAllowPrivate || cfg.ResearchDedupeThreshold != .94 || cfg.ResearchDedupeTTL.String() != "30m0s" || cfg.ResearchOllamaMaxInflight != 3 || cfg.ResearchOllamaQueueSize != 24 {
t.Fatalf("unexpected iterative research config: %+v", cfg)
}
}