This is an automated email from the ASF dual-hosted git repository.

vincbeck pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new 140c13dc96c Skip legacy models when selecting a Bedrock inference 
profile (#72521)
140c13dc96c is described below

commit 140c13dc96c229bf6af9f4f2bcc12ca2b410930e
Author: Vincent <[email protected]>
AuthorDate: Thu Sep 10 12:35:50 2026 -0400

    Skip legacy models when selecting a Bedrock inference profile (#72521)
    
    get_text_inference_profile_arn() returns the first "sonnet" inference 
profile
    in list_inference_profiles order. That order is not stable, and when it 
changed
    the helper started returning a profile backed by a model its provider had
    marked as legacy. Bedrock then rejects the request:
    
        ValidationException: This Model is marked by provider as Legacy and you
        have not been actively using the model in the last 30 days. Please 
upgrade
        to an active model on Amazon Bedrock.
    
    example_bedrock_batch_inference and example_bedrock_retrieve_and_generate 
both
    use this helper, so both fail for as long as a legacy model sits first in 
the
    listing.
    
    The inference profile summaries do not expose a lifecycle status, so look 
the
    legacy models up with list_foundation_models and skip any profile that
    resolves to one of them. Foundation model IDs are compared rather than ARNs
    because a global profile resolves to the same model in several regions.
    
    * Pick a stable inference profile for Bedrock system tests
    
    Requiring an ACTIVE lifecycle status keeps the selection correct if Bedrock 
ever
    reports a status beyond today's ACTIVE/LEGACY pair, and preferring the 
oldest
    release makes each run pick the same model instead of drifting onto a fresh 
one
    that batch inference or RAG may not support yet.
---
 .../tests/system/amazon/aws/utils/bedrock.py       | 60 +++++++++++++++++-----
 1 file changed, 48 insertions(+), 12 deletions(-)

diff --git a/providers/amazon/tests/system/amazon/aws/utils/bedrock.py 
b/providers/amazon/tests/system/amazon/aws/utils/bedrock.py
index 4b833b7438f..358848c9983 100644
--- a/providers/amazon/tests/system/amazon/aws/utils/bedrock.py
+++ b/providers/amazon/tests/system/amazon/aws/utils/bedrock.py
@@ -17,6 +17,7 @@
 from __future__ import annotations
 
 import logging
+import re
 
 log = logging.getLogger(__name__)
 
@@ -26,6 +27,21 @@ except ImportError:
     from airflow.decorators import task  # type: ignore[attr-defined, no-redef]
 
 
+def _foundation_model_id(model_arn: str) -> str:
+    """Return the model ID part of a foundation model ARN, which is identical 
in every region."""
+    return model_arn.rpartition("/")[2]
+
+
+def _release_date(inference_profile_id: str) -> str:
+    """
+    Return the ``YYYYMMDD`` release date model providers embed in their 
version, e.g.
+    ``global.anthropic.claude-sonnet-4-5-20250929-v1:0``. An ID without one 
sorts last, so an
+    unrecognised naming scheme is treated as the newest rather than silently 
preferred.
+    """
+    match = re.search(r"\d{8}", inference_profile_id)
+    return match.group() if match else "99999999"
+
+
 @task
 def get_text_inference_profile_arn() -> str:
     """
@@ -37,17 +53,37 @@ def get_text_inference_profile_arn() -> str:
     from airflow.providers.amazon.aws.hooks.bedrock import BedrockHook
 
     client = BedrockHook().conn
+
+    # Bedrock only accepts a model whose lifecycle status is ACTIVE, so 
requiring that status keeps this
+    # working if a provider ever reports something other than today's 
ACTIVE/LEGACY pair. The inference
+    # profile summaries do not carry the lifecycle status, only the foundation 
models a profile resolves to.
+    active_model_ids = {
+        model["modelId"]
+        for model in client.list_foundation_models()["modelSummaries"]
+        if model.get("modelLifecycle", {}).get("status") == "ACTIVE"
+    }
+
     profiles = 
client.list_inference_profiles(typeEquals="SYSTEM_DEFINED")["inferenceProfileSummaries"]
-    arns = [
-        profile["inferenceProfileArn"]
-        for profile in profiles
-        if profile.get("status") == "ACTIVE" and 
profile["inferenceProfileId"].startswith("global.anthropic.")
-    ]
-    log.info("Valid text inference profile ARNs: %s", arns)
-
-    for arn in arns:
+    # Oldest release first, so a run picks a mature model rather than a fresh 
one that batch inference or
+    # RAG may not support yet, and picks the same one on every run.
+    candidates = sorted(
+        (
+            profile
+            for profile in profiles
+            if profile.get("status") == "ACTIVE"
+            and profile["inferenceProfileId"].startswith("global.anthropic.")
+            and all(
+                _foundation_model_id(model["modelArn"]) in active_model_ids 
for model in profile["models"]
+            )
+        ),
+        key=lambda profile: (_release_date(profile["inferenceProfileId"]), 
profile["inferenceProfileId"]),
+    )
+    profile_ids = [profile["inferenceProfileId"] for profile in candidates]
+    log.info("Valid text inference profiles, oldest first: %s", profile_ids)
+
+    for profile in candidates:
         # Haiku has some version dependency issues: RAG only supports 3.5 but 
batch only supports 4.5
-        if "sonnet" in arn:
-            log.info("Selected inference profile ARN: %s", arn)
-            return arn
-    raise RuntimeError("No valid inference profiles found")
+        if "sonnet" in profile["inferenceProfileId"]:
+            log.info("Selected inference profile ARN: %s", 
profile["inferenceProfileArn"])
+            return profile["inferenceProfileArn"]
+    raise RuntimeError(f"No valid inference profiles found. Active candidates 
were: {profile_ids}")

Reply via email to