Skip to content

[integrations][anthropic] Stop sending rejected sampling parameters - #1037

Open
weiqingy wants to merge 1 commit into
apache:mainfrom
weiqingy:1036-anthropic-temperature
Open

[integrations][anthropic] Stop sending rejected sampling parameters#1037
weiqingy wants to merge 1 commit into
apache:mainfrom
weiqingy:1036-anthropic-temperature

Conversation

@weiqingy

@weiqingy weiqingy commented Aug 22, 2026

Copy link
Copy Markdown
Collaborator

Linked issue: #1036

Purpose of change

Claude Opus 4.7+ and the Sonnet, Fable and Mythos 5 lines return HTTP 400 for a non-default temperature, top_p or top_k. The Anthropic integration defaults temperature to 0.1 and sent it on every request without checking the model, so picking one of those models turned every chat call into a provider error. Both languages had the defect.

All three parameters are now dropped on models that reject them, in both languages. Dropped rather than clamped: omitting the parameter is accepted everywhere, while substituting the provider default would quietly change sampling behaviour. Each drop is logged once per model and parameter.

Three paths could reach the wire, and all three are gated:

Path Was
Java top-level temperature sent unconditionally
Java additional_kwargstop_p / top_k sent unconditionally
Java additional_kwargstemperature no case label, so forwarded as a raw body property

Python gates the merged kwargs immediately above its single create call.

The model list is deliberately separate from the prefill and structured-output lists in this connection: the three boundaries do not coincide. Structured output starts at 4.5, prefill rejection at 4.6, sampling rejection at 4.7, so Claude 4.6 rejects a prefill while still accepting a temperature. A test pins that.

One behaviour change. A caller setting temperature both at the top level and in additional_kwargs now has the additional_kwargs value win. Previously both were emitted under the same key, producing {"temperature":0.1,"temperature":0.5}, which is undefined. Typed and raw routes serialize identically for a number, so accepting models see no change on the wire.

One bug fix beyond the 400. The warn-once bookkeeping was keyed on the model alone, so a second parameter dropped for an already-warned model was discarded silently. It is now keyed on model and parameter.

Tests

Java 81 in AnthropicChatModelConnectionTest, 83 in the module. Python 84 passed, 2 skipped. Spotless, Ruff and RAT clean.

Coverage was driven by mutation testing. Every mutant in scope dies in both languages: the guard removed per parameter, each parameter's routing removed, and the warn key reverted to model-only.

Worth knowing for future edits: an unrecognised key is forwarded as a raw body property, so asserting the typed accessor is empty does not prove a parameter was left off. The drop tests assert the raw body too.

Not covered: a rewrite that keeps the dedup helper but rebuilds the message at the call site and logs unconditionally. Observing the LOG.warn call itself needs a logging binding in a module that has none.

API

No public API change. temperature, top_p and top_k keep their names, types and defaults; only whether they reach the provider depends on the model. No change on models that accept sampling parameters, including the default claude-sonnet-4-20250514.

Documentation

  • doc-needed
  • doc-not-needed
  • doc-included

chat_models.md: both temperature rows note the parameter is not sent on Claude 4.7+; the Java additional_kwargs row adds temperature and states the precedence. The Python additional_kwargs row was removed because that parameter does not exist in the Python setup.

Was this patch authored or co-authored using generative AI tooling?

  • Yes
  • No

Generated-by: Claude Code 2.1.234 (Claude Opus 5)

@github-actions github-actions Bot added doc-included Your PR already contains the necessary documentation updates. fixVersion/0.4.0 priority/major Default priority of the PR or issue. labels Aug 22, 2026
@weiqingy weiqingy changed the title [integrations][java][python] Stop sending temperature to Anthropic models that reject it [integrations] Stop sending temperature to Anthropic models that reject it Aug 23, 2026
@github-actions github-actions Bot added doc-included Your PR already contains the necessary documentation updates. and removed doc-included Your PR already contains the necessary documentation updates. labels Aug 23, 2026
@weiqingy weiqingy changed the title [integrations] Stop sending temperature to Anthropic models that reject it [integrations][anthropic] Stop sending temperature to Anthropic models that reject it Aug 23, 2026
@github-actions github-actions Bot added doc-included Your PR already contains the necessary documentation updates. and removed doc-included Your PR already contains the necessary documentation updates. labels Aug 23, 2026
Claude Opus 4.7 and later, and the Sonnet, Fable and Mythos 5 lines, answer
a non-default temperature, top_p or top_k with a 400. Sending the provider
default or omitting the parameter stays acceptable everywhere, so the
parameter is dropped rather than clamped: substituting the default would
quietly change sampling behavior instead of leaving it to the provider.

All three parameters are gated, on every path that reaches the request. In
Java that is the top-level temperature read and the additional_kwargs switch,
where a key without a case label is forwarded as a raw body property and so
reaches the API ungated. Python gates the merged kwargs above its single
create call.

Adding a temperature case to that switch means an additional_kwargs value now
takes precedence over the top-level one. Previously the two were emitted as a
typed field and a raw property under the same key, producing duplicate JSON
keys, which is undefined. The typed and raw routes serialize identically for
a number, so accepting models see no change.

The warn-once bookkeeping is keyed on the model and the parameter rather than
the model alone. Keyed on the model, a second parameter dropped for a model
that had already warned was discarded silently.

Generated-by: Claude Code 2.1.234 (Claude Opus 5)
@weiqingy
weiqingy force-pushed the 1036-anthropic-temperature branch from 3ad8bf2 to 178c0f5 Compare August 23, 2026 05:10
@weiqingy weiqingy changed the title [integrations][anthropic] Stop sending temperature to Anthropic models that reject it [integrations][anthropic] Stop sending rejected sampling parameters Aug 23, 2026
@github-actions github-actions Bot added doc-included Your PR already contains the necessary documentation updates. and removed doc-included Your PR already contains the necessary documentation updates. labels Aug 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

doc-included Your PR already contains the necessary documentation updates. fixVersion/0.4.0 priority/major Default priority of the PR or issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant