mirror of
https://github.com/langchain-ai/langchain.git
synced 2026-10-05 09:25:14 +03:00
fix(openai): expose inferred Responses API routing at initialization (#40715)
Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
This commit is contained in:
1 parent
8caf77085b
commit
17d3d892cd
2 files changed
+72
-1
No files matched your search
@@ -1206,7 +1206,7 @@ class BaseChatOpenAI(BaseChatModel):
|
||||
use_responses_api: bool | None = None
|
||||
"""Whether to use the Responses API instead of the Chat API.
|
||||
|
||||
If not specified then will be inferred based on invocation params.
|
||||
If not specified, set to `True` when instance settings require the Responses API,
|
||||
|
||||
!!! version-added "Added in `langchain-openai` 0.3.9"
|
||||
"""
|
||||
@@ -1325,6 +1325,13 @@ class BaseChatOpenAI(BaseChatModel):
|
||||
self._add_version("langchain-openai", __version__)
|
||||
return self
|
||||
|
||||
@model_validator(mode="after")
|
||||
def _infer_use_responses_api(self) -> Self:
|
||||
"""Expose unconditional instance-level Responses API routing."""
|
||||
if self.use_responses_api is None and self._use_responses_api({}):
|
||||
self.use_responses_api = True
|
||||
return self
|
||||
|
||||
@model_validator(mode="after")
|
||||
def validate_environment(self) -> Self:
|
||||
"""Validate that api key and python package exists in environment."""
|
||||
|
||||
@@ -4593,6 +4593,70 @@ def test_gpt_5_temperature_case_insensitive(
|
||||
assert payload["temperature"] == 0.7
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"kwargs",
|
||||
[
|
||||
{"output_version": "responses/v1"},
|
||||
{"context_management": []},
|
||||
{"include": []},
|
||||
{"reasoning": {}},
|
||||
{"truncation": "auto"},
|
||||
{"use_previous_response_id": True},
|
||||
{"model": "gpt-5-pro"},
|
||||
{"model": "gpt-5.3-codex"},
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize("explicit", [None, True, False])
|
||||
def test_infer_use_responses_api(kwargs: dict, explicit: bool | None) -> None:
|
||||
llm = ChatOpenAI(**kwargs, use_responses_api=explicit)
|
||||
expected = explicit if explicit is not None else True
|
||||
assert llm.use_responses_api is expected
|
||||
assert llm._use_responses_api({}) is expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"kwargs",
|
||||
[
|
||||
{},
|
||||
{"output_version": "v1"},
|
||||
{"reasoning_effort": "low"},
|
||||
{"model": "gpt-6-astra"},
|
||||
{"model_kwargs": {"text": {}}},
|
||||
{"model_kwargs": {"tools": [{"type": "web_search"}]}},
|
||||
],
|
||||
)
|
||||
def test_infer_use_responses_api_remains_dynamic(kwargs: dict) -> None:
|
||||
llm = ChatOpenAI(**kwargs)
|
||||
assert llm.use_responses_api is None
|
||||
assert llm._use_responses_api({"tools": [{"type": "web_search"}]})
|
||||
assert llm._use_responses_api({"text": {}})
|
||||
assert not llm._use_responses_api({})
|
||||
|
||||
|
||||
def test_infer_use_responses_api_from_output_version_env(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
monkeypatch.setenv("LC_OUTPUT_VERSION", "responses/v1")
|
||||
assert ChatOpenAI().use_responses_api is True
|
||||
|
||||
|
||||
def test_inferred_responses_api_bind_tools_strict() -> None:
|
||||
llm = ChatOpenAI(reasoning={})
|
||||
tool = {
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "get_weather",
|
||||
"parameters": {"type": "object", "properties": {}},
|
||||
},
|
||||
}
|
||||
bound = llm.bind_tools(
|
||||
[tool],
|
||||
response_format={"title": "Weather", "type": "object", "properties": {}},
|
||||
)
|
||||
assert isinstance(bound, RunnableBinding)
|
||||
assert "strict" not in bound.kwargs["tools"][0]["function"]
|
||||
|
||||
|
||||
def test_gpt_6_tools_use_responses_api() -> None:
|
||||
llm = ChatOpenAI(model="gpt-6-astra")
|
||||
tools = [
|
||||
|
||||
Reference in new issue
Block a user