iop/apps/node/internal/adapters/config_set.go
toki 695df72eac feat: runtime reconnect config refresh - node drain config refresh
- Add PHASE.md for cli-agent-group-grade-routing milestone
- Add SDD for automation-runtime-bridge
- Update edge configrefresh classify logic and tests
- Update node config_set, node.go, and run_manager for runtime config refresh
- Archive old plan/review docs for 06+05_node_drain_runtime_config
2026-06-23 13:33:21 +09:00

189 lines
4.3 KiB
Go

package adapters
import (
"encoding/json"
"fmt"
"sort"
"go.uber.org/zap"
"iop/apps/node/internal/adapters/cli"
"iop/apps/node/internal/adapters/mock"
"iop/apps/node/internal/adapters/ollama"
"iop/apps/node/internal/adapters/openai_compat"
"iop/apps/node/internal/adapters/vllm"
"iop/packages/go/config"
iop "iop/proto/gen/iop"
)
type ConfigSet struct {
Registry *Registry
Items map[string]ConfigItem
Runtime RuntimeConfig
}
// RuntimeConfig captures the node-wide runtime tuning carried alongside the
// adapter set so config refresh can detect concurrency and workspace changes.
type RuntimeConfig struct {
Concurrency int
WorkspaceRoot string
}
type ConfigItem struct {
Key string
Type string
Fingerprint string
}
type ConfigDiff struct {
Added []string
Updated []string
Removed []string
Unchanged []string
}
func BuildConfigSet(payload *iop.NodeConfigPayload, logger *zap.Logger) (*ConfigSet, error) {
reg := NewRegistry()
items := make(map[string]ConfigItem)
for _, ac := range payload.GetAdapters() {
if !ac.GetEnabled() {
continue
}
instanceKey := ac.GetName()
typeName := ac.GetType()
if instanceKey == "" {
instanceKey = typeName
}
var fingerprint string
switch typeName {
case "mock":
a := mock.New(logger)
reg.RegisterKeyed(instanceKey, typeName, a)
fingerprint = "mock"
case "ollama":
var cfg config.OllamaConf
if m := ac.GetOllama(); m != nil {
cfg = ollamaConfFromProto(m)
} else {
cfg = ollamaConfFromStruct(ac.GetSettings())
}
a := ollama.New(cfg, logger, instanceKey)
reg.RegisterKeyed(instanceKey, typeName, a)
bs, err := json.Marshal(cfg)
if err != nil {
return nil, fmt.Errorf("marshal ollama config: %w", err)
}
fingerprint = string(bs)
case "vllm":
var cfg config.VllmConf
if m := ac.GetVllm(); m != nil {
cfg = vllmConfFromProto(m)
} else {
cfg = vllmConfFromStruct(ac.GetSettings())
}
a := vllm.New(cfg, logger, instanceKey)
reg.RegisterKeyed(instanceKey, typeName, a)
bs, err := json.Marshal(cfg)
if err != nil {
return nil, fmt.Errorf("marshal vllm config: %w", err)
}
fingerprint = string(bs)
case "openai_compat":
var cfg config.OpenAICompatConf
if m := ac.GetOpenaiCompat(); m != nil {
cfg = openAICompatConfFromProto(m)
} else {
cfg = openAICompatConfFromStruct(ac.GetSettings())
}
a := openai_compat.New(cfg, logger, instanceKey)
reg.RegisterKeyed(instanceKey, typeName, a)
bs, err := json.Marshal(cfg)
if err != nil {
return nil, fmt.Errorf("marshal openai_compat config: %w", err)
}
fingerprint = string(bs)
case "cli":
var cfg config.CLIConf
if m := ac.GetCli(); m != nil {
cfg = cliConfFromProto(m)
} else {
cfg = cliConfFromStruct(ac.GetSettings())
}
a := cli.New(cfg, logger)
reg.RegisterKeyed(instanceKey, typeName, a)
bs, err := json.Marshal(cfg)
if err != nil {
return nil, fmt.Errorf("marshal cli config: %w", err)
}
fingerprint = string(bs)
default:
return nil, fmt.Errorf("adapters: unknown adapter type %q", typeName)
}
items[instanceKey] = ConfigItem{
Key: instanceKey,
Type: typeName,
Fingerprint: fingerprint,
}
}
return &ConfigSet{
Registry: reg,
Items: items,
Runtime: RuntimeConfig{
Concurrency: int(payload.GetRuntime().GetConcurrency()),
WorkspaceRoot: payload.GetRuntime().GetWorkspaceRoot(),
},
}, nil
}
func DiffConfigSets(current, next *ConfigSet) ConfigDiff {
var diff ConfigDiff
currItems := make(map[string]ConfigItem)
if current != nil {
currItems = current.Items
}
nextItems := make(map[string]ConfigItem)
if next != nil {
nextItems = next.Items
}
// Added / Updated / Unchanged
for k, nextItem := range nextItems {
currItem, exists := currItems[k]
if !exists {
diff.Added = append(diff.Added, k)
} else if currItem.Type != nextItem.Type || currItem.Fingerprint != nextItem.Fingerprint {
diff.Updated = append(diff.Updated, k)
} else {
diff.Unchanged = append(diff.Unchanged, k)
}
}
// Removed
for k := range currItems {
if _, exists := nextItems[k]; !exists {
diff.Removed = append(diff.Removed, k)
}
}
sort.Strings(diff.Added)
sort.Strings(diff.Updated)
sort.Strings(diff.Removed)
sort.Strings(diff.Unchanged)
return diff
}