diff --git a/braintrust-sdk/instrumentation/openai_2_8_0/build.gradle b/braintrust-sdk/instrumentation/openai_2_15_0/build.gradle similarity index 90% rename from braintrust-sdk/instrumentation/openai_2_8_0/build.gradle rename to braintrust-sdk/instrumentation/openai_2_15_0/build.gradle index 2f01b033..bab2df6f 100644 --- a/braintrust-sdk/instrumentation/openai_2_8_0/build.gradle +++ b/braintrust-sdk/instrumentation/openai_2_15_0/build.gradle @@ -2,7 +2,7 @@ muzzle { pass { group = 'com.openai' module = 'openai-java' - versions = '[2.8.0,)' + versions = '[2.15.0,)' } } @@ -17,7 +17,7 @@ dependencies { compileOnly 'net.bytebuddy:byte-buddy:1.17.5' // Target library — compileOnly because it will be on the app classpath at runtime - compileOnly 'com.openai:openai-java:2.8.0' + compileOnly 'com.openai:openai-java:2.15.0' // Test dependencies testImplementation(testFixtures(project(":test-harness"))) @@ -26,7 +26,7 @@ dependencies { testRuntimeOnly 'org.junit.platform:junit-platform-launcher' testImplementation 'net.bytebuddy:byte-buddy-agent:1.17.5' testRuntimeOnly "org.slf4j:slf4j-simple:${slf4jVersion}" - testImplementation 'com.openai:openai-java:2.8.0' + testImplementation 'com.openai:openai-java:2.15.0' } test { diff --git a/braintrust-sdk/instrumentation/openai_2_8_0/src/main/java/dev/braintrust/instrumentation/openai/BraintrustOpenAI.java b/braintrust-sdk/instrumentation/openai_2_15_0/src/main/java/dev/braintrust/instrumentation/openai/BraintrustOpenAI.java similarity index 81% rename from braintrust-sdk/instrumentation/openai_2_8_0/src/main/java/dev/braintrust/instrumentation/openai/BraintrustOpenAI.java rename to braintrust-sdk/instrumentation/openai_2_15_0/src/main/java/dev/braintrust/instrumentation/openai/BraintrustOpenAI.java index 92d1677a..2fc0d4eb 100644 --- a/braintrust-sdk/instrumentation/openai_2_8_0/src/main/java/dev/braintrust/instrumentation/openai/BraintrustOpenAI.java +++ b/braintrust-sdk/instrumentation/openai_2_15_0/src/main/java/dev/braintrust/instrumentation/openai/BraintrustOpenAI.java @@ -9,13 +9,13 @@ public class BraintrustOpenAI { /** Instrument openai client with braintrust traces */ public static OpenAIClient wrapOpenAI(OpenTelemetry openTelemetry, OpenAIClient openAIClient) { - return dev.braintrust.instrumentation.openai.v2_8_0.BraintrustOpenAI.wrapOpenAI( + return dev.braintrust.instrumentation.openai.v2_15_0.BraintrustOpenAI.wrapOpenAI( openTelemetry, openAIClient); } public static ChatCompletionCreateParams buildChatCompletionsPrompt( BraintrustPrompt prompt, Map parameters) { - return dev.braintrust.instrumentation.openai.v2_8_0.BraintrustOpenAI + return dev.braintrust.instrumentation.openai.v2_15_0.BraintrustOpenAI .buildChatCompletionsPrompt(prompt, parameters); } } diff --git a/braintrust-sdk/instrumentation/openai_2_8_0/src/main/java/dev/braintrust/instrumentation/openai/v2_8_0/BraintrustOpenAI.java b/braintrust-sdk/instrumentation/openai_2_15_0/src/main/java/dev/braintrust/instrumentation/openai/v2_15_0/BraintrustOpenAI.java similarity index 99% rename from braintrust-sdk/instrumentation/openai_2_8_0/src/main/java/dev/braintrust/instrumentation/openai/v2_8_0/BraintrustOpenAI.java rename to braintrust-sdk/instrumentation/openai_2_15_0/src/main/java/dev/braintrust/instrumentation/openai/v2_15_0/BraintrustOpenAI.java index c8b95f65..bcba2caa 100644 --- a/braintrust-sdk/instrumentation/openai_2_8_0/src/main/java/dev/braintrust/instrumentation/openai/v2_8_0/BraintrustOpenAI.java +++ b/braintrust-sdk/instrumentation/openai_2_15_0/src/main/java/dev/braintrust/instrumentation/openai/v2_15_0/BraintrustOpenAI.java @@ -1,4 +1,4 @@ -package dev.braintrust.instrumentation.openai.v2_8_0; +package dev.braintrust.instrumentation.openai.v2_15_0; import com.openai.client.OpenAIClient; import com.openai.core.ClientOptions; diff --git a/braintrust-sdk/instrumentation/openai_2_8_0/src/main/java/dev/braintrust/instrumentation/openai/v2_8_0/TracingHttpClient.java b/braintrust-sdk/instrumentation/openai_2_15_0/src/main/java/dev/braintrust/instrumentation/openai/v2_15_0/TracingHttpClient.java similarity index 79% rename from braintrust-sdk/instrumentation/openai_2_8_0/src/main/java/dev/braintrust/instrumentation/openai/v2_8_0/TracingHttpClient.java rename to braintrust-sdk/instrumentation/openai_2_15_0/src/main/java/dev/braintrust/instrumentation/openai/v2_15_0/TracingHttpClient.java index 8c456f0d..ea4d0ded 100644 --- a/braintrust-sdk/instrumentation/openai_2_8_0/src/main/java/dev/braintrust/instrumentation/openai/v2_8_0/TracingHttpClient.java +++ b/braintrust-sdk/instrumentation/openai_2_15_0/src/main/java/dev/braintrust/instrumentation/openai/v2_15_0/TracingHttpClient.java @@ -1,12 +1,13 @@ -package dev.braintrust.instrumentation.openai.v2_8_0; +package dev.braintrust.instrumentation.openai.v2_15_0; +import com.fasterxml.jackson.databind.json.JsonMapper; +import com.openai.core.ObjectMappers; import com.openai.core.RequestOptions; -import com.openai.core.http.HttpClient; -import com.openai.core.http.HttpRequest; -import com.openai.core.http.HttpRequestBody; -import com.openai.core.http.HttpResponse; +import com.openai.core.http.*; import com.openai.helpers.ChatCompletionAccumulator; +import com.openai.helpers.ResponseAccumulator; import com.openai.models.chat.completions.ChatCompletionChunk; +import com.openai.models.responses.ResponseStreamEvent; import dev.braintrust.bootstrap.BraintrustBridge; import dev.braintrust.instrumentation.InstrumentationSemConv; import dev.braintrust.json.BraintrustJsonMapper; @@ -23,6 +24,7 @@ @Slf4j class TracingHttpClient implements HttpClient { + private static final JsonMapper JSON_MAPPER = ObjectMappers.jsonMapper(); private final Tracer tracer; private final HttpClient underlying; @@ -173,7 +175,8 @@ private static void tagSpanFromBuffer(Span span, byte[] bytes, Long timeToFirstT if (bytes.length == 0) return; try { String firstLine = firstNonEmptyLine(bytes); - if (firstLine != null && firstLine.startsWith("data:")) { + if (firstLine != null + && (firstLine.startsWith("data:") || firstLine.startsWith("event:"))) { tagSpanFromSseBytes(span, bytes, timeToFirstTokenNanos); } else { InstrumentationSemConv.tagLLMSpanResponse( @@ -205,26 +208,60 @@ private static String firstNonEmptyLine(byte[] bytes) { private static void tagSpanFromSseBytes( Span span, byte[] sseBytes, Long timeToFirstTokenNanos) { try { - var accumulator = ChatCompletionAccumulator.create(); var reader = new BufferedReader( new InputStreamReader( new ByteArrayInputStream(sseBytes), StandardCharsets.UTF_8)); String line; + String responseJson = null; while ((line = reader.readLine()) != null) { if (!line.startsWith("data:")) continue; - String data = line.substring("data:".length()).strip(); - if (data.isEmpty() || data.equals("[DONE]")) continue; - ChatCompletionChunk chunk = - BraintrustJsonMapper.get().readValue(data, ChatCompletionChunk.class); - accumulator.accumulate(chunk); + var firstEventJson = line.substring("data:".length()).strip(); + // after the first data chunk is found, read the rest of the stream with the proper + // accumulator type + var jsonTree = JSON_MAPPER.readTree(firstEventJson); + if (jsonTree.has("type") && jsonTree.get("type").asText().startsWith("response")) { + // response API SSEvents + ResponseAccumulator accumulator = ResponseAccumulator.create(); + accumulator.accumulate( + JSON_MAPPER.readValue(firstEventJson, ResponseStreamEvent.class)); + while ((line = reader.readLine()) != null) { + if (!line.startsWith("data:")) continue; + String data = line.substring("data:".length()).strip(); + if (data.isEmpty() || data.equals("[DONE]")) continue; + ResponseStreamEvent rse = + JSON_MAPPER.readValue(data, ResponseStreamEvent.class); + accumulator.accumulate(rse); + } + responseJson = JSON_MAPPER.writeValueAsString(accumulator.response()); + } else if (jsonTree.has("object") + && jsonTree.get("object").asText().equals("chat.completion.chunk")) { + // completions API SSEvents + var accumulator = ChatCompletionAccumulator.create(); + accumulator.accumulate( + JSON_MAPPER.readValue(firstEventJson, ChatCompletionChunk.class)); + while ((line = reader.readLine()) != null) { + if (!line.startsWith("data:")) continue; + String data = line.substring("data:".length()).strip(); + if (data.isEmpty() || data.equals("[DONE]")) continue; + ChatCompletionChunk chunk = + BraintrustJsonMapper.get() + .readValue(data, ChatCompletionChunk.class); + accumulator.accumulate(chunk); + } + responseJson = JSON_MAPPER.writeValueAsString(accumulator.chatCompletion()); + } else { + log.warn("unknown SSE object {}", firstEventJson); + } + break; + } + if (null != responseJson) { + InstrumentationSemConv.tagLLMSpanResponse( + span, + InstrumentationSemConv.PROVIDER_NAME_OPENAI, + responseJson, + timeToFirstTokenNanos); } - var chatCompletion = accumulator.chatCompletion(); - InstrumentationSemConv.tagLLMSpanResponse( - span, - InstrumentationSemConv.PROVIDER_NAME_OPENAI, - BraintrustJsonMapper.toJson(chatCompletion), - timeToFirstTokenNanos); } catch (Exception e) { log.error("Could not parse SSE buffer to tag streaming span output", e); } @@ -233,8 +270,7 @@ private static void tagSpanFromSseBytes( /** * {@link HttpResponse} wrapper for streaming (SSE) responses. Its {@link #body()} returns a tee * {@link InputStream} that copies every byte the caller reads into an in-memory buffer. When - * the stream is fully consumed and {@link #close()} is called, the accumulated bytes are - * available via {@link #collectedBytes()} for span tagging. + * the stream is fully consumed and {@link #close()} is called. */ private static final class TeeingStreamHttpResponse implements HttpResponse { private final HttpResponse delegate; @@ -271,17 +307,13 @@ private void onStreamClosed() { } } - byte[] collectedBytes() { - return teeBuffer.toByteArray(); - } - @Override public int statusCode() { return delegate.statusCode(); } @Override - public com.openai.core.http.Headers headers() { + public Headers headers() { return delegate.headers(); } @@ -295,7 +327,7 @@ public void close() { try { teeStream.close(); // triggers onStreamClosed if not already fired (e.g. abandoned // stream) - } catch (java.io.IOException ignored) { + } catch (IOException ignored) { } delegate.close(); } @@ -322,7 +354,7 @@ private static final class TeeInputStream extends InputStream { } @Override - public int read() throws java.io.IOException { + public int read() throws IOException { int b = source.read(); if (b == -1) { notifyClosed(); diff --git a/braintrust-sdk/instrumentation/openai_2_8_0/src/main/java/dev/braintrust/instrumentation/openai/v2_8_0/auto/OpenAIInstrumentationModule.java b/braintrust-sdk/instrumentation/openai_2_15_0/src/main/java/dev/braintrust/instrumentation/openai/v2_15_0/auto/OpenAIInstrumentationModule.java similarity index 92% rename from braintrust-sdk/instrumentation/openai_2_8_0/src/main/java/dev/braintrust/instrumentation/openai/v2_8_0/auto/OpenAIInstrumentationModule.java rename to braintrust-sdk/instrumentation/openai_2_15_0/src/main/java/dev/braintrust/instrumentation/openai/v2_15_0/auto/OpenAIInstrumentationModule.java index 7e1b1be9..861a8f70 100644 --- a/braintrust-sdk/instrumentation/openai_2_8_0/src/main/java/dev/braintrust/instrumentation/openai/v2_8_0/auto/OpenAIInstrumentationModule.java +++ b/braintrust-sdk/instrumentation/openai_2_15_0/src/main/java/dev/braintrust/instrumentation/openai/v2_15_0/auto/OpenAIInstrumentationModule.java @@ -1,4 +1,4 @@ -package dev.braintrust.instrumentation.openai.v2_8_0.auto; +package dev.braintrust.instrumentation.openai.v2_15_0.auto; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; @@ -8,7 +8,7 @@ import dev.braintrust.instrumentation.InstrumentationModule; import dev.braintrust.instrumentation.TypeInstrumentation; import dev.braintrust.instrumentation.TypeTransformer; -import dev.braintrust.instrumentation.openai.v2_8_0.BraintrustOpenAI; +import dev.braintrust.instrumentation.openai.v2_15_0.BraintrustOpenAI; import io.opentelemetry.api.GlobalOpenTelemetry; import java.util.List; import java.util.Set; @@ -20,10 +20,10 @@ @AutoService(InstrumentationModule.class) public class OpenAIInstrumentationModule extends InstrumentationModule { private static final String MANUAL_INSTRUMENTATION_PACKAGE = - "dev.braintrust.instrumentation.openai.v2_8_0."; + "dev.braintrust.instrumentation.openai.v2_15_0."; public OpenAIInstrumentationModule() { - super("openai_2_8_0"); + super("openai_2_15_0"); } @Override diff --git a/braintrust-sdk/instrumentation/openai_2_15_0/src/test/java/dev/braintrust/instrumentation/openai/v2_15_0/BraintrustOpenAITest.java b/braintrust-sdk/instrumentation/openai_2_15_0/src/test/java/dev/braintrust/instrumentation/openai/v2_15_0/BraintrustOpenAITest.java new file mode 100644 index 00000000..768c1e3b --- /dev/null +++ b/braintrust-sdk/instrumentation/openai_2_15_0/src/test/java/dev/braintrust/instrumentation/openai/v2_15_0/BraintrustOpenAITest.java @@ -0,0 +1,372 @@ +package dev.braintrust.instrumentation.openai.v2_15_0; + +import static org.junit.jupiter.api.Assertions.*; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.openai.client.OpenAIClient; +import com.openai.client.okhttp.OpenAIOkHttpClient; +import com.openai.core.http.StreamResponse; +import com.openai.helpers.ChatCompletionAccumulator; +import com.openai.helpers.ResponseAccumulator; +import com.openai.models.ChatModel; +import com.openai.models.Reasoning; +import com.openai.models.ReasoningEffort; +import com.openai.models.chat.completions.ChatCompletionCreateParams; +import com.openai.models.chat.completions.ChatCompletionStreamOptions; +import com.openai.models.responses.*; +import dev.braintrust.TestHarness; +import dev.braintrust.instrumentation.Instrumenter; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.sdk.trace.data.SpanData; +import java.util.List; +import java.util.concurrent.TimeUnit; +import lombok.SneakyThrows; +import net.bytebuddy.agent.ByteBuddyAgent; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class BraintrustOpenAITest { + private static final ObjectMapper JSON_MAPPER = new ObjectMapper(); + + @BeforeAll + public static void beforeAll() { + var instrumentation = ByteBuddyAgent.install(); + Instrumenter.install(instrumentation, BraintrustOpenAITest.class.getClassLoader()); + } + + private TestHarness testHarness; + + @BeforeEach + void beforeEach() { + testHarness = TestHarness.setup(); + } + + @Test + @SneakyThrows + void testCompletions() { + OpenAIClient openAIClient = + OpenAIOkHttpClient.builder() + .baseUrl(testHarness.openAiBaseUrl()) + .apiKey(testHarness.openAiApiKey()) + .build(); + + var request = + ChatCompletionCreateParams.builder() + .model(ChatModel.GPT_4O_MINI) + .addSystemMessage("You are a helpful assistant") + .addUserMessage("What is the capital of France?") + .temperature(0.0) + .build(); + + var response = openAIClient.chat().completions().create(request); + assertNotNull(response); + var spans = testHarness.awaitExportedSpans(); + assertEquals(1, spans.size()); + assertValidOpenAISpan(spans.get(0), false); + } + + @Test + @SneakyThrows + void testCompletionsStreaming() { + OpenAIClient openAIClient = + OpenAIOkHttpClient.builder() + .baseUrl(testHarness.openAiBaseUrl()) + .apiKey(testHarness.openAiApiKey()) + .build(); + + var request = + ChatCompletionCreateParams.builder() + .model(ChatModel.GPT_4O_MINI) + .addSystemMessage("You are a helpful assistant") + .addUserMessage("What is the capital of France?") + .temperature(0.0) + .streamOptions( + ChatCompletionStreamOptions.builder().includeUsage(true).build()) + .build(); + + var accumulator = ChatCompletionAccumulator.create(); + try (var stream = openAIClient.chat().completions().createStreaming(request)) { + stream.stream().forEach(accumulator::accumulate); + } + assertFalse(accumulator.chatCompletion().choices().isEmpty(), "should generate a response"); + + // Verify spans + var spans = testHarness.awaitExportedSpans(); + assertEquals(1, spans.size()); + assertValidOpenAISpan(spans.get(0), true); + } + + @Test + @SneakyThrows + void testCompletionsAsync() { + OpenAIClient openAIClient = + OpenAIOkHttpClient.builder() + .baseUrl(testHarness.openAiBaseUrl()) + .apiKey(testHarness.openAiApiKey()) + .build(); + + var request = + ChatCompletionCreateParams.builder() + .model(ChatModel.GPT_4O_MINI) + .addSystemMessage("You are a helpful assistant") + .addUserMessage("What is the capital of France?") + .temperature(0.0) + .build(); + + var response = + openAIClient.async().chat().completions().create(request).get(5, TimeUnit.MINUTES); + assertNotNull(response); + assertNotNull(response.id()); + + var spans = testHarness.awaitExportedSpans(); + assertEquals(1, spans.size()); + assertValidOpenAISpan(spans.get(0), false); + } + + @Test + @SneakyThrows + void testCompletionsAsyncStreaming() { + OpenAIClient openAIClient = + OpenAIOkHttpClient.builder() + .baseUrl(testHarness.openAiBaseUrl()) + .apiKey(testHarness.openAiApiKey()) + .build(); + + var request = + ChatCompletionCreateParams.builder() + .model(ChatModel.GPT_4O_MINI) + .addSystemMessage("You are a helpful assistant") + .addUserMessage("What is the capital of France?") + .temperature(0.0) + .streamOptions( + ChatCompletionStreamOptions.builder().includeUsage(true).build()) + .build(); + + var fullResponse = new StringBuilder(); + var stream = openAIClient.async().chat().completions().createStreaming(request); + stream.subscribe( + chunk -> { + if (!chunk.choices().isEmpty()) { + chunk.choices().get(0).delta().content().ifPresent(fullResponse::append); + } + }); + stream.onCompleteFuture().get(30, TimeUnit.SECONDS); + + assertFalse(fullResponse.toString().isEmpty()); + + var spans = testHarness.awaitExportedSpans(); + assertEquals(1, spans.size()); + var span = spans.get(0); + + assertEquals("Chat Completion", span.getName()); + + String metadataJson = + span.getAttributes().get(AttributeKey.stringKey("braintrust.metadata")); + assertNotNull(metadataJson); + JsonNode metadata = JSON_MAPPER.readTree(metadataJson); + assertEquals("openai", metadata.get("provider").asText()); + + assertNotNull(span.getAttributes().get(AttributeKey.stringKey("braintrust.input_json"))); + + String outputJson = + span.getAttributes().get(AttributeKey.stringKey("braintrust.output_json")); + assertNotNull(outputJson); + var outputChoices = JSON_MAPPER.readTree(outputJson); + assertEquals(1, outputChoices.size()); + assertEquals("assistant", outputChoices.get(0).get("message").get("role").asText()); + + String metricsJson = span.getAttributes().get(AttributeKey.stringKey("braintrust.metrics")); + assertNotNull(metricsJson); + JsonNode metrics = JSON_MAPPER.readTree(metricsJson); + assertTrue(metrics.has("prompt_tokens")); + assertTrue(metrics.has("completion_tokens")); + assertTrue(metrics.has("tokens")); + assertTrue( + metrics.has("time_to_first_token"), + "time_to_first_token should be present for streaming"); + assertTrue(metrics.get("time_to_first_token").asDouble() >= 0.0); + } + + @Test + @SneakyThrows + void testResponses() { + OpenAIClient openAIClient = + OpenAIOkHttpClient.builder() + .baseUrl(testHarness.openAiBaseUrl()) + .apiKey(testHarness.openAiApiKey()) + .build(); + + var inputMsg = + EasyInputMessage.builder() + .role(EasyInputMessage.Role.USER) + .content("What is the capital of France? Reply in one word.") + .build(); + + var request = + ResponseCreateParams.builder() + .model("o4-mini") + .reasoning( + Reasoning.builder() + .effort(ReasoningEffort.LOW) + .summary(Reasoning.Summary.AUTO) + .build()) + .inputOfResponse(List.of(ResponseInputItem.ofEasyInputMessage(inputMsg))) + .build(); + + var response = openAIClient.responses().create(request); + + assertNotNull(response); + assertNotNull(response.id()); + + var spans = testHarness.awaitExportedSpans(); + assertEquals(1, spans.size()); + assertValidOpenAISpan(spans.get(0), false); + } + + @Test + void testResponsesStreaming() { + OpenAIClient client = + OpenAIOkHttpClient.builder() + .baseUrl(testHarness.openAiBaseUrl()) + .apiKey(testHarness.openAiApiKey()) + .build(); + try (StreamResponse stream = + client.responses() + .createStreaming( + ResponseCreateParams.builder() + .model(ChatModel.GPT_4O_MINI) + .instructions("You are a helpful assistant") + .inputOfResponse( + List.of( + ResponseInputItem.ofEasyInputMessage( + EasyInputMessage.builder() + .role( + EasyInputMessage + .Role.USER) + .content( + "What is the" + + " capital of" + + " France?") + .build()))) + .build())) { + ResponseAccumulator accumulator = ResponseAccumulator.create(); + stream.stream().forEach(accumulator::accumulate); + Response response = accumulator.response(); + assertFalse( + response.output() + .get(0) + .asMessage() + .content() + .get(0) + .asOutputText() + .text() + .isEmpty(), + "should generate a response"); + } + var spans = testHarness.awaitExportedSpans(); + assertEquals(1, spans.size()); + assertValidOpenAISpan(spans.get(0), true); + } + + @Test + @SneakyThrows + void testResponsesAsync() { + OpenAIClient openAIClient = + OpenAIOkHttpClient.builder() + .baseUrl(testHarness.openAiBaseUrl()) + .apiKey(testHarness.openAiApiKey()) + .build(); + + var inputMsg = + EasyInputMessage.builder() + .role(EasyInputMessage.Role.USER) + .content("What is the capital of France? Reply in one word.") + .build(); + + var request = + ResponseCreateParams.builder() + .model(ChatModel.GPT_4O_MINI) + .instructions("You are a helpful assistant") + .inputOfResponse(List.of(ResponseInputItem.ofEasyInputMessage(inputMsg))) + .build(); + + var response = openAIClient.async().responses().create(request).get(5, TimeUnit.MINUTES); + assertNotNull(response); + assertNotNull(response.id()); + + var spans = testHarness.awaitExportedSpans(); + assertEquals(1, spans.size()); + assertValidOpenAISpan(spans.get(0), false); + } + + @Test + @SneakyThrows + void testResponsesAsyncStreaming() { + OpenAIClient openAIClient = + OpenAIOkHttpClient.builder() + .baseUrl(testHarness.openAiBaseUrl()) + .apiKey(testHarness.openAiApiKey()) + .build(); + + var request = + ResponseCreateParams.builder() + .model(ChatModel.GPT_4O_MINI) + .instructions("You are a helpful assistant") + .inputOfResponse( + List.of( + ResponseInputItem.ofEasyInputMessage( + EasyInputMessage.builder() + .role(EasyInputMessage.Role.USER) + .content("What is the capital of France?") + .build()))) + .build(); + + var fullResponse = new StringBuilder(); + var stream = openAIClient.async().responses().createStreaming(request); + stream.subscribe( + event -> + event.outputTextDelta() + .ifPresent(delta -> fullResponse.append(delta.delta()))); + stream.onCompleteFuture().get(30, TimeUnit.SECONDS); + + assertFalse(fullResponse.toString().isEmpty()); + + var spans = testHarness.awaitExportedSpans(); + assertEquals(1, spans.size()); + assertValidOpenAISpan(spans.get(0), true); + } + + @SneakyThrows + private static void assertValidOpenAISpan(SpanData span, boolean isStreaming) { + var attributes = span.getAttributes(); + // proper provider + { + String metadataJson = attributes.get(AttributeKey.stringKey("braintrust.metadata")); + assertNotNull(metadataJson, "metadata must be set"); + JsonNode metadata = JSON_MAPPER.readTree(metadataJson); + assertTrue(metadata.has("provider")); + assertEquals("openai", metadata.get("provider").asText()); + } + // ttft check + { + String metricsJson = attributes.get(AttributeKey.stringKey("braintrust.metrics")); + assertNotNull(metricsJson, "metrics must be set"); + JsonNode metrics = JSON_MAPPER.readTree(metricsJson); + var ttft = metrics.get("time_to_first_token"); + if (isStreaming) { + assertNotNull(ttft); + } else { + assertNull(ttft); + } + } + // input + output + assertNotNull( + attributes.get(AttributeKey.stringKey("braintrust.input_json")), + "input must be set"); + assertNotNull( + attributes.get(AttributeKey.stringKey("braintrust.output_json")), + "output must be set"); + } +} diff --git a/braintrust-sdk/instrumentation/openai_2_8_0/src/test/java/dev/braintrust/instrumentation/openai/v2_8_0/BraintrustOpenAITest.java b/braintrust-sdk/instrumentation/openai_2_8_0/src/test/java/dev/braintrust/instrumentation/openai/v2_8_0/BraintrustOpenAITest.java deleted file mode 100644 index 17c3ea31..00000000 --- a/braintrust-sdk/instrumentation/openai_2_8_0/src/test/java/dev/braintrust/instrumentation/openai/v2_8_0/BraintrustOpenAITest.java +++ /dev/null @@ -1,400 +0,0 @@ -package dev.braintrust.instrumentation.openai.v2_8_0; - -import static org.junit.jupiter.api.Assertions.*; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.openai.client.OpenAIClient; -import com.openai.client.okhttp.OpenAIOkHttpClient; -import com.openai.models.ChatModel; -import com.openai.models.Reasoning; -import com.openai.models.ReasoningEffort; -import com.openai.models.chat.completions.ChatCompletionCreateParams; -import com.openai.models.chat.completions.ChatCompletionStreamOptions; -import com.openai.models.responses.EasyInputMessage; -import com.openai.models.responses.ResponseCreateParams; -import com.openai.models.responses.ResponseInputItem; -import dev.braintrust.TestHarness; -import dev.braintrust.instrumentation.Instrumenter; -import io.opentelemetry.api.common.AttributeKey; -import java.util.List; -import java.util.concurrent.TimeUnit; -import lombok.SneakyThrows; -import net.bytebuddy.agent.ByteBuddyAgent; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class BraintrustOpenAITest { - private static final ObjectMapper JSON_MAPPER = new ObjectMapper(); - - @BeforeAll - public static void beforeAll() { - var instrumentation = ByteBuddyAgent.install(); - Instrumenter.install(instrumentation, BraintrustOpenAITest.class.getClassLoader()); - } - - private TestHarness testHarness; - - @BeforeEach - void beforeEach() { - testHarness = TestHarness.setup(); - } - - @Test - @SneakyThrows - void testWrapOpenAi() { - // Create OpenAI client using TestHarness configuration - // TestHarness automatically provides the correct base URL and API key - OpenAIClient openAIClient = - OpenAIOkHttpClient.builder() - .baseUrl(testHarness.openAiBaseUrl()) - .apiKey(testHarness.openAiApiKey()) - .build(); - - var request = - ChatCompletionCreateParams.builder() - .model(ChatModel.GPT_4O_MINI) - .addSystemMessage("You are a helpful assistant") - .addUserMessage("What is the capital of France?") - .temperature(0.0) - .build(); - - var response = openAIClient.chat().completions().create(request); - - // Verify the response (same assertions work for both modes) - assertNotNull(response); - assertNotNull(response.id()); - assertTrue(response.choices().get(0).message().content().isPresent()); - String content = response.choices().get(0).message().content().get(); - assertTrue(content.toLowerCase().contains("paris"), "Response should mention Paris"); - - // Verify spans were exported - var spans = testHarness.awaitExportedSpans(); - assertEquals(1, spans.size()); - var span = spans.get(0); - - // Verify span name matches other SDKs - assertEquals("Chat Completion", span.getName()); - - // Verify span_attributes JSON - String spanAttributesJson = - span.getAttributes().get(AttributeKey.stringKey("braintrust.span_attributes")); - assertNotNull(spanAttributesJson); - JsonNode spanAttributes = JSON_MAPPER.readTree(spanAttributesJson); - assertEquals("llm", spanAttributes.get("type").asText()); - - // Verify braintrust.metadata JSON - String metadataJson = - span.getAttributes().get(AttributeKey.stringKey("braintrust.metadata")); - assertNotNull(metadataJson); - JsonNode metadata = JSON_MAPPER.readTree(metadataJson); - assertEquals("openai", metadata.get("provider").asText()); - assertTrue( - metadata.get("model").asText().startsWith("gpt-4o-mini"), - "model should start with gpt-4o-mini"); - - // Verify braintrust.metrics JSON (tokens) - String metricsJson = span.getAttributes().get(AttributeKey.stringKey("braintrust.metrics")); - assertNotNull(metricsJson); - JsonNode metrics = JSON_MAPPER.readTree(metricsJson); - assertTrue(metrics.has("prompt_tokens"), "prompt_tokens should be present"); - assertTrue( - metrics.get("prompt_tokens").asInt() >= 0, "prompt_tokens should be non-negative"); - assertTrue(metrics.has("completion_tokens"), "completion_tokens should be present"); - assertTrue( - metrics.get("completion_tokens").asInt() >= 0, - "completion_tokens should be non-negative"); - assertTrue(metrics.has("tokens"), "tokens should be present"); - assertTrue(metrics.get("tokens").asInt() >= 0, "tokens should be non-negative"); - assertFalse( - metrics.has("time_to_first_token"), - "time_to_first_token should not be present for non-streaming"); - - // Verify output (choices array) - String outputJson = - span.getAttributes().get(AttributeKey.stringKey("braintrust.output_json")); - assertNotNull(outputJson); - var outputChoices = JSON_MAPPER.readTree(outputJson); - assertEquals(1, outputChoices.size()); - var choice = outputChoices.get(0); - assertEquals("assistant", choice.get("message").get("role").asText()); - assertNotNull(choice.get("finish_reason")); - } - - @Test - @SneakyThrows - void testWrapOpenAiStreaming() { - OpenAIClient openAIClient = - OpenAIOkHttpClient.builder() - .baseUrl(testHarness.openAiBaseUrl()) - .apiKey(testHarness.openAiApiKey()) - .build(); - - var request = - ChatCompletionCreateParams.builder() - .model(ChatModel.GPT_4O_MINI) - .addSystemMessage("You are a helpful assistant") - .addUserMessage("What is the capital of France?") - .temperature(0.0) - .streamOptions( - ChatCompletionStreamOptions.builder().includeUsage(true).build()) - .build(); - - // Consume the stream - StringBuilder fullResponse = new StringBuilder(); - try (var stream = openAIClient.chat().completions().createStreaming(request)) { - stream.stream() - .forEach( - chunk -> { - if (!chunk.choices().isEmpty()) { - chunk.choices() - .get(0) - .delta() - .content() - .ifPresent(fullResponse::append); - } - }); - } - - // Verify the response - assertFalse(fullResponse.isEmpty(), "Should have received streaming response"); - assertTrue( - fullResponse.toString().toLowerCase().contains("paris"), - "Response should mention Paris"); - - // Verify spans - var spans = testHarness.awaitExportedSpans(); - assertEquals(1, spans.size()); - var span = spans.get(0); - - assertEquals("Chat Completion", span.getName()); - - // Verify braintrust.metadata has provider=openai - String metadataJson = - span.getAttributes().get(AttributeKey.stringKey("braintrust.metadata")); - assertNotNull(metadataJson); - JsonNode metadata = JSON_MAPPER.readTree(metadataJson); - assertEquals("openai", metadata.get("provider").asText()); - - // Verify time_to_first_token is in braintrust.metrics JSON - String metricsJson = span.getAttributes().get(AttributeKey.stringKey("braintrust.metrics")); - assertNotNull(metricsJson); - JsonNode metrics = JSON_MAPPER.readTree(metricsJson); - assertTrue(metrics.has("time_to_first_token"), "time_to_first_token should be present"); - assertTrue( - metrics.get("time_to_first_token").asDouble() >= 0.0, - "time_to_first_token should be non-negative"); - } - - @Test - @SneakyThrows - void testWrapOpenAiResponses() { - OpenAIClient openAIClient = - OpenAIOkHttpClient.builder() - .baseUrl(testHarness.openAiBaseUrl()) - .apiKey(testHarness.openAiApiKey()) - .build(); - - var inputMsg = - EasyInputMessage.builder() - .role(EasyInputMessage.Role.USER) - .content("What is the capital of France? Reply in one word.") - .build(); - - var request = - ResponseCreateParams.builder() - .model("o4-mini") - .reasoning( - Reasoning.builder() - .effort(ReasoningEffort.LOW) - .summary(Reasoning.Summary.AUTO) - .build()) - .inputOfResponse(List.of(ResponseInputItem.ofEasyInputMessage(inputMsg))) - .build(); - - var response = openAIClient.responses().create(request); - - assertNotNull(response); - assertNotNull(response.id()); - assertFalse(response.output().isEmpty(), "Response should have output items"); - - var spans = testHarness.awaitExportedSpans(); - assertEquals(1, spans.size()); - var span = spans.get(0); - - // Span name for /v1/responses endpoint - assertEquals("responses", span.getName()); - - // span_attributes type=llm - String spanAttributesJson = - span.getAttributes().get(AttributeKey.stringKey("braintrust.span_attributes")); - assertNotNull(spanAttributesJson); - JsonNode spanAttributes = JSON_MAPPER.readTree(spanAttributesJson); - assertEquals("llm", spanAttributes.get("type").asText()); - - // metadata: provider and model - String metadataJson = - span.getAttributes().get(AttributeKey.stringKey("braintrust.metadata")); - assertNotNull(metadataJson); - JsonNode metadata = JSON_MAPPER.readTree(metadataJson); - assertEquals("openai", metadata.get("provider").asText()); - assertTrue(metadata.get("model").asText().startsWith("o4-mini")); - - // input_json: captured from "input" array - String inputJson = - span.getAttributes().get(AttributeKey.stringKey("braintrust.input_json")); - assertNotNull(inputJson, "braintrust.input_json should be set"); - JsonNode inputItems = JSON_MAPPER.readTree(inputJson); - assertTrue(inputItems.isArray() && inputItems.size() > 0); - assertEquals("user", inputItems.get(0).get("role").asText()); - - // output_json: captured from "output" array - String outputJson = - span.getAttributes().get(AttributeKey.stringKey("braintrust.output_json")); - assertNotNull(outputJson, "braintrust.output_json should be set"); - JsonNode outputItems = JSON_MAPPER.readTree(outputJson); - assertTrue(outputItems.isArray() && outputItems.size() > 0); - - // metrics: tokens from Responses API usage fields - String metricsJson = span.getAttributes().get(AttributeKey.stringKey("braintrust.metrics")); - assertNotNull(metricsJson); - JsonNode metrics = JSON_MAPPER.readTree(metricsJson); - assertTrue(metrics.has("prompt_tokens"), "prompt_tokens should be present"); - assertTrue(metrics.get("prompt_tokens").asInt() >= 0); - assertTrue(metrics.has("completion_tokens"), "completion_tokens should be present"); - assertTrue(metrics.get("completion_tokens").asInt() >= 0); - assertTrue(metrics.has("tokens"), "tokens should be present"); - assertTrue(metrics.get("tokens").asInt() >= 0); - assertTrue( - metrics.has("completion_reasoning_tokens"), - "completion_reasoning_tokens should be present"); - assertTrue(metrics.get("completion_reasoning_tokens").asInt() >= 0); - } - - @Test - @SneakyThrows - void testWrapOpenAiAsync() { - OpenAIClient openAIClient = - OpenAIOkHttpClient.builder() - .baseUrl(testHarness.openAiBaseUrl()) - .apiKey(testHarness.openAiApiKey()) - .build(); - - var request = - ChatCompletionCreateParams.builder() - .model(ChatModel.GPT_4O_MINI) - .addSystemMessage("You are a helpful assistant") - .addUserMessage("What is the capital of France?") - .temperature(0.0) - .build(); - - var response = openAIClient.async().chat().completions().create(request).get(); - - assertNotNull(response); - assertNotNull(response.id()); - assertTrue(response.choices().get(0).message().content().isPresent()); - String content = response.choices().get(0).message().content().get(); - assertTrue(content.toLowerCase().contains("paris"), "Response should mention Paris"); - - var spans = testHarness.awaitExportedSpans(); - assertEquals(1, spans.size()); - var span = spans.get(0); - - assertEquals("Chat Completion", span.getName()); - - String spanAttributesJson = - span.getAttributes().get(AttributeKey.stringKey("braintrust.span_attributes")); - assertNotNull(spanAttributesJson); - JsonNode spanAttributes = JSON_MAPPER.readTree(spanAttributesJson); - assertEquals("llm", spanAttributes.get("type").asText()); - - String metadataJson = - span.getAttributes().get(AttributeKey.stringKey("braintrust.metadata")); - assertNotNull(metadataJson); - JsonNode metadata = JSON_MAPPER.readTree(metadataJson); - assertEquals("openai", metadata.get("provider").asText()); - - String outputJson = - span.getAttributes().get(AttributeKey.stringKey("braintrust.output_json")); - assertNotNull(outputJson); - var outputChoices = JSON_MAPPER.readTree(outputJson); - assertEquals(1, outputChoices.size()); - assertEquals("assistant", outputChoices.get(0).get("message").get("role").asText()); - - String metricsJson = span.getAttributes().get(AttributeKey.stringKey("braintrust.metrics")); - assertNotNull(metricsJson); - JsonNode metrics = JSON_MAPPER.readTree(metricsJson); - assertTrue(metrics.has("prompt_tokens")); - assertTrue(metrics.has("completion_tokens")); - assertTrue(metrics.has("tokens")); - assertFalse( - metrics.has("time_to_first_token"), - "time_to_first_token should not be present for non-streaming"); - } - - @Test - @SneakyThrows - void testWrapOpenAiAsyncStreaming() { - OpenAIClient openAIClient = - OpenAIOkHttpClient.builder() - .baseUrl(testHarness.openAiBaseUrl()) - .apiKey(testHarness.openAiApiKey()) - .build(); - - var request = - ChatCompletionCreateParams.builder() - .model(ChatModel.GPT_4O_MINI) - .addSystemMessage("You are a helpful assistant") - .addUserMessage("What is the capital of France?") - .temperature(0.0) - .streamOptions( - ChatCompletionStreamOptions.builder().includeUsage(true).build()) - .build(); - - var fullResponse = new StringBuilder(); - var stream = openAIClient.async().chat().completions().createStreaming(request); - stream.subscribe( - chunk -> { - if (!chunk.choices().isEmpty()) { - chunk.choices().get(0).delta().content().ifPresent(fullResponse::append); - } - }); - stream.onCompleteFuture().get(30, TimeUnit.SECONDS); - - assertFalse(fullResponse.toString().isEmpty()); - assertTrue(fullResponse.toString().toLowerCase().contains("paris")); - - var spans = testHarness.awaitExportedSpans(); - assertEquals(1, spans.size()); - var span = spans.get(0); - - assertEquals("Chat Completion", span.getName()); - - String metadataJson = - span.getAttributes().get(AttributeKey.stringKey("braintrust.metadata")); - assertNotNull(metadataJson); - JsonNode metadata = JSON_MAPPER.readTree(metadataJson); - assertEquals("openai", metadata.get("provider").asText()); - - assertNotNull(span.getAttributes().get(AttributeKey.stringKey("braintrust.input_json"))); - - String outputJson = - span.getAttributes().get(AttributeKey.stringKey("braintrust.output_json")); - assertNotNull(outputJson); - var outputChoices = JSON_MAPPER.readTree(outputJson); - assertEquals(1, outputChoices.size()); - assertEquals("assistant", outputChoices.get(0).get("message").get("role").asText()); - - String metricsJson = span.getAttributes().get(AttributeKey.stringKey("braintrust.metrics")); - assertNotNull(metricsJson); - JsonNode metrics = JSON_MAPPER.readTree(metricsJson); - assertTrue(metrics.has("prompt_tokens")); - assertTrue(metrics.has("completion_tokens")); - assertTrue(metrics.has("tokens")); - assertTrue( - metrics.has("time_to_first_token"), - "time_to_first_token should be present for streaming"); - assertTrue(metrics.get("time_to_first_token").asDouble() >= 0.0); - } -} diff --git a/btx/build.gradle b/btx/build.gradle index 150600cf..5c2fe440 100644 --- a/btx/build.gradle +++ b/btx/build.gradle @@ -16,7 +16,7 @@ repositories { dependencies { // Braintrust SDK (local project dependencies) testImplementation project(':braintrust-sdk') - testImplementation project(':braintrust-sdk:instrumentation:openai_2_8_0') + testImplementation project(':braintrust-sdk:instrumentation:openai_2_15_0') testImplementation project(':braintrust-sdk:instrumentation:anthropic_2_2_0') testImplementation project(':braintrust-sdk:instrumentation:genai_1_18_0') testImplementation project(':braintrust-sdk:instrumentation:langchain_1_8_0') diff --git a/examples/build.gradle b/examples/build.gradle index 6a231b18..fa732452 100644 --- a/examples/build.gradle +++ b/examples/build.gradle @@ -20,7 +20,7 @@ def braintrustLogLevel = System.getenv('BRAINTRUST_LOG_LEVEL') ?: 'info' dependencies { implementation project(':braintrust-sdk') - implementation project(':braintrust-sdk:instrumentation:openai_2_8_0') + implementation project(':braintrust-sdk:instrumentation:openai_2_15_0') implementation project(':braintrust-sdk:instrumentation:anthropic_2_2_0') implementation project(':braintrust-sdk:instrumentation:genai_1_18_0') implementation project(':braintrust-sdk:instrumentation:langchain_1_8_0') diff --git a/settings.gradle b/settings.gradle index ea5c0e07..f4d4f199 100644 --- a/settings.gradle +++ b/settings.gradle @@ -11,7 +11,7 @@ include 'braintrust-java-agent' include 'braintrust-java-agent:bootstrap' include 'braintrust-java-agent:internal' include 'braintrust-java-agent:instrumenter' -include 'braintrust-sdk:instrumentation:openai_2_8_0' +include 'braintrust-sdk:instrumentation:openai_2_15_0' include 'braintrust-sdk:instrumentation:anthropic_2_2_0' include 'braintrust-sdk:instrumentation:genai_1_18_0' include 'braintrust-sdk:instrumentation:langchain_1_8_0' diff --git a/test-harness/src/testFixtures/resources/cassettes/braintrust/mappings/otel_v1_traces-0583545e-9c03-414a-9243-7d8d03d99a94.json b/test-harness/src/testFixtures/resources/cassettes/braintrust/mappings/otel_v1_traces-0583545e-9c03-414a-9243-7d8d03d99a94.json new file mode 100644 index 00000000..63af8e94 --- /dev/null +++ b/test-harness/src/testFixtures/resources/cassettes/braintrust/mappings/otel_v1_traces-0583545e-9c03-414a-9243-7d8d03d99a94.json @@ -0,0 +1,39 @@ +{ + "id" : "0583545e-9c03-414a-9243-7d8d03d99a94", + "name" : "otel_v1_traces", + "request" : { + "url" : "/otel/v1/traces", + "method" : "POST", + "headers" : { + "Content-Type" : { + "equalTo" : "application/x-protobuf" + } + }, + "bodyPatterns" : [ { + "binaryEqualTo" : "Cu8HCrIBCiAKDHNlcnZpY2UubmFtZRIQCg5icmFpbnRydXN0LWFwcAoiCg9zZXJ2aWNlLnZlcnNpb24SDwoNMC4zLjYtYzY3NjFlMgogChZ0ZWxlbWV0cnkuc2RrLmxhbmd1YWdlEgYKBGphdmEKJQoSdGVsZW1ldHJ5LnNkay5uYW1lEg8KDW9wZW50ZWxlbWV0cnkKIQoVdGVsZW1ldHJ5LnNkay52ZXJzaW9uEggKBjEuNTkuMBK3BgoRCg9icmFpbnRydXN0LWphdmESoQYKEMb5rDSOS6u1UGerItzcGiESCJlE8FS7LNU1Kg9DaGF0IENvbXBsZXRpb24wATkQuitEpsisGEHQ9ytopsisGEqRAQoVYnJhaW50cnVzdC5pbnB1dF9qc29uEngKdlt7ImNvbnRlbnQiOiJZb3UgYXJlIGEgaGVscGZ1bCBhc3Npc3RhbnQiLCJyb2xlIjoic3lzdGVtIn0seyJjb250ZW50IjoiV2hhdCBpcyB0aGUgY2FwaXRhbCBvZiBGcmFuY2U/Iiwicm9sZSI6InVzZXIifV1KcAoSYnJhaW50cnVzdC5tZXRyaWNzEloKWHsiY29tcGxldGlvbl90b2tlbnMiOjcsInByb21wdF90b2tlbnMiOjIzLCJ0b2tlbnMiOjMwLCJ0aW1lX3RvX2ZpcnN0X3Rva2VuIjowLjAwNzE2OTQxNn1KLgoaYnJhaW50cnVzdC5zcGFuX2F0dHJpYnV0ZXMSEAoOeyJ0eXBlIjoibGxtIn1KMgoRYnJhaW50cnVzdC5wYXJlbnQSHQobcHJvamVjdF9uYW1lOmphdmEtdW5pdC10ZXN0SrwBChZicmFpbnRydXN0Lm91dHB1dF9qc29uEqEBCp4BW3siZmluaXNoX3JlYXNvbiI6InN0b3AiLCJpbmRleCI6MCwibG9ncHJvYnMiOm51bGwsIm1lc3NhZ2UiOnsiY29udGVudCI6IlRoZSBjYXBpdGFsIG9mIEZyYW5jZSBpcyBQYXJpcy4iLCJyZWZ1c2FsIjpudWxsLCJyb2xlIjoiYXNzaXN0YW50IiwidG9vbF9jYWxscyI6W119fV1KrAEKE2JyYWludHJ1c3QubWV0YWRhdGESlAEKkQF7InByb3ZpZGVyIjoib3BlbmFpIiwicmVxdWVzdF9wYXRoIjoiY2hhdC9jb21wbGV0aW9ucyIsIm1vZGVsIjoiZ3B0LTRvLW1pbmkiLCJyZXF1ZXN0X2Jhc2VfdXJpIjoiaHR0cDovL2xvY2FsaG9zdDo2MTQyOSIsInJlcXVlc3RfbWV0aG9kIjoiUE9TVCJ9egCFAQEBAAA=" + } ] + }, + "response" : { + "status" : 200, + "headers" : { + "X-Cache" : "Miss from cloudfront", + "x-amz-apigw-id" : "c6QhIGeJoAMEEow=", + "vary" : "Origin", + "x-amzn-Remapped-content-length" : "0", + "X-Amz-Cf-Pop" : [ "SFO53-P8", "SFO53-P1" ], + "X-Amzn-Trace-Id" : "Root=1-69fa613a-775ac6ea1ee86e342dc61a99;Parent=72dd6c0f00472e06;Sampled=0;Lineage=1:24be3d11:0", + "Date" : "Tue, 05 May 2026 21:29:30 GMT", + "Via" : "1.1 78084fc122c4500a240b888394ad4976.cloudfront.net (CloudFront), 1.1 459b85c545909b647abc5dea4320a0da.cloudfront.net (CloudFront)", + "access-control-expose-headers" : "x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id", + "access-control-allow-credentials" : "true", + "x-bt-internal-trace-id" : "69fa613a0000000065df853c605795d3", + "x-amzn-RequestId" : "17d6ec8b-ec3e-46d3-aed6-0a1a2d78f24c", + "X-Amz-Cf-Id" : "7rWOJ_5F-lDZbKtu8kRjwJRj5LmAXiDRrDK6p-9k9ftDanQtgMh4tg==", + "etag" : "W/\"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk\"", + "Content-Type" : "application/x-protobuf" + } + }, + "uuid" : "0583545e-9c03-414a-9243-7d8d03d99a94", + "persistent" : true, + "insertionIndex" : 255 +} \ No newline at end of file diff --git a/test-harness/src/testFixtures/resources/cassettes/braintrust/mappings/otel_v1_traces-16e37454-11f7-4aa1-a9f6-8b9dee6d3a89.json b/test-harness/src/testFixtures/resources/cassettes/braintrust/mappings/otel_v1_traces-16e37454-11f7-4aa1-a9f6-8b9dee6d3a89.json new file mode 100644 index 00000000..e9082fb2 --- /dev/null +++ b/test-harness/src/testFixtures/resources/cassettes/braintrust/mappings/otel_v1_traces-16e37454-11f7-4aa1-a9f6-8b9dee6d3a89.json @@ -0,0 +1,39 @@ +{ + "id" : "16e37454-11f7-4aa1-a9f6-8b9dee6d3a89", + "name" : "otel_v1_traces", + "request" : { + "url" : "/otel/v1/traces", + "method" : "POST", + "headers" : { + "Content-Type" : { + "equalTo" : "application/x-protobuf" + } + }, + "bodyPatterns" : [ { + "binaryEqualTo" : "CsEICrIBCiAKDHNlcnZpY2UubmFtZRIQCg5icmFpbnRydXN0LWFwcAoiCg9zZXJ2aWNlLnZlcnNpb24SDwoNMC4zLjYtYzY3NjFlMgogChZ0ZWxlbWV0cnkuc2RrLmxhbmd1YWdlEgYKBGphdmEKJQoSdGVsZW1ldHJ5LnNkay5uYW1lEg8KDW9wZW50ZWxlbWV0cnkKIQoVdGVsZW1ldHJ5LnNkay52ZXJzaW9uEggKBjEuNTkuMBKJBwoRCg9icmFpbnRydXN0LWphdmES8wYKEEZ8++JSi6pYQ6HzNvs2+ZISCMLoRwqe63tKKglyZXNwb25zZXMwATnwcT9/psisGEGE1jwgp8isGEpqChVicmFpbnRydXN0LmlucHV0X2pzb24SUQpPW3siY29udGVudCI6IldoYXQgaXMgdGhlIGNhcGl0YWwgb2YgRnJhbmNlPyBSZXBseSBpbiBvbmUgd29yZC4iLCJyb2xlIjoidXNlciJ9XUpvChJicmFpbnRydXN0Lm1ldHJpY3MSWQpXeyJjb21wbGV0aW9uX3Rva2VucyI6MzgsInByb21wdF90b2tlbnMiOjE4LCJ0b2tlbnMiOjU2LCJjb21wbGV0aW9uX3JlYXNvbmluZ190b2tlbnMiOjB9Si4KGmJyYWludHJ1c3Quc3Bhbl9hdHRyaWJ1dGVzEhAKDnsidHlwZSI6ImxsbSJ9SjIKEWJyYWludHJ1c3QucGFyZW50Eh0KG3Byb2plY3RfbmFtZTpqYXZhLXVuaXQtdGVzdErIAgoWYnJhaW50cnVzdC5vdXRwdXRfanNvbhKtAgqqAlt7ImlkIjoicnNfMDM2NTIwZTIxNjllZmE3NDAwNjlmYTYxM2I5M2E0ODE5NWIzOGY2OGE4Nzc1MjRmZDIiLCJ0eXBlIjoicmVhc29uaW5nIiwic3VtbWFyeSI6W119LHsiaWQiOiJtc2dfMDM2NTIwZTIxNjllZmE3NDAwNjlmYTYxM2M3NjMwODE5NTgyY2MxMjRjNDU1OWM3ZTAiLCJ0eXBlIjoibWVzc2FnZSIsInN0YXR1cyI6ImNvbXBsZXRlZCIsImNvbnRlbnQiOlt7InR5cGUiOiJvdXRwdXRfdGV4dCIsImFubm90YXRpb25zIjpbXSwibG9ncHJvYnMiOltdLCJ0ZXh0IjoiUGFyaXMifV0sInJvbGUiOiJhc3Npc3RhbnQifV1KoQEKE2JyYWludHJ1c3QubWV0YWRhdGESiQEKhgF7InByb3ZpZGVyIjoib3BlbmFpIiwicmVxdWVzdF9wYXRoIjoicmVzcG9uc2VzIiwibW9kZWwiOiJvNC1taW5pIiwicmVxdWVzdF9iYXNlX3VyaSI6Imh0dHA6Ly9sb2NhbGhvc3Q6NjE0MjkiLCJyZXF1ZXN0X21ldGhvZCI6IlBPU1QifXoAhQEBAQAA" + } ] + }, + "response" : { + "status" : 200, + "headers" : { + "X-Cache" : "Miss from cloudfront", + "x-amz-apigw-id" : "c6QhmF92IAMEHXw=", + "vary" : "Origin", + "x-amzn-Remapped-content-length" : "0", + "X-Amz-Cf-Pop" : [ "SFO53-P8", "SFO53-P1" ], + "X-Amzn-Trace-Id" : "Root=1-69fa613d-7798a4a30ad1a01e6e660890;Parent=13c5353e1e5e26a9;Sampled=0;Lineage=1:24be3d11:0", + "Date" : "Tue, 05 May 2026 21:29:33 GMT", + "Via" : "1.1 1192096cca5216ce826d805f95b99ae6.cloudfront.net (CloudFront), 1.1 6db0e3fcf85d00de1ac587c2611daca6.cloudfront.net (CloudFront)", + "access-control-expose-headers" : "x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id", + "access-control-allow-credentials" : "true", + "x-bt-internal-trace-id" : "69fa613d000000002c7e4eecc90d4549", + "x-amzn-RequestId" : "c7f89a2d-f180-47ba-b4ad-c45cb9134870", + "X-Amz-Cf-Id" : "R0FrNjEns2U_5ezsVYRqlj8Syu8w8vTeHb_4q_gNwSfXC3fxgqTKWA==", + "etag" : "W/\"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk\"", + "Content-Type" : "application/x-protobuf" + } + }, + "uuid" : "16e37454-11f7-4aa1-a9f6-8b9dee6d3a89", + "persistent" : true, + "insertionIndex" : 254 +} \ No newline at end of file diff --git a/test-harness/src/testFixtures/resources/cassettes/braintrust/mappings/otel_v1_traces-345e8cfc-b988-4f27-b4ba-f22847ec2339.json b/test-harness/src/testFixtures/resources/cassettes/braintrust/mappings/otel_v1_traces-345e8cfc-b988-4f27-b4ba-f22847ec2339.json new file mode 100644 index 00000000..61f791af --- /dev/null +++ b/test-harness/src/testFixtures/resources/cassettes/braintrust/mappings/otel_v1_traces-345e8cfc-b988-4f27-b4ba-f22847ec2339.json @@ -0,0 +1,39 @@ +{ + "id" : "345e8cfc-b988-4f27-b4ba-f22847ec2339", + "name" : "otel_v1_traces", + "request" : { + "url" : "/otel/v1/traces", + "method" : "POST", + "headers" : { + "Content-Type" : { + "equalTo" : "application/x-protobuf" + } + }, + "bodyPatterns" : [ { + "binaryEqualTo" : "Cs4HCrIBCiAKDHNlcnZpY2UubmFtZRIQCg5icmFpbnRydXN0LWFwcAoiCg9zZXJ2aWNlLnZlcnNpb24SDwoNMC4zLjYtYzY3NjFlMgogChZ0ZWxlbWV0cnkuc2RrLmxhbmd1YWdlEgYKBGphdmEKJQoSdGVsZW1ldHJ5LnNkay5uYW1lEg8KDW9wZW50ZWxlbWV0cnkKIQoVdGVsZW1ldHJ5LnNkay52ZXJzaW9uEggKBjEuNTkuMBKWBgoRCg9icmFpbnRydXN0LWphdmESgAYKEK+JCZSpp0MqG/X7yghAIp8SCHrhvpfbRR+BKg9DaGF0IENvbXBsZXRpb24wATkQgxaFp8isGEHBE52np8isGEqRAQoVYnJhaW50cnVzdC5pbnB1dF9qc29uEngKdlt7ImNvbnRlbnQiOiJZb3UgYXJlIGEgaGVscGZ1bCBhc3Npc3RhbnQiLCJyb2xlIjoic3lzdGVtIn0seyJjb250ZW50IjoiV2hhdCBpcyB0aGUgY2FwaXRhbCBvZiBGcmFuY2U/Iiwicm9sZSI6InVzZXIifV1KTgoSYnJhaW50cnVzdC5tZXRyaWNzEjgKNnsiY29tcGxldGlvbl90b2tlbnMiOjcsInByb21wdF90b2tlbnMiOjIzLCJ0b2tlbnMiOjMwfUouChpicmFpbnRydXN0LnNwYW5fYXR0cmlidXRlcxIQCg57InR5cGUiOiJsbG0ifUoyChFicmFpbnRydXN0LnBhcmVudBIdChtwcm9qZWN0X25hbWU6amF2YS11bml0LXRlc3RKvQEKFmJyYWludHJ1c3Qub3V0cHV0X2pzb24SogEKnwFbeyJpbmRleCI6MCwibWVzc2FnZSI6eyJyb2xlIjoiYXNzaXN0YW50IiwiY29udGVudCI6IlRoZSBjYXBpdGFsIG9mIEZyYW5jZSBpcyBQYXJpcy4iLCJyZWZ1c2FsIjpudWxsLCJhbm5vdGF0aW9ucyI6W119LCJsb2dwcm9icyI6bnVsbCwiZmluaXNoX3JlYXNvbiI6InN0b3AifV1KrAEKE2JyYWludHJ1c3QubWV0YWRhdGESlAEKkQF7InByb3ZpZGVyIjoib3BlbmFpIiwicmVxdWVzdF9wYXRoIjoiY2hhdC9jb21wbGV0aW9ucyIsIm1vZGVsIjoiZ3B0LTRvLW1pbmkiLCJyZXF1ZXN0X2Jhc2VfdXJpIjoiaHR0cDovL2xvY2FsaG9zdDo2MTQyOSIsInJlcXVlc3RfbWV0aG9kIjoiUE9TVCJ9egCFAQEBAAA=" + } ] + }, + "response" : { + "status" : 200, + "headers" : { + "X-Cache" : "Miss from cloudfront", + "x-amz-apigw-id" : "c6Qh_FOYoAMEPfg=", + "vary" : "Origin", + "x-amzn-Remapped-content-length" : "0", + "X-Amz-Cf-Pop" : [ "SFO53-P8", "SFO53-P1" ], + "X-Amzn-Trace-Id" : "Root=1-69fa613f-4723e14f09767f9516db1517;Parent=243bfd2d2bc539b8;Sampled=0;Lineage=1:24be3d11:0", + "Date" : "Tue, 05 May 2026 21:29:35 GMT", + "Via" : "1.1 f87d91065dc3f8a4150aaedb0d948cd8.cloudfront.net (CloudFront), 1.1 c8c3180933886633be93f042334d6e12.cloudfront.net (CloudFront)", + "access-control-expose-headers" : "x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id", + "access-control-allow-credentials" : "true", + "x-bt-internal-trace-id" : "69fa613f000000004edb3095136d04d9", + "x-amzn-RequestId" : "4eb00730-a76f-47a7-bcf8-80296ca9b19b", + "X-Amz-Cf-Id" : "kozl9H8Hf9U5Ex6V76f775BUA0fHiBQWvstZzMOOB8pwg1z42wvPPg==", + "etag" : "W/\"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk\"", + "Content-Type" : "application/x-protobuf" + } + }, + "uuid" : "345e8cfc-b988-4f27-b4ba-f22847ec2339", + "persistent" : true, + "insertionIndex" : 252 +} \ No newline at end of file diff --git a/test-harness/src/testFixtures/resources/cassettes/braintrust/mappings/otel_v1_traces-54ca1231-3491-4b83-b678-3b97a45d0e94.json b/test-harness/src/testFixtures/resources/cassettes/braintrust/mappings/otel_v1_traces-54ca1231-3491-4b83-b678-3b97a45d0e94.json new file mode 100644 index 00000000..ba26337a --- /dev/null +++ b/test-harness/src/testFixtures/resources/cassettes/braintrust/mappings/otel_v1_traces-54ca1231-3491-4b83-b678-3b97a45d0e94.json @@ -0,0 +1,39 @@ +{ + "id" : "54ca1231-3491-4b83-b678-3b97a45d0e94", + "name" : "otel_v1_traces", + "request" : { + "url" : "/otel/v1/traces", + "method" : "POST", + "headers" : { + "Content-Type" : { + "equalTo" : "application/x-protobuf" + } + }, + "bodyPatterns" : [ { + "binaryEqualTo" : "Co8ICrIBCiAKDHNlcnZpY2UubmFtZRIQCg5icmFpbnRydXN0LWFwcAoiCg9zZXJ2aWNlLnZlcnNpb24SDwoNMC4zLjYtYzY3NjFlMgogChZ0ZWxlbWV0cnkuc2RrLmxhbmd1YWdlEgYKBGphdmEKJQoSdGVsZW1ldHJ5LnNkay5uYW1lEg8KDW9wZW50ZWxlbWV0cnkKIQoVdGVsZW1ldHJ5LnNkay52ZXJzaW9uEggKBjEuNTkuMBLXBgoRCg9icmFpbnRydXN0LWphdmESwQYKELA8IAbKGggoef5Fhnjo/vsSCOfcCmDedGzEKglyZXNwb25zZXMwATkALpoQqMisGEHlvvw8qMisGEpXChVicmFpbnRydXN0LmlucHV0X2pzb24SPgo8W3siY29udGVudCI6IldoYXQgaXMgdGhlIGNhcGl0YWwgb2YgRnJhbmNlPyIsInJvbGUiOiJ1c2VyIn1dSpABChJicmFpbnRydXN0Lm1ldHJpY3MSegp4eyJjb21wbGV0aW9uX3Rva2VucyI6OCwicHJvbXB0X3Rva2VucyI6MjMsInRva2VucyI6MzEsImNvbXBsZXRpb25fcmVhc29uaW5nX3Rva2VucyI6MCwidGltZV90b19maXJzdF90b2tlbiI6MC4wMDEwOTc2MjV9Si4KGmJyYWludHJ1c3Quc3Bhbl9hdHRyaWJ1dGVzEhAKDnsidHlwZSI6ImxsbSJ9SjIKEWJyYWludHJ1c3QucGFyZW50Eh0KG3Byb2plY3RfbmFtZTpqYXZhLXVuaXQtdGVzdEqDAgoWYnJhaW50cnVzdC5vdXRwdXRfanNvbhLoAQrlAVt7ImlkIjoibXNnXzA4MmQ4ZjkxZmJkNmUzMTgwMDY5ZmE2MTQxODM0ODgxOTZiZTAyN2Y4ZWRjMmYzYjM1IiwiY29udGVudCI6W3siYW5ub3RhdGlvbnMiOltdLCJ0ZXh0IjoiVGhlIGNhcGl0YWwgb2YgRnJhbmNlIGlzIFBhcmlzLiIsInR5cGUiOiJvdXRwdXRfdGV4dCIsImxvZ3Byb2JzIjpbXX1dLCJyb2xlIjoiYXNzaXN0YW50Iiwic3RhdHVzIjoiY29tcGxldGVkIiwidHlwZSI6Im1lc3NhZ2UifV1KpQEKE2JyYWludHJ1c3QubWV0YWRhdGESjQEKigF7InByb3ZpZGVyIjoib3BlbmFpIiwicmVxdWVzdF9wYXRoIjoicmVzcG9uc2VzIiwibW9kZWwiOiJncHQtNG8tbWluaSIsInJlcXVlc3RfYmFzZV91cmkiOiJodHRwOi8vbG9jYWxob3N0OjYxNDI5IiwicmVxdWVzdF9tZXRob2QiOiJQT1NUIn16AIUBAQEAAA==" + } ] + }, + "response" : { + "status" : 200, + "headers" : { + "X-Cache" : "Miss from cloudfront", + "x-amz-apigw-id" : "c6QiWH39oAMEcGg=", + "vary" : "Origin", + "x-amzn-Remapped-content-length" : "0", + "X-Amz-Cf-Pop" : [ "SFO53-P8", "SFO53-P1" ], + "X-Amzn-Trace-Id" : "Root=1-69fa6141-5b1e06ab2afe4fe567bfd4a3;Parent=58ac98949191426d;Sampled=0;Lineage=1:24be3d11:0", + "Date" : "Tue, 05 May 2026 21:29:38 GMT", + "Via" : "1.1 5cf315a7bafce190fcf84f55b9019bda.cloudfront.net (CloudFront), 1.1 a11ff1ad6e4c16fe95e18b435889304a.cloudfront.net (CloudFront)", + "access-control-expose-headers" : "x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id", + "access-control-allow-credentials" : "true", + "x-bt-internal-trace-id" : "69fa6141000000000e75b060800dd1e6", + "x-amzn-RequestId" : "f4fade7d-b72c-4a87-bcc6-d5ffb7399cfe", + "X-Amz-Cf-Id" : "mjRA0uLjQwhcl1Jjz8Bm0A8vyUghXNlIUwNT4D9DHboB0FwFgJfrBA==", + "etag" : "W/\"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk\"", + "Content-Type" : "application/x-protobuf" + } + }, + "uuid" : "54ca1231-3491-4b83-b678-3b97a45d0e94", + "persistent" : true, + "insertionIndex" : 250 +} \ No newline at end of file diff --git a/test-harness/src/testFixtures/resources/cassettes/braintrust/mappings/otel_v1_traces-775e27b5-8787-4981-93c4-edd300187bb4.json b/test-harness/src/testFixtures/resources/cassettes/braintrust/mappings/otel_v1_traces-775e27b5-8787-4981-93c4-edd300187bb4.json new file mode 100644 index 00000000..cb1a86b7 --- /dev/null +++ b/test-harness/src/testFixtures/resources/cassettes/braintrust/mappings/otel_v1_traces-775e27b5-8787-4981-93c4-edd300187bb4.json @@ -0,0 +1,39 @@ +{ + "id" : "775e27b5-8787-4981-93c4-edd300187bb4", + "name" : "otel_v1_traces", + "request" : { + "url" : "/otel/v1/traces", + "method" : "POST", + "headers" : { + "Content-Type" : { + "equalTo" : "application/x-protobuf" + } + }, + "bodyPatterns" : [ { + "binaryEqualTo" : "Cu4HCrIBCiAKDHNlcnZpY2UubmFtZRIQCg5icmFpbnRydXN0LWFwcAoiCg9zZXJ2aWNlLnZlcnNpb24SDwoNMC4zLjYtYzY3NjFlMgogChZ0ZWxlbWV0cnkuc2RrLmxhbmd1YWdlEgYKBGphdmEKJQoSdGVsZW1ldHJ5LnNkay5uYW1lEg8KDW9wZW50ZWxlbWV0cnkKIQoVdGVsZW1ldHJ5LnNkay52ZXJzaW9uEggKBjEuNTkuMBK2BgoRCg9icmFpbnRydXN0LWphdmESoAYKEL7f4AoHt0wTGl+ERUygUfkSCMcmJFBX8CddKg9DaGF0IENvbXBsZXRpb24wATkYvxZPqMisGEH5Q/toqMisGEqRAQoVYnJhaW50cnVzdC5pbnB1dF9qc29uEngKdlt7ImNvbnRlbnQiOiJZb3UgYXJlIGEgaGVscGZ1bCBhc3Npc3RhbnQiLCJyb2xlIjoic3lzdGVtIn0seyJjb250ZW50IjoiV2hhdCBpcyB0aGUgY2FwaXRhbCBvZiBGcmFuY2U/Iiwicm9sZSI6InVzZXIifV1KbwoSYnJhaW50cnVzdC5tZXRyaWNzElkKV3siY29tcGxldGlvbl90b2tlbnMiOjcsInByb21wdF90b2tlbnMiOjIzLCJ0b2tlbnMiOjMwLCJ0aW1lX3RvX2ZpcnN0X3Rva2VuIjowLjAwMTAwNTc1fUouChpicmFpbnRydXN0LnNwYW5fYXR0cmlidXRlcxIQCg57InR5cGUiOiJsbG0ifUoyChFicmFpbnRydXN0LnBhcmVudBIdChtwcm9qZWN0X25hbWU6amF2YS11bml0LXRlc3RKvAEKFmJyYWludHJ1c3Qub3V0cHV0X2pzb24SoQEKngFbeyJmaW5pc2hfcmVhc29uIjoic3RvcCIsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbCwibWVzc2FnZSI6eyJjb250ZW50IjoiVGhlIGNhcGl0YWwgb2YgRnJhbmNlIGlzIFBhcmlzLiIsInJlZnVzYWwiOm51bGwsInJvbGUiOiJhc3Npc3RhbnQiLCJ0b29sX2NhbGxzIjpbXX19XUqsAQoTYnJhaW50cnVzdC5tZXRhZGF0YRKUAQqRAXsicHJvdmlkZXIiOiJvcGVuYWkiLCJyZXF1ZXN0X3BhdGgiOiJjaGF0L2NvbXBsZXRpb25zIiwibW9kZWwiOiJncHQtNG8tbWluaSIsInJlcXVlc3RfYmFzZV91cmkiOiJodHRwOi8vbG9jYWxob3N0OjYxNDI5IiwicmVxdWVzdF9tZXRob2QiOiJQT1NUIn16AIUBAQEAAA==" + } ] + }, + "response" : { + "status" : 200, + "headers" : { + "X-Cache" : "Miss from cloudfront", + "x-amz-apigw-id" : "c6QifFidIAMEF7w=", + "vary" : "Origin", + "x-amzn-Remapped-content-length" : "0", + "X-Amz-Cf-Pop" : [ "SFO53-P8", "SFO53-P1" ], + "X-Amzn-Trace-Id" : "Root=1-69fa6142-2d5c109c4f9423490ca92e05;Parent=197ed29d6363de32;Sampled=0;Lineage=1:24be3d11:0", + "Date" : "Tue, 05 May 2026 21:29:38 GMT", + "Via" : "1.1 5cf315a7bafce190fcf84f55b9019bda.cloudfront.net (CloudFront), 1.1 ae36c784d97e7ce679dceb12ec90e722.cloudfront.net (CloudFront)", + "access-control-expose-headers" : "x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id", + "access-control-allow-credentials" : "true", + "x-bt-internal-trace-id" : "69fa61420000000022ba2aa82ecaaa3a", + "x-amzn-RequestId" : "24b1b62e-d73c-4c8c-ad85-4957d5f41c0f", + "X-Amz-Cf-Id" : "-Fge29U153EDMGDZ3a4cH1UBd7JvP7Grv5ylL-txcZovEFRNJaCTdg==", + "etag" : "W/\"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk\"", + "Content-Type" : "application/x-protobuf" + } + }, + "uuid" : "775e27b5-8787-4981-93c4-edd300187bb4", + "persistent" : true, + "insertionIndex" : 249 +} \ No newline at end of file diff --git a/test-harness/src/testFixtures/resources/cassettes/braintrust/mappings/otel_v1_traces-99b58611-0146-4ad1-b73e-bcccb277fe9d.json b/test-harness/src/testFixtures/resources/cassettes/braintrust/mappings/otel_v1_traces-99b58611-0146-4ad1-b73e-bcccb277fe9d.json new file mode 100644 index 00000000..bf8e275c --- /dev/null +++ b/test-harness/src/testFixtures/resources/cassettes/braintrust/mappings/otel_v1_traces-99b58611-0146-4ad1-b73e-bcccb277fe9d.json @@ -0,0 +1,39 @@ +{ + "id" : "99b58611-0146-4ad1-b73e-bcccb277fe9d", + "name" : "otel_v1_traces", + "request" : { + "url" : "/otel/v1/traces", + "method" : "POST", + "headers" : { + "Content-Type" : { + "equalTo" : "application/x-protobuf" + } + }, + "bodyPatterns" : [ { + "binaryEqualTo" : "Co8ICrIBCiAKDHNlcnZpY2UubmFtZRIQCg5icmFpbnRydXN0LWFwcAoiCg9zZXJ2aWNlLnZlcnNpb24SDwoNMC4zLjYtYzY3NjFlMgogChZ0ZWxlbWV0cnkuc2RrLmxhbmd1YWdlEgYKBGphdmEKJQoSdGVsZW1ldHJ5LnNkay5uYW1lEg8KDW9wZW50ZWxlbWV0cnkKIQoVdGVsZW1ldHJ5LnNkay52ZXJzaW9uEggKBjEuNTkuMBLXBgoRCg9icmFpbnRydXN0LWphdmESwQYKEMPm5lru/LMvN1yG04PPTO0SCEYll3pobquBKglyZXNwb25zZXMwATmoZ5jMp8isGEE7AyH8p8isGEpXChVicmFpbnRydXN0LmlucHV0X2pzb24SPgo8W3siY29udGVudCI6IldoYXQgaXMgdGhlIGNhcGl0YWwgb2YgRnJhbmNlPyIsInJvbGUiOiJ1c2VyIn1dSpABChJicmFpbnRydXN0Lm1ldHJpY3MSegp4eyJjb21wbGV0aW9uX3Rva2VucyI6OCwicHJvbXB0X3Rva2VucyI6MjMsInRva2VucyI6MzEsImNvbXBsZXRpb25fcmVhc29uaW5nX3Rva2VucyI6MCwidGltZV90b19maXJzdF90b2tlbiI6MC4wMDE2MTQxMjV9Si4KGmJyYWludHJ1c3Quc3Bhbl9hdHRyaWJ1dGVzEhAKDnsidHlwZSI6ImxsbSJ9SjIKEWJyYWludHJ1c3QucGFyZW50Eh0KG3Byb2plY3RfbmFtZTpqYXZhLXVuaXQtdGVzdEqDAgoWYnJhaW50cnVzdC5vdXRwdXRfanNvbhLoAQrlAVt7ImlkIjoibXNnXzBhZmVkNGZjYjA1MGIwZjMwMDY5ZmE2MTQwNjg1ODgxOTRhYmU3ZjE1MmE4ZTVkNmYyIiwiY29udGVudCI6W3siYW5ub3RhdGlvbnMiOltdLCJ0ZXh0IjoiVGhlIGNhcGl0YWwgb2YgRnJhbmNlIGlzIFBhcmlzLiIsInR5cGUiOiJvdXRwdXRfdGV4dCIsImxvZ3Byb2JzIjpbXX1dLCJyb2xlIjoiYXNzaXN0YW50Iiwic3RhdHVzIjoiY29tcGxldGVkIiwidHlwZSI6Im1lc3NhZ2UifV1KpQEKE2JyYWludHJ1c3QubWV0YWRhdGESjQEKigF7InByb3ZpZGVyIjoib3BlbmFpIiwicmVxdWVzdF9wYXRoIjoicmVzcG9uc2VzIiwibW9kZWwiOiJncHQtNG8tbWluaSIsInJlcXVlc3RfYmFzZV91cmkiOiJodHRwOi8vbG9jYWxob3N0OjYxNDI5IiwicmVxdWVzdF9tZXRob2QiOiJQT1NUIn16AIUBAQEAAA==" + } ] + }, + "response" : { + "status" : 200, + "headers" : { + "X-Cache" : "Miss from cloudfront", + "x-amz-apigw-id" : "c6QiLG_JoAMEquA=", + "vary" : "Origin", + "x-amzn-Remapped-content-length" : "0", + "X-Amz-Cf-Pop" : [ "SFO53-P8", "SFO53-P1" ], + "X-Amzn-Trace-Id" : "Root=1-69fa6140-5655cfb14a4e2e320eeb5deb;Parent=0aac73529b3346cd;Sampled=0;Lineage=1:24be3d11:0", + "Date" : "Tue, 05 May 2026 21:29:36 GMT", + "Via" : "1.1 dcd6c7d5f9e83c64e0ef0f23f0704dfa.cloudfront.net (CloudFront), 1.1 fdfef4416a2144ecb1660f70dad57e94.cloudfront.net (CloudFront)", + "access-control-expose-headers" : "x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id", + "access-control-allow-credentials" : "true", + "x-bt-internal-trace-id" : "69fa6140000000002af2bcb4d6da84fe", + "x-amzn-RequestId" : "96eef02e-d8fd-4172-97d2-14c433db5239", + "X-Amz-Cf-Id" : "jDLSMWZCCcxqLFEWDGhUM48mAEXJKFEmtrU1cQP6aIUpx_iZpUO-sA==", + "etag" : "W/\"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk\"", + "Content-Type" : "application/x-protobuf" + } + }, + "uuid" : "99b58611-0146-4ad1-b73e-bcccb277fe9d", + "persistent" : true, + "insertionIndex" : 251 +} \ No newline at end of file diff --git a/test-harness/src/testFixtures/resources/cassettes/braintrust/mappings/otel_v1_traces-b7f91205-9930-4248-834c-37e913a19a55.json b/test-harness/src/testFixtures/resources/cassettes/braintrust/mappings/otel_v1_traces-b7f91205-9930-4248-834c-37e913a19a55.json new file mode 100644 index 00000000..d2f6f8a3 --- /dev/null +++ b/test-harness/src/testFixtures/resources/cassettes/braintrust/mappings/otel_v1_traces-b7f91205-9930-4248-834c-37e913a19a55.json @@ -0,0 +1,39 @@ +{ + "id" : "b7f91205-9930-4248-834c-37e913a19a55", + "name" : "otel_v1_traces", + "request" : { + "url" : "/otel/v1/traces", + "method" : "POST", + "headers" : { + "Content-Type" : { + "equalTo" : "application/x-protobuf" + } + }, + "bodyPatterns" : [ { + "binaryEqualTo" : "Cs4HCrIBCiAKDHNlcnZpY2UubmFtZRIQCg5icmFpbnRydXN0LWFwcAoiCg9zZXJ2aWNlLnZlcnNpb24SDwoNMC4zLjYtYzY3NjFlMgogChZ0ZWxlbWV0cnkuc2RrLmxhbmd1YWdlEgYKBGphdmEKJQoSdGVsZW1ldHJ5LnNkay5uYW1lEg8KDW9wZW50ZWxlbWV0cnkKIQoVdGVsZW1ldHJ5LnNkay52ZXJzaW9uEggKBjEuNTkuMBKWBgoRCg9icmFpbnRydXN0LWphdmESgAYKEBQJSzr7AHluWugA4r22NVISCEdMCovnu8UtKg9DaGF0IENvbXBsZXRpb24wATm4IqTZpcisGEHTXh8jpsisGEqRAQoVYnJhaW50cnVzdC5pbnB1dF9qc29uEngKdlt7ImNvbnRlbnQiOiJZb3UgYXJlIGEgaGVscGZ1bCBhc3Npc3RhbnQiLCJyb2xlIjoic3lzdGVtIn0seyJjb250ZW50IjoiV2hhdCBpcyB0aGUgY2FwaXRhbCBvZiBGcmFuY2U/Iiwicm9sZSI6InVzZXIifV1KTgoSYnJhaW50cnVzdC5tZXRyaWNzEjgKNnsiY29tcGxldGlvbl90b2tlbnMiOjcsInByb21wdF90b2tlbnMiOjIzLCJ0b2tlbnMiOjMwfUouChpicmFpbnRydXN0LnNwYW5fYXR0cmlidXRlcxIQCg57InR5cGUiOiJsbG0ifUoyChFicmFpbnRydXN0LnBhcmVudBIdChtwcm9qZWN0X25hbWU6amF2YS11bml0LXRlc3RKvQEKFmJyYWludHJ1c3Qub3V0cHV0X2pzb24SogEKnwFbeyJpbmRleCI6MCwibWVzc2FnZSI6eyJyb2xlIjoiYXNzaXN0YW50IiwiY29udGVudCI6IlRoZSBjYXBpdGFsIG9mIEZyYW5jZSBpcyBQYXJpcy4iLCJyZWZ1c2FsIjpudWxsLCJhbm5vdGF0aW9ucyI6W119LCJsb2dwcm9icyI6bnVsbCwiZmluaXNoX3JlYXNvbiI6InN0b3AifV1KrAEKE2JyYWludHJ1c3QubWV0YWRhdGESlAEKkQF7InByb3ZpZGVyIjoib3BlbmFpIiwicmVxdWVzdF9wYXRoIjoiY2hhdC9jb21wbGV0aW9ucyIsIm1vZGVsIjoiZ3B0LTRvLW1pbmkiLCJyZXF1ZXN0X2Jhc2VfdXJpIjoiaHR0cDovL2xvY2FsaG9zdDo2MTQyOSIsInJlcXVlc3RfbWV0aG9kIjoiUE9TVCJ9egCFAQEBAAA=" + } ] + }, + "response" : { + "status" : 200, + "headers" : { + "X-Cache" : "Miss from cloudfront", + "x-amz-apigw-id" : "c6Qg8HrooAMEmIA=", + "vary" : "Origin", + "x-amzn-Remapped-content-length" : "0", + "X-Amz-Cf-Pop" : [ "SFO53-P8", "SFO53-P1" ], + "X-Amzn-Trace-Id" : "Root=1-69fa6138-2d09d9b9794ae47b2d991ed5;Parent=069a5502d6934f8f;Sampled=0;Lineage=1:24be3d11:0", + "Date" : "Tue, 05 May 2026 21:29:29 GMT", + "Via" : "1.1 4a4857880fe33b59bd5c244742e8fe4e.cloudfront.net (CloudFront), 1.1 a11ff1ad6e4c16fe95e18b435889304a.cloudfront.net (CloudFront)", + "access-control-expose-headers" : "x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id", + "access-control-allow-credentials" : "true", + "x-bt-internal-trace-id" : "69fa613800000000307b5dbf427e160f", + "x-amzn-RequestId" : "169aedf9-40cd-445c-a74c-6f6199e9aa31", + "X-Amz-Cf-Id" : "hVOdUis_FjP_0JQc12SHFGbig2l0gO4dmVBt_R0u8Mbkwm220n3mUA==", + "etag" : "W/\"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk\"", + "Content-Type" : "application/x-protobuf" + } + }, + "uuid" : "b7f91205-9930-4248-834c-37e913a19a55", + "persistent" : true, + "insertionIndex" : 256 +} \ No newline at end of file diff --git a/test-harness/src/testFixtures/resources/cassettes/braintrust/mappings/otel_v1_traces-da2cc964-ede4-435e-aa2a-2db24d5ecc0f.json b/test-harness/src/testFixtures/resources/cassettes/braintrust/mappings/otel_v1_traces-da2cc964-ede4-435e-aa2a-2db24d5ecc0f.json new file mode 100644 index 00000000..918c7ef4 --- /dev/null +++ b/test-harness/src/testFixtures/resources/cassettes/braintrust/mappings/otel_v1_traces-da2cc964-ede4-435e-aa2a-2db24d5ecc0f.json @@ -0,0 +1,39 @@ +{ + "id" : "da2cc964-ede4-435e-aa2a-2db24d5ecc0f", + "name" : "otel_v1_traces", + "request" : { + "url" : "/otel/v1/traces", + "method" : "POST", + "headers" : { + "Content-Type" : { + "equalTo" : "application/x-protobuf" + } + }, + "bodyPatterns" : [ { + "binaryEqualTo" : "CuUHCrIBCiAKDHNlcnZpY2UubmFtZRIQCg5icmFpbnRydXN0LWFwcAoiCg9zZXJ2aWNlLnZlcnNpb24SDwoNMC4zLjYtYzY3NjFlMgogChZ0ZWxlbWV0cnkuc2RrLmxhbmd1YWdlEgYKBGphdmEKJQoSdGVsZW1ldHJ5LnNkay5uYW1lEg8KDW9wZW50ZWxlbWV0cnkKIQoVdGVsZW1ldHJ5LnNkay52ZXJzaW9uEggKBjEuNTkuMBKtBgoRCg9icmFpbnRydXN0LWphdmESlwYKEOEez6/NNfZQ/uVXPeMwG4sSCEEI/AH150gBKglyZXNwb25zZXMwATmwOI41p8isGEFH6MFsp8isGEpqChVicmFpbnRydXN0LmlucHV0X2pzb24SUQpPW3siY29udGVudCI6IldoYXQgaXMgdGhlIGNhcGl0YWwgb2YgRnJhbmNlPyBSZXBseSBpbiBvbmUgd29yZC4iLCJyb2xlIjoidXNlciJ9XUpuChJicmFpbnRydXN0Lm1ldHJpY3MSWApWeyJjb21wbGV0aW9uX3Rva2VucyI6MiwicHJvbXB0X3Rva2VucyI6MjgsInRva2VucyI6MzAsImNvbXBsZXRpb25fcmVhc29uaW5nX3Rva2VucyI6MH1KLgoaYnJhaW50cnVzdC5zcGFuX2F0dHJpYnV0ZXMSEAoOeyJ0eXBlIjoibGxtIn1KMgoRYnJhaW50cnVzdC5wYXJlbnQSHQobcHJvamVjdF9uYW1lOmphdmEtdW5pdC10ZXN0SukBChZicmFpbnRydXN0Lm91dHB1dF9qc29uEs4BCssBW3siaWQiOiJtc2dfMDlmMTNiYWU2ZjM2NDJlNDAwNjlmYTYxM2RmYzc0ODE5NDk5MTI3ZWI3NGQxNTFkYzMiLCJ0eXBlIjoibWVzc2FnZSIsInN0YXR1cyI6ImNvbXBsZXRlZCIsImNvbnRlbnQiOlt7InR5cGUiOiJvdXRwdXRfdGV4dCIsImFubm90YXRpb25zIjpbXSwibG9ncHJvYnMiOltdLCJ0ZXh0IjoiUGFyaXMifV0sInJvbGUiOiJhc3Npc3RhbnQifV1KpQEKE2JyYWludHJ1c3QubWV0YWRhdGESjQEKigF7InByb3ZpZGVyIjoib3BlbmFpIiwicmVxdWVzdF9wYXRoIjoicmVzcG9uc2VzIiwibW9kZWwiOiJncHQtNG8tbWluaSIsInJlcXVlc3RfYmFzZV91cmkiOiJodHRwOi8vbG9jYWxob3N0OjYxNDI5IiwicmVxdWVzdF9tZXRob2QiOiJQT1NUIn16AIUBAQEAAA==" + } ] + }, + "response" : { + "status" : 200, + "headers" : { + "X-Cache" : "Miss from cloudfront", + "x-amz-apigw-id" : "c6QhzHs1oAMELrQ=", + "vary" : "Origin", + "x-amzn-Remapped-content-length" : "0", + "X-Amz-Cf-Pop" : [ "SFO53-P8", "SFO53-P1" ], + "X-Amzn-Trace-Id" : "Root=1-69fa613e-1751732f7f6ba19b56f99024;Parent=618472f86815a9a8;Sampled=0;Lineage=1:24be3d11:0", + "Date" : "Tue, 05 May 2026 21:29:34 GMT", + "Via" : "1.1 0d596bf21dbb8ca0d865a97c7e7bb19c.cloudfront.net (CloudFront), 1.1 459b85c545909b647abc5dea4320a0da.cloudfront.net (CloudFront)", + "access-control-expose-headers" : "x-bt-cursor,x-bt-found-existing,x-bt-query-plan,x-bt-api-duration-ms,x-bt-brainstore-duration-ms,x-bt-internal-trace-id", + "access-control-allow-credentials" : "true", + "x-bt-internal-trace-id" : "69fa613e000000005609049842771ce2", + "x-amzn-RequestId" : "52b1215e-6bd4-4cb9-954f-326136df2431", + "X-Amz-Cf-Id" : "Mi2Y0lACQWEgcQyUhLrUkCEv-SY0b-_5cElQjs9ypj-SQEWIENueDA==", + "etag" : "W/\"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk\"", + "Content-Type" : "application/x-protobuf" + } + }, + "uuid" : "da2cc964-ede4-435e-aa2a-2db24d5ecc0f", + "persistent" : true, + "insertionIndex" : 253 +} \ No newline at end of file diff --git a/test-harness/src/testFixtures/resources/cassettes/openai/__files/chat_completions-0b8f4614-7306-4447-b4bf-c8c023c61619.txt b/test-harness/src/testFixtures/resources/cassettes/openai/__files/chat_completions-0b8f4614-7306-4447-b4bf-c8c023c61619.txt new file mode 100644 index 00000000..53ed41fe --- /dev/null +++ b/test-harness/src/testFixtures/resources/cassettes/openai/__files/chat_completions-0b8f4614-7306-4447-b4bf-c8c023c61619.txt @@ -0,0 +1,22 @@ +data: {"id":"chatcmpl-DcHcXuYMAxmkQupFOTMwFIhHldPDl","object":"chat.completion.chunk","created":1778016569,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_97c29773b5","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"BKWdF62sT"} + +data: {"id":"chatcmpl-DcHcXuYMAxmkQupFOTMwFIhHldPDl","object":"chat.completion.chunk","created":1778016569,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_97c29773b5","choices":[{"index":0,"delta":{"content":"The"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"ealtys5g"} + +data: {"id":"chatcmpl-DcHcXuYMAxmkQupFOTMwFIhHldPDl","object":"chat.completion.chunk","created":1778016569,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_97c29773b5","choices":[{"index":0,"delta":{"content":" capital"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"IPv"} + +data: {"id":"chatcmpl-DcHcXuYMAxmkQupFOTMwFIhHldPDl","object":"chat.completion.chunk","created":1778016569,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_97c29773b5","choices":[{"index":0,"delta":{"content":" of"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"5nk8XdkW"} + +data: {"id":"chatcmpl-DcHcXuYMAxmkQupFOTMwFIhHldPDl","object":"chat.completion.chunk","created":1778016569,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_97c29773b5","choices":[{"index":0,"delta":{"content":" France"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"T2ye"} + +data: {"id":"chatcmpl-DcHcXuYMAxmkQupFOTMwFIhHldPDl","object":"chat.completion.chunk","created":1778016569,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_97c29773b5","choices":[{"index":0,"delta":{"content":" is"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"h2JlHZV8"} + +data: {"id":"chatcmpl-DcHcXuYMAxmkQupFOTMwFIhHldPDl","object":"chat.completion.chunk","created":1778016569,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_97c29773b5","choices":[{"index":0,"delta":{"content":" Paris"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Hq1Zo"} + +data: {"id":"chatcmpl-DcHcXuYMAxmkQupFOTMwFIhHldPDl","object":"chat.completion.chunk","created":1778016569,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_97c29773b5","choices":[{"index":0,"delta":{"content":"."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"0R6JBPlaHK"} + +data: {"id":"chatcmpl-DcHcXuYMAxmkQupFOTMwFIhHldPDl","object":"chat.completion.chunk","created":1778016569,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_97c29773b5","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"X4heZ"} + +data: {"id":"chatcmpl-DcHcXuYMAxmkQupFOTMwFIhHldPDl","object":"chat.completion.chunk","created":1778016569,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_97c29773b5","choices":[],"usage":{"prompt_tokens":23,"completion_tokens":7,"total_tokens":30,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"nCvFBZJdYbD"} + +data: [DONE] + diff --git a/test-harness/src/testFixtures/resources/cassettes/openai/__files/chat_completions-5fddb64e-58c5-4dd3-8696-5ff07db32475.json b/test-harness/src/testFixtures/resources/cassettes/openai/__files/chat_completions-5fddb64e-58c5-4dd3-8696-5ff07db32475.json new file mode 100644 index 00000000..a3746e69 --- /dev/null +++ b/test-harness/src/testFixtures/resources/cassettes/openai/__files/chat_completions-5fddb64e-58c5-4dd3-8696-5ff07db32475.json @@ -0,0 +1,36 @@ +{ + "id": "chatcmpl-DcHcc9vhUm4JKDrO5mYcjLBvNQ7MS", + "object": "chat.completion", + "created": 1778016574, + "model": "gpt-4o-mini-2024-07-18", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "The capital of France is Paris.", + "refusal": null, + "annotations": [] + }, + "logprobs": null, + "finish_reason": "stop" + } + ], + "usage": { + "prompt_tokens": 23, + "completion_tokens": 7, + "total_tokens": 30, + "prompt_tokens_details": { + "cached_tokens": 0, + "audio_tokens": 0 + }, + "completion_tokens_details": { + "reasoning_tokens": 0, + "audio_tokens": 0, + "accepted_prediction_tokens": 0, + "rejected_prediction_tokens": 0 + } + }, + "service_tier": "default", + "system_fingerprint": "fp_97c29773b5" +} diff --git a/test-harness/src/testFixtures/resources/cassettes/openai/__files/chat_completions-6290e82f-d374-486e-8d4a-b939c86682d0.json b/test-harness/src/testFixtures/resources/cassettes/openai/__files/chat_completions-6290e82f-d374-486e-8d4a-b939c86682d0.json new file mode 100644 index 00000000..e93accc6 --- /dev/null +++ b/test-harness/src/testFixtures/resources/cassettes/openai/__files/chat_completions-6290e82f-d374-486e-8d4a-b939c86682d0.json @@ -0,0 +1,36 @@ +{ + "id": "chatcmpl-DcHcW4G4o7XnHHpUjRyIk8wNw3uTk", + "object": "chat.completion", + "created": 1778016568, + "model": "gpt-4o-mini-2024-07-18", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "The capital of France is Paris.", + "refusal": null, + "annotations": [] + }, + "logprobs": null, + "finish_reason": "stop" + } + ], + "usage": { + "prompt_tokens": 23, + "completion_tokens": 7, + "total_tokens": 30, + "prompt_tokens_details": { + "cached_tokens": 0, + "audio_tokens": 0 + }, + "completion_tokens_details": { + "reasoning_tokens": 0, + "audio_tokens": 0, + "accepted_prediction_tokens": 0, + "rejected_prediction_tokens": 0 + } + }, + "service_tier": "default", + "system_fingerprint": "fp_97c29773b5" +} diff --git a/test-harness/src/testFixtures/resources/cassettes/openai/__files/chat_completions-6f2f5093-383e-4499-b2fa-d3d52cbfa3ab.txt b/test-harness/src/testFixtures/resources/cassettes/openai/__files/chat_completions-6f2f5093-383e-4499-b2fa-d3d52cbfa3ab.txt new file mode 100644 index 00000000..de6318d1 --- /dev/null +++ b/test-harness/src/testFixtures/resources/cassettes/openai/__files/chat_completions-6f2f5093-383e-4499-b2fa-d3d52cbfa3ab.txt @@ -0,0 +1,22 @@ +data: {"id":"chatcmpl-DcHcgaLm0pW90Vu2Xl81UUFxMlXCQ","object":"chat.completion.chunk","created":1778016578,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_97c29773b5","choices":[{"index":0,"delta":{"role":"assistant","content":"","refusal":null},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"mTav7KquJ"} + +data: {"id":"chatcmpl-DcHcgaLm0pW90Vu2Xl81UUFxMlXCQ","object":"chat.completion.chunk","created":1778016578,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_97c29773b5","choices":[{"index":0,"delta":{"content":"The"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Owioev3R"} + +data: {"id":"chatcmpl-DcHcgaLm0pW90Vu2Xl81UUFxMlXCQ","object":"chat.completion.chunk","created":1778016578,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_97c29773b5","choices":[{"index":0,"delta":{"content":" capital"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"UIW"} + +data: {"id":"chatcmpl-DcHcgaLm0pW90Vu2Xl81UUFxMlXCQ","object":"chat.completion.chunk","created":1778016578,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_97c29773b5","choices":[{"index":0,"delta":{"content":" of"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"UEALnQGF"} + +data: {"id":"chatcmpl-DcHcgaLm0pW90Vu2Xl81UUFxMlXCQ","object":"chat.completion.chunk","created":1778016578,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_97c29773b5","choices":[{"index":0,"delta":{"content":" France"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"9dU4"} + +data: {"id":"chatcmpl-DcHcgaLm0pW90Vu2Xl81UUFxMlXCQ","object":"chat.completion.chunk","created":1778016578,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_97c29773b5","choices":[{"index":0,"delta":{"content":" is"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"WAYUuDLQ"} + +data: {"id":"chatcmpl-DcHcgaLm0pW90Vu2Xl81UUFxMlXCQ","object":"chat.completion.chunk","created":1778016578,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_97c29773b5","choices":[{"index":0,"delta":{"content":" Paris"},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"uGLo5"} + +data: {"id":"chatcmpl-DcHcgaLm0pW90Vu2Xl81UUFxMlXCQ","object":"chat.completion.chunk","created":1778016578,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_97c29773b5","choices":[{"index":0,"delta":{"content":"."},"logprobs":null,"finish_reason":null}],"usage":null,"obfuscation":"Cnm6kdrqF0"} + +data: {"id":"chatcmpl-DcHcgaLm0pW90Vu2Xl81UUFxMlXCQ","object":"chat.completion.chunk","created":1778016578,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_97c29773b5","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null,"obfuscation":"256rO"} + +data: {"id":"chatcmpl-DcHcgaLm0pW90Vu2Xl81UUFxMlXCQ","object":"chat.completion.chunk","created":1778016578,"model":"gpt-4o-mini-2024-07-18","service_tier":"default","system_fingerprint":"fp_97c29773b5","choices":[],"usage":{"prompt_tokens":23,"completion_tokens":7,"total_tokens":30,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}},"obfuscation":"cYYwSLnd5si"} + +data: [DONE] + diff --git a/test-harness/src/testFixtures/resources/cassettes/openai/__files/responses-5fe80689-c90a-48e4-9d9e-dc0bd0eeb6d1.json b/test-harness/src/testFixtures/resources/cassettes/openai/__files/responses-5fe80689-c90a-48e4-9d9e-dc0bd0eeb6d1.json new file mode 100644 index 00000000..b3cd82f8 --- /dev/null +++ b/test-harness/src/testFixtures/resources/cassettes/openai/__files/responses-5fe80689-c90a-48e4-9d9e-dc0bd0eeb6d1.json @@ -0,0 +1,77 @@ +{ + "id": "resp_036520e2169efa740069fa613a97448195a702e60d24895835", + "object": "response", + "created_at": 1778016570, + "status": "completed", + "background": false, + "billing": { + "payer": "developer" + }, + "completed_at": 1778016572, + "error": null, + "frequency_penalty": 0.0, + "incomplete_details": null, + "instructions": null, + "max_output_tokens": null, + "max_tool_calls": null, + "model": "o4-mini-2025-04-16", + "moderation": null, + "output": [ + { + "id": "rs_036520e2169efa740069fa613b93a48195b38f68a877524fd2", + "type": "reasoning", + "summary": [] + }, + { + "id": "msg_036520e2169efa740069fa613c7630819582cc124c4559c7e0", + "type": "message", + "status": "completed", + "content": [ + { + "type": "output_text", + "annotations": [], + "logprobs": [], + "text": "Paris" + } + ], + "role": "assistant" + } + ], + "parallel_tool_calls": true, + "presence_penalty": 0.0, + "previous_response_id": null, + "prompt_cache_key": null, + "prompt_cache_retention": "in_memory", + "reasoning": { + "effort": "low", + "summary": "detailed" + }, + "safety_identifier": null, + "service_tier": "default", + "store": true, + "temperature": 1.0, + "text": { + "format": { + "type": "text" + }, + "verbosity": "medium" + }, + "tool_choice": "auto", + "tools": [], + "top_logprobs": 0, + "top_p": 1.0, + "truncation": "disabled", + "usage": { + "input_tokens": 18, + "input_tokens_details": { + "cached_tokens": 0 + }, + "output_tokens": 38, + "output_tokens_details": { + "reasoning_tokens": 0 + }, + "total_tokens": 56 + }, + "user": null, + "metadata": {} +} \ No newline at end of file diff --git a/test-harness/src/testFixtures/resources/cassettes/openai/__files/responses-9798f9bb-c5d0-4c0a-b211-d0c8fa441c00.json b/test-harness/src/testFixtures/resources/cassettes/openai/__files/responses-9798f9bb-c5d0-4c0a-b211-d0c8fa441c00.json new file mode 100644 index 00000000..ee2086ea --- /dev/null +++ b/test-harness/src/testFixtures/resources/cassettes/openai/__files/responses-9798f9bb-c5d0-4c0a-b211-d0c8fa441c00.json @@ -0,0 +1,72 @@ +{ + "id": "resp_09f13bae6f3642e40069fa613d80c08194b02612f7b8c4d20e", + "object": "response", + "created_at": 1778016573, + "status": "completed", + "background": false, + "billing": { + "payer": "developer" + }, + "completed_at": 1778016574, + "error": null, + "frequency_penalty": 0.0, + "incomplete_details": null, + "instructions": "You are a helpful assistant", + "max_output_tokens": null, + "max_tool_calls": null, + "model": "gpt-4o-mini-2024-07-18", + "moderation": null, + "output": [ + { + "id": "msg_09f13bae6f3642e40069fa613dfc74819499127eb74d151dc3", + "type": "message", + "status": "completed", + "content": [ + { + "type": "output_text", + "annotations": [], + "logprobs": [], + "text": "Paris" + } + ], + "role": "assistant" + } + ], + "parallel_tool_calls": true, + "presence_penalty": 0.0, + "previous_response_id": null, + "prompt_cache_key": null, + "prompt_cache_retention": "in_memory", + "reasoning": { + "effort": null, + "summary": null + }, + "safety_identifier": null, + "service_tier": "default", + "store": true, + "temperature": 1.0, + "text": { + "format": { + "type": "text" + }, + "verbosity": "medium" + }, + "tool_choice": "auto", + "tools": [], + "top_logprobs": 0, + "top_p": 1.0, + "truncation": "disabled", + "usage": { + "input_tokens": 28, + "input_tokens_details": { + "cached_tokens": 0 + }, + "output_tokens": 2, + "output_tokens_details": { + "reasoning_tokens": 0 + }, + "total_tokens": 30 + }, + "user": null, + "metadata": {} +} \ No newline at end of file diff --git a/test-harness/src/testFixtures/resources/cassettes/openai/__files/responses-c56562c2-4ea1-44f1-9ee5-d61b3fcd4e5b.txt b/test-harness/src/testFixtures/resources/cassettes/openai/__files/responses-c56562c2-4ea1-44f1-9ee5-d61b3fcd4e5b.txt new file mode 100644 index 00000000..45a17a71 --- /dev/null +++ b/test-harness/src/testFixtures/resources/cassettes/openai/__files/responses-c56562c2-4ea1-44f1-9ee5-d61b3fcd4e5b.txt @@ -0,0 +1,45 @@ +event: response.created +data: {"type":"response.created","response":{"id":"resp_0afed4fcb050b0f30069fa614004f081949b044e153b828250","object":"response","created_at":1778016576,"status":"in_progress","background":false,"completed_at":null,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":"You are a helpful assistant","max_output_tokens":null,"max_tool_calls":null,"model":"gpt-4o-mini-2024-07-18","moderation":null,"output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt_cache_key":null,"prompt_cache_retention":"in_memory","reasoning":{"effort":null,"summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null,"metadata":{}},"sequence_number":0} + +event: response.in_progress +data: {"type":"response.in_progress","response":{"id":"resp_0afed4fcb050b0f30069fa614004f081949b044e153b828250","object":"response","created_at":1778016576,"status":"in_progress","background":false,"completed_at":null,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":"You are a helpful assistant","max_output_tokens":null,"max_tool_calls":null,"model":"gpt-4o-mini-2024-07-18","moderation":null,"output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt_cache_key":null,"prompt_cache_retention":"in_memory","reasoning":{"effort":null,"summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null,"metadata":{}},"sequence_number":1} + +event: response.output_item.added +data: {"type":"response.output_item.added","item":{"id":"msg_0afed4fcb050b0f30069fa614068588194abe7f152a8e5d6f2","type":"message","status":"in_progress","content":[],"role":"assistant"},"output_index":0,"sequence_number":2} + +event: response.content_part.added +data: {"type":"response.content_part.added","content_index":0,"item_id":"msg_0afed4fcb050b0f30069fa614068588194abe7f152a8e5d6f2","output_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":""},"sequence_number":3} + +event: response.output_text.delta +data: {"type":"response.output_text.delta","content_index":0,"delta":"The","item_id":"msg_0afed4fcb050b0f30069fa614068588194abe7f152a8e5d6f2","logprobs":[],"obfuscation":"lEzDVp5Mv7IWk","output_index":0,"sequence_number":4} + +event: response.output_text.delta +data: {"type":"response.output_text.delta","content_index":0,"delta":" capital","item_id":"msg_0afed4fcb050b0f30069fa614068588194abe7f152a8e5d6f2","logprobs":[],"obfuscation":"Xi4bc0RQ","output_index":0,"sequence_number":5} + +event: response.output_text.delta +data: {"type":"response.output_text.delta","content_index":0,"delta":" of","item_id":"msg_0afed4fcb050b0f30069fa614068588194abe7f152a8e5d6f2","logprobs":[],"obfuscation":"kgLY3Giw7pK4o","output_index":0,"sequence_number":6} + +event: response.output_text.delta +data: {"type":"response.output_text.delta","content_index":0,"delta":" France","item_id":"msg_0afed4fcb050b0f30069fa614068588194abe7f152a8e5d6f2","logprobs":[],"obfuscation":"2kPrFsypJ","output_index":0,"sequence_number":7} + +event: response.output_text.delta +data: {"type":"response.output_text.delta","content_index":0,"delta":" is","item_id":"msg_0afed4fcb050b0f30069fa614068588194abe7f152a8e5d6f2","logprobs":[],"obfuscation":"vIcceBhPZ8JFx","output_index":0,"sequence_number":8} + +event: response.output_text.delta +data: {"type":"response.output_text.delta","content_index":0,"delta":" Paris","item_id":"msg_0afed4fcb050b0f30069fa614068588194abe7f152a8e5d6f2","logprobs":[],"obfuscation":"KXZqgLrX4b","output_index":0,"sequence_number":9} + +event: response.output_text.delta +data: {"type":"response.output_text.delta","content_index":0,"delta":".","item_id":"msg_0afed4fcb050b0f30069fa614068588194abe7f152a8e5d6f2","logprobs":[],"obfuscation":"B02ree6fcIkpgtV","output_index":0,"sequence_number":10} + +event: response.output_text.done +data: {"type":"response.output_text.done","content_index":0,"item_id":"msg_0afed4fcb050b0f30069fa614068588194abe7f152a8e5d6f2","logprobs":[],"output_index":0,"sequence_number":11,"text":"The capital of France is Paris."} + +event: response.content_part.done +data: {"type":"response.content_part.done","content_index":0,"item_id":"msg_0afed4fcb050b0f30069fa614068588194abe7f152a8e5d6f2","output_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":"The capital of France is Paris."},"sequence_number":12} + +event: response.output_item.done +data: {"type":"response.output_item.done","item":{"id":"msg_0afed4fcb050b0f30069fa614068588194abe7f152a8e5d6f2","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"The capital of France is Paris."}],"role":"assistant"},"output_index":0,"sequence_number":13} + +event: response.completed +data: {"type":"response.completed","response":{"id":"resp_0afed4fcb050b0f30069fa614004f081949b044e153b828250","object":"response","created_at":1778016576,"status":"completed","background":false,"completed_at":1778016576,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":"You are a helpful assistant","max_output_tokens":null,"max_tool_calls":null,"model":"gpt-4o-mini-2024-07-18","moderation":null,"output":[{"id":"msg_0afed4fcb050b0f30069fa614068588194abe7f152a8e5d6f2","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"The capital of France is Paris."}],"role":"assistant"}],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt_cache_key":null,"prompt_cache_retention":"in_memory","reasoning":{"effort":null,"summary":null},"safety_identifier":null,"service_tier":"default","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":{"input_tokens":23,"input_tokens_details":{"cached_tokens":0},"output_tokens":8,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":31},"user":null,"metadata":{}},"sequence_number":14} + diff --git a/test-harness/src/testFixtures/resources/cassettes/openai/__files/responses-dcbbcd6a-bd6e-40c2-b73d-0361e3ab941c.txt b/test-harness/src/testFixtures/resources/cassettes/openai/__files/responses-dcbbcd6a-bd6e-40c2-b73d-0361e3ab941c.txt new file mode 100644 index 00000000..daa417fb --- /dev/null +++ b/test-harness/src/testFixtures/resources/cassettes/openai/__files/responses-dcbbcd6a-bd6e-40c2-b73d-0361e3ab941c.txt @@ -0,0 +1,45 @@ +event: response.created +data: {"type":"response.created","response":{"id":"resp_082d8f91fbd6e3180069fa6141298c81968a74ad806bb9248a","object":"response","created_at":1778016577,"status":"in_progress","background":false,"completed_at":null,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":"You are a helpful assistant","max_output_tokens":null,"max_tool_calls":null,"model":"gpt-4o-mini-2024-07-18","moderation":null,"output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt_cache_key":null,"prompt_cache_retention":"in_memory","reasoning":{"effort":null,"summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null,"metadata":{}},"sequence_number":0} + +event: response.in_progress +data: {"type":"response.in_progress","response":{"id":"resp_082d8f91fbd6e3180069fa6141298c81968a74ad806bb9248a","object":"response","created_at":1778016577,"status":"in_progress","background":false,"completed_at":null,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":"You are a helpful assistant","max_output_tokens":null,"max_tool_calls":null,"model":"gpt-4o-mini-2024-07-18","moderation":null,"output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt_cache_key":null,"prompt_cache_retention":"in_memory","reasoning":{"effort":null,"summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null,"metadata":{}},"sequence_number":1} + +event: response.output_item.added +data: {"type":"response.output_item.added","item":{"id":"msg_082d8f91fbd6e3180069fa614183488196be027f8edc2f3b35","type":"message","status":"in_progress","content":[],"role":"assistant"},"output_index":0,"sequence_number":2} + +event: response.content_part.added +data: {"type":"response.content_part.added","content_index":0,"item_id":"msg_082d8f91fbd6e3180069fa614183488196be027f8edc2f3b35","output_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":""},"sequence_number":3} + +event: response.output_text.delta +data: {"type":"response.output_text.delta","content_index":0,"delta":"The","item_id":"msg_082d8f91fbd6e3180069fa614183488196be027f8edc2f3b35","logprobs":[],"obfuscation":"6OVmjvj1yBnvP","output_index":0,"sequence_number":4} + +event: response.output_text.delta +data: {"type":"response.output_text.delta","content_index":0,"delta":" capital","item_id":"msg_082d8f91fbd6e3180069fa614183488196be027f8edc2f3b35","logprobs":[],"obfuscation":"sbSMLKAM","output_index":0,"sequence_number":5} + +event: response.output_text.delta +data: {"type":"response.output_text.delta","content_index":0,"delta":" of","item_id":"msg_082d8f91fbd6e3180069fa614183488196be027f8edc2f3b35","logprobs":[],"obfuscation":"gkI9jnR2w9kL7","output_index":0,"sequence_number":6} + +event: response.output_text.delta +data: {"type":"response.output_text.delta","content_index":0,"delta":" France","item_id":"msg_082d8f91fbd6e3180069fa614183488196be027f8edc2f3b35","logprobs":[],"obfuscation":"IURAy0UID","output_index":0,"sequence_number":7} + +event: response.output_text.delta +data: {"type":"response.output_text.delta","content_index":0,"delta":" is","item_id":"msg_082d8f91fbd6e3180069fa614183488196be027f8edc2f3b35","logprobs":[],"obfuscation":"0wBjvcHDcQQcS","output_index":0,"sequence_number":8} + +event: response.output_text.delta +data: {"type":"response.output_text.delta","content_index":0,"delta":" Paris","item_id":"msg_082d8f91fbd6e3180069fa614183488196be027f8edc2f3b35","logprobs":[],"obfuscation":"tjwj9OIXUg","output_index":0,"sequence_number":9} + +event: response.output_text.delta +data: {"type":"response.output_text.delta","content_index":0,"delta":".","item_id":"msg_082d8f91fbd6e3180069fa614183488196be027f8edc2f3b35","logprobs":[],"obfuscation":"RqJMvVosZHdS1QP","output_index":0,"sequence_number":10} + +event: response.output_text.done +data: {"type":"response.output_text.done","content_index":0,"item_id":"msg_082d8f91fbd6e3180069fa614183488196be027f8edc2f3b35","logprobs":[],"output_index":0,"sequence_number":11,"text":"The capital of France is Paris."} + +event: response.content_part.done +data: {"type":"response.content_part.done","content_index":0,"item_id":"msg_082d8f91fbd6e3180069fa614183488196be027f8edc2f3b35","output_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":"The capital of France is Paris."},"sequence_number":12} + +event: response.output_item.done +data: {"type":"response.output_item.done","item":{"id":"msg_082d8f91fbd6e3180069fa614183488196be027f8edc2f3b35","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"The capital of France is Paris."}],"role":"assistant"},"output_index":0,"sequence_number":13} + +event: response.completed +data: {"type":"response.completed","response":{"id":"resp_082d8f91fbd6e3180069fa6141298c81968a74ad806bb9248a","object":"response","created_at":1778016577,"status":"completed","background":false,"completed_at":1778016577,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":"You are a helpful assistant","max_output_tokens":null,"max_tool_calls":null,"model":"gpt-4o-mini-2024-07-18","moderation":null,"output":[{"id":"msg_082d8f91fbd6e3180069fa614183488196be027f8edc2f3b35","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"The capital of France is Paris."}],"role":"assistant"}],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt_cache_key":null,"prompt_cache_retention":"in_memory","reasoning":{"effort":null,"summary":null},"safety_identifier":null,"service_tier":"default","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":{"input_tokens":23,"input_tokens_details":{"cached_tokens":0},"output_tokens":8,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":31},"user":null,"metadata":{}},"sequence_number":14} + diff --git a/test-harness/src/testFixtures/resources/cassettes/openai/mappings/chat_completions-0b8f4614-7306-4447-b4bf-c8c023c61619.json b/test-harness/src/testFixtures/resources/cassettes/openai/mappings/chat_completions-0b8f4614-7306-4447-b4bf-c8c023c61619.json new file mode 100644 index 00000000..cc2403a8 --- /dev/null +++ b/test-harness/src/testFixtures/resources/cassettes/openai/mappings/chat_completions-0b8f4614-7306-4447-b4bf-c8c023c61619.json @@ -0,0 +1,52 @@ +{ + "id" : "0b8f4614-7306-4447-b4bf-c8c023c61619", + "name" : "chat_completions", + "request" : { + "url" : "/chat/completions", + "method" : "POST", + "headers" : { + "Content-Type" : { + "equalTo" : "application/json" + } + }, + "bodyPatterns" : [ { + "equalToJson" : "{\"messages\":[{\"content\":\"You are a helpful assistant\",\"role\":\"system\"},{\"content\":\"What is the capital of France?\",\"role\":\"user\"}],\"model\":\"gpt-4o-mini\",\"stream_options\":{\"include_usage\":true},\"temperature\":0.0,\"stream\":true}", + "ignoreArrayOrder" : true, + "ignoreExtraElements" : false + } ] + }, + "response" : { + "status" : 200, + "bodyFileName" : "chat_completions-0b8f4614-7306-4447-b4bf-c8c023c61619.txt", + "headers" : { + "x-request-id" : "req_eb5e5ffd6c444eb9b77c8d1d5b80d981", + "x-ratelimit-limit-tokens" : "150000000", + "openai-organization" : "braintrust-data", + "Server" : "cloudflare", + "CF-Ray" : "9f72d746bff8f3f6-SJC", + "X-Content-Type-Options" : "nosniff", + "x-ratelimit-reset-requests" : "2ms", + "x-ratelimit-remaining-tokens" : "149999982", + "x-openai-proxy-wasm" : "v0.1", + "x-ratelimit-remaining-requests" : "29999", + "Date" : "Tue, 05 May 2026 21:29:29 GMT", + "x-ratelimit-reset-tokens" : "0s", + "access-control-expose-headers" : "X-Request-ID", + "set-cookie" : "__cf_bm=T5LJpbSHOr0A.bPGaAKOMPgo7Vsd0SylHIc4Nmu_DOE-1778016569.3999074-1.0.1.1-QP7j4KbpMA4ATXyhu4lYSR2dzct8QIYpBVmewEV_UCzEI6NeaMcE.MxY.8uJmhmZlangP.pXE2QVAv7QlsGPlTD8acsRqLRFpzJDOu.PxHeTgfNBTvxKf4daHvitWLjm; HttpOnly; Secure; Path=/; Domain=api.openai.com; Expires=Tue, 05 May 2026 21:59:29 GMT", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", + "CF-Cache-Status" : "DYNAMIC", + "x-ratelimit-limit-requests" : "30000", + "openai-version" : "2020-10-01", + "openai-processing-ms" : "227", + "alt-svc" : "h3=\":443\"; ma=86400", + "openai-project" : "proj_vsCSXafhhByzWOThMrJcZiw9", + "Content-Type" : "text/event-stream; charset=utf-8" + } + }, + "uuid" : "0b8f4614-7306-4447-b4bf-c8c023c61619", + "persistent" : true, + "scenarioName" : "scenario-1-chat-completions", + "requiredScenarioState" : "Started", + "newScenarioState" : "scenario-1-chat-completions-2", + "insertionIndex" : 55 +} \ No newline at end of file diff --git a/test-harness/src/testFixtures/resources/cassettes/openai/mappings/chat_completions-5fddb64e-58c5-4dd3-8696-5ff07db32475.json b/test-harness/src/testFixtures/resources/cassettes/openai/mappings/chat_completions-5fddb64e-58c5-4dd3-8696-5ff07db32475.json new file mode 100644 index 00000000..e96160f3 --- /dev/null +++ b/test-harness/src/testFixtures/resources/cassettes/openai/mappings/chat_completions-5fddb64e-58c5-4dd3-8696-5ff07db32475.json @@ -0,0 +1,51 @@ +{ + "id" : "5fddb64e-58c5-4dd3-8696-5ff07db32475", + "name" : "chat_completions", + "request" : { + "url" : "/chat/completions", + "method" : "POST", + "headers" : { + "Content-Type" : { + "equalTo" : "application/json" + } + }, + "bodyPatterns" : [ { + "equalToJson" : "{\"messages\":[{\"content\":\"You are a helpful assistant\",\"role\":\"system\"},{\"content\":\"What is the capital of France?\",\"role\":\"user\"}],\"model\":\"gpt-4o-mini\",\"temperature\":0.0}", + "ignoreArrayOrder" : true, + "ignoreExtraElements" : false + } ] + }, + "response" : { + "status" : 200, + "bodyFileName" : "chat_completions-5fddb64e-58c5-4dd3-8696-5ff07db32475.json", + "headers" : { + "x-request-id" : "req_7ed44f86908a4dda9ea8c2c7d18edee7", + "x-ratelimit-limit-tokens" : "150000000", + "openai-organization" : "braintrust-data", + "Server" : "cloudflare", + "CF-Ray" : "9f72d7684a31e9e7-SJC", + "X-Content-Type-Options" : "nosniff", + "x-ratelimit-reset-requests" : "2ms", + "x-ratelimit-remaining-tokens" : "149999980", + "x-openai-proxy-wasm" : "v0.1", + "x-ratelimit-remaining-requests" : "29999", + "Date" : "Tue, 05 May 2026 21:29:35 GMT", + "x-ratelimit-reset-tokens" : "0s", + "access-control-expose-headers" : "X-Request-ID", + "set-cookie" : "__cf_bm=mUk0msKJfL61BO3StZLhdJS0b6LnBvPrgHrHHSIu5uI-1778016574.768675-1.0.1.1-Vb4VOfhgujcRgHXFpMtQetDVtQY9hFeodYxWcm7VJsGV6UGx619mWHUcAEfqoGy59NRzhy6Mj5P4TuDXp.HERDQMwX7A1FFcrnUfMkMZCwJjPbnmDtBbiY13ss36WVN7; HttpOnly; Secure; Path=/; Domain=api.openai.com; Expires=Tue, 05 May 2026 21:59:35 GMT", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", + "CF-Cache-Status" : "DYNAMIC", + "x-ratelimit-limit-requests" : "30000", + "openai-version" : "2020-10-01", + "openai-processing-ms" : "405", + "alt-svc" : "h3=\":443\"; ma=86400", + "openai-project" : "proj_vsCSXafhhByzWOThMrJcZiw9", + "Content-Type" : "application/json" + } + }, + "uuid" : "5fddb64e-58c5-4dd3-8696-5ff07db32475", + "persistent" : true, + "scenarioName" : "scenario-3-chat-completions", + "requiredScenarioState" : "scenario-3-chat-completions-2", + "insertionIndex" : 52 +} \ No newline at end of file diff --git a/test-harness/src/testFixtures/resources/cassettes/openai/mappings/chat_completions-6290e82f-d374-486e-8d4a-b939c86682d0.json b/test-harness/src/testFixtures/resources/cassettes/openai/mappings/chat_completions-6290e82f-d374-486e-8d4a-b939c86682d0.json new file mode 100644 index 00000000..5af29d6a --- /dev/null +++ b/test-harness/src/testFixtures/resources/cassettes/openai/mappings/chat_completions-6290e82f-d374-486e-8d4a-b939c86682d0.json @@ -0,0 +1,52 @@ +{ + "id" : "6290e82f-d374-486e-8d4a-b939c86682d0", + "name" : "chat_completions", + "request" : { + "url" : "/chat/completions", + "method" : "POST", + "headers" : { + "Content-Type" : { + "equalTo" : "application/json" + } + }, + "bodyPatterns" : [ { + "equalToJson" : "{\"messages\":[{\"content\":\"You are a helpful assistant\",\"role\":\"system\"},{\"content\":\"What is the capital of France?\",\"role\":\"user\"}],\"model\":\"gpt-4o-mini\",\"temperature\":0.0}", + "ignoreArrayOrder" : true, + "ignoreExtraElements" : false + } ] + }, + "response" : { + "status" : 200, + "bodyFileName" : "chat_completions-6290e82f-d374-486e-8d4a-b939c86682d0.json", + "headers" : { + "x-request-id" : "req_df78ead25a1b46f4b227b82fc5c02038", + "x-ratelimit-limit-tokens" : "150000000", + "openai-organization" : "braintrust-data", + "Server" : "cloudflare", + "CF-Ray" : "9f72d73e5c1f7e30-SJC", + "X-Content-Type-Options" : "nosniff", + "x-ratelimit-reset-requests" : "2ms", + "x-ratelimit-remaining-tokens" : "149999982", + "x-openai-proxy-wasm" : "v0.1", + "x-ratelimit-remaining-requests" : "29999", + "Date" : "Tue, 05 May 2026 21:29:28 GMT", + "x-ratelimit-reset-tokens" : "0s", + "access-control-expose-headers" : "X-Request-ID", + "set-cookie" : "__cf_bm=KToap3nu2yQjy.LyJo7o1T0q36s4Asl1IregUAmGvjY-1778016568.06161-1.0.1.1-H_SEYbZSfSaWbFyGzZ5AX3qel_JCEhopAORVjieBzyd4Scg7XNWQJv3ok3otf6N_CGVlnNlLCKCCoGSZI9dG3WdlPU8Iz2iAS5_.Bv7onGCAmi4WRFqtTBMpbuA6Fy_v; HttpOnly; Secure; Path=/; Domain=api.openai.com; Expires=Tue, 05 May 2026 21:59:28 GMT", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", + "CF-Cache-Status" : "DYNAMIC", + "x-ratelimit-limit-requests" : "30000", + "openai-version" : "2020-10-01", + "openai-processing-ms" : "425", + "alt-svc" : "h3=\":443\"; ma=86400", + "openai-project" : "proj_vsCSXafhhByzWOThMrJcZiw9", + "Content-Type" : "application/json" + } + }, + "uuid" : "6290e82f-d374-486e-8d4a-b939c86682d0", + "persistent" : true, + "scenarioName" : "scenario-3-chat-completions", + "requiredScenarioState" : "Started", + "newScenarioState" : "scenario-3-chat-completions-2", + "insertionIndex" : 56 +} \ No newline at end of file diff --git a/test-harness/src/testFixtures/resources/cassettes/openai/mappings/chat_completions-6f2f5093-383e-4499-b2fa-d3d52cbfa3ab.json b/test-harness/src/testFixtures/resources/cassettes/openai/mappings/chat_completions-6f2f5093-383e-4499-b2fa-d3d52cbfa3ab.json new file mode 100644 index 00000000..a50db1cf --- /dev/null +++ b/test-harness/src/testFixtures/resources/cassettes/openai/mappings/chat_completions-6f2f5093-383e-4499-b2fa-d3d52cbfa3ab.json @@ -0,0 +1,51 @@ +{ + "id" : "6f2f5093-383e-4499-b2fa-d3d52cbfa3ab", + "name" : "chat_completions", + "request" : { + "url" : "/chat/completions", + "method" : "POST", + "headers" : { + "Content-Type" : { + "equalTo" : "application/json" + } + }, + "bodyPatterns" : [ { + "equalToJson" : "{\"messages\":[{\"content\":\"You are a helpful assistant\",\"role\":\"system\"},{\"content\":\"What is the capital of France?\",\"role\":\"user\"}],\"model\":\"gpt-4o-mini\",\"stream_options\":{\"include_usage\":true},\"temperature\":0.0,\"stream\":true}", + "ignoreArrayOrder" : true, + "ignoreExtraElements" : false + } ] + }, + "response" : { + "status" : 200, + "bodyFileName" : "chat_completions-6f2f5093-383e-4499-b2fa-d3d52cbfa3ab.txt", + "headers" : { + "x-request-id" : "req_3a3e9c15ed6244d2b42292bfe5ffa52d", + "x-ratelimit-limit-tokens" : "150000000", + "openai-organization" : "braintrust-data", + "Server" : "cloudflare", + "CF-Ray" : "9f72d77d8c3ccd36-SJC", + "X-Content-Type-Options" : "nosniff", + "x-ratelimit-reset-requests" : "2ms", + "x-ratelimit-remaining-tokens" : "149999980", + "x-openai-proxy-wasm" : "v0.1", + "x-ratelimit-remaining-requests" : "29999", + "Date" : "Tue, 05 May 2026 21:29:38 GMT", + "x-ratelimit-reset-tokens" : "0s", + "access-control-expose-headers" : "X-Request-ID", + "set-cookie" : "__cf_bm=1bImsr7XrkccyOBHgqzl4FVv5Uc..rQU.EDl8EHUGMA-1778016578.1651561-1.0.1.1-BJyguj0NFg_uazCO_HbSkZ25afdJjBxISnYaMH4KeKGt2Of0WbQ3R76HVlI6YChK45zo98Vi3nNvPutIg34wlUUCkM_eBFFJC7y4FQ9WRgoUz6zA9uvVyW267mbQYw9P; HttpOnly; Secure; Path=/; Domain=api.openai.com; Expires=Tue, 05 May 2026 21:59:38 GMT", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", + "CF-Cache-Status" : "DYNAMIC", + "x-ratelimit-limit-requests" : "30000", + "openai-version" : "2020-10-01", + "openai-processing-ms" : "245", + "alt-svc" : "h3=\":443\"; ma=86400", + "openai-project" : "proj_vsCSXafhhByzWOThMrJcZiw9", + "Content-Type" : "text/event-stream; charset=utf-8" + } + }, + "uuid" : "6f2f5093-383e-4499-b2fa-d3d52cbfa3ab", + "persistent" : true, + "scenarioName" : "scenario-1-chat-completions", + "requiredScenarioState" : "scenario-1-chat-completions-2", + "insertionIndex" : 49 +} \ No newline at end of file diff --git a/test-harness/src/testFixtures/resources/cassettes/openai/mappings/responses-5fe80689-c90a-48e4-9d9e-dc0bd0eeb6d1.json b/test-harness/src/testFixtures/resources/cassettes/openai/mappings/responses-5fe80689-c90a-48e4-9d9e-dc0bd0eeb6d1.json new file mode 100644 index 00000000..f0a5e054 --- /dev/null +++ b/test-harness/src/testFixtures/resources/cassettes/openai/mappings/responses-5fe80689-c90a-48e4-9d9e-dc0bd0eeb6d1.json @@ -0,0 +1,47 @@ +{ + "id" : "5fe80689-c90a-48e4-9d9e-dc0bd0eeb6d1", + "name" : "responses", + "request" : { + "url" : "/responses", + "method" : "POST", + "headers" : { + "Content-Type" : { + "equalTo" : "application/json" + } + }, + "bodyPatterns" : [ { + "equalToJson" : "{\"input\":[{\"content\":\"What is the capital of France? Reply in one word.\",\"role\":\"user\"}],\"model\":\"o4-mini\",\"reasoning\":{\"effort\":\"low\",\"summary\":\"auto\"}}", + "ignoreArrayOrder" : true, + "ignoreExtraElements" : false + } ] + }, + "response" : { + "status" : 200, + "bodyFileName" : "responses-5fe80689-c90a-48e4-9d9e-dc0bd0eeb6d1.json", + "headers" : { + "x-request-id" : "req_2b57d4c05fe541518422dcdacca47bd2", + "x-ratelimit-limit-tokens" : "150000000", + "openai-organization" : "braintrust-data", + "Server" : "cloudflare", + "CF-Ray" : "9f72d74cfa2be16d-SJC", + "X-Content-Type-Options" : "nosniff", + "x-ratelimit-reset-requests" : "2ms", + "x-ratelimit-remaining-tokens" : "149999775", + "x-ratelimit-remaining-requests" : "29999", + "Date" : "Tue, 05 May 2026 21:29:32 GMT", + "x-ratelimit-reset-tokens" : "0s", + "set-cookie" : "__cf_bm=bbV5qyWKhcTvQXBSX5T6fTi3no9mabXMXD6cPn3dtYc-1778016570.3953266-1.0.1.1-LbkKYHfUDeVoDi864tyr2_cChJ9CJgtVESJ.5hzZoPbxqbjN4bno51OpXtRsAPkZPyghQa4jf.4kEuPG4l5zKfHPmqZpfH8vO3VTBGG8_53vqYQPH1A_bVWPBcYmO1o_; HttpOnly; Secure; Path=/; Domain=api.openai.com; Expires=Tue, 05 May 2026 21:59:32 GMT", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", + "CF-Cache-Status" : "DYNAMIC", + "x-ratelimit-limit-requests" : "30000", + "openai-version" : "2020-10-01", + "openai-processing-ms" : "2331", + "alt-svc" : "h3=\":443\"; ma=86400", + "openai-project" : "proj_vsCSXafhhByzWOThMrJcZiw9", + "Content-Type" : "application/json" + } + }, + "uuid" : "5fe80689-c90a-48e4-9d9e-dc0bd0eeb6d1", + "persistent" : true, + "insertionIndex" : 54 +} \ No newline at end of file diff --git a/test-harness/src/testFixtures/resources/cassettes/openai/mappings/responses-9798f9bb-c5d0-4c0a-b211-d0c8fa441c00.json b/test-harness/src/testFixtures/resources/cassettes/openai/mappings/responses-9798f9bb-c5d0-4c0a-b211-d0c8fa441c00.json new file mode 100644 index 00000000..3b3fc106 --- /dev/null +++ b/test-harness/src/testFixtures/resources/cassettes/openai/mappings/responses-9798f9bb-c5d0-4c0a-b211-d0c8fa441c00.json @@ -0,0 +1,47 @@ +{ + "id" : "9798f9bb-c5d0-4c0a-b211-d0c8fa441c00", + "name" : "responses", + "request" : { + "url" : "/responses", + "method" : "POST", + "headers" : { + "Content-Type" : { + "equalTo" : "application/json" + } + }, + "bodyPatterns" : [ { + "equalToJson" : "{\"input\":[{\"content\":\"What is the capital of France? Reply in one word.\",\"role\":\"user\"}],\"instructions\":\"You are a helpful assistant\",\"model\":\"gpt-4o-mini\"}", + "ignoreArrayOrder" : true, + "ignoreExtraElements" : false + } ] + }, + "response" : { + "status" : 200, + "bodyFileName" : "responses-9798f9bb-c5d0-4c0a-b211-d0c8fa441c00.json", + "headers" : { + "x-request-id" : "req_681b1fa879e44b9491024dd90e529aa6", + "x-ratelimit-limit-tokens" : "150000000", + "openai-organization" : "braintrust-data", + "Server" : "cloudflare", + "CF-Ray" : "9f72d760082397f0-SJC", + "X-Content-Type-Options" : "nosniff", + "x-ratelimit-reset-requests" : "2ms", + "x-ratelimit-remaining-tokens" : "149999952", + "x-ratelimit-remaining-requests" : "29999", + "Date" : "Tue, 05 May 2026 21:29:34 GMT", + "x-ratelimit-reset-tokens" : "0s", + "set-cookie" : "__cf_bm=ZPA5eX5E0g4KsRrSAfIi62P8N18NG2e5ABzcPNC_7uw-1778016573.4467661-1.0.1.1-67VCHBTBjRlsyTBFYN275PenW9RvB0SwxEperowSkj58CqabIy84Xw1Ud0.nS.m7Prd59KLdO2Ceae4vs7lPtETopQMYASJs8oqKbTecBcyZ413W_kEBThkLMwcrmP1v; HttpOnly; Secure; Path=/; Domain=api.openai.com; Expires=Tue, 05 May 2026 21:59:34 GMT", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", + "CF-Cache-Status" : "DYNAMIC", + "x-ratelimit-limit-requests" : "30000", + "openai-version" : "2020-10-01", + "openai-processing-ms" : "684", + "alt-svc" : "h3=\":443\"; ma=86400", + "openai-project" : "proj_vsCSXafhhByzWOThMrJcZiw9", + "Content-Type" : "application/json" + } + }, + "uuid" : "9798f9bb-c5d0-4c0a-b211-d0c8fa441c00", + "persistent" : true, + "insertionIndex" : 53 +} \ No newline at end of file diff --git a/test-harness/src/testFixtures/resources/cassettes/openai/mappings/responses-c56562c2-4ea1-44f1-9ee5-d61b3fcd4e5b.json b/test-harness/src/testFixtures/resources/cassettes/openai/mappings/responses-c56562c2-4ea1-44f1-9ee5-d61b3fcd4e5b.json new file mode 100644 index 00000000..6fa93537 --- /dev/null +++ b/test-harness/src/testFixtures/resources/cassettes/openai/mappings/responses-c56562c2-4ea1-44f1-9ee5-d61b3fcd4e5b.json @@ -0,0 +1,44 @@ +{ + "id" : "c56562c2-4ea1-44f1-9ee5-d61b3fcd4e5b", + "name" : "responses", + "request" : { + "url" : "/responses", + "method" : "POST", + "headers" : { + "Content-Type" : { + "equalTo" : "application/json" + } + }, + "bodyPatterns" : [ { + "equalToJson" : "{\"input\":[{\"content\":\"What is the capital of France?\",\"role\":\"user\"}],\"instructions\":\"You are a helpful assistant\",\"model\":\"gpt-4o-mini\",\"stream\":true}", + "ignoreArrayOrder" : true, + "ignoreExtraElements" : false + } ] + }, + "response" : { + "status" : 200, + "bodyFileName" : "responses-c56562c2-4ea1-44f1-9ee5-d61b3fcd4e5b.txt", + "headers" : { + "x-request-id" : "req_7a845137bcac4208b7080f27505b377c", + "openai-organization" : "braintrust-data", + "Server" : "cloudflare", + "CF-Ray" : "9f72d76fbf003884-SJC", + "X-Content-Type-Options" : "nosniff", + "Date" : "Tue, 05 May 2026 21:29:36 GMT", + "set-cookie" : "__cf_bm=I3OhMy3xY3c4K68I_CNMNO9eG6Z.zi0TY.nkaFZPXgY-1778016575.9585218-1.0.1.1-P2ldC3TM9wBFUTnDS9UvRNzK17w1t9kppvynOZNlg4gsJF0AV2lEuLKkO4t54P4r3oaud4QvhfR2NLUSDP82EIpyglv7L5kN2CRRW6uGAZEELp_H5Ij.WwVMdFsml4zx; HttpOnly; Secure; Path=/; Domain=api.openai.com; Expires=Tue, 05 May 2026 21:59:36 GMT", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", + "CF-Cache-Status" : "DYNAMIC", + "openai-version" : "2020-10-01", + "openai-processing-ms" : "85", + "alt-svc" : "h3=\":443\"; ma=86400", + "openai-project" : "proj_vsCSXafhhByzWOThMrJcZiw9", + "Content-Type" : "text/event-stream; charset=utf-8" + } + }, + "uuid" : "c56562c2-4ea1-44f1-9ee5-d61b3fcd4e5b", + "persistent" : true, + "scenarioName" : "scenario-2-responses", + "requiredScenarioState" : "Started", + "newScenarioState" : "scenario-2-responses-2", + "insertionIndex" : 51 +} \ No newline at end of file diff --git a/test-harness/src/testFixtures/resources/cassettes/openai/mappings/responses-dcbbcd6a-bd6e-40c2-b73d-0361e3ab941c.json b/test-harness/src/testFixtures/resources/cassettes/openai/mappings/responses-dcbbcd6a-bd6e-40c2-b73d-0361e3ab941c.json new file mode 100644 index 00000000..595f7b77 --- /dev/null +++ b/test-harness/src/testFixtures/resources/cassettes/openai/mappings/responses-dcbbcd6a-bd6e-40c2-b73d-0361e3ab941c.json @@ -0,0 +1,43 @@ +{ + "id" : "dcbbcd6a-bd6e-40c2-b73d-0361e3ab941c", + "name" : "responses", + "request" : { + "url" : "/responses", + "method" : "POST", + "headers" : { + "Content-Type" : { + "equalTo" : "application/json" + } + }, + "bodyPatterns" : [ { + "equalToJson" : "{\"input\":[{\"content\":\"What is the capital of France?\",\"role\":\"user\"}],\"instructions\":\"You are a helpful assistant\",\"model\":\"gpt-4o-mini\",\"stream\":true}", + "ignoreArrayOrder" : true, + "ignoreExtraElements" : false + } ] + }, + "response" : { + "status" : 200, + "bodyFileName" : "responses-dcbbcd6a-bd6e-40c2-b73d-0361e3ab941c.txt", + "headers" : { + "x-request-id" : "req_c8469ae7b7c9458187c4d593c136dc8d", + "openai-organization" : "braintrust-data", + "Server" : "cloudflare", + "CF-Ray" : "9f72d776e922c52e-SJC", + "X-Content-Type-Options" : "nosniff", + "Date" : "Tue, 05 May 2026 21:29:37 GMT", + "set-cookie" : "__cf_bm=UAfStjUG7TqQO2AT39yQUpEF3Q_JDlRq042ezabkYXA-1778016577.1018875-1.0.1.1-VNRMauYejdNYk4.v11yIKJ579Jmi3R4mS.Bf_q_mrTF.CZJqq_iYJRKPORIck2g6tbs60qsfWLnBlZqQ.anizLw4p3skqM973qWAACvdJmxlhzLZ6CHW3ciX0mCSAuOT; HttpOnly; Secure; Path=/; Domain=api.openai.com; Expires=Tue, 05 May 2026 21:59:37 GMT", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", + "CF-Cache-Status" : "DYNAMIC", + "openai-version" : "2020-10-01", + "openai-processing-ms" : "109", + "alt-svc" : "h3=\":443\"; ma=86400", + "openai-project" : "proj_vsCSXafhhByzWOThMrJcZiw9", + "Content-Type" : "text/event-stream; charset=utf-8" + } + }, + "uuid" : "dcbbcd6a-bd6e-40c2-b73d-0361e3ab941c", + "persistent" : true, + "scenarioName" : "scenario-2-responses", + "requiredScenarioState" : "scenario-2-responses-2", + "insertionIndex" : 50 +} \ No newline at end of file