@@ -240,7 +240,10 @@ export const Streaming: Story = {
240240 */
241241export const StreamingAllowsQueueing : Story = {
242242 args : {
243+ // A queue-backed turn is in flight: both flags are set, so the primary
244+ // button queues the next message rather than starting a concurrent turn.
243245 isStreaming : true ,
246+ isQueuing : true ,
244247 placeholder : "Type a message..." ,
245248 onSend : fn ( ) ,
246249 onStop : fn ( ) ,
@@ -267,12 +270,48 @@ export const StreamingAllowsQueueing: Story = {
267270 } ,
268271} ;
269272
273+ /**
274+ * Test: A stream started outside the queue (editAndRerun/regenerateResponse sets
275+ * `isStreaming` but not `isQueuing`) disables the primary button, so a click or
276+ * Enter can't start a second concurrent turn that would clobber the active one.
277+ */
278+ export const NonQueueStreamBlocksSend : Story = {
279+ args : {
280+ isStreaming : true ,
281+ isQueuing : false ,
282+ placeholder : "Type a message..." ,
283+ onSend : fn ( ) ,
284+ onStop : fn ( ) ,
285+ } ,
286+ play : async ( { canvasElement, args } ) => {
287+ const canvas = within ( canvasElement ) ;
288+
289+ const textarea = canvas . getByPlaceholderText ( "Type a message..." ) ;
290+ await userEvent . type ( textarea , "Next question" ) ;
291+
292+ // The primary button is present but disabled in this state.
293+ const queueButton = canvas . getByRole ( "button" , { name : / q u e u e m e s s a g e / i } ) ;
294+ await expect ( queueButton ) . toBeDisabled ( ) ;
295+
296+ // Enter must not slip past the disabled button and dispatch a send.
297+ await userEvent . type ( textarea , "{Enter}" ) ;
298+ await expect ( args . onSend ) . not . toHaveBeenCalled ( ) ;
299+
300+ // Stop remains available to abort the externally-started stream.
301+ const stopButton = canvas . getByRole ( "button" , { name : / s t o p r e s p o n s e / i } ) ;
302+ await userEvent . click ( stopButton ) ;
303+ await expect ( args . onStop ) . toHaveBeenCalled ( ) ;
304+ } ,
305+ } ;
306+
270307/**
271308 * Test: Queued messages render as removable chips above the input
272309 */
273310export const WithQueuedMessages : Story = {
274311 args : {
312+ // Messages are queued, so the queue is busy and queueing stays enabled.
275313 isStreaming : true ,
314+ isQueuing : true ,
276315 placeholder : "Type a message..." ,
277316 onRemoveQueuedMessage : fn ( ) ,
278317 queuedMessages : [
0 commit comments