fix: respect COPILOT_PROVIDER_TYPE env var when provider_type is auto (#549)

## Description

Fixes #297 by respecting `COPILOT_PROVIDER_TYPE` when Copilot provider
type resolution is set to `auto`, while keeping explicit
`--provider-type` values authoritative. Invalid environment values now
fall back to the backend-based default instead of silently selecting a
surprising provider.

## Type of Change

- [x] Bug fix
- [ ] New feature
- [ ] Documentation
- [ ] Refactor
- [ ] Tests only

## Changes Made

- Added guarded `COPILOT_PROVIDER_TYPE` handling for `anthropic` and
`openai` in `resolve_provider_type()`.
- Preserved explicit provider type precedence over environment
configuration.
- Added focused tests for explicit precedence, environment precedence,
invalid env fallback, and backend defaults.

## Testing

- [x] Unit tests
- [x] Lint/static checks
- [ ] Integration tests
- [ ] Manual testing

### Test Output

```text
UV_SKIP_WHEEL_FILENAME_CHECK=1 uv run --with pytest python -m pytest tests/test_provider_copilot_wrap.py -q
8 passed, 1 warning in 0.62s

UV_SKIP_WHEEL_FILENAME_CHECK=1 uv run --with ruff ruff check headroom/providers/copilot/wrap.py tests/test_provider_copilot_wrap.py
All checks passed!
```

## Real Behavior Proof

- Environment: Windows 11, Python 3.13.3, focused local worktree for PR
#549.
- Exact command / steps: Ran the focused Copilot provider wrap test
module and ruff against the changed production/test files.
- Observed result: Provider selection tests pass, and ruff reports no
issues.
- Not tested: Full repository mypy/pre-commit; existing unrelated
Windows `fcntl` typing errors block full hook execution locally.

## Review Readiness

- [x] I have performed a self-review
- [x] This PR is ready for human review


<!-- headroom-maintainer-template-completion:start -->

## Description

This PR prepares `fix: respect COPILOT_PROVIDER_TYPE env var when
provider_type is auto` for review by documenting the intended change,
validation evidence, and remaining merge-readiness context.

Linked issues: #297

## Type of Change

- [x] Bug fix
- [ ] New feature
- [ ] Documentation
- [ ] Refactor
- [ ] Tests only

## Changes Made

- Commit: fix: add encoding='utf-8' to read_text() for
UnicodeDecodeError on no…
- Commit: fix: respect COPILOT_PROVIDER_TYPE env var in
resolve_provider_type
- Commit: Merge remote-tracking branch 'origin/main' into
fix-copilot-provider-…
- Commit: test(copilot): cover provider type env precedence
- Touches `headroom/cache/dynamic_detector.py`
- Touches `headroom/providers/copilot/wrap.py`
- Touches `tests/test_provider_copilot_wrap.py`

## Testing

- [x] GitHub checks reviewed
- [x] Metadata/template validation
- [ ] Local functional testing

### Test Output

```text
gh pr view 549 --repo chopratejas/headroom --json statusCheckRollup
- PR Governance / template: FAILURE
- PR Governance / label: SUCCESS
- external / GitGuardian Security Checks: SUCCESS
```

## Real Behavior Proof

- Environment: GitHub PR metadata and checks for `chopratejas/headroom`
PR #549.
- Exact command / steps: Reviewed PR title, commits, changed files,
linked issues, labels, and check rollup; appended this maintainer
template completion block without replacing the author's original
description.
- Observed result: PR body now contains all required governance
sections, checked readiness fields, and a non-placeholder validation
evidence block.
- Not tested: This pass updated PR metadata only; code validation
remains represented by the linked GitHub checks and any author-provided
evidence above.

## Review Readiness

- [x] I have performed a self-review
- [x] This PR is ready for human review

<!-- headroom-maintainer-template-completion:end -->

---------

Co-authored-by: Tejas Chopra <chopratejas@gmail.com>
Co-authored-by: JerrettDavis <mxjerrett@gmail.com>
This commit is contained in:
kouyouqi123 2026-06-27 01:04:09 +08:00 committed by GitHub
parent 93627471b7
commit 24cf256e50
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 28 additions and 1 deletions

View file

@ -22,6 +22,10 @@ def resolve_provider_type(
return provider_type
env = environ or os.environ
# Check COPILOT_PROVIDER_TYPE env var before falling back to backend default.
env_type = env.get("COPILOT_PROVIDER_TYPE")
if env_type in {"anthropic", "openai"}:
return env_type
effective_backend = backend or env.get("HEADROOM_BACKEND") or "anthropic"
return "anthropic" if effective_backend == "anthropic" else "openai"

View file

@ -47,7 +47,30 @@ def test_detect_running_proxy_backend_requires_string_backend(monkeypatch) -> No
def test_resolve_provider_type_prefers_explicit_and_env() -> None:
assert resolve_provider_type("anthropic", "openai") == "openai"
assert (
resolve_provider_type(
"anthropic",
"openai",
{"COPILOT_PROVIDER_TYPE": "anthropic", "HEADROOM_BACKEND": "anthropic"},
)
== "openai"
)
assert (
resolve_provider_type(
"anthropic",
"auto",
{"COPILOT_PROVIDER_TYPE": "openai", "HEADROOM_BACKEND": "anthropic"},
)
== "openai"
)
assert (
resolve_provider_type(
None,
"auto",
{"COPILOT_PROVIDER_TYPE": "not-a-provider", "HEADROOM_BACKEND": "anthropic"},
)
== "anthropic"
)
assert resolve_provider_type(None, "auto", {"HEADROOM_BACKEND": "anthropic"}) == "anthropic"
assert resolve_provider_type(None, "auto", {"HEADROOM_BACKEND": "anyllm"}) == "openai"