返回 DeepSeek-Reasonix
load_normalize.go
根目录 / internal / config / load_normalize.go
1 package config
2
3 import (
4 "fmt"
5 "strings"
6
7 "reasonix/internal/permissionpreset"
8 )
9
10 // normalizeLoadedConfig applies post-merge compatibility repairs and validates
11 // mode enums in their established order.
12 func normalizeLoadedConfig(cfg *Config) error {
13 normalizePermissionPresetFields(cfg)
14 normalizePluginCommandLines(cfg)
15 normalizeLegacyEffort(cfg)
16 cfg.ignoredLegacyStepLimits = normalizeLegacyAgentStepLimits(cfg)
17 normalizeRetiredAutoPlan(cfg)
18 if err := validateCompletionValidationModes(cfg.Agent.CompletionValidation); err != nil {
19 return err
20 }
21 normalizeLegacyMCPTiers(cfg)
22 normalizeLegacyStepFunBaseURLs(cfg)
23 normalizeLegacyLongCatContextWindows(cfg)
24 normalizeLegacyQwenContextWindows(cfg)
25 normalizeLegacyStepFunContextWindows(cfg)
26 normalizeLegacyKimiK3Catalog(cfg)
27 normalizeOpenCodeGoRuntimeCompatibility(cfg)
28 normalizeLegacyOpenCodeGoInstalls(cfg)
29 normalizeLegacyMimoCustomProviders(cfg)
30 normalizeLegacyProviderModels(cfg)
31 normalizeDesktopOfficialProviderAccess(cfg)
32 // Project reasonix.toml files remain read-only during runtime loading, but
33 // exact catalog routes can still safely repair a stale protocol in memory.
34 // The user-global startup path persists the same repair before this load.
35 repairProviderEndpointContracts(cfg)
36 normalizeOfficialDeepSeekModels(cfg)
37 migrateBillingDisplayCurrency(cfg)
38 freezeProviderBillingCurrencies(cfg)
39 applyDeepSeekOfficialDefaultPricing(cfg)
40 backfillDeepSeekOfficialPrices(cfg)
41 normalizeEffortConfig(cfg)
42 backfillDeepSeekPro(cfg)
43 return nil
44 }
45
46 // normalizePermissionPresetFields is the load-time compatibility boundary for
47 // user-facing execution presets. Known legacy values are migrated to canonical
48 // names. Unknown non-empty values fail closed and produce a visible load
49 // warning rather than silently inheriting a more permissive default.
50 func normalizePermissionPresetFields(cfg *Config) {
51 if cfg == nil {
52 return
53 }
54 normalize := func(path string, value *string, emptyDefault bool) {
55 raw := strings.ToLower(strings.TrimSpace(*value))
56 if raw == "" {
57 if emptyDefault {
58 *value = string(permissionpreset.WorkspaceWrite)
59 }
60 return
61 }
62 known := permissionpreset.Valid(raw)
63 if !known {
64 switch raw {
65 case "ask", "auto", "yolo", "readonly", "read_only", "workspace", "workspace_write", "danger_full_access", "full", "full-access", "bypass":
66 known = true
67 }
68 }
69 *value = string(permissionpreset.Normalize(raw))
70 if !known {
71 cfg.addLoadWarning(fmt.Sprintf("%s has unknown permission preset %q; using read-only", path, raw))
72 }
73 }
74 normalize("desktop.default_tool_approval_mode", &cfg.Desktop.DefaultToolApprovalMode, true)
75 normalize("bot.tool_approval_mode", &cfg.Bot.ToolApprovalMode, true)
76 normalize("bot.qq.tool_approval_mode", &cfg.Bot.QQ.ToolApprovalMode, false)
77 normalize("bot.dingtalk.tool_approval_mode", &cfg.Bot.Dingtalk.ToolApprovalMode, false)
78 for i := range cfg.Bot.Connections {
79 normalize(fmt.Sprintf("bot.connections[%d].tool_approval_mode", i), &cfg.Bot.Connections[i].ToolApprovalMode, false)
80 }
81 for i := range cfg.Bot.Routes {
82 normalize(fmt.Sprintf("bot.routes[%d].tool_approval_mode", i), &cfg.Bot.Routes[i].ToolApprovalMode, false)
83 }
84 }
85
85 lines GO