mirror of
https://github.com/nesquena/hermes-webui.git
synced 2026-05-24 18:50:15 +00:00
91 lines
4.2 KiB
Python
91 lines
4.2 KiB
Python
"""Regression tests for per-turn response duration in WebUI.
|
|
|
|
The WebUI should expose how long an agent turn took, using backend timing so
|
|
reload/reconnect does not lose the measurement.
|
|
"""
|
|
from pathlib import Path
|
|
|
|
REPO = Path(__file__).resolve().parent.parent
|
|
STREAMING_PY = (REPO / "api" / "streaming.py").read_text(encoding="utf-8")
|
|
MESSAGES_JS = (REPO / "static" / "messages.js").read_text(encoding="utf-8")
|
|
ROUTES_PY = (REPO / "api" / "routes.py").read_text(encoding="utf-8")
|
|
UI_JS = (REPO / "static" / "ui.js").read_text(encoding="utf-8")
|
|
CSS = (REPO / "static" / "style.css").read_text(encoding="utf-8")
|
|
|
|
|
|
def test_streaming_done_payload_includes_backend_turn_duration():
|
|
assert "duration_seconds" in STREAMING_PY, (
|
|
"api/streaming.py should include a backend-measured duration_seconds "
|
|
"field in the done usage payload."
|
|
)
|
|
assert "pending_started_at" in STREAMING_PY and "time.time()" in STREAMING_PY, (
|
|
"Turn duration should be measured from the persisted pending_started_at "
|
|
"start time, not only from browser-local state."
|
|
)
|
|
assert "recovered/legacy flows" in STREAMING_PY, (
|
|
"The missing-start fallback should be documented so it is not mistaken "
|
|
"for the primary timing path."
|
|
)
|
|
assert "_turnDuration" in STREAMING_PY, (
|
|
"The measured duration should be persisted on the assistant message so "
|
|
"it survives reload after the SSE stream settles."
|
|
)
|
|
|
|
|
|
def test_done_handler_persists_duration_on_last_assistant_message():
|
|
assert "d.usage.duration_seconds" in MESSAGES_JS, (
|
|
"static/messages.js should read duration_seconds from the done usage payload."
|
|
)
|
|
assert "lastAsst._turnDuration" in MESSAGES_JS, (
|
|
"The done handler should attach the duration to the last assistant message "
|
|
"so renderMessages() can display it after the live stream settles."
|
|
)
|
|
|
|
|
|
def test_ui_formats_and_renders_turn_duration_in_footer_and_activity_summary():
|
|
assert "function _formatTurnDuration" in UI_JS, (
|
|
"ui.js should centralize duration formatting for footer and compact activity display."
|
|
)
|
|
assert "msg-duration-inline" in UI_JS and "Done in" in UI_JS, (
|
|
"Expanded/non-activity display should show a subtle footer chip like 'Done in 42s'."
|
|
)
|
|
assert "tool-call-group-duration" in UI_JS, (
|
|
"Compact tool activity summary should have a dedicated duration span at the end of the line."
|
|
)
|
|
assert "data-turn-duration" in UI_JS, (
|
|
"Activity groups need a stable data-turn-duration hook so settled duration can update the summary."
|
|
)
|
|
assert "compactActivityForMessage" in UI_JS, (
|
|
"When compact activity is present, duration should live on the Activity row "
|
|
"instead of being duplicated in the assistant footer."
|
|
)
|
|
assert ".msg-duration-inline" in CSS and ".tool-call-group-duration" in CSS, (
|
|
"Duration UI should have explicit CSS hooks for the footer chip and compact activity summary."
|
|
)
|
|
|
|
|
|
def test_active_compact_activity_elapsed_timer_uses_persisted_start_time():
|
|
assert '"pending_started_at": s.pending_started_at' in ROUTES_PY, (
|
|
"/api/chat/start should return the persisted pending_started_at timestamp "
|
|
"so the live timer starts from backend/session truth."
|
|
)
|
|
assert "startData.pending_started_at" in MESSAGES_JS, (
|
|
"send() should copy chat-start pending_started_at into S.session before "
|
|
"attaching the live stream."
|
|
)
|
|
assert "function _formatActiveElapsedTimer" in UI_JS and "padStart(2,'0')" in UI_JS, (
|
|
"ui.js should format the running timer in MM:SS form."
|
|
)
|
|
assert "data-turn-started-at" in UI_JS and "data-active-turn-elapsed" in UI_JS, (
|
|
"Live compact Activity groups need stable start-time and active-elapsed "
|
|
"hooks for browser QA and reconnect/rerender safety."
|
|
)
|
|
assert "Working " in UI_JS, (
|
|
"The in-progress Activity summary should distinguish the live counter "
|
|
"from the settled 'Done in …' duration."
|
|
)
|
|
assert "setInterval" in UI_JS and "_clearActivityElapsedTimer" in UI_JS, (
|
|
"The active elapsed label should tick while running and clear its interval "
|
|
"on terminal/error/session-switch cleanup paths."
|
|
)
|