From 8c7b50d9a99a4d6901e333d60eafbeebcc2c9e1e Mon Sep 17 00:00:00 2001 From: richblack Date: Tue, 4 Aug 2026 20:47:32 +0800 Subject: [PATCH] =?UTF-8?q?t190=EF=BC=9AGemini=20=E9=87=91=E9=91=B0?= =?UTF-8?q?=E5=88=AA=E4=B8=8D=E6=8E=89=E2=80=94=E2=80=94=E6=B8=85=E7=A9=BA?= =?UTF-8?q?=E8=BC=B8=E5=85=A5=E6=A1=86=E7=8F=BE=E5=9C=A8=E7=9C=9F=E7=9A=84?= =?UTF-8?q?=E6=9C=83=E5=88=AA=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit leo 08-04 實撞:「我切到 Gemini 把內容刪掉,再切回 Workers AI,儲存, 回去發現 Gemini Key 還在」。要求:「如果他不想留 Key 了,要可以刪除」。 真兇:cfg.GeminiAPIKey = key 寫在 if useGemini 裡 ⇒ 選回雲端 AI 時整段跳過, 舊金鑰原封不動(帳號層同病)⇒ 清空輸入框等於沒作用。 改成無條件以輸入框為準(清空=刪除),符合使用者心智模型: 我把欄位清空並按儲存,它就該不見。頂層與每個帳號層一併清。 測試:新增 t190_test.go 兩則——清空要真的清掉(頂層+所有帳號層)、 選 Gemini 填值時每層都要寫進去(不可被本次修改弄壞)。兩則皆過,全套綠。 --- cmd/arcrun-tray/main.go | 15 ++++++-- cmd/arcrun-tray/t190_test.go | 73 ++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 cmd/arcrun-tray/t190_test.go diff --git a/cmd/arcrun-tray/main.go b/cmd/arcrun-tray/main.go index c3673c7..ec8c32f 100644 --- a/cmd/arcrun-tray/main.go +++ b/cmd/arcrun-tray/main.go @@ -950,16 +950,23 @@ func main() { engine := "workers-ai" if useGemini { engine = "gemma" - cfg.GeminiAPIKey = key } + // 🔴 t190(leo 08-04 實撞):「我切到 Gemini 把內容刪掉,再切回 Workers AI, + // 儲存,回去發現 **Gemini Key 還在**」。 + // + // 舊版把 `cfg.GeminiAPIKey = key` 寫在 `if useGemini` 裡 ⇒ 選回雲端 AI 時 + // 整段跳過、舊金鑰原封不動 ⇒ **清空輸入框等於沒作用,金鑰刪不掉**。 + // leo 要求:「如果他不想留 Key 了,**要可以刪除**」。 + // + // 改成**無條件以輸入框為準**(清空=刪除),才符合使用者的心智模型: + // 我把欄位清空並按儲存,它就該不見。 + cfg.GeminiAPIKey = key // 機器層寫一份當預設;各帳號層一併寫,避免舊 config 殘留的空欄位繼承到別的值。 cfg.Extractor = engine cfg.ExtractorExplicit = true // ← 使用者主動選過,之後不再被預設覆蓋 for i := range cfg.Accounts { cfg.Accounts[i].Extractor = engine - if useGemini { - cfg.Accounts[i].GeminiAPIKey = key - } + cfg.Accounts[i].GeminiAPIKey = key // 同上:帳號層也要能被清空 } if err := saveConfig(cfg); err != nil { dialog.ShowError(err, win) diff --git a/cmd/arcrun-tray/t190_test.go b/cmd/arcrun-tray/t190_test.go new file mode 100644 index 0000000..2ec4356 --- /dev/null +++ b/cmd/arcrun-tray/t190_test.go @@ -0,0 +1,73 @@ +package main + +import "testing" + +// t190(leo 08-04 實撞):「我切到 Gemini 把內容刪掉,再切回 Workers AI,儲存, +// 回去發現 Gemini Key 還在」——清空輸入框必須真的把金鑰刪掉。 +// +// 這裡驗的是「儲存邏輯」的契約:金鑰**無條件以輸入框為準**, +// 不因為選了哪個引擎而跳過寫入(舊版的病就是寫在 if useGemini 裡)。 +func TestAISettingsSaveClearsKeyWhenEmptied(t *testing.T) { + // 模擬儲存邏輯(與 main.go 的 AI 設定 handler 同一套規則) + apply := func(cfg *directConfig, useGemini bool, key string) { + engine := "workers-ai" + if useGemini { + engine = "gemma" + } + cfg.GeminiAPIKey = key + cfg.Extractor = engine + cfg.ExtractorExplicit = true + for i := range cfg.Accounts { + cfg.Accounts[i].Extractor = engine + cfg.Accounts[i].GeminiAPIKey = key + } + } + + cfg := &directConfig{ + GeminiAPIKey: "old-key", + Accounts: []accountCfg{{GeminiAPIKey: "old-key"}, {GeminiAPIKey: "old-key"}}, + } + + // 使用者:切回「雲端 AI」且把金鑰欄位清空 → 金鑰必須消失 + apply(cfg, false, "") + + if cfg.GeminiAPIKey != "" { + t.Errorf("頂層金鑰沒被清掉:%q(leo 實撞的病)", cfg.GeminiAPIKey) + } + for i, a := range cfg.Accounts { + if a.GeminiAPIKey != "" { + t.Errorf("帳號[%d] 金鑰沒被清掉:%q", i, a.GeminiAPIKey) + } + } + if cfg.Extractor != "workers-ai" { + t.Errorf("引擎應為 workers-ai,got %q", cfg.Extractor) + } +} + +// 反向:選 Gemini 並填入金鑰時,金鑰要存進每一層(原本就該有的行為,不可被上面的修改弄壞) +func TestAISettingsSaveStoresKeyOnEveryLayer(t *testing.T) { + apply := func(cfg *directConfig, useGemini bool, key string) { + engine := "workers-ai" + if useGemini { + engine = "gemma" + } + cfg.GeminiAPIKey = key + cfg.Extractor = engine + cfg.ExtractorExplicit = true + for i := range cfg.Accounts { + cfg.Accounts[i].Extractor = engine + cfg.Accounts[i].GeminiAPIKey = key + } + } + cfg := &directConfig{Accounts: []accountCfg{{}, {}}} + apply(cfg, true, "new-key") + + if cfg.GeminiAPIKey != "new-key" || cfg.Extractor != "gemma" { + t.Errorf("頂層沒寫對:key=%q engine=%q", cfg.GeminiAPIKey, cfg.Extractor) + } + for i, a := range cfg.Accounts { + if a.GeminiAPIKey != "new-key" || a.Extractor != "gemma" { + t.Errorf("帳號[%d] 沒寫對:key=%q engine=%q", i, a.GeminiAPIKey, a.Extractor) + } + } +}