@@ -82,6 +82,7 @@ public class DebugEmlSuperAgentRunServiceImpl implements DebugEmlSuperAgentRunSe
private static final Logger log = LoggerFactory . getLogger ( DebugEmlSuperAgentRunServiceImpl . class ) ;
private static final String SOURCE_PROVIDER = " DEBUG_EML_UPLOAD " ;
private static final String SOURCE_CHANNEL = " EMAIL " ;
private static final String REPLY_POLICY_MODE = " manual " ;
private static final String SCHEMA_VERSION = " debug-eml-upload-v1 " ;
private static final DateTimeFormatter DATE_FOLDER_FORMATTER = DateTimeFormatter . BASIC_ISO_DATE ;
private static final Pattern CID_REFERENCE_PATTERN = Pattern . compile (
@@ -479,12 +480,9 @@ public class DebugEmlSuperAgentRunServiceImpl implements DebugEmlSuperAgentRunSe
String htmlBodySanitized = htmlSanitizerService . sanitizeHtml ( htmlWithOssUrls ) ;
String htmlRenderMode = htmlSanitizerService . htmlRenderMode ( htmlWithOssUrls ) ;
Map < String , Object > payload = buildAgentBusLikePayload (
runId ,
runLabel ,
createdAt ,
externalMessageId ,
externalConversationId ,
originalMessageId ,
originalConversationId ,
parsed ,
htmlWithOssUrls ,
uploadedMedia ) ;
@@ -528,11 +526,15 @@ public class DebugEmlSuperAgentRunServiceImpl implements DebugEmlSuperAgentRunSe
SuperAgentMailDebugRequest superAgentRequest = new SuperAgentMailDebugRequest (
buildSuperAgentMessage ( payloadJson ) ,
" debug-eml- " + runId ,
Map . of (
" source " , " th-hotel-debug-eml-upload " ,
" debug_run_id " , runId . toString ( ) ,
" source_message_id " , captureResult . inboxId ( ) . toString ( ) ,
" hotel_id " , hotelId ) ) ;
buildSuperAgentMetadata (
runId ,
runLabel ,
captureResult . inboxId ( ) ,
hotelId ,
externalMessageId ,
externalConversationId ,
originalMessageId ,
originalConversationId ) ) ;
List < SuperAgentOpenApiTraceEvent > streamedTraceEvents = new ArrayList < > ( ) ;
Consumer < SuperAgentOpenApiTraceEvent > traceConsumer = traceEvent - > {
streamedTraceEvents . add ( traceEvent ) ;
@@ -919,28 +921,24 @@ public class DebugEmlSuperAgentRunServiceImpl implements DebugEmlSuperAgentRunSe
}
/**
* 组装接近 AgentBus 邮件输入的 payload。
* 组装发给 SuperAgent 的 AgentBus Outlook 邮件 payload。调试来源信息放入 Open API metadata,
* 避免 DEBUG_EML_UPLOAD 等调试语义影响 SuperAgent 对实时 AgentBus 邮件的判断。
*/
private Map < String , Object > buildAgentBusLikePayload (
Long runId ,
String runLabel ,
LocalDateTime createdAt ,
String externalMessageId ,
String externalConversationId ,
String originalMessageId ,
String originalConversationId ,
ParsedEmlMessage parsed ,
String htmlWithOssUrls ,
List < UploadedMedia > uploadedMedia ) {
Map < String , Object > source = new LinkedHashMap < > ( ) ;
source . put ( " channel " , SOURCE_CHANNEL ) ;
source . put ( " provider " , SOURCE_PROVIDER ) ;
source . put ( " external_message_id " , externalMessageId ) ;
source . put ( " external_conversation_id " , externalConversationId ) ;
source . put ( " original_message_id " , originalMessageId ) ;
source . put ( " original_conversation_id " , originalConversationId ) ;
source . put ( " sender " , parsed . sender ( ) ) ;
source . put ( " subject " , parsed . subject ( ) ) ;
source . put ( " sent_at " , parsed . sentAt ( ) = = null ? null : parsed . sentAt ( ) . toString ( ) ) ;
source . put ( " received_at " , utcInstantText ( createdAt ) ) ;
Map < String , Object > body = new LinkedHashMap < > ( ) ;
body . put ( " content_type " , contentType ( parsed , htmlWithOssUrls ) ) ;
@@ -950,26 +948,56 @@ public class DebugEmlSuperAgentRunServiceImpl implements DebugEmlSuperAgentRunSe
List < Map < String , Object > > inlineImages = mediaPayload ( uploadedMedia , SourceMessageMediaType . INLINE_IMAGE . code ( ) ) ;
List < Map < String , Object > > attachments = mediaPayload ( uploadedMedia , SourceMessageMediaType . ATTACHMENT . code ( ) ) ;
Map < String , Object > replyPolicy = new LinkedHashMap < > ( ) ;
replyPolicy . put ( " mode " , " debug_only " ) ;
replyPolicy . put ( " final_only " , true ) ;
Map < String , Object > debugContext = new LinkedHashMap < > ( ) ;
debugContext . put ( " debug_run_id " , runId . toString ( ) ) ;
debugContext . put ( " run_label " , runLabel ) ;
debugContext . put ( " original_eml_oss_url " , uploadedMedia . get ( 0 ) . result ( ) . externalUrl ( ) ) ;
Map < String , Object > payload = new LinkedHashMap < > ( ) ;
payload . put ( " schema_version " , SCHEMA_VERSION ) ;
payload . put ( " text " , parsed . textBody ( ) ) ;
payload . put ( " received_at " , utcInstantText ( createdAt ) ) ;
payload . put ( " source " , source ) ;
payload . put ( " body " , body ) ;
payload . put ( " inline_images " , inlineImages ) ;
payload . put ( " attachments " , attachments ) ;
payload . put ( " reply_policy " , replyPolicy ) ;
payload . put ( " debug_context " , debugContext ) ;
payload . put ( " reply_policy " , replyPolicy ( ) );
return payload ;
}
/**
* 构造 AgentBus Outlook 关键字段中的回复策略。Debug 链路第一版不自动回复客户,使用非 Debug 专属的人工处理语义。
*/
private Map < String , Object > replyPolicy ( ) {
Map < String , Object > replyPolicy = new LinkedHashMap < > ( ) ;
replyPolicy . put ( " mode " , REPLY_POLICY_MODE ) ;
replyPolicy . put ( " final_only " , true ) ;
return replyPolicy ;
}
/**
* 构造 Debug EML 调用 SuperAgent 的 metadata。这里保存调试来源和原始 EML 标识,不混入邮件主 payload。
*/
private Map < String , Object > buildSuperAgentMetadata (
Long runId ,
String runLabel ,
Long sourceMessageId ,
String hotelId ,
String externalMessageId ,
String externalConversationId ,
String originalMessageId ,
String originalConversationId ) {
Map < String , Object > debugContext = new LinkedHashMap < > ( ) ;
putIfNotNull ( debugContext , " debug_run_id " , runId = = null ? null : runId . toString ( ) ) ;
putIfNotNull ( debugContext , " run_label " , runLabel ) ;
putIfNotNull ( debugContext , " original_message_id " , originalMessageId ) ;
putIfNotNull ( debugContext , " original_conversation_id " , originalConversationId ) ;
Map < String , Object > metadata = new LinkedHashMap < > ( ) ;
metadata . put ( " source " , " th-hotel-debug-eml-upload " ) ;
putIfNotNull ( metadata , " debug_run_id " , runId = = null ? null : runId . toString ( ) ) ;
putIfNotNull ( metadata , " source_message_id " , sourceMessageId = = null ? null : sourceMessageId . toString ( ) ) ;
putIfNotNull ( metadata , " hotel_id " , hotelId ) ;
putIfNotNull ( metadata , " external_message_id " , externalMessageId ) ;
putIfNotNull ( metadata , " external_conversation_id " , externalConversationId ) ;
metadata . put ( " debug_context " , debugContext ) ;
return metadata ;
}
/**
* 构造媒体 payload 数组。
*/
@@ -978,13 +1006,12 @@ public class DebugEmlSuperAgentRunServiceImpl implements DebugEmlSuperAgentRunSe
. filter ( item - > mediaType . equals ( item . result ( ) . mediaType ( ) ) )
. map ( item - > {
Map < String , Object > media = new LinkedHashMap < > ( ) ;
media . put ( " id " , item . result ( ) . externalMediaId ( ) ) ;
media . put ( " media_type " , item . result ( ) . mediaType ( ) ) ;
media . put ( " file_name " , item . result ( ) . fileName ( ) ) ;
media . put ( " content_type " , item . result ( ) . contentType ( ) ) ;
media . put ( " size_bytes " , item . result ( ) . sizeBytes ( ) ) ;
media . put ( " external_url " , item . result ( ) . externalUrl ( ) ) ;
media . put ( " external_media_id " , item . result ( ) . externalMediaId ( ) ) ;
media . put ( " object_key " , item . result ( ) . objectKey ( ) ) ;
if ( item . contentId ( ) ! = null ) {
media . put ( " content_id " , item . contentId ( ) ) ;
}
@@ -1000,16 +1027,21 @@ public class DebugEmlSuperAgentRunServiceImpl implements DebugEmlSuperAgentRunSe
boolean hasText = parsed . textBody ( ) ! = null & & ! parsed . textBody ( ) . isBlank ( ) ;
boolean hasHtml = htmlWithOssUrls ! = null & & ! htmlWithOssUrls . isBlank ( ) ;
if ( hasText & & hasHtml ) {
return " MIXED " ;
return " mixed " ;
}
return hasHtml ? " HTML " : " TEXT " ;
return hasHtml ? " html " : " text " ;
}
/**
* 构造发送给 SuperAgent 的消息文本。
*/
private String buildSuperAgentMessage ( String payloadJson ) {
return "请基于以下 Debug 邮件 JSON 输出结构化任务抽取结果,只返回 JSON, 不要创建订单或任务: \ n " + payloadJson ;
return """
请基于以下 AgentBus Outlook 邮件 JSON 输出结构化任务抽取结果。
只返回 SuperAgent 当前约定的 JSON 或 S10/S99 特殊结果, 不要创建订单、任务、OPERA 操作或客户回复。
AgentBus Outlook 邮件 JSON:
""" + payloadJson ;
}
/**
@@ -1282,6 +1314,25 @@ public class DebugEmlSuperAgentRunServiceImpl implements DebugEmlSuperAgentRunSe
return trimmed . isEmpty ( ) ? null : trimmed ;
}
/**
* 向 metadata 写入非空字段,避免 Map.of 不能容纳 null, 也避免输出无意义空值。
*/
private void putIfNotNull ( Map < String , Object > target , String key , Object value ) {
if ( value ! = null ) {
target . put ( key , value ) ;
}
}
/**
* 将数据库 UTC LocalDateTime 转为带 Z 的 ISO-8601 时间点。
*/
private String utcInstantText ( LocalDateTime value ) {
if ( value = = null ) {
return null ;
}
return value . atOffset ( ZoneOffset . UTC ) . toInstant ( ) . toString ( ) ;
}
/**
* 去掉 URL 末尾斜杠,便于用公开基础 URL 还原对象路径。
*/