Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 17 additions & 7 deletions src/OpenClaw.SetupEngine.UI/Pages/AiSetupPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -878,6 +878,7 @@ private async Task RunCoreAsync(Func<CancellationToken, Task> action, bool submi
_request.Dispose();
_request = new();
var token = _request.Token;
var reportedFailure = false;
_busy = true;
_activities.Clear();
_activityKey = null;
Expand Down Expand Up @@ -923,6 +924,7 @@ private async Task RunCoreAsync(Func<CancellationToken, Task> action, bool submi
if (Client?.Phase is not (GatewayAiSetupPhase.Running or GatewayAiSetupPhase.Uncertain or
GatewayAiSetupPhase.VerificationRequired or GatewayAiSetupPhase.Prepared))
_providerOperationActive = false;
reportedFailure = true;
ReportFailure(ex);
_activityStatus = SetupInstallationStatus.Failed;
}
Expand All @@ -939,7 +941,7 @@ private async Task RunCoreAsync(Func<CancellationToken, Task> action, bool submi
if (Client?.Phase is GatewayAiSetupPhase.Cancelled or GatewayAiSetupPhase.Rejected)
{
_providerOperationActive = false;
if (Client.Phase == GatewayAiSetupPhase.Rejected)
if (Client.Phase == GatewayAiSetupPhase.Rejected && !reportedFailure)
ShowError("Rejected");
}
Render();
Expand Down Expand Up @@ -1213,12 +1215,21 @@ private bool CanConnectManual() =>
private void Preference_Changed(object sender, RoutedEventArgs e) => Render();
private static string S(string key) => SetupLocalization.GetString("Onboarding_AiSetup_" + key);
private static Visibility Visible(bool value) => value ? Visibility.Visible : Visibility.Collapsed;
private void ShowError(string key)
private void ShowError(string key, string? detail = null)
{
if (BackdropLocked) _providerError = S(key);
var message = S(key);
detail ??= key is "VerificationFailed" or "Rejected"
? Client?.VerificationFailure ?? Client?.Wizard?.Error : null;
if (!string.IsNullOrWhiteSpace(detail))
{
// Rejected is rendered again when the request settles. Retain the exact verification cause.
var sanitized = SetupLogger.Sanitize(detail);
message += " " + sanitized[..Math.Min(sanitized.Length, 2048)];
}
if (BackdropLocked) _providerError = message;
else
{
ErrorBar.Message = S(key);
ErrorBar.Message = message;
ErrorBar.IsOpen = true;
}
Render();
Expand All @@ -1238,9 +1249,8 @@ private void ReportFailure(Exception error)
ShowError(error is LocalAiSelectionRejectedException ? "LocalChanged" :
error is UnauthorizedAccessException ? "AdminRequired" :
Client?.Phase == GatewayAiSetupPhase.Prepared ? "PreparedChanged" :
_localExpectedModel is not null || Client?.RequiresReconciliation == true ? "Uncertain" : "Failed");
if (error is LocalAiSelectionRejectedException)
ErrorBar.Message += " " + error.Message;
_localExpectedModel is not null || Client?.RequiresReconciliation == true ? "Uncertain" : "Failed",
error.Message);
Render();
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/OpenClaw.SetupEngine/GatewayAiSetupClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public sealed class GatewayAiSetupClient(
public GatewayAiSetupWizardResult? Wizard { get; private set; }
public string? SessionId { get; private set; }
public string? VerifiedModelRef { get; private set; }
public string? VerificationFailure { get; private set; }
public bool IsBusy => _busy;
public GatewayAiSetupRoute Route => _route;
public long ConnectionGeneration => transport.Generation;
Expand Down Expand Up @@ -167,6 +168,7 @@ private void Select(GatewayAiSetupChoice choice)
throw new NotSupportedException("This gateway does not advertise the selected setup method.");
Selection = choice;
VerifiedModelRef = null;
VerificationFailure = null;
Phase = GatewayAiSetupPhase.Choosing;
}

Expand Down Expand Up @@ -344,6 +346,7 @@ private async Task<GatewayAiSetupVerification> VerifyRouteAsync(string expected,
{
var generation = transport.Generation;
VerifiedModelRef = null;
VerificationFailure = null;
_verifiedGeneration = 0;
var result = await ExecuteAsync<GatewayAiSetupVerification>("openclaw.setup.verify", RouteParams(), 120_000, ct);
ct.ThrowIfCancellationRequested();
Expand All @@ -354,6 +357,7 @@ private async Task<GatewayAiSetupVerification> VerifyRouteAsync(string expected,
throw new InvalidDataException("Verification did not confirm the selected model.");
if (!result.Ok && (string.IsNullOrWhiteSpace(result.Status) || string.IsNullOrWhiteSpace(result.Error)))
throw new InvalidDataException("The gateway returned an incomplete verification failure.");
VerificationFailure = result.Ok ? null : result.Error;
VerifiedModelRef = result.Ok ? result.ModelRef : null;
_verifiedGeneration = result.Ok ? generation : 0;
return result;
Expand Down
4 changes: 2 additions & 2 deletions tests/OpenClaw.Tray.UITests/OnboardingAiPageTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ await WithPageAsync(async (page, transport, completed) =>
Assert.False(Find<ItemsControl>(page, "CandidateChoices").IsEnabled);
Assert.Equal(0, completed());
typeof(AiSetupPage).GetMethod("ShowError", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)!
.Invoke(page, ["Failed"]);
.Invoke(page, ["Failed", null]);
var error = Find<InfoBar>(page, "ProviderActivityError");
Assert.True(error.IsOpen);
Assert.False(string.IsNullOrWhiteSpace(error.Message));
Expand Down Expand Up @@ -426,7 +426,7 @@ await WithPageAsync(async (page, transport, completed) =>
using (await OnboardingNativeProof.CaptureAsync(ui.TestWindow, $"followup-provider-loading-{theme}", output,
["Connect your AI", "Synthetic provider loading", "Cancel"], requiredContent: page)) { }
typeof(AiSetupPage).GetMethod("ShowError", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)!
.Invoke(page, ["Failed"]);
.Invoke(page, ["Failed", null]);
Assert.True(Find<InfoBar>(page, "ProviderActivityError").IsOpen);
using (await OnboardingNativeProof.CaptureAsync(ui.TestWindow, $"followup-provider-inline-error-{theme}", output,
["Connect your AI", "Cancel"], requiredContent: page)) { }
Expand Down
Loading