feat(action): support continuing executable actions after state restored

This commit is contained in:
2026-04-07 23:16:12 +08:00
parent a114044c23
commit 3640cc2108
5 changed files with 245 additions and 18 deletions

View File

@@ -3,7 +3,6 @@ package work.slhaf.partner.core.action;
import com.alibaba.fastjson2.JSONObject;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import work.slhaf.partner.core.action.entity.ExecutableAction;
@@ -57,16 +56,6 @@ public class ActionCore implements StateSerializable {
// TODO 通过 Config 指定采用何种 runnerClient当前只提供 LocalRunnerClient
runnerClient = new LocalRunnerClient(existedMetaActions, virtualExecutor, baseActionPath);
register();
setupShutdownHook();
}
private void setupShutdownHook() {
// 将执行中的行动状态置为失败
val executingActionSet = listActions(ExecutableAction.Status.EXECUTING, null);
for (ExecutableAction executableAction : executingActionSet) {
executableAction.setStatus(ExecutableAction.Status.FAILED);
executableAction.setResult("由于系统中断而失败");
}
}
@CapabilityMethod

View File

@@ -48,6 +48,9 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
platformExecutor = actionCapability.getExecutor(ActionCore.ExecutorType.PLATFORM);
runnerClient = actionCapability.runnerClient();
blockManager = new ExecutingActionBlockManager(cognitionCapability.contextWorkspace());
actionCapability.listActions(Action.Status.EXECUTING, null)
.forEach(this::execute);
}
public void execute(Action action) {
@@ -115,7 +118,8 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
private void handleExecutableAction(ExecutableAction executableAction) {
val source = executableAction.getSource();
if (executableAction.getStatus() != Action.Status.PREPARE) {
val status = executableAction.getStatus();
if (status != Action.Status.PREPARE && status != Action.Status.EXECUTING) {
return;
}
val actionChain = executableAction.getActionChain();
@@ -124,6 +128,7 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
executableAction.setResult("行动链为空");
return;
}
normalizeExecutingStage(executableAction, actionChain);
// 注册执行中行动
val phaser = new Phaser();
executableAction.setStatus(Action.Status.EXECUTING);
@@ -133,13 +138,13 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
// 开始执行
val stageCursor = new Object() {
int stageCount;
boolean executingStageUpdated;
boolean stageCountUpdated;
boolean executingStageUpdated = false;
boolean stageCountUpdated = false;
void init() {
stageCount = 0;
executingStageUpdated = false;
stageCountUpdated = false;
val orderList = new ArrayList<>(actionChain.keySet());
orderList.sort(Integer::compareTo);
stageCount = orderList.indexOf(executableAction.getExecutingStage());
update();
}
@@ -376,6 +381,33 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
return stageIndex >= 2 && (stageIndex - 2) % 2 == 0;
}
private void normalizeExecutingStage(ExecutableAction executableAction, Map<Integer, List<MetaAction>> actionChain) {
Integer firstStage = actionChain.keySet().stream()
.min(Integer::compareTo)
.orElse(null);
if (firstStage == null) {
return;
}
if (actionChain.containsKey(executableAction.getExecutingStage())) {
return;
}
if (executableAction.getStatus() == Action.Status.EXECUTING) {
resetExecutableActionForReplay(executableAction);
}
executableAction.setExecutingStage(firstStage);
}
private void resetExecutableActionForReplay(ExecutableAction executableAction) {
executableAction.getHistory().clear();
executableAction.getActionChain().values().forEach(metaActions -> metaActions.forEach(metaAction -> {
metaAction.getParams().clear();
metaAction.getResult().reset();
}));
if (hasExecutableResult(executableAction)) {
executableAction.setResult("");
}
}
private void ensureExecutableResult(ExecutableAction executableAction, boolean failed, String failureReason) {
if (hasExecutableResult(executableAction)) {
return;

View File

@@ -55,7 +55,7 @@ class ActionScheduler : AbstractAgentModule.Standalone() {
.stream()
.filter { it is SchedulableExecutableAction }
.map { it as SchedulableExecutableAction }
.collect(Collectors.toSet<SchedulableExecutableAction>())
.collect(Collectors.toSet())
val persisted: MutableSet<Schedulable> = mutableSetOf()
persisted.addAll(persistedExecutable)
synchronized(runtimeSchedulables) {