praisonaiagents 0.0.85__py3-none-any.whl → 0.0.87__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/agent/agent.py +44 -3
- praisonaiagents/agents/agents.py +79 -66
- praisonaiagents/mcp/mcp.py +12 -0
- {praisonaiagents-0.0.85.dist-info → praisonaiagents-0.0.87.dist-info}/METADATA +1 -1
- {praisonaiagents-0.0.85.dist-info → praisonaiagents-0.0.87.dist-info}/RECORD +7 -7
- {praisonaiagents-0.0.85.dist-info → praisonaiagents-0.0.87.dist-info}/WHEEL +0 -0
- {praisonaiagents-0.0.85.dist-info → praisonaiagents-0.0.87.dist-info}/top_level.txt +0 -0
praisonaiagents/agent/agent.py
CHANGED
@@ -526,6 +526,44 @@ Your Goal: {self.goal}
|
|
526
526
|
tools=self.tools
|
527
527
|
)
|
528
528
|
|
529
|
+
def _cast_arguments(self, func, arguments):
|
530
|
+
"""Cast arguments to their expected types based on function signature."""
|
531
|
+
if not callable(func) or not arguments:
|
532
|
+
return arguments
|
533
|
+
|
534
|
+
try:
|
535
|
+
sig = inspect.signature(func)
|
536
|
+
casted_args = {}
|
537
|
+
|
538
|
+
for param_name, arg_value in arguments.items():
|
539
|
+
if param_name in sig.parameters:
|
540
|
+
param = sig.parameters[param_name]
|
541
|
+
if param.annotation != inspect.Parameter.empty:
|
542
|
+
# Handle common type conversions
|
543
|
+
if param.annotation == int and isinstance(arg_value, (str, float)):
|
544
|
+
try:
|
545
|
+
casted_args[param_name] = int(float(arg_value))
|
546
|
+
except (ValueError, TypeError):
|
547
|
+
casted_args[param_name] = arg_value
|
548
|
+
elif param.annotation == float and isinstance(arg_value, (str, int)):
|
549
|
+
try:
|
550
|
+
casted_args[param_name] = float(arg_value)
|
551
|
+
except (ValueError, TypeError):
|
552
|
+
casted_args[param_name] = arg_value
|
553
|
+
elif param.annotation == bool and isinstance(arg_value, str):
|
554
|
+
casted_args[param_name] = arg_value.lower() in ('true', '1', 'yes', 'on')
|
555
|
+
else:
|
556
|
+
casted_args[param_name] = arg_value
|
557
|
+
else:
|
558
|
+
casted_args[param_name] = arg_value
|
559
|
+
else:
|
560
|
+
casted_args[param_name] = arg_value
|
561
|
+
|
562
|
+
return casted_args
|
563
|
+
except Exception as e:
|
564
|
+
logging.debug(f"Type casting failed for {getattr(func, '__name__', 'unknown function')}: {e}")
|
565
|
+
return arguments
|
566
|
+
|
529
567
|
def execute_tool(self, function_name, arguments):
|
530
568
|
"""
|
531
569
|
Execute a tool dynamically based on the function name and arguments.
|
@@ -576,7 +614,8 @@ Your Goal: {self.goal}
|
|
576
614
|
run_params = {k: v for k, v in arguments.items()
|
577
615
|
if k in inspect.signature(instance.run).parameters
|
578
616
|
and k != 'self'}
|
579
|
-
|
617
|
+
casted_params = self._cast_arguments(instance.run, run_params)
|
618
|
+
return instance.run(**casted_params)
|
580
619
|
|
581
620
|
# CrewAI: If it's a class with an _run method, instantiate and call _run
|
582
621
|
elif inspect.isclass(func) and hasattr(func, '_run'):
|
@@ -584,11 +623,13 @@ Your Goal: {self.goal}
|
|
584
623
|
run_params = {k: v for k, v in arguments.items()
|
585
624
|
if k in inspect.signature(instance._run).parameters
|
586
625
|
and k != 'self'}
|
587
|
-
|
626
|
+
casted_params = self._cast_arguments(instance._run, run_params)
|
627
|
+
return instance._run(**casted_params)
|
588
628
|
|
589
629
|
# Otherwise treat as regular function
|
590
630
|
elif callable(func):
|
591
|
-
|
631
|
+
casted_arguments = self._cast_arguments(func, arguments)
|
632
|
+
return func(**casted_arguments)
|
592
633
|
except Exception as e:
|
593
634
|
error_msg = str(e)
|
594
635
|
logging.error(f"Error executing tool {function_name}: {error_msg}")
|
praisonaiagents/agents/agents.py
CHANGED
@@ -13,6 +13,16 @@ from ..task.task import Task
|
|
13
13
|
from ..process.process import Process, LoopItems
|
14
14
|
import asyncio
|
15
15
|
import uuid
|
16
|
+
from enum import Enum
|
17
|
+
|
18
|
+
# Task status constants
|
19
|
+
class TaskStatus(Enum):
|
20
|
+
"""Enumeration for task status values to ensure consistency"""
|
21
|
+
COMPLETED = "completed"
|
22
|
+
IN_PROGRESS = "in progress"
|
23
|
+
NOT_STARTED = "not started"
|
24
|
+
FAILED = "failed"
|
25
|
+
UNKNOWN = "unknown"
|
16
26
|
|
17
27
|
# Set up logger
|
18
28
|
logger = logging.getLogger(__name__)
|
@@ -49,6 +59,55 @@ def process_video(video_path: str, seconds_per_frame=2):
|
|
49
59
|
video.release()
|
50
60
|
return base64_frames
|
51
61
|
|
62
|
+
def process_task_context(context_item, verbose=0, user_id=None):
|
63
|
+
"""
|
64
|
+
Process a single context item for task execution.
|
65
|
+
This helper function avoids code duplication between async and sync execution methods.
|
66
|
+
|
67
|
+
Args:
|
68
|
+
context_item: The context item to process (can be string, list, task object, or dict)
|
69
|
+
verbose: Verbosity level for logging
|
70
|
+
user_id: User ID for database queries
|
71
|
+
|
72
|
+
Returns:
|
73
|
+
str: Formatted context string for this item
|
74
|
+
"""
|
75
|
+
if isinstance(context_item, str):
|
76
|
+
return f"Input Content:\n{context_item}"
|
77
|
+
elif isinstance(context_item, list):
|
78
|
+
return f"Input Content: {' '.join(str(x) for x in context_item)}"
|
79
|
+
elif hasattr(context_item, 'result'): # Task object
|
80
|
+
# Ensure the previous task is completed before including its result
|
81
|
+
task_status = getattr(context_item, 'status', None)
|
82
|
+
task_name = context_item.name if context_item.name else context_item.description
|
83
|
+
|
84
|
+
if context_item.result and task_status == TaskStatus.COMPLETED.value:
|
85
|
+
return f"Result of previous task {task_name}:\n{context_item.result.raw}"
|
86
|
+
elif task_status == TaskStatus.COMPLETED.value and not context_item.result:
|
87
|
+
return f"Previous task {task_name} completed but produced no result."
|
88
|
+
else:
|
89
|
+
return f"Previous task {task_name} is not yet completed (status: {task_status or TaskStatus.UNKNOWN.value})."
|
90
|
+
elif isinstance(context_item, dict) and "vector_store" in context_item:
|
91
|
+
from ..knowledge.knowledge import Knowledge
|
92
|
+
try:
|
93
|
+
# Handle both string and dict configs
|
94
|
+
cfg = context_item["vector_store"]
|
95
|
+
if isinstance(cfg, str):
|
96
|
+
cfg = json.loads(cfg)
|
97
|
+
|
98
|
+
knowledge = Knowledge(config={"vector_store": cfg}, verbose=verbose)
|
99
|
+
|
100
|
+
# Only use user_id as filter
|
101
|
+
db_results = knowledge.search(
|
102
|
+
context_item.get("query", ""), # Use query from context if available
|
103
|
+
user_id=user_id if user_id else None
|
104
|
+
)
|
105
|
+
return f"[DB Context]: {str(db_results)}"
|
106
|
+
except Exception as e:
|
107
|
+
return f"[Vector DB Error]: {e}"
|
108
|
+
else:
|
109
|
+
return str(context_item) # Fallback for unknown types
|
110
|
+
|
52
111
|
class PraisonAIAgents:
|
53
112
|
def __init__(self, agents, tasks=None, verbose=0, completion_checker=None, max_retries=5, process="sequential", manager_llm=None, memory=False, memory_config=None, embedder=None, user_id=None, max_iter=10, stream=True, name: Optional[str] = None):
|
54
113
|
# Add check at the start if memory is requested
|
@@ -250,44 +309,21 @@ Expected Output: {task.expected_output}.
|
|
250
309
|
if task.context:
|
251
310
|
context_results = [] # Use list to avoid duplicates
|
252
311
|
for context_item in task.context:
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
context_results.append(f"Input Content: {' '.join(str(x) for x in context_item)}")
|
257
|
-
elif hasattr(context_item, 'result'): # Task object
|
258
|
-
if context_item.result:
|
259
|
-
context_results.append(
|
260
|
-
f"Result of previous task {context_item.name if context_item.name else context_item.description}:\n{context_item.result.raw}"
|
261
|
-
)
|
262
|
-
else:
|
263
|
-
context_results.append(
|
264
|
-
f"Previous task {context_item.name if context_item.name else context_item.description} has no result yet."
|
265
|
-
)
|
266
|
-
elif isinstance(context_item, dict) and "vector_store" in context_item:
|
267
|
-
from ..knowledge.knowledge import Knowledge
|
268
|
-
try:
|
269
|
-
# Handle both string and dict configs
|
270
|
-
cfg = context_item["vector_store"]
|
271
|
-
if isinstance(cfg, str):
|
272
|
-
cfg = json.loads(cfg)
|
273
|
-
|
274
|
-
knowledge = Knowledge(config={"vector_store": cfg}, verbose=self.verbose)
|
275
|
-
|
276
|
-
# Only use user_id as filter
|
277
|
-
db_results = knowledge.search(
|
278
|
-
task.description,
|
279
|
-
user_id=self.user_id if self.user_id else None
|
280
|
-
)
|
281
|
-
context_results.append(f"[DB Context]: {str(db_results)}")
|
282
|
-
except Exception as e:
|
283
|
-
context_results.append(f"[Vector DB Error]: {e}")
|
312
|
+
# Use the centralized helper function
|
313
|
+
context_str = process_task_context(context_item, self.verbose, self.user_id)
|
314
|
+
context_results.append(context_str)
|
284
315
|
|
285
|
-
# Join unique context results
|
316
|
+
# Join unique context results with proper formatting
|
286
317
|
unique_contexts = list(dict.fromkeys(context_results)) # Remove duplicates
|
318
|
+
if self.verbose >= 3:
|
319
|
+
logger.info(f"Task {task_id} context items: {len(unique_contexts)}")
|
320
|
+
for i, ctx in enumerate(unique_contexts):
|
321
|
+
logger.info(f"Context {i+1}: {ctx[:100]}...")
|
322
|
+
context_separator = '\n\n'
|
287
323
|
task_prompt += f"""
|
288
324
|
Context:
|
289
325
|
|
290
|
-
{
|
326
|
+
{context_separator.join(unique_contexts)}
|
291
327
|
"""
|
292
328
|
task_prompt += "Please provide only the final result of your work. Do not add any conversation or extra explanation."
|
293
329
|
|
@@ -573,44 +609,21 @@ Expected Output: {task.expected_output}.
|
|
573
609
|
if task.context:
|
574
610
|
context_results = [] # Use list to avoid duplicates
|
575
611
|
for context_item in task.context:
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
context_results.append(f"Input Content: {' '.join(str(x) for x in context_item)}")
|
580
|
-
elif hasattr(context_item, 'result'): # Task object
|
581
|
-
if context_item.result:
|
582
|
-
context_results.append(
|
583
|
-
f"Result of previous task {context_item.name if context_item.name else context_item.description}:\n{context_item.result.raw}"
|
584
|
-
)
|
585
|
-
else:
|
586
|
-
context_results.append(
|
587
|
-
f"Previous task {context_item.name if context_item.name else context_item.description} has no result yet."
|
588
|
-
)
|
589
|
-
elif isinstance(context_item, dict) and "vector_store" in context_item:
|
590
|
-
from ..knowledge.knowledge import Knowledge
|
591
|
-
try:
|
592
|
-
# Handle both string and dict configs
|
593
|
-
cfg = context_item["vector_store"]
|
594
|
-
if isinstance(cfg, str):
|
595
|
-
cfg = json.loads(cfg)
|
596
|
-
|
597
|
-
knowledge = Knowledge(config={"vector_store": cfg}, verbose=self.verbose)
|
598
|
-
|
599
|
-
# Only use user_id as filter
|
600
|
-
db_results = knowledge.search(
|
601
|
-
task.description,
|
602
|
-
user_id=self.user_id if self.user_id else None
|
603
|
-
)
|
604
|
-
context_results.append(f"[DB Context]: {str(db_results)}")
|
605
|
-
except Exception as e:
|
606
|
-
context_results.append(f"[Vector DB Error]: {e}")
|
612
|
+
# Use the centralized helper function
|
613
|
+
context_str = process_task_context(context_item, self.verbose, self.user_id)
|
614
|
+
context_results.append(context_str)
|
607
615
|
|
608
|
-
# Join unique context results
|
616
|
+
# Join unique context results with proper formatting
|
609
617
|
unique_contexts = list(dict.fromkeys(context_results)) # Remove duplicates
|
618
|
+
if self.verbose >= 3:
|
619
|
+
logger.info(f"Task {task_id} context items: {len(unique_contexts)}")
|
620
|
+
for i, ctx in enumerate(unique_contexts):
|
621
|
+
logger.info(f"Context {i+1}: {ctx[:100]}...")
|
622
|
+
context_separator = '\n\n'
|
610
623
|
task_prompt += f"""
|
611
624
|
Context:
|
612
625
|
|
613
|
-
{
|
626
|
+
{context_separator.join(unique_contexts)}
|
614
627
|
"""
|
615
628
|
|
616
629
|
# Add memory context if available
|
praisonaiagents/mcp/mcp.py
CHANGED
@@ -212,6 +212,18 @@ class MCP:
|
|
212
212
|
|
213
213
|
# Set up stdio client
|
214
214
|
self.is_sse = False
|
215
|
+
|
216
|
+
# Ensure UTF-8 encoding in environment for Docker compatibility
|
217
|
+
env = kwargs.get('env', {})
|
218
|
+
if not env:
|
219
|
+
env = os.environ.copy()
|
220
|
+
env.update({
|
221
|
+
'PYTHONIOENCODING': 'utf-8',
|
222
|
+
'LC_ALL': 'C.UTF-8',
|
223
|
+
'LANG': 'C.UTF-8'
|
224
|
+
})
|
225
|
+
kwargs['env'] = env
|
226
|
+
|
215
227
|
self.server_params = StdioServerParameters(
|
216
228
|
command=cmd,
|
217
229
|
args=arguments,
|
@@ -1,10 +1,10 @@
|
|
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=
|
4
|
+
praisonaiagents/agent/agent.py,sha256=rnUCrrEB_7kLrSsHwZydiRg7ygIokGIrKZ0P6WYuj4M,86363
|
5
5
|
praisonaiagents/agent/image_agent.py,sha256=-5MXG594HVwSpFMcidt16YBp7udtik-Cp7eXlzLE1fY,8696
|
6
6
|
praisonaiagents/agents/__init__.py,sha256=_1d6Pqyk9EoBSo7E68sKyd1jDRlN1vxvVIRpoMc0Jcw,168
|
7
|
-
praisonaiagents/agents/agents.py,sha256=
|
7
|
+
praisonaiagents/agents/agents.py,sha256=lFWJDZeWQcr6RttV-pxvny-jfAM3UWiYjMnYo8pZYe0,59429
|
8
8
|
praisonaiagents/agents/autoagents.py,sha256=olYDn--rlJp-SckxILqmREkkgNlzCgEEcAUzfMj-54E,13518
|
9
9
|
praisonaiagents/knowledge/__init__.py,sha256=xL1Eh-a3xsHyIcU4foOWF-JdWYIYBALJH9bge0Ujuto,246
|
10
10
|
praisonaiagents/knowledge/chunking.py,sha256=G6wyHa7_8V0_7VpnrrUXbEmUmptlT16ISJYaxmkSgmU,7678
|
@@ -12,7 +12,7 @@ praisonaiagents/knowledge/knowledge.py,sha256=Po0JZsgjYJrXdNSggmUGOWidZEF0f8xo4n
|
|
12
12
|
praisonaiagents/llm/__init__.py,sha256=ttPQQJQq6Tah-0updoEXDZFKWtJAM93rBWRoIgxRWO8,689
|
13
13
|
praisonaiagents/llm/llm.py,sha256=Y8z7mfzL_OMhoPSIr7k7Demk8HvHmJZv80EXFY6SUEU,91863
|
14
14
|
praisonaiagents/mcp/__init__.py,sha256=ibbqe3_7XB7VrIcUcetkZiUZS1fTVvyMy_AqCSFG8qc,240
|
15
|
-
praisonaiagents/mcp/mcp.py,sha256
|
15
|
+
praisonaiagents/mcp/mcp.py,sha256=-U6md6zHoJZCWF8XFq921Yy5CcSNaGqvjg3aRT737LM,16765
|
16
16
|
praisonaiagents/mcp/mcp_sse.py,sha256=DLh3F_aoVRM1X-7hgIOWOw4FQ1nGmn9YNbQTesykzn4,6792
|
17
17
|
praisonaiagents/memory/memory.py,sha256=I8dOTkrl1i-GgQbDcrFOsSruzJ7MiI6Ys37DK27wrUs,35537
|
18
18
|
praisonaiagents/process/__init__.py,sha256=lkYbL7Hn5a0ldvJtkdH23vfIIZLIcanK-65C0MwaorY,52
|
@@ -40,7 +40,7 @@ praisonaiagents/tools/xml_tools.py,sha256=iYTMBEk5l3L3ryQ1fkUnNVYK-Nnua2Kx2S0dxN
|
|
40
40
|
praisonaiagents/tools/yaml_tools.py,sha256=uogAZrhXV9O7xvspAtcTfpKSQYL2nlOTvCQXN94-G9A,14215
|
41
41
|
praisonaiagents/tools/yfinance_tools.py,sha256=s2PBj_1v7oQnOobo2fDbQBACEHl61ftG4beG6Z979ZE,8529
|
42
42
|
praisonaiagents/tools/train/data/generatecot.py,sha256=H6bNh-E2hqL5MW6kX3hqZ05g9ETKN2-kudSjiuU_SD8,19403
|
43
|
-
praisonaiagents-0.0.
|
44
|
-
praisonaiagents-0.0.
|
45
|
-
praisonaiagents-0.0.
|
46
|
-
praisonaiagents-0.0.
|
43
|
+
praisonaiagents-0.0.87.dist-info/METADATA,sha256=W0Db67jMCP_PNX-Y9cjasKCxLKN6r5oTwtuAzBR_pNM,1244
|
44
|
+
praisonaiagents-0.0.87.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
|
45
|
+
praisonaiagents-0.0.87.dist-info/top_level.txt,sha256=_HsRddrJ23iDx5TTqVUVvXG2HeHBL5voshncAMDGjtA,16
|
46
|
+
praisonaiagents-0.0.87.dist-info/RECORD,,
|
File without changes
|
File without changes
|