From a56ec43d29407d68b530c9fa2ace207197fe24d8 Mon Sep 17 00:00:00 2001 From: Frank Song Date: Thu, 14 May 2026 22:57:15 +0800 Subject: [PATCH] Show skill detail API errors --- CHANGELOG.md | 2 ++ .../skill-detail-error-after.png | Bin 0 -> 34247 bytes .../skill-detail-error-before.png | Bin 0 -> 27046 bytes static/panels.js | 26 ++++++++++++++++ tests/test_skill_detail_error_guard.py | 28 ++++++++++++++++++ 5 files changed, 56 insertions(+) create mode 100644 docs/pr-media/guard-skill-detail-errors/skill-detail-error-after.png create mode 100644 docs/pr-media/guard-skill-detail-errors/skill-detail-error-before.png create mode 100644 tests/test_skill_detail_error_guard.py diff --git a/CHANGELOG.md b/CHANGELOG.md index b6df1a29..53e3e6d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ ### Fixed +- Skills detail panes now display API error payloads returned with `success: false` instead of silently rendering an empty `(no content)` view. + - **PR #2234** by @Jordan-SkyLF (refines #2207) — Three update-banner improvements: (1) Update summaries no longer repeat the same bullet under both "What you'll notice" and "Worth knowing" — visible notice items keep priority, and the secondary section is omitted when there is no distinct detail to show. (2) Update summaries now cap large commit lists (24 + probe item) before sending them to the summarizer and disclose when the summary uses only the latest commit subjects, while keeping the full comparison link available — bounds summarizer cost on large update ranges while remaining honest about coverage. (3) Update banners now wrap generated-summary links and long update text on narrow/mobile screens inside the banner instead of pushing controls off-screen. 108-line regression coverage for short-target dedup, repeated Agent-summary bullets, large-range capped input, and responsive wrapping. - **PR #2236** by @jasonjcwu — Silent failure detection in `api/streaming.py` now scans only NEW messages, not the full conversation history. Pre-fix, the `_assistant_added` check at `_run_agent_streaming` scanned all messages in `result["messages"]` (including pre-turn history); if any prior turn contained an assistant response, `_assistant_added` was `True` and the apperror SSE event was silently skipped, leaving the user staring at a blank response after a provider 401/429/rate-limit error. Fix extracts a `_has_new_assistant_reply(all_messages, prev_count)` helper that only inspects messages beyond the pre-turn history offset (`_previous_context_messages`); applied to both the main detection path and the self-heal/retry `_heal_ok` check. 15-test regression suite covering empty/short/long-history scenarios, the heal path, and the `len < prev_count` edge-case fallback. Also includes a small alignment fix to `test_issue1857_usage_overwrite.py` so the FakeAgent message shape matches what the real agent produces. diff --git a/docs/pr-media/guard-skill-detail-errors/skill-detail-error-after.png b/docs/pr-media/guard-skill-detail-errors/skill-detail-error-after.png new file mode 100644 index 0000000000000000000000000000000000000000..9bb58ac5679be01d1642e01548f54b3a7933960a GIT binary patch literal 34247 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

Sf4We8sF`J^{Mw>{otWo3U9{ZEmh+o_!z0smS+2 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 CW=5X? literal 0 HcmV?d00001 diff --git a/static/panels.js b/static/panels.js index 8ebf44d6..b6b06453 100644 --- a/static/panels.js +++ b/static/panels.js @@ -3244,6 +3244,21 @@ function _renderSkillDetail(name, content, linkedFiles) { _setSkillHeaderButtons('read'); } +function _renderSkillError(name, message) { + const title = $('skillDetailTitle'); + const body = $('skillDetailBody'); + const empty = $('skillDetailEmpty'); + if (title) title.textContent = name; + if (body) { + body.innerHTML = `

${esc(message || t('skill_load_failed'))}
`; + body.style.display = ''; + } + if (empty) empty.style.display = 'none'; + _currentSkillDetail = null; + _skillMode = 'empty'; + _setSkillHeaderButtons('empty'); +} + function _setSkillHeaderButtons(mode) { const editBtn = $('btnEditSkillDetail'); const delBtn = $('btnDeleteSkillDetail'); @@ -3264,6 +3279,12 @@ async function openSkill(name, el) { _editingSkillName = null; try { const data = await api(`/api/skills/content?name=${encodeURIComponent(name)}`); + if (data && (data.success === false || data.error)) { + const message = data.error || t('skill_load_failed'); + _renderSkillError(name, message); + setStatus(t('skill_load_failed') + message); + return; + } _currentSkillDetail = { name, content: data.content || '', linked_files: data.linked_files || {} }; _renderSkillDetail(name, data.content || '', data.linked_files || {}); } catch(e) { setStatus(t('skill_load_failed') + e.message); } @@ -3272,6 +3293,11 @@ async function openSkill(name, el) { async function openSkillFile(skillName, filePath) { try { const data = await api(`/api/skills/content?name=${encodeURIComponent(skillName)}&file=${encodeURIComponent(filePath)}`); + if (data && data.error) { + _renderSkillError(skillName, data.error); + setStatus(t('skill_file_load_failed') + data.error); + return; + } const body = $('skillDetailBody'); if (!body) return; const ext = (filePath.split('.').pop() || '').toLowerCase(); diff --git a/tests/test_skill_detail_error_guard.py b/tests/test_skill_detail_error_guard.py new file mode 100644 index 00000000..f4cb02aa --- /dev/null +++ b/tests/test_skill_detail_error_guard.py @@ -0,0 +1,28 @@ +from pathlib import Path + + +ROOT = Path(__file__).resolve().parent.parent +PANELS_JS = (ROOT / "static" / "panels.js").read_text(encoding="utf-8") + + +def test_skill_detail_api_error_renders_in_detail_pane(): + assert "function _renderSkillError(name, message)" in PANELS_JS + assert "data.success === false || data.error" in PANELS_JS + assert "_renderSkillError(name, message);" in PANELS_JS + assert "_currentSkillDetail = null;" in PANELS_JS + assert "_setSkillHeaderButtons('empty');" in PANELS_JS + + +def test_skill_detail_no_longer_silently_falls_back_on_error_payload(): + success_guard = PANELS_JS.index("data.success === false || data.error") + render_detail = PANELS_JS.index("_renderSkillDetail(name, data.content || ''") + assert success_guard < render_detail + + +def test_skill_linked_file_api_error_renders_in_detail_pane(): + file_fetch = PANELS_JS.index("/api/skills/content?name=${encodeURIComponent(skillName)}&file=") + file_error_guard = PANELS_JS.index("if (data && data.error)", file_fetch) + file_render = PANELS_JS.index("_renderSkillError(skillName, data.error);", file_fetch) + body_lookup = PANELS_JS.index("const body = $('skillDetailBody');", file_fetch) + assert file_error_guard < body_lookup + assert file_render < body_lookup