feat: 用 .env 替代 Python 文件配置 LLM,补充单元测试#1
Open
OuyangWenyu wants to merge 1 commit into
Open
Conversation
- hydroagent/config.py: 新增 _load_dotenv() 在 import 时自动加载 .env, 新增 _apply_env_overrides() 将环境变量覆盖到配置字典 - 新建 .env.example 模板,支持 LLM_API_KEY/LLM_MODEL/LLM_BASE_URL 等 - configs/example_private.py: 引导用户优先使用 .env - .gitignore: 新增 .omx/ .pytest_cache/ - test/: 80 个单元测试覆盖 config/llm/skill_registry
There was a problem hiding this comment.
Pull request overview
该 PR 将 HydroAgent 的 LLM/路径配置从“改 Python 文件”升级为“使用 .env 环境变量”,以降低首次上手门槛,并为 config / llm / skill_registry 三个核心模块补齐较完整的单元测试覆盖。
Changes:
- 在
hydroagent/config.py中新增.env加载与环境变量覆盖逻辑(优先级高于private.py)。 - 新增
.env.example模板,并更新 legacyconfigs/example_private.py文档以引导优先使用.env。 - 新增 3 份 pytest 测试文件,覆盖 config/llm/skill_registry 的核心行为。
Reviewed changes
Copilot reviewed 7 out of 10 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
.env.example |
提供可复制的环境变量配置模板,降低配置门槛 |
hydroagent/config.py |
增加 .env 读取与 env 覆盖到配置字典的能力 |
configs/example_private.py |
文档更新:推荐 .env,保留 Python 私有配置向后兼容 |
.gitignore |
增加对 .omx/、.pytest_cache/ 的忽略规则 |
AGENTS.md |
新增仓库协作/运行指引文档(需同步 .env 配置说明) |
test/test_config.py |
新增 config 单测覆盖(deep_copy/merge/env override/build config 等) |
test/test_llm.py |
新增 llm 单测覆盖(profile/reasoning style/token tracker 等) |
test/test_skill_registry.py |
新增 skill registry 单测覆盖(frontmatter/scan/match 等) |
uv.lock |
依赖锁文件更新以匹配新增/现有依赖状态 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+15
to
+37
| def _load_dotenv(): | ||
| """Load .env file from project root into os.environ (never overrides existing vars). | ||
|
|
||
| Called once at import time so all downstream code sees the env vars. | ||
| Lines are silently skipped if the file doesn't exist, is empty, or the | ||
| line is a comment / malformed. | ||
| """ | ||
| env_path = Path(__file__).parent.parent / ".env" | ||
| if not env_path.exists(): | ||
| return | ||
| with open(env_path, "r", encoding="utf-8") as f: | ||
| for line in f: | ||
| line = line.strip() | ||
| if not line or line.startswith("#") or "=" not in line: | ||
| continue | ||
| key, _, value = line.partition("=") | ||
| key = key.strip() | ||
| value = value.strip() | ||
| # Strip surrounding quotes (both single and double) | ||
| if len(value) >= 2 and value[0] == value[-1] and value[0] in ('"', "'"): | ||
| value = value[1:-1] | ||
| if key not in os.environ: | ||
| os.environ[key] = value |
Comment on lines
+213
to
+217
| def _set_if_present(d: dict, key: str, env_var: str, convert=None): | ||
| """Set d[key] from os.environ[env_var] if the var exists.""" | ||
| val = os.environ.get(env_var) | ||
| if val is not None: | ||
| d[key] = convert(val) if convert else val |
Comment on lines
231
to
+236
| Search order (highest priority last, so later overwrites earlier): | ||
| 1. Built-in DEFAULTS | ||
| 2. HydroAgent legacy configs/definitions*.py | ||
| 3. ~/.hydroagent/config.json (user-level, written by setup wizard) | ||
| 4. config_path argument (explicit override, e.g. --config) | ||
| 3. .env file (env vars loaded at import time) | ||
| 4. ~/.hydroagent/config.json (user-level, written by setup wizard) | ||
| 5. config_path argument (explicit override, e.g. --config) |
Comment on lines
+73
to
+76
| ## Configuration | ||
|
|
||
| Copy `configs/example_private.py` → `configs/private.py`. Required: `OPENAI_API_KEY`, `OPENAI_BASE_URL`, `DATASET_DIR`, `RESULT_DIR`. Any OpenAI-compatible endpoint works (Qwen, DeepSeek, OpenAI, Ollama). | ||
|
|
Comment on lines
+3
to
+4
| import pytest | ||
|
|
Comment on lines
+3
to
+5
| import os | ||
| from pathlib import Path | ||
|
|
Comment on lines
+3
to
+4
| from pathlib import Path | ||
|
|
Comment on lines
+37
to
+38
| # Regex needs content between --- markers: "---\nCONTENT\n---\n" | ||
| # "---\n---\nBody" has nothing between the dashes so it doesn't match |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
用 .env 环境变量文件替代 Python 代码配置 LLM API Key/模型/端点,降低配置门槛。同时为 config/llm/skill_registry 三个核心模块补充 80 个单元测试。
Changes
hydroagent/config.py新增_load_dotenv()在 import 时自动加载.env,新增_apply_env_overrides()将环境变量覆盖到配置字典,优先级高于private.py.env.example,支持LLM_API_KEY/LLM_MODEL/LLM_BASE_URL/DATASET_DIR等环境变量configs/example_private.py更新文档引导用户优先使用.env,旧的private.py仍然可用.gitignore新增.omx/.pytest_cache/test/下 80 个 pytest 用例覆盖_deep_copy、_deep_merge、_apply_env_overrides、build_hydromodel_config、model_profile、detect_reasoning_style、TokenTracker、SkillRegistry等Files Changed
.env.examplehydroagent/config.pyconfigs/example_private.py.gitignoretest/test_config.pytest/test_llm.pytest/test_skill_registry.pyuv.lockTesting
80 个单元测试全部通过:
Related Issues
None