实现SuperAgent特殊入口结果处理

This commit is contained in:
andy
2026-07-10 12:05:57 +08:00
parent 9de4f0e7b6
commit 74e429a2cb
29 changed files with 1121 additions and 97 deletions

View File

@@ -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();
}
}

View File

@@ -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 运行失败。
*/