feat: improve retry first column controls

This commit is contained in:
2026-07-07 20:28:13 +08:00
parent c5fa238598
commit 184b6b65b0
2 changed files with 132 additions and 61 deletions
+121 -56
View File
@@ -81,6 +81,51 @@ REQUEST_TABLE_COLUMN_KEY_SET = set(REQUEST_TABLE_COLUMN_KEYS)
REQUEST_TABLE_CELL_INDEX = {key: index for index, key in enumerate(REQUEST_TABLE_COLUMN_KEYS)}
DEFAULT_REQUEST_TABLE_VISIBLE_COLUMNS = REQUEST_TABLE_COLUMN_KEYS
DEFAULT_REQUEST_TABLE_SORT_COLUMN = "seq"
REQUEST_TABLE_WIDTH_PROFILES = {
"compact": {
"seq": 7,
"req_id": 18,
"resp_id": 18,
"thread": 18,
"started": 19,
"status": 7,
"path": 22,
"model": 16,
"effort": 8,
"reasoning": 8,
"token_col": 8,
"req": 10,
"resp": 10,
"chunks": 14,
"first": 12,
"duration": 8,
"updated": 8,
"note": 22,
"round": 10,
},
"wide": {
"seq": 7,
"req_id": 24,
"resp_id": 24,
"thread": 36,
"started": 19,
"status": 7,
"path": 40,
"model": 24,
"effort": 8,
"reasoning": 8,
"token_col": 8,
"req": 12,
"resp": 12,
"chunks": 16,
"first": 14,
"duration": 8,
"updated": 8,
"note": 48,
"round": 10,
},
}
REQUEST_TABLE_MIN_COLUMN_WIDTH = 4
REQUEST_TABLE_COLUMN_ALIASES = {
"seq": ("seq",),
"req_id": ("req id", "request id", "request_id"),
@@ -295,6 +340,29 @@ def request_table_hidden_columns(value: Any, columns: list[str]) -> list[str]:
return hidden
def request_table_column_width_value(value: Any) -> int | None:
try:
width = int(str(value or "").strip())
except Exception:
return None
if width <= 0:
return None
return max(REQUEST_TABLE_MIN_COLUMN_WIDTH, width)
def request_table_width_overrides(value: Any) -> dict[str, int]:
requested = value if isinstance(value, dict) else {}
overrides: dict[str, int] = {}
for raw_key, raw_width in requested.items():
width = request_table_column_width_value(raw_width)
if width is None:
continue
for column_key in request_table_column_keys(raw_key):
if column_key:
overrides[column_key] = width
return overrides
def normalize_request_table_sort_column(value: Any) -> str:
column_key = str(value or "").strip()
if column_key in REQUEST_TABLE_COLUMN_KEY_SET:
@@ -320,9 +388,11 @@ def normalize_request_table_preferences(data: Any) -> dict[str, Any]:
hidden_columns = request_table_hidden_columns(source.get("hidden_columns"), columns)
if len(hidden_columns) >= len(columns) and columns:
hidden_columns = [column_key for column_key in hidden_columns if column_key != columns[0]]
width_overrides = request_table_width_overrides(source.get("widths"))
return {
"columns": columns,
"hidden_columns": hidden_columns,
"widths": {column_key: width for column_key, width in width_overrides.items() if column_key in columns},
}
@@ -338,6 +408,7 @@ def request_table_visible_columns(preferences: dict[str, Any]) -> list[str]:
def request_table_preferences_from_text(text: str) -> dict[str, Any]:
columns = []
hidden_columns = []
width_overrides: dict[str, int] = {}
seen: set[str] = set()
for line_number, raw_line in enumerate(text.splitlines(), start=1):
stripped = raw_line.strip()
@@ -350,6 +421,11 @@ def request_table_preferences_from_text(text: str) -> dict[str, Any]:
token = token[1:].strip()
if not token:
continue
width = None
width_match = re.match(r"^(.*?)(?:\s+(\d+))?$", token)
if width_match:
token = (width_match.group(1) or "").strip()
width = request_table_column_width_value(width_match.group(2))
column_keys = request_table_column_keys(token)
if not column_keys:
if hidden:
@@ -362,6 +438,8 @@ def request_table_preferences_from_text(text: str) -> dict[str, Any]:
columns.append(column_key)
if hidden:
hidden_columns.append(column_key)
if width is not None:
width_overrides[column_key] = width
if not columns:
raise ValueError("no request columns found in editor document")
missing = [column_key for column_key in REQUEST_TABLE_COLUMN_KEYS if column_key not in seen]
@@ -369,6 +447,7 @@ def request_table_preferences_from_text(text: str) -> dict[str, Any]:
{
"columns": columns + missing,
"hidden_columns": hidden_columns + missing,
"widths": width_overrides,
}
)
@@ -376,17 +455,20 @@ def request_table_preferences_from_text(text: str) -> dict[str, Any]:
def request_table_preferences_document(preferences: dict[str, Any]) -> str:
normalized = normalize_request_table_preferences(preferences)
hidden = set(normalized["hidden_columns"])
widths = normalized["widths"]
lines = [
"# Request table columns.",
"# One column key per line.",
"# Prefix with # to hide a column.",
"# Optional: append an integer width, e.g. `first 14` or `in 10`.",
"# Move lines up or down to change display order.",
"# Common keys: in, out, cache, req_id, resp_id, req_bytes, resp_bytes, round.",
"",
]
for column_key in normalized["columns"]:
prefix = "# " if column_key in hidden else ""
lines.append(f"{prefix}{column_key}")
width_suffix = f" {widths[column_key]}" if column_key in widths else ""
lines.append(f"{prefix}{column_key}{width_suffix}")
return "\n".join(lines).rstrip() + "\n"
@@ -769,6 +851,7 @@ def normalize_request_retry_firsts(value: Any) -> list[dict[str, Any]]:
continue
firsts.append(
{
"round": parse_int_value(item.get("round")),
"slot": parse_int_value(item.get("slot")),
"first_delay_ms": item.get("first_response_delay_ms", item.get("first_delay_ms", item.get("first_ms"))),
"outcome": str(item.get("outcome") or "").strip(),
@@ -781,6 +864,20 @@ def normalize_request_retry_firsts(value: Any) -> list[dict[str, Any]]:
return firsts
def request_retry_first_label(first: dict[str, Any], fallback_round: Any = None) -> str:
round_number = parse_int_value(first.get("round"))
if round_number is None:
round_number = parse_int_value(fallback_round)
slot = parse_int_value(first.get("slot"))
if round_number is not None:
if slot is not None and slot > 1:
return f"{round_number}-{slot}"
return str(round_number)
if slot is not None:
return str(slot)
return "?"
def request_retry_round_text(row: dict[str, Any]) -> str:
round_number = parse_int_value(row.get("reasoning_retry_current_round"))
width = parse_int_value(row.get("reasoning_retry_current_width"))
@@ -793,8 +890,11 @@ def request_retry_round_text(row: dict[str, Any]) -> str:
return f"{round_number}({max(0, width)})"
def request_retry_first_summary(first: dict[str, Any]) -> str:
def request_retry_first_summary(first: dict[str, Any], fallback_round: Any = None) -> str:
bits = []
round_label = request_retry_first_label(first, fallback_round)
if round_label != "?":
bits.append(f"round {round_label}")
slot = parse_int_value(first.get("slot"))
if slot is not None:
bits.append(f"slot {slot}")
@@ -823,10 +923,11 @@ def request_retry_first_summary(first: dict[str, Any]) -> str:
def request_retry_wave_summary(row: dict[str, Any]) -> str:
summaries = []
fallback_round = row.get("reasoning_retry_current_round")
for first in row.get("reasoning_retry_current_firsts") or []:
if not isinstance(first, dict):
continue
summary = request_retry_first_summary(first)
summary = request_retry_first_summary(first, fallback_round)
if summary:
summaries.append(summary)
return "; ".join(summaries)
@@ -838,10 +939,7 @@ def request_retry_firsts_compact_text(row: dict[str, Any]) -> str:
if not isinstance(first, dict):
continue
delay = format_duration_ms_as_seconds(first.get("first_delay_ms"))
if delay == "-":
delay = str(first.get("outcome") or "-").strip() or "-"
slot = parse_int_value(first.get("slot"))
parts.append(f"{slot if slot is not None else '?'}:{delay}")
parts.append(delay if delay != "-" else "?")
return " ".join(parts)
@@ -1744,48 +1842,7 @@ def run_textual(
self.request_table_preferences = load_request_table_preferences()
self.request_table_density = "compact"
self.request_table_width_profiles = {
"compact": {
"seq": 7,
"req_id": 18,
"resp_id": 18,
"thread": 18,
"started": 19,
"status": 7,
"path": 22,
"model": 16,
"effort": 8,
"reasoning": 8,
"token_col": 8,
"req": 10,
"resp": 10,
"chunks": 14,
"first": 8,
"duration": 8,
"updated": 8,
"note": 22,
"round": 10,
},
"wide": {
"seq": 7,
"req_id": 24,
"resp_id": 24,
"thread": 36,
"started": 19,
"status": 7,
"path": 40,
"model": 24,
"effort": 8,
"reasoning": 8,
"token_col": 8,
"req": 12,
"resp": 12,
"chunks": 16,
"first": 8,
"duration": 8,
"updated": 8,
"note": 48,
"round": 10,
},
density: dict(widths) for density, widths in REQUEST_TABLE_WIDTH_PROFILES.items()
}
def compose(self) -> ComposeResult:
@@ -1875,6 +1932,16 @@ def run_textual(
return False
return True
def _request_table_column_width(self, column_key: str, density: str | None = None) -> int:
normalized = normalize_request_table_preferences(self.request_table_preferences)
override = request_table_column_width_value(normalized.get("widths", {}).get(column_key))
if override is not None:
return override
active_density = density or self.request_table_density
width_profile = self.request_table_width_profiles[active_density]
column = REQUEST_TABLE_COLUMN_BY_KEY[column_key]
return width_profile[column["width_key"]]
def _request_row_key(self, row: dict[str, Any]) -> str:
return f"{row['seq']}:{row['request_id']}"
@@ -1897,12 +1964,11 @@ def run_textual(
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
selected_row_key = self._selected_request_key()
width_profile = self.request_table_width_profiles[self.request_table_density]
table.clear(columns=True)
self.request_table_column_keys = {}
for column_key in self._visible_request_column_keys():
column = REQUEST_TABLE_COLUMN_BY_KEY[column_key]
width = width_profile[column["width_key"]]
width = self._request_table_column_width(column_key)
self.request_table_column_keys[column_key] = table.add_column(
column["label"],
width=width,
@@ -2140,10 +2206,11 @@ def run_textual(
"path": width_profile["path"],
"model": width_profile["model"],
"effort": width_profile["effort"],
"first": width_profile["first"],
"note": width_profile["note"],
"round": width_profile["round"],
}
for name in ("req_id", "resp_id", "thread", "path", "model", "effort", "note", "round"):
for name in ("req_id", "resp_id", "thread", "path", "model", "effort", "first", "note", "round"):
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):
@@ -2164,13 +2231,11 @@ def run_textual(
def _apply_request_table_width_profile(self, density: str) -> None:
table = self.query_one("#requests_table", DataTable)
width_profile = self.request_table_width_profiles[density]
for name, key in self.request_table_column_keys.items():
column = table.columns.get(key)
width_key = REQUEST_TABLE_COLUMN_BY_KEY.get(name, {}).get("width_key", name)
if column is None or width_key not in width_profile:
if column is None:
continue
column.width = width_profile[width_key]
column.width = self._request_table_column_width(name, density)
self.request_table_density = density
self._rerender_requests_after_layout_change()
self._set_status(f"request table mode {density}")
+11 -5
View File
@@ -230,6 +230,7 @@ class CodexRetryGatewayTUITests(unittest.TestCase):
"reasoning_retry_current_width": 2,
"reasoning_retry_current_firsts": [
{
"round": 3,
"slot": 1,
"first_response_delay_ms": 1200,
"outcome": "ok",
@@ -238,6 +239,7 @@ class CodexRetryGatewayTUITests(unittest.TestCase):
"reasoning_tokens": 516,
},
{
"round": 3,
"slot": 2,
"first_delay_ms": 1800,
"outcome": "retry",
@@ -254,10 +256,11 @@ class CodexRetryGatewayTUITests(unittest.TestCase):
self.assertEqual(row["reasoning_retry_current_width"], 2)
self.assertEqual(len(row["reasoning_retry_current_firsts"]), 2)
self.assertEqual(mod.request_retry_round_text(row), "3(2)")
self.assertIn("1:1.2s", mod.request_first_text(row))
self.assertIn("slot 1", mod.request_retry_wave_summary(row))
self.assertEqual(mod.request_first_text(row), "1.2s 1.8s")
self.assertIn("round 3 slot 1", mod.request_retry_wave_summary(row))
self.assertIn("retry round 3(2)", mod.render_request_detail(row))
self.assertIn("current wave slot 1 first 1.2s", mod.render_request_detail(row))
self.assertIn("first 1.2s 1.8s", mod.render_request_detail(row))
self.assertIn("current wave round 3 slot 1 first 1.2s", mod.render_request_detail(row))
self.assertEqual(mod.request_row_cells(row)[20], "3(2)")
def test_request_table_preferences_round_trip(self) -> None:
@@ -273,12 +276,14 @@ class CodexRetryGatewayTUITests(unittest.TestCase):
{
"columns": ["round", "seq", "status", "unknown"],
"hidden_columns": ["status", "unknown"],
"widths": {"round": 14, "status": 9, "unknown": 99},
}
)
self.assertEqual(saved_path, prefs_path)
loaded = mod.load_request_table_preferences()
self.assertEqual(loaded["columns"][:3], ["round", "seq", "status"])
self.assertEqual(loaded["hidden_columns"], ["status"])
self.assertEqual(loaded["widths"], {"round": 14, "status": 9})
def test_request_table_preferences_from_text_hides_and_reorders_columns(self) -> None:
mod = load_module()
@@ -286,9 +291,9 @@ class CodexRetryGatewayTUITests(unittest.TestCase):
"\n".join(
[
"# comment",
"thread",
"thread 24",
"seq",
"# cache",
"# cache 9",
"in",
"out",
"",
@@ -297,6 +302,7 @@ class CodexRetryGatewayTUITests(unittest.TestCase):
)
self.assertEqual(prefs["columns"][:6], ["thread", "seq", "cache", "in", "out", "req_id"])
self.assertIn("cache", prefs["hidden_columns"])
self.assertEqual(prefs["widths"], {"thread": 24, "cache": 9})
def test_request_table_preferences_expand_legacy_usage_column(self) -> None:
mod = load_module()