feat: Tool metadata register flag and dynamic source updater UI
This commit is contained in:
@@ -55,11 +55,24 @@ public class ToolMetadata {
|
||||
private String podUrl;
|
||||
|
||||
// 2-4. 가시성 여부
|
||||
private boolean visible = true;
|
||||
@Builder.Default
|
||||
private Boolean visible = true;
|
||||
|
||||
// 2-5. Redis 등록 여부 (UI 표출용)
|
||||
@Builder.Default
|
||||
private boolean isRegistered = true;
|
||||
private Boolean isRegistered = true;
|
||||
|
||||
public boolean isVisible() {
|
||||
return visible != null ? visible : true;
|
||||
}
|
||||
|
||||
public boolean isRegistered() {
|
||||
return isRegistered != null ? isRegistered : true;
|
||||
}
|
||||
|
||||
public void setRegistered(Boolean isRegistered) {
|
||||
this.isRegistered = isRegistered;
|
||||
}
|
||||
|
||||
// 3. 연동 아키텍처 구분 (DIRECT / MCI_EAI)
|
||||
private String integrationType; // 연동 타입: "DIRECT" 또는 "MCI_EAI"
|
||||
|
||||
@@ -68,7 +68,7 @@ public class ToolScaffolder {
|
||||
String createDate = getOrAsk(args, 7, scanner, "8. 작성일 (엔터 입력 시 '" + defaultDate + "'): ");
|
||||
if (createDate.trim().isEmpty()) createDate = defaultDate;
|
||||
|
||||
String result = scaffold(baseName, interfaceId, description, group, routingType, moduleName, author, createDate);
|
||||
String result = scaffold(baseName, interfaceId, description, group, routingType, moduleName, author, createDate, true);
|
||||
System.out.println(result);
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ public class ToolScaffolder {
|
||||
return scanner.nextLine().trim();
|
||||
}
|
||||
|
||||
public static String scaffold(String baseName, String interfaceId, String description, String group, String routingType, String moduleName, String author, String createDate) throws IOException {
|
||||
public static String scaffold(String baseName, String interfaceId, String description, String group, String routingType, String moduleName, String author, String createDate, boolean register) throws IOException {
|
||||
Path serviceDir = Paths.get(moduleName, BASE_PACKAGE_PATH, "service");
|
||||
Path dtoDir = Paths.get(moduleName, BASE_PACKAGE_PATH, "dto");
|
||||
|
||||
@@ -186,39 +186,55 @@ public class ToolScaffolder {
|
||||
name = "%s",
|
||||
description = "%s",
|
||||
prompt = "%s",
|
||||
mappingId = "%s"
|
||||
mappingId = "%s",
|
||||
register = %s
|
||||
)
|
||||
public Object execute(%sReq req) {
|
||||
return executeLegacy("%s", "%s", req);
|
||||
}
|
||||
}
|
||||
""".formatted(
|
||||
BASE_PACKAGE, BASE_PACKAGE, BASE_PACKAGE, BASE_PACKAGE, BASE_PACKAGE,
|
||||
BASE_PACKAGE, baseName, author, createDate, createDate, author,
|
||||
routingType, group, baseName,
|
||||
toolName, description, description + " 해줘.", interfaceId,
|
||||
toolName, description, description + " 해줘.", interfaceId, register,
|
||||
baseName, routingType, interfaceId
|
||||
);
|
||||
|
||||
Files.writeString(serviceDir.resolve(baseName + "Service.java"), serviceContent);
|
||||
|
||||
// Append to YAML if exists
|
||||
Path yamlPath = Paths.get(moduleName, "src/main/resources", "application-local.yml");
|
||||
// Append to YAML
|
||||
Path resourcesDir = Paths.get(moduleName, "src/main/resources");
|
||||
Files.createDirectories(resourcesDir);
|
||||
Path yamlPath = resourcesDir.resolve("application-local.yml");
|
||||
|
||||
String yamlContent = "";
|
||||
if (Files.exists(yamlPath)) {
|
||||
String yamlContent = Files.readString(yamlPath);
|
||||
if (yamlContent.contains("functions:")) {
|
||||
String newFunctionYaml = """
|
||||
|
||||
%s:
|
||||
description: "%s"
|
||||
prompt: "%s"
|
||||
mappingId: "%s"
|
||||
""".formatted(toolName, description, description + " 해줘.", interfaceId);
|
||||
yamlContent = yamlContent.replaceFirst("functions:", "functions:" + newFunctionYaml);
|
||||
Files.writeString(yamlPath, yamlContent);
|
||||
log.append("[YAML] ").append(yamlPath).append(" (함수 설정 자동 등록됨)\n");
|
||||
}
|
||||
yamlContent = Files.readString(yamlPath);
|
||||
}
|
||||
|
||||
String newFunctionYaml = """
|
||||
|
||||
%s:
|
||||
description: "%s"
|
||||
prompt: "%s"
|
||||
mappingId: "%s"
|
||||
""".formatted(toolName, description, description + " 해줘.", interfaceId);
|
||||
|
||||
if (yamlContent.contains("functions:")) {
|
||||
yamlContent = yamlContent.replaceFirst("functions:", "functions:" + newFunctionYaml);
|
||||
} else {
|
||||
if (!yamlContent.isEmpty() && !yamlContent.endsWith("\n")) {
|
||||
yamlContent += "\n";
|
||||
}
|
||||
yamlContent += """
|
||||
mcp:
|
||||
functions:%s""".formatted(newFunctionYaml);
|
||||
}
|
||||
|
||||
Files.writeString(yamlPath, yamlContent);
|
||||
log.append("[YAML] ").append(yamlPath).append(" (함수 설정 자동 등록됨)\n");
|
||||
|
||||
log.append("\n=========================================\n");
|
||||
log.append(" Scaffolding Complete!\n");
|
||||
log.append("=========================================\n");
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package io.shinhanlife.axhub.common.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class ToolSourceUpdater {
|
||||
|
||||
public static void updateToolSource(String toolName, String domainGroup, String description, boolean register) throws Exception {
|
||||
// 1. Find all *Service.java files in axhub-tool-* directories
|
||||
Path rootDir = Paths.get(".");
|
||||
|
||||
List<Path> javaFiles;
|
||||
try (Stream<Path> paths = Files.walk(rootDir)) {
|
||||
javaFiles = paths
|
||||
.filter(Files::isRegularFile)
|
||||
.filter(p -> p.toString().endsWith("Service.java"))
|
||||
.filter(p -> p.toString().contains("axhub-tool-"))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
Path targetFile = null;
|
||||
String content = null;
|
||||
|
||||
// 2. Find the specific file for the tool
|
||||
Pattern namePattern = Pattern.compile("@McpFunction\\\\s*\\\\([^)]*name\\\\s*=\\\\s*\\\"" + Pattern.quote(toolName) + "\\\"", Pattern.DOTALL);
|
||||
|
||||
for (Path path : javaFiles) {
|
||||
String text = Files.readString(path);
|
||||
if (namePattern.matcher(text).find()) {
|
||||
targetFile = path;
|
||||
content = text;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (targetFile == null) {
|
||||
throw new Exception("소스 코드를 찾을 수 없습니다: " + toolName);
|
||||
}
|
||||
|
||||
// 3. Update @McpTool group
|
||||
if (domainGroup != null && !domainGroup.trim().isEmpty()) {
|
||||
Pattern groupPattern = Pattern.compile("(@McpTool\\\\s*\\\\([^)]*group\\\\s*=\\\\s*\\\")([^\\\"]+)(\\\")", Pattern.DOTALL);
|
||||
Matcher groupMatcher = groupPattern.matcher(content);
|
||||
if (groupMatcher.find()) {
|
||||
content = groupMatcher.replaceFirst("$1" + domainGroup + "$3");
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Update @McpFunction description
|
||||
if (description != null) {
|
||||
Pattern funcPattern = Pattern.compile("(@McpFunction\\\\s*\\\\([^)]*name\\\\s*=\\\\s*\\\"" + Pattern.quote(toolName) + "\\\"[^)]*description\\\\s*=\\\\s*\\\")([^\\\"]+)(\\\")", Pattern.DOTALL);
|
||||
Matcher funcMatcher = funcPattern.matcher(content);
|
||||
if (funcMatcher.find()) {
|
||||
content = funcMatcher.replaceFirst("$1" + description.replace("\\", "\\\\").replace("$", "\\\\$") + "$3");
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Update register flag
|
||||
Pattern regPattern = Pattern.compile("(@McpFunction\\\\s*\\\\([^)]*name\\\\s*=\\\\s*\\\"" + Pattern.quote(toolName) + "\\\"[^)]*register\\\\s*=\\\\s*)(true|false)([^a-zA-Z0-9])", Pattern.DOTALL);
|
||||
Matcher regMatcher = regPattern.matcher(content);
|
||||
if (regMatcher.find()) {
|
||||
content = regMatcher.replaceFirst("$1" + register + "$3");
|
||||
} else {
|
||||
Pattern addRegPattern = Pattern.compile("(@McpFunction\\\\s*\\\\([^)]*name\\\\s*=\\\\s*\\\"" + Pattern.quote(toolName) + "\\\")", Pattern.DOTALL);
|
||||
Matcher addRegMatcher = addRegPattern.matcher(content);
|
||||
if (addRegMatcher.find()) {
|
||||
content = addRegMatcher.replaceFirst("$1, register = " + register);
|
||||
}
|
||||
}
|
||||
|
||||
// 6. Write back to file
|
||||
Files.writeString(targetFile, content);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user