package com.easyagents.agui; import com.easyagents.agent.runtime.event.AgentRuntimeEvent; import com.easyagents.agent.runtime.event.AgentRuntimeEventType; import io.agentscope.core.agui.event.AguiEvent; import org.junit.Assert; import org.junit.Test; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * {@link AguiRuntimeEventProjector} 的协议顺序与终态测试。 */ public class AguiRuntimeEventProjectorTest { /** * 验证文本、推理、工具和成功终态按 AG-UI 顺序投影。 */ @Test public void shouldProjectSuccessfulRunInProtocolOrder() { AguiRuntimeEventProjector projector = new AguiRuntimeEventProjector("thread-1", "run-1"); List events = new ArrayList<>(); events.addAll(projector.project(event(AgentRuntimeEventType.STARTED, null, null, Map.of()))); events.addAll(projector.project(event( AgentRuntimeEventType.REASONING_STARTED, "reasoning-1", null, Map.of()))); events.addAll(projector.project(event( AgentRuntimeEventType.REASONING_DELTA, "reasoning-1", null, Map.of("reasoning", "分析")))); events.addAll(projector.project(event( AgentRuntimeEventType.REASONING_COMPLETED, "reasoning-1", null, Map.of()))); events.addAll(projector.project(event( AgentRuntimeEventType.MESSAGE_DELTA, "message-1", null, Map.of("text", "你好")))); events.addAll(projector.project(event( AgentRuntimeEventType.TOOL_CALL, null, "tool-1", Map.of("toolName", "search", "input", Map.of("q", "AG-UI"))))); events.addAll(projector.project(event( AgentRuntimeEventType.TOOL_RESULT, null, "tool-1", Map.of("text", "done")))); events.addAll(projector.project(event(AgentRuntimeEventType.COMPLETED, null, null, Map.of()))); Assert.assertEquals(List.of( "RunStarted", "ReasoningMessageStart", "ReasoningMessageContent", "ReasoningMessageEnd", "TextMessageStart", "TextMessageContent", "ToolCallStart", "ToolCallArgs", "ToolCallEnd", "ToolCallResult", "TextMessageEnd", "RunFinished"), events.stream().map(value -> value.getClass().getSimpleName()).toList()); Assert.assertEquals( "reasoning", ((AguiEvent.ReasoningMessageStart) events.get(1)).role()); Assert.assertTrue(projector.isTerminated()); } /** * 验证失败终态不会追加成功事件,终态后的迟到事件会被丢弃。 */ @Test public void shouldEmitSingleErrorTerminalAndIgnoreLateEvents() { AguiRuntimeEventProjector projector = new AguiRuntimeEventProjector("thread-1", "run-1"); List failed = projector.project(event( AgentRuntimeEventType.FAILED, null, null, Map.of("message", "boom"))); List late = projector.project(event(AgentRuntimeEventType.COMPLETED, null, null, Map.of())); Assert.assertEquals(2, failed.size()); Assert.assertTrue(failed.get(0) instanceof AguiEvent.RunStarted); Assert.assertEquals( new AguiExtendedEvent.RunError("thread-1", "run-1", "boom", "AGENT_RUNTIME_FAILED"), failed.get(1)); Assert.assertTrue(late.isEmpty()); } private static AgentRuntimeEvent event( AgentRuntimeEventType type, String messageId, String toolCallId, Map payload) { AgentRuntimeEvent event = AgentRuntimeEvent.of(type); event.setMessageId(messageId); event.setToolCallId(toolCallId); event.setPayload(payload); return event; } }