mirror of
https://github.com/nesquena/hermes-webui.git
synced 2026-07-20 22:51:07 +00:00
100 lines
4.0 KiB
Python
100 lines
4.0 KiB
Python
"""Regression tests for issue #4539: transparent-stream tool-call rows
|
|
vanish on turn settle, reappear only after tab/session switch."""
|
|
|
|
import re
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
UI_JS = (ROOT / "static" / "ui.js").read_text(encoding="utf-8")
|
|
|
|
|
|
def _settled_cleanup_selector():
|
|
"""Extract the settled-node cleanup querySelectorAll string."""
|
|
anchor = ".tool-worklog-group:not([data-compression-card])"
|
|
idx = UI_JS.index(anchor)
|
|
marker = ".forEach(el=>el.remove())"
|
|
end = UI_JS.index(marker, idx) + len(marker)
|
|
line_start = UI_JS.rfind("\n", 0, idx) + 1
|
|
return UI_JS[line_start:end]
|
|
|
|
|
|
def _tool_bucketing_block():
|
|
"""Extract the tool-call bucketing region including burst-ID pre-scan."""
|
|
start = UI_JS.index("const knownBurstIds=")
|
|
end = UI_JS.index("\n }", UI_JS.index("for(const tc of (S.toolCalls||[])){", start)) + len("\n }")
|
|
return UI_JS[start:end]
|
|
|
|
|
|
class TestCleanupSelectorProtectsTransparentToolRows:
|
|
"""Fix A: the settled-node cleanup must not remove transparent tool rows."""
|
|
|
|
def test_tool_card_row_arm_excludes_event_type_tool(self):
|
|
selector = _settled_cleanup_selector()
|
|
assert ".tool-card-row:not([data-compression-card]):not([data-event-type=\"tool\"])" in selector, (
|
|
"The .tool-card-row cleanup arm must exclude [data-event-type='tool'] "
|
|
"rows to protect transparent tool-call rows from deletion"
|
|
)
|
|
|
|
def test_thinking_arm_still_excludes_event_type_thinking(self):
|
|
selector = _settled_cleanup_selector()
|
|
assert ":not([data-event-type=\"thinking\"])" in selector, (
|
|
"The .agent-activity-thinking arm must still exclude "
|
|
"[data-event-type='thinking'] rows"
|
|
)
|
|
|
|
def test_tool_and_thinking_arms_follow_same_event_type_pattern(self):
|
|
selector = _settled_cleanup_selector()
|
|
assert ":not([data-event-type=\"tool\"])" in selector
|
|
assert ":not([data-event-type=\"thinking\"])" in selector
|
|
|
|
|
|
class TestBurstIdFallbackWhenSegmentLacksBurstAttribute:
|
|
"""Fix B: bucketing must fall back to assistant:${aIdx} when no segment
|
|
carries a matching data-activity-burst-id."""
|
|
|
|
def test_burst_resolvable_check_before_burst_key(self):
|
|
block = _tool_bucketing_block()
|
|
assert "burstResolvable" in block, (
|
|
"The tool-call bucketing loop must check burst-ID resolvability "
|
|
"before using 'burst:' as the bucket key"
|
|
)
|
|
|
|
def test_burst_ids_pre_scanned_from_assistant_segments(self):
|
|
block = _tool_bucketing_block()
|
|
assert "assistantSegments.values()" in block, (
|
|
"knownBurstIds must be built from assistantSegments before the loop"
|
|
)
|
|
assert "knownBurstIds.has(burstId)" in block, (
|
|
"burstResolvable must use the pre-scanned knownBurstIds set"
|
|
)
|
|
|
|
def test_fallback_uses_burst_resolvable_not_raw_burst_id(self):
|
|
block = _tool_bucketing_block()
|
|
assert re.search(r"burstResolvable\?.*burst:", block), (
|
|
"The bucket key must use burstResolvable (not raw burstId) "
|
|
"as the guard for the burst: key path"
|
|
)
|
|
|
|
def test_assistant_fallback_preserved(self):
|
|
block = _tool_bucketing_block()
|
|
assert "`assistant:${aIdx}`" in block, (
|
|
"The assistant:${aIdx} fallback must still be present"
|
|
)
|
|
|
|
|
|
class TestDecorateTransparentEventRowSetsEventType:
|
|
"""Confirms the decorator still sets the attributes the cleanup
|
|
selector depends on for its exclusion."""
|
|
|
|
def test_decorator_sets_data_event_type(self):
|
|
start = UI_JS.index("function _decorateTransparentEventRow(row, opts){")
|
|
end = UI_JS.index("\nfunction ", start + 1)
|
|
block = UI_JS[start:end]
|
|
assert "row.setAttribute('data-event-type',type)" in block
|
|
|
|
def test_tool_type_triggers_transparent_event_card(self):
|
|
start = UI_JS.index("function _decorateTransparentEventRow(row, opts){")
|
|
end = UI_JS.index("\nfunction ", start + 1)
|
|
block = UI_JS[start:end]
|
|
assert "if(type==='tool')" in block
|