[bot] Bedrock ConverseStream drops tool use and non-text content blocks in streaming spans
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 64/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 静か
- 技術スタック
- aws, java
- 領域
- cloud, observability
調査の方向性
braintrust-sdk/instrumentation/aws_bedrock_2_30_0/src/main/java/dev/braintrust/instrumentation/awsbedrock/v2_30_0/BraintrustBedrockInterceptor.java の TeeingSubscriber.onNext、parseDeltaText、buildConverseJson から着手してください。ストリーミングイベントの処理を、braintrust-sdk/src/main/java/dev/braintrust/instrumentation/InstrumentationSemConv.java の normalizeBedrockMessage() と比較し、既存の Bedrock テストを確認してください。ストリーミング中の tool-use コンテンツ、識別子、名前、入力が span 出力に表現され、BraintrustAWSBedrockTest.java でカバレッジが追加されていれば完了です。
索引モデルが issue の本文から書いたものです。
説明
Summary
The Bedrock ConverseStream instrumentation in TeeingSubscriber only accumulates delta.text from contentBlockDelta events. When the model returns tool use content blocks during streaming (a documented and supported Bedrock feature), the tool call data is silently dropped from the span output.
Non-streaming Converse calls handle tool use correctly — normalizeBedrockMessage() in InstrumentationSemConv already recognizes toolUse, toolResult, and image content block types and adds appropriate type annotations. The gap is exclusively in the streaming path.
What is missing
1. TeeingSubscriber only parses text deltas (lines 273–289)
case "contentBlockDelta" -> {
String t = parseDeltaText(payload); // only looks for delta.text
if (t != null) {
text.append(t);
// ...
}
}
parseDeltaText() (lines 322–339) searches exclusively for delta.text. Bedrock ConverseStream sends delta.toolUse for tool use blocks (containing incremental input JSON), which is silently ignored.
2. contentBlockStart events are not handled
The TeeingSubscriber switch (lines 273–289) has no case for contentBlockStart. This event carries toolUse.toolUseId and toolUse.name — metadata needed to reconstruct the tool call. Without it, even if tool use deltas were captured, the tool name and ID would be lost.
3. buildConverseJson always produces a single text block (lines 385–410)
gen.writeArrayFieldStart("content");
gen.writeStartObject();
gen.writeStringField("text", text); // always one text block
gen.writeEndObject();
gen.writeEndArray();
The synthetic response JSON always contains exactly one {"text": "..."} content block, regardless of what the model actually returned. When the model requests a tool call, the span output will show empty text instead of the tool invocation.
Impact
When a streaming Bedrock call triggers tool use (common in agentic workflows):
- The span's
output_jsoncontains[{"role":"assistant","content":[{"text":"","type":"text"}]}]— as if the model returned nothing - The
stopReasonis captured as"tool_use", contradicting the empty output - Tool call names, IDs, and argument JSON are permanently lost from the trace
- Non-streaming
Conversecalls with tool use are correctly captured
Braintrust docs status
- Bedrock is listed as a supported cloud provider at https://www.braintrust.dev/docs/integrations/ai-providers: supported
- Tool calling in Bedrock streaming is not specifically documented on Braintrust docs: not_found
Upstream sources
- Bedrock ConverseStream API reference: https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_ConverseStream.html — documents
toolConfigparameter and streaming tool use events (contentBlockStartwithtoolUse,contentBlockDeltawithtoolUseinput) - Bedrock tool use examples: https://docs.aws.amazon.com/bedrock/latest/userguide/tool-use-examples.html — shows ConverseStream with tool use
- Bedrock streaming event sequence: Events include
contentBlockStart(carriesstart.toolUsewithtoolUseIdandname),contentBlockDelta(carriesdelta.toolUsewithinputJSON fragments), andcontentBlockStop
Local files inspected
braintrust-sdk/instrumentation/aws_bedrock_2_30_0/src/main/java/dev/braintrust/instrumentation/awsbedrock/v2_30_0/BraintrustBedrockInterceptor.java— lines 273–289 (TeeingSubscriber.onNext: onlycontentBlockDelta→text,messageStop,metadatahandled; nocontentBlockStart), lines 322–339 (parseDeltaText: onlydelta.text), lines 385–410 (buildConverseJson: hardcoded single text block)braintrust-sdk/src/main/java/dev/braintrust/instrumentation/InstrumentationSemConv.java— lines 400–434 (normalizeBedrockMessage: non-streaming path correctly handlestoolUse,toolResult,imagecontent block types)braintrust-sdk/instrumentation/aws_bedrock_2_30_0/src/test/java/dev/braintrust/instrumentation/awsbedrock/v2_30_0/BraintrustAWSBedrockTest.java— no streaming test exercises tool use responses
- 主要言語
- Java
- スター
- 21
- フォーク
- 5
- 平均マージ
- 2日 7時間
- マージ済み PR(30日)
- 8
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
braintrustdata/braintrust-sdk-java のほかの issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
braintrustdata/braintrust-sdk-java の issue をすべて見る
似ている issue
-
documentation
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
inu-appcenter/memorIN-backend#288 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
-
frontend maui-pilot pilot-ask question
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
-
area/plugin
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
kestra-io/plugin-kestra#190 ·