feat: support per-role api_key in role_llms for multi-gateway setups (#94)

* feat: support per-role api_key in role_llms for multi-gateway setups

* test: add per-role api_key precedence tests for openai_compatible provider

---------

Co-authored-by: k176060444-lgtm <k176060444-lgtm@users.noreply.github.com>
This commit is contained in:
KK 2026-08-19 15:43:12 +08:00 committed by GitHub
parent 0badc3340c
commit 8db46605b3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 31 additions and 3 deletions

View File

@ -65,3 +65,24 @@ class TestOpenAICompatibleClient:
)
client.get_llm()
assert not [w for w in recwarn if "not in the known model list" in str(w.message)]
def test_per_role_api_key_wins_over_env(self, monkeypatch):
monkeypatch.setenv("OPENAI_COMPATIBLE_API_KEY", "env-key")
monkeypatch.delenv("OPENAI_API_KEY", raising=False)
# api_key passed via kwargs (role_llms spec) must take precedence.
client = OpenAIClient(
"my-model", base_url="https://relay.example/v1",
provider="openai_compatible", api_key="role-key",
)
llm = client.get_llm()
assert llm.client._client.api_key == "role-key"
def test_role_api_key_absent_falls_back_to_env(self, monkeypatch):
monkeypatch.setenv("OPENAI_COMPATIBLE_API_KEY", "env-key")
monkeypatch.delenv("OPENAI_API_KEY", raising=False)
client = OpenAIClient(
"my-model", base_url="https://relay.example/v1",
provider="openai_compatible",
)
llm = client.get_llm()
assert llm.client._client.api_key == "env-key"

View File

@ -373,13 +373,16 @@ class TradingAgentsGraph:
if k not in _PROVIDER_SPECIFIC_KWARGS}
)
key = (provider.lower(), spec["model"], base_url)
key = (provider.lower(), spec["model"], base_url, spec.get("api_key"))
if key not in cache:
client_kwargs = dict(role_kwargs)
if spec.get("api_key"):
client_kwargs["api_key"] = spec["api_key"]
cache[key] = create_llm_client(
provider=provider,
model=spec["model"],
base_url=base_url,
**role_kwargs,
**client_kwargs,
).get_llm()
resolved[role] = cache[key]

View File

@ -187,8 +187,12 @@ class OpenAIClient(BaseLLMClient):
"(例如 https://your-relay.example/v1"
)
llm_kwargs["base_url"] = self.base_url
# Per-role api_key (from role_llms spec) wins over env vars, so
# several OpenAI-compatible gateways with different keys can run
# side by side (e.g. opencode-go + a local proxy relay).
api_key = (
os.environ.get("OPENAI_COMPATIBLE_API_KEY")
self.kwargs.get("api_key")
or os.environ.get("OPENAI_COMPATIBLE_API_KEY")
or os.environ.get("OPENAI_API_KEY")
)
if api_key: