mirror of
https://github.com/nesquena/hermes-webui.git
synced 2026-07-21 07:00:23 +00:00
Merge latest master into compression recovery action
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
|
||||
### Fixed
|
||||
|
||||
- **An in-progress CLI session now shows in the sidebar before its final output lands.** A CLI/agent session that had real activity (messages and user turns) but hadn't produced its final output yet was hidden from the sidebar until it completed, so an actively-running CLI session could be invisible while you waited on it. Such a session (real message count + user turns, not yet ended, no end reason) is now surfaced while it's still running. Empty/never-really-started rows stay hidden as before. Thanks @rodboev. (#5593, #5587)
|
||||
- **A completed answer is no longer followed by a misleading "No response from provider" card.** On the streaming settlement path, a stale terminal/partial-result flag could force the generic `no_response` error even when the current turn had already produced a full assistant answer — so you'd see the reply and then an error card under it. The generic silent-error path is now suppressed only when the merged current turn actually has a completed assistant answer; genuine failures (real silent failures, partial failures, auth/quota errors, cancellation, replayed rows, terminal tool/compression cases) all keep their existing error behavior. Thanks @rodboev. (#5592, #5575)
|
||||
- **The Mermaid diagram toolbar's "fit" and "fullscreen" buttons are now distinct icons.** The two buttons rendered a byte-identical glyph (the fullscreen icon was the fit icon's corner brackets drawn twice), so you couldn't tell them apart. Fullscreen now shows a distinct corner-frame-with-diagonal-arrows icon, visually separable from fit-to-screen's plain corner brackets. Thanks @rodboev. (#5565, #5525)
|
||||
- **Running out of provider credentials now shows an actionable message instead of a bare "Error."** When a provider's credential pool was exhausted ("All 0 credential(s) exhausted for <provider>"), the turn failed with a generic error and no hint, because that message didn't match the quota-error pattern and fell through to the catch-all. It's now classified distinctly with a hint that tells you what happened and what to do, without swallowing genuine quota errors or blocking partial-result harvesting. (This is the classification half of the credential-exhaustion work; recovering partial output on that path is a separate follow-up.) (#5559, #3929)
|
||||
|
||||
+10
-1
@@ -214,10 +214,19 @@ def is_cli_session_row_visible(row: dict) -> bool:
|
||||
if not is_cli_session_row(row):
|
||||
return True
|
||||
|
||||
message_count = _as_positive_int(row.get("actual_message_count") or row.get("message_count"))
|
||||
actual_message_count = _as_positive_int(row.get("actual_message_count"))
|
||||
message_count = actual_message_count or _as_positive_int(row.get("message_count"))
|
||||
if message_count <= 0:
|
||||
return False
|
||||
|
||||
if (
|
||||
actual_message_count > 0
|
||||
and _count_user_turns(row) > 0
|
||||
and row.get("ended_at") is None
|
||||
and not row.get("end_reason")
|
||||
):
|
||||
return True
|
||||
|
||||
if "tui" in {
|
||||
_normalize_source_name(row.get("source")),
|
||||
_normalize_source_name(row.get("source_tag")),
|
||||
|
||||
@@ -293,6 +293,66 @@ def test_webui_state_db_session_without_sidecar_appears_when_agent_sessions_enab
|
||||
post('/api/settings', {'show_cli_sessions': False})
|
||||
|
||||
|
||||
def test_active_cli_state_db_session_with_persisted_user_turn_is_visible_in_cli_bucket():
|
||||
"""Active default-title CLI rows with persisted user content stay visible in the CLI bucket."""
|
||||
conn = _ensure_state_db()
|
||||
active_sid = 'cli_active_visible_001'
|
||||
older_sid = 'cli_older_visible_001'
|
||||
ended_sid = 'cli_ended_hidden_001'
|
||||
now = time.time()
|
||||
try:
|
||||
conn.execute(
|
||||
"INSERT OR REPLACE INTO sessions "
|
||||
"(id, source, title, model, started_at, message_count, ended_at, end_reason) "
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
(active_sid, 'cli', 'Untitled', 'openai/gpt-5', now + 20, 0, None, None),
|
||||
)
|
||||
conn.execute("DELETE FROM messages WHERE session_id = ?", (active_sid,))
|
||||
_insert_message(conn, active_sid, 'user', 'Active CLI session still running', now + 21)
|
||||
|
||||
conn.execute(
|
||||
"INSERT OR REPLACE INTO sessions "
|
||||
"(id, source, title, model, started_at, message_count, ended_at, end_reason) "
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
(older_sid, 'cli', 'Named CLI Session', 'openai/gpt-5', now, 1, None, None),
|
||||
)
|
||||
conn.execute("DELETE FROM messages WHERE session_id = ?", (older_sid,))
|
||||
_insert_message(conn, older_sid, 'user', 'Older visible CLI session', now + 1)
|
||||
|
||||
conn.execute(
|
||||
"INSERT OR REPLACE INTO sessions "
|
||||
"(id, source, title, model, started_at, message_count, ended_at, end_reason) "
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
(ended_sid, 'cli', 'Untitled', 'openai/gpt-5', now + 10, 1, now + 11, 'cli-close'),
|
||||
)
|
||||
conn.execute("DELETE FROM messages WHERE session_id = ?", (ended_sid,))
|
||||
_insert_message(conn, ended_sid, 'user', 'Ended CLI session', now + 11)
|
||||
conn.commit()
|
||||
|
||||
post('/api/settings', {'show_cli_sessions': True})
|
||||
|
||||
data, status = get('/api/sessions?sidebar_source=cli')
|
||||
assert status == 200
|
||||
sessions = data.get('sessions', [])
|
||||
session_ids = [s.get('session_id') for s in sessions]
|
||||
assert active_sid in session_ids
|
||||
assert older_sid in session_ids
|
||||
assert ended_sid not in session_ids, "ended default-title CLI rows with one user turn stay hidden"
|
||||
|
||||
active = next(s for s in sessions if s.get('session_id') == active_sid)
|
||||
older = next(s for s in sessions if s.get('session_id') == older_sid)
|
||||
assert active.get('message_count') == 1
|
||||
assert active.get('updated_at') > older.get('updated_at')
|
||||
assert session_ids.index(active_sid) < session_ids.index(older_sid)
|
||||
finally:
|
||||
try:
|
||||
_remove_test_sessions(conn, active_sid, older_sid, ended_sid)
|
||||
conn.close()
|
||||
except Exception:
|
||||
pass
|
||||
post('/api/settings', {'show_cli_sessions': False})
|
||||
|
||||
|
||||
def test_gateway_sessions_without_messages_are_hidden_from_sidebar():
|
||||
"""Regression: empty agent session rows must not appear as broken sidebar entries."""
|
||||
conn = _ensure_state_db()
|
||||
|
||||
Reference in New Issue
Block a user