Skip to content

馃┕ fix: Don't Replay Reasoning to OpenAI Bedrock Models - #581

Merged
danny-avila merged 4 commits into
LibreChat-AI:mainfrom
devanchohan:fix/bedrock-reasoning-replay-non-claude
Sep 30, 2026
Merged

danny-avila merged 4 commits into
LibreChat-AI:mainfrom
devanchohan:fix/bedrock-reasoning-replay-non-claude

Conversation

@devanchohan

@devanchohan devanchohan commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Summary

A handoff from Bedrock Claude to Bedrock OpenAI GPT fails on the receiving agent's first request once the history includes Claude reasoning. Bedrock rejects the request with:

ValidationException: This model doesn't support the reasoningContent.reasoningText.text field for assistant messages.

In LibreChat this occurs during a handoff within one run. Reported in LibreChat-AI/LibreChat#16510. The reported production case was a Claude Sonnet 5 agent handing off to global.openai.gpt-6-luna after tool use.

Cause

Claude turns keep Bedrock-native reasoning_content with their reasoning text and signature. The existing cross-provider filter removes reasoning from other providers, but both agents here use Bedrock. The converter therefore sends Claude's reasoning back as reasoningContent to an OpenAI target that rejects it.

Change

  • Model-aware conversion. convertToConverseMessages(messages, { model }) takes the target model. The streaming adapter passes this.model, keeping the base model identity separate from an optional application inference profile.
  • Limit the fix to OpenAI targets. Drop native reasoning_content and v1 reasoning blocks for identified openai.* targets, including geography-prefixed model IDs. Keep text and tool calls. A reasoning-only assistant turn uses the existing _ placeholder.
  • Handle model-bearing ARNs. Classify model IDs embedded in foundation-model/ and system inference-profile/ ARNs. OpenAI targets do not bypass the filter just because they are configured by ARN.
  • Preserve compatibility. Other model families retain the existing reasoning-replay behavior. This avoids assuming DeepSeek, Kimi, Qwen, Nova, or other families reject their own reasoning history. Calls without a model and opaque application-inference-profile or provisioned-model ARNs also retain the existing behavior. The code comment documents this deliberate scope.

Out of scope: _generateNonStreaming still delegates to @langchain/aws's converter. This PR does not validate every model family's Bedrock reasoning-replay requirements or change their behavior.

Tests

Conversion and outgoing streaming request regressions cover:

  • Claude-to-OpenAI handoffs, preserving text and tool calls while dropping reasoning;
  • plain model IDs, foundation-model ARNs, and system inference-profile ARNs;
  • Claude reasoning preservation, opaque ARN fallback, and application profile overrides;
  • reasoning-only placeholders and v1 reasoning conversion;
  • unchanged native/v1 reasoning and tool-call replay for other model families;
  • other AWS partitions and case-insensitive model classification.

The original ARN regressions produced 8 expected failures before the ARN fix. The compatibility regressions produced 18 expected failures under the broader Claude-only rule.

Final local checks and exact-head CI state are recorded in the latest head handoff comment. Live Bedrock API validation and the full local repository test suite were not run.

馃 Generated with Claude Code; review follow-ups by Lia.

A handoff that stays on Bedrock but changes model family (an agent on
Claude handing over to one on OpenAI GPT) fails on the receiving agent's
first request. The Claude turns in the history keep Bedrock-native
reasoning_content, and the cross-provider reasoning drop only covers
reasoning from another provider, so the blocks reach the GPT request and
Bedrock rejects it:

  ValidationException: This model doesn't support the
  reasoningContent.reasoningText.text field for assistant messages.

The same happens when a conversation switches from Claude to GPT.

convertToConverseMessages now takes the target model, and the Bedrock
chat model passes this.model. Prior reasoning (reasoning_content, and v1
reasoning blocks) is replayed only to Claude; for any other identified
model it is dropped, and a turn left empty gets the existing placeholder.
A model that can't be identified (none given, or an ARN) keeps the
reasoning, so existing callers are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@lia-by-librechat

lia-by-librechat Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Updated this PR to 7f49cdbf206337b30ceabddb82a9f4037379e2cc.

  • Classifies the model ID embedded in foundation-model and system inference-profile ARNs before deciding whether to replay Claude reasoning.
  • Keeps Claude reasoning intact and preserves the compatibility fallback for opaque application-inference-profile and provisioned-model ARNs.
  • Adds native/v1 conversion coverage and streaming request regressions, including profile overrides and other AWS partitions. The new regressions produced 8 expected failures before the fix.
  • Formats the updated files and corrects their import ordering.
Local check Result
Bedrock and cache tests 13 suites; 182 passed, 4 skipped
Tracing tests 11 suites; 203 passed
npx tsc --noEmit Passed
Production build Passed
Touched-file ESLint, zero warnings Passed
Touched-file import order and Prettier Passed

CI for this exact head is awaiting GitHub's fork-workflow approval. No external review has arrived for this head yet. Live Bedrock API validation and the full local repository test suite were not run. The non-streaming path remains outside this PR's scope.

@lia-by-librechat lia-by-librechat Bot changed the title 馃┕ fix: Don't Replay Claude Reasoning to Non-Claude Bedrock Models 馃┕ fix: Don't Replay Reasoning to OpenAI Bedrock Models Sep 29, 2026
@lia-by-librechat

lia-by-librechat Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Independent review follow-up pushed to c90de0a025966ce486dfddded5166bd3fd294b82.

  • Scope concern addressed: suppress prior reasoning only for identified OpenAI Bedrock targets. Other families retain pre-PR behavior. The code comment explicitly says their Bedrock replay requirements have not been verified here; native-provider API requirements are not evidence for Converse.
  • ARN finding addressed: foundation-model and system inference-profile ARNs containing OpenAI model IDs do not bypass the filter. Opaque resource ARNs retain the compatibility fallback.
  • Regression coverage: native/v1 reasoning and tool-call preservation for other families; outgoing streaming controls for DeepSeek, Kimi, and Qwen. These assert converter compatibility, not live Bedrock acceptance. The new compatibility tests produced 18 expected failures under the broader gate before the fix.
  • Non-streaming acknowledged: explicitly remains outside this PR's scope. The existing test file names are retained.
Check on this exact head Result
Bedrock, cache, and tracing tests 24 suites; 402 passed, 4 skipped
npx tsc --noEmit Passed
Production build Passed
Touched-file ESLint with zero warnings Passed
Touched-file import order and Prettier Passed

CI state: in_progress. No external review has arrived for this head yet. CI on the prior ARN-only head 7f49cdbf206337b30ceabddb82a9f4037379e2cc passed, but does not cover this head.

Live Bedrock validation and the full local repository test suite were not run. No issue labels, issue comments, release, or dependency-bump changes were made.

@danny-avila
danny-avila merged commit b1a5be0 into LibreChat-AI:main Sep 30, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants