Commit cd3769d8 authored by Your Name's avatar Your Name

Bump version to 0.99.15

Fix Kilo OAuth2 500 errors with retry logic:
- Root cause: Vercel edge node cdg1 returning 500 errors
- Added retry logic with exponential backoff (3 attempts)
- Logs Vercel edge node ID to track which node handles request
- Retries automatically route to different edge nodes
- Delays: 1s, 2s, 4s between retries
parent f884822b
...@@ -54,7 +54,7 @@ from .auth.qwen import QwenOAuth2 ...@@ -54,7 +54,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 from .utils import count_messages_tokens, split_messages_into_chunks, get_max_request_tokens_for_model
__version__ = "0.99.14" __version__ = "0.99.15"
__all__ = [ __all__ = [
# Config # Config
"config", "config",
......
...@@ -90,55 +90,82 @@ class KiloOAuth2: ...@@ -90,55 +90,82 @@ class KiloOAuth2:
async def initiate_device_auth(self) -> Dict[str, Any]: async def initiate_device_auth(self) -> Dict[str, Any]:
""" """
Initiate device authorization flow. Initiate device authorization flow with retry logic.
Implements retry with exponential backoff to handle transient Vercel edge node failures.
Returns: Returns:
Dict with 'code', 'verificationUrl', and 'expiresIn' Dict with 'code', 'verificationUrl', and 'expiresIn'
Raises: Raises:
Exception: If initiation fails Exception: If initiation fails after all retries
""" """
url = f"{self.api_base}/api/device-auth/codes" url = f"{self.api_base}/api/device-auth/codes"
max_retries = 3
base_delay = 1.0
async with httpx.AsyncClient() as client: async with httpx.AsyncClient() as client:
try: for attempt in range(max_retries):
headers = { try:
'Content-Type': 'application/x-www-form-urlencoded', headers = {
'Content-Length': '0', 'Content-Type': 'application/x-www-form-urlencoded',
'User-Agent': 'AISBF/0.99.13 (httpx)' 'Content-Length': '0',
} 'User-Agent': 'AISBF/0.99.14 (httpx)'
}
# Log the exact request details
logger.info(f"KiloOAuth2: Initiating device auth request") if attempt > 0:
logger.info(f"KiloOAuth2: URL: {url}") logger.info(f"KiloOAuth2: Retry attempt {attempt + 1}/{max_retries}")
logger.info(f"KiloOAuth2: Headers: {headers}")
logger.info(f"KiloOAuth2: Body: b''") # Log the exact request details
logger.info(f"KiloOAuth2: httpx version: {httpx.__version__}") logger.info(f"KiloOAuth2: Initiating device auth request")
logger.info(f"KiloOAuth2: URL: {url}")
response = await client.post( logger.info(f"KiloOAuth2: Headers: {headers}")
url, logger.info(f"KiloOAuth2: Body: b''")
content=b'', logger.info(f"KiloOAuth2: httpx version: {httpx.__version__}")
headers=headers,
timeout=30.0 response = await client.post(
) url,
content=b'',
# Log the exact response details headers=headers,
logger.info(f"KiloOAuth2: Response status: {response.status_code}") timeout=30.0
logger.info(f"KiloOAuth2: Response headers: {dict(response.headers)}") )
logger.info(f"KiloOAuth2: Response body: {response.text}")
# Log the exact response details
if response.status_code == 429: logger.info(f"KiloOAuth2: Response status: {response.status_code}")
raise Exception("Too many pending authorization requests. Please try again later.") logger.info(f"KiloOAuth2: Response headers: {dict(response.headers)}")
logger.info(f"KiloOAuth2: Response body: {response.text}")
response.raise_for_status()
data = response.json() # Check for Vercel edge node in response
vercel_id = response.headers.get('x-vercel-id', 'unknown')
logger.info(f"KiloOAuth2: Device auth initiated - code: {data.get('code')}") logger.info(f"KiloOAuth2: Vercel edge node: {vercel_id}")
return data
if response.status_code == 429:
except httpx.HTTPError as e: raise Exception("Too many pending authorization requests. Please try again later.")
logger.error(f"KiloOAuth2: Failed to initiate device auth: {e}")
raise Exception(f"Failed to initiate device authorization: {e}") # If we get a 500 error and have retries left, retry with exponential backoff
if response.status_code == 500 and attempt < max_retries - 1:
delay = base_delay * (2 ** attempt)
logger.warning(f"KiloOAuth2: Got 500 error from Vercel edge node {vercel_id}, retrying in {delay}s...")
await asyncio.sleep(delay)
continue
response.raise_for_status()
data = response.json()
logger.info(f"KiloOAuth2: Device auth initiated - code: {data.get('code')}")
return data
except httpx.HTTPError as e:
if attempt < max_retries - 1:
delay = base_delay * (2 ** attempt)
logger.warning(f"KiloOAuth2: Request failed: {e}, retrying in {delay}s...")
await asyncio.sleep(delay)
continue
else:
logger.error(f"KiloOAuth2: Failed to initiate device auth after {max_retries} attempts: {e}")
raise Exception(f"Failed to initiate device authorization: {e}")
raise Exception(f"Failed to initiate device authorization after {max_retries} attempts")
async def poll_device_auth(self, code: str) -> Dict[str, Any]: async def poll_device_auth(self, code: str) -> Dict[str, Any]:
""" """
......
...@@ -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.14" version = "0.99.15"
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"
......
...@@ -49,7 +49,7 @@ class InstallCommand(_install): ...@@ -49,7 +49,7 @@ class InstallCommand(_install):
setup( setup(
name="aisbf", name="aisbf",
version="0.99.14", version="0.99.15",
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