praisonaiagents 0.0.2__py3-none-any.whl → 0.0.4__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.
- {agents → praisonaiagents}/__init__.py +2 -2
 - praisonaiagents/agents/__init__.py +4 -0
 - praisonaiagents/agents/agents.py +318 -0
 - praisonaiagents/build/lib/praisonaiagents/__init__.py +1 -0
 - praisonaiagents/build/lib/praisonaiagents/agent/__init__.py +4 -0
 - praisonaiagents/build/lib/praisonaiagents/agent/agent.py +350 -0
 - praisonaiagents/main.py +112 -0
 - praisonaiagents/task/__init__.py +4 -0
 - praisonaiagents/task/task.py +48 -0
 - {praisonaiagents-0.0.2.dist-info → praisonaiagents-0.0.4.dist-info}/METADATA +2 -2
 - praisonaiagents-0.0.4.dist-info/RECORD +20 -0
 - praisonaiagents-0.0.4.dist-info/top_level.txt +1 -0
 - praisonaiagents-0.0.2.dist-info/RECORD +0 -12
 - praisonaiagents-0.0.2.dist-info/top_level.txt +0 -1
 - {agents → praisonaiagents}/agent/__init__.py +0 -0
 - {agents → praisonaiagents}/agent/agent.py +0 -0
 - {agents → praisonaiagents/build/lib/praisonaiagents}/agents/__init__.py +0 -0
 - {agents → praisonaiagents/build/lib/praisonaiagents}/agents/agents.py +0 -0
 - {agents → praisonaiagents/build/lib/praisonaiagents}/main.py +0 -0
 - {agents → praisonaiagents/build/lib/praisonaiagents}/task/__init__.py +0 -0
 - {agents → praisonaiagents/build/lib/praisonaiagents}/task/task.py +0 -0
 - {praisonaiagents-0.0.2.dist-info → praisonaiagents-0.0.4.dist-info}/WHEEL +0 -0
 
| 
         @@ -3,7 +3,7 @@ Praison AI Agents - A package for hierarchical AI agent task execution 
     | 
|
| 
       3 
3 
     | 
    
         
             
            """
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            from .agent.agent import Agent
         
     | 
| 
       6 
     | 
    
         
            -
            from .agents.agents import  
     | 
| 
      
 6 
     | 
    
         
            +
            from .agents.agents import PraisonAIAgents
         
     | 
| 
       7 
7 
     | 
    
         
             
            from .task.task import Task
         
     | 
| 
       8 
8 
     | 
    
         
             
            from .main import (
         
     | 
| 
       9 
9 
     | 
    
         
             
                TaskOutput,
         
     | 
| 
         @@ -20,7 +20,7 @@ from .main import ( 
     | 
|
| 
       20 
20 
     | 
    
         | 
| 
       21 
21 
     | 
    
         
             
            __all__ = [
         
     | 
| 
       22 
22 
     | 
    
         
             
                'Agent',
         
     | 
| 
       23 
     | 
    
         
            -
                ' 
     | 
| 
      
 23 
     | 
    
         
            +
                'PraisonAIAgents',
         
     | 
| 
       24 
24 
     | 
    
         
             
                'Task',
         
     | 
| 
       25 
25 
     | 
    
         
             
                'TaskOutput',
         
     | 
| 
       26 
26 
     | 
    
         
             
                'ReflectionOutput',
         
     | 
| 
         @@ -0,0 +1,318 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            import os
         
     | 
| 
      
 2 
     | 
    
         
            +
            import time
         
     | 
| 
      
 3 
     | 
    
         
            +
            import json
         
     | 
| 
      
 4 
     | 
    
         
            +
            import logging
         
     | 
| 
      
 5 
     | 
    
         
            +
            from typing import Any, Dict, Optional
         
     | 
| 
      
 6 
     | 
    
         
            +
            from pydantic import BaseModel
         
     | 
| 
      
 7 
     | 
    
         
            +
            from rich.text import Text
         
     | 
| 
      
 8 
     | 
    
         
            +
            from rich.panel import Panel
         
     | 
| 
      
 9 
     | 
    
         
            +
            from rich.console import Console
         
     | 
| 
      
 10 
     | 
    
         
            +
            from ..main import display_error, TaskOutput, error_logs, client
         
     | 
| 
      
 11 
     | 
    
         
            +
            from ..agent.agent import Agent
         
     | 
| 
      
 12 
     | 
    
         
            +
            from ..task.task import Task
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            class PraisonAIAgents:
         
     | 
| 
      
 15 
     | 
    
         
            +
                def __init__(self, agents, tasks, verbose=0, completion_checker=None, max_retries=5, process="sequential", manager_llm=None):
         
     | 
| 
      
 16 
     | 
    
         
            +
                    self.agents = agents
         
     | 
| 
      
 17 
     | 
    
         
            +
                    self.tasks = {}
         
     | 
| 
      
 18 
     | 
    
         
            +
                    if max_retries < 3:
         
     | 
| 
      
 19 
     | 
    
         
            +
                        max_retries = 3
         
     | 
| 
      
 20 
     | 
    
         
            +
                    self.completion_checker = completion_checker if completion_checker else self.default_completion_checker
         
     | 
| 
      
 21 
     | 
    
         
            +
                    self.task_id_counter = 0
         
     | 
| 
      
 22 
     | 
    
         
            +
                    self.verbose = verbose
         
     | 
| 
      
 23 
     | 
    
         
            +
                    self.max_retries = max_retries
         
     | 
| 
      
 24 
     | 
    
         
            +
                    self.process = process
         
     | 
| 
      
 25 
     | 
    
         
            +
                    self.manager_llm = manager_llm
         
     | 
| 
      
 26 
     | 
    
         
            +
                    for task in tasks:
         
     | 
| 
      
 27 
     | 
    
         
            +
                        self.add_task(task)
         
     | 
| 
      
 28 
     | 
    
         
            +
                        task.status = "not started"
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                def add_task(self, task):
         
     | 
| 
      
 31 
     | 
    
         
            +
                    task_id = self.task_id_counter
         
     | 
| 
      
 32 
     | 
    
         
            +
                    task.id = task_id
         
     | 
| 
      
 33 
     | 
    
         
            +
                    self.tasks[task_id] = task
         
     | 
| 
      
 34 
     | 
    
         
            +
                    self.task_id_counter += 1
         
     | 
| 
      
 35 
     | 
    
         
            +
                    return task_id
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                def clean_json_output(self, output: str) -> str:
         
     | 
| 
      
 38 
     | 
    
         
            +
                    cleaned = output.strip()
         
     | 
| 
      
 39 
     | 
    
         
            +
                    if cleaned.startswith("```json"):
         
     | 
| 
      
 40 
     | 
    
         
            +
                        cleaned = cleaned[len("```json"):].strip()
         
     | 
| 
      
 41 
     | 
    
         
            +
                    if cleaned.startswith("```"):
         
     | 
| 
      
 42 
     | 
    
         
            +
                        cleaned = cleaned[len("```"):].strip()
         
     | 
| 
      
 43 
     | 
    
         
            +
                    if cleaned.endswith("```"):
         
     | 
| 
      
 44 
     | 
    
         
            +
                        cleaned = cleaned[:-3].strip()
         
     | 
| 
      
 45 
     | 
    
         
            +
                    return cleaned
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                def default_completion_checker(self, task, agent_output):
         
     | 
| 
      
 48 
     | 
    
         
            +
                    if task.output_json and task.result and task.result.json_dict:
         
     | 
| 
      
 49 
     | 
    
         
            +
                        return True
         
     | 
| 
      
 50 
     | 
    
         
            +
                    if task.output_pydantic and task.result and task.result.pydantic:
         
     | 
| 
      
 51 
     | 
    
         
            +
                        return True
         
     | 
| 
      
 52 
     | 
    
         
            +
                    return len(agent_output.strip()) > 0
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                def execute_task(self, task_id):
         
     | 
| 
      
 55 
     | 
    
         
            +
                    if task_id not in self.tasks:
         
     | 
| 
      
 56 
     | 
    
         
            +
                        display_error(f"Error: Task with ID {task_id} does not exist")
         
     | 
| 
      
 57 
     | 
    
         
            +
                        return
         
     | 
| 
      
 58 
     | 
    
         
            +
                    task = self.tasks[task_id]
         
     | 
| 
      
 59 
     | 
    
         
            +
                    if task.status == "not started":
         
     | 
| 
      
 60 
     | 
    
         
            +
                        task.status = "in progress"
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                    executor_agent = task.agent
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                    task_prompt = f"""
         
     | 
| 
      
 65 
     | 
    
         
            +
                    You need to do the following task: {task.description}.
         
     | 
| 
      
 66 
     | 
    
         
            +
                    Expected Output: {task.expected_output}.
         
     | 
| 
      
 67 
     | 
    
         
            +
                    """
         
     | 
| 
      
 68 
     | 
    
         
            +
                    if task.context:
         
     | 
| 
      
 69 
     | 
    
         
            +
                        context_results = ""
         
     | 
| 
      
 70 
     | 
    
         
            +
                        for context_task in task.context:
         
     | 
| 
      
 71 
     | 
    
         
            +
                            if context_task.result:
         
     | 
| 
      
 72 
     | 
    
         
            +
                                context_results += f"Result of previous task {context_task.name if context_task.name else context_task.description}: {context_task.result.raw}\n"
         
     | 
| 
      
 73 
     | 
    
         
            +
                            else:
         
     | 
| 
      
 74 
     | 
    
         
            +
                                context_results += f"Previous task {context_task.name if context_task.name else context_task.description} had no result.\n"
         
     | 
| 
      
 75 
     | 
    
         
            +
                        task_prompt += f"""
         
     | 
| 
      
 76 
     | 
    
         
            +
                        Here are the results of previous tasks that might be useful:\n
         
     | 
| 
      
 77 
     | 
    
         
            +
                        {context_results}
         
     | 
| 
      
 78 
     | 
    
         
            +
                        """
         
     | 
| 
      
 79 
     | 
    
         
            +
                    task_prompt += "Please provide only the final result of your work. Do not add any conversation or extra explanation."
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                    if self.verbose >= 2:
         
     | 
| 
      
 82 
     | 
    
         
            +
                        logging.info(f"Executing task {task_id}: {task.description} using {executor_agent.name}")
         
     | 
| 
      
 83 
     | 
    
         
            +
                    logging.debug(f"Starting execution of task {task_id} with prompt:\n{task_prompt}")
         
     | 
| 
      
 84 
     | 
    
         
            +
                    agent_output = executor_agent.chat(task_prompt, tools=task.tools)
         
     | 
| 
      
 85 
     | 
    
         
            +
                    if agent_output:
         
     | 
| 
      
 86 
     | 
    
         
            +
                        task_output = TaskOutput(
         
     | 
| 
      
 87 
     | 
    
         
            +
                            description=task.description,
         
     | 
| 
      
 88 
     | 
    
         
            +
                            summary=task.description[:10],
         
     | 
| 
      
 89 
     | 
    
         
            +
                            raw=agent_output,
         
     | 
| 
      
 90 
     | 
    
         
            +
                            agent=executor_agent.name,
         
     | 
| 
      
 91 
     | 
    
         
            +
                            output_format="RAW"
         
     | 
| 
      
 92 
     | 
    
         
            +
                        )
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                        if task.output_json:
         
     | 
| 
      
 95 
     | 
    
         
            +
                            cleaned = self.clean_json_output(agent_output)
         
     | 
| 
      
 96 
     | 
    
         
            +
                            try:
         
     | 
| 
      
 97 
     | 
    
         
            +
                                parsed = json.loads(cleaned)
         
     | 
| 
      
 98 
     | 
    
         
            +
                                task_output.json_dict = parsed
         
     | 
| 
      
 99 
     | 
    
         
            +
                                task_output.output_format = "JSON"
         
     | 
| 
      
 100 
     | 
    
         
            +
                            except:
         
     | 
| 
      
 101 
     | 
    
         
            +
                                logging.warning(f"Warning: Could not parse output of task {task_id} as JSON")
         
     | 
| 
      
 102 
     | 
    
         
            +
                                logging.debug(f"Output that failed JSON parsing: {agent_output}")
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
                        if task.output_pydantic:
         
     | 
| 
      
 105 
     | 
    
         
            +
                            cleaned = self.clean_json_output(agent_output)
         
     | 
| 
      
 106 
     | 
    
         
            +
                            try:
         
     | 
| 
      
 107 
     | 
    
         
            +
                                parsed = json.loads(cleaned)
         
     | 
| 
      
 108 
     | 
    
         
            +
                                pyd_obj = task.output_pydantic(**parsed)
         
     | 
| 
      
 109 
     | 
    
         
            +
                                task_output.pydantic = pyd_obj
         
     | 
| 
      
 110 
     | 
    
         
            +
                                task_output.output_format = "Pydantic"
         
     | 
| 
      
 111 
     | 
    
         
            +
                            except:
         
     | 
| 
      
 112 
     | 
    
         
            +
                                logging.warning(f"Warning: Could not parse output of task {task_id} as Pydantic Model")
         
     | 
| 
      
 113 
     | 
    
         
            +
                                logging.debug(f"Output that failed Pydantic parsing: {agent_output}")
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
                        task.result = task_output
         
     | 
| 
      
 116 
     | 
    
         
            +
                        return task_output
         
     | 
| 
      
 117 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 118 
     | 
    
         
            +
                        task.status = "failed"
         
     | 
| 
      
 119 
     | 
    
         
            +
                        return None
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
                def save_output_to_file(self, task, task_output):
         
     | 
| 
      
 122 
     | 
    
         
            +
                    if task.output_file:
         
     | 
| 
      
 123 
     | 
    
         
            +
                        try:
         
     | 
| 
      
 124 
     | 
    
         
            +
                            if task.create_directory:
         
     | 
| 
      
 125 
     | 
    
         
            +
                                os.makedirs(os.path.dirname(task.output_file), exist_ok=True)
         
     | 
| 
      
 126 
     | 
    
         
            +
                            with open(task.output_file, "w") as f:
         
     | 
| 
      
 127 
     | 
    
         
            +
                                f.write(str(task_output))
         
     | 
| 
      
 128 
     | 
    
         
            +
                            if self.verbose >= 1:
         
     | 
| 
      
 129 
     | 
    
         
            +
                                logging.info(f"Task output saved to {task.output_file}")
         
     | 
| 
      
 130 
     | 
    
         
            +
                        except Exception as e:
         
     | 
| 
      
 131 
     | 
    
         
            +
                            display_error(f"Error saving task output to file: {e}")
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
                def run_task(self, task_id):
         
     | 
| 
      
 134 
     | 
    
         
            +
                    if task_id not in self.tasks:
         
     | 
| 
      
 135 
     | 
    
         
            +
                        display_error(f"Error: Task with ID {task_id} does not exist")
         
     | 
| 
      
 136 
     | 
    
         
            +
                        return
         
     | 
| 
      
 137 
     | 
    
         
            +
                    task = self.tasks[task_id]
         
     | 
| 
      
 138 
     | 
    
         
            +
                    if task.status == "completed":
         
     | 
| 
      
 139 
     | 
    
         
            +
                        logging.info(f"Task with ID {task_id} is already completed")
         
     | 
| 
      
 140 
     | 
    
         
            +
                        return
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
                    retries = 0
         
     | 
| 
      
 143 
     | 
    
         
            +
                    while task.status != "completed" and retries < self.max_retries:
         
     | 
| 
      
 144 
     | 
    
         
            +
                        logging.debug(f"Attempt {retries+1} for task {task_id}")
         
     | 
| 
      
 145 
     | 
    
         
            +
                        if task.status in ["not started", "in progress"]:
         
     | 
| 
      
 146 
     | 
    
         
            +
                            task_output = self.execute_task(task_id)
         
     | 
| 
      
 147 
     | 
    
         
            +
                            if task_output and self.completion_checker(task, task_output.raw):
         
     | 
| 
      
 148 
     | 
    
         
            +
                                task.status = "completed"
         
     | 
| 
      
 149 
     | 
    
         
            +
                                if task.callback:
         
     | 
| 
      
 150 
     | 
    
         
            +
                                    task.callback(task_output)
         
     | 
| 
      
 151 
     | 
    
         
            +
                                self.save_output_to_file(task, task_output)
         
     | 
| 
      
 152 
     | 
    
         
            +
                                if self.verbose >= 1:
         
     | 
| 
      
 153 
     | 
    
         
            +
                                    logging.info(f"Task {task_id} completed successfully.")
         
     | 
| 
      
 154 
     | 
    
         
            +
                            else:
         
     | 
| 
      
 155 
     | 
    
         
            +
                                task.status = "in progress"
         
     | 
| 
      
 156 
     | 
    
         
            +
                                if self.verbose >= 1:
         
     | 
| 
      
 157 
     | 
    
         
            +
                                    logging.info(f"Task {task_id} not completed, retrying")
         
     | 
| 
      
 158 
     | 
    
         
            +
                                time.sleep(1)
         
     | 
| 
      
 159 
     | 
    
         
            +
                                retries += 1
         
     | 
| 
      
 160 
     | 
    
         
            +
                        else:
         
     | 
| 
      
 161 
     | 
    
         
            +
                            if task.status == "failed":
         
     | 
| 
      
 162 
     | 
    
         
            +
                                logging.info("Task is failed, resetting to in-progress for another try...")
         
     | 
| 
      
 163 
     | 
    
         
            +
                                task.status = "in progress"
         
     | 
| 
      
 164 
     | 
    
         
            +
                            else:
         
     | 
| 
      
 165 
     | 
    
         
            +
                                logging.info("Invalid Task status")
         
     | 
| 
      
 166 
     | 
    
         
            +
                                break
         
     | 
| 
      
 167 
     | 
    
         
            +
             
     | 
| 
      
 168 
     | 
    
         
            +
                    if retries == self.max_retries and task.status != "completed":
         
     | 
| 
      
 169 
     | 
    
         
            +
                        logging.info(f"Task {task_id} failed after {self.max_retries} retries.")
         
     | 
| 
      
 170 
     | 
    
         
            +
             
     | 
| 
      
 171 
     | 
    
         
            +
                def run_all_tasks(self):
         
     | 
| 
      
 172 
     | 
    
         
            +
                    if self.process == "sequential":
         
     | 
| 
      
 173 
     | 
    
         
            +
                        for task_id in self.tasks:
         
     | 
| 
      
 174 
     | 
    
         
            +
                            if self.tasks[task_id].status != "completed":
         
     | 
| 
      
 175 
     | 
    
         
            +
                                self.run_task(task_id)
         
     | 
| 
      
 176 
     | 
    
         
            +
                    elif self.process == "hierarchical":
         
     | 
| 
      
 177 
     | 
    
         
            +
                        logging.debug(f"Starting hierarchical task execution with {len(self.tasks)} tasks")
         
     | 
| 
      
 178 
     | 
    
         
            +
                        manager_agent = Agent(
         
     | 
| 
      
 179 
     | 
    
         
            +
                            name="Manager",
         
     | 
| 
      
 180 
     | 
    
         
            +
                            role="Project manager",
         
     | 
| 
      
 181 
     | 
    
         
            +
                            goal="Manage the entire flow of tasks and delegate them to the right agent",
         
     | 
| 
      
 182 
     | 
    
         
            +
                            backstory="Expert project manager to coordinate tasks among agents",
         
     | 
| 
      
 183 
     | 
    
         
            +
                            llm=self.manager_llm,
         
     | 
| 
      
 184 
     | 
    
         
            +
                            verbose=self.verbose,
         
     | 
| 
      
 185 
     | 
    
         
            +
                            markdown=True,
         
     | 
| 
      
 186 
     | 
    
         
            +
                            self_reflect=False
         
     | 
| 
      
 187 
     | 
    
         
            +
                        )
         
     | 
| 
      
 188 
     | 
    
         
            +
             
     | 
| 
      
 189 
     | 
    
         
            +
                        class ManagerInstructions(BaseModel):
         
     | 
| 
      
 190 
     | 
    
         
            +
                            task_id: int
         
     | 
| 
      
 191 
     | 
    
         
            +
                            agent_name: str
         
     | 
| 
      
 192 
     | 
    
         
            +
                            action: str
         
     | 
| 
      
 193 
     | 
    
         
            +
             
     | 
| 
      
 194 
     | 
    
         
            +
                        manager_task = Task(
         
     | 
| 
      
 195 
     | 
    
         
            +
                            name="manager_task",
         
     | 
| 
      
 196 
     | 
    
         
            +
                            description="Decide the order of tasks and which agent executes them",
         
     | 
| 
      
 197 
     | 
    
         
            +
                            expected_output="All tasks completed successfully",
         
     | 
| 
      
 198 
     | 
    
         
            +
                            agent=manager_agent
         
     | 
| 
      
 199 
     | 
    
         
            +
                        )
         
     | 
| 
      
 200 
     | 
    
         
            +
                        manager_task_id = self.add_task(manager_task)
         
     | 
| 
      
 201 
     | 
    
         
            +
                        logging.info(f"Created manager task with ID {manager_task_id}")
         
     | 
| 
      
 202 
     | 
    
         
            +
             
     | 
| 
      
 203 
     | 
    
         
            +
                        completed_count = 0
         
     | 
| 
      
 204 
     | 
    
         
            +
                        total_tasks = len(self.tasks) - 1
         
     | 
| 
      
 205 
     | 
    
         
            +
                        logging.info(f"Need to complete {total_tasks} tasks (excluding manager task)")
         
     | 
| 
      
 206 
     | 
    
         
            +
             
     | 
| 
      
 207 
     | 
    
         
            +
                        while completed_count < total_tasks:
         
     | 
| 
      
 208 
     | 
    
         
            +
                            tasks_summary = []
         
     | 
| 
      
 209 
     | 
    
         
            +
                            for tid, tk in self.tasks.items():
         
     | 
| 
      
 210 
     | 
    
         
            +
                                if tk.name == "manager_task":
         
     | 
| 
      
 211 
     | 
    
         
            +
                                    continue
         
     | 
| 
      
 212 
     | 
    
         
            +
                                task_info = {
         
     | 
| 
      
 213 
     | 
    
         
            +
                                    "task_id": tid,
         
     | 
| 
      
 214 
     | 
    
         
            +
                                    "name": tk.name,
         
     | 
| 
      
 215 
     | 
    
         
            +
                                    "description": tk.description,
         
     | 
| 
      
 216 
     | 
    
         
            +
                                    "status": tk.status if tk.status else "not started",
         
     | 
| 
      
 217 
     | 
    
         
            +
                                    "agent": tk.agent.name if tk.agent else "No agent"
         
     | 
| 
      
 218 
     | 
    
         
            +
                                }
         
     | 
| 
      
 219 
     | 
    
         
            +
                                tasks_summary.append(task_info)
         
     | 
| 
      
 220 
     | 
    
         
            +
                                logging.info(f"Task {tid} status: {task_info}")
         
     | 
| 
      
 221 
     | 
    
         
            +
             
     | 
| 
      
 222 
     | 
    
         
            +
                            manager_prompt = f"""
         
     | 
| 
      
 223 
     | 
    
         
            +
            Here is the current status of all tasks except yours (manager_task):
         
     | 
| 
      
 224 
     | 
    
         
            +
            {tasks_summary}
         
     | 
| 
      
 225 
     | 
    
         
            +
             
     | 
| 
      
 226 
     | 
    
         
            +
            Provide a JSON with the structure:
         
     | 
| 
      
 227 
     | 
    
         
            +
            {{
         
     | 
| 
      
 228 
     | 
    
         
            +
               "task_id": <int>,
         
     | 
| 
      
 229 
     | 
    
         
            +
               "agent_name": "<string>",
         
     | 
| 
      
 230 
     | 
    
         
            +
               "action": "<execute or stop>"
         
     | 
| 
      
 231 
     | 
    
         
            +
            }}
         
     | 
| 
      
 232 
     | 
    
         
            +
            """
         
     | 
| 
      
 233 
     | 
    
         
            +
             
     | 
| 
      
 234 
     | 
    
         
            +
                            try:
         
     | 
| 
      
 235 
     | 
    
         
            +
                                logging.info("Requesting manager instructions...")
         
     | 
| 
      
 236 
     | 
    
         
            +
                                manager_response = client.beta.chat.completions.parse(
         
     | 
| 
      
 237 
     | 
    
         
            +
                                    model=self.manager_llm,
         
     | 
| 
      
 238 
     | 
    
         
            +
                                    messages=[
         
     | 
| 
      
 239 
     | 
    
         
            +
                                        {"role": "system", "content": manager_task.description},
         
     | 
| 
      
 240 
     | 
    
         
            +
                                        {"role": "user", "content": manager_prompt}
         
     | 
| 
      
 241 
     | 
    
         
            +
                                    ],
         
     | 
| 
      
 242 
     | 
    
         
            +
                                    temperature=0.7,
         
     | 
| 
      
 243 
     | 
    
         
            +
                                    response_format=ManagerInstructions
         
     | 
| 
      
 244 
     | 
    
         
            +
                                )
         
     | 
| 
      
 245 
     | 
    
         
            +
                                parsed_instructions = manager_response.choices[0].message.parsed
         
     | 
| 
      
 246 
     | 
    
         
            +
                                logging.info(f"Manager instructions: {parsed_instructions}")
         
     | 
| 
      
 247 
     | 
    
         
            +
                            except Exception as e:
         
     | 
| 
      
 248 
     | 
    
         
            +
                                display_error(f"Manager parse error: {e}")
         
     | 
| 
      
 249 
     | 
    
         
            +
                                logging.error(f"Manager parse error: {str(e)}", exc_info=True)
         
     | 
| 
      
 250 
     | 
    
         
            +
                                break
         
     | 
| 
      
 251 
     | 
    
         
            +
             
     | 
| 
      
 252 
     | 
    
         
            +
                            selected_task_id = parsed_instructions.task_id
         
     | 
| 
      
 253 
     | 
    
         
            +
                            selected_agent_name = parsed_instructions.agent_name
         
     | 
| 
      
 254 
     | 
    
         
            +
                            action = parsed_instructions.action
         
     | 
| 
      
 255 
     | 
    
         
            +
             
     | 
| 
      
 256 
     | 
    
         
            +
                            logging.info(f"Manager selected task_id={selected_task_id}, agent={selected_agent_name}, action={action}")
         
     | 
| 
      
 257 
     | 
    
         
            +
             
     | 
| 
      
 258 
     | 
    
         
            +
                            if action.lower() == "stop":
         
     | 
| 
      
 259 
     | 
    
         
            +
                                logging.info("Manager decided to stop task execution")
         
     | 
| 
      
 260 
     | 
    
         
            +
                                break
         
     | 
| 
      
 261 
     | 
    
         
            +
             
     | 
| 
      
 262 
     | 
    
         
            +
                            if selected_task_id not in self.tasks:
         
     | 
| 
      
 263 
     | 
    
         
            +
                                error_msg = f"Manager selected invalid task id {selected_task_id}"
         
     | 
| 
      
 264 
     | 
    
         
            +
                                display_error(error_msg)
         
     | 
| 
      
 265 
     | 
    
         
            +
                                logging.error(error_msg)
         
     | 
| 
      
 266 
     | 
    
         
            +
                                break
         
     | 
| 
      
 267 
     | 
    
         
            +
             
     | 
| 
      
 268 
     | 
    
         
            +
                            original_agent = self.tasks[selected_task_id].agent.name if self.tasks[selected_task_id].agent else "None"
         
     | 
| 
      
 269 
     | 
    
         
            +
                            for a in self.agents:
         
     | 
| 
      
 270 
     | 
    
         
            +
                                if a.name == selected_agent_name:
         
     | 
| 
      
 271 
     | 
    
         
            +
                                    self.tasks[selected_task_id].agent = a
         
     | 
| 
      
 272 
     | 
    
         
            +
                                    logging.info(f"Changed agent for task {selected_task_id} from {original_agent} to {selected_agent_name}")
         
     | 
| 
      
 273 
     | 
    
         
            +
                                    break
         
     | 
| 
      
 274 
     | 
    
         
            +
             
     | 
| 
      
 275 
     | 
    
         
            +
                            if self.tasks[selected_task_id].status != "completed":
         
     | 
| 
      
 276 
     | 
    
         
            +
                                logging.info(f"Starting execution of task {selected_task_id}")
         
     | 
| 
      
 277 
     | 
    
         
            +
                                self.run_task(selected_task_id)
         
     | 
| 
      
 278 
     | 
    
         
            +
                                logging.info(f"Finished execution of task {selected_task_id}, status: {self.tasks[selected_task_id].status}")
         
     | 
| 
      
 279 
     | 
    
         
            +
             
     | 
| 
      
 280 
     | 
    
         
            +
                            if self.tasks[selected_task_id].status == "completed":
         
     | 
| 
      
 281 
     | 
    
         
            +
                                completed_count += 1
         
     | 
| 
      
 282 
     | 
    
         
            +
                                logging.info(f"Task {selected_task_id} completed. Total completed: {completed_count}/{total_tasks}")
         
     | 
| 
      
 283 
     | 
    
         
            +
             
     | 
| 
      
 284 
     | 
    
         
            +
                        self.tasks[manager_task.id].status = "completed"
         
     | 
| 
      
 285 
     | 
    
         
            +
                        if self.verbose >= 1:
         
     | 
| 
      
 286 
     | 
    
         
            +
                            logging.info("All tasks completed under manager supervision.")
         
     | 
| 
      
 287 
     | 
    
         
            +
                        logging.info("Hierarchical task execution finished")
         
     | 
| 
      
 288 
     | 
    
         
            +
             
     | 
| 
      
 289 
     | 
    
         
            +
                def get_task_status(self, task_id):
         
     | 
| 
      
 290 
     | 
    
         
            +
                    if task_id in self.tasks:
         
     | 
| 
      
 291 
     | 
    
         
            +
                        return self.tasks[task_id].status
         
     | 
| 
      
 292 
     | 
    
         
            +
                    return None
         
     | 
| 
      
 293 
     | 
    
         
            +
             
     | 
| 
      
 294 
     | 
    
         
            +
                def get_all_tasks_status(self):
         
     | 
| 
      
 295 
     | 
    
         
            +
                    return {task_id: self.tasks[task_id].status for task_id in self.tasks}
         
     | 
| 
      
 296 
     | 
    
         
            +
             
     | 
| 
      
 297 
     | 
    
         
            +
                def get_task_result(self, task_id):
         
     | 
| 
      
 298 
     | 
    
         
            +
                    if task_id in self.tasks:
         
     | 
| 
      
 299 
     | 
    
         
            +
                        return self.tasks[task_id].result
         
     | 
| 
      
 300 
     | 
    
         
            +
                    return None
         
     | 
| 
      
 301 
     | 
    
         
            +
             
     | 
| 
      
 302 
     | 
    
         
            +
                def get_task_details(self, task_id):
         
     | 
| 
      
 303 
     | 
    
         
            +
                    if task_id in self.tasks:
         
     | 
| 
      
 304 
     | 
    
         
            +
                        return str(self.tasks[task_id])
         
     | 
| 
      
 305 
     | 
    
         
            +
                    return None
         
     | 
| 
      
 306 
     | 
    
         
            +
             
     | 
| 
      
 307 
     | 
    
         
            +
                def get_agent_details(self, agent_name):
         
     | 
| 
      
 308 
     | 
    
         
            +
                    agent = [task.agent for task in self.tasks.values() if task.agent and task.agent.name == agent_name]
         
     | 
| 
      
 309 
     | 
    
         
            +
                    if agent:
         
     | 
| 
      
 310 
     | 
    
         
            +
                        return str(agent[0])
         
     | 
| 
      
 311 
     | 
    
         
            +
                    return None
         
     | 
| 
      
 312 
     | 
    
         
            +
             
     | 
| 
      
 313 
     | 
    
         
            +
                def start(self):
         
     | 
| 
      
 314 
     | 
    
         
            +
                    self.run_all_tasks()
         
     | 
| 
      
 315 
     | 
    
         
            +
                    return {
         
     | 
| 
      
 316 
     | 
    
         
            +
                        "task_status": self.get_all_tasks_status(),
         
     | 
| 
      
 317 
     | 
    
         
            +
                        "task_results": {task_id: self.get_task_result(task_id) for task_id in self.tasks}
         
     | 
| 
      
 318 
     | 
    
         
            +
                    } 
         
     | 
| 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
             
         
     | 
| 
         @@ -0,0 +1,350 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            import logging
         
     | 
| 
      
 2 
     | 
    
         
            +
            import json
         
     | 
| 
      
 3 
     | 
    
         
            +
            import time
         
     | 
| 
      
 4 
     | 
    
         
            +
            from typing import List, Optional, Any, Dict, Union, Literal
         
     | 
| 
      
 5 
     | 
    
         
            +
            from rich.console import Console
         
     | 
| 
      
 6 
     | 
    
         
            +
            from rich.live import Live
         
     | 
| 
      
 7 
     | 
    
         
            +
            from ..main import (
         
     | 
| 
      
 8 
     | 
    
         
            +
                display_error,
         
     | 
| 
      
 9 
     | 
    
         
            +
                display_tool_call,
         
     | 
| 
      
 10 
     | 
    
         
            +
                display_instruction,
         
     | 
| 
      
 11 
     | 
    
         
            +
                display_interaction,
         
     | 
| 
      
 12 
     | 
    
         
            +
                display_generating,
         
     | 
| 
      
 13 
     | 
    
         
            +
                ReflectionOutput,
         
     | 
| 
      
 14 
     | 
    
         
            +
                client,
         
     | 
| 
      
 15 
     | 
    
         
            +
                error_logs
         
     | 
| 
      
 16 
     | 
    
         
            +
            )
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            class Agent:
         
     | 
| 
      
 19 
     | 
    
         
            +
                def __init__(
         
     | 
| 
      
 20 
     | 
    
         
            +
                    self,
         
     | 
| 
      
 21 
     | 
    
         
            +
                    name: str,
         
     | 
| 
      
 22 
     | 
    
         
            +
                    role: str,
         
     | 
| 
      
 23 
     | 
    
         
            +
                    goal: str,
         
     | 
| 
      
 24 
     | 
    
         
            +
                    backstory: str,
         
     | 
| 
      
 25 
     | 
    
         
            +
                    llm: Optional[Union[str, Any]] = "gpt-4o-mini",
         
     | 
| 
      
 26 
     | 
    
         
            +
                    tools: Optional[List[Any]] = None,
         
     | 
| 
      
 27 
     | 
    
         
            +
                    function_calling_llm: Optional[Any] = None,
         
     | 
| 
      
 28 
     | 
    
         
            +
                    max_iter: int = 20,
         
     | 
| 
      
 29 
     | 
    
         
            +
                    max_rpm: Optional[int] = None,
         
     | 
| 
      
 30 
     | 
    
         
            +
                    max_execution_time: Optional[int] = None,
         
     | 
| 
      
 31 
     | 
    
         
            +
                    memory: bool = True,
         
     | 
| 
      
 32 
     | 
    
         
            +
                    verbose: bool = False,
         
     | 
| 
      
 33 
     | 
    
         
            +
                    allow_delegation: bool = False,
         
     | 
| 
      
 34 
     | 
    
         
            +
                    step_callback: Optional[Any] = None,
         
     | 
| 
      
 35 
     | 
    
         
            +
                    cache: bool = True,
         
     | 
| 
      
 36 
     | 
    
         
            +
                    system_template: Optional[str] = None,
         
     | 
| 
      
 37 
     | 
    
         
            +
                    prompt_template: Optional[str] = None,
         
     | 
| 
      
 38 
     | 
    
         
            +
                    response_template: Optional[str] = None,
         
     | 
| 
      
 39 
     | 
    
         
            +
                    allow_code_execution: Optional[bool] = False,
         
     | 
| 
      
 40 
     | 
    
         
            +
                    max_retry_limit: int = 2,
         
     | 
| 
      
 41 
     | 
    
         
            +
                    respect_context_window: bool = True,
         
     | 
| 
      
 42 
     | 
    
         
            +
                    code_execution_mode: Literal["safe", "unsafe"] = "safe",
         
     | 
| 
      
 43 
     | 
    
         
            +
                    embedder_config: Optional[Dict[str, Any]] = None,
         
     | 
| 
      
 44 
     | 
    
         
            +
                    knowledge_sources: Optional[List[Any]] = None,
         
     | 
| 
      
 45 
     | 
    
         
            +
                    use_system_prompt: Optional[bool] = True,
         
     | 
| 
      
 46 
     | 
    
         
            +
                    markdown: bool = True,
         
     | 
| 
      
 47 
     | 
    
         
            +
                    self_reflect: bool = True,
         
     | 
| 
      
 48 
     | 
    
         
            +
                    max_reflection_iter: int = 3
         
     | 
| 
      
 49 
     | 
    
         
            +
                ):
         
     | 
| 
      
 50 
     | 
    
         
            +
                    self.name = name
         
     | 
| 
      
 51 
     | 
    
         
            +
                    self.role = role
         
     | 
| 
      
 52 
     | 
    
         
            +
                    self.goal = goal
         
     | 
| 
      
 53 
     | 
    
         
            +
                    self.backstory = backstory
         
     | 
| 
      
 54 
     | 
    
         
            +
                    self.llm = llm
         
     | 
| 
      
 55 
     | 
    
         
            +
                    self.tools = tools if tools else []
         
     | 
| 
      
 56 
     | 
    
         
            +
                    self.function_calling_llm = function_calling_llm
         
     | 
| 
      
 57 
     | 
    
         
            +
                    self.max_iter = max_iter
         
     | 
| 
      
 58 
     | 
    
         
            +
                    self.max_rpm = max_rpm
         
     | 
| 
      
 59 
     | 
    
         
            +
                    self.max_execution_time = max_execution_time
         
     | 
| 
      
 60 
     | 
    
         
            +
                    self.memory = memory
         
     | 
| 
      
 61 
     | 
    
         
            +
                    self.verbose = verbose
         
     | 
| 
      
 62 
     | 
    
         
            +
                    self.allow_delegation = allow_delegation
         
     | 
| 
      
 63 
     | 
    
         
            +
                    self.step_callback = step_callback
         
     | 
| 
      
 64 
     | 
    
         
            +
                    self.cache = cache
         
     | 
| 
      
 65 
     | 
    
         
            +
                    self.system_template = system_template
         
     | 
| 
      
 66 
     | 
    
         
            +
                    self.prompt_template = prompt_template
         
     | 
| 
      
 67 
     | 
    
         
            +
                    self.response_template = response_template
         
     | 
| 
      
 68 
     | 
    
         
            +
                    self.allow_code_execution = allow_code_execution
         
     | 
| 
      
 69 
     | 
    
         
            +
                    self.max_retry_limit = max_retry_limit
         
     | 
| 
      
 70 
     | 
    
         
            +
                    self.respect_context_window = respect_context_window
         
     | 
| 
      
 71 
     | 
    
         
            +
                    self.code_execution_mode = code_execution_mode
         
     | 
| 
      
 72 
     | 
    
         
            +
                    self.embedder_config = embedder_config
         
     | 
| 
      
 73 
     | 
    
         
            +
                    self.knowledge_sources = knowledge_sources
         
     | 
| 
      
 74 
     | 
    
         
            +
                    self.use_system_prompt = use_system_prompt
         
     | 
| 
      
 75 
     | 
    
         
            +
                    self.chat_history = []
         
     | 
| 
      
 76 
     | 
    
         
            +
                    self.markdown = markdown
         
     | 
| 
      
 77 
     | 
    
         
            +
                    self.self_reflect = self_reflect
         
     | 
| 
      
 78 
     | 
    
         
            +
                    self.max_reflection_iter = max_reflection_iter
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                def execute_tool(self, function_name, arguments):
         
     | 
| 
      
 81 
     | 
    
         
            +
                    logging.debug(f"{self.name} executing tool {function_name} with arguments: {arguments}")
         
     | 
| 
      
 82 
     | 
    
         
            +
                    if function_name == "get_weather":
         
     | 
| 
      
 83 
     | 
    
         
            +
                        location = arguments.get("location", "Unknown Location")
         
     | 
| 
      
 84 
     | 
    
         
            +
                        return {"temperature": "25C", "condition": "Sunny", "location": location}
         
     | 
| 
      
 85 
     | 
    
         
            +
                    elif function_name == "search_tool":
         
     | 
| 
      
 86 
     | 
    
         
            +
                        query = arguments.get("query", "AI trends in 2024")
         
     | 
| 
      
 87 
     | 
    
         
            +
                        return {"results": [
         
     | 
| 
      
 88 
     | 
    
         
            +
                            {"title": "AI advancements in 2024", "link": "url1", "summary": "Lots of advancements"},
         
     | 
| 
      
 89 
     | 
    
         
            +
                            {"title": "New trends in AI", "link": "url2", "summary": "New trends being found"}
         
     | 
| 
      
 90 
     | 
    
         
            +
                        ]}
         
     | 
| 
      
 91 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 92 
     | 
    
         
            +
                        return f"Tool '{function_name}' is not recognized"
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                def clear_history(self):
         
     | 
| 
      
 95 
     | 
    
         
            +
                    self.chat_history = []
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                def __str__(self):
         
     | 
| 
      
 98 
     | 
    
         
            +
                    return f"Agent(name='{self.name}', role='{self.role}', goal='{self.goal}')"
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                def _chat_completion(self, messages, temperature=0.2, tools=None, stream=True):
         
     | 
| 
      
 101 
     | 
    
         
            +
                    console = Console()
         
     | 
| 
      
 102 
     | 
    
         
            +
                    start_time = time.time()
         
     | 
| 
      
 103 
     | 
    
         
            +
                    logging.debug(f"{self.name} sending messages to LLM: {messages}")
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
                    formatted_tools = []
         
     | 
| 
      
 106 
     | 
    
         
            +
                    if tools:
         
     | 
| 
      
 107 
     | 
    
         
            +
                        for tool in tools:
         
     | 
| 
      
 108 
     | 
    
         
            +
                            if isinstance(tool, dict):
         
     | 
| 
      
 109 
     | 
    
         
            +
                                formatted_tools.append(tool)
         
     | 
| 
      
 110 
     | 
    
         
            +
                            elif hasattr(tool, "to_openai_tool"):
         
     | 
| 
      
 111 
     | 
    
         
            +
                                formatted_tools.append(tool.to_openai_tool())
         
     | 
| 
      
 112 
     | 
    
         
            +
                            elif isinstance(tool, str):
         
     | 
| 
      
 113 
     | 
    
         
            +
                                formatted_tools.append({
         
     | 
| 
      
 114 
     | 
    
         
            +
                                    "type": "function",
         
     | 
| 
      
 115 
     | 
    
         
            +
                                    "function": {
         
     | 
| 
      
 116 
     | 
    
         
            +
                                        "name": tool,
         
     | 
| 
      
 117 
     | 
    
         
            +
                                        "description": f"This is a tool called {tool}",
         
     | 
| 
      
 118 
     | 
    
         
            +
                                        "parameters": {
         
     | 
| 
      
 119 
     | 
    
         
            +
                                            "type": "object",
         
     | 
| 
      
 120 
     | 
    
         
            +
                                            "properties": {},
         
     | 
| 
      
 121 
     | 
    
         
            +
                                        },
         
     | 
| 
      
 122 
     | 
    
         
            +
                                    }
         
     | 
| 
      
 123 
     | 
    
         
            +
                                })
         
     | 
| 
      
 124 
     | 
    
         
            +
                            else:
         
     | 
| 
      
 125 
     | 
    
         
            +
                                display_error(f"Warning: Tool {tool} not recognized")
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
                    try:
         
     | 
| 
      
 128 
     | 
    
         
            +
                        initial_response = client.chat.completions.create(
         
     | 
| 
      
 129 
     | 
    
         
            +
                            model=self.llm,
         
     | 
| 
      
 130 
     | 
    
         
            +
                            messages=messages,
         
     | 
| 
      
 131 
     | 
    
         
            +
                            temperature=temperature,
         
     | 
| 
      
 132 
     | 
    
         
            +
                            tools=formatted_tools if formatted_tools else None,
         
     | 
| 
      
 133 
     | 
    
         
            +
                            stream=False
         
     | 
| 
      
 134 
     | 
    
         
            +
                        )
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                        tool_calls = getattr(initial_response.choices[0].message, 'tool_calls', None)
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
                        if tool_calls:
         
     | 
| 
      
 139 
     | 
    
         
            +
                            messages.append({
         
     | 
| 
      
 140 
     | 
    
         
            +
                                "role": "assistant",
         
     | 
| 
      
 141 
     | 
    
         
            +
                                "content": initial_response.choices[0].message.content,
         
     | 
| 
      
 142 
     | 
    
         
            +
                                "tool_calls": tool_calls
         
     | 
| 
      
 143 
     | 
    
         
            +
                            })
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
                            for tool_call in tool_calls:
         
     | 
| 
      
 146 
     | 
    
         
            +
                                function_name = tool_call.function.name
         
     | 
| 
      
 147 
     | 
    
         
            +
                                arguments = json.loads(tool_call.function.arguments)
         
     | 
| 
      
 148 
     | 
    
         
            +
             
     | 
| 
      
 149 
     | 
    
         
            +
                                if self.verbose:
         
     | 
| 
      
 150 
     | 
    
         
            +
                                    display_tool_call(f"Agent {self.name} is calling function '{function_name}' with arguments: {arguments}")
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
                                tool_result = self.execute_tool(function_name, arguments)
         
     | 
| 
      
 153 
     | 
    
         
            +
                                results_str = json.dumps(tool_result) if tool_result else "Function returned an empty output"
         
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
      
 155 
     | 
    
         
            +
                                if self.verbose:
         
     | 
| 
      
 156 
     | 
    
         
            +
                                    display_tool_call(f"Function '{function_name}' returned: {results_str}")
         
     | 
| 
      
 157 
     | 
    
         
            +
             
     | 
| 
      
 158 
     | 
    
         
            +
                                messages.append({
         
     | 
| 
      
 159 
     | 
    
         
            +
                                    "role": "tool",
         
     | 
| 
      
 160 
     | 
    
         
            +
                                    "tool_call_id": tool_call.id,
         
     | 
| 
      
 161 
     | 
    
         
            +
                                    "content": results_str
         
     | 
| 
      
 162 
     | 
    
         
            +
                                })
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
      
 164 
     | 
    
         
            +
                        if stream:
         
     | 
| 
      
 165 
     | 
    
         
            +
                            response_stream = client.chat.completions.create(
         
     | 
| 
      
 166 
     | 
    
         
            +
                                model=self.llm,
         
     | 
| 
      
 167 
     | 
    
         
            +
                                messages=messages,
         
     | 
| 
      
 168 
     | 
    
         
            +
                                temperature=temperature,
         
     | 
| 
      
 169 
     | 
    
         
            +
                                stream=True
         
     | 
| 
      
 170 
     | 
    
         
            +
                            )
         
     | 
| 
      
 171 
     | 
    
         
            +
                            full_response_text = ""
         
     | 
| 
      
 172 
     | 
    
         
            +
                            with Live(display_generating("", start_time), refresh_per_second=4) as live:
         
     | 
| 
      
 173 
     | 
    
         
            +
                                for chunk in response_stream:
         
     | 
| 
      
 174 
     | 
    
         
            +
                                    if chunk.choices[0].delta.content:
         
     | 
| 
      
 175 
     | 
    
         
            +
                                        full_response_text += chunk.choices[0].delta.content
         
     | 
| 
      
 176 
     | 
    
         
            +
                                        live.update(display_generating(full_response_text, start_time))
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
                            final_response = client.chat.completions.create(
         
     | 
| 
      
 179 
     | 
    
         
            +
                                model=self.llm,
         
     | 
| 
      
 180 
     | 
    
         
            +
                                messages=messages,
         
     | 
| 
      
 181 
     | 
    
         
            +
                                temperature=temperature,
         
     | 
| 
      
 182 
     | 
    
         
            +
                                stream=False
         
     | 
| 
      
 183 
     | 
    
         
            +
                            )
         
     | 
| 
      
 184 
     | 
    
         
            +
                            return final_response
         
     | 
| 
      
 185 
     | 
    
         
            +
                        else:
         
     | 
| 
      
 186 
     | 
    
         
            +
                            if tool_calls:
         
     | 
| 
      
 187 
     | 
    
         
            +
                                final_response = client.chat.completions.create(
         
     | 
| 
      
 188 
     | 
    
         
            +
                                    model=self.llm,
         
     | 
| 
      
 189 
     | 
    
         
            +
                                    messages=messages,
         
     | 
| 
      
 190 
     | 
    
         
            +
                                    temperature=temperature,
         
     | 
| 
      
 191 
     | 
    
         
            +
                                    stream=False
         
     | 
| 
      
 192 
     | 
    
         
            +
                                )
         
     | 
| 
      
 193 
     | 
    
         
            +
                                return final_response
         
     | 
| 
      
 194 
     | 
    
         
            +
                            else:
         
     | 
| 
      
 195 
     | 
    
         
            +
                                return initial_response
         
     | 
| 
      
 196 
     | 
    
         
            +
             
     | 
| 
      
 197 
     | 
    
         
            +
                    except Exception as e:
         
     | 
| 
      
 198 
     | 
    
         
            +
                        display_error(f"Error in chat completion: {e}")
         
     | 
| 
      
 199 
     | 
    
         
            +
                        return None
         
     | 
| 
      
 200 
     | 
    
         
            +
             
     | 
| 
      
 201 
     | 
    
         
            +
                def chat(self, prompt, temperature=0.2, tools=None, output_json=None):
         
     | 
| 
      
 202 
     | 
    
         
            +
                    if self.use_system_prompt:
         
     | 
| 
      
 203 
     | 
    
         
            +
                        system_prompt = f"""{self.backstory}\n
         
     | 
| 
      
 204 
     | 
    
         
            +
                        Your Role: {self.role}\n
         
     | 
| 
      
 205 
     | 
    
         
            +
                        Your Goal: {self.goal}
         
     | 
| 
      
 206 
     | 
    
         
            +
                        """
         
     | 
| 
      
 207 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 208 
     | 
    
         
            +
                        system_prompt = None
         
     | 
| 
      
 209 
     | 
    
         
            +
                    
         
     | 
| 
      
 210 
     | 
    
         
            +
                    messages = []
         
     | 
| 
      
 211 
     | 
    
         
            +
                    if system_prompt:
         
     | 
| 
      
 212 
     | 
    
         
            +
                        messages.append({"role": "system", "content": system_prompt})
         
     | 
| 
      
 213 
     | 
    
         
            +
                    messages.extend(self.chat_history)
         
     | 
| 
      
 214 
     | 
    
         
            +
                    messages.append({"role": "user", "content": prompt})
         
     | 
| 
      
 215 
     | 
    
         
            +
             
     | 
| 
      
 216 
     | 
    
         
            +
                    final_response_text = None
         
     | 
| 
      
 217 
     | 
    
         
            +
                    reflection_count = 0
         
     | 
| 
      
 218 
     | 
    
         
            +
                    start_time = time.time()
         
     | 
| 
      
 219 
     | 
    
         
            +
             
     | 
| 
      
 220 
     | 
    
         
            +
                    while True:
         
     | 
| 
      
 221 
     | 
    
         
            +
                        try:
         
     | 
| 
      
 222 
     | 
    
         
            +
                            if self.verbose:
         
     | 
| 
      
 223 
     | 
    
         
            +
                                display_instruction(f"Agent {self.name} is processing prompt: {prompt}")
         
     | 
| 
      
 224 
     | 
    
         
            +
             
     | 
| 
      
 225 
     | 
    
         
            +
                            formatted_tools = []
         
     | 
| 
      
 226 
     | 
    
         
            +
                            if tools:
         
     | 
| 
      
 227 
     | 
    
         
            +
                                for tool in tools:
         
     | 
| 
      
 228 
     | 
    
         
            +
                                    if isinstance(tool, dict):
         
     | 
| 
      
 229 
     | 
    
         
            +
                                        formatted_tools.append(tool)
         
     | 
| 
      
 230 
     | 
    
         
            +
                                    elif hasattr(tool, "to_openai_tool"):
         
     | 
| 
      
 231 
     | 
    
         
            +
                                        formatted_tools.append(tool.to_openai_tool())
         
     | 
| 
      
 232 
     | 
    
         
            +
                                    elif isinstance(tool, str):
         
     | 
| 
      
 233 
     | 
    
         
            +
                                        formatted_tools.append({
         
     | 
| 
      
 234 
     | 
    
         
            +
                                            "type": "function",
         
     | 
| 
      
 235 
     | 
    
         
            +
                                            "function": {
         
     | 
| 
      
 236 
     | 
    
         
            +
                                                "name": tool,
         
     | 
| 
      
 237 
     | 
    
         
            +
                                                "description": f"This is a tool called {tool}",
         
     | 
| 
      
 238 
     | 
    
         
            +
                                                "parameters": {
         
     | 
| 
      
 239 
     | 
    
         
            +
                                                    "type": "object",
         
     | 
| 
      
 240 
     | 
    
         
            +
                                                    "properties": {},
         
     | 
| 
      
 241 
     | 
    
         
            +
                                                },
         
     | 
| 
      
 242 
     | 
    
         
            +
                                            }
         
     | 
| 
      
 243 
     | 
    
         
            +
                                        })
         
     | 
| 
      
 244 
     | 
    
         
            +
                                    else:
         
     | 
| 
      
 245 
     | 
    
         
            +
                                        display_error(f"Warning: Tool {tool} not recognized")
         
     | 
| 
      
 246 
     | 
    
         
            +
             
     | 
| 
      
 247 
     | 
    
         
            +
                            response = self._chat_completion(messages, temperature=temperature, tools=formatted_tools if formatted_tools else None)
         
     | 
| 
      
 248 
     | 
    
         
            +
                            if not response:
         
     | 
| 
      
 249 
     | 
    
         
            +
                                return None
         
     | 
| 
      
 250 
     | 
    
         
            +
                                
         
     | 
| 
      
 251 
     | 
    
         
            +
                            tool_calls = getattr(response.choices[0].message, 'tool_calls', None)
         
     | 
| 
      
 252 
     | 
    
         
            +
             
     | 
| 
      
 253 
     | 
    
         
            +
                            if tool_calls:
         
     | 
| 
      
 254 
     | 
    
         
            +
                                messages.append({
         
     | 
| 
      
 255 
     | 
    
         
            +
                                    "role": "assistant",
         
     | 
| 
      
 256 
     | 
    
         
            +
                                    "content": response.choices[0].message.content,
         
     | 
| 
      
 257 
     | 
    
         
            +
                                    "tool_calls": tool_calls
         
     | 
| 
      
 258 
     | 
    
         
            +
                                })
         
     | 
| 
      
 259 
     | 
    
         
            +
                                
         
     | 
| 
      
 260 
     | 
    
         
            +
                                for tool_call in tool_calls:
         
     | 
| 
      
 261 
     | 
    
         
            +
                                    function_name = tool_call.function.name
         
     | 
| 
      
 262 
     | 
    
         
            +
                                    arguments = json.loads(tool_call.function.arguments)
         
     | 
| 
      
 263 
     | 
    
         
            +
             
     | 
| 
      
 264 
     | 
    
         
            +
                                    if self.verbose:
         
     | 
| 
      
 265 
     | 
    
         
            +
                                        display_tool_call(f"Agent {self.name} is calling function '{function_name}' with arguments: {arguments}")
         
     | 
| 
      
 266 
     | 
    
         
            +
             
     | 
| 
      
 267 
     | 
    
         
            +
                                    tool_result = self.execute_tool(function_name, arguments)
         
     | 
| 
      
 268 
     | 
    
         
            +
             
     | 
| 
      
 269 
     | 
    
         
            +
                                    if tool_result:
         
     | 
| 
      
 270 
     | 
    
         
            +
                                        if self.verbose:
         
     | 
| 
      
 271 
     | 
    
         
            +
                                            display_tool_call(f"Function '{function_name}' returned: {tool_result}")
         
     | 
| 
      
 272 
     | 
    
         
            +
                                        messages.append({
         
     | 
| 
      
 273 
     | 
    
         
            +
                                            "role": "tool",
         
     | 
| 
      
 274 
     | 
    
         
            +
                                            "tool_call_id": tool_call.id,
         
     | 
| 
      
 275 
     | 
    
         
            +
                                            "content": json.dumps(tool_result)
         
     | 
| 
      
 276 
     | 
    
         
            +
                                        })
         
     | 
| 
      
 277 
     | 
    
         
            +
                                    else:
         
     | 
| 
      
 278 
     | 
    
         
            +
                                        messages.append({
         
     | 
| 
      
 279 
     | 
    
         
            +
                                            "role": "tool",
         
     | 
| 
      
 280 
     | 
    
         
            +
                                            "tool_call_id": tool_call.id,
         
     | 
| 
      
 281 
     | 
    
         
            +
                                            "content": "Function returned an empty output"
         
     | 
| 
      
 282 
     | 
    
         
            +
                                        })
         
     | 
| 
      
 283 
     | 
    
         
            +
                                    
         
     | 
| 
      
 284 
     | 
    
         
            +
                                response = self._chat_completion(messages, temperature=temperature)
         
     | 
| 
      
 285 
     | 
    
         
            +
                                if not response:
         
     | 
| 
      
 286 
     | 
    
         
            +
                                    return None
         
     | 
| 
      
 287 
     | 
    
         
            +
                                response_text = response.choices[0].message.content.strip()
         
     | 
| 
      
 288 
     | 
    
         
            +
                            else:
         
     | 
| 
      
 289 
     | 
    
         
            +
                                response_text = response.choices[0].message.content.strip()
         
     | 
| 
      
 290 
     | 
    
         
            +
             
     | 
| 
      
 291 
     | 
    
         
            +
                            if not self.self_reflect:
         
     | 
| 
      
 292 
     | 
    
         
            +
                                self.chat_history.append({"role": "user", "content": prompt})
         
     | 
| 
      
 293 
     | 
    
         
            +
                                self.chat_history.append({"role": "assistant", "content": response_text})
         
     | 
| 
      
 294 
     | 
    
         
            +
                                if self.verbose:
         
     | 
| 
      
 295 
     | 
    
         
            +
                                    logging.info(f"Agent {self.name} final response: {response_text}")
         
     | 
| 
      
 296 
     | 
    
         
            +
                                display_interaction(prompt, response_text, markdown=self.markdown, generation_time=time.time() - start_time)
         
     | 
| 
      
 297 
     | 
    
         
            +
                                return response_text
         
     | 
| 
      
 298 
     | 
    
         
            +
             
     | 
| 
      
 299 
     | 
    
         
            +
                            reflection_prompt = f"""
         
     | 
| 
      
 300 
     | 
    
         
            +
                            Reflect on your previous response: '{response_text}'.
         
     | 
| 
      
 301 
     | 
    
         
            +
                            Identify any flaws, improvements, or actions.
         
     | 
| 
      
 302 
     | 
    
         
            +
                            Provide a "satisfactory" status ('yes' or 'no').
         
     | 
| 
      
 303 
     | 
    
         
            +
                            Output MUST be JSON with 'reflection' and 'satisfactory'.
         
     | 
| 
      
 304 
     | 
    
         
            +
                            """
         
     | 
| 
      
 305 
     | 
    
         
            +
                            logging.debug(f"{self.name} reflection attempt {reflection_count+1}, sending prompt: {reflection_prompt}")
         
     | 
| 
      
 306 
     | 
    
         
            +
                            messages.append({"role": "user", "content": reflection_prompt})
         
     | 
| 
      
 307 
     | 
    
         
            +
             
     | 
| 
      
 308 
     | 
    
         
            +
                            try:
         
     | 
| 
      
 309 
     | 
    
         
            +
                                reflection_response = client.beta.chat.completions.parse(
         
     | 
| 
      
 310 
     | 
    
         
            +
                                    model=self.llm,
         
     | 
| 
      
 311 
     | 
    
         
            +
                                    messages=messages,
         
     | 
| 
      
 312 
     | 
    
         
            +
                                    temperature=temperature,
         
     | 
| 
      
 313 
     | 
    
         
            +
                                    response_format=ReflectionOutput
         
     | 
| 
      
 314 
     | 
    
         
            +
                                )
         
     | 
| 
      
 315 
     | 
    
         
            +
             
     | 
| 
      
 316 
     | 
    
         
            +
                                reflection_output = reflection_response.choices[0].message.parsed
         
     | 
| 
      
 317 
     | 
    
         
            +
             
     | 
| 
      
 318 
     | 
    
         
            +
                                if self.verbose:
         
     | 
| 
      
 319 
     | 
    
         
            +
                                    display_self_reflection(f"Agent {self.name} self reflection: reflection='{reflection_output.reflection}' satisfactory='{reflection_output.satisfactory}'")
         
     | 
| 
      
 320 
     | 
    
         
            +
             
     | 
| 
      
 321 
     | 
    
         
            +
                                messages.append({"role": "assistant", "content": f"Self Reflection: {reflection_output.reflection} Satisfactory?: {reflection_output.satisfactory}"})
         
     | 
| 
      
 322 
     | 
    
         
            +
             
     | 
| 
      
 323 
     | 
    
         
            +
                                if reflection_output.satisfactory == "yes":
         
     | 
| 
      
 324 
     | 
    
         
            +
                                    if self.verbose:
         
     | 
| 
      
 325 
     | 
    
         
            +
                                        display_self_reflection("Agent marked the response as satisfactory")
         
     | 
| 
      
 326 
     | 
    
         
            +
                                    self.chat_history.append({"role": "assistant", "content": response_text})
         
     | 
| 
      
 327 
     | 
    
         
            +
                                    display_interaction(prompt, response_text, markdown=self.markdown, generation_time=time.time() - start_time)
         
     | 
| 
      
 328 
     | 
    
         
            +
                                    return response_text
         
     | 
| 
      
 329 
     | 
    
         
            +
             
     | 
| 
      
 330 
     | 
    
         
            +
                                logging.debug(f"{self.name} reflection not satisfactory, requesting regeneration.")
         
     | 
| 
      
 331 
     | 
    
         
            +
                                messages.append({"role": "user", "content": "Now regenerate your response using the reflection you made"})
         
     | 
| 
      
 332 
     | 
    
         
            +
                                response = self._chat_completion(messages, temperature=temperature, tools=None, stream=True)
         
     | 
| 
      
 333 
     | 
    
         
            +
                                response_text = response.choices[0].message.content.strip()
         
     | 
| 
      
 334 
     | 
    
         
            +
                            except Exception as e:
         
     | 
| 
      
 335 
     | 
    
         
            +
                                display_error(f"Error in parsing self-reflection json {e}. Retrying")
         
     | 
| 
      
 336 
     | 
    
         
            +
                                logging.error("Reflection parsing failed.", exc_info=True)
         
     | 
| 
      
 337 
     | 
    
         
            +
                                messages.append({"role": "assistant", "content": f"Self Reflection failed."})
         
     | 
| 
      
 338 
     | 
    
         
            +
                            
         
     | 
| 
      
 339 
     | 
    
         
            +
                            reflection_count += 1
         
     | 
| 
      
 340 
     | 
    
         
            +
             
     | 
| 
      
 341 
     | 
    
         
            +
                            self.chat_history.append({"role": "user", "content": prompt})
         
     | 
| 
      
 342 
     | 
    
         
            +
                            self.chat_history.append({"role": "assistant", "content": response_text})
         
     | 
| 
      
 343 
     | 
    
         
            +
             
     | 
| 
      
 344 
     | 
    
         
            +
                            if self.verbose:
         
     | 
| 
      
 345 
     | 
    
         
            +
                                logging.info(f"Agent {self.name} final response: {response_text}")
         
     | 
| 
      
 346 
     | 
    
         
            +
                            display_interaction(prompt, response_text, markdown=self.markdown, generation_time=time.time() - start_time)
         
     | 
| 
      
 347 
     | 
    
         
            +
                            return response_text
         
     | 
| 
      
 348 
     | 
    
         
            +
                        except Exception as e:
         
     | 
| 
      
 349 
     | 
    
         
            +
                            display_error(f"Error in chat: {e}")
         
     | 
| 
      
 350 
     | 
    
         
            +
                            return None 
         
     | 
    
        praisonaiagents/main.py
    ADDED
    
    | 
         @@ -0,0 +1,112 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            import os
         
     | 
| 
      
 2 
     | 
    
         
            +
            import time
         
     | 
| 
      
 3 
     | 
    
         
            +
            import json
         
     | 
| 
      
 4 
     | 
    
         
            +
            import logging
         
     | 
| 
      
 5 
     | 
    
         
            +
            from typing import List, Optional, Dict, Any, Union, Literal, Type
         
     | 
| 
      
 6 
     | 
    
         
            +
            from openai import OpenAI
         
     | 
| 
      
 7 
     | 
    
         
            +
            from pydantic import BaseModel
         
     | 
| 
      
 8 
     | 
    
         
            +
            from rich import print
         
     | 
| 
      
 9 
     | 
    
         
            +
            from rich.console import Console
         
     | 
| 
      
 10 
     | 
    
         
            +
            from rich.panel import Panel
         
     | 
| 
      
 11 
     | 
    
         
            +
            from rich.text import Text
         
     | 
| 
      
 12 
     | 
    
         
            +
            from rich.markdown import Markdown
         
     | 
| 
      
 13 
     | 
    
         
            +
            from rich.logging import RichHandler
         
     | 
| 
      
 14 
     | 
    
         
            +
            from rich.live import Live
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            LOGLEVEL = os.environ.get('LOGLEVEL', 'INFO').upper()
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            logging.basicConfig(
         
     | 
| 
      
 19 
     | 
    
         
            +
                level=getattr(logging, LOGLEVEL, logging.INFO),
         
     | 
| 
      
 20 
     | 
    
         
            +
                format="%(asctime)s %(filename)s:%(lineno)d %(levelname)s %(message)s",
         
     | 
| 
      
 21 
     | 
    
         
            +
                datefmt="[%X]",
         
     | 
| 
      
 22 
     | 
    
         
            +
                handlers=[RichHandler(rich_tracebacks=True)]
         
     | 
| 
      
 23 
     | 
    
         
            +
            )
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            # Global list to store error logs
         
     | 
| 
      
 26 
     | 
    
         
            +
            error_logs = []
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
            def display_interaction(message: str, response: str, markdown: bool = True, generation_time: Optional[float] = None):
         
     | 
| 
      
 29 
     | 
    
         
            +
                console = Console()
         
     | 
| 
      
 30 
     | 
    
         
            +
                if generation_time is not None:
         
     | 
| 
      
 31 
     | 
    
         
            +
                    console.print(Text(f"Response generated in {generation_time:.1f}s", style="dim"))
         
     | 
| 
      
 32 
     | 
    
         
            +
                else:
         
     | 
| 
      
 33 
     | 
    
         
            +
                    console.print(Text("Response Generation Complete", style="dim"))
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                if markdown:
         
     | 
| 
      
 36 
     | 
    
         
            +
                    console.print(Panel.fit(Markdown(message), title="Message", border_style="cyan"))
         
     | 
| 
      
 37 
     | 
    
         
            +
                    console.print(Panel.fit(Markdown(response), title="Response", border_style="cyan"))
         
     | 
| 
      
 38 
     | 
    
         
            +
                else:
         
     | 
| 
      
 39 
     | 
    
         
            +
                    console.print(Panel.fit(Text(message, style="bold green"), title="Message", border_style="cyan"))
         
     | 
| 
      
 40 
     | 
    
         
            +
                    console.print(Panel.fit(Text(response, style="bold white"), title="Response", border_style="cyan"))
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            def display_self_reflection(message: str):
         
     | 
| 
      
 43 
     | 
    
         
            +
                console = Console()
         
     | 
| 
      
 44 
     | 
    
         
            +
                console.print(Panel.fit(Text(message, style="bold yellow"), title="Self Reflection", border_style="magenta"))
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
            def display_instruction(message: str):
         
     | 
| 
      
 47 
     | 
    
         
            +
                console = Console()
         
     | 
| 
      
 48 
     | 
    
         
            +
                console.print(Panel.fit(Text(message, style="bold blue"), title="Instruction", border_style="cyan"))
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
            def display_tool_call(message: str):
         
     | 
| 
      
 51 
     | 
    
         
            +
                console = Console()
         
     | 
| 
      
 52 
     | 
    
         
            +
                console.print(Panel.fit(Text(message, style="bold cyan"), title="Tool Call", border_style="green"))
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
            def display_error(message: str):
         
     | 
| 
      
 55 
     | 
    
         
            +
                console = Console()
         
     | 
| 
      
 56 
     | 
    
         
            +
                console.print(Panel.fit(Text(message, style="bold red"), title="Error", border_style="red"))
         
     | 
| 
      
 57 
     | 
    
         
            +
                # Store errors
         
     | 
| 
      
 58 
     | 
    
         
            +
                error_logs.append(message)
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
            def display_generating(content: str = "", start_time: Optional[float] = None):
         
     | 
| 
      
 61 
     | 
    
         
            +
                elapsed_str = ""
         
     | 
| 
      
 62 
     | 
    
         
            +
                if start_time is not None:
         
     | 
| 
      
 63 
     | 
    
         
            +
                    elapsed = time.time() - start_time
         
     | 
| 
      
 64 
     | 
    
         
            +
                    elapsed_str = f" {elapsed:.1f}s"
         
     | 
| 
      
 65 
     | 
    
         
            +
                return Panel(Markdown(content), title=f"Generating...{elapsed_str}", border_style="green")
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
            def clean_triple_backticks(text: str) -> str:
         
     | 
| 
      
 68 
     | 
    
         
            +
                """Remove triple backticks and surrounding json fences from a string."""
         
     | 
| 
      
 69 
     | 
    
         
            +
                cleaned = text.strip()
         
     | 
| 
      
 70 
     | 
    
         
            +
                if cleaned.startswith("```json"):
         
     | 
| 
      
 71 
     | 
    
         
            +
                    cleaned = cleaned[len("```json"):].strip()
         
     | 
| 
      
 72 
     | 
    
         
            +
                if cleaned.startswith("```"):
         
     | 
| 
      
 73 
     | 
    
         
            +
                    cleaned = cleaned[len("```"):].strip()
         
     | 
| 
      
 74 
     | 
    
         
            +
                if cleaned.endswith("```"):
         
     | 
| 
      
 75 
     | 
    
         
            +
                    cleaned = cleaned[:-3].strip()
         
     | 
| 
      
 76 
     | 
    
         
            +
                return cleaned
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
            class ReflectionOutput(BaseModel):
         
     | 
| 
      
 79 
     | 
    
         
            +
                reflection: str
         
     | 
| 
      
 80 
     | 
    
         
            +
                satisfactory: Literal["yes", "no"]
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
            client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
            class TaskOutput(BaseModel):
         
     | 
| 
      
 85 
     | 
    
         
            +
                description: str
         
     | 
| 
      
 86 
     | 
    
         
            +
                summary: Optional[str] = None
         
     | 
| 
      
 87 
     | 
    
         
            +
                raw: str
         
     | 
| 
      
 88 
     | 
    
         
            +
                pydantic: Optional[BaseModel] = None
         
     | 
| 
      
 89 
     | 
    
         
            +
                json_dict: Optional[Dict[str, Any]] = None
         
     | 
| 
      
 90 
     | 
    
         
            +
                agent: str
         
     | 
| 
      
 91 
     | 
    
         
            +
                output_format: Literal["RAW", "JSON", "Pydantic"] = "RAW"
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                def json(self) -> Optional[str]:
         
     | 
| 
      
 94 
     | 
    
         
            +
                    if self.output_format == "JSON" and self.json_dict:
         
     | 
| 
      
 95 
     | 
    
         
            +
                        return json.dumps(self.json_dict)
         
     | 
| 
      
 96 
     | 
    
         
            +
                    return None
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                def to_dict(self) -> dict:
         
     | 
| 
      
 99 
     | 
    
         
            +
                    output_dict = {}
         
     | 
| 
      
 100 
     | 
    
         
            +
                    if self.json_dict:
         
     | 
| 
      
 101 
     | 
    
         
            +
                        output_dict.update(self.json_dict)
         
     | 
| 
      
 102 
     | 
    
         
            +
                    if self.pydantic:
         
     | 
| 
      
 103 
     | 
    
         
            +
                        output_dict.update(self.pydantic.model_dump())
         
     | 
| 
      
 104 
     | 
    
         
            +
                    return output_dict
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                def __str__(self):
         
     | 
| 
      
 107 
     | 
    
         
            +
                    if self.pydantic:
         
     | 
| 
      
 108 
     | 
    
         
            +
                        return str(self.pydantic)
         
     | 
| 
      
 109 
     | 
    
         
            +
                    elif self.json_dict:
         
     | 
| 
      
 110 
     | 
    
         
            +
                        return json.dumps(self.json_dict)
         
     | 
| 
      
 111 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 112 
     | 
    
         
            +
                        return self.raw 
         
     | 
| 
         @@ -0,0 +1,48 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            import logging
         
     | 
| 
      
 2 
     | 
    
         
            +
            from typing import List, Optional, Dict, Any, Type
         
     | 
| 
      
 3 
     | 
    
         
            +
            from pydantic import BaseModel
         
     | 
| 
      
 4 
     | 
    
         
            +
            from ..main import TaskOutput
         
     | 
| 
      
 5 
     | 
    
         
            +
            from ..agent.agent import Agent
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            class Task:
         
     | 
| 
      
 8 
     | 
    
         
            +
                def __init__(
         
     | 
| 
      
 9 
     | 
    
         
            +
                    self,
         
     | 
| 
      
 10 
     | 
    
         
            +
                    description: str,
         
     | 
| 
      
 11 
     | 
    
         
            +
                    expected_output: str,
         
     | 
| 
      
 12 
     | 
    
         
            +
                    agent: Optional[Agent] = None,
         
     | 
| 
      
 13 
     | 
    
         
            +
                    name: Optional[str] = None,
         
     | 
| 
      
 14 
     | 
    
         
            +
                    tools: Optional[List[Any]] = None,
         
     | 
| 
      
 15 
     | 
    
         
            +
                    context: Optional[List["Task"]] = None,
         
     | 
| 
      
 16 
     | 
    
         
            +
                    async_execution: Optional[bool] = False,
         
     | 
| 
      
 17 
     | 
    
         
            +
                    config: Optional[Dict[str, Any]] = None,
         
     | 
| 
      
 18 
     | 
    
         
            +
                    output_file: Optional[str] = None,
         
     | 
| 
      
 19 
     | 
    
         
            +
                    output_json: Optional[Type[BaseModel]] = None,
         
     | 
| 
      
 20 
     | 
    
         
            +
                    output_pydantic: Optional[Type[BaseModel]] = None,
         
     | 
| 
      
 21 
     | 
    
         
            +
                    callback: Optional[Any] = None,
         
     | 
| 
      
 22 
     | 
    
         
            +
                    status: str = "not started",
         
     | 
| 
      
 23 
     | 
    
         
            +
                    result: Optional[TaskOutput] = None,
         
     | 
| 
      
 24 
     | 
    
         
            +
                    create_directory: Optional[bool] = False,
         
     | 
| 
      
 25 
     | 
    
         
            +
                    id: Optional[int] = None
         
     | 
| 
      
 26 
     | 
    
         
            +
                ):
         
     | 
| 
      
 27 
     | 
    
         
            +
                    self.description = description
         
     | 
| 
      
 28 
     | 
    
         
            +
                    self.expected_output = expected_output
         
     | 
| 
      
 29 
     | 
    
         
            +
                    self.name = name
         
     | 
| 
      
 30 
     | 
    
         
            +
                    self.agent = agent
         
     | 
| 
      
 31 
     | 
    
         
            +
                    self.tools = tools if tools else []
         
     | 
| 
      
 32 
     | 
    
         
            +
                    self.context = context if context else []
         
     | 
| 
      
 33 
     | 
    
         
            +
                    self.async_execution = async_execution
         
     | 
| 
      
 34 
     | 
    
         
            +
                    self.config = config if config else {}
         
     | 
| 
      
 35 
     | 
    
         
            +
                    self.output_file = output_file
         
     | 
| 
      
 36 
     | 
    
         
            +
                    self.output_json = output_json
         
     | 
| 
      
 37 
     | 
    
         
            +
                    self.output_pydantic = output_pydantic
         
     | 
| 
      
 38 
     | 
    
         
            +
                    self.callback = callback
         
     | 
| 
      
 39 
     | 
    
         
            +
                    self.status = status
         
     | 
| 
      
 40 
     | 
    
         
            +
                    self.result = result
         
     | 
| 
      
 41 
     | 
    
         
            +
                    self.create_directory = create_directory
         
     | 
| 
      
 42 
     | 
    
         
            +
                    self.id = id
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                    if self.output_json and self.output_pydantic:
         
     | 
| 
      
 45 
     | 
    
         
            +
                        raise ValueError("Only one output type can be defined")
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                def __str__(self):
         
     | 
| 
      
 48 
     | 
    
         
            +
                    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}')" 
         
     | 
| 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            Metadata-Version: 2.1
         
     | 
| 
       2 
2 
     | 
    
         
             
            Name: praisonaiagents
         
     | 
| 
       3 
     | 
    
         
            -
            Version: 0.0. 
     | 
| 
       4 
     | 
    
         
            -
            Summary:  
     | 
| 
      
 3 
     | 
    
         
            +
            Version: 0.0.4
         
     | 
| 
      
 4 
     | 
    
         
            +
            Summary: Praison AI agents for completing complex tasks with Self Reflection Agents
         
     | 
| 
       5 
5 
     | 
    
         
             
            Author: Mervin Praison
         
     | 
| 
       6 
6 
     | 
    
         
             
            Requires-Dist: pydantic
         
     | 
| 
       7 
7 
     | 
    
         
             
            Requires-Dist: rich
         
     | 
| 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            praisonaiagents/__init__.py,sha256=gI8vEabBTRPsE_E8GA5sBMi4sTtJI-YokPrH2Nor-k0,741
         
     | 
| 
      
 2 
     | 
    
         
            +
            praisonaiagents/main.py,sha256=zDhN5KKtKbfruolDNxlyJkcFlkSt4KQkQTDRfQVAhxc,3960
         
     | 
| 
      
 3 
     | 
    
         
            +
            praisonaiagents/agent/__init__.py,sha256=sKO8wGEXvtCrvV1e834r1Okv0XAqAxqZCqz6hKLiTvA,79
         
     | 
| 
      
 4 
     | 
    
         
            +
            praisonaiagents/agent/agent.py,sha256=CCCjv-qtr6hSB-BG7C8l3z-pXQpnTkX9bW6me36YiaU,15512
         
     | 
| 
      
 5 
     | 
    
         
            +
            praisonaiagents/agents/__init__.py,sha256=7RDeQNSqZg5uBjD4M_0p_F6YgfWuDuxPFydPU50kDYc,120
         
     | 
| 
      
 6 
     | 
    
         
            +
            praisonaiagents/agents/agents.py,sha256=kgzesSMIOHB_ig_qJmCY5jzllaIcuy56jsJnFvpEAyk,13482
         
     | 
| 
      
 7 
     | 
    
         
            +
            praisonaiagents/build/lib/praisonaiagents/__init__.py,sha256=Nqnn8clbgv-5l0PgxcTOldg8mkMKrFn4TvPL-rYUUGg,1
         
     | 
| 
      
 8 
     | 
    
         
            +
            praisonaiagents/build/lib/praisonaiagents/main.py,sha256=zDhN5KKtKbfruolDNxlyJkcFlkSt4KQkQTDRfQVAhxc,3960
         
     | 
| 
      
 9 
     | 
    
         
            +
            praisonaiagents/build/lib/praisonaiagents/agent/__init__.py,sha256=sKO8wGEXvtCrvV1e834r1Okv0XAqAxqZCqz6hKLiTvA,79
         
     | 
| 
      
 10 
     | 
    
         
            +
            praisonaiagents/build/lib/praisonaiagents/agent/agent.py,sha256=PwbeW6v4Ldcl10JQr9_7TBfg4_FskQh-mGoFUdGxg8w,15483
         
     | 
| 
      
 11 
     | 
    
         
            +
            praisonaiagents/build/lib/praisonaiagents/agents/__init__.py,sha256=cgCLFLFcLp9SizmFSHUkH5aX-1seAAsRtQbtIHBBso4,101
         
     | 
| 
      
 12 
     | 
    
         
            +
            praisonaiagents/build/lib/praisonaiagents/agents/agents.py,sha256=P2FAtlfD3kPib5a1oLVYanxlU6e4-GhBMQ0YDY5MHY4,13473
         
     | 
| 
      
 13 
     | 
    
         
            +
            praisonaiagents/build/lib/praisonaiagents/task/__init__.py,sha256=VL5hXVmyGjINb34AalxpBMl-YW9m5EDcRkMTKkSSl7c,80
         
     | 
| 
      
 14 
     | 
    
         
            +
            praisonaiagents/build/lib/praisonaiagents/task/task.py,sha256=4Y1qX8OeEFcid2yhAiPYylvHpuDmWORsyNL16_BiVvI,1831
         
     | 
| 
      
 15 
     | 
    
         
            +
            praisonaiagents/task/__init__.py,sha256=VL5hXVmyGjINb34AalxpBMl-YW9m5EDcRkMTKkSSl7c,80
         
     | 
| 
      
 16 
     | 
    
         
            +
            praisonaiagents/task/task.py,sha256=4Y1qX8OeEFcid2yhAiPYylvHpuDmWORsyNL16_BiVvI,1831
         
     | 
| 
      
 17 
     | 
    
         
            +
            praisonaiagents-0.0.4.dist-info/METADATA,sha256=l-buIBQrgYLY8_1_qAQ6-ZqKJ1OlBNtjejWEFMcy4gQ,232
         
     | 
| 
      
 18 
     | 
    
         
            +
            praisonaiagents-0.0.4.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
         
     | 
| 
      
 19 
     | 
    
         
            +
            praisonaiagents-0.0.4.dist-info/top_level.txt,sha256=_HsRddrJ23iDx5TTqVUVvXG2HeHBL5voshncAMDGjtA,16
         
     | 
| 
      
 20 
     | 
    
         
            +
            praisonaiagents-0.0.4.dist-info/RECORD,,
         
     | 
| 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            praisonaiagents
         
     | 
| 
         @@ -1,12 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            agents/__init__.py,sha256=479EdtuXm27prpz83bfm6DCoUfx-W0u-LNIphAlqXDc,723
         
     | 
| 
       2 
     | 
    
         
            -
            agents/main.py,sha256=zDhN5KKtKbfruolDNxlyJkcFlkSt4KQkQTDRfQVAhxc,3960
         
     | 
| 
       3 
     | 
    
         
            -
            agents/agent/__init__.py,sha256=sKO8wGEXvtCrvV1e834r1Okv0XAqAxqZCqz6hKLiTvA,79
         
     | 
| 
       4 
     | 
    
         
            -
            agents/agent/agent.py,sha256=CCCjv-qtr6hSB-BG7C8l3z-pXQpnTkX9bW6me36YiaU,15512
         
     | 
| 
       5 
     | 
    
         
            -
            agents/agents/__init__.py,sha256=cgCLFLFcLp9SizmFSHUkH5aX-1seAAsRtQbtIHBBso4,101
         
     | 
| 
       6 
     | 
    
         
            -
            agents/agents/agents.py,sha256=P2FAtlfD3kPib5a1oLVYanxlU6e4-GhBMQ0YDY5MHY4,13473
         
     | 
| 
       7 
     | 
    
         
            -
            agents/task/__init__.py,sha256=VL5hXVmyGjINb34AalxpBMl-YW9m5EDcRkMTKkSSl7c,80
         
     | 
| 
       8 
     | 
    
         
            -
            agents/task/task.py,sha256=4Y1qX8OeEFcid2yhAiPYylvHpuDmWORsyNL16_BiVvI,1831
         
     | 
| 
       9 
     | 
    
         
            -
            praisonaiagents-0.0.2.dist-info/METADATA,sha256=hCCZISknDJwJREyP1L92Dot8Hk0fjE4XMhFAkeknOdo,199
         
     | 
| 
       10 
     | 
    
         
            -
            praisonaiagents-0.0.2.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
         
     | 
| 
       11 
     | 
    
         
            -
            praisonaiagents-0.0.2.dist-info/top_level.txt,sha256=OHAN-tVxGXbi966rMQE_BK7YyDEYoe-JL20jvf6URgI,7
         
     | 
| 
       12 
     | 
    
         
            -
            praisonaiagents-0.0.2.dist-info/RECORD,,
         
     | 
| 
         @@ -1 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            agents
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     |