| 1 | package boot |
| 2 | |
| 3 | import ( |
| 4 | "fmt" |
| 5 | "strings" |
| 6 | |
| 7 | "reasonix/internal/config" |
| 8 | "reasonix/internal/event" |
| 9 | ) |
| 10 | |
| 11 | func emitUserConfigUpgradeNotice(sink event.Sink, cfg *config.Config, deepSeekProtocolMigrated bool, deepSeekProtocolMigErr error, endpointRepairs []config.ProviderEndpointRepair) { |
| 12 | if len(endpointRepairs) > 0 { |
| 13 | text, detail := providerEndpointRepairNotice(cfg, endpointRepairs) |
| 14 | sink.Emit(event.Event{ |
| 15 | Kind: event.Notice, |
| 16 | Level: event.LevelInfo, |
| 17 | Text: text, |
| 18 | Detail: detail, |
| 19 | }) |
| 20 | return |
| 21 | } |
| 22 | if deepSeekProtocolMigrated { |
| 23 | detail := cfg.OpenCodeGoUpgradeSummary() |
| 24 | if detail == "" { |
| 25 | detail = "Legacy built-in DeepSeek defaults now use Chat Completions with independent web search." |
| 26 | } |
| 27 | sink.Emit(event.Event{ |
| 28 | Kind: event.Notice, |
| 29 | Level: event.LevelInfo, |
| 30 | Text: "User configuration was upgraded.", |
| 31 | Detail: detail + " Protocol changes start a new provider cache prefix; later requests rebuild normal prefix-cache reuse.", |
| 32 | }) |
| 33 | } else if deepSeekProtocolMigErr != nil { |
| 34 | sink.Emit(event.Event{ |
| 35 | Kind: event.Notice, |
| 36 | Level: event.LevelWarn, |
| 37 | Text: "DeepSeek protocol migration did not complete.", |
| 38 | Detail: deepSeekProtocolMigErr.Error(), |
| 39 | }) |
| 40 | } |
| 41 | } |
| 42 | |
| 43 | func providerEndpointRepairNotice(cfg *config.Config, repairs []config.ProviderEndpointRepair) (string, string) { |
| 44 | lang := "" |
| 45 | if cfg != nil { |
| 46 | lang = cfg.DesktopLanguage() |
| 47 | if lang == "" { |
| 48 | lang = cfg.Language |
| 49 | } |
| 50 | } |
| 51 | chinese := strings.HasPrefix(strings.ToLower(strings.TrimSpace(lang)), "zh") |
| 52 | details := make([]string, 0, len(repairs)) |
| 53 | for _, repair := range repairs { |
| 54 | if chinese { |
| 55 | details = append(details, fmt.Sprintf( |
| 56 | "已自动修复供应商连接“%s”:协议由 %s 调整为 %s;请求地址为 %s", |
| 57 | repair.ProviderName, |
| 58 | providerProtocolNoticeLabel(repair.FromProtocol), |
| 59 | providerProtocolNoticeLabel(repair.ToProtocol), |
| 60 | repair.RequestURL, |
| 61 | )) |
| 62 | continue |
| 63 | } |
| 64 | details = append(details, fmt.Sprintf( |
| 65 | "%s: protocol %s → %s; request URL %s", |
| 66 | repair.ProviderName, |
| 67 | providerProtocolNoticeLabel(repair.FromProtocol), |
| 68 | providerProtocolNoticeLabel(repair.ToProtocol), |
| 69 | repair.RequestURL, |
| 70 | )) |
| 71 | } |
| 72 | if chinese { |
| 73 | return "已自动修复供应商连接设置。", strings.Join(details, "\n") + "。协议变更会启用新的供应商缓存前缀,后续请求会重新建立正常的前缀缓存复用。" |
| 74 | } |
| 75 | return "Provider connection settings were repaired.", strings.Join(details, "\n") + ". Protocol changes start a new provider cache prefix; later requests rebuild normal prefix-cache reuse." |
| 76 | } |
| 77 | |
| 78 | func providerProtocolNoticeLabel(kind string) string { |
| 79 | switch strings.ToLower(strings.TrimSpace(kind)) { |
| 80 | case "anthropic": |
| 81 | return "Anthropic Messages" |
| 82 | case "responses", "dashscope-responses": |
| 83 | return "Responses" |
| 84 | case "openai": |
| 85 | return "OpenAI Chat Completions" |
| 86 | default: |
| 87 | return strings.TrimSpace(kind) |
| 88 | } |
| 89 | } |
| 90 |