From cba9ff4f0b7be7ee214e922d926496725a3dad7c Mon Sep 17 00:00:00 2001 From: slhafzjw Date: Sat, 14 Mar 2026 21:27:38 +0800 Subject: [PATCH] refactor(action): pass launcher through meta action flow instead of inferring command by file extension --- .../slhaf/partner/core/action/ActionCore.java | 3 +- .../core/action/entity/GeneratedData.java | 1 + .../partner/core/action/entity/MetaAction.kt | 6 +- .../core/action/entity/MetaActionInfo.kt | 55 +++++++++++++------ .../execution/CommandExecutionService.java | 12 +--- .../execution/OriginExecutionService.java | 14 +---- .../runner/mcp/DynamicActionMcpManager.java | 12 ++-- .../executor/DynamicActionGenerator.java | 2 + .../action/executor/entity/RepairerInput.java | 2 +- .../modules/action/planner/ActionPlanner.java | 12 ++-- 10 files changed, 62 insertions(+), 57 deletions(-) diff --git a/Partner-Core/src/main/java/work/slhaf/partner/core/action/ActionCore.java b/Partner-Core/src/main/java/work/slhaf/partner/core/action/ActionCore.java index 469f53e5..d3455ed1 100644 --- a/Partner-Core/src/main/java/work/slhaf/partner/core/action/ActionCore.java +++ b/Partner-Core/src/main/java/work/slhaf/partner/core/action/ActionCore.java @@ -329,7 +329,8 @@ public class ActionCore extends PartnerCore { MetaAction.Type type = BUILTIN_LOCATION.equals(split[0]) ? MetaAction.Type.BUILTIN : MetaAction.Type.MCP; return new MetaAction( split[1], - metaActionInfo.isIo(), + metaActionInfo.getIo(), + metaActionInfo.getLauncher(), type, split[0] ); diff --git a/Partner-Core/src/main/java/work/slhaf/partner/core/action/entity/GeneratedData.java b/Partner-Core/src/main/java/work/slhaf/partner/core/action/entity/GeneratedData.java index 512e33c8..49de01d0 100644 --- a/Partner-Core/src/main/java/work/slhaf/partner/core/action/entity/GeneratedData.java +++ b/Partner-Core/src/main/java/work/slhaf/partner/core/action/entity/GeneratedData.java @@ -10,6 +10,7 @@ public class GeneratedData { private List dependencies; private String code; private String codeType; + private String launcher; private boolean serialize; private JSONObject responseSchema; } diff --git a/Partner-Core/src/main/java/work/slhaf/partner/core/action/entity/MetaAction.kt b/Partner-Core/src/main/java/work/slhaf/partner/core/action/entity/MetaAction.kt index 48ace057..4a5be26e 100644 --- a/Partner-Core/src/main/java/work/slhaf/partner/core/action/entity/MetaAction.kt +++ b/Partner-Core/src/main/java/work/slhaf/partner/core/action/entity/MetaAction.kt @@ -13,9 +13,13 @@ data class MetaAction( * 是否IO密集,用于决定使用何种线程池 */ val io: Boolean = false, + /** + * 启动器/解释器,对于原生 MCP Tool 、Dynamic Action 来说可忽略,目前仅用于 ORIGIN 类型 + */ + val launcher: String? = null, /** * 行动程序类型,可分为 MCP、ORIGIN、BUILTIN 三种, - * 分别对应读取到的 MCP Tool、生成的临时行动程序、本地内置行动 + * 分别对应读取到的 MCP Tool、生成的临时行动程序、内置行动 */ val type: Type, /** diff --git a/Partner-Core/src/main/java/work/slhaf/partner/core/action/entity/MetaActionInfo.kt b/Partner-Core/src/main/java/work/slhaf/partner/core/action/entity/MetaActionInfo.kt index c0b4a8af..b49335dc 100644 --- a/Partner-Core/src/main/java/work/slhaf/partner/core/action/entity/MetaActionInfo.kt +++ b/Partner-Core/src/main/java/work/slhaf/partner/core/action/entity/MetaActionInfo.kt @@ -1,25 +1,44 @@ -package work.slhaf.partner.core.action.entity; +package work.slhaf.partner.core.action.entity -import com.alibaba.fastjson2.JSONObject; -import lombok.Data; +import com.alibaba.fastjson2.JSONObject -import java.util.List; -import java.util.Map; -@Data -public class MetaActionInfo { - private boolean io; +data class MetaActionInfo( + /** + * 是否 IO 密集 + */ + val io: Boolean, + /** + * 所需的启动器/解释器 + */ + val launcher: String?, + /** + * 参数描述 + */ + val params: Map, + /** + * 行动功能描述 + */ + val description: String, + /** + * 行动标签 + */ + val tags: Set, + /** + * 前置行动依赖 + */ + val preActions: Set, + /** + * 后置行动依赖 + */ + val postActions: Set, - private Map params; - private String description; - private List tags; - - private List preActions; - private List postActions; /** * 是否严格依赖前置行动的成功执行,若为true且前置行动失败则不执行该行动,后置任务多为触发式。默认即执行。 */ - private boolean strictDependencies; - - private JSONObject responseSchema; -} + val strictDependencies: Boolean, + /** + * 响应格式说明 + */ + val responseSchema: JSONObject, +) diff --git a/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/execution/CommandExecutionService.java b/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/execution/CommandExecutionService.java index e7c0598f..515cf217 100644 --- a/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/execution/CommandExecutionService.java +++ b/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/execution/CommandExecutionService.java @@ -11,18 +11,10 @@ import java.util.concurrent.atomic.AtomicInteger; public class CommandExecutionService { - public String[] buildCommands(String ext, Map params, String absolutePath) { - String command = switch (ext) { - case "py" -> "python"; - case "sh" -> "bash"; - default -> null; - }; - if (command == null) { - return null; - } + public String[] buildCommands(String launcher, Map params, String absolutePath) { int paramSize = params == null ? 0 : params.size(); String[] commands = new String[paramSize + 2]; - commands[0] = command; + commands[0] = launcher; commands[1] = absolutePath; AtomicInteger paramCount = new AtomicInteger(2); if (params != null) { diff --git a/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/execution/OriginExecutionService.java b/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/execution/OriginExecutionService.java index 9b869565..d3100f86 100644 --- a/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/execution/OriginExecutionService.java +++ b/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/execution/OriginExecutionService.java @@ -1,6 +1,5 @@ package work.slhaf.partner.core.action.runner.execution; -import cn.hutool.core.io.FileUtil; import work.slhaf.partner.core.action.entity.MetaAction; import work.slhaf.partner.core.action.runner.RunnerClient; @@ -17,18 +16,7 @@ public class OriginExecutionService { public RunnerClient.RunnerResponse run(MetaAction metaAction) { RunnerClient.RunnerResponse response = new RunnerClient.RunnerResponse(); File file = new File(metaAction.getLocation()); - String ext = FileUtil.getSuffix(file); - if (ext == null || ext.isEmpty()) { - response.setOk(false); - response.setData("未知文件类型"); - return response; - } - String[] commands = commandExecutionService.buildCommands(ext, metaAction.getParams(), file.getAbsolutePath()); - if (commands == null || commands.length == 0) { - response.setOk(false); - response.setData("不支持的文件类型: " + file.getName()); - return response; - } + String[] commands = commandExecutionService.buildCommands(metaAction.getLauncher(), metaAction.getParams(), file.getAbsolutePath()); CommandExecutionService.Result execResult = commandExecutionService.exec(commands); response.setOk(execResult.isOk()); response.setData(execResult.getTotal()); diff --git a/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/mcp/DynamicActionMcpManager.java b/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/mcp/DynamicActionMcpManager.java index 7efa380c..b809d054 100644 --- a/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/mcp/DynamicActionMcpManager.java +++ b/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/mcp/DynamicActionMcpManager.java @@ -1,6 +1,5 @@ package work.slhaf.partner.core.action.runner.mcp; -import cn.hutool.core.io.FileUtil; import cn.hutool.json.JSONUtil; import com.alibaba.fastjson2.JSONObject; import io.modelcontextprotocol.common.McpTransportContext; @@ -292,8 +291,8 @@ public class DynamicActionMcpManager implements AutoCloseable { Map additional = Map.of( "pre", info.getPreActions(), "post", info.getPostActions(), - "strict_pre", info.isStrictDependencies(), - "io", info.isIo() + "strict_pre", info.getStrictDependencies(), + "io", info.getIo() ); McpSchema.Tool tool = McpSchema.Tool.builder() .name(name) @@ -305,18 +304,17 @@ public class DynamicActionMcpManager implements AutoCloseable { .build(); return McpStatelessServerFeatures.AsyncToolSpecification.builder() .tool(tool) - .callHandler(buildToolHandler(program)) + .callHandler(buildToolHandler(program, info.getLauncher())) .build(); } - private BiFunction> buildToolHandler(File program) { + private BiFunction> buildToolHandler(File program, String launcher) { return (mcpTransportContext, callToolRequest) -> { Map arguments = callToolRequest.arguments(); if (arguments == null) { arguments = Map.of(); } - String ext = FileUtil.getSuffix(program); - String[] commands = commandExecutionService.buildCommands(ext, arguments, program.getAbsolutePath()); + String[] commands = commandExecutionService.buildCommands(launcher, arguments, program.getAbsolutePath()); if (commands == null) { return Mono.just(McpSchema.CallToolResult.builder() .addTextContent("未知文件类型: " + program.getName()) diff --git a/Partner-Core/src/main/java/work/slhaf/partner/module/modules/action/executor/DynamicActionGenerator.java b/Partner-Core/src/main/java/work/slhaf/partner/module/modules/action/executor/DynamicActionGenerator.java index 6b994b9e..05c27375 100644 --- a/Partner-Core/src/main/java/work/slhaf/partner/module/modules/action/executor/DynamicActionGenerator.java +++ b/Partner-Core/src/main/java/work/slhaf/partner/module/modules/action/executor/DynamicActionGenerator.java @@ -46,6 +46,7 @@ public class DynamicActionGenerator extends AbstractAgentModule.Sub recentMessages; - private Map params; + private Map params; private String actionDescription; private List historyActionResults; } diff --git a/Partner-Core/src/main/java/work/slhaf/partner/module/modules/action/planner/ActionPlanner.java b/Partner-Core/src/main/java/work/slhaf/partner/module/modules/action/planner/ActionPlanner.java index c0a2246f..b7d0722b 100644 --- a/Partner-Core/src/main/java/work/slhaf/partner/module/modules/action/planner/ActionPlanner.java +++ b/Partner-Core/src/main/java/work/slhaf/partner/module/modules/action/planner/ActionPlanner.java @@ -380,12 +380,12 @@ public class ActionPlanner extends AbstractAgentModule.Running preActions = metaActionInfo.getPreActions(); - boolean preActionsExist = preActions != null && !preActions.isEmpty(); + Set preActions = metaActionInfo.getPreActions(); + boolean preActionsExist = preActions.isEmpty(); if (!preActionsExist) { continue; } - if (!metaActionInfo.isStrictDependencies()) { + if (!metaActionInfo.getStrictDependencies()) { continue; } if (checkDependenciesExist(lastOrder, preActions, primaryActionChain)) { @@ -398,8 +398,8 @@ public class ActionPlanner extends AbstractAgentModule.Running actionsInChain = primaryActionChain.computeIfAbsent(lastOrder, list -> new ArrayList<>()); - preActions = new ArrayList<>(preActions); - preActions.removeAll(actionsInChain); + preActions = new HashSet<>(preActions); + actionsInChain.forEach(preActions::remove); actionsInChain.addAll(preActions); tempOrders.add(lastOrder); } @@ -418,7 +418,7 @@ public class ActionPlanner extends AbstractAgentModule.Running preActions, + private boolean checkDependenciesExist(int lastOrder, Set preActions, Map> primaryActionChain) { if (!primaryActionChain.containsKey(lastOrder)) { return false;