feat(openrouter): add langchain-openrouter provider package (#35211)

Add a first-party `langchain-openrouter` partner package
(`ChatOpenRouter`) that wraps the official `openrouter` Python SDK,
providing native support for OpenRouter-specific features that
`ChatOpenAI` intentionally does not handle.

Also adds scope-clarifying docstrings to `ChatOpenAI` / `BaseChatOpenAI`
warning users away from using `base_url` overrides with third-party
providers.

---

Closes #31325
Closes #32967
Closes #32977
Closes #32981
Closes #33643
Closes #33757
Closes #34056
Closes #34797
Closes #34962

Supersedes #33902, #34867 (thank you @elonfeng and @okamototk for your
initial work on this!)

---

Bugs with upstream sdk:
- https://github.com/OpenRouterTeam/python-sdk/issues/38
- https://github.com/OpenRouterTeam/python-sdk/issues/51
- https://github.com/OpenRouterTeam/python-sdk/issues/52
This commit is contained in:
Mason Daugherty
2026-02-15 02:09:13 -05:00
committed by GitHub
parent b97c629f9a
commit f9fd7be695
29 changed files with 8958 additions and 4 deletions

View File

@@ -1,4 +1,15 @@
"""OpenAI chat wrapper."""
"""OpenAI chat wrapper.
!!! warning "API scope"
`ChatOpenAI` targets
[official OpenAI API specifications](https://github.com/openai/openai-openapi)
only. Non-standard response fields added by third-party providers (e.g.,
`reasoning_content`, `reasoning_details`) are **not** extracted or
preserved. If you are pointing `base_url` at a provider such as
OpenRouter, vLLM, or DeepSeek, use the corresponding provider-specific
LangChain package instead (e.g., `ChatDeepSeek`, `ChatOpenRouter`).
"""
from __future__ import annotations
@@ -511,7 +522,14 @@ _DictOrPydantic: TypeAlias = dict | _BM
class BaseChatOpenAI(BaseChatModel):
"""Base wrapper around OpenAI large language models for chat."""
"""Base wrapper around OpenAI large language models for chat.
This base class targets
[official OpenAI API specifications](https://github.com/openai/openai-openapi)
only. Non-standard response fields added by third-party providers (e.g.,
`reasoning_content`) are not extracted. Use a provider-specific subclass for
full provider support.
"""
client: Any = Field(default=None, exclude=True)
@@ -2262,6 +2280,16 @@ class BaseChatOpenAI(BaseChatModel):
class ChatOpenAI(BaseChatOpenAI): # type: ignore[override]
r"""Interface to OpenAI chat model APIs.
!!! warning "API scope"
`ChatOpenAI` targets
[official OpenAI API specifications](https://github.com/openai/openai-openapi)
only. Non-standard response fields added by third-party providers (e.g.,
`reasoning_content`, `reasoning_details`) are **not** extracted or
preserved. If you are pointing `base_url` at a provider such as
OpenRouter, vLLM, or DeepSeek, use the corresponding provider-specific
LangChain package instead (e.g., `ChatDeepSeek`, `ChatOpenRouter`).
???+ info "Setup"
Install `langchain-openai` and set environment variable `OPENAI_API_KEY`.