mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-16 12:27:53 +08:00
test(goal): cover automatic managed JSON completion in real graphs
This commit is contained in:
parent
2c0f43c5dc
commit
66d8cc6c3b
@ -68,31 +68,16 @@ class GoalJsonGraphIntegrationTest {
|
|||||||
@Autowired private vip.mate.agent.progress.ProgressLedgerService progress;
|
@Autowired private vip.mate.agent.progress.ProgressLedgerService progress;
|
||||||
|
|
||||||
@org.junit.jupiter.params.ParameterizedTest
|
@org.junit.jupiter.params.ParameterizedTest
|
||||||
@org.junit.jupiter.params.provider.CsvSource({"false,false", "false,true", "true,false", "true,true"})
|
@org.junit.jupiter.params.provider.CsvSource({"false,false,false", "false,true,false", "true,false,false", "true,true,false",
|
||||||
void realGraphsPreserveAuthenticatedOriginThroughReadPublishCheckAndComplete(boolean plan, boolean scheduled) throws Exception {
|
"false,false,true", "false,true,true", "true,false,true", "true,true,true"})
|
||||||
String username = "graph-" + UUID.randomUUID();
|
void realGraphsPreserveAuthenticatedOriginThroughReadPublishCheckAndComplete(boolean plan, boolean scheduled, boolean automatic) throws Exception {
|
||||||
long userId = IdWorker.getId();
|
Fixture fixture = configuredGoal(scheduled);
|
||||||
String conversation = UUID.randomUUID().toString();
|
String username = fixture.username(); String conversation = fixture.conversation();
|
||||||
jdbc.update("INSERT INTO mate_user(id,username,password,enabled,role,create_time,update_time,deleted) VALUES (?,?,?,TRUE,'user',CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,0)", userId, username, "unused");
|
GoalEntity goal = fixture.goal(); GoalRunCoordinator.ClaimedRun run = fixture.run(); ChatOrigin origin = fixture.origin();
|
||||||
jdbc.update("INSERT INTO mate_conversation(id,conversation_id,username,workspace_id,agent_id,create_time,update_time,deleted) VALUES (?,?,?,1,1,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,0)", IdWorker.getId(), conversation, username);
|
when(evaluator.evaluate(any(), anyList(), anyString())).thenReturn(automatic
|
||||||
var request = new GoalCreateRequest(); request.setConversationId(conversation); request.setAgentId(1L); request.setWorkspaceId(1L);
|
? new GoalEvaluationResult(1, "offline graph semantic verdict", "completed", true, "fixture", 1, 0,
|
||||||
request.setTitle("Managed graph fixture"); request.setDescription("Produce JSON"); request.setPersistentExecution(scheduled); request.setAutoFollowupEnabled(false);
|
List.of(new GoalChecklistVerdict.CriterionVerdict("C1", true, "fixture only")), null)
|
||||||
GoalEntity goal = goals.create(request, username);
|
: GoalEvaluationResult.fallback("offline_graph_fixture"));
|
||||||
goals.appendCriterion(goal.getId(), "Produce the report", username);
|
|
||||||
goals.recordEvaluation(goal.getId(), new GoalEvaluationResult(1, "offline semantic fixture", "completed", true,
|
|
||||||
"fixture", 1, 0, List.of(new GoalChecklistVerdict.CriterionVerdict("C1", true, "fixture only")), null), 1, 1);
|
|
||||||
requirements.configure(goal.getId(), "r", new GoalJsonAcceptanceService.ConfigureRequest(0L, "report", List.of("summary")), username);
|
|
||||||
GoalRunCoordinator.ClaimedRun run = null;
|
|
||||||
ChatOrigin origin = ChatOrigin.web(conversation, username, 1L, null, null, userId).withAgent(1L);
|
|
||||||
if (scheduled) {
|
|
||||||
jdbc.update("UPDATE mate_agent_goal SET auto_followup_enabled=TRUE WHERE id=?", goal.getId());
|
|
||||||
var now = java.time.LocalDateTime.now(); continuations.discover(now);
|
|
||||||
run = coordinator.claim(continuations.get(goal.getId()), goals.getById(goal.getId()), now);
|
|
||||||
assertNotNull(run); assertTrue(coordinator.markRunning(run, now));
|
|
||||||
origin = ChatOrigin.web(conversation, username, 1L, null).withAgent(1L)
|
|
||||||
.withExecutionAttribution(new vip.mate.agent.context.ExecutionAttribution(goal.getId(), run.attempt().id(), null, null, run.attempt().leaseToken()));
|
|
||||||
}
|
|
||||||
when(evaluator.evaluate(any(), anyList(), anyString())).thenReturn(GoalEvaluationResult.fallback("offline_graph_fixture"));
|
|
||||||
var toolSet = tools.getEnabledToolSet().withAllowedToolsOnly(Set.of("getManagedGoalJsonSlots", "publishManagedGoalJson", "checkManagedGoalJson", "completeGoal"));
|
var toolSet = tools.getEnabledToolSet().withAllowedToolsOnly(Set.of("getManagedGoalJsonSlots", "publishManagedGoalJson", "checkManagedGoalJson", "completeGoal"));
|
||||||
assertEquals(4, toolSet.callbacks().size());
|
assertEquals(4, toolSet.callbacks().size());
|
||||||
ChatModel model = mock(ChatModel.class);
|
ChatModel model = mock(ChatModel.class);
|
||||||
@ -126,10 +111,16 @@ class GoalJsonGraphIntegrationTest {
|
|||||||
arguments = json.writeValueAsString(Map.of("criterionKey", "r", "expectedRequirementRevision", revision.get(),
|
arguments = json.writeValueAsString(Map.of("criterionKey", "r", "expectedRequirementRevision", revision.get(),
|
||||||
"artifactId", last.path("artifactId").asText(), "expectedGeneration", last.path("generation").asText()));
|
"artifactId", last.path("artifactId").asText(), "expectedGeneration", last.path("generation").asText()));
|
||||||
}
|
}
|
||||||
case 4 -> { assertTrue(last.path("acceptanceEligible").asBoolean(), String.valueOf(last)); name = "completeGoal"; }
|
case 4 -> {
|
||||||
|
assertTrue(last.path("acceptanceEligible").asBoolean(), String.valueOf(last));
|
||||||
|
if (automatic) return new ChatResponse(List.of(new Generation(new AssistantMessage("Managed JSON is ready for final validation."))));
|
||||||
|
name = "completeGoal";
|
||||||
|
}
|
||||||
default -> {
|
default -> {
|
||||||
if (last != null) assertEquals("completed", last.path("status").asText(), String.valueOf(last));
|
if (!automatic) {
|
||||||
assertEquals(GoalStatus.COMPLETED, goals.getById(goal.getId()).getStatus());
|
if (last != null) assertEquals("completed", last.path("status").asText(), String.valueOf(last));
|
||||||
|
assertEquals(GoalStatus.COMPLETED, goals.getById(goal.getId()).getStatus());
|
||||||
|
}
|
||||||
return new ChatResponse(List.of(new Generation(new AssistantMessage("Managed JSON fixture completed."))));
|
return new ChatResponse(List.of(new Generation(new AssistantMessage("Managed JSON fixture completed."))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -138,15 +129,7 @@ class GoalJsonGraphIntegrationTest {
|
|||||||
};
|
};
|
||||||
when(model.call(any(Prompt.class))).thenAnswer(script);
|
when(model.call(any(Prompt.class))).thenAnswer(script);
|
||||||
when(model.stream(any(Prompt.class))).thenAnswer(invocation -> Flux.just(script.answer(invocation)));
|
when(model.stream(any(Prompt.class))).thenAnswer(invocation -> Flux.just(script.answer(invocation)));
|
||||||
CompiledGraph graph = ReflectionTestUtils.invokeMethod(builder, plan ? "buildPlanExecuteGraph" : "buildReActGraph", toolSet, model, 12, null);
|
var agent = graphAgent(plan, toolSet, model);
|
||||||
assertNotNull(graph);
|
|
||||||
vip.mate.agent.BaseAgent agent = plan
|
|
||||||
? new vip.mate.agent.graph.plan.StateGraphPlanExecuteAgent(mock(ChatClient.class), conversations, graph, planning, model, window, toolSet)
|
|
||||||
: new StateGraphReActAgent(mock(ChatClient.class), conversations, graph, model, window, toolSet);
|
|
||||||
ReflectionTestUtils.setField(agent, "agentId", "1");
|
|
||||||
ReflectionTestUtils.setField(agent, "agentName", "JSON graph fixture");
|
|
||||||
ReflectionTestUtils.setField(agent, "systemPrompt", "Follow the user's managed JSON requirements.");
|
|
||||||
ReflectionTestUtils.setField(agent, "goalService", goals);
|
|
||||||
ChatOriginHolder.set(origin);
|
ChatOriginHolder.set(origin);
|
||||||
try { assertNotNull(agent.chat("Produce and check the managed JSON report.", conversation)); }
|
try { assertNotNull(agent.chat("Produce and check the managed JSON report.", conversation)); }
|
||||||
finally { ChatOriginHolder.clear(); }
|
finally { ChatOriginHolder.clear(); }
|
||||||
@ -158,6 +141,81 @@ class GoalJsonGraphIntegrationTest {
|
|||||||
}
|
}
|
||||||
assertFalse(progress.load(conversation).asMap().containsKey("auto_getManagedGoalJsonSlots"),
|
assertFalse(progress.load(conversation).asMap().containsKey("auto_getManagedGoalJsonSlots"),
|
||||||
"Current acceptance reads must not become a permanent done step that discourages reloading");
|
"Current acceptance reads must not become a permanent done step that discourages reloading");
|
||||||
assertTrue(calls.get() >= 6 && calls.get() <= 10, "Bounded scripted model calls: " + calls.get());
|
assertTrue(calls.get() >= (automatic ? 5 : 6) && calls.get() <= 10, "Bounded scripted model calls: " + calls.get());
|
||||||
}
|
}
|
||||||
|
@org.junit.jupiter.params.ParameterizedTest
|
||||||
|
@org.junit.jupiter.params.provider.ValueSource(booleans = {false, true})
|
||||||
|
void automaticGraphCannotPromoteAPassingSemanticVerdictWithoutManagedBytes(boolean plan) throws Exception {
|
||||||
|
Fixture fixture = configuredGoal(false);
|
||||||
|
when(evaluator.evaluate(any(), anyList(), anyString())).thenReturn(new GoalEvaluationResult(
|
||||||
|
1, "PASS from offline semantic fixture", "completed", true, "fixture", 1, 0,
|
||||||
|
List.of(new GoalChecklistVerdict.CriterionVerdict("C1", true, "fixture only")), null));
|
||||||
|
var toolSet = tools.getEnabledToolSet().withAllowedToolsOnly(Set.of("getManagedGoalJsonSlots", "publishManagedGoalJson", "checkManagedGoalJson", "completeGoal"));
|
||||||
|
ChatModel model = mock(ChatModel.class);
|
||||||
|
AtomicInteger calls = new AtomicInteger();
|
||||||
|
org.mockito.stubbing.Answer<ChatResponse> script = invocation -> {
|
||||||
|
int step = calls.getAndIncrement();
|
||||||
|
if (plan && step == 0) return new ChatResponse(List.of(new Generation(new AssistantMessage(
|
||||||
|
"{\"needs_planning\":true,\"steps\":[\"Read current managed JSON requirements and report status\"]}"))));
|
||||||
|
if (plan) step--;
|
||||||
|
if (step == 0) return new ChatResponse(List.of(new Generation(AssistantMessage.builder().content("")
|
||||||
|
.toolCalls(List.of(new AssistantMessage.ToolCall("read-current", "function", "getManagedGoalJsonSlots", "{}"))).build())));
|
||||||
|
return new ChatResponse(List.of(new Generation(new AssistantMessage("PASS. All requirements are completed."))));
|
||||||
|
};
|
||||||
|
when(model.call(any(Prompt.class))).thenAnswer(script);
|
||||||
|
when(model.stream(any(Prompt.class))).thenAnswer(invocation -> Flux.just(script.answer(invocation)));
|
||||||
|
var agent = graphAgent(plan, toolSet, model);
|
||||||
|
ChatOriginHolder.set(fixture.origin());
|
||||||
|
try { assertNotNull(agent.chat("Read the current managed JSON requirements and report status.", fixture.conversation())); }
|
||||||
|
finally { ChatOriginHolder.clear(); }
|
||||||
|
verify(evaluator, atLeastOnce()).evaluate(any(), anyList(), anyString());
|
||||||
|
assertEquals(GoalStatus.ACTIVE, goals.getById(fixture.goal().getId()).getStatus());
|
||||||
|
assertTrue(goals.getById(fixture.goal().getId()).isJsonAcceptanceRequired());
|
||||||
|
assertEquals("NO_ARTIFACT", bindings.state(fixture.goal().getId(), fixture.username()).getFirst().status());
|
||||||
|
assertTrue(goals.listEvents(fixture.goal().getId(), 30).stream().noneMatch(e -> "completed".equals(e.getEventType())));
|
||||||
|
assertTrue(calls.get() < 10, "Bounded offline rejection flow: " + calls.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
private record Fixture(String username, String conversation, GoalEntity goal,
|
||||||
|
GoalRunCoordinator.ClaimedRun run, ChatOrigin origin) { }
|
||||||
|
|
||||||
|
private Fixture configuredGoal(boolean scheduled) {
|
||||||
|
String username = "graph-" + UUID.randomUUID();
|
||||||
|
long userId = IdWorker.getId();
|
||||||
|
String conversation = UUID.randomUUID().toString();
|
||||||
|
jdbc.update("INSERT INTO mate_user(id,username,password,enabled,role,create_time,update_time,deleted) VALUES (?,?,?,TRUE,'user',CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,0)", userId, username, "unused");
|
||||||
|
jdbc.update("INSERT INTO mate_conversation(id,conversation_id,username,workspace_id,agent_id,create_time,update_time,deleted) VALUES (?,?,?,1,1,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,0)", IdWorker.getId(), conversation, username);
|
||||||
|
var request = new GoalCreateRequest(); request.setConversationId(conversation); request.setAgentId(1L); request.setWorkspaceId(1L);
|
||||||
|
request.setTitle("Managed graph fixture"); request.setDescription("Produce JSON"); request.setPersistentExecution(scheduled); request.setAutoFollowupEnabled(false);
|
||||||
|
GoalEntity goal = goals.create(request, username);
|
||||||
|
goals.appendCriterion(goal.getId(), "Produce the report", username);
|
||||||
|
goals.recordEvaluation(goal.getId(), new GoalEvaluationResult(1, "offline semantic fixture", "completed", true,
|
||||||
|
"fixture", 1, 0, List.of(new GoalChecklistVerdict.CriterionVerdict("C1", true, "fixture only")), null), 1, 1);
|
||||||
|
requirements.configure(goal.getId(), "r", new GoalJsonAcceptanceService.ConfigureRequest(0L, "report", List.of("summary")), username);
|
||||||
|
GoalRunCoordinator.ClaimedRun run = null;
|
||||||
|
ChatOrigin origin = ChatOrigin.web(conversation, username, 1L, null, null, userId).withAgent(1L);
|
||||||
|
if (scheduled) {
|
||||||
|
jdbc.update("UPDATE mate_agent_goal SET auto_followup_enabled=TRUE WHERE id=?", goal.getId());
|
||||||
|
var now = java.time.LocalDateTime.now(); continuations.discover(now);
|
||||||
|
run = coordinator.claim(continuations.get(goal.getId()), goals.getById(goal.getId()), now);
|
||||||
|
assertNotNull(run); assertTrue(coordinator.markRunning(run, now));
|
||||||
|
origin = ChatOrigin.web(conversation, username, 1L, null).withAgent(1L)
|
||||||
|
.withExecutionAttribution(new vip.mate.agent.context.ExecutionAttribution(goal.getId(), run.attempt().id(), null, null, run.attempt().leaseToken()));
|
||||||
|
}
|
||||||
|
return new Fixture(username, conversation, goal, run, origin);
|
||||||
|
}
|
||||||
|
|
||||||
|
private vip.mate.agent.BaseAgent graphAgent(boolean plan, vip.mate.agent.AgentToolSet toolSet, ChatModel model) {
|
||||||
|
CompiledGraph graph = ReflectionTestUtils.invokeMethod(builder, plan ? "buildPlanExecuteGraph" : "buildReActGraph", toolSet, model, 12, null);
|
||||||
|
assertNotNull(graph);
|
||||||
|
vip.mate.agent.BaseAgent agent = plan
|
||||||
|
? new vip.mate.agent.graph.plan.StateGraphPlanExecuteAgent(mock(ChatClient.class), conversations, graph, planning, model, window, toolSet)
|
||||||
|
: new StateGraphReActAgent(mock(ChatClient.class), conversations, graph, model, window, toolSet);
|
||||||
|
ReflectionTestUtils.setField(agent, "agentId", "1");
|
||||||
|
ReflectionTestUtils.setField(agent, "agentName", "JSON graph fixture");
|
||||||
|
ReflectionTestUtils.setField(agent, "systemPrompt", "Follow the user's managed JSON requirements.");
|
||||||
|
ReflectionTestUtils.setField(agent, "goalService", goals);
|
||||||
|
return agent;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user