Fix generated-mode executor reruns and dashboard flow

This commit is contained in:
axiomlogicnexus 2026-05-06 00:22:12 +02:00
parent 4cc10edf4d
commit 4d50ffaba4
5 changed files with 536 additions and 8 deletions

View file

@ -10,6 +10,7 @@
#include "Components/VerticalBox.h"
#include "Components/VerticalBoxSlot.h"
#include "HAL/PlatformTime.h"
#include "HyperTwistTraining/HyperTwistTrainingRuntimeLibrary.h"
namespace HyperTwistCoachDashboardWidgetInternal
{
@ -35,6 +36,27 @@ namespace HyperTwistCoachDashboardWidgetInternal
Weak
};
bool ContainsTagIgnoreCase(const TArray<FString>& Tags, const FString& ExpectedTag)
{
return Tags.ContainsByPredicate(
[&ExpectedTag](const FString& Candidate)
{
return Candidate.Equals(ExpectedTag, ESearchCase::IgnoreCase);
}
);
}
bool IsGeneratedModeLaunchDeck(const FHyperTwistTrainingRunState& RunState)
{
return RunState.ActiveDeck.IsStructurallyValid()
&& RunState.ActiveDeck.ImportedRuntimeSurface.IsStructurallyValid()
&& RunState.ActiveDeck.ImportedRuntimeSurface.SurfaceKind.Equals(
TEXT("generated-mode"),
ESearchCase::IgnoreCase
)
&& !ContainsTagIgnoreCase(RunState.ActiveDeck.Tags, TEXT("generated-mode:owned-execution"));
}
struct FHandoffHistoryDashboardBias
{
int32 QueueAcceptedDeltaCount = 0;
@ -3648,7 +3670,26 @@ FHyperTwistTrainingRunStepResult UHyperTwistCoachDashboardWidget::SubmitSyntheti
bool UHyperTwistCoachDashboardWidget::ContinueCurrentRunFlow()
{
bool bSucceeded = false;
if (CachedRunState.Session.IsStructurallyValid() && CachedRunState.CurrentSelection.TrainingCase.IsStructurallyValid())
if (HyperTwistCoachDashboardWidgetInternal::IsGeneratedModeLaunchDeck(CachedRunState))
{
FHyperTwistTrainingRunState RunState;
FString BlockedReason;
bSucceeded = UHyperTwistTrainingRuntimeLibrary::TryExecuteActiveImportedGeneratedModeLaunchRequest(
this,
RunState,
BlockedReason
);
if (bSucceeded)
{
LastStepResult = FHyperTwistTrainingRunStepResult();
RefreshTrainingState();
SyncRetainedRunRecap();
SyncSelectedQueueEntry();
SyncSelectedAttempt();
UpdateDashboardPresentation();
}
}
else if (CachedRunState.Session.IsStructurallyValid() && CachedRunState.CurrentSelection.TrainingCase.IsStructurallyValid())
{
bSucceeded = StartLiveAttemptTimer();
}
@ -10203,9 +10244,25 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
== EHyperTwistTrainingSessionState::Aborted);
const bool bHasNextCaseFromLastStep = bHasSessionScopedLastStep
&& LastStepResult.AttemptResolution.NextCaseSelection.IsStructurallyValid();
const bool bGeneratedModeLaunchDeck =
HyperTwistCoachDashboardWidgetInternal::IsGeneratedModeLaunchDeck(CachedRunState);
const bool bCanExecuteGeneratedModeLaunch = [this, bGeneratedModeLaunchDeck]()
{
if (!bGeneratedModeLaunchDeck)
{
return false;
}
FHyperTwistTrainingImportedGeneratedModeLaunchConfig ActiveGeneratedModeLaunchConfig;
return UHyperTwistTrainingRuntimeLibrary::TryGetActiveImportedGeneratedModeLaunchConfig(
this,
ActiveGeneratedModeLaunchConfig
);
}();
const bool bCanContinueCurrentRun = !bHasLiveAttemptTimer
&& bHasRunnableCurrentCase
&& !bLastStepCompletedRun;
&& !bLastStepCompletedRun
&& (!bGeneratedModeLaunchDeck || bCanExecuteGeneratedModeLaunch);
const bool bCanLaunchCoachRun = !bHasLiveAttemptTimer
&& (
CachedCoachPanelState.bCanStartQueuedRun
@ -10249,13 +10306,25 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
);
}
}
else if (bGeneratedModeLaunchDeck && !bCanExecuteGeneratedModeLaunch)
{
TransitionStatusLine =
TEXT("Transition: generated-mode selectors are still incomplete. Finish the active selector choices before executing the owned generated run.");
}
else if (bCanContinueCurrentRun)
{
const FHyperTwistTrainingCase& TransitionCase = CachedRunState.CurrentSelection.TrainingCase;
const FString TransitionPrompt = TransitionCase.PromptLabel.IsEmpty()
? ActiveCaseId
: TransitionCase.PromptLabel;
if (bHasNextCaseFromLastStep)
if (bGeneratedModeLaunchDeck)
{
TransitionStatusLine = FString::Printf(
TEXT("Transition: generated-mode request is staged on %s. Execute the owned generated run when ready."),
*TransitionPrompt
);
}
else if (bHasNextCaseFromLastStep)
{
TransitionStatusLine = FString::Printf(
TEXT("Transition: next case loaded after the last attempt. Continue the run to begin %s."),
@ -10296,11 +10365,13 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
}
const FString ContinueRunLabel = bHasLiveAttemptTimer
? (bLiveInspectionPhase ? TEXT("Start Solve") : TEXT("Attempt Active"))
: (bHasNextCaseFromLastStep
? TEXT("Continue Run")
: (bCanContinueCurrentRun
? (CachedRunSummary.AttemptCount > 0 ? TEXT("Start Next Attempt") : TEXT("Start First Attempt"))
: TransitionLaunchLabel));
: (bGeneratedModeLaunchDeck
? (bCanExecuteGeneratedModeLaunch ? TEXT("Execute Generated Run") : TEXT("Resolve Selectors"))
: (bHasNextCaseFromLastStep
? TEXT("Continue Run")
: (bCanContinueCurrentRun
? (CachedRunSummary.AttemptCount > 0 ? TEXT("Start Next Attempt") : TEXT("Start First Attempt"))
: TransitionLaunchLabel)));
const bool bHasMethodDrillRun = CachedMethodDrillRunState.IsStructurallyValid();
const bool bHasMethodDrillDiagnosticPacket = CachedMethodDrillDiagnosticPacket.IsStructurallyValid();
const bool bHasMethodDrillFollowUpTemplate = CachedMethodDrillFollowUpTemplate.IsStructurallyValid();

View file

@ -157,6 +157,25 @@ FHyperTwistTrainingImportedGeneratedModeLaunchRequest UHyperTwistTrainingRuntime
return FHyperTwistTrainingImportedGeneratedModeLaunchRequest();
}
bool UHyperTwistTrainingRuntimeLibrary::TryExecuteActiveImportedGeneratedModeLaunchRequest(
UObject* WorldContextObject,
FHyperTwistTrainingRunState& OutRunState,
FString& OutBlockedReason
)
{
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
{
return TrainingSubsystem->TryExecuteActiveImportedGeneratedModeLaunchRequest(
OutRunState,
OutBlockedReason
);
}
OutRunState = FHyperTwistTrainingRunState();
OutBlockedReason = TEXT("Training subsystem was unavailable.");
return false;
}
FHyperTwistTrainingRunState UHyperTwistTrainingRuntimeLibrary::ApplyActiveImportedRuntimeSelectorOption(
UObject* WorldContextObject,
const FString& SelectorId,

View file

@ -155,6 +155,258 @@ namespace HyperTwistTrainingSubsystemInternal
return SelectorParts.Num() > 0 ? FString::Join(SelectorParts, TEXT(" | ")) : TEXT("no selector choices");
}
FString SanitizeGeneratedModeToken(const FString& Value)
{
FString Sanitized;
Sanitized.Reserve(Value.Len());
for (const TCHAR Character : Value)
{
if (FChar::IsAlnum(Character))
{
Sanitized.AppendChar(FChar::ToLower(Character));
}
else if (Sanitized.IsEmpty() || Sanitized[Sanitized.Len() - 1] != TEXT('-'))
{
Sanitized.AppendChar(TEXT('-'));
}
}
while (Sanitized.StartsWith(TEXT("-")))
{
Sanitized.RightChopInline(1, EAllowShrinking::No);
}
while (Sanitized.EndsWith(TEXT("-")))
{
Sanitized.LeftChopInline(1, EAllowShrinking::No);
}
return Sanitized.IsEmpty() ? TEXT("value") : Sanitized;
}
const FHyperTwistTrainingCase* FindFirstStructurallyValidCase(const FHyperTwistTrainingDeck& Deck)
{
return Deck.Cases.FindByPredicate(
[](const FHyperTwistTrainingCase& Candidate)
{
return Candidate.IsStructurallyValid();
}
);
}
EHyperTwistTrainingPromptKind ResolveGeneratedModePromptKind(
const FHyperTwistTrainingCase& SeedCase,
const FHyperTwistTrainingImportedGeneratedModeLaunchRequest& LaunchRequest
)
{
const FString RuntimeModeId = LaunchRequest.LaunchConfig.RuntimeModeId.ToLower();
const FString GeneratorType = LaunchRequest.LaunchConfig.GeneratorType.ToLower();
if (RuntimeModeId.Contains(TEXT("recognition")) || GeneratorType.Contains(TEXT("recognition")))
{
return EHyperTwistTrainingPromptKind::Recognition;
}
if (RuntimeModeId.Contains(TEXT("state"))
|| GeneratorType.Contains(TEXT("state"))
|| RuntimeModeId.Contains(TEXT("scramble"))
|| GeneratorType.Contains(TEXT("scramble")))
{
return EHyperTwistTrainingPromptKind::State;
}
if ((SeedCase.PromptKind == EHyperTwistTrainingPromptKind::Algorithm
|| SeedCase.PromptKind == EHyperTwistTrainingPromptKind::Sequence
|| SeedCase.PromptKind == EHyperTwistTrainingPromptKind::Memo)
&& SeedCase.CanonicalNotation.IsEmpty())
{
return EHyperTwistTrainingPromptKind::State;
}
return SeedCase.PromptKind;
}
FString BuildGeneratedModeExecutionSessionId(
const FHyperTwistTrainingImportedGeneratedModeLaunchRequest& LaunchRequest
)
{
const FString BaseSessionId = !LaunchRequest.LaunchConfig.TrainingSessionId.IsEmpty()
? LaunchRequest.LaunchConfig.TrainingSessionId
: TEXT("generated-mode");
const FString ExecutionToken = FGuid::NewGuid().ToString(EGuidFormats::Digits).ToLower();
return FString::Printf(
TEXT("%s__generated__%s__%s"),
*BaseSessionId,
*SanitizeGeneratedModeToken(LaunchRequest.RequestId),
*ExecutionToken
);
}
FString BuildGeneratedModeCanonicalStateRef(
const FHyperTwistTrainingImportedGeneratedModeLaunchRequest& LaunchRequest
)
{
const FString SurfaceToken = SanitizeGeneratedModeToken(LaunchRequest.LaunchConfig.SurfaceId);
const FString RuntimeToken = SanitizeGeneratedModeToken(LaunchRequest.LaunchConfig.RuntimeModeId);
const FString RequestToken = SanitizeGeneratedModeToken(LaunchRequest.RequestId);
return FString::Printf(
TEXT("generated-mode/%s/%s/%s"),
*SurfaceToken,
*RuntimeToken,
*RequestToken
);
}
bool TryBuildGeneratedModeExecutionDeck(
const FHyperTwistTrainingDeck& SourceDeck,
const FHyperTwistTrainingImportedGeneratedModeLaunchRequest& LaunchRequest,
FHyperTwistTrainingDeck& OutDeck,
FString& OutBlockedReason
)
{
OutDeck = FHyperTwistTrainingDeck();
OutBlockedReason.Reset();
if (!SourceDeck.IsStructurallyValid())
{
OutBlockedReason = TEXT("Generated-mode executor requires a structurally valid source deck.");
return false;
}
if (!LaunchRequest.IsStructurallyValid())
{
OutBlockedReason = TEXT("Generated-mode executor requires a structurally valid launch request.");
return false;
}
const FHyperTwistTrainingCase* SeedCase = FindFirstStructurallyValidCase(SourceDeck);
if (SeedCase == nullptr)
{
OutBlockedReason = TEXT("Generated-mode executor could not find a structurally valid source case.");
return false;
}
const FString SelectorSummary = FormatGeneratedModeSelectorSummary(SourceDeck, LaunchRequest);
const FString PromptBaseLabel = !LaunchRequest.LaunchConfig.SurfaceLabel.IsEmpty()
? LaunchRequest.LaunchConfig.SurfaceLabel
: SourceDeck.Title;
const FString CaseExecutionNote = FString::Printf(
TEXT("Owned generated-mode execution case produced from request %s."),
*LaunchRequest.RequestId
);
const FString DeckExecutionNote = FString::Printf(
TEXT("Owned generated-mode execution deck produced from request %s."),
*LaunchRequest.RequestId
);
FHyperTwistTrainingCase GeneratedCase = *SeedCase;
GeneratedCase.CaseId = FString::Printf(
TEXT("%s/generated/%s"),
*SourceDeck.DeckId,
*SanitizeGeneratedModeToken(LaunchRequest.RequestId)
);
GeneratedCase.PuzzleId = !LaunchRequest.LaunchConfig.PuzzleId.IsEmpty()
? LaunchRequest.LaunchConfig.PuzzleId
: SeedCase->PuzzleId;
GeneratedCase.PromptKind = ResolveGeneratedModePromptKind(*SeedCase, LaunchRequest);
GeneratedCase.PromptLabel = !PromptBaseLabel.IsEmpty() && !SelectorSummary.IsEmpty()
? FString::Printf(
TEXT("%s | %s"),
*PromptBaseLabel,
*SelectorSummary
)
: PromptBaseLabel;
GeneratedCase.CanonicalStateRef = BuildGeneratedModeCanonicalStateRef(LaunchRequest);
GeneratedCase.CanonicalNotation.Reset();
GeneratedCase.AlternateNotations.Reset();
GeneratedCase.ScrambleNotation.Reset();
GeneratedCase.SubsetId = SourceDeck.SubsetId;
GeneratedCase.Difficulty = SeedCase->Difficulty;
GeneratedCase.Tags = SeedCase->Tags;
GeneratedCase.Tags.AddUnique(TEXT("runtime-surface:generated-mode"));
GeneratedCase.Tags.AddUnique(TEXT("generated-mode:owned-execution"));
GeneratedCase.Tags.AddUnique(
FString::Printf(
TEXT("generated-request:%s"),
*SanitizeGeneratedModeToken(LaunchRequest.RequestId)
)
);
GeneratedCase.Tags.AddUnique(
FString::Printf(
TEXT("generated-surface:%s"),
*SanitizeGeneratedModeToken(LaunchRequest.LaunchConfig.SurfaceId)
)
);
for (const FHyperTwistTrainingImportedRuntimeSelectorChoice& Choice : LaunchRequest.LaunchConfig.SelectorChoices)
{
if (!Choice.IsStructurallyValid())
{
continue;
}
GeneratedCase.Tags.AddUnique(
FString::Printf(
TEXT("generated-selector:%s=%s"),
*SanitizeGeneratedModeToken(Choice.SelectorId),
*SanitizeGeneratedModeToken(Choice.SelectedValue)
)
);
}
GeneratedCase.AllowedDeliveryModes = SeedCase->AllowedDeliveryModes;
if (GeneratedCase.AllowedDeliveryModes.Num() == 0)
{
GeneratedCase.AllowedDeliveryModes = SourceDeck.DeliveryModes;
}
GeneratedCase.AllowedDeliveryModes.AddUnique(LaunchRequest.LaunchConfig.DeliveryMode);
GeneratedCase.TimeTargetMs = SeedCase->TimeTargetMs;
GeneratedCase.SourceAttribution = SeedCase->SourceAttribution.IsStructurallyValid()
? SeedCase->SourceAttribution
: SourceDeck.SourceAttribution;
if (GeneratedCase.SourceAttribution.SourceCaseId.IsEmpty())
{
GeneratedCase.SourceAttribution.SourceCaseId = SeedCase->CaseId;
}
GeneratedCase.SourceAttribution.SourceNotes = GeneratedCase.SourceAttribution.SourceNotes.IsEmpty()
? CaseExecutionNote
: FString::Printf(
TEXT("%s | %s"),
*GeneratedCase.SourceAttribution.SourceNotes,
*CaseExecutionNote
);
OutDeck = SourceDeck;
OutDeck.SelectionPolicy = EHyperTwistTrainingSelectionPolicy::Scripted;
OutDeck.Title = !SourceDeck.Title.IsEmpty()
? SourceDeck.Title
: (!LaunchRequest.LaunchConfig.SurfaceLabel.IsEmpty()
? LaunchRequest.LaunchConfig.SurfaceLabel
: TEXT("Generated mode deck"));
OutDeck.bSupportsAlgorithmReveal =
SourceDeck.bSupportsAlgorithmReveal && !GeneratedCase.CanonicalNotation.IsEmpty();
OutDeck.Cases.Reset();
OutDeck.Cases.Add(GeneratedCase);
OutDeck.Tags.AddUnique(TEXT("runtime-surface:generated-mode"));
OutDeck.Tags.AddUnique(TEXT("generated-mode:owned-execution"));
OutDeck.Tags.AddUnique(
FString::Printf(
TEXT("generated-request:%s"),
*SanitizeGeneratedModeToken(LaunchRequest.RequestId)
)
);
OutDeck.ImportedRuntimeSurface = SourceDeck.ImportedRuntimeSurface;
OutDeck.SourceAttribution.SourceNotes = OutDeck.SourceAttribution.SourceNotes.IsEmpty()
? DeckExecutionNote
: FString::Printf(
TEXT("%s | %s"),
*OutDeck.SourceAttribution.SourceNotes,
*DeckExecutionNote
);
if (!OutDeck.IsStructurallyValid() || !OutDeck.ImportedRuntimeSurface.IsStructurallyValid())
{
OutBlockedReason = TEXT("Generated-mode executor could not build a structurally valid owned execution deck.");
return false;
}
return true;
}
TArray<FString> ExtractCaseIdsFromDeck(const FHyperTwistTrainingDeck& Deck)
{
TArray<FString> CaseIds;
@ -871,6 +1123,179 @@ FHyperTwistTrainingImportedGeneratedModeLaunchRequest UHyperTwistTrainingSubsyst
return ActiveImportedGeneratedModeLaunchRequest;
}
bool UHyperTwistTrainingSubsystem::TryExecuteActiveImportedGeneratedModeLaunchRequest(
FHyperTwistTrainingRunState& OutRunState,
FString& OutBlockedReason
)
{
OutRunState = FHyperTwistTrainingRunState();
OutBlockedReason.Reset();
if (!HasActiveRun() || !ActiveRunState.IsStructurallyValid())
{
OutBlockedReason = TEXT("Generated-mode execution requires an active training run.");
return false;
}
FHyperTwistTrainingImportedRuntimeSurface RuntimeSurface;
if (!UHyperTwistTrainingCatalogLibrary::TryGetImportedRuntimeSurfaceFromDeck(
ActiveRunState.ActiveDeck,
RuntimeSurface)
|| !RuntimeSurface.IsStructurallyValid()
|| !RuntimeSurface.SurfaceKind.Equals(TEXT("generated-mode"), ESearchCase::IgnoreCase))
{
OutBlockedReason = TEXT("Active run is not a generated-mode imported runtime surface.");
return false;
}
if (!ActiveRunState.ImportedRuntimeSelectionState.IsStructurallyValid()
|| ActiveRunState.ImportedRuntimeSelectionState.SurfaceId != RuntimeSurface.SurfaceId
|| !ActiveRunState.ImportedRuntimeSelectionState.SurfaceKind.Equals(
RuntimeSurface.SurfaceKind,
ESearchCase::IgnoreCase))
{
OutBlockedReason = TEXT("Generated-mode execution requires imported selector state that matches the active runtime surface.");
return false;
}
FHyperTwistTrainingImportedGeneratedModeLaunchRequest LaunchRequest =
ActiveImportedGeneratedModeLaunchRequest;
bool bNeedsFreshLaunchRequest = !LaunchRequest.IsStructurallyValid();
if (!bNeedsFreshLaunchRequest
&& (LaunchRequest.LaunchConfig.DeckId != ActiveRunState.ActiveDeck.DeckId
|| LaunchRequest.LaunchConfig.SurfaceId != RuntimeSurface.SurfaceId
|| !LaunchRequest.LaunchConfig.RuntimeModeId.Equals(
RuntimeSurface.RuntimeModeId,
ESearchCase::IgnoreCase)))
{
bNeedsFreshLaunchRequest = true;
}
for (const FHyperTwistTrainingImportedRuntimeSelector& Selector : RuntimeSurface.Selectors)
{
const FHyperTwistTrainingImportedRuntimeSelectorChoice* ActiveChoice =
ActiveRunState.ImportedRuntimeSelectionState.SelectorChoices.FindByPredicate(
[&Selector](const FHyperTwistTrainingImportedRuntimeSelectorChoice& Candidate)
{
return Candidate.SelectorId == Selector.SelectorId && Candidate.IsStructurallyValid();
}
);
if (ActiveChoice == nullptr)
{
OutBlockedReason = FString::Printf(
TEXT("Generated-mode execution is blocked because selector %s is unresolved."),
*Selector.Label
);
return false;
}
const FHyperTwistTrainingImportedRuntimeSelectorChoice* RequestChoice =
LaunchRequest.LaunchConfig.SelectorChoices.FindByPredicate(
[&Selector](const FHyperTwistTrainingImportedRuntimeSelectorChoice& Candidate)
{
return Candidate.SelectorId == Selector.SelectorId && Candidate.IsStructurallyValid();
}
);
if (RequestChoice == nullptr || RequestChoice->SelectedValue != ActiveChoice->SelectedValue)
{
bNeedsFreshLaunchRequest = true;
}
}
if (bNeedsFreshLaunchRequest)
{
LaunchRequest = CreateActiveImportedGeneratedModeLaunchRequest(
TEXT("runtime-imported-generated-mode-executor")
);
}
if (!LaunchRequest.IsStructurallyValid())
{
OutBlockedReason = TEXT("Generated-mode execution could not derive a structurally valid launch request.");
return false;
}
if (LaunchRequest.LaunchConfig.DeckId != ActiveRunState.ActiveDeck.DeckId
|| LaunchRequest.LaunchConfig.SurfaceId != RuntimeSurface.SurfaceId
|| !LaunchRequest.LaunchConfig.RuntimeModeId.Equals(
RuntimeSurface.RuntimeModeId,
ESearchCase::IgnoreCase))
{
OutBlockedReason = TEXT("Active generated-mode launch request does not match the active runtime surface.");
return false;
}
for (const FHyperTwistTrainingImportedRuntimeSelector& Selector : RuntimeSurface.Selectors)
{
const FHyperTwistTrainingImportedRuntimeSelectorChoice* RequestChoice =
LaunchRequest.LaunchConfig.SelectorChoices.FindByPredicate(
[&Selector](const FHyperTwistTrainingImportedRuntimeSelectorChoice& Candidate)
{
return Candidate.SelectorId == Selector.SelectorId && Candidate.IsStructurallyValid();
}
);
const FHyperTwistTrainingImportedRuntimeSelectorChoice* ActiveChoice =
ActiveRunState.ImportedRuntimeSelectionState.SelectorChoices.FindByPredicate(
[&Selector](const FHyperTwistTrainingImportedRuntimeSelectorChoice& Candidate)
{
return Candidate.SelectorId == Selector.SelectorId && Candidate.IsStructurallyValid();
}
);
if (RequestChoice == nullptr || ActiveChoice == nullptr)
{
OutBlockedReason = FString::Printf(
TEXT("Generated-mode execution is blocked because selector %s is unresolved."),
*Selector.Label
);
return false;
}
if (RequestChoice->SelectedValue != ActiveChoice->SelectedValue)
{
OutBlockedReason = FString::Printf(
TEXT("Generated-mode execution is blocked because selector %s no longer matches the active selection state."),
*Selector.Label
);
return false;
}
}
const FHyperTwistTrainingRunState SourceRunState = ActiveRunState;
FHyperTwistTrainingDeck GeneratedDeck;
if (!HyperTwistTrainingSubsystemInternal::TryBuildGeneratedModeExecutionDeck(
SourceRunState.ActiveDeck,
LaunchRequest,
GeneratedDeck,
OutBlockedReason))
{
return false;
}
const FString ExecutionSessionId =
HyperTwistTrainingSubsystemInternal::BuildGeneratedModeExecutionSessionId(LaunchRequest);
const FHyperTwistTrainingRunState StartedRunState = StartTrainingRunFromDeck(
GeneratedDeck,
SourceRunState.Session.UserId,
ExecutionSessionId,
LaunchRequest.LaunchConfig.DeliveryMode
);
if (!StartedRunState.IsStructurallyValid())
{
OutBlockedReason = TEXT("Generated-mode executor could not start a structurally valid owned run.");
return false;
}
ActiveRunState.ImportedRuntimeSelectionState = SourceRunState.ImportedRuntimeSelectionState;
ActiveImportedGeneratedModeLaunchRequest = LaunchRequest;
ActiveRunState.ImportedGeneratedModeLaunchRequest = LaunchRequest;
RefreshSummary();
TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::RecordRunState(
TrainingRepositoryState,
ActiveRunState
);
RefreshRepositoryViews();
OutRunState = ActiveRunState;
return OutRunState.IsStructurallyValid();
}
FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::ApplyActiveImportedRuntimeSelectorOption(
const FString& SelectorId,
const FString& OptionId

View file

@ -72,6 +72,13 @@ public:
const FString& RequestSource
);
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training", meta = (WorldContext = "WorldContextObject"))
static bool TryExecuteActiveImportedGeneratedModeLaunchRequest(
UObject* WorldContextObject,
FHyperTwistTrainingRunState& OutRunState,
FString& OutBlockedReason
);
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training", meta = (WorldContext = "WorldContextObject"))
static FHyperTwistTrainingRunState ApplyActiveImportedRuntimeSelectorOption(
UObject* WorldContextObject,

View file

@ -58,6 +58,12 @@ public:
const FString& RequestSource
);
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training")
bool TryExecuteActiveImportedGeneratedModeLaunchRequest(
FHyperTwistTrainingRunState& OutRunState,
FString& OutBlockedReason
);
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training")
FHyperTwistTrainingRunState ApplyActiveImportedRuntimeSelectorOption(
const FString& SelectorId,