From 866b262cddb10a54b832b9cd1ca25fa3c698dee4 Mon Sep 17 00:00:00 2001 From: TarasVovk669 Date: Wed, 7 Aug 2024 11:55:31 +0200 Subject: [PATCH] Add `refusal` field to ChatCompletionMessage and related classes - Updated OpenAiChatModel, OpenAiApi, and OpenAiStreamFunctionCallingHelper to include the `refusal` field in metadata. - Adjusted constructors and methods to handle the new `refusal` attribute. - Modified related tests to account for the new `refusal` field. - Add the refusal field value to the Spring AI AssistantMessage metadata Resolves #1178 --- .../ai/openai/OpenAiChatModel.java | 20 ++++++++++--------- .../ai/openai/api/OpenAiApi.java | 5 +++-- .../OpenAiStreamFunctionCallingHelper.java | 3 ++- .../api/tool/OpenAiApiToolFunctionCallIT.java | 2 +- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiChatModel.java b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiChatModel.java index b4d479a91..3ecad08d3 100644 --- a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiChatModel.java +++ b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiChatModel.java @@ -241,12 +241,13 @@ public class OpenAiChatModel extends AbstractToolCallSupport implements ChatMode List generations = choices.stream().map(choice -> { // @formatter:off - Map metadata = Map.of( - "id", chatCompletion.id() != null ? chatCompletion.id() : "", - "role", choice.message().role() != null ? choice.message().role().name() : "", - "index", choice.index(), - "finishReason", choice.finishReason() != null ? choice.finishReason().name() : ""); - // @formatter:on + Map metadata = Map.of( + "id", chatCompletion.id() != null ? chatCompletion.id() : "", + "role", choice.message().role() != null ? choice.message().role().name() : "", + "index", choice.index(), + "finishReason", choice.finishReason() != null ? choice.finishReason().name() : "", + "refusal", StringUtils.hasText(choice.message().refusal()) ? choice.message().refusal() : ""); + // @formatter:on return buildGeneration(choice, metadata); }).toList(); @@ -313,7 +314,8 @@ public class OpenAiChatModel extends AbstractToolCallSupport implements ChatMode "id", chatCompletion2.id(), "role", roleMap.getOrDefault(id, ""), "index", choice.index(), - "finishReason", choice.finishReason() != null ? choice.finishReason().name() : ""); + "finishReason", choice.finishReason() != null ? choice.finishReason().name() : "", + "refusal", StringUtils.hasText(choice.message().refusal()) ? choice.message().refusal() : ""); return buildGeneration(choice, metadata); }).toList(); @@ -453,7 +455,7 @@ public class OpenAiChatModel extends AbstractToolCallSupport implements ChatMode }).toList(); } return List.of(new ChatCompletionMessage(assistantMessage.getContent(), - ChatCompletionMessage.Role.ASSISTANT, null, null, toolCalls)); + ChatCompletionMessage.Role.ASSISTANT, null, null, toolCalls, null)); } else if (message.getMessageType() == MessageType.TOOL) { ToolResponseMessage toolMessage = (ToolResponseMessage) message; @@ -466,7 +468,7 @@ public class OpenAiChatModel extends AbstractToolCallSupport implements ChatMode return toolMessage.getResponses() .stream() .map(tr -> new ChatCompletionMessage(tr.responseData(), ChatCompletionMessage.Role.TOOL, tr.name(), - tr.id(), null)) + tr.id(), null, null)) .toList(); } else { diff --git a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiApi.java b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiApi.java index c71cb02a5..f946c98d5 100644 --- a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiApi.java +++ b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiApi.java @@ -560,7 +560,8 @@ public class OpenAiApi { @JsonProperty("role") Role role, @JsonProperty("name") String name, @JsonProperty("tool_call_id") String toolCallId, - @JsonProperty("tool_calls") List toolCalls) {// @formatter:on + @JsonProperty("tool_calls") List toolCalls, + @JsonProperty("refusal") String refusal) {// @formatter:on /** * Get message content as String. @@ -582,7 +583,7 @@ public class OpenAiApi { * @param role The role of the author of this message. */ public ChatCompletionMessage(Object content, Role role) { - this(content, role, null, null, null); + this(content, role, null, null, null, null); } /** diff --git a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiStreamFunctionCallingHelper.java b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiStreamFunctionCallingHelper.java index b0e23ce36..02bfd3108 100644 --- a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiStreamFunctionCallingHelper.java +++ b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiStreamFunctionCallingHelper.java @@ -91,6 +91,7 @@ public class OpenAiStreamFunctionCallingHelper { role = (role != null ? role : Role.ASSISTANT); // default to ASSISTANT (if null String name = (current.name() != null ? current.name() : previous.name()); String toolCallId = (current.toolCallId() != null ? current.toolCallId() : previous.toolCallId()); + String refusal = (current.refusal() != null ? current.refusal() : previous.refusal()); List toolCalls = new ArrayList<>(); ToolCall lastPreviousTooCall = null; @@ -120,7 +121,7 @@ public class OpenAiStreamFunctionCallingHelper { toolCalls.add(lastPreviousTooCall); } } - return new ChatCompletionMessage(content, role, name, toolCallId, toolCalls); + return new ChatCompletionMessage(content, role, name, toolCallId, toolCalls, refusal); } private ToolCall merge(ToolCall previous, ToolCall current) { diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/api/tool/OpenAiApiToolFunctionCallIT.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/api/tool/OpenAiApiToolFunctionCallIT.java index 8b2241024..1753b6eac 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/api/tool/OpenAiApiToolFunctionCallIT.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/api/tool/OpenAiApiToolFunctionCallIT.java @@ -122,7 +122,7 @@ public class OpenAiApiToolFunctionCallIT { // extend conversation with function response. messages.add(new ChatCompletionMessage("" + weatherResponse.temp() + weatherRequest.unit(), - Role.TOOL, functionName, toolCall.id(), null)); + Role.TOOL, functionName, toolCall.id(), null, null)); } }