PraisonAI 2.2.34__tar.gz → 2.2.36__tar.gz
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.
Potentially problematic release.
This version of PraisonAI might be problematic. Click here for more details.
- {praisonai-2.2.34 → praisonai-2.2.36}/PKG-INFO +2 -2
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/cli.py +48 -9
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/deploy.py +1 -1
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/agents.py +4 -2
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/chat.py +136 -23
- {praisonai-2.2.34 → praisonai-2.2.36}/pyproject.toml +4 -4
- {praisonai-2.2.34 → praisonai-2.2.36}/README.md +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/README.md +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/__init__.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/__main__.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/agents_generator.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/api/call.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/auto.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/chainlit_ui.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/inbuilt_tools/__init__.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/inbuilt_tools/autogen_tools.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/inc/__init__.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/inc/config.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/inc/models.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/public/android-chrome-192x192.png +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/public/android-chrome-512x512.png +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/public/apple-touch-icon.png +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/public/fantasy.svg +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/public/favicon-16x16.png +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/public/favicon-32x32.png +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/public/favicon.ico +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/public/game.svg +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/public/logo_dark.png +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/public/logo_light.png +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/public/movie.svg +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/public/praison-ai-agents-architecture-dark.png +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/public/praison-ai-agents-architecture.png +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/public/thriller.svg +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/scheduler.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/setup/__init__.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/setup/build.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/setup/config.yaml +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/setup/post_install.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/setup/setup_conda_env.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/setup/setup_conda_env.sh +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/setup.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/test.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/train.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/train_vision.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/README.md +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/callbacks.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/code.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/colab.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/colab_chainlit.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/components/aicoder.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/config/chainlit.md +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/config/translations/bn.json +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/config/translations/en-US.json +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/config/translations/gu.json +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/config/translations/he-IL.json +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/config/translations/hi.json +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/config/translations/kn.json +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/config/translations/ml.json +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/config/translations/mr.json +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/config/translations/ta.json +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/config/translations/te.json +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/config/translations/zh-CN.json +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/context.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/database_config.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/db.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/public/fantasy.svg +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/public/game.svg +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/public/logo_dark.png +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/public/logo_light.png +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/public/movie.svg +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/public/praison.css +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/public/thriller.svg +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/realtime.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/realtimeclient/__init__.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/realtimeclient/tools.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/sql_alchemy.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/ui/tools.md +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/upload_vision.py +0 -0
- {praisonai-2.2.34 → praisonai-2.2.36}/praisonai/version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: PraisonAI
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.36
|
|
4
4
|
Summary: PraisonAI is an AI Agents Framework with Self Reflection. PraisonAI application combines PraisonAI Agents, AutoGen, and CrewAI into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customisation, and efficient human-agent collaboration.
|
|
5
5
|
Author: Mervin Praison
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -64,7 +64,7 @@ Requires-Dist: playwright (>=1.47.0) ; extra == "code"
|
|
|
64
64
|
Requires-Dist: plotly (>=5.24.0) ; extra == "realtime"
|
|
65
65
|
Requires-Dist: praisonai-tools (>=0.0.15) ; extra == "autogen"
|
|
66
66
|
Requires-Dist: praisonai-tools (>=0.0.15) ; extra == "crewai"
|
|
67
|
-
Requires-Dist: praisonaiagents (>=0.0.
|
|
67
|
+
Requires-Dist: praisonaiagents (>=0.0.109)
|
|
68
68
|
Requires-Dist: pyautogen (>=0.2.19) ; extra == "autogen"
|
|
69
69
|
Requires-Dist: pydantic (<=2.10.1) ; extra == "chat"
|
|
70
70
|
Requires-Dist: pydantic (<=2.10.1) ; extra == "code"
|
|
@@ -170,6 +170,25 @@ class PraisonAI:
|
|
|
170
170
|
pass
|
|
171
171
|
return None
|
|
172
172
|
|
|
173
|
+
def read_file_if_provided(self, file_path):
|
|
174
|
+
"""
|
|
175
|
+
Read content from a file if the file path is provided.
|
|
176
|
+
Returns the file content or None if file cannot be read.
|
|
177
|
+
"""
|
|
178
|
+
if not file_path:
|
|
179
|
+
return None
|
|
180
|
+
|
|
181
|
+
try:
|
|
182
|
+
with open(file_path, 'r', encoding='utf-8') as f:
|
|
183
|
+
file_content = f.read().strip()
|
|
184
|
+
return file_content if file_content else None
|
|
185
|
+
except FileNotFoundError:
|
|
186
|
+
print(f"[red]ERROR: File not found: {file_path}[/red]")
|
|
187
|
+
sys.exit(1)
|
|
188
|
+
except Exception as e:
|
|
189
|
+
print(f"[red]ERROR: Failed to read file: {e}[/red]")
|
|
190
|
+
sys.exit(1)
|
|
191
|
+
|
|
173
192
|
def main(self):
|
|
174
193
|
"""
|
|
175
194
|
The main function of the PraisonAI object. It parses the command-line arguments,
|
|
@@ -189,15 +208,24 @@ class PraisonAI:
|
|
|
189
208
|
|
|
190
209
|
# Check for piped input from stdin
|
|
191
210
|
stdin_input = self.read_stdin_if_available()
|
|
211
|
+
|
|
212
|
+
# Check for file input if --file is provided
|
|
213
|
+
file_input = self.read_file_if_provided(getattr(args, 'file', None))
|
|
192
214
|
|
|
193
215
|
if args.command:
|
|
194
216
|
if args.command.startswith("tests.test") or args.command.startswith("tests/test"): # Argument used for testing purposes
|
|
195
217
|
print("test")
|
|
196
218
|
return "test"
|
|
197
219
|
else:
|
|
198
|
-
#
|
|
220
|
+
# Combine command with any available inputs (stdin and/or file)
|
|
221
|
+
combined_inputs = []
|
|
199
222
|
if stdin_input:
|
|
200
|
-
|
|
223
|
+
combined_inputs.append(stdin_input)
|
|
224
|
+
if file_input:
|
|
225
|
+
combined_inputs.append(file_input)
|
|
226
|
+
|
|
227
|
+
if combined_inputs:
|
|
228
|
+
combined_prompt = f"{args.command} {' '.join(combined_inputs)}"
|
|
201
229
|
result = self.handle_direct_prompt(combined_prompt)
|
|
202
230
|
print(result)
|
|
203
231
|
return result
|
|
@@ -206,20 +234,30 @@ class PraisonAI:
|
|
|
206
234
|
elif hasattr(args, 'direct_prompt') and args.direct_prompt:
|
|
207
235
|
# Only handle direct prompt if agent_file wasn't explicitly set in constructor
|
|
208
236
|
if original_agent_file == "agents.yaml": # Default value, so safe to use direct prompt
|
|
209
|
-
#
|
|
210
|
-
|
|
237
|
+
# Combine direct prompt with any available inputs (stdin and/or file)
|
|
238
|
+
prompt_parts = [args.direct_prompt]
|
|
211
239
|
if stdin_input:
|
|
212
|
-
|
|
240
|
+
prompt_parts.append(stdin_input)
|
|
241
|
+
if file_input:
|
|
242
|
+
prompt_parts.append(file_input)
|
|
243
|
+
prompt = ' '.join(prompt_parts)
|
|
213
244
|
result = self.handle_direct_prompt(prompt)
|
|
214
245
|
print(result)
|
|
215
246
|
return result
|
|
216
247
|
else:
|
|
217
248
|
# Agent file was explicitly set, ignore direct prompt and use the file
|
|
218
249
|
pass
|
|
219
|
-
elif stdin_input:
|
|
220
|
-
# If only stdin input is provided (no command), use it as direct prompt
|
|
221
|
-
if original_agent_file == "agents.yaml": # Default value, so safe to use
|
|
222
|
-
|
|
250
|
+
elif stdin_input or file_input:
|
|
251
|
+
# If only stdin/file input is provided (no command), use it as direct prompt
|
|
252
|
+
if original_agent_file == "agents.yaml": # Default value, so safe to use input as prompt
|
|
253
|
+
# Combine any available inputs
|
|
254
|
+
inputs = []
|
|
255
|
+
if stdin_input:
|
|
256
|
+
inputs.append(stdin_input)
|
|
257
|
+
if file_input:
|
|
258
|
+
inputs.append(file_input)
|
|
259
|
+
combined_input = ' '.join(inputs)
|
|
260
|
+
result = self.handle_direct_prompt(combined_input)
|
|
223
261
|
print(result)
|
|
224
262
|
return result
|
|
225
263
|
# If no command or direct_prompt, preserve agent_file from constructor (don't overwrite)
|
|
@@ -530,6 +568,7 @@ class PraisonAI:
|
|
|
530
568
|
parser.add_argument("--public", action="store_true", help="Use ngrok to expose the server publicly (only with --call)")
|
|
531
569
|
parser.add_argument("--merge", action="store_true", help="Merge existing agents.yaml with auto-generated agents instead of overwriting")
|
|
532
570
|
parser.add_argument("--claudecode", action="store_true", help="Enable Claude Code integration for file modifications and coding tasks")
|
|
571
|
+
parser.add_argument("--file", "-f", type=str, help="Read input from a file and append it to the prompt")
|
|
533
572
|
|
|
534
573
|
# If we're in a test environment, parse with empty args to avoid pytest interference
|
|
535
574
|
if in_test_env:
|
|
@@ -56,7 +56,7 @@ class CloudDeployer:
|
|
|
56
56
|
file.write("FROM python:3.11-slim\n")
|
|
57
57
|
file.write("WORKDIR /app\n")
|
|
58
58
|
file.write("COPY . .\n")
|
|
59
|
-
file.write("RUN pip install flask praisonai==2.2.
|
|
59
|
+
file.write("RUN pip install flask praisonai==2.2.36 gunicorn markdown\n")
|
|
60
60
|
file.write("EXPOSE 8080\n")
|
|
61
61
|
file.write('CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]\n')
|
|
62
62
|
|
|
@@ -467,10 +467,12 @@ async def ui_run_praisonai(config, topic, tools_dict):
|
|
|
467
467
|
role_tools.append(callable_func)
|
|
468
468
|
# Add API tool definition to task's tools
|
|
469
469
|
task_tools.append(tool_def)
|
|
470
|
-
# Also set the agent's tools to include both
|
|
471
|
-
agent.tools = role_tools
|
|
472
470
|
else:
|
|
473
471
|
logger.warning(f"Tool '{tool_name}' not found. Skipping.")
|
|
472
|
+
|
|
473
|
+
# Set the agent's tools after collecting all tools
|
|
474
|
+
if role_tools:
|
|
475
|
+
agent.tools = role_tools
|
|
474
476
|
|
|
475
477
|
for tname, tdetails in details.get('tasks', {}).items():
|
|
476
478
|
description_filled = tdetails['description'].format(topic=topic)
|
|
@@ -7,6 +7,8 @@ import json
|
|
|
7
7
|
import asyncio
|
|
8
8
|
import io
|
|
9
9
|
import base64
|
|
10
|
+
import importlib.util
|
|
11
|
+
import inspect
|
|
10
12
|
|
|
11
13
|
# Third-party imports
|
|
12
14
|
from dotenv import load_dotenv
|
|
@@ -59,6 +61,76 @@ def load_setting(key: str) -> str:
|
|
|
59
61
|
|
|
60
62
|
cl_data._data_layer = db_manager
|
|
61
63
|
|
|
64
|
+
def load_custom_tools():
|
|
65
|
+
"""Load custom tools from tools.py if it exists"""
|
|
66
|
+
custom_tools = {}
|
|
67
|
+
try:
|
|
68
|
+
spec = importlib.util.spec_from_file_location("tools", "tools.py")
|
|
69
|
+
if spec is None:
|
|
70
|
+
logger.debug("tools.py not found in current directory")
|
|
71
|
+
return custom_tools
|
|
72
|
+
|
|
73
|
+
module = importlib.util.module_from_spec(spec)
|
|
74
|
+
spec.loader.exec_module(module)
|
|
75
|
+
|
|
76
|
+
# Load all functions from tools.py
|
|
77
|
+
for name, obj in inspect.getmembers(module):
|
|
78
|
+
if not name.startswith('_') and callable(obj) and not inspect.isclass(obj):
|
|
79
|
+
# Store function in globals for access
|
|
80
|
+
globals()[name] = obj
|
|
81
|
+
|
|
82
|
+
# Get function signature to build parameters
|
|
83
|
+
sig = inspect.signature(obj)
|
|
84
|
+
params_properties = {}
|
|
85
|
+
required_params = []
|
|
86
|
+
|
|
87
|
+
for param_name, param in sig.parameters.items():
|
|
88
|
+
if param_name != 'self': # Skip self parameter
|
|
89
|
+
# Get type annotation if available
|
|
90
|
+
param_type = "string" # Default type
|
|
91
|
+
if param.annotation != inspect.Parameter.empty:
|
|
92
|
+
if param.annotation == int:
|
|
93
|
+
param_type = "integer"
|
|
94
|
+
elif param.annotation == float:
|
|
95
|
+
param_type = "number"
|
|
96
|
+
elif param.annotation == bool:
|
|
97
|
+
param_type = "boolean"
|
|
98
|
+
|
|
99
|
+
params_properties[param_name] = {
|
|
100
|
+
"type": param_type,
|
|
101
|
+
"description": f"Parameter {param_name}"
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
# Add to required if no default value
|
|
105
|
+
if param.default == inspect.Parameter.empty:
|
|
106
|
+
required_params.append(param_name)
|
|
107
|
+
|
|
108
|
+
# Build tool definition
|
|
109
|
+
tool_def = {
|
|
110
|
+
"type": "function",
|
|
111
|
+
"function": {
|
|
112
|
+
"name": name,
|
|
113
|
+
"description": obj.__doc__ or f"Function {name.replace('_', ' ')}",
|
|
114
|
+
"parameters": {
|
|
115
|
+
"type": "object",
|
|
116
|
+
"properties": params_properties,
|
|
117
|
+
"required": required_params
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
custom_tools[name] = tool_def
|
|
123
|
+
logger.info(f"Loaded custom tool: {name}")
|
|
124
|
+
|
|
125
|
+
logger.info(f"Loaded {len(custom_tools)} custom tools from tools.py")
|
|
126
|
+
except Exception as e:
|
|
127
|
+
logger.warning(f"Error loading custom tools: {e}")
|
|
128
|
+
|
|
129
|
+
return custom_tools
|
|
130
|
+
|
|
131
|
+
# Load custom tools
|
|
132
|
+
custom_tools_dict = load_custom_tools()
|
|
133
|
+
|
|
62
134
|
tavily_api_key = os.getenv("TAVILY_API_KEY")
|
|
63
135
|
tavily_client = TavilyClient(api_key=tavily_api_key) if tavily_api_key else None
|
|
64
136
|
|
|
@@ -72,7 +144,7 @@ async def tavily_web_search(query):
|
|
|
72
144
|
response = tavily_client.search(query)
|
|
73
145
|
logger.debug(f"Tavily search response: {response}")
|
|
74
146
|
|
|
75
|
-
async with
|
|
147
|
+
async with AsyncWebCrawler() as crawler:
|
|
76
148
|
results = []
|
|
77
149
|
for result in response.get('results', []):
|
|
78
150
|
url = result.get('url')
|
|
@@ -97,20 +169,28 @@ async def tavily_web_search(query):
|
|
|
97
169
|
"results": results
|
|
98
170
|
})
|
|
99
171
|
|
|
100
|
-
tools
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
"
|
|
172
|
+
# Build tools list with Tavily and custom tools
|
|
173
|
+
tools = []
|
|
174
|
+
|
|
175
|
+
# Add Tavily tool if API key is available
|
|
176
|
+
if tavily_api_key:
|
|
177
|
+
tools.append({
|
|
178
|
+
"type": "function",
|
|
179
|
+
"function": {
|
|
180
|
+
"name": "tavily_web_search",
|
|
181
|
+
"description": "Search the web using Tavily API and crawl the resulting URLs",
|
|
182
|
+
"parameters": {
|
|
183
|
+
"type": "object",
|
|
184
|
+
"properties": {
|
|
185
|
+
"query": {"type": "string", "description": "Search query"}
|
|
186
|
+
},
|
|
187
|
+
"required": ["query"]
|
|
188
|
+
}
|
|
111
189
|
}
|
|
112
|
-
}
|
|
113
|
-
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
# Add custom tools from tools.py
|
|
193
|
+
tools.extend(list(custom_tools_dict.values()))
|
|
114
194
|
|
|
115
195
|
# Authentication configuration
|
|
116
196
|
AUTH_PASSWORD_ENABLED = os.getenv("AUTH_PASSWORD_ENABLED", "true").lower() == "true" # Password authentication enabled by default
|
|
@@ -235,7 +315,8 @@ User Question: {message.content}
|
|
|
235
315
|
]
|
|
236
316
|
}
|
|
237
317
|
|
|
238
|
-
if
|
|
318
|
+
# Pass tools if we have any (Tavily or custom)
|
|
319
|
+
if tools:
|
|
239
320
|
completion_params["tools"] = tools
|
|
240
321
|
completion_params["tool_choice"] = "auto"
|
|
241
322
|
|
|
@@ -254,7 +335,7 @@ User Question: {message.content}
|
|
|
254
335
|
await msg.stream_token(token)
|
|
255
336
|
full_response += token
|
|
256
337
|
|
|
257
|
-
if
|
|
338
|
+
if tools and 'tool_calls' in delta and delta['tool_calls'] is not None:
|
|
258
339
|
for tool_call in delta['tool_calls']:
|
|
259
340
|
if current_tool_call is None or tool_call.index != current_tool_call['index']:
|
|
260
341
|
if current_tool_call:
|
|
@@ -284,10 +365,17 @@ User Question: {message.content}
|
|
|
284
365
|
cl.user_session.set("message_history", message_history)
|
|
285
366
|
await msg.update()
|
|
286
367
|
|
|
287
|
-
if
|
|
288
|
-
available_functions = {
|
|
289
|
-
|
|
290
|
-
|
|
368
|
+
if tool_calls and tools: # Check if we have any tools and tool calls
|
|
369
|
+
available_functions = {}
|
|
370
|
+
|
|
371
|
+
# Add Tavily function if available
|
|
372
|
+
if tavily_api_key:
|
|
373
|
+
available_functions["tavily_web_search"] = tavily_web_search
|
|
374
|
+
|
|
375
|
+
# Add all custom tool functions from globals
|
|
376
|
+
for tool_name in custom_tools_dict:
|
|
377
|
+
if tool_name in globals():
|
|
378
|
+
available_functions[tool_name] = globals()[tool_name]
|
|
291
379
|
messages = message_history + [{"role": "assistant", "content": None, "function_call": {
|
|
292
380
|
"name": tool_calls[0]['function']['name'],
|
|
293
381
|
"arguments": tool_calls[0]['function']['arguments']
|
|
@@ -301,9 +389,25 @@ User Question: {message.content}
|
|
|
301
389
|
if function_args:
|
|
302
390
|
try:
|
|
303
391
|
function_args = json.loads(function_args)
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
)
|
|
392
|
+
|
|
393
|
+
# Call function based on whether it's async or sync
|
|
394
|
+
if asyncio.iscoroutinefunction(function_to_call):
|
|
395
|
+
# For async functions like tavily_web_search
|
|
396
|
+
if function_name == "tavily_web_search":
|
|
397
|
+
function_response = await function_to_call(
|
|
398
|
+
query=function_args.get("query"),
|
|
399
|
+
)
|
|
400
|
+
else:
|
|
401
|
+
# For custom async functions, pass all arguments
|
|
402
|
+
function_response = await function_to_call(**function_args)
|
|
403
|
+
else:
|
|
404
|
+
# For sync functions (most custom tools)
|
|
405
|
+
function_response = function_to_call(**function_args)
|
|
406
|
+
|
|
407
|
+
# Convert response to string if needed
|
|
408
|
+
if not isinstance(function_response, str):
|
|
409
|
+
function_response = json.dumps(function_response)
|
|
410
|
+
|
|
307
411
|
messages.append(
|
|
308
412
|
{
|
|
309
413
|
"role": "function",
|
|
@@ -313,6 +417,15 @@ User Question: {message.content}
|
|
|
313
417
|
)
|
|
314
418
|
except json.JSONDecodeError:
|
|
315
419
|
logger.error(f"Failed to parse function arguments: {function_args}")
|
|
420
|
+
except Exception as e:
|
|
421
|
+
logger.error(f"Error calling function {function_name}: {str(e)}")
|
|
422
|
+
messages.append(
|
|
423
|
+
{
|
|
424
|
+
"role": "function",
|
|
425
|
+
"name": function_name,
|
|
426
|
+
"content": f"Error: {str(e)}",
|
|
427
|
+
}
|
|
428
|
+
)
|
|
316
429
|
|
|
317
430
|
second_response = await acompletion(
|
|
318
431
|
model=model_name,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "PraisonAI"
|
|
3
|
-
version = "2.2.
|
|
3
|
+
version = "2.2.36"
|
|
4
4
|
description = "PraisonAI is an AI Agents Framework with Self Reflection. PraisonAI application combines PraisonAI Agents, AutoGen, and CrewAI into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customisation, and efficient human-agent collaboration."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = ""
|
|
@@ -12,7 +12,7 @@ dependencies = [
|
|
|
12
12
|
"rich>=13.7",
|
|
13
13
|
"markdown>=3.5",
|
|
14
14
|
"pyparsing>=3.0.0",
|
|
15
|
-
"praisonaiagents>=0.0.
|
|
15
|
+
"praisonaiagents>=0.0.109",
|
|
16
16
|
"python-dotenv>=0.19.0",
|
|
17
17
|
"instructor>=1.3.3",
|
|
18
18
|
"PyYAML>=6.0",
|
|
@@ -95,7 +95,7 @@ autogen = ["pyautogen>=0.2.19", "praisonai-tools>=0.0.15", "crewai"]
|
|
|
95
95
|
|
|
96
96
|
[tool.poetry]
|
|
97
97
|
name = "PraisonAI"
|
|
98
|
-
version = "2.2.
|
|
98
|
+
version = "2.2.36"
|
|
99
99
|
description = "PraisonAI is an AI Agents Framework with Self Reflection. PraisonAI application combines PraisonAI Agents, AutoGen, and CrewAI into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customisation, and efficient human-agent collaboration."
|
|
100
100
|
authors = ["Mervin Praison"]
|
|
101
101
|
license = ""
|
|
@@ -113,7 +113,7 @@ python = ">=3.10,<3.13"
|
|
|
113
113
|
rich = ">=13.7"
|
|
114
114
|
markdown = ">=3.5"
|
|
115
115
|
pyparsing = ">=3.0.0"
|
|
116
|
-
praisonaiagents = ">=0.0.
|
|
116
|
+
praisonaiagents = ">=0.0.109"
|
|
117
117
|
python-dotenv = ">=0.19.0"
|
|
118
118
|
instructor = ">=1.3.3"
|
|
119
119
|
PyYAML = ">=6.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{praisonai-2.2.34 → praisonai-2.2.36}/praisonai/public/praison-ai-agents-architecture-dark.png
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|