Skip to content

Commit c613d88

Browse files
Fix OpenAI Java 4.54 compatibility (#12340)
Fix OpenAI Java 4.54 compatibility Address OpenAI compatibility review feedback [skip ci] Merge branch 'master' into alexeyk/fix-openai-java-4.54-muzzle Co-authored-by: alexey.kuznetsov <alexey.kuznetsov@datadoghq.com>
1 parent 3726ca3 commit c613d88

5 files changed

Lines changed: 194 additions & 11 deletions

File tree

dd-java-agent/instrumentation/openai-java/openai-java-3.0/gradle.lockfile

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,11 @@ com.google.j2objc:j2objc-annotations:2.8=annotationProcessor,latestDepTestAnnota
6161
com.google.j2objc:j2objc-annotations:3.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath
6262
com.google.re2j:re2j:1.8=latestDepTestRuntimeClasspath,testRuntimeClasspath
6363
com.openai:openai-java-client-okhttp:3.0.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
64-
com.openai:openai-java-client-okhttp:4.52.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath
64+
com.openai:openai-java-client-okhttp:4.54.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath
6565
com.openai:openai-java-core:3.0.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
66-
com.openai:openai-java-core:4.52.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath
66+
com.openai:openai-java-core:4.54.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath
6767
com.openai:openai-java:3.0.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
68-
com.openai:openai-java:4.52.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath
68+
com.openai:openai-java:4.54.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath
6969
com.squareup.moshi:moshi:1.11.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath
7070
com.squareup.okhttp3:logging-interceptor:3.12.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath
7171
com.squareup.okhttp3:logging-interceptor:4.12.0=testRuntimeClasspath
@@ -118,7 +118,8 @@ org.hamcrest:hamcrest-core:1.3=latestDepTestRuntimeClasspath,testRuntimeClasspat
118118
org.hamcrest:hamcrest:3.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath
119119
org.jctools:jctools-core-jdk11:4.0.6=latestDepTestRuntimeClasspath,testRuntimeClasspath
120120
org.jctools:jctools-core:4.0.6=latestDepTestRuntimeClasspath,testRuntimeClasspath
121-
org.jetbrains.kotlin:kotlin-reflect:1.8.10=latestDepTestRuntimeClasspath,testRuntimeClasspath
121+
org.jetbrains.kotlin:kotlin-reflect:1.8.10=testRuntimeClasspath
122+
org.jetbrains.kotlin:kotlin-reflect:1.8.20=latestDepTestRuntimeClasspath
122123
org.jetbrains.kotlin:kotlin-stdlib-common:1.8.0=compileClasspath,latestDepTestCompileClasspath,testCompileClasspath
123124
org.jetbrains.kotlin:kotlin-stdlib-common:1.9.10=latestDepTestRuntimeClasspath,testRuntimeClasspath
124125
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0=compileClasspath,latestDepTestCompileClasspath,testCompileClasspath

dd-java-agent/instrumentation/openai-java/openai-java-3.0/src/main/java/datadog/trace/instrumentation/openai_java/FunctionCallOutputExtractor.java

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,11 @@
33
import com.openai.models.responses.ResponseInputItem;
44
import datadog.trace.util.MethodHandles;
55
import java.lang.invoke.MethodHandle;
6+
import java.util.Optional;
67
import org.slf4j.Logger;
78
import org.slf4j.LoggerFactory;
89

9-
/**
10-
* Helper class to handle FunctionCallOutput.output() method changes between openai-java versions.
11-
*
12-
* <p>In version 3.x: output() returns String In version 4.0+: output() returns Output)
13-
*/
10+
/** Helper class to handle FunctionCallOutput method changes between openai-java versions. */
1411
public class FunctionCallOutputExtractor {
1512
private static final Logger log = LoggerFactory.getLogger(FunctionCallOutputExtractor.class);
1613

@@ -19,11 +16,13 @@ public class FunctionCallOutputExtractor {
1916
private static final MethodHandles METHOD_HANDLES =
2017
new MethodHandles(FUNCTION_CALL_OUTPUT_CLASS.getClassLoader());
2118

19+
private static final MethodHandle CALL_ID_METHOD;
2220
private static final MethodHandle OUTPUT_METHOD;
2321
private static final MethodHandle IS_STRING_METHOD;
2422
private static final MethodHandle AS_STRING_METHOD;
2523

2624
static {
25+
CALL_ID_METHOD = METHOD_HANDLES.method(FUNCTION_CALL_OUTPUT_CLASS, "callId");
2726
OUTPUT_METHOD = METHOD_HANDLES.method(FUNCTION_CALL_OUTPUT_CLASS, "output");
2827

2928
Class<?> outputClass = null;
@@ -46,6 +45,36 @@ public class FunctionCallOutputExtractor {
4645
}
4746
}
4847

48+
/**
49+
* Extracts the function call ID across openai-java versions.
50+
*
51+
* <ul>
52+
* <li>Versions before 4.54: {@code callId()} returns {@code String}.
53+
* <li>Version 4.54+: {@code callId()} returns {@code Optional<String>}.
54+
* </ul>
55+
*/
56+
public static String getCallIdAsString(ResponseInputItem.FunctionCallOutput functionCallOutput) {
57+
try {
58+
Object callId = METHOD_HANDLES.invoke(CALL_ID_METHOD, functionCallOutput);
59+
if (callId instanceof Optional) {
60+
callId = ((Optional<?>) callId).orElse(null);
61+
}
62+
if (callId == null || callId instanceof String) {
63+
return (String) callId;
64+
}
65+
} catch (Throwable ignored) {
66+
}
67+
return null;
68+
}
69+
70+
/**
71+
* Extracts the function call output across openai-java versions.
72+
*
73+
* <ul>
74+
* <li>Version 3.x: {@code output()} returns {@code String}.
75+
* <li>Version 4.0+: {@code output()} returns {@code Output}.
76+
* </ul>
77+
*/
4978
public static String getOutputAsString(ResponseInputItem.FunctionCallOutput functionCallOutput) {
5079
try {
5180
Object output = METHOD_HANDLES.invoke(OUTPUT_METHOD, functionCallOutput);

dd-java-agent/instrumentation/openai-java/openai-java-3.0/src/main/java/datadog/trace/instrumentation/openai_java/ResponseDecorator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ private LLMObs.LLMMessage extractInputItemMessage(ResponseInputItem item) {
279279
Optional<ResponseInputItem.FunctionCallOutput> functionCallOutput = item.functionCallOutput();
280280
if (functionCallOutput.isPresent()) {
281281
ResponseInputItem.FunctionCallOutput output = functionCallOutput.get();
282-
String callId = output.callId();
282+
String callId = FunctionCallOutputExtractor.getCallIdAsString(output);
283283
String result = FunctionCallOutputExtractor.getOutputAsString(output);
284284
LLMObs.ToolResult toolResult =
285285
LLMObs.ToolResult.from("", "function_call_output", callId, result);

dd-java-agent/instrumentation/openai-java/openai-java-3.0/src/test/groovy/ResponseServiceTest.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ class ResponseServiceTest extends OpenAiTest {
216216
inputTags[1].toolCalls[0].arguments == [location: "San Francisco, CA"]
217217
inputTags[2].toolResults.size() == 1
218218
inputTags[2].toolResults[0].type == "function_call_output"
219-
!inputTags.isEmpty()
219+
inputTags[2].toolResults[0].toolId == "call_123"
220220
inputTags[2].toolResults[0].result == '{"temperature": "72°F", "conditions": "sunny", "humidity": "65%"}'
221221
222222
where:

0 commit comments

Comments
 (0)