Implement Phase 6R-AA provider usage cost dashboard shell
This commit is contained in:
parent
65f1357ce5
commit
a2fba2ef99
14 changed files with 1411 additions and 31 deletions
|
|
@ -903,6 +903,65 @@ namespace HyperTwistContractLibraryInternal
|
|||
return Profile;
|
||||
}
|
||||
|
||||
FHyperTwistSpeechUsageCostDashboardShellProfile MakeDefaultSpeechUsageCostDashboardShellProfile(
|
||||
const FString& ProfileId
|
||||
)
|
||||
{
|
||||
FHyperTwistSpeechUsageCostDashboardShellProfile Profile;
|
||||
Profile.DashboardShellProfileId = ProfileId;
|
||||
Profile.ShellKind = TEXT("operator-usage-cost-dashboard");
|
||||
Profile.UsageSurfaceMode = TEXT("normalized-usage-summary-card");
|
||||
Profile.CostSurfaceMode = TEXT("estimate-first-cost-card");
|
||||
Profile.EscalationBannerMode = TEXT("route-and-budget-posture-banner");
|
||||
Profile.RefreshActionId = TEXT("refresh-provider-usage-cost-dashboard");
|
||||
Profile.RouteInspectActionId = TEXT("inspect-provider-route");
|
||||
Profile.BudgetInspectActionId = TEXT("review-provider-budget");
|
||||
Profile.bSupportsProviderSummary = true;
|
||||
Profile.bSupportsEstimateBadges = true;
|
||||
Profile.bSupportsQuotaEscalationBanner = true;
|
||||
Profile.bSupportsRouteDiagnostics = true;
|
||||
|
||||
auto AddPanel = [&Profile](
|
||||
const TCHAR* PanelId,
|
||||
const TCHAR* PanelKind,
|
||||
const TCHAR* AnchorId,
|
||||
const bool bVisibleByDefault
|
||||
)
|
||||
{
|
||||
FHyperTwistSpeechShellPanelLayout Panel;
|
||||
Panel.PanelId = PanelId;
|
||||
Panel.PanelKind = PanelKind;
|
||||
Panel.AnchorId = AnchorId;
|
||||
Panel.bVisibleByDefault = bVisibleByDefault;
|
||||
Profile.Panels.Add(Panel);
|
||||
};
|
||||
|
||||
auto AddAction = [&Profile](
|
||||
const TCHAR* ActionId,
|
||||
const TCHAR* InputBinding,
|
||||
const TCHAR* SurfaceId
|
||||
)
|
||||
{
|
||||
FHyperTwistSpeechShellActionBinding ActionBinding;
|
||||
ActionBinding.ActionId = ActionId;
|
||||
ActionBinding.InputBinding = InputBinding;
|
||||
ActionBinding.SurfaceId = SurfaceId;
|
||||
Profile.ActionBindings.Add(ActionBinding);
|
||||
};
|
||||
|
||||
AddPanel(TEXT("provider-summary-card"), TEXT("provider-summary-card"), TEXT("top-left"), true);
|
||||
AddPanel(TEXT("usage-meter-card"), TEXT("usage-meter-card"), TEXT("left-stack-below-provider"), true);
|
||||
AddPanel(TEXT("cost-estimate-card"), TEXT("cost-estimate-card"), TEXT("top-right"), true);
|
||||
AddPanel(TEXT("quota-state-card"), TEXT("quota-state-card"), TEXT("right-stack-below-cost"), true);
|
||||
AddPanel(TEXT("route-diagnostics-card"), TEXT("route-diagnostics-card"), TEXT("bottom-right"), true);
|
||||
|
||||
AddAction(TEXT("refresh-provider-usage-cost-dashboard"), TEXT("F5"), TEXT("provider-summary-card"));
|
||||
AddAction(TEXT("inspect-provider-route"), TEXT("P"), TEXT("route-diagnostics-card"));
|
||||
AddAction(TEXT("review-provider-budget"), TEXT("B"), TEXT("quota-state-card"));
|
||||
AddAction(TEXT("close-speech-session"), TEXT("Escape"), TEXT("session-root"));
|
||||
return Profile;
|
||||
}
|
||||
|
||||
FHyperTwistSpeechModelPayloadDescriptor MakeSpeechModelPayloadDescriptor(
|
||||
const TCHAR* PayloadId,
|
||||
const TCHAR* PayloadKind,
|
||||
|
|
@ -981,7 +1040,10 @@ namespace HyperTwistContractLibraryInternal
|
|||
TEXT("promptHints"),
|
||||
TEXT("normalizedUsageEvents"),
|
||||
TEXT("normalizedCostEvents"),
|
||||
TEXT("quotaRateLimitState")
|
||||
TEXT("quotaRateLimitState"),
|
||||
TEXT("providerUsageCostDashboardShell"),
|
||||
TEXT("providerQuotaEscalationBanner"),
|
||||
TEXT("providerRouteCostDiagnostics")
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -2202,6 +2264,11 @@ FHyperTwistSpeechSessionConfig UHyperTwistContractLibrary::MakeSampleSpeechSessi
|
|||
true,
|
||||
false
|
||||
);
|
||||
Config.UsageCostDashboardShellProfileId = TEXT("speech-provider-usage-cost-dashboard-shell-v1");
|
||||
Config.UsageCostDashboardShellProfileDefinition =
|
||||
HyperTwistContractLibraryInternal::MakeDefaultSpeechUsageCostDashboardShellProfile(
|
||||
Config.UsageCostDashboardShellProfileId
|
||||
);
|
||||
Config.PayloadCustodyProfileId = TEXT("downloadable-model-payload-custody-v1");
|
||||
Config.PayloadCustodyProfileDefinition =
|
||||
HyperTwistContractLibraryInternal::MakeDefaultSpeechPayloadCustodyProfile(
|
||||
|
|
@ -2309,7 +2376,10 @@ FHyperTwistSpeechServiceHealth UHyperTwistContractLibrary::MakeMockSpeechService
|
|||
TEXT("payloadIntegrityReview"),
|
||||
TEXT("normalizedUsageEvents"),
|
||||
TEXT("normalizedCostEvents"),
|
||||
TEXT("quotaRateLimitState")
|
||||
TEXT("quotaRateLimitState"),
|
||||
TEXT("providerUsageCostDashboardShell"),
|
||||
TEXT("providerQuotaEscalationBanner"),
|
||||
TEXT("providerRouteCostDiagnostics")
|
||||
};
|
||||
Health.SupportedOrchestrationProfiles = {
|
||||
TEXT("python-batch-transcribe-v1")
|
||||
|
|
|
|||
|
|
@ -341,7 +341,10 @@ FHyperTwistSpeechServiceHealth UHyperTwistHttpSpeechClient::GetSpeechServiceHeal
|
|||
TEXT("payloadIntegrityReview"),
|
||||
TEXT("normalizedUsageEvents"),
|
||||
TEXT("normalizedCostEvents"),
|
||||
TEXT("quotaRateLimitState")
|
||||
TEXT("quotaRateLimitState"),
|
||||
TEXT("providerUsageCostDashboardShell"),
|
||||
TEXT("providerQuotaEscalationBanner"),
|
||||
TEXT("providerRouteCostDiagnostics")
|
||||
};
|
||||
Health.SupportedOrchestrationProfiles = {
|
||||
TEXT("python-batch-transcribe-v1")
|
||||
|
|
@ -415,7 +418,10 @@ FHyperTwistSpeechServiceHealth UHyperTwistHttpSpeechClient::GetSpeechServiceHeal
|
|||
TEXT("payloadIntegrityReview"),
|
||||
TEXT("normalizedUsageEvents"),
|
||||
TEXT("normalizedCostEvents"),
|
||||
TEXT("quotaRateLimitState")
|
||||
TEXT("quotaRateLimitState"),
|
||||
TEXT("providerUsageCostDashboardShell"),
|
||||
TEXT("providerQuotaEscalationBanner"),
|
||||
TEXT("providerRouteCostDiagnostics")
|
||||
};
|
||||
Health.SupportedOrchestrationProfiles = {
|
||||
TEXT("python-batch-transcribe-v1")
|
||||
|
|
@ -474,6 +480,9 @@ FHyperTwistSpeechServiceHealth UHyperTwistHttpSpeechClient::GetSpeechServiceHeal
|
|||
Health.Capabilities.AddUnique(TEXT("normalizedUsageEvents"));
|
||||
Health.Capabilities.AddUnique(TEXT("normalizedCostEvents"));
|
||||
Health.Capabilities.AddUnique(TEXT("quotaRateLimitState"));
|
||||
Health.Capabilities.AddUnique(TEXT("providerUsageCostDashboardShell"));
|
||||
Health.Capabilities.AddUnique(TEXT("providerQuotaEscalationBanner"));
|
||||
Health.Capabilities.AddUnique(TEXT("providerRouteCostDiagnostics"));
|
||||
Health.SupportedOrchestrationProfiles.AddUnique(TEXT("python-batch-transcribe-v1"));
|
||||
if (Health.ProviderProfileId.IsEmpty())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -146,6 +146,9 @@ FHyperTwistSpeechServiceHealth UHyperTwistMockSpeechClient::GetSpeechServiceHeal
|
|||
Health.Capabilities.AddUnique(TEXT("normalizedUsageEvents"));
|
||||
Health.Capabilities.AddUnique(TEXT("normalizedCostEvents"));
|
||||
Health.Capabilities.AddUnique(TEXT("quotaRateLimitState"));
|
||||
Health.Capabilities.AddUnique(TEXT("providerUsageCostDashboardShell"));
|
||||
Health.Capabilities.AddUnique(TEXT("providerQuotaEscalationBanner"));
|
||||
Health.Capabilities.AddUnique(TEXT("providerRouteCostDiagnostics"));
|
||||
Health.SupportedOrchestrationProfiles.AddUnique(TEXT("python-batch-transcribe-v1"));
|
||||
return Health;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2916,6 +2916,11 @@ namespace HyperTwistTrainingSubsystemInternal
|
|||
const bool bSessionOpen
|
||||
);
|
||||
|
||||
FHyperTwistSpeechUsageCostDashboardShellState BuildSpeechUsageCostDashboardShellState(
|
||||
const FHyperTwistSpeechSessionConfig& SessionConfig,
|
||||
const FHyperTwistTrainingCompanionSpeechSessionState* PriorState
|
||||
);
|
||||
|
||||
FHyperTwistSpeechMicrophoneShellProfile BuildDefaultCoachCommandMicrophoneShellProfile(const FString& ProfileId)
|
||||
{
|
||||
FHyperTwistSpeechMicrophoneShellProfile Profile;
|
||||
|
|
@ -2978,6 +2983,65 @@ namespace HyperTwistTrainingSubsystemInternal
|
|||
return Profile;
|
||||
}
|
||||
|
||||
FHyperTwistSpeechUsageCostDashboardShellProfile BuildDefaultSpeechUsageCostDashboardShellProfile(
|
||||
const FString& ProfileId
|
||||
)
|
||||
{
|
||||
FHyperTwistSpeechUsageCostDashboardShellProfile Profile;
|
||||
Profile.DashboardShellProfileId = ProfileId;
|
||||
Profile.ShellKind = TEXT("operator-usage-cost-dashboard");
|
||||
Profile.UsageSurfaceMode = TEXT("normalized-usage-summary-card");
|
||||
Profile.CostSurfaceMode = TEXT("estimate-first-cost-card");
|
||||
Profile.EscalationBannerMode = TEXT("route-and-budget-posture-banner");
|
||||
Profile.RefreshActionId = TEXT("refresh-provider-usage-cost-dashboard");
|
||||
Profile.RouteInspectActionId = TEXT("inspect-provider-route");
|
||||
Profile.BudgetInspectActionId = TEXT("review-provider-budget");
|
||||
Profile.bSupportsProviderSummary = true;
|
||||
Profile.bSupportsEstimateBadges = true;
|
||||
Profile.bSupportsQuotaEscalationBanner = true;
|
||||
Profile.bSupportsRouteDiagnostics = true;
|
||||
|
||||
auto AddPanel = [&Profile](
|
||||
const TCHAR* PanelId,
|
||||
const TCHAR* PanelKind,
|
||||
const TCHAR* AnchorId,
|
||||
const bool bVisibleByDefault
|
||||
)
|
||||
{
|
||||
FHyperTwistSpeechShellPanelLayout Panel;
|
||||
Panel.PanelId = PanelId;
|
||||
Panel.PanelKind = PanelKind;
|
||||
Panel.AnchorId = AnchorId;
|
||||
Panel.bVisibleByDefault = bVisibleByDefault;
|
||||
Profile.Panels.Add(Panel);
|
||||
};
|
||||
|
||||
auto AddAction = [&Profile](
|
||||
const TCHAR* ActionId,
|
||||
const TCHAR* InputBinding,
|
||||
const TCHAR* SurfaceId
|
||||
)
|
||||
{
|
||||
FHyperTwistSpeechShellActionBinding ActionBinding;
|
||||
ActionBinding.ActionId = ActionId;
|
||||
ActionBinding.InputBinding = InputBinding;
|
||||
ActionBinding.SurfaceId = SurfaceId;
|
||||
Profile.ActionBindings.Add(ActionBinding);
|
||||
};
|
||||
|
||||
AddPanel(TEXT("provider-summary-card"), TEXT("provider-summary-card"), TEXT("top-left"), true);
|
||||
AddPanel(TEXT("usage-meter-card"), TEXT("usage-meter-card"), TEXT("left-stack-below-provider"), true);
|
||||
AddPanel(TEXT("cost-estimate-card"), TEXT("cost-estimate-card"), TEXT("top-right"), true);
|
||||
AddPanel(TEXT("quota-state-card"), TEXT("quota-state-card"), TEXT("right-stack-below-cost"), true);
|
||||
AddPanel(TEXT("route-diagnostics-card"), TEXT("route-diagnostics-card"), TEXT("bottom-right"), true);
|
||||
|
||||
AddAction(TEXT("refresh-provider-usage-cost-dashboard"), TEXT("F5"), TEXT("provider-summary-card"));
|
||||
AddAction(TEXT("inspect-provider-route"), TEXT("P"), TEXT("route-diagnostics-card"));
|
||||
AddAction(TEXT("review-provider-budget"), TEXT("B"), TEXT("quota-state-card"));
|
||||
AddAction(TEXT("close-speech-session"), TEXT("Escape"), TEXT("session-root"));
|
||||
return Profile;
|
||||
}
|
||||
|
||||
FHyperTwistSpeechModelPayloadDescriptor MakeSpeechModelPayloadDescriptor(
|
||||
const TCHAR* PayloadId,
|
||||
const TCHAR* PayloadKind,
|
||||
|
|
@ -3056,7 +3120,10 @@ namespace HyperTwistTrainingSubsystemInternal
|
|||
TEXT("promptHints"),
|
||||
TEXT("normalizedUsageEvents"),
|
||||
TEXT("normalizedCostEvents"),
|
||||
TEXT("quotaRateLimitState")
|
||||
TEXT("quotaRateLimitState"),
|
||||
TEXT("providerUsageCostDashboardShell"),
|
||||
TEXT("providerQuotaEscalationBanner"),
|
||||
TEXT("providerRouteCostDiagnostics")
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -3691,6 +3758,26 @@ namespace HyperTwistTrainingSubsystemInternal
|
|||
false
|
||||
);
|
||||
}
|
||||
if (SessionConfig.UsageCostDashboardShellProfileId.IsEmpty()
|
||||
&& SessionConfig.UsageCostDashboardShellProfileDefinition.IsStructurallyValid())
|
||||
{
|
||||
SessionConfig.UsageCostDashboardShellProfileId =
|
||||
SessionConfig.UsageCostDashboardShellProfileDefinition.DashboardShellProfileId;
|
||||
}
|
||||
if (SessionConfig.UsageCostDashboardShellProfileId.IsEmpty())
|
||||
{
|
||||
SessionConfig.UsageCostDashboardShellProfileId =
|
||||
TEXT("speech-provider-usage-cost-dashboard-shell-v1");
|
||||
}
|
||||
if (!SessionConfig.UsageCostDashboardShellProfileDefinition.IsStructurallyValid())
|
||||
{
|
||||
SessionConfig.UsageCostDashboardShellProfileDefinition =
|
||||
BuildDefaultSpeechUsageCostDashboardShellProfile(
|
||||
SessionConfig.UsageCostDashboardShellProfileId
|
||||
);
|
||||
}
|
||||
SessionConfig.UsageCostDashboardShellProfileId =
|
||||
SessionConfig.UsageCostDashboardShellProfileDefinition.DashboardShellProfileId;
|
||||
}
|
||||
|
||||
void ApplySpeechProviderProfileHealthDefaults(
|
||||
|
|
@ -4020,6 +4107,9 @@ namespace HyperTwistTrainingSubsystemInternal
|
|||
Health.Capabilities.AddUnique(TEXT("normalizedUsageEvents"));
|
||||
Health.Capabilities.AddUnique(TEXT("normalizedCostEvents"));
|
||||
Health.Capabilities.AddUnique(TEXT("quotaRateLimitState"));
|
||||
Health.Capabilities.AddUnique(TEXT("providerUsageCostDashboardShell"));
|
||||
Health.Capabilities.AddUnique(TEXT("providerQuotaEscalationBanner"));
|
||||
Health.Capabilities.AddUnique(TEXT("providerRouteCostDiagnostics"));
|
||||
}
|
||||
|
||||
bool IsSpeechPermissionError(const FString& ErrorText)
|
||||
|
|
@ -4241,6 +4331,279 @@ namespace HyperTwistTrainingSubsystemInternal
|
|||
);
|
||||
}
|
||||
|
||||
void AddSpeechUsageCostDashboardIssue(
|
||||
FHyperTwistSpeechUsageCostDashboardShellState& ShellState,
|
||||
const FHyperTwistSpeechUsageCostDashboardIssue& Issue
|
||||
)
|
||||
{
|
||||
if (!Issue.IsStructurallyValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ShellState.Issues.Add(Issue);
|
||||
if (!ShellState.ActiveIssue.IsStructurallyValid())
|
||||
{
|
||||
ShellState.ActiveIssue = Issue;
|
||||
}
|
||||
}
|
||||
|
||||
void ApplySpeechUsageCostDashboardPosture(
|
||||
const FHyperTwistSpeechUsageCostDashboardShellProfile& Profile,
|
||||
const FHyperTwistSpeechSessionConfig& SessionConfig,
|
||||
const FHyperTwistSpeechServiceHealth& ServiceHealth,
|
||||
const FString& LastError,
|
||||
FHyperTwistSpeechUsageCostDashboardShellState& ShellState
|
||||
)
|
||||
{
|
||||
const FHyperTwistSpeechProviderProfile EffectiveProfile =
|
||||
ServiceHealth.ProviderProfileDefinition.IsStructurallyValid()
|
||||
? ServiceHealth.ProviderProfileDefinition
|
||||
: (SessionConfig.ProviderProfileDefinition.IsStructurallyValid()
|
||||
? SessionConfig.ProviderProfileDefinition
|
||||
: BuildDefaultHttpSpeechProviderProfile(
|
||||
TEXT("Local HTTP Speech Sidecar"),
|
||||
TEXT("http://127.0.0.1:8766")
|
||||
));
|
||||
const FHyperTwistSpeechProviderRouteDecision EffectiveRouteDecision =
|
||||
ServiceHealth.ProviderRouteDecision.IsStructurallyValid()
|
||||
? ServiceHealth.ProviderRouteDecision
|
||||
: SessionConfig.ProviderRouteDecision;
|
||||
const FHyperTwistSpeechNormalizedUsageEvent EffectiveUsageEvent =
|
||||
ServiceHealth.LatestUsageEvent.IsStructurallyValid()
|
||||
? ServiceHealth.LatestUsageEvent
|
||||
: SessionConfig.UsageEventTemplate;
|
||||
const FHyperTwistSpeechNormalizedCostEvent EffectiveCostEvent =
|
||||
ServiceHealth.LatestCostEvent.IsStructurallyValid()
|
||||
? ServiceHealth.LatestCostEvent
|
||||
: SessionConfig.CostEventTemplate;
|
||||
const FHyperTwistSpeechQuotaRateLimitState EffectiveQuotaState =
|
||||
ServiceHealth.QuotaRateLimitState.IsStructurallyValid()
|
||||
? ServiceHealth.QuotaRateLimitState
|
||||
: BuildDefaultSpeechQuotaRateLimitState(
|
||||
SessionConfig.UsageCostAccountingProfileDefinition.IsStructurallyValid()
|
||||
? SessionConfig.UsageCostAccountingProfileDefinition
|
||||
: BuildDefaultSpeechUsageCostAccountingProfile(
|
||||
TEXT("speech-usage-cost-accounting-v1")
|
||||
),
|
||||
EffectiveProfile,
|
||||
!EffectiveRouteDecision.SelectedServiceLaneId.IsEmpty()
|
||||
? EffectiveRouteDecision.SelectedServiceLaneId
|
||||
: TEXT("speech/python-service"),
|
||||
TEXT("within-budget"),
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
60,
|
||||
3600,
|
||||
25.0f
|
||||
);
|
||||
const FString EffectiveError = !LastError.IsEmpty()
|
||||
? LastError
|
||||
: (!ServiceHealth.LastError.IsEmpty()
|
||||
? ServiceHealth.LastError
|
||||
: EffectiveRouteDecision.FailureReason);
|
||||
|
||||
ShellState.ActiveProviderProfileId = EffectiveProfile.ProviderProfileId;
|
||||
ShellState.ActiveProviderDisplayLabel = !EffectiveProfile.DisplayLabel.IsEmpty()
|
||||
? EffectiveProfile.DisplayLabel
|
||||
: EffectiveProfile.ProviderProfileId;
|
||||
ShellState.ActiveServiceLaneId = !EffectiveRouteDecision.SelectedServiceLaneId.IsEmpty()
|
||||
? EffectiveRouteDecision.SelectedServiceLaneId
|
||||
: (!SessionConfig.OrchestrationProfile.ServiceLaneId.IsEmpty()
|
||||
? SessionConfig.OrchestrationProfile.ServiceLaneId
|
||||
: TEXT("speech/python-service"));
|
||||
ShellState.ActiveRouteStateId = !EffectiveRouteDecision.RouteStateId.IsEmpty()
|
||||
? EffectiveRouteDecision.RouteStateId
|
||||
: (ServiceHealth.bReady ? TEXT("route-ready") : TEXT("route-health-unknown"));
|
||||
ShellState.UsageAggregationWindowId = !EffectiveUsageEvent.AggregationWindowId.IsEmpty()
|
||||
? EffectiveUsageEvent.AggregationWindowId
|
||||
: TEXT("service-health-window");
|
||||
ShellState.CostAggregationWindowId = !EffectiveCostEvent.AggregationWindowId.IsEmpty()
|
||||
? EffectiveCostEvent.AggregationWindowId
|
||||
: TEXT("service-health-window");
|
||||
ShellState.UsageMeterKind = !EffectiveUsageEvent.MeterKind.IsEmpty()
|
||||
? EffectiveUsageEvent.MeterKind
|
||||
: TEXT("audio-seconds");
|
||||
ShellState.CurrencyCode = !EffectiveCostEvent.CurrencyCode.IsEmpty()
|
||||
? EffectiveCostEvent.CurrencyCode
|
||||
: TEXT("USD");
|
||||
ShellState.LatestUsageEventId = !EffectiveUsageEvent.UsageEventId.IsEmpty()
|
||||
? EffectiveUsageEvent.UsageEventId
|
||||
: TEXT("speech-usage-event/unavailable");
|
||||
ShellState.LatestCostEventId = !EffectiveCostEvent.CostEventId.IsEmpty()
|
||||
? EffectiveCostEvent.CostEventId
|
||||
: TEXT("speech-cost-event/unavailable");
|
||||
ShellState.LatestQuotaStateId = !EffectiveQuotaState.QuotaStateId.IsEmpty()
|
||||
? EffectiveQuotaState.QuotaStateId
|
||||
: TEXT("speech-quota-state/unavailable");
|
||||
ShellState.LatestRouteDecisionId = !EffectiveRouteDecision.RouteDecisionId.IsEmpty()
|
||||
? EffectiveRouteDecision.RouteDecisionId
|
||||
: TEXT("speech-route-decision/unavailable");
|
||||
ShellState.DisplayedUsageQuantity = FMath::Max(0.0f, EffectiveUsageEvent.ReportedQuantity);
|
||||
ShellState.DisplayedEstimatedCostUsd = FMath::Max(0.0f, EffectiveCostEvent.EstimatedCost);
|
||||
ShellState.DisplayedReportedCostUsd = FMath::Max(0.0f, EffectiveCostEvent.ReportedCost);
|
||||
ShellState.RemainingEstimatedSpendUsd =
|
||||
FMath::Max(0.0f, EffectiveQuotaState.RemainingEstimatedSpendUsd);
|
||||
ShellState.RemainingRequestCount = FMath::Max(0, EffectiveQuotaState.RemainingRequestCount);
|
||||
ShellState.RemainingAudioSeconds = FMath::Max(0, EffectiveQuotaState.RemainingAudioSeconds);
|
||||
ShellState.bDashboardVisible = true;
|
||||
ShellState.bProviderSummaryVisible = Profile.bSupportsProviderSummary;
|
||||
ShellState.bUsageCardVisible = true;
|
||||
ShellState.bCostCardVisible = true;
|
||||
ShellState.bQuotaCardVisible = true;
|
||||
ShellState.bRouteDiagnosticsVisible = Profile.bSupportsRouteDiagnostics;
|
||||
ShellState.bProviderReceiptPosted = EffectiveCostEvent.bHasProviderPostedCharge;
|
||||
ShellState.bEstimateBadgeVisible =
|
||||
Profile.bSupportsEstimateBadges
|
||||
&& (EffectiveUsageEvent.bEstimateOnly || EffectiveCostEvent.bEstimateOnly);
|
||||
ShellState.bQuotaKnown = EffectiveQuotaState.bQuotaKnown;
|
||||
ShellState.bRateLimited = EffectiveQuotaState.bRateLimited;
|
||||
ShellState.bHardBlocked = EffectiveQuotaState.bHardBlocked;
|
||||
ShellState.bRouteReady = EffectiveRouteDecision.IsStructurallyValid()
|
||||
? EffectiveRouteDecision.bRouteReady
|
||||
: ServiceHealth.bReady;
|
||||
ShellState.Issues.Reset();
|
||||
ShellState.ActiveIssue = FHyperTwistSpeechUsageCostDashboardIssue();
|
||||
|
||||
ShellState.StatusLine = TEXT("Provider usage and budget posture within current bounds.");
|
||||
ShellState.DetailLine = FString::Printf(
|
||||
TEXT("%s reports %.2f %s and %.2f %s estimated cost in %s."),
|
||||
*ShellState.ActiveProviderDisplayLabel,
|
||||
ShellState.DisplayedUsageQuantity,
|
||||
*ShellState.UsageMeterKind,
|
||||
ShellState.DisplayedEstimatedCostUsd,
|
||||
*ShellState.CurrencyCode,
|
||||
*ShellState.UsageAggregationWindowId
|
||||
);
|
||||
ShellState.bEscalationBannerVisible = false;
|
||||
|
||||
if (!ShellState.bRouteReady || !ServiceHealth.bReady || !EffectiveError.IsEmpty())
|
||||
{
|
||||
FHyperTwistSpeechUsageCostDashboardIssue Issue;
|
||||
Issue.IssueId = TEXT("provider-route-degraded");
|
||||
Issue.IssueKind = TEXT("route-degraded");
|
||||
Issue.StatusLine = TEXT("Provider route requires attention.");
|
||||
Issue.DetailLine = EffectiveError.IsEmpty()
|
||||
? TEXT("The provider route is not currently ready. Inspect the active route before relying on usage or cost posture.")
|
||||
: FString::Printf(
|
||||
TEXT("The provider route reported '%s'. Inspect the active route before relying on usage or cost posture."),
|
||||
*EffectiveError
|
||||
);
|
||||
Issue.RecommendedActionId = Profile.RouteInspectActionId;
|
||||
AddSpeechUsageCostDashboardIssue(ShellState, Issue);
|
||||
ShellState.StatusLine = Issue.StatusLine;
|
||||
ShellState.DetailLine = Issue.DetailLine;
|
||||
ShellState.bEscalationBannerVisible = Profile.bSupportsQuotaEscalationBanner;
|
||||
}
|
||||
|
||||
if (ShellState.bHardBlocked)
|
||||
{
|
||||
FHyperTwistSpeechUsageCostDashboardIssue Issue;
|
||||
Issue.IssueId = TEXT("provider-hard-blocked");
|
||||
Issue.IssueKind = TEXT("hard-blocked");
|
||||
Issue.StatusLine = TEXT("Provider usage blocked.");
|
||||
Issue.DetailLine = FString::Printf(
|
||||
TEXT("The quota state is '%s'. Resolve provider budget posture before depending on further provider-backed capture."),
|
||||
*EffectiveQuotaState.StateReason
|
||||
);
|
||||
Issue.RecommendedActionId = Profile.BudgetInspectActionId;
|
||||
AddSpeechUsageCostDashboardIssue(ShellState, Issue);
|
||||
ShellState.ActiveIssue = Issue;
|
||||
ShellState.StatusLine = Issue.StatusLine;
|
||||
ShellState.DetailLine = Issue.DetailLine;
|
||||
ShellState.bEscalationBannerVisible = Profile.bSupportsQuotaEscalationBanner;
|
||||
}
|
||||
else if (ShellState.bRateLimited)
|
||||
{
|
||||
FHyperTwistSpeechUsageCostDashboardIssue Issue;
|
||||
Issue.IssueId = TEXT("provider-rate-limited");
|
||||
Issue.IssueKind = TEXT("rate-limited");
|
||||
Issue.StatusLine = TEXT("Provider rate limit reached.");
|
||||
Issue.DetailLine = FString::Printf(
|
||||
TEXT("Remaining requests: %d. Remaining audio seconds: %d. Review provider budget posture before more routed capture."),
|
||||
ShellState.RemainingRequestCount,
|
||||
ShellState.RemainingAudioSeconds
|
||||
);
|
||||
Issue.RecommendedActionId = Profile.BudgetInspectActionId;
|
||||
AddSpeechUsageCostDashboardIssue(ShellState, Issue);
|
||||
ShellState.ActiveIssue = Issue;
|
||||
ShellState.StatusLine = Issue.StatusLine;
|
||||
ShellState.DetailLine = Issue.DetailLine;
|
||||
ShellState.bEscalationBannerVisible = Profile.bSupportsQuotaEscalationBanner;
|
||||
}
|
||||
else if (!ShellState.bQuotaKnown
|
||||
&& ShellState.bRouteReady
|
||||
&& EffectiveError.IsEmpty()
|
||||
&& ServiceHealth.bReady)
|
||||
{
|
||||
FHyperTwistSpeechUsageCostDashboardIssue Issue;
|
||||
Issue.IssueId = TEXT("provider-budget-posture-unknown");
|
||||
Issue.IssueKind = TEXT("budget-posture-unknown");
|
||||
Issue.StatusLine = TEXT("Provider budget posture unknown.");
|
||||
Issue.DetailLine =
|
||||
TEXT("Quota and spend snapshots are not confirmed yet. Treat the current dashboard values as routing diagnostics, not settled provider billing.");
|
||||
Issue.RecommendedActionId = Profile.BudgetInspectActionId;
|
||||
AddSpeechUsageCostDashboardIssue(ShellState, Issue);
|
||||
ShellState.ActiveIssue = Issue;
|
||||
ShellState.bEscalationBannerVisible = Profile.bSupportsQuotaEscalationBanner;
|
||||
}
|
||||
|
||||
if (ShellState.bEstimateBadgeVisible && !ShellState.bProviderReceiptPosted && ShellState.Issues.Num() <= 0)
|
||||
{
|
||||
ShellState.DetailLine += TEXT(" Current cost remains estimate-only.");
|
||||
}
|
||||
|
||||
ShellState.ActiveIssueCount = ShellState.Issues.Num();
|
||||
}
|
||||
|
||||
void SynchronizeSpeechUsageCostDashboardState(
|
||||
FHyperTwistTrainingCompanionSpeechSessionState& SessionState
|
||||
)
|
||||
{
|
||||
FHyperTwistSpeechSessionConfig EffectiveConfig = SessionState.SessionConfig;
|
||||
ApplySpeechUsageCostDefaults(EffectiveConfig);
|
||||
if (!SessionState.UsageCostDashboardShellState.IsStructurallyValid())
|
||||
{
|
||||
SessionState.UsageCostDashboardShellState =
|
||||
BuildSpeechUsageCostDashboardShellState(EffectiveConfig, &SessionState);
|
||||
}
|
||||
|
||||
const FHyperTwistSpeechUsageCostDashboardShellProfile Profile =
|
||||
EffectiveConfig.UsageCostDashboardShellProfileDefinition.IsStructurallyValid()
|
||||
? EffectiveConfig.UsageCostDashboardShellProfileDefinition
|
||||
: BuildDefaultSpeechUsageCostDashboardShellProfile(
|
||||
!EffectiveConfig.UsageCostDashboardShellProfileId.IsEmpty()
|
||||
? EffectiveConfig.UsageCostDashboardShellProfileId
|
||||
: TEXT("speech-provider-usage-cost-dashboard-shell-v1")
|
||||
);
|
||||
|
||||
FHyperTwistSpeechUsageCostDashboardShellState& ShellState =
|
||||
SessionState.UsageCostDashboardShellState;
|
||||
ShellState.DashboardShellProfileId = Profile.DashboardShellProfileId;
|
||||
ShellState.AvailableActionIds.Reset();
|
||||
for (const FHyperTwistSpeechShellActionBinding& ActionBinding : Profile.ActionBindings)
|
||||
{
|
||||
ShellState.AvailableActionIds.AddUnique(ActionBinding.ActionId);
|
||||
}
|
||||
|
||||
ApplySpeechUsageCostDashboardPosture(
|
||||
Profile,
|
||||
EffectiveConfig,
|
||||
SessionState.ServiceHealth,
|
||||
SessionState.LastError,
|
||||
ShellState
|
||||
);
|
||||
|
||||
ShellState.AvailableActionIds.AddUnique(Profile.RefreshActionId);
|
||||
ShellState.AvailableActionIds.AddUnique(Profile.RouteInspectActionId);
|
||||
ShellState.AvailableActionIds.AddUnique(Profile.BudgetInspectActionId);
|
||||
if (ShellState.ActiveIssue.IsStructurallyValid())
|
||||
{
|
||||
ShellState.AvailableActionIds.AddUnique(ShellState.ActiveIssue.RecommendedActionId);
|
||||
}
|
||||
}
|
||||
|
||||
FHyperTwistSpeechMicrophoneShellState BuildCoachCommandMicrophoneShellState(
|
||||
const FHyperTwistSpeechSessionConfig& SessionConfig,
|
||||
const FHyperTwistTrainingCompanionSpeechSessionState* PriorState,
|
||||
|
|
@ -4344,6 +4707,58 @@ namespace HyperTwistTrainingSubsystemInternal
|
|||
return ShellState;
|
||||
}
|
||||
|
||||
FHyperTwistSpeechUsageCostDashboardShellState BuildSpeechUsageCostDashboardShellState(
|
||||
const FHyperTwistSpeechSessionConfig& SessionConfig,
|
||||
const FHyperTwistTrainingCompanionSpeechSessionState* PriorState
|
||||
)
|
||||
{
|
||||
const FHyperTwistSpeechUsageCostDashboardShellProfile Profile =
|
||||
SessionConfig.UsageCostDashboardShellProfileDefinition.IsStructurallyValid()
|
||||
? SessionConfig.UsageCostDashboardShellProfileDefinition
|
||||
: BuildDefaultSpeechUsageCostDashboardShellProfile(
|
||||
!SessionConfig.UsageCostDashboardShellProfileId.IsEmpty()
|
||||
? SessionConfig.UsageCostDashboardShellProfileId
|
||||
: TEXT("speech-provider-usage-cost-dashboard-shell-v1")
|
||||
);
|
||||
|
||||
FHyperTwistSpeechUsageCostDashboardShellState ShellState;
|
||||
ShellState.DashboardShellProfileId = Profile.DashboardShellProfileId;
|
||||
ShellState.ActiveProviderProfileId = SessionConfig.ProviderProfileDefinition.IsStructurallyValid()
|
||||
? SessionConfig.ProviderProfileDefinition.ProviderProfileId
|
||||
: TEXT("speech-provider/local-http-sidecar-profile-v1");
|
||||
ShellState.ActiveProviderDisplayLabel = SessionConfig.ProviderProfileDefinition.IsStructurallyValid()
|
||||
? SessionConfig.ProviderProfileDefinition.DisplayLabel
|
||||
: TEXT("Local HTTP Speech Sidecar");
|
||||
ShellState.ActiveServiceLaneId = !SessionConfig.OrchestrationProfile.ServiceLaneId.IsEmpty()
|
||||
? SessionConfig.OrchestrationProfile.ServiceLaneId
|
||||
: TEXT("speech/python-service");
|
||||
ShellState.ActiveRouteStateId = SessionConfig.ProviderRouteDecision.IsStructurallyValid()
|
||||
? SessionConfig.ProviderRouteDecision.RouteStateId
|
||||
: TEXT("route-ready");
|
||||
ShellState.UsageAggregationWindowId = SessionConfig.UsageEventTemplate.AggregationWindowId;
|
||||
ShellState.CostAggregationWindowId = SessionConfig.CostEventTemplate.AggregationWindowId;
|
||||
ShellState.UsageMeterKind = SessionConfig.UsageEventTemplate.MeterKind;
|
||||
ShellState.CurrencyCode = SessionConfig.CostEventTemplate.CurrencyCode;
|
||||
ShellState.LatestUsageEventId = SessionConfig.UsageEventTemplate.UsageEventId;
|
||||
ShellState.LatestCostEventId = SessionConfig.CostEventTemplate.CostEventId;
|
||||
ShellState.LatestQuotaStateId = TEXT("speech-quota-state/uninitialized");
|
||||
ShellState.LatestRouteDecisionId = SessionConfig.ProviderRouteDecision.IsStructurallyValid()
|
||||
? SessionConfig.ProviderRouteDecision.RouteDecisionId
|
||||
: TEXT("speech-route-decision/uninitialized");
|
||||
for (const FHyperTwistSpeechShellActionBinding& ActionBinding : Profile.ActionBindings)
|
||||
{
|
||||
ShellState.AvailableActionIds.AddUnique(ActionBinding.ActionId);
|
||||
}
|
||||
|
||||
if (PriorState != nullptr && PriorState->UsageCostDashboardShellState.IsStructurallyValid())
|
||||
{
|
||||
ShellState = PriorState->UsageCostDashboardShellState;
|
||||
ShellState.DashboardShellProfileId = Profile.DashboardShellProfileId;
|
||||
}
|
||||
|
||||
return ShellState;
|
||||
}
|
||||
|
||||
FHyperTwistVisionCorrectionState BuildClassicCubeCorrectionState(
|
||||
const FHyperTwistVisionSessionConfig& SessionConfig,
|
||||
const FHyperTwistVisionReconstructionSession& ReconstructionSession,
|
||||
|
|
@ -9779,6 +10194,9 @@ FHyperTwistSpeechTranscriptResult UHyperTwistTrainingSubsystem::SubmitActiveComp
|
|||
HyperTwistTrainingSubsystemInternal::SynchronizeSpeechMicrophoneShellState(
|
||||
ActiveCompanionSpeechSessionState
|
||||
);
|
||||
HyperTwistTrainingSubsystemInternal::SynchronizeSpeechUsageCostDashboardState(
|
||||
ActiveCompanionSpeechSessionState
|
||||
);
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
|
@ -10693,6 +11111,9 @@ void UHyperTwistTrainingSubsystem::RefreshCompanionSpeechServiceHealth()
|
|||
HyperTwistTrainingSubsystemInternal::SynchronizeSpeechMicrophoneShellState(
|
||||
ActiveCompanionSpeechSessionState
|
||||
);
|
||||
HyperTwistTrainingSubsystemInternal::SynchronizeSpeechUsageCostDashboardState(
|
||||
ActiveCompanionSpeechSessionState
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -10718,6 +11139,9 @@ void UHyperTwistTrainingSubsystem::RefreshCompanionSpeechServiceHealth()
|
|||
HyperTwistTrainingSubsystemInternal::SynchronizeSpeechMicrophoneShellState(
|
||||
ActiveCompanionSpeechSessionState
|
||||
);
|
||||
HyperTwistTrainingSubsystemInternal::SynchronizeSpeechUsageCostDashboardState(
|
||||
ActiveCompanionSpeechSessionState
|
||||
);
|
||||
}
|
||||
|
||||
void UHyperTwistTrainingSubsystem::AppendRecognitionReplayEvent(
|
||||
|
|
|
|||
|
|
@ -2575,6 +2575,300 @@ struct FHyperTwistSpeechQuotaRateLimitState
|
|||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistSpeechUsageCostDashboardShellProfile
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DashboardShellProfileId = TEXT("speech-provider-usage-cost-dashboard-shell-v1");
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ShellKind = TEXT("operator-usage-cost-dashboard");
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString UsageSurfaceMode = TEXT("normalized-usage-summary-card");
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString CostSurfaceMode = TEXT("estimate-first-cost-card");
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString EscalationBannerMode = TEXT("route-and-budget-posture-banner");
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString RefreshActionId = TEXT("refresh-provider-usage-cost-dashboard");
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString RouteInspectActionId = TEXT("inspect-provider-route");
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString BudgetInspectActionId = TEXT("review-provider-budget");
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bSupportsProviderSummary = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bSupportsEstimateBadges = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bSupportsQuotaEscalationBanner = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bSupportsRouteDiagnostics = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FHyperTwistSpeechShellPanelLayout> Panels;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FHyperTwistSpeechShellActionBinding> ActionBindings;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
if (DashboardShellProfileId.IsEmpty()
|
||||
|| ShellKind.IsEmpty()
|
||||
|| UsageSurfaceMode.IsEmpty()
|
||||
|| CostSurfaceMode.IsEmpty()
|
||||
|| EscalationBannerMode.IsEmpty()
|
||||
|| RefreshActionId.IsEmpty()
|
||||
|| RouteInspectActionId.IsEmpty()
|
||||
|| BudgetInspectActionId.IsEmpty()
|
||||
|| Panels.Num() <= 0
|
||||
|| ActionBindings.Num() <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const FHyperTwistSpeechShellPanelLayout& Panel : Panels)
|
||||
{
|
||||
if (!Panel.IsStructurallyValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (const FHyperTwistSpeechShellActionBinding& ActionBinding : ActionBindings)
|
||||
{
|
||||
if (!ActionBinding.IsStructurallyValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistSpeechUsageCostDashboardIssue
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString IssueId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString IssueKind;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString StatusLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DetailLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString RecommendedActionId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bRequiresOperatorAttention = true;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !IssueId.IsEmpty()
|
||||
&& !IssueKind.IsEmpty()
|
||||
&& !StatusLine.IsEmpty()
|
||||
&& !DetailLine.IsEmpty()
|
||||
&& !RecommendedActionId.IsEmpty();
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistSpeechUsageCostDashboardShellState
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DashboardShellProfileId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ActiveProviderProfileId = TEXT("speech-provider/local-http-sidecar-profile-v1");
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ActiveProviderDisplayLabel = TEXT("Local HTTP Speech Sidecar");
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ActiveServiceLaneId = TEXT("speech/python-service");
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ActiveRouteStateId = TEXT("route-ready");
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString UsageAggregationWindowId = TEXT("service-health-window");
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString CostAggregationWindowId = TEXT("service-health-window");
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString UsageMeterKind = TEXT("audio-seconds");
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString CurrencyCode = TEXT("USD");
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString StatusLine = TEXT("Provider usage and budget posture within current bounds.");
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DetailLine = TEXT("Normalized usage, cost, and quota posture are ready for operator review.");
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString LatestUsageEventId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString LatestCostEventId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString LatestQuotaStateId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString LatestRouteDecisionId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float DisplayedUsageQuantity = 0.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float DisplayedEstimatedCostUsd = 0.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float DisplayedReportedCostUsd = 0.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float RemainingEstimatedSpendUsd = 0.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 RemainingRequestCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 RemainingAudioSeconds = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bDashboardVisible = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bProviderSummaryVisible = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bUsageCardVisible = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bCostCardVisible = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bQuotaCardVisible = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bRouteDiagnosticsVisible = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bEstimateBadgeVisible = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bEscalationBannerVisible = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bProviderReceiptPosted = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bQuotaKnown = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bRateLimited = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHardBlocked = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bRouteReady = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 ActiveIssueCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FHyperTwistSpeechUsageCostDashboardIssue ActiveIssue;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FHyperTwistSpeechUsageCostDashboardIssue> Issues;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FString> AvailableActionIds;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
if (DashboardShellProfileId.IsEmpty()
|
||||
|| ActiveProviderProfileId.IsEmpty()
|
||||
|| ActiveProviderDisplayLabel.IsEmpty()
|
||||
|| ActiveServiceLaneId.IsEmpty()
|
||||
|| ActiveRouteStateId.IsEmpty()
|
||||
|| UsageAggregationWindowId.IsEmpty()
|
||||
|| CostAggregationWindowId.IsEmpty()
|
||||
|| UsageMeterKind.IsEmpty()
|
||||
|| CurrencyCode.IsEmpty()
|
||||
|| StatusLine.IsEmpty()
|
||||
|| DetailLine.IsEmpty()
|
||||
|| LatestUsageEventId.IsEmpty()
|
||||
|| LatestCostEventId.IsEmpty()
|
||||
|| LatestQuotaStateId.IsEmpty()
|
||||
|| LatestRouteDecisionId.IsEmpty()
|
||||
|| DisplayedUsageQuantity < 0.0f
|
||||
|| DisplayedEstimatedCostUsd < 0.0f
|
||||
|| DisplayedReportedCostUsd < 0.0f
|
||||
|| RemainingEstimatedSpendUsd < 0.0f
|
||||
|| RemainingRequestCount < 0
|
||||
|| RemainingAudioSeconds < 0
|
||||
|| ActiveIssueCount < 0
|
||||
|| AvailableActionIds.Num() <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ActiveIssueCount != Issues.Num())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ActiveIssueCount > 0 && !ActiveIssue.IsStructurallyValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const FHyperTwistSpeechUsageCostDashboardIssue& Issue : Issues)
|
||||
{
|
||||
if (!Issue.IsStructurallyValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (const FString& ActionId : AvailableActionIds)
|
||||
{
|
||||
if (ActionId.IsEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistSpeechSessionConfig
|
||||
{
|
||||
|
|
@ -2646,6 +2940,12 @@ struct FHyperTwistSpeechSessionConfig
|
|||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FHyperTwistSpeechNormalizedCostEvent CostEventTemplate;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString UsageCostDashboardShellProfileId = TEXT("speech-provider-usage-cost-dashboard-shell-v1");
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FHyperTwistSpeechUsageCostDashboardShellProfile UsageCostDashboardShellProfileDefinition;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString PayloadCustodyProfileId = TEXT("downloadable-model-payload-custody-v1");
|
||||
|
||||
|
|
@ -2692,6 +2992,8 @@ struct FHyperTwistSpeechSessionConfig
|
|||
|| !UsageCostAccountingProfileDefinition.IsStructurallyValid()
|
||||
|| !UsageEventTemplate.IsStructurallyValid()
|
||||
|| !CostEventTemplate.IsStructurallyValid()
|
||||
|| UsageCostDashboardShellProfileId.IsEmpty()
|
||||
|| !UsageCostDashboardShellProfileDefinition.IsStructurallyValid()
|
||||
|| PayloadCustodyProfileId.IsEmpty()
|
||||
|| !PayloadCustodyProfileDefinition.IsStructurallyValid()
|
||||
|| RequiredModelPayloads.Num() <= 0
|
||||
|
|
|
|||
|
|
@ -1940,6 +1940,9 @@ struct FHyperTwistTrainingCompanionSpeechSessionState
|
|||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FHyperTwistSpeechMicrophoneShellState MicrophoneShellState;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FHyperTwistSpeechUsageCostDashboardShellState UsageCostDashboardShellState;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FHyperTwistSpeechTranscriptResult LastTranscriptResult;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,267 @@
|
|||
// Copyright HyperTwist, Inc. All Rights Reserved.
|
||||
|
||||
#include "Misc/AutomationTest.h"
|
||||
|
||||
#include "Engine/GameInstance.h"
|
||||
#include "HyperTwistRecognition/HyperTwistSpeechClient.h"
|
||||
#include "HyperTwistTraining/HyperTwistTrainingSubsystem.h"
|
||||
#include "UObject/UnrealType.h"
|
||||
|
||||
#if WITH_AUTOMATION_TESTS
|
||||
|
||||
namespace HyperTwistWhisperCppPhase6RAATestInternal
|
||||
{
|
||||
FHyperTwistTrainingDeck MakeSpeechDeck()
|
||||
{
|
||||
FHyperTwistTrainingDeck Deck;
|
||||
Deck.DeckId = TEXT("phase6r-aa/provider-usage-cost-dashboard");
|
||||
Deck.Title = TEXT("Phase 6R-AA Provider Usage/Cost Dashboard");
|
||||
Deck.DeliveryModes = {
|
||||
EHyperTwistTrainingDeliveryMode::CoachReviewed
|
||||
};
|
||||
|
||||
FHyperTwistTrainingCase TrainingCase;
|
||||
TrainingCase.CaseId = TEXT("phase6r-aa-case");
|
||||
TrainingCase.PuzzleId = TEXT("cube/3x3x3");
|
||||
TrainingCase.PromptKind = EHyperTwistTrainingPromptKind::Sequence;
|
||||
TrainingCase.PromptLabel = TEXT("Phase 6R-AA Coach Speech");
|
||||
TrainingCase.AllowedDeliveryModes = {
|
||||
EHyperTwistTrainingDeliveryMode::CoachReviewed
|
||||
};
|
||||
Deck.Cases = {TrainingCase};
|
||||
return Deck;
|
||||
}
|
||||
|
||||
void ForceSpeechClientKind(UHyperTwistTrainingSubsystem* TrainingSubsystem, const FString& ClientKind)
|
||||
{
|
||||
if (TrainingSubsystem == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (FStrProperty* SpeechClientKindProperty = FindFProperty<FStrProperty>(
|
||||
UHyperTwistTrainingSubsystem::StaticClass(),
|
||||
TEXT("CompanionSpeechClientKind")
|
||||
))
|
||||
{
|
||||
SpeechClientKindProperty->SetPropertyValue_InContainer(TrainingSubsystem, ClientKind);
|
||||
}
|
||||
}
|
||||
|
||||
UHyperTwistTrainingSubsystem* MakeSpeechSubsystem(const FString& SessionId, const FString& ClientKind)
|
||||
{
|
||||
UGameInstance* GameInstance = NewObject<UGameInstance>(GetTransientPackage());
|
||||
if (GameInstance == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UHyperTwistTrainingSubsystem* TrainingSubsystem = NewObject<UHyperTwistTrainingSubsystem>(GameInstance);
|
||||
if (TrainingSubsystem == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ForceSpeechClientKind(TrainingSubsystem, ClientKind);
|
||||
const FHyperTwistTrainingRunState RunState = TrainingSubsystem->StartTrainingRunFromDeck(
|
||||
MakeSpeechDeck(),
|
||||
TEXT("phase6r-aa-user"),
|
||||
SessionId,
|
||||
EHyperTwistTrainingDeliveryMode::CoachReviewed
|
||||
);
|
||||
return RunState.IsStructurallyValid() ? TrainingSubsystem : nullptr;
|
||||
}
|
||||
|
||||
UHyperTwistHttpSpeechClient* ResolveHttpSpeechClient(UHyperTwistTrainingSubsystem* TrainingSubsystem)
|
||||
{
|
||||
if (TrainingSubsystem == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FString CloseError;
|
||||
TrainingSubsystem->CloseActiveCompanionSpeechSession(CloseError);
|
||||
|
||||
if (FObjectPropertyBase* ClientProperty = FindFProperty<FObjectPropertyBase>(
|
||||
UHyperTwistTrainingSubsystem::StaticClass(),
|
||||
TEXT("ActiveCompanionSpeechClientObject")
|
||||
))
|
||||
{
|
||||
return Cast<UHyperTwistHttpSpeechClient>(
|
||||
ClientProperty->GetObjectPropertyValue_InContainer(TrainingSubsystem)
|
||||
);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool ContainsPanelId(
|
||||
const TArray<FHyperTwistSpeechShellPanelLayout>& Panels,
|
||||
const FString& ExpectedPanelId
|
||||
)
|
||||
{
|
||||
for (const FHyperTwistSpeechShellPanelLayout& Panel : Panels)
|
||||
{
|
||||
if (Panel.PanelId == ExpectedPanelId)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ContainsActionId(
|
||||
const TArray<FHyperTwistSpeechShellActionBinding>& ActionBindings,
|
||||
const FString& ExpectedActionId
|
||||
)
|
||||
{
|
||||
for (const FHyperTwistSpeechShellActionBinding& ActionBinding : ActionBindings)
|
||||
{
|
||||
if (ActionBinding.ActionId == ExpectedActionId)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
||||
FHyperTwistWhisperCppPhase6RAAUsageCostDashboardSessionConfigTest,
|
||||
"HyperTwist.Permissive.WhisperCpp.Phase6R.AA.UsageCostDashboardSessionConfig",
|
||||
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
|
||||
)
|
||||
|
||||
bool FHyperTwistWhisperCppPhase6RAAUsageCostDashboardSessionConfigTest::RunTest(const FString& Parameters)
|
||||
{
|
||||
UHyperTwistTrainingSubsystem* TrainingSubsystem =
|
||||
HyperTwistWhisperCppPhase6RAATestInternal::MakeSpeechSubsystem(
|
||||
TEXT("phase6r-aa-config-session"),
|
||||
TEXT("mock")
|
||||
);
|
||||
TestNotNull(TEXT("The speech subsystem must be constructed for Phase 6R-AA."), TrainingSubsystem);
|
||||
if (TrainingSubsystem == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FString OpenError;
|
||||
TestTrue(TEXT("The mock dashboard route must open a speech session."), TrainingSubsystem->OpenActiveCompanionSpeechSession(OpenError));
|
||||
TestTrue(TEXT("Opening the mock dashboard speech session must not report an error."), OpenError.IsEmpty());
|
||||
|
||||
const FHyperTwistSpeechSessionConfig& Config =
|
||||
TrainingSubsystem->GetActiveCompanionSpeechSessionState().SessionConfig;
|
||||
|
||||
TestTrue(TEXT("The dashboard session config must remain structurally valid."), Config.IsStructurallyValid());
|
||||
TestEqual(TEXT("The dashboard shell profile id must be present."), Config.UsageCostDashboardShellProfileId, TEXT("speech-provider-usage-cost-dashboard-shell-v1"));
|
||||
TestTrue(TEXT("The dashboard shell profile must remain structurally valid."), Config.UsageCostDashboardShellProfileDefinition.IsStructurallyValid());
|
||||
TestEqual(TEXT("The dashboard shell must preserve the operator-facing shell kind."), Config.UsageCostDashboardShellProfileDefinition.ShellKind, TEXT("operator-usage-cost-dashboard"));
|
||||
TestEqual(TEXT("The dashboard shell must preserve the refresh action id."), Config.UsageCostDashboardShellProfileDefinition.RefreshActionId, TEXT("refresh-provider-usage-cost-dashboard"));
|
||||
TestEqual(TEXT("The dashboard shell must preserve the route inspect action id."), Config.UsageCostDashboardShellProfileDefinition.RouteInspectActionId, TEXT("inspect-provider-route"));
|
||||
TestTrue(TEXT("The dashboard shell must support quota escalation banners."), Config.UsageCostDashboardShellProfileDefinition.bSupportsQuotaEscalationBanner);
|
||||
TestTrue(TEXT("The dashboard shell must include the provider summary panel."), HyperTwistWhisperCppPhase6RAATestInternal::ContainsPanelId(Config.UsageCostDashboardShellProfileDefinition.Panels, TEXT("provider-summary-card")));
|
||||
TestTrue(TEXT("The dashboard shell must include the route diagnostics action."), HyperTwistWhisperCppPhase6RAATestInternal::ContainsActionId(Config.UsageCostDashboardShellProfileDefinition.ActionBindings, TEXT("inspect-provider-route")));
|
||||
return true;
|
||||
}
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
||||
FHyperTwistWhisperCppPhase6RAAUsageCostDashboardShellStateTest,
|
||||
"HyperTwist.Permissive.WhisperCpp.Phase6R.AA.UsageCostDashboardShellState",
|
||||
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
|
||||
)
|
||||
|
||||
bool FHyperTwistWhisperCppPhase6RAAUsageCostDashboardShellStateTest::RunTest(const FString& Parameters)
|
||||
{
|
||||
UHyperTwistTrainingSubsystem* TrainingSubsystem =
|
||||
HyperTwistWhisperCppPhase6RAATestInternal::MakeSpeechSubsystem(
|
||||
TEXT("phase6r-aa-shell-session"),
|
||||
TEXT("mock")
|
||||
);
|
||||
TestNotNull(TEXT("The speech subsystem must be constructed for Phase 6R-AA."), TrainingSubsystem);
|
||||
if (TrainingSubsystem == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FString OpenError;
|
||||
TestTrue(TEXT("The mock dashboard route must open a speech session."), TrainingSubsystem->OpenActiveCompanionSpeechSession(OpenError));
|
||||
TestTrue(TEXT("Opening the mock dashboard speech session must not report an error."), OpenError.IsEmpty());
|
||||
|
||||
const FHyperTwistTrainingCompanionSpeechSessionState SessionState =
|
||||
TrainingSubsystem->GetActiveCompanionSpeechSessionState();
|
||||
const FHyperTwistSpeechServiceHealth& Health = SessionState.ServiceHealth;
|
||||
const FHyperTwistSpeechUsageCostDashboardShellState& Dashboard =
|
||||
SessionState.UsageCostDashboardShellState;
|
||||
|
||||
TestTrue(TEXT("The service health must expose the usage/cost dashboard shell."), Health.Capabilities.Contains(TEXT("providerUsageCostDashboardShell")));
|
||||
TestTrue(TEXT("The service health must expose the quota escalation banner capability."), Health.Capabilities.Contains(TEXT("providerQuotaEscalationBanner")));
|
||||
TestTrue(TEXT("The service health must expose the route cost diagnostics capability."), Health.Capabilities.Contains(TEXT("providerRouteCostDiagnostics")));
|
||||
|
||||
TestTrue(TEXT("The dashboard shell state must remain structurally valid."), Dashboard.IsStructurallyValid());
|
||||
TestEqual(TEXT("The dashboard shell must preserve the mock provider profile."), Dashboard.ActiveProviderProfileId, TEXT("speech-provider/mock-offline-profile-v1"));
|
||||
TestEqual(TEXT("The dashboard shell must preserve the ready route state."), Dashboard.ActiveRouteStateId, TEXT("route-ready"));
|
||||
TestTrue(TEXT("The dashboard shell must preserve estimate badge visibility."), Dashboard.bEstimateBadgeVisible);
|
||||
TestTrue(TEXT("The dashboard shell must preserve quota visibility."), Dashboard.bQuotaKnown);
|
||||
TestFalse(TEXT("The dashboard shell must not escalate healthy mock posture."), Dashboard.bEscalationBannerVisible);
|
||||
TestEqual(TEXT("The dashboard shell must preserve zero active issues on the healthy mock route."), Dashboard.ActiveIssueCount, 0);
|
||||
TestTrue(TEXT("The dashboard shell must preserve the refresh action."), Dashboard.AvailableActionIds.Contains(TEXT("refresh-provider-usage-cost-dashboard")));
|
||||
TestTrue(TEXT("The dashboard shell must preserve the budget review action."), Dashboard.AvailableActionIds.Contains(TEXT("review-provider-budget")));
|
||||
TestTrue(TEXT("The dashboard shell must surface the mock usage quantity."), FMath::IsNearlyEqual(Dashboard.DisplayedUsageQuantity, 0.75f));
|
||||
TestTrue(TEXT("The dashboard shell must surface the mock estimated cost."), FMath::IsNearlyEqual(Dashboard.DisplayedEstimatedCostUsd, 0.01f));
|
||||
return true;
|
||||
}
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
||||
FHyperTwistWhisperCppPhase6RAAProviderBackedDashboardFallbackTest,
|
||||
"HyperTwist.Permissive.WhisperCpp.Phase6R.AA.ProviderBackedDashboardFallback",
|
||||
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
|
||||
)
|
||||
|
||||
bool FHyperTwistWhisperCppPhase6RAAProviderBackedDashboardFallbackTest::RunTest(const FString& Parameters)
|
||||
{
|
||||
UHyperTwistTrainingSubsystem* TrainingSubsystem =
|
||||
HyperTwistWhisperCppPhase6RAATestInternal::MakeSpeechSubsystem(
|
||||
TEXT("phase6r-aa-provider-session"),
|
||||
TEXT("http-sidecar")
|
||||
);
|
||||
TestNotNull(TEXT("The speech subsystem must be constructed for Phase 6R-AA."), TrainingSubsystem);
|
||||
if (TrainingSubsystem == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
UHyperTwistHttpSpeechClient* HttpSpeechClient =
|
||||
HyperTwistWhisperCppPhase6RAATestInternal::ResolveHttpSpeechClient(TrainingSubsystem);
|
||||
TestNotNull(TEXT("The provider-backed speech client must be available for the dashboard fallback test."), HttpSpeechClient);
|
||||
if (HttpSpeechClient == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
HttpSpeechClient->ServiceBaseUrl.Reset();
|
||||
|
||||
FString OpenError;
|
||||
TestFalse(TEXT("The provider-backed dashboard path must fail cleanly when no provider endpoint is configured."), TrainingSubsystem->OpenActiveCompanionSpeechSession(OpenError));
|
||||
TestEqual(TEXT("The provider-backed dashboard path must report the missing service base URL."), OpenError, TEXT("service-base-url-missing"));
|
||||
|
||||
const FHyperTwistTrainingCompanionSpeechSessionState SessionState =
|
||||
TrainingSubsystem->GetActiveCompanionSpeechSessionState();
|
||||
const FHyperTwistSpeechUsageCostDashboardShellState& Dashboard =
|
||||
SessionState.UsageCostDashboardShellState;
|
||||
|
||||
TestTrue(TEXT("The provider-backed dashboard fallback must remain structurally valid."), Dashboard.IsStructurallyValid());
|
||||
TestEqual(TEXT("The fallback dashboard must preserve the sidecar profile id."), Dashboard.ActiveProviderProfileId, TEXT("speech-provider/local-http-sidecar-profile-v1"));
|
||||
TestEqual(TEXT("The fallback dashboard must preserve the awaiting-endpoint route state."), Dashboard.ActiveRouteStateId, TEXT("route-awaiting-endpoint"));
|
||||
TestFalse(TEXT("The fallback dashboard must expose an unready route."), Dashboard.bRouteReady);
|
||||
TestFalse(TEXT("The fallback dashboard must keep quota unknown during route failure."), Dashboard.bQuotaKnown);
|
||||
TestTrue(TEXT("The fallback dashboard must escalate route failure posture."), Dashboard.bEscalationBannerVisible);
|
||||
TestEqual(TEXT("The fallback dashboard must surface one active issue."), Dashboard.ActiveIssueCount, 1);
|
||||
TestEqual(TEXT("The fallback dashboard must surface the route-degraded issue kind."), Dashboard.ActiveIssue.IssueKind, TEXT("route-degraded"));
|
||||
TestEqual(TEXT("The fallback dashboard must preserve the route inspect action."), Dashboard.ActiveIssue.RecommendedActionId, TEXT("inspect-provider-route"));
|
||||
TestTrue(TEXT("The fallback dashboard detail line must preserve the missing-endpoint reason."), Dashboard.DetailLine.Contains(TEXT("service-base-url-missing")));
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -191,8 +191,12 @@ Status update on `2026-05-21`:
|
|||
pass is now consumed
|
||||
- the bounded first-party `Phase 6R-Z` normalized usage/cost event-model packet is now landed in
|
||||
current code
|
||||
- the current next bounded move is a source-backed `Phase 6R-AA` first-party operator-facing
|
||||
provider usage/cost dashboard shell preparation/control pass, not a new restrictive packet by
|
||||
- the generic source-backed `Phase 6R-AA` first-party operator-facing provider usage/cost
|
||||
dashboard shell control pass is now consumed
|
||||
- the bounded first-party `Phase 6R-AA` operator-facing provider usage/cost dashboard shell
|
||||
packet is now landed in current code
|
||||
- the current next bounded move is a source-backed `Phase 6R-AB` first-party provider
|
||||
usage/cost history/export shell preparation/control pass, not a new restrictive packet by
|
||||
default
|
||||
- use the repo-row README census, the portfolio standing refresh backfill, and the `2R-A`
|
||||
ownership contract for the current queue after that correction
|
||||
|
|
@ -342,8 +346,8 @@ Current practical interpretation:
|
|||
- the landed `PostHog/posthog` boundary-sensitive widening packet now lives in `docs/HYPERTWIST_PHASE_4R_PACKET_4R_D_POSTHOG_CONTROL_PLANE_IMPLEMENTATION_2026-05-13.md`
|
||||
- the landed `screenpipe/screenpipe` boundary-sensitive widening packet now lives in `docs/HYPERTWIST_PHASE_4R_PACKET_4R_E_SCREENPIPE_CAPTURE_HISTORY_IMPLEMENTATION_2026-05-13.md`
|
||||
- the landed `remotion-dev/remotion` boundary-sensitive widening packet now lives in `docs/HYPERTWIST_PHASE_4R_PACKET_4R_F_REMOTION_MEDIA_EXPORT_IMPLEMENTATION_2026-05-13.md`
|
||||
- the next bounded move is a source-backed `Phase 6R-Z` first-party normalized usage/cost
|
||||
event-model preparation/control pass
|
||||
- the next bounded move is a source-backed `Phase 6R-AB` first-party provider usage/cost
|
||||
history/export shell preparation/control pass
|
||||
|
||||
Companion docs:
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,159 @@
|
|||
# HyperTwist Phase 6R-AA first-party operator-facing provider usage/cost dashboard shell implementation packet
|
||||
|
||||
Created on `2026-05-25`
|
||||
|
||||
## Status
|
||||
|
||||
- first-party HyperTwist packet
|
||||
- bounded `Phase 6R-AA` implementation slice
|
||||
|
||||
## Purpose
|
||||
|
||||
This packet lands the next bounded first-party slice above the landed speech
|
||||
session, microphone-shell, payload-custody, provider-custody,
|
||||
provider-routing, and normalized usage/cost event seams.
|
||||
|
||||
The landed slice is:
|
||||
|
||||
- first-party operator-facing provider usage/cost dashboard shell
|
||||
|
||||
It is not:
|
||||
|
||||
- an actual billing export packet
|
||||
- an actual charge-settlement packet
|
||||
- a usage/cost history export packet
|
||||
- an actual payload-shipping packet
|
||||
- a real device-permission workflow packet
|
||||
- a native audio-device route ownership packet
|
||||
- a provider-specific overlay packet
|
||||
- a broad assistant-platform packet
|
||||
|
||||
## Current authority basis
|
||||
|
||||
This implementation packet stands on:
|
||||
|
||||
- `docs/ops/HYPERTWIST_PROVIDER_NEUTRALITY_AND_BYOK_DOCTRINE_2026-05-21.md`
|
||||
- `docs/arch/HYPERTWIST_PHASE6R_AA_FIRST_PARTY_OPERATOR_FACING_PROVIDER_USAGE_COST_DASHBOARD_SHELL_PREPARATION_PACKET_2026-05-25.md`
|
||||
- `docs/arch/HYPERTWIST_PHASE6R_Z_FIRST_PARTY_NORMALIZED_USAGE_COST_EVENT_MODEL_IMPLEMENTATION_PACKET_2026-05-25.md`
|
||||
|
||||
The preserved owners do not change:
|
||||
|
||||
- first-party HyperTwist remains the top-level provider/session owner
|
||||
- first-party HyperTwist remains the usage/cost governance owner
|
||||
- `ggml-org/whisper.cpp` remains bounded to offline STT donor seams
|
||||
- `SYSTRAN/faster-whisper` remains bounded to complementary Python
|
||||
orchestration/service-lane seams
|
||||
|
||||
## Landed scope
|
||||
|
||||
The current code now owns a bounded operator-facing dashboard seam through:
|
||||
|
||||
- retained recognition contract types for:
|
||||
- `FHyperTwistSpeechUsageCostDashboardShellProfile`
|
||||
- `FHyperTwistSpeechUsageCostDashboardIssue`
|
||||
- `FHyperTwistSpeechUsageCostDashboardShellState`
|
||||
- expanded `FHyperTwistSpeechSessionConfig`
|
||||
- expanded `FHyperTwistTrainingCompanionSpeechSessionState`
|
||||
- contract-library defaults for:
|
||||
- dashboard shell profile ids and definitions
|
||||
- dashboard panel ids and action bindings
|
||||
- service-health capability exposure
|
||||
- active companion session-config and service-health dashboard composition in:
|
||||
- `UHyperTwistTrainingSubsystem`
|
||||
- direct speech-client health capability exposure in:
|
||||
- `UHyperTwistHttpSpeechClient`
|
||||
- `UHyperTwistMockSpeechClient`
|
||||
- focused automation coverage in:
|
||||
- `HyperTwistWhisperCppPhase6RAAUsageCostDashboardShellContractTest.cpp`
|
||||
|
||||
## Why this is still intentionally bounded
|
||||
|
||||
This packet lands the operator-facing dashboard shell family only.
|
||||
|
||||
Still deferred:
|
||||
|
||||
- provider usage/cost history/export shell surfaces
|
||||
- actual billing export or settlement
|
||||
- actual downloadable model/payload shipping
|
||||
- real device-permission workflow
|
||||
- native audio-device route ownership beyond bounded shell posture
|
||||
- broad assistant-platform scope
|
||||
|
||||
## Validation
|
||||
|
||||
Build validation:
|
||||
|
||||
- `UnrealHyperTwistEditor Win64 Development`
|
||||
|
||||
Focused automation validation:
|
||||
|
||||
- `HyperTwist.Permissive.WhisperCpp.Phase6R.AA` `3/3`
|
||||
|
||||
Regression automation validation:
|
||||
|
||||
- `HyperTwist.Permissive.WhisperCpp.Phase6R.Z` `3/3`
|
||||
- `HyperTwist.Permissive.WhisperCpp.Phase6R.Y` `3/3`
|
||||
- `HyperTwist.Permissive.WhisperCpp.Phase6R.X` `3/3`
|
||||
- `HyperTwist.Permissive.WhisperCpp.Phase6R.W` `3/3`
|
||||
- `HyperTwist.Permissive.WhisperCpp.Phase6R.V` `3/3`
|
||||
- `HyperTwist.Permissive.WhisperCpp.Phase6R.U` `3/3`
|
||||
- `HyperTwist.Permissive.WhisperCpp.Phase6R.E` `3/3`
|
||||
- `HyperTwist.Permissive.FasterWhisper.Phase6R.F` `3/3`
|
||||
- `HyperTwist.Permissive.Piper.Phase6R.G` `3/3`
|
||||
- `HyperTwist.Permissive.Coqui.Phase6R.H` `3/3`
|
||||
- `HyperTwist.CleanRoom.CubeDesk` `14/14`
|
||||
|
||||
Non-blocking warnings stayed limited to the existing Unreal headless/editor
|
||||
noise, the pre-existing plugin dependency warning on `UnrealMCP`, and the
|
||||
known `http:/speech/health` and `http:/vision/health` hostname-resolution
|
||||
warnings in provider-backed automation.
|
||||
|
||||
## Queue effect
|
||||
|
||||
This packet consumes the current `Phase 6R-AA` implementation slice.
|
||||
|
||||
`ggml-org/whisper.cpp` remains only partially incorporated:
|
||||
|
||||
- landed now:
|
||||
- speech transcript session boundary
|
||||
- live microphone shell boundary
|
||||
- device-permission and capture-route readiness shell posture
|
||||
- downloadable model and payload custody boundary
|
||||
- first-party provider-profile and BYOK custody boundary
|
||||
- first-party provider routing and workflow-policy boundary
|
||||
- first-party normalized usage/cost event-model boundary
|
||||
- first-party operator-facing provider usage/cost dashboard shell boundary
|
||||
for:
|
||||
- dashboard shell profile ids and definitions
|
||||
- dashboard issue and shell-state posture
|
||||
- companion-session dashboard composition
|
||||
- capability exposure for:
|
||||
- `providerUsageCostDashboardShell`
|
||||
- `providerQuotaEscalationBanner`
|
||||
- `providerRouteCostDiagnostics`
|
||||
- still deferred:
|
||||
- provider usage/cost history/export shell surfaces
|
||||
- actual downloadable model/payload shipping
|
||||
- actual billing export or settlement
|
||||
- real device-permission workflow
|
||||
- native audio-device route ownership beyond bounded shell posture
|
||||
- broad assistant-platform scope
|
||||
|
||||
The next clean move is:
|
||||
|
||||
- a source-backed `Phase 6R-AB` first-party provider usage/cost history/export
|
||||
shell preparation/control pass
|
||||
|
||||
Keep the future sequencing guards visible:
|
||||
|
||||
- first-party HyperTwist
|
||||
- keep the top-level provider/session contract, routing/policy lane,
|
||||
usage/cost governance lane, and operator-facing dashboard shell lane
|
||||
first-party
|
||||
- `ggml-org/whisper.cpp`
|
||||
- keep code-license judgments separate from actual model or payload shipping
|
||||
review in any follow-on packet
|
||||
- `SYSTRAN/faster-whisper`
|
||||
- keep the row complementary to the landed provider/session, custody,
|
||||
routing, usage/cost, and dashboard seams rather than widening it into
|
||||
usage/cost history/export ownership
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
# HyperTwist Phase 6R-AA first-party operator-facing provider usage/cost dashboard shell preparation packet
|
||||
|
||||
Created on `2026-05-25`
|
||||
|
||||
## Status
|
||||
|
||||
- first-party HyperTwist packet
|
||||
- source-backed `Phase 6R-AA` preparation/control slice
|
||||
|
||||
## Purpose
|
||||
|
||||
This packet scopes the next bounded first-party slice above the landed speech
|
||||
session, microphone-shell, payload-custody, provider-custody,
|
||||
provider-routing, and normalized usage/cost event seams.
|
||||
|
||||
The granted slice is:
|
||||
|
||||
- first-party operator-facing provider usage/cost dashboard shell only
|
||||
|
||||
It is not:
|
||||
|
||||
- an actual billing or charge-settlement packet
|
||||
- a usage/cost history export packet
|
||||
- an actual payload-shipping packet
|
||||
- a real device-permission workflow packet
|
||||
- a native audio-device route ownership packet
|
||||
- a provider-specific overlay packet
|
||||
- a voice-output packet
|
||||
- a broad assistant-platform packet
|
||||
|
||||
## Current authority basis
|
||||
|
||||
This control pass stands on:
|
||||
|
||||
- `docs/ops/HYPERTWIST_PROVIDER_NEUTRALITY_AND_BYOK_DOCTRINE_2026-05-21.md`
|
||||
- `docs/arch/HYPERTWIST_PHASE6R_Z_FIRST_PARTY_NORMALIZED_USAGE_COST_EVENT_MODEL_IMPLEMENTATION_PACKET_2026-05-25.md`
|
||||
- `docs/v6_5_deep_manual_pack/HyperTwist/ROADMAP.md`
|
||||
|
||||
The preserved owners do not change here:
|
||||
|
||||
- first-party HyperTwist remains the top-level provider/session owner
|
||||
- first-party HyperTwist remains the usage/cost governance owner
|
||||
- `ggml-org/whisper.cpp` remains bounded to offline STT donor seams
|
||||
- `SYSTRAN/faster-whisper` remains bounded to complementary Python
|
||||
orchestration/service-lane seams
|
||||
|
||||
## Granted family
|
||||
|
||||
The bounded `Phase 6R-AA` slice may land:
|
||||
|
||||
1. first-party operator-facing usage/cost dashboard shell profile ids and
|
||||
definitions
|
||||
2. dashboard issue and shell-state record shapes
|
||||
3. session-config and companion-session-state expansion for those shapes
|
||||
4. bounded capability exposure for:
|
||||
- `providerUsageCostDashboardShell`
|
||||
- `providerQuotaEscalationBanner`
|
||||
- `providerRouteCostDiagnostics`
|
||||
5. focused automation for mock healthy posture and provider-backed fallback
|
||||
posture
|
||||
|
||||
The packet must stay out of:
|
||||
|
||||
- actual billing export, settlement, or invoice reconciliation
|
||||
- actual payload download or redistribution ownership
|
||||
- real device-permission workflow ownership
|
||||
- native audio-device route ownership
|
||||
- provider-specific dashboard skinning
|
||||
|
||||
## Proposed implementation shape
|
||||
|
||||
Land the narrower first-party boundary through:
|
||||
|
||||
- retained recognition contract types for:
|
||||
- usage/cost dashboard shell profile
|
||||
- dashboard issue
|
||||
- dashboard shell state
|
||||
- expanded speech session config
|
||||
- expanded companion speech session state
|
||||
- contract-library defaults for:
|
||||
- dashboard shell profile ids and definitions
|
||||
- dashboard action bindings and panel ids
|
||||
- service-health capability exposure
|
||||
- training-subsystem composition for:
|
||||
- provider summary posture
|
||||
- route diagnostics posture
|
||||
- usage and cost summary cards
|
||||
- quota escalation banner posture
|
||||
- provider-backed fallback issue posture
|
||||
- direct speech-client health capability exposure for:
|
||||
- `providerUsageCostDashboardShell`
|
||||
- `providerQuotaEscalationBanner`
|
||||
- `providerRouteCostDiagnostics`
|
||||
|
||||
## Validation target
|
||||
|
||||
Validate with:
|
||||
|
||||
- Unreal build for `UnrealHyperTwistEditor Win64 Development`
|
||||
- focused automation:
|
||||
- `HyperTwist.Permissive.WhisperCpp.Phase6R.AA`
|
||||
- regressions:
|
||||
- `HyperTwist.Permissive.WhisperCpp.Phase6R.Z`
|
||||
- `HyperTwist.Permissive.WhisperCpp.Phase6R.Y`
|
||||
- `HyperTwist.Permissive.WhisperCpp.Phase6R.X`
|
||||
- `HyperTwist.Permissive.WhisperCpp.Phase6R.W`
|
||||
- `HyperTwist.Permissive.WhisperCpp.Phase6R.V`
|
||||
- `HyperTwist.Permissive.WhisperCpp.Phase6R.U`
|
||||
- `HyperTwist.Permissive.WhisperCpp.Phase6R.E`
|
||||
- `HyperTwist.Permissive.FasterWhisper.Phase6R.F`
|
||||
- `HyperTwist.Permissive.Piper.Phase6R.G`
|
||||
- `HyperTwist.Permissive.Coqui.Phase6R.H`
|
||||
- `HyperTwist.CleanRoom.CubeDesk`
|
||||
|
||||
## Queue effect
|
||||
|
||||
If this packet lands cleanly, the next bounded move becomes:
|
||||
|
||||
- a source-backed `Phase 6R-AB` first-party provider usage/cost history/export
|
||||
shell preparation/control pass
|
||||
|
||||
Keep the narrow sequencing guards visible:
|
||||
|
||||
- keep actual billing and settlement separate from dashboard shell ownership
|
||||
- keep actual payload shipping separate from usage/cost governance
|
||||
- keep real device-permission workflow and native capture-route ownership
|
||||
outside this packet
|
||||
|
|
@ -168,15 +168,19 @@ The next bounded move is now:
|
|||
control pass is now consumed
|
||||
26. the bounded first-party `Phase 6R-Z` normalized usage/cost event-model packet is now
|
||||
landed in current code
|
||||
27. the next bounded move is a source-backed `Phase 6R-AA` first-party operator-facing
|
||||
provider usage/cost dashboard shell preparation/control pass
|
||||
28. keep the speech-lane guard visible:
|
||||
27. the generic source-backed `Phase 6R-AA` first-party operator-facing provider usage/cost
|
||||
dashboard shell control pass is now consumed
|
||||
28. the bounded first-party `Phase 6R-AA` operator-facing provider usage/cost dashboard shell
|
||||
packet is now landed in current code
|
||||
29. the next bounded move is a source-backed `Phase 6R-AB` first-party provider usage/cost
|
||||
history/export shell preparation/control pass
|
||||
30. keep the speech-lane guard visible:
|
||||
- keep code-license judgments separate from model, voice, and payload-license review
|
||||
29. keep the provider-neutral speech-lane guard visible:
|
||||
31. keep the provider-neutral speech-lane guard visible:
|
||||
- first-party HyperTwist owns the top-level provider/session contract
|
||||
- `whisper.cpp` and `faster-whisper` may win narrower donor slices without inheriting that
|
||||
lane, the provider routing/policy lane, or the usage/cost governance lane
|
||||
30. keep the `MagicTile` guard visible:
|
||||
32. keep the `MagicTile` guard visible:
|
||||
- keep broad non-Euclidean interaction or WinForms/OpenTK host-shell ownership closed by
|
||||
default unless a narrower first-party gap is proven above the landed macro-remapping seam
|
||||
|
||||
|
|
|
|||
|
|
@ -215,8 +215,9 @@ The correct implementation order is:
|
|||
|
||||
Current landed ordering status:
|
||||
|
||||
- steps `1` through `4` now have bounded first-party implementation anchors
|
||||
- operator-facing overlays remain the next first-party gap
|
||||
- steps `1` through `5` now have bounded first-party implementation anchors
|
||||
- usage/cost history/export shells and actual billing/settlement remain later
|
||||
first-party work
|
||||
- provider-specific adapters remain later work
|
||||
|
||||
Do not invert that order.
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@ Do not collapse those three tiers into one undifferentiated "features" voice.
|
|||
| First-party provider profile and BYOK custody boundary | Implemented now | landed first-party `Phase 6R-X` | First-party provider-profile definitions, BYOK custody definitions, per-profile model/capability maps, and out-of-band auth-reference wording are now live above the landed speech session, shell, and payload-custody seams. |
|
||||
| First-party provider routing and workflow-policy boundary | Implemented now | landed first-party `Phase 6R-Y` | First-party routing-policy ids/definitions, route-decision summaries, fallback-health posture, and workflow-policy capability exposure are now live above the landed provider-custody seam. |
|
||||
| First-party normalized usage/cost event surface | Implemented now | landed first-party `Phase 6R-Z` | First-party accounting-profile definitions, normalized usage/cost event templates and health summaries, quota/rate-limit state, and bounded capability exposure are now live above the landed provider-routing seam. |
|
||||
| First-party operator-facing provider usage/cost dashboard shell | Implemented now | landed first-party `Phase 6R-AA` | First-party dashboard shell profiles, dashboard issue/state objects, quota escalation banners, route diagnostics, and operator-facing panel/action contracts are now live above the landed normalized usage/cost seam. |
|
||||
| Analytics/reporting surfaces | Implemented now | landed analytics/reporting packets | Reporting is real, but bounded to accepted retained slices. |
|
||||
| Browser/spatial/media adjunct surfaces | Implemented now | landed `three.js`, `react-three-fiber`, `xr`, `model-viewer`, `remotion` packets | These are implemented bounded families, not proof of unlimited browser-shell parity. |
|
||||
|
||||
|
|
@ -221,6 +222,7 @@ repo.
|
|||
| Provider-neutral BYOK/profile custody boundary | Implemented now | landed first-party `Phase 6R-X` packet | Current bounded provider-profile ids/definitions, BYOK custody ids/definitions, per-profile model/capability maps, and out-of-band auth-reference wording. |
|
||||
| First-party provider routing and workflow-policy boundary | Implemented now | landed first-party `Phase 6R-Y` packet | Current bounded routing-policy ids/definitions, route-decision summaries, explicit fallback-health posture, and workflow-policy capability exposure above the landed provider/session and provider-custody seams. |
|
||||
| First-party normalized usage/cost event surface | Implemented now | landed first-party `Phase 6R-Z` packet | Current bounded accounting-profile ids/definitions, normalized usage/cost event summaries, quota/rate-limit state, and bounded capability exposure above the landed provider-routing seam. |
|
||||
| First-party operator-facing provider usage/cost dashboard shell | Implemented now | landed first-party `Phase 6R-AA` packet | Current bounded dashboard shell profile ids/definitions, dashboard issue/state posture, and capability exposure above the landed normalized usage/cost seam. |
|
||||
| OpenAI-compatible custom endpoint support | Deep-source grounded retained | doctrine-defined first-party target | First-class target is now represented in the landed custody model, but full routing/runtime support is still deferred. |
|
||||
| Provider-specific overlays | Shallow placeholder | future provider-family work only | Keep internal until source-grounded and normalized. |
|
||||
|
||||
|
|
|
|||
|
|
@ -167,10 +167,14 @@ Canonical discovery surfaces for roadmap interpretation:
|
|||
pass is now consumed
|
||||
- the bounded first-party `Phase 6R-Z` normalized usage/cost event-model packet is now landed in
|
||||
current code
|
||||
- the current next bounded move is a source-backed `Phase 6R-AA` first-party operator-facing
|
||||
provider usage/cost dashboard shell preparation/control pass, while keeping actual billing,
|
||||
real device-permission workflow, native capture-route ownership, and actual payload shipping
|
||||
separately deferred
|
||||
- the generic source-backed `Phase 6R-AA` first-party operator-facing provider usage/cost
|
||||
dashboard shell control pass is now consumed
|
||||
- the bounded first-party `Phase 6R-AA` operator-facing provider usage/cost dashboard shell
|
||||
packet is now landed in current code
|
||||
- the current next bounded move is a source-backed `Phase 6R-AB` first-party provider
|
||||
usage/cost history/export shell preparation/control pass, while keeping actual billing,
|
||||
settlement, real device-permission workflow, native capture-route ownership, and actual
|
||||
payload shipping separately deferred
|
||||
- the repo-row implementation queue is now live from that `Phase 6R-A` entry point rather than
|
||||
waiting on another first-party packet
|
||||
|
||||
|
|
@ -257,16 +261,15 @@ Current routing truth:
|
|||
- `brianpeiris/RiftSketch`
|
||||
- the v6.3 CSV label `not_live_reference_or_discard_candidate` is not the final state by itself; read the closed `0R-E` packet for the retained-versus-discarded split
|
||||
|
||||
The next bounded move is a source-backed `Phase 6R-AA` first-party
|
||||
operator-facing provider usage/cost dashboard shell preparation/control pass.
|
||||
The next bounded move is a source-backed `Phase 6R-AB` first-party provider
|
||||
usage/cost history/export shell preparation/control pass.
|
||||
|
||||
Queue interpretation after that control pass:
|
||||
|
||||
- then continue with the retained repo-row queue
|
||||
- highest current repo-row queue pressure sits in:
|
||||
- the first-party operator-facing provider usage/cost dashboard shell
|
||||
remainder above the
|
||||
partially landed `whisper.cpp` and `faster-whisper` speech seams
|
||||
- the first-party provider usage/cost history/export shell remainder above
|
||||
the partially landed `whisper.cpp` and `faster-whisper` speech seams
|
||||
- `HactarCE/Hyperspeedcube` is now closed for the currently justified retained row:
|
||||
- landed:
|
||||
- puzzle catalog contract
|
||||
|
|
@ -369,8 +372,9 @@ Queue interpretation after that control pass:
|
|||
- normalized usage events
|
||||
- normalized cost events
|
||||
- quota/rate-limit state
|
||||
- operator-facing provider usage/cost dashboard shell
|
||||
- still deferred:
|
||||
- operator-facing provider usage/cost dashboard surfaces
|
||||
- provider usage/cost history/export shell surfaces
|
||||
- real device-permission workflow
|
||||
- native capture-route ownership beyond bounded shell posture
|
||||
- actual downloadable model or payload shipping
|
||||
|
|
@ -418,12 +422,13 @@ Queue interpretation after that control pass:
|
|||
- viseme / gesture runtime integration
|
||||
- broad assistant-platform scope
|
||||
- the next queue shape is now:
|
||||
- first-party normalized usage/cost event-model assessment above the landed speech session,
|
||||
shell, payload-custody, provider-custody, and provider-routing seams
|
||||
- first-party provider usage/cost history/export shell assessment above the landed speech
|
||||
session, shell, payload-custody, provider-custody, provider-routing, normalized usage/cost,
|
||||
and operator-facing dashboard seams
|
||||
- the next bounded move should stay narrow:
|
||||
- a source-backed `Phase 6R-Z` control pass before any widening into actual payload shipping,
|
||||
real device-permission workflow, broad voice-output ownership, or broad assistant-platform
|
||||
scope
|
||||
- a source-backed `Phase 6R-AB` control pass before any widening into actual billing
|
||||
settlement, actual payload shipping, real device-permission workflow, broad voice-output
|
||||
ownership, or broad assistant-platform scope
|
||||
- keep the speech-input / voice sidecar legal sequencing guard visible:
|
||||
- keep code-license judgments separate from model, voice, and payload-license review
|
||||
- keep the provider-neutral speech-lane guard visible:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue