Skip to content

Python: fix(bedrock): keep reasoning content so extended thinking works with tool calls - #8936

Open
Leela Mahalakshmi (Leela0o5) wants to merge 1 commit into
microsoft:mainfrom
Leela0o5:fix/bedrock-reasoning-content
Open

Leela Mahalakshmi (Leela0o5) wants to merge 1 commit into
microsoft:mainfrom
Leela0o5:fix/bedrock-reasoning-content

Conversation

@Leela0o5

Copy link
Copy Markdown
Contributor

Motivation

BedrockChatClient was not handling reasoningContent properly. Because of this, reasoning was not shown, and tool calls with extended thinking could fail because the required reasoning signature was missing.

Changes

  • Convert Bedrock reasoningContent to text_reasoning.
  • Preserve the reasoning signature in protected_data.
  • Convert text_reasoning back to reasoningContent in requests.
  • Handle reasoning updates from ConverseStream.
  • Follow the approach used by the AI client.

Impact

Reasoning is now available to callers, and extended thinking with tool calls should work correctly. Non-reasoning requests are unchanged.

Testing

  • Added unit tests using stubbed Bedrock responses.
  • I have not tested with live Bedrock yet.
  • redactedContent is still not handled.

Related Issue

Fixes #8935

Checklist

  • Builds without errors or warnings
  • Unit tests pass
  • Added tests
  • No breaking changes

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@agent-framework-automation agent-framework-automation Bot added the python Usage: [Issues, PRs], Target: Python label Oct 1, 2026

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Content.from_text(text=json.dumps(json_value, ensure_ascii=False), raw_representation=block)
)
continue
if isinstance(reasoning := block.get("reasoningContent"), Mapping):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Leela Mahalakshmi (@Leela0o5) This preserves only the reasoningText arm, but Bedrock can also return reasoningContent.redactedContent for redacted thinking blocks. Those blocks must be replayed unchanged with the tool-use turn; dropping them here (and in the streaming path) can still make a tool-result continuation fail. Could this preserve and serialize redactedContent unchanged, with non-streaming and streaming coverage?

@eavanvalkenburg

Copy link
Copy Markdown
Member

/review

@github-actions github-actions Bot 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.

MAF Automated Review — Iteration 1

Result: Findings reported
Scope: full PR (1 commit(s)): 6b49c10fe5ea
Model: gpt-5.6-sol

Overview

The change maps Bedrock reasoning text and signatures into text_reasoning, preserves their order with tool calls, and replays signed reasoning only from assistant messages. The new tests cover non-streaming parsing, single-block streaming aggregation, replay shape, and role gating. Streaming still loses reasoning-block boundaries when a response contains consecutive reasoning blocks, which can pair modified text with the wrong signature during tool-result continuation.

Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
1 verified finding remained after source verification (1 medium) across 1 file. Details are attached to the affected lines below.

Affected areas: python/packages/bedrock/agent_framework_bedrock/_chat_client.py

if reasoning_text is not None or signature is not None:
contents.append(
Content.from_text_reasoning(
text=reasoning_text, protected_data=signature, raw_representation=delta

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.

Each streamed reasoning delta is emitted without its contentBlockIndex. When a response contains consecutive reasoning blocks, ChatResponse.from_updates coalesces them into one text_reasoning item and keeps only the later signature, unlike non-streaming parsing. Replaying that history therefore pairs modified text with the wrong signature and can make Bedrock reject tool-result continuation. Please assign a stable per-block ID from contentBlockIndex so deltas merge within one block while distinct blocks remain separate, and cover the two-block case.

This branch was successfully deployed

1 active deployment
github-app-auth — 6b49c10f Deployed Oct 1, 2026 by Leela0o5 via team_check #5739
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: [Bug]: BedrockChatClient drops reasoningContent, so extended thinking with tool calls fails

3 participants