What's broken
In the legacy workflow editor (WorkflowLive.Edit, served from /w/new/legacy and /w/:id/legacy), handle_info({:ai_assistant, action, payload}, socket) does a case action over :canvas_state_changed, :workflow_params_changed, :message_status_changed, :register_component, :unregister_component. There is no fallthrough.
When the legacy AI assistant LiveComponent registers, the parent LV subscribes to ai_session:#{session_id} so it can relay :message_status_changed back to the LiveComponent. That relay is what tells the spinner to stop and renders the finished message. The same PubSub topic also carries the four streaming events used by the collaborative editor: :streaming_status, :streaming_chunk, :streaming_changes, :streaming_error. These were added later for the React side and the legacy case never grew clauses for them. As soon as Apollo emits the first event (typically a :streaming_status "Thinking..."), the LV crashes with CaseClauseError.
How it surfaced
Sentry on v2.16.2, 1 event so far: LIGHTNING-1MV. Breadcrumbs show :register_component for a new AI session, then :streaming_status with text: "Thinking...", then the crash in LightningWeb.WorkflowLive.Edit.handle_info/2.
The two AI assistants are wired very differently:
- The legacy editor uses the server-rendered
LightningWeb.AiAssistant.Component LiveComponent. It does not display character-by-character streaming. It shows a static loading indicator and then renders the finished message once :message_status_changed arrives. The only PubSub event it actually consumes is :message_status_changed.
- The collaborative editor is pure React. The collab LV does not subscribe to
ai_session:* at all. Its React side joins LightningWeb.AiAssistantChannel, which is where the four streaming events are consumed and rendered as the typewriter effect via a Zustand store.
Because the streaming events still flow through the shared ai_session:#{session_id} PubSub topic, they reach the legacy LV by accident, and that is what crashes it.
What to fix
Minimal fix: add a catch-all clause to the case in Edit.handle_info({:ai_assistant, ...}) so unknown actions are dropped silently. The legacy LV consumes none of the four streaming events, so dropping them is correct and does not change any user-visible behaviour. :message_status_changed continues to be handled and remains the relay that lets the LiveComponent finish loading.
A cleaner option, not subscribing the legacy LV to ai_session:* at all and routing :message_status_changed through a narrower channel, is more invasive than the deprecation timeline of the legacy editor warrants.
What's broken
In the legacy workflow editor (
WorkflowLive.Edit, served from/w/new/legacyand/w/:id/legacy),handle_info({:ai_assistant, action, payload}, socket)does acase actionover:canvas_state_changed,:workflow_params_changed,:message_status_changed,:register_component,:unregister_component. There is no fallthrough.When the legacy AI assistant LiveComponent registers, the parent LV subscribes to
ai_session:#{session_id}so it can relay:message_status_changedback to the LiveComponent. That relay is what tells the spinner to stop and renders the finished message. The same PubSub topic also carries the four streaming events used by the collaborative editor::streaming_status,:streaming_chunk,:streaming_changes,:streaming_error. These were added later for the React side and the legacycasenever grew clauses for them. As soon as Apollo emits the first event (typically a:streaming_status"Thinking..."), the LV crashes withCaseClauseError.How it surfaced
Sentry on
v2.16.2, 1 event so far: LIGHTNING-1MV. Breadcrumbs show:register_componentfor a new AI session, then:streaming_statuswithtext: "Thinking...", then the crash inLightningWeb.WorkflowLive.Edit.handle_info/2.The two AI assistants are wired very differently:
LightningWeb.AiAssistant.ComponentLiveComponent. It does not display character-by-character streaming. It shows a static loading indicator and then renders the finished message once:message_status_changedarrives. The only PubSub event it actually consumes is:message_status_changed.ai_session:*at all. Its React side joinsLightningWeb.AiAssistantChannel, which is where the four streaming events are consumed and rendered as the typewriter effect via a Zustand store.Because the streaming events still flow through the shared
ai_session:#{session_id}PubSub topic, they reach the legacy LV by accident, and that is what crashes it.What to fix
Minimal fix: add a catch-all clause to the case in
Edit.handle_info({:ai_assistant, ...})so unknown actions are dropped silently. The legacy LV consumes none of the four streaming events, so dropping them is correct and does not change any user-visible behaviour.:message_status_changedcontinues to be handled and remains the relay that lets the LiveComponent finish loading.A cleaner option, not subscribing the legacy LV to
ai_session:*at all and routing:message_status_changedthrough a narrower channel, is more invasive than the deprecation timeline of the legacy editor warrants.