MineContext icon indicating copy to clipboard operation
MineContext copied to clipboard

[BUG]: 修改 Prompt 後點擊「查看歷史記錄」出現「加载历史记录失败」

Open MumuTW opened this issue 1 month ago • 0 comments

🐛 Bug description [Please make everyone to understand it]

在「設定 → Prompts」頁面中,使用者修改並保存 Prompts 後,立即點擊「查看歷史記錄」按鈕,前端會顯示錯誤 toast:

加载历史记录失败

Image

此錯誤訊息無法讓使用者理解實際原因,且在 Debug 模式先前已啟用的情況下仍會發生,導致無法確認是:

  • Debug 模式狀態問題
    還是
  • 歷史檔案讀取 / 權限 / 其他後端錯誤

目前此問題可重現,行為不符合預期。


目前行為(Actual Behavior)

  1. 使用者在設定頁面編輯任一 Prompt 類別內容。

  2. 點擊「保存」按鈕,前端呼叫 POST /api/settings/prompts

  3. 保存成功(顯示「Prompts保存成功」)。

  4. 使用者在同一頁面點擊「查看歷史記錄」。

  5. 前端呼叫 GET /api/settings/prompts/history/{category}

  6. 前端顯示 toast:

    加载历史记录失败

  7. Console 目前只看得到籠統錯誤訊息,無明確 HTTP 狀態碼與後端錯誤原因說明。

🧑‍💻 Step to reproduce

在目前行為發生的前提下,重現路徑如下:

  1. 確認系統已啟動並可透過瀏覽器進入設定頁面。
  2. 在「Prompts 設定」頁,選擇任一 Prompt 分類(例如:content_generation 下的某個子項)。
  3. 修改該 Prompt 內容。
  4. 點擊「保存」:
    • 前端會呼叫 POST /api/settings/prompts
  5. 不重新整理頁面,直接點擊該分類的「查看歷史記錄」按鈕:
    • 前端呼叫 GET /api/settings/prompts/history/{category}
  6. 觀察:
    • 預期:彈出歷史記錄 modal 並顯示歷史列表。
    • 實際:顯示 toast「加载历史记录失败」且歷史列表載入失敗。

👾 Expected result

  • Debug 模式已啟用且歷史檔案存在 的前提下:
    • 點擊「查看歷史記錄」應成功列出歷史版本清單。
  • 若無法讀取歷史記錄,前端應顯示具體原因,例如:
    • Debug 模式未啟用
    • 該分類尚無歷史記錄
    • 伺服器錯誤(含 HTTP 狀態碼與簡短說明)

而不是一律只顯示「加载历史记录失败」。

🚑 Any additional information

相關程式碼位置(目前已查閱部分)

前端:opencontext/web/static/js/settings.js

  • 全域狀態

    let currentPrompts = {};
    
  • 載入 Prompts 並設定 currentPrompts

    // loadPromptsToCategories(...) 內部邏輯(節錄)
    if (promptsData.code === 0 && promptsData.data) {
        const rawPrompts = promptsData.data.prompts || promptsData.data;
        currentPrompts = rawPrompts;
        // 後續依照 PROMPT_CATEGORIES.path 讀取對應的 prompt
    }
    

    目前觀察:
    currentPrompts 可能包含除了純粹 prompt 文本以外的其他設定欄位(例如 content_generation、模型設定等),這些欄位的來源與職責邊界尚未完全釐清。

  • 保存 Prompts

    async function savePrompts() {
        try {
            const response = await fetch('/api/settings/prompts', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ prompts: currentPrompts })
            });
            const data = await response.json();
            // ...
        } catch (e) {
            // ...
        }
    }
    

    這裡會直接將整個 currentPrompts 物件送往 /api/settings/prompts

  • 查看歷史記錄

    async function viewHistory(category) {
        currentCategory = category;
        selectedHistoryFile = null;
    
        try {
            const response = await fetch(`/api/settings/prompts/history/${category}`);
            const data = await response.json();
    
            if (data.code === 0 && data.data) {
                // 渲染歷史列表
            } else {
                showToast('加载历史记录失败', true);
            }
        } catch (error) {
            console.error('加载历史记录失败:', error);
            showToast('加载历史记录失败', true);
        }
    }
    

    目前錯誤處理只顯示統一的錯誤訊息,並未把錯誤原因(例如 debug 未啟用、權限、檔案問題)反映給使用者。


後端:opencontext/server/routes/settings.py

  • Prompts 相關 API

    • POST /api/settings/prompts 會呼叫 prompt_mgr.save_prompts(request.prompts)
    • GET /api/settings/prompts/history/{category} 會在某處檢查 Debug 模式是否啟用:
      debug_config = config.get("content_generation", {}).get("debug", {})
      # 若 debug_config 未啟用,會拒絕讀取歷史(實際邏輯與錯誤訊息需再確認)
      

    上述顯示:歷史記錄的開放條件與 content_generation.debug 設定有關


後端:opencontext/config/prompt_manager.py

  • Prompts 儲存

    class PromptManager:
        def save_prompts(self, prompts_data: dict) -> bool:
            # ...
            with open(user_prompts_path, "w", encoding="utf-8") as f:
                yaml.dump(
                    prompts_data,
                    f,
                    Dumper=LiteralDumper,
                    default_flow_style=False,
                    allow_unicode=True,
                )
    
            # 更新記憶中的 prompts
            self.prompts = self._deep_merge(self.prompts, prompts_data)
            return True
    

    目前行為:
    整個 prompts_data 會原封不動寫入 user_prompts_{lang}.yaml,沒有過濾非 prompt 類的鍵值。


後端:opencontext/config/config_manager.py

  • 一般設定(含 content_generation.debug)儲存

    class ConfigManager:
        def save_user_settings(self, settings: dict) -> None:
            if "content_generation" in settings:
                user_settings["content_generation"] = settings["content_generation"]
            # 寫入 user_setting.yaml
    

    這裡說明:
    content_generation.debug 真正的生效來源是 user_setting.yaml,由 /api/settings/general 管理,並非由 PromptManager.save_prompts 管理。


目前推論的可能問題點(尚未完全證實)

以下為基於程式架構與行為的「合理懷疑」,尚未以實際 HTTP 回應與 server logs 完全驗證,需要開發團隊協助確認。

  1. 前端狀態混用

    • currentPrompts 作為全域物件,被多個函數共用(載入、保存、可能還包括 debug 相關操作)。
    • currentPrompts 可能不僅包含「純 prompts」,也包含 content_generation 等與 general settings 有關的欄位。
  2. API 職責邊界不清

    • POST /api/settings/prompts 在目前實作下,可能被送入含有非 prompt 類欄位的 payload。
    • 後端 PromptManager.save_prompts() 會將整個物件寫入 user_prompts_{lang}.yaml,造成「prompts 檔案中參雜 general 設定欄位」的情況。
  3. Debug 設定與歷史 API 的耦合

    • /api/settings/prompts/history/{category} 會根據 config.get("content_generation").get("debug") 判斷是否允許讀取歷史。
    • 若 debug 狀態與前端或 prompts 檔案的內容出現不一致,可能導致歷史 API 拒絕服務,進而觸發「加载历史记录失败」錯誤。
  4. 錯誤訊息被前端遮蔽

    • 即便後端有返回明確錯誤原因,前端目前一律只顯示「加载历史记录失败」,導致實際 root cause 隱藏在 Network / logs 中。

建議修復方向(Proposal)

1. 前端:明確區分 prompts 與 general 設定

  • savePrompts() 中,只送出「真正屬於 prompts 的資料」:

    • 具體作法可以是:

      • 在組裝 payload 前,deep clone 一份 currentPrompts,移除所有非 prompt 類的頂層 key,例如:
        • content_generation
        • vlm_model
        • embedding_model
        • 其他屬於 general/config 的欄位
    • 目標:確保 /api/settings/prompts 的 payload 只包含「Prompts 設定」,不含 general/debug 相關配置。

  • loadPromptsToCategories() 中:

    • 對從 /api/settings/prompts 取得的資料做一次淨化(只保留與 prompt 類別相關的內容),避免 currentPrompts 被混入不應該存在的 general 設定。

2. 後端:PromptManager.save_prompts 增加防禦性驗證

  • 在實際寫入 user_prompts_{lang}.yaml 前,過濾掉不應由 PromptManager 管理的頂層欄位,例如:

    • content_generation
    • vlm_model
    • embedding_model
    • capture
    • processing
    • logging
  • 保留一份 log,記錄被移除的 key 以利後續追蹤:

    • 例如:

      Removed non-prompt configuration 'content_generation' from prompts data

  • 這樣可以避免 prompts 檔案成為各種設定的「垃圾桶」,也降低將來 schema 演進時的風險。

3. 歷史 API:錯誤訊息與狀態碼的清楚定義

  • 建議針對不同錯誤情境給固定的 code / message,例如:

    • Debug 未啟用:
      • HTTP 400403code: X001message: "Debug mode is not enabled"
    • 沒有歷史記錄:
      • HTTP 200code: 0data: []
    • 檔案讀取錯誤:
      • HTTP 500code: X002message: "Failed to load prompt history"
  • 這樣前端可以根據 data.codeHTTP status 顯示更有意義的提示,而不只是統一的「加载历史记录失败」。

4. 前端錯誤提示改善(與後端錯誤碼配合)

  • viewHistory() 中:

    • 讀取 response.statusdata.codedata.message,對於已知錯誤情境給出具體提示,例如:
      • Debug 未啟用:提示「Debug 模式未啟用,請到系統設定中開啟 Debug 後再嘗試查看歷史記錄」。
      • 其他錯誤:顯示簡短錯誤描述,並在 Console 中輸出完整錯誤資訊以供開發人員除錯。

🛠️ MineContext Version

0.1.5

💻 Platform Details

MacOS

MumuTW avatar Nov 18 '25 07:11 MumuTW