Skip to content

fix(claude): explicit Claude 5.x model table for request policy - #4655

Closed
aheritier wants to merge 17 commits into
docker:mainfrom
aheritier:feat/claude5x-model-table
Closed

aheritier wants to merge 17 commits into
docker:mainfrom
aheritier:feat/claude5x-model-table

Conversation

@aheritier

Copy link
Copy Markdown
Collaborator

Closes #4651. Part of #4583 (Claude 5.x core) and epic #4580.

What

Replace the name-based guesses for Claude 5.x with an explicit table of the nine models (modelinfo.LookupClaude5). Anthropic Direct, Vertex and Bedrock Converse now send each of them a request it accepts. IDs outside the table keep exactly today's behavior.

Model Can disable thinking Server prefix check
Haiku 5.5, Opus 5, Sonnet 5 yes Haiku 5.5 only
Opus 5.5, Sonnet 5.5, Fable 5.1 no yes
Fable 5, Mythos 5, Mythos 5.1 no no

All nine use adaptive thinking by default, reject token budgets and sampling params, and accept every effort level up to max.

Bugs fixed (each with a test that failed before)

  • Haiku 5.5: thinking_budget: high was sent as budget_tokens, which every 5.x model rejects.
  • Bedrock: effort and token budgets became budget_tokens on Sonnet 5/5.5, Haiku 5.5, Fable and Mythos.
  • Bedrock: temperature/top_p/top_k were sent to 5.x models.
  • thinking_budget: none never reached the Claude clients through the factory. applyModelDefaults turns it into a nil budget plus WithNoThinking, so on 5.x thinking stayed on at the server default, on Direct, Vertex and Bedrock. It is now sent as disabled where the model allows it and as adaptive/low otherwise.
  • Thinking prefix check: it was wrong for Mythos 5.1 (no server check) and missing for Haiku, Opus and Sonnet 5.5.
  • Opus 5.5 and Sonnet 5.5 were sent thinking: disabled, which they reject.
  • TUI effort cycle hid xhigh/max on Haiku 5.5, Sonnet 5 and Sonnet 5.5.

Behavior changes to review

  • none on a model that can't disable thinking (Opus/Sonnet 5.5, Fable, Mythos) is sent as adaptive with low effort. When the value came from config, a startup warning says so. Internal calls (titles, MCP sampling) get the same mapping silently.
  • A token budget on a 5.x model becomes adaptive with no effort, so the model's own default applies. max_tokens is not raised, and the warning now says the token ceiling is not enforced.
  • A request ending on an assistant message (prefill) is rejected locally before sending, on Direct, Vertex and Bedrock.
  • Tool-mode structured output on 5.x fails with ErrorCodeStructuredOutputFailed after the first plain-text answer, instead of retrying with reminders. Each retry would end on the model's answer, which 5.x rejects. feat(Claude): Claude 5.x core — request policy and signed history #4583 asks for "one inference, then a graceful model error", with no role rewrite.
  • Mythos 5.1 no longer gets the automatic drop_block binding. Haiku, Opus and Sonnet 5.5 now get it, the same way Fable 5.1 already did. The default policy itself (drop_block vs error) is feat(anthropic): Claude 5.x safety defaults (prefix error, temporary fallback block, Mythos 5 on Converse) #4652.

Tests

  • Table lookup: fixtures written independently of the production table, covering Vertex @date, Bedrock us.anthropic.…-v1:0, gateway prefixes and near-miss IDs. openai/claude-… IDs deliberately don't match.
  • Final requests captured through the real factory (providers.NewDefaultRegistry()) for Direct standard, Direct Beta, Vertex Model Garden (path, anthropic_version, bearer auth, no API key, de-duplicated betas), Bedrock Converse and a title clone, plus legacy controls.
  • Runtime test for the structured-output path.

Validation

  • task build passes.
  • golangci-lint v2.14.0 reports 0 issues, and go run ./lint . reports no offenses.
  • go test -race -shuffle=on ./pkg/modelinfo/ ./pkg/model/provider/... ./pkg/runtime/ passes.
  • go test ./e2e -run '^TestWasmProviderDependencies$|^TestDependencies$' passes.
  • task test-wasm-providers: the WASM JS packages pass. Running it needed a minimal environment, because Node rejected my shell's environment size.
  • task test fails only pkg/teamloader TestLoadExamples (10 Gemini examples, GOOGLE_API_KEY or GEMINI_API_KEY environment variable is required under .env.test). The base commit 7eedf8d fails identically on this machine.

Not verified against live services: Bedrock thinking: {"type":"disabled"} and the thinking-binding beta on Vertex. The docs say so.

Signed-off-by: Arnaud Héritier <aheritier@apache.org>
…bilities

Signed-off-by: Arnaud Héritier <aheritier@apache.org>
… table

Signed-off-by: Arnaud Héritier <aheritier@apache.org>
Signed-off-by: Arnaud Héritier <aheritier@apache.org>
Signed-off-by: Arnaud Héritier <aheritier@apache.org>
Signed-off-by: Arnaud Héritier <aheritier@apache.org>
…actory

applyModelDefaults turns a configured none into a nil budget plus
WithNoThinking, so the Anthropic and Bedrock clients never saw it and
Claude 5.x kept its default thinking. Restore the explicit none for the
Claude 5.x table so it is sent as disabled or adaptive low.

Signed-off-by: Arnaud Héritier <aheritier@apache.org>
…orts

Signed-off-by: Arnaud Héritier <aheritier@apache.org>
Signed-off-by: Arnaud Héritier <aheritier@apache.org>
…retry

A tool-mode reminder retry ends the request on the model's plain-text
answer, which Claude 5.x rejects as an assistant prefill. Fail with the
coded structured-output error after the first inference instead.

Signed-off-by: Arnaud Héritier <aheritier@apache.org>
Signed-off-by: Arnaud Héritier <aheritier@apache.org>
…and 0 budgets

Signed-off-by: Arnaud Héritier <aheritier@apache.org>
…e thinking

Signed-off-by: Arnaud Héritier <aheritier@apache.org>
Signed-off-by: Arnaud Héritier <aheritier@apache.org>
Importing vertexai for IsModelGardenConfig linked the OpenAI SDK into the
lean embedder surface (e2e TestDependencies). Check the publisher directly.

Signed-off-by: Arnaud Héritier <aheritier@apache.org>
@aheritier
aheritier requested a review from a team as a code owner October 19, 2026 21:51
Copilot AI balanced review requested due to automatic review settings October 19, 2026 21:51
@aheritier
aheritier enabled auto-merge October 19, 2026 21:52
Signed-off-by: Arnaud Héritier <aheritier@apache.org>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Request validation remains incomplete, and thinking-off and unknown-model policies conflict with the linked requirements.

4 open issues
What changed in this PR

Adds an explicit nine-model Claude 5.x capability table and applies request policies across Anthropic Direct, Vertex, and Bedrock.

Changes:

  • Updates thinking, effort, sampling, and prefix-check behavior.
  • Adds local prefill rejection and limits structured-output retries.
  • Adds request tests and documents transport behavior and limitations.
File Description
pkg/​runtime/​structured_output.go Stops reminder retries for Claude 5.x.
pkg/​runtime/​structured_output_test.go Tests failure after one inference.
pkg/​runtime/​loop.go Passes serving model to structured-output handling.
pkg/​modelinfo/​thinking_levels.go Enables all effort tiers for table models.
pkg/​modelinfo/​modelinfo.go Uses table for thinking capabilities.
pkg/​modelinfo/​claude5.go Defines model policies and ID lookup.
pkg/​modelinfo/​claude5_test.go Tests lookup and capabilities.
pkg/​model/​provider/​providerutil/​prefill.go Adds shared assistant-tail detection.
pkg/​model/​provider/​providerutil/​prefill_test.go Tests conversation-tail detection.
pkg/​model/​provider/​providers/​claude5_requests_test.go Captures requests through provider factories.
pkg/​model/​provider/​factory.go Warns about unsupported thinking-off settings.
pkg/​model/​provider/​factory_test.go Tests warning conditions.
pkg/​model/​provider/​bedrock/​client.go Applies Claude 5.x Converse policies.
pkg/​model/​provider/​bedrock/​client_test.go Tests Converse request behavior.
pkg/​model/​provider/​anthropic/​thinking.go Restores disabled budgets and controls effort.
pkg/​model/​provider/​anthropic/​thinking_binding_test.go Updates binding and budget-warning tests.
pkg/​model/​provider/​anthropic/​system_context_test.go Uses a legacy model for prefill testing.
pkg/​model/​provider/​anthropic/​features_integration_test.go Tests thinking policies and prefill rejection.
pkg/​model/​provider/​anthropic/​client.go Rejects detected assistant prefills locally.
pkg/​model/​provider/​anthropic/​capabilities.go Consults the explicit capability table.
pkg/​model/​provider/​anthropic/​capabilities_test.go Tests table-backed capability predicates.
docs/​providers/​bedrock/​index.md Documents Converse policies and verification limits.
docs/​providers/​anthropic/​index.md Documents Claude 5.x request behavior.

Review effort: Balanced

Comment on lines +60 to 64
if _, ok := modelinfo.LookupClaude5(model); ok {
return true
}
m, ok := parseClaudeModel(model)
return ok && (m.atLeast("opus", 5, 0) || m.atLeast("sonnet", 5, 0) || m.family == "fable" || m.family == "mythos")

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intentional: the maintainer decided that IDs outside the nine-model table keep today's name heuristics, so nothing that works now regresses. Making the table the only source of 5.x behavior would drop sampling omission and adaptive defaults for IDs like claude-haiku-5 or claude-mythos-5-preview, causing 400s. #4651 has been updated to record this decision.

Comment on lines +328 to +330
if budget.IsDisabled() {
if isClaude5 && !c5.CanDisableThinking {
return "low", true

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intentional, per maintainer decision: a configured none on a model that can't disable thinking is sent as adaptive/low, with a startup warning. A local error would break title generation and MCP sampling, which request no-thinking internally, on Opus/Sonnet 5.5, Fable and Mythos. #4651 has been updated to record this decision.

Comment on lines +105 to +111
req := captureFinalRequest(t, latest.ModelConfig{
Provider: "anthropic", Model: "claude-haiku-5-5",
ThinkingBudget: &latest.ThinkingBudget{Effort: "high"}, Temperature: new(0.2),
}, anthropicEnv)
assert.Equal(t, "adaptive", field(req.body, "thinking", "type"))
assert.Equal(t, "high", field(req.body, "output_config", "effort"))
assert.NotContains(t, req.body, "temperature")

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in e89cd77. The standard-path cases now use Sonnet 5 (no automatic binding) with interleaved_thinking: false and assert the standard anthropic-beta header, including a token-budget case that checks effort is omitted. The Haiku 5.5 case is renamed to say it goes through Beta.

Comment on lines +9 to +18
// FinalAssistantPrefill reports whether the conversation ends with an
// assistant message that is not a tool call, i.e. a response prefill.
// Trailing system messages are ignored.
func FinalAssistantPrefill(messages []chat.Message) bool {
for _, msg := range slices.Backward(messages) {
switch msg.Role {
case chat.MessageRoleSystem:
continue
case chat.MessageRoleAssistant:
return len(msg.ToolCalls) == 0

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A history ending on an assistant tool_use with no tool_result is invalid for every Claude model, and the API rejects it with an explicit missing-tool-result error. It isn't a prefill. The runtime always appends tool results before the next call, so a 5.x-only 'prefill' check here would mislabel the error without preventing anything.

@aheritier aheritier added area/docs Documentation changes area/models LLM model integrations and model providers area/providers/anthropic For features/issues/fixes related to the usage of Anthropic models area/providers/bedrock AWS Bedrock provider support area/runtime Runtime engine, agent loop execution, tool dispatch, loop detection kind/fix PR fixes a bug (maps to fix:). Use on PRs only. labels Oct 19, 2026
… the factory level

Signed-off-by: Arnaud Héritier <aheritier@apache.org>
@aheritier

Copy link
Copy Markdown
Collaborator Author

Superseded by #4657: same commits, moved to a docker/docker-agent branch so #4656 can be a real GitHub stack on top of it. The review threads above remain here for reference.

@aheritier aheritier closed this Oct 19, 2026
auto-merge was automatically disabled October 19, 2026 22:17

Pull request was closed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/docs Documentation changes area/models LLM model integrations and model providers area/providers/anthropic For features/issues/fixes related to the usage of Anthropic models area/providers/bedrock AWS Bedrock provider support area/runtime Runtime engine, agent loop execution, tool dispatch, loop detection kind/fix PR fixes a bug (maps to fix:). Use on PRs only.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(anthropic): explicit Claude 5.x model table and request-policy resolver

2 participants