Skip to content

Commit e229321

Browse files
authored
support fireworks dev tier (#258)
* support fireworks dev tier * more fixes * fix tests
1 parent a39b535 commit e229321

File tree

5 files changed

+558
-61
lines changed

5 files changed

+558
-61
lines changed

eval_protocol/auth.py

Lines changed: 92 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,48 @@
66

77
logger = logging.getLogger(__name__)
88

9+
# Default locations (used for tests and as fallback). Actual resolution is dynamic via _get_auth_ini_file().
910
FIREWORKS_CONFIG_DIR = Path.home() / ".fireworks"
1011
AUTH_INI_FILE = FIREWORKS_CONFIG_DIR / "auth.ini"
1112

1213

14+
def _get_profile_base_dir() -> Path:
15+
"""
16+
Resolve the Fireworks configuration base directory following firectl behavior:
17+
- Default: ~/.fireworks
18+
- If FIREWORKS_PROFILE is set and non-empty: ~/.fireworks/profiles/<profile>
19+
"""
20+
profile_name = os.environ.get("FIREWORKS_PROFILE", "").strip()
21+
base_dir = Path.home() / ".fireworks"
22+
if profile_name:
23+
base_dir = base_dir / "profiles" / profile_name
24+
return base_dir
25+
26+
27+
def _get_auth_ini_file() -> Path:
28+
"""
29+
Determine the auth.ini file path.
30+
Priority:
31+
1) FIREWORKS_AUTH_FILE env var when set
32+
2) ~/.fireworks[/profiles/<profile>]/auth.ini (profile driven)
33+
"""
34+
auth_file_env = os.environ.get("FIREWORKS_AUTH_FILE")
35+
if auth_file_env:
36+
return Path(auth_file_env)
37+
return _get_profile_base_dir() / "auth.ini"
38+
39+
40+
def _is_profile_active() -> bool:
41+
"""
42+
Returns True if a specific profile or explicit auth file is active.
43+
In this case, profile-based credentials should take precedence over env vars.
44+
"""
45+
if os.environ.get("FIREWORKS_AUTH_FILE"):
46+
return True
47+
prof = os.environ.get("FIREWORKS_PROFILE", "").strip()
48+
return bool(prof)
49+
50+
1351
def _parse_simple_auth_file(file_path: Path) -> Dict[str, str]:
1452
"""
1553
Parses an auth file with simple key=value lines.
@@ -20,7 +58,7 @@ def _parse_simple_auth_file(file_path: Path) -> Dict[str, str]:
2058
if not file_path.exists():
2159
return creds
2260
try:
23-
with open(file_path, "r") as f:
61+
with open(file_path, "r", encoding="utf-8") as f:
2462
for line in f:
2563
line = line.strip()
2664
if not line or line.startswith("#") or line.startswith(";"):
@@ -39,7 +77,7 @@ def _parse_simple_auth_file(file_path: Path) -> Dict[str, str]:
3977
if key in ["api_key", "account_id"] and value:
4078
creds[key] = value
4179
except Exception as e:
42-
logger.warning(f"Error during simple parsing of {file_path}: {e}")
80+
logger.warning("Error during simple parsing of %s: %s", str(file_path), e)
4381
return creds
4482

4583

@@ -48,44 +86,50 @@ def _get_credential_from_config_file(key_name: str) -> Optional[str]:
4886
Helper to get a specific credential (api_key or account_id) from auth.ini.
4987
Tries simple parsing first, then configparser.
5088
"""
51-
if not AUTH_INI_FILE.exists():
89+
auth_ini_path = _get_auth_ini_file()
90+
if not auth_ini_path.exists():
5291
return None
5392

5493
# 1. Try simple key-value parsing first
55-
simple_creds = _parse_simple_auth_file(AUTH_INI_FILE)
94+
simple_creds = _parse_simple_auth_file(auth_ini_path)
5695
if key_name in simple_creds:
57-
logger.debug(f"Using {key_name} from simple key-value parsing of {AUTH_INI_FILE}.")
96+
logger.debug("Using %s from simple key-value parsing of %s.", key_name, str(auth_ini_path))
5897
return simple_creds[key_name]
5998

6099
# 2. Fallback to configparser if not found via simple parsing or if simple parsing failed
61100
# This path will also generate the "no section headers" warning if applicable,
62101
# but only if simple parsing didn't yield the key.
63102
try:
64103
config = configparser.ConfigParser()
65-
config.read(AUTH_INI_FILE)
104+
config.read(auth_ini_path)
66105

67106
# Try [fireworks] section
68107
if "fireworks" in config and config.has_option("fireworks", key_name):
69108
value_from_file = config.get("fireworks", key_name)
70109
if value_from_file:
71-
logger.debug(f"Using {key_name} from [fireworks] section in {AUTH_INI_FILE}.")
110+
logger.debug("Using %s from [fireworks] section in %s.", key_name, str(auth_ini_path))
72111
return value_from_file
73112

74113
# Try default section (configparser might place items without section header here)
75114
if config.has_option(config.default_section, key_name):
76115
value_from_default = config.get(config.default_section, key_name)
77116
if value_from_default:
78-
logger.debug(f"Using {key_name} from default section [{config.default_section}] in {AUTH_INI_FILE}.")
117+
logger.debug(
118+
"Using %s from default section [%s] in %s.",
119+
key_name,
120+
config.default_section,
121+
str(auth_ini_path),
122+
)
79123
return value_from_default
80124

81125
except configparser.MissingSectionHeaderError:
82126
# This error implies the file is purely key-value, which simple parsing should have handled.
83127
# If simple parsing failed to get the key, then it's likely not there or malformed.
84-
logger.debug(f"{AUTH_INI_FILE} has no section headers, and simple parsing did not find {key_name}.")
128+
logger.debug("%s has no section headers, and simple parsing did not find %s.", str(auth_ini_path), key_name)
85129
except configparser.Error as e_config:
86-
logger.warning(f"Configparser error reading {AUTH_INI_FILE} for {key_name}: {e_config}")
130+
logger.warning("Configparser error reading %s for %s: %s", str(auth_ini_path), key_name, e_config)
87131
except Exception as e_general:
88-
logger.warning(f"Unexpected error reading {AUTH_INI_FILE} for {key_name}: {e_general}")
132+
logger.warning("Unexpected error reading %s for %s: %s", str(auth_ini_path), key_name, e_general)
89133

90134
return None
91135

@@ -101,14 +145,24 @@ def get_fireworks_api_key() -> Optional[str]:
101145
Returns:
102146
The API key if found, otherwise None.
103147
"""
104-
api_key = os.environ.get("FIREWORKS_API_KEY")
105-
if api_key:
106-
logger.debug("Using FIREWORKS_API_KEY from environment variable.")
107-
return api_key
108-
109-
api_key_from_file = _get_credential_from_config_file("api_key")
110-
if api_key_from_file:
111-
return api_key_from_file
148+
# If a profile is active, prefer profile file first, then env
149+
if _is_profile_active():
150+
api_key_from_file = _get_credential_from_config_file("api_key")
151+
if api_key_from_file:
152+
return api_key_from_file
153+
api_key = os.environ.get("FIREWORKS_API_KEY")
154+
if api_key:
155+
logger.debug("Using FIREWORKS_API_KEY from environment variable (profile active but file missing).")
156+
return api_key
157+
else:
158+
# Default behavior: env overrides file
159+
api_key = os.environ.get("FIREWORKS_API_KEY")
160+
if api_key:
161+
logger.debug("Using FIREWORKS_API_KEY from environment variable.")
162+
return api_key
163+
api_key_from_file = _get_credential_from_config_file("api_key")
164+
if api_key_from_file:
165+
return api_key_from_file
112166

113167
logger.debug("Fireworks API key not found in environment variables or auth.ini.")
114168
return None
@@ -125,14 +179,24 @@ def get_fireworks_account_id() -> Optional[str]:
125179
Returns:
126180
The Account ID if found, otherwise None.
127181
"""
128-
account_id = os.environ.get("FIREWORKS_ACCOUNT_ID")
129-
if account_id:
130-
logger.debug("Using FIREWORKS_ACCOUNT_ID from environment variable.")
131-
return account_id
132-
133-
account_id_from_file = _get_credential_from_config_file("account_id")
134-
if account_id_from_file:
135-
return account_id_from_file
182+
# If a profile is active, prefer profile file first, then env
183+
if _is_profile_active():
184+
account_id_from_file = _get_credential_from_config_file("account_id")
185+
if account_id_from_file:
186+
return account_id_from_file
187+
account_id = os.environ.get("FIREWORKS_ACCOUNT_ID")
188+
if account_id:
189+
logger.debug("Using FIREWORKS_ACCOUNT_ID from environment variable (profile active but file missing).")
190+
return account_id
191+
else:
192+
# Default behavior: env overrides file
193+
account_id = os.environ.get("FIREWORKS_ACCOUNT_ID")
194+
if account_id:
195+
logger.debug("Using FIREWORKS_ACCOUNT_ID from environment variable.")
196+
return account_id
197+
account_id_from_file = _get_credential_from_config_file("account_id")
198+
if account_id_from_file:
199+
return account_id_from_file
136200

137201
logger.debug("Fireworks Account ID not found in environment variables or auth.ini.")
138202
return None
@@ -152,5 +216,5 @@ def get_fireworks_api_base() -> str:
152216
if os.environ.get("FIREWORKS_API_BASE"):
153217
logger.debug("Using FIREWORKS_API_BASE from environment variable.")
154218
else:
155-
logger.debug(f"FIREWORKS_API_BASE not set in environment, defaulting to {api_base}.")
219+
logger.debug("FIREWORKS_API_BASE not set in environment, defaulting to %s.", api_base)
156220
return api_base

0 commit comments

Comments
 (0)