From e19c37d813ca255109ba572a9857fa193abb2718 Mon Sep 17 00:00:00 2001 From: liunianxuxie <34098623+liunianxuxie@users.noreply.github.com> Date: Thu, 17 Sep 2026 14:53:54 +0800 Subject: [PATCH] fix(setup): detect optional extras in BOM-prefixed configs (#5504) --- README.md | 2 +- backend/tests/test_detect_uv_extras.py | 19 +++++++++++++++++++ scripts/AGENTS.md | 3 ++- scripts/detect_uv_extras.py | 2 +- 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bb65e2d57..e27637d96 100644 --- a/README.md +++ b/README.md @@ -149,7 +149,7 @@ It is disabled by default; see the linked guide to enable it. only, and does not include `.env`, raw conversation messages, or user file contents. - > **Advanced / manual configuration**: If you prefer to edit `config.yaml` directly, run `make config` instead to copy the full template. See `config.example.yaml` for the complete reference including CLI-backed providers (Codex CLI, Claude Code OAuth), OpenRouter, Responses API, subagent runtime caps such as `subagents.max_total_per_run`, and more. + > **Advanced / manual configuration**: If you prefer to edit `config.yaml` directly, run `make config` instead to copy the full template. Optional dependency auto-detection accepts UTF-8 configuration files with or without a byte-order mark (BOM). See `config.example.yaml` for the complete reference including CLI-backed providers (Codex CLI, Claude Code OAuth), OpenRouter, Responses API, subagent runtime caps such as `subagents.max_total_per_run`, and more. Optional per-model pricing must use one currency across all priced models. DeerFlow disables Console cost estimates when currencies are mixed rather diff --git a/backend/tests/test_detect_uv_extras.py b/backend/tests/test_detect_uv_extras.py index 1da032b74..8c99d903f 100644 --- a/backend/tests/test_detect_uv_extras.py +++ b/backend/tests/test_detect_uv_extras.py @@ -125,6 +125,25 @@ def test_section_value_does_not_descend_into_grandchildren(): assert detect.section_value(yaml_lines, "database", "backend") == "sqlite" +@pytest.mark.parametrize("encoding", ["utf-8", "utf-8-sig"]) +@pytest.mark.parametrize( + ("config_text", "expected"), + [ + ("database:\n backend: postgres\n", ["postgres"]), + ("tools:\n - name: browser_navigate\n", ["browser"]), + ("models:\n - use: langchain_ollama:ChatOllama\n", ["ollama"]), + ("database:\n backend: sqlite\n", []), + ("# database:\n# backend: postgres\n", []), + ], + ids=["postgres", "browser", "ollama", "sqlite", "commented"], +) +def test_detect_from_config_utf8_with_optional_bom(tmp_path, encoding, config_text, expected): + """A UTF-8 BOM must not hide the first section or enable inactive extras.""" + cfg = tmp_path / "config.yaml" + cfg.write_text(config_text, encoding=encoding) + assert detect.detect_from_config(cfg) == expected + + def test_detect_from_config_postgres_via_database(tmp_path): cfg = tmp_path / "config.yaml" cfg.write_text("database:\n backend: postgres\n postgres_url: $DATABASE_URL\n") diff --git a/scripts/AGENTS.md b/scripts/AGENTS.md index b244388f3..daaf275fb 100644 --- a/scripts/AGENTS.md +++ b/scripts/AGENTS.md @@ -4,7 +4,8 @@ Optional browser dependency detection reads the top-level `tools:` sequence without requiring `name` to be its first mapping key. Both indented and indentless lists are supported; nested option names and block-scalar text must not enable the browser extra. Keep the detector standard-library-only -because it runs before dependency synchronization. +because it runs before dependency synchronization. Read UTF-8 config files +with or without a leading BOM so the first section remains detectable. The root `PORT` value configures Docker's published nginx ingress only; local orchestration pins Next.js to `3000`. Runtime commands launch from the already diff --git a/scripts/detect_uv_extras.py b/scripts/detect_uv_extras.py index eb7941411..eaee57951 100755 --- a/scripts/detect_uv_extras.py +++ b/scripts/detect_uv_extras.py @@ -345,7 +345,7 @@ def models_use_providers(lines: list[str]) -> set[str]: def detect_from_config(path: Path) -> list[str]: try: - text = path.read_text(encoding="utf-8", errors="replace") + text = path.read_text(encoding="utf-8-sig", errors="replace") except OSError: return [] lines = text.splitlines()