Update, API version.

This commit is contained in:
retoor 2025-09-28 08:31:47 +02:00
parent 05ab6c1476
commit 93bcd444d2

109
botje.py Normal file → Executable file
View File

@ -1,13 +1,11 @@
#!/usr/bin/env python3
import os
import argparse
import json
import subprocess
from openai import OpenAI
import sys
import shlex
import requests
# ANSI escape codes for colors
class Colors:
RED = '\033[91m'
GREEN = '\033[92m'
@ -17,28 +15,13 @@ class Colors:
CYAN = '\033[96m'
RESET = '\033[0m'
# Initialize the OpenAI client
# It will automatically pick up the OPENAI_API_KEY from your environment variables.
try:
client = OpenAI()
except ImportError:
print(f"{Colors.RED}OpenAI Python package not found. Please install it with 'pip install openai'{Colors.RESET}")
exit(1)
except Exception as e:
print(f"{Colors.RED}Error initializing OpenAI client: {e}{Colors.RESET}")
print(f"{Colors.YELLOW}Please ensure your OPENAI_API_KEY environment variable is set correctly.{Colors.RESET}")
api_key = os.environ.get("OPENAI_API_KEY")
if not api_key:
print(f"{Colors.RED}Error: OPENAI_API_KEY environment variable not set.{Colors.RESET}")
exit(1)
class AutonomousBot:
"""
An autonomous bot that executes tasks based on a user prompt.
It can call functions, manage its state, and decompose complex tasks.
"""
def __init__(self, prompt, memory=None):
"""
Initializes the bot with a prompt and an optional memory of past actions.
"""
self.initial_prompt = prompt
self.memory = memory if memory is not None else []
self.is_finished = False
@ -156,7 +139,6 @@ class AutonomousBot:
}
def get_system_prompt(self):
"""Constructs the system prompt for the AI model."""
return f"""You are an autonomous AI builder bot. Your goal is to accomplish the user's request by calling functions to interact with the system.
You have complete CRUD access to the filesystem and can execute terminal commands. Be aware of your actions and their consequences.
@ -179,10 +161,7 @@ Here is a summary of the steps taken so far:
"""
def run(self):
"""
Main execution loop for the bot.
"""
print(f"{Colors.GREEN}▶ Starting bot with prompt: '{self.initial_prompt}'{Colors.RESET}")
print(f"{Colors.GREEN}Starting bot with prompt: '{self.initial_prompt}'{Colors.RESET}")
messages = [
{"role": "system", "content": self.get_system_prompt()},
@ -191,21 +170,33 @@ Here is a summary of the steps taken so far:
while not self.is_finished:
try:
print(f"\n{Colors.BLUE}🤔 Thinking...{Colors.RESET}")
response = client.chat.completions.create(
model="gpt-4-turbo",
messages=messages,
tools=self.tools,
tool_choice="auto",
)
print(f"\n{Colors.BLUE}Thinking...{Colors.RESET}")
response_message = response.choices[0].message
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {api_key}"
}
payload = {
"model": "gpt-4-turbo",
"messages": messages,
"tools": self.tools,
"tool_choice": "auto"
}
response_raw = requests.post("https://api.openai.com/v1/chat/completions", headers=headers, json=payload)
if response_raw.status_code != 200:
print(f"{Colors.RED}Error from OpenAI API: {response_raw.status_code} - {response_raw.text}{Colors.RESET}")
break
response_json = response_raw.json()
response_message = response_json['choices'][0]['message']
messages.append(response_message)
tool_calls = response_message.tool_calls
tool_calls = response_message.get('tool_calls')
if not tool_calls:
print(f"\n{Colors.CYAN}🤖 AI Response (no tool call):{Colors.RESET}")
no_tool_call_message = response_message.content or "No text content in response."
print(f"\n{Colors.CYAN}AI Response (no tool call):{Colors.RESET}")
no_tool_call_message = response_message.get('content') or "No text content in response."
print(no_tool_call_message)
messages.append({
@ -215,25 +206,25 @@ Here is a summary of the steps taken so far:
continue
for tool_call in tool_calls:
function_name = tool_call.function.name
function_name = tool_call['function']['name']
function_to_call = self.available_functions.get(function_name)
function_args = {}
if not function_to_call:
print(f"{Colors.RED}Unknown function called by model: {function_name}{Colors.RESET}")
print(f"{Colors.RED}Unknown function called by model: {function_name}{Colors.RESET}")
tool_result = {"status": "error", "message": f"Unknown function: {function_name}"}
else:
try:
function_args = json.loads(tool_call.function.arguments)
print(f"\n{Colors.GREEN}Calling function: `{function_name}` with arguments:{Colors.RESET}")
function_args = json.loads(tool_call['function']['arguments'])
print(f"\n{Colors.GREEN}Calling function: `{function_name}` with arguments:{Colors.RESET}")
print(json.dumps(function_args, indent=2))
tool_result = function_to_call(**function_args)
except Exception as e:
print(f"{Colors.RED}Error calling function '{function_name}': {e}{Colors.RESET}")
print(f"{Colors.RED}Error calling function '{function_name}': {e}{Colors.RESET}")
tool_result = {"status": "error", "message": str(e)}
messages.append({
"tool_call_id": tool_call.id,
"tool_call_id": tool_call['id'],
"role": "tool",
"name": function_name,
"content": json.dumps(tool_result),
@ -245,7 +236,7 @@ Here is a summary of the steps taken so far:
})
except Exception as e:
print(f"\n{Colors.RED}An unexpected error occurred in the main loop: {e}{Colors.RESET}")
print(f"\n{Colors.RED}An unexpected error occurred in the main loop: {e}{Colors.RESET}")
break
def _write_file(self, filepath, content, purpose=""):
@ -256,10 +247,10 @@ Here is a summary of the steps taken so far:
with open(filepath, 'w', encoding='utf-8') as f:
f.write(content)
purpose_text = f" ({purpose})" if purpose else ""
print(f"{Colors.GREEN}File '{filepath}' created{purpose_text} successfully.{Colors.RESET}")
print(f"{Colors.GREEN}File '{filepath}' created{purpose_text} successfully.{Colors.RESET}")
return {"status": "success", "filepath": filepath}
except Exception as e:
print(f"{Colors.RED}Error creating file '{filepath}': {e}{Colors.RESET}")
print(f"{Colors.RED}Error creating file '{filepath}': {e}{Colors.RESET}")
return {"status": "error", "message": str(e)}
def create_file(self, filepath, content):
@ -272,25 +263,25 @@ Here is a summary of the steps taken so far:
try:
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
print(f"{Colors.GREEN}File '{filepath}' read successfully.{Colors.RESET}")
print(f"{Colors.GREEN}File '{filepath}' read successfully.{Colors.RESET}")
return {"status": "success", "content": content}
except FileNotFoundError:
print(f"{Colors.RED}File not found: '{filepath}'{Colors.RESET}")
print(f"{Colors.RED}File not found: '{filepath}'{Colors.RESET}")
return {"status": "error", "message": "File not found."}
except Exception as e:
print(f"{Colors.RED}Error reading file '{filepath}': {e}{Colors.RESET}")
print(f"{Colors.RED}Error reading file '{filepath}': {e}{Colors.RESET}")
return {"status": "error", "message": str(e)}
def delete_file(self, filepath):
try:
os.remove(filepath)
print(f"{Colors.GREEN}File '{filepath}' deleted successfully.{Colors.RESET}")
print(f"{Colors.GREEN}File '{filepath}' deleted successfully.{Colors.RESET}")
return {"status": "success", "filepath": filepath}
except FileNotFoundError:
print(f"{Colors.RED}File not found: '{filepath}'{Colors.RESET}")
print(f"{Colors.RED}File not found: '{filepath}'{Colors.RESET}")
return {"status": "error", "message": "File not found."}
except Exception as e:
print(f"{Colors.RED}Error deleting file '{filepath}': {e}{Colors.RESET}")
print(f"{Colors.RED}Error deleting file '{filepath}': {e}{Colors.RESET}")
return {"status": "error", "message": str(e)}
def terminal_execute(self, command):
@ -311,11 +302,11 @@ Here is a summary of the steps taken so far:
print(f" - Return Code: {result.returncode}")
return output
except Exception as e:
print(f"{Colors.RED}Error executing command '{command}': {e}{Colors.RESET}")
print(f"{Colors.RED}Error executing command '{command}': {e}{Colors.RESET}")
return {"status": "error", "message": str(e), "stdout": "", "stderr": str(e), "returncode": -1}
def finish_task(self, reason):
print(f"\n{Colors.YELLOW}🏁 BOT INSTANCE FINISHED: {reason}{Colors.RESET}")
print(f"\n{Colors.YELLOW}BOT INSTANCE FINISHED: {reason}{Colors.RESET}")
self.is_finished = True
return {"status": "finished"}
@ -323,13 +314,13 @@ Here is a summary of the steps taken so far:
print("\n" + "="*50)
print(" PYRAMID OF BUILDERS")
print("="*50)
print(f"{Colors.MAGENTA}🚀 Delegating remaining prompt to a new bot instance...{Colors.RESET}")
print(f"{Colors.MAGENTA}Delegating remaining prompt to a new bot instance...{Colors.RESET}")
print(f" python {__file__} \"{remaining_prompt}\"")
try:
subprocess.Popen([sys.executable, __file__, remaining_prompt])
print(f"{Colors.GREEN}New bot instance launched successfully.{Colors.RESET}")
print(f"{Colors.GREEN}New bot instance launched successfully.{Colors.RESET}")
except Exception as e:
print(f"{Colors.RED}Failed to launch new bot instance: {e}{Colors.RESET}")
print(f"{Colors.RED}Failed to launch new bot instance: {e}{Colors.RESET}")
return {"status": "error", "message": f"Failed to delegate: {e}"}
self.initial_prompt = current_task_prompt
@ -338,9 +329,6 @@ Here is a summary of the steps taken so far:
return {"status": "success", "message": "Task split. This bot will now handle the first part."}
def main():
"""
Entry point for the CLI application.
"""
parser = argparse.ArgumentParser(description="An autonomous bot to execute tasks.")
parser.add_argument("prompt", type=str, help="The user prompt describing the task to be done.")
args = parser.parse_args()
@ -350,3 +338,4 @@ def main():
if __name__ == "__main__":
main()