Description
There are two main issues with the current implementation of the createRequest method (see additional context below) in the OpenAiChatModel class:
- Inability to Pass
tool_callsortool_call_id: TheChatCompletionMessageconstructor called in thecreateRequestmethod does not allow passingtool_callsortool_call_id. These are always initialized asnull.
java
public ChatCompletionMessage(Object content, Role role) {
this(content, role, null, null, null);
}
- Discrepancy in Message Roles:
There is a discrepancy between the
MessageTypeenum inAbstractMessageand theRoleenum in OpenAI messages.
MessageType in AbstractMessage:
java
public enum MessageType {
USER("user"),
ASSISTANT("assistant"),
SYSTEM("system"),
FUNCTION("function");
}
Role in OpenAI messages:
java
public enum Role {
@JsonProperty("system")
SYSTEM,
@JsonProperty("user")
USER,
@JsonProperty("assistant")
ASSISTANT,
@JsonProperty("tool")
TOOL
}
This results in in an java.lang.IllegalArgumentException
Steps to Reproduce
Passing a FunctionMessage in a prompt results in an error:
@Test
public void testPromptWithTool() throws JsonProcessingException {
Prompt prompt = new Prompt(new FunctionMessage(""));
openAiChatModel.call(prompt);
}
Error:
java.lang.IllegalArgumentException: No enum constant org.springframework.ai.openai.api.OpenAiApi.ChatCompletionMessage.Role.FUNCTION
at java.base/java.lang.Enum.valueOf(Enum.java:293)
at org.springframework.ai.openai.api.OpenAiApi$ChatCompletionMessage$Role.valueOf(OpenAiApi.java:488)
at org.springframework.ai.openai.OpenAiChatModel.lambda$createRequest$9(OpenAiChatModel.java:267)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
at java.base/java.util.Collections$2.tryAdvance(Collections.java:5073)
at java.base/java.util.Collections$2.forEachRemaining(Collections.java:5081)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:575)
at java.base/java.util.stream.AbstractPipeline.evaluateToArrayNode(AbstractPipeline.java:260)
at java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:616)
at java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:622)
at java.base/java.util.stream.ReferencePipeline.toList(ReferencePipeline.java:627)
at org.springframework.ai.openai.OpenAiChatModel.createRequest(OpenAiChatModel.java:268)
at org.springframework.ai.openai.OpenAiChatModel.call(OpenAiChatModel.java:140)
at it.ai.foundation.ServiceChatModelTest.testPromptWithTool(ServiceChatModelTest.java:143)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
Expected Behavior
The current implementation of the createRequest method does not cover all possible prompts that a user could define. The expected behavior should be as follows:
- Support for Tool Calls:
-
The
createRequestmethod should allow passingtool_callsandtool_call_idto theChatCompletionMessageconstructor. This will enable the proper handling of tool calls within the chat prompt. -
Consistent Message Roles:
- The
MessageTypeenum inAbstractMessageshould be aligned with theRoleenum in OpenAI messages. Alternatively, a mapping should be provided to ensure that all message types are correctly translated and no errors occur due to missing enum constants.
Additional Context
Here is the current implementation of the createRequest method:
ChatCompletionRequest createRequest(Prompt prompt, boolean stream) {
Set<String> functionsForThisRequest = new HashSet<>();
List<ChatCompletionMessage> chatCompletionMessages = prompt.getInstructions().stream().map(m -> {
// Add text content.
List<MediaContent> contents = new ArrayList<>(List.of(new MediaContent(m.getContent())));
if (!CollectionUtils.isEmpty(m.getMedia())) {
// Add media content.
contents.addAll(m.getMedia()
.stream()
.map(media -> new MediaContent(
new MediaContent.ImageUrl(this.fromMediaData(media.getMimeType(), media.getData()))))
.toList());
}
return new ChatCompletionMessage(contents, ChatCompletionMessage.Role.valueOf(m.getMessageType().name()));
}).toList();
// rest of the code...
}
Comment From: ThomasVitale
Thanks for reporting this issue. The function calling APIs have been recently refactored and improved. The changes should have handled both points you reported.
- The
ChatCompletionMessagein theOpenAiApiclass accepts bothtoolCallIdandtoolCalls. See: https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiApi.java#L519 - The
MessageTypeenum usestoolas the role name instead offunction. See: https://github.com/spring-projects/spring-ai/blob/main/spring-ai-core/src/main/java/org/springframework/ai/chat/messages/MessageType.java#L51
Can you confirm this issue is fixed?
Comment From: csterwa
@RikJux please let us know if this is resolved. Will close in 7 days if no response. Thank you.
Comment From: csterwa
Closing for now.