[OpenAiChatModel] Inability to Pass `tool_calls` or `tool_call_id` and Discrepancy in Message Roles
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.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.MessageTypeinAbstractMessage:public enum MessageType { USER("user"), ASSISTANT("assistant"), SYSTEM("system"), FUNCTION("function"); }Rolein OpenAI messages: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.
- The
-
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.
- The
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...
}
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?
@RikJux please let us know if this is resolved. Will close in 7 days if no response. Thank you.
Closing for now.