- Add configrefresh package for config classification, request handling - Add bootstrap refresh_admin.go for admin-level config refresh - Add edgevalidate package for config validation - Update edge bootstrap runtime with refresh capabilities - Update edge service layer with config refresh integration - Update openai layer routes/chat_handler/server for config refresh - Update edgecmd config handling with refresh support - Update input manager, transport server, status provider - Add edge.yaml config updates and go/config package changes - Add hostsetup templates and test updates - Update roadmap and phase documentation for runtime-reconnect-config-refresh
101 lines
2.8 KiB
Go
101 lines
2.8 KiB
Go
package edgevalidate
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
edgenode "iop/apps/edge/internal/node"
|
|
"iop/packages/go/config"
|
|
)
|
|
|
|
// ValidateEdgeConfig validates Edge config fields that config.LoadEdge does
|
|
// not check: adapter endpoint presence, per-node adapter-enabled requirements,
|
|
// and node store consistency (token uniqueness). It is the shared validation
|
|
// path used by both `config check` and the refresh candidate loader so that
|
|
// the same ruleset applies regardless of the entry point.
|
|
func ValidateEdgeConfig(cfg *config.EdgeConfig) error {
|
|
_, err := edgenode.LoadFromConfig(cfg.Nodes)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for i, n := range cfg.Nodes {
|
|
name := n.ID
|
|
if name == "" {
|
|
name = n.Alias
|
|
}
|
|
if name == "" {
|
|
name = fmt.Sprintf("index %d", i)
|
|
}
|
|
|
|
hasOllama := anyOllamaEnabled(n.Adapters)
|
|
hasVllm := anyVllmEnabled(n.Adapters)
|
|
hasOpenAICompat := anyOpenAICompatEnabled(n.Adapters)
|
|
if !hasOllama && !n.Adapters.CLI.Enabled && !hasVllm && !hasOpenAICompat {
|
|
return fmt.Errorf("node %q: at least one adapter must be enabled", name)
|
|
}
|
|
if n.Adapters.Ollama.Enabled && n.Adapters.Ollama.BaseURL == "" {
|
|
return fmt.Errorf("node %q: ollama adapter base_url must not be empty", name)
|
|
}
|
|
for j, inst := range n.Adapters.OllamaInstances {
|
|
if inst.Enabled && inst.BaseURL == "" {
|
|
return fmt.Errorf("node %q: ollama_instances[%d] %q: base_url must not be empty", name, j, inst.Name)
|
|
}
|
|
}
|
|
if n.Adapters.Vllm.Enabled && n.Adapters.Vllm.Endpoint == "" {
|
|
return fmt.Errorf("node %q: vllm adapter endpoint must not be empty", name)
|
|
}
|
|
for j, inst := range n.Adapters.VllmInstances {
|
|
if inst.Enabled && inst.Endpoint == "" {
|
|
return fmt.Errorf("node %q: vllm_instances[%d] %q: endpoint must not be empty", name, j, inst.Name)
|
|
}
|
|
}
|
|
if n.Adapters.OpenAICompat.Enabled && n.Adapters.OpenAICompat.Endpoint == "" {
|
|
return fmt.Errorf("node %q: openai_compat adapter endpoint must not be empty", name)
|
|
}
|
|
for j, inst := range n.Adapters.OpenAICompatInstances {
|
|
if inst.Enabled && inst.Endpoint == "" {
|
|
return fmt.Errorf("node %q: openai_compat_instances[%d] %q: endpoint must not be empty", name, j, inst.Name)
|
|
}
|
|
}
|
|
if n.Runtime.Concurrency < 0 {
|
|
return fmt.Errorf("node %q: runtime concurrency must be non-negative", name)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func anyOllamaEnabled(a config.AdaptersConf) bool {
|
|
if a.Ollama.Enabled {
|
|
return true
|
|
}
|
|
for _, inst := range a.OllamaInstances {
|
|
if inst.Enabled {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func anyVllmEnabled(a config.AdaptersConf) bool {
|
|
if a.Vllm.Enabled {
|
|
return true
|
|
}
|
|
for _, inst := range a.VllmInstances {
|
|
if inst.Enabled {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func anyOpenAICompatEnabled(a config.AdaptersConf) bool {
|
|
if a.OpenAICompat.Enabled {
|
|
return true
|
|
}
|
|
for _, inst := range a.OpenAICompatInstances {
|
|
if inst.Enabled {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|