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

View File

@@ -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;
} }
/** /**

View File

@@ -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 与 resultstage_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;

View File

@@ -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()
)) ))

View File

@@ -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;
} }

View File

@@ -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) {