praisonaiagents 0.0.42__py3-none-any.whl → 0.0.43__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/main.py +4 -0
- praisonaiagents/process/process.py +161 -80
- praisonaiagents/task/task.py +45 -2
- {praisonaiagents-0.0.42.dist-info → praisonaiagents-0.0.43.dist-info}/METADATA +1 -1
- {praisonaiagents-0.0.42.dist-info → praisonaiagents-0.0.43.dist-info}/RECORD +7 -7
- {praisonaiagents-0.0.42.dist-info → praisonaiagents-0.0.43.dist-info}/WHEEL +0 -0
- {praisonaiagents-0.0.42.dist-info → praisonaiagents-0.0.43.dist-info}/top_level.txt +0 -0
praisonaiagents/main.py
CHANGED
@@ -23,6 +23,10 @@ logging.basicConfig(
|
|
23
23
|
handlers=[RichHandler(rich_tracebacks=True)]
|
24
24
|
)
|
25
25
|
|
26
|
+
# Add these lines to suppress markdown parser debug logs
|
27
|
+
logging.getLogger('markdown_it').setLevel(logging.WARNING)
|
28
|
+
logging.getLogger('rich.markdown').setLevel(logging.WARNING)
|
29
|
+
|
26
30
|
# Global list to store error logs
|
27
31
|
error_logs = []
|
28
32
|
|
@@ -5,6 +5,8 @@ from pydantic import BaseModel
|
|
5
5
|
from ..agent.agent import Agent
|
6
6
|
from ..task.task import Task
|
7
7
|
from ..main import display_error, client
|
8
|
+
import csv
|
9
|
+
import os
|
8
10
|
|
9
11
|
class LoopItems(BaseModel):
|
10
12
|
items: List[Any]
|
@@ -62,46 +64,47 @@ class Process:
|
|
62
64
|
if prev_task and prev_task.result:
|
63
65
|
# Handle loop data
|
64
66
|
if current_task.task_type == "loop":
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
Process this data into a list format:
|
79
|
-
{prev_task.result.raw}
|
80
|
-
|
81
|
-
Return a JSON object with an 'items' array containing the items to process.
|
82
|
-
"""
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
67
|
+
# # create a loop manager Agent
|
68
|
+
# loop_manager = Agent(
|
69
|
+
# name="Loop Manager",
|
70
|
+
# role="Loop data processor",
|
71
|
+
# goal="Process loop data and convert it to list format",
|
72
|
+
# backstory="Expert at handling loop data and converting it to proper format",
|
73
|
+
# llm=self.manager_llm,
|
74
|
+
# verbose=self.verbose,
|
75
|
+
# markdown=True
|
76
|
+
# )
|
77
|
+
|
78
|
+
# # get the loop data convert it to list using calling Agent class chat
|
79
|
+
# loop_prompt = f"""
|
80
|
+
# Process this data into a list format:
|
81
|
+
# {prev_task.result.raw}
|
82
|
+
|
83
|
+
# Return a JSON object with an 'items' array containing the items to process.
|
84
|
+
# """
|
85
|
+
# if current_task.async_execution:
|
86
|
+
# loop_data_str = await loop_manager.achat(
|
87
|
+
# prompt=loop_prompt,
|
88
|
+
# output_json=LoopItems
|
89
|
+
# )
|
90
|
+
# else:
|
91
|
+
# loop_data_str = loop_manager.chat(
|
92
|
+
# prompt=loop_prompt,
|
93
|
+
# output_json=LoopItems
|
94
|
+
# )
|
93
95
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
96
|
+
# try:
|
97
|
+
# # The response will already be parsed into LoopItems model
|
98
|
+
# loop_data[f"loop_{current_task.name}"] = {
|
99
|
+
# "items": loop_data_str.items,
|
100
|
+
# "index": 0,
|
101
|
+
# "remaining": len(loop_data_str.items)
|
102
|
+
# }
|
103
|
+
# context += f"\nCurrent loop item: {loop_data_str.items[0]}"
|
104
|
+
# except Exception as e:
|
105
|
+
# display_error(f"Failed to process loop data: {e}")
|
106
|
+
# context += f"\n{prev_name}: {prev_task.result.raw}"
|
107
|
+
context += f"\n{prev_name}: {prev_task.result.raw}"
|
105
108
|
else:
|
106
109
|
context += f"\n{prev_name}: {prev_task.result.raw}"
|
107
110
|
|
@@ -144,13 +147,17 @@ Return a JSON object with an 'items' array containing the items to process.
|
|
144
147
|
next_task = None
|
145
148
|
if current_task and current_task.result:
|
146
149
|
if current_task.task_type in ["decision", "loop"]:
|
147
|
-
|
150
|
+
# MINIMAL CHANGE: use pydantic decision if present
|
151
|
+
decision_str = current_task.result.raw.lower()
|
152
|
+
if current_task.result.pydantic and hasattr(current_task.result.pydantic, "decision"):
|
153
|
+
decision_str = current_task.result.pydantic.decision.lower()
|
154
|
+
|
148
155
|
# Check conditions
|
149
156
|
for condition, tasks in current_task.condition.items():
|
150
|
-
if condition.lower()
|
157
|
+
if condition.lower() == decision_str:
|
151
158
|
# Handle both list and direct string values
|
152
159
|
task_value = tasks[0] if isinstance(tasks, list) else tasks
|
153
|
-
if not task_value or task_value == "exit":
|
160
|
+
if not task_value or task_value == "exit":
|
154
161
|
logging.info("Workflow exit condition met, ending workflow")
|
155
162
|
current_task = None
|
156
163
|
break
|
@@ -322,7 +329,76 @@ Provide a JSON with the structure:
|
|
322
329
|
if not start_task:
|
323
330
|
start_task = list(self.tasks.values())[0]
|
324
331
|
logging.info("No start task marked, using first task")
|
325
|
-
|
332
|
+
|
333
|
+
# If loop type and no input_file, default to tasks.csv
|
334
|
+
if start_task and start_task.task_type == "loop" and not start_task.input_file:
|
335
|
+
start_task.input_file = "tasks.csv"
|
336
|
+
|
337
|
+
# --- If loop + input_file, read file & create tasks
|
338
|
+
if start_task and start_task.task_type == "loop" and getattr(start_task, "input_file", None):
|
339
|
+
try:
|
340
|
+
file_ext = os.path.splitext(start_task.input_file)[1].lower()
|
341
|
+
new_tasks = []
|
342
|
+
|
343
|
+
if file_ext == ".csv":
|
344
|
+
# existing CSV reading logic
|
345
|
+
with open(start_task.input_file, "r", encoding="utf-8") as f:
|
346
|
+
# Try as simple CSV first
|
347
|
+
reader = csv.reader(f)
|
348
|
+
previous_task = None
|
349
|
+
for i, row in enumerate(reader):
|
350
|
+
if row: # Skip empty rows
|
351
|
+
task_desc = row[0] # Take first column
|
352
|
+
row_task = Task(
|
353
|
+
description=task_desc, # Keep full row as description
|
354
|
+
agent=start_task.agent,
|
355
|
+
name=task_desc, # Use first column as name
|
356
|
+
is_start=(i == 0),
|
357
|
+
task_type="task",
|
358
|
+
condition={
|
359
|
+
"complete": ["next"],
|
360
|
+
"retry": ["current"]
|
361
|
+
}
|
362
|
+
)
|
363
|
+
self.tasks[row_task.id] = row_task
|
364
|
+
new_tasks.append(row_task)
|
365
|
+
|
366
|
+
if previous_task:
|
367
|
+
previous_task.next_tasks = [row_task.name]
|
368
|
+
previous_task.condition["complete"] = [row_task.name]
|
369
|
+
previous_task = row_task
|
370
|
+
else:
|
371
|
+
# If not CSV, read lines
|
372
|
+
with open(start_task.input_file, "r", encoding="utf-8") as f:
|
373
|
+
lines = f.read().splitlines()
|
374
|
+
previous_task = None
|
375
|
+
for i, line in enumerate(lines):
|
376
|
+
row_task = Task(
|
377
|
+
description=line.strip(),
|
378
|
+
agent=start_task.agent,
|
379
|
+
name=line.strip(),
|
380
|
+
is_start=(i == 0),
|
381
|
+
task_type="task",
|
382
|
+
condition={
|
383
|
+
"complete": ["next"],
|
384
|
+
"retry": ["current"]
|
385
|
+
}
|
386
|
+
)
|
387
|
+
self.tasks[row_task.id] = row_task
|
388
|
+
new_tasks.append(row_task)
|
389
|
+
|
390
|
+
if previous_task:
|
391
|
+
previous_task.next_tasks = [row_task.name]
|
392
|
+
previous_task.condition["complete"] = [row_task.name]
|
393
|
+
previous_task = row_task
|
394
|
+
|
395
|
+
if new_tasks:
|
396
|
+
start_task = new_tasks[0]
|
397
|
+
logging.info(f"Created {len(new_tasks)} tasks from: {start_task.input_file}")
|
398
|
+
except Exception as e:
|
399
|
+
logging.error(f"Failed to read file tasks: {e}")
|
400
|
+
|
401
|
+
# end of the new block
|
326
402
|
current_task = start_task
|
327
403
|
visited_tasks = set()
|
328
404
|
loop_data = {} # Store loop-specific data
|
@@ -346,40 +422,41 @@ Provide a JSON with the structure:
|
|
346
422
|
if prev_task and prev_task.result:
|
347
423
|
# Handle loop data
|
348
424
|
if current_task.task_type == "loop":
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
Process this data into a list format:
|
363
|
-
{prev_task.result.raw}
|
364
|
-
|
365
|
-
Return a JSON object with an 'items' array containing the items to process.
|
366
|
-
"""
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
425
|
+
# # create a loop manager Agent
|
426
|
+
# loop_manager = Agent(
|
427
|
+
# name="Loop Manager",
|
428
|
+
# role="Loop data processor",
|
429
|
+
# goal="Process loop data and convert it to list format",
|
430
|
+
# backstory="Expert at handling loop data and converting it to proper format",
|
431
|
+
# llm=self.manager_llm,
|
432
|
+
# verbose=self.verbose,
|
433
|
+
# markdown=True
|
434
|
+
# )
|
435
|
+
|
436
|
+
# # get the loop data convert it to list using calling Agent class chat
|
437
|
+
# loop_prompt = f"""
|
438
|
+
# Process this data into a list format:
|
439
|
+
# {prev_task.result.raw}
|
440
|
+
|
441
|
+
# Return a JSON object with an 'items' array containing the items to process.
|
442
|
+
# """
|
443
|
+
# loop_data_str = loop_manager.chat(
|
444
|
+
# prompt=loop_prompt,
|
445
|
+
# output_json=LoopItems
|
446
|
+
# )
|
371
447
|
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
448
|
+
# try:
|
449
|
+
# # The response will already be parsed into LoopItems model
|
450
|
+
# loop_data[f"loop_{current_task.name}"] = {
|
451
|
+
# "items": loop_data_str.items,
|
452
|
+
# "index": 0,
|
453
|
+
# "remaining": len(loop_data_str.items)
|
454
|
+
# }
|
455
|
+
# context += f"\nCurrent loop item: {loop_data_str.items[0]}"
|
456
|
+
# except Exception as e:
|
457
|
+
# display_error(f"Failed to process loop data: {e}")
|
458
|
+
# context += f"\n{prev_name}: {prev_task.result.raw}"
|
459
|
+
context += f"\n{prev_name}: {prev_task.result.raw}"
|
383
460
|
else:
|
384
461
|
context += f"\n{prev_name}: {prev_task.result.raw}"
|
385
462
|
|
@@ -396,7 +473,7 @@ Return a JSON object with an 'items' array containing the items to process.
|
|
396
473
|
yield task_id
|
397
474
|
visited_tasks.add(task_id)
|
398
475
|
|
399
|
-
# Reset completed task to "not started" so it can run again
|
476
|
+
# Reset completed task to "not started" so it can run again: Only for workflow because some tasks may be revisited
|
400
477
|
if self.tasks[task_id].status == "completed":
|
401
478
|
logging.debug(f"Task {task_id} was completed, resetting to 'not started' for next iteration.")
|
402
479
|
self.tasks[task_id].status = "not started"
|
@@ -422,13 +499,17 @@ Return a JSON object with an 'items' array containing the items to process.
|
|
422
499
|
next_task = None
|
423
500
|
if current_task and current_task.result:
|
424
501
|
if current_task.task_type in ["decision", "loop"]:
|
425
|
-
|
502
|
+
# MINIMAL CHANGE: use pydantic decision if present
|
503
|
+
decision_str = current_task.result.raw.lower()
|
504
|
+
if current_task.result.pydantic and hasattr(current_task.result.pydantic, "decision"):
|
505
|
+
decision_str = current_task.result.pydantic.decision.lower()
|
506
|
+
|
426
507
|
# Check conditions
|
427
508
|
for condition, tasks in current_task.condition.items():
|
428
|
-
if condition.lower()
|
509
|
+
if condition.lower() == decision_str:
|
429
510
|
# Handle both list and direct string values
|
430
511
|
task_value = tasks[0] if isinstance(tasks, list) else tasks
|
431
|
-
if not task_value or task_value == "exit":
|
512
|
+
if not task_value or task_value == "exit":
|
432
513
|
logging.info("Workflow exit condition met, ending workflow")
|
433
514
|
current_task = None
|
434
515
|
break
|
praisonaiagents/task/task.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import logging
|
2
2
|
import asyncio
|
3
|
-
from typing import List, Optional, Dict, Any, Type, Callable, Union, Coroutine
|
3
|
+
from typing import List, Optional, Dict, Any, Type, Callable, Union, Coroutine, Literal
|
4
4
|
from pydantic import BaseModel
|
5
5
|
from ..main import TaskOutput
|
6
6
|
from ..agent.agent import Agent
|
@@ -37,8 +37,10 @@ class Task:
|
|
37
37
|
is_start: bool = False,
|
38
38
|
loop_state: Optional[Dict[str, Union[str, int]]] = None,
|
39
39
|
memory=None,
|
40
|
-
quality_check=True
|
40
|
+
quality_check=True,
|
41
|
+
input_file: Optional[str] = None
|
41
42
|
):
|
43
|
+
self.input_file = input_file
|
42
44
|
self.id = str(uuid.uuid4()) if id is None else str(id)
|
43
45
|
self.name = name
|
44
46
|
self.description = description
|
@@ -83,6 +85,47 @@ class Task:
|
|
83
85
|
# Track previous tasks based on next_tasks relationships
|
84
86
|
self.previous_tasks = []
|
85
87
|
|
88
|
+
# If task_type="decision" and output_pydantic is not set
|
89
|
+
if self.task_type == "decision" and not self.output_pydantic:
|
90
|
+
from pydantic import BaseModel
|
91
|
+
from typing import Literal
|
92
|
+
|
93
|
+
# Gather condition keys for the "decision" field
|
94
|
+
condition_keys = list(self.condition.keys())
|
95
|
+
if not condition_keys:
|
96
|
+
# Fall back to placeholders if nothing is specified
|
97
|
+
condition_keys = ["next_task", "exit"]
|
98
|
+
|
99
|
+
# Create a dynamic literal type from condition keys
|
100
|
+
DecisionLiteral = Literal.__getitem__(tuple(condition_keys))
|
101
|
+
|
102
|
+
class DecisionModel(BaseModel):
|
103
|
+
response: str
|
104
|
+
decision: DecisionLiteral
|
105
|
+
|
106
|
+
self.output_pydantic = DecisionModel
|
107
|
+
|
108
|
+
# If task_type="loop" and output_pydantic is not set
|
109
|
+
if self.task_type == "loop" and not self.output_pydantic:
|
110
|
+
from pydantic import BaseModel
|
111
|
+
from typing import Literal
|
112
|
+
|
113
|
+
# Gather condition keys for the "decision" field
|
114
|
+
condition_keys = list(self.condition.keys())
|
115
|
+
if not condition_keys:
|
116
|
+
# Fall back to placeholders if nothing is specified
|
117
|
+
condition_keys = ["next_item", "exit"]
|
118
|
+
|
119
|
+
# Create a dynamic literal type
|
120
|
+
LoopLiteral = Literal.__getitem__(tuple(condition_keys))
|
121
|
+
|
122
|
+
class LoopModel(BaseModel):
|
123
|
+
response: str
|
124
|
+
decision: LoopLiteral
|
125
|
+
loop_id: str # Additional field for loop
|
126
|
+
|
127
|
+
self.output_pydantic = LoopModel
|
128
|
+
|
86
129
|
def __str__(self):
|
87
130
|
return f"Task(name='{self.name if self.name else 'None'}', description='{self.description}', agent='{self.agent.name if self.agent else 'None'}', status='{self.status}')"
|
88
131
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
praisonaiagents/__init__.py,sha256=MCgAj12hVJ0YZmVmdmZgYAAMfPdWSoNSiDlRJCvrJqA,1276
|
2
|
-
praisonaiagents/main.py,sha256=
|
2
|
+
praisonaiagents/main.py,sha256=wcFooRmCY38wtkSNFt6-nhZafgrHotCZE0S6U8IWgUY,14093
|
3
3
|
praisonaiagents/agent/__init__.py,sha256=sKO8wGEXvtCrvV1e834r1Okv0XAqAxqZCqz6hKLiTvA,79
|
4
4
|
praisonaiagents/agent/agent.py,sha256=rWvuZKP1fMF-BBe7I554FVk56Wse_iHyjoRRNEuyC5o,37836
|
5
5
|
praisonaiagents/agents/__init__.py,sha256=_1d6Pqyk9EoBSo7E68sKyd1jDRlN1vxvVIRpoMc0Jcw,168
|
@@ -10,9 +10,9 @@ praisonaiagents/knowledge/chunking.py,sha256=FzoNY0q8MkvG4gADqk4JcRhmH3lcEHbRdon
|
|
10
10
|
praisonaiagents/knowledge/knowledge.py,sha256=dJd8WuFV3w-zWaSAcT21PcXGRIZZc6YxBsJZDfmZNrk,12358
|
11
11
|
praisonaiagents/memory/memory.py,sha256=ZxqSpOUxk9jeTKGW0ZiTifC0uZtym-EZILP3kuOOKkU,35626
|
12
12
|
praisonaiagents/process/__init__.py,sha256=lkYbL7Hn5a0ldvJtkdH23vfIIZLIcanK-65C0MwaorY,52
|
13
|
-
praisonaiagents/process/process.py,sha256=
|
13
|
+
praisonaiagents/process/process.py,sha256=_1Nk37kOYakPaUWAJff86rP0ENyykXqMnhTp8E0efuE,30802
|
14
14
|
praisonaiagents/task/__init__.py,sha256=VL5hXVmyGjINb34AalxpBMl-YW9m5EDcRkMTKkSSl7c,80
|
15
|
-
praisonaiagents/task/task.py,sha256=
|
15
|
+
praisonaiagents/task/task.py,sha256=VcUl7dVNy5gj3Gq4H9SQU9S3Oy-0qYHSG-lEIlx2Rvg,13085
|
16
16
|
praisonaiagents/tools/__init__.py,sha256=-0lV5n5cG54vYW6REjXIfuJnCLKnfQIDlXsySCaPB9s,7347
|
17
17
|
praisonaiagents/tools/arxiv_tools.py,sha256=1stb31zTjLTon4jCnpZG5de9rKc9QWgC0leLegvPXWo,10528
|
18
18
|
praisonaiagents/tools/calculator_tools.py,sha256=S1xPT74Geurvjm52QMMIG29zDXVEWJmM6nmyY7yF298,9571
|
@@ -33,7 +33,7 @@ praisonaiagents/tools/wikipedia_tools.py,sha256=pGko-f33wqXgxJTv8db7TbizY5XnzBQR
|
|
33
33
|
praisonaiagents/tools/xml_tools.py,sha256=iYTMBEk5l3L3ryQ1fkUnNVYK-Nnua2Kx2S0dxNMMs1A,17122
|
34
34
|
praisonaiagents/tools/yaml_tools.py,sha256=uogAZrhXV9O7xvspAtcTfpKSQYL2nlOTvCQXN94-G9A,14215
|
35
35
|
praisonaiagents/tools/yfinance_tools.py,sha256=s2PBj_1v7oQnOobo2fDbQBACEHl61ftG4beG6Z979ZE,8529
|
36
|
-
praisonaiagents-0.0.
|
37
|
-
praisonaiagents-0.0.
|
38
|
-
praisonaiagents-0.0.
|
39
|
-
praisonaiagents-0.0.
|
36
|
+
praisonaiagents-0.0.43.dist-info/METADATA,sha256=KfaypGamyAdt7T24cowH5_OUfhuEwIjDc2BU4XOxTmU,664
|
37
|
+
praisonaiagents-0.0.43.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
38
|
+
praisonaiagents-0.0.43.dist-info/top_level.txt,sha256=_HsRddrJ23iDx5TTqVUVvXG2HeHBL5voshncAMDGjtA,16
|
39
|
+
praisonaiagents-0.0.43.dist-info/RECORD,,
|
File without changes
|
File without changes
|