mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-11-02 14:11:49 +08:00
fix(agent): parse employee drafts after reasoning blocks (#648)
This commit is contained in:
parent
894c945fab
commit
6bbd3ac4da
@ -295,6 +295,14 @@ public class AgentGenerationService {
|
||||
private JsonNode parseJson(String response) {
|
||||
if (response == null || response.isBlank()) return null;
|
||||
String cleaned = response.trim();
|
||||
// Some reasoning models prepend thinking to content on non-streaming
|
||||
// calls. Strip only leading blocks: tags inside JSON string values are
|
||||
// legitimate persona text, and JSON examples in thinking are not drafts.
|
||||
while (cleaned.startsWith("<think>")) {
|
||||
int end = cleaned.indexOf("</think>", "<think>".length());
|
||||
if (end < 0) return null; // Incomplete reasoning is not a final answer.
|
||||
cleaned = cleaned.substring(end + "</think>".length()).trim();
|
||||
}
|
||||
if (cleaned.startsWith("```json")) cleaned = cleaned.substring(7);
|
||||
else if (cleaned.startsWith("```")) cleaned = cleaned.substring(3);
|
||||
if (cleaned.endsWith("```")) cleaned = cleaned.substring(0, cleaned.length() - 3);
|
||||
|
||||
@ -0,0 +1,86 @@
|
||||
package vip.mate.agent.service;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.springframework.ai.chat.messages.AssistantMessage;
|
||||
import org.springframework.ai.chat.model.ChatModel;
|
||||
import org.springframework.ai.chat.model.ChatResponse;
|
||||
import org.springframework.ai.chat.model.Generation;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import vip.mate.agent.AgentGraphBuilder;
|
||||
import vip.mate.exception.MateClawException;
|
||||
import vip.mate.llm.model.ModelConfigEntity;
|
||||
import vip.mate.llm.service.ModelConfigService;
|
||||
import vip.mate.skill.service.SkillService;
|
||||
import vip.mate.tool.service.AvailableToolService;
|
||||
import vip.mate.wiki.service.WikiKnowledgeBaseService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
class AgentGenerationServiceTest {
|
||||
private ChatModel model;
|
||||
private AgentGenerationService service;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
var configs = mock(ModelConfigService.class);
|
||||
var builder = mock(AgentGraphBuilder.class);
|
||||
var tools = mock(AvailableToolService.class);
|
||||
var skills = mock(SkillService.class);
|
||||
var kbs = mock(WikiKnowledgeBaseService.class);
|
||||
var config = new ModelConfigEntity();
|
||||
model = mock(ChatModel.class);
|
||||
when(configs.getDefaultModel()).thenReturn(config);
|
||||
when(builder.buildRuntimeChatModel(config)).thenReturn(model);
|
||||
when(tools.listAvailable()).thenReturn(List.of());
|
||||
when(skills.listEnabledSkills(1L)).thenReturn(List.of());
|
||||
when(kbs.listByWorkspace(1L)).thenReturn(List.of());
|
||||
service = new AgentGenerationService(configs, builder, new ObjectMapper(), tools, skills, kbs);
|
||||
}
|
||||
|
||||
private void response(String text) {
|
||||
when(model.call(any(Prompt.class))).thenReturn(new ChatResponse(
|
||||
List.of(new Generation(new AssistantMessage(text)))));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"{\"name\":\"周报助手\"}",
|
||||
"```json\n{\"name\":\"周报助手\"}\n```",
|
||||
"<think>先考虑配置</think>\n{\"name\":\"周报助手\"}",
|
||||
"<think>{\"name\":\"思考中的示例\"}</think>\n```json\n{\"name\":\"周报助手\"}\n```",
|
||||
" \n<think>第一步</think>\n<think>第二步</think>\n{\"name\":\"周报助手\"}"
|
||||
})
|
||||
void acceptsFinalJsonAfterOptionalThinking(String text) {
|
||||
response(text);
|
||||
assertEquals("周报助手", service.generateDraft("跨部门周报汇总", 1L).getName());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"{\"name\":\"助手\",\"systemPrompt\":\"保留 <think>示例</think> 原文\"}",
|
||||
"<think>规划</think>\n{\"name\":\"助手\",\"systemPrompt\":\"保留 <think>示例</think> 原文\"}"
|
||||
})
|
||||
void preservesLiteralTagsInsideJsonStrings(String text) {
|
||||
response(text);
|
||||
assertEquals("保留 <think>示例</think> 原文", service.generateDraft("助手", 1L).getSystemPrompt());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"", "<think>{\"name\":\"未完成思考\"}",
|
||||
"<think>{\"name\":\"只有思考\"}</think>",
|
||||
"<think>规划</think>\n{\"name\":", "[]",
|
||||
"说明文字 {\"name\":\"不应猜测提取\"}"
|
||||
})
|
||||
void rejectsMissingOrMalformedFinalObject(String text) {
|
||||
response(text);
|
||||
assertThrows(MateClawException.class, () -> service.generateDraft("助手", 1L));
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user