fix(gateway): 熔断计入持续 4xx + 去 assert + Protocol/transient 去重

P1-2 非可重试错误(持续 401/403)也 record_failure,坏 key 可触发熔断。
P1-9 _complete_structured 的 assert 改显式 raise ValueError(-O 安全)。
P2 GatewayRun 抽到 orchestrator/_protocols.py 单点(去 4 处重复);
  _is_transient 抽到 adapters/base.py is_transient_by_name(去 3 处重复);
  Gemini Protocol 改 async def;gateway._retrying 去无用 async。
This commit is contained in:
Yaojia Wang
2026-06-21 19:32:49 +02:00
parent f7004e8d74
commit 016509c5c6
15 changed files with 178 additions and 65 deletions

View File

@@ -108,6 +108,22 @@ def transient(msg: str = "boom") -> TransientProviderError:
return TransientProviderError(msg)
class AuthError(Exception):
"""模拟持续性鉴权失败(坏 key / 账号被禁):带 `status_code`**非**瞬时不可重试。
适配器对 401/403 不翻译为 `TransientProviderError`,原样上抛;网关须对其计入熔断
P1-2而非每次白打同一坏 provider。
"""
def __init__(self, msg: str = "unauthorized", *, status_code: int = 401) -> None:
super().__init__(msg)
self.status_code = status_code
def auth_error(status_code: int = 401) -> AuthError:
return AuthError(status_code=status_code)
def chain(*routes: tuple[str, str]) -> list[Route]:
return [Route(provider=p, model=m) for p, m in routes]