Summary
InstrumentationSemConv.tagBedrockRequest() extracts inferenceConfig (maxTokens/temperature/topP/stopSequences), system, and messages from the Bedrock Converse/ConverseStream request body, but never reads the top-level toolConfig field. toolConfig carries the tool definitions and tool-choice policy sent to the model — a core, documented part of the Converse API request — and is silently dropped from every Bedrock LLM span's braintrust.metadata/braintrust.input_json, for both streaming and non-streaming calls.
This is a request-side gap and is distinct from issue #85 (which covers the response-side streaming reconstruction dropping tool-use content blocks in TeeingSubscriber/buildConverseJson). Even for non-streaming Converse calls where the response-side tool use is captured correctly by normalizeBedrockMessage(), the request never shows what tools were offered to the model or what tool-choice policy was set.
What is missing
In tagBedrockRequest() (InstrumentationSemConv.java, lines 339-396):
if (requestBody != null) {
JsonNode requestJson = BraintrustJsonMapper.get().readTree(requestBody);
if (requestJson.has("inferenceConfig")) { ... } // handled
if (requestJson.has("messages")) { ... } // handled
}
There is no if (requestJson.has("toolConfig")) branch anywhere in this method. The Converse/ConverseStream request body's toolConfig object — containing tools (an array of toolSpec definitions with name/description/inputSchema) and toolChoice (auto/any/{tool: {name}}) — is read from requestBody but never surfaced into metadata or input_json. A trace of a tool-enabled Bedrock call shows the conversation and inference params but gives no visibility into which tools were available or how tool selection was constrained, even though the model's resulting stopReason: "tool_use" and tool call are otherwise correctly displayed.
Braintrust docs status
Upstream sources
Local files inspected
braintrust-sdk/src/main/java/dev/braintrust/instrumentation/InstrumentationSemConv.java — lines 339-396 (tagBedrockRequest: reads inferenceConfig, system, messages; no toolConfig handling anywhere in the method or file)
braintrust-sdk/instrumentation/aws_bedrock_2_30_0/src/main/java/dev/braintrust/instrumentation/awsbedrock/v2_30_0/BraintrustBedrockInterceptor.java — passes the raw request body through to tagBedrockRequest; no separate toolConfig handling
braintrust-sdk/instrumentation/aws_bedrock_2_30_0/src/test/java/dev/braintrust/instrumentation/awsbedrock/v2_30_0/BraintrustAWSBedrockTest.java — no test asserts on toolConfig appearing in captured metadata
Summary
InstrumentationSemConv.tagBedrockRequest()extractsinferenceConfig(maxTokens/temperature/topP/stopSequences),system, andmessagesfrom the Bedrock Converse/ConverseStream request body, but never reads the top-leveltoolConfigfield.toolConfigcarries the tool definitions and tool-choice policy sent to the model — a core, documented part of the Converse API request — and is silently dropped from every Bedrock LLM span'sbraintrust.metadata/braintrust.input_json, for both streaming and non-streaming calls.This is a request-side gap and is distinct from issue #85 (which covers the response-side streaming reconstruction dropping tool-use content blocks in
TeeingSubscriber/buildConverseJson). Even for non-streamingConversecalls where the response-side tool use is captured correctly bynormalizeBedrockMessage(), the request never shows what tools were offered to the model or what tool-choice policy was set.What is missing
In
tagBedrockRequest()(InstrumentationSemConv.java, lines 339-396):There is no
if (requestJson.has("toolConfig"))branch anywhere in this method. The Converse/ConverseStream request body'stoolConfigobject — containingtools(an array oftoolSpecdefinitions withname/description/inputSchema) andtoolChoice(auto/any/{tool: {name}}) — is read fromrequestBodybut never surfaced intometadataorinput_json. A trace of a tool-enabled Bedrock call shows the conversation and inference params but gives no visibility into which tools were available or how tool selection was constrained, even though the model's resultingstopReason: "tool_use"and tool call are otherwise correctly displayed.Braintrust docs status
Upstream sources
toolConfigas a top-level request field alongsidemessages,system,inferenceConfigtoolConfigrequest fieldtoolConfig.tools/toolConfig.toolChoicesemanticsLocal files inspected
braintrust-sdk/src/main/java/dev/braintrust/instrumentation/InstrumentationSemConv.java— lines 339-396 (tagBedrockRequest: readsinferenceConfig,system,messages; notoolConfighandling anywhere in the method or file)braintrust-sdk/instrumentation/aws_bedrock_2_30_0/src/main/java/dev/braintrust/instrumentation/awsbedrock/v2_30_0/BraintrustBedrockInterceptor.java— passes the raw request body through totagBedrockRequest; no separate toolConfig handlingbraintrust-sdk/instrumentation/aws_bedrock_2_30_0/src/test/java/dev/braintrust/instrumentation/awsbedrock/v2_30_0/BraintrustAWSBedrockTest.java— no test asserts ontoolConfigappearing in captured metadata