OpenAI's completion_tokens already includes reasoning_tokens as a subset,
so adding them again was incorrectly inflating token counts by ~2x for
all reasoning models (o1, o3, o4-mini, etc.).
This aligns with other OpenAI-compatible providers (OpenRouter, Vercel,
Cerebras, Groq) which use completion_tokens directly.
Note: This is different from Google Gemini where thinking_tokens ARE
reported separately and need to be added.
Fixes#4065
Fix indentation so structured-output request executes even when add_schema_to_system_prompt is false; add regression tests for choices=null in both structured and non-structured paths.
Avoid indexing response.choices[0] when proxies return choices=null/empty; raise a clear ModelProviderError (with base_url hint) and use the validated first choice for content/finish_reason
- agent/views.py: Move RateLimitError import inside format_error() function
to avoid loading openai SDK (~800ms) at module level
- llm/messages.py: Replace openai.BaseModel with pydantic.BaseModel directly
to remove unnecessary openai dependency
- filesystem/file_system.py: Move reportlab imports inside sync_to_disk_sync()
to avoid ~40ms startup cost when PDF generation is not used
- utils.py: Convert OpenAIBadRequestError and GroqBadRequestError to lazy
loaders to avoid loading SDKs at module level
This improves import time for users who don't use OpenAI provider,
especially when using Anthropic, Google, or other providers.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Content blocks are dictionaries at runtime despite type annotations
indicating Pydantic models. Added type: ignore comments to allow
dictionary-style .get() access which works correctly at runtime.
Previously, cache_control was applied to every content block and tool call
in a message, which could exceed Anthropic's limit of 4 cache breakpoints
per request. This fix ensures cache_control is only applied to the last
block in each message type:
- Last text block in UserMessage/AssistantMessage content
- Last tool_use block when AssistantMessage has tool calls
- Only the last overall block when AssistantMessage has both content and tools
This prevents exceeding the cache breakpoint limit while maintaining
correct caching behavior.
Fix KeyError that occurs when using OpenAI reasoning models (o1, o3, etc.)
with temperature=None or frequency_penalty=None.
The code was using 'del' to remove keys that may not exist in model_params
dictionary. Changed to use .pop() with default value for safe key removal.
Fixes crash scenario:
- ChatOpenAI(model='o1-mini', temperature=None) -> KeyError
Changes:
- Replace 'del model_params[key]' with 'model_params.pop(key, None)'
- Ensures parameters are safely removed even if not present in dict