Add Calibrate AI Control UI and fleet LLM backend wiring.
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled

Operators toggle Logic gates vs AI Control on Settings, refresh local Ollama models, and save ai_endpoint settings via Calibrate PUT; server scheduler and agent snapshot/command paths support stateless 60s fleet decisions.
This commit is contained in:
AetherForge
2026-06-07 02:14:28 -07:00
parent 34afa28f81
commit 0002e5fd93
33 changed files with 2791 additions and 12 deletions

View File

@@ -20,6 +20,7 @@ import (
"crypto-miner-server/internal/builder"
"crypto-miner-server/internal/cloudflared"
"crypto-miner-server/internal/db"
fleetai "crypto-miner-server/internal/ai"
"crypto-miner-server/internal/maintenance"
"crypto-miner-server/internal/pool"
"crypto-miner-server/internal/scheduler"
@@ -268,6 +269,17 @@ func main() {
defer fleetSched.Stop()
wsHub.SetConnectTaskRunner(fleetSched)
fleetAISched := fleetai.NewScheduler(
&api.ConfigAIAdapter{Src: configProvider},
&api.WSHubSnapshotAdapter{Hub: wsHub},
&api.FleetAIExecutor{Hub: wsHub},
&api.DatabaseAIDecisionStore{DB: database},
)
fleetAISched.Start()
defer fleetAISched.Stop()
fleetAIHandler := api.NewFleetAIHandler(configProvider, database)
log.Println("Fleet AI Control scheduler initialized")
// Initialize blueprint handler (config presets)
blueprintHandler := api.NewBlueprintHandler(cfg.DataDir)
log.Println("Blueprint handler initialized")
@@ -305,7 +317,7 @@ func main() {
log.Printf("Web root: %s", webRoot)
// Initialize router
router := api.NewRouter(database, wsHub, configHandler, builderHandler, blueprintHandler, aiHandler, fleetHandler, dropperHandler, spreadHandler, spreadCredHandler, deployPlanHandler, publicHandler, pathForgeHandler, pathTracerHandler, webRoot, cfg.DataDir, func() string {
router := api.NewRouter(database, wsHub, configHandler, builderHandler, blueprintHandler, aiHandler, fleetHandler, fleetAIHandler, dropperHandler, spreadHandler, spreadCredHandler, deployPlanHandler, publicHandler, pathForgeHandler, pathTracerHandler, webRoot, cfg.DataDir, func() string {
return configProvider.PublicURL()
}, cfg.Port, func() bool {
return cfg.ConnectorToken() != ""
@@ -379,6 +391,7 @@ func applyRuntimeConfig(cfg *Config, wsHub *api.WSHub, poolManager *pool.Manager
ReconTiers: cfg.Server.TripleOnionPolicy.ReconTiers,
DeployLanes: cfg.Server.TripleOnionPolicy.DeployLanes,
},
AIControlEnabled: cfg.Server.AIControlEnabled,
})
}
if poolManager != nil {
@@ -479,6 +492,46 @@ func (p *serverConfigProvider) UpdateConfigFromJSON(data json.RawMessage) error
return nil
}
func (p *serverConfigProvider) GetFleetAIConfig() api.FleetAIConfigView {
if p == nil || p.config == nil {
return api.FleetAIConfigView{}
}
s := p.config.Server
interval := s.AIDecisionIntervalSec
if interval <= 0 {
interval = 60
}
return api.FleetAIConfigView{
AIControlEnabled: s.AIControlEnabled,
AIEndpoint: s.AIEndpoint,
AIModel: s.AIModel,
AINoContext: s.AINoContext,
AIDecisionIntervalSec: interval,
}
}
func (p *serverConfigProvider) UpdateFleetAIConfig(v api.FleetAIConfigView) error {
if p == nil || p.config == nil {
return fmt.Errorf("config unavailable")
}
if v.AIDecisionIntervalSec < 0 {
return fmt.Errorf("ai_decision_interval_sec must be ≥ 0")
}
payload, err := json.Marshal(map[string]interface{}{
"server": map[string]interface{}{
"ai_control_enabled": v.AIControlEnabled,
"ai_endpoint": v.AIEndpoint,
"ai_model": v.AIModel,
"ai_no_context": v.AINoContext,
"ai_decision_interval_sec": v.AIDecisionIntervalSec,
},
})
if err != nil {
return err
}
return p.UpdateConfigFromJSON(payload)
}
// findAgentSourceDir locates the agent source code directory
// It searches relative to the server binary location and the current working directory
func findAgentSourceDir() string {