Summary
@anthropic-ai/claude-agent-sdk appears to have regressed after 0.3.150: successful tool-use turns can emit a completed assistant thinking block whose thinking text is empty, while the raw stream only contains a signature_delta and no thinking_delta text.
This reproduces with AWS Bedrock and Claude Code runtimes packaged by the Agent SDK. It affects SDK consumers that render or persist partial assistant events/transcripts because the SDK output contains a signed, completed thinking block with no displayable content.
Expected behavior
For a successful turn with no displayable thinking text, one of these contracts should hold:
- No assistant
thinking block is emitted at all, or
- A non-displayable/redacted metadata block is emitted in a way consumers can distinguish from visible thinking, or
- The SDK documentation explicitly states that signature-only
thinking blocks with thinking: "" are valid and must be suppressed by renderers/transcript consumers.
If thinking: { type: "adaptive", display: "summarized" } is requested and a summarized thinking block is emitted, I would expect non-empty thinking_delta text or no visible thinking block.
Actual behavior
In 0.3.152+, successful tool-use turns can produce this raw-event shape:
{"type":"content_block_start","index":0,"content_block":{"type":"thinking","thinking":"","signature":""}}
{"type":"content_block_delta","index":0,"delta":{"type":"signature_delta","signature":"..."}}
{"type":"content_block_stop","index":0}
The completed assistant message then contains:
{"type":"thinking","thinking":"","signature":"..."}
There are zero thinking_delta events and zero displayable thinking characters.
Environment
- SDK package:
@anthropic-ai/claude-agent-sdk
- Provider: AWS Bedrock
- Region:
us-east-1
- Models tested:
us.anthropic.claude-opus-4-7[1m]
us.anthropic.claude-opus-4-8[1m]
- Node:
v22.22.3
- npm:
10.9.8
- Local OS used for repro: macOS arm64
- Repro options:
thinking: { type: "adaptive", display: "summarized" }
includePartialMessages: true
permissionMode: "bypassPermissions"
allowedTools: ["Bash"]
Reproduction script shape
This is the probe shape used for the matrices below. The important part is counting raw SDKPartialAssistantMessage.event records before any application-level rendering or transcript processing.
import { query } from "@anthropic-ai/claude-agent-sdk";
const prompt = "Use the Bash tool exactly once to run `printf eval-alpha`, then reply with only DONE.";
const stats = {
rawThinkingStarts: 0,
rawThinkingDeltaEvents: 0,
rawThinkingDeltaChars: 0,
rawSignatureDeltas: 0,
finalThinkingBlocks: 0,
emptyFinalThinkingBlocks: 0,
finalThinkingChars: 0,
reportedModels: [],
resultSubtype: null,
};
for await (const msg of query({
prompt,
options: {
model: "us.anthropic.claude-opus-4-7[1m]",
thinking: { type: "adaptive", display: "summarized" },
includePartialMessages: true,
maxTurns: 3,
allowedTools: ["Bash"],
permissionMode: "bypassPermissions",
allowDangerouslySkipPermissions: true,
},
})) {
if (msg.type === "stream_event") {
const event = msg.event;
if (event?.type === "content_block_start" && event.content_block?.type === "thinking") {
stats.rawThinkingStarts += 1;
}
if (event?.type === "content_block_delta") {
const delta = event.delta;
if (delta?.type === "thinking_delta") {
stats.rawThinkingDeltaEvents += 1;
stats.rawThinkingDeltaChars += typeof delta.thinking === "string" ? delta.thinking.length : 0;
}
if (delta?.type === "signature_delta") stats.rawSignatureDeltas += 1;
}
if (event?.message?.model && !stats.reportedModels.includes(event.message.model)) {
stats.reportedModels.push(event.message.model);
}
}
if (msg.type === "assistant") {
for (const block of msg.message?.content ?? []) {
if (block?.type === "thinking") {
stats.finalThinkingBlocks += 1;
const text = typeof block.thinking === "string" ? block.thinking : "";
stats.finalThinkingChars += text.length;
if (!text.trim()) stats.emptyFinalThinkingBlocks += 1;
}
}
}
if (msg.type === "result") stats.resultSubtype = msg.subtype;
}
console.log(stats);
Formal proof 1: this is a runtime-version regression
Definitions:
- A displayable thinking block exists iff either raw stream output contains at least one
thinking_delta with non-empty delta.thinking, or the completed assistant message contains a thinking block whose thinking.trim().length > 0.
- A signature-only empty thinking block exists iff the raw stream emits a
thinking block start and a signature_delta, but emits zero thinking_delta characters, and the completed assistant message contains thinking: "".
- The application consumer cannot display text that is absent from
SDKPartialAssistantMessage.event and absent from the completed assistant message.
Observed with the same prompt, provider, model family, and SDK options:
| SDK / Claude Code |
Requested model |
Result |
Raw thinking_delta chars |
Empty final thinking blocks |
Conclusion |
0.3.150 / 2.1.150 |
us.anthropic.claude-opus-4-7[1m] |
success |
96 |
0 |
Displayable thinking exists. |
0.3.152 / 2.1.152 |
us.anthropic.claude-opus-4-7[1m] |
success |
0 |
1 |
Signature-only empty thinking block. |
0.3.153 / 2.1.153 |
us.anthropic.claude-opus-4-7[1m] |
success |
0 |
1 |
Signature-only empty thinking block. |
0.3.156 / 2.1.156 |
us.anthropic.claude-opus-4-7[1m] |
success |
0 |
1 |
Signature-only empty thinking block. |
0.3.157 / 2.1.157 |
us.anthropic.claude-opus-4-7[1m] |
success |
0 |
1 |
Signature-only empty thinking block. |
Therefore, between 0.3.150 and 0.3.152, successful tool-use turns started producing signed empty thinking blocks instead of displayable summarized thinking for the same observable SDK contract.
Note: 0.3.151 is not published in the npm registry, so the first published post-0.3.150 candidate I could test was 0.3.152.
Formal proof 2: the issue follows runtime version, not AWS credentials/account
I also crossed two AWS Bedrock credential sets with old/new SDK runtimes using the same five safe Bash tool-use prompts: echo_alpha, math_node, pwd_check, two_commands, list_count.
Each run used:
us.anthropic.claude-opus-4-7[1m]
thinking: { type: "adaptive", display: "summarized" }
includePartialMessages: true
permissionMode: "bypassPermissions"
| Runtime |
Credential set |
Successes |
Thinking blocks |
Empty thinking blocks |
Non-empty thinking chars |
Signature-only thinking deltas |
0.3.153 / 2.1.153 |
A |
5/5 |
5 |
5 |
0 |
5 |
0.3.150 / 2.1.150 |
B |
5/5 |
4 |
0 |
846 |
4 |
0.3.150 / 2.1.150 |
A |
5/5 |
5 |
0 |
2,362 |
5 |
0.3.153 / 2.1.153 |
B |
5/5 |
5 |
5 |
0 |
5 |
Since 0.3.150 produced non-empty thinking on both credential sets, and 0.3.153 produced empty thinking on both credential sets, the observed behavior follows SDK/Claude Code runtime version rather than the AWS credential set.
Formal proof 3: Opus 4.8 does not eliminate the issue on newer runtimes
I tested us.anthropic.claude-opus-4-8[1m], which the stream reported as claude-opus-4-8.
| SDK / Claude Code |
Requested model |
Result |
Raw thinking_delta chars |
Empty final thinking blocks |
Notes |
0.3.150 / 2.1.150 |
us.anthropic.claude-opus-4-8[1m] |
5/5 successes |
67 |
0 |
Can call 4.8; when thinking was emitted, it was non-empty. |
0.3.154 / 2.1.154 |
us.anthropic.claude-opus-4-8[1m] |
5/5 successes |
0 |
5 |
Latest produced empty thinking blocks. |
0.3.156 / 2.1.156 |
us.anthropic.claude-opus-4-8[1m] |
success |
0 |
1 |
next still reproduced the issue. |
0.3.157 / 2.1.157 |
us.anthropic.claude-opus-4-8[1m] |
success |
0 |
1 |
May 29 latest/next still reproduced the issue in a local Bedrock raw-stream probe. |
A single-prompt variant sweep on 0.3.154 + 4.8[1m] also reproduced the empty signature-only shape for:
thinking: { type: "adaptive" }
thinking: { type: "adaptive", display: "summarized" }
thinking: { type: "adaptive", display: "omitted" }
thinking: { type: "enabled", budgetTokens: 1024, display: "summarized" }
thinking: { type: "disabled" } produced no thinking block, as expected.
Five-prompt repeat on May 29, 2026 with us.anthropic.claude-opus-4-8[1m]:
| Provider |
SDK / Claude Code |
Successes |
Thinking blocks |
Empty thinking blocks |
Raw thinking_delta chars |
Raw signature deltas |
| AWS Bedrock |
0.3.156 / 2.1.156 |
5/5 |
5 |
5 |
0 |
5 |
| AWS Bedrock |
0.3.157 / 2.1.157 |
5/5 |
5 |
5 |
0 |
5 |
Formal proof 4: the data is absent at the SDK raw-event boundary
The SDK type for partial streaming messages is:
type SDKPartialAssistantMessage = {
type: "stream_event";
event: BetaRawMessageStreamEvent;
// ...
};
For affected runs, SDKPartialAssistantMessage.event contains a thinking block start and a signature_delta, but no thinking_delta text. The final assistant message also contains a thinking block with thinking: "".
Therefore the missing displayable text is already absent at the earliest SDK event boundary available to consumers. A renderer/transcript consumer downstream of the SDK cannot recover the thinking text.
This does not prove whether the native Claude Code binary is faithfully forwarding a provider response or applying an internal transform before surfacing SDK events. It does prove that SDK consumers receive a signed empty visible-thinking block in successful turns.
Formal proof 5: direct Anthropic provider did not reproduce the issue
I also tested the same raw SDK event boundary with Bedrock disabled and the direct Anthropic provider. This used local Claude Code auth rather than ANTHROPIC_API_KEY in the shell environment.
Single-prompt matrix, same safe Bash tool-use prompt and thinking: { type: "adaptive", display: "summarized" }:
| Provider |
SDK / Claude Code |
Requested model |
Result |
Raw thinking_delta chars |
Empty final thinking blocks |
| Direct Anthropic |
0.3.150 / 2.1.150 |
claude-opus-4-7 |
success |
103 |
0 |
| Direct Anthropic |
0.3.150 / 2.1.150 |
claude-opus-4-8 |
success |
100 |
0 |
| Direct Anthropic |
0.3.152 / 2.1.152 |
claude-opus-4-7 |
success |
103 |
0 |
| Direct Anthropic |
0.3.152 / 2.1.152 |
claude-opus-4-8 |
success |
100 |
0 |
| Direct Anthropic |
0.3.153 / 2.1.153 |
claude-opus-4-7 |
success |
156 |
0 |
| Direct Anthropic |
0.3.153 / 2.1.153 |
claude-opus-4-8 |
success |
100 |
0 |
| Direct Anthropic |
0.3.154 / 2.1.154 |
claude-opus-4-7 |
success |
108 |
0 |
| Direct Anthropic |
0.3.154 / 2.1.154 |
claude-opus-4-8 |
success |
100 |
0 |
| Direct Anthropic |
0.3.156 / 2.1.156 |
claude-opus-4-7 |
success |
172 |
0 |
| Direct Anthropic |
0.3.156 / 2.1.156 |
claude-opus-4-8 |
success |
100 |
0 |
| Direct Anthropic |
0.3.157 / 2.1.157 |
claude-opus-4-7 |
success |
108 |
0 |
| Direct Anthropic |
0.3.157 / 2.1.157 |
claude-opus-4-8 |
success |
108 |
0 |
Five-prompt direct-provider controls against the Bedrock failure cases:
| Provider |
SDK / Claude Code |
Requested model |
Successes |
Thinking blocks |
Empty thinking blocks |
Raw thinking_delta chars |
Raw signature deltas |
| Direct Anthropic |
0.3.153 / 2.1.153 |
claude-opus-4-7 |
5/5 |
5 |
0 |
512 |
5 |
| Direct Anthropic |
0.3.154 / 2.1.154 |
claude-opus-4-8 |
5/5 |
5 |
0 |
546 |
5 |
| Direct Anthropic |
0.3.156 / 2.1.156 |
claude-opus-4-8 |
5/5 |
5 |
0 |
618 |
5 |
| Direct Anthropic |
0.3.157 / 2.1.157 |
claude-opus-4-8 |
5/5 |
5 |
0 |
530 |
5 |
Conclusion: the empty signature-only thinking issue did not reproduce on the direct Anthropic provider in this matrix. The currently observed failure appears specific to the Bedrock provider path in Claude Code/Agent SDK 0.3.152+, including 0.3.156 and 0.3.157 in local raw-stream probes; the same SDK versions and prompts produced non-empty thinking on direct Anthropic.
Impact
SDK consumers that render or persist assistant thinking blocks need to special-case signed empty thinking blocks. Without that special case, UIs can show completed empty reasoning sections and transcripts can contain completed assistant thinking blocks with no displayable content.
Request
Can you clarify whether signature-only thinking blocks with thinking: "" are intentional SDK output?
If intentional, please document the contract and recommended consumer behavior. If unintentional, please either restore non-empty summarized thinking output for display: "summarized" or suppress visible thinking blocks when no thinking_delta text is available.
Summary
@anthropic-ai/claude-agent-sdkappears to have regressed after0.3.150: successful tool-use turns can emit a completed assistantthinkingblock whosethinkingtext is empty, while the raw stream only contains asignature_deltaand nothinking_deltatext.This reproduces with AWS Bedrock and Claude Code runtimes packaged by the Agent SDK. It affects SDK consumers that render or persist partial assistant events/transcripts because the SDK output contains a signed, completed
thinkingblock with no displayable content.Expected behavior
For a successful turn with no displayable thinking text, one of these contracts should hold:
thinkingblock is emitted at all, orthinkingblocks withthinking: ""are valid and must be suppressed by renderers/transcript consumers.If
thinking: { type: "adaptive", display: "summarized" }is requested and a summarized thinking block is emitted, I would expect non-emptythinking_deltatext or no visible thinking block.Actual behavior
In
0.3.152+, successful tool-use turns can produce this raw-event shape:{"type":"content_block_start","index":0,"content_block":{"type":"thinking","thinking":"","signature":""}} {"type":"content_block_delta","index":0,"delta":{"type":"signature_delta","signature":"..."}} {"type":"content_block_stop","index":0}The completed assistant message then contains:
{"type":"thinking","thinking":"","signature":"..."}There are zero
thinking_deltaevents and zero displayable thinking characters.Environment
@anthropic-ai/claude-agent-sdkus-east-1us.anthropic.claude-opus-4-7[1m]us.anthropic.claude-opus-4-8[1m]v22.22.310.9.8thinking: { type: "adaptive", display: "summarized" }includePartialMessages: truepermissionMode: "bypassPermissions"allowedTools: ["Bash"]Reproduction script shape
This is the probe shape used for the matrices below. The important part is counting raw
SDKPartialAssistantMessage.eventrecords before any application-level rendering or transcript processing.Formal proof 1: this is a runtime-version regression
Definitions:
thinking_deltawith non-emptydelta.thinking, or the completed assistant message contains athinkingblock whosethinking.trim().length > 0.thinkingblock start and asignature_delta, but emits zerothinking_deltacharacters, and the completed assistant message containsthinking: "".SDKPartialAssistantMessage.eventand absent from the completed assistant message.Observed with the same prompt, provider, model family, and SDK options:
0.3.150/2.1.150us.anthropic.claude-opus-4-7[1m]0.3.152/2.1.152us.anthropic.claude-opus-4-7[1m]0.3.153/2.1.153us.anthropic.claude-opus-4-7[1m]0.3.156/2.1.156us.anthropic.claude-opus-4-7[1m]0.3.157/2.1.157us.anthropic.claude-opus-4-7[1m]Therefore, between
0.3.150and0.3.152, successful tool-use turns started producing signed emptythinkingblocks instead of displayable summarized thinking for the same observable SDK contract.Note:
0.3.151is not published in the npm registry, so the first published post-0.3.150candidate I could test was0.3.152.Formal proof 2: the issue follows runtime version, not AWS credentials/account
I also crossed two AWS Bedrock credential sets with old/new SDK runtimes using the same five safe Bash tool-use prompts:
echo_alpha,math_node,pwd_check,two_commands,list_count.Each run used:
us.anthropic.claude-opus-4-7[1m]thinking: { type: "adaptive", display: "summarized" }includePartialMessages: truepermissionMode: "bypassPermissions"0.3.153/2.1.1530.3.150/2.1.1500.3.150/2.1.1500.3.153/2.1.153Since
0.3.150produced non-empty thinking on both credential sets, and0.3.153produced empty thinking on both credential sets, the observed behavior follows SDK/Claude Code runtime version rather than the AWS credential set.Formal proof 3: Opus 4.8 does not eliminate the issue on newer runtimes
I tested
us.anthropic.claude-opus-4-8[1m], which the stream reported asclaude-opus-4-8.0.3.150/2.1.150us.anthropic.claude-opus-4-8[1m]0.3.154/2.1.154us.anthropic.claude-opus-4-8[1m]0.3.156/2.1.156us.anthropic.claude-opus-4-8[1m]nextstill reproduced the issue.0.3.157/2.1.157us.anthropic.claude-opus-4-8[1m]latest/nextstill reproduced the issue in a local Bedrock raw-stream probe.A single-prompt variant sweep on
0.3.154+4.8[1m]also reproduced the empty signature-only shape for:thinking: { type: "adaptive" }thinking: { type: "adaptive", display: "summarized" }thinking: { type: "adaptive", display: "omitted" }thinking: { type: "enabled", budgetTokens: 1024, display: "summarized" }thinking: { type: "disabled" }produced no thinking block, as expected.Five-prompt repeat on May 29, 2026 with
us.anthropic.claude-opus-4-8[1m]:0.3.156/2.1.1560.3.157/2.1.157Formal proof 4: the data is absent at the SDK raw-event boundary
The SDK type for partial streaming messages is:
For affected runs,
SDKPartialAssistantMessage.eventcontains athinkingblock start and asignature_delta, but nothinking_deltatext. The final assistant message also contains athinkingblock withthinking: "".Therefore the missing displayable text is already absent at the earliest SDK event boundary available to consumers. A renderer/transcript consumer downstream of the SDK cannot recover the thinking text.
This does not prove whether the native Claude Code binary is faithfully forwarding a provider response or applying an internal transform before surfacing SDK events. It does prove that SDK consumers receive a signed empty visible-thinking block in successful turns.
Formal proof 5: direct Anthropic provider did not reproduce the issue
I also tested the same raw SDK event boundary with Bedrock disabled and the direct Anthropic provider. This used local Claude Code auth rather than
ANTHROPIC_API_KEYin the shell environment.Single-prompt matrix, same safe Bash tool-use prompt and
thinking: { type: "adaptive", display: "summarized" }:0.3.150/2.1.150claude-opus-4-70.3.150/2.1.150claude-opus-4-80.3.152/2.1.152claude-opus-4-70.3.152/2.1.152claude-opus-4-80.3.153/2.1.153claude-opus-4-70.3.153/2.1.153claude-opus-4-80.3.154/2.1.154claude-opus-4-70.3.154/2.1.154claude-opus-4-80.3.156/2.1.156claude-opus-4-70.3.156/2.1.156claude-opus-4-80.3.157/2.1.157claude-opus-4-70.3.157/2.1.157claude-opus-4-8Five-prompt direct-provider controls against the Bedrock failure cases:
0.3.153/2.1.153claude-opus-4-70.3.154/2.1.154claude-opus-4-80.3.156/2.1.156claude-opus-4-80.3.157/2.1.157claude-opus-4-8Conclusion: the empty signature-only thinking issue did not reproduce on the direct Anthropic provider in this matrix. The currently observed failure appears specific to the Bedrock provider path in Claude Code/Agent SDK
0.3.152+, including0.3.156and0.3.157in local raw-stream probes; the same SDK versions and prompts produced non-empty thinking on direct Anthropic.Impact
SDK consumers that render or persist assistant thinking blocks need to special-case signed empty thinking blocks. Without that special case, UIs can show completed empty reasoning sections and transcripts can contain completed assistant
thinkingblocks with no displayable content.Request
Can you clarify whether signature-only
thinkingblocks withthinking: ""are intentional SDK output?If intentional, please document the contract and recommended consumer behavior. If unintentional, please either restore non-empty summarized thinking output for
display: "summarized"or suppress visiblethinkingblocks when nothinking_deltatext is available.