fix: derive streaming status from retry firsts
This commit is contained in:
@@ -23,7 +23,7 @@ from typing import Any
|
||||
|
||||
|
||||
APP_NAME = "codex-retry-gateway-tui"
|
||||
FALLBACK_VERSION = "0.1.7"
|
||||
FALLBACK_VERSION = "0.1.8"
|
||||
DEFAULT_GATEWAY_ADMIN_PATH = "/__codex_retry_gateway"
|
||||
DEFAULT_GATEWAY_URL = "http://127.0.0.1:4610/__codex_retry_gateway"
|
||||
DEFAULT_API_URL = DEFAULT_GATEWAY_URL
|
||||
@@ -870,6 +870,7 @@ def normalize_request_retry_firsts(value: Any) -> list[dict[str, Any]]:
|
||||
{
|
||||
"round": parse_int_value(item.get("round")),
|
||||
"slot": parse_int_value(item.get("slot")),
|
||||
"first_response_at": item.get("first_response_at"),
|
||||
"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(),
|
||||
"status_code": item.get("status_code", item.get("upstream_status_code", item.get("status"))),
|
||||
@@ -1339,13 +1340,38 @@ def request_match_score(row: dict[str, Any], needle: str) -> bool:
|
||||
return needle in haystack
|
||||
|
||||
|
||||
def request_retry_first_received_at(row: dict[str, Any]) -> Any:
|
||||
latest_value = None
|
||||
latest_at = None
|
||||
for first in row.get("reasoning_retry_current_firsts") or []:
|
||||
if not isinstance(first, dict):
|
||||
continue
|
||||
value = first.get("first_response_at")
|
||||
parsed = parse_datetime(value)
|
||||
if parsed and (latest_at is None or parsed > latest_at):
|
||||
latest_value = value
|
||||
latest_at = parsed
|
||||
return latest_value
|
||||
|
||||
|
||||
def request_has_received_first(row: dict[str, Any]) -> bool:
|
||||
if parse_datetime(row.get("first_response_at")):
|
||||
return True
|
||||
for first in row.get("reasoning_retry_current_firsts") or []:
|
||||
if not isinstance(first, dict):
|
||||
continue
|
||||
if parse_datetime(first.get("first_response_at")) or parse_int_value(first.get("first_delay_ms")) is not None:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def request_lifecycle_label(row: dict[str, Any]) -> str:
|
||||
state = str(row.get("lifecycle_state") or "").strip().lower()
|
||||
if request_is_discarded(row):
|
||||
return "discarded"
|
||||
if state in {"finish", "finished", "complete", "completed"} or parse_datetime(row.get("finished_at")):
|
||||
return "finished"
|
||||
if state in {"receive_first", "streaming"} or parse_datetime(row.get("first_response_at")):
|
||||
if state in {"receive_first", "streaming"} or request_has_received_first(row):
|
||||
return "streaming"
|
||||
return "waiting"
|
||||
|
||||
@@ -1368,11 +1394,12 @@ def request_is_discarded(row: dict[str, Any]) -> bool:
|
||||
|
||||
|
||||
def request_activity_at(row: dict[str, Any]) -> Any:
|
||||
for key in ("last_activity_at", "first_response_at", "started_at"):
|
||||
value = row.get(key)
|
||||
if parse_datetime(value):
|
||||
return value
|
||||
candidates = [row.get("last_activity_at"), row.get("first_response_at"), request_retry_first_received_at(row), row.get("started_at")]
|
||||
parsed_candidates = [(parse_datetime(value), value) for value in candidates]
|
||||
valid_candidates = [(parsed, value) for parsed, value in parsed_candidates if parsed]
|
||||
if not valid_candidates:
|
||||
return None
|
||||
return max(valid_candidates, key=lambda item: item[0])[1]
|
||||
|
||||
|
||||
def request_activity_age_seconds(row: dict[str, Any], now: dt.datetime | None = None) -> float | None:
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "codex-retry-gateway-tui"
|
||||
version = "0.1.7"
|
||||
version = "0.1.8"
|
||||
description = "Terminal UI for codex-retry-gateway monitoring and control"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.11"
|
||||
|
||||
@@ -143,6 +143,18 @@ class CodexRetryGatewayTUITests(unittest.TestCase):
|
||||
"first_response_at": "2026-07-10T11:59:55Z",
|
||||
"last_activity_at": "2026-07-10T11:59:55Z",
|
||||
}
|
||||
retry_streaming = {
|
||||
"lifecycle_state": "sent",
|
||||
"started_at": "2026-07-10T11:59:00Z",
|
||||
"reasoning_retry_current_firsts": [
|
||||
{
|
||||
"round": 1,
|
||||
"slot": 1,
|
||||
"first_response_at": "2026-07-10T11:59:58Z",
|
||||
"first_delay_ms": 2200,
|
||||
}
|
||||
],
|
||||
}
|
||||
complete = {"lifecycle_state": "finish", "status_code": 200}
|
||||
discarded = {
|
||||
"lifecycle_state": "finish",
|
||||
@@ -161,6 +173,8 @@ class CodexRetryGatewayTUITests(unittest.TestCase):
|
||||
|
||||
self.assertEqual(mod.request_status_label(waiting, now), "waiting")
|
||||
self.assertEqual(mod.request_status_label(streaming, now), "streaming")
|
||||
self.assertEqual(mod.request_status_label(retry_streaming, now), "streaming")
|
||||
self.assertEqual(mod.request_activity_at(retry_streaming), "2026-07-10T11:59:58Z")
|
||||
self.assertEqual(mod.request_status_label(complete, now), "HTTP 200")
|
||||
self.assertEqual(mod.request_status_label(discarded, now), "discarded")
|
||||
self.assertEqual(mod.request_status_label(slow_waiting, now), "waiting 30.0s")
|
||||
|
||||
Reference in New Issue
Block a user