diff --git a/Partner-Core/src/main/java/work/slhaf/partner/module/modules/action/executor/ExecutingActionBlockManager.java b/Partner-Core/src/main/java/work/slhaf/partner/module/modules/action/executor/ExecutingActionBlockManager.java new file mode 100644 index 00000000..f410bc5c --- /dev/null +++ b/Partner-Core/src/main/java/work/slhaf/partner/module/modules/action/executor/ExecutingActionBlockManager.java @@ -0,0 +1,370 @@ +package work.slhaf.partner.module.modules.action.executor; + +import kotlin.Unit; +import org.jetbrains.annotations.NotNull; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import work.slhaf.partner.core.action.entity.*; +import work.slhaf.partner.core.action.entity.intervention.MetaIntervention; +import work.slhaf.partner.core.cognition.BlockContent; +import work.slhaf.partner.core.cognition.ContextBlock; +import work.slhaf.partner.core.cognition.ContextWorkspace; +import work.slhaf.partner.module.modules.action.executor.entity.HistoryAction; + +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Locale; +import java.util.Set; +import java.util.stream.Collectors; + +class ExecutingActionBlockManager { + + private static final String SOURCE = "action_executor"; + + private final ContextWorkspace contextWorkspace; + + ExecutingActionBlockManager(ContextWorkspace contextWorkspace) { + this.contextWorkspace = contextWorkspace; + } + + void emitStateActionTriggeredBlock(StateAction stateAction) { + StateActionSnapshot snapshot = stateAction.snapshot(); + + String blockName = buildBlockName(stateAction.getUuid()); + String emittedAt = emittedAt(); + String event = "state_action_triggered"; + + contextWorkspace.register(new ContextBlock( + buildStateActionFullBlock(snapshot, blockName, emittedAt, event), + buildStateActionCompactBlock(snapshot, blockName, emittedAt, event), + buildStateActionAbstractBlock(snapshot, blockName, event), + Set.of(ContextBlock.VisibleDomain.ACTION), + 70, + 18, + 10 + )); + } + + private @NotNull BlockContent buildStateActionAbstractBlock(StateActionSnapshot snapshot, String blockName, String event) { + return new ActionBlockContent(blockName, SOURCE) { + @Override + protected void fillXml(@NotNull Document document, @NotNull Element root) { + appendEventElement(document, root, event); + appendTextElement(document, root, "description", snapshot.getDescription()); + } + }; + } + + private @NotNull BlockContent buildStateActionCompactBlock(StateActionSnapshot snapshot, String blockName, String emittedAt, String event) { + return new ActionBlockContent(blockName, SOURCE) { + @Override + protected void fillXml(@NotNull Document document, @NotNull Element root) { + appendEventElement(document, root, event); + appendTextElement(document, root, "emitted_at", emittedAt); + appendTextElement(document, root, "reason", snapshot.getReason()); + appendTextElement(document, root, "description", snapshot.getDescription()); + } + }; + } + + private @NotNull BlockContent buildStateActionFullBlock(StateActionSnapshot snapshot, String blockName, String emittedAt, String event) { + return new ActionBlockContent(blockName, SOURCE) { + @Override + protected void fillXml(@NotNull Document document, @NotNull Element root) { + appendEventElement(document, root, event); + appendTextElement(document, root, "emitted_at", emittedAt); + appendTextElement(document, root, "reason", snapshot.getReason()); + appendTextElement(document, root, "description", snapshot.getDescription()); + appendTextElement(document, root, "source", snapshot.getSource()); + appendTextElement(document, root, "schedule_type", snapshot.getScheduleType().name().toLowerCase(Locale.ROOT)); + } + }; + } + + void emitActionLaunchedBlock(ExecutableAction action) { + ExecutableActionSnapshot snapshot = action.snapshot(); + + String blockName = buildBlockName(action.getUuid()); + String emittedAt = emittedAt(); + String event = "executable_action_launched"; + + contextWorkspace.register(new ContextBlock( + buildActionLaunchedFullBlock(snapshot, blockName, event, emittedAt), + buildActionCompactBlock(snapshot, blockName, event, emittedAt), + buildActionAbstractBlock(snapshot, blockName, event), + Set.of(ContextBlock.VisibleDomain.ACTION), + 28, + 6, + 18 + )); + + } + + private @NotNull BlockContent buildActionAbstractBlock(ExecutableActionSnapshot snapshot, String blockName, String event) { + return new ActionBlockContent(blockName, SOURCE) { + @Override + protected void fillXml(@NotNull Document document, @NotNull Element root) { + appendEventElement(document, root, event); + appendTextElement(document, root, "description", snapshot.getDescription()); + } + }; + } + + private @NotNull BlockContent buildActionCompactBlock(ExecutableActionSnapshot snapshot, String blockName, String event, String emittedAt) { + return new ActionBlockContent(blockName, SOURCE) { + @Override + protected void fillXml(@NotNull Document document, @NotNull Element root) { + appendEventElement(document, root, event); + appendTextElement(document, root, "emitted_at", emittedAt); + appendTextElement(document, root, "primary_action_chain_size", snapshot.getActionChainSize()); + appendTextElement(document, root, "reason", snapshot.getReason()); + appendTextElement(document, root, "description", snapshot.getDescription()); + + Schedulable.ScheduleType scheduleType = snapshot.getScheduleType(); + String scheduleContent = snapshot.getScheduleContent(); + + if (scheduleType != null && scheduleContent != null) { + appendChildElement(document, root, "schedule_info", (element) -> { + appendTextElement(document, element, "schedule_type", scheduleType.name().toLowerCase(Locale.ROOT)); + appendTextElement(document, element, "schedule_content", scheduleContent); + return Unit.INSTANCE; + }); + } + } + }; + } + + private @NotNull BlockContent buildActionLaunchedFullBlock(ExecutableActionSnapshot snapshot, String blockName, String event, String emittedAt) { + return new ActionBlockContent(blockName, SOURCE) { + @Override + protected void fillXml(@NotNull Document document, @NotNull Element root) { + appendEventElement(document, root, event); + appendTextElement(document, root, "emitted_at", emittedAt); + appendTextElement(document, root, "primary_action_chain_size", snapshot.getActionChainSize()); + appendTextElement(document, root, "reason", snapshot.getReason()); + appendTextElement(document, root, "description", snapshot.getDescription()); + appendTextElement(document, root, "source", snapshot.getSource()); + appendTextElement(document, root, "tendency", snapshot.getTendency()); + + Schedulable.ScheduleType scheduleType = snapshot.getScheduleType(); + String scheduleContent = snapshot.getScheduleContent(); + + if (scheduleType != null && scheduleContent != null) { + appendChildElement(document, root, "schedule_info", (element) -> { + appendTextElement(document, element, "schedule_type", scheduleType.name().toLowerCase(Locale.ROOT)); + appendTextElement(document, element, "schedule_content", scheduleContent); + return Unit.INSTANCE; + }); + } + } + }; + } + + void emitActionStageSettledBlock(ExecutableAction action) { + ExecutableActionSnapshot snapshot = action.snapshot(); + + String blockName = buildBlockName(action.getUuid()); + String emittedAt = emittedAt(); + String event = "executable_action_stage_settled"; + + contextWorkspace.register(new ContextBlock( + buildActionStageFullBlock(snapshot, blockName, emittedAt, event), + buildActionStageCompactBlock(snapshot, blockName, emittedAt, event), + buildActionStageAbstractBlock(snapshot, blockName, event), + Set.of(ContextBlock.VisibleDomain.ACTION), + 55, + 10, + 12 + )); + } + + private @NotNull BlockContent buildActionStageAbstractBlock(ExecutableActionSnapshot snapshot, String blockName, String event) { + int settledStage = snapshot.getExecutingStage(); + List history = snapshot.getHistory().get(settledStage); + + return new ActionBlockContent(blockName, SOURCE) { + @Override + protected void fillXml(@NotNull Document document, @NotNull Element root) { + appendEventElement(document, root, event); + appendTextElement(document, root, "abstract", history.size() + " meta actions are resolved in stage " + settledStage); + } + }; + } + + private @NotNull BlockContent buildActionStageCompactBlock(ExecutableActionSnapshot snapshot, String blockName, String emittedAt, String event) { + int settledStage = snapshot.getExecutingStage(); + List history = snapshot.getHistory().get(settledStage); + + return new ActionBlockContent(blockName, SOURCE) { + @Override + protected void fillXml(@NotNull Document document, @NotNull Element root) { + appendEventElement(document, root, event); + appendTextElement(document, root, "emitted_at", emittedAt); + appendTextElement(document, root, "action_chain_size", snapshot.getActionChainSize()); + appendTextElement(document, root, "abstract", history.size() + " meta actions are resolved in stage " + settledStage); + } + }; + } + + private @NotNull BlockContent buildActionStageFullBlock(ExecutableActionSnapshot snapshot, String blockName, String emittedAt, String event) { + int settledStage = snapshot.getExecutingStage(); + List history = snapshot.getHistory().get(settledStage); + + return new ActionBlockContent(blockName, SOURCE) { + @Override + protected void fillXml(@NotNull Document document, @NotNull Element root) { + appendEventElement(document, root, event); + appendTextElement(document, root, "emitted_at", emittedAt); + appendTextElement(document, root, "action_chain_size", snapshot.getActionChainSize()); + appendTextElement(document, root, "settled_action_chain_stage", settledStage); + appendListElement(document, + root, + "settled_meta_actions", + "meta_action", + history.subList(0, Math.min(3, history.size())), + (item, action) -> { + String primaryResult = action.result(); + String result = primaryResult.length() > 160 ? primaryResult.substring(0, 160) : primaryResult; + + appendTextElement(document, item, "action_key", action.actionKey()); + appendTextElement(document, item, "result", result); + return Unit.INSTANCE; + } + ); + } + }; + } + + void emitActionCorrectionBlock(ExecutableAction action, String reason, List interventions) { + ExecutableActionSnapshot snapshot = action.snapshot(); + + String blockName = buildBlockName(action.getUuid()); + String emittedAt = emittedAt(); + String event = "executable_action_correction_triggered"; + + contextWorkspace.register(new ContextBlock( + buildActionCorrectionFullBlock(snapshot, reason, interventions, blockName, emittedAt, event), + buildActionCorrectionCompactBlock(snapshot, reason, interventions, blockName, emittedAt, event), + buildActionCorrectionAbstractBlock(snapshot, interventions, blockName, event), + Set.of(ContextBlock.VisibleDomain.ACTION), + 22, + 5, + 22 + )); + } + + private @NotNull BlockContent buildActionCorrectionAbstractBlock(ExecutableActionSnapshot snapshot, List interventions, String blockName, String event) { + return new ActionBlockContent(blockName, SOURCE) { + @Override + protected void fillXml(@NotNull Document document, @NotNull Element root) { + appendEventElement(document, root, event); + appendTextElement(document, root, "abstract", interventions.size() + " interventions occurred after stage " + snapshot.getExecutingStage()); + } + }; + } + + private @NotNull BlockContent buildActionCorrectionCompactBlock(ExecutableActionSnapshot snapshot, String reason, List interventions, String blockName, String emittedAt, String event) { + return new ActionBlockContent(blockName, SOURCE, BlockContent.Urgency.HIGH) { + @Override + protected void fillXml(@NotNull Document document, @NotNull Element root) { + Set affectedStage = interventions.stream().map(MetaIntervention::getOrder).collect(Collectors.toSet()); + + appendEventElement(document, root, event); + appendTextElement(document, root, "emitted_at", emittedAt); + appendTextElement(document, root, "action_chain_size", snapshot.getActionChainSize()); + appendTextElement(document, root, "abstract", interventions.size() + " interventions occurred after stage " + snapshot.getExecutingStage() + ", stage: " + affectedStage + " are affected"); + appendTextElement(document, root, "correction_reason", reason); + } + }; + } + + private @NotNull BlockContent buildActionCorrectionFullBlock(ExecutableActionSnapshot snapshot, String reason, List interventions, String blockName, String emittedAt, String event) { + return new ActionBlockContent(blockName, SOURCE, BlockContent.Urgency.HIGH) { + @Override + protected void fillXml(@NotNull Document document, @NotNull Element root) { + appendEventElement(document, root, event); + appendTextElement(document, root, "emitted_at", emittedAt); + appendTextElement(document, root, "action_chain_size", snapshot.getActionChainSize()); + appendTextElement(document, root, "correction_reason", reason); + appendListElement(document, + root, + "applied_interventions", + "intervention", + interventions, + (item, intervention) -> { + appendTextElement(document, item, "type", intervention.getType().name().toLowerCase(Locale.ROOT)); + appendTextElement(document, item, "affected_stage", intervention.getOrder()); + appendTextElement(document, item, "applied_action_key_set", intervention.getActions()); + return Unit.INSTANCE; + } + ); + } + }; + } + + void emitActionFinishedBlock(ExecutableAction action) { + ExecutableActionSnapshot snapshot = action.snapshot(); + + String blockName = buildBlockName(action.getUuid()); + String emittedAt = emittedAt(); + String event = "executable_action_finished"; + + contextWorkspace.register(new ContextBlock( + buildActionFinishedFullBlock(snapshot, blockName, emittedAt, event), + buildActionFinishedFullBlock(snapshot, blockName, emittedAt, event), + buildActionFinishedAbstractBlock(snapshot, blockName, event), + Set.of(ContextBlock.VisibleDomain.ACTION), + 35, + 14, + 24 + )); + } + + private @NotNull BlockContent buildActionFinishedAbstractBlock(ExecutableActionSnapshot snapshot, String blockName, String event) { + return new ActionBlockContent(blockName, SOURCE) { + @Override + protected void fillXml(@NotNull Document document, @NotNull Element root) { + appendEventElement(document, root, event); + appendTextElement(document, root, "final_status", snapshot.getStatus().name().toLowerCase(Locale.ROOT)); + } + }; + } + + private @NotNull BlockContent buildActionFinishedFullBlock(ExecutableActionSnapshot snapshot, String blockName, String emittedAt, String event) { + return new ActionBlockContent(blockName, SOURCE, BlockContent.Urgency.HIGH) { + @Override + protected void fillXml(@NotNull Document document, @NotNull Element root) { + appendEventElement(document, root, event); + appendTextElement(document, root, "emitted_at", emittedAt); + appendTextElement(document, root, "final_status", snapshot.getStatus().name().toLowerCase(Locale.ROOT)); + appendTextElement(document, root, "result", snapshot.getResult()); + } + }; + } + + private String emittedAt() { + return ZonedDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + } + + private String buildBlockName(String actionId) { + return "executing_action-" + actionId; + } + + + private static abstract class ActionBlockContent extends BlockContent { + + private ActionBlockContent(@NotNull String blockName, @NotNull String source, @NotNull Urgency urgency) { + super(blockName, source, urgency); + } + + private ActionBlockContent(@NotNull String blockName, @NotNull String source) { + super(blockName, source); + } + + protected void appendEventElement(@NotNull Document document, @NotNull Element root, String event) { + appendTextElement(document, root, "event", event); + } + } + +}