diff --git a/apps/cloud-api/tests/test_cloud_planner_config.py b/apps/cloud-api/tests/test_cloud_planner_config.py
index 0ddc1ac..d71c13a 100644
--- a/apps/cloud-api/tests/test_cloud_planner_config.py
+++ b/apps/cloud-api/tests/test_cloud_planner_config.py
@@ -40,6 +40,15 @@ def test_build_cloud_planner_client_uses_managed_anthropic_key() -> None:
assert client._api_key == "managed-api-key"
+def test_build_cloud_planner_client_uses_anthropic_base_url() -> None:
+ client = build_cloud_planner_client(
+ _resolved_profile("anthropic", base_url="https://anthropic-proxy.example")
+ )
+
+ assert isinstance(client, AnthropicToolCallingClient)
+ assert client._base_url == "https://anthropic-proxy.example"
+
+
def test_build_cloud_planner_client_uses_openai_compatible_base_url() -> None:
client = build_cloud_planner_client(
_resolved_profile("openai-compatible", base_url="https://compat.example/v1")
diff --git a/apps/cloud-api/tests/test_llm_provider_management.py b/apps/cloud-api/tests/test_llm_provider_management.py
index bd4d126..3054cf7 100644
--- a/apps/cloud-api/tests/test_llm_provider_management.py
+++ b/apps/cloud-api/tests/test_llm_provider_management.py
@@ -136,6 +136,29 @@ def test_provider_profile_requires_admin_scope(monkeypatch) -> None:
)
+def test_anthropic_profile_accepts_custom_base_url(monkeypatch) -> None:
+ from cryptography.fernet import Fernet
+
+ monkeypatch.setenv(
+ "CLOUD_LLM_PROVIDER_ENCRYPTION_KEY", Fernet.generate_key().decode()
+ )
+ app = create_app(config=CloudControlConfig(database_url="sqlite:///:memory:"))
+ with TestClient(app) as client:
+ _create_admin(client)
+ response = client.post(
+ "/v1/planner/providers",
+ headers=_csrf_headers(client),
+ json=_profile_payload(
+ name="Anthropic proxy",
+ provider_type="anthropic",
+ base_url="https://anthropic-proxy.example/",
+ ),
+ )
+
+ assert response.status_code == 201, response.text
+ assert response.json()["base_url"] == "https://anthropic-proxy.example"
+
+
def test_profile_write_requires_encryption_key(monkeypatch) -> None:
monkeypatch.delenv("CLOUD_LLM_PROVIDER_ENCRYPTION_KEY", raising=False)
app = create_app(config=CloudControlConfig(database_url="sqlite:///:memory:"))
diff --git a/cloud-console/src/views/LlmProvidersView.vue b/cloud-console/src/views/LlmProvidersView.vue
index 127e299..c7fd25b 100644
--- a/cloud-console/src/views/LlmProvidersView.vue
+++ b/cloud-console/src/views/LlmProvidersView.vue
@@ -98,7 +98,7 @@ async function saveProfile() {
saving.value = true;
try {
- const baseUrl = form.provider_type === "anthropic" ? null : form.base_url.trim() || null;
+ const baseUrl = form.base_url.trim() || null;
if (editingId.value) {
const existing = profiles.value.find((profile) => profile.id === editingId.value);
if (!existing) throw new Error("Provider profile no longer exists");
@@ -195,8 +195,8 @@ onMounted(refresh);
-