Skip to content

feat: 用 .env 替代 Python 文件配置 LLM,补充单元测试#1

Open
OuyangWenyu wants to merge 1 commit into
mainfrom
dev
Open

feat: 用 .env 替代 Python 文件配置 LLM,补充单元测试#1
OuyangWenyu wants to merge 1 commit into
mainfrom
dev

Conversation

@OuyangWenyu

Copy link
Copy Markdown

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_overridesbuild_hydromodel_configmodel_profiledetect_reasoning_styleTokenTrackerSkillRegistry

Files Changed

File Type Description
.env.example Added 环境变量配置模板
hydroagent/config.py Modified 支持 .env 加载 + env var 覆盖
configs/example_private.py Modified 引导使用 .env
.gitignore Modified 新增忽略规则
test/test_config.py Added 配置模块测试 (29 cases)
test/test_llm.py Added LLM 模块测试 (32 cases)
test/test_skill_registry.py Added Skill 注册表测试 (19 cases)
uv.lock Modified 依赖锁文件更新

Testing

80 个单元测试全部通过:

test/test_config.py ............... 29 passed
test/test_llm.py .................. 32 passed
test/test_skill_registry.py ...... 19 passed

Related Issues

None

- 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

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

该 PR 将 HydroAgent 的 LLM/路径配置从“改 Python 文件”升级为“使用 .env 环境变量”,以降低首次上手门槛,并为 config / llm / skill_registry 三个核心模块补齐较完整的单元测试覆盖。

Changes:

  • hydroagent/config.py 中新增 .env 加载与环境变量覆盖逻辑(优先级高于 private.py)。
  • 新增 .env.example 模板,并更新 legacy configs/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 thread hydroagent/config.py
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 thread hydroagent/config.py
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 thread hydroagent/config.py
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 thread AGENTS.md
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 thread test/test_llm.py
Comment on lines +3 to +4
import pytest

Comment thread test/test_config.py
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants