Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/added-settings-parity-batch-8.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Expose the knowledge pipeline settings in the dashboard Settings dialog: a new Knowledge pipeline block on the Knowledge tab edits the bead synthesizer (on/off applies at once; schedule, target layer, minimum confidence, per-cycle fact and GitHub API caps, bead retention), scheduled curator promotion, repository code maps and the kick primer caps through the owner-only `PUT /api/config/knowledge/pipeline`, shows the engine, vault paths and primer merge strategy read-only, and labels the public read-only MCP switch with its YAML key (#11854).
456 changes: 456 additions & 0 deletions dashboard/openapi.json

Large diffs are not rendered by default.

146 changes: 74 additions & 72 deletions src/docs/api-reference.md

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions src/docs/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ Optional capabilities, each off or inert until you turn it on. Where a feature h

The other features on this tab (OpenTelemetry export, external execution, auto-plan, issue claims, PR follow-up, long-running runs, provider rotation, merge recommendations, convergence rollout, stall replan, and question auto-close) are explained by their **?** tooltips, and their configuration keys are listed in the [Hive operator reference](operator-reference.md#configuration-blocks).

## Knowledge

Whether the public read-only knowledge MCP endpoint is on, the knowledge pipeline, and the external knowledge connectors. The **Knowledge pipeline** block sets the bead synthesizer (schedule, target layer, minimum confidence, per-cycle fact and GitHub API caps, bead retention), scheduled curator promotion (schedule, threshold, source and target layers), repository code maps (schedule, layer, size cap) and the kick primer's fact and byte caps. Turning the bead synthesizer on or off applies at once; the other pipeline settings apply after a restart, and 0 or empty restores the default. The engine, the vault paths and the primer merge strategy are shown read-only because they are set in `hive.yaml`. The repositories to map and the primer priority list stay yaml-only. See [Knowledge curator](knowledge-curator.md) and [Knowledge connectors](knowledge-connectors.md).

## Advisory

How many advisory findings are shown, how often they refresh, and when a finding counts as stale. See [Advisory](advisory.md) and [Advisory staleness](advisory-staleness.md).
Expand Down
20 changes: 10 additions & 10 deletions src/pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6479,11 +6479,11 @@ const (
defaultGitHubAPIReserve = DefaultGitHubAPIReserve
defaultGitHubAPICritical = DefaultGitHubAPICritical
defaultPollIntervalMins = 5
defaultKnowledgeMaxFacts = 25
defaultKnowledgeMaxBytes = 4096
defaultKnowledgeMaxFacts = DefaultKnowledgePrimerMaxFacts
defaultKnowledgeMaxBytes = DefaultKnowledgePrimerMaxBytes
defaultKnowledgeEngine = "llm-wiki"
defaultCuratorSchedule = "daily"
defaultPromoteThreshold = 0.9
defaultCuratorSchedule = DefaultCuratorSchedule
defaultPromoteThreshold = DefaultCuratorAutoPromoteThreshold
defaultSensingTTLSeconds = 900
defaultSensingPullbackSeconds = 900
defaultBudgetPeriodDays = 7
Expand Down Expand Up @@ -6884,7 +6884,7 @@ func (c *Config) applyDefaults() {
c.Knowledge.Primer.MaxBytes = defaultKnowledgeMaxBytes
}
if c.Knowledge.Primer.MergeStrategy == "" {
c.Knowledge.Primer.MergeStrategy = "precedence"
c.Knowledge.Primer.MergeStrategy = DefaultKnowledgePrimerMergeStrategy
}
if len(c.Knowledge.Primer.Priority) == 0 {
c.Knowledge.Primer.Priority = []string{"regression", "gotcha", "test_scaffold", "pattern", "decision"}
Expand All @@ -6902,22 +6902,22 @@ func (c *Config) applyDefaults() {
c.Knowledge.Curator.AutoPromoteThreshold = defaultPromoteThreshold
}
if c.Knowledge.BeadSynthesizer.Schedule == "" {
c.Knowledge.BeadSynthesizer.Schedule = "hourly"
c.Knowledge.BeadSynthesizer.Schedule = DefaultBeadSynthSchedule
}
if c.Knowledge.BeadSynthesizer.MinConfidence == 0 {
c.Knowledge.BeadSynthesizer.MinConfidence = 0.5
c.Knowledge.BeadSynthesizer.MinConfidence = DefaultBeadSynthMinConfidence
}
if c.Knowledge.BeadSynthesizer.TargetLayer == "" {
c.Knowledge.BeadSynthesizer.TargetLayer = "project"
c.Knowledge.BeadSynthesizer.TargetLayer = DefaultBeadSynthTargetLayer
}
if c.Knowledge.BeadSynthesizer.MaxFactsPerCycle == 0 {
c.Knowledge.BeadSynthesizer.MaxFactsPerCycle = 20
c.Knowledge.BeadSynthesizer.MaxFactsPerCycle = DefaultBeadSynthMaxFactsPerCycle
}
if c.Knowledge.BeadSynthesizer.MaxAPICallsPerCycle == 0 {
c.Knowledge.BeadSynthesizer.MaxAPICallsPerCycle = DefaultBeadSynthMaxAPICallsPerCycle
}
if c.Knowledge.BeadSynthesizer.VaultPath == "" {
c.Knowledge.BeadSynthesizer.VaultPath = "/data/vaults/bead-synth-wiki"
c.Knowledge.BeadSynthesizer.VaultPath = DefaultBeadSynthVaultPath
}
}
}
Expand Down
93 changes: 93 additions & 0 deletions src/pkg/config/knowledge_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,99 @@ type BeadSynthesizerConfig struct {
// DefaultBeadSynthMaxAPICallsPerCycle is the default per-cycle PR GET cap.
const DefaultBeadSynthMaxAPICallsPerCycle = 40

// Knowledge pipeline defaults that applyDefaults sets at Load; runtime editors
// substitute the same values so a cleared field restores the default.
const (
DefaultBeadSynthSchedule = "hourly"
DefaultBeadSynthMinConfidence = 0.5
DefaultBeadSynthTargetLayer = "project"
DefaultBeadSynthMaxFactsPerCycle = 20
DefaultBeadSynthVaultPath = "/data/vaults/bead-synth-wiki"
DefaultCuratorSchedule = "daily"
DefaultCuratorAutoPromoteThreshold = 0.9
DefaultKnowledgePrimerMaxFacts = 25
DefaultKnowledgePrimerMaxBytes = 4096
DefaultKnowledgePrimerMergeStrategy = "precedence"
)

// KnowledgeSchedules are the schedule values the bead synthesizer, curator
// and code map loops understand (knowledge.ParseSynthSchedule).
var KnowledgeSchedules = []string{"hourly", "daily"}

// ValidateKnowledgePipeline checks the scalar bead_synthesizer, curator,
// code_maps and primer keys the dashboard edits: schedules must be hourly or
// daily (empty uses the default), layers must be personal, project, org or
// community, confidences lie in [0, 1], counts and byte caps are not
// negative, and scheduled promotion may not promote a layer into itself.
// Unset (zero) fields pass, so callers can validate just the keys they edit.
func ValidateKnowledgePipeline(k KnowledgeConfig) error {
for _, s := range []struct{ field, v string }{
{"knowledge.bead_synthesizer.schedule", k.BeadSynthesizer.Schedule},
{"knowledge.curator.schedule", k.Curator.Schedule},
{"knowledge.code_maps.schedule", k.CodeMaps.Schedule},
} {
v := strings.ToLower(strings.TrimSpace(s.v))
if v != "" && v != "hourly" && v != "daily" {
return fmt.Errorf("%s %q must be hourly or daily", s.field, s.v)
}
}
for _, l := range []struct{ field, v string }{
{"knowledge.bead_synthesizer.target_layer", k.BeadSynthesizer.TargetLayer},
{"knowledge.curator.promote_from", k.Curator.PromoteFrom},
{"knowledge.curator.promote_to", k.Curator.PromoteTo},
{"knowledge.code_maps.layer", k.CodeMaps.Layer},
} {
if v := strings.TrimSpace(l.v); v != "" && !knowledgeLayerNames[v] {
return fmt.Errorf("%s %q must be personal, project, org or community", l.field, l.v)
}
}
from, to := strings.TrimSpace(k.Curator.PromoteFrom), strings.TrimSpace(k.Curator.PromoteTo)
if from == "" {
from = "project"
}
if to == "" {
to = "org"
}
if from == to {
return fmt.Errorf("knowledge.curator.promote_from and promote_to must name different layers (both %q)", from)
}
for _, f := range []struct {
field string
v float64
}{
{"knowledge.bead_synthesizer.min_confidence", k.BeadSynthesizer.MinConfidence},
{"knowledge.curator.auto_promote_threshold", k.Curator.AutoPromoteThreshold},
} {
if f.v < 0 || f.v > 1 {
return fmt.Errorf("%s must be between 0 and 1", f.field)
}
}
type intField struct {
field string
v int
}
ints := []intField{
{"knowledge.bead_synthesizer.max_facts_per_cycle", k.BeadSynthesizer.MaxFactsPerCycle},
{"knowledge.bead_synthesizer.max_api_calls_per_cycle", k.BeadSynthesizer.MaxAPICallsPerCycle},
{"knowledge.code_maps.max_bytes", k.CodeMaps.MaxBytes},
{"knowledge.primer.max_facts", k.Primer.MaxFacts},
{"knowledge.primer.max_bytes", k.Primer.MaxBytes},
}
if rp := k.BeadSynthesizer.RetentionPolicy; rp != nil {
ints = append(ints,
intField{"knowledge.bead_synthesizer.retention_policy.max_beads", rp.MaxBeads},
intField{"knowledge.bead_synthesizer.retention_policy.archive_after_synth_days", rp.ArchiveAfterSynthDays},
intField{"knowledge.bead_synthesizer.retention_policy.high_priority_retain_days", rp.HighPriorityRetainDays},
)
}
for _, f := range ints {
if f.v < 0 {
return fmt.Errorf("%s must be 0 (default) or greater", f.field)
}
}
return nil
}

// EffectiveMaxAPICallsPerCycle returns the configured cap or the default.
func (b BeadSynthesizerConfig) EffectiveMaxAPICallsPerCycle() int {
if b.MaxAPICallsPerCycle <= 0 {
Expand Down
2 changes: 2 additions & 0 deletions src/pkg/dashboard/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,8 @@ func (s *Server) RegisterAPI(deps *Dependencies) {
s.mux.HandleFunc("POST /api/config/knowledge/connectors/{name}/sync", s.handleKnowledgeConnectorsSync)
s.mux.HandleFunc("GET /api/config/knowledge/agent-scopes", s.handleKnowledgeAgentScopesGet)
s.mux.HandleFunc("PUT /api/config/knowledge/agent-scopes", s.handleKnowledgeAgentScopesPut)
s.mux.HandleFunc("GET /api/config/knowledge/pipeline", s.handleKnowledgePipelineGet)
s.mux.HandleFunc("PUT /api/config/knowledge/pipeline", s.handleKnowledgePipelinePut)
s.mux.HandleFunc("GET /api/knowledge/git-sources", s.handleGitSourcesList)
s.mux.HandleFunc("POST /api/knowledge/git-sources", s.handleGitSourcesConnect)
s.mux.HandleFunc("DELETE /api/knowledge/git-sources", s.handleGitSourcesDisconnect)
Expand Down
Loading
Loading