@@ -5793,6 +5793,139 @@ def test_transform_google_file_data(self):
57935793 }
57945794
57955795
5796+ @pytest .mark .parametrize ("span_streaming" , [True , False ])
5797+ @pytest .mark .parametrize ("stream_gen_ai_spans" , [True , False ])
5798+ @pytest .mark .parametrize (
5799+ "ai_type,expected_system" ,
5800+ [
5801+ # Real LangChain _type values (from _llm_type properties)
5802+ # OpenAI
5803+ ("openai-chat" , "openai-chat" ),
5804+ ("openai" , "openai" ),
5805+ # Azure OpenAI
5806+ ("azure-openai-chat" , "azure-openai-chat" ),
5807+ ("azure" , "azure" ),
5808+ # Anthropic
5809+ ("anthropic-chat" , "anthropic-chat" ),
5810+ # Google
5811+ ("vertexai" , "vertexai" ),
5812+ ("chat-google-generative-ai" , "chat-google-generative-ai" ),
5813+ ("google_gemini" , "google_gemini" ),
5814+ # AWS Bedrock
5815+ ("amazon_bedrock_chat" , "amazon_bedrock_chat" ),
5816+ ("amazon_bedrock" , "amazon_bedrock" ),
5817+ # Cohere
5818+ ("cohere-chat" , "cohere-chat" ),
5819+ # Ollama
5820+ ("chat-ollama" , "chat-ollama" ),
5821+ ("ollama-llm" , "ollama-llm" ),
5822+ # Mistral
5823+ ("mistralai-chat" , "mistralai-chat" ),
5824+ # Fireworks
5825+ ("fireworks-chat" , "fireworks-chat" ),
5826+ ("fireworks" , "fireworks" ),
5827+ # HuggingFace
5828+ ("huggingface-chat-wrapper" , "huggingface-chat-wrapper" ),
5829+ # Groq
5830+ ("groq-chat" , "groq-chat" ),
5831+ # NVIDIA
5832+ ("chat-nvidia-ai-playground" , "chat-nvidia-ai-playground" ),
5833+ # xAI
5834+ ("xai-chat" , "xai-chat" ),
5835+ # DeepSeek
5836+ ("chat-deepseek" , "chat-deepseek" ),
5837+ # Edge cases
5838+ ("" , None ),
5839+ (None , None ),
5840+ ],
5841+ )
5842+ def test_langchain_ai_system_detection (
5843+ sentry_init ,
5844+ capture_events ,
5845+ capture_items ,
5846+ ai_type ,
5847+ expected_system ,
5848+ stream_gen_ai_spans ,
5849+ span_streaming ,
5850+ ):
5851+ sentry_init (
5852+ integrations = [LangchainIntegration ()],
5853+ disabled_integrations = [StdlibIntegration ],
5854+ traces_sample_rate = 1.0 ,
5855+ stream_gen_ai_spans = stream_gen_ai_spans ,
5856+ trace_lifecycle = "stream" if span_streaming else "static" ,
5857+ )
5858+
5859+ callback = SentryLangchainCallback (max_span_map_size = 100 , include_prompts = True )
5860+
5861+ run_id = "test-ai-system-uuid"
5862+ serialized = {"_type" : ai_type } if ai_type is not None else {}
5863+ prompts = ["Test prompt" ]
5864+
5865+ if span_streaming or stream_gen_ai_spans :
5866+ items = capture_items ("span" )
5867+
5868+ with start_transaction ():
5869+ callback .on_llm_start (
5870+ serialized = serialized ,
5871+ prompts = prompts ,
5872+ run_id = run_id ,
5873+ invocation_params = {"_type" : ai_type , "model" : "test-model" },
5874+ )
5875+
5876+ generation = Mock (text = "Test response" , message = None )
5877+ response = Mock (generations = [[generation ]])
5878+ callback .on_llm_end (response = response , run_id = run_id )
5879+
5880+ sentry_sdk .flush ()
5881+ spans = [item .payload for item in items ]
5882+ llm_spans = [
5883+ span
5884+ for span in spans
5885+ if span ["attributes" ].get ("sentry.op" ) == "gen_ai.text_completion"
5886+ ]
5887+
5888+ assert len (llm_spans ) > 0
5889+ llm_span = llm_spans [0 ]
5890+
5891+ if expected_system is not None :
5892+ assert llm_span ["attributes" ][SPANDATA .GEN_AI_SYSTEM ] == expected_system
5893+ else :
5894+ assert SPANDATA .GEN_AI_SYSTEM not in llm_span .get ("attributes" , {})
5895+ else :
5896+ events = capture_events ()
5897+
5898+ with start_transaction ():
5899+ callback .on_llm_start (
5900+ serialized = serialized ,
5901+ prompts = prompts ,
5902+ run_id = run_id ,
5903+ invocation_params = {"_type" : ai_type , "model" : "test-model" },
5904+ )
5905+
5906+ generation = Mock (text = "Test response" , message = None )
5907+ response = Mock (generations = [[generation ]])
5908+ callback .on_llm_end (response = response , run_id = run_id )
5909+
5910+ assert len (events ) > 0
5911+ tx = events [0 ]
5912+ assert tx ["type" ] == "transaction"
5913+
5914+ llm_spans = [
5915+ span
5916+ for span in tx .get ("spans" , [])
5917+ if span .get ("op" ) == "gen_ai.text_completion"
5918+ ]
5919+
5920+ assert len (llm_spans ) > 0
5921+ llm_span = llm_spans [0 ]
5922+
5923+ if expected_system is not None :
5924+ assert llm_span ["data" ][SPANDATA .GEN_AI_SYSTEM ] == expected_system
5925+ else :
5926+ assert SPANDATA .GEN_AI_SYSTEM not in llm_span .get ("data" , {})
5927+
5928+
57965929class TestTransformLangchainMessageContent :
57975930 """Tests for _transform_langchain_message_content function."""
57985931
0 commit comments