From 5fedd11d170a23adb3d6461ee58250d562533f66 Mon Sep 17 00:00:00 2001 From: Jonas Kunz Date: Wed, 12 Feb 2025 01:12:08 +0100 Subject: [PATCH] Fix support for OpenAI developer messages (#539) * log instead of throw on unhandled message * Report developer messages as developer role * remove unnecessary string concat * spotless and fix 0.8 compatibility --- custom/build.gradle.kts | 2 +- docs/configure.md | 4 +- .../otel/openai/wrappers/ApiAdapter.java | 6 ++ .../wrappers/ChatCompletionEventsHelper.java | 43 ++++++++-- .../otel/openai/v0_14/ApiAdapterImpl.java | 11 ++- .../elastic/otel/openai/v0_14/ChatTest.java | 9 ++ .../build.gradle.kts | 4 +- .../otel/openai/v0_2/ApiAdapterImpl.java | 17 +++- .../OpenAiClientInstrumentationModule.java | 0 ...nAiOkHttpClientBuilderInstrumentation.java | 0 .../co/elastic/otel/openai/v0_2/ChatTest.java | 9 ++ .../otel/openai/v0_2/EmbeddingsTest.java | 0 .../co/elastic/otel/openai/ChatTestBase.java | 71 ++++++++++++++++ .../src/main/resources/mappings/chattest.yaml | 82 +++++++++++++++++++ renovate.json | 2 +- settings.gradle.kts | 2 +- 16 files changed, 243 insertions(+), 19 deletions(-) rename instrumentation/openai-client-instrumentation/{instrumentation-0.2 => instrumentation-0.8}/build.gradle.kts (81%) rename instrumentation/openai-client-instrumentation/{instrumentation-0.2 => instrumentation-0.8}/src/main/java/co/elastic/otel/openai/v0_2/ApiAdapterImpl.java (88%) rename instrumentation/openai-client-instrumentation/{instrumentation-0.2 => instrumentation-0.8}/src/main/java/co/elastic/otel/openai/v0_2/OpenAiClientInstrumentationModule.java (100%) rename instrumentation/openai-client-instrumentation/{instrumentation-0.2 => instrumentation-0.8}/src/main/java/co/elastic/otel/openai/v0_2/OpenAiOkHttpClientBuilderInstrumentation.java (100%) rename instrumentation/openai-client-instrumentation/{instrumentation-0.2 => instrumentation-0.8}/src/test/java/co/elastic/otel/openai/v0_2/ChatTest.java (88%) rename instrumentation/openai-client-instrumentation/{instrumentation-0.2 => instrumentation-0.8}/src/test/java/co/elastic/otel/openai/v0_2/EmbeddingsTest.java (100%) diff --git a/custom/build.gradle.kts b/custom/build.gradle.kts index 688e8233..b49e0711 100644 --- a/custom/build.gradle.kts +++ b/custom/build.gradle.kts @@ -3,7 +3,7 @@ plugins { } val instrumentations = listOf( - ":instrumentation:openai-client-instrumentation:instrumentation-0.2", + ":instrumentation:openai-client-instrumentation:instrumentation-0.8", ":instrumentation:openai-client-instrumentation:instrumentation-0.14" ) diff --git a/docs/configure.md b/docs/configure.md index 5b2f72b0..13b28bb2 100644 --- a/docs/configure.md +++ b/docs/configure.md @@ -122,8 +122,10 @@ It supports: * Tracing for requests, including GenAI-specific attributes such as token usage * Opt-In logging of OpenAI request and response content payloads +The minimum supported version is `0.8.0`. + Note that this instrumentation is currently in **tech preview**, because the OpenAI client itself is still in beta. -Once the OpenAI client is stable, this instrumentation will be GAed, but we'll likely drop support for beta versions of the client after some time. +Once the OpenAI client is stable, this instrumentation will be GAed. We'll drop support for older beta versions of the client after some time. The instrumentation is on by default and can be disabled by setting either the `OTEL_INSTRUMENTATION_OPENAI_CLIENT_ENABLED` environment variable or the `otel.instrumentation.openai-client.enabled` JVM property to `false`. In addition, this instrumentation provides the following configuration options: diff --git a/instrumentation/openai-client-instrumentation/common/src/main/java/co/elastic/otel/openai/wrappers/ApiAdapter.java b/instrumentation/openai-client-instrumentation/common/src/main/java/co/elastic/otel/openai/wrappers/ApiAdapter.java index 7ae10668..3365cd74 100644 --- a/instrumentation/openai-client-instrumentation/common/src/main/java/co/elastic/otel/openai/wrappers/ApiAdapter.java +++ b/instrumentation/openai-client-instrumentation/common/src/main/java/co/elastic/otel/openai/wrappers/ApiAdapter.java @@ -21,6 +21,7 @@ import com.openai.models.ChatCompletionAssistantMessageParam; import com.openai.models.ChatCompletionContentPart; import com.openai.models.ChatCompletionCreateParams; +import com.openai.models.ChatCompletionDeveloperMessageParam; import com.openai.models.ChatCompletionMessageParam; import com.openai.models.ChatCompletionSystemMessageParam; import com.openai.models.ChatCompletionToolMessageParam; @@ -75,6 +76,11 @@ protected static void init(Supplier implementation) { */ public abstract String asText(ChatCompletionSystemMessageParam.Content content); + /** + * @return the contained text, if the content is text. null otherwise. + */ + public abstract String asText(ChatCompletionDeveloperMessageParam.Content content); + /** * @return the contained text, if the content is text. null otherwise. */ diff --git a/instrumentation/openai-client-instrumentation/common/src/main/java/co/elastic/otel/openai/wrappers/ChatCompletionEventsHelper.java b/instrumentation/openai-client-instrumentation/common/src/main/java/co/elastic/otel/openai/wrappers/ChatCompletionEventsHelper.java index 683390b6..efbe9f56 100644 --- a/instrumentation/openai-client-instrumentation/common/src/main/java/co/elastic/otel/openai/wrappers/ChatCompletionEventsHelper.java +++ b/instrumentation/openai-client-instrumentation/common/src/main/java/co/elastic/otel/openai/wrappers/ChatCompletionEventsHelper.java @@ -24,6 +24,7 @@ import com.openai.models.ChatCompletionAssistantMessageParam; import com.openai.models.ChatCompletionContentPartText; import com.openai.models.ChatCompletionCreateParams; +import com.openai.models.ChatCompletionDeveloperMessageParam; import com.openai.models.ChatCompletionMessage; import com.openai.models.ChatCompletionMessageParam; import com.openai.models.ChatCompletionMessageToolCall; @@ -40,10 +41,14 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.logging.Level; import java.util.stream.Collectors; public class ChatCompletionEventsHelper { + private static final java.util.logging.Logger LOG = + java.util.logging.Logger.getLogger(ChatCompletionEventsHelper.class.getName()); + private static final Logger EV_LOGGER = GlobalOpenTelemetry.get().getLogsBridge().get(Constants.INSTRUMENTATION_NAME); @@ -66,6 +71,14 @@ public static void emitPromptLogEvents( if (settings.captureMessageContent) { putIfNotEmpty(bodyBuilder, "content", contentToString(sysMsg.content())); } + } else if (concreteMessageParam instanceof ChatCompletionDeveloperMessageParam) { + ChatCompletionDeveloperMessageParam sysMsg = + (ChatCompletionDeveloperMessageParam) concreteMessageParam; + eventType = "gen_ai.system.message"; + putIfNotEmpty(bodyBuilder, "role", "developer"); + if (settings.captureMessageContent) { + putIfNotEmpty(bodyBuilder, "content", contentToString(sysMsg.content())); + } } else if (concreteMessageParam instanceof ChatCompletionUserMessageParam) { ChatCompletionUserMessageParam userMsg = (ChatCompletionUserMessageParam) concreteMessageParam; @@ -102,7 +115,8 @@ public static void emitPromptLogEvents( bodyBuilder.put("id", toolMsg.toolCallId()); } } else { - throw new IllegalStateException("Unhandled type : " + msg.getClass().getName()); + LOG.log(Level.WARNING, "Unhandled OpenAI message type will be dropped: {0}", msg); + continue; } newEvent(eventType).setBody(bodyBuilder.build()).emit(); } @@ -119,9 +133,7 @@ private static String contentToString(ChatCompletionToolMessageParam.Content con if (text != null) { return text; } else if (content.isArrayOfContentParts()) { - return content.asArrayOfContentParts().stream() - .map(ChatCompletionContentPartText::text) - .collect(Collectors.joining()); + return joinContentParts(content.asArrayOfContentParts()); } else { throw new IllegalStateException("Unhandled content type for " + content); } @@ -146,14 +158,29 @@ private static String contentToString(ChatCompletionSystemMessageParam.Content c if (text != null) { return text; } else if (content.isArrayOfContentParts()) { - return content.asArrayOfContentParts().stream() - .map(ChatCompletionContentPartText::text) - .collect(Collectors.joining()); + return joinContentParts(content.asArrayOfContentParts()); + } else { + throw new IllegalStateException("Unhandled content type for " + content); + } + } + + private static String contentToString(ChatCompletionDeveloperMessageParam.Content content) { + String text = ApiAdapter.get().asText(content); + if (text != null) { + return text; + } else if (content.isArrayOfContentParts()) { + return joinContentParts(content.asArrayOfContentParts()); } else { throw new IllegalStateException("Unhandled content type for " + content); } } + private static String joinContentParts(List contentParts) { + return contentParts.stream() + .map(ChatCompletionContentPartText::text) + .collect(Collectors.joining()); + } + private static String contentToString(ChatCompletionUserMessageParam.Content content) { String text = ApiAdapter.get().asText(content); if (text != null) { @@ -228,7 +255,7 @@ private static LogRecordBuilder newEvent(String name) { private static Value buildToolCallEventObject(ChatCompletionMessageToolCall call) { Map> result = new HashMap<>(); result.put("id", Value.of(call.id())); - result.put("type", Value.of(call._type().toString())); + result.put("type", Value.of("function")); // "function" is the only currently supported type result.put("function", buildFunctionEventObject(call.function())); return Value.of(result); } diff --git a/instrumentation/openai-client-instrumentation/instrumentation-0.14/src/main/java/co/elastic/otel/openai/v0_14/ApiAdapterImpl.java b/instrumentation/openai-client-instrumentation/instrumentation-0.14/src/main/java/co/elastic/otel/openai/v0_14/ApiAdapterImpl.java index 9de26cc5..5d686949 100644 --- a/instrumentation/openai-client-instrumentation/instrumentation-0.14/src/main/java/co/elastic/otel/openai/v0_14/ApiAdapterImpl.java +++ b/instrumentation/openai-client-instrumentation/instrumentation-0.14/src/main/java/co/elastic/otel/openai/v0_14/ApiAdapterImpl.java @@ -22,6 +22,7 @@ import com.openai.models.ChatCompletionAssistantMessageParam; import com.openai.models.ChatCompletionContentPart; import com.openai.models.ChatCompletionCreateParams; +import com.openai.models.ChatCompletionDeveloperMessageParam; import com.openai.models.ChatCompletionMessageParam; import com.openai.models.ChatCompletionSystemMessageParam; import com.openai.models.ChatCompletionToolMessageParam; @@ -38,6 +39,9 @@ public Object extractConcreteCompletionMessageParam(ChatCompletionMessageParam b if (base.isSystem()) { return base.asSystem(); } + if (base.isDeveloper()) { + return base.asDeveloper(); + } if (base.isUser()) { return base.asUser(); } @@ -47,7 +51,7 @@ public Object extractConcreteCompletionMessageParam(ChatCompletionMessageParam b if (base.isTool()) { return base.asTool(); } - throw new IllegalStateException("Unhandled message param type: " + base); + return null; } @Override @@ -65,6 +69,11 @@ public String asText(ChatCompletionSystemMessageParam.Content content) { return content.isText() ? content.asText() : null; } + @Override + public String asText(ChatCompletionDeveloperMessageParam.Content content) { + return content.isText() ? content.asText() : null; + } + @Override public String asText(ChatCompletionUserMessageParam.Content content) { return content.isText() ? content.asText() : null; diff --git a/instrumentation/openai-client-instrumentation/instrumentation-0.14/src/test/java/co/elastic/otel/openai/v0_14/ChatTest.java b/instrumentation/openai-client-instrumentation/instrumentation-0.14/src/test/java/co/elastic/otel/openai/v0_14/ChatTest.java index 622412a6..1ce12c5b 100644 --- a/instrumentation/openai-client-instrumentation/instrumentation-0.14/src/test/java/co/elastic/otel/openai/v0_14/ChatTest.java +++ b/instrumentation/openai-client-instrumentation/instrumentation-0.14/src/test/java/co/elastic/otel/openai/v0_14/ChatTest.java @@ -20,6 +20,7 @@ import co.elastic.otel.openai.ChatTestBase; import com.openai.models.ChatCompletionAssistantMessageParam; +import com.openai.models.ChatCompletionDeveloperMessageParam; import com.openai.models.ChatCompletionMessageParam; import com.openai.models.ChatCompletionMessageToolCall; import com.openai.models.ChatCompletionSystemMessageParam; @@ -63,6 +64,14 @@ protected ChatCompletionMessageParam createSystemMessage(String content) { .build()); } + @Override + protected ChatCompletionMessageParam createDeveloperMessage(String content) { + return ChatCompletionMessageParam.ofDeveloper( + ChatCompletionDeveloperMessageParam.builder() + .content(ChatCompletionDeveloperMessageParam.Content.ofText(content)) + .build()); + } + @Override protected ChatCompletionMessageParam createToolMessage(String response, String id) { return ChatCompletionMessageParam.ofTool( diff --git a/instrumentation/openai-client-instrumentation/instrumentation-0.2/build.gradle.kts b/instrumentation/openai-client-instrumentation/instrumentation-0.8/build.gradle.kts similarity index 81% rename from instrumentation/openai-client-instrumentation/instrumentation-0.2/build.gradle.kts rename to instrumentation/openai-client-instrumentation/instrumentation-0.8/build.gradle.kts index 9cbe3314..9fd219a1 100644 --- a/instrumentation/openai-client-instrumentation/instrumentation-0.2/build.gradle.kts +++ b/instrumentation/openai-client-instrumentation/instrumentation-0.8/build.gradle.kts @@ -5,7 +5,7 @@ plugins { id("elastic-otel.instrumentation-conventions") } -val openAiVersion = "0" +".13.0"; // DO NOT UPGRADE, string operations are used to prevent renovate upgrades +val openAiVersion = "0.13.0"; // DO NOT UPGRADE dependencies { compileOnly("com.openai:openai-java:${openAiVersion}") @@ -19,7 +19,7 @@ muzzle { pass { group.set("com.openai") module.set("openai-java") - versions.set("(,${openAiVersion}]") + versions.set("[0.8,${openAiVersion}]") assertInverse.set(true) } } diff --git a/instrumentation/openai-client-instrumentation/instrumentation-0.2/src/main/java/co/elastic/otel/openai/v0_2/ApiAdapterImpl.java b/instrumentation/openai-client-instrumentation/instrumentation-0.8/src/main/java/co/elastic/otel/openai/v0_2/ApiAdapterImpl.java similarity index 88% rename from instrumentation/openai-client-instrumentation/instrumentation-0.2/src/main/java/co/elastic/otel/openai/v0_2/ApiAdapterImpl.java rename to instrumentation/openai-client-instrumentation/instrumentation-0.8/src/main/java/co/elastic/otel/openai/v0_2/ApiAdapterImpl.java index f00ac3cc..0eae8f75 100644 --- a/instrumentation/openai-client-instrumentation/instrumentation-0.2/src/main/java/co/elastic/otel/openai/v0_2/ApiAdapterImpl.java +++ b/instrumentation/openai-client-instrumentation/instrumentation-0.8/src/main/java/co/elastic/otel/openai/v0_2/ApiAdapterImpl.java @@ -22,6 +22,7 @@ import com.openai.models.ChatCompletionAssistantMessageParam; import com.openai.models.ChatCompletionContentPart; import com.openai.models.ChatCompletionCreateParams; +import com.openai.models.ChatCompletionDeveloperMessageParam; import com.openai.models.ChatCompletionMessageParam; import com.openai.models.ChatCompletionSystemMessageParam; import com.openai.models.ChatCompletionToolMessageParam; @@ -38,6 +39,9 @@ public Object extractConcreteCompletionMessageParam(ChatCompletionMessageParam b if (base.isChatCompletionSystemMessageParam()) { return base.asChatCompletionSystemMessageParam(); } + if (base.isChatCompletionDeveloperMessageParam()) { + return base.asChatCompletionDeveloperMessageParam(); + } if (base.isChatCompletionUserMessageParam()) { return base.asChatCompletionUserMessageParam(); } @@ -47,7 +51,7 @@ public Object extractConcreteCompletionMessageParam(ChatCompletionMessageParam b if (base.isChatCompletionToolMessageParam()) { return base.asChatCompletionToolMessageParam(); } - throw new IllegalStateException("Unhandled message param type: " + base); + return null; } @Override @@ -61,11 +65,11 @@ public String extractText(ChatCompletionContentPart part) { @Override public String extractType(ChatCompletionCreateParams.ResponseFormat val) { if (val.isResponseFormatText()) { - return val.asResponseFormatText()._type().toString(); + return "text"; } else if (val.isResponseFormatJsonObject()) { - return val.asResponseFormatJsonObject()._type().toString(); + return "json_object"; } else if (val.isResponseFormatJsonSchema()) { - return val.asResponseFormatJsonSchema()._type().toString(); + return "json_schema"; } return null; } @@ -93,6 +97,11 @@ public String asText(ChatCompletionSystemMessageParam.Content content) { return content.isTextContent() ? content.asTextContent() : null; } + @Override + public String asText(ChatCompletionDeveloperMessageParam.Content content) { + return content.isTextContent() ? content.asTextContent() : null; + } + @Override public String asText(ChatCompletionAssistantMessageParam.Content content) { return content.isTextContent() ? content.asTextContent() : null; diff --git a/instrumentation/openai-client-instrumentation/instrumentation-0.2/src/main/java/co/elastic/otel/openai/v0_2/OpenAiClientInstrumentationModule.java b/instrumentation/openai-client-instrumentation/instrumentation-0.8/src/main/java/co/elastic/otel/openai/v0_2/OpenAiClientInstrumentationModule.java similarity index 100% rename from instrumentation/openai-client-instrumentation/instrumentation-0.2/src/main/java/co/elastic/otel/openai/v0_2/OpenAiClientInstrumentationModule.java rename to instrumentation/openai-client-instrumentation/instrumentation-0.8/src/main/java/co/elastic/otel/openai/v0_2/OpenAiClientInstrumentationModule.java diff --git a/instrumentation/openai-client-instrumentation/instrumentation-0.2/src/main/java/co/elastic/otel/openai/v0_2/OpenAiOkHttpClientBuilderInstrumentation.java b/instrumentation/openai-client-instrumentation/instrumentation-0.8/src/main/java/co/elastic/otel/openai/v0_2/OpenAiOkHttpClientBuilderInstrumentation.java similarity index 100% rename from instrumentation/openai-client-instrumentation/instrumentation-0.2/src/main/java/co/elastic/otel/openai/v0_2/OpenAiOkHttpClientBuilderInstrumentation.java rename to instrumentation/openai-client-instrumentation/instrumentation-0.8/src/main/java/co/elastic/otel/openai/v0_2/OpenAiOkHttpClientBuilderInstrumentation.java diff --git a/instrumentation/openai-client-instrumentation/instrumentation-0.2/src/test/java/co/elastic/otel/openai/v0_2/ChatTest.java b/instrumentation/openai-client-instrumentation/instrumentation-0.8/src/test/java/co/elastic/otel/openai/v0_2/ChatTest.java similarity index 88% rename from instrumentation/openai-client-instrumentation/instrumentation-0.2/src/test/java/co/elastic/otel/openai/v0_2/ChatTest.java rename to instrumentation/openai-client-instrumentation/instrumentation-0.8/src/test/java/co/elastic/otel/openai/v0_2/ChatTest.java index b386f5af..ca7b5e36 100644 --- a/instrumentation/openai-client-instrumentation/instrumentation-0.2/src/test/java/co/elastic/otel/openai/v0_2/ChatTest.java +++ b/instrumentation/openai-client-instrumentation/instrumentation-0.8/src/test/java/co/elastic/otel/openai/v0_2/ChatTest.java @@ -20,6 +20,7 @@ import co.elastic.otel.openai.ChatTestBase; import com.openai.models.ChatCompletionAssistantMessageParam; +import com.openai.models.ChatCompletionDeveloperMessageParam; import com.openai.models.ChatCompletionMessageParam; import com.openai.models.ChatCompletionMessageToolCall; import com.openai.models.ChatCompletionSystemMessageParam; @@ -63,6 +64,14 @@ protected ChatCompletionMessageParam createSystemMessage(String content) { .build()); } + @Override + protected ChatCompletionMessageParam createDeveloperMessage(String content) { + return ChatCompletionMessageParam.ofChatCompletionDeveloperMessageParam( + ChatCompletionDeveloperMessageParam.builder() + .content(ChatCompletionDeveloperMessageParam.Content.ofTextContent(content)) + .build()); + } + @Override protected ChatCompletionMessageParam createToolMessage(String response, String id) { return ChatCompletionMessageParam.ofChatCompletionToolMessageParam( diff --git a/instrumentation/openai-client-instrumentation/instrumentation-0.2/src/test/java/co/elastic/otel/openai/v0_2/EmbeddingsTest.java b/instrumentation/openai-client-instrumentation/instrumentation-0.8/src/test/java/co/elastic/otel/openai/v0_2/EmbeddingsTest.java similarity index 100% rename from instrumentation/openai-client-instrumentation/instrumentation-0.2/src/test/java/co/elastic/otel/openai/v0_2/EmbeddingsTest.java rename to instrumentation/openai-client-instrumentation/instrumentation-0.8/src/test/java/co/elastic/otel/openai/v0_2/EmbeddingsTest.java diff --git a/instrumentation/openai-client-instrumentation/testing-common/src/main/java/co/elastic/otel/openai/ChatTestBase.java b/instrumentation/openai-client-instrumentation/testing-common/src/main/java/co/elastic/otel/openai/ChatTestBase.java index 662a38b6..b34e7af5 100644 --- a/instrumentation/openai-client-instrumentation/testing-common/src/main/java/co/elastic/otel/openai/ChatTestBase.java +++ b/instrumentation/openai-client-instrumentation/testing-common/src/main/java/co/elastic/otel/openai/ChatTestBase.java @@ -238,6 +238,75 @@ void chat() throws Exception { equalTo(SERVER_PORT, (long) openai.getPort()))))); } + @Test + void testDeveloperMessage() { + InstrumentationSettingsAccessor.setCaptureMessageContent(openai.client, true); + + ChatCompletionCreateParams params = + ChatCompletionCreateParams.builder() + .messages( + Arrays.asList( + createDeveloperMessage( + "You are an assistant which just answers every query with tomato"), + createUserMessage("Say something"))) + .model(TEST_CHAT_MODEL) + .build(); + + ChatCompletion chatCompletion = openai.client.chat().completions().create(params); + chatCompletion.validate(); + + List spans = testing.spans(); + assertThat(spans.size()).isEqualTo(1); + SpanContext spanCtx = spans.get(0).getSpanContext(); + assertThat(testing.logRecords()) + .anySatisfy( + log -> { + assertThat(log) + .hasAttributesSatisfying( + attr -> + assertThat(attr) + .containsEntry(GEN_AI_SYSTEM, "openai") + .containsEntry("event.name", "gen_ai.system.message")) + .hasSpanContext(spanCtx); + assertThat(log.getBodyValue()) + .satisfies( + ValAssert.map() + .entry( + "content", + "You are an assistant which just answers every query with tomato") + .entry("role", "developer")); + }) + .anySatisfy( + log -> { + assertThat(log) + .hasAttributesSatisfying( + attr -> + assertThat(attr) + .containsEntry(GEN_AI_SYSTEM, "openai") + .containsEntry("event.name", "gen_ai.user.message")) + .hasSpanContext(spanCtx); + assertThat(log.getBodyValue()) + .satisfies(ValAssert.map().entry("content", "Say something")); + }) + .anySatisfy( + log -> { + assertThat(log) + .hasAttributesSatisfying( + attr -> + assertThat(attr) + .containsEntry(GEN_AI_SYSTEM, "openai") + .containsEntry("event.name", "gen_ai.choice")) + .hasSpanContext(spanCtx); + assertThat(log.getBodyValue()) + .satisfies( + ValAssert.map() + .entry("finish_reason", "stop") + .entry("index", 0) + .entry("message", ValAssert.map().entry("content", "Tomato."))); + }) + .hasSize(3); + } + @Test void allTheClientOptions() { ChatCompletionCreateParams params = @@ -2343,5 +2412,7 @@ protected abstract ChatCompletionMessageParam createAssistantMessage( protected abstract ChatCompletionMessageParam createSystemMessage(String content); + protected abstract ChatCompletionMessageParam createDeveloperMessage(String content); + protected abstract ChatCompletionMessageParam createToolMessage(String response, String id); } diff --git a/instrumentation/openai-client-instrumentation/testing-common/src/main/resources/mappings/chattest.yaml b/instrumentation/openai-client-instrumentation/testing-common/src/main/resources/mappings/chattest.yaml index 3d8bf361..09774a6e 100644 --- a/instrumentation/openai-client-instrumentation/testing-common/src/main/resources/mappings/chattest.yaml +++ b/instrumentation/openai-client-instrumentation/testing-common/src/main/resources/mappings/chattest.yaml @@ -1237,3 +1237,85 @@ response: uuid: 02ad43a7-4627-4cc7-b5e6-538c9ff83b53 persistent: true insertionIndex: 156 +--- +id: 9cf035b1-1d20-40fe-ae7f-d4658b6c2b6c +name: chat_completions +request: + url: /chat/completions + method: POST + bodyPatterns: + - equalToJson: |- + { + "messages" : [ { + "content" : "You are an assistant which just answers every query with tomato", + "role" : "developer" + }, { + "content" : "Say something", + "role" : "user" + } ], + "model" : "gpt-4o-mini" + } + ignoreArrayOrder: false + ignoreExtraElements: false +response: + status: 200 + body: | + { + "id": "chatcmpl-Axv1FgV1kYD5pEnZxEtx8xxyUzOY6", + "object": "chat.completion", + "created": 1738843897, + "model": "gpt-4o-mini-2024-07-18", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "Tomato.", + "refusal": null + }, + "logprobs": null, + "finish_reason": "stop" + } + ], + "usage": { + "prompt_tokens": 24, + "completion_tokens": 4, + "total_tokens": 28, + "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_72ed7ab54c" + } + headers: + Date: "Thu, 06 Feb 2025 12:11:37 GMT" + Content-Type: application/json + access-control-expose-headers: X-Request-ID + openai-organization: test_openai_org_id + openai-processing-ms: "293" + openai-version: 2020-10-01 + x-ratelimit-limit-requests: "10000" + x-ratelimit-limit-tokens: "200000" + x-ratelimit-remaining-requests: "9998" + x-ratelimit-remaining-tokens: "199962" + x-ratelimit-reset-requests: 16.352s + x-ratelimit-reset-tokens: 11ms + x-request-id: req_50bca1112cf267b0d9002dc20daf38f6 + strict-transport-security: max-age=31536000; includeSubDomains; preload + cf-cache-status: DYNAMIC + Set-Cookie: test_set_cookie + X-Content-Type-Options: nosniff + Server: cloudflare + CF-RAY: 90db0b36dbed1e51-FRA + alt-svc: h3=":443"; ma=86400 +uuid: 9cf035b1-1d20-40fe-ae7f-d4658b6c2b6c +persistent: true +insertionIndex: 57 diff --git a/renovate.json b/renovate.json index ad64255c..6f9d74ed 100644 --- a/renovate.json +++ b/renovate.json @@ -19,6 +19,6 @@ ".buildkite/**", "examples/**", "jvmti-access/jni-build/*.Dockerfile", - "instrumentation/openai-client-instrumentation/instrumentation-0.2/build.gradle.kts" + "instrumentation/openai-client-instrumentation/instrumentation-0.8/build.gradle.kts" ] } diff --git a/settings.gradle.kts b/settings.gradle.kts index 8edd172a..598a04ac 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -19,7 +19,7 @@ include("custom") include("instrumentation") include("instrumentation:openai-client-instrumentation:common") include("instrumentation:openai-client-instrumentation:testing-common") -include("instrumentation:openai-client-instrumentation:instrumentation-0.2") +include("instrumentation:openai-client-instrumentation:instrumentation-0.8") include("instrumentation:openai-client-instrumentation:instrumentation-0.14") include("inferred-spans") include("resources")