mirror of
https://github.com/openai/codex.git
synced 2026-10-20 17:38:45 +00:00
Preserve usage limit windows in turn and compaction analytics (#48174)
## Why Usage limit errors discarded the server-selected window responsible for the limit, leaving turn and compaction analytics unable to distinguish five-hour limits from weekly limits. ## What changed Preserve optional `limit_window_minutes` from usage limit error responses in `UsageLimitReachedError` and report it as `usage_limit_window_minutes` in turn and compaction events. Accept unsigned integers that fit in `u16`; treat missing, null, malformed, or out-of-range values as unknown. Events for other error kinds report `null`. ## Testing Add coverage for HTTP and wrapped WebSocket error mapping, analytics serialization and reduction, and app-server propagation to turn and local/remote compaction events. Cases include five-hour and weekly windows, missing or invalid values, and unrelated errors. GitOrigin-RevId: a32066a007559d91a3c868a756bfd0f976777176
This commit is contained in:
@@ -457,6 +457,48 @@ fn map_api_error_distinguishes_http_quota_errors_from_rate_limits() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_api_error_preserves_optional_usage_limit_window() {
|
||||
let cases = [
|
||||
(None, None),
|
||||
(Some(serde_json::json!(null)), None),
|
||||
(Some(serde_json::json!(300)), Some(300)),
|
||||
(Some(serde_json::json!(10080)), Some(10080)),
|
||||
(Some(serde_json::json!(-1)), None),
|
||||
(Some(serde_json::json!(65536)), None),
|
||||
(Some(serde_json::json!("300")), None),
|
||||
(Some(serde_json::json!({"minutes": 300})), None),
|
||||
];
|
||||
|
||||
for (window, expected) in cases {
|
||||
let mut body = serde_json::json!({
|
||||
"error": {
|
||||
"type": "usage_limit_reached",
|
||||
"plan_type": "pro",
|
||||
}
|
||||
});
|
||||
if let Some(window) = window.as_ref() {
|
||||
body["error"]["limit_window_minutes"] = window.clone();
|
||||
}
|
||||
let err = map_api_error(ApiError::Transport(TransportError::Http {
|
||||
retry_after: None,
|
||||
status: http::StatusCode::TOO_MANY_REQUESTS,
|
||||
url: None,
|
||||
headers: None,
|
||||
body: Some(body.to_string()),
|
||||
}));
|
||||
|
||||
let CodexErrorDetails::UsageLimitReached(usage_limit) = err.details() else {
|
||||
panic!("expected usage-limit error for {window:?}, got {err:?}");
|
||||
};
|
||||
assert_eq!(usage_limit.limit_window_minutes, expected, "{window:?}");
|
||||
assert_eq!(
|
||||
err.to_codex_protocol_error(),
|
||||
CodexErrorInfo::UsageLimitExceeded
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_api_error_maps_usage_limit_limit_name_header() {
|
||||
let mut headers = HeaderMap::new();
|
||||
|
||||
Reference in New Issue
Block a user