Skip to content

[codex] Improve Companion runtime console#120

Merged
Telli merged 6 commits into
mainfrom
codex/companion-runtime-console
May 18, 2026
Merged

[codex] Improve Companion runtime console#120
Telli merged 6 commits into
mainfrom
codex/companion-runtime-console

Conversation

@Telli
Copy link
Copy Markdown
Contributor

@Telli Telli commented May 17, 2026

Summary

  • Refactors the Avalonia Companion into a Runtime Console shell with a cleaner header, left navigation, shared styles, and improved Setup/Chat/Canvas/Approvals/Admin/WhatsApp surfaces.
  • Adds Home, Sessions, Runtime Events, Plugins & Channels, Models & Providers, Workflows, Automations, Memory & Profiles, and Payment Lab screens backed by typed client/VM methods.
  • Adds confirmation dialog plumbing for risky mutation actions plus focused VM/headless coverage for the new shell and gating behavior.

Validation

  • dotnet format OpenClaw.Net.slnx --include ... scoped to touched C# files
  • dotnet build OpenClaw.Net.slnx
  • dotnet test src/OpenClaw.Tests/OpenClaw.Tests.csproj --filter "FullyQualifiedName~Companion|FullyQualifiedName~Integration|FullyQualifiedName~Payment"
  • dotnet test src/OpenClaw.Tests/OpenClaw.Tests.csproj --no-build
  • git diff --check

Summary by CodeRabbit

  • New Features

    • Automations: view run history/details, replay runs, clear quarantine
    • Workflows: list, run, inspect runs, and respond to pending inputs
    • Payments lab: virtual cards, machine payments, status lookup
    • Runtime Console: Sessions, Runtime Events, Dashboard, Plugins & Channels, Profiles, Providers UIs
    • Confirmation dialogs: integrated for destructive/mutation actions
  • UI/Style

    • New companion UI styles for typography, cards, badges, buttons
  • Tests

    • Added UI and runtime-console tests for navigation and key flows

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 17, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 88409b4a-3488-4a0e-a2b9-b2f7c2ce9ac6

📥 Commits

Reviewing files that changed from the base of the PR and between 1c38c83 and 8fa4153.

📒 Files selected for processing (1)
  • src/OpenClaw.Companion/Services/WindowConfirmationDialogService.cs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/OpenClaw.Companion/Services/WindowConfirmationDialogService.cs

📝 Walkthrough

Walkthrough

Extends the Companion UI and client: adds automations/workflows HTTP APIs, confirmation dialog services, UI styles, many MainWindowViewModel feature sections (Automations, Workflows, Sessions, Runtime Events, Payments, Plugins, Profiles, Providers, Dashboard), runtime-console helpers, and tests.

Changes

Companion Runtime Console Feature Expansion

Layer / File(s) Summary
HTTP Client Extension for Automations & Workflows
src/OpenClaw.Client/OpenClawHttpClient.cs
OpenClawHttpClient adds a workflows base Uri and initialization, eight public methods for automation runs (list, detail, replay, clear quarantine) and workflows (list, run, get snapshot, respond), plus private URI builders.
Confirmation Dialog Service & Implementations
src/OpenClaw.Companion/Services/IConfirmationDialogService.cs, src/OpenClaw.Companion/Services/WindowConfirmationDialogService.cs
IConfirmationDialogService contract introduced alongside DenyConfirmationDialogService and WindowConfirmationDialogService; the latter builds and displays modal dialogs with cancellation handling and returns boolean results.
UI Styles, Theme, and Application Setup
src/OpenClaw.Companion/Styles/CompanionStyles.axaml, src/OpenClaw.Companion/App.axaml, src/OpenClaw.Companion/App.axaml.cs
CompanionStyles.axaml defines typography, card/badge, button, and empty-state styles; App.axaml includes the new StyleInclude; App.axaml.cs refactors MainWindow construction to attach WindowConfirmationDialogService.
Message Model Classification
src/OpenClaw.Companion/Models/ChatMessage.cs
ChatMessage adds computed properties to classify role (user/assistant/system), detect tool events/errors via heuristics, and flag streaming placeholders.
Runtime Console Shared Helpers
src/OpenClaw.Companion/ViewModels/MainWindowViewModel.RuntimeConsoleHelpers.cs
Adds navigation command, integration client creation helpers, ConfirmMutationAsync wrapper, collection-replace helper, and formatting utilities for timestamps and compact joins.
Approval Decision Confirmation
src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Approvals.cs
SubmitApprovalDecisionAsync now gates denial and mutation approval with user confirmation prompts; NotifyPendingApprovalsChanged also notifies PendingApprovalsBadge.
Automations View Model Section
src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Automations.cs
MainWindowViewModel.Automations adds observable state, selection handling, and relay commands for load/run (dry/live with confirmation)/delete/replay/clear-quarantine; includes AutomationRow, AutomationTemplateRow, and AutomationRunRow models.
Workflows View Model Section
src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Workflows.cs
MainWindowViewModel.Workflows defines observable state and async commands for load/run/snapshot/respond workflows with confirmation gating and JSON payload parsing; includes WorkflowRow, WorkflowEventRow, and WorkflowPendingInputRow models.
Sessions View Model Section
src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Sessions.cs
MainWindowViewModel.Sessions adds observable filter/pagination state and async commands for session list loading with snippet enrichment, pagination, and selected-session detail/timeline loading; includes SessionRow model.
Runtime Events View Model Section
src/OpenClaw.Companion/ViewModels/MainWindowViewModel.RuntimeEvents.cs
MainWindowViewModel.RuntimeEvents defines observable filter fields and async relay command to load runtime events via RuntimeEventQuery; includes RuntimeEventRow model with timestamp formatting and actor derivation and RawJson preview.
Payments View Model Section
src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Payments.cs
MainWindowViewModel.Payments defines observable payment state and four async commands: load setup, issue virtual card, execute machine payment, and lookup status—each validated and gated with confirmation; includes FundingSourceRow model.
Plugins View Model Section
src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Plugins.cs
MainWindowViewModel.Plugins loads plugins, compatibility catalog, and channels via async relay command, replacing collections with PluginRow and CompatibilityRow mapped objects.
Profiles View Model Section
src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Profiles.cs
MainWindowViewModel.Profiles adds observable state and two async commands to load profiles/memory/learning data and search memory notes; selection triggers detail loading; includes ProfileRow, MemoryNoteRow, and LearningProposalRow models.
Providers View Model Section
src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Providers.cs
MainWindowViewModel.Providers loads provider routes and tool presets via async relay command, populating collections with ProviderRouteRow and ToolPresetRow mapped objects.
Dashboard View Model Section
src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Dashboard.cs
MainWindowViewModel.Dashboard loads dashboard counters/approval history/recent events/channel readiness and includes ChannelReadinessRow model with detail formatting.
Core ViewModel & Managed Gateway Updates
src/OpenClaw.Companion/ViewModels/MainWindowViewModel.cs, src/OpenClaw.Companion/ViewModels/MainWindowViewModel.ManagedGateway.cs
MainWindowViewModel adds Messages collection-changed handler for HasMessages/HasNoMessages notifications; ManagedGateway refreshes provider summary and embedded-model reason when setup provider/model changes.
UI Canvas Tests
src/OpenClaw.Tests/CompanionCanvasUiTests.cs
Updated tab selection test to select by header and added new UI test verifying runtime console shell rendering and section navigation by header.
Runtime Console Unit Tests
src/OpenClaw.Tests/CompanionRuntimeConsoleTests.cs
CompanionRuntimeConsoleTests adds navigation, confirmation-gated payment/automation tests, runtime event formatting, sessions loading/pagination/selection tests, and test helpers for HTTP stubbing and temp settings directories.
Test Collection Attributes
src/OpenClaw.Tests/LocalInferenceSupervisorTests.cs, src/OpenClaw.Tests/ManagedGatewayServiceTests.cs
Add xUnit collection attributes to coordinate environment-variable-dependent test classes.

🎯 4 (Complex) | ⏱️ ~60 minutes

"🐰
A dozen features hop into view,
Workflows, payments, profiles too—
With dialogs that ask,
And sessions to task,
The console now sparkles brand new!"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title '[codex] Improve Companion runtime console' directly relates to the main changeset, which refactors the Companion into a Runtime Console shell with improved navigation, styles, and new screens.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/companion-runtime-console

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Dashboard.cs Fixed
Comment thread src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Plugins.cs Fixed
Comment thread src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Payments.cs Fixed
Comment thread src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Payments.cs Fixed
@Telli Telli marked this pull request as ready for review May 17, 2026 09:54
Copilot AI review requested due to automatic review settings May 17, 2026 09:54
@augmentcode
Copy link
Copy Markdown

augmentcode Bot commented May 17, 2026

🤖 Augment PR Summary

Summary: Refactors the Avalonia Companion into a Runtime Console-style shell and extends the integration client surface to support new operational screens.

Changes:

  • Reworks MainWindow.axaml into a left-nav console layout and adds shared UI styles via CompanionStyles.axaml.
  • Adds a confirmation dialog abstraction (IConfirmationDialogService) and wires it into the desktop app startup.
  • Introduces new MainWindowViewModel partials for Home/Dashboard, Sessions, Runtime Events, Plugins & Channels, Models & Providers, Workflows, Automations, Memory & Profiles, and Payment Lab.
  • Extends OpenClawHttpClient with integration endpoints for workflow listing/runs/responses and automation run history/replay/quarantine clearing.
  • Enhances chat message classification (user/assistant/system/tool/error) for richer rendering.
  • Updates and adds tests covering the new runtime console shell/navigation and confirmation-gated mutations.

Technical Notes: Risky mutation actions (approvals/automations/payments/workflows) now route through a confirmation prompt before calling the integration API.

🤖 Was this summary useful? React with 👍 or 👎

Copy link
Copy Markdown

@augmentcode augmentcode Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed. 3 suggestions posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

public bool IsAssistant => Role == ChatRole.Assistant;
public bool IsSystem => Role == ChatRole.System && !IsToolEvent && !IsError;
public bool IsToolEvent => Role == ChatRole.System &&
(Text.StartsWith("Agent invoked tool:", StringComparison.OrdinalIgnoreCase) ||
Copy link
Copy Markdown

@augmentcode augmentcode Bot May 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ChatMessage.IsToolEvent/IsError call Text.StartsWith/Contains without a null guard; if Text is ever null (e.g., from deserialization), this will throw and break chat rendering. Consider defensively handling null (similar to how IsStreamingPlaceholder uses string.IsNullOrWhiteSpace).

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

}
};

await dialog.ShowDialog(owner);
Copy link
Copy Markdown

@augmentcode augmentcode Bot May 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ConfirmAsync checks cancellationToken before showing the dialog, but cancellation while the dialog is open won’t interrupt ShowDialog(owner), so callers can still block waiting for UI input. This can cause hangs in flows that expect cancellation (shutdown/timeouts) to abort the confirmation prompt.

Severity: low

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

partial void OnSelectedSessionChanged(SessionRow? value)
{
if (value is not null)
_ = LoadSelectedSessionAsync(value);
Copy link
Copy Markdown

@augmentcode augmentcode Bot May 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This selection-change handler starts LoadSelectedSessionAsync as fire-and-forget, which can race: a slower request for an older selection can complete later and overwrite SelectedSessionDetail/timeline with stale data. Consider guarding the apply step (e.g., compare current selection or use cancellation) to keep the UI consistent.

Severity: medium

Other Locations
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Automations.cs:35
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Profiles.cs:35

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Nitpick comments (1)
src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Providers.cs (1)

47-50: ⚡ Quick win

Handle expected failures explicitly and avoid swallowing unexpected exceptions.

Catching all exceptions here makes diagnostics harder and can hide programming bugs. Prefer specific catches for operational failures and let unknown exceptions propagate.

Proposed fix
+using System.Net.Http;
@@
-        catch (Exception ex)
+        catch (OperationCanceledException ex)
+        {
+            ProvidersStatus = $"Providers load canceled: {ex.Message}";
+        }
+        catch (HttpRequestException ex)
+        {
+            ProvidersStatus = $"Providers load failed: {ex.Message}";
+        }
+        catch (TaskCanceledException ex)
+        {
+            ProvidersStatus = $"Providers load timed out: {ex.Message}";
+        }
+        catch (Exception)
         {
-            ProvidersStatus = $"Providers load failed: {ex.Message}";
+            throw;
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Providers.cs` around
lines 47 - 50, The current blanket catch(Exception ex) that sets ProvidersStatus
swallows unexpected bugs; change it to catch only expected operational
exceptions (e.g., IOException, ProviderLoadException or InvalidDataException)
and set ProvidersStatus inside those specific catch blocks, and either remove
the broad catch or rethrow for unhandled exceptions (use catch (Exception ex) {
ProvidersStatus = $"Providers load failed: {ex.Message}"; throw; } if you need
the message but must not swallow). Update the method containing this block (the
provider-loading routine that assigns ProvidersStatus) to explicitly handle
known failure types and let other exceptions propagate so they surface during
debugging.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/OpenClaw.Companion/Services/WindowConfirmationDialogService.cs`:
- Around line 15-16: The modal ShowDialog call in
WindowConfirmationDialogService (the code around the
cancellationToken.IsCancellationRequested check) doesn't honor cancellation
because ShowDialog blocks; register the provided CancellationToken to close the
dialog when cancelled by attaching a callback that calls
window.Dispatcher.Invoke(() => window.Close()) (or Dispatcher.BeginInvoke) so
the UI thread closes the modal; ensure you store and dispose/unregister the
registration (e.g., via token.Register returning a
CancellationTokenRegistration) so you remove it after ShowDialog returns; apply
the same change to the other occurrence handling the token near the ShowDialog
call around the later block (lines 73-74).

In `@src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Automations.cs`:
- Around line 32-36: OnSelectedAutomationChanged fires a fire-and-forget
LoadAutomationDetailAsync which can return out-of-order and overwrite
AutomationDetail/AutomationRunRows for a new selection; change the flow so each
load is cancellable or validated: introduce a per-viewmodel
CancellationTokenSource (or capture the requested automationId) before calling
LoadAutomationDetailAsync, pass the token (or capture id) into the async loader
(LoadAutomationDetailAsync and the code that sets
AutomationDetail/AutomationRunRows) and when the call completes verify the token
has not been cancelled (or the returned AutomationDetail.AutomationId matches
the current SelectedAutomation?.AutomationId) before applying results to
AutomationDetail/AutomationRunRows; also cancel the previous token (or bump a
request id) at the start of OnSelectedAutomationChanged to prevent stale
responses from applying.

In `@src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Payments.cs`:
- Around line 92-95: The catch block that sets PaymentsStatus on failure should
also clear stale funding options: in the catch handling around the Payments
setup load (where PaymentsStatus = $"Payment setup load failed: {ex.Message}";)
ensure FundingSourceRows is reset (e.g., clear the collection or replace it with
an empty list/observable) so the UI no longer shows previously loaded
providers/environments, then set PaymentsStatus with the error message as
before.

In `@src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Profiles.cs`:
- Around line 32-35: OnSelectedProfileChanged currently launches
LoadProfileDetailAsync without guarding against out-of-order completions; change
the flow so when SelectedProfile is null you immediately clear
SelectedProfileDetail, and inside the async load (LoadProfileDetailAsync / the
GetProfileAsync continuation) capture the actorId you requested and before
assigning SelectedProfileDetail verify that SelectedProfile is non-null and
SelectedProfile.ActorId equals that captured actorId, skipping the update if
they differ (thus preventing stale A results from overwriting B).

In `@src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Sessions.cs`:
- Around line 57-170: The PR added substantial sessions logic but lacks focused
unit tests for VM behaviors; add tests covering LoadSessionsAsync (filter
application, deduping via SessionRow.FromSummary, SessionsStatus text),
pagination via NextSessionsPageAsync/PreviousSessionsPageAsync (SessionsPage
increment/decrement and SessionsHasMore behavior), snippet enrichment via
LoadSessionSnippetsAsync (search triggers and snippet mapping), and selection
detail loading via LoadSelectedSessionAsync (SelectedSessionDetail content and
timeline rows via ReplaceItems SessionTimelineRows). Use mocks/stubs of
OpenClawHttpClient to return controlled ListSessionsAsync, SearchSessionsAsync,
GetSessionAsync, and GetSessionTimelineAsync responses, and assert
SessionRows/HasSessionRows, SessionsHasMore, SessionsStatus, SessionsPage and
SelectedSessionDetail/HasSessionTimelineRows are updated as expected.
- Around line 51-55: The async load for session details can be overwritten by
stale responses; modify OnSelectedSessionChanged and LoadSelectedSessionAsync to
guard against this by capturing an identifier for the selection (e.g.,
SelectedSession?.Id or the SessionRow reference) at the start of
LoadSelectedSessionAsync and verifying it still matches SelectedSession before
applying results; alternatively add a CancellationTokenSource field (e.g.,
_loadSelectedSessionCts) that you cancel in OnSelectedSessionChanged and pass
into LoadSelectedSessionAsync to abort prior work. Also, when an awaited call
fails, only clear or set TimelineRows (or the prior timeline UI) if the
selection still matches the captured id/token to avoid leaving prior timeline
rows visible.

In `@src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Workflows.cs`:
- Around line 70-111: The RunSelectedWorkflowAsync and RespondWorkflowInputAsync
methods lack an in-flight guard and can be re-entered; add a boolean
flag/property (reuse the existing IsWorkflowsBusy pattern) and at the top of
each method check if IsWorkflowsBusy then return, set IsWorkflowsBusy = true
before doing external calls (before
RequireIntegrationClient/RunWorkflowAsync/any client mutation) and reset
IsWorkflowsBusy = false in a finally block so it always clears; ensure
UI-updates (WorkflowsStatus, WorkflowRunId, ReplaceItems, OnPropertyChanged)
remain the same and do not run when the guard prevents re-entry.
- Around line 174-182: ApplyWorkflowSnapshot replaces the WorkflowPendingInputs
collection but doesn't validate SelectedWorkflowPendingInput, allowing a stale
selection; update ApplyWorkflowSnapshot to reconcile the selection after calling
ReplaceItems(WorkflowPendingInputs, ...) by finding a matching item (e.g., by Id
or Port) in the new WorkflowPendingInputs (items produced by
WorkflowPendingInputRow.FromInput) and keep SelectedWorkflowPendingInput if
found, otherwise set SelectedWorkflowPendingInput to null, then raise property
change for SelectedWorkflowPendingInput as needed.

In `@src/OpenClaw.Tests/CompanionCanvasUiTests.cs`:
- Around line 59-60: Replace brittle numeric selection and plain text checks by
locating the TabItem whose Header equals the target label (e.g., "Sessions"),
set tabControl.SelectedItem to that TabItem, run Dispatcher.UIThread.RunJobs(),
and then assert the tabControl.SelectedItem (or SelectedIndex) equals that
TabItem and that its Content (or the view/control inside SelectedContent) is the
expected active section. Apply the same change for the other occurrences around
lines 113-117 so tests select by header and verify the selected TabItem and its
content rather than relying on header text anywhere in the UI chrome.

---

Nitpick comments:
In `@src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Providers.cs`:
- Around line 47-50: The current blanket catch(Exception ex) that sets
ProvidersStatus swallows unexpected bugs; change it to catch only expected
operational exceptions (e.g., IOException, ProviderLoadException or
InvalidDataException) and set ProvidersStatus inside those specific catch
blocks, and either remove the broad catch or rethrow for unhandled exceptions
(use catch (Exception ex) { ProvidersStatus = $"Providers load failed:
{ex.Message}"; throw; } if you need the message but must not swallow). Update
the method containing this block (the provider-loading routine that assigns
ProvidersStatus) to explicitly handle known failure types and let other
exceptions propagate so they surface during debugging.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 31b84ea1-faa1-4b9a-a840-fdcc17f35e47

📥 Commits

Reviewing files that changed from the base of the PR and between efb90aa and 35910b8.

📒 Files selected for processing (23)
  • src/OpenClaw.Client/OpenClawHttpClient.cs
  • src/OpenClaw.Companion/App.axaml
  • src/OpenClaw.Companion/App.axaml.cs
  • src/OpenClaw.Companion/Models/ChatMessage.cs
  • src/OpenClaw.Companion/Services/IConfirmationDialogService.cs
  • src/OpenClaw.Companion/Services/WindowConfirmationDialogService.cs
  • src/OpenClaw.Companion/Styles/CompanionStyles.axaml
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Approvals.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Automations.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Dashboard.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.ManagedGateway.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Payments.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Plugins.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Profiles.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Providers.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.RuntimeConsoleHelpers.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.RuntimeEvents.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Sessions.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Workflows.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.cs
  • src/OpenClaw.Companion/Views/MainWindow.axaml
  • src/OpenClaw.Tests/CompanionCanvasUiTests.cs
  • src/OpenClaw.Tests/CompanionRuntimeConsoleTests.cs

Comment thread src/OpenClaw.Companion/Services/WindowConfirmationDialogService.cs
Comment thread src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Payments.cs Outdated
Comment thread src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Profiles.cs Outdated
Comment thread src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Sessions.cs
Comment on lines +57 to +170
[RelayCommand]
private async Task LoadSessionsAsync()
{
if (IsSessionsBusy)
return;

IsSessionsBusy = true;
try
{
if (!RequireIntegrationClient(out var client, status => SessionsStatus = status) || client is null)
return;

var query = new SessionListQuery
{
Search = EmptyToNull(SessionsSearchText),
ChannelId = EmptyToNull(SessionsChannelId),
SenderId = EmptyToNull(SessionsSenderId),
State = TryParseSessionState(SessionsState),
Starred = SessionsStarredOnly ? true : null,
Tag = EmptyToNull(SessionsTag)
};
var response = await client.ListSessionsAsync(SessionsPage, pageSize: 25, query, CancellationToken.None);
var snippets = await LoadSessionSnippetsAsync(client);
var rows = response.Active.Select(item => SessionRow.FromSummary(item, "active", snippets))
.Concat(response.Persisted.Items.Select(item => SessionRow.FromSummary(item, "persisted", snippets)))
.GroupBy(static row => row.SessionId, StringComparer.Ordinal)
.Select(static group => group.First())
.ToList();

SessionsHasMore = response.Persisted.HasMore;
ReplaceItems(SessionRows, rows);
OnPropertyChanged(nameof(HasSessionRows));
SessionsStatus = rows.Count == 0
? "No sessions match the current filters."
: $"{rows.Count} session{(rows.Count == 1 ? "" : "s")} loaded.";
}
catch (Exception ex)
{
SessionsStatus = $"Sessions load failed: {ex.Message}";
}
finally
{
IsSessionsBusy = false;
}
}

[RelayCommand]
private async Task NextSessionsPageAsync()
{
if (!SessionsHasMore)
return;

SessionsPage++;
await LoadSessionsAsync();
}

[RelayCommand]
private async Task PreviousSessionsPageAsync()
{
if (SessionsPage <= 1)
return;

SessionsPage--;
await LoadSessionsAsync();
}

private async Task<Dictionary<string, string>> LoadSessionSnippetsAsync(OpenClaw.Client.OpenClawHttpClient client)
{
if (string.IsNullOrWhiteSpace(SessionsSearchText))
return new Dictionary<string, string>(StringComparer.Ordinal);

var search = await client.SearchSessionsAsync(new SessionSearchQuery
{
Text = SessionsSearchText,
ChannelId = EmptyToNull(SessionsChannelId),
SenderId = EmptyToNull(SessionsSenderId),
Limit = 25,
SnippetLength = 180
}, CancellationToken.None);

return search.Result.Items
.GroupBy(static item => item.SessionId, StringComparer.Ordinal)
.ToDictionary(static group => group.Key, static group => group.First().Snippet, StringComparer.Ordinal);
}

private async Task LoadSelectedSessionAsync(SessionRow row)
{
try
{
if (!RequireIntegrationClient(out var client, status => SelectedSessionDetail = status) || client is null)
return;

var detail = await client.GetSessionAsync(row.SessionId, CancellationToken.None);
var timeline = await client.GetSessionTimelineAsync(row.SessionId, 100, CancellationToken.None);
SelectedSessionDetail = string.Join(Environment.NewLine, new[]
{
$"Session: {row.SessionId}",
$"Channel: {row.ChannelId}",
$"Sender: {row.SenderId}",
$"State: {row.State}",
$"Active: {detail.IsActive}",
$"Branches: {detail.BranchCount}",
$"History turns: {row.HistoryTurns}",
$"Tokens: {row.TotalTokens}"
});
ReplaceItems(SessionTimelineRows, timeline.Events.Select(RuntimeEventRow.FromEntry));
OnPropertyChanged(nameof(HasSessionTimelineRows));
}
catch (Exception ex)
{
SelectedSessionDetail = $"Session detail load failed: {ex.Message}";
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

Add focused tests for sessions query/pagination/selection behavior.

This introduces substantial sessions logic (filters, paging, dedupe, snippet enrichment, detail/timeline loading) but the provided test changes don’t include targeted sessions VM coverage.

As per coding guidelines, **/*.{cs,csproj}: Update tests where appropriate when making changes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Sessions.cs` around
lines 57 - 170, The PR added substantial sessions logic but lacks focused unit
tests for VM behaviors; add tests covering LoadSessionsAsync (filter
application, deduping via SessionRow.FromSummary, SessionsStatus text),
pagination via NextSessionsPageAsync/PreviousSessionsPageAsync (SessionsPage
increment/decrement and SessionsHasMore behavior), snippet enrichment via
LoadSessionSnippetsAsync (search triggers and snippet mapping), and selection
detail loading via LoadSelectedSessionAsync (SelectedSessionDetail content and
timeline rows via ReplaceItems SessionTimelineRows). Use mocks/stubs of
OpenClawHttpClient to return controlled ListSessionsAsync, SearchSessionsAsync,
GetSessionAsync, and GetSessionTimelineAsync responses, and assert
SessionRows/HasSessionRows, SessionsHasMore, SessionsStatus, SessionsPage and
SelectedSessionDetail/HasSessionTimelineRows are updated as expected.

Comment thread src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Workflows.cs
Comment thread src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Workflows.cs
Comment thread src/OpenClaw.Tests/CompanionCanvasUiTests.cs Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the Avalonia Companion into a broader Runtime Console shell, adding navigation and operator-facing screens for runtime administration, workflows, automations, sessions, payments, plugins, providers, and memory/profile surfaces.

Changes:

  • Reworks the Companion UI shell with a left-nav tab layout, shared styles, dashboard, and expanded admin/setup/chat/canvas/WhatsApp/payment screens.
  • Adds typed runtime-console view-model surfaces and client methods for sessions, events, plugins, providers, workflows, automations, profiles, and payments.
  • Adds confirmation dialog plumbing for risky actions plus focused UI/view-model tests.

Reviewed changes

Copilot reviewed 22 out of 23 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
src/OpenClaw.Tests/CompanionRuntimeConsoleTests.cs Adds VM/runtime-console behavior tests.
src/OpenClaw.Tests/CompanionCanvasUiTests.cs Updates canvas tab index and adds runtime shell UI coverage.
src/OpenClaw.Companion/Views/MainWindow.axaml Rebuilds Companion UI into Runtime Console shell and screens.
src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Workflows.cs Adds workflow list/run/response VM support.
src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Sessions.cs Adds session list/detail/timeline VM support.
src/OpenClaw.Companion/ViewModels/MainWindowViewModel.RuntimeEvents.cs Adds runtime event query/detail VM support.
src/OpenClaw.Companion/ViewModels/MainWindowViewModel.RuntimeConsoleHelpers.cs Adds navigation, badges, confirmation, and shared helpers.
src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Providers.cs Adds providers/tool-presets VM support.
src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Profiles.cs Adds profiles, memory notes, and learning proposal VM support.
src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Plugins.cs Adds plugins, compatibility, and channel readiness VM support.
src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Payments.cs Adds Payment Lab VM commands and rows.
src/OpenClaw.Companion/ViewModels/MainWindowViewModel.ManagedGateway.cs Updates derived setup/local-model notifications.
src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Dashboard.cs Adds dashboard metrics and summary collections.
src/OpenClaw.Companion/ViewModels/MainWindowViewModel.cs Adds message collection notifications.
src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Automations.cs Adds automation list/detail/run/delete VM support.
src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Approvals.cs Adds confirmation gates for approval decisions and badge updates.
src/OpenClaw.Companion/Styles/CompanionStyles.axaml Adds shared Companion UI styles.
src/OpenClaw.Companion/Services/WindowConfirmationDialogService.cs Adds Avalonia modal confirmation service.
src/OpenClaw.Companion/Services/IConfirmationDialogService.cs Adds confirmation service abstraction and deny-by-default implementation.
src/OpenClaw.Companion/Models/ChatMessage.cs Adds chat message classification helpers.
src/OpenClaw.Companion/App.axaml.cs Wires confirmation dialog service into the main window.
src/OpenClaw.Companion/App.axaml Includes shared Companion styles.
src/OpenClaw.Client/OpenClawHttpClient.cs Adds workflow and automation-run client APIs.

Comment on lines +73 to +78
client = CreateIntegrationClient(out var error);
if (client is not null)
return true;

setStatus(error ?? "Invalid gateway URL.");
return false;
Comment on lines +51 to +54
partial void OnSelectedSessionChanged(SessionRow? value)
{
if (value is not null)
_ = LoadSelectedSessionAsync(value);
Comment on lines +32 to +35
partial void OnSelectedProfileChanged(ProfileRow? value)
{
if (value is not null)
_ = LoadProfileDetailAsync(value.ActorId);
Comment on lines +32 to +35
partial void OnSelectedAutomationChanged(AutomationRow? value)
{
if (value is not null)
_ = LoadAutomationDetailAsync(value.AutomationId);
Comment on lines +69 to +78
var query = new SessionListQuery
{
Search = EmptyToNull(SessionsSearchText),
ChannelId = EmptyToNull(SessionsChannelId),
SenderId = EmptyToNull(SessionsSenderId),
State = TryParseSessionState(SessionsState),
Starred = SessionsStarredOnly ? true : null,
Tag = EmptyToNull(SessionsTag)
};
var response = await client.ListSessionsAsync(SessionsPage, pageSize: 25, query, CancellationToken.None);
Comment on lines +100 to +102
WorkflowRunDetail = BuildWorkflowRunText(result.WorkflowId, result.RunId, result.Status, result.BackendId, result.Output, result.Error);
ReplaceItems(WorkflowEventRows, result.Events.Select(WorkflowEventRow.FromEvent));
ReplaceItems(WorkflowPendingInputs, []);
Comment on lines +103 to +108
private static string ToIndentedJson<T>(T value)
{
try
{
return JsonSerializer.Serialize(value, new JsonSerializerOptions { WriteIndented = true });
}
<Grid Grid.Row="0" ColumnDefinitions="*,Auto"><StackPanel><TextBlock Text="Workflows" Classes="page-title" /><TextBlock Text="{Binding WorkflowsStatus}" Classes="muted" /></StackPanel><Button Grid.Column="1" Content="Load" Command="{Binding LoadWorkflowsCommand}" Classes="primary" /></Grid>
<Grid Grid.Row="1" ColumnDefinitions="2*,3*" ColumnSpacing="12">
<Border Grid.Column="0" Classes="section-card"><ListBox ItemsSource="{Binding WorkflowRows}" SelectedItem="{Binding SelectedWorkflow}" Background="Transparent" BorderThickness="0"><ListBox.ItemTemplate><DataTemplate DataType="vm:WorkflowRow"><StackPanel Margin="0,0,0,8"><TextBlock Text="{Binding DisplayName}" FontWeight="SemiBold" /><TextBlock Text="{Binding WorkflowName}" Classes="muted" /><TextBlock Text="{Binding Status}" Classes="muted" /></StackPanel></DataTemplate></ListBox.ItemTemplate></ListBox></Border>
<Border Grid.Column="1" Classes="section-card"><Grid RowDefinitions="Auto,Auto,*,Auto" RowSpacing="8"><Grid ColumnDefinitions="*,Auto"><TextBox Text="{Binding WorkflowInput}" Watermark="Workflow input" AcceptsReturn="True" MinHeight="58" TextWrapping="Wrap" /><Button Grid.Column="1" Content="Run" Command="{Binding RunSelectedWorkflowCommand}" Margin="8,0,0,0" /></Grid><Grid Grid.Row="1" ColumnDefinitions="*,Auto"><TextBox Text="{Binding WorkflowRunId}" Watermark="Run id" /><Button Grid.Column="1" Content="Load Run" Command="{Binding LoadWorkflowRunCommand}" Margin="8,0,0,0" /></Grid><TextBox Grid.Row="2" Text="{Binding WorkflowRunDetail}" IsReadOnly="True" AcceptsReturn="True" Classes="monospace" TextWrapping="Wrap" /><Grid Grid.Row="3" ColumnDefinitions="*,Auto"><ComboBox ItemsSource="{Binding WorkflowPendingInputs}" SelectedItem="{Binding SelectedWorkflowPendingInput}" MinWidth="180"><ComboBox.ItemTemplate><DataTemplate DataType="vm:WorkflowPendingInputRow"><TextBlock Text="{Binding PortId}" /></DataTemplate></ComboBox.ItemTemplate></ComboBox><Button Grid.Column="1" Content="Send Response" Command="{Binding RespondWorkflowInputCommand}" Margin="8,0,0,0" /></Grid></Grid></Border>
<Grid RowDefinitions="Auto,*" RowSpacing="10" Margin="12,0,0,0">
<Grid Grid.Row="0" ColumnDefinitions="*,Auto"><StackPanel><TextBlock Text="Automations" Classes="page-title" /><TextBlock Text="{Binding AutomationsStatus}" Classes="muted" /></StackPanel><Button Grid.Column="1" Content="Load" Command="{Binding LoadAutomationsCommand}" Classes="primary" /></Grid>
<Grid Grid.Row="1" ColumnDefinitions="2*,3*" ColumnSpacing="12">
<Border Grid.Column="0" Classes="section-card"><ListBox ItemsSource="{Binding AutomationRows}" SelectedItem="{Binding SelectedAutomation}" Background="Transparent" BorderThickness="0"><ListBox.ItemTemplate><DataTemplate DataType="vm:AutomationRow"><StackPanel Margin="0,0,0,8"><TextBlock Text="{Binding Name}" FontWeight="SemiBold" /><TextBlock Text="{Binding Schedule}" Classes="muted" /><TextBlock Text="{Binding State}" Classes="muted" /></StackPanel></DataTemplate></ListBox.ItemTemplate></ListBox></Border>
</Style>

<Style Selector="Button.danger">
<Setter Property="Foreground" Value="#ff453a" />
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Automations.cs (1)

33-44: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Clear stale run state immediately when automation selection changes.

When selection changes to a new automation, previous SelectedAutomationRun/AutomationRunRows stay active until the async detail load finishes. In that window, replay can pair a stale run ID with the newly selected automation ID.

Suggested fix
 partial void OnSelectedAutomationChanged(AutomationRow? value)
 {
+    SelectedAutomationRun = null;
+    ReplaceItems(AutomationRunRows, []);
+    OnPropertyChanged(nameof(HasAutomationRunRows));
+
     if (value is null)
     {
         AutomationDetail = "Select an automation to inspect run state.";
-        ReplaceItems(AutomationRunRows, []);
-        OnPropertyChanged(nameof(HasAutomationRunRows));
         return;
     }
 
     _ = LoadAutomationDetailAsync(value.AutomationId);
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Automations.cs` around
lines 33 - 44, OnSelectedAutomationChanged should clear any stale run state
immediately when selection changes: when value is null do as now, and when value
is non-null first set SelectedAutomationRun = null, clear AutomationRunRows via
ReplaceItems(AutomationRunRows, Array.Empty<AutomationRunRow>()), update
AutomationDetail to a loading/placeholder string and raise
OnPropertyChanged(nameof(HasAutomationRunRows)) before calling _ =
LoadAutomationDetailAsync(value.AutomationId); this ensures
SelectedAutomationRun/AutomationRunRows are reset synchronously so an in-flight
LoadAutomationDetailAsync cannot leave a stale run ID paired with the new
automation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/OpenClaw.Companion/ViewModels/MainWindowViewModel.RuntimeConsoleHelpers.cs`:
- Around line 30-31: AttachConfirmationDialogService should guard against a null
injection: validate the dialogService parameter in
AttachConfirmationDialogService and throw an ArgumentNullException (or similar)
if it's null instead of assigning it blindly to _confirmationDialogService;
update the method that sets _confirmationDialogService
(AttachConfirmationDialogService) to perform the null check so later
confirmation requests won't hit a NullReferenceException.

---

Duplicate comments:
In `@src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Automations.cs`:
- Around line 33-44: OnSelectedAutomationChanged should clear any stale run
state immediately when selection changes: when value is null do as now, and when
value is non-null first set SelectedAutomationRun = null, clear
AutomationRunRows via ReplaceItems(AutomationRunRows,
Array.Empty<AutomationRunRow>()), update AutomationDetail to a
loading/placeholder string and raise
OnPropertyChanged(nameof(HasAutomationRunRows)) before calling _ =
LoadAutomationDetailAsync(value.AutomationId); this ensures
SelectedAutomationRun/AutomationRunRows are reset synchronously so an in-flight
LoadAutomationDetailAsync cannot leave a stale run ID paired with the new
automation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 84bbe229-a74b-43cd-a187-3c9189e482c2

📥 Commits

Reviewing files that changed from the base of the PR and between 35910b8 and 99dbc5e.

📒 Files selected for processing (18)
  • src/OpenClaw.Companion/Models/ChatMessage.cs
  • src/OpenClaw.Companion/Services/WindowConfirmationDialogService.cs
  • src/OpenClaw.Companion/Styles/CompanionStyles.axaml
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Automations.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Dashboard.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Payments.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Plugins.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Profiles.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Providers.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.RuntimeConsoleHelpers.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.RuntimeEvents.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Sessions.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Workflows.cs
  • src/OpenClaw.Companion/Views/MainWindow.axaml
  • src/OpenClaw.Tests/CompanionCanvasUiTests.cs
  • src/OpenClaw.Tests/CompanionRuntimeConsoleTests.cs
  • src/OpenClaw.Tests/LocalInferenceSupervisorTests.cs
  • src/OpenClaw.Tests/ManagedGatewayServiceTests.cs
✅ Files skipped from review due to trivial changes (1)
  • src/OpenClaw.Companion/Styles/CompanionStyles.axaml
🚧 Files skipped from review as they are similar to previous changes (10)
  • src/OpenClaw.Companion/Models/ChatMessage.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Providers.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.RuntimeEvents.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Dashboard.cs
  • src/OpenClaw.Companion/Services/WindowConfirmationDialogService.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Plugins.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Payments.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Profiles.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Workflows.cs
  • src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Sessions.cs

Comment thread src/OpenClaw.Companion/ViewModels/MainWindowViewModel.RuntimeConsoleHelpers.cs Outdated
Comment thread src/OpenClaw.Tests/CompanionRuntimeConsoleTests.cs Fixed
private bool _isAutomationsBusy;

[ObservableProperty]
private string _automationsStatus = "Automations not loaded.";
private AutomationRunRow? _selectedAutomationRun;

[ObservableProperty]
private string _automationDetail = "Select an automation to inspect run state.";
private bool _isDashboardBusy;

[ObservableProperty]
private string _dashboardStatus = "Dashboard not loaded.";
private int _dashboardChannelsReady;

[ObservableProperty]
private string _dashboardLastRefreshed = "never";
private bool _isPaymentsBusy;

[ObservableProperty]
private string _paymentsStatus = "Payment Lab not loaded.";
private string _paymentsStatus = "Payment Lab not loaded.";

[ObservableProperty]
private string _paymentProvider = "";
private string _paymentProvider = "";

[ObservableProperty]
private string _paymentEnvironment = PaymentEnvironments.Test;
private string _paymentEnvironment = PaymentEnvironments.Test;

[ObservableProperty]
private string _paymentSetupSummary = "Load setup status before running payment actions.";
private string _paymentSetupSummary = "Load setup status before running payment actions.";

[ObservableProperty]
private string _virtualCardMerchantName = "";
private string _virtualCardMerchantName = "";

[ObservableProperty]
private string _virtualCardMerchantUrl = "";
@Telli Telli merged commit 62062c5 into main May 18, 2026
18 checks passed
@Telli Telli deleted the codex/companion-runtime-console branch May 18, 2026 01:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants