from __future__ import annotations import os from dataclasses import dataclass from pathlib import Path from typing import Iterable, Optional from dotenv import load_dotenv DEFAULT_ENV_FILENAMES = (".env",) @dataclass(slots=True) class CoreAgentConfig: model: str api_key: Optional[str] base_url: Optional[str] timeout: float = 120.0 def load_core_agent_env(env_dir: str | Path | None = None) -> Optional[Path]: """Load a local .env file for the standalone core_agent package.""" root = Path(env_dir).resolve() if env_dir is not None else Path(__file__).resolve().parent for filename in DEFAULT_ENV_FILENAMES: env_path = root / filename if env_path.is_file(): load_dotenv(env_path, override=False) return env_path return None def build_core_agent_config(env: Optional[dict[str, str]] = None) -> CoreAgentConfig: values = env if env is not None else os.environ model = _first_nonempty(values, ("CORE_AGENT_MODEL", "MODEL_NAME", "OPENAI_MODEL", "MODEL"), "gpt-4.1-mini") api_key = _first_nonempty(values, ("OPENAI_API_KEY", "API_KEY")) base_url = _first_nonempty(values, ("OPENAI_BASE_URL", "BASE_URL")) timeout_raw = _first_nonempty(values, ("CORE_AGENT_TIMEOUT", "OPENAI_TIMEOUT", "REQUEST_TIMEOUT"), "120") try: timeout = float(timeout_raw) if timeout_raw is not None else 120.0 except (TypeError, ValueError): timeout = 120.0 return CoreAgentConfig(model=model, api_key=api_key, base_url=base_url, timeout=timeout) def apply_compat_env_aliases(env: Optional[dict[str, str]] = None) -> None: """Mirror Myagent-style env names into OpenAI-compatible names when absent.""" values = env if env is not None else os.environ _set_if_missing(values, "OPENAI_API_KEY", _first_nonempty(values, ("API_KEY",))) _set_if_missing(values, "OPENAI_BASE_URL", _first_nonempty(values, ("BASE_URL",))) _set_if_missing(values, "CORE_AGENT_MODEL", _first_nonempty(values, ("MODEL_NAME", "MODEL"))) def _first_nonempty(values: dict[str, str], keys: Iterable[str], default: Optional[str] = None) -> Optional[str]: for key in keys: value = values.get(key) if value is not None and str(value).strip(): return str(value).strip() return default def _set_if_missing(values: dict[str, str], key: str, value: Optional[str]) -> None: if value is None: return if not values.get(key): values[key] = value