refactor(ActionData): migrate to Kotlin sealed class and data classes, update planner/scheduler usage

This commit is contained in:
2026-02-08 16:27:44 +08:00
parent 8ca2b9998d
commit cdea8d6322
7 changed files with 122 additions and 108 deletions

View File

@@ -1,80 +1,143 @@
package work.slhaf.partner.core.action.entity; package work.slhaf.partner.core.action.entity
import lombok.Data; import work.slhaf.partner.module.modules.action.dispatcher.executor.entity.HistoryAction
import work.slhaf.partner.module.modules.action.dispatcher.executor.entity.HistoryAction; import java.time.ZonedDateTime
import java.util.*
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/** /**
* 行动模块传递的行动数据包含行动uuid、倾向、状态、行动链、结果、发起原因、行动描述等信息。 * 行动模块传递的行动数据包含行动uuid、倾向、状态、行动链、结果、发起原因、行动描述等信息。
*/ */
@Data sealed class ActionData {
public abstract class ActionData {
/** /**
* 行动ID * 行动ID
*/ */
protected String uuid; val uuid: String = UUID.randomUUID().toString()
/** /**
* 行动倾向 * 行动倾向
*/ */
protected String tendency; abstract val tendency: String
/** /**
* 行动状态 * 行动状态
*/ */
protected ActionStatus status; var status: ActionStatus = ActionStatus.PREPARE
/** /**
* 行动链 * 行动链
*/ */
protected Map<Integer, List<MetaAction>> actionChain; abstract val actionChain: MutableMap<Int, MutableList<MetaAction>>
/** /**
* 行动阶段(当前阶段) * 行动阶段(当前阶段)
*/ */
protected int executingStage; var executingStage: Int = 0
/** /**
* 行动结果 * 行动结果
*/ */
protected String result; lateinit var result: String
protected Map<Integer, List<HistoryAction>> history = new HashMap<>();
val history: MutableMap<Int, MutableList<HistoryAction>> = mutableMapOf()
/** /**
* 修复上下文 * 修复上下文
*/ */
protected Map<Integer, List<String>> additionalContext; val additionalContext: MutableMap<Int, MutableList<String>> = mutableMapOf()
/** /**
* 行动原因 * 行动原因
*/ */
protected String reason; abstract val reason: String
/** /**
* 行动描述 * 行动描述
*/ */
protected String description; abstract val description: String
/** /**
* 行动来源 * 行动来源
*/ */
protected String source; abstract val source: String
public enum ActionStatus { enum class ActionStatus {
/** /**
* 执行成功 * 执行成功
*/ */
SUCCESS, SUCCESS,
/** /**
* 执行失败 * 执行失败
*/ */
FAILED, FAILED,
/** /**
* 执行中 * 执行中
*/ */
EXECUTING, EXECUTING,
/** /**
* 暂时中断 * 暂时中断
*/ */
INTERRUPTED, INTERRUPTED,
/** /**
* 预备执行 * 预备执行
*/ */
PREPARE PREPARE
} }
} }
/**
* 计划行动数据类,继承自{@link ActionData},扩展了属性{@link ScheduledActionData#type}和{@link ScheduledActionData#scheduleContent},用于标识计划类型(单次还是周期性任务)和计划内容
*/
data class ScheduledActionData(
override val tendency: String,
override val actionChain: MutableMap<Int, MutableList<MetaAction>>,
override val reason: String,
override val description: String,
override val source: String,
val scheduleType: ScheduleType,
val scheduleContent: String,
) : ActionData() {
val scheduleHistories = ArrayList<ScheduleHistory>()
fun recordAndReset() {
val newHistory = ScheduleHistory(ZonedDateTime.now(), result, history.toMap())
scheduleHistories.add(newHistory)
additionalContext.clear()
executingStage = 0
for (entry in actionChain) {
for (action in entry.value) {
action.params.clear()
action.result = MetaAction.Result()
}
}
status = ActionStatus.PREPARE
}
enum class ScheduleType {
CYCLE,
ONCE
}
data class ScheduleHistory(
val endTime: ZonedDateTime,
val result: String,
val history: Map<Int, List<HistoryAction>>
)
}
/**
* 即时行动数据类
*/
data class ImmediateActionData(
override val tendency: String,
override val actionChain: MutableMap<Int, MutableList<MetaAction>>,
override val reason: String,
override val description: String,
override val source: String,
) : ActionData()

View File

@@ -1,12 +0,0 @@
package work.slhaf.partner.core.action.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 即时行动数据类,继承自{@link ActionData}
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class ImmediateActionData extends ActionData {
}

View File

@@ -1,44 +0,0 @@
package work.slhaf.partner.core.action.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import work.slhaf.partner.module.modules.action.dispatcher.executor.entity.HistoryAction;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 计划行动数据类,继承自{@link ActionData},扩展了属性{@link ScheduledActionData#type}和{@link ScheduledActionData#scheduleContent},用于标识计划类型(单次还是周期性任务)和计划内容
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class ScheduledActionData extends ActionData {
private ScheduledType type;
private String scheduleContent; //如果为周期则对应cron表达式如果为一次性则对应为ZonedDateTime字符串
private List<ScheduledHistory> scheduledHistories = new ArrayList<>();
public void recordAndReset() {
this.scheduledHistories.add(new ScheduledHistory(ZonedDateTime.now(), this.result, Map.copyOf(this.history)));
// 清理执行时内容
this.additionalContext.clear();
this.executingStage = 0;
this.getActionChain().forEach((stage, actions) -> {
for (MetaAction action : actions) {
action.getParams().clear();
action.setResult(new MetaAction.Result());
}
});
this.setStatus(ActionStatus.PREPARE);
}
public enum ScheduledType {
CYCLE, ONCE
}
private record ScheduledHistory(ZonedDateTime endTime, String result, Map<Integer, List<HistoryAction>> history) {
}
}

View File

@@ -90,7 +90,7 @@ class ActionScheduler : AgentRunningSubModule<Set<ScheduledActionData>, Void>()
} }
val parseToZonedDateTime = parseToZonedDateTime( val parseToZonedDateTime = parseToZonedDateTime(
actionData.type, actionData.scheduleType,
actionData.scheduleContent, actionData.scheduleContent,
ZonedDateTime.now() ZonedDateTime.now()
) ?: run { ) ?: run {
@@ -226,7 +226,7 @@ class ActionScheduler : AgentRunningSubModule<Set<ScheduledActionData>, Void>()
for (actionData in primaryActions) { for (actionData in primaryActions) {
val latestExecutingTime = val latestExecutingTime =
parseToZonedDateTime( parseToZonedDateTime(
actionData.type, actionData.scheduleType,
actionData.scheduleContent, actionData.scheduleContent,
now now
) ?: run { ) ?: run {
@@ -250,12 +250,13 @@ class ActionScheduler : AgentRunningSubModule<Set<ScheduledActionData>, Void>()
} }
private fun parseToZonedDateTime( private fun parseToZonedDateTime(
scheduleType: ScheduledActionData.ScheduledType, scheduleType: ScheduledActionData.ScheduleType,
scheduleContent: String, scheduleContent: String,
now: ZonedDateTime now: ZonedDateTime
): ZonedDateTime? { ): ZonedDateTime? {
return when (scheduleType) { return when (scheduleType) {
ScheduledActionData.ScheduledType.CYCLE -> { ScheduledActionData.ScheduleType.CYCLE
-> {
val cron = try { val cron = try {
cronParser.parse(scheduleContent).validate() cronParser.parse(scheduleContent).validate()
} catch (_: Exception) { } catch (_: Exception) {
@@ -265,7 +266,7 @@ class ActionScheduler : AgentRunningSubModule<Set<ScheduledActionData>, Void>()
executionTime.nextExecution(now).getOrNull() executionTime.nextExecution(now).getOrNull()
} }
ScheduledActionData.ScheduledType.ONCE -> { ScheduledActionData.ScheduleType.ONCE -> {
val executionTime = try { val executionTime = try {
ZonedDateTime.parse(scheduleContent) ZonedDateTime.parse(scheduleContent)
} catch (_: Exception) { } catch (_: Exception) {

View File

@@ -153,7 +153,7 @@ public class ActionPlanner extends PreRunningModule {
private void putActionData(List<EvaluatorResult> evaluatorResults, PartnerRunningFlowContext context) { private void putActionData(List<EvaluatorResult> evaluatorResults, PartnerRunningFlowContext context) {
for (EvaluatorResult evaluatorResult : evaluatorResults) { for (EvaluatorResult evaluatorResult : evaluatorResults) {
ActionData actionData = assemblyHelper.buildActionData(evaluatorResult); ActionData actionData = assemblyHelper.buildActionData(evaluatorResult, context.getUserId());
if (evaluatorResult.isNeedConfirm()) { if (evaluatorResult.isNeedConfirm()) {
actionCapability.putPendingActions(context.getUserId(), actionData); actionCapability.putPendingActions(context.getUserId(), actionData);
} else { } else {
@@ -231,24 +231,25 @@ public class ActionPlanner extends PreRunningModule {
return input; return input;
} }
private ActionData buildActionData(EvaluatorResult evaluatorResult) { private ActionData buildActionData(EvaluatorResult evaluatorResult, String userId) {
Map<Integer, List<MetaAction>> actionChain = getActionChain(evaluatorResult); Map<Integer, List<MetaAction>> actionChain = getActionChain(evaluatorResult);
return switch (evaluatorResult.getType()) { return switch (evaluatorResult.getType()) {
case PLANNING -> { case PLANNING -> new ScheduledActionData(
ScheduledActionData actionInfo = new ScheduledActionData(); evaluatorResult.getTendency(),
actionInfo.setActionChain(actionChain); actionChain,
actionInfo.setScheduleContent(evaluatorResult.getScheduleContent()); evaluatorResult.getReason(),
actionInfo.setStatus(ActionData.ActionStatus.PREPARE); evaluatorResult.getDescription(),
actionInfo.setUuid(UUID.randomUUID().toString()); userId,
yield actionInfo; evaluatorResult.getScheduleType(),
} evaluatorResult.getScheduleContent()
case IMMEDIATE -> { );
ImmediateActionData actionInfo = new ImmediateActionData(); case IMMEDIATE -> new ImmediateActionData(
actionInfo.setActionChain(actionChain); evaluatorResult.getTendency(),
actionInfo.setStatus(ActionData.ActionStatus.PREPARE); actionChain,
actionInfo.setUuid(UUID.randomUUID().toString()); evaluatorResult.getReason(),
yield actionInfo; evaluatorResult.getDescription(),
} userId
);
}; };
} }

View File

@@ -1,6 +1,7 @@
package work.slhaf.partner.module.modules.action.planner.evaluator.entity; package work.slhaf.partner.module.modules.action.planner.evaluator.entity;
import lombok.Data; import lombok.Data;
import work.slhaf.partner.core.action.entity.ScheduledActionData;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -11,8 +12,11 @@ public class EvaluatorResult {
private boolean needConfirm; private boolean needConfirm;
private ActionType type; private ActionType type;
private String scheduleContent; private String scheduleContent;
private ScheduledActionData.ScheduleType scheduleType;
private Map<Integer, List<String>> primaryActionChain; private Map<Integer, List<String>> primaryActionChain;
private String tendency; private String tendency;
private String reason;
private String description;
public enum ActionType { public enum ActionType {
IMMEDIATE, PLANNING IMMEDIATE, PLANNING

View File

@@ -1,6 +1,7 @@
package work.slhaf.partner.module.modules.action.dispatcher.executor; package work.slhaf.partner.module.modules.action.dispatcher.executor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.junit.jupiter.api.*; import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
@@ -373,15 +374,15 @@ class ActionExecutorTest {
} }
private ImmediateActionData buildActionData(Map<Integer, List<MetaAction>> actionChain) { private ImmediateActionData buildActionData(Map<Integer, List<MetaAction>> actionChain) {
ImmediateActionData actionData = new ImmediateActionData(); val immediateActionData = new ImmediateActionData(
actionData.setStatus(ActionData.ActionStatus.PREPARE); "tendency",
actionData.setActionChain(actionChain); actionChain,
actionData.setAdditionalContext(initAdditionalContext(actionChain)); "reason",
actionData.setReason("reason"); "desc",
actionData.setDescription("desc"); "source"
actionData.setSource("source"); );
actionData.setTendency("tendency"); immediateActionData.getAdditionalContext().putAll(initAdditionalContext(actionChain));
return actionData; return immediateActionData;
} }
private Map<Integer, List<MetaAction>> singleStageChain(boolean io) { private Map<Integer, List<MetaAction>> singleStageChain(boolean io) {