Move API credentials to .env and set gpt-5.6-luna model
- Load OPENAI_API_KEY and OPENAI_BASE_URL from gitignored .env (repo-root, CWD-independent) - Fix command explanation to use the configured model instead of hardcoded gpt-4o-mini - Update default model and fallbacks to gpt-5.6-luna - Document .env-based configuration in READMEs
This commit is contained in:
@@ -1 +1,2 @@
|
|||||||
OPENAI_API_KEY="your-openai-api-key-here"
|
OPENAI_API_KEY="your-openai-api-key-here"
|
||||||
|
OPENAI_BASE_URL="https://api.openai.com/v1"
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ Arguments:
|
|||||||
--theme <theme> : Set syntax highlighting theme (e.g., monokai, github-dark)
|
--theme <theme> : Set syntax highlighting theme (e.g., monokai, github-dark)
|
||||||
|
|
||||||
Current configuration per edison.yaml:
|
Current configuration per edison.yaml:
|
||||||
* Model : gpt-4o-mini
|
* Model : gpt-5.6-luna
|
||||||
* Temperature : 0
|
* Temperature : 0
|
||||||
* Max. Tokens : 500
|
* Max. Tokens : 500
|
||||||
* Safety : on
|
* Safety : on
|
||||||
@@ -64,13 +64,27 @@ cd command-assistant
|
|||||||
.\install_edison.bat
|
.\install_edison.bat
|
||||||
```
|
```
|
||||||
|
|
||||||
## OpenAI API Key Configuration
|
## API Configuration
|
||||||
|
|
||||||
Configure your OpenAI API key using one of these methods:
|
Edison needs an API key (and, when using a proxy, a base URL) to talk to your model backend. The recommended way is a `.env` file in the repository root, which is gitignored and therefore never checked in:
|
||||||
|
|
||||||
- Environment variable: `export OPENAI_API_KEY=<yourkey>` (Linux/macOS) or `$env:OPENAI_API_KEY="<yourkey>"` (Windows)
|
```bash
|
||||||
- Create a file at `~/.openai.apikey` with just the key
|
# .env (do not commit this file)
|
||||||
- Add the key to the `edison.yaml` configuration file
|
OPENAI_API_KEY="your-api-key"
|
||||||
|
OPENAI_BASE_URL="https://api.openai.com/v1"
|
||||||
|
```
|
||||||
|
|
||||||
|
Copy `.env.example` to get started:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also provide the key using any of these methods (in order of precedence):
|
||||||
|
|
||||||
|
- `OPENAI_API_KEY` / `OPENAI_BASE_URL` environment variables (or in `.env`)
|
||||||
|
- A file at `~/.openai.apikey` containing just the key
|
||||||
|
- The `openai_api_key` / `base_url` entries in `edison.yaml`
|
||||||
|
|
||||||
## Usage Examples
|
## Usage Examples
|
||||||
|
|
||||||
|
|||||||
+12
-3
@@ -80,7 +80,7 @@ The rich terminal UI provides:
|
|||||||
Edison can be configured via the `edison.yaml` file. Here's an example configuration:
|
Edison can be configured via the `edison.yaml` file. Here's an example configuration:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
model: gpt-3.5-turbo
|
model: gpt-5.6-luna
|
||||||
temperature: 0
|
temperature: 0
|
||||||
max_tokens: 500
|
max_tokens: 500
|
||||||
safety: true
|
safety: true
|
||||||
@@ -88,13 +88,22 @@ safety: true
|
|||||||
|
|
||||||
## API Key
|
## API Key
|
||||||
|
|
||||||
Edison requires an OpenAI API key to function. You can provide it in one of the following ways:
|
Edison requires an API key to function. The recommended way is a `.env` file in the repository root (gitignored, so not checked in):
|
||||||
|
|
||||||
|
```
|
||||||
|
OPENAI_API_KEY="your-api-key"
|
||||||
|
OPENAI_BASE_URL="https://api.openai.com/v1"
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also provide it in one of the following ways:
|
||||||
|
|
||||||
1. Environment variable: `OPENAI_API_KEY="your-api-key"`
|
1. Environment variable: `OPENAI_API_KEY="your-api-key"`
|
||||||
2. `.env` file in the same directory as the script
|
2. `.env` file in the repository root
|
||||||
3. `.openai.apikey` file in your home directory
|
3. `.openai.apikey` file in your home directory
|
||||||
4. In the `edison.yaml` configuration file: `openai_api_key: "your-api-key"`
|
4. In the `edison.yaml` configuration file: `openai_api_key: "your-api-key"`
|
||||||
|
|
||||||
|
When using a custom backend or proxy, set `OPENAI_BASE_URL` (or `base_url` in `edison.yaml`) to its endpoint.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT
|
MIT
|
||||||
|
|||||||
@@ -11,6 +11,31 @@ from edison.utils import logging_utils
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def get_env_path():
|
||||||
|
"""
|
||||||
|
Get the path to the project's `.env` file, independent of the current working directory.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The absolute path to the `.env` file at the repository root.
|
||||||
|
"""
|
||||||
|
project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
|
return os.path.join(project_root, ".env")
|
||||||
|
|
||||||
|
def get_base_url(config):
|
||||||
|
"""
|
||||||
|
Get the API base URL from the environment or config.
|
||||||
|
|
||||||
|
Prefers the `OPENAI_BASE_URL` environment variable, falling back to the
|
||||||
|
`base_url` value in the provided config dictionary.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config (dict): A dictionary containing configuration values.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str or None: The API base URL, or None if not set.
|
||||||
|
"""
|
||||||
|
return os.getenv("OPENAI_BASE_URL") or config.get("base_url")
|
||||||
|
|
||||||
def get_api_key(config):
|
def get_api_key(config):
|
||||||
"""
|
"""
|
||||||
Get the OpenAI API key from various sources.
|
Get the OpenAI API key from various sources.
|
||||||
@@ -26,7 +51,7 @@ def get_api_key(config):
|
|||||||
Returns:
|
Returns:
|
||||||
str: The OpenAI API key
|
str: The OpenAI API key
|
||||||
"""
|
"""
|
||||||
dotenv.load_dotenv()
|
dotenv.load_dotenv(get_env_path())
|
||||||
|
|
||||||
# Method 1: Read API key from environment variable
|
# Method 1: Read API key from environment variable
|
||||||
# The user can set their OpenAI API key by creating a ".env" file in the same
|
# The user can set their OpenAI API key by creating a ".env" file in the same
|
||||||
@@ -68,6 +93,9 @@ def create_client(config):
|
|||||||
OpenAI: An initialized OpenAI client.
|
OpenAI: An initialized OpenAI client.
|
||||||
"""
|
"""
|
||||||
api_key = get_api_key(config)
|
api_key = get_api_key(config)
|
||||||
|
base_url = get_base_url(config)
|
||||||
|
if base_url:
|
||||||
|
return OpenAI(api_key=api_key, base_url=base_url)
|
||||||
return OpenAI(api_key=api_key)
|
return OpenAI(api_key=api_key)
|
||||||
|
|
||||||
def call_api(client, config, query):
|
def call_api(client, config, query):
|
||||||
@@ -95,7 +123,7 @@ def call_api(client, config, query):
|
|||||||
try:
|
try:
|
||||||
# Use the modern API pattern
|
# Use the modern API pattern
|
||||||
response = client.chat.completions.create(
|
response = client.chat.completions.create(
|
||||||
model=config.get("model", "gpt-4o-mini"),
|
model=config.get("model", "gpt-5.6-luna"),
|
||||||
messages=[
|
messages=[
|
||||||
{"role": "system", "content": system_prompt},
|
{"role": "system", "content": system_prompt},
|
||||||
{"role": "user", "content": prompt}
|
{"role": "user", "content": prompt}
|
||||||
@@ -137,7 +165,7 @@ def call_api_streaming(client, config, query, callback):
|
|||||||
try:
|
try:
|
||||||
# Use the streaming API pattern
|
# Use the streaming API pattern
|
||||||
response = client.chat.completions.create(
|
response = client.chat.completions.create(
|
||||||
model=config.get("model", "gpt-4o-mini"),
|
model=config.get("model", "gpt-5.6-luna"),
|
||||||
messages=[
|
messages=[
|
||||||
{"role": "system", "content": system_prompt},
|
{"role": "system", "content": system_prompt},
|
||||||
{"role": "user", "content": prompt}
|
{"role": "user", "content": prompt}
|
||||||
|
|||||||
+8
-3
@@ -1,7 +1,10 @@
|
|||||||
model: gpt-4o-mini # Default model for command generation
|
model: gpt-5.6-luna # Default model for command generation
|
||||||
temperature: 0
|
temperature: 0
|
||||||
max_tokens: 500
|
max_tokens: 500
|
||||||
|
|
||||||
|
# API base URL (optional): Set via OPENAI_BASE_URL in .env, or uncomment below
|
||||||
|
# base_url: https://api.openai.com/v1
|
||||||
|
|
||||||
# Safety: If set to False, commands returned from the AI will be run *without* prompting the user.
|
# Safety: If set to False, commands returned from the AI will be run *without* prompting the user.
|
||||||
safety: True
|
safety: True
|
||||||
|
|
||||||
@@ -27,5 +30,7 @@ ui:
|
|||||||
# Structured explanations: Generate more structured command explanations
|
# Structured explanations: Generate more structured command explanations
|
||||||
structured_explanations: True
|
structured_explanations: True
|
||||||
|
|
||||||
# Open AI API Key (optional): The key can aso be provided via environment variable (OPENAI_API_KEY), .env, or ~/.openai.apikey file
|
# OpenAI API Key (optional): The key can be provided via .env (OPENAI_API_KEY),
|
||||||
openai_api_key:
|
# an environment variable, or the ~/.openai.apikey file. Prefer .env so the key
|
||||||
|
# is not checked into version control.
|
||||||
|
# openai_api_key: your-api-key-here
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ def handle_command_execution(client, config, command, explain=False):
|
|||||||
use_rich = ui_config.get("rich_formatting", True)
|
use_rich = ui_config.get("rich_formatting", True)
|
||||||
|
|
||||||
# Generate explanation
|
# Generate explanation
|
||||||
explanation = get_command_explanation(client, command, structured=structured)
|
explanation = get_command_explanation(client, command, structured=structured, model=config.get("model"))
|
||||||
|
|
||||||
if use_rich:
|
if use_rich:
|
||||||
print() # Add a blank line before the explanation
|
print() # Add a blank line before the explanation
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ def handle_streaming_output_interactive(token):
|
|||||||
# Print the token without a newline and flush immediately
|
# Print the token without a newline and flush immediately
|
||||||
print(token, end='', flush=True)
|
print(token, end='', flush=True)
|
||||||
|
|
||||||
def get_command_explanation(client, command, structured=False):
|
def get_command_explanation(client, command, structured=False, model=None):
|
||||||
"""
|
"""
|
||||||
Get an explanation for a command.
|
Get an explanation for a command.
|
||||||
|
|
||||||
@@ -33,6 +33,7 @@ def get_command_explanation(client, command, structured=False):
|
|||||||
client: The OpenAI client.
|
client: The OpenAI client.
|
||||||
command (str): The command to explain.
|
command (str): The command to explain.
|
||||||
structured (bool): Whether to use structured explanation format.
|
structured (bool): Whether to use structured explanation format.
|
||||||
|
model (str): The model to use for explanation.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: The explanation of the command.
|
str: The explanation of the command.
|
||||||
@@ -61,7 +62,7 @@ def get_command_explanation(client, command, structured=False):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
response = client.chat.completions.create(
|
response = client.chat.completions.create(
|
||||||
model="gpt-4o-mini",
|
model=model or "gpt-5.6-luna",
|
||||||
messages=[
|
messages=[
|
||||||
{"role": "system", "content": system_prompt},
|
{"role": "system", "content": system_prompt},
|
||||||
{"role": "user", "content": command}
|
{"role": "user", "content": command}
|
||||||
@@ -284,7 +285,7 @@ def interactive_mode(client, config):
|
|||||||
use_rich = ui_config.get("rich_formatting", True)
|
use_rich = ui_config.get("rich_formatting", True)
|
||||||
|
|
||||||
# Generate explanation
|
# Generate explanation
|
||||||
explanation = get_command_explanation(client, command, structured=structured)
|
explanation = get_command_explanation(client, command, structured=structured, model=config.get("model"))
|
||||||
|
|
||||||
if use_rich:
|
if use_rich:
|
||||||
print() # Add a blank line before the explanation
|
print() # Add a blank line before the explanation
|
||||||
|
|||||||
Reference in New Issue
Block a user