praisonaiagents 0.0.112__py3-none-any.whl → 0.0.113__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.
- praisonaiagents/llm/llm.py +100 -124
- {praisonaiagents-0.0.112.dist-info → praisonaiagents-0.0.113.dist-info}/METADATA +1 -1
- {praisonaiagents-0.0.112.dist-info → praisonaiagents-0.0.113.dist-info}/RECORD +5 -5
- {praisonaiagents-0.0.112.dist-info → praisonaiagents-0.0.113.dist-info}/WHEEL +0 -0
- {praisonaiagents-0.0.112.dist-info → praisonaiagents-0.0.113.dist-info}/top_level.txt +0 -0
praisonaiagents/llm/llm.py
CHANGED
@@ -364,6 +364,66 @@ class LLM:
|
|
364
364
|
|
365
365
|
return messages, original_prompt
|
366
366
|
|
367
|
+
def _format_tools_for_litellm(self, tools: Optional[List[Any]]) -> Optional[List[Dict]]:
|
368
|
+
"""Format tools for LiteLLM - handles all tool formats.
|
369
|
+
|
370
|
+
Supports:
|
371
|
+
- Pre-formatted OpenAI tools (dicts with type='function')
|
372
|
+
- Lists of pre-formatted tools
|
373
|
+
- Callable functions
|
374
|
+
- String function names
|
375
|
+
|
376
|
+
Args:
|
377
|
+
tools: List of tools in various formats
|
378
|
+
|
379
|
+
Returns:
|
380
|
+
List of formatted tools or None
|
381
|
+
"""
|
382
|
+
if not tools:
|
383
|
+
return None
|
384
|
+
|
385
|
+
formatted_tools = []
|
386
|
+
for tool in tools:
|
387
|
+
# Check if the tool is already in OpenAI format (e.g. from MCP.to_openai_tool())
|
388
|
+
if isinstance(tool, dict) and 'type' in tool and tool['type'] == 'function':
|
389
|
+
# Validate nested dictionary structure before accessing
|
390
|
+
if 'function' in tool and isinstance(tool['function'], dict) and 'name' in tool['function']:
|
391
|
+
logging.debug(f"Using pre-formatted OpenAI tool: {tool['function']['name']}")
|
392
|
+
formatted_tools.append(tool)
|
393
|
+
else:
|
394
|
+
logging.debug(f"Skipping malformed OpenAI tool: missing function or name")
|
395
|
+
# Handle lists of tools (e.g. from MCP.to_openai_tool())
|
396
|
+
elif isinstance(tool, list):
|
397
|
+
for subtool in tool:
|
398
|
+
if isinstance(subtool, dict) and 'type' in subtool and subtool['type'] == 'function':
|
399
|
+
# Validate nested dictionary structure before accessing
|
400
|
+
if 'function' in subtool and isinstance(subtool['function'], dict) and 'name' in subtool['function']:
|
401
|
+
logging.debug(f"Using pre-formatted OpenAI tool from list: {subtool['function']['name']}")
|
402
|
+
formatted_tools.append(subtool)
|
403
|
+
else:
|
404
|
+
logging.debug(f"Skipping malformed OpenAI tool in list: missing function or name")
|
405
|
+
elif callable(tool):
|
406
|
+
tool_def = self._generate_tool_definition(tool)
|
407
|
+
if tool_def:
|
408
|
+
formatted_tools.append(tool_def)
|
409
|
+
elif isinstance(tool, str):
|
410
|
+
tool_def = self._generate_tool_definition(tool)
|
411
|
+
if tool_def:
|
412
|
+
formatted_tools.append(tool_def)
|
413
|
+
else:
|
414
|
+
logging.debug(f"Skipping tool of unsupported type: {type(tool)}")
|
415
|
+
|
416
|
+
# Validate JSON serialization before returning
|
417
|
+
if formatted_tools:
|
418
|
+
try:
|
419
|
+
import json
|
420
|
+
json.dumps(formatted_tools) # Validate serialization
|
421
|
+
except (TypeError, ValueError) as e:
|
422
|
+
logging.error(f"Tools are not JSON serializable: {e}")
|
423
|
+
return None
|
424
|
+
|
425
|
+
return formatted_tools if formatted_tools else None
|
426
|
+
|
367
427
|
def get_response(
|
368
428
|
self,
|
369
429
|
prompt: Union[str, List[Dict]],
|
@@ -445,33 +505,7 @@ class LLM:
|
|
445
505
|
litellm.set_verbose = False
|
446
506
|
|
447
507
|
# Format tools if provided
|
448
|
-
formatted_tools =
|
449
|
-
if tools:
|
450
|
-
formatted_tools = []
|
451
|
-
for tool in tools:
|
452
|
-
# Check if the tool is already in OpenAI format (e.g. from MCP.to_openai_tool())
|
453
|
-
if isinstance(tool, dict) and 'type' in tool and tool['type'] == 'function':
|
454
|
-
logging.debug(f"Using pre-formatted OpenAI tool: {tool['function']['name']}")
|
455
|
-
formatted_tools.append(tool)
|
456
|
-
# Handle lists of tools (e.g. from MCP.to_openai_tool())
|
457
|
-
elif isinstance(tool, list):
|
458
|
-
for subtool in tool:
|
459
|
-
if isinstance(subtool, dict) and 'type' in subtool and subtool['type'] == 'function':
|
460
|
-
logging.debug(f"Using pre-formatted OpenAI tool from list: {subtool['function']['name']}")
|
461
|
-
formatted_tools.append(subtool)
|
462
|
-
elif callable(tool):
|
463
|
-
tool_def = self._generate_tool_definition(tool.__name__)
|
464
|
-
if tool_def:
|
465
|
-
formatted_tools.append(tool_def)
|
466
|
-
elif isinstance(tool, str):
|
467
|
-
tool_def = self._generate_tool_definition(tool)
|
468
|
-
if tool_def:
|
469
|
-
formatted_tools.append(tool_def)
|
470
|
-
else:
|
471
|
-
logging.debug(f"Skipping tool of unsupported type: {type(tool)}")
|
472
|
-
|
473
|
-
if not formatted_tools:
|
474
|
-
formatted_tools = None
|
508
|
+
formatted_tools = self._format_tools_for_litellm(tools)
|
475
509
|
|
476
510
|
# Build messages list using shared helper
|
477
511
|
messages, original_prompt = self._build_messages(
|
@@ -1202,74 +1236,8 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
|
|
1202
1236
|
start_time = time.time()
|
1203
1237
|
reflection_count = 0
|
1204
1238
|
|
1205
|
-
# Format tools for LiteLLM
|
1206
|
-
formatted_tools =
|
1207
|
-
if tools:
|
1208
|
-
logging.debug(f"Starting tool formatting for {len(tools)} tools")
|
1209
|
-
formatted_tools = []
|
1210
|
-
for tool in tools:
|
1211
|
-
logging.debug(f"Processing tool: {tool.__name__ if hasattr(tool, '__name__') else str(tool)}")
|
1212
|
-
if hasattr(tool, '__name__'):
|
1213
|
-
tool_name = tool.__name__
|
1214
|
-
tool_doc = tool.__doc__ or "No description available"
|
1215
|
-
# Get function signature
|
1216
|
-
import inspect
|
1217
|
-
sig = inspect.signature(tool)
|
1218
|
-
logging.debug(f"Tool signature: {sig}")
|
1219
|
-
params = {}
|
1220
|
-
required = []
|
1221
|
-
for name, param in sig.parameters.items():
|
1222
|
-
logging.debug(f"Processing parameter: {name} with annotation: {param.annotation}")
|
1223
|
-
param_type = "string"
|
1224
|
-
if param.annotation != inspect.Parameter.empty:
|
1225
|
-
if param.annotation == int:
|
1226
|
-
param_type = "integer"
|
1227
|
-
elif param.annotation == float:
|
1228
|
-
param_type = "number"
|
1229
|
-
elif param.annotation == bool:
|
1230
|
-
param_type = "boolean"
|
1231
|
-
elif param.annotation == Dict:
|
1232
|
-
param_type = "object"
|
1233
|
-
elif param.annotation == List:
|
1234
|
-
param_type = "array"
|
1235
|
-
elif hasattr(param.annotation, "__name__"):
|
1236
|
-
param_type = param.annotation.__name__.lower()
|
1237
|
-
params[name] = {"type": param_type}
|
1238
|
-
if param.default == inspect.Parameter.empty:
|
1239
|
-
required.append(name)
|
1240
|
-
|
1241
|
-
logging.debug(f"Generated parameters: {params}")
|
1242
|
-
logging.debug(f"Required parameters: {required}")
|
1243
|
-
|
1244
|
-
tool_def = {
|
1245
|
-
"type": "function",
|
1246
|
-
"function": {
|
1247
|
-
"name": tool_name,
|
1248
|
-
"description": tool_doc,
|
1249
|
-
"parameters": {
|
1250
|
-
"type": "object",
|
1251
|
-
"properties": params,
|
1252
|
-
"required": required
|
1253
|
-
}
|
1254
|
-
}
|
1255
|
-
}
|
1256
|
-
# Ensure tool definition is JSON serializable
|
1257
|
-
try:
|
1258
|
-
json.dumps(tool_def) # Test serialization
|
1259
|
-
logging.debug(f"Generated tool definition: {tool_def}")
|
1260
|
-
formatted_tools.append(tool_def)
|
1261
|
-
except TypeError as e:
|
1262
|
-
logging.error(f"Tool definition not JSON serializable: {e}")
|
1263
|
-
continue
|
1264
|
-
|
1265
|
-
# Validate final tools list
|
1266
|
-
if formatted_tools:
|
1267
|
-
try:
|
1268
|
-
json.dumps(formatted_tools) # Final serialization check
|
1269
|
-
logging.debug(f"Final formatted tools: {json.dumps(formatted_tools, indent=2)}")
|
1270
|
-
except TypeError as e:
|
1271
|
-
logging.error(f"Final tools list not JSON serializable: {e}")
|
1272
|
-
formatted_tools = None
|
1239
|
+
# Format tools for LiteLLM using the shared helper
|
1240
|
+
formatted_tools = self._format_tools_for_litellm(tools)
|
1273
1241
|
|
1274
1242
|
response_text = ""
|
1275
1243
|
if reasoning_steps:
|
@@ -2070,36 +2038,44 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
|
|
2070
2038
|
display_error(f"Error in response_async: {str(error)}")
|
2071
2039
|
raise
|
2072
2040
|
|
2073
|
-
def _generate_tool_definition(self,
|
2074
|
-
"""Generate a tool definition from a function name."""
|
2075
|
-
|
2076
|
-
|
2077
|
-
|
2078
|
-
|
2079
|
-
|
2080
|
-
|
2081
|
-
|
2082
|
-
|
2083
|
-
|
2084
|
-
|
2085
|
-
|
2086
|
-
|
2087
|
-
|
2088
|
-
logging.debug(f"
|
2089
|
-
|
2041
|
+
def _generate_tool_definition(self, function_or_name) -> Optional[Dict]:
|
2042
|
+
"""Generate a tool definition from a function or function name."""
|
2043
|
+
if callable(function_or_name):
|
2044
|
+
# Function object passed directly
|
2045
|
+
func = function_or_name
|
2046
|
+
function_name = func.__name__
|
2047
|
+
logging.debug(f"Generating tool definition for callable: {function_name}")
|
2048
|
+
else:
|
2049
|
+
# Function name string passed
|
2050
|
+
function_name = function_or_name
|
2051
|
+
logging.debug(f"Attempting to generate tool definition for: {function_name}")
|
2052
|
+
|
2053
|
+
# First try to get the tool definition if it exists
|
2054
|
+
tool_def_name = f"{function_name}_definition"
|
2055
|
+
tool_def = globals().get(tool_def_name)
|
2056
|
+
logging.debug(f"Looking for {tool_def_name} in globals: {tool_def is not None}")
|
2057
|
+
|
2058
|
+
if not tool_def:
|
2059
|
+
import __main__
|
2060
|
+
tool_def = getattr(__main__, tool_def_name, None)
|
2061
|
+
logging.debug(f"Looking for {tool_def_name} in __main__: {tool_def is not None}")
|
2062
|
+
|
2063
|
+
if tool_def:
|
2064
|
+
logging.debug(f"Found tool definition: {tool_def}")
|
2065
|
+
return tool_def
|
2090
2066
|
|
2091
|
-
|
2092
|
-
|
2093
|
-
|
2094
|
-
|
2095
|
-
|
2096
|
-
|
2097
|
-
|
2098
|
-
|
2099
|
-
|
2100
|
-
|
2101
|
-
|
2102
|
-
|
2067
|
+
# Try to find the function
|
2068
|
+
func = globals().get(function_name)
|
2069
|
+
logging.debug(f"Looking for {function_name} in globals: {func is not None}")
|
2070
|
+
|
2071
|
+
if not func:
|
2072
|
+
import __main__
|
2073
|
+
func = getattr(__main__, function_name, None)
|
2074
|
+
logging.debug(f"Looking for {function_name} in __main__: {func is not None}")
|
2075
|
+
|
2076
|
+
if not func or not callable(func):
|
2077
|
+
logging.debug(f"Function {function_name} not found or not callable")
|
2078
|
+
return None
|
2103
2079
|
|
2104
2080
|
import inspect
|
2105
2081
|
# Handle Langchain and CrewAI tools
|
@@ -16,7 +16,7 @@ praisonaiagents/knowledge/__init__.py,sha256=xL1Eh-a3xsHyIcU4foOWF-JdWYIYBALJH9b
|
|
16
16
|
praisonaiagents/knowledge/chunking.py,sha256=G6wyHa7_8V0_7VpnrrUXbEmUmptlT16ISJYaxmkSgmU,7678
|
17
17
|
praisonaiagents/knowledge/knowledge.py,sha256=OKPar-XGyAp1ndmbOOdCgqFnTCqpOThYVSIZRxZyP58,15683
|
18
18
|
praisonaiagents/llm/__init__.py,sha256=bSywIHBHH0YUf4hSx-FmFXkRv2g1Rlhuk-gjoImE8j8,925
|
19
|
-
praisonaiagents/llm/llm.py,sha256=
|
19
|
+
praisonaiagents/llm/llm.py,sha256=z7o4tlKO0NJCqaXlnlwtPT768YjAB6tqNe_lg2KMTkk,111271
|
20
20
|
praisonaiagents/mcp/__init__.py,sha256=ibbqe3_7XB7VrIcUcetkZiUZS1fTVvyMy_AqCSFG8qc,240
|
21
21
|
praisonaiagents/mcp/mcp.py,sha256=-fFx4MHffnN2woLnnV7Pzx3-1SFkn2j8Gp5F5ZIwKJ0,19698
|
22
22
|
praisonaiagents/mcp/mcp_sse.py,sha256=z8TMFhW9xuLQ7QnpOa3n1-nSHt0-Bf27qso0u4qxYSY,8357
|
@@ -52,7 +52,7 @@ praisonaiagents/tools/xml_tools.py,sha256=iYTMBEk5l3L3ryQ1fkUnNVYK-Nnua2Kx2S0dxN
|
|
52
52
|
praisonaiagents/tools/yaml_tools.py,sha256=uogAZrhXV9O7xvspAtcTfpKSQYL2nlOTvCQXN94-G9A,14215
|
53
53
|
praisonaiagents/tools/yfinance_tools.py,sha256=s2PBj_1v7oQnOobo2fDbQBACEHl61ftG4beG6Z979ZE,8529
|
54
54
|
praisonaiagents/tools/train/data/generatecot.py,sha256=H6bNh-E2hqL5MW6kX3hqZ05g9ETKN2-kudSjiuU_SD8,19403
|
55
|
-
praisonaiagents-0.0.
|
56
|
-
praisonaiagents-0.0.
|
57
|
-
praisonaiagents-0.0.
|
58
|
-
praisonaiagents-0.0.
|
55
|
+
praisonaiagents-0.0.113.dist-info/METADATA,sha256=er3TyTx5TQPXGEtyNVBXkNnUUKo8jf7nBtv908Y7WlY,1669
|
56
|
+
praisonaiagents-0.0.113.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
57
|
+
praisonaiagents-0.0.113.dist-info/top_level.txt,sha256=_HsRddrJ23iDx5TTqVUVvXG2HeHBL5voshncAMDGjtA,16
|
58
|
+
praisonaiagents-0.0.113.dist-info/RECORD,,
|
File without changes
|
File without changes
|