fix: tighten tui layout and request progress

This commit is contained in:
2026-06-30 10:16:08 +08:00
parent fc88744c50
commit 35780329c4
3 changed files with 49 additions and 10 deletions
+27 -8
View File
@@ -359,6 +359,24 @@ def age_since(value: Any) -> str:
return format_elapsed_seconds(seconds)
def request_updated_at(row: dict[str, Any]) -> Any:
for key in ("last_activity_at", "usage_last_updated_at", "finished_at"):
value = row.get(key)
if parse_datetime(value):
return value
return None
def request_updated_elapsed(row: dict[str, Any]) -> str:
return elapsed_between(row.get("started_at"), request_updated_at(row))
def request_chunk_progress(row: dict[str, Any]) -> str:
if not row.get("response_stream"):
return "-"
return f"{row.get('stream_chunk_count') or 0} / {format_bytes(row.get('response_bytes_received'))}"
def status_kind(value: Any) -> str:
text = str(value or "").strip().lower()
if text in {"ok", "operational", "success"}:
@@ -558,7 +576,7 @@ def render_request_detail(row: dict[str, Any]) -> str:
f"life {request_lifecycle_label(row)}",
f"started {short_time(row['started_at'])}",
f"finished {short_time(row['finished_at'])}",
f"updated {age_since(row['usage_last_updated_at'])}",
f"updated {request_updated_elapsed(row)}",
]
if row.get("model"):
bits.append(f"model {row['model']}")
@@ -753,11 +771,11 @@ def run_textual(api_url: str, status_url: str, refresh_seconds: int, timeout: in
Screen { layout: vertical; }
#summary { height: 1; padding: 0 1; color: $accent; }
#paths { height: 1; padding: 0 1; color: $text-muted; }
#controls { height: 2; }
#tables { height: 1fr; }
#controls { height: 1; padding: 0 1; color: $text-muted; }
#tables { height: 1; padding: 0 1; color: $text-muted; }
#requests_table, #logs_table, #profiles_table { height: 1fr; }
#detail { height: 5; padding: 0 1; border-top: solid $panel; }
#status { height: 2; padding: 0 1; color: $text-muted; }
#detail { height: 3; padding: 0 1; border-top: solid $panel; }
#status { height: 1; padding: 0 1; color: $text-muted; }
"""
BINDINGS = [
@@ -813,7 +831,7 @@ def run_textual(api_url: str, status_url: str, refresh_seconds: int, timeout: in
requests = self.query_one("#requests_table", DataTable)
requests.cursor_type = "row"
requests.zebra_stripes = True
requests.add_columns("Seq", "ID", "Status", "Path", "Model", "Reasoning", "Req", "Resp", "First", "Duration", "Updated", "Note")
requests.add_columns("Seq", "ID", "Status", "Path", "Model", "Reasoning", "Req", "Resp", "Chunks", "First", "Duration", "Updated", "Note")
logs = self.query_one("#logs_table", DataTable)
logs.cursor_type = "row"
@@ -994,9 +1012,10 @@ def run_textual(api_url: str, status_url: str, refresh_seconds: int, timeout: in
row["reasoning_tokens"] if row["reasoning_tokens"] is not None else "-",
format_bytes(row["request_body_bytes"]),
format_bytes(row["response_bytes_received"]),
request_chunk_progress(row),
format_ms(row["first_response_delay_ms"]),
format_ms(row["duration_ms"]),
age_since(row.get("usage_last_updated_at")),
request_updated_elapsed(row),
f"{row['upstream_attempt_count'] or 0}x {short_text(row['error'], 18)}",
key=key,
)
@@ -1236,7 +1255,7 @@ def print_once(snapshot: dict[str, Any], filter_text: str = "") -> None:
print(
f"{row['seq']:>6} {short_text(row['request_id'], 16):<16} {status_symbol(row)} {row.get('status_code') or '-':<4} "
f"{short_text(row['path'], 20):<20} {short_text(row['model'] or row['requested_model'] or row['forwarded_model'], 16):<16} "
f"{format_ms(row['duration_ms']):<8} {age_since(row.get('usage_last_updated_at')):<8} "
f"{request_chunk_progress(row):<14} {format_ms(row['duration_ms']):<8} {request_updated_elapsed(row):<8} "
f"{format_count(row['upstream_attempt_count'] or 0):<4} {short_text(row['error'], 30)}"
)
+1 -1
View File
@@ -1,6 +1,6 @@
[project]
name = "codex-retry-gateway-tui"
version = "0.1.1"
version = "0.1.2"
description = "Terminal UI for codex-retry-gateway monitoring and control"
readme = "README.md"
requires-python = ">=3.11"
+21 -1
View File
@@ -72,7 +72,27 @@ class CodexRetryGatewayTUITests(unittest.TestCase):
mod.gateway_status_url("http://127.0.0.1:4610/__codex_retry_gateway"),
"http://127.0.0.1:4610/__codex_retry_gateway/api/status",
)
self.assertIn("updated", mod.render_request_detail({"seq": 1, "request_id": "r", "method": "POST", "path": "/responses", "status_code": 200, "upstream_status_code": 200, "upstream_attempt_count": 1, "first_response_delay_ms": 10, "duration_ms": 20, "request_body_bytes": 3, "response_bytes_received": 4, "stream_chunk_count": 1, "started_at": "2026-06-30T00:00:00Z", "finished_at": "2026-06-30T00:00:01Z", "usage_last_updated_at": "2026-06-30T00:00:01Z"}))
row = {
"seq": 1,
"request_id": "r",
"method": "POST",
"path": "/responses",
"status_code": 200,
"upstream_status_code": 200,
"upstream_attempt_count": 1,
"first_response_delay_ms": 10,
"duration_ms": 20,
"request_body_bytes": 3,
"response_bytes_received": 4096,
"stream_chunk_count": 7,
"response_stream": True,
"started_at": "2026-06-30T00:00:00Z",
"finished_at": "2026-06-30T00:00:01Z",
"usage_last_updated_at": "2026-06-30T00:00:01Z",
}
self.assertIn("updated 1.0s", mod.render_request_detail(row))
self.assertEqual(mod.request_updated_elapsed(row), "1.0s")
self.assertEqual(mod.request_chunk_progress(row), "7 / 4.1KB")
def test_default_api_url_discovers_gateway_state(self) -> None:
mod = load_module()