# refactor(chat-ao): split controller into Base + Coworker subclass - #810
Open
anfibiacreativa wants to merge 2 commits into
Open
anfibiacreativa wants to merge 2 commits into
anfibiacreativa wants to merge 2 commits into
Conversation
First step of decoupling the AO-direct/Coworker and CMA-bridge chat paths so a change to one cannot regress the other (see docs/chat-ao-controller-decoupling.md). - base-chat-controller.js: BaseChatController with everything shared by both harnesses (WS lifecycle, streaming, tool calls, question/plan/permission, send/stop, skills) plus overridable hooks (loadEpisodes, switchEpisode, _onSessionReady, _onSessionError, startNewEpisode). - coworker-chat-controller.js: CoworkerChatController extends Base with the orchestrator REST episode cluster (list/messages/context, warm/attach, loadEpisodes/_loadEpisode/_refreshEpisodeList/switchEpisode). - ao-controller.js: thin re-export of the Coworker controller so chat-ao.js and existing tests are unchanged. Zero behavior change: 316 chat-ao tests pass. The CMA subclass lands next.
Base + Coworker/CMA subclass responsibility matrix and staged rollout that the split follows. Referenced by the controller source comments.
anfibiacreativa
added this pull request to stack #812
October 3, 2026 07:43
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ao-controller.jsintoBaseChatController(shared by both harnesses) andCoworkerChatController extends Base(orchestrator REST episode history).ao-controller.jsis now a thin re-export of the Coworker controller, sochat-ao.jsand all existing tests are unchanged.docs/chat-ao-controller-decoupling.md) that the split — and the follow-up CMA subclass — follows.Why
The chat controller serves two harnesses from one class: AO-direct / CX Coworker (orchestrator REST history) and the CMA bridge (WS-only, replay on reconnect). Because they share one file, every change forced the question "does this regress the other path?" — the divergence (episode loading/resume, session-ready/error handling) is small but keeps growing, and a single shared controller makes isolation impossible. This is the first step of a staged decoupling so a change to one path cannot regress the other.
What Changed
base-chat-controller.js—BaseChatControllerholds everything common to both harnesses: WebSocket lifecycle (_connectionInfo/_ensureSocket/_connect/reconnect), streaming (_onTextDelta/_onTextDone), tool-call handling, question/plan/permission flows,sendMessage/stop, skills, and theEVENT_HANDLERSdispatch. The harness-specific seams are exposed as overridable hooks:loadEpisodes,switchEpisode,_onSessionReady,_onSessionError,startNewEpisode.coworker-chat-controller.js—CoworkerChatController extends Basewith the orchestrator REST episode cluster:_fetchEpisodes/_fetchEpisodeMessages/_fetchEpisodeContext/_fetchWarmSession,warmSession/_attach/reattachIfIdle, andloadEpisodes/_loadEpisode/_refreshEpisodeList/switchEpisode(incl. the 24h stale-episode rule).ao-controller.js— reduced to a thin re-export of the Coworker controller, preserving the historical default export sochat-ao.jsand the test suite need no import changes.docs/chat-ao-controller-decoupling.md— the Base / Coworker / CMA responsibility matrix and staged rollout, referenced from the source comments.This is intentionally behavior-preserving. No CMA subclass yet and no routing change — today's only instantiated controller is Coworker, which is byte-equivalent in behavior to the previous single class.
Test Plan
test/nx2/blocks/chat-ao/**— 316 tests across 19 files pass (zero behavior change).Risks / Follow-ups
this._attach()/this._refreshEpisodeList()(now Coworker methods) via dynamic dispatch, which is why Base keeps no-op hook defaults.CmaChatController extends Base— ports the ewoncma bridge features (buildAoConnectionInfo+activationKeycombined withx-site,friendlyBackendError, skills→bridge,?bridge=override, +menu customizations), folds in resume-on-reload, and selects the subclass byew.altHarnessinchat-ao.js.feat/chat-ao-stop-indicator) lands in Base (shared behavior).ewoncmaas a long-lived branch once its CMA work is absorbed current withmain.Test URLs: