mirror of
https://github.com/slhaf/Partner.git
synced 2026-05-12 08:43:02 +08:00
refactor(action-core): return Result for meta action lookups and adapt runtime callers
This commit is contained in:
@@ -8,6 +8,7 @@ import work.slhaf.partner.core.action.entity.MetaActionInfo;
|
|||||||
import work.slhaf.partner.core.action.entity.intervention.MetaIntervention;
|
import work.slhaf.partner.core.action.entity.intervention.MetaIntervention;
|
||||||
import work.slhaf.partner.core.action.runner.RunnerClient;
|
import work.slhaf.partner.core.action.runner.RunnerClient;
|
||||||
import work.slhaf.partner.framework.agent.factory.capability.annotation.Capability;
|
import work.slhaf.partner.framework.agent.factory.capability.annotation.Capability;
|
||||||
|
import work.slhaf.partner.framework.agent.support.Result;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -23,9 +24,9 @@ public interface ActionCapability {
|
|||||||
|
|
||||||
ExecutorService getExecutor(ActionCore.ExecutorType type);
|
ExecutorService getExecutor(ActionCore.ExecutorType type);
|
||||||
|
|
||||||
MetaAction loadMetaAction(@NonNull String actionKey);
|
Result<MetaAction> loadMetaAction(@NonNull String actionKey);
|
||||||
|
|
||||||
MetaActionInfo loadMetaActionInfo(@NonNull String actionKey);
|
Result<MetaActionInfo> loadMetaActionInfo(@NonNull String actionKey);
|
||||||
|
|
||||||
void registerMetaActions(@NonNull Map<String, MetaActionInfo> metaActions);
|
void registerMetaActions(@NonNull Map<String, MetaActionInfo> metaActions);
|
||||||
|
|
||||||
|
|||||||
@@ -14,12 +14,14 @@ import work.slhaf.partner.core.action.exception.ActionLookupException;
|
|||||||
import work.slhaf.partner.core.action.runner.LocalRunnerClient;
|
import work.slhaf.partner.core.action.runner.LocalRunnerClient;
|
||||||
import work.slhaf.partner.core.action.runner.RunnerClient;
|
import work.slhaf.partner.core.action.runner.RunnerClient;
|
||||||
import work.slhaf.partner.framework.agent.config.ConfigCenter;
|
import work.slhaf.partner.framework.agent.config.ConfigCenter;
|
||||||
|
import work.slhaf.partner.framework.agent.exception.ExceptionReporterHandler;
|
||||||
import work.slhaf.partner.framework.agent.factory.capability.annotation.CapabilityCore;
|
import work.slhaf.partner.framework.agent.factory.capability.annotation.CapabilityCore;
|
||||||
import work.slhaf.partner.framework.agent.factory.capability.annotation.CapabilityMethod;
|
import work.slhaf.partner.framework.agent.factory.capability.annotation.CapabilityMethod;
|
||||||
import work.slhaf.partner.framework.agent.factory.context.Shutdown;
|
import work.slhaf.partner.framework.agent.factory.context.Shutdown;
|
||||||
import work.slhaf.partner.framework.agent.state.State;
|
import work.slhaf.partner.framework.agent.state.State;
|
||||||
import work.slhaf.partner.framework.agent.state.StateSerializable;
|
import work.slhaf.partner.framework.agent.state.StateSerializable;
|
||||||
import work.slhaf.partner.framework.agent.state.StateValue;
|
import work.slhaf.partner.framework.agent.state.StateValue;
|
||||||
|
import work.slhaf.partner.framework.agent.support.Result;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
@@ -114,49 +116,49 @@ public class ActionCore implements StateSerializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@CapabilityMethod
|
@CapabilityMethod
|
||||||
public MetaAction loadMetaAction(@NonNull String actionKey) {
|
public Result<MetaAction> loadMetaAction(@NonNull String actionKey) {
|
||||||
MetaActionInfo metaActionInfo = existedMetaActions.get(actionKey);
|
MetaActionInfo metaActionInfo = existedMetaActions.get(actionKey);
|
||||||
if (metaActionInfo == null) {
|
if (metaActionInfo == null) {
|
||||||
throw new ActionLookupException(
|
return Result.failure(new ActionLookupException(
|
||||||
"Meta action info not found for action key: " + actionKey,
|
"Meta action info not found for action key: " + actionKey,
|
||||||
actionKey,
|
actionKey,
|
||||||
"META_ACTION"
|
"META_ACTION"
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
String[] split = actionKey.split("::", 2);
|
String[] split = actionKey.split("::", 2);
|
||||||
if (split.length < 2) {
|
if (split.length < 2) {
|
||||||
throw new ActionLookupException(
|
return Result.failure(new ActionLookupException(
|
||||||
"Invalid action key format: " + actionKey,
|
"Invalid action key format: " + actionKey,
|
||||||
actionKey,
|
actionKey,
|
||||||
"META_ACTION"
|
"META_ACTION"
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
MetaAction.Type type = switch (split[0]) {
|
MetaAction.Type type = switch (split[0]) {
|
||||||
case BUILTIN_LOCATION -> MetaAction.Type.BUILTIN;
|
case BUILTIN_LOCATION -> MetaAction.Type.BUILTIN;
|
||||||
case ORIGIN_LOCATION -> MetaAction.Type.ORIGIN;
|
case ORIGIN_LOCATION -> MetaAction.Type.ORIGIN;
|
||||||
default -> MetaAction.Type.MCP;
|
default -> MetaAction.Type.MCP;
|
||||||
};
|
};
|
||||||
return new MetaAction(
|
return Result.success(new MetaAction(
|
||||||
split[1],
|
split[1],
|
||||||
metaActionInfo.getIo(),
|
metaActionInfo.getIo(),
|
||||||
metaActionInfo.getLauncher(),
|
metaActionInfo.getLauncher(),
|
||||||
type,
|
type,
|
||||||
split[0]
|
split[0]
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@CapabilityMethod
|
@CapabilityMethod
|
||||||
public MetaActionInfo loadMetaActionInfo(@NonNull String actionKey) {
|
public Result<MetaActionInfo> loadMetaActionInfo(@NonNull String actionKey) {
|
||||||
MetaActionInfo info = existedMetaActions.get(actionKey);
|
MetaActionInfo info = existedMetaActions.get(actionKey);
|
||||||
if (info == null) {
|
if (info == null) {
|
||||||
throw new ActionLookupException(
|
return Result.failure(new ActionLookupException(
|
||||||
"Meta action description not found for action key: " + actionKey,
|
"Meta action description not found for action key: " + actionKey,
|
||||||
actionKey,
|
actionKey,
|
||||||
"META_ACTION_INFO"
|
"META_ACTION_INFO"
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
return info;
|
return Result.success(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
@CapabilityMethod
|
@CapabilityMethod
|
||||||
@@ -175,7 +177,6 @@ public class ActionCore implements StateSerializable {
|
|||||||
if (executableAction == null) {
|
if (executableAction == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加锁确保同步
|
// 加锁确保同步
|
||||||
synchronized (executableAction.getStatus()) {
|
synchronized (executableAction.getStatus()) {
|
||||||
applyInterventions(interventions, executableAction);
|
applyInterventions(interventions, executableAction);
|
||||||
@@ -188,10 +189,12 @@ public class ActionCore implements StateSerializable {
|
|||||||
interventions.sort(Comparator.comparingInt(MetaIntervention::getOrder));
|
interventions.sort(Comparator.comparingInt(MetaIntervention::getOrder));
|
||||||
|
|
||||||
for (MetaIntervention intervention : interventions) {
|
for (MetaIntervention intervention : interventions) {
|
||||||
List<MetaAction> actions = intervention.getActions()
|
Result<List<MetaAction>> actionsResult = resolveInterventionActions(intervention);
|
||||||
.stream()
|
if (actionsResult.isFailure()) {
|
||||||
.map(this::loadMetaAction)
|
reportLookupFailure(actionsResult.exceptionOrNull());
|
||||||
.toList();
|
continue;
|
||||||
|
}
|
||||||
|
List<MetaAction> actions = actionsResult.getOrNull();
|
||||||
|
|
||||||
switch (intervention.getType()) {
|
switch (intervention.getType()) {
|
||||||
case InterventionType.APPEND -> handleAppend(executableAction, intervention.getOrder(), actions);
|
case InterventionType.APPEND -> handleAppend(executableAction, intervention.getOrder(), actions);
|
||||||
@@ -210,6 +213,27 @@ public class ActionCore implements StateSerializable {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Result<List<MetaAction>> resolveInterventionActions(MetaIntervention intervention) {
|
||||||
|
List<MetaAction> actions = new ArrayList<>();
|
||||||
|
for (String actionKey : intervention.getActions()) {
|
||||||
|
Result<MetaAction> metaActionResult = loadMetaAction(actionKey);
|
||||||
|
if (metaActionResult.isFailure()) {
|
||||||
|
Throwable throwable = metaActionResult.exceptionOrNull();
|
||||||
|
return Result.failure(throwable == null
|
||||||
|
? new ActionLookupException("Meta action lookup failed: " + actionKey, actionKey, "META_ACTION")
|
||||||
|
: throwable);
|
||||||
|
}
|
||||||
|
actions.add(metaActionResult.getOrNull());
|
||||||
|
}
|
||||||
|
return Result.success(actions);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reportLookupFailure(Throwable throwable) {
|
||||||
|
if (throwable instanceof ActionLookupException lookupException) {
|
||||||
|
ExceptionReporterHandler.INSTANCE.report(lookupException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在未进入执行阶段的行动单元组新增新的行动
|
* 在未进入执行阶段的行动单元组新增新的行动
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ sealed class ExecutableAction(
|
|||||||
/**
|
/**
|
||||||
* 行动结果
|
* 行动结果
|
||||||
*/
|
*/
|
||||||
lateinit var result: String
|
var result: String? = null
|
||||||
|
|
||||||
val history: MutableMap<Int, MutableList<HistoryAction>> = mutableMapOf()
|
val history: MutableMap<Int, MutableList<HistoryAction>> = mutableMapOf()
|
||||||
|
|
||||||
@@ -142,7 +142,7 @@ sealed class ExecutableAction(
|
|||||||
tendency = tendency,
|
tendency = tendency,
|
||||||
actionChainSize = actionChain.size,
|
actionChainSize = actionChain.size,
|
||||||
executingStage = executingStage,
|
executingStage = executingStage,
|
||||||
result = if (::result.isInitialized) result else null,
|
result = result,
|
||||||
history = history.mapValues { (_, value) -> value.toList() },
|
history = history.mapValues { (_, value) -> value.toList() },
|
||||||
scheduleType = schedulable?.scheduleType,
|
scheduleType = schedulable?.scheduleType,
|
||||||
scheduleContent = schedulable?.scheduleContent,
|
scheduleContent = schedulable?.scheduleContent,
|
||||||
@@ -169,7 +169,7 @@ data class SchedulableExecutableAction @JvmOverloads constructor(
|
|||||||
val scheduleHistories = ArrayList<ScheduleHistory>()
|
val scheduleHistories = ArrayList<ScheduleHistory>()
|
||||||
|
|
||||||
fun recordAndReset() {
|
fun recordAndReset() {
|
||||||
val newHistory = ScheduleHistory(ZonedDateTime.now(), result, history.toMap())
|
val newHistory = ScheduleHistory(ZonedDateTime.now(), result ?: "null", history.toMap())
|
||||||
scheduleHistories.add(newHistory)
|
scheduleHistories.add(newHistory)
|
||||||
|
|
||||||
executingStage = 0
|
executingStage = 0
|
||||||
|
|||||||
@@ -15,8 +15,11 @@ import work.slhaf.partner.core.cognition.BlockContent;
|
|||||||
import work.slhaf.partner.core.cognition.CognitionCapability;
|
import work.slhaf.partner.core.cognition.CognitionCapability;
|
||||||
import work.slhaf.partner.core.cognition.ContextBlock;
|
import work.slhaf.partner.core.cognition.ContextBlock;
|
||||||
import work.slhaf.partner.core.cognition.ContextWorkspace;
|
import work.slhaf.partner.core.cognition.ContextWorkspace;
|
||||||
|
import work.slhaf.partner.framework.agent.exception.AgentException;
|
||||||
|
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.support.Result;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
@@ -291,7 +294,8 @@ class BuiltinInterventionActionProvider implements BuiltinActionProvider {
|
|||||||
Set.of(),
|
Set.of(),
|
||||||
true,
|
true,
|
||||||
JSONObject.of(
|
JSONObject.of(
|
||||||
"result", "Intervene status."
|
"ok", "Intervene status",
|
||||||
|
"result", "Intervene result or failed message."
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -305,6 +309,15 @@ class BuiltinInterventionActionProvider implements BuiltinActionProvider {
|
|||||||
Integer order = BuiltinActionRegistry.BuiltinActionDefinition.requireInt(params, "order");
|
Integer order = BuiltinActionRegistry.BuiltinActionDefinition.requireInt(params, "order");
|
||||||
List<String> actions = requireActions(params, type);
|
List<String> actions = requireActions(params, type);
|
||||||
ExecutableAction target = requireTargetAction(targetId);
|
ExecutableAction target = requireTargetAction(targetId);
|
||||||
|
Result<Void> validationResult = validateActionKeys(actions);
|
||||||
|
if (validationResult.isFailure()) {
|
||||||
|
reportFailure(validationResult.exceptionOrNull());
|
||||||
|
Throwable throwable = validationResult.exceptionOrNull();
|
||||||
|
return JSONObject.of(
|
||||||
|
"ok", false,
|
||||||
|
"result", throwable == null ? "Intervention action validation failed" : throwable.getLocalizedMessage()
|
||||||
|
).toJSONString();
|
||||||
|
}
|
||||||
|
|
||||||
MetaIntervention intervention = new MetaIntervention();
|
MetaIntervention intervention = new MetaIntervention();
|
||||||
intervention.setType(type);
|
intervention.setType(type);
|
||||||
@@ -383,4 +396,26 @@ class BuiltinInterventionActionProvider implements BuiltinActionProvider {
|
|||||||
.orElseThrow(() -> new IllegalArgumentException("未找到对应的 Action: " + targetId));
|
.orElseThrow(() -> new IllegalArgumentException("未找到对应的 Action: " + targetId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Result<Void> validateActionKeys(List<String> actions) {
|
||||||
|
for (String actionKey : actions) {
|
||||||
|
Result<work.slhaf.partner.core.action.entity.MetaAction> metaActionResult = actionCapability.loadMetaAction(actionKey);
|
||||||
|
if (metaActionResult.isFailure()) {
|
||||||
|
Throwable throwable = metaActionResult.exceptionOrNull();
|
||||||
|
return Result.failure(throwable == null
|
||||||
|
? new work.slhaf.partner.core.action.exception.ActionLookupException(
|
||||||
|
"Meta action lookup failed: " + actionKey,
|
||||||
|
actionKey,
|
||||||
|
"META_ACTION"
|
||||||
|
) : throwable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Result.success(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reportFailure(Throwable throwable) {
|
||||||
|
if (throwable instanceof AgentException agentException) {
|
||||||
|
ExceptionReporterHandler.INSTANCE.report(agentException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,11 +7,14 @@ import work.slhaf.partner.core.action.ActionCore;
|
|||||||
import work.slhaf.partner.core.action.entity.*;
|
import work.slhaf.partner.core.action.entity.*;
|
||||||
import work.slhaf.partner.core.action.runner.RunnerClient;
|
import work.slhaf.partner.core.action.runner.RunnerClient;
|
||||||
import work.slhaf.partner.core.cognition.CognitionCapability;
|
import work.slhaf.partner.core.cognition.CognitionCapability;
|
||||||
|
import work.slhaf.partner.framework.agent.exception.AgentException;
|
||||||
|
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.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 work.slhaf.partner.framework.agent.factory.component.annotation.InjectModule;
|
import work.slhaf.partner.framework.agent.factory.component.annotation.InjectModule;
|
||||||
import work.slhaf.partner.framework.agent.factory.context.Shutdown;
|
import work.slhaf.partner.framework.agent.factory.context.Shutdown;
|
||||||
|
import work.slhaf.partner.framework.agent.support.Result;
|
||||||
import work.slhaf.partner.module.action.executor.entity.*;
|
import work.slhaf.partner.module.action.executor.entity.*;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -311,7 +314,14 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
|
|||||||
|
|
||||||
val executingStage = actionData.getExecutingStage();
|
val executingStage = actionData.getExecutingStage();
|
||||||
|
|
||||||
val extractorInput = assemblyHelper.buildExtractorInput(metaAction.getKey(), actionData.getUuid(), actionData.getDescription());
|
Result<ExtractorInput> extractorInputResult = assemblyHelper.buildExtractorInput(metaAction.getKey(), actionData.getUuid(), actionData.getDescription());
|
||||||
|
if (extractorInputResult.isFailure()) {
|
||||||
|
reportFailure(extractorInputResult.exceptionOrNull());
|
||||||
|
Throwable throwable = extractorInputResult.exceptionOrNull();
|
||||||
|
failureReason = buildAttemptFailureReason("参数提取失败", throwable == null ? null : throwable.getLocalizedMessage());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
val extractorInput = extractorInputResult.getOrNull();
|
||||||
ExtractorResult extractorResult = paramsExtractor.execute(extractorInput);
|
ExtractorResult extractorResult = paramsExtractor.execute(extractorInput);
|
||||||
|
|
||||||
if (extractorResult == null || !extractorResult.isOk()) {
|
if (extractorResult == null || !extractorResult.isOk()) {
|
||||||
@@ -331,7 +341,7 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (result.getStatus() == MetaAction.Result.Status.SUCCESS) {
|
if (result.getStatus() == MetaAction.Result.Status.SUCCESS) {
|
||||||
val historyAction = new HistoryAction(actionKey, actionCapability.loadMetaActionInfo(actionKey).getDescription(), result.getData());
|
val historyAction = new HistoryAction(actionKey, resolveHistoryDescription(actionKey), result.getData());
|
||||||
actionData.getHistory()
|
actionData.getHistory()
|
||||||
.computeIfAbsent(executingStage, integer -> new ArrayList<>())
|
.computeIfAbsent(executingStage, integer -> new ArrayList<>())
|
||||||
.add(historyAction);
|
.add(historyAction);
|
||||||
@@ -497,6 +507,24 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String resolveHistoryDescription(String actionKey) {
|
||||||
|
Result<MetaActionInfo> metaActionInfoResult = actionCapability.loadMetaActionInfo(actionKey);
|
||||||
|
if (metaActionInfoResult.isFailure()) {
|
||||||
|
reportFailure(metaActionInfoResult.exceptionOrNull());
|
||||||
|
return actionKey;
|
||||||
|
}
|
||||||
|
MetaActionInfo metaActionInfo = metaActionInfoResult.getOrNull();
|
||||||
|
return metaActionInfo == null || metaActionInfo.getDescription().isBlank()
|
||||||
|
? actionKey
|
||||||
|
: metaActionInfo.getDescription();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reportFailure(Throwable throwable) {
|
||||||
|
if (throwable instanceof AgentException agentException) {
|
||||||
|
ExceptionReporterHandler.INSTANCE.report(agentException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private record MetaActionsListeningRecord(AtomicBoolean accepting, int phase) {
|
private record MetaActionsListeningRecord(AtomicBoolean accepting, int phase) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -511,12 +539,22 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
|
|||||||
private AssemblyHelper() {
|
private AssemblyHelper() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExtractorInput buildExtractorInput(String actionKey, @NotNull String uuid, @NotNull String description) {
|
private Result<ExtractorInput> buildExtractorInput(String actionKey, @NotNull String uuid, @NotNull String description) {
|
||||||
|
Result<MetaActionInfo> metaActionInfoResult = actionCapability.loadMetaActionInfo(actionKey);
|
||||||
|
if (metaActionInfoResult.isFailure()) {
|
||||||
|
Throwable throwable = metaActionInfoResult.exceptionOrNull();
|
||||||
|
return Result.failure(throwable == null
|
||||||
|
? new work.slhaf.partner.core.action.exception.ActionLookupException(
|
||||||
|
"Meta action description not found for action key: " + actionKey,
|
||||||
|
actionKey,
|
||||||
|
"META_ACTION_INFO"
|
||||||
|
) : throwable);
|
||||||
|
}
|
||||||
ExtractorInput input = new ExtractorInput();
|
ExtractorInput input = new ExtractorInput();
|
||||||
input.setMetaActionInfo(actionCapability.loadMetaActionInfo(actionKey));
|
input.setMetaActionInfo(metaActionInfoResult.getOrNull());
|
||||||
input.setTargetActionId(uuid);
|
input.setTargetActionId(uuid);
|
||||||
input.setTargetActionDesc(description);
|
input.setTargetActionDesc(description);
|
||||||
return input;
|
return Result.success(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CorrectorInput buildCorrectorInput(ExecutableAction executableAction) {
|
private CorrectorInput buildCorrectorInput(ExecutableAction executableAction) {
|
||||||
@@ -525,7 +563,7 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
|
|||||||
List<CorrectorInput.ActionChainItem> overviewItems = list.stream()
|
List<CorrectorInput.ActionChainItem> overviewItems = list.stream()
|
||||||
.map(metaAction -> new CorrectorInput.ActionChainItem(
|
.map(metaAction -> new CorrectorInput.ActionChainItem(
|
||||||
metaAction.getKey(),
|
metaAction.getKey(),
|
||||||
actionCapability.loadMetaActionInfo(metaAction.getKey()).getDescription(),
|
resolveHistoryDescription(metaAction.getKey()),
|
||||||
metaAction.getResult().getStatus().name().toLowerCase(Locale.ROOT)
|
metaAction.getResult().getStatus().name().toLowerCase(Locale.ROOT)
|
||||||
))
|
))
|
||||||
.toList();
|
.toList();
|
||||||
|
|||||||
@@ -11,10 +11,12 @@ import work.slhaf.partner.core.cognition.BlockContent;
|
|||||||
import work.slhaf.partner.core.cognition.CognitionCapability;
|
import work.slhaf.partner.core.cognition.CognitionCapability;
|
||||||
import work.slhaf.partner.core.cognition.CommunicationBlockContent;
|
import work.slhaf.partner.core.cognition.CommunicationBlockContent;
|
||||||
import work.slhaf.partner.core.cognition.ContextBlock;
|
import work.slhaf.partner.core.cognition.ContextBlock;
|
||||||
|
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.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 work.slhaf.partner.framework.agent.factory.component.annotation.InjectModule;
|
import work.slhaf.partner.framework.agent.factory.component.annotation.InjectModule;
|
||||||
|
import work.slhaf.partner.framework.agent.support.Result;
|
||||||
import work.slhaf.partner.module.action.executor.ActionExecutor;
|
import work.slhaf.partner.module.action.executor.ActionExecutor;
|
||||||
import work.slhaf.partner.module.action.planner.evaluator.ActionEvaluator;
|
import work.slhaf.partner.module.action.planner.evaluator.ActionEvaluator;
|
||||||
import work.slhaf.partner.module.action.planner.evaluator.entity.EvaluatorInput;
|
import work.slhaf.partner.module.action.planner.evaluator.entity.EvaluatorInput;
|
||||||
@@ -147,6 +149,9 @@ public class ActionPlanner extends AbstractAgentModule.Running<PartnerRunningFlo
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ExecutableAction executableAction = assemblyHelper.buildActionData(evaluatorResult, source);
|
ExecutableAction executableAction = assemblyHelper.buildActionData(evaluatorResult, source);
|
||||||
|
if (executableAction == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
passedActions.add(executableAction);
|
passedActions.add(executableAction);
|
||||||
if (evaluatorResult.isNeedConfirm()) {
|
if (evaluatorResult.isNeedConfirm()) {
|
||||||
registerPendingContextBlock(executableAction, evaluatorResult, input);
|
registerPendingContextBlock(executableAction, evaluatorResult, input);
|
||||||
@@ -346,6 +351,9 @@ public class ActionPlanner extends AbstractAgentModule.Running<PartnerRunningFlo
|
|||||||
|
|
||||||
private ExecutableAction buildActionData(EvaluatorResult evaluatorResult, String userId) {
|
private ExecutableAction buildActionData(EvaluatorResult evaluatorResult, String userId) {
|
||||||
Map<Integer, List<MetaAction>> actionChain = getActionChain(evaluatorResult);
|
Map<Integer, List<MetaAction>> actionChain = getActionChain(evaluatorResult);
|
||||||
|
if (actionChain == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return switch (evaluatorResult.getType()) {
|
return switch (evaluatorResult.getType()) {
|
||||||
case PLANNING -> new SchedulableExecutableAction(
|
case PLANNING -> new SchedulableExecutableAction(
|
||||||
evaluatorResult.getTendency(),
|
evaluatorResult.getTendency(),
|
||||||
@@ -366,20 +374,28 @@ public class ActionPlanner extends AbstractAgentModule.Running<PartnerRunningFlo
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private @NotNull Map<Integer, List<MetaAction>> getActionChain(EvaluatorResult evaluatorResult) {
|
private Map<Integer, List<MetaAction>> getActionChain(EvaluatorResult evaluatorResult) {
|
||||||
Map<Integer, List<MetaAction>> actionChain = new HashMap<>();
|
Map<Integer, List<MetaAction>> actionChain = new HashMap<>();
|
||||||
Map<Integer, List<String>> primaryActionChain = evaluatorResult.getPrimaryActionChain();
|
Map<Integer, List<String>> primaryActionChain = evaluatorResult.getPrimaryActionChain();
|
||||||
fixDependencies(primaryActionChain);
|
if (!fixDependencies(primaryActionChain)) {
|
||||||
primaryActionChain.forEach((order, actionKeys) -> {
|
return null;
|
||||||
List<MetaAction> metaActions = actionKeys.stream()
|
}
|
||||||
.map(actionKey -> actionCapability.loadMetaAction(actionKey))
|
for (Map.Entry<Integer, List<String>> entry : primaryActionChain.entrySet()) {
|
||||||
.toList();
|
List<MetaAction> metaActions = new ArrayList<>();
|
||||||
actionChain.put(order, metaActions);
|
for (String actionKey : entry.getValue()) {
|
||||||
});
|
Result<MetaAction> metaActionResult = actionCapability.loadMetaAction(actionKey);
|
||||||
|
if (metaActionResult.isFailure()) {
|
||||||
|
reportFailure(metaActionResult);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
metaActions.add(metaActionResult.getOrNull());
|
||||||
|
}
|
||||||
|
actionChain.put(entry.getKey(), metaActions);
|
||||||
|
}
|
||||||
return actionChain;
|
return actionChain;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fixDependencies(Map<Integer, List<String>> primaryActionChain) {
|
private boolean fixDependencies(Map<Integer, List<String>> primaryActionChain) {
|
||||||
// 先将 primaryActionChain 的节点序号修正为从1开始依次增大
|
// 先将 primaryActionChain 的节点序号修正为从1开始依次增大
|
||||||
fixOrder(primaryActionChain);
|
fixOrder(primaryActionChain);
|
||||||
List<Integer> fixedOrders = new ArrayList<>(primaryActionChain.keySet().stream().toList());
|
List<Integer> fixedOrders = new ArrayList<>(primaryActionChain.keySet().stream().toList());
|
||||||
@@ -392,7 +408,12 @@ public class ActionPlanner extends AbstractAgentModule.Running<PartnerRunningFlo
|
|||||||
List<String> actionKeys = primaryActionChain.get(fixedOrder);
|
List<String> actionKeys = primaryActionChain.get(fixedOrder);
|
||||||
for (String actionKey : actionKeys) {
|
for (String actionKey : actionKeys) {
|
||||||
// 根据 actionKey 加载行动信息,并检查是否存在必需前置依赖
|
// 根据 actionKey 加载行动信息,并检查是否存在必需前置依赖
|
||||||
MetaActionInfo metaActionInfo = actionCapability.loadMetaActionInfo(actionKey);
|
Result<MetaActionInfo> metaActionInfoResult = actionCapability.loadMetaActionInfo(actionKey);
|
||||||
|
if (metaActionInfoResult.isFailure()) {
|
||||||
|
reportFailure(metaActionInfoResult);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
MetaActionInfo metaActionInfo = metaActionInfoResult.getOrNull();
|
||||||
Set<String> preActions = metaActionInfo.getPreActions();
|
Set<String> preActions = metaActionInfo.getPreActions();
|
||||||
boolean preActionsExist = preActions.isEmpty();
|
boolean preActionsExist = preActions.isEmpty();
|
||||||
if (!preActionsExist) {
|
if (!preActionsExist) {
|
||||||
@@ -420,6 +441,13 @@ public class ActionPlanner extends AbstractAgentModule.Running<PartnerRunningFlo
|
|||||||
fixedOrders.clear();
|
fixedOrders.clear();
|
||||||
fixedOrders.addAll(tempOrders);
|
fixedOrders.addAll(tempOrders);
|
||||||
} while (fixed.getAndSet(false));
|
} while (fixed.getAndSet(false));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reportFailure(Result<?> result) {
|
||||||
|
if (result.exceptionOrNull() instanceof work.slhaf.partner.framework.agent.exception.AgentException agentException) {
|
||||||
|
ExceptionReporterHandler.INSTANCE.report(agentException);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fixOrder(Map<Integer, List<String>> primaryActionChain) {
|
private void fixOrder(Map<Integer, List<String>> primaryActionChain) {
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import org.junit.jupiter.api.BeforeEach;
|
|||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.io.TempDir;
|
import org.junit.jupiter.api.io.TempDir;
|
||||||
import work.slhaf.partner.core.action.entity.*;
|
import work.slhaf.partner.core.action.entity.*;
|
||||||
|
import work.slhaf.partner.core.action.exception.ActionLookupException;
|
||||||
|
import work.slhaf.partner.framework.agent.support.Result;
|
||||||
import work.slhaf.partner.module.action.executor.entity.HistoryAction;
|
import work.slhaf.partner.module.action.executor.entity.HistoryAction;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
@@ -331,4 +333,32 @@ class ActionCoreTest {
|
|||||||
assertEquals(1, schedulableAction.getScheduleHistories().size());
|
assertEquals(1, schedulableAction.getScheduleHistories().size());
|
||||||
assertEquals("cycle-result", schedulableAction.getScheduleHistories().getFirst().getResult());
|
assertEquals("cycle-result", schedulableAction.getScheduleHistories().getFirst().getResult());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldReturnResultForMetaActionLookup() {
|
||||||
|
MetaActionInfo metaActionInfo = new MetaActionInfo(
|
||||||
|
true,
|
||||||
|
"python",
|
||||||
|
Map.of(),
|
||||||
|
"demo",
|
||||||
|
Set.of(),
|
||||||
|
Set.of(),
|
||||||
|
Set.of(),
|
||||||
|
false,
|
||||||
|
JSONObject.of()
|
||||||
|
);
|
||||||
|
actionCore.registerMetaActions(Map.of("builtin::demo", metaActionInfo));
|
||||||
|
|
||||||
|
Result<MetaAction> success = actionCore.loadMetaAction("builtin::demo");
|
||||||
|
assertTrue(success.isSuccess());
|
||||||
|
assertEquals("demo", success.getOrNull().getName());
|
||||||
|
|
||||||
|
Result<MetaAction> failure = actionCore.loadMetaAction("builtin::missing");
|
||||||
|
assertTrue(failure.isFailure());
|
||||||
|
assertInstanceOf(ActionLookupException.class, failure.exceptionOrNull());
|
||||||
|
|
||||||
|
Result<MetaActionInfo> infoFailure = actionCore.loadMetaActionInfo("builtin::missing");
|
||||||
|
assertTrue(infoFailure.isFailure());
|
||||||
|
assertInstanceOf(ActionLookupException.class, infoFailure.exceptionOrNull());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import work.slhaf.partner.core.action.entity.*;
|
|||||||
import work.slhaf.partner.core.action.runner.RunnerClient;
|
import work.slhaf.partner.core.action.runner.RunnerClient;
|
||||||
import work.slhaf.partner.core.cognition.CognitionCapability;
|
import work.slhaf.partner.core.cognition.CognitionCapability;
|
||||||
import work.slhaf.partner.core.cognition.ContextWorkspace;
|
import work.slhaf.partner.core.cognition.ContextWorkspace;
|
||||||
|
import work.slhaf.partner.framework.agent.support.Result;
|
||||||
import work.slhaf.partner.module.action.executor.entity.ExtractorResult;
|
import work.slhaf.partner.module.action.executor.entity.ExtractorResult;
|
||||||
import work.slhaf.partner.module.action.executor.entity.HistoryAction;
|
import work.slhaf.partner.module.action.executor.entity.HistoryAction;
|
||||||
|
|
||||||
@@ -121,7 +122,7 @@ class ActionExecutorTest {
|
|||||||
when(actionCapability.getExecutor(ActionCore.ExecutorType.PLATFORM)).thenReturn(platformExecutor);
|
when(actionCapability.getExecutor(ActionCore.ExecutorType.PLATFORM)).thenReturn(platformExecutor);
|
||||||
when(actionCapability.runnerClient()).thenReturn(runnerClient);
|
when(actionCapability.runnerClient()).thenReturn(runnerClient);
|
||||||
when(actionCapability.listActions(Action.Status.EXECUTING, null)).thenReturn(Set.of());
|
when(actionCapability.listActions(Action.Status.EXECUTING, null)).thenReturn(Set.of());
|
||||||
when(actionCapability.loadMetaActionInfo(anyString())).thenReturn(new MetaActionInfo(
|
when(actionCapability.loadMetaActionInfo(anyString())).thenReturn(Result.success(new MetaActionInfo(
|
||||||
false,
|
false,
|
||||||
null,
|
null,
|
||||||
Map.of(),
|
Map.of(),
|
||||||
@@ -131,7 +132,7 @@ class ActionExecutorTest {
|
|||||||
Set.of(),
|
Set.of(),
|
||||||
false,
|
false,
|
||||||
new com.alibaba.fastjson2.JSONObject()
|
new com.alibaba.fastjson2.JSONObject()
|
||||||
));
|
)));
|
||||||
when(cognitionCapability.contextWorkspace()).thenReturn(new ContextWorkspace());
|
when(cognitionCapability.contextWorkspace()).thenReturn(new ContextWorkspace());
|
||||||
|
|
||||||
ExtractorResult extractorResult = new ExtractorResult();
|
ExtractorResult extractorResult = new ExtractorResult();
|
||||||
@@ -186,6 +187,130 @@ class ActionExecutorTest {
|
|||||||
assertEquals("rerun-ok", metaAction.getResult().getData());
|
assertEquals("rerun-ok", metaAction.getResult().getData());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldMarkMetaActionFailedWhenMetaActionInfoLookupFailsBeforeExtraction() throws Exception {
|
||||||
|
ActionCapability actionCapability = Mockito.mock(ActionCapability.class);
|
||||||
|
CognitionCapability cognitionCapability = Mockito.mock(CognitionCapability.class);
|
||||||
|
ParamsExtractor paramsExtractor = Mockito.mock(ParamsExtractor.class);
|
||||||
|
ActionCorrector actionCorrector = Mockito.mock(ActionCorrector.class);
|
||||||
|
ActionCorrectionRecognizer actionCorrectionRecognizer = Mockito.mock(ActionCorrectionRecognizer.class);
|
||||||
|
RunnerClient runnerClient = Mockito.mock(RunnerClient.class);
|
||||||
|
|
||||||
|
ExecutorService virtualExecutor = registerExecutor(Executors.newFixedThreadPool(2));
|
||||||
|
ExecutorService platformExecutor = registerExecutor(Executors.newFixedThreadPool(2));
|
||||||
|
|
||||||
|
when(actionCapability.getExecutor(ActionCore.ExecutorType.VIRTUAL)).thenReturn(virtualExecutor);
|
||||||
|
when(actionCapability.getExecutor(ActionCore.ExecutorType.PLATFORM)).thenReturn(platformExecutor);
|
||||||
|
when(actionCapability.runnerClient()).thenReturn(runnerClient);
|
||||||
|
when(actionCapability.listActions(Action.Status.EXECUTING, null)).thenReturn(Set.of());
|
||||||
|
when(actionCapability.loadMetaActionInfo(anyString())).thenReturn(Result.failure(new work.slhaf.partner.core.action.exception.ActionLookupException(
|
||||||
|
"missing",
|
||||||
|
"builtin::command",
|
||||||
|
"META_ACTION_INFO"
|
||||||
|
)));
|
||||||
|
when(cognitionCapability.contextWorkspace()).thenReturn(new ContextWorkspace());
|
||||||
|
|
||||||
|
ActionExecutor actionExecutor = new ActionExecutor();
|
||||||
|
inject(actionExecutor, "actionCapability", actionCapability);
|
||||||
|
inject(actionExecutor, "cognitionCapability", cognitionCapability);
|
||||||
|
inject(actionExecutor, "paramsExtractor", paramsExtractor);
|
||||||
|
inject(actionExecutor, "actionCorrector", actionCorrector);
|
||||||
|
inject(actionExecutor, "actionCorrectionRecognizer", actionCorrectionRecognizer);
|
||||||
|
actionExecutor.init();
|
||||||
|
|
||||||
|
MetaAction metaAction = metaAction("command");
|
||||||
|
ImmediateExecutableAction action = new ImmediateExecutableAction(
|
||||||
|
"urgent",
|
||||||
|
actionChain(metaAction),
|
||||||
|
"reason",
|
||||||
|
"desc",
|
||||||
|
"planner",
|
||||||
|
"lookup-fail-uuid"
|
||||||
|
);
|
||||||
|
|
||||||
|
actionExecutor.execute(action);
|
||||||
|
waitUntilFinished(action);
|
||||||
|
|
||||||
|
verify(paramsExtractor, never()).execute(any());
|
||||||
|
verify(runnerClient, never()).submit(any(MetaAction.class));
|
||||||
|
assertEquals(Action.Status.SUCCESS, action.getStatus());
|
||||||
|
assertEquals(MetaAction.Result.Status.FAILED, metaAction.getResult().getStatus());
|
||||||
|
assertTrue(metaAction.getResult().getData().contains("参数提取失败"));
|
||||||
|
assertEquals(metaAction.getResult().getData(), action.getResult());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldFallbackToActionKeyWhenHistoryDescriptionLookupFails() throws Exception {
|
||||||
|
ActionCapability actionCapability = Mockito.mock(ActionCapability.class);
|
||||||
|
CognitionCapability cognitionCapability = Mockito.mock(CognitionCapability.class);
|
||||||
|
ParamsExtractor paramsExtractor = Mockito.mock(ParamsExtractor.class);
|
||||||
|
ActionCorrector actionCorrector = Mockito.mock(ActionCorrector.class);
|
||||||
|
ActionCorrectionRecognizer actionCorrectionRecognizer = Mockito.mock(ActionCorrectionRecognizer.class);
|
||||||
|
RunnerClient runnerClient = Mockito.mock(RunnerClient.class);
|
||||||
|
|
||||||
|
ExecutorService virtualExecutor = registerExecutor(Executors.newFixedThreadPool(2));
|
||||||
|
ExecutorService platformExecutor = registerExecutor(Executors.newFixedThreadPool(2));
|
||||||
|
|
||||||
|
when(actionCapability.getExecutor(ActionCore.ExecutorType.VIRTUAL)).thenReturn(virtualExecutor);
|
||||||
|
when(actionCapability.getExecutor(ActionCore.ExecutorType.PLATFORM)).thenReturn(platformExecutor);
|
||||||
|
when(actionCapability.runnerClient()).thenReturn(runnerClient);
|
||||||
|
when(actionCapability.listActions(Action.Status.EXECUTING, null)).thenReturn(Set.of());
|
||||||
|
when(cognitionCapability.contextWorkspace()).thenReturn(new ContextWorkspace());
|
||||||
|
|
||||||
|
when(actionCapability.loadMetaActionInfo(anyString()))
|
||||||
|
.thenReturn(Result.success(new MetaActionInfo(
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
Map.of(),
|
||||||
|
"demo action",
|
||||||
|
Set.of(),
|
||||||
|
Set.of(),
|
||||||
|
Set.of(),
|
||||||
|
false,
|
||||||
|
new com.alibaba.fastjson2.JSONObject()
|
||||||
|
)))
|
||||||
|
.thenReturn(Result.failure(new work.slhaf.partner.core.action.exception.ActionLookupException(
|
||||||
|
"missing desc",
|
||||||
|
"builtin::command",
|
||||||
|
"META_ACTION_INFO"
|
||||||
|
)));
|
||||||
|
|
||||||
|
ExtractorResult extractorResult = new ExtractorResult();
|
||||||
|
extractorResult.setOk(true);
|
||||||
|
extractorResult.setParams(Map.of("fresh", "value"));
|
||||||
|
when(paramsExtractor.execute(any())).thenReturn(extractorResult);
|
||||||
|
doAnswer(invocation -> {
|
||||||
|
MetaAction metaAction = invocation.getArgument(0);
|
||||||
|
metaAction.getResult().setStatus(MetaAction.Result.Status.SUCCESS);
|
||||||
|
metaAction.getResult().setData("history-ok");
|
||||||
|
return null;
|
||||||
|
}).when(runnerClient).submit(any(MetaAction.class));
|
||||||
|
|
||||||
|
ActionExecutor actionExecutor = new ActionExecutor();
|
||||||
|
inject(actionExecutor, "actionCapability", actionCapability);
|
||||||
|
inject(actionExecutor, "cognitionCapability", cognitionCapability);
|
||||||
|
inject(actionExecutor, "paramsExtractor", paramsExtractor);
|
||||||
|
inject(actionExecutor, "actionCorrector", actionCorrector);
|
||||||
|
inject(actionExecutor, "actionCorrectionRecognizer", actionCorrectionRecognizer);
|
||||||
|
actionExecutor.init();
|
||||||
|
|
||||||
|
MetaAction metaAction = metaAction("command");
|
||||||
|
ImmediateExecutableAction action = new ImmediateExecutableAction(
|
||||||
|
"urgent",
|
||||||
|
actionChain(metaAction),
|
||||||
|
"reason",
|
||||||
|
"desc",
|
||||||
|
"planner",
|
||||||
|
"history-fallback-uuid"
|
||||||
|
);
|
||||||
|
|
||||||
|
actionExecutor.execute(action);
|
||||||
|
waitUntilFinished(action);
|
||||||
|
|
||||||
|
assertEquals(Action.Status.SUCCESS, action.getStatus());
|
||||||
|
assertEquals("builtin::command", action.getHistory().get(1).getFirst().description());
|
||||||
|
}
|
||||||
|
|
||||||
private void waitUntilFinished(ImmediateExecutableAction action) throws InterruptedException {
|
private void waitUntilFinished(ImmediateExecutableAction action) throws InterruptedException {
|
||||||
long deadline = System.currentTimeMillis() + 3000;
|
long deadline = System.currentTimeMillis() + 3000;
|
||||||
while (System.currentTimeMillis() < deadline) {
|
while (System.currentTimeMillis() < deadline) {
|
||||||
|
|||||||
Reference in New Issue
Block a user