{"repo": "1120202562/tidesign", "files": {"experiments/shared/deepseek_config.py": {"43aeaf5146096815a334def886d509ae0c45cb06": {"t": 1785745422.178976, "n": 4204, "h": "6b5bef7faf676554", "c": "#!/usr/bin/env python3\n\"\"\"Load DeepSeek-compatible model settings from env or Claude Code/Codex config.\n\nThis module never prints or persists API secrets. Use ``redacted_summary`` when\nyou need to show which configuration source is active.\n\"\"\"\n\nfrom __future__ import annotations\n\nimport os\nimport pwd\nfrom dataclasses import dataclass\nfrom pathlib import Path\n\ntry:\n import tomllib\nexcept ModuleNotFoundError: # Python < 3.11\n tomllib = None # type: ignore[assignment]\n\n\nANTHROPIC_BASE_URL = \"ANTHROPIC_BASE_URL\"\nANTHROPIC_AUTH_TOKEN = \"ANTHROPIC_AUTH_TOKEN\"\nANTHROPIC_MODEL = \"ANTHROPIC_MODEL\"\nANTHROPIC_DEFAULT_SONNET_MODEL = \"ANTHROPIC_DEFAULT_SONNET_MODEL\"\nANTHROPIC_DEFAULT_HAIKU_MODEL = \"ANTHROPIC_DEFAULT_HAIKU_MODEL\"\nDEEPSEEK_API_KEY = \"DEEPSEEK_API_KEY\"\nDEEPSEEK_BASE_URL = \"DEEPSEEK_BASE_URL\"\nDEEPSEEK_MODEL = \"DEEPSEEK_MODEL\"\nPROJECT_LLM_MODEL = \"PROJECT_LLM_MODEL\"\n\n\ndef _real_home() -> Path:\n try:\n return Path(pwd.getpwuid(os.getuid()).pw_dir)\n except Exception:\n return Path.home()\n\n\nDEFAULT_CONFIG_PATH = _real_home() / \".codex\" / \"config.toml\"\n\n\n@dataclass(frozen=True)\nclass DeepSeekConfig:\n api_key: str\n anthropic_base_url: str\n model: str\n fast_model: str\n source: str\n\n @property\n def configured(self) -> bool:\n return bool(self.api_key and self.anthropic_base_url and self.model)\n\n def redacted_summary(self) -> str:\n key_status = \"present\" if self.api_key else \"missing\"\n return (\n f\"source={self.source}; base_url={self.anthropic_base_url or 'missing'}; \"\n f\"model={self.model or 'missing'}; api_key={key_status}\"\n )\n\n\ndef _load_codex_config(path: Path) -> dict[str, str]:\n if not path.exists():\n return {}\n keys = {\n ANTHROPIC_BASE_URL,\n ANTHROPIC_AUTH_TOKEN,\n ANTHROPIC_MODEL,\n ANTHROPIC_DEFAULT_SONNET_MODEL,\n ANTHROPIC_DEFAULT_HAIKU_MODEL,\n DEEPSEEK_API_KEY,\n DEEPSEEK_BASE_URL,\n DEEPSEEK_MODEL,\n }\n if tomllib is None:\n values = {}\n for line in path.read_text(encoding=\"utf-8\").splitlines():\n stripped = line.strip()\n if not stripped or stripped.startswith(\"#\") or \"=\" not in stripped:\n continue\n key, raw_value = stripped.split(\"=\", 1)\n key = key.strip()\n if key in keys:\n values[key] = raw_value.strip().strip('\"').strip(\"'\")\n return values\n\n try:\n data = tomllib.loads(path.read_text(encoding=\"utf-8\"))\n except Exception:\n return {}\n\n values: dict[str, str] = {}\n for key in keys:\n value = data.get(key)\n if value:\n values[key] = str(value)\n\n env_section = data.get(\"env\")\n if isinstance(env_section, dict):\n for key in keys:\n value = env_section.get(key)\n if value:\n values.setdefault(key, str(value))\n return values\n\n\ndef load_deepseek_config(config_path: Path | None = None) -> DeepSeekConfig:\n \"\"\"Load model config from environment first, then Claude Code/Codex config.\"\"\"\n path = config_path or Path(os.environ.get(\"CODEX_CONFIG_PATH\", DEFAULT_CONFIG_PATH))\n file_values = _load_codex_config(path)\n\n def pick(*keys: str, default: str = \"\") -> str:\n for key in keys:\n value = os.environ.get(key) or file_values.get(key)\n if value:\n return value\n return default\n\n api_key = pick(DEEPSEEK_API_KEY, ANTHROPIC_AUTH_TOKEN)\n base_url = pick(DEEPSEEK_BASE_URL, ANTHROPIC_BASE_URL, default=\"https://api.deepseek.com/anthropic\")\n model = pick(PROJECT_LLM_MODEL, DEEPSEEK_MODEL, ANTHROPIC_MODEL, ANTHROPIC_DEFAULT_SONNET_MODEL)\n fast_model = pick(ANTHROPIC_DEFAULT_HAIKU_MODEL, default=model)\n source = \"environment\" if any(os.environ.get(k) for k in (DEEPSEEK_API_KEY, ANTHROPIC_AUTH_TOKEN)) else str(path)\n return DeepSeekConfig(\n api_key=api_key,\n anthropic_base_url=base_url.rstrip(\"/\"),\n model=model,\n fast_model=fast_model,\n source=source,\n )\n\n\ndef has_model_config(config_path: Path | None = None) -> bool:\n return load_deepseek_config(config_path).configured\n"}}}}