diff --git a/OS/01/.gitignore b/.gitignore similarity index 100% rename from OS/01/.gitignore rename to .gitignore diff --git a/OS/01/_archive/core/__init__.py b/OS/01/__init__.py similarity index 100% rename from OS/01/_archive/core/__init__.py rename to OS/01/__init__.py diff --git a/OS/01/_archive/core/__pycache__/core.cpython-310.pyc b/OS/01/_archive/core/__pycache__/core.cpython-310.pyc deleted file mode 100644 index 08501b6..0000000 Binary files a/OS/01/_archive/core/__pycache__/core.cpython-310.pyc and /dev/null differ diff --git a/OS/01/assistant/conversations/user.json b/OS/01/assistant/conversations/user.json deleted file mode 100644 index eb1136c..0000000 --- a/OS/01/assistant/conversations/user.json +++ /dev/null @@ -1 +0,0 @@ -[{"role": "user", "type": "message", "content": "And it works really well.\n"}] \ No newline at end of file diff --git a/OS/01/assistant/create_interpreter.py b/OS/01/assistant/create_interpreter.py deleted file mode 100644 index 7f2f473..0000000 --- a/OS/01/assistant/create_interpreter.py +++ /dev/null @@ -1,131 +0,0 @@ -from interpreter import interpreter -import os -import glob -import json -import requests - -def create_interpreter(): - ### SYSTEM MESSAGE - - # The system message is where most of the 01's behavior is configured. - # You can put code into the system message {{ in brackets like this }} which will be rendered just before the interpreter starts writing a message. - - system_message = """ - -You are an executive assistant AI that helps the user manage their tasks. You can run Python code. - -Store the user's tasks in a Python list called `tasks`. - ---- - -The user's current task is: {{ tasks[0] if tasks else "No current tasks." }} - -{{ -if len(tasks) > 1: - print("The next task is: ", tasks[1]) -}} - ---- - -When the user completes the current task, you should remove it from the list and read the next item by running `tasks = tasks[1:]\ntasks[0]`. Then, tell the user what the next task is. - -When the user tells you about a set of tasks, you should intelligently order tasks, batch similar tasks, and break down large tasks into smaller tasks (for this, you should consult the user and get their permission to break it down). Your goal is to manage the task list as intelligently as possible, to make the user as efficient and non-overwhelmed as possible. They will require a lot of encouragement, support, and kindness. Don't say too much about what's ahead of them— just try to focus them on each step at a time. - -After starting a task, you should check in with the user around the estimated completion time to see if the task is completed. Use the `schedule(datetime, message)` function, which has already been imported. - -To do this, schedule a reminder based on estimated completion time using the function `schedule(datetime_object, "Your message here.")`, WHICH HAS ALREADY BEEN IMPORTED. YOU DON'T NEED TO IMPORT THE `schedule` FUNCTION. IT IS AVALIABLE. You'll recieve the message at `datetime_object`. - -You guide the user through the list one task at a time, convincing them to move forward, giving a pep talk if need be. Your job is essentially to answer "what should I (the user) be doing right now?" for every moment of the day. - -Remember: You can run Python code. Be very concise. Ensure that you actually run code every time! THIS IS IMPORTANT. You NEED to write code. **Help the user by being very concise in your answers.** Do not break down tasks excessively, just into simple, few minute steps. Don't assume the user lives their life in a certain way— pick very general tasks if you're breaking a task down. - - """.strip() - - interpreter.custom_instructions = system_message - - ### LLM SETTINGS - - # Local settings - # interpreter.llm.model = "local" - # interpreter.llm.api_base = "https://localhost:8080/v1" # Llamafile default - # interpreter.llm.max_tokens = 1000 - # interpreter.llm.context_window = 3000 - - # Hosted settings - interpreter.llm.api_key = os.getenv('OPENAI_API_KEY') - interpreter.llm.model = "gpt-4" - interpreter.auto_run = True - interpreter.force_task_completion = False - - - ### MISC SETTINGS - - interpreter.offline = True - interpreter.id = 206 # Used to identify itself to other interpreters. This should be changed programatically so it's unique. - - - ### RESET conversations/user.json - - script_dir = os.path.dirname(os.path.abspath(__file__)) - user_json_path = os.path.join(script_dir, 'conversations', 'user.json') - with open(user_json_path, 'w') as file: - json.dump([], file) - - - ### CONNECT TO /run - - class Python: - """ - This class contains all requirements for being a custom language in Open Interpreter: - - - name (an attribute) - - run (a method) - - stop (a method) - - terminate (a method) - """ - - # This is the name that will appear to the LLM. - name = "python" - - def __init__(self): - self.halt = False - - def run(self, code): - """Generator that yields a dictionary in LMC Format.""" - - # Prepare the data - data = {"language": "python", "code": code} - - # Send the data to the /run endpoint - computer_port = os.getenv('COMPUTER_PORT', '9000') - response = requests.post(f"http://localhost:{computer_port}/run", json=data, stream=True) - # Stream the response - for chunk in response.iter_content(chunk_size=100000000): - if self.halt: - self.halt = False - break - if chunk: # filter out keep-alive new lines - yield json.loads(chunk.decode()) - - def stop(self): - self.halt = True - - def terminate(self): - """Terminates the entire process.""" - # dramatic!! - pass - - interpreter.computer.languages = [Python] - - ### SKILLS - - script_dir = os.path.dirname(os.path.abspath(__file__)) - skills_dir = os.path.join(script_dir, 'skills') - for file in glob.glob(os.path.join(skills_dir, '*.py')): - with open(file, 'r') as f: - for chunk in interpreter.computer.run("python", f.read()): - print(chunk) - - ### RETURN INTERPRETER - - return interpreter \ No newline at end of file diff --git a/OS/01/assistant/conversations/another-interpreter.json b/OS/01/conversations/another-interpreter.json similarity index 100% rename from OS/01/assistant/conversations/another-interpreter.json rename to OS/01/conversations/another-interpreter.json diff --git a/OS/01/conversations/user.json b/OS/01/conversations/user.json new file mode 100644 index 0000000..89007e9 --- /dev/null +++ b/OS/01/conversations/user.json @@ -0,0 +1 @@ +[{"role": "user", "type": "message", "content": "\ub2e4\uc74c \uc601\uc0c1\uc5d0\uc11c \ub9cc\ub098\uc694!\n"}] \ No newline at end of file diff --git a/OS/01/user/user.py b/OS/01/device.py similarity index 77% rename from OS/01/user/user.py rename to OS/01/device.py index 2a50636..a6a128b 100644 --- a/OS/01/user/user.py +++ b/OS/01/device.py @@ -13,6 +13,11 @@ import ast from pydub import AudioSegment from pydub.playback import play import io +import wave +import tempfile +from datetime import datetime +from utils.check_filtered_kernel import check_filtered_kernel +from interpreter import interpreter # Just for code execution. Maybe we should let people do from interpreter.computer import run? # Configuration for Audio Recording CHUNK = 1024 # Record in chunks of 1024 samples @@ -23,18 +28,13 @@ RECORDING = False # Flag to control recording state SPACEBAR_PRESSED = False # Flag to track spacebar press state # Configuration for WebSocket -PORT = os.getenv('ASSISTANT_PORT', '8000') -WS_URL = f"ws://localhost:{PORT}/user" +WS_URL = os.getenv('SERVER_URL') +if not WS_URL: + raise ValueError("The environment variable SERVER_URL is not set. Please set it to proceed.") # Initialize PyAudio p = pyaudio.PyAudio() - -import wave -import tempfile -from datetime import datetime - - def record_audio(): """Record audio from the microphone and add it to the queue.""" stream = p.open(format=FORMAT, channels=CHANNELS, rate=RATE, input=True, frames_per_buffer=CHUNK) @@ -110,8 +110,15 @@ async def websocket_communication(WS_URL): print("Press the spacebar to start/stop recording. Press ESC to exit.") asyncio.create_task(message_sender(websocket)) + message_so_far = {"role": None, "type": None, "format": None, "content": None} + async for message in websocket: - print(message) + + if "content" in message_so_far: + if any(message_so_far[key] != message[key] for key in message_so_far): + message_so_far = message + else: + message_so_far["content"] += message if message["type"] == "audio" and "content" in message: audio_bytes = bytes(ast.literal_eval(message["content"])) @@ -124,8 +131,18 @@ async def websocket_communication(WS_URL): play(audio) await asyncio.sleep(1) + + # Run the code if that's the device's job + if os.getenv('CODE_RUNNER') == "device": + if message["type"] == "code" and "end" in message: + language = message_so_far["format"] + code = message_so_far["content"] + result = interpreter.computer.run(language, code) + send_queue.put(result) + + except: - print("Connecting...") + print(f"Connecting to `{WS_URL}`...") await asyncio.sleep(2) def main(): @@ -140,4 +157,4 @@ def main(): p.terminate() if __name__ == "__main__": - main() + main() \ No newline at end of file diff --git a/OS/01/i.py b/OS/01/i.py new file mode 100644 index 0000000..9bfd478 --- /dev/null +++ b/OS/01/i.py @@ -0,0 +1,82 @@ +import os +import glob +import json +import requests +from pathlib import Path + +def configure_interpreter(interpreter): + ### SYSTEM MESSAGE + + # The system message is where most of the 01's behavior is configured. + # You can put code into the system message {{ in brackets like this }} which will be rendered just before the interpreter starts writing a message. + + system_message = """ + + You are an executive assistant AI that helps the user manage their tasks. You can run Python code. + + Store the user's tasks in a Python list called `tasks`. + + --- + + The user's current task is: {{ tasks[0] if tasks else "No current tasks." }} + + {{ + if len(tasks) > 1: + print("The next task is: ", tasks[1]) + }} + + --- + + When the user completes the current task, you should remove it from the list and read the next item by running `tasks = tasks[1:]\ntasks[0]`. Then, tell the user what the next task is. + + When the user tells you about a set of tasks, you should intelligently order tasks, batch similar tasks, and break down large tasks into smaller tasks (for this, you should consult the user and get their permission to break it down). Your goal is to manage the task list as intelligently as possible, to make the user as efficient and non-overwhelmed as possible. They will require a lot of encouragement, support, and kindness. Don't say too much about what's ahead of them— just try to focus them on each step at a time. + + After starting a task, you should check in with the user around the estimated completion time to see if the task is completed. Use the `schedule(datetime, message)` function, which has already been imported. + + To do this, schedule a reminder based on estimated completion time using the function `schedule(datetime_object, "Your message here.")`, WHICH HAS ALREADY BEEN IMPORTED. YOU DON'T NEED TO IMPORT THE `schedule` FUNCTION. IT IS AVALIABLE. You'll recieve the message at `datetime_object`. + + You guide the user through the list one task at a time, convincing them to move forward, giving a pep talk if need be. Your job is essentially to answer "what should I (the user) be doing right now?" for every moment of the day. + + Remember: You can run Python code. Be very concise. Ensure that you actually run code every time! THIS IS IMPORTANT. You NEED to write code. **Help the user by being very concise in your answers.** Do not break down tasks excessively, just into simple, few minute steps. Don't assume the user lives their life in a certain way— pick very general tasks if you're breaking a task down. + + """.strip() + + interpreter.custom_instructions = system_message + + ### LLM SETTINGS + + # Local settings + # interpreter.llm.model = "local" + # interpreter.llm.api_base = "https://localhost:8080/v1" # Llamafile default + # interpreter.llm.max_tokens = 1000 + # interpreter.llm.context_window = 3000 + + # Hosted settings + interpreter.llm.api_key = os.getenv('OPENAI_API_KEY') + interpreter.llm.model = "gpt-4" + interpreter.auto_run = True + interpreter.force_task_completion = False + + + ### MISC SETTINGS + + interpreter.offline = True + interpreter.id = 206 # Used to identify itself to other interpreters. This should be changed programatically so it's unique. + + + ### RESET conversations/user.json + + script_dir = os.path.dirname(os.path.abspath(__file__)) + user_json_path = os.path.join(script_dir, 'conversations', 'user.json') + with open(user_json_path, 'w') as file: + json.dump([], file) + + ### SKILLS + + skills_path = Path(__file__).parent / 'skills' + for file in glob.glob(os.path.join(skills_path, '*.py')): + with open(file, 'r') as f: + for chunk in interpreter.computer.run("python", f.read()): + print(chunk) + + return interpreter \ No newline at end of file diff --git a/OS/01/assistant/llm/start.py b/OS/01/llm.py similarity index 50% rename from OS/01/assistant/llm/start.py rename to OS/01/llm.py index 1d7a1f6..49a39bc 100644 --- a/OS/01/assistant/llm/start.py +++ b/OS/01/llm.py @@ -1,26 +1,11 @@ -""" -Responsible for setting up the language model, downloading it if necessary. - -Ideally should pick the best LLM for the hardware. - -Should this be a shell script? -""" - import os import subprocess - +from pathlib import Path ### LLM SETUP -# Define the path to the models directory -models_dir = "models/" - -# Check and create the models directory if it doesn't exist -if not os.path.exists(models_dir): - os.makedirs(models_dir) - # Define the path to a llamafile -llamafile_path = os.path.join(models_dir, "phi-2.Q4_K_M.llamafile") +llamafile_path = Path(__file__).parent / 'model.llamafile' # Check if the new llamafile exists, if not download it if not os.path.exists(llamafile_path): @@ -36,5 +21,5 @@ if not os.path.exists(llamafile_path): # Make the new llamafile executable subprocess.run(["chmod", "+x", llamafile_path], check=True) -# Run the new llamafile in the background -subprocess.Popen([llamafile_path]) \ No newline at end of file +# Run the new llamafile +subprocess.run([str(llamafile_path)], check=True) \ No newline at end of file diff --git a/OS/01/_archive/interface/__init__.py b/OS/01/models/phi-2.llamafile similarity index 100% rename from OS/01/_archive/interface/__init__.py rename to OS/01/models/phi-2.llamafile diff --git a/OS/01/requirements.txt b/OS/01/requirements.txt index 0c4cf75..63a9d47 100644 --- a/OS/01/requirements.txt +++ b/OS/01/requirements.txt @@ -1,6 +1,6 @@ git+https://github.com/KillianLucas/open-interpreter.git asyncio -pyaudio +PyAudio pynput fastapi uvicorn diff --git a/OS/01/computer/run.py b/OS/01/run.py similarity index 100% rename from OS/01/computer/run.py rename to OS/01/run.py diff --git a/OS/01/assistant/assistant.py b/OS/01/server.py similarity index 67% rename from OS/01/assistant/assistant.py rename to OS/01/server.py index 9e54643..16f2a9e 100644 --- a/OS/01/assistant/assistant.py +++ b/OS/01/server.py @@ -1,11 +1,3 @@ -""" -Exposes a POST endpoint called /computer. Things from there go into the queue. - -Exposes a ws endpoint called /user. Things from there go into the queue. We also send things in the queue back (that are role: assistant) - -In a while loop we watch the queue and handle it. -""" - from starlette.websockets import WebSocketDisconnect import ast import json @@ -19,18 +11,18 @@ import re from fastapi import FastAPI from threading import Thread from starlette.websockets import WebSocket -from create_interpreter import create_interpreter from stt import stt from tts import tts from pathlib import Path +import asyncio +from i import configure_interpreter +import urllib.parse +from interpreter import interpreter -# Create interpreter -interpreter = create_interpreter() +app = FastAPI() conversation_history_path = Path(__file__).parent / 'conversations' / 'user.json' - - # This is so we only say() full sentences def is_full_sentence(text): return text.endswith(('.', '!', '?')) @@ -38,19 +30,59 @@ def is_full_sentence(text): def split_into_sentences(text): return re.split(r'(?<=[.!?])\s+', text) -app = FastAPI() +# Global queues +receive_queue = queue.Queue() +send_queue = queue.Queue() +recieve_computer_queue = queue.Queue() # Just for computer messages from the device +# Switch code executor to device if that's set +if os.getenv('CODE_RUNNER') == "device": -import asyncio + # (This should probably just loop through all languages and apply these changes instead) + class Python: + # This is the name that will appear to the LLM. + name = "python" -# Global queues -receive_queue = queue.Queue() -send_queue = queue.Queue() + def __init__(self): + self.halt = False + + def run(self, code): + """Generator that yields a dictionary in LMC Format.""" + + # Prepare the data + message = {"role": "assistant", "type": "code", "format": "python", "content": code} + + # Unless it was just sent to the device, send it wrapped in flags + if not (interpreter.messages and interpreter.messages[-1] == message): + send_queue.put({"role": "assistant", "type": "code", "format": "python", "start": True}) + send_queue.put(message) + send_queue.put({"role": "assistant", "type": "code", "format": "python", "end": True}) + + # Stream the response + print("Waiting for the device to respond...") + while True: + chunk = recieve_computer_queue.get() + print("Server recieved from device:", chunk) + if "end" in chunk: + break + yield chunk + + def stop(self): + self.halt = True + + def terminate(self): + """Terminates the entire process.""" + # dramatic!! do nothing + pass + interpreter.computer.languages = [Python] -@app.websocket("/user") +# Configure interpreter +interpreter = configure_interpreter(interpreter) + +@app.websocket("/") async def websocket_endpoint(websocket: WebSocket): await websocket.accept() receive_task = asyncio.create_task(receive_messages(websocket)) @@ -60,35 +92,16 @@ async def websocket_endpoint(websocket: WebSocket): async def receive_messages(websocket: WebSocket): while True: data = await websocket.receive_text() - receive_queue.put(data) + if type(data) == dict and data["role"] == "computer": + recieve_computer_queue.put(data) # To be handled by interpreter.computer.run + else: + receive_queue.put(data) async def send_messages(websocket: WebSocket): while True: message = await asyncio.get_event_loop().run_in_executor(None, send_queue.get) print(message) await websocket.send_json(message) - - - - - - - -@app.post("/computer") -async def read_computer(item: dict): - await asyncio.get_event_loop().run_in_executor(None, receive_queue.put, item) - - - - - - - - - - - - def queue_listener(): audio_file = bytearray() @@ -173,4 +186,9 @@ queue_thread.start() # Run the FastAPI app if __name__ == "__main__": - uvicorn.run(app, host="0.0.0.0", port=int(os.getenv('ASSISTANT_PORT', 8000))) + server_url = os.getenv('SERVER_URL') + if not server_url: + raise ValueError("The environment variable SERVER_URL is not set. Please set it to proceed.") + parsed_url = urllib.parse.urlparse(server_url) + print("Starting `server.py`...") + uvicorn.run(app, host=parsed_url.hostname, port=parsed_url.port) diff --git a/OS/01/assistant/skills/schedule.py b/OS/01/skills/schedule.py similarity index 100% rename from OS/01/assistant/skills/schedule.py rename to OS/01/skills/schedule.py diff --git a/OS/01/start.sh b/OS/01/start.sh index 01a261a..130c5ef 100755 --- a/OS/01/start.sh +++ b/OS/01/start.sh @@ -1,51 +1,72 @@ ### SETTINGS -export MODE_01=LIGHT -export ASSISTANT_PORT=8000 -export COMPUTER_PORT=8001 +# If ALL_LOCAL is False, we'll use OpenAI's services +export ALL_LOCAL=False +# export OPENAI_API_KEY=sk-... -# Kill whatever's on the ASSISTANT_PORT and COMPUTER_PORT -lsof -ti tcp:$ASSISTANT_PORT | xargs kill -lsof -ti tcp:$COMPUTER_PORT | xargs kill +# If SERVER_START, this is where we'll serve the server. +# If DEVICE_START, this is where the device expects the server to be. +export SERVER_URL=ws://localhost:8000/ +export SERVER_START=True +export DEVICE_START=True + +# Control where various operations happen— can be `device` or `server`. +export CODE_RUNNER=server +export TTS_RUNNER=device # If server, audio will be sent over websocket. +export STT_RUNNER=device # If server, audio will be sent over websocket. + +# Will expose the server publically and display that URL. +export SERVER_EXPOSE_PUBLICALLY=False ### SETUP +# (for dev, reset the ports we were using) + +PORT=$(echo $SERVER_URL | grep -oE "[0-9]+") +lsof -ti tcp:$PORT | xargs kill +PORT=$(echo $DEVICE_URL | grep -oE "[0-9]+") +lsof -ti tcp:$PORT | xargs kill + +# Check the current Python version +PYTHON_VERSION=$(python -V 2>&1 | cut -d " " -f 2 | cut -d "." -f 1-2) + +# If the Python version is not 3.10 or 3.11, switch to it using pyenv +if [[ "$PYTHON_VERSION" != "3.10" ]] && [[ "$PYTHON_VERSION" != "3.11" ]]; then + echo "Switching to Python 3.10 using pyenv..." + pyenv install 3.10.0 + pyenv shell 3.10.0 +fi + # INSTALL REQUIREMENTS +# (for dev, this is disabled for speed) + # if [[ "$OSTYPE" == "darwin"* ]]; then # brew update # brew install portaudio ffmpeg # fi # pip install -r requirements.txt -### COMPUTER +### START -# START KERNEL WATCHER +# DEVICE -python computer/kernel_watcher.py & +if [[ "$DEVICE_START" == "True" ]]; then + python device.py & +fi -# START RUN ENDPOINT +# SERVER -python computer/run.py & +if [[ "$SERVER_START" == "True" ]]; then + python server.py & +fi -# START SST AND TTS SERVICES +# TTS, STT # (todo) # (i think we should start with hosted services) -# START LLM +# LLM # (disabled, we'll start with hosted services) -# python core/llm/start.py & - -sleep 6 - -# START ASSISTANT - -python assistant/assistant.py & - -### USER - -# START USER - -python user/user.py & \ No newline at end of file +# python core/llm/start.py & \ No newline at end of file diff --git a/OS/01/assistant/stt.py b/OS/01/stt.py similarity index 100% rename from OS/01/assistant/stt.py rename to OS/01/stt.py diff --git a/OS/01/assistant/tts.py b/OS/01/tts.py similarity index 100% rename from OS/01/assistant/tts.py rename to OS/01/tts.py diff --git a/OS/01/assistant/__init__.py b/OS/01/utils/__init__.py similarity index 100% rename from OS/01/assistant/__init__.py rename to OS/01/utils/__init__.py diff --git a/OS/01/computer/kernel_watcher.py b/OS/01/utils/check_filtered_kernel.py similarity index 71% rename from OS/01/computer/kernel_watcher.py rename to OS/01/utils/check_filtered_kernel.py index 383609e..f31c6ac 100644 --- a/OS/01/computer/kernel_watcher.py +++ b/OS/01/utils/check_filtered_kernel.py @@ -1,13 +1,5 @@ -""" -Watches the kernel. When it sees something that passes a filter, -it sends POST request with that to /computer. -""" - import subprocess -import time -import requests import platform -import os def get_kernel_messages(): """ @@ -40,22 +32,15 @@ def custom_filter(message): else: return None +last_messages = "" -def main(): - last_messages = "" - while True: +def check_filtered_kernel(): messages = get_kernel_messages() messages.replace(last_messages, "") messages = messages.split("\n") - messages_for_core = [] + filtered_messages = [] for message in messages: if custom_filter(message): - messages_for_core.append(message) - if messages_for_core: - port = os.getenv('ASSISTANT_PORT', 8000) - requests.post(f'http://localhost:{port}/computer', json = {'messages': messages_for_core}) - time.sleep(5) - -if __name__ == "__main__": - main() + filtered_messages.append(message) + return filtered_messages \ No newline at end of file diff --git a/OS/01/utils/run_endpoint.py b/OS/01/utils/run_endpoint.py new file mode 100644 index 0000000..d3e9ead --- /dev/null +++ b/OS/01/utils/run_endpoint.py @@ -0,0 +1,28 @@ +""" +Exposes a SSE streaming server endpoint at /run, which recieves language and code, +and streams the output. +""" +import os +import json +from interpreter import interpreter +import uvicorn + +from fastapi import FastAPI +from fastapi.responses import StreamingResponse +from pydantic import BaseModel + +class Code(BaseModel): + language: str + code: str + +app = FastAPI() + +@app.post("/run") +async def run_code(code: Code): + def generator(): + for chunk in interpreter.computer.run(code.language, code.code): + yield json.dumps(chunk) + return StreamingResponse(generator()) + +if __name__ == "__main__": + uvicorn.run(app, host="0.0.0.0", port=int(os.getenv('COMPUTER_PORT', 9000))) \ No newline at end of file diff --git a/OS/README.md b/OS/README.md index ab6a056..ac79cfa 100644 --- a/OS/README.md +++ b/OS/README.md @@ -1,3 +1,32 @@ +# New: The 8th Architecture + +``` +/01 + start.sh # entrypoint, runs server, device, llm + server.py # uses tts and stt if it must, exposes "/" + device.py # also uses tts and stt, hits "/" + llm.py # starts an openai-compatible server + model.llamafile + i.py # creates an interpreter which server just imports + tts.py + stt.py + /conversations + user.json + /skills # files in here will run in the 01's interpreter + schedule.py + ... +``` + +This is flatter and simpler. + +**Device** handles the device — i.e. everything the user interacts + watching the kernel + running code (which produces `computer` LMC messages) if `DEVICE_EXECUTE_CODE` is true. Runs TTS and STT, sends LMC messages to "/". + +**Server** serves "/", a websocket that accepts `user` LMC messages and sends back `assistant` LMC messages. Runs code (which produces `computer` LMC messages) if `SERVER_EXECUTE_CODE` is true. + +**Llm** starts an OpenAI-compatible server with `model.llamafile`. Downloads a heavily quantized Phi-2 if `model.llamafile` doesn't exist. + +**I** creates an `interpreter` object. This is where you configure the 01's behavior. + # What is this? This is the operating system that powers the 01. diff --git a/OS/01/assistant/llm/models/mistral.llamafile b/OS/_archive/core/__init__.py similarity index 100% rename from OS/01/assistant/llm/models/mistral.llamafile rename to OS/_archive/core/__init__.py diff --git a/OS/01/_archive/core/core.py b/OS/_archive/core/core.py similarity index 100% rename from OS/01/_archive/core/core.py rename to OS/_archive/core/core.py diff --git a/OS/01/_archive/core/i_endpoint.py b/OS/_archive/core/i_endpoint.py similarity index 100% rename from OS/01/_archive/core/i_endpoint.py rename to OS/_archive/core/i_endpoint.py diff --git a/OS/01/_archive/core/kernel_watch.py b/OS/_archive/core/kernel_watch.py similarity index 100% rename from OS/01/_archive/core/kernel_watch.py rename to OS/_archive/core/kernel_watch.py diff --git a/OS/01/_archive/core/start_core.py b/OS/_archive/core/start_core.py similarity index 100% rename from OS/01/_archive/core/start_core.py rename to OS/_archive/core/start_core.py diff --git a/OS/01/assistant/llm/models/moonbeam.llamafile b/OS/_archive/interface/__init__.py similarity index 100% rename from OS/01/assistant/llm/models/moonbeam.llamafile rename to OS/_archive/interface/__init__.py diff --git a/OS/01/_archive/interface/candidate_animation.html b/OS/_archive/interface/candidate_animation.html similarity index 100% rename from OS/01/_archive/interface/candidate_animation.html rename to OS/_archive/interface/candidate_animation.html diff --git a/OS/01/_archive/interface/display.html b/OS/_archive/interface/display.html similarity index 100% rename from OS/01/_archive/interface/display.html rename to OS/_archive/interface/display.html diff --git a/OS/01/_archive/interface/interface.py b/OS/_archive/interface/interface.py similarity index 100% rename from OS/01/_archive/interface/interface.py rename to OS/_archive/interface/interface.py diff --git a/OS/01/_archive/listen.py b/OS/_archive/listen.py similarity index 100% rename from OS/01/_archive/listen.py rename to OS/_archive/listen.py diff --git a/OS/01/user/record.py b/OS/_archive/record.py similarity index 100% rename from OS/01/user/record.py rename to OS/_archive/record.py