实现SuperAgent特殊入口结果处理
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
package cn.nianxx.thhotel.platform.common.enums;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* SuperAgent 入口阶段非结构化结果码。该结果只说明来源消息处理结论,不代表业务任务。
|
||||
*/
|
||||
public enum SourceMessageOnlyResultCode {
|
||||
/** 纯信息类邮件,不需要形成业务素材包。 */
|
||||
S000("S000", "PURE_INFORMATION", "纯信息类邮件"),
|
||||
/** 入口问题导致无法形成业务素材包。 */
|
||||
S999("S999", "MATERIAL_PACKAGE_UNAVAILABLE", "无法形成业务素材包");
|
||||
|
||||
private final String code;
|
||||
private final String meaning;
|
||||
private final String description;
|
||||
|
||||
SourceMessageOnlyResultCode(String code, String meaning, String description) {
|
||||
this.code = code;
|
||||
this.meaning = meaning;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String code() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String meaning() {
|
||||
return meaning;
|
||||
}
|
||||
|
||||
public String description() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按 SuperAgent 返回的稳定代码查找枚举,大小写敏感,避免误吞其他文本。
|
||||
*/
|
||||
public static Optional<SourceMessageOnlyResultCode> fromCode(String code) {
|
||||
return Arrays.stream(values())
|
||||
.filter(value -> value.code.equals(code))
|
||||
.findFirst();
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import cn.nianxx.thhotel.integrations.storage.aliyunoss.common.result.ObjectStor
|
||||
import cn.nianxx.thhotel.integrations.storage.aliyunoss.service.ObjectStorageService;
|
||||
import cn.nianxx.thhotel.integrations.storage.aliyunoss.service.impl.AliyunOssProperties;
|
||||
import cn.nianxx.thhotel.integrations.storage.aliyunoss.service.impl.ObjectStorageException;
|
||||
import cn.nianxx.thhotel.platform.common.enums.SourceMessageOnlyResultCode;
|
||||
import cn.nianxx.thhotel.platform.debug.common.dto.DebugEmlSuperAgentRunDraft;
|
||||
import cn.nianxx.thhotel.platform.debug.common.dto.DebugEmlSuperAgentRunStatusUpdate;
|
||||
import cn.nianxx.thhotel.platform.debug.common.dto.DebugEmlSuperAgentRunUpdate;
|
||||
@@ -27,8 +28,11 @@ import cn.nianxx.thhotel.platform.message.service.EmlMessageParseService;
|
||||
import cn.nianxx.thhotel.platform.message.service.SourceMessageCaptureService;
|
||||
import cn.nianxx.thhotel.platform.message.service.SourceMessageHtmlSanitizerService;
|
||||
import cn.nianxx.thhotel.platform.message.service.impl.EmlMessageParseException;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
@@ -47,6 +51,8 @@ import java.util.regex.Pattern;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.client.ResourceAccessException;
|
||||
import org.springframework.web.client.RestClientResponseException;
|
||||
|
||||
/**
|
||||
* Debug EML 上传到 SuperAgent 服务实现。编排解析、OSS、SourceMessage 和 SuperAgent 调用。
|
||||
@@ -139,7 +145,7 @@ public class DebugEmlSuperAgentRunServiceImpl implements DebugEmlSuperAgentRunSe
|
||||
"OSS 上传失败。",
|
||||
exception);
|
||||
} catch (SuperAgentOpenApiException exception) {
|
||||
markFailed(runId, "SuperAgent 调用失败。", DebugEmlSuperAgentRunStatus.SUPERAGENT_FAILED, nowUtc());
|
||||
markFailed(runId, superAgentFailureSummary(exception), DebugEmlSuperAgentRunStatus.SUPERAGENT_FAILED, nowUtc());
|
||||
throw new DebugEmlSuperAgentException(
|
||||
HttpStatus.BAD_GATEWAY,
|
||||
"SUPERAGENT_OPEN_API_FAILED",
|
||||
@@ -155,6 +161,66 @@ public class DebugEmlSuperAgentRunServiceImpl implements DebugEmlSuperAgentRunSe
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 SuperAgent 失败安全摘要,只记录错误类型,不保存响应 body、API Key、正文或附件 URL。
|
||||
*/
|
||||
private String superAgentFailureSummary(SuperAgentOpenApiException exception) {
|
||||
Throwable rootCause = rootCause(exception);
|
||||
if (rootCause instanceof RestClientResponseException responseException) {
|
||||
return "SuperAgent Open API HTTP 调用失败,HTTP 状态:" + responseException.getStatusCode().value() + "。";
|
||||
}
|
||||
if (hasCause(exception, SocketTimeoutException.class)) {
|
||||
return "SuperAgent Open API 调用超时。";
|
||||
}
|
||||
if (hasCause(exception, ResourceAccessException.class)) {
|
||||
return "SuperAgent Open API 网络连接失败。";
|
||||
}
|
||||
if (rootCause instanceof JsonProcessingException) {
|
||||
return "SuperAgent Open API 响应 JSON 解析失败。";
|
||||
}
|
||||
String message = trimToNull(exception.getMessage());
|
||||
if (message != null && !"SuperAgent Open API 调用失败。".equals(message)) {
|
||||
return safeErrorSummary(message);
|
||||
}
|
||||
return "SuperAgent Open API 调用失败。";
|
||||
}
|
||||
|
||||
/**
|
||||
* 取最底层异常,便于判断 HTTP、网络和解析失败类型。
|
||||
*/
|
||||
private Throwable rootCause(Throwable throwable) {
|
||||
Throwable current = throwable;
|
||||
while (current.getCause() != null) {
|
||||
current = current.getCause();
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断异常链中是否包含指定类型。
|
||||
*/
|
||||
private boolean hasCause(Throwable throwable, Class<? extends Throwable> causeType) {
|
||||
Throwable current = throwable;
|
||||
while (current != null) {
|
||||
if (causeType.isInstance(current)) {
|
||||
return true;
|
||||
}
|
||||
current = current.getCause();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 限制错误摘要长度,避免外部异常消息过长进入调试表。
|
||||
*/
|
||||
private String safeErrorSummary(String message) {
|
||||
String value = message.trim();
|
||||
if (value.length() <= 512) {
|
||||
return value;
|
||||
}
|
||||
return value.substring(0, 512);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行已创建 runId 的主流程。
|
||||
*/
|
||||
@@ -534,6 +600,10 @@ public class DebugEmlSuperAgentRunServiceImpl implements DebugEmlSuperAgentRunSe
|
||||
warnings.add("SuperAgent 最终回答为空。");
|
||||
return null;
|
||||
}
|
||||
JsonNode sourceMessageOnlyResult = parseSourceMessageOnlyResult(rawAnswer);
|
||||
if (sourceMessageOnlyResult != null) {
|
||||
return sourceMessageOnlyResult;
|
||||
}
|
||||
try {
|
||||
return objectMapper.readTree(rawAnswer);
|
||||
} catch (Exception exception) {
|
||||
@@ -542,6 +612,32 @@ public class DebugEmlSuperAgentRunServiceImpl implements DebugEmlSuperAgentRunSe
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 识别 Debug 链路中的 S000/S999 入口结果,避免把可识别文本误报为 JSON 解析失败。
|
||||
*/
|
||||
private JsonNode parseSourceMessageOnlyResult(String rawAnswer) {
|
||||
String trimmedAnswer = trimToNull(rawAnswer);
|
||||
if (trimmedAnswer == null) {
|
||||
return null;
|
||||
}
|
||||
int separatorIndex = trimmedAnswer.indexOf(',');
|
||||
String code = separatorIndex < 0 ? trimmedAnswer : trimmedAnswer.substring(0, separatorIndex).trim();
|
||||
SourceMessageOnlyResultCode resultCode = SourceMessageOnlyResultCode.fromCode(code).orElse(null);
|
||||
if (resultCode == null || separatorIndex < 0) {
|
||||
return null;
|
||||
}
|
||||
String sourceMessageId = trimToNull(trimmedAnswer.substring(separatorIndex + 1));
|
||||
if (sourceMessageId == null) {
|
||||
return null;
|
||||
}
|
||||
ObjectNode result = objectMapper.createObjectNode();
|
||||
result.put("entry_result_code", resultCode.code());
|
||||
result.put("entry_result_source_message_id", sourceMessageId);
|
||||
result.put("entry_result_meaning", resultCode.meaning());
|
||||
result.put("entry_result_description", resultCode.description());
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记 Debug 运行失败。
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user