- Since 3 November, Sonnet 4.6 output carries Anthropic's text watermark, but the docs say text from a request that sets
temperature,top_portop_kto a non-default value "might not carry the watermark." That includes values your framework sets for you. - I captured the request bodies of 17 client setups against a local stub. Every current release of the Anthropic SDKs, LangChain, LiteLLM, Pydantic AI, DSPy, Instructor, the Vercel AI SDK, Claude Code and the Agent SDK sent no sampling parameters at all.
- The exceptions are older or awkward: LangChain JS 0.3.x sends
temperature: 1, top_p: -1, top_k: -1on every Sonnet 4.6 call (about 410,000 downloads last week), DSPy before 3.0.4 sends 0.0, and LlamaIndex sends 0.1 once you pin the SDK back far enough to make it run.
Anthropic's 3 November release note added three models to its text watermark: Claude Mythos 5, Opus 4.7 and Sonnet 4.6. The mark lives in the word choices themselves. It adds no tokens or hidden characters, and it survives copy and paste.
The developer doc for it is two paragraphs long, and the second one is the interesting one. On Sonnet 4.6, a request that sets any of the three sampling parameters to a non-default value might produce text without the mark. If you rely on the watermark, the doc says to omit all three, "including any that a framework or client library sets for you."
The doc doesn't say which frameworks do that, so I checked.
Why only Sonnet 4.6
Newer Claude models don't take sampling parameters at all. The Anthropic Python SDK removed temperature, top_p and top_k from messages.create() in version 1.0.0 on 20 August. Its migration guide says "Current models do not use these sampling parameters" and tells you to pass them through extra_body for an older model that still honours them.
The example it gives for that is model="claude-sonnet-4-6" with extra_body={"temperature": 0.2}. That's exactly the request the watermark doc warns about.
Claude Code has the same cut-off built in. Its 2.1.319 binary only attaches a temperature for models that predate Opus 4.7. So among the models that got the mark this week, Sonnet 4.6 is the one that still listens to a temperature. It's also the one plenty of production code is still pinned to.
How I tested
I wrote a small local server that pretends to be api.anthropic.com. It logs every request body and answers with a stub message, so no real API call is made and nothing costs money. Then I pointed each client at it through its base URL setting, asked for claude-sonnet-4-6, and set no sampling parameters myself. That's the default a developer gets by copying the quickstart.
I couldn't check the mark itself. Watermark detection is in private preview, behind an application form for regulators, researchers, media and enterprises checking their own output. What I can show is what each library puts on the wire, which is the half of the question you control.
The clean ones
Current releases sent no temperature, top_p or top_k field:
- Anthropic Python SDK 2.6.0 and JS SDK 1.6.0
- langchain-anthropic 1.7.10 (Python) and @langchain/anthropic 1.6.1 (JS)
- LiteLLM 1.108.2, Pydantic AI 2.66.0, DSPy 3.4.1, Instructor 1.17.0
- Vercel AI SDK 6.0.324 with @ai-sdk/anthropic 3.0.139, both
generateTextandstreamText - The OpenAI Python SDK against Anthropic's OpenAI-compatible endpoint
- Claude Agent SDK 0.2.179 and Claude Code 2.1.319 with default settings
Older Python LangChain was clean too. The conda environment on my own machine still has langchain-anthropic 0.3.19 with Anthropic SDK 0.101.0, and it sent nothing either.
Claude Code has one wrinkle. With thinking switched off, through MAX_THINKING_TOKENS=0 or CLAUDE_CODE_DISABLE_THINKING=1, it sends temperature: 1 on Sonnet 4.6. One is the API's default value, so this shouldn't count as non-default. But it's an explicit field, and the doc's safest advice is to send none.
The JS SDK still passes a temperature straight through if you set one, which the Python SDK no longer lets you do without extra_body.
LangChain JS 0.3: three fields on every call
@langchain/anthropic 0.3.26 and 0.3.34, the last 0.3 release from December 2025, both sent this on a plain invoke() with nothing configured:
"temperature": 1, "top_p": -1, "top_k": -1
The class sets those as its defaults and serialises them into every request. The -1 is LangChain's own placeholder for "not set." Whether Anthropic's server reads it the same way, or as a non-default value, I can't tell from the outside, and that's the problem. You don't want the mark to depend on how a server handles a legacy placeholder.
The 0.3 code does strip the defaults for opus-4-1, sonnet-4-5 and haiku-4-5, because those models reject temperature and top_p together. Sonnet 4.6 came out after that list was written, so it isn't on it. On claude-sonnet-4-5 the same code sent only top_k: -1.
Passing temperature: null removes the temperature field. Passing topP: null or topK: null does not: on Sonnet 4.6 both still went out as -1. What did work was overriding them in invocationKwargs:
new ChatAnthropic({
model: "claude-sonnet-4-6",
temperature: null,
invocationKwargs: { top_p: undefined, top_k: undefined },
})
That request went out with none of the three. The better fix is upgrading. Version 1.0.0 from October 2025 declares the fields without defaults, and nothing goes out unless you set it.
This isn't a fringe version. npm's per-version counts for last week show 410,601 of @langchain/anthropic's 2,103,966 downloads were on a 0.x release, about 19.5%. 0.3.34 alone had 143,897, the third most-downloaded version of the package.
DSPy before 3.0.4: temperature 0.0
DSPy's dspy.LM defaulted to temperature: float = 0.0 up to and including 3.0.0. With dspy 2.6.27 and the current LiteLLM underneath, a bare lm("Say ok.") against Sonnet 4.6 sent "temperature": 0.0.
From 3.0.4 (November 2025) onward the default is None and nothing is sent. If you have a DSPy program pinned to 2.x because an optimised prompt was tuned against it, your Sonnet 4.6 calls are going out at temperature 0.
LlamaIndex: broken first, then 0.1
llama-index-llms-anthropic 0.12.3 is the current release, from 12 October. A fresh pip install resolves it next to Anthropic SDK 2.6.0, and a plain .chat() call then crashes before any request goes out, with TypeError: Cannot instantiate typing.Union.
With the SDK pinned to 1.17.0 it fails differently: Messages.create() got an unexpected keyword argument 'temperature'. That error tells you what LlamaIndex is about to do. Its Anthropic class has temperature: float = DEFAULT_TEMPERATURE, and DEFAULT_TEMPERATURE in llama-index-core is 0.1.
Pin the SDK back to 0.125.0, the last release before 1.0, and the call works. The request carries "temperature": 0.1.
LlamaIndex keeps a list of models it won't send a temperature to. It covers Opus 4.7, Opus 4.8, Opus 5, Opus 5.5, Fable 5, Sonnet 5, Sonnet 5.5 and Haiku 5.5. Sonnet 4.6 isn't on it, on PyPI or on the main branch. So the usual way to get LlamaIndex working with Sonnet 4.6 today, pinning the SDK below 1.0, is also the way that gets you 0.1. The package had 80,550 downloads last week.
What to do with this
If nobody in your organisation relies on the watermark, none of this changes your output quality. Temperature 0.1 on Sonnet 4.6 is a perfectly reasonable setting.
If you do rely on it, for an AI Act labelling duty or to prove later that a document came out of Claude, check what your stack sends rather than what your code says. Your code may not set a temperature anywhere while the library still does. The quickest check is the one I used. Point ANTHROPIC_BASE_URL, or your framework's base URL option, at a local listener that prints the JSON body, and read the request.
Then remove what you find. Upgrade @langchain/anthropic to 1.x, move DSPy to 3.0.4 or later, and for LlamaIndex either wait for a fix or call the Anthropic SDK directly. And if a pipeline sets a temperature on purpose, moving it to a model where sampling parameters don't exist anymore removes the question entirely.
One thing is still unclear. Anthropic's support article lists Opus 4.6 next to Sonnet 4.6 under the same limitation, while the developer doc and release note name only Sonnet 4.6. If you're on Opus 4.6, treat it the same way until that's settled.