1414
1515"""Configuration utility functions."""
1616
17- from typing import Dict , Any
17+ from pathlib import Path
18+ from typing import Dict , Any , Optional
19+ import logging
20+
21+ from dotenv import load_dotenv , dotenv_values
22+ from yaml import safe_load , YAMLError
1823
1924from .constants import AUTO_CREATE_VE
25+ from .config import CommonConfig
26+
27+ logger = logging .getLogger (__name__ )
2028
2129
2230def is_invalid_config (s : str ) -> bool :
@@ -27,26 +35,137 @@ def is_valid_config(s: str) -> bool:
2735 return not is_invalid_config (s )
2836
2937
38+ def load_dotenv_file (project_dir : Path ) -> Dict [str , str ]:
39+ """Load environment variables from .env file (standard dotenv format).
40+
41+ Args:
42+ project_dir: Project directory containing .env file
43+
44+ Returns:
45+ Dictionary of environment variables from .env file
46+ """
47+ env_file_path = project_dir / ".env"
48+ if not env_file_path .exists ():
49+ return {}
50+
51+ # Load .env into environment temporarily to get the values
52+ load_dotenv (env_file_path )
53+ env_values = dotenv_values (env_file_path )
54+ return {k : str (v ) for k , v in env_values .items () if v is not None }
55+
56+
57+ def load_veadk_yaml_file (project_dir : Path ) -> Dict [str , str ]:
58+ """Load and flatten veADK's config.yaml file.
59+
60+ Args:
61+ project_dir: Project directory containing config.yaml file
62+
63+ Returns:
64+ Dictionary of flattened environment variables from config.yaml
65+ """
66+ config_yaml_path = project_dir / "config.yaml"
67+ if not config_yaml_path .exists ():
68+ return {}
69+
70+ try :
71+ with open (config_yaml_path , "r" , encoding = "utf-8" ) as yaml_file :
72+ config_dict = safe_load (yaml_file ) or {}
73+
74+ # Flatten nested dictionary structure like veADK does
75+ flattened_config = flatten_dict (config_dict )
76+ # Convert to uppercase keys like veADK does
77+ return {k .upper (): str (v ) for k , v in flattened_config .items () if v is not None }
78+ except (FileNotFoundError , PermissionError ) as e :
79+ logger .warning (f"Cannot read config.yaml: { e } " )
80+ return {}
81+ except (YAMLError , ValueError ) as e :
82+ logger .warning (f"Invalid YAML format in config.yaml: { e } " )
83+ return {}
84+
85+
86+ def load_compat_config_files (project_dir : Optional [Path ] = None ) -> Dict [str , str ]:
87+ """Load compatibility configuration files (.env and veADK config.yaml).
88+
89+ This function loads external configuration files for veADK compatibility:
90+ 1. Load standard .env file if exists (higher priority)
91+ 2. Load veADK config.yaml file if exists and flatten nested structure (lower priority)
92+
93+ Args:
94+ project_dir: Project directory to search for files. If None, uses current working directory.
95+
96+ Returns:
97+ Dictionary of environment variables from .env file and veADK config.yaml
98+ """
99+ if project_dir is None :
100+ project_dir = Path .cwd ()
101+
102+ veadk_envs = {}
103+ veadk_envs .update (load_veadk_yaml_file (project_dir ))
104+ veadk_envs .update (load_dotenv_file (project_dir ))
105+
106+ return veadk_envs
107+
108+
109+ def flatten_dict (
110+ d : Dict [str , Any ], parent_key : str = "" , sep : str = "_"
111+ ) -> Dict [str , str ]:
112+ """Flatten a nested dictionary like veADK does.
113+
114+ Input: {"model": {"name": "doubao"}}
115+ Output: {"MODEL_NAME": "doubao"}
116+
117+ Args:
118+ d: Dictionary to flatten
119+ parent_key: Parent key prefix
120+ sep: Separator to use
121+
122+ Returns:
123+ Flattened dictionary with string values
124+ """
125+ items = []
126+ for k , v in d .items ():
127+ new_key = f"{ parent_key } { sep } { k } " if parent_key else k
128+ if isinstance (v , dict ):
129+ items .extend (flatten_dict (v , new_key , sep = sep ).items ())
130+ else :
131+ items .append ((new_key .upper (), str (v )))
132+ return dict (items )
133+
134+
30135def merge_runtime_envs (
31- common_config : Any , strategy_config : Dict [str , Any ]
136+ common_config : CommonConfig ,
137+ strategy_config : Dict [str , Any ],
138+ project_dir : Optional [Path ] = None ,
32139) -> Dict [str , str ]:
33- """Merge application-level and strategy-level environment variables .
140+ """Merge environment variables from multiple sources with veADK compatibility .
34141
35- Strategy-level variables override application-level ones with the same name.
142+ Priority order (highest to lowest):
143+ 1. Strategy-level runtime_envs (from agentkit.yaml launch_types.*.runtime_envs)
144+ 2. Common-level runtime_envs (from agentkit.yaml common.runtime_envs)
145+ 3. .env file environment variables (standard dotenv format)
146+ 4. config.yaml file environment variables (veADK style, flattened)
36147
37148 Args:
38149 common_config: CommonConfig instance
39150 strategy_config: Strategy configuration dict
151+ project_dir: Project directory for loading veADK files and .env file
40152
41153 Returns:
42154 Merged environment variables dict
43155 """
44156 merged_envs = {}
45157
158+ # Load veADK environment files first (lowest priority)
159+ veadk_envs = load_compat_config_files (project_dir )
160+ if veadk_envs :
161+ merged_envs .update (veadk_envs )
162+
163+ # Add common-level runtime_envs (medium priority)
46164 app_level_envs = getattr (common_config , "runtime_envs" , {})
47165 if isinstance (app_level_envs , dict ):
48166 merged_envs .update (app_level_envs )
49167
168+ # Add strategy-level runtime_envs (highest priority)
50169 strategy_level_envs = strategy_config .get ("runtime_envs" , {})
51170 if isinstance (strategy_level_envs , dict ):
52171 merged_envs .update (strategy_level_envs )
0 commit comments