mirror of
https://github.com/slhaf/Partner.git
synced 2026-05-12 08:43:02 +08:00
refactor(action): switch builtin actions to provider-driven self-registration
This commit is contained in:
@@ -2,7 +2,7 @@ package work.slhaf.partner.module.action.builtin;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
interface BuiltinActionProvider {
|
public interface BuiltinActionProvider {
|
||||||
List<BuiltinActionRegistry.BuiltinActionDefinition> provideBuiltinActions();
|
List<BuiltinActionRegistry.BuiltinActionDefinition> provideBuiltinActions();
|
||||||
|
|
||||||
String createActionKey(String actionName);
|
String createActionKey(String actionName);
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import work.slhaf.partner.framework.agent.factory.capability.annotation.InjectCa
|
|||||||
import work.slhaf.partner.framework.agent.factory.component.abstracts.AbstractAgentModule;
|
import work.slhaf.partner.framework.agent.factory.component.abstracts.AbstractAgentModule;
|
||||||
import work.slhaf.partner.framework.agent.factory.component.annotation.Init;
|
import work.slhaf.partner.framework.agent.factory.component.annotation.Init;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -26,32 +25,26 @@ public class BuiltinActionRegistry extends AbstractAgentModule.Standalone {
|
|||||||
|
|
||||||
@Init
|
@Init
|
||||||
public void init() {
|
public void init() {
|
||||||
definitions.clear();
|
|
||||||
for (BuiltinActionDefinition definition : buildDefaultActionDefinitions()) {
|
|
||||||
definitions.put(definition.actionKey(), definition);
|
|
||||||
}
|
|
||||||
actionCapability.registerMetaActions(exportMetaActionInfos());
|
|
||||||
actionCapability.runnerClient().setBuiltinActionRegistry(this);
|
actionCapability.runnerClient().setBuiltinActionRegistry(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<BuiltinActionDefinition> buildDefaultActionDefinitions() {
|
public void register(BuiltinActionProvider provider) {
|
||||||
List<BuiltinActionDefinition> builtinActionDefinitions = new ArrayList<>();
|
List<BuiltinActionDefinition> builtinActionDefinitions = provider.provideBuiltinActions();
|
||||||
BuiltinActionProvider commandActionProvider = new BuiltinCommandActionProvider();
|
if (builtinActionDefinitions == null || builtinActionDefinitions.isEmpty()) {
|
||||||
BuiltinActionProvider capabilityActionProvider = new BuiltinCapabilityActionProvider();
|
return;
|
||||||
BuiltinActionProvider interventionActionProvider = new BuiltinInterventionActionProvider();
|
}
|
||||||
BuiltinActionProvider dynamicActionProvider = new BuiltinDynamicActionProvider();
|
Map<String, MetaActionInfo> metaActionInfos = new LinkedHashMap<>();
|
||||||
|
for (BuiltinActionDefinition definition : builtinActionDefinitions) {
|
||||||
builtinActionDefinitions.addAll(commandActionProvider.provideBuiltinActions());
|
definitions.put(definition.actionKey(), definition);
|
||||||
builtinActionDefinitions.addAll(capabilityActionProvider.provideBuiltinActions());
|
metaActionInfos.put(definition.actionKey(), definition.metaActionInfo());
|
||||||
builtinActionDefinitions.addAll(interventionActionProvider.provideBuiltinActions());
|
}
|
||||||
builtinActionDefinitions.addAll(dynamicActionProvider.provideBuiltinActions());
|
actionCapability.registerMetaActions(metaActionInfos);
|
||||||
|
|
||||||
return builtinActionDefinitions;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void defineBuiltinAction(String name, MetaActionInfo metaActionInfo, Function<Map<String, Object>, String> invoker) {
|
public void defineBuiltinAction(String name, MetaActionInfo metaActionInfo, Function<Map<String, Object>, String> invoker) {
|
||||||
BuiltinActionDefinition definition = new BuiltinActionDefinition(BUILTIN_LOCATION + "::" + name, metaActionInfo, invoker);
|
BuiltinActionDefinition definition = new BuiltinActionDefinition(BUILTIN_LOCATION + "::" + name, metaActionInfo, invoker);
|
||||||
definitions.put(definition.actionKey(), definition);
|
definitions.put(definition.actionKey(), definition);
|
||||||
|
actionCapability.registerMetaActions(Map.of(definition.actionKey(), definition.metaActionInfo()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public String call(@NonNull String actionKey, @NonNull Map<String, Object> params) {
|
public String call(@NonNull String actionKey, @NonNull Map<String, Object> params) {
|
||||||
@@ -70,11 +63,6 @@ public class BuiltinActionRegistry extends AbstractAgentModule.Standalone {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, MetaActionInfo> exportMetaActionInfos() {
|
|
||||||
Map<String, MetaActionInfo> metaActions = new LinkedHashMap<>();
|
|
||||||
definitions.forEach((key, value) -> metaActions.put(key, value.metaActionInfo()));
|
|
||||||
return metaActions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public record BuiltinActionDefinition(
|
public record BuiltinActionDefinition(
|
||||||
String actionKey,
|
String actionKey,
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ import work.slhaf.partner.core.memory.pojo.MemorySlice;
|
|||||||
import work.slhaf.partner.core.memory.pojo.MemoryUnit;
|
import work.slhaf.partner.core.memory.pojo.MemoryUnit;
|
||||||
import work.slhaf.partner.framework.agent.factory.capability.annotation.InjectCapability;
|
import work.slhaf.partner.framework.agent.factory.capability.annotation.InjectCapability;
|
||||||
import work.slhaf.partner.framework.agent.factory.component.annotation.AgentComponent;
|
import work.slhaf.partner.framework.agent.factory.component.annotation.AgentComponent;
|
||||||
|
import work.slhaf.partner.framework.agent.factory.component.annotation.Init;
|
||||||
|
import work.slhaf.partner.framework.agent.factory.component.annotation.InjectModule;
|
||||||
import work.slhaf.partner.framework.agent.support.Result;
|
import work.slhaf.partner.framework.agent.support.Result;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -32,6 +34,13 @@ class BuiltinCapabilityActionProvider implements BuiltinActionProvider {
|
|||||||
private CognitionCapability cognitionCapability;
|
private CognitionCapability cognitionCapability;
|
||||||
@InjectCapability
|
@InjectCapability
|
||||||
private MemoryCapability memoryCapability;
|
private MemoryCapability memoryCapability;
|
||||||
|
@InjectModule
|
||||||
|
private BuiltinActionRegistry builtinActionRegistry;
|
||||||
|
|
||||||
|
@Init
|
||||||
|
public void init() {
|
||||||
|
builtinActionRegistry.register(this);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<BuiltinActionRegistry.BuiltinActionDefinition> provideBuiltinActions() {
|
public List<BuiltinActionRegistry.BuiltinActionDefinition> provideBuiltinActions() {
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ import work.slhaf.partner.core.action.entity.MetaActionInfo;
|
|||||||
import work.slhaf.partner.core.action.runner.execution.CommandExecutionService;
|
import work.slhaf.partner.core.action.runner.execution.CommandExecutionService;
|
||||||
import work.slhaf.partner.core.action.runner.policy.ExecutionPolicyRegistry;
|
import work.slhaf.partner.core.action.runner.policy.ExecutionPolicyRegistry;
|
||||||
import work.slhaf.partner.core.action.runner.policy.WrappedLaunchSpec;
|
import work.slhaf.partner.core.action.runner.policy.WrappedLaunchSpec;
|
||||||
|
import work.slhaf.partner.framework.agent.factory.component.annotation.AgentComponent;
|
||||||
|
import work.slhaf.partner.framework.agent.factory.component.annotation.Init;
|
||||||
|
import work.slhaf.partner.framework.agent.factory.component.annotation.InjectModule;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.RandomAccessFile;
|
import java.io.RandomAccessFile;
|
||||||
@@ -21,6 +24,7 @@ import java.util.function.Function;
|
|||||||
|
|
||||||
import static work.slhaf.partner.core.action.ActionCore.BUILTIN_LOCATION;
|
import static work.slhaf.partner.core.action.ActionCore.BUILTIN_LOCATION;
|
||||||
|
|
||||||
|
@AgentComponent
|
||||||
class BuiltinCommandActionProvider implements BuiltinActionProvider {
|
class BuiltinCommandActionProvider implements BuiltinActionProvider {
|
||||||
|
|
||||||
private static final String COMMAND_LOCATION = BUILTIN_LOCATION + "::" + "command";
|
private static final String COMMAND_LOCATION = BUILTIN_LOCATION + "::" + "command";
|
||||||
@@ -38,6 +42,14 @@ class BuiltinCommandActionProvider implements BuiltinActionProvider {
|
|||||||
private final ConcurrentHashMap<String, CommandHandle> commandHandles = new ConcurrentHashMap<>();
|
private final ConcurrentHashMap<String, CommandHandle> commandHandles = new ConcurrentHashMap<>();
|
||||||
private final CommandExecutionService commandExecutionService = CommandExecutionService.INSTANCE;
|
private final CommandExecutionService commandExecutionService = CommandExecutionService.INSTANCE;
|
||||||
|
|
||||||
|
@InjectModule
|
||||||
|
private BuiltinActionRegistry builtinActionRegistry;
|
||||||
|
|
||||||
|
@Init
|
||||||
|
public void init() {
|
||||||
|
builtinActionRegistry.register(this);
|
||||||
|
}
|
||||||
|
|
||||||
private Map<String, String> commandParams() {
|
private Map<String, String> commandParams() {
|
||||||
Map<String, String> params = new LinkedHashMap<>();
|
Map<String, String> params = new LinkedHashMap<>();
|
||||||
params.put("arg", param("required", "string", "Command executable name or path."));
|
params.put("arg", param("required", "string", "Command executable name or path."));
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import work.slhaf.partner.core.action.ActionCapability;
|
|||||||
import work.slhaf.partner.core.action.entity.*;
|
import work.slhaf.partner.core.action.entity.*;
|
||||||
import work.slhaf.partner.framework.agent.factory.capability.annotation.InjectCapability;
|
import work.slhaf.partner.framework.agent.factory.capability.annotation.InjectCapability;
|
||||||
import work.slhaf.partner.framework.agent.factory.component.annotation.AgentComponent;
|
import work.slhaf.partner.framework.agent.factory.component.annotation.AgentComponent;
|
||||||
|
import work.slhaf.partner.framework.agent.factory.component.annotation.Init;
|
||||||
import work.slhaf.partner.framework.agent.factory.component.annotation.InjectModule;
|
import work.slhaf.partner.framework.agent.factory.component.annotation.InjectModule;
|
||||||
import work.slhaf.partner.module.action.scheduler.ActionScheduler;
|
import work.slhaf.partner.module.action.scheduler.ActionScheduler;
|
||||||
|
|
||||||
@@ -29,6 +30,13 @@ class BuiltinDynamicActionProvider implements BuiltinActionProvider {
|
|||||||
private ActionCapability actionCapability;
|
private ActionCapability actionCapability;
|
||||||
@InjectModule
|
@InjectModule
|
||||||
private ActionScheduler actionScheduler;
|
private ActionScheduler actionScheduler;
|
||||||
|
@InjectModule
|
||||||
|
private BuiltinActionRegistry builtinActionRegistry;
|
||||||
|
|
||||||
|
@Init
|
||||||
|
public void init() {
|
||||||
|
builtinActionRegistry.register(this);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<BuiltinActionRegistry.BuiltinActionDefinition> provideBuiltinActions() {
|
public List<BuiltinActionRegistry.BuiltinActionDefinition> provideBuiltinActions() {
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ import work.slhaf.partner.framework.agent.exception.AgentRuntimeException;
|
|||||||
import work.slhaf.partner.framework.agent.exception.ExceptionReporterHandler;
|
import work.slhaf.partner.framework.agent.exception.ExceptionReporterHandler;
|
||||||
import work.slhaf.partner.framework.agent.factory.capability.annotation.InjectCapability;
|
import work.slhaf.partner.framework.agent.factory.capability.annotation.InjectCapability;
|
||||||
import work.slhaf.partner.framework.agent.factory.component.annotation.AgentComponent;
|
import work.slhaf.partner.framework.agent.factory.component.annotation.AgentComponent;
|
||||||
|
import work.slhaf.partner.framework.agent.factory.component.annotation.Init;
|
||||||
|
import work.slhaf.partner.framework.agent.factory.component.annotation.InjectModule;
|
||||||
import work.slhaf.partner.framework.agent.support.Result;
|
import work.slhaf.partner.framework.agent.support.Result;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -35,6 +37,13 @@ class BuiltinInterventionActionProvider implements BuiltinActionProvider {
|
|||||||
private ActionCapability actionCapability;
|
private ActionCapability actionCapability;
|
||||||
@InjectCapability
|
@InjectCapability
|
||||||
private CognitionCapability cognitionCapability;
|
private CognitionCapability cognitionCapability;
|
||||||
|
@InjectModule
|
||||||
|
private BuiltinActionRegistry builtinActionRegistry;
|
||||||
|
|
||||||
|
@Init
|
||||||
|
public void init() {
|
||||||
|
builtinActionRegistry.register(this);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<BuiltinActionRegistry.BuiltinActionDefinition> provideBuiltinActions() {
|
public List<BuiltinActionRegistry.BuiltinActionDefinition> provideBuiltinActions() {
|
||||||
|
|||||||
@@ -52,29 +52,51 @@ class BuiltinActionRegistryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testInitRegistersMetaActionsAndMountsRunner() throws Exception {
|
void testInitMountsRunner() throws Exception {
|
||||||
ActionCapability actionCapability = mock(ActionCapability.class);
|
ActionCapability actionCapability = mock(ActionCapability.class);
|
||||||
RunnerClient runnerClient = mock(RunnerClient.class);
|
RunnerClient runnerClient = mock(RunnerClient.class);
|
||||||
when(actionCapability.runnerClient()).thenReturn(runnerClient);
|
when(actionCapability.runnerClient()).thenReturn(runnerClient);
|
||||||
|
|
||||||
BuiltinActionRegistry registry = spy(new BuiltinActionRegistry());
|
BuiltinActionRegistry registry = new BuiltinActionRegistry();
|
||||||
doReturn(List.of(
|
|
||||||
buildDefinition("echo", buildMetaActionInfo("echo"), params -> params.get("value").toString())
|
|
||||||
)).when(registry).buildDefaultActionDefinitions();
|
|
||||||
injectActionCapability(registry, actionCapability);
|
injectActionCapability(registry, actionCapability);
|
||||||
|
|
||||||
registry.init();
|
registry.init();
|
||||||
|
|
||||||
|
verify(runnerClient).setBuiltinActionRegistry(registry);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testRegisterProviderRegistersDefinitionsAndMetaActions() throws Exception {
|
||||||
|
ActionCapability actionCapability = mock(ActionCapability.class);
|
||||||
|
BuiltinActionRegistry registry = new BuiltinActionRegistry();
|
||||||
|
injectActionCapability(registry, actionCapability);
|
||||||
|
|
||||||
|
BuiltinActionProvider provider = new BuiltinActionProvider() {
|
||||||
|
@Override
|
||||||
|
public List<BuiltinActionRegistry.BuiltinActionDefinition> provideBuiltinActions() {
|
||||||
|
return List.of(buildDefinition("echo", buildMetaActionInfo("echo"), params -> params.get("value").toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String createActionKey(String actionName) {
|
||||||
|
return BUILTIN_LOCATION + "::" + actionName;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
registry.register(provider);
|
||||||
|
|
||||||
verify(actionCapability).registerMetaActions(argThat(metaActions ->
|
verify(actionCapability).registerMetaActions(argThat(metaActions ->
|
||||||
metaActions.containsKey("builtin::echo")
|
metaActions.containsKey("builtin::echo")
|
||||||
&& "echo".equals(metaActions.get("builtin::echo").getDescription())
|
&& "echo".equals(metaActions.get("builtin::echo").getDescription())
|
||||||
));
|
));
|
||||||
verify(runnerClient).setBuiltinActionRegistry(registry);
|
Assertions.assertEquals("hello", registry.call("builtin::echo", Map.of("value", "hello")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testCallReturnsStringifiedResults() {
|
void testCallReturnsStringifiedResults() throws Exception {
|
||||||
|
ActionCapability actionCapability = mock(ActionCapability.class);
|
||||||
BuiltinActionRegistry registry = new BuiltinActionRegistry();
|
BuiltinActionRegistry registry = new BuiltinActionRegistry();
|
||||||
|
injectActionCapability(registry, actionCapability);
|
||||||
registry.defineBuiltinAction("echo", buildMetaActionInfo("echo"), params -> params.get("value").toString());
|
registry.defineBuiltinAction("echo", buildMetaActionInfo("echo"), params -> params.get("value").toString());
|
||||||
registry.defineBuiltinAction("json", buildMetaActionInfo("json"), params -> Map.of("ok", true).toString());
|
registry.defineBuiltinAction("json", buildMetaActionInfo("json"), params -> Map.of("ok", true).toString());
|
||||||
registry.defineBuiltinAction("nil", buildMetaActionInfo("nil"), params -> null);
|
registry.defineBuiltinAction("nil", buildMetaActionInfo("nil"), params -> null);
|
||||||
@@ -91,8 +113,10 @@ class BuiltinActionRegistryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testCallPropagatesInvokerFailure() {
|
void testCallPropagatesInvokerFailure() throws Exception {
|
||||||
|
ActionCapability actionCapability = mock(ActionCapability.class);
|
||||||
BuiltinActionRegistry registry = new BuiltinActionRegistry();
|
BuiltinActionRegistry registry = new BuiltinActionRegistry();
|
||||||
|
injectActionCapability(registry, actionCapability);
|
||||||
registry.defineBuiltinAction("boom", buildMetaActionInfo("boom"), params -> {
|
registry.defineBuiltinAction("boom", buildMetaActionInfo("boom"), params -> {
|
||||||
throw new IllegalStateException("boom");
|
throw new IllegalStateException("boom");
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user