Treat CoderAI broker warm-up as wait-and-retry, not a provider failure

CoderAI workers often run on small/edge hardware that drops its broker
session while cooling down to avoid overheating. A missing broker session
("No active CoderAI broker session...") was treated as a hard error:
record_failure() was called in both the provider handler and the rotation
loop, so three of them in one request disabled the provider for a 300s
cooldown — exactly when it just needed a moment to warm back up.

Now this transient condition is handled gracefully:
- coderai.py no longer records a failure when the error is a missing broker
  session (in any request path), so it never counts toward the disable
  threshold.
- The rotation handler detects the CoderAI warm-up condition and waits
  CODERAI_WARMUP_WAIT_SECONDS (10s) before retrying the same provider, up to
  CODERAI_MAX_WARMUP_WAITS (3) times, fully transparent to the client. Only
  after that does it fail over to the next provider — still without recording
  a failure.

Bump version to 0.99.76.
Co-Authored-By: 's avatarClaude Opus 4.8 <noreply@anthropic.com>
parent 03f3e110
......@@ -55,7 +55,7 @@ from .auth.qwen import QwenOAuth2
from .handlers import RequestHandler, RotationHandler, AutoselectHandler
from .utils import count_messages_tokens, split_messages_into_chunks, get_max_request_tokens_for_model
__version__ = "0.99.75"
__version__ = "0.99.76"
__all__ = [
# Config
"config",
......
......@@ -65,6 +65,14 @@ from .prompt_analysis import analyze_prompt_payload
_autoselect_result_cache: dict = {}
_autoselect_result_cache_ttl: int = 3600 # seconds
# CoderAI providers often run on small/edge hardware that drops its broker session
# while cooling down. Treat a missing broker session as a transient "warming up"
# state: wait CODERAI_WARMUP_WAIT_SECONDS and retry the same provider, up to
# CODERAI_MAX_WARMUP_WAITS times, instead of recording a failure (which would
# disable the provider for a long cooldown).
CODERAI_WARMUP_WAIT_SECONDS: float = 10.0
CODERAI_MAX_WARMUP_WAITS: int = 3
# Registry for proxied content — shared across all RequestHandler instances.
# Values: {"type": "broker", "provider_id": str, "path": str}
# or {"type": "http", "url": str}
......@@ -3481,6 +3489,7 @@ class RotationHandler:
max_retries = 5
tried_models = [] # Track which models have been tried
model_retry_counts = {} # Track retry count per model
coderai_warmup_counts = {} # Track CoderAI "warming up" waits per model
last_error = None
successful_model = None
successful_handler = None
......@@ -3898,6 +3907,32 @@ class RotationHandler:
except Exception as e:
last_error = str(e)
# CoderAI "warming up": the broker session is temporarily gone while
# the (often small/edge) worker cools down. This is NOT a provider
# fault — do not record a failure (which would disable the provider for
# a long cooldown). Instead wait a few seconds and retry the same
# provider, up to a bounded number of times, fully transparent to the
# client.
if self._is_coderai_warming_error(e, provider_id):
warmup_count = coderai_warmup_counts.get(model_key, 0)
if warmup_count < CODERAI_MAX_WARMUP_WAITS:
coderai_warmup_counts[model_key] = warmup_count + 1
logger.warning(
f"CoderAI provider {provider_id} is warming up (no broker session); "
f"waiting {CODERAI_WARMUP_WAIT_SECONDS:.0f}s and retrying "
f"(warmup {warmup_count + 1}/{CODERAI_MAX_WARMUP_WAITS}) — not recorded as a failure"
)
await asyncio.sleep(CODERAI_WARMUP_WAIT_SECONDS)
continue
logger.warning(
f"CoderAI provider {provider_id} still warming up after "
f"{warmup_count} wait(s); failing over to the next provider "
f"(still not recorded as a failure)"
)
tried_models.append(current_model)
continue
handler.record_failure()
# Increment retry count for this model
......@@ -4295,6 +4330,28 @@ class RotationHandler:
return True
return False
def _is_coderai_warming_error(self, error, provider_id) -> bool:
"""Return True when the error is a CoderAI provider that is merely 'warming up'.
CoderAI workers often run on small/edge hardware that disconnects its broker
session while cooling down (to avoid overheating). A missing broker session is
therefore a transient condition, not a provider fault: instead of recording a
failure (which would count toward disabling the provider for a long cooldown),
the rotation should wait a few seconds and retry the same provider.
"""
msg = str(error or '')
if 'No active CoderAI broker session' not in msg:
return False
# The message is already CoderAI-specific; confirm the provider type when we
# can, but don't require it (the snapshot lookup may be unavailable).
try:
ptype = (self._get_provider_type(provider_id) or '').lower()
if ptype and ptype != 'coderai':
return False
except Exception:
pass
return True
async def _prime_stream(self, response):
"""Pull the first chunk of a streaming response so that immediate provider
errors are raised here (within the rotation retry loop) instead of after the
......
......@@ -502,8 +502,14 @@ class CoderAIProviderHandler(BaseProviderHandler):
if not stream:
self.record_success()
return response
except Exception:
self.record_failure()
except Exception as e:
# A missing broker session means the CoderAI worker (often small/edge
# hardware) is warming up / cooling down to avoid overheating — a
# transient condition, not a provider fault. Don't record a failure for
# it (that would count toward disabling the provider for a long
# cooldown); the rotation handler waits a few seconds and retries.
if 'No active CoderAI broker session' not in str(e):
self.record_failure()
raise
async def get_models(self) -> List[Model]:
......
......@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "aisbf"
version = "0.99.75"
version = "0.99.76"
description = "AISBF - AI Service Broker Framework || AI Should Be Free - A modular proxy server for managing multiple AI provider integrations"
readme = "README.md"
license = "GPL-3.0-or-later"
......
......@@ -106,7 +106,7 @@ class InstallCommand(_install):
setup(
name="aisbf",
version="0.99.75",
version="0.99.76",
author="AISBF Contributors",
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",
......
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