diff --git a/mateclaw-server/src/main/java/vip/mate/agent/service/AgentGenerationService.java b/mateclaw-server/src/main/java/vip/mate/agent/service/AgentGenerationService.java
index 8534cfca..c30e830d 100644
--- a/mateclaw-server/src/main/java/vip/mate/agent/service/AgentGenerationService.java
+++ b/mateclaw-server/src/main/java/vip/mate/agent/service/AgentGenerationService.java
@@ -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("")) {
+ int end = cleaned.indexOf("", "".length());
+ if (end < 0) return null; // Incomplete reasoning is not a final answer.
+ cleaned = cleaned.substring(end + "".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);
diff --git a/mateclaw-server/src/test/java/vip/mate/agent/service/AgentGenerationServiceTest.java b/mateclaw-server/src/test/java/vip/mate/agent/service/AgentGenerationServiceTest.java
new file mode 100644
index 00000000..8db913ef
--- /dev/null
+++ b/mateclaw-server/src/test/java/vip/mate/agent/service/AgentGenerationServiceTest.java
@@ -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```",
+ "先考虑配置\n{\"name\":\"周报助手\"}",
+ "{\"name\":\"思考中的示例\"}\n```json\n{\"name\":\"周报助手\"}\n```",
+ " \n第一步\n第二步\n{\"name\":\"周报助手\"}"
+ })
+ void acceptsFinalJsonAfterOptionalThinking(String text) {
+ response(text);
+ assertEquals("周报助手", service.generateDraft("跨部门周报汇总", 1L).getName());
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {
+ "{\"name\":\"助手\",\"systemPrompt\":\"保留 示例 原文\"}",
+ "规划\n{\"name\":\"助手\",\"systemPrompt\":\"保留 示例 原文\"}"
+ })
+ void preservesLiteralTagsInsideJsonStrings(String text) {
+ response(text);
+ assertEquals("保留 示例 原文", service.generateDraft("助手", 1L).getSystemPrompt());
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {
+ "", "{\"name\":\"未完成思考\"}",
+ "{\"name\":\"只有思考\"}",
+ "规划\n{\"name\":", "[]",
+ "说明文字 {\"name\":\"不应猜测提取\"}"
+ })
+ void rejectsMissingOrMalformedFinalObject(String text) {
+ response(text);
+ assertThrows(MateClawException.class, () -> service.generateDraft("助手", 1L));
+ }
+}