Add WorkflowStream service for Duo Chat streaming

What does this MR do and why?

Second of three MRs splitting the Duo Agentic Chat WebSocket service layer into independently reviewable pieces. Depends on BufferedEventHub (MR 1). Nothing consumes this class yet.

stream_manager is a module-level singleton that conflates socket mechanics with lifecycle: callers cannot scope a stream to one workflow, and every consumer has to interpret raw close codes for itself.

WorkflowStream owns a single WebSocket connection through the stream worker and exposes it as a small state machine (IDLE → CONNECTING → OPENED → CLOSED | ERROR). Buffering and replay come from BufferedEventHub.

Close codes are categorised into { category, retryable } so consumers branch on intent rather than on numbers:

Code Category Retryable
1000 normal No
1001 going_away Yes
1008 policy_violation No
1013 try_again_later No
4400 invalid_request No
1006 / other error Yes

Unknown codes fall through to a retryable error rather than being treated as a clean shutdown — that fallthrough is what makes a dropped connection (1006) recoverable in MR 3.

Second commit: gl.dwsMockSocket

exposeMockSocket moves out of stream_manager.js into dws_mock_websocket.js, so both stream_manager and WorkflowStream share one implementation instead of duplicating it.

It now takes a getter rather than a worker instance. Both callers null their worker on terminate(), and resolving per call keeps the console helpers no-ops afterwards instead of posting to a worker that is already gone. Behaviour for stream_manager is unchanged, which is why its specs are untouched — they are the regression guard.

Whichever module creates a worker last owns the global. stream_manager is the live consumer today; WorkflowStream takes over in MR 4.

Chain

MR Delivers
1 !249095 (merged) BufferedEventHub
2 this MR WorkflowStream
3 !249096 (merged) RetryableWorkflowStream + factory
4 !245705 (merged) Wiring + retry UX

How to validate

yarn jest ee/spec/frontend/ai/duo_agentic_chat/websocket/
Edited by Enrique Alcántara

Merge request reports

Loading
Loading