PraisonAI 2.0.26__cp312-cp312-manylinux_2_39_x86_64.whl → 2.0.27__cp312-cp312-manylinux_2_39_x86_64.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.
Potentially problematic release.
This version of PraisonAI might be problematic. Click here for more details.
- praisonai/deploy.py +1 -1
- praisonai/ui/agents.py +106 -56
- praisonai/ui/tools.md +133 -0
- {praisonai-2.0.26.dist-info → praisonai-2.0.27.dist-info}/METADATA +1 -1
- {praisonai-2.0.26.dist-info → praisonai-2.0.27.dist-info}/RECORD +8 -8
- praisonai/ui/together.py +0 -775
- {praisonai-2.0.26.dist-info → praisonai-2.0.27.dist-info}/LICENSE +0 -0
- {praisonai-2.0.26.dist-info → praisonai-2.0.27.dist-info}/WHEEL +0 -0
- {praisonai-2.0.26.dist-info → praisonai-2.0.27.dist-info}/entry_points.txt +0 -0
praisonai/deploy.py
CHANGED
|
@@ -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.0.
|
|
59
|
+
file.write("RUN pip install flask praisonai==2.0.27 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
|
|
praisonai/ui/agents.py
CHANGED
|
@@ -5,6 +5,8 @@ import yaml
|
|
|
5
5
|
import logging
|
|
6
6
|
import inspect
|
|
7
7
|
import chainlit as cl
|
|
8
|
+
from praisonaiagents import Agent, Task, PraisonAIAgents, register_display_callback
|
|
9
|
+
|
|
8
10
|
framework = "praisonai"
|
|
9
11
|
config_list = [
|
|
10
12
|
{
|
|
@@ -14,12 +16,19 @@ config_list = [
|
|
|
14
16
|
}
|
|
15
17
|
]
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
actions=[
|
|
19
|
+
actions = [
|
|
20
20
|
cl.Action(name="run", value="run", label="✅ Run"),
|
|
21
21
|
cl.Action(name="modify", value="modify", label="🔧 Modify"),
|
|
22
22
|
]
|
|
23
|
+
|
|
24
|
+
@cl.action_callback("run")
|
|
25
|
+
async def on_run(action):
|
|
26
|
+
await main(cl.Message(content=""))
|
|
27
|
+
|
|
28
|
+
@cl.action_callback("modify")
|
|
29
|
+
async def on_modify(action):
|
|
30
|
+
await cl.Message(content="Modify the agents and tools from below settings").send()
|
|
31
|
+
|
|
23
32
|
import os
|
|
24
33
|
import sys
|
|
25
34
|
import yaml
|
|
@@ -37,9 +46,6 @@ import chainlit as cl
|
|
|
37
46
|
from chainlit.types import ThreadDict
|
|
38
47
|
import chainlit.data as cl_data
|
|
39
48
|
|
|
40
|
-
# External imports from your local packages (adjust if needed)
|
|
41
|
-
from praisonaiagents import Agent, Task, PraisonAIAgents
|
|
42
|
-
|
|
43
49
|
# -----------------------------------------------------------------------------
|
|
44
50
|
# Global Setup
|
|
45
51
|
# -----------------------------------------------------------------------------
|
|
@@ -53,14 +59,12 @@ message_queue = Queue() # Queue to handle messages sent to Chainlit UI
|
|
|
53
59
|
agent_file = "agents.yaml"
|
|
54
60
|
|
|
55
61
|
# -----------------------------------------------------------------------------
|
|
56
|
-
# Database and Settings Logic
|
|
62
|
+
# Database and Settings Logic
|
|
57
63
|
# -----------------------------------------------------------------------------
|
|
58
64
|
|
|
59
65
|
MAX_RETRIES = 3
|
|
60
66
|
RETRY_DELAY = 1 # seconds
|
|
61
67
|
|
|
62
|
-
# Original DatabaseManager from chainlit_ui.py, unmodified logic, plus minimal
|
|
63
|
-
# placeholder methods for Chainlit's data layer calls (create_user, get_user, etc.)
|
|
64
68
|
from db import DatabaseManager
|
|
65
69
|
|
|
66
70
|
async def init_database_with_retry():
|
|
@@ -118,7 +122,7 @@ async def update_thread_metadata(thread_id: str, metadata: dict):
|
|
|
118
122
|
raise
|
|
119
123
|
|
|
120
124
|
# -----------------------------------------------------------------------------
|
|
121
|
-
# Callback Manager
|
|
125
|
+
# Callback Manager
|
|
122
126
|
# -----------------------------------------------------------------------------
|
|
123
127
|
|
|
124
128
|
class CallbackManager:
|
|
@@ -161,7 +165,50 @@ def callback(name: str, is_async: bool = False):
|
|
|
161
165
|
return decorator
|
|
162
166
|
|
|
163
167
|
# -----------------------------------------------------------------------------
|
|
164
|
-
#
|
|
168
|
+
# ADDITIONAL CALLBACKS
|
|
169
|
+
# -----------------------------------------------------------------------------
|
|
170
|
+
def interaction_callback(message=None, response=None, **kwargs):
|
|
171
|
+
logger.debug(f"[CALLBACK: interaction] Message: {message} | Response: {response}")
|
|
172
|
+
message_queue.put({
|
|
173
|
+
"content": f"[CALLBACK: interaction] Message: {message} | Response: {response}",
|
|
174
|
+
"author": "Callback"
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
def error_callback(message=None, **kwargs):
|
|
178
|
+
logger.error(f"[CALLBACK: error] Message: {message}")
|
|
179
|
+
message_queue.put({
|
|
180
|
+
"content": f"[CALLBACK: error] Message: {message}",
|
|
181
|
+
"author": "Callback"
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
def tool_call_callback(message=None, **kwargs):
|
|
185
|
+
logger.debug(f"[CALLBACK: tool_call] Tool used: {message}")
|
|
186
|
+
message_queue.put({
|
|
187
|
+
"content": f"[CALLBACK: tool_call] Tool used: {message}",
|
|
188
|
+
"author": "Callback"
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
def instruction_callback(message=None, **kwargs):
|
|
192
|
+
logger.debug(f"[CALLBACK: instruction] Instruction: {message}")
|
|
193
|
+
message_queue.put({
|
|
194
|
+
"content": f"[CALLBACK: instruction] Instruction: {message}",
|
|
195
|
+
"author": "Callback"
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
def self_reflection_callback(message=None, **kwargs):
|
|
199
|
+
logger.debug(f"[CALLBACK: self_reflection] Reflection: {message}")
|
|
200
|
+
message_queue.put({
|
|
201
|
+
"content": f"[CALLBACK: self_reflection] Reflection: {message}",
|
|
202
|
+
"author": "Callback"
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
register_display_callback('error', error_callback)
|
|
206
|
+
register_display_callback('tool_call', tool_call_callback)
|
|
207
|
+
register_display_callback('instruction', instruction_callback)
|
|
208
|
+
register_display_callback('self_reflection', self_reflection_callback)
|
|
209
|
+
|
|
210
|
+
# -----------------------------------------------------------------------------
|
|
211
|
+
# Tools Loader
|
|
165
212
|
# -----------------------------------------------------------------------------
|
|
166
213
|
|
|
167
214
|
def load_tools_from_tools_py():
|
|
@@ -182,7 +229,10 @@ def load_tools_from_tools_py():
|
|
|
182
229
|
|
|
183
230
|
for name, obj in inspect.getmembers(module):
|
|
184
231
|
if not name.startswith('_') and callable(obj) and not inspect.isclass(obj):
|
|
232
|
+
# Store the function in globals
|
|
185
233
|
globals()[name] = obj
|
|
234
|
+
|
|
235
|
+
# Build the function definition
|
|
186
236
|
tool_def = {
|
|
187
237
|
"type": "function",
|
|
188
238
|
"function": {
|
|
@@ -190,16 +240,14 @@ def load_tools_from_tools_py():
|
|
|
190
240
|
"description": obj.__doc__ or f"Function to {name.replace('_', ' ')}",
|
|
191
241
|
"parameters": {
|
|
192
242
|
"type": "object",
|
|
193
|
-
"properties": {
|
|
194
|
-
|
|
195
|
-
"type": "string",
|
|
196
|
-
"description": "The search query to look up information about"
|
|
197
|
-
}
|
|
198
|
-
},
|
|
199
|
-
"required": ["query"]
|
|
243
|
+
"properties": {},
|
|
244
|
+
"required": []
|
|
200
245
|
}
|
|
201
|
-
}
|
|
246
|
+
},
|
|
247
|
+
# Keep the actual callable as well
|
|
248
|
+
"callable": obj,
|
|
202
249
|
}
|
|
250
|
+
|
|
203
251
|
tools_dict[name] = tool_def
|
|
204
252
|
logger.info(f"Loaded and globalized tool function: {name}")
|
|
205
253
|
|
|
@@ -209,7 +257,7 @@ def load_tools_from_tools_py():
|
|
|
209
257
|
return tools_dict
|
|
210
258
|
|
|
211
259
|
# -----------------------------------------------------------------------------
|
|
212
|
-
# Async Queue Processor
|
|
260
|
+
# Async Queue Processor
|
|
213
261
|
# -----------------------------------------------------------------------------
|
|
214
262
|
|
|
215
263
|
async def process_message_queue():
|
|
@@ -223,7 +271,7 @@ async def process_message_queue():
|
|
|
223
271
|
logger.error(f"Error processing message queue: {e}")
|
|
224
272
|
|
|
225
273
|
# -----------------------------------------------------------------------------
|
|
226
|
-
# Step & Task Callbacks
|
|
274
|
+
# Step & Task Callbacks
|
|
227
275
|
# -----------------------------------------------------------------------------
|
|
228
276
|
|
|
229
277
|
async def step_callback(step_details):
|
|
@@ -351,9 +399,8 @@ def sync_step_callback_wrapper(step_details):
|
|
|
351
399
|
logger.error(f"Error in sync_step_callback_wrapper: {e}", exc_info=True)
|
|
352
400
|
|
|
353
401
|
# -----------------------------------------------------------------------------
|
|
354
|
-
# Main PraisonAI Runner
|
|
402
|
+
# Main PraisonAI Runner
|
|
355
403
|
# -----------------------------------------------------------------------------
|
|
356
|
-
|
|
357
404
|
async def ui_run_praisonai(config, topic, tools_dict):
|
|
358
405
|
logger.info("Starting ui_run_praisonai")
|
|
359
406
|
agents_map = {}
|
|
@@ -370,8 +417,6 @@ async def ui_run_praisonai(config, topic, tools_dict):
|
|
|
370
417
|
goal_filled = details['goal'].format(topic=topic)
|
|
371
418
|
backstory_filled = details['backstory'].format(topic=topic)
|
|
372
419
|
|
|
373
|
-
await cl.Message(content=f"[DEBUG] Creating agent: {role_name}", author="System").send()
|
|
374
|
-
|
|
375
420
|
def step_callback_sync(step_details):
|
|
376
421
|
step_details["agent_name"] = role_name
|
|
377
422
|
try:
|
|
@@ -394,7 +439,8 @@ async def ui_run_praisonai(config, topic, tools_dict):
|
|
|
394
439
|
max_rpm=details.get('max_rpm'),
|
|
395
440
|
max_execution_time=details.get('max_execution_time'),
|
|
396
441
|
cache=details.get('cache', True),
|
|
397
|
-
step_callback=step_callback_sync
|
|
442
|
+
step_callback=step_callback_sync,
|
|
443
|
+
self_reflect=details.get('self_reflect', False)
|
|
398
444
|
)
|
|
399
445
|
agents_map[role] = agent
|
|
400
446
|
|
|
@@ -402,17 +448,35 @@ async def ui_run_praisonai(config, topic, tools_dict):
|
|
|
402
448
|
for role, details in config['roles'].items():
|
|
403
449
|
agent = agents_map[role]
|
|
404
450
|
role_name = agent.name
|
|
451
|
+
|
|
452
|
+
# -------------------------------------------------------------
|
|
453
|
+
# FIX: Skip empty or invalid tool names to avoid null tool objects
|
|
454
|
+
# -------------------------------------------------------------
|
|
405
455
|
role_tools = []
|
|
456
|
+
task_tools = [] # Initialize task_tools outside the loop
|
|
457
|
+
|
|
406
458
|
for tool_name in details.get('tools', []):
|
|
459
|
+
if not tool_name or not tool_name.strip():
|
|
460
|
+
logger.warning("Skipping empty tool name.")
|
|
461
|
+
continue
|
|
407
462
|
if tool_name in tools_dict:
|
|
408
|
-
|
|
463
|
+
# Create a copy of the tool definition
|
|
464
|
+
tool_def = tools_dict[tool_name].copy()
|
|
465
|
+
# Store the callable separately and remove from definition
|
|
466
|
+
callable_func = tool_def.pop("callable")
|
|
467
|
+
# Add callable to role_tools for task execution
|
|
468
|
+
role_tools.append(callable_func)
|
|
469
|
+
# Add API tool definition to task's tools
|
|
470
|
+
task_tools.append(tool_def)
|
|
471
|
+
# Also set the agent's tools to include both
|
|
472
|
+
agent.tools = role_tools
|
|
473
|
+
else:
|
|
474
|
+
logger.warning(f"Tool '{tool_name}' not found. Skipping.")
|
|
409
475
|
|
|
410
476
|
for tname, tdetails in details.get('tasks', {}).items():
|
|
411
477
|
description_filled = tdetails['description'].format(topic=topic)
|
|
412
478
|
expected_output_filled = tdetails['expected_output'].format(topic=topic)
|
|
413
479
|
|
|
414
|
-
await cl.Message(content=f"[DEBUG] Created task: {tname} for {role_name}", author="System").send()
|
|
415
|
-
|
|
416
480
|
def task_callback_sync(task_output):
|
|
417
481
|
try:
|
|
418
482
|
loop_ = asyncio.new_event_loop()
|
|
@@ -426,7 +490,7 @@ async def ui_run_praisonai(config, topic, tools_dict):
|
|
|
426
490
|
description=description_filled,
|
|
427
491
|
expected_output=expected_output_filled,
|
|
428
492
|
agent=agent,
|
|
429
|
-
tools=
|
|
493
|
+
tools=task_tools, # Pass API tool definitions
|
|
430
494
|
async_execution=True,
|
|
431
495
|
context=[],
|
|
432
496
|
config=tdetails.get('config', {}),
|
|
@@ -454,6 +518,7 @@ async def ui_run_praisonai(config, topic, tools_dict):
|
|
|
454
518
|
|
|
455
519
|
await cl.Message(content="Starting PraisonAI agents execution...", author="System").send()
|
|
456
520
|
|
|
521
|
+
# Decide how to process tasks
|
|
457
522
|
if config.get('process') == 'hierarchical':
|
|
458
523
|
prai_agents = PraisonAIAgents(
|
|
459
524
|
agents=list(agents_map.values()),
|
|
@@ -493,10 +558,11 @@ async def ui_run_praisonai(config, topic, tools_dict):
|
|
|
493
558
|
raise
|
|
494
559
|
|
|
495
560
|
# -----------------------------------------------------------------------------
|
|
496
|
-
# Chainlit Handlers + logic
|
|
561
|
+
# Chainlit Handlers + logic
|
|
497
562
|
# -----------------------------------------------------------------------------
|
|
498
563
|
|
|
499
564
|
tools_dict = load_tools_from_tools_py()
|
|
565
|
+
print(f"[DEBUG] tools_dict: {tools_dict}")
|
|
500
566
|
|
|
501
567
|
# Load agent config (default) from 'agents.yaml'
|
|
502
568
|
with open(agent_file, 'r') as f:
|
|
@@ -520,9 +586,6 @@ if AUTH_PASSWORD_ENABLED:
|
|
|
520
586
|
|
|
521
587
|
@cl.set_chat_profiles
|
|
522
588
|
async def set_profiles(current_user: cl.User):
|
|
523
|
-
"""
|
|
524
|
-
Keep all the same starter logic from chainlit_ui.py.
|
|
525
|
-
"""
|
|
526
589
|
return [
|
|
527
590
|
cl.ChatProfile(
|
|
528
591
|
name="Auto",
|
|
@@ -577,7 +640,6 @@ async def set_profiles(current_user: cl.User):
|
|
|
577
640
|
@cl.on_chat_start
|
|
578
641
|
async def start_chat():
|
|
579
642
|
try:
|
|
580
|
-
# Load model name from database
|
|
581
643
|
model_name = load_setting("model_name") or os.getenv("MODEL_NAME", "gpt-4o-mini")
|
|
582
644
|
cl.user_session.set("model_name", model_name)
|
|
583
645
|
logger.debug(f"Model name: {model_name}")
|
|
@@ -587,16 +649,19 @@ async def start_chat():
|
|
|
587
649
|
[{"role": "system", "content": "You are a helpful assistant."}],
|
|
588
650
|
)
|
|
589
651
|
|
|
590
|
-
# Create tools.py if it doesn't exist
|
|
591
652
|
if not os.path.exists("tools.py"):
|
|
592
653
|
with open("tools.py", "w") as f:
|
|
593
654
|
f.write("# Add your custom tools here\n")
|
|
594
655
|
|
|
656
|
+
if not os.path.exists("agents.yaml"):
|
|
657
|
+
with open("agents.yaml", "w") as f:
|
|
658
|
+
f.write("# Add your custom agents here\n")
|
|
659
|
+
|
|
595
660
|
settings = await cl.ChatSettings(
|
|
596
661
|
[
|
|
597
662
|
TextInput(id="Model", label="OpenAI - Model", initial=model_name),
|
|
598
663
|
TextInput(id="BaseUrl", label="OpenAI - Base URL", initial=config_list[0]['base_url']),
|
|
599
|
-
TextInput(id="ApiKey", label="OpenAI - API Key", initial=config_list[0]['api_key']),
|
|
664
|
+
TextInput(id="ApiKey", label="OpenAI - API Key", initial=config_list[0]['api_key']),
|
|
600
665
|
Select(
|
|
601
666
|
id="Framework",
|
|
602
667
|
label="Framework",
|
|
@@ -608,7 +673,7 @@ async def start_chat():
|
|
|
608
673
|
cl.user_session.set("settings", settings)
|
|
609
674
|
chat_profile = cl.user_session.get("chat_profile")
|
|
610
675
|
|
|
611
|
-
if chat_profile=="Manual":
|
|
676
|
+
if chat_profile == "Manual":
|
|
612
677
|
agent_file = "agents.yaml"
|
|
613
678
|
full_agent_file_path = os.path.abspath(agent_file)
|
|
614
679
|
if os.path.exists(full_agent_file_path):
|
|
@@ -628,7 +693,7 @@ async def start_chat():
|
|
|
628
693
|
[
|
|
629
694
|
TextInput(id="Model", label="OpenAI - Model", initial=model_name),
|
|
630
695
|
TextInput(id="BaseUrl", label="OpenAI - Base URL", initial=config_list[0]['base_url']),
|
|
631
|
-
TextInput(id="ApiKey", label="OpenAI - API Key", initial=config_list[0]['api_key']),
|
|
696
|
+
TextInput(id="ApiKey", label="OpenAI - API Key", initial=config_list[0]['api_key']),
|
|
632
697
|
Select(
|
|
633
698
|
id="Framework",
|
|
634
699
|
label="Framework",
|
|
@@ -655,13 +720,8 @@ async def start_chat():
|
|
|
655
720
|
logger.error(f"Error in start_chat: {str(e)}")
|
|
656
721
|
await cl.Message(content=f"An error occurred while starting the chat: {str(e)}").send()
|
|
657
722
|
|
|
658
|
-
|
|
659
723
|
@cl.on_chat_resume
|
|
660
724
|
async def on_chat_resume(thread: ThreadDict):
|
|
661
|
-
"""
|
|
662
|
-
Logic from chainlit_ui.py for chat resume:
|
|
663
|
-
- Restore message history from thread steps
|
|
664
|
-
"""
|
|
665
725
|
try:
|
|
666
726
|
message_history = cl.user_session.get("message_history", [])
|
|
667
727
|
root_messages = [m for m in thread["steps"] if m["parentId"] is None]
|
|
@@ -676,11 +736,6 @@ async def on_chat_resume(thread: ThreadDict):
|
|
|
676
736
|
|
|
677
737
|
@cl.on_message
|
|
678
738
|
async def main(message: cl.Message):
|
|
679
|
-
"""
|
|
680
|
-
Merged logic from colab_combined.py and chainlit_ui.py for main message:
|
|
681
|
-
- Use existing ui_run_praisonai to process user message with PraisonAI
|
|
682
|
-
- Keep message history, no changes to logic
|
|
683
|
-
"""
|
|
684
739
|
try:
|
|
685
740
|
logger.info(f"User message: {message.content}")
|
|
686
741
|
await cl.Message(
|
|
@@ -691,7 +746,6 @@ async def main(message: cl.Message):
|
|
|
691
746
|
# Run PraisonAI
|
|
692
747
|
result = await ui_run_praisonai(config, message.content, tools_dict)
|
|
693
748
|
|
|
694
|
-
# Update message history
|
|
695
749
|
message_history = cl.user_session.get("message_history", [])
|
|
696
750
|
message_history.append({"role": "user", "content": message.content})
|
|
697
751
|
message_history.append({"role": "assistant", "content": str(result)})
|
|
@@ -704,14 +758,12 @@ async def main(message: cl.Message):
|
|
|
704
758
|
|
|
705
759
|
@cl.on_settings_update
|
|
706
760
|
async def on_settings_update(settings):
|
|
707
|
-
"""Handle updates to the ChatSettings form."""
|
|
708
761
|
try:
|
|
709
762
|
global config_list, framework
|
|
710
763
|
config_list[0]['model'] = settings["Model"]
|
|
711
764
|
config_list[0]['base_url'] = settings["BaseUrl"]
|
|
712
765
|
config_list[0]['api_key'] = settings["ApiKey"]
|
|
713
766
|
|
|
714
|
-
# Save settings to database with retry
|
|
715
767
|
for attempt in range(MAX_RETRIES):
|
|
716
768
|
try:
|
|
717
769
|
await save_setting_with_retry("model_name", config_list[0]['model'])
|
|
@@ -724,7 +776,6 @@ async def on_settings_update(settings):
|
|
|
724
776
|
continue
|
|
725
777
|
raise
|
|
726
778
|
|
|
727
|
-
# Save to environment variables for compatibility
|
|
728
779
|
os.environ["OPENAI_API_KEY"] = config_list[0]['api_key']
|
|
729
780
|
os.environ["OPENAI_MODEL_NAME"] = config_list[0]['model']
|
|
730
781
|
os.environ["OPENAI_API_BASE"] = config_list[0]['base_url']
|
|
@@ -739,7 +790,6 @@ async def on_settings_update(settings):
|
|
|
739
790
|
with open("tools.py", "w") as f:
|
|
740
791
|
f.write(settings["tools"])
|
|
741
792
|
|
|
742
|
-
# Update thread metadata if exists with retry
|
|
743
793
|
thread_id = cl.user_session.get("thread_id")
|
|
744
794
|
if thread_id:
|
|
745
795
|
for attempt in range(MAX_RETRIES):
|
|
@@ -749,6 +799,7 @@ async def on_settings_update(settings):
|
|
|
749
799
|
metadata = thread.get("metadata", {})
|
|
750
800
|
if isinstance(metadata, str):
|
|
751
801
|
try:
|
|
802
|
+
import json
|
|
752
803
|
metadata = json.loads(metadata)
|
|
753
804
|
except json.JSONDecodeError:
|
|
754
805
|
metadata = {}
|
|
@@ -766,10 +817,9 @@ async def on_settings_update(settings):
|
|
|
766
817
|
except Exception as e:
|
|
767
818
|
logger.error(f"Error updating settings: {str(e)}")
|
|
768
819
|
await cl.Message(content=f"An error occurred while updating settings: {str(e)}. Retrying...").send()
|
|
769
|
-
# One final retry after a longer delay
|
|
770
820
|
try:
|
|
771
821
|
await asyncio.sleep(RETRY_DELAY * 2)
|
|
772
822
|
await on_settings_update(settings)
|
|
773
823
|
except Exception as e:
|
|
774
824
|
logger.error(f"Final retry failed: {str(e)}")
|
|
775
|
-
await cl.Message(content=f"Failed to update settings after retries: {str(e)}").send()
|
|
825
|
+
await cl.Message(content=f"Failed to update settings after retries: {str(e)}").send()
|
praisonai/ui/tools.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Understanding Tool Integration in AI Agents - A Beginner's Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
This guide explains how to properly integrate tools (functions) that an AI agent can use, making them both understandable to the OpenAI API and executable by your code.
|
|
5
|
+
|
|
6
|
+
## Key Components
|
|
7
|
+
|
|
8
|
+
### 1. Tool Definition Structure
|
|
9
|
+
```python
|
|
10
|
+
# Example tool definition in tools.py
|
|
11
|
+
def search_tool(query: str) -> list:
|
|
12
|
+
"""
|
|
13
|
+
Perform a web search using DuckDuckGo.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
query (str): The search query string.
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
list: Search results with title, url, and snippet.
|
|
20
|
+
"""
|
|
21
|
+
# Function implementation...
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### 2. Tool Dictionary Format
|
|
25
|
+
```python
|
|
26
|
+
tools_dict = {
|
|
27
|
+
'search_tool': {
|
|
28
|
+
'type': 'function',
|
|
29
|
+
'function': {
|
|
30
|
+
'name': 'search_tool',
|
|
31
|
+
'description': '...',
|
|
32
|
+
'parameters': {
|
|
33
|
+
'type': 'object',
|
|
34
|
+
'properties': {
|
|
35
|
+
'query': {'type': 'string'}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
'callable': search_tool # The actual Python function
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## The Two-Part System
|
|
45
|
+
|
|
46
|
+
### Part 1: OpenAI API Communication
|
|
47
|
+
```python
|
|
48
|
+
# task_tools: What OpenAI understands
|
|
49
|
+
task_tools = []
|
|
50
|
+
tool_def = tools_dict[tool_name].copy()
|
|
51
|
+
callable_func = tool_def.pop("callable") # Remove the Python function
|
|
52
|
+
task_tools.append(tool_def) # Add clean JSON-serializable definition
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Part 2: Function Execution
|
|
56
|
+
```python
|
|
57
|
+
# role_tools: What your code executes
|
|
58
|
+
role_tools = []
|
|
59
|
+
role_tools.append(callable_func) # Store the actual function
|
|
60
|
+
agent.tools = role_tools # Give agent access to executable functions
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Putting It All Together
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
# Initialize empty lists
|
|
67
|
+
role_tools = [] # For executable functions
|
|
68
|
+
task_tools = [] # For OpenAI API definitions
|
|
69
|
+
|
|
70
|
+
# Process each tool
|
|
71
|
+
for tool_name in tools_list:
|
|
72
|
+
if tool_name in tools_dict:
|
|
73
|
+
# 1. Get the tool definition
|
|
74
|
+
tool_def = tools_dict[tool_name].copy()
|
|
75
|
+
|
|
76
|
+
# 2. Separate the callable function
|
|
77
|
+
callable_func = tool_def.pop("callable")
|
|
78
|
+
|
|
79
|
+
# 3. Store the function for execution
|
|
80
|
+
role_tools.append(callable_func)
|
|
81
|
+
|
|
82
|
+
# 4. Store the API definition
|
|
83
|
+
task_tools.append(tool_def)
|
|
84
|
+
|
|
85
|
+
# 5. Give agent access to functions
|
|
86
|
+
agent.tools = role_tools
|
|
87
|
+
|
|
88
|
+
# Create task with API definitions
|
|
89
|
+
task = Task(
|
|
90
|
+
description="...",
|
|
91
|
+
tools=task_tools, # OpenAI API will use these
|
|
92
|
+
agent=agent, # Agent has access to callable functions
|
|
93
|
+
# ... other parameters ...
|
|
94
|
+
)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Why This Works
|
|
98
|
+
|
|
99
|
+
1. **API Communication**
|
|
100
|
+
- OpenAI API receives clean JSON tool definitions
|
|
101
|
+
- No Python functions that would cause serialization errors
|
|
102
|
+
|
|
103
|
+
2. **Function Execution**
|
|
104
|
+
- Agent has access to actual Python functions
|
|
105
|
+
- Can execute tools when OpenAI decides to use them
|
|
106
|
+
|
|
107
|
+
3. **Separation of Concerns**
|
|
108
|
+
- `task_tools`: Describes what tools can do (for OpenAI)
|
|
109
|
+
- `role_tools`: Actually does the work (for Python)
|
|
110
|
+
|
|
111
|
+
## Common Errors and Solutions
|
|
112
|
+
|
|
113
|
+
1. **"Invalid type for 'tools[0]'"**
|
|
114
|
+
- Cause: Sending null or invalid tool definition to OpenAI
|
|
115
|
+
- Solution: Use proper tool definition format in `task_tools`
|
|
116
|
+
|
|
117
|
+
2. **"Object of type function is not JSON serializable"**
|
|
118
|
+
- Cause: Trying to send Python function to OpenAI API
|
|
119
|
+
- Solution: Remove callable function from API definition
|
|
120
|
+
|
|
121
|
+
3. **"Tool is not callable"**
|
|
122
|
+
- Cause: Agent doesn't have access to executable functions
|
|
123
|
+
- Solution: Set `agent.tools = role_tools`
|
|
124
|
+
|
|
125
|
+
## Best Practices
|
|
126
|
+
|
|
127
|
+
1. Always initialize both `task_tools` and `role_tools` lists
|
|
128
|
+
2. Make clean copies of tool definitions to avoid modifying originals
|
|
129
|
+
3. Keep tool definitions JSON-serializable for API communication
|
|
130
|
+
4. Ensure agents have access to callable functions
|
|
131
|
+
5. Document tool parameters and return values clearly
|
|
132
|
+
|
|
133
|
+
This structure maintains clean separation between API communication and actual function execution, making your AI agent system both reliable and maintainable.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: PraisonAI
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.27
|
|
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,<3.13
|
|
@@ -5,7 +5,7 @@ praisonai/api/call.py,sha256=iHdAlgIH_oTsEbjaGGu1Jjo6DTfMR-SfFdtSxnOLCeY,11032
|
|
|
5
5
|
praisonai/auto.py,sha256=uLDm8CU3L_3amZsd55yzf9RdBF1uW-BGSx7nl9ctNZ4,8680
|
|
6
6
|
praisonai/chainlit_ui.py,sha256=bNR7s509lp0I9JlJNvwCZRUZosC64qdvlFCt8NmFamQ,12216
|
|
7
7
|
praisonai/cli.py,sha256=M69ji9gQGzWVLewNhTwH5kYZuj63TzlcishxoRx18ug,21210
|
|
8
|
-
praisonai/deploy.py,sha256=
|
|
8
|
+
praisonai/deploy.py,sha256=31iwBcknlJLz0UcywPaGJZp4FkW1w6qcAAJOwY5KP9c,6028
|
|
9
9
|
praisonai/inbuilt_tools/__init__.py,sha256=fai4ZJIKz7-iOnGZv5jJX0wmT77PKa4x2jqyaJddKFA,569
|
|
10
10
|
praisonai/inbuilt_tools/autogen_tools.py,sha256=kJdEv61BTYvdHOaURNEpBcWq8Rs-oC03loNFTIjT-ak,4687
|
|
11
11
|
praisonai/inc/__init__.py,sha256=sPDlYBBwdk0VlWzaaM_lG0_LD07lS2HRGvPdxXJFiYg,62
|
|
@@ -35,7 +35,7 @@ praisonai/setup.py,sha256=0jHgKnIPCtBZiGYaYyTz3PzrJI6nBy55VXk2UctXlDo,373
|
|
|
35
35
|
praisonai/test.py,sha256=OL-wesjA5JTohr8rtr6kWoaS4ImkJg2l0GXJ-dUUfRU,4090
|
|
36
36
|
praisonai/train.py,sha256=DvORlrwKOD-2v4r_z84eV3LsfzpNs-WnPKb5cQB3_t4,11071
|
|
37
37
|
praisonai/ui/README.md,sha256=QG9yucvBieVjCjWFzu6hL9xNtYllkoqyJ_q1b0YYAco,1124
|
|
38
|
-
praisonai/ui/agents.py,sha256=
|
|
38
|
+
praisonai/ui/agents.py,sha256=bLzer5ivtwr1iol60Sb77Zu36mBrEkeYKy0UYjYdwiU,32841
|
|
39
39
|
praisonai/ui/callbacks.py,sha256=V4_-GjxmjDFmugUZGfQHKtNSysx7rT6i1UblbM_8lIM,1968
|
|
40
40
|
praisonai/ui/chat.py,sha256=rlYwhTd3giBuvtK4Yc9kf6N9jfVT0VrZ-mLIzhANGiQ,13565
|
|
41
41
|
praisonai/ui/code.py,sha256=GD_xQTo7qzpOM98tu4MOPsviJdXU__Ta3JIfsjoRe6U,15797
|
|
@@ -80,10 +80,10 @@ praisonai/ui/realtimeclient/__init__.py,sha256=zA2xa7rBUSw77wFkndJMQNNPqdH6ywQ3u
|
|
|
80
80
|
praisonai/ui/realtimeclient/realtimedocs.txt,sha256=hmgd8Uwy2SkjSndyyF_-ZOaNxiyHwGaQLGc67DvV-sI,26395
|
|
81
81
|
praisonai/ui/realtimeclient/tools.py,sha256=IJOYwVOBW5Ocn5_iV9pFkmSKR3WU3YpX3kwF0I3jikQ,7855
|
|
82
82
|
praisonai/ui/sql_alchemy.py,sha256=cfyL9uFfuizKFvW0aZfUBlJWPQYI-YBi1v4vxlkb1BQ,29615
|
|
83
|
-
praisonai/ui/
|
|
83
|
+
praisonai/ui/tools.md,sha256=Ad3YH_ZCLMWlz3mDXllQnQ_S5l55LWqLdcZSh-EXrHI,3956
|
|
84
84
|
praisonai/version.py,sha256=ugyuFliEqtAwQmH4sTlc16YXKYbFWDmfyk87fErB8-8,21
|
|
85
|
-
praisonai-2.0.
|
|
86
|
-
praisonai-2.0.
|
|
87
|
-
praisonai-2.0.
|
|
88
|
-
praisonai-2.0.
|
|
89
|
-
praisonai-2.0.
|
|
85
|
+
praisonai-2.0.27.dist-info/LICENSE,sha256=kqvFysVlnFxYOu0HxCe2HlmZmJtdmNGOxWRRkT9TsWc,1035
|
|
86
|
+
praisonai-2.0.27.dist-info/METADATA,sha256=KBht1TLRK5J3jCtte9Qd8zC6UWb9Cgs2WYo-yoaJWI8,21774
|
|
87
|
+
praisonai-2.0.27.dist-info/WHEEL,sha256=rqU-pzVJ6on7cnU-SP20blBtY1yM7u0ejCbKCZ5K36I,110
|
|
88
|
+
praisonai-2.0.27.dist-info/entry_points.txt,sha256=I_xc6a6MNTTfLxYmAxe0rgey0G-_hbY07oFW-ZDnkw4,135
|
|
89
|
+
praisonai-2.0.27.dist-info/RECORD,,
|