diff --git a/interpreter/__init__.py b/interpreter/__init__.py index 7ed72105b..688fd4aaf 100644 --- a/interpreter/__init__.py +++ b/interpreter/__init__.py @@ -12,17 +12,20 @@ Configuration ------------ ->>> from interpreter import Interpreter, Config +>>> from interpreter import Interpreter, Profile -# Use defaults -interpreter = Interpreter() +Use defaults: -# Load from custom profile -config = Config.from_file("~/custom_profile.json") -interpreter = Interpreter(config) +>>> interpreter = Interpreter() + +Load from custom profile: + +>>> profile = Profile.from_file("~/custom_profile.py") +>>> interpreter = Interpreter(profile) + +Save current settings: -# Save current settings -interpreter.save_config("~/my_settings.json") +>>> interpreter.save_profile("~/my_settings.py") """ # Use lazy imports to avoid loading heavy modules immediately diff --git a/interpreter/cli.py b/interpreter/cli.py index 26b011dcb..6a391e22b 100644 --- a/interpreter/cli.py +++ b/interpreter/cli.py @@ -270,10 +270,16 @@ def parse_args(): subprocess.run([opener, profile_dir]) sys.exit(0) + # If custom profile specified, load it and update args if args["profile"] != profile.profile_path: - profile.load(args["profile"]) + # Load the specified profile, ignoring any defaults + profile = Profile.from_file(args["profile"]) + # Find which settings were explicitly set via command line flags + cli_provided = {k for k,v in parser._option_string_actions.items() + if v.dest in args and sys.argv.__contains__(k)} + # Update args with profile values, preserving any CLI overrides for key, value in vars(profile).items(): - if key in args and args[key] is None: + if key in args and key not in cli_provided: args[key] = value if args["save"]: diff --git a/interpreter/interpreter.py b/interpreter/interpreter.py index ab3cfdd3c..61cccce65 100644 --- a/interpreter/interpreter.py +++ b/interpreter/interpreter.py @@ -93,17 +93,20 @@ class Interpreter: -------- >>> from interpreter import Interpreter - # Basic usage - interpreter = Interpreter() - interpreter.chat() + Basic usage: - # With custom configuration - from interpreter import Profile - profile = Profile.from_file("~/custom_profile.json") - interpreter = Interpreter(profile) + >>> interpreter = Interpreter() + >>> interpreter.chat() - # Save settings for later - interpreter.save_profile("~/my_settings.json") + With custom configuration: + + >>> from interpreter import Profile + >>> profile = Profile.from_file("~/custom_profile.py") + >>> interpreter = Interpreter(profile) + + Save settings for later: + + >>> interpreter.save_profile("~/my_settings.py") Parameters ---------- @@ -152,7 +155,7 @@ def load_profile(self, path): Load settings from a profile file Example: - >>> interpreter.load_profile("~/work_settings.json") + >>> interpreter.load_profile("~/work_settings.py") """ self._profile.load(path) # Update interpreter attributes from new profile @@ -164,7 +167,7 @@ def save_profile(self, path=None): Save current settings as a profile Example: - >>> interpreter.save_profile("~/my_preferred_settings.json") + >>> interpreter.save_profile("~/my_preferred_settings.py") """ # Update profile object with current values self._profile.from_dict(self.to_dict()) @@ -177,7 +180,7 @@ def from_profile(cls, path): Create new interpreter instance from a profile file Example: - >>> interpreter = Interpreter.from_profile("~/work_settings.json") + >>> interpreter = Interpreter.from_profile("~/work_settings.py") """ return cls(Profile.from_file(path)) diff --git a/interpreter/misc/welcome.py b/interpreter/misc/welcome.py index 512f577ab..220d30175 100644 --- a/interpreter/misc/welcome.py +++ b/interpreter/misc/welcome.py @@ -254,9 +254,9 @@ def welcome_message(): --serve Start in server mode example: interpreter "create a python script" -example: interpreter -m gpt-4 "analyze data.csv" +example: interpreter -m gpt-4 "analyze data.csv" example: interpreter --auto-run "install nodejs" -example: interpreter --profile work.json +example: interpreter --profile work.py """ ) @@ -282,9 +282,9 @@ def welcome_message(): --serve Start in server mode example: interpreter "create a python script" -example: interpreter -m gpt-4 "analyze data.csv" +example: interpreter -m gpt-4 "analyze data.csv" example: interpreter --auto-run "install nodejs" -example: interpreter --profile work.json +example: interpreter --profile work.py """ ) diff --git a/interpreter/profiles.py b/interpreter/profiles.py index 140361c14..e522ca65e 100644 --- a/interpreter/profiles.py +++ b/interpreter/profiles.py @@ -1,8 +1,5 @@ -import json import os -import platform import sys -from datetime import datetime class Profile: @@ -16,14 +13,17 @@ class Profile: -------- >>> from interpreter import Profile - # Load defaults (and ~/.openinterpreter if it exists) - profile = Profile() + Load defaults (and ~/.openinterpreter if it exists): - # Load from specific profile - profile = Profile.from_file("~/custom_profile.json") + >>> profile = Profile() - # Save current settings - profile.save("~/my_settings.json") + Load from specific profile: + + >>> profile = Profile.from_file("~/custom_profile.py") + + Save current settings: + + >>> profile.save("~/my_settings.py") """ DEFAULT_PROFILE_FOLDER = "~/.openinterpreter" @@ -69,7 +69,7 @@ def __init__(self): # Debug settings self.debug = False # Whether to enable debug mode - # Set default path but don't load from it + # Initialize with default path (which may be overridden in from_file) self.profile_path = self.DEFAULT_PROFILE_PATH def to_dict(self): @@ -129,12 +129,16 @@ def load(self, path): path += ".py" if not os.path.exists(path): - # If file doesn't exist, if it's the default, that's fine + # If the missing file is the default profile path, that's fine - + # we'll use the defaults from __init__ if os.path.abspath(os.path.expanduser(path)) == os.path.abspath( os.path.expanduser(self.DEFAULT_PROFILE_PATH) ): return raise FileNotFoundError(f"Profile file not found at {path}") + else: + # Update profile_path when loading succeeds + self.profile_path = os.path.abspath(path) # Create a temporary namespace to execute the profile in namespace = {} @@ -147,7 +151,9 @@ def load(self, path): # This avoids loading the full interpreter module which is resource intensive content = content.replace( "from interpreter import interpreter", - "class Interpreter:\n pass\ninterpreter = Interpreter()", + "class Interpreter:\n" + " pass\n" + "interpreter = Interpreter()", ) # Execute the modified profile content @@ -168,4 +174,6 @@ def from_file(cls, path): """Create a new profile instance from a file""" profile = cls() profile.load(path) + # Update profile_path after successful load + profile.profile_path = os.path.abspath(os.path.expanduser(path)) return profile