@@ -1460,6 +1460,72 @@ async def test_streamed_run_surfaces_redacted_output_validation_error(
14601460 _assert_secret_absent_from_agents_traceback (error , _MODEL_OUTPUT_SECRET )
14611461
14621462
1463+ @pytest .mark .parametrize ("redacted" , [False , True ])
1464+ @pytest .mark .asyncio
1465+ async def test_streamed_task_observers_follow_model_data_policy (
1466+ monkeypatch : pytest .MonkeyPatch ,
1467+ redacted : bool ,
1468+ ) -> None :
1469+ monkeypatch .setattr (_debug , "DONT_LOG_MODEL_DATA" , redacted )
1470+ monkeypatch .setattr (_debug , "DONT_LOG_TOOL_DATA" , False )
1471+ input_secret = "STREAM_TASK_INPUT_CANARY"
1472+ context = {"private" : "STREAM_TASK_CONTEXT_CANARY" }
1473+ session = SimpleListSession (
1474+ session_id = "stream-task-redaction" ,
1475+ history = [{"role" : "user" , "content" : "STREAM_TASK_SESSION_CANARY" }],
1476+ )
1477+ model = ScriptedModel (steps = [[get_text_message (f'{{"answer": "{ _MODEL_OUTPUT_SECRET } "}}' )]])
1478+ agent = Agent (name = "A" , model = model , output_type = _RequiredOutput )
1479+ result = Runner .run_streamed (agent , input_secret , context = context , session = session )
1480+ task = result .run_loop_task
1481+ assert task is not None
1482+ observed = asyncio .get_running_loop ().create_future ()
1483+
1484+ def observe_task (completed : asyncio .Task [Any ]) -> None :
1485+ error = completed .exception ()
1486+ assert isinstance (error , ModelBehaviorError )
1487+ # Snapshot before a result accessor or stream consumer can sanitize the exception.
1488+ frames = [dict (frame ) for frame in _agents_traceback_frame_locals (error )]
1489+ observed .set_result ((error , frames , repr (frames )))
1490+
1491+ task .add_done_callback (observe_task )
1492+ error , callback_frames , callback_snapshot = await observed
1493+ with pytest .raises (ModelBehaviorError ) as exc_info :
1494+ await task
1495+ assert exc_info .value is error
1496+ await_frames = _agents_traceback_frame_locals (error )
1497+
1498+ if redacted :
1499+ assert error .run_data is None
1500+ assert error .__cause__ is None
1501+ assert error .__context__ is None
1502+ for secret in (
1503+ input_secret ,
1504+ context ["private" ],
1505+ "STREAM_TASK_SESSION_CANARY" ,
1506+ _MODEL_OUTPUT_SECRET ,
1507+ ):
1508+ assert secret not in callback_snapshot
1509+ _assert_secret_absent_from_agents_traceback (error , secret )
1510+ for frame in callback_frames + await_frames :
1511+ for value in frame .values ():
1512+ assert value is not session
1513+ assert value is not result
1514+ assert value is not context
1515+ assert not isinstance (value , RunContextWrapper )
1516+ else :
1517+ assert _MODEL_OUTPUT_SECRET in str (error )
1518+ assert isinstance (error .__cause__ , ValidationError )
1519+ assert input_secret in callback_snapshot
1520+ assert any (frame .get ("session" ) is session for frame in callback_frames )
1521+ assert any (frame .get ("session" ) is session for frame in await_frames )
1522+
1523+ with pytest .raises (ModelBehaviorError ) as stream_exc_info :
1524+ async for _ in result .stream_events ():
1525+ pass
1526+ assert stream_exc_info .value is error
1527+
1528+
14631529@pytest .mark .parametrize ("redacted" , [False , True ])
14641530@pytest .mark .asyncio
14651531async def test_streamed_run_loop_exception_follows_model_data_policy (
0 commit comments