@@ -787,3 +787,152 @@ async def mock_map_tool_result_part(part):
787787 pytest .skip (
788788 "MCP test needs to be rewritten to use agent.run() instead of manually calling toolset methods"
789789 )
790+
791+
792+ @pytest .mark .asyncio
793+ async def test_context_cleanup_after_run (sentry_init , test_agent ):
794+ """
795+ Test that the pydantic_ai_agent context is properly cleaned up after agent execution.
796+ """
797+ import sentry_sdk
798+
799+ sentry_init (
800+ integrations = [PydanticAIIntegration ()],
801+ traces_sample_rate = 1.0 ,
802+ )
803+
804+ # Verify context is not set before run
805+ scope = sentry_sdk .get_current_scope ()
806+ assert "pydantic_ai_agent" not in scope ._contexts
807+
808+ # Run the agent
809+ await test_agent .run ("Test input" )
810+
811+ # Verify context is cleaned up after run
812+ assert "pydantic_ai_agent" not in scope ._contexts
813+
814+
815+ def test_context_cleanup_after_run_sync (sentry_init , test_agent ):
816+ """
817+ Test that the pydantic_ai_agent context is properly cleaned up after sync agent execution.
818+ """
819+ import sentry_sdk
820+
821+ sentry_init (
822+ integrations = [PydanticAIIntegration ()],
823+ traces_sample_rate = 1.0 ,
824+ )
825+
826+ # Verify context is not set before run
827+ scope = sentry_sdk .get_current_scope ()
828+ assert "pydantic_ai_agent" not in scope ._contexts
829+
830+ # Run the agent synchronously
831+ test_agent .run_sync ("Test input" )
832+
833+ # Verify context is cleaned up after run
834+ assert "pydantic_ai_agent" not in scope ._contexts
835+
836+
837+ @pytest .mark .asyncio
838+ async def test_context_cleanup_after_streaming (sentry_init , test_agent ):
839+ """
840+ Test that the pydantic_ai_agent context is properly cleaned up after streaming execution.
841+ """
842+ import sentry_sdk
843+
844+ sentry_init (
845+ integrations = [PydanticAIIntegration ()],
846+ traces_sample_rate = 1.0 ,
847+ )
848+
849+ # Verify context is not set before run
850+ scope = sentry_sdk .get_current_scope ()
851+ assert "pydantic_ai_agent" not in scope ._contexts
852+
853+ # Run the agent with streaming
854+ async with test_agent .run_stream ("Test input" ) as result :
855+ async for _ in result .stream_output ():
856+ pass
857+
858+ # Verify context is cleaned up after streaming completes
859+ assert "pydantic_ai_agent" not in scope ._contexts
860+
861+
862+ @pytest .mark .asyncio
863+ async def test_context_cleanup_on_error (sentry_init , test_agent ):
864+ """
865+ Test that the pydantic_ai_agent context is cleaned up even when an error occurs.
866+ """
867+ import sentry_sdk
868+
869+ # Create an agent with a tool that raises an error
870+ @test_agent .tool_plain
871+ def failing_tool () -> str :
872+ """A tool that always fails."""
873+ raise ValueError ("Tool error" )
874+
875+ sentry_init (
876+ integrations = [PydanticAIIntegration ()],
877+ traces_sample_rate = 1.0 ,
878+ )
879+
880+ # Verify context is not set before run
881+ scope = sentry_sdk .get_current_scope ()
882+ assert "pydantic_ai_agent" not in scope ._contexts
883+
884+ # Run the agent - this may or may not raise depending on pydantic-ai's error handling
885+ try :
886+ await test_agent .run ("Use the failing tool" )
887+ except Exception :
888+ pass
889+
890+ # Verify context is cleaned up even if there was an error
891+ assert "pydantic_ai_agent" not in scope ._contexts
892+
893+
894+ @pytest .mark .asyncio
895+ async def test_context_isolation_concurrent_agents (sentry_init , test_agent ):
896+ """
897+ Test that concurrent agent executions maintain isolated contexts.
898+ """
899+ import sentry_sdk
900+
901+ sentry_init (
902+ integrations = [PydanticAIIntegration ()],
903+ traces_sample_rate = 1.0 ,
904+ )
905+
906+ # Create a second agent
907+ agent2 = Agent (
908+ "test" ,
909+ name = "test_agent_2" ,
910+ system_prompt = "Second test agent." ,
911+ )
912+
913+ async def run_and_check_context (agent , agent_name ):
914+ """Run an agent and verify its context during and after execution."""
915+ # Before execution, context should not exist in the outer scope
916+ outer_scope = sentry_sdk .get_current_scope ()
917+
918+ # Run the agent
919+ await agent .run (f"Input for { agent_name } " )
920+
921+ # After execution, verify context is cleaned up
922+ # Note: Due to isolation_scope, we can't easily check the inner scope here,
923+ # but we can verify the outer scope remains clean
924+ assert "pydantic_ai_agent" not in outer_scope ._contexts
925+
926+ return agent_name
927+
928+ # Run both agents concurrently
929+ results = await asyncio .gather (
930+ run_and_check_context (test_agent , "agent1" ),
931+ run_and_check_context (agent2 , "agent2" ),
932+ )
933+
934+ assert results == ["agent1" , "agent2" ]
935+
936+ # Final check: outer scope should be clean
937+ final_scope = sentry_sdk .get_current_scope ()
938+ assert "pydantic_ai_agent" not in final_scope ._contexts
0 commit comments