diff --git a/internal/api/handlers/management/config_lists.go b/internal/api/handlers/management/config_lists.go index bc261cc8..af48b14f 100644 --- a/internal/api/handlers/management/config_lists.go +++ b/internal/api/handlers/management/config_lists.go @@ -116,7 +116,7 @@ func sanitizeStringSlice(in []string) []string { func geminiKeyStringsFromConfig(cfg *config.Config) []string { if cfg == nil || len(cfg.GeminiKey) == 0 { - return []string{} + return nil } out := make([]string, 0, len(cfg.GeminiKey)) for i := range cfg.GeminiKey { diff --git a/internal/config/config.go b/internal/config/config.go index 68008a9b..baed1a54 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -544,6 +544,9 @@ func mergeMappingPreserve(dst, src *yaml.Node) { dv := dst.Content[idx+1] mergeNodePreserve(dv, sv) } else { + if shouldSkipEmptyCollectionOnPersist(sk.Value, sv) { + continue + } // Append new key/value pair by deep-copying from src dst.Content = append(dst.Content, deepCopyNode(sk), deepCopyNode(sv)) } @@ -623,6 +626,33 @@ func findMapKeyIndex(mapNode *yaml.Node, key string) int { return -1 } +func shouldSkipEmptyCollectionOnPersist(key string, node *yaml.Node) bool { + switch key { + case "generative-language-api-key", + "gemini-api-key", + "claude-api-key", + "codex-api-key", + "openai-compatibility": + return isEmptyCollectionNode(node) + default: + return false + } +} + +func isEmptyCollectionNode(node *yaml.Node) bool { + if node == nil { + return true + } + switch node.Kind { + case yaml.SequenceNode: + return len(node.Content) == 0 + case yaml.ScalarNode: + return node.Tag == "!!null" + default: + return false + } +} + // deepCopyNode creates a deep copy of a yaml.Node graph. func deepCopyNode(n *yaml.Node) *yaml.Node { if n == nil {