From d34d11821b89da66da22013b4a5ef44a8f4f6eba Mon Sep 17 00:00:00 2001 From: AJV20 <24819659+AJV20@users.noreply.github.com> Date: Fri, 29 May 2026 22:22:15 -0400 Subject: [PATCH] fix: label tool output cards persistently --- CHANGELOG.md | 7 ++++ static/style.css | 3 +- static/ui.js | 1 + ...ssue2867_tool_output_visual_distinction.py | 33 +++++++++++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 tests/test_issue2867_tool_output_visual_distinction.py diff --git a/CHANGELOG.md b/CHANGELOG.md index ea29cc24..c8ec9465 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,13 @@ ## [Unreleased] +## [v0.51.171] — 2026-05-30 — Release EQ (stage-batch53 — tool-output card badge + Neon opt-in skin) + +### Added + +- Tool-call output cards now carry a persistent "Tool output" badge and accent rail so tool output stays visually distinct from final assistant responses without requiring hover (#2867). +- New opt-in "Neon" cyberpunk skin (dark-first, purple/cyan accents). Default-off; select it from the skin list like Catppuccin or Nous. + ## [v0.51.170] — 2026-05-30 — Release EP (stage-batch52 — run-aware SSE replay cursors) ### Fixed diff --git a/static/style.css b/static/style.css index 90b36834..0b9097e5 100644 --- a/static/style.css +++ b/static/style.css @@ -2544,11 +2544,12 @@ body.resizing .sidebar{transition:none!important;} display:none; } } -.tool-card{background:var(--surface-subtle);border:1px solid var(--border-muted);border-left:2px solid var(--border-muted);border-radius:var(--radius-card);margin:2px 0;overflow:hidden;transition:border-color .15s,background-color .15s;} +.tool-card{background:var(--surface-subtle);border:1px solid var(--border-muted);border-left:3px solid var(--accent-bg-strong);border-radius:var(--radius-card);margin:2px 0;overflow:hidden;transition:border-color .15s,background-color .15s;} .tool-card:hover{border-color:var(--border2);background:var(--surface-subtle-hover);} .tool-card-running{border-color:var(--accent-bg-strong);background:var(--accent-bg);} .tool-card-header{display:flex;align-items:center;gap:var(--space-2);padding:var(--space-1) var(--space-3);cursor:pointer;user-select:none;} .tool-card-icon{font-size:13px;flex-shrink:0;opacity:.65;} +.tool-card-badge{flex-shrink:0;font-size:10px;line-height:1.2;text-transform:uppercase;letter-spacing:.045em;font-weight:700;color:var(--accent-text);background:var(--accent-bg);border:1px solid var(--accent-bg-strong);border-radius:999px;padding:1px 6px;} .tool-card-name{font-size:var(--font-size-xs);font-weight:600;color:var(--muted);font-family:'SF Mono',ui-monospace,monospace;flex-shrink:0;} .tool-card-preview{font-size:var(--font-size-xs);color:var(--muted);opacity:.62;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;} .tool-card-toggle{font-size:10px;color:var(--muted);opacity:.45;flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;transform-origin:center;transition:transform .18s ease;will-change:transform;} diff --git a/static/ui.js b/static/ui.js index 50ffce78..5f2a9360 100644 --- a/static/ui.js +++ b/static/ui.js @@ -6987,6 +6987,7 @@ function buildToolCard(tc){
${runIndicator} ${icon} + Tool output ${esc(displayName)} ${esc(previewText)} ${hasDetail?`${li('chevron-right',12)}`:''} diff --git a/tests/test_issue2867_tool_output_visual_distinction.py b/tests/test_issue2867_tool_output_visual_distinction.py new file mode 100644 index 00000000..f8daca29 --- /dev/null +++ b/tests/test_issue2867_tool_output_visual_distinction.py @@ -0,0 +1,33 @@ +from pathlib import Path + +ROOT = Path(__file__).resolve().parent.parent +UI_JS = (ROOT / "static" / "ui.js").read_text(encoding="utf-8") +STYLE_CSS = (ROOT / "static" / "style.css").read_text(encoding="utf-8") + + +def test_tool_cards_render_persistent_tool_output_badge(): + """Tool output must remain distinguishable without relying on hover state.""" + build_start = UI_JS.index('function buildToolCard(tc){') + build_end = UI_JS.index('function _syncToolCallGroupSummary', build_start) + build_tool_card = UI_JS[build_start:build_end] + + assert 'Tool output' in build_tool_card + assert '${esc(displayName)}' in build_tool_card + assert build_tool_card.index('class="tool-card-badge"') < build_tool_card.index('class="tool-card-name"') + + +def test_tool_card_badge_style_is_not_hover_only(): + badge_rule_start = STYLE_CSS.index('.tool-card-badge{') + badge_rule_end = STYLE_CSS.index('}', badge_rule_start) + badge_rule = STYLE_CSS[badge_rule_start:badge_rule_end] + + assert '.tool-card:hover .tool-card-badge' not in STYLE_CSS + assert 'text-transform:uppercase' in badge_rule + assert 'background:var(--accent-bg)' in badge_rule + assert 'border:1px solid var(--accent-bg-strong)' in badge_rule + assert 'color:var(--accent-text)' in badge_rule + + +def test_tool_cards_have_persistent_accent_rail(): + assert '.tool-card{background:var(--surface-subtle);' in STYLE_CSS + assert 'border-left:3px solid var(--accent-bg-strong)' in STYLE_CSS