Skip to content
This repository was archived by the owner on Mar 9, 2026. It is now read-only.

Commit 924b8c6

Browse files
committed
Refactor configuration handling, add setup command. Resolves #3
This commit introduces a significant overhaul of the configuration handling in the AICodeBot. The OpenAI API key is no longer fetched directly from the environment variables in the cli.py file. Instead, a new helper function, get_config_file, has been added to helpers.py. This function checks if the AICODEBOT_CONFIG_FILE environment variable is set and uses its value as the path to the configuration file. If the environment variable is not set, it defaults to using a file named .aicodebot.yaml in the user's home directory. The setup command in cli.py has been updated to use this new function. It now also accepts a new option, --gpt-4-supported, which is a flag indicating whether the user has access to GPT-4. This information is stored in the configuration file along with the OpenAI API key. The setup_config function in cli.py has been updated to reflect these changes. It now accepts two arguments: the OpenAI API key and a boolean indicating whether GPT-4 is supported. If the OpenAI API key is not provided, the function will attempt to fetch it from the environment variables or prompt the user to enter it. The function then validates the API key and checks if GPT-4 is supported (unless the --gpt-4-supported flag was used). The configuration data is then written to the configuration file. The read_config function in helpers.py has also been updated to use the new get_config_file function. Finally, tests have been added to test_cli.py to test the new setup command and the changes to the configuration handling.
1 parent fce0488 commit 924b8c6

File tree

3 files changed

+110
-33
lines changed

3 files changed

+110
-33
lines changed

aicodebot/cli.py

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from aicodebot import version as aicodebot_version
22
from aicodebot.helpers import (
33
exec_and_get_output,
4+
get_config_file,
45
get_llm_model,
56
get_token_length,
67
git_diff_context,
@@ -26,7 +27,6 @@
2627
PRECISE_TEMPERATURE = 0
2728
CREATIVE_TEMPERATURE = 0.7
2829
DEFAULT_SPINNER = "point"
29-
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
3030

3131
# ----------------------- Setup for rich console output ---------------------- #
3232

@@ -295,23 +295,24 @@ def review(commit, verbose):
295295

296296
@cli.command()
297297
@click.option("--openai-api-key", "-k", help="Your OpenAI API key")
298-
def setup(openai_api_key):
298+
@click.option("--gpt-4-supported", "-4", help="Whether you have access to GPT-4", is_flag=True)
299+
def setup(openai_api_key, gpt_4_supported):
299300
"""Set up the configuration file with your OpenAI API key
300301
If the config file already exists, it will ask you if you want to remove it and recreate it.
301302
"""
302-
config_file = Path(read_config.CONFIG_FILE)
303+
config_file = get_config_file()
303304
if config_file.exists():
304305
if not click.confirm(
305306
f"The config file already exists at {config_file}. Do you want to remove it and recreate it?"
306307
):
307308
console.print("Setup cancelled. 🚫")
308-
return
309+
sys.exit(1)
309310

310311
# Remove the existing config file
311312
config_file.unlink()
312313

313314
# Call the setup_config function with the provided arguments
314-
setup_config(openai_api_key)
315+
setup_config(openai_api_key, gpt_4_supported)
315316

316317

317318
@cli.command
@@ -392,18 +393,21 @@ def sidekick(request, verbose, files):
392393
# ---------------------------------------------------------------------------- #
393394

394395

395-
def setup_config(openai_api_key=OPENAI_API_KEY):
396+
def setup_config(openai_api_key=None, gpt_4_supported=None):
396397
config = read_config()
398+
openai.api_key = openai_api_key
397399
if config:
398400
openai.api_key = config["OPENAI_API_KEY"]
401+
logger.success(f"Using OpenAI API key from {get_config_file()}")
399402
return config
400-
elif openai_api_key:
401-
openai.api_key = openai_api_key
403+
elif os.getenv("OPENAI_API_KEY"):
404+
logger.info("Using OPENAI_API_KEY environment variable")
405+
openai.api_key = os.getenv("OPENAI_API_KEY")
402406

403-
console.print(
404-
f"[bold red]The config file does not exist.[/bold red]\n"
405-
f"Let's set that up for you at {read_config.CONFIG_FILE}\n"
406-
)
407+
logger.info(f"openai.api_key {openai.api_key}")
408+
409+
config_file = get_config_file()
410+
console.print(f"[bold red]The config file does not exist.[/bold red]\nLet's set that up for you at {config_file}\n")
407411

408412
if not openai.api_key:
409413
openai_api_key_url = "https://platform.openai.com/account/api-keys"
@@ -417,30 +421,33 @@ def setup_config(openai_api_key=OPENAI_API_KEY):
417421

418422
openai.api_key = click.prompt("Please enter your OpenAI API key")
419423

424+
logger.info(f"openai.api_key 2 {openai.api_key}")
420425
# Validate the API key and check if it supports GPT-4
421-
try:
422-
click.echo("Validating the API key, and checking if GPT-4 is supported...")
423-
engines = engine.Engine.list()
424-
logger.trace(f"Engines: {engines}")
425-
gpt_4_supported = "gpt-4" in [engine.id for engine in engines.data]
426-
if gpt_4_supported:
427-
click.echo("✅ The API key is valid and supports GPT-4.")
428-
else:
429-
click.echo("✅ The API key is valid, but does not support GPT-4. GPT-3.5 will be used instead.")
430-
except Exception as e:
431-
raise click.ClickException(f"Failed to validate the API key: {str(e)}") from e
426+
if gpt_4_supported is None:
427+
try:
428+
click.echo("Validating the API key, and checking if GPT-4 is supported...")
429+
engines = engine.Engine.list()
430+
logger.trace(f"Engines: {engines}")
431+
gpt_4_supported = "gpt-4" in [engine.id for engine in engines.data]
432+
if gpt_4_supported:
433+
click.echo("✅ The API key is valid and supports GPT-4.")
434+
else:
435+
click.echo("✅ The API key is valid, but does not support GPT-4. GPT-3.5 will be used instead.")
436+
except Exception as e:
437+
raise click.ClickException(f"Failed to validate the API key: {str(e)}") from e
432438

433439
config_data = {"config_version": 1, "OPENAI_API_KEY": openai.api_key, "gpt_4_supported": gpt_4_supported}
434440

435-
with Path.open(read_config.CONFIG_FILE, "w") as f:
441+
logger.info(f"openai.api_key 3 {openai.api_key}")
442+
443+
with Path.open(config_file, "w") as f:
436444
yaml.dump(config_data, f)
437445

438446
console.print(
439-
f"[bold green]Created {read_config.CONFIG_FILE} with your OpenAI API key.[/bold green] "
447+
f"[bold green]Created {config_file} with your OpenAI API key.[/bold green] "
440448
"Now, please re-run aicodebot and let's get started!"
441449
)
442450
sys.exit(0)
443-
return config_data
444451

445452

446453
class RichLiveCallbackHandler(BaseCallbackHandler):

aicodebot/helpers.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -124,14 +124,22 @@ def exec_and_get_output(command):
124124
return result.stdout
125125

126126

127+
def get_config_file():
128+
if "AICODEBOT_CONFIG_FILE" in os.environ:
129+
config_file = Path(os.getenv("AICODEBOT_CONFIG_FILE"))
130+
else:
131+
config_file = Path(Path.home() / ".aicodebot.yaml")
132+
logger.debug(f"Using config file {config_file}")
133+
return config_file
134+
135+
127136
def read_config():
128-
if read_config.CONFIG_FILE.exists():
129-
logger.debug(f"Config file {read_config.CONFIG_FILE} exists")
130-
with Path(read_config.CONFIG_FILE).open("r") as f:
137+
"""Read the config file and return its contents as a dictionary."""
138+
config_file = get_config_file()
139+
if config_file.exists():
140+
logger.debug(f"Config file {config_file} exists")
141+
with Path(config_file).open("r") as f:
131142
return yaml.safe_load(f)
132143
else:
133-
logger.debug(f"Config file {read_config.CONFIG_FILE} does not exist")
144+
logger.debug(f"Config file {config_file} does not exist")
134145
return None
135-
136-
137-
read_config.CONFIG_FILE = Path(Path.home() / ".aicodebot.yaml")

tests/test_cli.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from aicodebot import version as aicodebot_version
22
from aicodebot.cli import cli
3+
from aicodebot.helpers import read_config
4+
from pathlib import Path
35
import os, pytest
46

57

@@ -33,3 +35,63 @@ def test_debug_failure(cli_runner):
3335
result = cli_runner.invoke(cli, ["debug", "ls", "-9"])
3436
assert result.exit_code > 0, f"Output: {result.output}"
3537
assert "ls -9" in result.output
38+
39+
40+
def test_setup(cli_runner, tmp_path, monkeypatch):
41+
# Unset the environment variable for the OpenAI API key
42+
monkeypatch.delenv("OPENAI_API_KEY", raising=False)
43+
assert not os.getenv("OPENAI_API_KEY")
44+
45+
temp_config_file = Path(tmp_path / ".aicodebot.test.yaml")
46+
# set AICODEBOT_CONFIG_FILE to the temp config file
47+
monkeypatch.setenv("AICODEBOT_CONFIG_FILE", str(temp_config_file))
48+
49+
assert os.getenv("AICODEBOT_CONFIG_FILE") == str(temp_config_file)
50+
51+
assert read_config() is None
52+
53+
# Run the setup command
54+
result = cli_runner.invoke(cli, ["setup", "--openai-api-key", "fake_api_key", "--gpt-4-supported"])
55+
56+
# Check if the command was successful
57+
assert result.exit_code == 0, f"Output: {result.output}"
58+
59+
# Check if the config file was created
60+
assert Path(temp_config_file).exists()
61+
62+
# Load the config file
63+
config_data = read_config()
64+
65+
# Check if the config file contains the correct data
66+
assert config_data == {"config_version": 1, "OPENAI_API_KEY": "fake_api_key", "gpt_4_supported": True}
67+
68+
# Run the setup command again, should fail because the config file already exists
69+
result = cli_runner.invoke(cli, ["setup", "--openai-api-key", "fake_api_key", "--gpt-4-supported"])
70+
assert result.exit_code == 1, f"Output: {result.output}"
71+
assert "Setup cancelled" in result.output
72+
73+
74+
def test_setup_with_openai_key(cli_runner, tmp_path, monkeypatch):
75+
monkeypatch.setenv("OPENAI_API_KEY", "fake_api_key2")
76+
assert os.getenv("OPENAI_API_KEY") == "fake_api_key2"
77+
78+
temp_config_file = Path(tmp_path / ".aicodebot.test.yaml")
79+
# set AICODEBOT_CONFIG_FILE to the temp config file
80+
monkeypatch.setenv("AICODEBOT_CONFIG_FILE", str(temp_config_file))
81+
82+
assert read_config() is None
83+
84+
# Run the setup command
85+
result = cli_runner.invoke(cli, ["setup"])
86+
87+
# Check if the command was successful
88+
assert result.exit_code == 0, f"Output: {result.output}"
89+
90+
# Check if the config file was created
91+
assert Path(temp_config_file).exists()
92+
93+
# Load the config file
94+
config_data = read_config()
95+
96+
# Check if the config file contains the correct data
97+
assert config_data == {"config_version": 1, "OPENAI_API_KEY": "fake_api_key2", "gpt_4_supported": False}

0 commit comments

Comments
 (0)