Node store/workspace 위치를 Edge가 내려주는 runtime payload에서 분리한다. Chat Completions tool 요청은 내부 실행에서 tool_choice=none으로 낮춰 downstream 자동 tool 호출 요구로 실패하지 않게 맞춘다.
187 lines
4.2 KiB
Go
187 lines
4.2 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 node-wide runtime tuning carried alongside the adapter
|
|
// set so config refresh can detect concurrency changes.
|
|
type RuntimeConfig struct {
|
|
Concurrency int
|
|
}
|
|
|
|
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()),
|
|
},
|
|
}, 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
|
|
}
|