Skip to content

feat: auto-load base URL env vars for OpenAI, Anthropic, and Gemini c…#155

Open
yauheniya-adesso wants to merge 7 commits into
alexzhang13:mainfrom
yauheniya-adesso:feat/auto-load-base-url-env-vars
Open

feat: auto-load base URL env vars for OpenAI, Anthropic, and Gemini c…#155
yauheniya-adesso wants to merge 7 commits into
alexzhang13:mainfrom
yauheniya-adesso:feat/auto-load-base-url-env-vars

Conversation

@yauheniya-adesso
Copy link
Copy Markdown

Many organisations route API calls through a custom gateway or proxy
(e.g. using OPENAI_API_BASE). Currently these env vars are silently
ignored unless base_url is passed explicitly in code.

This PR adds automatic fallback support in all three main clients:

  • OPENAI_API_BASE → OpenAI client
  • ANTHROPIC_BASE_URL → Anthropic client
  • GEMINI_API_BASE → Gemini client

Also adds .env.example documenting all supported environment variables
across every backend.

No breaking changes — existing behaviour is preserved when env vars are unset.

…lients

- OpenAI: reads OPENAI_API_BASE as fallback base_url
- Anthropic: reads ANTHROPIC_BASE_URL as fallback base_url; api_key now optional (auto-loaded from ANTHROPIC_API_KEY)
- Gemini: reads GEMINI_API_BASE as fallback base_url
- Add .env.example covering all supported backends
Copilot AI review requested due to automatic review settings April 30, 2026 10:49
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds automatic environment-variable fallbacks for configuring LLM client base URLs, enabling use behind custom gateways/proxies without requiring base_url to be passed explicitly in code.

Changes:

  • OpenAI client: fall back to OPENAI_API_BASE when base_url is not provided.
  • Anthropic client: support ANTHROPIC_API_KEY + ANTHROPIC_BASE_URL fallbacks and make api_key optional.
  • Gemini client: add base_url param and fall back to GEMINI_API_BASE; document supported env vars via new .env.example.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
rlm/clients/openai.py Adds env fallback for OpenAI base URL (OPENAI_API_BASE).
rlm/clients/anthropic.py Adds dotenv/env defaults for API key + base URL and updates constructor.
rlm/clients/gemini.py Adds base URL configuration support via env + constructor argument.
.env.example Documents environment variables for supported backends.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread rlm/clients/openai.py
Comment on lines +40 to +42
# Fall back to OPENAI_API_BASE env var if base_url is not explicitly provided.
if base_url is None:
base_url = DEFAULT_OPENAI_API_BASE
Comment thread rlm/clients/anthropic.py
Comment on lines +32 to +46
if api_key is None:
api_key = DEFAULT_ANTHROPIC_API_KEY

if api_key is None:
raise ValueError(
"Anthropic API key is required. Set ANTHROPIC_API_KEY env var or pass api_key."
)

# Fall back to ANTHROPIC_BASE_URL env var if base_url is not explicitly provided.
if base_url is None:
base_url = DEFAULT_ANTHROPIC_BASE_URL

client_kwargs = {"api_key": api_key, "timeout": self.timeout}
if base_url is not None:
client_kwargs["base_url"] = base_url
Comment thread rlm/clients/gemini.py
Comment on lines +41 to +51
# Fall back to GEMINI_API_BASE env var if base_url is not explicitly provided.
if base_url is None:
base_url = DEFAULT_GEMINI_API_BASE

# Configure HTTP options with timeout
http_options = types.HttpOptions(timeout=int(self.timeout * 1000)) # milliseconds
http_options = types.HttpOptions(
timeout=int(self.timeout * 1000), # milliseconds
**({
"base_url": base_url
} if base_url is not None else {}),
)
Comment thread .env.example Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 30, 2026 15:24
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds automatic environment-variable fallbacks for configuring custom/proxy API base URLs across the OpenAI, Anthropic, and Gemini clients, and documents supported env vars in a new .env.example.

Changes:

  • OpenAI client now falls back to OPENAI_API_BASE when base_url isn’t provided.
  • Anthropic client now falls back to ANTHROPIC_BASE_URL and allows api_key to be omitted (env fallback).
  • Gemini client now supports GEMINI_API_BASE and forwards it via http_options when present.
  • Adds .env.example enumerating supported environment variables.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
rlm/clients/openai.py Reads OPENAI_API_BASE from env and uses it as default base_url.
rlm/clients/anthropic.py Adds dotenv/env fallbacks for api_key and base_url, and wires base_url into Anthropic SDK constructors.
rlm/clients/gemini.py Reads GEMINI_API_BASE from env and conditionally forwards it through types.HttpOptions.
.env.example Documents expected env vars for multiple backends (OpenAI/Anthropic/Gemini + others).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread rlm/clients/anthropic.py Outdated
Comment on lines 26 to 27
base_url: str | None = None,
max_tokens: int = 32768,
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed — moved base_url after max_tokens to preserve positional argument order.

Comment thread rlm/clients/anthropic.py
Comment on lines +40 to +44
# Fall back to ANTHROPIC_BASE_URL env var if base_url is not explicitly provided.
if base_url is None:
base_url = DEFAULT_ANTHROPIC_BASE_URL

client_kwargs = {"api_key": api_key, "timeout": self.timeout}
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Unit tests for this exact behavior were added in tests/clients/test_base_url_env_vars.py. Specifically, TestAnthropicClientEnvVars::test_base_url_from_env patches DEFAULT_ANTHROPIC_BASE_URL and asserts the value is forwarded to the anthropic.Anthropic constructor, and test_base_url_not_passed_when_env_not_set covers the case where the env var is unset.

Comment thread rlm/clients/openai.py
Comment on lines +41 to +42
if base_url is None:
base_url = DEFAULT_OPENAI_API_BASE
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Addressed — tests/clients/test_base_url_env_vars.py covers this. Specifically, TestOpenAIClientBaseUrl::test_base_url_from_env patches DEFAULT_OPENAI_API_BASE and asserts the value is forwarded to the openai.OpenAI constructor, test_explicit_base_url_overrides_env verifies an explicit argument takes precedence, and test_base_url_is_none_when_env_not_set covers the unset case.

Comment thread rlm/clients/gemini.py
Comment on lines +41 to 45
# Fall back to GEMINI_API_BASE env var if base_url is not explicitly provided.
if base_url is None:
base_url = DEFAULT_GEMINI_API_BASE

# Configure HTTP options with timeout
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Addressed — tests/clients/test_base_url_env_vars.py covers this. Specifically, TestGeminiClientBaseUrl::test_base_url_from_env patches DEFAULT_GEMINI_API_BASE and types.HttpOptions and asserts the expected base_url is passed to HttpOptions, test_explicit_base_url_overrides_env verifies an explicit argument takes precedence over the env var, and test_base_url_absent_when_env_not_set covers the unset case.

Copilot AI review requested due to automatic review settings May 1, 2026 08:55
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds automatic environment-variable fallbacks for configuring client base URLs (and for Anthropic, API key), enabling organizations to route OpenAI/Anthropic/Gemini traffic through gateways/proxies without requiring explicit base_url arguments in code.

Changes:

  • Add OPENAI_API_BASE, ANTHROPIC_BASE_URL, and GEMINI_API_BASE env-var fallbacks in the respective clients.
  • Add ANTHROPIC_API_KEY env-var fallback and validation in AnthropicClient.
  • Add a consolidated .env.example plus new unit tests covering the fallback behavior.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
rlm/clients/openai.py Loads OPENAI_API_BASE and uses it when base_url isn’t provided.
rlm/clients/anthropic.py Loads ANTHROPIC_API_KEY / ANTHROPIC_BASE_URL, adds fallbacks + error on missing key.
rlm/clients/gemini.py Loads GEMINI_API_BASE and passes it into HttpOptions when provided.
tests/clients/test_base_url_env_vars.py New unit tests validating env-var fallback and precedence behavior.
.env.example Documents supported environment variables across backends.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/clients/test_base_url_env_vars.py Outdated
"""

import os
from unittest.mock import MagicMock, patch
Comment on lines +30 to +32
with patch("rlm.clients.openai.DEFAULT_OPENAI_API_BASE", "https://my-org.example.com/v1"):
client = OpenAIClient(api_key="test-key")

Comment on lines +42 to +44

client = OpenAIClient(api_key="test-key", base_url="https://explicit.example.com/v1")

Comment on lines +54 to +56

client = OpenAIClient(api_key="test-key")

Comment on lines +102 to +105
from rlm.clients.anthropic import AnthropicClient

client = AnthropicClient()

Comment on lines +171 to +174
from rlm.clients.gemini import GeminiClient

client = GeminiClient(api_key="test-key", base_url="https://explicit.example.com")

Comment thread tests/clients/test_base_url_env_vars.py Outdated
):
from rlm.clients.gemini import GeminiClient

client = GeminiClient(api_key="test-key")
Comment on lines +76 to +79
from rlm.clients.anthropic import AnthropicClient

client = AnthropicClient()

Comment on lines +134 to +137
from rlm.clients.anthropic import AnthropicClient

client = AnthropicClient()

Comment on lines +157 to +160
from rlm.clients.gemini import GeminiClient

client = GeminiClient(api_key="test-key")

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed — renamed unused client assignments to _ across all three test classes.

Copilot AI review requested due to automatic review settings May 2, 2026 19:32
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

rlm/clients/openai.py:47

  • When OPENAI_API_BASE is set to a custom gateway/proxy URL and api_key is omitted, api_key remains None because the env-key fallback only triggers for the default OpenAI base URL (or a few hard-coded provider URLs). This undermines the intended “API key env var fallback” behavior and can lead to an unauthenticated client (depending on SDK behavior). Consider defaulting to DEFAULT_OPENAI_API_KEY for any unrecognized base_url (only overriding it for known providers like OpenRouter/Vercel/Prime), and add a unit test covering OPENAI_API_BASE + omitted api_key to ensure the OpenAI key is still forwarded.
        # Fall back to OPENAI_API_BASE env var if base_url is not explicitly provided.
        if base_url is None:
            base_url = DEFAULT_OPENAI_API_BASE

        if api_key is None:
            if base_url == "https://api.openai.com/v1" or base_url is None:
                api_key = DEFAULT_OPENAI_API_KEY
            elif base_url == "https://openrouter.ai/api/v1":

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@yauheniya-adesso
Copy link
Copy Markdown
Author

Addressed the suppressed concern from the "Pull request overview" regarding OPENAI_API_BASE + omitted api_key. Added an else branch in OpenAIClient.init that falls back to DEFAULT_OPENAI_API_KEY for any unrecognized base URL, ensuring custom gateways set via OPENAI_API_BASE are not left unauthenticated. Covered by the new test_openai_api_key_used_for_custom_base_url test.

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