Skip to content

Commit d3ed6c7

Browse files
calebedenCopilotkarkarl
authored
refactor(chat): remove the retired FunctionalUI chat surface (#1110)
* refactor(chat): remove legacy FunctionalUI surface Remove the unreachable FunctionalUI chat root, timeline, composer, virtualization helpers, proof fixtures, and migration-debt tests. Keep remaining FunctionalUI consumers intact and guard production chat ownership through the Reactor mount path. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * fix(chat): finish legacy timeline cleanup Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 1bf3409c-6c88-4d6c-b015-7e9cbf5e02da * docs(architecture): point chat closure at Reactor host Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 1bf3409c-6c88-4d6c-b015-7e9cbf5e02da * fix(chat): preserve media contracts after cleanup Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 1bf3409c-6c88-4d6c-b015-7e9cbf5e02da --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Co-authored-by: Karen Lai <7976322+karkarl@users.noreply.github.com> Copilot-Session: 1bf3409c-6c88-4d6c-b015-7e9cbf5e02da
1 parent 3880b62 commit d3ed6c7

31 files changed

Lines changed: 150 additions & 7788 deletions

‎.editorconfig‎

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -202,13 +202,3 @@ dotnet_diagnostic.REACTOR_DIALOG_001.severity = none
202202

203203
[src/OpenClaw.Tray.WinUI/Windows/ChatWindow.xaml.cs]
204204
dotnet_diagnostic.REACTOR_DIALOG_001.severity = none
205-
206-
[src/OpenClaw.Tray.WinUI/Chat/OpenClawChatRoot.cs]
207-
dotnet_diagnostic.REACTOR_THEME_004.severity = none
208-
209-
[src/OpenClaw.Tray.WinUI/Chat/OpenClawComposer.cs]
210-
dotnet_diagnostic.REACTOR_A11Y_001.severity = none
211-
212-
[src/OpenClaw.Tray.WinUI/Chat/OpenClawChatTimeline.cs]
213-
dotnet_diagnostic.REACTOR_A11Y_001.severity = none
214-
dotnet_diagnostic.REACTOR_THEME_004.severity = none

‎DEVELOPMENT.md‎

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -230,27 +230,26 @@ Useful local scripts:
230230

231231
## Architecture Overview
232232

233-
### Native chat surface (FunctionalUI + OpenClaw.Chat)
233+
### Native chat surface (Reactor + OpenClaw.Chat)
234234

235235
The Hub Chat tab (`src/OpenClaw.Tray.WinUI/Pages/ChatPage.xaml`) and the
236236
tray ChatWindow popup (`src/OpenClaw.Tray.WinUI/Windows/ChatWindow.xaml`)
237237
render their conversations with native WinUI 3 controls via the in-repo
238-
`OpenClawTray.FunctionalUI` helper and `OpenClaw.Chat` model/reducer code.
238+
Reactor components and `OpenClaw.Chat` model/reducer code.
239239
The standard WebView2-hosted gateway web client remains available as a
240240
settings-controlled fallback.
241241

242242
**Layering:**
243243

244244
```
245-
src/OpenClaw.Tray.WinUI/Chat/ OpenClawChatTimeline · OpenClawComposer · OpenClawSessionHeader
245+
src/OpenClaw.Tray.WinUI/Chat/ OpenClawReactorChatRoot · ReactorChatTimeline · ReactorChatComposer
246246
OpenClawChatDataProvider (adapts OpenClawGatewayClient → IChatDataProvider)
247-
OpenClawChatRoot (FunctionalUI component composing the chat surface)
248-
FunctionalChatHostExtensions (mounts FunctionalUI into a XAML <Border>)
249-
IChatGatewayBridge (testability seam over OpenClawGatewayClient)
247+
ReactorChatHostExtensions (mounts Reactor into a XAML <Border>)
248+
IChatGatewayBridge (testability seam over OpenClawGatewayClient)
250249
▲ depends on
251250
src/OpenClaw.Chat/ ChatThread · ChatTimelineState · IChatDataProvider · ChatTimelineReducer
252251
▲ rendered by
253-
src/OpenClawTray.FunctionalUI/ Component · RenderContext · FunctionalHostControl · WinUI elements
252+
Reactor.WinUI Component · hooks · ReactorHostControl · WinUI elements
254253
```
255254

256255
**Lifecycle:**
@@ -259,12 +258,13 @@ src/OpenClawTray.FunctionalUI/ Component · RenderContext · FunctionalHostCon
259258
created in `InitializeGatewayClient` and disposed inside
260259
`UnsubscribeGatewayEvents`. Both the Hub Chat tab and the tray ChatWindow
261260
consume the same provider - opening either surface shows identical state.
262-
- Each XAML host (`ChatPage`, `ChatWindow`) mounts its own `FunctionalHostControl`
263-
with `ContentTarget` pointing at a `<Border x:Name="ChatHost"/>`. The
261+
- `ReactorChatHostExtensions` mounts a dedicated `ReactorHostControl` for each
262+
XAML surface (`ChatPage`, `ChatWindow`) as the child of its
263+
`<Border x:Name="ChatHost"/>`. The
264264
surrounding chrome (NavigationView, popup header) stays XAML.
265265
- Provider events fire on the WebSocket-receive thread; the provider
266266
marshals `Changed` / `NotificationRequested` callbacks through a
267-
dispatcher post delegate (`DispatcherQueue.AsPost()`), so FunctionalUI
267+
dispatcher post delegate (`DispatcherQueue.AsPost()`), so Reactor
268268
components observe state on the UI thread.
269269

270270
**Adding new chat behavior:** model new events in `OpenClaw.Chat`'s

‎docs/ARCHITECTURE.md‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,7 @@ These are the canonical homes. Do not reintroduce private copies elsewhere.
110110
| `src/OpenClaw.Tray.WinUI/Windows/HubWindow.xaml.cs` | navigation/catalog policy → `HubPageRegistry`; notification banner projection → `AppNotificationInfoBarPresenter`; keep Frame, NavigationView, back-stack mutation, control application, and route side effects in the view |
111111
| `src/OpenClaw.Tray.WinUI/Services/TrayMenuRenderer.cs` | semantic composition → `TrayMenuPresenter`; connection toggle projection → `ConnectionTogglePresenter`; keep WinUI control construction and callback application in the renderer |
112112
| `src/OpenClaw.Tray.WinUI/Chat/OpenClawChatDataProvider.cs` | Keep as the `IChatDataProvider` facade; atomic runtime coordination → `ChatConversationState`, lock-internal state mechanics → its queue/reset/history/presentation/lifecycle/approval substates, queue decisions → `ChatSendQueuePolicy`, history IO → `ChatHistoryLoader`, mapping → `ChatEventMapper`, native tool projection → `NativeToolProjector`, snapshots → `ChatSnapshotProjector`, metadata → `ChatMetadataStore`, persistence → `ChatStatePersistence` |
113-
| `src/OpenClaw.Tray.WinUI/Chat/OpenClawChatTimeline.cs` | `ReactorChatTimeline` (production `ItemsView` / `ItemContainer`), `ChatBubbleRenderer`, `ToolCallCardRenderer`, `PermissionRequestCard`, `AttachmentBubbleRenderer` |
114-
| `src/OpenClaw.Tray.WinUI/Chat/OpenClawComposer.cs` | `ComposerViewModel`, `SlashCommandPalette`, `AttachmentPreviewStrip`, `VoiceComposerController` (legacy FunctionalUI surface; the production path is `ReactorChatComposer.cs` below) |
113+
| `src/OpenClaw.Tray.WinUI/Chat/ReactorChatTimeline.cs` | `ChatBubbleRenderer`, `PermissionRequestCard`, `AttachmentBubbleRenderer`; tool rendering stays in `ToolCallCardRenderer` |
115114
| `src/OpenClaw.Tray.WinUI/Chat/OpenClawReactorChatRoot.cs` | Keep as the provider-subscription/selection/timeline-composition root only; composer state → `ChatComposerViewModel`, composer workflow → `ChatComposerController`, composer view → `ReactorChatComposer.cs` |
116115
| `src/OpenClaw.Tray.WinUI/Chat/ReactorChatComposer.cs` | Declarative view only; workflow/state changes go in `ChatComposerViewModel`/`ChatComposerController`, not new Reactor `UseState`/refs here |
117116
| `src/OpenClaw.Tray.WinUI/Pages/ConnectionPage.xaml.cs` | `ConnectionPagePlan` (pure), `ConnectionPageViewModel`, `GatewayDirectConnectService`, gateway row models |
@@ -203,7 +202,7 @@ leading and trailing pipe. Columns, in order:
203202
| navigation-scope | authoritative | src/OpenClaw.Tray.WinUI/Windows/HubWindow.xaml.cs | page view-model activation/deactivation and disposal lifetime | NavigationScopeManager | HubWindow keeps frame navigation back-stack and rail selection | transient page view models are activated on navigation and deactivated then disposed on navigate-away | NavigationScopeManagerTests.NavigatingAway_DeactivatesAndDisposesPreviousViewModel | behavioral | - |
204203
| composition-root | authoritative | src/OpenClaw.Tray.WinUI/App.xaml.cs | presentation-layer service construction and wiring | AppServiceRegistration | App remains the composition root and owns non-DI service lifetimes | one validated root ServiceProvider; App-owned singletons registered as instances are never disposed by the container | AppServiceRegistrationTests.Dispose_DoesNotDisposeAppOwnedInstanceSingletons | behavioral | - |
205204
| node-summary-text | authoritative | src/OpenClaw.Tray.WinUI/App.xaml.cs | node-summary clipboard text formatting | NodeSummaryText | App keeps the clipboard side effect (building the DataPackage and setting clipboard content) | copied node-summary text is projected only by NodeSummaryText.Build (online/offline state, display-name fallback, short id, detail text, newline join) | NodeSummaryTextTests.Build_MultipleNodes_OneLinePerNodeJoinedByNewline | behavioral | - |
206-
| reactor-chat-timeline | authoritative | src/OpenClaw.Tray.WinUI/Chat/OpenClawChatTimeline.cs | production chat message virtualization, row realization, and imperative scroll follow | ReactorChatTimeline through OpenClawReactorChatRoot and ReactorHostControl | OpenClawChatTimeline remains a legacy focused-test surface while its runtime route is migrated | the default chat route mounts one direct ReactorHostControl per XAML chat target; Reactor owns stable-key ItemsView and ItemContainer realization without a custom native list, collection reconciler, or scroll-layout mutation | review-only: user explicitly deferred new tests for this migration; required build and existing shared/tray suites still run | review-only | when Reactor timeline proof coverage replaces the legacy focused UI host coverage |
205+
| reactor-chat-timeline | authoritative | removed legacy FunctionalUI chat timeline | production chat message virtualization, row realization, and imperative scroll follow | ReactorChatTimeline through OpenClawReactorChatRoot and ReactorHostControl | - | the default chat route mounts one direct ReactorHostControl per XAML chat target; Reactor owns stable-key ItemsView and ItemContainer realization without a custom native list, collection reconciler, or scroll-layout mutation | ChatTimelinePresentationTests.ReactorTimeline_UsesNonSelectableItemsViewContainersAndAnnotatedScrollBar | source-shape | when ReactorChatTimeline is replaced as the production virtualization owner |
207206
| chat-tool-activity-renderer | authoritative | src/OpenClaw.Tray.WinUI/Chat/ReactorChatTimeline.cs | production standalone tool-call and grouped activity presentation, summaries, disclosures, and detail rendering | ChatToolActivityPresentation + ToolCallCardRenderer | ReactorChatTimeline projects rows and delegates realization only | consecutive invocation grouping preserves source chronology; stable group identity comes from session, generation, and first tool entry; selectable output remains capped at 240px | ChatToolActivityPresentationTests.Project_GroupsOnlyConsecutiveSpansOfAtLeastTwoTools | behavioral | - |
208207
| chat-history-replay-projection | authoritative | src/OpenClaw.Tray.WinUI/Chat/OpenClawChatDataProvider.cs | array-valued history content ordering projection | ChatHistoryReplayProjection | provider applies projected text and tool parts to the reducer | interleaved text, calls, and results replay in source order without clearing active tool correlation | OpenClawChatDataProviderTests.LoadHistoryAsync_InterleavedContentParts_PreserveChronologyAndCorrelation | behavioral | - |
209208
| assistant-media-protocol-projection | authoritative | src/OpenClaw.Shared/OpenClawGatewayClient.cs | structured assistant media content parsing and assistant-only legacy MEDIA directive redaction/projection | AssistantMediaDirectiveParser + ChatMediaContentInfo | gateway client preserves ordered typed media while tray presentation receives only safe filenames and metadata | user text never activates media directives; accepted local sources never enter visible assistant text or notifications; media-only messages survive live and history parsing | AssistantMediaDirectiveParserTests.Project_AssistantAbsolutePath_ProducesMediaWithoutExposingPath | behavioral | - |
@@ -213,7 +212,7 @@ leading and trailing pipe. Columns, in order:
213212
| gateway-media-message-projection | authoritative | src/OpenClaw.Tray.WinUI/Chat/OpenClawChatDataProvider.cs | gateway media-envelope parsing, safe filename/MIME normalization, attachment signatures, and provenance-safe attachment descriptors | GatewayMediaMessageProjection + ChatAttachmentPresentation | provider applies the projection to live, reset, backfill, and history ingress and owns stateful echo correlation | gateway text never becomes a private marker; gateway descriptors have no preview key; only local opaque preview keys can access image bytes | GatewayMediaMessageProjectionTests.ValidEnvelope_ProjectsSafeDescriptorAndCleanProse | behavioral | - |
214213
| provider-gateway-media-parsing-closed | closed | src/OpenClaw.Tray.WinUI/Chat/OpenClawChatDataProvider.cs | private gateway media-envelope parsing or descriptor construction | GatewayMediaMessageProjection | provider retains stateful pending-echo queues, reset gates, sidecar matching, and reducer application | all user ingress paths call the focused projection and do not independently parse gateway media text | review-only | review-only | when user-message ingestion leaves OpenClawChatDataProvider |
215214
| reactor-tool-rendering-closed | closed | src/OpenClaw.Tray.WinUI/Chat/ReactorChatTimeline.cs | per-tool and grouped activity summary/detail rendering implementation | ToolCallCardRenderer | row projection, virtualization, hover state, assistant runs, and renderer delegation only | ReactorChatTimeline contains no tool detail renderer and delegates both standalone and grouped tool rows | ChatTimelinePresentationTests.ReactorTimeline_DelegatesToolAndActivityRenderingToFocusedOwner | source-shape | when ReactorChatTimeline is replaced as the production virtualization owner |
216-
| functional-chat-default-mount | closed | src/OpenClaw.Tray.WinUI/Chat/FunctionalChatHostExtensions.cs | mounting the FunctionalUI chat tree as the default ChatPage or ChatWindow surface | ReactorChatHostExtensions and OpenClawReactorChatRoot | legacy FunctionalUI chat files may remain for focused compatibility coverage only | ChatPage and ChatWindow mount the Reactor root directly into their existing ChatHost Borders; no FunctionalUI component mounts or nests Reactor on the default path | review-only: user explicitly deferred new tests for this migration; required build and existing shared/tray suites still run | review-only | when legacy FunctionalUI chat surfaces are removed |
215+
| functional-chat-default-mount | closed | src/OpenClaw.Tray.WinUI/Chat/ReactorChatHostExtensions.cs | mounting the FunctionalUI chat tree as the default ChatPage or ChatWindow surface | ReactorChatHostExtensions and OpenClawReactorChatRoot | - | ChatPage and ChatWindow mount the Reactor root directly into their existing ChatHost Borders through ReactorChatHostExtensions | ChatToolCallsToggleContractTests.ProductionChatSurfaces_MountReactorRoot | source-shape | when ReactorChatHostExtensions is replaced as the authoritative production chat mount owner |
217216
| settings-store | authoritative | settings and permission UI surfaces | direct SettingsManager mutation and blanket self-write suppression | ISettingsStore | non-permission legacy surfaces may read SettingsManager until migrated; direct saves publish origin null | every save publishes one versioned event; only the matching writer ignores its own origin while all other active consumers refresh | SettingsSharedStateContractTests.TwoActiveSettingsPageViewModels_IgnoreOnlyOwnWrites_InBothDirections | behavioral | when every settings surface reads and writes through ISettingsStore |
218217
| settings-page-vm | authoritative | src/OpenClaw.Tray.WinUI/Pages/SettingsPage.xaml.cs | settings load, persist, echo-guard, and auto-save wiring | SettingsPageViewModel | code-behind keeps gateway-uninstall, gateway-info and uptime timer, saved-indicator visual, and app-info population | each settings control persists its field through the store preserving mutate-save-notify order and does not re-persist on external change | SettingsPageViewModelTests.ExternalChange_ReloadsWithoutRePersisting | behavioral | when the Settings page holds no settings persistence logic in code-behind |
219218
| exec-approvals-store | authoritative | src/OpenClaw.Tray.WinUI/Pages/PermissionsPage.xaml.cs | direct exec-approvals.json snapshot, CAS persistence, file observation, and mutable policy cache | ExecApprovalsStore through IExecApprovalsPresentationStore | SystemCapability and NodeService consume the same App-owned concrete store for runtime enforcement | pure reads create nothing; CAS rejects stale hashes; one store-owned observer publishes each distinct external replacement once and retains the last valid presentation snapshot on typed failure | ExecApprovalsStoreTests.Changed_ExternalCorruptThenValid_RaisesFailureThenRecovery | behavioral | - |

0 commit comments

Comments
 (0)