Escape model picker display text

This commit is contained in:
Frank Song committed 2026-05-14 23:03:48 +08:00
1 parent 5677b12a88
commit 0461b97d15
4 files changed
+25 -3

No files matched your search

+2
View File
@@ -8,6 +8,8 @@
### Fixed
- Model picker rows now escape provider-supplied model names and IDs before rendering, and the providers panel escapes load-error text before inserting it into the DOM.
- **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.
+1 -1
View File
@@ -5569,7 +5569,7 @@ async function loadProvidersPanel(){
list.appendChild(_buildProviderCard(p));
}
}catch(e){
list.innerHTML='<div style="color:var(--error);padding:12px;font-size:13px">Failed to load providers: '+e.message+'</div>';
list.innerHTML='<div style="color:var(--error);padding:12px;font-size:13px">Failed to load providers: '+esc(e.message||String(e))+'</div>';
}
}
+2 -2
View File
@@ -1206,7 +1206,7 @@ function renderModelDropdown(){
}
}
const badgeHtml=m.badge?`<span class="model-opt-badge model-opt-badge--${esc(m.badge.role||'configured')}">${esc(badgeLabel)}</span>`:'';
row.innerHTML=`<div class="model-opt-top"><span class="model-opt-name">${esc(modelName)}</span>${badgeHtml}</div><span class="model-opt-id">${m.id}</span>`;
row.innerHTML=`<div class="model-opt-top"><span class="model-opt-name">${esc(modelName)}</span>${badgeHtml}</div><span class="model-opt-id">${esc(m.id)}</span>`;
row.onclick=()=>selectModelFromDropdown(m.value);
dd.appendChild(row);
}
@@ -1234,7 +1234,7 @@ function renderModelDropdown(){
const badgeHtml=m.badge?`<span class="model-opt-badge model-opt-badge--${esc(m.badge.role||'configured')}">${esc(m.badge.label||'Configured')}</span>`:'';
// Inline provider chip on every row that has a group (#1425)
const providerChip=m.group?`<span class="model-opt-provider">${esc(m.group)}</span>`:'';
row.innerHTML=`<div class="model-opt-top"><span class="model-opt-name">${m.name}</span>${badgeHtml}${providerChip}</div><span class="model-opt-id">${m.id}</span>`;
row.innerHTML=`<div class="model-opt-top"><span class="model-opt-name">${esc(m.name)}</span>${badgeHtml}${providerChip}</div><span class="model-opt-id">${esc(m.id)}</span>`;
row.onclick=()=>selectModelFromDropdown(m.value);
dd.appendChild(row);
}
+20
View File
@@ -0,0 +1,20 @@
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
def test_model_picker_escapes_provider_supplied_model_labels():
src = (ROOT / "static" / "ui.js").read_text()
assert '<span class="model-opt-id">${esc(m.id)}</span>' in src
assert '<span class="model-opt-name">${esc(m.name)}</span>' in src
assert '<span class="model-opt-id">${m.id}</span>' not in src
assert '<span class="model-opt-name">${m.name}</span>' not in src
def test_providers_panel_escapes_load_error_text():
src = (ROOT / "static" / "panels.js").read_text()
assert "Failed to load providers: '+esc(e.message||String(e))+'" in src
assert "Failed to load providers: '+e.message+'" not in src