fix(core): address gateway URL review feedback

This commit is contained in:
John Kennedy
2026-07-11 13:45:18 -07:00
parent 0344b627dc
commit b667222964
7 changed files with 59 additions and 22 deletions

View File

@@ -1,15 +1,11 @@
"""Shared configuration for LangSmith Gateway provider endpoints."""
from __future__ import annotations
import os
from typing import TYPE_CHECKING, Final, Literal, TypedDict
if TYPE_CHECKING:
from collections.abc import Mapping
from typing_extensions import NotRequired
from collections.abc import Mapping
from typing import Final, Literal, TypedDict
from urllib.parse import urlsplit, urlunsplit
from typing_extensions import NotRequired
GatewayProvider = Literal["anthropic", "fireworks", "google_genai", "openai"]
@@ -50,6 +46,16 @@ _DISABLED_GATEWAY_VALUES: Final = frozenset({"false", "0", "no"})
_ENABLED_GATEWAY_VALUES: Final = frozenset({"true", "1", "yes"})
def _append_gateway_provider_path(url: str, provider_path: str) -> str:
"""Append a provider path without changing a URL's query or fragment."""
parsed_url = urlsplit(url)
if parsed_url.path.rstrip("/").endswith(provider_path):
return url
return urlunsplit(
parsed_url._replace(path=f"{parsed_url.path.rstrip('/')}{provider_path}")
)
def resolve_langsmith_gateway_url(provider: GatewayProvider) -> str | None:
"""Resolve the configured LangSmith Gateway URL for a provider.
@@ -78,11 +84,6 @@ def resolve_langsmith_gateway_url(provider: GatewayProvider) -> str | None:
provider_path = provider_config["path"]
if raw_url.lower() not in _ENABLED_GATEWAY_VALUES:
if raw_url.rstrip("/").endswith(provider_path):
return raw_url
return f"{raw_url.rstrip('/')}{provider_path}"
return _append_gateway_provider_path(raw_url, provider_path)
gateway_url = LANGSMITH_GATEWAY_URL
if gateway_url.endswith(provider_path):
return gateway_url
return f"{gateway_url}{provider_path}"
return _append_gateway_provider_path(LANGSMITH_GATEWAY_URL, provider_path)

View File

@@ -1,10 +1,13 @@
"""Tests for LangSmith Gateway URL configuration."""
from typing import get_type_hints
import pytest
from langchain_core.utils.gateway import (
LANGSMITH_GATEWAY_PROVIDERS,
LANGSMITH_GATEWAY_URL,
GatewayProviderConfig,
resolve_langsmith_gateway_url,
)
@@ -93,3 +96,36 @@ def test_langsmith_gateway_provider_matrix() -> None:
},
"openai": {"path": "/openai/v1", "oauth": True, "static_key": True},
}
@pytest.mark.parametrize(
("provider", "url", "expected_url"),
[
(
"openai",
"https://gateway.example.com?api-version=1#gateway",
"https://gateway.example.com/openai/v1?api-version=1#gateway",
),
(
"openai",
"https://gateway.example.com/openai/v1?api-version=1#gateway",
"https://gateway.example.com/openai/v1?api-version=1#gateway",
),
],
)
def test_resolve_langsmith_gateway_url_preserves_query_and_fragment(
monkeypatch: pytest.MonkeyPatch,
provider: str,
url: str,
expected_url: str,
) -> None:
"""Provider paths are added before URL query and fragment components."""
monkeypatch.setenv("LANGSMITH_GATEWAY", url)
assert resolve_langsmith_gateway_url(provider) == expected_url # type: ignore[arg-type]
def test_gateway_provider_config_runtime_type_metadata() -> None:
"""The public provider configuration retains optional-key metadata at runtime."""
assert GatewayProviderConfig.__optional_keys__ == {"notes"}
assert get_type_hints(GatewayProviderConfig)["notes"] is str

View File

@@ -24,7 +24,7 @@ version = "1.4.8"
requires-python = ">=3.10.0,<4.0.0"
dependencies = [
"anthropic>=0.96.0,<1.0.0",
"langchain-core>=1.4.7,<2.0.0",
"langchain-core>=1.4.10,<2.0.0",
"pydantic>=2.7.4,<3.0.0",
]

View File

@@ -552,7 +552,7 @@ wheels = [
[[package]]
name = "langchain"
version = "1.3.11"
version = "1.3.12"
source = { editable = "../../langchain_v1" }
dependencies = [
{ name = "langchain-core" },
@@ -662,7 +662,7 @@ requires-dist = [
]
[package.metadata.requires-dev]
lint = [{ name = "ruff", specifier = ">=0.13.1,<0.14.0" }]
lint = [{ name = "ruff", specifier = ">=0.13.1,<0.16.0" }]
test = [
{ name = "blockbuster", specifier = ">=1.5.5,<1.6" },
{ name = "defusedxml", specifier = ">=0.7.1,<1.0.0" },
@@ -689,7 +689,7 @@ typing = [
[[package]]
name = "langchain-core"
version = "1.4.8"
version = "1.4.9"
source = { editable = "../../core" }
dependencies = [
{ name = "jsonpatch" },

View File

@@ -23,7 +23,7 @@ classifiers = [
version = "1.4.3"
requires-python = ">=3.10.0,<4.0.0"
dependencies = [
"langchain-core>=1.4.7,<2.0.0",
"langchain-core>=1.4.10,<2.0.0",
"fireworks-ai>=1.2.0a71,<2.0.0",
"openai>=2.0.0,<3.0.0",
"requests>=2.0.0,<3.0.0",

View File

@@ -737,7 +737,7 @@ wheels = [
[[package]]
name = "langchain-core"
version = "1.4.8"
version = "1.4.9"
source = { editable = "../../core" }
dependencies = [
{ name = "jsonpatch" },

View File

@@ -23,7 +23,7 @@ classifiers = [
version = "1.3.4"
requires-python = ">=3.10.0,<4.0.0"
dependencies = [
"langchain-core>=1.4.9,<2.0.0",
"langchain-core>=1.4.10,<2.0.0",
"openai>=2.26.0,<3.0.0",
"tiktoken>=0.7.0,<1.0.0",
]