refactor(action): support built-in actions

This commit is contained in:
2026-03-12 10:41:17 +08:00
parent 3c550af33d
commit 6c8a1b2636
10 changed files with 310 additions and 19 deletions

View File

@@ -53,6 +53,8 @@ public interface ActionCapability {
MetaActionInfo loadMetaActionInfo(@NonNull String actionKey);
void registerMetaActions(@NonNull Map<String, MetaActionInfo> metaActions);
Map<String, MetaActionInfo> listAvailableMetaActions();
boolean checkExists(String... actionKeys);

View File

@@ -30,6 +30,7 @@ import java.util.stream.Collectors;
@CapabilityCore(value = "action")
@Slf4j
public class ActionCore extends PartnerCore<ActionCore> {
public static final String BUILTIN_LOCATION = "builtin";
private final Lock cacheLock = new ReentrantLock();
// 由于当前的执行器逻辑实现,平台线程池大小不得小于 2这里规定为最小为 4
@@ -273,7 +274,12 @@ public class ActionCore extends PartnerCore<ActionCore> {
}
@CapabilityMethod
public Map<String, MetaActionInfo> listAvailableActions() {
public void registerMetaActions(@NonNull Map<String, MetaActionInfo> metaActions) {
existedMetaActions.putAll(metaActions);
}
@CapabilityMethod
public Map<String, MetaActionInfo> listAvailableMetaActions() {
return existedMetaActions;
}
@@ -320,10 +326,11 @@ public class ActionCore extends PartnerCore<ActionCore> {
if (split.length < 2) {
throw new MetaActionNotFoundException("未找到对应的行动程序,原因: 传入的 actionKey(" + actionKey + ") 存在异常");
}
MetaAction.Type type = BUILTIN_LOCATION.equals(split[0]) ? MetaAction.Type.BUILTIN : MetaAction.Type.MCP;
return new MetaAction(
split[1],
metaActionInfo.isIo(),
MetaAction.Type.MCP,
type,
split[0]
);
}

View File

@@ -14,12 +14,14 @@ data class MetaAction(
*/
val io: Boolean = false,
/**
* 行动程序类型,可分为 MCP、ORIGIN 两种,前者对应读取到的 MCP Tool、后者对应生成的临时行动程序
* 行动程序类型,可分为 MCP、ORIGIN、BUILTIN 三种,
* 分别对应读取到的 MCP Tool、生成的临时行动程序、本地内置行动
*/
val type: Type,
/**
* 当类型为 MCP 时,该字段对应相应 MCP Client 注册时生成的 id;
* 当类型为 ORIGIN 时,该字段对应相应的磁盘路径字符串
* 当类型为 ORIGIN 时,该字段对应相应的磁盘路径字符串;
* 当类型为 BUILTIN 时,该字段固定为 builtin
*/
val location: String,
) {
@@ -67,7 +69,12 @@ data class MetaAction(
/**
* 适用于‘临时生成’的行动程序,在生成后根据序列化选项及执行情况,进行持久化
*/
ORIGIN
ORIGIN,
/**
* 由本地内置注册表直接执行的行动
*/
BUILTIN
}
}

View File

@@ -224,6 +224,7 @@ public class LocalRunnerClient extends RunnerClient {
response = switch (metaAction.getType()) {
case MetaAction.Type.MCP -> doRunWithMcp(metaAction);
case MetaAction.Type.ORIGIN -> doRunWithOrigin(metaAction);
case MetaAction.Type.BUILTIN -> doRunWithBuiltin(metaAction);
};
} catch (Exception e) {
response = new RunnerResponse();

View File

@@ -1,8 +1,8 @@
package work.slhaf.partner.core.action.runner;
import com.alibaba.fastjson2.JSONObject;
import io.modelcontextprotocol.server.McpStatelessAsyncServer;
import lombok.Data;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.jetbrains.annotations.Nullable;
@@ -11,6 +11,7 @@ import work.slhaf.partner.core.action.entity.MetaAction;
import work.slhaf.partner.core.action.entity.MetaAction.Result;
import work.slhaf.partner.core.action.entity.MetaActionInfo;
import work.slhaf.partner.core.action.exception.ActionInitFailedException;
import work.slhaf.partner.module.modules.action.builtin.BuiltinActionRegistry;
import java.io.IOException;
import java.nio.file.Files;
@@ -45,8 +46,8 @@ public abstract class RunnerClient {
protected final ConcurrentHashMap<String, MetaActionInfo> existedMetaActions;
protected final ExecutorService executor;
//TODO 仍可提供内部 MCP但调用方式需要结合 AgentContext来获取否则生命周期不合
protected McpStatelessAsyncServer innerMcpServer;
@Setter
protected BuiltinActionRegistry builtinActionRegistry;
/**
* ActionCore 将注入虚拟线程池
@@ -82,6 +83,23 @@ public abstract class RunnerClient {
public abstract void persistSerialize(MetaActionInfo metaActionInfo, ActionFileMetaData fileMetaData);
protected RunnerResponse doRunWithBuiltin(MetaAction metaAction) {
RunnerResponse response = new RunnerResponse();
if (builtinActionRegistry == null) {
response.setOk(false);
response.setData("BuiltinActionRegistry 未初始化");
return response;
}
try {
response.setData(builtinActionRegistry.call(metaAction.getKey(), metaAction.getParams()));
response.setOk(true);
} catch (Exception e) {
response.setOk(false);
response.setData(e.getLocalizedMessage());
}
return response;
}
protected void createPath(String pathStr) {
val path = Path.of(pathStr);
try {

View File

@@ -30,8 +30,13 @@ public class SandboxRunnerClient extends RunnerClient {
}
protected RunnerResponse doRun(MetaAction metaAction) {
// 调用沙盒执行器
return null;
return switch (metaAction.getType()) {
case BUILTIN -> doRunWithBuiltin(metaAction);
case MCP, ORIGIN -> {
// 调用沙盒执行器
yield null;
}
};
}
@Override

View File

@@ -0,0 +1,76 @@
package work.slhaf.partner.module.modules.action.builtin;
import com.alibaba.fastjson2.JSONObject;
import lombok.Getter;
import lombok.NonNull;
import work.slhaf.partner.api.agent.factory.capability.annotation.InjectCapability;
import work.slhaf.partner.api.agent.factory.component.abstracts.AbstractAgentModule;
import work.slhaf.partner.api.agent.factory.component.annotation.Init;
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.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import static work.slhaf.partner.core.action.ActionCore.BUILTIN_LOCATION;
public class BuiltinActionRegistry extends AbstractAgentModule.Standalone {
@Getter
private final Map<String, BuiltinActionDefinition> definitions = new LinkedHashMap<>();
@InjectCapability
private ActionCapability actionCapability;
public static BuiltinActionDefinition definition(String name, MetaActionInfo metaActionInfo,
Function<Map<String, Object>, Object> invoker) {
return new BuiltinActionDefinition(BUILTIN_LOCATION + "::" + name, metaActionInfo, invoker);
}
@Init
public void init() {
definitions.clear();
for (BuiltinActionDefinition definition : buildDefinitions()) {
definitions.put(definition.actionKey(), definition);
}
actionCapability.registerMetaActions(exportMetaActionInfos());
actionCapability.runnerClient().setBuiltinActionRegistry(this);
}
protected List<BuiltinActionDefinition> buildDefinitions() {
return List.of();
}
public String call(@NonNull String actionKey, @NonNull Map<String, Object> params) {
BuiltinActionDefinition definition = definitions.get(actionKey);
if (definition == null) {
throw new MetaActionNotFoundException("未找到对应的内置行动程序: " + actionKey);
}
Object result = definition.invoker().apply(params);
if (result == null) {
return "null";
}
if (result instanceof String string) {
return string;
}
if (result instanceof Number || result instanceof Boolean || result instanceof Map || result instanceof Iterable) {
return JSONObject.toJSONString(result);
}
return String.valueOf(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(
String actionKey,
MetaActionInfo metaActionInfo,
Function<Map<String, Object>, Object> invoker
) {
}
}