diff --git a/spring-ai-alibaba-jmanus/pom.xml b/spring-ai-alibaba-jmanus/pom.xml
index 3d0cf204e9..902e39a92e 100644
--- a/spring-ai-alibaba-jmanus/pom.xml
+++ b/spring-ai-alibaba-jmanus/pom.xml
@@ -255,6 +255,23 @@
mockito-junit-jupiter
test
+
+
+
+ org.apache.poi
+ poi-ooxml
+ 5.2.3
+
+
+ org.apache.poi
+ poi
+ 5.2.3
+
+
+ commons-io
+ commons-io
+ 2.15.1
+
diff --git a/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/dynamic/agent/model/enums/AgentEnum.java b/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/dynamic/agent/model/enums/AgentEnum.java
index c8c6d64123..e0692dcaaa 100644
--- a/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/dynamic/agent/model/enums/AgentEnum.java
+++ b/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/dynamic/agent/model/enums/AgentEnum.java
@@ -26,7 +26,8 @@ public enum AgentEnum {
MAPREDUCE_DATA_PREPARE_AGENT("MAPREDUCE_DATA_PREPARE_AGENT", "mapreduce_data_prepare_agent"),
MAPREDUCE_FIN_AGENT("MAPREDUCE_FIN_AGENT", "mapreduce_fin_agent"),
MAPREDUCE_MAP_TASK_AGENT("MAPREDUCE_MAP_TASK_AGENT", "mapreduce_map_task_agent"),
- MAPREDUCE_REDUCE_TASK_AGENT("MAPREDUCE_REDUCE_TASK_AGENT", "mapreduce_reduce_task_agent");
+ MAPREDUCE_REDUCE_TASK_AGENT("MAPREDUCE_REDUCE_TASK_AGENT", "mapreduce_reduce_task_agent"),
+ PPT_GENERATOR_AGENT("PPT_GENERATOR_AGENT", "ppt_generator_agent");
private String agentName;
diff --git a/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/dynamic/prompt/model/enums/PromptEnum.java b/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/dynamic/prompt/model/enums/PromptEnum.java
index 5340853e77..64c5c57b38 100644
--- a/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/dynamic/prompt/model/enums/PromptEnum.java
+++ b/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/dynamic/prompt/model/enums/PromptEnum.java
@@ -94,10 +94,10 @@ public enum PromptEnum {
"tool/doc-loader-tool-parameters.txt"),
// File Merge Tool
- FILE_MERGE_TOOL_DESCRIPTION("FILE_MERGE_TOOL_DESCRIPTION", MessageType.SYSTEM, PromptType.TOOL_DESCRIPTION, true,
- "tool/file-merge-tool-description.txt"),
- FILE_MERGE_TOOL_PARAMETERS("FILE_MERGE_TOOL_PARAMETERS", MessageType.SYSTEM, PromptType.TOOL_PARAMETER, true,
- "tool/file-merge-tool-parameters.txt"),
+ FILE_MERGE_TOOL_TOOL_DESCRIPTION("FILE_MERGE_TOOL_TOOL_DESCRIPTION", MessageType.SYSTEM,
+ PromptType.TOOL_DESCRIPTION, true, "tool/file-merge-tool-description.txt"),
+ FILE_MERGE_TOOL_TOOL_PARAMETERS("FILE_MERGE_TOOL_TOOL_PARAMETERS", MessageType.SYSTEM, PromptType.TOOL_PARAMETER,
+ true, "tool/file-merge-tool-parameters.txt"),
// Data Split Tool
DATA_SPLIT_TOOL_DESCRIPTION("DATA_SPLIT_TOOL_DESCRIPTION", MessageType.SYSTEM, PromptType.TOOL_DESCRIPTION, true,
@@ -127,7 +127,13 @@ public enum PromptEnum {
TERMINATE_TOOL_DESCRIPTION("TERMINATE_TOOL_DESCRIPTION", MessageType.SYSTEM, PromptType.TOOL_DESCRIPTION, true,
"tool/terminate-tool-description.txt"),
TERMINATE_TOOL_PARAMETERS("TERMINATE_TOOL_PARAMETERS", MessageType.SYSTEM, PromptType.TOOL_PARAMETER, true,
- "tool/terminate-tool-parameters.txt");
+ "tool/terminate-tool-parameters.txt"),
+
+ // PPT Generator Tool
+ PPTGENERATOROPERATOR_TOOL_DESCRIPTION("PPTGENERATOROPERATOR_TOOL_DESCRIPTION", MessageType.SYSTEM,
+ PromptType.TOOL_DESCRIPTION, true, "tool/ppt-generator-operator-tool-description.txt"),
+ PPTGENERATOROPERATOR_TOOL_PARAMETERS("PPTGENERATOROPERATOR_TOOL_PARAMETERS", MessageType.SYSTEM,
+ PromptType.TOOL_PARAMETER, true, "tool/ppt-generator-operator-tool-parameters.txt");
private String promptName;
diff --git a/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/planning/PlanningFactory.java b/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/planning/PlanningFactory.java
index 334c55d2cd..62bc86aba2 100644
--- a/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/planning/PlanningFactory.java
+++ b/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/planning/PlanningFactory.java
@@ -83,6 +83,7 @@
import com.alibaba.cloud.ai.example.manus.tool.mapreduce.ReduceOperationTool;
import com.alibaba.cloud.ai.example.manus.tool.textOperator.TextFileOperator;
import com.alibaba.cloud.ai.example.manus.tool.textOperator.TextFileService;
+import com.alibaba.cloud.ai.example.manus.tool.pptGenerator.PptGeneratorOperator;
import com.alibaba.cloud.ai.example.manus.workflow.SummaryWorkflow;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -150,6 +151,9 @@ public class PlanningFactory implements IPlanningFactory {
@Lazy
private CronService cronService;
+ @Autowired
+ private PptGeneratorOperator pptGeneratorOperator;
+
public PlanningFactory(ChromeDriverService chromeDriverService, PlanExecutionRecorder recorder,
ManusProperties manusProperties, TextFileService textFileService, McpService mcpService,
SmartContentSavingService innerStorageService, UnifiedDirectoryManager unifiedDirectoryManager,
@@ -241,6 +245,7 @@ public Map toolCallbackMap(String planId, String ro
unifiedDirectoryManager, terminateColumns));
toolDefinitions.add(new FinalizeTool(planId, manusProperties, sharedStateManager, unifiedDirectoryManager));
toolDefinitions.add(new CronTool(cronService, objectMapper, toolPromptManager));
+ toolDefinitions.add(pptGeneratorOperator);
List functionCallbacks = mcpService.getFunctionCallbacks(planId);
for (McpServiceEntity toolCallback : functionCallbacks) {
diff --git a/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/tool/pptGenerator/IPptGeneratorService.java b/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/tool/pptGenerator/IPptGeneratorService.java
new file mode 100644
index 0000000000..54274f6961
--- /dev/null
+++ b/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/tool/pptGenerator/IPptGeneratorService.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.cloud.ai.example.manus.tool.pptGenerator;
+
+import java.io.IOException;
+
+import com.alibaba.cloud.ai.example.manus.config.ManusProperties;
+import com.alibaba.cloud.ai.example.manus.tool.textOperator.FileState;
+
+/**
+ * PPT generator service interface, providing PPT file operation management functions
+ */
+public interface IPptGeneratorService {
+
+ /**
+ * Get the file state
+ * @param planId Plan ID
+ * @return File state
+ */
+ FileState getFileState(String planId);
+
+ /**
+ * Update the file state
+ * @param planId Plan ID
+ * @param filePath File path
+ * @param operationResult Operation result
+ */
+ void updateFileState(String planId, String filePath, String operationResult);
+
+ /**
+ * Get the current file path
+ * @param planId Plan ID
+ * @return Current file path
+ */
+ String getCurrentFilePath(String planId);
+
+ /**
+ * Get the last operation result
+ * @param planId Plan ID
+ * @return Last operation result
+ */
+ String getLastOperationResult(String planId);
+
+ /**
+ * Validate PPT file path
+ * @param planId Plan ID
+ * @param filePath File path
+ * @return Validated absolute path
+ * @throws IOException IO exception
+ */
+ String validatePptFilePath(String planId, String filePath) throws IOException;
+
+ /**
+ * Check if the file type is supported
+ * @param filePath File path
+ * @return True if supported, false otherwise
+ */
+ boolean isSupportedPptFileType(String filePath);
+
+ /**
+ * Get the file extension
+ * @param filePath File path
+ * @return File extension
+ */
+ String getFileExtension(String filePath);
+
+ /**
+ * Clean up plan resources
+ * @param planId Plan ID
+ */
+ void cleanupForPlan(String planId);
+
+ /**
+ * Get the Manus configuration properties
+ * @return Manus configuration properties
+ */
+ ManusProperties getManusProperties();
+
+}
diff --git a/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/tool/pptGenerator/PptGeneratorOperator.java b/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/tool/pptGenerator/PptGeneratorOperator.java
new file mode 100644
index 0000000000..531d13e602
--- /dev/null
+++ b/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/tool/pptGenerator/PptGeneratorOperator.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.cloud.ai.example.manus.tool.pptGenerator;
+
+import com.alibaba.cloud.ai.example.manus.tool.AbstractBaseTool;
+import com.alibaba.cloud.ai.example.manus.tool.ToolPromptManager;
+import com.alibaba.cloud.ai.example.manus.tool.code.ToolExecuteResult;
+import com.alibaba.cloud.ai.example.manus.tool.filesystem.UnifiedDirectoryManager;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+
+@Component
+public class PptGeneratorOperator extends AbstractBaseTool {
+
+ private static final Logger log = LoggerFactory.getLogger(PptGeneratorOperator.class);
+
+ private final PptGeneratorService pptGeneratorService;
+
+ private final ObjectMapper objectMapper;
+
+ private final ToolPromptManager toolPromptManager;
+
+ private final UnifiedDirectoryManager unifiedDirectoryManager;
+
+ private static final String TOOL_NAME = "ppt_generator_operator";
+
+ public PptGeneratorOperator(PptGeneratorService pptGeneratorService, ObjectMapper objectMapper,
+ ToolPromptManager toolPromptManager, UnifiedDirectoryManager unifiedDirectoryManager) {
+ this.pptGeneratorService = pptGeneratorService;
+ this.objectMapper = objectMapper;
+ this.toolPromptManager = toolPromptManager;
+ this.unifiedDirectoryManager = unifiedDirectoryManager;
+ }
+
+ /**
+ * Run the tool (accepts JSON string input)
+ */
+ @Override
+ public ToolExecuteResult run(PptInput input) {
+ log.info("PptGeneratorOperator input: action={}, outputPath={}, title={}", input.getAction(),
+ input.getOutputPath(), input.getTitle());
+ try {
+ String planId = this.currentPlanId;
+
+ if (!"create".equals(input.getAction())) {
+ pptGeneratorService.updateFileState(planId, input.getOutputPath(),
+ "Error: Unsupported operations: " + input.getAction());
+ return new ToolExecuteResult(
+ "Unsupported operations: " + input.getAction() + ",Only supports the 'create' operation");
+ }
+
+ // Validate the path. This will throw an exception if the path is invalid.
+ String resultPath = validateAndProcessPath(planId, input.getOutputPath());
+ input.setOutputPath(resultPath);
+
+ // Update the file state to processing.
+ pptGeneratorService.updateFileState(planId, resultPath, "Processing: Generating PPT file");
+
+ String path = pptGeneratorService.createPpt(input);
+
+ // Update the file state to success.
+ pptGeneratorService.updateFileState(planId, path, "Success: PPT file generated successfully");
+
+ return new ToolExecuteResult("PPT file generated successfully, save path: " + path);
+ }
+ catch (IllegalArgumentException e) {
+ String planId = this.currentPlanId;
+ pptGeneratorService.updateFileState(planId, input.getOutputPath(),
+ "Error: Parameter validation failed: " + e.getMessage());
+ return new ToolExecuteResult("Parameter validation failed: " + e.getMessage());
+ }
+ catch (Exception e) {
+ log.error("PPT generation failed", e);
+ String planId = this.currentPlanId;
+ pptGeneratorService.updateFileState(planId, input.getOutputPath(),
+ "Error: PPT generation failed: " + e.getMessage());
+ return new ToolExecuteResult("PPT generation failed: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Validate and process the output path.
+ * @param planId Plan ID
+ * @param outputPath Output path
+ * @return Processed absolute path
+ * @throws IOException IO exception
+ */
+ private String validateAndProcessPath(String planId, String outputPath) throws IOException {
+ // Even if the path is empty, call the validation method, which will throw an
+ // IllegalArgumentException.
+ return pptGeneratorService.validatePptFilePath(planId, outputPath);
+ }
+
+ @Override
+ public String getName() {
+ return TOOL_NAME;
+ }
+
+ @Override
+ public String getDescription() {
+ return toolPromptManager.getToolDescription("pptGeneratorOperator");
+ }
+
+ @Override
+ public String getParameters() {
+ return toolPromptManager.getToolParameters("pptGeneratorOperator");
+ }
+
+ @Override
+ public Class getInputType() {
+ return PptInput.class;
+ }
+
+ @Override
+ public String getServiceGroup() {
+ return "default-service-group";
+ }
+
+ @Override
+ public void cleanup(String planId) {
+ // Clean up file state.
+ pptGeneratorService.cleanupForPlan(planId);
+ log.info("Cleaning up PPT generator resources for plan: {}", planId);
+ }
+
+ @Override
+ public String getCurrentToolStateString() {
+ String planId = this.currentPlanId;
+ if (planId != null) {
+ return String.format("PPT Generator - Current File: %s, Last Operation: %s",
+ pptGeneratorService.getCurrentFilePath(planId), pptGeneratorService.getLastOperationResult(planId));
+ }
+ return "PPT Generator is ready";
+ }
+
+}
diff --git a/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/tool/pptGenerator/PptGeneratorService.java b/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/tool/pptGenerator/PptGeneratorService.java
new file mode 100644
index 0000000000..41ed70168f
--- /dev/null
+++ b/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/tool/pptGenerator/PptGeneratorService.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.cloud.ai.example.manus.tool.pptGenerator;
+
+import com.alibaba.cloud.ai.example.manus.tool.pptGenerator.PptInput.SlideContent;
+import com.alibaba.cloud.ai.example.manus.config.ManusProperties;
+import com.alibaba.cloud.ai.example.manus.tool.filesystem.UnifiedDirectoryManager;
+import com.alibaba.cloud.ai.example.manus.tool.textOperator.FileState;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.poi.xslf.usermodel.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.awt.Rectangle;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Service
+public class PptGeneratorService implements IPptGeneratorService {
+
+ private static final Logger log = LoggerFactory.getLogger(PptGeneratorService.class);
+
+ @Autowired
+ private ManusProperties manusProperties;
+
+ @Autowired
+ private UnifiedDirectoryManager unifiedDirectoryManager;
+
+ // File state management.
+ private final ConcurrentHashMap fileStates = new ConcurrentHashMap<>();
+
+ // Supported PPT file extensions.
+ private static final Set SUPPORTED_EXTENSIONS = new HashSet<>(Set.of(".pptx", ".ppt"));
+
+ /**
+ * Create a PPT file.
+ * @param pptInput PPT input parameters.
+ * @return Path of the generated PPT file.
+ * @throws IOException IO exception.
+ */
+ public String createPpt(PptInput pptInput) throws IOException {
+ // Validate input.
+ if (pptInput == null) {
+ throw new IllegalArgumentException("PPT input cannot be null");
+ }
+ if (StringUtils.isBlank(pptInput.getOutputPath())) {
+ throw new IllegalArgumentException("Output path cannot be blank");
+ }
+ if (StringUtils.isBlank(pptInput.getTitle())) {
+ throw new IllegalArgumentException("Title cannot be blank");
+ }
+
+ // Create PPT document.
+ XMLSlideShow presentation = new XMLSlideShow();
+
+ try {
+ // Create title slide.
+ XSLFSlideMaster titleMaster = presentation.getSlideMasters().get(0);
+ XSLFSlideLayout titleLayout = titleMaster.getLayout(SlideLayout.TITLE);
+ if (titleLayout == null) {
+ log.error("PPT template is missing the required layout (TITLE)");
+ throw new IllegalStateException("PPT template is missing the required layout (TITLE)");
+ }
+ XSLFSlide titleSlide = presentation.createSlide(titleLayout);
+
+ // Set title and subtitle.
+ XSLFTextShape titleShape = titleSlide.getPlaceholder(0);
+ if (titleShape != null) {
+ titleShape.setText(pptInput.getTitle());
+ }
+
+ XSLFTextShape subtitleShape = titleSlide.getPlaceholder(1);
+ if (subtitleShape != null && StringUtils.isNotBlank(pptInput.getSubtitle())) {
+ subtitleShape.setText(pptInput.getSubtitle());
+ }
+
+ // Create content slide.
+ XSLFSlideLayout contentLayout = titleMaster.getLayout(SlideLayout.TITLE_AND_CONTENT);
+ if (contentLayout == null) {
+ log.error("PPT template is missing the required layout (TITLE_AND_CONTENT)");
+ throw new IllegalStateException("PPT template is missing the required layout (TITLE_AND_CONTENT)");
+ }
+
+ List slideContents = pptInput.getSlideContents();
+ if (slideContents != null && !slideContents.isEmpty()) {
+ for (int i = 0; i < slideContents.size(); i++) {
+ SlideContent slideContent = slideContents.get(i);
+ if (slideContent == null) {
+ continue;
+ }
+
+ // Validate slide content.
+ if (StringUtils.isBlank(slideContent.getTitle())
+ && StringUtils.isBlank(slideContent.getContent())) {
+ log.warn("Skip empty slide content, index: {}", i);
+ continue;
+ }
+
+ XSLFSlide contentSlide = presentation.createSlide(contentLayout);
+
+ // Set slide title.
+ XSLFTextShape contentTitle = contentSlide.getPlaceholder(0);
+ if (contentTitle != null && StringUtils.isNotBlank(slideContent.getTitle())) {
+ contentTitle.setText(slideContent.getTitle());
+ }
+
+ // Set slide content.
+ XSLFTextShape contentBody = contentSlide.getPlaceholder(1);
+ if (contentBody != null && StringUtils.isNotBlank(slideContent.getContent())) {
+ contentBody.setText(slideContent.getContent());
+ }
+
+ // Insert image (if specified).
+ if (StringUtils.isNotBlank(slideContent.getImagePath())) {
+ File imageFile = new File(slideContent.getImagePath());
+ if (imageFile.exists()) {
+ try (FileInputStream fis = new FileInputStream(imageFile)) {
+ byte[] pictureData = IOUtils.toByteArray(fis);
+ XSLFPictureData picture = presentation.addPicture(pictureData,
+ XSLFPictureData.PictureType.JPEG);
+ XSLFPictureShape pictureShape = contentSlide.createPicture(picture);
+ // Set image position and size.
+ pictureShape.setAnchor(new Rectangle(50, 150, 400, 300));
+ }
+ catch (IOException e) {
+ log.warn("Failed to load image: {}", imageFile.getAbsolutePath(), e);
+ }
+ }
+ else {
+ log.warn("Specified image file does not exist: {}", imageFile.getAbsolutePath());
+ }
+ }
+ }
+ }
+
+ // Save PPT file.
+ File outputFile = new File(pptInput.getOutputPath());
+ try (FileOutputStream out = new FileOutputStream(outputFile)) {
+ presentation.write(out);
+ }
+
+ log.info("PPT created successfully: {}", pptInput.getOutputPath());
+ return pptInput.getOutputPath();
+ }
+ finally {
+ // Ensure resources are properly released.
+ try {
+ presentation.close();
+ }
+ catch (IOException e) {
+ log.warn("Failed to close PPT document", e);
+ }
+ }
+ }
+
+ // PptGeneratorService interface implementation.
+
+ @Override
+ public FileState getFileState(String planId) {
+ return fileStates.computeIfAbsent(planId, k -> new FileState());
+ }
+
+ @Override
+ public void updateFileState(String planId, String filePath, String operationResult) {
+ FileState fileState = getFileState(planId);
+ fileState.setCurrentFilePath(filePath);
+ fileState.setLastOperationResult(operationResult);
+ log.info("Updated PPT file state for plan {}: path={}, result={}", planId, filePath, operationResult);
+ }
+
+ @Override
+ public String getCurrentFilePath(String planId) {
+ return getFileState(planId).getCurrentFilePath();
+ }
+
+ @Override
+ public String getLastOperationResult(String planId) {
+ return getFileState(planId).getLastOperationResult();
+ }
+
+ @Override
+ public String validatePptFilePath(String planId, String filePath) throws IOException {
+ // 1. Basic validation.
+ if (StringUtils.isBlank(filePath)) {
+ throw new IllegalArgumentException("File path cannot be blank");
+ }
+
+ // 2. File type validation.
+ if (!isSupportedPptFileType(filePath)) {
+ throw new IllegalArgumentException("Unsupported file type: " + getFileExtension(filePath));
+ }
+
+ // 3. Path normalization.
+ Path requestedPath = Path.of(filePath).normalize();
+
+ // 4. Security validation - prevent path traversal attacks.
+ if (requestedPath.toString().contains("../") || requestedPath.isAbsolute()) {
+ throw new SecurityException("Illegal path: absolute path or parent directory reference is not allowed");
+ }
+
+ // 5. Limit output directory range.
+ Path baseDir = Path.of("extensions/pptGenerator").normalize();
+
+ // 6. Get the final absolute path.
+ Path absolutePath = unifiedDirectoryManager.getSpecifiedDirectory(baseDir.resolve(requestedPath).toString());
+
+ // 7. Ensure the directory exists.
+ Files.createDirectories(absolutePath.getParent());
+
+ return absolutePath.toString();
+ }
+
+ @Override
+ public boolean isSupportedPptFileType(String filePath) {
+ String fileExtension = getFileExtension(filePath);
+ return SUPPORTED_EXTENSIONS.contains(fileExtension.toLowerCase());
+ }
+
+ @Override
+ public String getFileExtension(String filePath) {
+ if (filePath == null || filePath.trim().isEmpty()) {
+ return "";
+ }
+ int lastDotIndex = filePath.lastIndexOf('.');
+ return lastDotIndex > 0 ? filePath.substring(lastDotIndex) : "";
+ }
+
+ @Override
+ public void cleanupForPlan(String planId) {
+ fileStates.remove(planId);
+ log.info("Cleaned up PPT generator file state for plan: {}", planId);
+ }
+
+ @Override
+ public ManusProperties getManusProperties() {
+ return manusProperties;
+ }
+
+}
diff --git a/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/tool/pptGenerator/PptInput.java b/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/tool/pptGenerator/PptInput.java
new file mode 100644
index 0000000000..68de93128b
--- /dev/null
+++ b/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/tool/pptGenerator/PptInput.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.cloud.ai.example.manus.tool.pptGenerator;
+
+import java.util.List;
+
+public class PptInput {
+
+ private String action;
+
+ @com.fasterxml.jackson.annotation.JsonProperty("output_path")
+ private String outputPath;
+
+ private String title;
+
+ private String subtitle;
+
+ @com.fasterxml.jackson.annotation.JsonProperty("slide_contents")
+ private List slideContents;
+
+ public static class SlideContent {
+
+ private String title;
+
+ private String content;
+
+ @com.fasterxml.jackson.annotation.JsonProperty("image_path")
+ private String imagePath;
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public void setContent(String content) {
+ this.content = content;
+ }
+
+ public String getImagePath() {
+ return imagePath;
+ }
+
+ public void setImagePath(String imagePath) {
+ this.imagePath = imagePath;
+ }
+
+ }
+
+ public PptInput() {
+ }
+
+ public String getAction() {
+ return action;
+ }
+
+ public void setAction(String action) {
+ this.action = action;
+ }
+
+ public String getOutputPath() {
+ return outputPath;
+ }
+
+ public void setOutputPath(String outputPath) {
+ this.outputPath = outputPath;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getSubtitle() {
+ return subtitle;
+ }
+
+ public void setSubtitle(String subtitle) {
+ this.subtitle = subtitle;
+ }
+
+ public List getSlideContents() {
+ return slideContents;
+ }
+
+ public void setSlideContents(List slideContents) {
+ this.slideContents = slideContents;
+ }
+
+}
diff --git a/spring-ai-alibaba-jmanus/src/main/resources/prompts/en/descriptions.properties b/spring-ai-alibaba-jmanus/src/main/resources/prompts/en/descriptions.properties
index 3a5c35ce61..5c6eaa3669 100644
--- a/spring-ai-alibaba-jmanus/src/main/resources/prompts/en/descriptions.properties
+++ b/spring-ai-alibaba-jmanus/src/main/resources/prompts/en/descriptions.properties
@@ -30,8 +30,8 @@ INNER_STORAGE_CONTENT_TOOL_TOOL_DESCRIPTION=Description for internal storage con
INNER_STORAGE_CONTENT_TOOL_TOOL_PARAMETERS=Parameter definition JSON for internal storage content tool
DOC_LOADER_TOOL_DESCRIPTION=Description for document loader tool
DOC_LOADER_TOOL_PARAMETERS=Parameter definition JSON for document loader tool
-FILE_MERGE_TOOL_DESCRIPTION=Description for file merge tool
-FILE_MERGE_TOOL_PARAMETERS=Parameter definition JSON for file merge tool
+FILE_MERGE_TOOL_TOOL_DESCRIPTION=Description for file merge tool
+FILE_MERGE_TOOL_TOOL_PARAMETERS=Parameter definition JSON for file merge tool
DATA_SPLIT_TOOL_DESCRIPTION=Description for data split tool
DATA_SPLIT_TOOL_PARAMETERS=Parameter definition JSON for data split tool
MAP_OUTPUT_TOOL_DESCRIPTION=Description for map output tool
@@ -42,3 +42,5 @@ FINALIZE_TOOL_DESCRIPTION=Description for finalize tool
FINALIZE_TOOL_PARAMETERS=Parameter definition JSON for finalize tool
TERMINATE_TOOL_DESCRIPTION=Description for terminate tool
TERMINATE_TOOL_PARAMETERS=Parameter definition JSON for terminate tool
+PPT_GENERATOR_TOOL_DESCRIPTION=Description for PPT generator tool
+PPT_GENERATOR_TOOL_PARAMETERS=Parameter definition JSON for PPT generator tool
diff --git a/spring-ai-alibaba-jmanus/src/main/resources/prompts/en/tool/ppt-generator-operator-tool-description.txt b/spring-ai-alibaba-jmanus/src/main/resources/prompts/en/tool/ppt-generator-operator-tool-description.txt
new file mode 100644
index 0000000000..0b10363032
--- /dev/null
+++ b/spring-ai-alibaba-jmanus/src/main/resources/prompts/en/tool/ppt-generator-operator-tool-description.txt
@@ -0,0 +1,12 @@
+Tool for creating and generating PPT files.
+
+Supported operations:
+- create: Create a new PPT file, requires output_path and title parameters, subtitle and slide_contents are optional
+
+Supported PPT file types:
+- .pptx
+- .ppt
+
+When creating PPT, you can set:
+- Title and subtitle
+- Multiple slides, each slide can contain title, content and image path
diff --git a/spring-ai-alibaba-jmanus/src/main/resources/prompts/en/tool/ppt-generator-operator-tool-parameters.txt b/spring-ai-alibaba-jmanus/src/main/resources/prompts/en/tool/ppt-generator-operator-tool-parameters.txt
new file mode 100644
index 0000000000..5482d0ac9c
--- /dev/null
+++ b/spring-ai-alibaba-jmanus/src/main/resources/prompts/en/tool/ppt-generator-operator-tool-parameters.txt
@@ -0,0 +1,50 @@
+{
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "action": {
+ "type": "string",
+ "const": "create"
+ },
+ "output_path": {
+ "type": "string",
+ "description": "Path to save the generated PPT file"
+ },
+ "title": {
+ "type": "string",
+ "description": "Title of the PPT"
+ },
+ "subtitle": {
+ "type": "string",
+ "description": "Subtitle of the PPT (optional)"
+ },
+ "slide_contents": {
+ "type": "array",
+ "description": "List of slide contents (optional)",
+ "items": {
+ "type": "object",
+ "properties": {
+ "title": {
+ "type": "string",
+ "description": "Slide title"
+ },
+ "content": {
+ "type": "string",
+ "description": "Slide content"
+ },
+ "image_path": {
+ "type": "string",
+ "description": "Image path in the slide (optional)"
+ }
+ },
+ "required": ["title", "content"],
+ "additionalProperties": false
+ }
+ }
+ },
+ "required": ["action", "output_path", "title"],
+ "additionalProperties": false
+ }
+ ]
+}
diff --git a/spring-ai-alibaba-jmanus/src/main/resources/prompts/startup-agents/en/ppt_generator_agent/agent-config.yml b/spring-ai-alibaba-jmanus/src/main/resources/prompts/startup-agents/en/ppt_generator_agent/agent-config.yml
new file mode 100644
index 0000000000..1ea9a0e127
--- /dev/null
+++ b/spring-ai-alibaba-jmanus/src/main/resources/prompts/startup-agents/en/ppt_generator_agent/agent-config.yml
@@ -0,0 +1,27 @@
+# PPT Generator Agent Configuration
+agentName: PPT_GENERATOR_AGENT
+agentDescription: A professional PowerPoint presentation generation agent capable of automatically creating PPT files with a title slide and multiple content slides, supporting both text and images.
+availableToolKeys:
+ - ppt_generator_operator
+ - inner_storage_content_tool
+ - text_file_operator
+ - terminate
+
+# Next Step Prompt Configuration
+nextStepPrompt: |
+ You are a professional PPT generation operator.
+
+ Use the ppt_generator_operator tool to create a PPT file that includes a title slide and multiple content slides.
+
+ This agent supports the following features:
+ - Create a new PPT presentation
+ - Set the title slide (including title and subtitle)
+ - Add multiple content slides, each slide may include:
+ - Slide title
+ - Text content
+
+ To extract content from existing text files or documents, please use the text_file_operator or inner_storage_content_tool.
+
+ Note:
+ - When specifying the path for generating the PPT, do not use an absolute address.
+ - Please return the path of the generated PPT file to the user.
diff --git a/spring-ai-alibaba-jmanus/src/main/resources/prompts/startup-agents/zh/ppt_generator_agent/agent-config.yml b/spring-ai-alibaba-jmanus/src/main/resources/prompts/startup-agents/zh/ppt_generator_agent/agent-config.yml
new file mode 100644
index 0000000000..06460b75fb
--- /dev/null
+++ b/spring-ai-alibaba-jmanus/src/main/resources/prompts/startup-agents/zh/ppt_generator_agent/agent-config.yml
@@ -0,0 +1,27 @@
+# PPT生成代理配置
+agentName: PPT_GENERATOR_AGENT
+agentDescription: 一个专业的PowerPoint演示文稿生成代理,能够自动创建包含标题页和多个内容页的PPT文件,内容支持文本与图片。
+availableToolKeys:
+ - ppt_generator_operator
+ - inner_storage_content_tool
+ - text_file_operator
+ - terminate
+
+# 下一步操作提示配置
+nextStepPrompt: |
+ 您是一名专业的PPT生成操作员。
+
+ 请使用 ppt_generator_operator 工具创建一个包含标题页和多个内容幻灯片的PPT文件。
+
+ 本代理支持以下功能:
+ - 创建新PPT演示文稿
+ - 设置标题页(包含标题与副标题)
+ - 添加多个内容幻灯片,每页可包含:
+ - 幻灯片标题
+ - 文本内容
+
+ 如需从已有文本或文档中提取内容,请使用 text_file_operator 或 inner_storage_content_tool。
+
+ 注意:
+ - 在指定生成PPT路径时不要使用绝对地址
+ - 请返回给用户生成的PPT文件路径
diff --git a/spring-ai-alibaba-jmanus/src/main/resources/prompts/zh/descriptions.properties b/spring-ai-alibaba-jmanus/src/main/resources/prompts/zh/descriptions.properties
index 3281b7ff1f..8440d043c2 100644
--- a/spring-ai-alibaba-jmanus/src/main/resources/prompts/zh/descriptions.properties
+++ b/spring-ai-alibaba-jmanus/src/main/resources/prompts/zh/descriptions.properties
@@ -30,8 +30,8 @@ INNER_STORAGE_CONTENT_TOOL_TOOL_DESCRIPTION=\u5185\u90E8\u5B58\u50A8\u5185\u5BB9
INNER_STORAGE_CONTENT_TOOL_TOOL_PARAMETERS=\u5185\u90E8\u5B58\u50A8\u5185\u5BB9\u5DE5\u5177\u7684\u53C2\u6570\u5B9A\u4E49JSON
DOC_LOADER_TOOL_DESCRIPTION=\u6587\u6863\u52A0\u8F7D\u5DE5\u5177\u7684\u63CF\u8FF0\u4FE1\u606F
DOC_LOADER_TOOL_PARAMETERS=\u6587\u6863\u52A0\u8F7D\u5DE5\u5177\u7684\u53C2\u6570\u5B9A\u4E49JSON
-FILE_MERGE_TOOL_DESCRIPTION=\u6587\u4EF6\u5408\u5E76\u5DE5\u5177\u7684\u63CF\u8FF0\u4FE1\u606F
-FILE_MERGE_TOOL_PARAMETERS=\u6587\u4EF6\u5408\u5E76\u5DE5\u5177\u7684\u53C2\u6570\u5B9A\u4E49JSON
+FILE_MERGE_TOOL_TOOL_DESCRIPTION=\u6587\u4EF6\u5408\u5E76\u5DE5\u5177\u7684\u63CF\u8FF0\u4FE1\u606F
+FILE_MERGE_TOOL_TOOL_PARAMETERS=\u6587\u4EF6\u5408\u5E76\u5DE5\u5177\u7684\u53C2\u6570\u5B9A\u4E49JSON
DATA_SPLIT_TOOL_DESCRIPTION=\u6570\u636E\u5206\u5272\u5DE5\u5177\u7684\u63CF\u8FF0\u4FE1\u606F
DATA_SPLIT_TOOL_PARAMETERS=\u6570\u636E\u5206\u5272\u5DE5\u5177\u7684\u53C2\u6570\u5B9A\u4E49JSON
MAP_OUTPUT_TOOL_DESCRIPTION=\u6620\u5C04\u8F93\u51FA\u5DE5\u5177\u7684\u63CF\u8FF0\u4FE1\u606F
@@ -42,3 +42,5 @@ FINALIZE_TOOL_DESCRIPTION=\u5B8C\u6210\u5DE5\u5177\u7684\u63CF\u8FF0\u4FE1\u606F
FINALIZE_TOOL_PARAMETERS=\u5B8C\u6210\u5DE5\u5177\u7684\u53C2\u6570\u5B9A\u4E49JSON
TERMINATE_TOOL_DESCRIPTION=\u7EC8\u6B62\u5DE5\u5177\u7684\u63CF\u8FF0\u4FE1\u606F
TERMINATE_TOOL_PARAMETERS=\u7EC8\u6B62\u5DE5\u5177\u7684\u53C2\u6570\u5B9A\u4E49JSON
+PPTGENERATOROPERATOR_TOOL_DESCRIPTION=PPT\u751F\u6210\u5668\u5DE5\u5177\u7684\u63CF\u8FF0\u4FE1\u606F
+PPTGENERATOROPERATOR_TOOL_PARAMETERS=PPT\u751F\u6210\u5668\u5DE5\u5177\u7684\u53C2\u6570\u5B9A\u4E49JSON
diff --git a/spring-ai-alibaba-jmanus/src/main/resources/prompts/zh/tool/ppt-generator-operator-tool-description.txt b/spring-ai-alibaba-jmanus/src/main/resources/prompts/zh/tool/ppt-generator-operator-tool-description.txt
new file mode 100644
index 0000000000..902de42bf3
--- /dev/null
+++ b/spring-ai-alibaba-jmanus/src/main/resources/prompts/zh/tool/ppt-generator-operator-tool-description.txt
@@ -0,0 +1,12 @@
+用于创建和生成PPT文件的工具。
+
+支持的操作:
+- create:创建新的PPT文件,需要output_path、title参数,可选subtitle和slide_contents参数
+
+支持的PPT文件类型包括:
+- .pptx
+- .ppt
+
+创建PPT时可以设置:
+- 标题和副标题
+- 多张幻灯片,每张幻灯片可包含标题、内容和图片路径
diff --git a/spring-ai-alibaba-jmanus/src/main/resources/prompts/zh/tool/ppt-generator-operator-tool-parameters.txt b/spring-ai-alibaba-jmanus/src/main/resources/prompts/zh/tool/ppt-generator-operator-tool-parameters.txt
new file mode 100644
index 0000000000..fe26285f27
--- /dev/null
+++ b/spring-ai-alibaba-jmanus/src/main/resources/prompts/zh/tool/ppt-generator-operator-tool-parameters.txt
@@ -0,0 +1,50 @@
+{
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "action": {
+ "type": "string",
+ "const": "create"
+ },
+ "output_path": {
+ "type": "string",
+ "description": "生成的PPT文件保存路径"
+ },
+ "title": {
+ "type": "string",
+ "description": "PPT的标题"
+ },
+ "subtitle": {
+ "type": "string",
+ "description": "PPT的副标题(可选)"
+ },
+ "slide_contents": {
+ "type": "array",
+ "description": "幻灯片内容列表(可选)",
+ "items": {
+ "type": "object",
+ "properties": {
+ "title": {
+ "type": "string",
+ "description": "幻灯片标题"
+ },
+ "content": {
+ "type": "string",
+ "description": "幻灯片内容"
+ },
+ "image_path": {
+ "type": "string",
+ "description": "幻灯片中的图片路径(可选)"
+ }
+ },
+ "required": ["title", "content"],
+ "additionalProperties": false
+ }
+ }
+ },
+ "required": ["action", "output_path", "title"],
+ "additionalProperties": false
+ }
+ ]
+}