-
Notifications
You must be signed in to change notification settings - Fork 399
fix(proxy): retry accepted capacity bridge failures #1384
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 20 commits
da18b51
d614ba8
0ca2566
13e9022
8a223ae
c6b8a5a
57a9720
954f377
6bf1e42
ce99ca1
e087436
7024fe7
c5674e1
8ba36f4
104263f
18cbd12
efe2eb6
2379ee2
b3efd94
f526e28
580585f
337e9de
21358f9
374dc4e
b4d20d3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -411,6 +411,137 @@ def _durable_pending_tool_call_manifest( | |
| "Upstream flagged this request as possible cybersecurity work. " | ||
| "codex-lb is retrying on an account marked as authorized for security work." | ||
| ) | ||
| _SECURITY_WORK_NO_AUTHORIZED_ACCOUNTS_MESSAGE = ( | ||
| "Upstream flagged this request as possible cybersecurity work, but no account is marked as authorized for " | ||
| "security work. codex-lb is continuing with normal account selection; the upstream request may still fail until " | ||
| "an account with Trusted Access for Cyber is marked as security-work-authorized." | ||
| ) | ||
| _HTTP_BRIDGE_BACKGROUND_CLOSE_TIMEOUT_SECONDS = 5.0 | ||
| _HTTP_BRIDGE_BACKGROUND_CLEANUP_WARN_THRESHOLD = 100 | ||
| _HTTP_BRIDGE_TERMINAL_CAPACITY_RETRY_CODES = frozenset({"overloaded_error", "server_is_overloaded"}) | ||
| _HTTP_BRIDGE_TERMINAL_CAPACITY_RETRY_MESSAGES = ( | ||
| "selected model is at capacity", | ||
| "servers are currently overloaded", | ||
| ) | ||
|
|
||
|
|
||
| def _http_bridge_terminal_payload_contains_output(payload: dict[str, JsonValue] | None) -> bool: | ||
| if not isinstance(payload, dict): | ||
| return False | ||
| candidates: list[JsonValue | None] = [payload.get("output")] | ||
| response = payload.get("response") | ||
| if isinstance(response, dict): | ||
| candidates.append(response.get("output")) | ||
|
Komzpa marked this conversation as resolved.
|
||
| usage_candidates: list[JsonValue | None] = [payload.get("usage")] | ||
| if isinstance(response, dict): | ||
| usage_candidates.append(response.get("usage")) | ||
| for output in candidates: | ||
| if output is None: | ||
| continue | ||
| if isinstance(output, list): | ||
| if output: | ||
| return True | ||
| continue | ||
| return True | ||
| for usage in usage_candidates: | ||
| if not isinstance(usage, dict): | ||
| continue | ||
| output_tokens = usage.get("output_tokens") | ||
| if isinstance(output_tokens, (int, float)) and not isinstance(output_tokens, bool) and output_tokens > 0: | ||
| return True | ||
| output_token_details = usage.get("output_tokens_details") | ||
| if not isinstance(output_token_details, dict): | ||
| continue | ||
| reasoning_tokens = output_token_details.get("reasoning_tokens") | ||
| if ( | ||
| isinstance(reasoning_tokens, (int, float)) | ||
| and not isinstance(reasoning_tokens, bool) | ||
| and reasoning_tokens > 0 | ||
| ): | ||
| return True | ||
| return False | ||
|
|
||
|
|
||
| def _http_bridge_terminal_capacity_retry_message(message: str | None) -> bool: | ||
| if not isinstance(message, str): | ||
| return False | ||
| normalized = " ".join(message.casefold().split()) | ||
| return any(marker in normalized for marker in _HTTP_BRIDGE_TERMINAL_CAPACITY_RETRY_MESSAGES) | ||
|
|
||
|
|
||
| def _http_bridge_terminal_capacity_retry_error_code( | ||
| request_state: _WebSocketRequestState | None, | ||
| *, | ||
| event_type: str | None, | ||
| payload: dict[str, JsonValue] | None, | ||
| has_other_pending_requests: bool, | ||
| ) -> str | None: | ||
| """Classify one output-free accepted overload that native Codex can replay.""" | ||
| if request_state is None or request_state.enforce_openai_sdk_contract: | ||
| return None | ||
| if has_other_pending_requests: | ||
| return None | ||
| if request_state.last_downstream_sequence_number is not None: | ||
| return None | ||
| if request_state.downstream_visible or request_state.upstream_model_output_seen: | ||
| return None | ||
| if request_state.pending_function_call_ids or request_state.pending_tool_call_types: | ||
| return None | ||
| if request_state.response_id is None or request_state.awaiting_response_created: | ||
| return None | ||
| if request_state.response_event_count < 1: | ||
| return None | ||
| if request_state.event_queue is None: | ||
| return None | ||
| if not request_state.request_text or request_state.replay_count >= 1: | ||
| return None | ||
| if event_type not in {"error", "response.failed"}: | ||
| return None | ||
| if _http_bridge_terminal_payload_contains_output(payload): | ||
| return None | ||
| error_code = _normalize_error_code( | ||
| _websocket_event_error_code(event_type, payload), | ||
| _websocket_event_error_type(event_type, payload), | ||
| ) | ||
| if error_code in _HTTP_BRIDGE_TERMINAL_CAPACITY_RETRY_CODES: | ||
| return error_code | ||
| if not _http_bridge_terminal_capacity_retry_message(_websocket_event_error_message(event_type, payload)): | ||
| return None | ||
| return error_code or "model_at_capacity" | ||
|
|
||
|
|
||
| def _http_bridge_transport_close_capacity_retry_error_code( | ||
| request_state: _WebSocketRequestState | None, | ||
| *, | ||
| has_other_pending_requests: bool, | ||
| error_code: str | None, | ||
| error_message: str | None, | ||
| ) -> str | None: | ||
| """Classify output-free accepted disconnects that native Codex can replay.""" | ||
| if request_state is None or request_state.enforce_openai_sdk_contract: | ||
| return None | ||
| if has_other_pending_requests: | ||
| return None | ||
| if request_state.downstream_visible or request_state.upstream_model_output_seen: | ||
| return None | ||
| if request_state.pending_function_call_ids or request_state.pending_tool_call_types: | ||
| return None | ||
| if request_state.response_id is None or request_state.awaiting_response_created: | ||
| return None | ||
| if request_state.response_event_count < 1: | ||
| return None | ||
| if request_state.event_queue is None: | ||
| return None | ||
| if not request_state.request_text or request_state.replay_count >= 1: | ||
| return None | ||
| normalized_error_code = _normalize_error_code(error_code, None) | ||
| if normalized_error_code == "proxy_network_unavailable": | ||
| return None | ||
| if _http_bridge_terminal_capacity_retry_message(error_message): | ||
| return normalized_error_code or "model_at_capacity" | ||
| if normalized_error_code in {"stream_incomplete", "upstream_error", "upstream_unavailable"}: | ||
| return "stream_incomplete" | ||
| return None | ||
|
Komzpa marked this conversation as resolved.
|
||
|
|
||
|
|
||
| async def _wait_before_http_bridge_model_capacity_retry( | ||
|
|
@@ -1008,6 +1139,7 @@ async def _relay_http_bridge_upstream_messages( | |
|
|
||
| async with session.pending_lock: | ||
| archive_request_state = session.pending_requests[0] if len(session.pending_requests) == 1 else None | ||
| has_other_pending_requests = len(session.pending_requests) != 1 | ||
| response_events_seen = max( | ||
| (request_state.response_event_count for request_state in session.pending_requests), | ||
| default=0, | ||
|
|
@@ -1023,7 +1155,22 @@ async def _relay_http_bridge_upstream_messages( | |
| # or tool side effects. Clean websocket closes remain eligible | ||
| # for the bounded pre-created retry path below. | ||
| if message.error_code != "proxy_network_unavailable": | ||
| retried = await self._retry_http_bridge_precreated_request(session) | ||
| capacity_retry_code = _http_bridge_transport_close_capacity_retry_error_code( | ||
| archive_request_state, | ||
| has_other_pending_requests=has_other_pending_requests, | ||
| error_code=message.error_code, | ||
| error_message=message.error, | ||
| ) | ||
| capacity_retry_attempted = capacity_retry_code is not None and archive_request_state is not None | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When an untyped bridge close is not eligible for replay because output was already observed, another request is pending, or AGENTS.md reference: AGENTS.md:L105-L110 Useful? React with 👍 / 👎. |
||
| if capacity_retry_attempted and archive_request_state is not None: | ||
| retried = await self._retry_http_bridge_terminal_capacity_request( | ||
| session, | ||
| archive_request_state, | ||
| error_code=capacity_retry_code, | ||
| preserve_for_reader_failure=True, | ||
| ) | ||
| if not retried and not capacity_retry_attempted: | ||
| retried = await self._retry_http_bridge_precreated_request(session) | ||
| if retried: | ||
| continue | ||
| close_classification = ( | ||
|
|
@@ -2195,6 +2342,21 @@ async def _process_parsed_http_bridge_upstream_event( | |
| if retried: | ||
| return | ||
|
|
||
| capacity_retry_code = _http_bridge_terminal_capacity_retry_error_code( | ||
| terminal_request_state, | ||
| event_type=settlement_event_type, | ||
| payload=settlement_payload, | ||
| has_other_pending_requests=has_other_pending_requests, | ||
| ) | ||
| if capacity_retry_code is not None: | ||
| retried = await self._retry_http_bridge_terminal_capacity_request( | ||
| session, | ||
| terminal_request_state, | ||
| error_code=capacity_retry_code, | ||
| ) | ||
| if retried: | ||
| return | ||
|
|
||
| matched_event_queue = ( | ||
| completed_event_queue | ||
| if completed_event_queue_claimed and matched_request_state is terminal_request_state | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.