fix(llm): honor base_url on the Anthropic provider path (#780) - #888
Conversation
- AnthropicProvider accepts base_url and passes it to all three SDK
client construction sites (sync + both async)
- get_provider('anthropic', base_url=...) forwards it instead of
silently dropping it
- resolve_llm_settings: the OPENAI_BASE_URL env fallback now applies
to OpenAI-compatible providers only, so an ambient value cannot
redirect Anthropic traffic; explicit config llm.base_url still
applies to any provider
- rename _OPENAI_COMPATIBLE -> OPENAI_COMPATIBLE_PROVIDERS (shared
with core.llm_resolution)
Third-party review (post-PR, opencode/GLM) — APPROVESecond-pass review of the final diff:
Demo evidence: |
… OPENAI_BASE_URL env is OpenAI-compatible only)
|
Claude finished @frankbria's task in 2m 56s —— View job Precision bug-hunting review — completeScope: concrete defects only (logic errors, security, data loss, breaking contracts, leaks) — style/architecture/coverage handled by the general review.
✅ GLM review: no defects found.I traced the full chain and confirmed the implementation is correct:
( Env-leak guard — correct and behavior-preserving. No residual leak — security claim verified. Grep confirms Rename — clean. Zero remaining references to No inline findings to post. |

Closes #780 (remaining scope after #860 fixed the model override).
Problem
get_provider("anthropic", base_url=...)silently droppedbase_url, so a configuredllm.base_url(proxy/gateway deployments) never reached the Anthropic SDK.Change
AnthropicProvideracceptsbase_urland passes it to all three SDK client construction sites (syncAnthropic, bothAsyncAnthropicpaths).get_provider("anthropic", ...)forwardsbase_urlinstead of dropping it.resolve_llm_settingspreviously fell back to the ambientOPENAI_BASE_URLenv var for every provider — harmless only because the anthropic branch dropped it. Now thatbase_urlis honored, that fallback is gated to OpenAI-compatible providers (openai,ollama,vllm,compatible) so an ambientOPENAI_BASE_URLcannot silently redirect Anthropic traffic. An explicitllm.base_urlin.codeframe/config.yamlstill applies to any provider._OPENAI_COMPATIBLE→OPENAI_COMPATIBLE_PROVIDERS(now shared withcore.llm_resolution); updated the one demo-doc reference.Tests
tests/core/test_llm_resolution.py:test_anthropic_base_url_override_is_honored— asserts the value reaches the SDK client itself, guarding against a silent re-droptest_openai_base_url_env_does_not_leak_to_anthropictest_config_base_url_applies_to_anthropictest_openai_base_url_env_applies_to_openai_compatible(regression)Third-party review (pre-PR)
opencode (GLM) reviewed the diff: no Critical/Major findings. Both Minor findings (dangling
_OPENAI_COMPATIBLEreference indemo-pr552.md, stale docstring inllm_resolution.py) are fixed in this PR.Known limitations
Pre-existing call sites that bypass
resolve_llm_settingsstill won't pick up a configuredbase_url(deliberate defaults, out of scope here):core/tasks.pyget_provider()fallback,ui/routers/session_chat_ws.py, and the legacyapi_keybranches inprd_discovery.py/streaming_chat.py. Candidate follow-up under the #861 migration pattern.