@@ -199,21 +199,19 @@ def __init__(self):
199199 "Please set OPENAI_API_KEY environment variable."
200200 )
201201
202- # Initialize ChatOpenAI with JSON output mode
202+ # Initialize ChatOpenAI with low reasoning effort for speed
203203 self .llm = ChatOpenAI (
204204 model = OPENAI_MODEL ,
205205 api_key = OPENAI_API_KEY ,
206206 base_url = OPENAI_BASE_URL or None ,
207207 temperature = 0.0 ,
208- model_kwargs = { "response_format" : { "type" : "json_object" }} ,
208+ reasoning_effort = "low" ,
209209 )
210210
211211 # CSV tools only
212212 self .tools = self ._build_csv_tools ()
213213 self ._system_prompt = self ._build_system_prompt ()
214- # Pre-bind tools with strict=True for JSON mode compatibility
215- model_with_tools = self .llm .bind_tools (self .tools , strict = True ) if self .tools else self .llm
216- self ._react_agent = create_react_agent (model_with_tools , self .tools )
214+ self ._react_agent = create_react_agent (self .llm , self .tools )
217215
218216 def _build_system_prompt (self ) -> str :
219217 """Build a concise system prompt optimized for low-latency tool usage."""
@@ -334,6 +332,40 @@ def _csv_ticket_stats() -> str:
334332 stats = service .get_ticket_stats ()
335333 return json .dumps (stats , default = str )
336334
335+ def _csv_count_tickets (query : str = "" , status : str | None = None ) -> str :
336+ """Count matching tickets without returning data. Fast check before fetching details."""
337+ tickets = service .list_tickets ()
338+ if status :
339+ try :
340+ status_enum = TicketStatus (status .lower ())
341+ tickets = [t for t in tickets if t .status == status_enum ]
342+ except Exception :
343+ pass
344+ if query .strip ():
345+ q = query .strip ().lower ()
346+ tickets = [t for t in tickets if q in " " .join ([
347+ t .summary or "" , t .description or "" , t .notes or "" ,
348+ t .requester_name or "" , t .assigned_group or "" ,
349+ ]).lower ()]
350+ return json .dumps ({"count" : len (tickets ), "query" : query })
351+
352+ def _csv_search_with_details (query : str , limit : int = 10 ) -> str :
353+ """Search tickets with full details (notes, resolution, description) in one call."""
354+ q = query .lower ()
355+ detail_fields = compact_default_fields + ["notes" , "resolution" , "description" , "incident_id" ]
356+ matched = []
357+ for t in service .list_tickets ():
358+ text = " " .join ([
359+ t .summary or "" , t .description or "" , t .notes or "" ,
360+ t .requester_name or "" , t .assigned_group or "" , t .city or "" ,
361+ ]).lower ()
362+ if q in text :
363+ dump = t .model_dump ()
364+ matched .append ({k : v for k , v in dump .items () if k in detail_fields })
365+ if len (matched ) >= min (max (limit , 1 ), 25 ):
366+ break
367+ return json .dumps (matched , default = str )
368+
337369 return [
338370 StructuredTool .from_function (
339371 func = _csv_list_tickets ,
@@ -381,6 +413,19 @@ def _csv_ticket_stats() -> str:
381413 name = "csv_ticket_stats" ,
382414 description = "Get aggregated statistics: total, by_status, by_priority, by_group, by_city." ,
383415 ),
416+ StructuredTool .from_function (
417+ func = _csv_count_tickets ,
418+ name = "csv_count_tickets" ,
419+ description = "Count matching tickets WITHOUT returning data. Use to check result size before fetching details. Fast and cheap." ,
420+ ),
421+ StructuredTool .from_function (
422+ func = _csv_search_with_details ,
423+ name = "csv_search_tickets_with_details" ,
424+ description = (
425+ "Search tickets AND return full details (notes, resolution, description) in one call. "
426+ "Use for knowledgebase, analysis, or detailed reports. Limit defaults to 10, max 25."
427+ ),
428+ ),
384429 ]
385430
386431 async def run_agent (self , request : AgentRequest ) -> AgentResponse :
0 commit comments