Guard rotation handler build so a bad-cred provider skips instead of 500 (v0.99.98)

The per-rotation scan called get_provider_handler() unguarded. A rotation member
with invalid/expired credentials (e.g. codex) raises ValueError during credential
validation, which propagated uncaught and returned HTTP 500 for the whole
rotation (hermes bot hitting rotation/lisa). Wrap the build in try/except and
skip the provider on failure, so the rotation falls through to a working member.
Co-Authored-By: 's avatarClaude Opus 4.8 (1M context) <noreply@anthropic.com>
parent 34df388f
...@@ -55,7 +55,7 @@ from .auth.qwen import QwenOAuth2 ...@@ -55,7 +55,7 @@ from .auth.qwen import QwenOAuth2
from .handlers import RequestHandler, RotationHandler, AutoselectHandler from .handlers import RequestHandler, RotationHandler, AutoselectHandler
from .utils import count_messages_tokens, split_messages_into_chunks, get_max_request_tokens_for_model, get_max_completion_tokens_for_model from .utils import count_messages_tokens, split_messages_into_chunks, get_max_request_tokens_for_model, get_max_completion_tokens_for_model
__version__ = "0.99.97" __version__ = "0.99.98"
__all__ = [ __all__ = [
# Config # Config
"config", "config",
......
...@@ -3446,7 +3446,17 @@ class RotationHandler: ...@@ -3446,7 +3446,17 @@ class RotationHandler:
# intentionally NOT consulted here — disabling for a rotation is expressed # intentionally NOT consulted here — disabling for a rotation is expressed
# per entry above, so a manually-disabled provider is still usable in any # per entry above, so a manually-disabled provider is still usable in any
# rotation that lists it as enabled. # rotation that lists it as enabled.
provider_handler = get_provider_handler(provider_id, api_key, user_id=self.user_id) #
# Building the handler can raise (e.g. a provider with invalid/expired
# credentials raises ValueError during credential validation). That must
# NOT crash the whole rotation with a 500 — it just means this provider is
# unusable right now, so skip it and let the rotation try the next one.
try:
provider_handler = get_provider_handler(provider_id, api_key, user_id=self.user_id)
except Exception as e:
logger.warning(f" [SKIPPED] Provider {provider_id} unavailable: handler build failed ({e})")
skipped_providers.append(provider_id)
continue
if _provider_in_availability_cooldown(provider_handler): if _provider_in_availability_cooldown(provider_handler):
logger.warning(f" [SKIPPED] Provider {provider_id} is in an auto-disable cooldown (failure threshold or usage limit)") logger.warning(f" [SKIPPED] Provider {provider_id} is in an auto-disable cooldown (failure threshold or usage limit)")
skipped_providers.append(provider_id) skipped_providers.append(provider_id)
......
...@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" ...@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "aisbf" name = "aisbf"
version = "0.99.97" version = "0.99.98"
description = "AISBF - AI Service Broker Framework || AI Should Be Free - A modular proxy server for managing multiple AI provider integrations" description = "AISBF - AI Service Broker Framework || AI Should Be Free - A modular proxy server for managing multiple AI provider integrations"
readme = "README.md" readme = "README.md"
license = "GPL-3.0-or-later" license = "GPL-3.0-or-later"
......
...@@ -106,7 +106,7 @@ class InstallCommand(_install): ...@@ -106,7 +106,7 @@ class InstallCommand(_install):
setup( setup(
name="aisbf", name="aisbf",
version="0.99.97", version="0.99.98",
author="AISBF Contributors", author="AISBF Contributors",
author_email="stefy@nexlab.net", author_email="stefy@nexlab.net",
description="AISBF - AI Service Broker Framework || AI Should Be Free - A modular proxy server for managing multiple AI provider integrations", description="AISBF - AI Service Broker Framework || AI Should Be Free - A modular proxy server for managing multiple AI provider integrations",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment