@@ -32,6 +32,7 @@ class LLM:
3232 MAX_TOKEN_LIMIT = 120000 # Maximum token limit (for Claude 3.7 Sonnet)
3333 MAX_THINKING_BUDGET = 64000 # Maximum thinking budget
3434 MIN_THINKING_BUDGET = 1200 # Minimum thinking budget
35+ DEFAULT_OUTPUT_TOKENS = 32000
3536
3637 def __init__ (
3738 self ,
@@ -55,6 +56,7 @@ def __init__(
5556 self .is_thinking = False # Initialize is_thinking flag
5657 self .page_count = None # Initialize page count
5758 self .thinking_budget = self .THINKING_BUDGET_TOKENS # Default thinking budget
59+ self .thinking_token_limit : Optional [int ] = None
5860
5961 if self .backend == LLMEngine .DEFAULT :
6062 self .client = instructor .from_litellm (
@@ -67,7 +69,6 @@ def __init__(
6769 from pydantic_ai import Agent
6870 from pydantic_ai .models import KnownModelName
6971 from typing import cast
70- import asyncio
7172
7273 self .client = None
7374 self .agent = Agent (
@@ -158,7 +159,7 @@ def set_page_count(self, page_count: int) -> None:
158159 thinking_tokens = min (thinking_tokens , self .MAX_THINKING_BUDGET )
159160
160161 # Update token limit and thinking budget
161- self .token_limit = content_tokens
162+ self .thinking_token_limit = content_tokens
162163 self .thinking_budget = thinking_tokens
163164
164165 def request (
@@ -171,14 +172,7 @@ def request(
171172 # Combine messages into a single prompt
172173 combined_prompt = " " .join ([m ["content" ] for m in messages ])
173174 try :
174- # Create event loop if it doesn't exist
175- try :
176- loop = asyncio .get_event_loop ()
177- except RuntimeError :
178- loop = asyncio .new_event_loop ()
179- asyncio .set_event_loop (loop )
180-
181- result = loop .run_until_complete (
175+ result = asyncio .run (
182176 self .agent .run (
183177 combined_prompt ,
184178 result_type = response_model if response_model else str
@@ -225,139 +219,108 @@ def request(
225219
226220 def _request_with_router (self , messages : List [Dict [str , str ]], response_model : Optional [str ]) -> Any :
227221 """Handle request using router with or without thinking parameter"""
222+ max_tokens = self .DEFAULT_OUTPUT_TOKENS
223+ if self .token_limit is not None :
224+ max_tokens = self .token_limit
225+ elif self .is_thinking :
226+ max_tokens = self .thinking_token_limit
227+
228+ params = {
229+ "model" : self .model ,
230+ "messages" : messages ,
231+ "response_model" : response_model ,
232+ "temperature" : self .temperature ,
233+ "timeout" : self .TIMEOUT ,
234+ "max_completion_tokens" : max_tokens ,
235+ }
228236 if self .is_thinking :
229- # Add thinking parameter for supported models
230- thinking_param = {
231- "type" : "enabled" ,
232- "budget_tokens" : self .thinking_budget
233- }
234- try :
235- return self .router .completion (
236- model = self .model ,
237- messages = messages ,
238- response_model = response_model ,
239- temperature = self .temperature ,
240- timeout = self .TIMEOUT ,
241- thinking = thinking_param ,
242- )
243- except Exception as e :
244- # If thinking parameter causes an error, try without it
245- if "property 'thinking' is unsupported" in str (e ):
246- print (f"Warning: Model { self .model } doesn't support thinking parameter, proceeding without it." )
247- return self .router .completion (
248- model = self .model ,
249- messages = messages ,
250- response_model = response_model ,
251- temperature = self .temperature ,
252- timeout = self .TIMEOUT ,
253- )
254- else :
255- raise e
256- else :
257- # Normal request without thinking parameter
258- return self .router .completion (
259- model = self .model ,
260- messages = messages ,
261- response_model = response_model ,
262- temperature = self .temperature ,
263- timeout = self .TIMEOUT ,
264- )
237+ if litellm .supports_reasoning (self .model ):
238+ # Add thinking parameter for supported models
239+ thinking_param = {
240+ "type" : "enabled" ,
241+ "budget_tokens" : self .thinking_budget
242+ }
243+ params ["thinking" ] = thinking_param
244+ else :
245+ print (f"Warning: Model { self .model } doesn't support thinking parameter, proceeding without it." )
246+
247+ return self .router .completion (** params )
265248
266249 def _request_direct (self , messages : List [Dict [str , str ]], response_model : Optional [str ]) -> Any :
267250 """Handle direct request with or without thinking parameter"""
251+ max_tokens = self .DEFAULT_OUTPUT_TOKENS
252+ if self .token_limit is not None :
253+ max_tokens = self .token_limit
254+ elif self .is_thinking :
255+ max_tokens = self .thinking_token_limit
256+
268257 base_params = {
269258 "model" : self .model ,
270259 "messages" : messages ,
271260 "temperature" : self .temperature ,
272261 "response_model" : response_model ,
273262 "max_retries" : 1 ,
274- "max_tokens " : self . token_limit ,
263+ "max_completion_tokens " : max_tokens ,
275264 "timeout" : self .TIMEOUT ,
276265 }
277266
278267 if self .is_thinking :
279- # Try with thinking parameter
280- thinking_param = {
281- "type" : "enabled" ,
282- "budget_tokens" : self .thinking_budget
283- }
284- try :
285- return self .client .chat .completions .create (
286- ** base_params ,
287- thinking = thinking_param ,
288- )
289- except Exception as e :
290- # If thinking parameter causes an error, try without it
291- if "property 'thinking' is unsupported" in str (e ):
292- print (f"Warning: Model { self .model } doesn't support thinking parameter, proceeding without it." )
293- return self .client .chat .completions .create (** base_params )
294- else :
295- raise e
296- else :
297- # Normal request without thinking parameter
298- return self .client .chat .completions .create (** base_params )
299-
300- def raw_completion (self , messages : List [Dict [str , str ]]) -> str :
301- """Make raw completion request without response model."""
302- if self .router :
303- if self .is_thinking :
304- # Add thinking parameter for supported models
268+ if litellm .supports_reasoning (self .model ):
269+ # Try with thinking parameter
305270 thinking_param = {
306271 "type" : "enabled" ,
307272 "budget_tokens" : self .thinking_budget
308273 }
309- try :
310- raw_response = self .router .completion (
311- model = self .model ,
312- messages = messages ,
313- thinking = thinking_param ,
314- )
315- except Exception as e :
316- # If thinking parameter causes an error, try without it
317- if "property 'thinking' is unsupported" in str (e ):
318- print (f"Warning: Model { self .model } doesn't support thinking parameter, proceeding without it." )
319- raw_response = self .router .completion (
320- model = self .model ,
321- messages = messages ,
322- )
323- else :
324- raise e
274+ base_params ["thinking" ] = thinking_param
325275 else :
326- raw_response = self .router .completion (
327- model = self .model ,
328- messages = messages ,
276+ print (f"Warning: Model { self .model } doesn't support thinking parameter, proceeding without it." )
277+
278+ return self .client .chat .completions .create (** base_params )
279+
280+ def raw_completion (self , messages : List [Dict [str , str ]]) -> str :
281+ """Make raw completion request without response model."""
282+ if self .backend == LLMEngine .PYDANTIC_AI :
283+ # Combine messages into a single prompt
284+ combined_prompt = " " .join ([m ["content" ] for m in messages ])
285+ try :
286+ result = asyncio .run (
287+ self .agent .run (
288+ combined_prompt ,
289+ result_type = str
290+ )
329291 )
330- else :
331- if self .is_thinking :
292+ return result .data
293+ except Exception as e :
294+ raise ValueError (f"Failed to extract from source: { str (e )} " )
295+
296+ max_tokens = self .DEFAULT_OUTPUT_TOKENS
297+ if self .token_limit is not None :
298+ max_tokens = self .token_limit
299+ elif self .is_thinking :
300+ max_tokens = self .thinking_token_limit
301+
302+ params = {
303+ "model" : self .model ,
304+ "messages" : messages ,
305+ "max_completion_tokens" : max_tokens ,
306+ }
307+
308+ if self .is_thinking :
309+ if litellm .supports_reasoning (self .model ):
332310 # Add thinking parameter for supported models
333311 thinking_param = {
334312 "type" : "enabled" ,
335313 "budget_tokens" : self .thinking_budget
336314 }
337- try :
338- raw_response = litellm .completion (
339- model = self .model ,
340- messages = messages ,
341- max_tokens = self .token_limit ,
342- thinking = thinking_param ,
343- )
344- except Exception as e :
345- # If thinking parameter causes an error, try without it
346- if "property 'thinking' is unsupported" in str (e ):
347- print (f"Warning: Model { self .model } doesn't support thinking parameter, proceeding without it." )
348- raw_response = litellm .completion (
349- model = self .model ,
350- messages = messages ,
351- max_tokens = self .token_limit ,
352- )
353- else :
354- raise e
315+ params ["thinking" ] = thinking_param
355316 else :
356- raw_response = litellm .completion (
357- model = self .model ,
358- messages = messages ,
359- max_tokens = self .token_limit ,
360- )
317+ print (f"Warning: Model { self .model } doesn't support thinking parameter, proceeding without it." )
318+
319+ if self .router :
320+ raw_response = self .router .completion (** params )
321+ else :
322+ raw_response = litellm .completion (** params )
323+
361324 return raw_response .choices [0 ].message .content
362325
363326 def set_timeout (self , timeout_ms : int ) -> None :
0 commit comments