返回 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 normalizeLegacyKimiK3Catalog(cfg)
26 normalizeOpenCodeGoRuntimeCompatibility(cfg)
27 normalizeLegacyOpenCodeGoInstalls(cfg)
28 normalizeLegacyMimoCustomProviders(cfg)
29 normalizeLegacyProviderModels(cfg)
30 normalizeDesktopOfficialProviderAccess(cfg)
31 // Project reasonix.toml files remain read-only during runtime loading, but
32 // exact catalog routes can still safely repair a stale protocol in memory.
33 // The user-global startup path persists the same repair before this load.
34 repairProviderEndpointContracts(cfg)
35 normalizeOfficialDeepSeekModels(cfg)
36 migrateBillingDisplayCurrency(cfg)
37 freezeProviderBillingCurrencies(cfg)
38 applyDeepSeekOfficialDefaultPricing(cfg)
39 backfillDeepSeekOfficialPrices(cfg)
40 normalizeEffortConfig(cfg)
41 backfillDeepSeekPro(cfg)
42 return nil
43 }
44
45 // normalizePermissionPresetFields is the load-time compatibility boundary for
46 // user-facing execution presets. Known legacy values are migrated to canonical
47 // names. Unknown non-empty values fail closed and produce a visible load
48 // warning rather than silently inheriting a more permissive default.
49 func normalizePermissionPresetFields(cfg *Config) {
50 if cfg == nil {
51 return
52 }
53 normalize := func(path string, value *string, emptyDefault bool) {
54 raw := strings.ToLower(strings.TrimSpace(*value))
55 if raw == "" {
56 if emptyDefault {
57 *value = string(permissionpreset.WorkspaceWrite)
58 }
59 return
60 }
61 known := permissionpreset.Valid(raw)
62 if !known {
63 switch raw {
64 case "ask", "auto", "yolo", "readonly", "read_only", "workspace", "workspace_write", "danger_full_access", "full", "full-access", "bypass":
65 known = true
66 }
67 }
68 *value = string(permissionpreset.Normalize(raw))
69 if !known {
70 cfg.addLoadWarning(fmt.Sprintf("%s has unknown permission preset %q; using read-only", path, raw))
71 }
72 }
73 normalize("desktop.default_tool_approval_mode", &cfg.Desktop.DefaultToolApprovalMode, true)
74 normalize("bot.tool_approval_mode", &cfg.Bot.ToolApprovalMode, true)
75 normalize("bot.qq.tool_approval_mode", &cfg.Bot.QQ.ToolApprovalMode, false)
76 normalize("bot.dingtalk.tool_approval_mode", &cfg.Bot.Dingtalk.ToolApprovalMode, false)
77 for i := range cfg.Bot.Connections {
78 normalize(fmt.Sprintf("bot.connections[%d].tool_approval_mode", i), &cfg.Bot.Connections[i].ToolApprovalMode, false)
79 }
80 for i := range cfg.Bot.Routes {
81 normalize(fmt.Sprintf("bot.routes[%d].tool_approval_mode", i), &cfg.Bot.Routes[i].ToolApprovalMode, false)
82 }
83 }
84
84 lines GO