Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
413e206
fix(proxy): preserve pool usage-limit semantics
Jul 12, 2026
b3be9d5
style: normalize pool exhaustion imports
Jul 12, 2026
76b6485
fix(proxy): preserve structured retry hints
Jul 12, 2026
c7ccf29
docs(openspec): cover pool usage exhaustion errors
Komzpa Jul 18, 2026
4fa7301
fix(ci): satisfy pool usage PR gates
Komzpa Jul 18, 2026
fa1dd12
fix(balancer): tighten usage-limit exhaustion reporting
Komzpa Jul 18, 2026
ed61ed1
fix(balancer): preserve usage-limit reset metadata
Komzpa Jul 18, 2026
364f912
fix(balancer): require usage evidence for pool limits
Komzpa Jul 18, 2026
0f9aaae
fix(balancer): preserve cap semantics for usage limits
Komzpa Jul 18, 2026
8b9cd70
fix(balancer): preserve pressure usage priorities
Komzpa Jul 18, 2026
fc0432e
fix(proxy): resolve local overload codes against the canonical registry
Soju06 Jul 30, 2026
cc3ea7f
test(proxy): pin the #1246 status matrix at the Responses surface
Soju06 Jul 30, 2026
d73fd38
style: format unbound selection cap fallback
Soju06 Jul 30, 2026
3928346
fix(cache): recover invalidation after failed prime
mastertyko Jul 30, 2026
86344cd
fix(proxy): retry detached API key release
mastertyko Jul 30, 2026
c77b1fe
fix(review): P1 - preserve inline stream release latency
mastertyko Jul 30, 2026
11d9d4e
fix(review): P1 - bound detached release retry fan-out
mastertyko Jul 30, 2026
12dd30c
Merge remote-tracking branch 'refs/remotes/codex-lb-prs/pr-1545' into…
Jul 30, 2026
7545d95
fix(proxy): retry silent bridge response.create upstreams
Komzpa Jul 30, 2026
09a73da
fix(proxy): retry bridge missing-created at deadline
Komzpa Jul 30, 2026
f9ab363
fix(proxy): retry same-anchor missing-created turns
Komzpa Jul 30, 2026
98ef1aa
fix(proxy): keep recovering silent response.create upstreams
Komzpa Jul 30, 2026
cb1c3ce
fix(proxy): retry silent bridge creates sooner
Komzpa Jul 31, 2026
1bc93d6
fix(proxy): bound missing-created bridge retries
Komzpa Jul 31, 2026
ad28520
fix(proxy): penalize silent bridge create owners
Komzpa Jul 31, 2026
0115eab
fix(proxy): rebind silent bridge create owners
Komzpa Jul 31, 2026
a6347cc
fix(proxy): clear silent bridge anchors on terminal retire
Komzpa Jul 31, 2026
81c4f53
fix(proxy): clear stale bridge anchors after close attempt
Komzpa Jul 31, 2026
6e60454
fix(proxy): limit created-only close replay budget
Komzpa Jul 30, 2026
91b783c
fix(proxy): retry previsible stream eof continuations
Komzpa Jul 30, 2026
1387a5d
fix(proxy): keep fresh empty streams fail-closed
Komzpa Jul 30, 2026
2b9378d
fix(proxy): keep retrying unanchored silent bridge creates
Komzpa Jul 31, 2026
a448b9c
fix(proxy): use shared bridge cancellation helper
Komzpa Jul 31, 2026
78e919f
fix(db): tolerate deployed security lineage schema
Komzpa Jul 31, 2026
e7aeab6
test(proxy): align bridge recovery expectations
Komzpa Jul 31, 2026
4062577
fix(proxy): retire stale bridge gate holders
Komzpa Jul 31, 2026
e306335
fix(db): mark lineage digests as identifiers
Komzpa Jul 31, 2026
1b12951
fix(db): avoid password-hash signal for lineage markers
Komzpa Jul 31, 2026
acbf7a4
fix(proxy): honor usage exhaustion boundaries
Komzpa Jul 31, 2026
a49a9c0
Merge remote-tracking branch 'refs/remotes/codex-lb-prs/pr-1541' into…
Jul 31, 2026
83a11ed
fix(proxy): keep silent bridge failures account-neutral
Komzpa Aug 1, 2026
839cf51
fix(proxy): preserve terminal delivery across detach
choi138 Aug 1, 2026
24d7281
fix(proxy): preserve developer-interleaved fresh resends
choi138 Aug 1, 2026
ec8c23d
test(proxy): cover completed detach overlap
choi138 Aug 1, 2026
5edfb01
fix(proxy-responses): adapt explicit prompt cache controls
Komzpa Aug 1, 2026
67d7ee7
fix(proxy): replay full resend after bridge owner conflict
Komzpa Jul 31, 2026
028a60b
fix(proxy): fork model transition after owner conflict
Komzpa Jul 31, 2026
1f2dbfe
fix(proxy): prefer safe full-resend projection
Komzpa Aug 1, 2026
7de8c08
Merge remote-tracking branch 'origin/main' into fix/pr1555-migration-…
Komzpa Aug 1, 2026
c825b23
fix(db): merge live bridge and capability lineage heads
Komzpa Aug 1, 2026
ecc2819
chore(tests): format prompt cache coverage
Komzpa Aug 1, 2026
8ef5f0b
Merge remote-tracking branch 'refs/remotes/codex-lb-prs/pr-1565' into…
Aug 1, 2026
eede902
fix(proxy-responses): tolerate structured content type values
Komzpa Aug 1, 2026
68b543c
Merge remote-tracking branch 'refs/remotes/codex-lb-prs/pr-1566' into…
Aug 1, 2026
06b6993
fix(proxy): suppress duplicate side-effect tool calls
Komzpa Aug 2, 2026
699852c
Merge remote-tracking branch 'refs/remotes/codex-lb-prs/pr-1567' into…
Aug 2, 2026
539028e
Merge remote-tracking branch 'refs/remotes/codex-lb-prs/pr-1527' into…
Aug 1, 2026
f759cae
fix(compact): elide observed inline images at wire cap
Komzpa Jul 22, 2026
05dfdd6
fix(compact): handle eligible inline tool images safely
Komzpa Jul 22, 2026
2e93bb2
style(compact): format request trimming helpers
Komzpa Jul 22, 2026
2178dec
fix(compact): preserve context and nested file pins
Komzpa Jul 22, 2026
62d13dc
fix(compact): preserve inline image and file ownership
Komzpa Jul 23, 2026
0ae295d
test(compact): type captured compact payload
Komzpa Jul 28, 2026
e3dde57
fix(compact): isolate image elision constants
Komzpa Aug 2, 2026
7645a11
Merge remote-tracking branch 'refs/remotes/codex-lb-prs/pr-1457' into…
Aug 2, 2026
0346c6b
fix(proxy): penalize eventless bridge accounts
Komzpa Aug 3, 2026
5cac93a
Merge remote-tracking branch 'refs/remotes/codex-lb-prs/pr-1555' into…
Aug 3, 2026
9edd50f
Merge remote-tracking branch 'refs/remotes/codex-lb-prs/pr-1557' into…
Aug 1, 2026
7dfe811
fix(proxy): support bounded fresh developer suffixes
choi138 Aug 3, 2026
bb974f4
test(proxy): type replay safety fixture as JsonValue
choi138 Aug 3, 2026
455f1ac
Merge remote-tracking branch 'refs/remotes/codex-lb-prs/pr-1537' into…
Aug 3, 2026
914ffa9
Merge remote-tracking branch 'refs/remotes/codex-lb-prs/pr-1544' into…
Jul 30, 2026
0fc6fce
fix(http-bridge): keep missing-created watchdog armed after prelude
Komzpa Aug 3, 2026
d747bc4
Merge remote-tracking branch 'refs/remotes/codex-lb-prs/pr-1580' into…
Aug 3, 2026
e30ffe3
fix(compact): preserve tool search pairs
Komzpa Aug 5, 2026
8915921
Merge remote-tracking branch 'origin/main' into fix/live-compact-tool…
Komzpa Aug 5, 2026
3691fef
fix: repair live carrier stream merge
Komzpa Aug 5, 2026
2e89cc2
fix(db): merge live carrier migration heads
Komzpa Aug 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 4 additions & 44 deletions .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -1084,50 +1084,10 @@
]
},
{
"login": "shaqman",
"name": "Syakur Rahman",
"avatar_url": "https://avatars.githubusercontent.com/u/1113851?v=4",
"profile": "http://expressthisout.com/",
"contributions": [
"code",
"test"
]
},
{
"login": "cigro-manager",
"name": "cigro-manager",
"avatar_url": "https://avatars.githubusercontent.com/u/219247995?v=4",
"profile": "https://github.com/cigro-manager",
"contributions": [
"code"
]
},
{
"login": "lkraider",
"name": "Paul Eipper",
"avatar_url": "https://avatars.githubusercontent.com/u/52256?v=4",
"profile": "https://github.com/lkraider",
"contributions": [
"code",
"test",
"doc"
]
},
{
"login": "ret2basic",
"name": "ret2basic.eth",
"avatar_url": "https://avatars.githubusercontent.com/u/59381775?v=4",
"profile": "https://github.com/ret2basic",
"contributions": [
"code",
"test"
]
},
{
"login": "yeongjun-cigro",
"name": "유영준",
"avatar_url": "https://avatars.githubusercontent.com/u/260819931?v=4",
"profile": "https://github.com/yeongjun-cigro",
"login": "glopyglerky",
"name": "glopyglerky",
"avatar_url": "https://avatars.githubusercontent.com/u/189872235?v=4",
"profile": "https://github.com/glopyglerky",
"contributions": [
"code",
"test"
Expand Down
4 changes: 4 additions & 0 deletions app/core/balancer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
ROUTING_POLICY_PRESERVE,
TRAFFIC_CLASS_FOREGROUND,
TRAFFIC_CLASS_OPPORTUNISTIC,
USAGE_LIMIT_REACHED,
AccountState,
FailoverAction,
ResetPreferenceWindow,
Expand All @@ -28,6 +29,7 @@
handle_quota_exceeded,
handle_rate_limit,
plausible_rate_limit_reset_at,
pool_usage_exhaustion,
select_account,
)

Expand All @@ -52,6 +54,7 @@
"RoutingStrategy",
"TrafficClass",
"SelectionResult",
"USAGE_LIMIT_REACHED",
"UsageWeightedOrder",
"account_status_for_permanent_failure",
"configure_replica_salt",
Expand All @@ -61,5 +64,6 @@
"handle_quota_exceeded",
"handle_rate_limit",
"plausible_rate_limit_reset_at",
"pool_usage_exhaustion",
"select_account",
]
96 changes: 96 additions & 0 deletions app/core/balancer/logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,90 @@ class AccountState:
class SelectionResult:
account: AccountState | None
error_message: str | None
error_code: str | None = None
resets_at: int | None = None


USAGE_LIMIT_REACHED = "usage_limit_reached"


def pool_usage_exhaustion(
states: Iterable[AccountState],
*,
current: float,
ignore_standard_quota: bool = False,
ignore_standard_quota_account_ids: Collection[str] | None = None,
) -> SelectionResult | None:
"""Describe pool-wide subscription exhaustion without parsing retry text."""
if ignore_standard_quota:
return None
ignored_account_ids = set(ignore_standard_quota_account_ids or ())

def _primary_usage_evidence(state: AccountState) -> float | None:
return state.priority_used_percent if state.priority_used_percent is not None else state.used_percent

def _secondary_usage_evidence(state: AccountState) -> float | None:
if state.limit_scoped_usage and state.priority_secondary_used_percent is None:
return _primary_usage_evidence(state)
return (
state.priority_secondary_used_percent
if state.priority_secondary_used_percent is not None
else state.secondary_used_percent
)

def _usage_exhausted(state: AccountState) -> bool:
if state.status not in (AccountStatus.QUOTA_EXCEEDED, AccountStatus.RATE_LIMITED):
return False
usage_values = (_primary_usage_evidence(state), _secondary_usage_evidence(state))
return any(value is not None and float(value) >= 100.0 for value in usage_values)

def _usage_exhausted_reset_at(state: AccountState) -> float | None:
if state.status not in (AccountStatus.QUOTA_EXCEEDED, AccountStatus.RATE_LIMITED):
return None
candidates: list[float] = []
primary_evidence = _primary_usage_evidence(state)
secondary_evidence = _secondary_usage_evidence(state)
if primary_evidence is not None and float(primary_evidence) >= 100.0 and state.primary_reset_at is not None:
candidates.append(float(state.primary_reset_at))
if (
secondary_evidence is not None
and float(secondary_evidence) >= 100.0
and state.secondary_reset_at is not None
):
candidates.append(float(state.secondary_reset_at))
if not candidates:
return None
return max(candidates)

eligible = [
state
for state in states
if not state.ignore_standard_quota
and state.account_id not in ignored_account_ids
and state.status
not in (
AccountStatus.PAUSED,
AccountStatus.REAUTH_REQUIRED,
AccountStatus.DEACTIVATED,
)
]
if not eligible or any(not _usage_exhausted(state) for state in eligible):
return None

# Only usage-proven exhausted accounts reach this branch; surface the
# earliest reset for an actually exhausted window so the structured 429
# does not retry a secondary-window exhaustion at the primary reset time.
reset_candidates = [reset_at for state in eligible if (reset_at := _usage_exhausted_reset_at(state)) is not None]
resets_at = int(min(reset_candidates)) if reset_candidates else None
message = "Usage limit reached"
if resets_at is not None:
message = _format_retry_hint(max(0.0, resets_at - current))
return SelectionResult(
account=None,
error_message=message,
error_code=USAGE_LIMIT_REACHED,
resets_at=resets_at,
)


@dataclass(frozen=True, slots=True)
Expand Down Expand Up @@ -379,6 +463,8 @@ def select_account(
primary_first_usage_weighted: bool = False,
routing_costs: RoutingCostsByAccount | None = None,
replica_salt: str | None = None,
allow_usage_exhaustion_error: bool = True,
usage_exhaustion_states: Iterable[AccountState] | None = None,
) -> SelectionResult:
"""Select an eligible account by applying availability checks and routing strategy.

Expand Down Expand Up @@ -446,6 +532,7 @@ def select_account(
available: list[AccountState] = []
in_error_backoff: list[AccountState] = []
all_states = list(states)
usage_exhaustion_state_list = list(usage_exhaustion_states) if usage_exhaustion_states is not None else all_states
bypass_account_ids = None if bypass_quota_exceeded_account_ids is None else set(bypass_quota_exceeded_account_ids)

for state in all_states:
Expand Down Expand Up @@ -529,6 +616,15 @@ def _backoff_expires_at(s: AccountState) -> float:
return SelectionResult(None, f"opportunistic burn window closed: {reason}")
available = opportunistic_available
else:
if allow_usage_exhaustion_error:
usage_exhaustion = pool_usage_exhaustion(
usage_exhaustion_state_list,
current=current,
ignore_standard_quota=ignore_standard_quota or bypass_quota_exceeded,
ignore_standard_quota_account_ids=bypass_account_ids,
)
if usage_exhaustion is not None:
return usage_exhaustion
reauth_required = [s for s in all_states if s.status == AccountStatus.REAUTH_REQUIRED]
deactivated = [s for s in all_states if s.status == AccountStatus.DEACTIVATED]
paused = [s for s in all_states if s.status == AccountStatus.PAUSED]
Expand Down
16 changes: 13 additions & 3 deletions app/core/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,17 @@ class ResponseFailedEvent(TypedDict):
PREVIOUS_RESPONSE_NOT_FOUND_MESSAGE = "Previous response was not found; retry without previous_response_id."


def openai_error(code: str, message: str, error_type: str = "server_error") -> OpenAIErrorEnvelope:
return {"error": {"message": message, "type": error_type, "code": code}}
def openai_error(
code: str,
message: str,
error_type: str = "server_error",
*,
resets_at: int | float | None = None,
) -> OpenAIErrorEnvelope:
detail: OpenAIErrorDetail = {"message": message, "type": error_type, "code": code}
if resets_at is not None:
detail["resets_at"] = int(resets_at)
return {"error": detail}


def dashboard_error(code: str, message: str) -> DashboardErrorEnvelope:
Expand Down Expand Up @@ -105,9 +114,10 @@ def response_failed_event(
response_id: str | None = None,
created_at: int | None = None,
error_param: str | None = None,
resets_at: int | float | None = None,
incomplete_details: dict[str, str] | None = None,
) -> ResponseFailedEvent:
error = openai_error(code, message, error_type)["error"]
error = openai_error(code, message, error_type, resets_at=resets_at)["error"]
if error_param:
error["param"] = error_param
if created_at is None:
Expand Down
4 changes: 2 additions & 2 deletions app/core/openai/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@
_ASSISTANT_TEXT_PART_TYPES = frozenset({"text", "input_text", "output_text"})
_TOOL_TEXT_PART_TYPES = frozenset({"text", "input_text", "output_text", "refusal"})
_COMPACT_STATE_TOOL_NAMES = frozenset({"create_goal", "get_goal", "update_goal", "update_plan"})
_COMPACT_TOOL_CALL_ITEM_TYPES = frozenset({"function_call", "custom_tool_call", "apply_patch_call"})
_COMPACT_TOOL_CALL_ITEM_TYPES = frozenset({"function_call", "custom_tool_call", "apply_patch_call", "tool_search_call"})
_COMPACT_TOOL_CALL_OUTPUT_ITEM_TYPES = frozenset(
{"function_call_output", "custom_tool_call_output", "apply_patch_call_output"}
{"function_call_output", "custom_tool_call_output", "apply_patch_call_output", "tool_search_output"}
)
_EXPLICIT_PROMPT_CACHE_CONTENT_TYPES = frozenset({"input_text", "input_image", "input_file"})
_GOAL_CONTINUATION_CONTEXT_PREFIX = '<codex_internal_context source="goal">'
Expand Down
Loading
Loading