@@ -482,9 +482,9 @@ def test_fetch_ai_model_costs_custom_model_mapping(self) -> None:
482482 assert "nonexistent-mapping" not in models
483483
484484 @responses .activate
485- def test_fetch_ai_model_costs_with_glob_model_names (self ) -> None :
486- """Test that glob versions of model names are added correctly"""
487- # Mock responses with models that should generate glob patterns
485+ def test_fetch_ai_model_costs_with_normalized_and_prefix_glob_names (self ) -> None :
486+ """Test that normalized and prefix glob versions of model names are added correctly"""
487+ # Mock responses with models that have dates/versions that should be normalized
488488 mock_openrouter_response = {
489489 "data" : [
490490 {
@@ -502,7 +502,7 @@ def test_fetch_ai_model_costs_with_glob_model_names(self) -> None:
502502 },
503503 },
504504 {
505- "id" : "openai/gpt-4" , # No date/version, should not generate glob
505+ "id" : "openai/gpt-4" , # No date/version, normalized version same as original
506506 "pricing" : {
507507 "prompt" : "0.0000003" ,
508508 "completion" : "0.00000165" ,
@@ -548,104 +548,100 @@ def test_fetch_ai_model_costs_with_glob_model_names(self) -> None:
548548 assert "claude-3-5-haiku@20241022" in models
549549 assert "o3-pro-2025-06-10" in models
550550
551- # Check suffix glob versions were added
552- assert "gpt-4o-mini-* " in models
553- assert "claude-3-5-sonnet-* " in models
554- assert "claude-3-5-haiku@* " in models
555- assert "o3-pro-* " in models
551+ # Check normalized versions were added (dates/versions removed)
552+ assert "gpt-4o-mini" in models
553+ assert "claude-3-5-sonnet" in models
554+ assert "claude-3-5-haiku" in models # @ is not part of the date pattern
555+ assert "o3-pro" in models
556556
557- # Check prefix glob versions were added
558- assert "*gpt-4o-mini-20250522 " in models
559- assert "*claude-3-5-sonnet-20241022 " in models
557+ # Check prefix glob versions of normalized models were added
558+ assert "*gpt-4o-mini" in models
559+ assert "*claude-3-5-sonnet" in models
560560 assert "*gpt-4" in models
561- assert "*claude-3-5-haiku@20241022 " in models
562- assert "*o3-pro-2025-06-10 " in models
561+ assert "*claude-3-5-haiku" in models
562+ assert "*o3-pro" in models
563563
564- # Check prefix-suffix glob versions were added (only for models with suffix globs)
565- assert "*gpt-4o-mini-*" in models
566- assert "*claude-3-5-sonnet-*" in models
567- assert "*claude-3-5-haiku@*" in models
568- assert "*o3-pro-*" in models
569-
570- # Verify glob versions have same pricing as original models
564+ # Verify normalized versions have same pricing as original models
571565 gpt4o_mini_original = models ["gpt-4o-mini-20250522" ]
572- gpt4o_mini_glob = models ["gpt-4o-mini-*" ]
573- assert gpt4o_mini_original .get ("inputPerToken" ) == gpt4o_mini_glob .get ("inputPerToken" )
574- assert gpt4o_mini_original .get ("outputPerToken" ) == gpt4o_mini_glob .get ("outputPerToken" )
566+ gpt4o_mini_normalized = models ["gpt-4o-mini" ]
567+ assert gpt4o_mini_original .get ("inputPerToken" ) == gpt4o_mini_normalized .get (
568+ "inputPerToken"
569+ )
570+ assert gpt4o_mini_original .get ("outputPerToken" ) == gpt4o_mini_normalized .get (
571+ "outputPerToken"
572+ )
575573
576574 claude_sonnet_original = models ["claude-3-5-sonnet-20241022" ]
577- claude_sonnet_glob = models ["claude-3-5-sonnet-* " ]
578- assert claude_sonnet_original .get ("inputPerToken" ) == claude_sonnet_glob .get (
575+ claude_sonnet_normalized = models ["claude-3-5-sonnet" ]
576+ assert claude_sonnet_original .get ("inputPerToken" ) == claude_sonnet_normalized .get (
579577 "inputPerToken"
580578 )
581- assert claude_sonnet_original .get ("outputPerToken" ) == claude_sonnet_glob .get (
579+ assert claude_sonnet_original .get ("outputPerToken" ) == claude_sonnet_normalized .get (
582580 "outputPerToken"
583581 )
584582
585583 claude_haiku_original = models ["claude-3-5-haiku@20241022" ]
586- claude_haiku_glob = models ["claude-3-5-haiku@*" ]
587- assert claude_haiku_original .get ("inputPerToken" ) == claude_haiku_glob .get ("inputPerToken" )
588- assert claude_haiku_original .get ("outputPerToken" ) == claude_haiku_glob .get (
584+ claude_haiku_normalized = models ["claude-3-5-haiku" ]
585+ assert claude_haiku_original .get ("inputPerToken" ) == claude_haiku_normalized .get (
586+ "inputPerToken"
587+ )
588+ assert claude_haiku_original .get ("outputPerToken" ) == claude_haiku_normalized .get (
589589 "outputPerToken"
590590 )
591591
592592 o3_pro_original = models ["o3-pro-2025-06-10" ]
593- o3_pro_glob = models ["o3-pro-* " ]
594- assert o3_pro_original .get ("inputPerToken" ) == o3_pro_glob .get ("inputPerToken" )
595- assert o3_pro_original .get ("outputPerToken" ) == o3_pro_glob .get ("outputPerToken" )
593+ o3_pro_normalized = models ["o3-pro" ]
594+ assert o3_pro_original .get ("inputPerToken" ) == o3_pro_normalized .get ("inputPerToken" )
595+ assert o3_pro_original .get ("outputPerToken" ) == o3_pro_normalized .get ("outputPerToken" )
596596
597- # Verify gpt-4 (no date/version) doesn't have a suffix glob version
598- assert "gpt-4*" not in models
599-
600- # Verify prefix glob versions have same pricing as original models
601- gpt4_original = models ["gpt-4" ]
597+ # Verify prefix glob versions have same pricing as normalized models
598+ gpt4_normalized = models ["gpt-4" ]
602599 gpt4_prefix_glob = models ["*gpt-4" ]
603- assert gpt4_original .get ("inputPerToken" ) == gpt4_prefix_glob .get ("inputPerToken" )
604- assert gpt4_original .get ("outputPerToken" ) == gpt4_prefix_glob .get ("outputPerToken" )
600+ assert gpt4_normalized .get ("inputPerToken" ) == gpt4_prefix_glob .get ("inputPerToken" )
601+ assert gpt4_normalized .get ("outputPerToken" ) == gpt4_prefix_glob .get ("outputPerToken" )
605602
606- # Verify prefix-suffix glob versions have same pricing as original models
607- gpt4o_mini_prefix_suffix_glob = models ["*gpt-4o-mini-*" ]
608- assert gpt4o_mini_original .get ("inputPerToken" ) == gpt4o_mini_prefix_suffix_glob .get (
603+ gpt4o_mini_prefix_glob = models ["*gpt-4o-mini" ]
604+ assert gpt4o_mini_normalized .get ("inputPerToken" ) == gpt4o_mini_prefix_glob .get (
609605 "inputPerToken"
610606 )
611- assert gpt4o_mini_original .get ("outputPerToken" ) == gpt4o_mini_prefix_suffix_glob .get (
607+ assert gpt4o_mini_normalized .get ("outputPerToken" ) == gpt4o_mini_prefix_glob .get (
612608 "outputPerToken"
613609 )
614610
615- @responses .activate
616- def test_create_suffix_glob_model_name_various_formats (self ) -> None :
617- """Test suffix glob generation with various date and version formats"""
618- from sentry .tasks .ai_agent_monitoring import _create_suffix_glob_model_name
611+ def test_normalize_model_id (self ) -> None :
612+ """Test model ID normalization with various date and version formats"""
613+ from sentry .tasks .ai_agent_monitoring import _normalize_model_id
619614
620615 # Test cases with expected outputs
621616 test_cases = [
622- ("model-20250522" , "model-*" ), # YYYYMMDD -> *
623- ("model-2025-06-10" , "model-*" ), # YYYY-MM-DD -> *
624- ("model-2025/06/10" , "model-*" ), # YYYY/MM/DD -> *
625- ("model-2025.06.10" , "model-*" ), # YYYY.MM.DD -> *
626- ("model-v1.0" , "model-*" ), # v1.0 -> *
627- ("model-v2.1.0" , "model-*" ), # v2.1.0 -> *
628- ("model@20241022" , "model@*" ), # @YYYYMMDD -> @*
629- ("model-v1:0" , "model-*" ), # v1:0 -> *
630- ("model-20250610-v1:0" , "model-*" ), # YYYYMMDD-v1:0 -> *
631- ("model@20250610-v1:0" , "model@*" ), # @YYYYMMDD-v1:0 -> @*
617+ ("model-20250522" , "model" ), # YYYYMMDD removed
618+ ("model-2025-06-10" , "model" ), # YYYY-MM-DD removed
619+ ("model-2025/06/10" , "model" ), # YYYY/MM/DD removed
620+ ("model-2025.06.10" , "model" ), # YYYY.MM.DD removed
621+ ("model-v1.0" , "model" ), # v1.0 removed
622+ ("model@20241022" , "model" ), # @YYYYMMDD removed
623+ ("model-v1:0" , "model" ), # v1:0 removed
624+ ("model-20250610-v1:0" , "model" ), # YYYYMMDD-v1:0 removed
625+ ("model@20250610-v1:0" , "model" ), # @YYYYMMDD-v1:0 removed
626+ ("gpt-4" , "gpt-4" ), # No date/version, unchanged
627+ ("claude-3-5-sonnet" , "claude-3-5-sonnet" ), # Numbers are part of model name, unchanged
632628 ]
633629
634- for model_id , expected_glob in test_cases :
635- actual_glob = _create_suffix_glob_model_name (model_id )
630+ for model_id , expected_normalized in test_cases :
631+ actual_normalized = _normalize_model_id (model_id )
636632 assert (
637- actual_glob == expected_glob
638- ), f"Expected { expected_glob } for { model_id } , got { actual_glob } "
633+ actual_normalized == expected_normalized
634+ ), f"Expected { expected_normalized } for { model_id } , got { actual_normalized } "
639635
640- @responses .activate
641636 def test_create_prefix_glob_model_name (self ) -> None :
642637 """Test prefix glob generation for model names"""
643638 from sentry .tasks .ai_agent_monitoring import _create_prefix_glob_model_name
644639
645640 # Test cases with expected outputs
646641 test_cases = [
647642 ("gpt-4" , "*gpt-4" ),
648- ("gpt-4o-mini-*" , "*gpt-4o-mini-*" ),
643+ ("gpt-4o-mini" , "*gpt-4o-mini" ),
644+ ("claude-3-5-sonnet" , "*claude-3-5-sonnet" ),
649645 ("" , "*" ),
650646 ]
651647
0 commit comments