diff --git a/devgen/providers/anthropic.py b/devgen/providers/anthropic.py index f9174bb..1516398 100644 --- a/devgen/providers/anthropic.py +++ b/devgen/providers/anthropic.py @@ -1,5 +1,7 @@ import anthropic +from devgen.utils import format_token_limit_error, is_token_limit_error + class AnthropicProvider: """Generates content using Anthropic's Claude models.""" @@ -23,4 +25,9 @@ class AnthropicProvider: ) return message.content[0].text.strip() except Exception as e: - raise RuntimeError(f"Anthropic generation failed: {e}") + if is_token_limit_error(e): + raise RuntimeError(format_token_limit_error("Anthropic", e)) from e + raise RuntimeError( + f"Anthropic generation failed: {e}. " + "Check the model id and your account credits." + ) from e diff --git a/devgen/providers/gemini.py b/devgen/providers/gemini.py index 8ceafc8..4b25feb 100644 --- a/devgen/providers/gemini.py +++ b/devgen/providers/gemini.py @@ -2,6 +2,8 @@ import time from google import genai from google.genai import types +from devgen.utils import format_token_limit_error, is_token_limit_error + class GeminiProvider: """Generates content using Google's Gemini models.""" @@ -40,6 +42,10 @@ class GeminiProvider: return response.text.strip() except Exception as e: error_msg = str(e).upper() + # Token / context-window overflow is not retryable — no point + # backing off, the prompt is just too big. + if is_token_limit_error(e): + raise RuntimeError(format_token_limit_error("Gemini", e)) from e # Check for 429 or ResourceExhausted in common error formats if any( x in error_msg diff --git a/devgen/providers/huggingface.py b/devgen/providers/huggingface.py index 221a34e..90dc4d2 100644 --- a/devgen/providers/huggingface.py +++ b/devgen/providers/huggingface.py @@ -1,5 +1,7 @@ import requests +from devgen.utils import format_token_limit_error, is_token_limit_error + class HuggingfaceProvider: """Generates content using Hugging Face Inference API.""" @@ -46,6 +48,10 @@ class HuggingfaceProvider: f"Hugging Face model is loading: {err}. " "Wait a minute and retry, or pick a different model." ) + if is_token_limit_error(err): + raise RuntimeError( + format_token_limit_error("Hugging Face", err) + ) from err raise RuntimeError(f"Hugging Face API error: {err}") else: raise RuntimeError( @@ -55,6 +61,8 @@ class HuggingfaceProvider: except requests.HTTPError as e: status = e.response.status_code if e.response is not None else "?" + if is_token_limit_error(e): + raise RuntimeError(format_token_limit_error("Hugging Face", e)) from e raise RuntimeError( f"Hugging Face request failed (HTTP {status}): {e}. " "Check the model id and your token permissions." @@ -63,5 +71,9 @@ class HuggingfaceProvider: raise RuntimeError( f"Hugging Face network error: {e}. Check your connection." ) from e + except RuntimeError: + raise except Exception as e: + if is_token_limit_error(e): + raise RuntimeError(format_token_limit_error("Hugging Face", e)) from e raise RuntimeError(f"Hugging Face generation failed: {e}") from e diff --git a/devgen/providers/ollama.py b/devgen/providers/ollama.py index 2b362a4..577b07c 100644 --- a/devgen/providers/ollama.py +++ b/devgen/providers/ollama.py @@ -1,3 +1,4 @@ +from devgen.utils import format_token_limit_error, is_token_limit_error class OllamaProvider: @@ -37,6 +38,8 @@ class OllamaProvider: **kwargs, ) except Exception as e: + if is_token_limit_error(e): + raise RuntimeError(format_token_limit_error("Ollama", e)) from e raise RuntimeError( f"Ollama request failed (host={host}, model={chosen_model}): {e}. " "Is the Ollama server running? Start it with `ollama serve` and " diff --git a/devgen/providers/openai.py b/devgen/providers/openai.py index d3cd3ff..4bf155d 100644 --- a/devgen/providers/openai.py +++ b/devgen/providers/openai.py @@ -1,5 +1,7 @@ from openai import OpenAI +from devgen.utils import format_token_limit_error, is_token_limit_error + class OpenaiProvider: """Generates a response string using the OpenAI ChatCompletion API based on the provided prompt and parameters. This method initializes an OpenAI client with the given API key, sends a chat completion request with specified model and additional parameters, and returns the content of the generated message. @@ -59,6 +61,8 @@ class OpenaiProvider: **kwargs, ) except Exception as e: + if is_token_limit_error(e): + raise RuntimeError(format_token_limit_error("OpenAI", e)) from e raise RuntimeError( f"OpenAI request failed: {e}. " "Check the model name, API key permissions, and your account quota." diff --git a/devgen/providers/openrouter.py b/devgen/providers/openrouter.py index 5b9355c..3eea592 100644 --- a/devgen/providers/openrouter.py +++ b/devgen/providers/openrouter.py @@ -1,5 +1,7 @@ from openai import OpenAI +from devgen.utils import format_token_limit_error, is_token_limit_error + class OpenrouterProvider: """Generates content using OpenRouter (OpenAI-compatible API).""" @@ -36,6 +38,8 @@ class OpenrouterProvider: ) return response.choices[0].message.content.strip() except Exception as e: + if is_token_limit_error(e): + raise RuntimeError(format_token_limit_error("OpenRouter", e)) from e raise RuntimeError( f"OpenRouter request failed: {e}. " "Verify the model id (e.g. `openai/gpt-4o`) and your API key credits."