兼容Debug EML SSE断流兜底

This commit is contained in:
andy
2026-07-12 19:26:52 +08:00
parent 9d095cfd53
commit 807d045526
17 changed files with 556 additions and 47 deletions

View File

@@ -89,16 +89,30 @@ class SuperAgentOpenApiSseParserTest {
}
@Test
void shouldFailWhenEndEventMissingEvenIfAiContentExists() {
void shouldFailWhenEndEventMissingAndOnlyPartialAiContentExists() {
String sse = """
event: messages
data: {"type":"ai","content":"partial answer"}
""";
assertThatThrownBy(() -> parser.parse("session-debug-partial", sse))
.isInstanceOf(SuperAgentOpenApiException.class)
.hasMessageContaining("SuperAgent SSE 未收到结束事件。");
}
@Test
void shouldAcceptMissingEndEventWhenFinalAiContentExists() {
String sse = """
event: messages
data: {"type":"ai","content":"{\\"ai_task_results\\":[]}","response_metadata":{"finish_reason":"stop"}}
""";
assertThatThrownBy(() -> parser.parse("session-debug-004", sse))
.isInstanceOf(SuperAgentOpenApiException.class)
.hasMessageContaining("SuperAgent SSE 未收到结束事件。");
SuperAgentOpenApiResult result = parser.parse("session-debug-004", sse);
assertThat(result.rawAnswer()).isEqualTo("{\"ai_task_results\":[]}");
assertThat(result.eventTypes()).containsExactly("messages");
}
@Test

View File

@@ -8,6 +8,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
@@ -186,6 +187,44 @@ class DebugEmlSuperAgentControllerTest {
org.assertj.core.api.Assertions.assertThat(debugRunCount).isEqualTo(1L);
}
@Test
void shouldQueryDebugRunResultByIdForStreamFallback() throws Exception {
mockStorageAndSuperAgentSuccess();
mockMvc.perform(multipart(ENDPOINT)
.file(emlFile())
.param("hotel_id", "HOTEL-TEST")
.param("run_label", "query-run-fallback")
.header("X-TH-Hotel-Debug-Upload-Key", "test-debug-upload-key"))
.andExpect(status().isCreated());
Long runId = jdbcTemplate.queryForObject("""
SELECT id
FROM platform_debug_eml_superagent_run
WHERE run_label = 'query-run-fallback'
""", Long.class);
mockMvc.perform(get(ENDPOINT + "/" + runId)
.header("X-TH-Hotel-Debug-Upload-Key", "test-debug-upload-key"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.debug_run_id").value(runId.toString()))
.andExpect(jsonPath("$.source_message_id").isNotEmpty())
.andExpect(jsonPath("$.source_provider").value("DEBUG_EML_UPLOAD"))
.andExpect(jsonPath("$.uploaded_media", hasSize(greaterThanOrEqualTo(3))))
.andExpect(jsonPath("$.html_body_with_oss_urls", containsString("https://oss.example.test/")))
.andExpect(jsonPath("$.html_body_with_oss_urls", not(containsString("cid:inline-001"))))
.andExpect(jsonPath("$.html_body_sanitized", containsString("https://oss.example.test/")))
.andExpect(jsonPath("$.html_sanitize_required").value(true))
.andExpect(jsonPath("$.html_render_mode").value("SANITIZED_HTML"))
.andExpect(jsonPath("$.superagent_session_id").value("session-debug-001"))
.andExpect(jsonPath("$.superagent_run_id").value("run-debug-001"))
.andExpect(jsonPath("$.superagent_raw_answer", containsString("ai_task_results")))
.andExpect(jsonPath("$.superagent_parsed_json.ai_task_results[0].task_type").value("New Booking"))
.andExpect(jsonPath("$.status").value("SUPERAGENT_SUCCEEDED"))
.andExpect(jsonPath("$.safe_error_summary").doesNotExist())
.andExpect(content().string(not(containsString("test-debug-upload-key"))));
}
@Test
void shouldStreamDebugStagesSuperAgentTraceAndFinalResult() throws Exception {
when(objectStorageService.putObject(any())).thenAnswer(invocation -> {