Skip to content

Commit daaa975

Browse files
authored
Merge pull request #169 from hamedrabah/fix/openai-audio-transcription-output
Preserve OpenAI audio transcription output
2 parents fa8a906 + 14b5955 commit daaa975

2 files changed

Lines changed: 43 additions & 6 deletions

File tree

braintrust-sdk/src/main/java/dev/braintrust/instrumentation/InstrumentationSemConv.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,11 +199,14 @@ private static void tagOpenAIRequest(
199199
@SneakyThrows
200200
private static void tagOpenAIResponse(
201201
Span span, JsonNode responseJson, @Nullable Long timeToFirstTokenNanoseconds) {
202-
// Output — chat completions API uses "choices"; Responses API uses "output"
202+
// Output — chat completions API uses "choices"; Responses API uses "output"; audio
203+
// transcriptions and translations return a text-keyed object.
203204
if (responseJson.has("choices")) {
204205
span.setAttribute("braintrust.output_json", toJson(responseJson.get("choices")));
205206
} else if (responseJson.has("output")) {
206207
span.setAttribute("braintrust.output_json", toJson(responseJson.get("output")));
208+
} else if (responseJson.has("text")) {
209+
span.setAttribute("braintrust.output_json", toJson(responseJson));
207210
}
208211

209212
Map<String, Object> metrics = new HashMap<>();

braintrust-sdk/src/test/java/dev/braintrust/instrumentation/InstrumentationSemConvTest.java

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,7 @@
2020
import org.junit.jupiter.api.BeforeEach;
2121
import org.junit.jupiter.api.Test;
2222

23-
/**
24-
* Covers {@link InstrumentationSemConv#addServerSideChildSpans}: only vendor-executed (server-side)
25-
* tool calls in an OpenAI Responses body become child spans nested under the LLM span. Client-side
26-
* calls ({@code function_call}, {@code computer_call}) are excluded.
27-
*/
23+
/** Covers provider response tagging and {@link InstrumentationSemConv#addServerSideChildSpans}. */
2824
class InstrumentationSemConvTest {
2925

3026
private static final AttributeKey<String> SPAN_ATTRIBUTES =
@@ -81,6 +77,44 @@ private static JsonNode json(String s) {
8177
return BraintrustJsonMapper.fromJson(s, JsonNode.class);
8278
}
8379

80+
private SpanData tagOpenAIResponse(String responseBody) {
81+
Span span = tracer.spanBuilder("llm").startSpan();
82+
try {
83+
InstrumentationSemConv.tagLLMSpanResponse(
84+
tracer, span, InstrumentationSemConv.PROVIDER_NAME_OPENAI, responseBody);
85+
} finally {
86+
span.end();
87+
}
88+
return byName(exporter.getFinishedSpanItems(), "llm");
89+
}
90+
91+
@Test
92+
void tagsOpenAIAudioTranscriptionOutput() {
93+
SpanData span = tagOpenAIResponse("{\"text\":\"Hello from the recording.\"}");
94+
95+
assertEquals(
96+
json("{\"text\":\"Hello from the recording.\"}"),
97+
json(span.getAttributes().get(OUTPUT_JSON)));
98+
}
99+
100+
@Test
101+
void tagsOpenAIVerboseAudioTranscriptionOutput() {
102+
String body =
103+
"""
104+
{
105+
"text": "Hello from the recording.",
106+
"language": "english",
107+
"duration": 1.25,
108+
"segments": [{"id": 0, "text": "Hello from the recording."}],
109+
"words": [{"word": "Hello", "start": 0.0, "end": 0.4}]
110+
}
111+
""";
112+
113+
SpanData span = tagOpenAIResponse(body);
114+
115+
assertEquals(json(body), json(span.getAttributes().get(OUTPUT_JSON)));
116+
}
117+
84118
@Test
85119
void emitsWebSearchCallToolSpanParentedToLlm() {
86120
String body =

0 commit comments

Comments
 (0)