Skip to content

Commit d75c714

Browse files
committed
adding litellm tools fix
1 parent cb0fa20 commit d75c714

3 files changed

Lines changed: 148 additions & 6 deletions

File tree

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
1-
from praisonaiagents import Agent, Task, PraisonAIAgents
1+
from praisonaiagents import Agent
22
from praisonaiagents.tools import wiki_search, wiki_summary, wiki_page, wiki_random, wiki_language
33

4-
agent = Agent(
4+
agent1 = Agent(
55
instructions="You are a Wikipedia Agent",
66
tools=[wiki_search, wiki_summary, wiki_page, wiki_random, wiki_language],
77
llm="openai/gpt-4o-mini",
88
verbose=10
99
)
10-
agent.start("history of AI")
10+
agent1.start("history of AI in 1 line")
11+
12+
agent2 = Agent(
13+
instructions="You are a Wikipedia Agent",
14+
tools=[wiki_search, wiki_summary, wiki_page, wiki_random, wiki_language],
15+
llm="gpt-4o-mini",
16+
verbose=10
17+
)
18+
agent2.start("history of AI in 1 line")

src/praisonai-agents/praisonaiagents/agent/agent.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,7 @@ def chat(self, prompt, temperature=0.2, tools=None, output_json=None, output_pyd
754754
system_prompt=f"{self.backstory}\n\nYour Role: {self.role}\n\nYour Goal: {self.goal}" if self.use_system_prompt else None,
755755
chat_history=self.chat_history,
756756
temperature=temperature,
757-
tools=tools,
757+
tools=self.tools if tools is None else tools,
758758
output_json=output_json,
759759
output_pydantic=output_pydantic,
760760
verbose=self.verbose,
@@ -765,7 +765,7 @@ def chat(self, prompt, temperature=0.2, tools=None, output_json=None, output_pyd
765765
console=self.console,
766766
agent_name=self.name,
767767
agent_role=self.role,
768-
agent_tools=[t.__name__ if hasattr(t, '__name__') else str(t) for t in self.tools],
768+
agent_tools=[t.__name__ if hasattr(t, '__name__') else str(t) for t in (tools if tools is not None else self.tools)],
769769
execute_tool_fn=self.execute_tool, # Pass tool execution function
770770
reasoning_steps=reasoning_steps
771771
)

src/praisonai-agents/praisonaiagents/llm/llm.py

Lines changed: 135 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,23 @@ def get_response(
282282
# Disable litellm debug messages
283283
litellm.set_verbose = False
284284

285+
# Format tools if provided
286+
formatted_tools = None
287+
if tools:
288+
formatted_tools = []
289+
for tool in tools:
290+
if callable(tool):
291+
tool_def = self._generate_tool_definition(tool.__name__)
292+
elif isinstance(tool, str):
293+
tool_def = self._generate_tool_definition(tool)
294+
else:
295+
continue
296+
297+
if tool_def:
298+
formatted_tools.append(tool_def)
299+
if not formatted_tools:
300+
formatted_tools = None
301+
285302
# Build messages list
286303
messages = []
287304
if system_prompt:
@@ -340,6 +357,7 @@ def get_response(
340357
messages=messages,
341358
temperature=temperature,
342359
stream=False, # force non-streaming
360+
tools=formatted_tools,
343361
**{k:v for k,v in kwargs.items() if k != 'reasoning_steps'}
344362
)
345363
reasoning_content = resp["choices"][0]["message"].get("provider_specific_fields", {}).get("reasoning_content")
@@ -371,6 +389,7 @@ def get_response(
371389
for chunk in litellm.completion(
372390
model=self.model,
373391
messages=messages,
392+
tools=formatted_tools,
374393
temperature=temperature,
375394
stream=True,
376395
**kwargs
@@ -385,6 +404,7 @@ def get_response(
385404
for chunk in litellm.completion(
386405
model=self.model,
387406
messages=messages,
407+
tools=formatted_tools,
388408
temperature=temperature,
389409
stream=True,
390410
**kwargs
@@ -398,6 +418,7 @@ def get_response(
398418
final_response = litellm.completion(
399419
model=self.model,
400420
messages=messages,
421+
tools=formatted_tools,
401422
temperature=temperature,
402423
stream=False, # No streaming for tool call check
403424
**kwargs
@@ -1386,4 +1407,117 @@ async def aresponse(
13861407

13871408
except Exception as error:
13881409
display_error(f"Error in response_async: {str(error)}")
1389-
raise
1410+
raise
1411+
1412+
def _generate_tool_definition(self, function_name: str) -> Optional[Dict]:
1413+
"""Generate a tool definition from a function name."""
1414+
logging.debug(f"Attempting to generate tool definition for: {function_name}")
1415+
1416+
# First try to get the tool definition if it exists
1417+
tool_def_name = f"{function_name}_definition"
1418+
tool_def = globals().get(tool_def_name)
1419+
logging.debug(f"Looking for {tool_def_name} in globals: {tool_def is not None}")
1420+
1421+
if not tool_def:
1422+
import __main__
1423+
tool_def = getattr(__main__, tool_def_name, None)
1424+
logging.debug(f"Looking for {tool_def_name} in __main__: {tool_def is not None}")
1425+
1426+
if tool_def:
1427+
logging.debug(f"Found tool definition: {tool_def}")
1428+
return tool_def
1429+
1430+
# Try to find the function
1431+
func = globals().get(function_name)
1432+
logging.debug(f"Looking for {function_name} in globals: {func is not None}")
1433+
1434+
if not func:
1435+
import __main__
1436+
func = getattr(__main__, function_name, None)
1437+
logging.debug(f"Looking for {function_name} in __main__: {func is not None}")
1438+
1439+
if not func or not callable(func):
1440+
logging.debug(f"Function {function_name} not found or not callable")
1441+
return None
1442+
1443+
import inspect
1444+
# Handle Langchain and CrewAI tools
1445+
if inspect.isclass(func) and hasattr(func, 'run') and not hasattr(func, '_run'):
1446+
original_func = func
1447+
func = func.run
1448+
function_name = original_func.__name__
1449+
elif inspect.isclass(func) and hasattr(func, '_run'):
1450+
original_func = func
1451+
func = func._run
1452+
function_name = original_func.__name__
1453+
1454+
sig = inspect.signature(func)
1455+
logging.debug(f"Function signature: {sig}")
1456+
1457+
# Skip self, *args, **kwargs
1458+
parameters_list = []
1459+
for name, param in sig.parameters.items():
1460+
if name == "self":
1461+
continue
1462+
if param.kind in (inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD):
1463+
continue
1464+
parameters_list.append((name, param))
1465+
1466+
parameters = {
1467+
"type": "object",
1468+
"properties": {},
1469+
"required": []
1470+
}
1471+
1472+
# Parse docstring for parameter descriptions
1473+
docstring = inspect.getdoc(func)
1474+
logging.debug(f"Function docstring: {docstring}")
1475+
1476+
param_descriptions = {}
1477+
if docstring:
1478+
import re
1479+
param_section = re.split(r'\s*Args:\s*', docstring)
1480+
logging.debug(f"Param section split: {param_section}")
1481+
if len(param_section) > 1:
1482+
param_lines = param_section[1].split('\n')
1483+
for line in param_lines:
1484+
line = line.strip()
1485+
if line and ':' in line:
1486+
param_name, param_desc = line.split(':', 1)
1487+
param_descriptions[param_name.strip()] = param_desc.strip()
1488+
1489+
logging.debug(f"Parameter descriptions: {param_descriptions}")
1490+
1491+
for name, param in parameters_list:
1492+
param_type = "string" # Default type
1493+
if param.annotation != inspect.Parameter.empty:
1494+
if param.annotation == int:
1495+
param_type = "integer"
1496+
elif param.annotation == float:
1497+
param_type = "number"
1498+
elif param.annotation == bool:
1499+
param_type = "boolean"
1500+
elif param.annotation == list:
1501+
param_type = "array"
1502+
elif param.annotation == dict:
1503+
param_type = "object"
1504+
1505+
parameters["properties"][name] = {
1506+
"type": param_type,
1507+
"description": param_descriptions.get(name, "Parameter description not available")
1508+
}
1509+
1510+
if param.default == inspect.Parameter.empty:
1511+
parameters["required"].append(name)
1512+
1513+
logging.debug(f"Generated parameters: {parameters}")
1514+
tool_def = {
1515+
"type": "function",
1516+
"function": {
1517+
"name": function_name,
1518+
"description": docstring.split('\n\n')[0] if docstring else "No description available",
1519+
"parameters": parameters
1520+
}
1521+
}
1522+
logging.debug(f"Generated tool definition: {tool_def}")
1523+
return tool_def

0 commit comments

Comments
 (0)