@@ -421,6 +421,12 @@ def __init__(
421421 # Pass the entire string so LiteLLM can parse provider/model
422422 self .llm_instance = LLM (model = llm )
423423 self ._using_custom_llm = True
424+
425+ # Ensure tools are properly accessible when using custom LLM
426+ if tools :
427+ logging .debug (f"Tools passed to Agent with custom LLM: { tools } " )
428+ # Store the tools for later use
429+ self .tools = tools
424430 except ImportError as e :
425431 raise ImportError (
426432 "LLM features requested but dependencies not installed. "
@@ -519,9 +525,20 @@ def execute_tool(self, function_name, arguments):
519525 """
520526 logging .debug (f"{ self .name } executing tool { function_name } with arguments: { arguments } " )
521527
528+ # Special handling for MCP tools
529+ # Check if tools is an MCP instance with the requested function name
530+ from ..mcp .mcp import MCP
531+ if isinstance (self .tools , MCP ):
532+ logging .debug (f"Looking for MCP tool { function_name } " )
533+ # Check if any of the MCP tools match the function name
534+ for mcp_tool in self .tools .runner .tools :
535+ if hasattr (mcp_tool , 'name' ) and mcp_tool .name == function_name :
536+ logging .debug (f"Found matching MCP tool: { function_name } " )
537+ return self .tools .runner .call_tool (function_name , arguments )
538+
522539 # Try to find the function in the agent's tools list first
523540 func = None
524- for tool in self .tools :
541+ for tool in self .tools if isinstance ( self . tools , ( list , tuple )) else [] :
525542 if (callable (tool ) and getattr (tool , '__name__' , '' ) == function_name ) or \
526543 (inspect .isclass (tool ) and tool .__name__ == function_name ):
527544 func = tool
@@ -643,24 +660,64 @@ def _chat_completion(self, messages, temperature=0.2, tools=None, stream=True, r
643660 logging .warning (f"Tool { tool } not recognized" )
644661
645662 try :
646- if stream :
647- # Process as streaming response with formatted tools
648- final_response = self ._process_stream_response (
649- messages ,
650- temperature ,
651- start_time ,
652- formatted_tools = formatted_tools if formatted_tools else None ,
653- reasoning_steps = reasoning_steps
654- )
663+ # Use the custom LLM instance if available
664+ if self ._using_custom_llm and hasattr (self , 'llm_instance' ):
665+ if stream :
666+ # Debug logs for tool info
667+ if formatted_tools :
668+ logging .debug (f"Passing { len (formatted_tools )} formatted tools to LLM instance: { formatted_tools } " )
669+
670+ # Use the LLM instance for streaming responses
671+ final_response = self .llm_instance .get_response (
672+ prompt = messages [1 :], # Skip system message as LLM handles it separately
673+ system_prompt = messages [0 ]['content' ] if messages and messages [0 ]['role' ] == 'system' else None ,
674+ temperature = temperature ,
675+ tools = formatted_tools if formatted_tools else None ,
676+ verbose = self .verbose ,
677+ markdown = self .markdown ,
678+ stream = True ,
679+ console = self .console ,
680+ execute_tool_fn = self .execute_tool ,
681+ agent_name = self .name ,
682+ agent_role = self .role ,
683+ reasoning_steps = reasoning_steps
684+ )
685+ else :
686+ # Non-streaming with custom LLM
687+ final_response = self .llm_instance .get_response (
688+ prompt = messages [1 :],
689+ system_prompt = messages [0 ]['content' ] if messages and messages [0 ]['role' ] == 'system' else None ,
690+ temperature = temperature ,
691+ tools = formatted_tools if formatted_tools else None ,
692+ verbose = self .verbose ,
693+ markdown = self .markdown ,
694+ stream = False ,
695+ console = self .console ,
696+ execute_tool_fn = self .execute_tool ,
697+ agent_name = self .name ,
698+ agent_role = self .role ,
699+ reasoning_steps = reasoning_steps
700+ )
655701 else :
656- # Process as regular non-streaming response
657- final_response = client .chat .completions .create (
658- model = self .llm ,
659- messages = messages ,
660- temperature = temperature ,
661- tools = formatted_tools if formatted_tools else None ,
662- stream = False
663- )
702+ # Use the standard OpenAI client approach
703+ if stream :
704+ # Process as streaming response with formatted tools
705+ final_response = self ._process_stream_response (
706+ messages ,
707+ temperature ,
708+ start_time ,
709+ formatted_tools = formatted_tools if formatted_tools else None ,
710+ reasoning_steps = reasoning_steps
711+ )
712+ else :
713+ # Process as regular non-streaming response
714+ final_response = client .chat .completions .create (
715+ model = self .llm ,
716+ messages = messages ,
717+ temperature = temperature ,
718+ tools = formatted_tools if formatted_tools else None ,
719+ stream = False
720+ )
664721
665722 tool_calls = getattr (final_response .choices [0 ].message , 'tool_calls' , None )
666723
@@ -748,13 +805,26 @@ def chat(self, prompt, temperature=0.2, tools=None, output_json=None, output_pyd
748805
749806 if self ._using_custom_llm :
750807 try :
808+ # Special handling for MCP tools when using provider/model format
809+ tool_param = self .tools if tools is None else tools
810+
811+ # Convert MCP tool objects to OpenAI format if needed
812+ if tool_param is not None :
813+ from ..mcp .mcp import MCP
814+ if isinstance (tool_param , MCP ) and hasattr (tool_param , 'to_openai_tool' ):
815+ logging .debug ("Converting MCP tool to OpenAI format" )
816+ openai_tool = tool_param .to_openai_tool ()
817+ if openai_tool :
818+ tool_param = [openai_tool ]
819+ logging .debug (f"Converted MCP tool: { tool_param } " )
820+
751821 # Pass everything to LLM class
752822 response_text = self .llm_instance .get_response (
753823 prompt = prompt ,
754824 system_prompt = f"{ self .backstory } \n \n Your Role: { self .role } \n \n Your Goal: { self .goal } " if self .use_system_prompt else None ,
755825 chat_history = self .chat_history ,
756826 temperature = temperature ,
757- tools = self . tools if tools is None else tools ,
827+ tools = tool_param ,
758828 output_json = output_json ,
759829 output_pydantic = output_pydantic ,
760830 verbose = self .verbose ,
0 commit comments