praisonaiagents 0.0.14__py3-none-any.whl → 0.0.16__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -10,9 +10,7 @@ from rich.console import Console
10
10
  from ..main import display_error, TaskOutput, error_logs, client
11
11
  from ..agent.agent import Agent
12
12
  from ..task.task import Task
13
-
14
- class LoopItems(BaseModel):
15
- items: List[Any]
13
+ from ..process.process import Process, LoopItems
16
14
 
17
15
  def encode_file_to_base64(file_path: str) -> str:
18
16
  """Base64-encode a file."""
@@ -256,254 +254,24 @@ Expected Output: {task.expected_output}.
256
254
 
257
255
  def run_all_tasks(self):
258
256
  """Execute tasks based on execution mode"""
257
+ process = Process(
258
+ tasks=self.tasks,
259
+ agents=self.agents,
260
+ manager_llm=self.manager_llm,
261
+ verbose=self.verbose
262
+ )
263
+
259
264
  if self.process == "workflow":
260
- # Build workflow relationships first
261
- for task in self.tasks.values():
262
- if task.next_tasks:
263
- for next_task_name in task.next_tasks:
264
- next_task = next((t for t in self.tasks.values() if t.name == next_task_name), None)
265
- if next_task:
266
- next_task.previous_tasks.append(task.name)
267
-
268
- # Find start task
269
- start_task = None
270
- for task_id, task in self.tasks.items():
271
- if task.is_start:
272
- start_task = task
273
- break
274
-
275
- if not start_task:
276
- start_task = list(self.tasks.values())[0]
277
- logging.info("No start task marked, using first task")
278
-
279
- current_task = start_task
280
- visited_tasks = set()
281
- loop_data = {} # Store loop-specific data
282
-
283
- while current_task and current_task.id not in visited_tasks:
284
- task_id = current_task.id
285
- logging.info(f"Executing workflow task: {current_task.name if current_task.name else task_id}")
286
-
287
- # Add context from previous tasks to description
288
- if current_task.previous_tasks or current_task.context:
289
- context = "\nInput data from previous tasks:"
290
-
291
- # Add data from previous tasks in workflow
292
- for prev_name in current_task.previous_tasks:
293
- prev_task = next((t for t in self.tasks.values() if t.name == prev_name), None)
294
- if prev_task and prev_task.result:
295
- # Handle loop data
296
- if current_task.task_type == "loop":
297
- # create a loop manager Agent
298
- loop_manager = Agent(
299
- name="Loop Manager",
300
- role="Loop data processor",
301
- goal="Process loop data and convert it to list format",
302
- backstory="Expert at handling loop data and converting it to proper format",
303
- llm=self.manager_llm,
304
- verbose=self.verbose,
305
- markdown=True
306
- )
307
-
308
- # get the loop data convert it to list using calling Agent class chat
309
- loop_prompt = f"""
310
- Process this data into a list format:
311
- {prev_task.result.raw}
312
-
313
- Return a JSON object with an 'items' array containing the items to process.
314
- """
315
- loop_data_str = loop_manager.chat(
316
- prompt=loop_prompt,
317
- output_json=LoopItems
318
- )
319
-
320
- try:
321
- # The response will already be parsed into LoopItems model
322
- loop_data[f"loop_{current_task.name}"] = {
323
- "items": loop_data_str.items,
324
- "index": 0,
325
- "remaining": len(loop_data_str.items)
326
- }
327
- context += f"\nCurrent loop item: {loop_data_str.items[0]}"
328
- except Exception as e:
329
- display_error(f"Failed to process loop data: {e}")
330
- context += f"\n{prev_name}: {prev_task.result.raw}"
331
- else:
332
- context += f"\n{prev_name}: {prev_task.result.raw}"
333
-
334
- # Add data from context tasks
335
- if current_task.context:
336
- for ctx_task in current_task.context:
337
- if ctx_task.result and ctx_task.name != current_task.name:
338
- context += f"\n{ctx_task.name}: {ctx_task.result.raw}"
339
-
340
- # Update task description with context
341
- current_task.description = current_task.description + context
342
-
343
- # Execute task using existing run_task method
265
+ for task_id in process.workflow():
344
266
  self.run_task(task_id)
345
- visited_tasks.add(task_id)
346
-
347
- # Handle loop progression
348
- if current_task.task_type == "loop":
349
- loop_key = f"loop_{current_task.name}"
350
- if loop_key in loop_data:
351
- loop_info = loop_data[loop_key]
352
- loop_info["index"] += 1
353
- has_more = loop_info["remaining"] > 0
354
-
355
- # Update result to trigger correct condition
356
- if current_task.result:
357
- result = current_task.result.raw
358
- if has_more:
359
- result += "\nmore"
360
- else:
361
- result += "\ndone"
362
- current_task.result.raw = result
363
-
364
- # Determine next task based on result
365
- next_task = None
366
- if current_task.result:
367
- if current_task.task_type in ["decision", "loop"]:
368
- result = current_task.result.raw.lower()
369
- # Check conditions
370
- for condition, tasks in current_task.condition.items():
371
- if condition.lower() in result and tasks:
372
- next_task_name = tasks[0]
373
- next_task = next((t for t in self.tasks.values() if t.name == next_task_name), None)
374
- # For loops, allow revisiting the same task
375
- if next_task and next_task.id == current_task.id:
376
- visited_tasks.discard(current_task.id)
377
- break
378
-
379
- if not next_task and current_task.next_tasks:
380
- next_task_name = current_task.next_tasks[0]
381
- next_task = next((t for t in self.tasks.values() if t.name == next_task_name), None)
382
-
383
- current_task = next_task
384
- if not current_task:
385
- logging.info("Workflow execution completed")
386
- break
387
-
388
267
  elif self.process == "sequential":
389
- # Keep original sequential execution
390
- for task_id in self.tasks:
391
- if self.tasks[task_id].status != "completed":
392
- self.run_task(task_id)
393
-
268
+ for task_id in process.sequential():
269
+ self.run_task(task_id)
394
270
  elif self.process == "hierarchical":
395
- # Keep original hierarchical execution
396
- logging.debug(f"Starting hierarchical task execution with {len(self.tasks)} tasks")
397
- manager_agent = Agent(
398
- name="Manager",
399
- role="Project manager",
400
- goal="Manage the entire flow of tasks and delegate them to the right agent",
401
- backstory="Expert project manager to coordinate tasks among agents",
402
- llm=self.manager_llm,
403
- verbose=self.verbose,
404
- markdown=True,
405
- self_reflect=False
406
- )
407
-
408
- class ManagerInstructions(BaseModel):
409
- task_id: int
410
- agent_name: str
411
- action: str
412
-
413
- manager_task = Task(
414
- name="manager_task",
415
- description="Decide the order of tasks and which agent executes them",
416
- expected_output="All tasks completed successfully",
417
- agent=manager_agent
418
- )
419
- manager_task_id = self.add_task(manager_task)
420
- logging.info(f"Created manager task with ID {manager_task_id}")
421
-
422
- completed_count = 0
423
- total_tasks = len(self.tasks) - 1
424
- logging.info(f"Need to complete {total_tasks} tasks (excluding manager task)")
425
-
426
- while completed_count < total_tasks:
427
- tasks_summary = []
428
- for tid, tk in self.tasks.items():
429
- if tk.name == "manager_task":
430
- continue
431
- task_info = {
432
- "task_id": tid,
433
- "name": tk.name,
434
- "description": tk.description,
435
- "status": tk.status if tk.status else "not started",
436
- "agent": tk.agent.name if tk.agent else "No agent"
437
- }
438
- tasks_summary.append(task_info)
439
- logging.info(f"Task {tid} status: {task_info}")
440
-
441
- manager_prompt = f"""
442
- Here is the current status of all tasks except yours (manager_task):
443
- {tasks_summary}
444
-
445
- Provide a JSON with the structure:
446
- {{
447
- "task_id": <int>,
448
- "agent_name": "<string>",
449
- "action": "<execute or stop>"
450
- }}
451
- """
452
-
453
- try:
454
- logging.info("Requesting manager instructions...")
455
- manager_response = client.beta.chat.completions.parse(
456
- model=self.manager_llm,
457
- messages=[
458
- {"role": "system", "content": manager_task.description},
459
- {"role": "user", "content": manager_prompt}
460
- ],
461
- temperature=0.7,
462
- response_format=ManagerInstructions
463
- )
464
- parsed_instructions = manager_response.choices[0].message.parsed
465
- logging.info(f"Manager instructions: {parsed_instructions}")
466
- except Exception as e:
467
- display_error(f"Manager parse error: {e}")
468
- logging.error(f"Manager parse error: {str(e)}", exc_info=True)
469
- break
470
-
471
- selected_task_id = parsed_instructions.task_id
472
- selected_agent_name = parsed_instructions.agent_name
473
- action = parsed_instructions.action
474
-
475
- logging.info(f"Manager selected task_id={selected_task_id}, agent={selected_agent_name}, action={action}")
476
-
477
- if action.lower() == "stop":
478
- logging.info("Manager decided to stop task execution")
479
- break
480
-
481
- if selected_task_id not in self.tasks:
482
- error_msg = f"Manager selected invalid task id {selected_task_id}"
483
- display_error(error_msg)
484
- logging.error(error_msg)
485
- break
486
-
487
- original_agent = self.tasks[selected_task_id].agent.name if self.tasks[selected_task_id].agent else "None"
488
- for a in self.agents:
489
- if a.name == selected_agent_name:
490
- self.tasks[selected_task_id].agent = a
491
- logging.info(f"Changed agent for task {selected_task_id} from {original_agent} to {selected_agent_name}")
492
- break
493
-
494
- if self.tasks[selected_task_id].status != "completed":
495
- logging.info(f"Starting execution of task {selected_task_id}")
496
- self.run_task(selected_task_id)
497
- logging.info(f"Finished execution of task {selected_task_id}, status: {self.tasks[selected_task_id].status}")
498
-
499
- if self.tasks[selected_task_id].status == "completed":
500
- completed_count += 1
501
- logging.info(f"Task {selected_task_id} completed. Total completed: {completed_count}/{total_tasks}")
502
-
503
- self.tasks[manager_task.id].status = "completed"
504
- if self.verbose >= 1:
505
- logging.info("All tasks completed under manager supervision.")
506
- logging.info("Hierarchical task execution finished")
271
+ for task_id in process.hierarchical():
272
+ if isinstance(task_id, Task):
273
+ task_id = self.add_task(task_id)
274
+ self.run_task(task_id)
507
275
 
508
276
  def get_task_status(self, task_id):
509
277
  if task_id in self.tasks:
@@ -0,0 +1,3 @@
1
+ from .process import Process
2
+
3
+ __all__ = ['Process']
@@ -0,0 +1,263 @@
1
+ import logging
2
+ from typing import Dict, Optional, List, Any
3
+ from pydantic import BaseModel
4
+ from ..agent.agent import Agent
5
+ from ..task.task import Task
6
+ from ..main import display_error, client
7
+
8
+ class LoopItems(BaseModel):
9
+ items: List[Any]
10
+
11
+ class Process:
12
+ def __init__(self, tasks: Dict[str, Task], agents: List[Agent], manager_llm: Optional[str] = None, verbose: bool = False):
13
+ self.tasks = tasks
14
+ self.agents = agents
15
+ self.manager_llm = manager_llm
16
+ self.verbose = verbose
17
+
18
+ def workflow(self):
19
+ # Build workflow relationships first
20
+ for task in self.tasks.values():
21
+ if task.next_tasks:
22
+ for next_task_name in task.next_tasks:
23
+ next_task = next((t for t in self.tasks.values() if t.name == next_task_name), None)
24
+ if next_task:
25
+ next_task.previous_tasks.append(task.name)
26
+
27
+ # Find start task
28
+ start_task = None
29
+ for task_id, task in self.tasks.items():
30
+ if task.is_start:
31
+ start_task = task
32
+ break
33
+
34
+ if not start_task:
35
+ start_task = list(self.tasks.values())[0]
36
+ logging.info("No start task marked, using first task")
37
+
38
+ current_task = start_task
39
+ visited_tasks = set()
40
+ loop_data = {} # Store loop-specific data
41
+
42
+ while current_task and current_task.id not in visited_tasks:
43
+ task_id = current_task.id
44
+ logging.info(f"Executing workflow task: {current_task.name if current_task.name else task_id}")
45
+
46
+ # Add context from previous tasks to description
47
+ if current_task.previous_tasks or current_task.context:
48
+ context = "\nInput data from previous tasks:"
49
+
50
+ # Add data from previous tasks in workflow
51
+ for prev_name in current_task.previous_tasks:
52
+ prev_task = next((t for t in self.tasks.values() if t.name == prev_name), None)
53
+ if prev_task and prev_task.result:
54
+ # Handle loop data
55
+ if current_task.task_type == "loop":
56
+ # create a loop manager Agent
57
+ loop_manager = Agent(
58
+ name="Loop Manager",
59
+ role="Loop data processor",
60
+ goal="Process loop data and convert it to list format",
61
+ backstory="Expert at handling loop data and converting it to proper format",
62
+ llm=self.manager_llm,
63
+ verbose=self.verbose,
64
+ markdown=True
65
+ )
66
+
67
+ # get the loop data convert it to list using calling Agent class chat
68
+ loop_prompt = f"""
69
+ Process this data into a list format:
70
+ {prev_task.result.raw}
71
+
72
+ Return a JSON object with an 'items' array containing the items to process.
73
+ """
74
+ loop_data_str = loop_manager.chat(
75
+ prompt=loop_prompt,
76
+ output_json=LoopItems
77
+ )
78
+
79
+ try:
80
+ # The response will already be parsed into LoopItems model
81
+ loop_data[f"loop_{current_task.name}"] = {
82
+ "items": loop_data_str.items,
83
+ "index": 0,
84
+ "remaining": len(loop_data_str.items)
85
+ }
86
+ context += f"\nCurrent loop item: {loop_data_str.items[0]}"
87
+ except Exception as e:
88
+ display_error(f"Failed to process loop data: {e}")
89
+ context += f"\n{prev_name}: {prev_task.result.raw}"
90
+ else:
91
+ context += f"\n{prev_name}: {prev_task.result.raw}"
92
+
93
+ # Add data from context tasks
94
+ if current_task.context:
95
+ for ctx_task in current_task.context:
96
+ if ctx_task.result and ctx_task.name != current_task.name:
97
+ context += f"\n{ctx_task.name}: {ctx_task.result.raw}"
98
+
99
+ # Update task description with context
100
+ current_task.description = current_task.description + context
101
+
102
+ # Execute task using existing run_task method
103
+ yield task_id
104
+ visited_tasks.add(task_id)
105
+
106
+ # Handle loop progression
107
+ if current_task.task_type == "loop":
108
+ loop_key = f"loop_{current_task.name}"
109
+ if loop_key in loop_data:
110
+ loop_info = loop_data[loop_key]
111
+ loop_info["index"] += 1
112
+ has_more = loop_info["remaining"] > 0
113
+
114
+ # Update result to trigger correct condition
115
+ if current_task.result:
116
+ result = current_task.result.raw
117
+ if has_more:
118
+ result += "\nmore"
119
+ else:
120
+ result += "\ndone"
121
+ current_task.result.raw = result
122
+
123
+ # Determine next task based on result
124
+ next_task = None
125
+ if current_task.result:
126
+ if current_task.task_type in ["decision", "loop"]:
127
+ result = current_task.result.raw.lower()
128
+ # Check conditions
129
+ for condition, tasks in current_task.condition.items():
130
+ if condition.lower() in result and tasks:
131
+ next_task_name = tasks[0]
132
+ next_task = next((t for t in self.tasks.values() if t.name == next_task_name), None)
133
+ # For loops, allow revisiting the same task
134
+ if next_task and next_task.id == current_task.id:
135
+ visited_tasks.discard(current_task.id)
136
+ break
137
+
138
+ if not next_task and current_task.next_tasks:
139
+ next_task_name = current_task.next_tasks[0]
140
+ next_task = next((t for t in self.tasks.values() if t.name == next_task_name), None)
141
+
142
+ current_task = next_task
143
+ if not current_task:
144
+ logging.info("Workflow execution completed")
145
+ break
146
+
147
+ def sequential(self):
148
+ for task_id in self.tasks:
149
+ if self.tasks[task_id].status != "completed":
150
+ yield task_id
151
+
152
+ def hierarchical(self):
153
+ logging.debug(f"Starting hierarchical task execution with {len(self.tasks)} tasks")
154
+ manager_agent = Agent(
155
+ name="Manager",
156
+ role="Project manager",
157
+ goal="Manage the entire flow of tasks and delegate them to the right agent",
158
+ backstory="Expert project manager to coordinate tasks among agents",
159
+ llm=self.manager_llm,
160
+ verbose=self.verbose,
161
+ markdown=True,
162
+ self_reflect=False
163
+ )
164
+
165
+ class ManagerInstructions(BaseModel):
166
+ task_id: int
167
+ agent_name: str
168
+ action: str
169
+
170
+ manager_task = Task(
171
+ name="manager_task",
172
+ description="Decide the order of tasks and which agent executes them",
173
+ expected_output="All tasks completed successfully",
174
+ agent=manager_agent
175
+ )
176
+ manager_task_id = yield manager_task
177
+ logging.info(f"Created manager task with ID {manager_task_id}")
178
+
179
+ completed_count = 0
180
+ total_tasks = len(self.tasks) - 1
181
+ logging.info(f"Need to complete {total_tasks} tasks (excluding manager task)")
182
+
183
+ while completed_count < total_tasks:
184
+ tasks_summary = []
185
+ for tid, tk in self.tasks.items():
186
+ if tk.name == "manager_task":
187
+ continue
188
+ task_info = {
189
+ "task_id": tid,
190
+ "name": tk.name,
191
+ "description": tk.description,
192
+ "status": tk.status if tk.status else "not started",
193
+ "agent": tk.agent.name if tk.agent else "No agent"
194
+ }
195
+ tasks_summary.append(task_info)
196
+ logging.info(f"Task {tid} status: {task_info}")
197
+
198
+ manager_prompt = f"""
199
+ Here is the current status of all tasks except yours (manager_task):
200
+ {tasks_summary}
201
+
202
+ Provide a JSON with the structure:
203
+ {{
204
+ "task_id": <int>,
205
+ "agent_name": "<string>",
206
+ "action": "<execute or stop>"
207
+ }}
208
+ """
209
+
210
+ try:
211
+ logging.info("Requesting manager instructions...")
212
+ manager_response = client.beta.chat.completions.parse(
213
+ model=self.manager_llm,
214
+ messages=[
215
+ {"role": "system", "content": manager_task.description},
216
+ {"role": "user", "content": manager_prompt}
217
+ ],
218
+ temperature=0.7,
219
+ response_format=ManagerInstructions
220
+ )
221
+ parsed_instructions = manager_response.choices[0].message.parsed
222
+ logging.info(f"Manager instructions: {parsed_instructions}")
223
+ except Exception as e:
224
+ display_error(f"Manager parse error: {e}")
225
+ logging.error(f"Manager parse error: {str(e)}", exc_info=True)
226
+ break
227
+
228
+ selected_task_id = parsed_instructions.task_id
229
+ selected_agent_name = parsed_instructions.agent_name
230
+ action = parsed_instructions.action
231
+
232
+ logging.info(f"Manager selected task_id={selected_task_id}, agent={selected_agent_name}, action={action}")
233
+
234
+ if action.lower() == "stop":
235
+ logging.info("Manager decided to stop task execution")
236
+ break
237
+
238
+ if selected_task_id not in self.tasks:
239
+ error_msg = f"Manager selected invalid task id {selected_task_id}"
240
+ display_error(error_msg)
241
+ logging.error(error_msg)
242
+ break
243
+
244
+ original_agent = self.tasks[selected_task_id].agent.name if self.tasks[selected_task_id].agent else "None"
245
+ for a in self.agents:
246
+ if a.name == selected_agent_name:
247
+ self.tasks[selected_task_id].agent = a
248
+ logging.info(f"Changed agent for task {selected_task_id} from {original_agent} to {selected_agent_name}")
249
+ break
250
+
251
+ if self.tasks[selected_task_id].status != "completed":
252
+ logging.info(f"Starting execution of task {selected_task_id}")
253
+ yield selected_task_id
254
+ logging.info(f"Finished execution of task {selected_task_id}, status: {self.tasks[selected_task_id].status}")
255
+
256
+ if self.tasks[selected_task_id].status == "completed":
257
+ completed_count += 1
258
+ logging.info(f"Task {selected_task_id} completed. Total completed: {completed_count}/{total_tasks}")
259
+
260
+ self.tasks[manager_task.id].status = "completed"
261
+ if self.verbose >= 1:
262
+ logging.info("All tasks completed under manager supervision.")
263
+ logging.info("Hierarchical task execution finished")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: praisonaiagents
3
- Version: 0.0.14
3
+ Version: 0.0.16
4
4
  Summary: Praison AI agents for completing complex tasks with Self Reflection Agents
5
5
  Author: Mervin Praison
6
6
  Requires-Dist: pydantic
@@ -3,7 +3,7 @@ praisonaiagents/main.py,sha256=K2OxVKPmo4dNJbSWIsXDi_hm9CRx5O4km_74UGcszhk,5744
3
3
  praisonaiagents/agent/__init__.py,sha256=sKO8wGEXvtCrvV1e834r1Okv0XAqAxqZCqz6hKLiTvA,79
4
4
  praisonaiagents/agent/agent.py,sha256=zTYcDpJ5DzzBnefwLvhrtBlGQoRI4ZZAioDu5nKTPSs,24042
5
5
  praisonaiagents/agents/__init__.py,sha256=7RDeQNSqZg5uBjD4M_0p_F6YgfWuDuxPFydPU50kDYc,120
6
- praisonaiagents/agents/agents.py,sha256=ITvH8Yq_OzhyMC_Aid4qlqQbEM9cCfp7SayXg0ASJ5k,24526
6
+ praisonaiagents/agents/agents.py,sha256=-1Z-jIN2fkLM9P6nAq-OtKPTF8HIjA-a_Zznv8TfpFY,12964
7
7
  praisonaiagents/build/lib/praisonaiagents/__init__.py,sha256=Nqnn8clbgv-5l0PgxcTOldg8mkMKrFn4TvPL-rYUUGg,1
8
8
  praisonaiagents/build/lib/praisonaiagents/main.py,sha256=zDhN5KKtKbfruolDNxlyJkcFlkSt4KQkQTDRfQVAhxc,3960
9
9
  praisonaiagents/build/lib/praisonaiagents/agent/__init__.py,sha256=sKO8wGEXvtCrvV1e834r1Okv0XAqAxqZCqz6hKLiTvA,79
@@ -12,9 +12,11 @@ praisonaiagents/build/lib/praisonaiagents/agents/__init__.py,sha256=cgCLFLFcLp9S
12
12
  praisonaiagents/build/lib/praisonaiagents/agents/agents.py,sha256=P2FAtlfD3kPib5a1oLVYanxlU6e4-GhBMQ0YDY5MHY4,13473
13
13
  praisonaiagents/build/lib/praisonaiagents/task/__init__.py,sha256=VL5hXVmyGjINb34AalxpBMl-YW9m5EDcRkMTKkSSl7c,80
14
14
  praisonaiagents/build/lib/praisonaiagents/task/task.py,sha256=4Y1qX8OeEFcid2yhAiPYylvHpuDmWORsyNL16_BiVvI,1831
15
+ praisonaiagents/process/__init__.py,sha256=lkYbL7Hn5a0ldvJtkdH23vfIIZLIcanK-65C0MwaorY,52
16
+ praisonaiagents/process/process.py,sha256=HN_xNeG02T5QwcvcuSw8OiABVYbKIYJ-J--3H8Hd89Q,11722
15
17
  praisonaiagents/task/__init__.py,sha256=VL5hXVmyGjINb34AalxpBMl-YW9m5EDcRkMTKkSSl7c,80
16
18
  praisonaiagents/task/task.py,sha256=oMC5Zz1dMj0Ceice69aBS1KQQXMLqphc8wNOQ9zcu0Q,2570
17
- praisonaiagents-0.0.14.dist-info/METADATA,sha256=-pdlX7m7Sr2IovIrRt9QyBfkiwgK81rEd3_VklcmHNs,233
18
- praisonaiagents-0.0.14.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
19
- praisonaiagents-0.0.14.dist-info/top_level.txt,sha256=_HsRddrJ23iDx5TTqVUVvXG2HeHBL5voshncAMDGjtA,16
20
- praisonaiagents-0.0.14.dist-info/RECORD,,
19
+ praisonaiagents-0.0.16.dist-info/METADATA,sha256=Nb_ZUqzMHYl2CzLFiDFAclzAAx4G0LWN6IWADmYu0LY,233
20
+ praisonaiagents-0.0.16.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
21
+ praisonaiagents-0.0.16.dist-info/top_level.txt,sha256=_HsRddrJ23iDx5TTqVUVvXG2HeHBL5voshncAMDGjtA,16
22
+ praisonaiagents-0.0.16.dist-info/RECORD,,