diff --git a/agents-flex-core/src/main/java/com/agentsflex/core/parser/impl/DefaultAiMessageParser.java b/agents-flex-core/src/main/java/com/agentsflex/core/parser/impl/DefaultAiMessageParser.java new file mode 100644 index 0000000..e0bbaa3 --- /dev/null +++ b/agents-flex-core/src/main/java/com/agentsflex/core/parser/impl/DefaultAiMessageParser.java @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2023-2025, Agents-Flex (fuhai999@gmail.com). + *
+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * http://www.apache.org/licenses/LICENSE-2.0 + *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.agentsflex.core.parser.impl;
+
+import com.agentsflex.core.message.AiMessage;
+import com.agentsflex.core.message.FunctionCall;
+import com.agentsflex.core.message.MessageStatus;
+import com.agentsflex.core.parser.AiMessageParser;
+import com.agentsflex.core.parser.JSONObjectParser;
+import com.agentsflex.core.util.StringUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.JSONPath;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+
+public class DefaultAiMessageParser implements AiMessageParser {
+
+ private String contentPath;
+ private String reasoningContentPath;
+ private String indexPath;
+ private String totalTokensPath;
+ private String promptTokensPath;
+ private String completionTokensPath;
+ private JSONObjectParser> callsParser;
+
+ public String getContentPath() {
+ return contentPath;
+ }
+
+ public void setContentPath(String contentPath) {
+ this.contentPath = contentPath;
+ }
+
+ public String getReasoningContentPath() {
+ return reasoningContentPath;
+ }
+
+ public void setReasoningContentPath(String reasoningContentPath) {
+ this.reasoningContentPath = reasoningContentPath;
+ }
+
+ public String getIndexPath() {
+ return indexPath;
+ }
+
+ public void setIndexPath(String indexPath) {
+ this.indexPath = indexPath;
+ }
+
+ public String getTotalTokensPath() {
+ return totalTokensPath;
+ }
+
+ public void setTotalTokensPath(String totalTokensPath) {
+ this.totalTokensPath = totalTokensPath;
+ }
+
+ public String getPromptTokensPath() {
+ return promptTokensPath;
+ }
+
+ public void setPromptTokensPath(String promptTokensPath) {
+ this.promptTokensPath = promptTokensPath;
+ }
+
+ public String getCompletionTokensPath() {
+ return completionTokensPath;
+ }
+
+ public void setCompletionTokensPath(String completionTokensPath) {
+ this.completionTokensPath = completionTokensPath;
+ }
+
+ public JSONObjectParser
> getCallsParser() {
+ return callsParser;
+ }
+
+ public void setCallsParser(JSONObjectParser
> callsParser) {
+ this.callsParser = callsParser;
+ }
+
+ @Override
+ public AiMessage parse(JSONObject rootJson) {
+ AiMessage aiMessage = new AiMessage();
+
+ if (StringUtil.hasText(this.contentPath)) {
+ aiMessage.setContent((String) JSONPath.eval(rootJson, this.contentPath));
+ }
+
+ if (StringUtil.hasText(this.reasoningContentPath)) {
+ aiMessage.setReasoningContent((String) JSONPath.eval(rootJson, this.reasoningContentPath));
+ }
+
+ if (StringUtil.hasText(this.indexPath)) {
+ aiMessage.setIndex((Integer) JSONPath.eval(rootJson, this.indexPath));
+ }
+
+
+ if (StringUtil.hasText(promptTokensPath)) {
+ aiMessage.setPromptTokens((Integer) JSONPath.eval(rootJson, this.promptTokensPath));
+ }
+
+ if (StringUtil.hasText(completionTokensPath)) {
+ aiMessage.setCompletionTokens((Integer) JSONPath.eval(rootJson, this.completionTokensPath));
+ }
+
+ if (StringUtil.hasText(this.totalTokensPath)) {
+ aiMessage.setTotalTokens((Integer) JSONPath.eval(rootJson, this.totalTokensPath));
+ }
+ //some LLMs like Ollama not response the total tokens
+ else if (aiMessage.getPromptTokens() != null && aiMessage.getCompletionTokens() != null) {
+ aiMessage.setTotalTokens(aiMessage.getPromptTokens() + aiMessage.getCompletionTokens());
+ }
+
+ if (this.statusParser != null) {
+ aiMessage.setStatus(this.statusParser.parse(rootJson));
+ }
+
+ if (callsParser != null) {
+ aiMessage.setCalls(callsParser.parse(rootJson));
+ }
+
+ return aiMessage;
+ }
+
+
+ public static DefaultAiMessageParser getChatGPTMessageParser(boolean isStream) {
+ DefaultAiMessageParser aiMessageParser = new DefaultAiMessageParser();
+ if (isStream) {
+ aiMessageParser.setContentPath("$.choices[0].delta.content");
+ aiMessageParser.setReasoningContentPath("$.choices[0].delta.reasoning_content");
+ } else {
+ aiMessageParser.setContentPath("$.choices[0].message.content");
+ aiMessageParser.setReasoningContentPath("$.choices[0].message.reasoning_content");
+ }
+
+ aiMessageParser.setIndexPath("$.choices[0].index");
+ aiMessageParser.setTotalTokensPath("$.usage.total_tokens");
+ aiMessageParser.setPromptTokensPath("$.usage.prompt_tokens");
+ aiMessageParser.setCompletionTokensPath("$.usage.completion_tokens");
+
+ aiMessageParser.setStatusParser(content -> {
+ Object finishReason = JSONPath.eval(content, "$.choices[0].finish_reason");
+ if (finishReason != null) {
+ return MessageStatus.END;
+ }
+ return MessageStatus.MIDDLE;
+ });
+
+ aiMessageParser.setCallsParser(content -> {
+ JSONArray toolCalls = (JSONArray) JSONPath.eval(content, "$.choices[0].message.tool_calls");
+ if (toolCalls == null || toolCalls.isEmpty()) {
+ return Collections.emptyList();
+ }
+ List