| | import json
|
| | import os
|
| | import re
|
| | from typing import Any, Union
|
| |
|
| | from dotenv import load_dotenv
|
| | from fastmcp.mcp_config import (
|
| | RemoteMCPServer,
|
| | StdioMCPServer,
|
| | )
|
| | from pydantic import BaseModel
|
| |
|
| |
|
| | MCPServerConfig = Union[StdioMCPServer, RemoteMCPServer]
|
| |
|
| |
|
| | class Config(BaseModel):
|
| | """Configuration manager"""
|
| |
|
| | model_name: str
|
| | mcpServers: dict[str, MCPServerConfig] = {}
|
| | save_sessions: bool = True
|
| | session_dataset_repo: str = "akseljoonas/hf-agent-sessions"
|
| | auto_save_interval: int = 3
|
| | yolo_mode: bool = False
|
| |
|
| |
|
| | confirm_cpu_jobs: bool = True
|
| | auto_file_upload: bool = False
|
| |
|
| |
|
| | def substitute_env_vars(obj: Any) -> Any:
|
| | """
|
| | Recursively substitute environment variables in any data structure.
|
| |
|
| | Supports ${VAR_NAME} syntax for required variables and ${VAR_NAME:-default} for optional.
|
| | """
|
| | if isinstance(obj, str):
|
| | pattern = r"\$\{([^}:]+)(?::(-)?([^}]*))?\}"
|
| |
|
| | def replacer(match):
|
| | var_name = match.group(1)
|
| | has_default = match.group(2) is not None
|
| | default_value = match.group(3) if has_default else None
|
| |
|
| | env_value = os.environ.get(var_name)
|
| |
|
| | if env_value is not None:
|
| | return env_value
|
| | elif has_default:
|
| | return default_value or ""
|
| | else:
|
| | raise ValueError(
|
| | f"Environment variable '{var_name}' is not set. "
|
| | f"Add it to your .env file."
|
| | )
|
| |
|
| | return re.sub(pattern, replacer, obj)
|
| |
|
| | elif isinstance(obj, dict):
|
| | return {key: substitute_env_vars(value) for key, value in obj.items()}
|
| |
|
| | elif isinstance(obj, list):
|
| | return [substitute_env_vars(item) for item in obj]
|
| |
|
| | return obj
|
| |
|
| |
|
| | def load_config(config_path: str = "config.json") -> Config:
|
| | """
|
| | Load configuration with environment variable substitution.
|
| |
|
| | Use ${VAR_NAME} in your JSON for any secret.
|
| | Automatically loads from .env file.
|
| | """
|
| |
|
| | load_dotenv()
|
| |
|
| | with open(config_path, "r") as f:
|
| | raw_config = json.load(f)
|
| |
|
| | config_with_env = substitute_env_vars(raw_config)
|
| | return Config.model_validate(config_with_env)
|
| |
|