├── LICENSE ├── README.md └── babyagi.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Yohei Nakajima 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # babyagi_og 2 | The original BabyAGI, updated with LiteLLM and no vector database reliance (csv instead). 3 | 4 | For more information on this, check out (babyagi_archive)[https://github.com/yoheinakajima/babyagi_archive] which is a snapshot of the original BabyAGI repo as of September 2024. 5 | -------------------------------------------------------------------------------- /babyagi.py: -------------------------------------------------------------------------------- 1 | from openai import OpenAI 2 | import os 3 | import time 4 | import csv 5 | import json 6 | from collections import deque 7 | from typing import Dict, List 8 | import math 9 | 10 | # Set API Keys and Model Names 11 | MODEL_COMPLETION = "gpt-4o-mini" 12 | MODEL_EMBEDDING = "text-embedding-ada-002" 13 | OPENAI_API_KEY = os.environ['OPENAI_API_KEY'] 14 | 15 | # Initialize OpenAI Client 16 | client = OpenAI(api_key=OPENAI_API_KEY) 17 | 18 | # Set Variables 19 | CSV_FILE = "task_data.csv" 20 | OBJECTIVE = "Brainstorm and execute a social media brand targeting youth around AI with an ecommerce strategy." 21 | YOUR_FIRST_TASK = "Develop a task list." 22 | 23 | # Print OBJECTIVE 24 | print("\033[96m\033[1m" + "\n*****OBJECTIVE*****\n" + "\033[0m\033[0m") 25 | print(OBJECTIVE) 26 | 27 | # Ensure CSV file exists 28 | if not os.path.isfile(CSV_FILE): 29 | with open(CSV_FILE, mode='w', newline='', encoding='utf-8') as file: 30 | writer = csv.DictWriter(file, fieldnames=['result_id', 'task_name', 'result', 'embedding']) 31 | writer.writeheader() 32 | 33 | # Task list 34 | task_list = deque([]) 35 | 36 | def add_task(task: Dict): 37 | task_list.append(task) 38 | 39 | def get_embedding(text: str) -> List[float]: 40 | """Generate embedding for the given text.""" 41 | text = text.replace("\n", " ") 42 | try: 43 | response = client.embeddings.create( 44 | model=MODEL_EMBEDDING, 45 | input=[text] 46 | ) 47 | return response.data[0].embedding 48 | except Exception as e: 49 | print(f"Error generating embedding: {e}") 50 | return [] 51 | 52 | def cosine_similarity(vec1: List[float], vec2: List[float]) -> float: 53 | """Calculate cosine similarity between two vectors.""" 54 | dot_product = sum(a * b for a, b in zip(vec1, vec2)) 55 | magnitude1 = math.sqrt(sum(a * a for a in vec1)) 56 | magnitude2 = math.sqrt(sum(b * b for b in vec2)) 57 | if magnitude1 == 0 or magnitude2 == 0: 58 | return 0.0 59 | return dot_product / (magnitude1 * magnitude2) 60 | 61 | def context_agent(query: str, n: int) -> List[str]: 62 | """Retrieve top N most similar tasks based on the query embedding.""" 63 | query_embedding = get_embedding(query) 64 | results = [] 65 | 66 | try: 67 | with open(CSV_FILE, mode='r', newline='', encoding='utf-8') as file: 68 | reader = csv.DictReader(file) 69 | for row in reader: 70 | stored_embedding = json.loads(row['embedding']) 71 | similarity = cosine_similarity(query_embedding, stored_embedding) 72 | results.append({ 73 | 'task': row['task_name'], 74 | 'result': row['result'], 75 | 'similarity': similarity 76 | }) 77 | except Exception as e: 78 | print(f"Error reading CSV file: {e}") 79 | 80 | # Sort by similarity descending and return top n 81 | sorted_results = sorted(results, key=lambda x: x['similarity'], reverse=True) 82 | top_results = sorted_results[:n] 83 | return [item['task'] for item in top_results] 84 | 85 | def task_creation_agent(objective: str, result: Dict, task_description: str, incomplete_tasks: List[str]) -> List[Dict]: 86 | """Create new tasks based on the execution result.""" 87 | prompt = ( 88 | f"You are a task creation AI that uses the result of an execution agent to create new tasks with the following objective: {objective}. " 89 | f"The last completed task has the result: {result}. This result was based on this task description: {task_description}. " 90 | f"These are incomplete tasks: {', '.join(incomplete_tasks)}. Based on the result, create new tasks to be completed by the AI system that do not overlap with incomplete tasks. " 91 | f"Return the tasks as a JSON array." 92 | ) 93 | try: 94 | response = client.chat.completions.create( 95 | model=MODEL_COMPLETION, 96 | messages=[ 97 | {"role": "system", "content": "You are a helpful task creation assistant."}, 98 | {"role": "user", "content": prompt} 99 | ], 100 | temperature=0.5, 101 | max_tokens=150 102 | ) 103 | new_tasks_text = response.choices[0].message.content.strip() 104 | new_tasks = json.loads(new_tasks_text) 105 | if isinstance(new_tasks, list): 106 | return [{"task_name": task.strip()} for task in new_tasks] 107 | except json.JSONDecodeError: 108 | # Fallback: split by lines if JSON parsing fails 109 | new_tasks = new_tasks_text.split('\n') 110 | return [{"task_name": task.strip()} for task in new_tasks if task.strip()] 111 | except Exception as e: 112 | print(f"Error in task_creation_agent: {e}") 113 | return [] 114 | 115 | def prioritization_agent(this_task_id: int): 116 | """Reprioritize the task list based on the objective.""" 117 | global task_list 118 | task_names = [t["task_name"] for t in task_list] 119 | next_task_id = this_task_id + 1 120 | prompt = ( 121 | f"""You are a task prioritization AI tasked with cleaning the formatting of and reprioritizing the following tasks: {task_names}. 122 | Consider the ultimate objective of your team: {OBJECTIVE}. Do not remove any tasks. 123 | Return the result as a numbered list, like: 124 | 1. First task 125 | 2. Second task 126 | Start the task list with number {next_task_id}.""" 127 | ) 128 | try: 129 | response = client.chat.completions.create( 130 | model=MODEL_COMPLETION, 131 | messages=[ 132 | {"role": "system", "content": "You are a helpful task prioritization assistant."}, 133 | {"role": "user", "content": prompt} 134 | ], 135 | temperature=0.5, 136 | max_tokens=1000 137 | ) 138 | new_tasks_text = response.choices[0].message.content.strip() 139 | new_tasks = new_tasks_text.split('\n') 140 | task_list = deque() 141 | for task_string in new_tasks: 142 | task_parts = task_string.strip().split(".", 1) 143 | if len(task_parts) == 2: 144 | task_id = task_parts[0].strip() 145 | task_name = task_parts[1].strip() 146 | task_list.append({"task_id": task_id, "task_name": task_name}) 147 | except Exception as e: 148 | print(f"Error in prioritization_agent: {e}") 149 | 150 | def execution_agent(objective: str, task: str) -> str: 151 | """Execute the given task based on the objective and context.""" 152 | context = context_agent(query=objective, n=5) 153 | prompt = f"Objective: {objective}\nTask: {task}\nResponse:" 154 | try: 155 | response = client.chat.completions.create( 156 | model=MODEL_COMPLETION, 157 | messages=[ 158 | {"role": "system", "content": "You are an AI who performs one task based on the given objective."}, 159 | {"role": "user", "content": prompt} 160 | ], 161 | temperature=0.7, 162 | max_tokens=2000 163 | ) 164 | return response.choices[0].message.content.strip() 165 | except Exception as e: 166 | print(f"Error in execution_agent: {e}") 167 | return "" 168 | 169 | # Add the first task 170 | first_task = { 171 | "task_id": 1, 172 | "task_name": YOUR_FIRST_TASK 173 | } 174 | 175 | add_task(first_task) 176 | 177 | # Main loop 178 | task_id_counter = 1 179 | while True: 180 | if task_list: 181 | # Print the task list 182 | print("\033[95m\033[1m" + "\n*****TASK LIST*****\n" + "\033[0m\033[0m") 183 | for t in task_list: 184 | print(f"{t['task_id']}: {t['task_name']}") 185 | 186 | # Step 1: Pull the first task 187 | task = task_list.popleft() 188 | print("\033[92m\033[1m" + "\n*****NEXT TASK*****\n" + "\033[0m\033[0m") 189 | print(f"{task['task_id']}: {task['task_name']}") 190 | 191 | # Send to execution function to complete the task based on the context 192 | result = execution_agent(OBJECTIVE, task["task_name"]) 193 | this_task_id = int(task["task_id"]) 194 | print("\033[93m\033[1m" + "\n*****TASK RESULT*****\n" + "\033[0m\033[0m") 195 | print(result) 196 | 197 | # Step 2: Enrich result and store in CSV 198 | enriched_result = {'data': result} # Enrichment can be added here if needed 199 | result_id = f"result_{task['task_id']}" 200 | vector = enriched_result['data'] # Extract the actual result from the dictionary 201 | embedding = get_embedding(vector) 202 | 203 | # Append to CSV 204 | try: 205 | with open(CSV_FILE, mode='a', newline='', encoding='utf-8') as file: 206 | writer = csv.DictWriter(file, fieldnames=['result_id', 'task_name', 'result', 'embedding']) 207 | writer.writerow({ 208 | 'result_id': result_id, 209 | 'task_name': task['task_name'], 210 | 'result': result, 211 | 'embedding': json.dumps(embedding) 212 | }) 213 | except Exception as e: 214 | print(f"Error writing to CSV: {e}") 215 | 216 | # Step 3: Create new tasks and reprioritize task list 217 | new_tasks = task_creation_agent( 218 | objective=OBJECTIVE, 219 | result=enriched_result['data'], 220 | task_description=task["task_name"], 221 | incomplete_tasks=[t["task_name"] for t in task_list] 222 | ) 223 | 224 | for new_task in new_tasks: 225 | task_id_counter += 1 226 | new_task.update({"task_id": task_id_counter}) 227 | add_task(new_task) 228 | 229 | prioritization_agent(this_task_id) 230 | 231 | time.sleep(1) # Sleep before checking the task list again 232 | --------------------------------------------------------------------------------