Files
langchain/libs/partners/openrouter/tests/integration_tests/test_chat_models.py
Mason Daugherty f9fd7be695 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
2026-02-15 02:09:13 -05:00

70 lines
2.3 KiB
Python

"""Integration tests for `ChatOpenRouter` chat model."""
from __future__ import annotations
import pytest
from langchain_core.messages import AIMessageChunk, BaseMessageChunk
from pydantic import BaseModel, Field
from langchain_openrouter.chat_models import ChatOpenRouter
def test_basic_invoke() -> None:
"""Test basic invocation."""
model = ChatOpenRouter(model="openai/gpt-4o-mini", temperature=0)
response = model.invoke("Say 'hello' and nothing else.")
assert response.content
assert response.response_metadata.get("model_provider") == "openrouter"
def test_streaming() -> None:
"""Test streaming."""
model = ChatOpenRouter(model="openai/gpt-4o-mini", temperature=0)
full: BaseMessageChunk | None = None
for chunk in model.stream("Say 'hello' and nothing else."):
full = chunk if full is None else full + chunk
assert isinstance(full, AIMessageChunk)
assert full.content
def test_tool_calling() -> None:
"""Test tool calling via OpenRouter."""
class GetWeather(BaseModel):
"""Get the current weather in a given location."""
location: str = Field(description="The city and state")
model = ChatOpenRouter(model="openai/gpt-4o-mini", temperature=0)
model_with_tools = model.bind_tools([GetWeather])
response = model_with_tools.invoke("What's the weather in San Francisco?")
assert response.tool_calls
def test_structured_output() -> None:
"""Test structured output via OpenRouter."""
class Joke(BaseModel):
"""A joke."""
setup: str = Field(description="The setup of the joke")
punchline: str = Field(description="The punchline of the joke")
model = ChatOpenRouter(model="openai/gpt-4o-mini", temperature=0)
structured = model.with_structured_output(Joke)
result = structured.invoke("Tell me a joke about programming")
assert isinstance(result, Joke)
assert result.setup
assert result.punchline
@pytest.mark.xfail(reason="Depends on reasoning model availability on OpenRouter.")
def test_reasoning_content() -> None:
"""Test reasoning content from a reasoning model."""
model = ChatOpenRouter(
model="openai/o3-mini",
reasoning={"effort": "low"},
)
response = model.invoke("What is 2 + 2?")
assert response.content