streamUsage default diverges from Python: setting a custom baseURL disables it in langchain-openai but not in @langchain/openai
Summary
Setting a custom base URL changes the stream_usage default in Python but not in JS. The Python package documents the reasoning; the JS package neither matches the behaviour nor mentions it. Same conceptual setting, two different outcomes.
Measured
Python (langchain-openai):
ChatOpenAI(model="gpt-4o-mini", api_key="sk-test") # stream_usage = True
ChatOpenAI(model="gpt-4o-mini", api_key="sk-test", base_url="http://127.0.0.1:9/v1")# stream_usage = NoneJS (@langchain/openai):
new ChatOpenAI({ model: "gpt-4o-mini", apiKey: "sk-test" }) // streamUsage = true
new ChatOpenAI({ model: "gpt-4o-mini", apiKey: "sk-test", configuration: { baseURL: "http://…" } })// streamUsage = trueBoth with OPENAI_BASE_URL and OPENAI_API_BASE unset, so the constructor argument is the only variable.
Why Python does it
From chat_models/base.py, the ChatOpenAI docstring:
OPENAI_BASE_URLis also inspected by LangChain only to decide whether to default-enablestream_usage— when set, the default is left off because many non-OpenAI endpoints do not support streaming token usage.
and the init logic guards on self.openai_api_base is None and "OPENAI_BASE_URL" not in os.environ.
That reasoning is sound and applies equally to JS: a gateway, vLLM, or an OpenAI-compatible server that does not implement stream_options.include_usage gets sent the flag anyway, and depending on the server either ignores it or rejects the request. The JS user has no way to know this is happening, because nothing in the typings or docs mentions that streamUsage interacts with the base URL at all — streamUsage: boolean in chat_models/base.d.ts is the whole of it.
What I think should happen
Either direction is defensible, but they should not silently differ:
- Match Python — leave
streamUsageunset when a custombaseURL(orOPENAI_BASE_URL/OPENAI_API_BASE) is in play, with the same one-line rationale in the typings. - Keep JS as-is and document it — state in the
streamUsagedoc comment that it stays on against custom endpoints, and that servers which do not implementstream_options.include_usagemay need it disabled explicitly.
Option 1 is the smaller surprise for anyone running both languages against the same gateway, which is the case that produced this report.
Related
Same area as #11635 (the OPENAI_API_BASE → OPENAI_BASE_URL resolution order being documented in Python but not JS). Filing separately because that one is a docs fix and this one is a behavioural difference; happy to have them merged if you would rather track "what changes when you set a base URL" as one item.
Environment
@langchain/openai and langchain-openai as resolved on 2026-09-14; Node 22.23.2 and Python 3.12 on Windows. No network calls involved — both checks read the constructed object.
Source: langchain-ai/langchainjs