feat: add requiresApproval flag to support HITL workflows
This commit is contained in:
@@ -62,6 +62,10 @@ public class ToolMetadata {
|
|||||||
@Builder.Default
|
@Builder.Default
|
||||||
private Boolean isRegistered = true;
|
private Boolean isRegistered = true;
|
||||||
|
|
||||||
|
// 2-6. HITL 승인 필요 여부
|
||||||
|
@Builder.Default
|
||||||
|
private Boolean requiresApproval = false;
|
||||||
|
|
||||||
public boolean isVisible() {
|
public boolean isVisible() {
|
||||||
return visible != null ? visible : true;
|
return visible != null ? visible : true;
|
||||||
}
|
}
|
||||||
@@ -74,6 +78,10 @@ public class ToolMetadata {
|
|||||||
this.isRegistered = isRegistered;
|
this.isRegistered = isRegistered;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isRequiresApproval() {
|
||||||
|
return requiresApproval != null ? requiresApproval : false;
|
||||||
|
}
|
||||||
|
|
||||||
// 3. 연동 아키텍처 구분 (DIRECT / MCI_EAI)
|
// 3. 연동 아키텍처 구분 (DIRECT / MCI_EAI)
|
||||||
private String integrationType; // 연동 타입: "DIRECT" 또는 "MCI_EAI"
|
private String integrationType; // 연동 타입: "DIRECT" 또는 "MCI_EAI"
|
||||||
|
|
||||||
|
|||||||
@@ -190,7 +190,8 @@ public class ToolScaffolder {
|
|||||||
description = "%s",
|
description = "%s",
|
||||||
prompt = "%s",
|
prompt = "%s",
|
||||||
mappingId = "%s",
|
mappingId = "%s",
|
||||||
register = %s
|
register = %s,
|
||||||
|
requiresApproval = false
|
||||||
)
|
)
|
||||||
public Object execute(%sReq req) {
|
public Object execute(%sReq req) {
|
||||||
return executeLegacy("%s", "%s", req);
|
return executeLegacy("%s", "%s", req);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import java.util.stream.Stream;
|
|||||||
|
|
||||||
public class ToolSourceUpdater {
|
public class ToolSourceUpdater {
|
||||||
|
|
||||||
public static void updateToolSource(String toolName, String domainGroup, String description, boolean register) throws Exception {
|
public static void updateToolSource(String toolName, String domainGroup, String description, boolean register, Boolean requiresApproval) throws Exception {
|
||||||
// 1. Find all *Service.java files in axhub-tool-* directories
|
// 1. Find all *Service.java files in axhub-tool-* directories
|
||||||
String envSourceDir = System.getenv("AXHUB_SOURCE_DIR");
|
String envSourceDir = System.getenv("AXHUB_SOURCE_DIR");
|
||||||
Path rootDir = envSourceDir != null ? Paths.get(envSourceDir) : Paths.get(".");
|
Path rootDir = envSourceDir != null ? Paths.get(envSourceDir) : Paths.get(".");
|
||||||
@@ -87,6 +87,21 @@ public class ToolSourceUpdater {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 5.5 Update requiresApproval flag
|
||||||
|
if (requiresApproval != null) {
|
||||||
|
Pattern appPattern = Pattern.compile("(@McpFunction\\s*\\([^)]*name\\s*=\\s*\"" + Pattern.quote(toolName) + "\"[^)]*requiresApproval\\s*=\\s*)(true|false)([^a-zA-Z0-9])", Pattern.DOTALL);
|
||||||
|
Matcher appMatcher = appPattern.matcher(content);
|
||||||
|
if (appMatcher.find()) {
|
||||||
|
content = appMatcher.replaceFirst("$1" + requiresApproval + "$3");
|
||||||
|
} else {
|
||||||
|
Pattern addAppPattern = Pattern.compile("(@McpFunction\\s*\\([^)]*name\\s*=\\s*\"" + Pattern.quote(toolName) + "\")", Pattern.DOTALL);
|
||||||
|
Matcher addAppMatcher = addAppPattern.matcher(content);
|
||||||
|
if (addAppMatcher.find()) {
|
||||||
|
content = addAppMatcher.replaceFirst("$1, requiresApproval = " + requiresApproval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 6. Write back to file
|
// 6. Write back to file
|
||||||
Files.writeString(targetFile, content);
|
Files.writeString(targetFile, content);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,10 @@ public class ToolMetadata {
|
|||||||
@Builder.Default
|
@Builder.Default
|
||||||
private Boolean isRegistered = true;
|
private Boolean isRegistered = true;
|
||||||
|
|
||||||
|
// 2-6. HITL 승인 필요 여부
|
||||||
|
@Builder.Default
|
||||||
|
private Boolean requiresApproval = false;
|
||||||
|
|
||||||
public boolean isVisible() {
|
public boolean isVisible() {
|
||||||
return visible != null ? visible : true;
|
return visible != null ? visible : true;
|
||||||
}
|
}
|
||||||
@@ -74,6 +78,10 @@ public class ToolMetadata {
|
|||||||
this.isRegistered = isRegistered;
|
this.isRegistered = isRegistered;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isRequiresApproval() {
|
||||||
|
return requiresApproval != null ? requiresApproval : false;
|
||||||
|
}
|
||||||
|
|
||||||
// 3. 연동 아키텍처 구분 (DIRECT / MCI_EAI)
|
// 3. 연동 아키텍처 구분 (DIRECT / MCI_EAI)
|
||||||
private String integrationType; // 연동 타입: "DIRECT" 또는 "MCI_EAI"
|
private String integrationType; // 연동 타입: "DIRECT" 또는 "MCI_EAI"
|
||||||
|
|
||||||
|
|||||||
@@ -51,8 +51,9 @@ public class ScaffoldingController {
|
|||||||
String domainGroup = req.get("domainGroup");
|
String domainGroup = req.get("domainGroup");
|
||||||
String description = req.get("description");
|
String description = req.get("description");
|
||||||
boolean register = Boolean.parseBoolean(req.getOrDefault("register", "true"));
|
boolean register = Boolean.parseBoolean(req.getOrDefault("register", "true"));
|
||||||
|
Boolean requiresApproval = req.containsKey("requiresApproval") ? Boolean.parseBoolean(req.get("requiresApproval")) : null;
|
||||||
|
|
||||||
io.shinhanlife.axhub.common.util.ToolSourceUpdater.updateToolSource(toolName, domainGroup, description, register);
|
io.shinhanlife.axhub.common.util.ToolSourceUpdater.updateToolSource(toolName, domainGroup, description, register, requiresApproval);
|
||||||
return "성공";
|
return "성공";
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return "오류 발생: " + e.getMessage();
|
return "오류 발생: " + e.getMessage();
|
||||||
|
|||||||
@@ -19,4 +19,7 @@ public @interface McpFunction {
|
|||||||
|
|
||||||
// 추가: 툴 목록 노출 여부 제어 (false 시 라우팅은 되나 목록에서 숨김)
|
// 추가: 툴 목록 노출 여부 제어 (false 시 라우팅은 되나 목록에서 숨김)
|
||||||
boolean visible() default true;
|
boolean visible() default true;
|
||||||
|
|
||||||
|
// 추가: HITL 승인 체계 지원 (실행 전 사용자 승인 필요 여부)
|
||||||
|
boolean requiresApproval() default false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,9 @@ public class ToolMetadata {
|
|||||||
@Builder.Default
|
@Builder.Default
|
||||||
private Boolean isRegistered = true;
|
private Boolean isRegistered = true;
|
||||||
|
|
||||||
|
@Builder.Default
|
||||||
|
private Boolean requiresApproval = false;
|
||||||
|
|
||||||
public boolean isVisible() {
|
public boolean isVisible() {
|
||||||
return visible != null ? visible : true;
|
return visible != null ? visible : true;
|
||||||
}
|
}
|
||||||
@@ -57,4 +60,8 @@ public class ToolMetadata {
|
|||||||
this.isRegistered = isRegistered;
|
this.isRegistered = isRegistered;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isRequiresApproval() {
|
||||||
|
return requiresApproval != null ? requiresApproval : false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -101,6 +101,7 @@ public class ToolRegistryHeartbeatSender {
|
|||||||
boolean isVisible = functionAnnotation.visible();
|
boolean isVisible = functionAnnotation.visible();
|
||||||
meta.setVisible(isVisible);
|
meta.setVisible(isVisible);
|
||||||
meta.setRegistered(isRegister);
|
meta.setRegistered(isRegister);
|
||||||
|
meta.setRequiresApproval(functionAnnotation.requiresApproval());
|
||||||
|
|
||||||
Map<String, String> prompts = new HashMap<>();
|
Map<String, String> prompts = new HashMap<>();
|
||||||
String promptText = functionAnnotation.prompt();
|
String promptText = functionAnnotation.prompt();
|
||||||
|
|||||||
Reference in New Issue
Block a user