fix(action): stabilize staged action execution metadata

Use a stage-local Phaser in ActionExecutor so each action-chain stage
waits on its own execution phase. This avoids reusing a terminated
Phaser after the first stage completes, which could cause later stages
to advance without actually waiting for their MetaActions and trigger
FINAL_CHECK prematurely.

Add stage-level descriptions to evaluated action chains and pass them
through execution/correction contexts. Stage descriptions are now aligned
with normalized action-chain order, exposed to ParamsExtractor, persisted
in action state, and included in CorrectorInput so repeated MetaActions
can be parameterized and corrected according to their concrete stage
objective.

Also fix APPEND intervention semantics to append after the requested
stage instead of overwriting or dropping stages, and include stage
descriptions in correction prompts to distinguish stage intent from
generic MetaAction capability descriptions.
This commit is contained in:
2026-04-27 18:41:32 +08:00
parent 822ea82593
commit cf61c171a5
5 changed files with 41 additions and 9 deletions
@@ -229,13 +229,20 @@ public class ActionCore implements StateSerializable {
} }
/** /**
* 在未进入执行阶段的行动单元组新增新的行动 * 在指定阶段之后追加新的行动单元组
*/ */
private void handleAppend(ExecutableAction executableAction, int order, List<MetaAction> actions) { private void handleAppend(ExecutableAction executableAction, int order, List<MetaAction> actions) {
if (order <= executableAction.getExecutingStage()) Map<Integer, List<MetaAction>> actionChain = executableAction.getActionChain();
return; int targetOrder = nextAvailableOrder(actionChain, order + 1);
actionChain.put(targetOrder, actions);
}
executableAction.getActionChain().put(order, actions); private int nextAvailableOrder(Map<Integer, List<MetaAction>> actionChain, int startOrder) {
int order = startOrder;
while (actionChain.containsKey(order)) {
order++;
}
return order;
} }
/** /**
@@ -31,7 +31,7 @@ public class ActionCorrector extends AbstractAgentModule.Sub<CorrectorInput, Res
- 一条任务消息,其中包含: - 一条任务消息,其中包含:
- check_mode:当前纠偏模式,PROCESS_CHECK 表示过程纠偏,FINAL_CHECK 表示链路末尾目标未满足后的补救; - check_mode:当前纠偏模式,PROCESS_CHECK 表示过程纠偏,FINAL_CHECK 表示链路末尾目标未满足后的补救;
- executable_action_info:当前正在执行的行动信息,包括 executing_action_id、original_tendency、evaluation_passed_reason、description 与 from_who; - executable_action_info:当前正在执行的行动信息,包括 executing_action_id、original_tendency、evaluation_passed_reason、description 与 from_who;
- current_action_chain_overview:当前行动链概览,按 stage_count 分组,包含各阶段已有 meta_action 的 action_key、description、status 与 result。 - current_action_chain_overview:当前行动链概览,按 stage_count 分组,包含各阶段已有 meta_action 的 action_key、description、stage_description、status 与 result;stage_description 是该阶段的具体执行目标,description 是 MetaAction 的通用能力说明。
- available_meta_action:当前系统真实可用的 MetaAction 候选,包含 meta_action_key 与 meta_action_description。 - available_meta_action:当前系统真实可用的 MetaAction 候选,包含 meta_action_key 与 meta_action_description。
你的任务: 你的任务:
@@ -125,6 +125,9 @@ public class ActionCorrector extends AbstractAgentModule.Sub<CorrectorInput, Res
appendRepeatedElements(document, stageElement, "meta_action", stageData.getValue(), (metaActionElement, metaActionData) -> { appendRepeatedElements(document, stageElement, "meta_action", stageData.getValue(), (metaActionElement, metaActionData) -> {
appendTextElement(document, metaActionElement, "action_key", metaActionData.getActionKey()); appendTextElement(document, metaActionElement, "action_key", metaActionData.getActionKey());
appendTextElement(document, metaActionElement, "description", metaActionData.getDescription()); appendTextElement(document, metaActionElement, "description", metaActionData.getDescription());
if (metaActionData.getStageDescription() != null && !metaActionData.getStageDescription().isBlank()) {
appendTextElement(document, metaActionElement, "stage_description", metaActionData.getStageDescription());
}
appendTextElement(document, metaActionElement, "status", metaActionData.getStatus()); appendTextElement(document, metaActionElement, "status", metaActionData.getStatus());
appendTextElement(document, metaActionElement, "result", metaActionData.getResult()); appendTextElement(document, metaActionElement, "result", metaActionData.getResult());
return Unit.INSTANCE; return Unit.INSTANCE;
@@ -155,7 +155,6 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
actionCapability.putAction(executableAction); actionCapability.putAction(executableAction);
val actionChain = executableAction.getActionChain(); val actionChain = executableAction.getActionChain();
val phaser = new Phaser();
if (!prepareExecutableAction(executableAction, actionChain)) { if (!prepareExecutableAction(executableAction, actionChain)) {
return; return;
} }
@@ -172,7 +171,7 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
if (stageSelection.shouldStop()) { if (stageSelection.shouldStop()) {
break; break;
} }
val stageExecution = runCurrentStage(executableAction, phaser, stageCursor, stageSelection.metaActions()); val stageExecution = runCurrentStage(executableAction, stageCursor, stageSelection.metaActions());
if (stageExecution.closed()) { if (stageExecution.closed()) {
return; return;
} }
@@ -225,10 +224,10 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
private StageExecution runCurrentStage( private StageExecution runCurrentStage(
ExecutableAction executableAction, ExecutableAction executableAction,
Phaser phaser,
StageCursor stageCursor, StageCursor stageCursor,
List<MetaAction> metaActions List<MetaAction> metaActions
) { ) {
Phaser phaser = new Phaser();
val recognizerRecord = startRecognizerIfNeeded(executableAction, phaser); val recognizerRecord = startRecognizerIfNeeded(executableAction, phaser);
val listeningRecord = executeAndListening(metaActions, phaser, executableAction); val listeningRecord = executeAndListening(metaActions, phaser, executableAction);
phaser.awaitAdvance(listeningRecord.phase()); phaser.awaitAdvance(listeningRecord.phase());
@@ -775,6 +774,7 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
.map(metaAction -> new CorrectorInput.ActionChainItem( .map(metaAction -> new CorrectorInput.ActionChainItem(
metaAction.getKey(), metaAction.getKey(),
resolveHistoryDescription(metaAction.getKey()), resolveHistoryDescription(metaAction.getKey()),
executableAction.getStageDescriptions().get(stage),
metaAction.getResult().getStatus().name().toLowerCase(Locale.ROOT), metaAction.getResult().getStatus().name().toLowerCase(Locale.ROOT),
metaAction.getResult().getData() metaAction.getResult().getData()
)) ))
@@ -29,6 +29,7 @@ public class CorrectorInput {
public static class ActionChainItem { public static class ActionChainItem {
private String actionKey; private String actionKey;
private String description; private String description;
private String stageDescription;
private String status; private String status;
private String result; private String result;
} }
@@ -279,7 +279,7 @@ public class ActionPlanner extends AbstractAgentModule.Running<PartnerRunningFlo
if (actionChain == null) { if (actionChain == null) {
return null; return null;
} }
return switch (evaluatorResult.getType()) { ExecutableAction executableAction = switch (evaluatorResult.getType()) {
case PLANNING -> new SchedulableExecutableAction( case PLANNING -> new SchedulableExecutableAction(
evaluatorResult.getTendency(), evaluatorResult.getTendency(),
actionChain, actionChain,
@@ -297,6 +297,27 @@ public class ActionPlanner extends AbstractAgentModule.Running<PartnerRunningFlo
userId userId
); );
}; };
executableAction.getStageDescriptions().putAll(getStageDescriptions(evaluatorResult));
return executableAction;
}
private Map<Integer, String> getStageDescriptions(EvaluatorResult evaluatorResult) {
Map<Integer, String> descriptions = new HashMap<>();
List<EvaluatorResult.ChainElement> primaryActionChain = evaluatorResult.getPrimaryActionChain();
if (primaryActionChain == null || primaryActionChain.isEmpty()) {
return descriptions;
}
List<EvaluatorResult.ChainElement> orderedChain = new ArrayList<>(primaryActionChain);
orderedChain.sort(Comparator.comparing(EvaluatorResult.ChainElement::getOrder, Comparator.nullsLast(Integer::compareTo)));
int fixedOrder = 1;
for (EvaluatorResult.ChainElement chainElement : orderedChain) {
String description = chainElement.getDescription();
if (description != null && !description.isBlank()) {
descriptions.put(fixedOrder, description);
}
fixedOrder++;
}
return descriptions;
} }
private Map<Integer, List<MetaAction>> getActionChain(EvaluatorResult evaluatorResult) { private Map<Integer, List<MetaAction>> getActionChain(EvaluatorResult evaluatorResult) {