diff --git a/Partner-Core/src/main/java/work/slhaf/partner/module/modules/action/builtin/BuiltinActionProvider.java b/Partner-Core/src/main/java/work/slhaf/partner/module/modules/action/builtin/BuiltinActionProvider.java new file mode 100644 index 00000000..ceb55394 --- /dev/null +++ b/Partner-Core/src/main/java/work/slhaf/partner/module/modules/action/builtin/BuiltinActionProvider.java @@ -0,0 +1,7 @@ +package work.slhaf.partner.module.modules.action.builtin; + +import java.util.List; + +public interface BuiltinActionProvider { + List provideBuiltinActions(); +} diff --git a/Partner-Core/src/main/java/work/slhaf/partner/module/modules/action/builtin/BuiltinActionRegistry.java b/Partner-Core/src/main/java/work/slhaf/partner/module/modules/action/builtin/BuiltinActionRegistry.java index 2ade7904..5e50a9d3 100644 --- a/Partner-Core/src/main/java/work/slhaf/partner/module/modules/action/builtin/BuiltinActionRegistry.java +++ b/Partner-Core/src/main/java/work/slhaf/partner/module/modules/action/builtin/BuiltinActionRegistry.java @@ -9,6 +9,7 @@ import work.slhaf.partner.core.action.ActionCapability; import work.slhaf.partner.core.action.entity.MetaActionInfo; import work.slhaf.partner.core.action.exception.MetaActionNotFoundException; +import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -23,8 +24,6 @@ public class BuiltinActionRegistry extends AbstractAgentModule.Standalone { @InjectCapability private ActionCapability actionCapability; - private final BuiltinCommandActionManager builtinCommandActionManager = new BuiltinCommandActionManager(); - @Init public void init() { definitions.clear(); @@ -36,14 +35,10 @@ public class BuiltinActionRegistry extends AbstractAgentModule.Standalone { } protected List buildDefaultActionDefinitions() { - return List.of( - builtinCommandActionManager.buildCommandExecuteDefinition(), - builtinCommandActionManager.buildCommandStartDefinition(), - builtinCommandActionManager.buildCommandInspectDefinition(), - builtinCommandActionManager.buildCommandReadDefinition(), - builtinCommandActionManager.buildCommandCancelDefinition(), - builtinCommandActionManager.buildCommandOverviewDefinition() - ); + List builtinActionDefinitions = new ArrayList<>(); + BuiltinActionProvider commandActionProvider = new BuiltinCommandActionProvider(); + builtinActionDefinitions.addAll(commandActionProvider.provideBuiltinActions()); + return builtinActionDefinitions; } public void defineBuiltinAction(String name, MetaActionInfo metaActionInfo, Function, String> invoker) { @@ -109,4 +104,4 @@ public class BuiltinActionRegistry extends AbstractAgentModule.Standalone { } } -} \ No newline at end of file +} diff --git a/Partner-Core/src/main/java/work/slhaf/partner/module/modules/action/builtin/BuiltinCommandActionManager.java b/Partner-Core/src/main/java/work/slhaf/partner/module/modules/action/builtin/BuiltinCommandActionProvider.java similarity index 94% rename from Partner-Core/src/main/java/work/slhaf/partner/module/modules/action/builtin/BuiltinCommandActionManager.java rename to Partner-Core/src/main/java/work/slhaf/partner/module/modules/action/builtin/BuiltinCommandActionProvider.java index cf94f784..376132a1 100644 --- a/Partner-Core/src/main/java/work/slhaf/partner/module/modules/action/builtin/BuiltinCommandActionManager.java +++ b/Partner-Core/src/main/java/work/slhaf/partner/module/modules/action/builtin/BuiltinCommandActionProvider.java @@ -12,7 +12,7 @@ import java.util.function.Function; import static work.slhaf.partner.core.action.ActionCore.BUILTIN_LOCATION; -class BuiltinCommandActionManager { +class BuiltinCommandActionProvider implements BuiltinActionProvider { private static final String COMMAND_LOCATION = BUILTIN_LOCATION + "::" + "command"; private static final String COMMAND_ARG_PREFIX = "arg"; @@ -25,12 +25,24 @@ class BuiltinCommandActionManager { private final ConcurrentHashMap commandHandles = new ConcurrentHashMap<>(); private final CommandExecutionService commandExecutionService = CommandExecutionService.INSTANCE; + @Override + public List provideBuiltinActions() { + return List.of( + buildCommandExecuteDefinition(), + buildCommandStartDefinition(), + buildCommandInspectDefinition(), + buildCommandReadDefinition(), + buildCommandCancelDefinition(), + buildCommandOverviewDefinition() + ); + } + /** * 用于直接执行的 Builtin MetaAction * * @return 内建 MetaAction 定义数据,参数为常规命令列表,返回值为该命令的响应内容 */ - BuiltinActionRegistry.BuiltinActionDefinition buildCommandExecuteDefinition() { + private BuiltinActionRegistry.BuiltinActionDefinition buildCommandExecuteDefinition() { Set tags = new HashSet<>(basicTags); tags.add("Command Execution"); MetaActionInfo info = new MetaActionInfo( @@ -61,7 +73,7 @@ class BuiltinCommandActionManager { * * @return 内建 MetaAction 定义数据,参数为命令列表及进程描述,返回值为进程句柄 id */ - BuiltinActionRegistry.BuiltinActionDefinition buildCommandStartDefinition() { + private BuiltinActionRegistry.BuiltinActionDefinition buildCommandStartDefinition() { Set tags = new HashSet<>(basicTags); tags.add("Command Session"); MetaActionInfo info = new MetaActionInfo( @@ -106,7 +118,7 @@ class BuiltinCommandActionManager { * * @return 内建 MetaAction 定义数据,参数为进程 id,返回值为摘要内容(CommandInspectData) */ - BuiltinActionRegistry.BuiltinActionDefinition buildCommandInspectDefinition() { + private BuiltinActionRegistry.BuiltinActionDefinition buildCommandInspectDefinition() { Set tags = new HashSet<>(basicTags); tags.add("Command Session"); MetaActionInfo info = new MetaActionInfo( @@ -143,7 +155,7 @@ class BuiltinCommandActionManager { * * @return 内建 MetaAction 定义数据,参数为进程 id 与读取流(stdout/stderr),返回值为读取内容(CommandReadData) */ - BuiltinActionRegistry.BuiltinActionDefinition buildCommandReadDefinition() { + private BuiltinActionRegistry.BuiltinActionDefinition buildCommandReadDefinition() { Set tags = new HashSet<>(basicTags); tags.add("Command Session"); tags.add("Command Read"); @@ -206,7 +218,7 @@ class BuiltinCommandActionManager { * * @return 内建 MetaAction 定义数据,参数为进程 id,返回值为是否成功取消 */ - BuiltinActionRegistry.BuiltinActionDefinition buildCommandCancelDefinition() { + private BuiltinActionRegistry.BuiltinActionDefinition buildCommandCancelDefinition() { Set tags = new HashSet<>(basicTags); tags.add("Command Session"); tags.add("Command Cancel"); @@ -253,7 +265,7 @@ class BuiltinCommandActionManager { * * @return 内建 MetaAction 定义数据,无参数,返回值为后台进程集合(CommandOverviewItem) */ - BuiltinActionRegistry.BuiltinActionDefinition buildCommandOverviewDefinition() { + private BuiltinActionRegistry.BuiltinActionDefinition buildCommandOverviewDefinition() { Set tags = new HashSet<>(basicTags); tags.add("Command Session"); tags.add("Command Overview"); @@ -496,4 +508,4 @@ class BuiltinCommandActionManager { private String desc; private Integer exitCode; } -} \ No newline at end of file +} diff --git a/Partner-Core/src/test/java/work/slhaf/partner/module/modules/action/builtin/BuiltinCommandActionManagerTest.java b/Partner-Core/src/test/java/work/slhaf/partner/module/modules/action/builtin/BuiltinCommandActionProviderTest.java similarity index 50% rename from Partner-Core/src/test/java/work/slhaf/partner/module/modules/action/builtin/BuiltinCommandActionManagerTest.java rename to Partner-Core/src/test/java/work/slhaf/partner/module/modules/action/builtin/BuiltinCommandActionProviderTest.java index d2a40f10..47b345b1 100644 --- a/Partner-Core/src/test/java/work/slhaf/partner/module/modules/action/builtin/BuiltinCommandActionManagerTest.java +++ b/Partner-Core/src/test/java/work/slhaf/partner/module/modules/action/builtin/BuiltinCommandActionProviderTest.java @@ -5,15 +5,21 @@ import com.alibaba.fastjson2.JSONObject; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import java.util.List; import java.util.Map; -class BuiltinCommandActionManagerTest { +class BuiltinCommandActionProviderTest { @Test void testStartInspectReadAndOverview() throws Exception { - BuiltinCommandActionManager manager = new BuiltinCommandActionManager(); + BuiltinCommandActionProvider provider = new BuiltinCommandActionProvider(); + List definitions = provider.provideBuiltinActions(); + BuiltinActionRegistry.BuiltinActionDefinition start = requireDefinition(definitions, "builtin::command::start"); + BuiltinActionRegistry.BuiltinActionDefinition inspectDefinition = requireDefinition(definitions, "builtin::command::inspect"); + BuiltinActionRegistry.BuiltinActionDefinition readDefinition = requireDefinition(definitions, "builtin::command::read"); + BuiltinActionRegistry.BuiltinActionDefinition overviewDefinition = requireDefinition(definitions, "builtin::command::overview"); - String startResult = manager.buildCommandStartDefinition().invoker().apply(Map.of( + String startResult = start.invoker().apply(Map.of( "desc", "demo-session", "arg", "sh", "arg1", "-lc", @@ -22,7 +28,7 @@ class BuiltinCommandActionManagerTest { String executionId = JSONObject.parseObject(startResult).getString("executionId"); Assertions.assertNotNull(executionId); - JSONObject inspect = waitForInspectExit(manager, executionId); + JSONObject inspect = waitForInspectExit(inspectDefinition, executionId); Assertions.assertEquals("demo-session", inspect.getString("desc")); Assertions.assertEquals(0, inspect.getInteger("exitCode")); Assertions.assertTrue(inspect.getInteger("stdoutSize") > 0); @@ -30,7 +36,7 @@ class BuiltinCommandActionManagerTest { Assertions.assertTrue(inspect.getString("stdoutSummary").contains("hello")); Assertions.assertTrue(inspect.getString("stderrSummary").contains("oops")); - JSONObject read = JSONObject.parseObject(manager.buildCommandReadDefinition().invoker().apply(Map.of( + JSONObject read = JSONObject.parseObject(readDefinition.invoker().apply(Map.of( "id", executionId, "limit", 5 ))); @@ -40,7 +46,7 @@ class BuiltinCommandActionManagerTest { Assertions.assertTrue(read.getBooleanValue("contentTruncated")); Assertions.assertEquals("hello", read.getString("content")); - JSONObject overview = JSONObject.parseObject(manager.buildCommandOverviewDefinition().invoker().apply(Map.of())); + JSONObject overview = JSONObject.parseObject(overviewDefinition.invoker().apply(Map.of())); JSONArray result = overview.getJSONArray("result"); Assertions.assertTrue(result.stream().map(item -> (JSONObject) item) .anyMatch(item -> executionId.equals(item.getString("executionId")))); @@ -48,9 +54,13 @@ class BuiltinCommandActionManagerTest { @Test void testCancelStopsBackgroundCommand() throws Exception { - BuiltinCommandActionManager manager = new BuiltinCommandActionManager(); + BuiltinCommandActionProvider provider = new BuiltinCommandActionProvider(); + List definitions = provider.provideBuiltinActions(); + BuiltinActionRegistry.BuiltinActionDefinition start = requireDefinition(definitions, "builtin::command::start"); + BuiltinActionRegistry.BuiltinActionDefinition cancelDefinition = requireDefinition(definitions, "builtin::command::cancel"); + BuiltinActionRegistry.BuiltinActionDefinition inspectDefinition = requireDefinition(definitions, "builtin::command::inspect"); - String startResult = manager.buildCommandStartDefinition().invoker().apply(Map.of( + String startResult = start.invoker().apply(Map.of( "desc", "sleep-session", "arg", "sh", "arg1", "-lc", @@ -58,20 +68,30 @@ class BuiltinCommandActionManagerTest { )); String executionId = JSONObject.parseObject(startResult).getString("executionId"); - JSONObject cancel = JSONObject.parseObject(manager.buildCommandCancelDefinition().invoker().apply(Map.of( + JSONObject cancel = JSONObject.parseObject(cancelDefinition.invoker().apply(Map.of( "id", executionId ))); Assertions.assertEquals(executionId, cancel.getString("executionId")); Assertions.assertTrue(cancel.getBooleanValue("ok")); - JSONObject inspect = waitForInspectExit(manager, executionId); + JSONObject inspect = waitForInspectExit(inspectDefinition, executionId); Assertions.assertNotNull(inspect.get("endAt")); } - private JSONObject waitForInspectExit(BuiltinCommandActionManager manager, String executionId) throws Exception { + private BuiltinActionRegistry.BuiltinActionDefinition requireDefinition( + List definitions, + String actionKey + ) { + return definitions.stream() + .filter(definition -> actionKey.equals(definition.actionKey())) + .findFirst() + .orElseThrow(() -> new AssertionError("definition not found: " + actionKey)); + } + + private JSONObject waitForInspectExit(BuiltinActionRegistry.BuiltinActionDefinition inspectDefinition, String executionId) throws Exception { long deadline = System.currentTimeMillis() + 3000; while (System.currentTimeMillis() < deadline) { - JSONObject inspect = JSONObject.parseObject(manager.buildCommandInspectDefinition().invoker().apply(Map.of( + JSONObject inspect = JSONObject.parseObject(inspectDefinition.invoker().apply(Map.of( "id", executionId ))); if (inspect.get("exitCode") != null) {