@@ -345,6 +345,47 @@ async def test_streaming_emits_final_snapshot_only_when_stream_has_no_final_answ
345345 assert final_event .last_chunk is True
346346
347347
348+ @pytest .mark .asyncio
349+ async def test_streaming_final_snapshot_does_not_repeat_reasoning_content () -> None :
350+ client = DummyStreamingClient (
351+ stream_events_payload = [
352+ _event (session_id = "ses-1" , role = "assistant" , part_type = "reasoning" , delta = "draft plan" ),
353+ ],
354+ response_text = "final answer from send_message" ,
355+ response_raw = {
356+ "parts" : [
357+ {"type" : "reasoning" , "text" : "draft plan" },
358+ {"type" : "text" , "text" : "final answer from send_message" },
359+ ]
360+ },
361+ )
362+ executor = OpencodeAgentExecutor (client , streaming_enabled = True )
363+ executor ._should_stream = lambda context : True # type: ignore[method-assign]
364+ queue = DummyEventQueue ()
365+
366+ await executor .execute (
367+ make_request_context (task_id = "task-3b" , context_id = "ctx-3b" , text = "hello" ), queue
368+ )
369+
370+ reasoning_updates = [
371+ event
372+ for event in _artifact_updates (queue )
373+ if _artifact_stream_meta (event )["block_type" ] == "reasoning"
374+ ]
375+ assert len (reasoning_updates ) == 1
376+ assert _part_text (reasoning_updates [0 ]) == "draft plan"
377+
378+ text_updates = [
379+ event
380+ for event in _artifact_updates (queue )
381+ if _artifact_stream_meta (event )["block_type" ] == "text"
382+ ]
383+ assert len (text_updates ) == 1
384+ assert _part_text (text_updates [0 ]) == "final answer from send_message"
385+ assert "draft plan" not in _part_text (text_updates [0 ])
386+ assert _artifact_stream_meta (text_updates [0 ])["source" ] == "final_snapshot"
387+
388+
348389@pytest .mark .asyncio
349390async def test_execute_serializes_send_message_per_session () -> None :
350391 client = DummyStreamingClient (
0 commit comments