fix: honor shared OpenCode key at runtime

This commit is contained in:
AJV20 authored and nesquena-hermes committed 2026-05-30 02:18:06 +00:00
1 parent 3005811200
commit d2686eaedb
3 files changed
+66

No files matched your search

+4
View File
@@ -3,6 +3,10 @@
## [Unreleased]
### Fixed
- OpenCode provider key lookup now honors the shared `OPENCODE_API_KEY` fallback for both Zen and Go runtime paths, matching model-picker detection when provider-specific keys are absent (#3145).
## [v0.51.165] — 2026-05-30 — Release EK (stage-batch47 — stop EventSource reconnect storm on long-lived SSE streams)
### Fixed
+6
View File
@@ -682,6 +682,12 @@ _PROVIDER_ENV_VAR_ALIASES: dict[str, tuple[str, ...]] = {
# #1500 — agent runtime reads LM_API_KEY (canonical), but WebUI builds
# ≤ v0.50.272 wrote LMSTUDIO_API_KEY into .env. Keep reading both.
"lmstudio": ("LMSTUDIO_API_KEY",),
# #3145 — provider detection treats OPENCODE_API_KEY as enabling both
# OpenCode Zen and OpenCode Go. The runtime-facing lookup must read the same
# shared bridge key after the provider-specific slot, otherwise Settings can
# show the groups as configured while chat fails the no-key path.
"opencode-zen": ("OPENCODE_API_KEY",),
"opencode-go": ("OPENCODE_API_KEY",),
}
# Providers that use OAuth or token flows — their credentials are managed
@@ -0,0 +1,56 @@
"""Regression tests for shared OpenCode API key runtime lookup (#3145)."""
import pytest
@pytest.mark.parametrize("provider_id", ["opencode-zen", "opencode-go"])
def test_shared_opencode_api_key_resolves_for_runtime(monkeypatch, tmp_path, provider_id):
"""Runtime-facing key lookup should honor OPENCODE_API_KEY for both groups."""
import api.providers as providers
hermes_home = tmp_path / "hermes-home"
hermes_home.mkdir()
(hermes_home / ".env").write_text("OPENCODE_API_KEY=shared-opencode-key\n", encoding="utf-8")
monkeypatch.setattr(providers, "_get_hermes_home", lambda: hermes_home)
monkeypatch.delenv("OPENCODE_ZEN_API_KEY", raising=False)
monkeypatch.delenv("OPENCODE_GO_API_KEY", raising=False)
monkeypatch.delenv("OPENCODE_API_KEY", raising=False)
assert providers._provider_has_key(provider_id) is True
assert providers._get_provider_api_key(provider_id) == "shared-opencode-key"
@pytest.mark.parametrize("provider_id", ["opencode-zen", "opencode-go"])
def test_shared_opencode_api_key_resolves_from_process_env(monkeypatch, tmp_path, provider_id):
"""The shared env var should work even when no .env file exists."""
import api.providers as providers
monkeypatch.setattr(providers, "_get_hermes_home", lambda: tmp_path / "missing-home")
monkeypatch.delenv("OPENCODE_ZEN_API_KEY", raising=False)
monkeypatch.delenv("OPENCODE_GO_API_KEY", raising=False)
monkeypatch.setenv("OPENCODE_API_KEY", "shared-env-opencode-key")
assert providers._provider_has_key(provider_id) is True
assert providers._get_provider_api_key(provider_id) == "shared-env-opencode-key"
def test_provider_specific_opencode_key_still_wins_over_shared(monkeypatch, tmp_path):
"""Provider-specific env vars keep precedence over the shared fallback."""
import api.providers as providers
hermes_home = tmp_path / "hermes-home"
hermes_home.mkdir()
(hermes_home / ".env").write_text(
"OPENCODE_API_KEY=shared-opencode-key\n"
"OPENCODE_ZEN_API_KEY=zen-specific-key\n",
encoding="utf-8",
)
monkeypatch.setattr(providers, "_get_hermes_home", lambda: hermes_home)
monkeypatch.delenv("OPENCODE_API_KEY", raising=False)
monkeypatch.delenv("OPENCODE_ZEN_API_KEY", raising=False)
monkeypatch.delenv("OPENCODE_GO_API_KEY", raising=False)
assert providers._get_provider_api_key("opencode-zen") == "zen-specific-key"
assert providers._get_provider_api_key("opencode-go") == "shared-opencode-key"