mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-13 03:13:41 +08:00
fix(team): reject clarifying worker results (#610)
This commit is contained in:
parent
1eabbb68ac
commit
770198ba69
@ -57,6 +57,26 @@ public class TeamDispatchService {
|
|||||||
private static final Pattern GENERATED_FILE_MARKDOWN_LINK = Pattern.compile(
|
private static final Pattern GENERATED_FILE_MARKDOWN_LINK = Pattern.compile(
|
||||||
"\\[([^\\]\\r\\n]{1,200})]\\(((?:https?://[^/\\s)\\]]+)?/api/v1/files/generated/[A-Za-z0-9-]+)\\)");
|
"\\[([^\\]\\r\\n]{1,200})]\\(((?:https?://[^/\\s)\\]]+)?/api/v1/files/generated/[A-Za-z0-9-]+)\\)");
|
||||||
|
|
||||||
|
private static final Set<String> CLARIFICATION_CUES = Set.of(
|
||||||
|
"您希望",
|
||||||
|
"你希望",
|
||||||
|
"是否继续",
|
||||||
|
"请问",
|
||||||
|
"能否",
|
||||||
|
"可以提供",
|
||||||
|
"请提供",
|
||||||
|
"需要您",
|
||||||
|
"需要你",
|
||||||
|
"我应该",
|
||||||
|
"如何处理",
|
||||||
|
"what would you like",
|
||||||
|
"how should i",
|
||||||
|
"could you provide",
|
||||||
|
"please provide",
|
||||||
|
"do you want me",
|
||||||
|
"should i",
|
||||||
|
"would you like");
|
||||||
|
|
||||||
/** One JDK 21 virtual thread per member-agent run. */
|
/** One JDK 21 virtual thread per member-agent run. */
|
||||||
private static final ExecutorService DISPATCH_EXECUTOR =
|
private static final ExecutorService DISPATCH_EXECUTOR =
|
||||||
Executors.newVirtualThreadPerTaskExecutor();
|
Executors.newVirtualThreadPerTaskExecutor();
|
||||||
@ -337,9 +357,37 @@ public class TeamDispatchService {
|
|||||||
&& taskService.listDeliverables(task).isEmpty()) {
|
&& taskService.listDeliverables(task).isEmpty()) {
|
||||||
return "required deliverable was not attached";
|
return "required deliverable was not attached";
|
||||||
}
|
}
|
||||||
|
if (looksLikeClarificationQuestion(reply)) {
|
||||||
|
return "member asked for clarification instead of producing a result";
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean looksLikeClarificationQuestion(String reply) {
|
||||||
|
if (reply == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String normalized = reply.strip().replaceAll("\\s+", " ");
|
||||||
|
if (normalized.isBlank() || normalized.length() > 800) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String lower = normalized.toLowerCase();
|
||||||
|
boolean hasCue = CLARIFICATION_CUES.stream().anyMatch(lower::contains);
|
||||||
|
if (!hasCue) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return normalized.endsWith("?")
|
||||||
|
|| normalized.endsWith("?")
|
||||||
|
|| lower.contains("what would you like")
|
||||||
|
|| lower.contains("how should i")
|
||||||
|
|| lower.contains("could you provide")
|
||||||
|
|| lower.contains("please provide")
|
||||||
|
|| normalized.contains("请问")
|
||||||
|
|| normalized.contains("是否继续")
|
||||||
|
|| normalized.contains("如何处理")
|
||||||
|
|| normalized.contains("请提供");
|
||||||
|
}
|
||||||
|
|
||||||
private boolean attachGeneratedFileDeliverable(TeamTaskEntity task, String reply) {
|
private boolean attachGeneratedFileDeliverable(TeamTaskEntity task, String reply) {
|
||||||
if (!requiresDeliverable(task) || reply == null || reply.isBlank()) {
|
if (!requiresDeliverable(task) || reply == null || reply.isBlank()) {
|
||||||
return false;
|
return false;
|
||||||
@ -393,7 +441,8 @@ public class TeamDispatchService {
|
|||||||
- Execute this task now. Your final reply becomes the task result reported to the team lead, so end with a complete, self-contained summary of what you produced.
|
- Execute this task now. Your final reply becomes the task result reported to the team lead, so end with a complete, self-contained summary of what you produced.
|
||||||
- Report milestones with team_tasks(action="progress", taskId=%s, percent=..., step=...).
|
- Report milestones with team_tasks(action="progress", taskId=%s, percent=..., step=...).
|
||||||
- If the output is a document, spreadsheet or presentation, generate a real file (renderDocx / renderXlsx / renderPptx or the docx/pptx/xlsx skills) and register it with team_tasks(action="attach", taskId=%s, name="<file name>", url=<the download link the render tool returned>). Keep the result a summary — do not paste file contents.
|
- If the output is a document, spreadsheet or presentation, generate a real file (renderDocx / renderXlsx / renderPptx or the docx/pptx/xlsx skills) and register it with team_tasks(action="attach", taskId=%s, name="<file name>", url=<the download link the render tool returned>). Keep the result a summary — do not paste file contents.
|
||||||
- If you are missing an input you cannot obtain yourself, call team_tasks(action="comment", taskId=%s, type="blocker", text="what you need") and stop.
|
- If scope is ambiguous but you can make a reasonable assumption, state the assumption and continue.
|
||||||
|
- If you are missing an input you cannot obtain yourself, call team_tasks(action="comment", taskId=%s, type="blocker", text="what you need") and stop. Do not ask the lead or user for clarification in your final reply.
|
||||||
""".formatted(task.getId(), task.getId(), task.getId()));
|
""".formatted(task.getId(), task.getId(), task.getId()));
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -173,6 +173,26 @@ class TeamDispatchServiceTest {
|
|||||||
verify(eventChannel).publishTaskEvent(any(), eq("team_task_retrying"), any());
|
verify(eventChannel).publishTaskEvent(any(), eq("team_task_retrying"), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("a clarifying question is requeued instead of being reported as completed")
|
||||||
|
void settleClarifyingQuestionRequeues() {
|
||||||
|
TeamTaskEntity running = task(1L, MEMBER_A);
|
||||||
|
running.setStatus(TeamTaskStatus.IN_PROGRESS);
|
||||||
|
running.setDispatchCount(1);
|
||||||
|
when(taskService.getTask(1L)).thenReturn(running);
|
||||||
|
when(taskService.requeueUnusableResult(1L,
|
||||||
|
"member asked for clarification instead of producing a result"))
|
||||||
|
.thenReturn(true);
|
||||||
|
|
||||||
|
service.settleOutcome(running, "您希望我如何处理?");
|
||||||
|
|
||||||
|
verify(taskService).requeueUnusableResult(1L,
|
||||||
|
"member asked for clarification instead of producing a result");
|
||||||
|
verify(taskService, never()).completeTask(any(), any(), anyString());
|
||||||
|
verify(announceService, never()).announceTaskSettled(any());
|
||||||
|
verify(eventChannel).publishTaskEvent(any(), eq("team_task_retrying"), any());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@DisplayName("an unusable third result fails instead of bypassing the circuit breaker")
|
@DisplayName("an unusable third result fails instead of bypassing the circuit breaker")
|
||||||
void settleFallbackFailsAfterDispatchBudget() {
|
void settleFallbackFailsAfterDispatchBudget() {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user