praisonaiagents 0.0.67__py3-none-any.whl → 0.0.68__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -421,6 +421,12 @@ class Agent:
421
421
  # Pass the entire string so LiteLLM can parse provider/model
422
422
  self.llm_instance = LLM(model=llm)
423
423
  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
424
430
  except ImportError as e:
425
431
  raise ImportError(
426
432
  "LLM features requested but dependencies not installed. "
@@ -519,9 +525,20 @@ Your Goal: {self.goal}
519
525
  """
520
526
  logging.debug(f"{self.name} executing tool {function_name} with arguments: {arguments}")
521
527
 
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
+
522
539
  # Try to find the function in the agent's tools list first
523
540
  func = None
524
- for tool in self.tools:
541
+ for tool in self.tools if isinstance(self.tools, (list, tuple)) else []:
525
542
  if (callable(tool) and getattr(tool, '__name__', '') == function_name) or \
526
543
  (inspect.isclass(tool) and tool.__name__ == function_name):
527
544
  func = tool
@@ -643,24 +660,64 @@ Your Goal: {self.goal}
643
660
  logging.warning(f"Tool {tool} not recognized")
644
661
 
645
662
  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
+ )
655
701
  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
+ )
664
721
 
665
722
  tool_calls = getattr(final_response.choices[0].message, 'tool_calls', None)
666
723
 
@@ -748,13 +805,26 @@ Your Goal: {self.goal}
748
805
 
749
806
  if self._using_custom_llm:
750
807
  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
+
751
821
  # Pass everything to LLM class
752
822
  response_text = self.llm_instance.get_response(
753
823
  prompt=prompt,
754
824
  system_prompt=f"{self.backstory}\n\nYour Role: {self.role}\n\nYour Goal: {self.goal}" if self.use_system_prompt else None,
755
825
  chat_history=self.chat_history,
756
826
  temperature=temperature,
757
- tools=self.tools if tools is None else tools,
827
+ tools=tool_param,
758
828
  output_json=output_json,
759
829
  output_pydantic=output_pydantic,
760
830
  verbose=self.verbose,
@@ -289,15 +289,21 @@ class LLM:
289
289
  if tools:
290
290
  formatted_tools = []
291
291
  for tool in tools:
292
- if callable(tool):
292
+ # Check if the tool is already in OpenAI format (e.g. from MCP.to_openai_tool())
293
+ if isinstance(tool, dict) and 'type' in tool and tool['type'] == 'function':
294
+ logging.debug(f"Using pre-formatted OpenAI tool: {tool['function']['name']}")
295
+ formatted_tools.append(tool)
296
+ elif callable(tool):
293
297
  tool_def = self._generate_tool_definition(tool.__name__)
298
+ if tool_def:
299
+ formatted_tools.append(tool_def)
294
300
  elif isinstance(tool, str):
295
301
  tool_def = self._generate_tool_definition(tool)
302
+ if tool_def:
303
+ formatted_tools.append(tool_def)
296
304
  else:
297
- continue
305
+ logging.debug(f"Skipping tool of unsupported type: {type(tool)}")
298
306
 
299
- if tool_def:
300
- formatted_tools.append(tool_def)
301
307
  if not formatted_tools:
302
308
  formatted_tools = None
303
309
 
@@ -313,6 +313,45 @@ class MCP:
313
313
  """
314
314
  return iter(self._tools)
315
315
 
316
+ def to_openai_tool(self):
317
+ """Convert the MCP tool to an OpenAI-compatible tool definition.
318
+
319
+ This method is specifically invoked by the Agent class when using
320
+ provider/model format (e.g., "openai/gpt-4o-mini").
321
+
322
+ Returns:
323
+ dict: OpenAI-compatible tool definition
324
+ """
325
+ # For simplicity, we'll convert the first tool only if multiple exist
326
+ # More complex implementations could handle multiple tools
327
+ if not self.runner.tools:
328
+ logging.warning("No MCP tools available to convert to OpenAI format")
329
+ return None
330
+
331
+ # Get the first tool's schema
332
+ tool = self.runner.tools[0]
333
+
334
+ # Create OpenAI tool definition
335
+ parameters = {}
336
+ if hasattr(tool, 'inputSchema') and tool.inputSchema:
337
+ parameters = tool.inputSchema
338
+ else:
339
+ # Create a minimal schema if none exists
340
+ parameters = {
341
+ "type": "object",
342
+ "properties": {},
343
+ "required": []
344
+ }
345
+
346
+ return {
347
+ "type": "function",
348
+ "function": {
349
+ "name": tool.name,
350
+ "description": tool.description if hasattr(tool, 'description') else f"Call the {tool.name} tool",
351
+ "parameters": parameters
352
+ }
353
+ }
354
+
316
355
  def __del__(self):
317
356
  """Clean up resources when the object is garbage collected."""
318
357
  if hasattr(self, 'runner'):
@@ -1,11 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: praisonaiagents
3
- Version: 0.0.67
3
+ Version: 0.0.68
4
4
  Summary: Praison AI agents for completing complex tasks with Self Reflection Agents
5
5
  Author: Mervin Praison
6
6
  Requires-Dist: pydantic
7
7
  Requires-Dist: rich
8
8
  Requires-Dist: openai
9
+ Requires-Dist: mcp==1.6.0
9
10
  Provides-Extra: memory
10
11
  Requires-Dist: chromadb>=0.5.23; extra == "memory"
11
12
  Provides-Extra: knowledge
@@ -1,7 +1,7 @@
1
1
  praisonaiagents/__init__.py,sha256=Z2_rSA6mYozz0r3ioUgKzl3QV8uWRDS_QaqPg2oGjqg,1324
2
2
  praisonaiagents/main.py,sha256=l29nGEbV2ReBi4szURbnH0Fk0w2F_QZTmECysyZjYcA,15066
3
3
  praisonaiagents/agent/__init__.py,sha256=j0T19TVNbfZcClvpbZDDinQxZ0oORgsMrMqx16jZ-bA,128
4
- praisonaiagents/agent/agent.py,sha256=h3s0-1M88zujllDHnKijHmYeVihD75d-K9s2Y3IHLY4,61850
4
+ praisonaiagents/agent/agent.py,sha256=NiTUqkibCKW6Rx0HbR1peY3TtOcQl2O8XdrEV__gPlM,65805
5
5
  praisonaiagents/agent/image_agent.py,sha256=-5MXG594HVwSpFMcidt16YBp7udtik-Cp7eXlzLE1fY,8696
6
6
  praisonaiagents/agents/__init__.py,sha256=_1d6Pqyk9EoBSo7E68sKyd1jDRlN1vxvVIRpoMc0Jcw,168
7
7
  praisonaiagents/agents/agents.py,sha256=KLfSuz6nGEJM-n4xCXdtIkES6cUI-LwvMxI3R-MjrD0,37862
@@ -10,9 +10,9 @@ praisonaiagents/knowledge/__init__.py,sha256=xL1Eh-a3xsHyIcU4foOWF-JdWYIYBALJH9b
10
10
  praisonaiagents/knowledge/chunking.py,sha256=FzoNY0q8MkvG4gADqk4JcRhmH3lcEHbRdonDgitQa30,6624
11
11
  praisonaiagents/knowledge/knowledge.py,sha256=fQNREDiwdoisfIxJBLVkteXgq_8Gbypfc3UaZbxf5QY,13210
12
12
  praisonaiagents/llm/__init__.py,sha256=ttPQQJQq6Tah-0updoEXDZFKWtJAM93rBWRoIgxRWO8,689
13
- praisonaiagents/llm/llm.py,sha256=6QMRW47fgFozibzaqxa3dwxlD756rMLCRjL3eNsw8QQ,74088
13
+ praisonaiagents/llm/llm.py,sha256=l7Z2QjD9eFy0Zq5bwTVK7VOUHxeTyx866YWt3fS3vz8,74606
14
14
  praisonaiagents/mcp/__init__.py,sha256=IkYdrAK1bDQDm_0t3Wjt63Zwv3_IJgqz84Wqz9GH2iQ,111
15
- praisonaiagents/mcp/mcp.py,sha256=7EJo2Eyw89ePQzeKUzRZgW3E2ztLkMwQj2lCjFlzecQ,12281
15
+ praisonaiagents/mcp/mcp.py,sha256=BPPf5AIPXx28PaJJqOg6T3NRyymQH9YAD-Km7Ma9-KA,13681
16
16
  praisonaiagents/memory/memory.py,sha256=I8dOTkrl1i-GgQbDcrFOsSruzJ7MiI6Ys37DK27wrUs,35537
17
17
  praisonaiagents/process/__init__.py,sha256=lkYbL7Hn5a0ldvJtkdH23vfIIZLIcanK-65C0MwaorY,52
18
18
  praisonaiagents/process/process.py,sha256=HPw84OhnKQW3EyrDkpoQu0DcpxThbrzR2hWUgwQh9Pw,59955
@@ -39,7 +39,7 @@ praisonaiagents/tools/xml_tools.py,sha256=iYTMBEk5l3L3ryQ1fkUnNVYK-Nnua2Kx2S0dxN
39
39
  praisonaiagents/tools/yaml_tools.py,sha256=uogAZrhXV9O7xvspAtcTfpKSQYL2nlOTvCQXN94-G9A,14215
40
40
  praisonaiagents/tools/yfinance_tools.py,sha256=s2PBj_1v7oQnOobo2fDbQBACEHl61ftG4beG6Z979ZE,8529
41
41
  praisonaiagents/tools/train/data/generatecot.py,sha256=H6bNh-E2hqL5MW6kX3hqZ05g9ETKN2-kudSjiuU_SD8,19403
42
- praisonaiagents-0.0.67.dist-info/METADATA,sha256=sGyO2OxLcuZGGmq-2WZHg9RIvSB1tLPFOUpEst8VeU0,830
43
- praisonaiagents-0.0.67.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
44
- praisonaiagents-0.0.67.dist-info/top_level.txt,sha256=_HsRddrJ23iDx5TTqVUVvXG2HeHBL5voshncAMDGjtA,16
45
- praisonaiagents-0.0.67.dist-info/RECORD,,
42
+ praisonaiagents-0.0.68.dist-info/METADATA,sha256=wMy9WDu6aGcQWrQIFT1UMOfB-wcvrGqpeDwXqbQXIvM,856
43
+ praisonaiagents-0.0.68.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
44
+ praisonaiagents-0.0.68.dist-info/top_level.txt,sha256=_HsRddrJ23iDx5TTqVUVvXG2HeHBL5voshncAMDGjtA,16
45
+ praisonaiagents-0.0.68.dist-info/RECORD,,