fix: rerender wide mode request text

This commit is contained in:
2026-06-30 17:40:34 +08:00
parent 68d7250c6b
commit c85c7d896d
2 changed files with 107 additions and 32 deletions
+73 -32
View File
@@ -436,6 +436,29 @@ def request_chunk_progress(row: dict[str, Any]) -> str:
return f"{row.get('stream_chunk_count') or 0} / {format_bytes(row.get('response_bytes_received'))}" return f"{row.get('stream_chunk_count') or 0} / {format_bytes(row.get('response_bytes_received'))}"
def request_row_cells(row: dict[str, Any], text_limits: dict[str, int] | None = None) -> tuple[Any, ...]:
limits = text_limits or {}
note_prefix = f"{row['upstream_attempt_count'] or 0}x "
note_width = max(4, limits.get("note", 22) - len(note_prefix))
return (
str(row["seq"]),
short_text(primary_request_id(row), limits.get("id", 18)) or "-",
short_text(row["thread_id"], limits.get("thread", 18)) or "-",
short_time(row["started_at"]),
f"{status_symbol(row)} {row.get('status_code') or '-'}",
short_text(row["path"], limits.get("path", 22)),
short_text(row["model"] or row["requested_model"] or row["forwarded_model"], limits.get("model", 16)),
row["reasoning_tokens"] if row["reasoning_tokens"] is not None else "-",
short_text(request_usage_summary(row), limits.get("usage", 24)),
format_bytes(row["response_bytes_received"]),
request_chunk_progress(row),
format_duration_ms_as_seconds(row["first_response_delay_ms"]),
format_duration_ms_as_seconds(row["duration_ms"]),
request_updated_elapsed(row),
f"{note_prefix}{short_text(row['error'], note_width)}",
)
def status_kind(value: Any) -> str: def status_kind(value: Any) -> str:
text = str(value or "").strip().lower() text = str(value or "").strip().lower()
if text in {"ok", "operational", "success"}: if text in {"ok", "operational", "success"}:
@@ -1160,20 +1183,20 @@ def run_textual(api_url: str, status_url: str, refresh_seconds: int, timeout: in
}, },
"wide": { "wide": {
"seq": 7, "seq": 7,
"id": 20, "id": 36,
"thread": 30, "thread": 36,
"started": 19, "started": 19,
"status": 7, "status": 7,
"path": 34, "path": 40,
"model": 18, "model": 24,
"reasoning": 10, "reasoning": 10,
"usage": 52, "usage": 72,
"resp": 12, "resp": 12,
"chunks": 16, "chunks": 16,
"first": 8, "first": 8,
"duration": 8, "duration": 8,
"updated": 8, "updated": 8,
"note": 34, "note": 48,
}, },
} }
self.request_usage_width = self.request_table_width_profiles[self.request_table_density]["usage"] self.request_usage_width = self.request_table_width_profiles[self.request_table_density]["usage"]
@@ -1366,46 +1389,36 @@ def run_textual(api_url: str, status_url: str, refresh_seconds: int, timeout: in
self.render_logs() self.render_logs()
self.render_profiles() self.render_profiles()
if self.current_view == "requests": if self.current_view == "requests":
if self.requests: row = self._selected_request_row()
self.render_detail(self.requests[0], kind="request") if row:
self.render_detail(row, kind="request")
else: else:
self.query_one("#detail", Static).update("no requests") self.query_one("#detail", Static).update("no requests")
elif self.current_view == "logs": elif self.current_view == "logs":
if self.logs: row = self._selected_log_row()
self.render_detail(self.logs[0], kind="log") if row:
self.render_detail(row, kind="log")
else: else:
self.query_one("#detail", Static).update("no logs") self.query_one("#detail", Static).update("no logs")
elif self.current_view == "profiles": elif self.current_view == "profiles":
if self.profiles: row = self._selected_profile_row()
self.render_detail(self.profiles[0], kind="profile") if row:
self.render_detail(row, kind="profile")
else: else:
self.query_one("#detail", Static).update("no profiles") self.query_one("#detail", Static).update("no profiles")
def render_requests(self) -> None: def render_requests(self) -> None:
table = self.query_one("#requests_table", DataTable) table = self.query_one("#requests_table", DataTable)
selected_row_index = table.cursor_row if table.cursor_row is not None and table.cursor_row >= 0 else 0
text_limits = self._request_text_limits(table)
table.clear() table.clear()
self.request_by_key = {} self.request_by_key = {}
for row in self.requests: for row in self.requests:
key = f"{row['seq']}:{row['request_id']}" key = f"{row['seq']}:{row['request_id']}"
self.request_by_key[key] = row self.request_by_key[key] = row
table.add_row( table.add_row(*request_row_cells(row, text_limits), key=key)
str(row["seq"]), if self.requests:
short_text(primary_request_id(row), 18) or "-", self._select_table_row(table, min(selected_row_index, len(self.requests) - 1))
short_text(row["thread_id"], 18) or "-",
short_time(row["started_at"]),
f"{status_symbol(row)} {row.get('status_code') or '-'}",
short_text(row["path"], 22),
short_text(row["model"] or row["requested_model"] or row["forwarded_model"], 16),
row["reasoning_tokens"] if row["reasoning_tokens"] is not None else "-",
short_text(request_usage_summary(row), 24),
format_bytes(row["response_bytes_received"]),
request_chunk_progress(row),
format_duration_ms_as_seconds(row["first_response_delay_ms"]),
format_duration_ms_as_seconds(row["duration_ms"]),
request_updated_elapsed(row),
f"{row['upstream_attempt_count'] or 0}x {short_text(row['error'], 18)}",
key=key,
)
def render_logs(self) -> None: def render_logs(self) -> None:
table = self.query_one("#logs_table", DataTable) table = self.query_one("#logs_table", DataTable)
@@ -1488,9 +1501,37 @@ def run_textual(api_url: str, status_url: str, refresh_seconds: int, timeout: in
return return
self.request_usage_width = max(18, min(80, width)) self.request_usage_width = max(18, min(80, width))
column.width = self.request_usage_width column.width = self.request_usage_width
table.refresh(layout=True) self._rerender_requests_after_layout_change()
self._set_status(f"usage column width {self.request_usage_width}") self._set_status(f"usage column width {self.request_usage_width}")
def _request_text_limits(self, table: DataTable) -> dict[str, int]:
width_profile = self.request_table_width_profiles[self.request_table_density]
limits = {
"id": width_profile["id"],
"thread": width_profile["thread"],
"path": width_profile["path"],
"model": width_profile["model"],
"usage": self.request_usage_width,
"note": width_profile["note"],
}
for name in ("id", "thread", "path", "model", "usage", "note"):
key = self.request_table_column_keys.get(name)
column = table.columns.get(key) if key is not None else None
if column is None or not getattr(column, "width", 0):
continue
limits[name] = int(column.width)
return limits
def _rerender_requests_after_layout_change(self) -> None:
self.render_requests()
if self.current_view not in {"overview", "requests"}:
return
row = self._selected_request_row()
if row:
self.render_detail(row, kind="request")
else:
self.query_one("#detail", Static).update("no requests")
def _apply_request_table_width_profile(self, density: str) -> None: def _apply_request_table_width_profile(self, density: str) -> None:
table = self.query_one("#requests_table", DataTable) table = self.query_one("#requests_table", DataTable)
width_profile = self.request_table_width_profiles[density] width_profile = self.request_table_width_profiles[density]
@@ -1501,7 +1542,7 @@ def run_textual(api_url: str, status_url: str, refresh_seconds: int, timeout: in
column.width = width_profile[name] column.width = width_profile[name]
self.request_table_density = density self.request_table_density = density
self.request_usage_width = width_profile["usage"] self.request_usage_width = width_profile["usage"]
table.refresh(layout=True) self._rerender_requests_after_layout_change()
self._set_status(f"request table mode {density}") self._set_status(f"request table mode {density}")
def action_toggle_request_table_density(self) -> None: def action_toggle_request_table_density(self) -> None:
+34
View File
@@ -109,6 +109,40 @@ class CodexRetryGatewayTUITests(unittest.TestCase):
} }
self.assertEqual(mod.request_usage_summary(row), "in 75 | out 40 | cached 25 (25%)") self.assertEqual(mod.request_usage_summary(row), "in 75 | out 40 | cached 25 (25%)")
def test_request_row_cells_expand_with_wider_limits(self) -> None:
mod = load_module()
row = {
"seq": 1,
"request_id": "req_abcdefghijklmnopqrstuvwxyz0123456789",
"response_id": "resp_abcdefghijklmnopqrstuvwxyz0123456789",
"thread_id": "thread_abcdefghijklmnopqrstuvwxyz0123456789",
"started_at": "2026-06-30T12:00:00Z",
"status_code": 200,
"path": "/v1/responses/this/is/a/very/long/path/for/testing/truncation",
"model": "gpt-very-long-model-name-for-testing",
"requested_model": "",
"forwarded_model": "",
"reasoning_tokens": 516,
"input_tokens": 1200,
"output_tokens": 340,
"cached_tokens": 128,
"response_bytes_received": 363800,
"response_stream": True,
"stream_chunk_count": 587,
"first_response_delay_ms": 1500,
"duration_ms": 1542200,
"upstream_attempt_count": 2,
"error": "Selected model is at capacity. Please try a different model.",
"finished_at": "2026-06-30T12:25:00Z",
}
compact = mod.request_row_cells(row, {"id": 18, "thread": 18, "path": 22, "model": 16, "usage": 24, "note": 22})
wide = mod.request_row_cells(row, {"id": 36, "thread": 36, "path": 40, "model": 24, "usage": 72, "note": 48})
self.assertLess(len(compact[1]), len(wide[1]))
self.assertLess(len(compact[2]), len(wide[2]))
self.assertLess(len(compact[5]), len(wide[5]))
self.assertLess(len(compact[8]), len(wide[8]))
self.assertLess(len(compact[14]), len(wide[14]))
def test_request_rows_read_usage_from_nested_usage_object(self) -> None: def test_request_rows_read_usage_from_nested_usage_object(self) -> None:
mod = load_module() mod = load_module()
payload = { payload = {