You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by pa...@apache.org on 2026/09/22 07:06:59 UTC
(airflow) branch main updated: Replace retired gemini-2.0-flash example model in common.ai Vertex docs (#73516)
This is an automated email from the ASF dual-hosted git repository.
pankajastro 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 3eabbb59586 Replace retired gemini-2.0-flash example model in common.ai Vertex docs (#73516)
3eabbb59586 is described below
commit 3eabbb59586f3c4f321894a31a423256513e2244
Author: Pankaj Singh <98...@users.noreply.github.com>
AuthorDate: Tue Sep 22 12:36:47 2026 +0530
Replace retired gemini-2.0-flash example model in common.ai Vertex docs (#73516)
Google shut this model down on both Vertex AI and the Generative
Language API, so the connection form's placeholder and every doc page
that copied it sent a first-time user straight into a 404. The
existing tests only checked that the google-cloud prefix was a
provider pydantic-ai recognizes, never that the specific model after
the colon was actually servable, which is how a retired name went
unnoticed.
---
.../common/ai/docs/connections/pydantic_ai.rst | 4 +-
.../ai/docs/connections/pydantic_ai_vertex.rst | 8 +--
providers/common/ai/provider.yaml | 4 +-
.../providers/common/ai/get_provider_info.py | 4 +-
.../providers/common/ai/hooks/pydantic_ai.py | 8 +--
.../tests/unit/common/ai/hooks/test_pydantic_ai.py | 75 ++++++++++++++++++----
6 files changed, 75 insertions(+), 28 deletions(-)
diff --git a/providers/common/ai/docs/connections/pydantic_ai.rst b/providers/common/ai/docs/connections/pydantic_ai.rst
index f82f5d4042b..ba1447a5bed 100644
--- a/providers/common/ai/docs/connections/pydantic_ai.rst
+++ b/providers/common/ai/docs/connections/pydantic_ai.rst
@@ -44,7 +44,7 @@ Model
naming this connection rather than being resolved automatically.
Examples: ``openai:gpt-5.6-sol``, ``anthropic:claude-sonnet-5``,
- ``bedrock:us.anthropic.claude-opus-4-6-v1:0``, ``google:gemini-2.0-flash``
+ ``bedrock:us.anthropic.claude-opus-4-6-v1:0``, ``google:gemini-2.5-flash``
See `Anthropic's models overview <https://platform.claude.com/docs/en/about-claude/models/overview#latest-models-comparison>`__
for the current list of Claude model IDs across the Claude API, Amazon Bedrock, and Google Cloud.
@@ -145,7 +145,7 @@ in the environment:
{
"conn_type": "pydanticai",
- "extra": "{\"model\": \"google:gemini-2.0-flash\"}"
+ "extra": "{\"model\": \"google:gemini-2.5-flash\"}"
}
This connects to the Gemini API (Google AI Studio), not Vertex AI — pydantic-ai's
diff --git a/providers/common/ai/docs/connections/pydantic_ai_vertex.rst b/providers/common/ai/docs/connections/pydantic_ai_vertex.rst
index 03503960491..bbf210e79b8 100644
--- a/providers/common/ai/docs/connections/pydantic_ai_vertex.rst
+++ b/providers/common/ai/docs/connections/pydantic_ai_vertex.rst
@@ -63,8 +63,8 @@ Configuring the Connection
All fields below are ``extra`` (JSON) fields.
Model
- Google model identifier (e.g. ``google-cloud:gemini-2.0-flash``, or the
- bare ``gemini-2.0-flash``). A bare name is automatically resolved to
+ Google model identifier (e.g. ``google-cloud:gemini-2.5-flash``, or the
+ bare ``gemini-2.5-flash``). A bare name is automatically resolved to
``google-cloud:<name>``, instantiating the ``GoogleCloudProvider`` that
accepts this hook's ``project`` / ``location`` / ``service_account_info``
fields (see "Credentials" below) -- Vertex AI is this connection type's
@@ -152,7 +152,7 @@ environment:
{
"conn_type": "pydanticai_vertex",
- "extra": "{\"model\": \"google-cloud:gemini-2.0-flash\", \"project\": \"my-gcp-project\", \"location\": \"us-central1\"}"
+ "extra": "{\"model\": \"google-cloud:gemini-2.5-flash\", \"project\": \"my-gcp-project\", \"location\": \"us-central1\"}"
}
**Inline service account**
@@ -161,5 +161,5 @@ environment:
{
"conn_type": "pydanticai_vertex",
- "extra": "{\"model\": \"google-cloud:gemini-2.0-flash\", \"project\": \"my-gcp-project\", \"location\": \"us-central1\", \"service_account_info\": {\"type\": \"service_account\", \"project_id\": \"my-gcp-project\", \"private_key\": \"<contents of the service account JSON key's private_key field>\", \"client_email\": \"sa@my-gcp-project.iam.gserviceaccount.com\"}}"
+ "extra": "{\"model\": \"google-cloud:gemini-2.5-flash\", \"project\": \"my-gcp-project\", \"location\": \"us-central1\", \"service_account_info\": {\"type\": \"service_account\", \"project_id\": \"my-gcp-project\", \"private_key\": \"<contents of the service account JSON key's private_key field>\", \"client_email\": \"sa@my-gcp-project.iam.gserviceaccount.com\"}}"
}
diff --git a/providers/common/ai/provider.yaml b/providers/common/ai/provider.yaml
index 75b5f133e03..5dfd9867c37 100644
--- a/providers/common/ai/provider.yaml
+++ b/providers/common/ai/provider.yaml
@@ -345,13 +345,13 @@ connection-types:
- password
relabeling: {}
placeholders:
- extra: '{"model": "google-cloud:gemini-2.0-flash", "project": "my-project", "location":
+ extra: '{"model": "google-cloud:gemini-2.5-flash", "project": "my-project", "location":
"us-central1"} — add service_account_info (object) for SA auth; omit both to use Application
Default Credentials'
conn-fields:
model:
label: Model
- description: "Google model identifier (e.g. google-cloud:gemini-2.0-flash)"
+ description: "Google model identifier (e.g. google-cloud:gemini-2.5-flash)"
schema:
type:
- string
diff --git a/providers/common/ai/src/airflow/providers/common/ai/get_provider_info.py b/providers/common/ai/src/airflow/providers/common/ai/get_provider_info.py
index 658f1f10e77..316b43f107f 100644
--- a/providers/common/ai/src/airflow/providers/common/ai/get_provider_info.py
+++ b/providers/common/ai/src/airflow/providers/common/ai/get_provider_info.py
@@ -273,13 +273,13 @@ def get_provider_info():
"hidden-fields": ["schema", "port", "login", "host", "password"],
"relabeling": {},
"placeholders": {
- "extra": '{"model": "google-cloud:gemini-2.0-flash", "project": "my-project", "location": "us-central1"} — add service_account_info (object) for SA auth; omit both to use Application Default Credentials'
+ "extra": '{"model": "google-cloud:gemini-2.5-flash", "project": "my-project", "location": "us-central1"} — add service_account_info (object) for SA auth; omit both to use Application Default Credentials'
},
},
"conn-fields": {
"model": {
"label": "Model",
- "description": "Google model identifier (e.g. google-cloud:gemini-2.0-flash)",
+ "description": "Google model identifier (e.g. google-cloud:gemini-2.5-flash)",
"schema": {"type": ["string", "null"]},
},
"fallback_conn_ids": {
diff --git a/providers/common/ai/src/airflow/providers/common/ai/hooks/pydantic_ai.py b/providers/common/ai/src/airflow/providers/common/ai/hooks/pydantic_ai.py
index 9d9e15d0c16..f4167487d25 100644
--- a/providers/common/ai/src/airflow/providers/common/ai/hooks/pydantic_ai.py
+++ b/providers/common/ai/src/airflow/providers/common/ai/hooks/pydantic_ai.py
@@ -795,7 +795,7 @@ class PydanticAIVertexHook(PydanticAIHook):
- **extra** JSON::
{
- "model": "google-cloud:gemini-2.0-flash",
+ "model": "google-cloud:gemini-2.5-flash",
"project": "my-gcp-project",
"location": "us-central1",
"service_account_info": {...},
@@ -820,8 +820,8 @@ class PydanticAIVertexHook(PydanticAIHook):
works today.
:param llm_conn_id: Airflow connection ID.
- :param model_id: Model identifier, e.g. ``"google-cloud:gemini-2.0-flash"``. A
- bare name (e.g. ``"gemini-2.0-flash"``) defaults to Vertex AI; prefix with
+ :param model_id: Model identifier, e.g. ``"google-cloud:gemini-2.5-flash"``. A
+ bare name (e.g. ``"gemini-2.5-flash"``) defaults to Vertex AI; prefix with
``google:`` for the Generative Language API.
"""
@@ -838,7 +838,7 @@ class PydanticAIVertexHook(PydanticAIHook):
"relabeling": {},
"placeholders": {
"extra": (
- '{"model": "google-cloud:gemini-2.0-flash", '
+ '{"model": "google-cloud:gemini-2.5-flash", '
'"project": "my-project", "location": "us-central1"}'
" — add service_account_info (object) for SA auth;"
" omit both to use Application Default Credentials"
diff --git a/providers/common/ai/tests/unit/common/ai/hooks/test_pydantic_ai.py b/providers/common/ai/tests/unit/common/ai/hooks/test_pydantic_ai.py
index 9db95fce059..da1670f3dc8 100644
--- a/providers/common/ai/tests/unit/common/ai/hooks/test_pydantic_ai.py
+++ b/providers/common/ai/tests/unit/common/ai/hooks/test_pydantic_ai.py
@@ -46,7 +46,7 @@ from airflow.providers.common.ai.hooks.pydantic_ai import (
from airflow.providers.common.compat.sdk import AirflowNotFoundException
# Matches the `google...` provider key pydantic-ai expects before the `:model-name`
-# separator, e.g. "google-cloud" out of "google-cloud:gemini-2.0-flash".
+# separator, e.g. "google-cloud" out of "google-cloud:gemini-2.5-flash".
_GOOGLE_MODEL_PREFIX_RE = re.compile(r"google[\w-]*(?=:)")
@@ -84,6 +84,33 @@ def _extract_google_cloud_prefix(text: str) -> str:
return match.group()
+_KNOWN_SERVABLE_VERTEX_GEMINI_MODELS = frozenset({"gemini-2.5-flash"})
+
+_GOOGLE_CLOUD_MODEL_NAME_RE = re.compile(r"google-cloud:([\w.-]+)")
+
+
+def _assert_model_name_is_known_servable(text: str) -> None:
+ """
+ Extract the model name following a ``google-cloud:`` prefix in ``text`` and
+ assert it is in ``_KNOWN_SERVABLE_VERTEX_GEMINI_MODELS``.
+
+ The prefix-only checks above (``_assert_prefix_is_known_provider``) only
+ confirm pydantic-ai recognizes ``google-cloud`` as a provider; they never
+ check whether the specific model advertised after the colon is actually
+ servable, which is how a retired model name went unnoticed in the docs and
+ connection form.
+ """
+ match = _GOOGLE_CLOUD_MODEL_NAME_RE.search(text)
+ assert match, f"no google-cloud:<model> found in: {text!r}"
+ model_name = match.group(1)
+ assert model_name in _KNOWN_SERVABLE_VERTEX_GEMINI_MODELS, (
+ f"{model_name!r} is not in the maintained allowlist of known-servable Vertex "
+ f"Gemini models ({sorted(_KNOWN_SERVABLE_VERTEX_GEMINI_MODELS)}). If it has been "
+ "confirmed retired, replace it with a current model everywhere it's documented; "
+ "if it's a new, confirmed-servable model, add it to the allowlist."
+ )
+
+
class TestPydanticAIHookInit:
def test_default_conn_id(self):
hook = PydanticAIHook()
@@ -416,11 +443,11 @@ class TestPydanticAIHookModelProviderResolution:
"primary",
conn_type="pydanticai_vertex",
hook_class=PydanticAIVertexHook,
- extra={"model": "gemini-2.0-flash", "api_key": "some-key"},
+ extra={"model": "gemini-2.5-flash", "api_key": "some-key"},
)
hook = PydanticAIVertexHook(llm_conn_id="primary")
- assert hook.get_conn() is infer_model_stub.models["google-cloud:gemini-2.0-flash"]
+ assert hook.get_conn() is infer_model_stub.models["google-cloud:gemini-2.5-flash"]
def test_bedrock_bare_model_id_with_embedded_colon_gets_platform_prefix(self, registry, infer_model_stub):
"""A ``:`` alone doesn't pin a platform -- Bedrock's own ids contain one.
@@ -534,14 +561,14 @@ class TestPydanticAIHookModelProviderResolution:
"primary",
conn_type="pydanticai_vertex",
hook_class=PydanticAIVertexHook,
- extra={"model": "google-vertex:gemini-2.0-flash", "api_key": "some-key"},
+ extra={"model": "google-vertex:gemini-2.5-flash", "api_key": "some-key"},
)
hook = PydanticAIVertexHook(llm_conn_id="primary")
with caplog.at_level(logging.WARNING):
model = hook.get_conn()
- assert model is infer_model_stub.models["google-cloud:google-vertex:gemini-2.0-flash"]
+ assert model is infer_model_stub.models["google-cloud:google-vertex:gemini-2.5-flash"]
assert any("google-vertex" in r.message and "typo" in r.message for r in caplog.records)
def test_bedrock_native_id_does_not_warn(self, registry, infer_model_stub, caplog):
@@ -1689,7 +1716,7 @@ class TestPydanticAIVertexHook:
None,
None,
{
- "model": "google-cloud:gemini-2.0-flash",
+ "model": "google-cloud:gemini-2.5-flash",
"project": "my-project",
"location": "us-central1",
},
@@ -1706,7 +1733,7 @@ class TestPydanticAIVertexHook:
result = hook._get_provider_kwargs(
None,
None,
- {"model": "google:gemini-2.0-flash", "api_key": "gla-key"},
+ {"model": "google:gemini-2.5-flash", "api_key": "gla-key"},
)
assert result["api_key"] == "gla-key"
@@ -1725,7 +1752,7 @@ class TestPydanticAIVertexHook:
None,
None,
{
- "model": "google-cloud:gemini-2.0-flash",
+ "model": "google-cloud:gemini-2.5-flash",
"project": "my-project",
"location": "us-central1",
"vertexai": vertexai_value,
@@ -1759,7 +1786,7 @@ class TestPydanticAIVertexHook:
None,
None,
{
- "model": "google-cloud:gemini-2.0-flash",
+ "model": "google-cloud:gemini-2.5-flash",
"service_account_info": sa_info_dict,
},
)
@@ -1774,7 +1801,7 @@ class TestPydanticAIVertexHook:
def test_get_provider_kwargs_returns_empty_for_adc(self):
"""When no keys are in extra, return {} so ADC path is taken."""
hook = PydanticAIVertexHook.__new__(PydanticAIVertexHook)
- result = hook._get_provider_kwargs(None, None, {"model": "google-cloud:gemini-2.0-flash"})
+ result = hook._get_provider_kwargs(None, None, {"model": "google-cloud:gemini-2.5-flash"})
assert result == {}
@patch("airflow.providers.common.ai.hooks.pydantic_ai.infer_model", autospec=True)
@@ -1784,12 +1811,12 @@ class TestPydanticAIVertexHook:
conn = Connection(
conn_id="vertex_test",
conn_type="pydanticai_vertex",
- extra=json.dumps({"model": "google-cloud:gemini-2.0-flash"}),
+ extra=json.dumps({"model": "google-cloud:gemini-2.5-flash"}),
)
with patch.object(hook, "get_connection", return_value=conn):
hook.get_conn()
- mock_infer_model.assert_called_once_with("google-cloud:gemini-2.0-flash")
+ mock_infer_model.assert_called_once_with("google-cloud:gemini-2.5-flash")
@patch("airflow.providers.common.ai.hooks.pydantic_ai.infer_model", autospec=True)
@patch("airflow.providers.common.ai.hooks.pydantic_ai.infer_provider_class", autospec=True)
@@ -1804,7 +1831,7 @@ class TestPydanticAIVertexHook:
conn_type="pydanticai_vertex",
extra=json.dumps(
{
- "model": "google-cloud:gemini-2.0-flash",
+ "model": "google-cloud:gemini-2.5-flash",
"project": "my-project",
"location": "europe-west4",
}
@@ -1862,7 +1889,7 @@ class TestPydanticAIVertexHook:
conn_type="pydanticai_vertex",
extra=json.dumps(
{
- "model": "google-cloud:gemini-2.0-flash",
+ "model": "google-cloud:gemini-2.5-flash",
"project": "my-project",
"location": "us-central1",
"vertexai": True,
@@ -1937,6 +1964,26 @@ class TestPydanticAIVertexHook:
prefix = _extract_google_cloud_prefix(placeholder)
_assert_prefix_is_known_provider(prefix)
+ def test_conn_fields_model_description_names_a_servable_model(self):
+ connection_types = get_provider_info()["connection-types"]
+ vertex_conn_fields = next(
+ c["conn-fields"] for c in connection_types if c["connection-type"] == "pydanticai_vertex"
+ )
+ description = vertex_conn_fields["model"]["description"]
+ _assert_model_name_is_known_servable(description)
+
+ def test_conn_types_ui_field_behaviour_placeholder_names_a_servable_model(self):
+ connection_types = get_provider_info()["connection-types"]
+ vertex_connection_type = next(
+ c for c in connection_types if c["connection-type"] == "pydanticai_vertex"
+ )
+ placeholder = vertex_connection_type["ui-field-behaviour"]["placeholders"]["extra"]
+ _assert_model_name_is_known_servable(placeholder)
+
+ def test_ui_field_behaviour_placeholder_names_a_servable_model(self):
+ placeholder = PydanticAIVertexHook.get_ui_field_behaviour()["placeholders"]["extra"]
+ _assert_model_name_is_known_servable(placeholder)
+
ALL_HOOKS = [PydanticAIHook, PydanticAIAzureHook, PydanticAIBedrockHook, PydanticAIVertexHook]
DECLARED_CONNECTION_TYPES = [c["connection-type"] for c in get_provider_info()["connection-types"]]