diff --git a/agentscope-extensions/agentscope-extensions-agui/src/main/java/io/agentscope/core/agui/adapter/AguiAgentAdapter.java b/agentscope-extensions/agentscope-extensions-agui/src/main/java/io/agentscope/core/agui/adapter/AguiAgentAdapter.java
index 3ea6b3d5e..fb602267e 100644
--- a/agentscope-extensions/agentscope-extensions-agui/src/main/java/io/agentscope/core/agui/adapter/AguiAgentAdapter.java
+++ b/agentscope-extensions/agentscope-extensions-agui/src/main/java/io/agentscope/core/agui/adapter/AguiAgentAdapter.java
@@ -47,8 +47,9 @@
*
*
Event Mapping:
*
- * - AgentScope REASONING events → AG-UI TEXT_MESSAGE_* events (for TextBlock)
- * - AgentScope REASONING events → AG-UI REASONING_* events (for ThinkingBlock, when enabled)
+ * - AgentScope REASONING/SUMMARY events → AG-UI TEXT_MESSAGE_* events (for TextBlock)
+ * - AgentScope REASONING/SUMMARY events → AG-UI REASONING_* events (for
+ * ThinkingBlock, when enabled)
* - AgentScope TOOL_RESULT events → AG-UI TOOL_CALL_END events
* - ToolUseBlock content → AG-UI TOOL_CALL_START events
*
@@ -136,8 +137,8 @@ private List convertEvent(Event event, EventConversionState state) {
Msg msg = event.getMessage();
EventType type = event.getType();
- if (type == EventType.REASONING) {
- // Handle reasoning events - convert to text messages and tool calls
+ if (type == EventType.REASONING || type == EventType.SUMMARY) {
+ // Handle reasoning/summary events - convert to text messages and tool calls
for (ContentBlock block : msg.getContent()) {
if (block instanceof TextBlock textBlock) {
String text = textBlock.getText();
@@ -324,14 +325,14 @@ private String extractToolResultText(ToolResultBlock toolResult) {
StringBuilder sb = new StringBuilder();
for (ContentBlock output : toolResult.getOutput()) {
if (output instanceof TextBlock textBlock) {
- if (sb.length() > 0) {
+ if (!sb.isEmpty()) {
sb.append("\n");
}
sb.append(textBlock.getText());
}
}
- return sb.length() > 0 ? sb.toString() : null;
+ return !sb.isEmpty() ? sb.toString() : null;
}
/**
diff --git a/agentscope-extensions/agentscope-extensions-agui/src/test/java/io/agentscope/core/agui/adapter/AguiAgentAdapterTest.java b/agentscope-extensions/agentscope-extensions-agui/src/test/java/io/agentscope/core/agui/adapter/AguiAgentAdapterTest.java
index d7758aefd..f9f1d9ca1 100644
--- a/agentscope-extensions/agentscope-extensions-agui/src/test/java/io/agentscope/core/agui/adapter/AguiAgentAdapterTest.java
+++ b/agentscope-extensions/agentscope-extensions-agui/src/test/java/io/agentscope/core/agui/adapter/AguiAgentAdapterTest.java
@@ -171,6 +171,114 @@ void testRunWithStreamingTextEvents() {
assertEquals(1, startCount, "Should have only 1 start event for same message ID");
}
+ @Test
+ void testRunWithSummaryEventUsesTextMessages() {
+ Msg summaryChunk =
+ Msg.builder()
+ .id("msg-summary")
+ .role(MsgRole.ASSISTANT)
+ .content(
+ TextBlock.builder()
+ .text("Here is the conversation summary.")
+ .build())
+ .build();
+
+ Msg summaryFinal =
+ Msg.builder()
+ .id("msg-summary")
+ .role(MsgRole.ASSISTANT)
+ .content(
+ TextBlock.builder()
+ .text("Here is the conversation summary.")
+ .build())
+ .build();
+
+ Event summaryChunkEvent = new Event(EventType.SUMMARY, summaryChunk, false);
+ Event summaryFinalEvent = new Event(EventType.SUMMARY, summaryFinal, true);
+
+ when(mockAgent.stream(anyList(), any(StreamOptions.class)))
+ .thenReturn(Flux.just(summaryChunkEvent, summaryFinalEvent));
+
+ RunAgentInput input =
+ RunAgentInput.builder()
+ .threadId("thread-1")
+ .runId("run-1")
+ .messages(List.of(AguiMessage.userMessage("msg-1", "Hello")))
+ .build();
+
+ List events = adapter.run(input).collectList().block();
+
+ assertNotNull(events);
+
+ AguiEvent.TextMessageContent summaryContent =
+ events.stream()
+ .filter(e -> e instanceof AguiEvent.TextMessageContent)
+ .map(e -> (AguiEvent.TextMessageContent) e)
+ .findFirst()
+ .orElse(null);
+
+ assertNotNull(summaryContent, "Should convert SUMMARY to TextMessageContent");
+ assertEquals("msg-summary", summaryContent.messageId());
+ assertEquals("Here is the conversation summary.", summaryContent.delta());
+
+ long textEndCount =
+ events.stream().filter(e -> e instanceof AguiEvent.TextMessageEnd).count();
+ assertEquals(1, textEndCount, "Should close the summary text message exactly once");
+ }
+
+ @Test
+ void testRunWithStreamingSummaryEvents() {
+ Msg summaryChunk1 =
+ Msg.builder()
+ .id("msg-summary")
+ .role(MsgRole.ASSISTANT)
+ .content(TextBlock.builder().text("First part. ").build())
+ .build();
+
+ Msg summaryChunk2 =
+ Msg.builder()
+ .id("msg-summary")
+ .role(MsgRole.ASSISTANT)
+ .content(TextBlock.builder().text("Second part.").build())
+ .build();
+
+ Msg summaryFinal =
+ Msg.builder()
+ .id("msg-summary")
+ .role(MsgRole.ASSISTANT)
+ .content(TextBlock.builder().text("First part. Second part.").build())
+ .build();
+
+ Event event1 = new Event(EventType.SUMMARY, summaryChunk1, false);
+ Event event2 = new Event(EventType.SUMMARY, summaryChunk2, false);
+ Event event3 = new Event(EventType.SUMMARY, summaryFinal, true);
+
+ when(mockAgent.stream(anyList(), any(StreamOptions.class)))
+ .thenReturn(Flux.just(event1, event2, event3));
+
+ RunAgentInput input =
+ RunAgentInput.builder()
+ .threadId("thread-1")
+ .runId("run-1")
+ .messages(List.of(AguiMessage.userMessage("msg-1", "Hello")))
+ .build();
+
+ List events = adapter.run(input).collectList().block();
+
+ assertNotNull(events);
+
+ long contentCount =
+ events.stream().filter(e -> e instanceof AguiEvent.TextMessageContent).count();
+ assertEquals(2, contentCount, "Should stream summary chunks as text deltas");
+
+ long startCount =
+ events.stream().filter(e -> e instanceof AguiEvent.TextMessageStart).count();
+ assertEquals(1, startCount, "Should only start the summary message once");
+
+ long endCount = events.stream().filter(e -> e instanceof AguiEvent.TextMessageEnd).count();
+ assertEquals(1, endCount, "Should only end the summary message once");
+ }
+
@Test
void testRunWithToolCallEvent() {
Msg toolCallMsg =