33"""
44
55import os
6+ import re
67from dataclasses import asdict , dataclass , field
78from pathlib import Path
89from typing import TYPE_CHECKING , Any , Callable , Dict , List , Optional , Union
1314 from openevolve .llm .base import LLMInterface
1415
1516
17+ _ENV_VAR_PATTERN = re .compile (r"^\$\{([^}]+)\}$" ) # ${VAR}
18+
19+
20+ def _resolve_env_var (value : Optional [str ]) -> Optional [str ]:
21+ """
22+ Resolve ${VAR} environment variable reference in a string value.
23+ In current implementation pattern must match the entire string (e.g., "${OPENAI_API_KEY}"),
24+ not embedded within other text.
25+
26+ Args:
27+ value: The string value that may contain ${VAR} syntax
28+
29+ Returns:
30+ The resolved value with environment variable expanded, or original value if no match
31+
32+ Raises:
33+ ValueError: If the environment variable is referenced but not set
34+ """
35+ if value is None :
36+ return None
37+
38+ match = _ENV_VAR_PATTERN .match (value )
39+ if not match :
40+ return value
41+
42+ var_name = match .group (1 )
43+ env_value = os .environ .get (var_name )
44+ if env_value is None :
45+ raise ValueError (f"Environment variable { var_name } is not set" )
46+ return env_value
47+
48+
1649@dataclass
1750class LLMModelConfig :
1851 """Configuration for a single LLM model"""
1952
2053 # API configuration
2154 api_base : str = None
22- api_key : Optional [Union [str , Dict [str , str ]]] = (
23- None # either api_key or from_env: api_key_var_name
24- )
55+ api_key : Optional [str ] = None
2556 name : str = None
2657
2758 # Custom LLM client
@@ -48,18 +79,8 @@ class LLMModelConfig:
4879 reasoning_effort : Optional [str ] = None
4980
5081 def __post_init__ (self ):
51- """Post-initialization to set up API key"""
52- if self .api_key is not None :
53- if isinstance (self .api_key , dict ):
54- env_var_name = self .api_key .get ("from_env" )
55- if env_var_name is None :
56- raise ValueError (
57- f"api_key is a dict but 'from_env' key is not set: { self .api_key } "
58- )
59- key = os .environ .get (env_var_name )
60- if key is None :
61- raise ValueError (f"Environment variable { env_var_name } is not set" )
62- self .api_key = key
82+ """Post-initialization to resolve ${VAR} env var references in api_key"""
83+ self .api_key = _resolve_env_var (self .api_key )
6384
6485
6586@dataclass
@@ -97,7 +118,7 @@ class LLMConfig(LLMModelConfig):
97118
98119 def __post_init__ (self ):
99120 """Post-initialization to set up model configurations"""
100- super ().__post_init__ () # resolve from_env for api_key at LLMConfig level
121+ super ().__post_init__ () # Resolve ${VAR} in api_key at LLMConfig level
101122
102123 # Handle backward compatibility for primary_model(_weight) and secondary_model(_weight).
103124 if self .primary_model :
0 commit comments