From 323f746d8a2df514cef53d64695f05788842bdea Mon Sep 17 00:00:00 2001 From: devmrko Date: Wed, 22 Jul 2026 13:01:40 +0900 Subject: [PATCH] refs #701: load console profile overrides from dotenv --- .../apps/poc4/mcp_discovery_ui.py | 2 +- .../src/agent_console/profile.py | 29 ++++++++++++++++--- .../tests/test_scenarios.py | 9 ++++++ 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/poc4_active_source_20260714/apps/poc4/mcp_discovery_ui.py b/poc4_active_source_20260714/apps/poc4/mcp_discovery_ui.py index b763891..1f5b94c 100644 --- a/poc4_active_source_20260714/apps/poc4/mcp_discovery_ui.py +++ b/poc4_active_source_20260714/apps/poc4/mcp_discovery_ui.py @@ -6921,7 +6921,7 @@ def _process_submitted_question( def main() -> None: try: - profile = load_app_profile(APP_PROFILE_FILE) + profile = load_app_profile(APP_PROFILE_FILE, ENV_FILE) except AppProfileError as exc: st.set_page_config(page_title="AI 업무 에이전트", layout="wide") st.error(str(exc)) diff --git a/poc4_active_source_20260714/src/agent_console/profile.py b/poc4_active_source_20260714/src/agent_console/profile.py index 7c422d4..1591b41 100644 --- a/poc4_active_source_20260714/src/agent_console/profile.py +++ b/poc4_active_source_20260714/src/agent_console/profile.py @@ -61,17 +61,38 @@ def resolve_profile_path(default_path: Path) -> Path: return path if path.is_absolute() else default_path.parent / path -def _apply_environment_overrides(profile: AppProfile) -> AppProfile: +def _dotenv_value(name: str, path: Path | None) -> str: + """Read one simple KEY=value runtime setting without importing a dotenv lib.""" + + if path is None: + return "" + try: + lines = path.read_text(encoding="utf-8").splitlines() + except (OSError, UnicodeError): + return "" + prefix = f"{name}=" + for line in lines: + stripped = line.strip() + if stripped.startswith(prefix): + return stripped[len(prefix) :].strip().strip('"').strip("'") + return "" + + +def _apply_environment_overrides(profile: AppProfile, env_file: Path | None) -> AppProfile: """Apply deployment-specific presentation values without a code change.""" values = { - field_name: os.environ.get(env_name, "").strip() or getattr(profile, field_name) + field_name: ( + os.environ.get(env_name, "").strip() + or _dotenv_value(env_name, env_file) + or getattr(profile, field_name) + ) for field_name, env_name in _ENV_FIELD_NAMES.items() } return AppProfile(**values) -def load_app_profile(default_path: Path) -> AppProfile: +def load_app_profile(default_path: Path, env_file: Path | None = None) -> AppProfile: """Load the selectable product skin without coupling it to a PoC name.""" path = resolve_profile_path(default_path) @@ -101,7 +122,7 @@ def load_app_profile(default_path: Path) -> AppProfile: text_color=_string(theme, "text_color"), muted_color=_string(theme, "muted_color"), border_color=_string(theme, "border_color"), - )) + ), env_file) required = ( profile.product_name, profile.short_name, diff --git a/poc4_active_source_20260714/tests/test_scenarios.py b/poc4_active_source_20260714/tests/test_scenarios.py index e7429b5..679f931 100644 --- a/poc4_active_source_20260714/tests/test_scenarios.py +++ b/poc4_active_source_20260714/tests/test_scenarios.py @@ -28,6 +28,15 @@ class DemoScenarioConfigTest(unittest.TestCase): self.assertEqual(profile.page_title, "HMM AI 업무 에이전트") self.assertEqual(profile.primary_color, "#003b70") + def test_profile_reads_dotenv_values(self) -> None: + path = Path(__file__).parents[1] / "config" / "app_profile.json" + with tempfile.TemporaryDirectory() as temp_dir: + env_file = Path(temp_dir) / ".env" + env_file.write_text("AGENT_CONSOLE_SHORT_NAME=HMM\n", encoding="utf-8") + profile = load_app_profile(path, env_file) + + self.assertEqual(profile.short_name, "HMM") + def test_hmm_scenarios_are_enabled_and_unique(self) -> None: path = Path(__file__).parents[1] / "config" / "hmm_demo_scenarios.json" scenarios = load_demo_scenarios(path)