Skip to content

fix(anthropic): forward effort and thinking budgets - #17379

Open
maheshrbapatu wants to merge 8 commits into
ai-dynamo:mainfrom
maheshrbapatu:fix/17375-anthropic-reasoning-controls
Open

maheshrbapatu wants to merge 8 commits into
ai-dynamo:mainfrom
maheshrbapatu:fix/17375-anthropic-reasoning-controls

Conversation

@maheshrbapatu

@maheshrbapatu maheshrbapatu commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Overview

Forward output_config.effort and enabled-thinking budgets through Dynamo’s existing reasoning controls. This preserves acceptance of Claude Code’s adaptive/omitted/effort-high request shape while delivering the requested controls to workers.

Key Changes

Approximately 58 added production-code lines beyond the merged admission validation, excluding tests, comments, and whitespace.

  • anthropic.rs normalizes reasoning controls before dispatch.
  • types.rs maps effort to reasoning_effort and budgets to thinking_token_budget, preserving explicit adaptive and between-tools behavior.
  • Documentation describes backend/model enforcement requirements; forwarding is not a guarantee that every worker enforces a budget.

Validation

Case Before After / regression
Supported effort and enabled budgets Discarded Five representative HTTP cases cover all effort grades, two budgets and both response modes, checking canonical fields and stop conditions
Claude Code adaptive/omitted/high Effort ignored Accepted and forwarded without forcing up-front thinking
between_tools plus effort Effort ignored Effort forwarded while the explicit mode prevents up-front thinking
Invalid controls Ambiguous handling Rejected before backend dispatch

After rebasing onto main 1732fd7, all 28 real-HTTP admission, replay, and reasoning-control tests pass. These use scripted CPU backends and do not qualify live inference or Anthropic hosted behavior.

Issues and Ongoing Work

Pull Request Checklist
  • I used Dynamo's /pr-checklist skill.

Summary by CodeRabbit

  • New Features
    • Anthropic requests now support reasoning effort and thinking options, with supported settings forwarded to the backend.
  • Bug Fixes
    • Invalid Anthropic requests receive structured JSON errors with matching request IDs; malformed fields and unsupported values are rejected before generation.
    • Anthropic streaming responses now use protocol-specific terminal events instead of the [DONE] sentinel.
  • Documentation
    • Updated the documented default HTTP body limit from 192 MB to 45 MB and expanded Anthropic API compatibility details.

@copy-pr-bot

copy-pr-bot Bot commented Oct 27, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@github-actions

Copy link
Copy Markdown
Contributor

👋 Hi maheshrbapatu! Thank you for contributing to ai-dynamo/dynamo.

Just a reminder: The NVIDIA Test Github Validation CI runs an essential subset of the testing framework to quickly catch errors.Your PR reviewers may elect to test the changes comprehensively before approving your changes.

🚀

@github-actions github-actions Bot added fix external-contribution Pull request is from an external contributor documentation Improvements or additions to documentation frontend `python -m dynamo.frontend` and `dynamo-run in=http|text|grpc` labels Oct 27, 2026
@maheshrbapatu maheshrbapatu changed the title fix(anthropic): reject unenforced reasoning controls fix(anthropic): forward effort and thinking budgets Oct 27, 2026
@maheshrbapatu
maheshrbapatu force-pushed the fix/17375-anthropic-reasoning-controls branch from b6f4a16 to 6491165 Compare October 27, 2026 17:46
@maheshrbapatu
maheshrbapatu temporarily deployed to external_collaborator October 27, 2026 17:46 — with GitHub Actions Inactive
@maheshrbapatu
maheshrbapatu marked this pull request as ready for review October 27, 2026 17:52
@maheshrbapatu
maheshrbapatu requested review from a team as code owners October 27, 2026 17:52
@coderabbitai

coderabbitai Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Walkthrough

The Anthropic Messages service now validates request fields, returns request-ID-linked Anthropic errors, and forwards supported reasoning controls into backend requests. The change also updates streamed-response termination handling and documents request limits, validation rules, and control mappings.

Changes

Anthropic Messages compatibility

Layer / File(s) Summary
Request admission and error responses
docs/fern/pages/reference/components/frontend-configuration.mdx, lib/llm/Cargo.toml, lib/llm/src/http/service/anthropic.rs, lib/llm/src/http/service/anthropic/validation.rs, lib/llm/tests/anthropic_http_admission.rs, lib/llm/tests/frontend_protocol_validation_http.rs
The handlers validate raw request data and return Anthropic-formatted errors with request IDs. Validation covers system content, tool choices, metadata, thinking options, and numeric bounds. Documentation describes these rules and the 45 MiB body limit.
Reasoning-control conversion
docs/fern/pages/reference/components/frontend-configuration.mdx, lib/llm/src/http/service/anthropic.rs, lib/llm/src/protocols/anthropic/types.rs, lib/llm/tests/anthropic_reasoning_controls_http.rs, lib/llm/tests/anthropic_http_replay.rs
Request conversion forwards supported effort values and thinking budgets, maps between_tools to disabled thinking, and normalizes reasoning-template arguments. Tests cover accepted and rejected controls.
Protocol-specific stream termination
lib/llm/src/http/service/disconnect.rs, lib/llm/src/http/service/openai.rs, lib/llm/src/http/service/anthropic.rs, lib/llm/tests/anthropic_http_replay.rs, lib/llm/tests/common/http_harness.rs
The disconnect monitor receives an explicit done-sentinel setting. Anthropic streams are checked for a final message_stop or error event, while Chat Completions retains its done sentinel.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Severity of issue fixed: Medium

Merge Risk: Minimal · up to 64911

The checked reasoning controls and stream termination behavior do not present a known merge blocker.

Pre-merge checks: Passed 3 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Out of Scope Changes check Warning The PR contains changes outside #17375's stated HTTP/conversion/adapter reasoning-control scope. The documentation changes DYN_HTTP_BODY_LIMIT_MB from 192 MB to 45 MB, which is unrelated to reasonin… Revert the unrelated DYN_HTTP_BODY_LIMIT_MB default change and its dependent 45 MiB documentation claim. Move the budget shape/range validation to #17362/#17367, or exclude it from this PR if that dependency is merged separately. Retain t…
Passed Passed checks: 3 passed
Check name Status Explanation
Title check Passed The title clearly identifies the main change: forwarding Anthropic effort and thinking budgets.
Linked Issues check Passed The PR meets the coding requirements in #17375. AnthropicCreateMessageRequest conversion forwards supported output_config.effort values to reasoning_effort and enabled budget_tokens to `thinki…
Description check Passed The pull request description includes all required sections: Overview, Key Changes, Validation, and Issues and Ongoing Work. It provides implementation details, test coverage, limitations, linked issu…
Full details: Linked Issues check

Explanation

The PR meets the coding requirements in #17375. AnthropicCreateMessageRequest conversion forwards supported output_config.effort values to reasoning_effort and enabled budget_tokens to thinking_token_budget. The handler normalizes adaptive and between_tools without forcing up-front thinking, then normalizes template arguments before dispatch. Existing stop-condition extraction receives the forwarded budget. Real HTTP tests cover distinct effort and budget values, omission, the Claude Code adaptive/high shape, streaming and non-streaming requests, and between_tools with effort. The documentation states backend enforcement limits and does not claim live-model behavior.

Full details: Description check

Explanation

The pull request description includes all required sections: Overview, Key Changes, Validation, and Issues and Ongoing Work. It provides implementation details, test coverage, limitations, linked issues, and a completed checklist.

Full details: Out of Scope Changes check

Explanation

The PR contains changes outside #17375's stated HTTP/conversion/adapter reasoning-control scope. The documentation changes DYN_HTTP_BODY_LIMIT_MB from 192 MB to 45 MB, which is unrelated to reasoning-control forwarding. The PR also adds budget shape/range admission validation in validation.rs, although #17375 assigns that work to #17362/#17367. The broader error-envelope, request-validation, and SSE changes may support the dependency work, but the unrelated body-limit change is demonstrated out of scope.

Resolution

Revert the unrelated DYN_HTTP_BODY_LIMIT_MB default change and its dependent 45 MiB documentation claim. Move the budget shape/range validation to #17362/#17367, or exclude it from this PR if that dependency is merged separately. Retain the forwarding, normalization, stop-condition, focused tests, and compatibility documentation required by #17375.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Tip

🎯 Customize your risk assessments

Guide how CodeRabbit assesses merge risk and security architecture risk. Highlight sensitive changes and explain your security boundaries using Merge Risk Instructions and Security Risk Instructions in your review settings. Security architecture risk assessments require the Advanced plan or above.

✅ Automatic approvals, with your rules

Let CodeRabbit approve pull requests once required threads are resolved, pre-merge checks pass, and your risk limits are met. Enable Automatic approvals in review settings, with overrides for teams or file paths.

CodeRabbit Verify

  • Run CodeRabbit Verify to test the changes in this pull request.
Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 95f1b12 and 6491165.

Files selected for processing: 12
  • docs/fern/pages/reference/components/frontend-configuration.mdx
  • lib/llm/Cargo.toml
  • lib/llm/src/http/service/anthropic.rs
  • lib/llm/src/http/service/anthropic/validation.rs
  • lib/llm/src/http/service/disconnect.rs
  • lib/llm/src/http/service/openai.rs
  • lib/llm/src/protocols/anthropic/types.rs
  • lib/llm/tests/anthropic_http_admission.rs
  • lib/llm/tests/anthropic_http_replay.rs
  • lib/llm/tests/anthropic_reasoning_controls_http.rs
  • lib/llm/tests/common/http_harness.rs
  • lib/llm/tests/frontend_protocol_validation_http.rs

Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 10 remain after this review.

(model, stream)
}

pub(super) fn into_request(self, headers: &HeaderMap) -> Result<T, String> {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Every /v1/messages request now incurs multiple whole-body JSON scans before generation. identity() has already called fields(), then into_request() calls it again here, and Json::<T>::from_bytes parses the complete payload a third time; additionally, Box<RawValue> owns a full copy of the body. For supported requests near the 45 MiB ingress limit, this adds substantial per-request CPU and memory pressure directly on the inference admission path. Parse the request once while preserving the few raw fields needed for header-aware validation, and derive model/stream identity from that result instead of reparsing the body.

🤖 AI Fix

Replace the RawValue reparse pipeline with a single-pass extractor that produces the typed request, validation inputs, and model/stream identity without copying and rescanning the complete body.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Rebased onto #17367’s admission fix: ingress Bytes replace the owned body copy, and model/stream labels come from the single borrowed-field scan. Original typed parsing still provides duplicate-key rejection and field paths. Two linear passes remain; the measurements and their limits are recorded in #17367’s updated description.

async fn effort_and_manual_budgets_reach_canonical_fields() {
temp_env::async_with_vars(ENV, async {
let script = load_agent_fixture("text.sse").await.unwrap();
let svc = HarnessService::start(std::iter::repeat_n(script, 20)).await;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This creates 20 scripted HTTP exchanges by crossing five efforts, two budgets, and both response modes, but the production conversion handles these dimensions independently: effort is validated/copied separately, the budget is copied directly, and the backend request is always internally streaming. Repeating every effort for both budgets and both client stream values therefore protects no additional backend-field contract. Five cases can retain every effort while distributing both budget values and both client response modes, still detecting a hard-coded budget and stream-specific admission failure.

🤖 AI Fix

Replace the Cartesian product with five explicit cases that cover each effort once while distributing 1024/2048 budgets and false/true client streaming across them.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Replaced the 20-request cross-product with five explicit representative cases. Together they cover every effort grade, both budgets, and unary/streaming requests while asserting the canonical effort and thinking-budget stop condition.

@maheshrbapatu
maheshrbapatu force-pushed the fix/17375-anthropic-reasoning-controls branch from 6491165 to 8fc16b1 Compare October 28, 2026 05:19
@maheshrbapatu
maheshrbapatu requested review from a team as code owners October 28, 2026 05:19
@maheshrbapatu
maheshrbapatu temporarily deployed to external_collaborator October 28, 2026 05:19 — with GitHub Actions Inactive
@maheshrbapatu
maheshrbapatu force-pushed the fix/17375-anthropic-reasoning-controls branch from 8fc16b1 to b4e9a58 Compare October 28, 2026 05:40
@maheshrbapatu
maheshrbapatu temporarily deployed to external_collaborator October 28, 2026 05:40 — with GitHub Actions Inactive
Comment on lines +855 to +858
<Note>
These behaviors require a build containing
[PR #17367](https://github.com/ai-dynamo/dynamo/pull/17367).
</Note>

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.

Don't include these types of notes, it is assumed

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Removed the build note. The documentation now describes the behavior directly.


#### Reasoning Controls

Builds containing [#17375](https://github.com/ai-dynamo/dynamo/issues/17375) forward

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.

Don't include these types of notes, it is assumed

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Removed the issue-dependent wording and described the reasoning controls in the present tense. Docs checks and the strict link check pass.

Signed-off-by: maheshrbapatu <maheshbapatu@gmail.com>
… clients

Signed-off-by: maheshrbapatu <maheshbapatu@gmail.com>
Signed-off-by: maheshrbapatu <maheshbapatu@gmail.com>
Signed-off-by: maheshrbapatu <maheshbapatu@gmail.com>
Signed-off-by: maheshrbapatu <maheshbapatu@gmail.com>
Signed-off-by: maheshrbapatu <maheshbapatu@gmail.com>
@maheshrbapatu
maheshrbapatu force-pushed the fix/17375-anthropic-reasoning-controls branch from 7d91985 to 5a7f531 Compare November 3, 2026 20:02
@maheshrbapatu
maheshrbapatu temporarily deployed to external_collaborator November 3, 2026 20:02 — with GitHub Actions Inactive
Signed-off-by: maheshrbapatu <maheshbapatu@gmail.com>
@maheshrbapatu
maheshrbapatu temporarily deployed to external_collaborator November 3, 2026 20:25 — with GitHub Actions Inactive
Signed-off-by: maheshrbapatu <maheshbapatu@gmail.com>

This branch was previously deployed

1 inactive deployment
external_collaborator — 253591bc Deployed Nov 3, 2026 by maheshrbapatu via ok-to-test #44505
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation external-contribution Pull request is from an external contributor fix frontend `python -m dynamo.frontend` and `dynamo-run in=http|text|grpc` size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(anthropic): forward effort and thinking budgets through backend controls

2 participants