对齐Debug EML V4入站模型
This commit is contained in:
@@ -17,8 +17,8 @@ public class SuperAgentOpenApiProperties {
|
||||
private String baseUrl = "";
|
||||
/** SuperAgent Open API Key。 */
|
||||
private String apiKey = "";
|
||||
/** Debug EML 创建 session 时使用的 external_subject_id。 */
|
||||
private String externalSubjectId = "th-hotel-debug-eml-upload";
|
||||
/** Debug EML 创建 session 时使用的 external_subject_id;默认对齐实时 AgentBus V4 profile。 */
|
||||
private String externalSubjectId = "th-hotel-agentbus-source-message";
|
||||
/** AgentBus 自动分发创建 session 时使用的 external_subject_id。 */
|
||||
private String agentbusExternalSubjectId = "th-hotel-agentbus-source-message";
|
||||
/** 建立连接超时。 */
|
||||
|
||||
@@ -157,7 +157,7 @@ public class DebugEmlSuperAgentRunServiceImpl implements DebugEmlSuperAgentRunSe
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理单封 Debug EML 上传;第一版只展示 SuperAgent 结果,不创建订单或任务。
|
||||
* 处理单封 Debug EML 上传;本服务只展示 SuperAgent 结果,业务模型写入仍由正式回调 / MCP 负责。
|
||||
*/
|
||||
@Override
|
||||
public DebugEmlSuperAgentRunResult uploadAndRun(
|
||||
@@ -1098,7 +1098,7 @@ public class DebugEmlSuperAgentRunServiceImpl implements DebugEmlSuperAgentRunSe
|
||||
putIfNotNull(debugContext, "original_conversation_id", originalConversationId);
|
||||
|
||||
Map<String, Object> metadata = new LinkedHashMap<>();
|
||||
metadata.put("source", "th-hotel-debug-eml-upload");
|
||||
metadata.put("source", "th-hotel-debug-eml-v4-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);
|
||||
|
||||
@@ -47,7 +47,9 @@ superagent:
|
||||
enabled: ${SUPERAGENT_DEV_OPEN_API_ENABLED:${SUPERAGENT_OPEN_API_ENABLED:false}}
|
||||
base-url: ${DEERFLOW_DEV_BASE_URL:${DEERFLOW_BASE_URL:}}
|
||||
api-key: ${DEERFLOW_DEV_OPEN_API_KEY:${DEERFLOW_OPEN_API_KEY:}}
|
||||
external-subject-id: ${SUPERAGENT_DEV_DEBUG_EML_EXTERNAL_SUBJECT_ID:${SUPERAGENT_DEBUG_EML_EXTERNAL_SUBJECT_ID:th-hotel-debug-eml-upload}}
|
||||
# Debug EML 默认复用实时 AgentBus V4 subject,避免 V4 smoke 误打到历史 Debug V2/V3 profile。
|
||||
# 如需调历史 profile,必须显式配置 SUPERAGENT_DEV_DEBUG_EML_EXTERNAL_SUBJECT_ID。
|
||||
external-subject-id: ${SUPERAGENT_DEV_DEBUG_EML_EXTERNAL_SUBJECT_ID:${SUPERAGENT_DEBUG_EML_EXTERNAL_SUBJECT_ID:${SUPERAGENT_DEV_AGENTBUS_EXTERNAL_SUBJECT_ID:${SUPERAGENT_AGENTBUS_EXTERNAL_SUBJECT_ID:th-hotel-agentbus-source-message}}}}
|
||||
agentbus-external-subject-id: ${SUPERAGENT_DEV_AGENTBUS_EXTERNAL_SUBJECT_ID:${SUPERAGENT_AGENTBUS_EXTERNAL_SUBJECT_ID:th-hotel-agentbus-source-message}}
|
||||
connect-timeout: ${SUPERAGENT_DEV_DEBUG_EML_CONNECT_TIMEOUT:${SUPERAGENT_DEBUG_EML_CONNECT_TIMEOUT:15s}}
|
||||
read-timeout: ${SUPERAGENT_DEV_DEBUG_EML_READ_TIMEOUT:${SUPERAGENT_DEBUG_EML_READ_TIMEOUT:180s}}
|
||||
|
||||
@@ -45,7 +45,8 @@ superagent:
|
||||
enabled: ${SUPERAGENT_PROD_OPEN_API_ENABLED:false}
|
||||
base-url: ${DEERFLOW_PROD_BASE_URL:${DEERFLOW_BASE_URL}}
|
||||
api-key: ${DEERFLOW_PROD_OPEN_API_KEY:${DEERFLOW_OPEN_API_KEY}}
|
||||
external-subject-id: ${SUPERAGENT_PROD_DEBUG_EML_EXTERNAL_SUBJECT_ID:${SUPERAGENT_DEBUG_EML_EXTERNAL_SUBJECT_ID:th-hotel-debug-eml-upload}}
|
||||
# Debug EML 默认复用实时 AgentBus V4 subject;生产如需启用 Debug EML,必须额外确认权限、审计和 profile。
|
||||
external-subject-id: ${SUPERAGENT_PROD_DEBUG_EML_EXTERNAL_SUBJECT_ID:${SUPERAGENT_DEBUG_EML_EXTERNAL_SUBJECT_ID:${SUPERAGENT_PROD_AGENTBUS_EXTERNAL_SUBJECT_ID:${SUPERAGENT_AGENTBUS_EXTERNAL_SUBJECT_ID:th-hotel-agentbus-source-message}}}}
|
||||
agentbus-external-subject-id: ${SUPERAGENT_PROD_AGENTBUS_EXTERNAL_SUBJECT_ID:${SUPERAGENT_AGENTBUS_EXTERNAL_SUBJECT_ID:th-hotel-agentbus-source-message}}
|
||||
connect-timeout: ${SUPERAGENT_PROD_DEBUG_EML_CONNECT_TIMEOUT:${SUPERAGENT_DEBUG_EML_CONNECT_TIMEOUT:15s}}
|
||||
read-timeout: ${SUPERAGENT_PROD_DEBUG_EML_READ_TIMEOUT:${SUPERAGENT_DEBUG_EML_READ_TIMEOUT:180s}}
|
||||
|
||||
@@ -49,7 +49,9 @@ superagent:
|
||||
enabled: ${SUPERAGENT_TEST_OPEN_API_ENABLED:${SUPERAGENT_OPEN_API_ENABLED:false}}
|
||||
base-url: ${DEERFLOW_TEST_BASE_URL:${DEERFLOW_BASE_URL:}}
|
||||
api-key: ${DEERFLOW_TEST_OPEN_API_KEY:${DEERFLOW_OPEN_API_KEY:}}
|
||||
external-subject-id: ${SUPERAGENT_TEST_DEBUG_EML_EXTERNAL_SUBJECT_ID:${SUPERAGENT_DEBUG_EML_EXTERNAL_SUBJECT_ID:th-hotel-debug-eml-upload}}
|
||||
# Debug EML 默认复用实时 AgentBus V4 subject,避免 V4 smoke 误打到历史 Debug V2/V3 profile。
|
||||
# 如需调历史 profile,必须显式配置 SUPERAGENT_TEST_DEBUG_EML_EXTERNAL_SUBJECT_ID。
|
||||
external-subject-id: ${SUPERAGENT_TEST_DEBUG_EML_EXTERNAL_SUBJECT_ID:${SUPERAGENT_DEBUG_EML_EXTERNAL_SUBJECT_ID:${SUPERAGENT_TEST_AGENTBUS_EXTERNAL_SUBJECT_ID:${SUPERAGENT_AGENTBUS_EXTERNAL_SUBJECT_ID:th-hotel-agentbus-source-message}}}}
|
||||
agentbus-external-subject-id: ${SUPERAGENT_TEST_AGENTBUS_EXTERNAL_SUBJECT_ID:${SUPERAGENT_AGENTBUS_EXTERNAL_SUBJECT_ID:th-hotel-agentbus-source-message}}
|
||||
connect-timeout: ${SUPERAGENT_TEST_DEBUG_EML_CONNECT_TIMEOUT:${SUPERAGENT_DEBUG_EML_CONNECT_TIMEOUT:15s}}
|
||||
read-timeout: ${SUPERAGENT_TEST_DEBUG_EML_READ_TIMEOUT:${SUPERAGENT_DEBUG_EML_READ_TIMEOUT:180s}}
|
||||
|
||||
@@ -42,11 +42,13 @@ class SuperAgentOpenApiClientImplTest {
|
||||
void shouldRequestStreamingMessagesWithIncludeTraceAndEmitPublicTraceEvents() throws Exception {
|
||||
HttpServer server = HttpServer.create(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 0);
|
||||
AtomicReference<String> streamQuery = new AtomicReference<>();
|
||||
AtomicReference<String> sessionBody = new AtomicReference<>();
|
||||
AtomicReference<String> sessionCsrfToken = new AtomicReference<>();
|
||||
AtomicReference<String> sessionCookie = new AtomicReference<>();
|
||||
AtomicReference<String> streamCsrfToken = new AtomicReference<>();
|
||||
AtomicReference<String> streamCookie = new AtomicReference<>();
|
||||
server.createContext("/api/open/agent-sessions", exchange -> {
|
||||
sessionBody.set(new String(exchange.getRequestBody().readAllBytes(), StandardCharsets.UTF_8));
|
||||
sessionCsrfToken.set(exchange.getRequestHeaders().getFirst("X-CSRF-Token"));
|
||||
sessionCookie.set(exchange.getRequestHeaders().getFirst("Cookie"));
|
||||
byte[] response = "{\"session_id\":\"session-http-001\"}".getBytes(StandardCharsets.UTF_8);
|
||||
@@ -91,7 +93,6 @@ class SuperAgentOpenApiClientImplTest {
|
||||
properties.setEnabled(true);
|
||||
properties.setBaseUrl("http://127.0.0.1:" + server.getAddress().getPort());
|
||||
properties.setApiKey("df_open_test");
|
||||
properties.setExternalSubjectId("debug-subject");
|
||||
properties.setConnectTimeout(Duration.ofSeconds(5));
|
||||
properties.setReadTimeout(Duration.ofSeconds(5));
|
||||
SuperAgentOpenApiClientImpl client = new SuperAgentOpenApiClientImpl(
|
||||
@@ -106,6 +107,7 @@ class SuperAgentOpenApiClientImplTest {
|
||||
Map.of("source", "unit-test")), traceEvents::add);
|
||||
|
||||
assertThat(streamQuery.get()).isEqualTo("include_trace=true");
|
||||
assertThat(sessionBody.get()).contains("\"external_subject_id\":\"th-hotel-agentbus-source-message\"");
|
||||
assertThat(sessionCsrfToken.get()).isNotBlank();
|
||||
assertThat(sessionCookie.get()).contains("csrf_token=" + sessionCsrfToken.get());
|
||||
assertThat(streamCsrfToken.get()).isNotBlank();
|
||||
|
||||
@@ -22,6 +22,7 @@ import cn.nianxx.thhotel.integrations.ai.superagent.common.result.SuperAgentOpen
|
||||
import cn.nianxx.thhotel.integrations.ai.superagent.common.result.SuperAgentOpenApiTraceEvent;
|
||||
import cn.nianxx.thhotel.integrations.ai.superagent.service.SuperAgentOpenApiClient;
|
||||
import cn.nianxx.thhotel.integrations.ai.superagent.service.impl.SuperAgentOpenApiException;
|
||||
import cn.nianxx.thhotel.integrations.ai.superagent.service.impl.SuperAgentOpenApiProperties;
|
||||
import cn.nianxx.thhotel.integrations.storage.aliyunoss.common.request.ObjectStoragePutRequest;
|
||||
import cn.nianxx.thhotel.integrations.storage.aliyunoss.common.result.ObjectStoragePutResult;
|
||||
import cn.nianxx.thhotel.integrations.storage.aliyunoss.service.ObjectStorageService;
|
||||
@@ -68,8 +69,7 @@ import org.springframework.web.client.RestClientResponseException;
|
||||
"debug.eml-upload.include-booking-excel-extractions=true",
|
||||
"aliyun.oss.debug-eml-prefix=debug/eml/",
|
||||
"reservation.booking-excel-extraction.enabled=true",
|
||||
"superagent.open-api.enabled=true",
|
||||
"superagent.open-api.external-subject-id=test-debug-eml"
|
||||
"superagent.open-api.enabled=true"
|
||||
})
|
||||
@AutoConfigureMockMvc
|
||||
@ActiveProfiles("test")
|
||||
@@ -87,6 +87,9 @@ class DebugEmlSuperAgentControllerTest {
|
||||
@Autowired
|
||||
private DebugEmlSuperAgentRunService runService;
|
||||
|
||||
@Autowired
|
||||
private SuperAgentOpenApiProperties superAgentOpenApiProperties;
|
||||
|
||||
@Autowired
|
||||
private BookingExcelExtractionProperties bookingExcelExtractionProperties;
|
||||
|
||||
@@ -96,6 +99,13 @@ class DebugEmlSuperAgentControllerTest {
|
||||
@MockBean
|
||||
private SuperAgentOpenApiClient superAgentOpenApiClient;
|
||||
|
||||
@Test
|
||||
void shouldUseAgentBusV4SubjectByDefaultForDebugEmlSmoke() {
|
||||
org.assertj.core.api.Assertions.assertThat(superAgentOpenApiProperties.getExternalSubjectId())
|
||||
.isEqualTo("th-hotel-agentbus-source-message")
|
||||
.isEqualTo(superAgentOpenApiProperties.getAgentbusExternalSubjectId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectUploadWhenDebugKeyMissing() throws Exception {
|
||||
mockMvc.perform(multipart(ENDPOINT)
|
||||
@@ -218,7 +228,7 @@ class DebugEmlSuperAgentControllerTest {
|
||||
.contains("\"mode\":\"manual\"")
|
||||
.contains("\"final_only\":true");
|
||||
org.assertj.core.api.Assertions.assertThat(superAgentRequest.metadata())
|
||||
.containsEntry("source", "th-hotel-debug-eml-upload")
|
||||
.containsEntry("source", "th-hotel-debug-eml-v4-upload")
|
||||
.containsKey("debug_context");
|
||||
|
||||
Long debugRunCount = jdbcTemplate.queryForObject("""
|
||||
|
||||
@@ -1117,6 +1117,44 @@ class SuperAgentTaskResultControllerTest {
|
||||
assertThat(replayCardCount).isEqualTo(4L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRouteDebugEmlV4BusinessResultToV4ModelWithoutLegacyTask() throws Exception {
|
||||
SourceMessageCaptureResult source = captureDebugEmlSourceMessage("debug-eml-run-v4-business-001");
|
||||
String body = v4BusinessRootBody("debug-eml-run-v4-business-001");
|
||||
|
||||
mockMvc.perform(signedPost(body, "nonce-debug-eml-v4-business-001"))
|
||||
.andExpect(status().isCreated())
|
||||
.andExpect(jsonPath("$.source_message_id").value("debug-eml-run-v4-business-001"))
|
||||
.andExpect(jsonPath("$.accepted_count").value(2))
|
||||
.andExpect(jsonPath("$.items[0].task_id").doesNotExist())
|
||||
.andExpect(jsonPath("$.items[1].task_id").doesNotExist());
|
||||
|
||||
Long legacyTaskCount = jdbcTemplate.queryForObject("""
|
||||
SELECT COUNT(*)
|
||||
FROM workflow_reservation_task
|
||||
WHERE source_message_id = ?
|
||||
""", Long.class, source.inboxId());
|
||||
Long v4OrderTaskCount = jdbcTemplate.queryForObject("""
|
||||
SELECT COUNT(*)
|
||||
FROM workflow_reservation_v4_order_task
|
||||
WHERE source_message_id = ?
|
||||
AND order_ref = 'order-1'
|
||||
""", Long.class, source.inboxId());
|
||||
List<String> v4CardTypes = jdbcTemplate.queryForList("""
|
||||
SELECT card_type
|
||||
FROM workflow_reservation_v4_task_card
|
||||
WHERE source_message_id = ?
|
||||
ORDER BY card_sort_order, source_event_index
|
||||
""", String.class, source.inboxId());
|
||||
assertThat(legacyTaskCount).isZero();
|
||||
assertThat(v4OrderTaskCount).isEqualTo(1L);
|
||||
assertThat(v4CardTypes).containsExactly(
|
||||
"SOURCE_MESSAGE_DISPLAY",
|
||||
"BASIC_INFORMATION",
|
||||
"ROOM_INFORMATION",
|
||||
"PAYMENT");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldCreateV4OrderTasksForMultipleOrderRefs() throws Exception {
|
||||
SourceMessageCaptureResult source = captureSourceMessage("mail-v4-two-order-refs-001");
|
||||
@@ -3441,13 +3479,26 @@ class SuperAgentTaskResultControllerTest {
|
||||
}
|
||||
|
||||
private SourceMessageCaptureResult captureSourceMessage(String externalMessageId, String hotelId, String channel) {
|
||||
return captureSourceMessage(externalMessageId, hotelId, channel, "AGENTBUS", "agentbus-outlook-v1");
|
||||
}
|
||||
|
||||
private SourceMessageCaptureResult captureDebugEmlSourceMessage(String externalMessageId) {
|
||||
return captureSourceMessage(externalMessageId, "HOTEL-TEST", "EMAIL", "DEBUG_EML_UPLOAD", "debug-eml-upload-v1");
|
||||
}
|
||||
|
||||
private SourceMessageCaptureResult captureSourceMessage(
|
||||
String externalMessageId,
|
||||
String hotelId,
|
||||
String channel,
|
||||
String provider,
|
||||
String schemaVersion) {
|
||||
String providerFrameId = "frame-" + externalMessageId;
|
||||
if (providerFrameId.length() > 128) {
|
||||
providerFrameId = "frame-" + Integer.toHexString(externalMessageId.hashCode());
|
||||
}
|
||||
return captureService.capture(new CaptureSourceMessageCommand(
|
||||
hotelId,
|
||||
"AGENTBUS",
|
||||
provider,
|
||||
channel,
|
||||
externalMessageId,
|
||||
"thread-" + externalMessageId,
|
||||
@@ -3459,7 +3510,7 @@ class SuperAgentTaskResultControllerTest {
|
||||
"Please handle booking message.",
|
||||
"<html><body>Please handle booking message.</body></html>",
|
||||
"{\"source\":{\"external_message_id\":\"" + externalMessageId + "\"}}",
|
||||
"agentbus-outlook-v1",
|
||||
schemaVersion,
|
||||
List.of()
|
||||
));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user