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
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.14"
__version__ = "0.99.15"
__all__ = [
# Config
"config",
......
......@@ -90,55 +90,82 @@ class KiloOAuth2:
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:
Dict with 'code', 'verificationUrl', and 'expiresIn'
Raises:
Exception: If initiation fails
Exception: If initiation fails after all retries
"""
url = f"{self.api_base}/api/device-auth/codes"
max_retries = 3
base_delay = 1.0
async with httpx.AsyncClient() as client:
try:
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': '0',
'User-Agent': 'AISBF/0.99.13 (httpx)'
}
# Log the exact request details
logger.info(f"KiloOAuth2: Initiating device auth request")
logger.info(f"KiloOAuth2: URL: {url}")
logger.info(f"KiloOAuth2: Headers: {headers}")
logger.info(f"KiloOAuth2: Body: b''")
logger.info(f"KiloOAuth2: httpx version: {httpx.__version__}")
response = await client.post(
url,
content=b'',
headers=headers,
timeout=30.0
)
# Log the exact response details
logger.info(f"KiloOAuth2: Response status: {response.status_code}")
logger.info(f"KiloOAuth2: Response headers: {dict(response.headers)}")
logger.info(f"KiloOAuth2: Response body: {response.text}")
if response.status_code == 429:
raise Exception("Too many pending authorization requests. Please try again later.")
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:
logger.error(f"KiloOAuth2: Failed to initiate device auth: {e}")
raise Exception(f"Failed to initiate device authorization: {e}")
for attempt in range(max_retries):
try:
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': '0',
'User-Agent': 'AISBF/0.99.14 (httpx)'
}
if attempt > 0:
logger.info(f"KiloOAuth2: Retry attempt {attempt + 1}/{max_retries}")
# Log the exact request details
logger.info(f"KiloOAuth2: Initiating device auth request")
logger.info(f"KiloOAuth2: URL: {url}")
logger.info(f"KiloOAuth2: Headers: {headers}")
logger.info(f"KiloOAuth2: Body: b''")
logger.info(f"KiloOAuth2: httpx version: {httpx.__version__}")
response = await client.post(
url,
content=b'',
headers=headers,
timeout=30.0
)
# Log the exact response details
logger.info(f"KiloOAuth2: Response status: {response.status_code}")
logger.info(f"KiloOAuth2: Response headers: {dict(response.headers)}")
logger.info(f"KiloOAuth2: Response body: {response.text}")
# Check for Vercel edge node in response
vercel_id = response.headers.get('x-vercel-id', 'unknown')
logger.info(f"KiloOAuth2: Vercel edge node: {vercel_id}")
if response.status_code == 429:
raise Exception("Too many pending authorization requests. Please try again later.")
# 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]:
"""
......
......@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
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"
readme = "README.md"
license = "GPL-3.0-or-later"
......
......@@ -49,7 +49,7 @@ class InstallCommand(_install):
setup(
name="aisbf",
version="0.99.14",
version="0.99.15",
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