package tech.easyflow.manuagent.agent; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import com.fasterxml.jackson.databind.ObjectMapper; import io.agentscope.core.agui.adapter.AguiAgentAdapter; import java.util.UUID; import org.junit.jupiter.api.Test; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import tech.easyflow.manuagent.project.ProjectFileService; import tech.easyflow.manuagent.project.ProjectService; import tech.easyflow.manuagent.skill.SkillService; /** * 验证 Agent 事件持久化的精简规则。 */ class AgentExecutionServiceTest { /** * Run 在创建时已经固化模型配置 ID;执行和模型重连都必须沿用该 ID, * 不能在工厂内部重新读取可能已经变化的全局默认模型。 */ @Test void shouldCreateAgentWithModelBoundToRun() { UUID projectId = UUID.randomUUID(); UUID runId = UUID.randomUUID(); UUID modelId = UUID.randomUUID(); AgentFactory factory = mock(AgentFactory.class); AgentFactory.AgentHandle handle = mock(AgentFactory.AgentHandle.class); AguiAgentAdapter adapter = mock(AguiAgentAdapter.class); SkillService skillService = mock(SkillService.class); when(handle.adapter()).thenReturn(adapter); when(adapter.run(any())).thenReturn(Flux.empty()); when(skillService.enabledNames()).thenReturn(new String[] {"document"}); when(factory.create(eq(projectId), eq(modelId), any(String[].class))).thenReturn(handle); AgentExecutionService service = new AgentExecutionService( new ObjectMapper(), factory, mock(AgentEventService.class), mock(ProjectFileService.class), skillService); ProjectService.ProjectView project = mock(ProjectService.ProjectView.class); when(project.id()).thenReturn(projectId); when(project.threadId()).thenReturn("project-" + projectId); AgentRunService.RunView run = new AgentRunService.RunView( runId, projectId, modelId, "INITIAL", "RUNNING", null, null, null, null); service.execute(project, run, "执行测试", Mono.never(), () -> { }, () -> false); verify(factory).create(eq(projectId), eq(modelId), any(String[].class)); } /** * 验证文档视觉结果保留图片路径元数据并丢弃 Base64 正文。 */ @Test void shouldStripInlineImageDataFromPersistedToolResult() { String content = """ document_view_result={"images":[{"path":"work/tmp/document-view/a/render-1.png"}]} {"type":"image","source":{"media_type":"image/png","data":"very-large-base64"}} """; String result = AgentExecutionService.stripInlineImageData(content); assertThat(result).contains("render-1.png"); assertThat(result).doesNotContain("very-large-base64"); } }