From b9200b49c08bddb1c7a269823ff93843abcd8591 Mon Sep 17 00:00:00 2001 From: giulio-leone Date: Wed, 4 Mar 2026 05:29:42 +0100 Subject: [PATCH 1/5] Python: fix(google-ai): skip api_key check when use_vertexai is True --- .../ai/google/google_ai/services/google_ai_chat_completion.py | 2 +- .../ai/google/google_ai/services/google_ai_text_completion.py | 2 +- .../ai/google/google_ai/services/google_ai_text_embedding.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/python/semantic_kernel/connectors/ai/google/google_ai/services/google_ai_chat_completion.py b/python/semantic_kernel/connectors/ai/google/google_ai/services/google_ai_chat_completion.py index 50690e3b1679..7d6efa02eef7 100644 --- a/python/semantic_kernel/connectors/ai/google/google_ai/services/google_ai_chat_completion.py +++ b/python/semantic_kernel/connectors/ai/google/google_ai/services/google_ai_chat_completion.py @@ -119,7 +119,7 @@ def __init__( if not client: if google_ai_settings.use_vertexai and not google_ai_settings.cloud_project_id: raise ServiceInitializationError("Project ID must be provided when use_vertexai is True.") - if not google_ai_settings.api_key: + if not google_ai_settings.use_vertexai and not google_ai_settings.api_key: raise ServiceInitializationError("The API key is required when use_vertexai is False.") super().__init__( diff --git a/python/semantic_kernel/connectors/ai/google/google_ai/services/google_ai_text_completion.py b/python/semantic_kernel/connectors/ai/google/google_ai/services/google_ai_text_completion.py index ed1858825a95..2fe7f5070846 100644 --- a/python/semantic_kernel/connectors/ai/google/google_ai/services/google_ai_text_completion.py +++ b/python/semantic_kernel/connectors/ai/google/google_ai/services/google_ai_text_completion.py @@ -90,7 +90,7 @@ def __init__( if not client: if google_ai_settings.use_vertexai and not google_ai_settings.cloud_project_id: raise ServiceInitializationError("Project ID must be provided when use_vertexai is True.") - if not google_ai_settings.api_key: + if not google_ai_settings.use_vertexai and not google_ai_settings.api_key: raise ServiceInitializationError("The API key is required when use_vertexai is False.") super().__init__( diff --git a/python/semantic_kernel/connectors/ai/google/google_ai/services/google_ai_text_embedding.py b/python/semantic_kernel/connectors/ai/google/google_ai/services/google_ai_text_embedding.py index 12fc227ebd07..185187fa1585 100644 --- a/python/semantic_kernel/connectors/ai/google/google_ai/services/google_ai_text_embedding.py +++ b/python/semantic_kernel/connectors/ai/google/google_ai/services/google_ai_text_embedding.py @@ -81,7 +81,7 @@ def __init__( if not client: if google_ai_settings.use_vertexai and not google_ai_settings.cloud_project_id: raise ServiceInitializationError("Project ID must be provided when use_vertexai is True.") - if not google_ai_settings.api_key: + if not google_ai_settings.use_vertexai and not google_ai_settings.api_key: raise ServiceInitializationError("The API key is required when use_vertexai is False.") super().__init__( From 4f0b06ee593e61187881280cf95ce0590182f2f0 Mon Sep 17 00:00:00 2001 From: giulio-leone <6887247+giulio-leone@users.noreply.github.com> Date: Fri, 6 Mar 2026 03:51:27 +0100 Subject: [PATCH 2/5] fix: add vertexai parameter validation and tests --- .../services/google_ai_chat_completion.py | 2 ++ .../services/google_ai_text_completion.py | 2 ++ .../services/google_ai_text_embedding.py | 2 ++ .../services/test_google_ai_chat_completion.py | 14 ++++++++++++++ .../services/test_google_ai_text_completion.py | 14 ++++++++++++++ .../services/test_google_ai_text_embedding.py | 16 +++++++++++++++- 6 files changed, 49 insertions(+), 1 deletion(-) diff --git a/python/semantic_kernel/connectors/ai/google/google_ai/services/google_ai_chat_completion.py b/python/semantic_kernel/connectors/ai/google/google_ai/services/google_ai_chat_completion.py index 7d6efa02eef7..22422c331d2b 100644 --- a/python/semantic_kernel/connectors/ai/google/google_ai/services/google_ai_chat_completion.py +++ b/python/semantic_kernel/connectors/ai/google/google_ai/services/google_ai_chat_completion.py @@ -119,6 +119,8 @@ def __init__( if not client: if google_ai_settings.use_vertexai and not google_ai_settings.cloud_project_id: raise ServiceInitializationError("Project ID must be provided when use_vertexai is True.") + if google_ai_settings.use_vertexai and not google_ai_settings.cloud_region: + raise ServiceInitializationError("Region must be provided when use_vertexai is True.") if not google_ai_settings.use_vertexai and not google_ai_settings.api_key: raise ServiceInitializationError("The API key is required when use_vertexai is False.") diff --git a/python/semantic_kernel/connectors/ai/google/google_ai/services/google_ai_text_completion.py b/python/semantic_kernel/connectors/ai/google/google_ai/services/google_ai_text_completion.py index 2fe7f5070846..3a00faf2e20c 100644 --- a/python/semantic_kernel/connectors/ai/google/google_ai/services/google_ai_text_completion.py +++ b/python/semantic_kernel/connectors/ai/google/google_ai/services/google_ai_text_completion.py @@ -90,6 +90,8 @@ def __init__( if not client: if google_ai_settings.use_vertexai and not google_ai_settings.cloud_project_id: raise ServiceInitializationError("Project ID must be provided when use_vertexai is True.") + if google_ai_settings.use_vertexai and not google_ai_settings.cloud_region: + raise ServiceInitializationError("Region must be provided when use_vertexai is True.") if not google_ai_settings.use_vertexai and not google_ai_settings.api_key: raise ServiceInitializationError("The API key is required when use_vertexai is False.") diff --git a/python/semantic_kernel/connectors/ai/google/google_ai/services/google_ai_text_embedding.py b/python/semantic_kernel/connectors/ai/google/google_ai/services/google_ai_text_embedding.py index 185187fa1585..61cc04309590 100644 --- a/python/semantic_kernel/connectors/ai/google/google_ai/services/google_ai_text_embedding.py +++ b/python/semantic_kernel/connectors/ai/google/google_ai/services/google_ai_text_embedding.py @@ -81,6 +81,8 @@ def __init__( if not client: if google_ai_settings.use_vertexai and not google_ai_settings.cloud_project_id: raise ServiceInitializationError("Project ID must be provided when use_vertexai is True.") + if google_ai_settings.use_vertexai and not google_ai_settings.cloud_region: + raise ServiceInitializationError("Region must be provided when use_vertexai is True.") if not google_ai_settings.use_vertexai and not google_ai_settings.api_key: raise ServiceInitializationError("The API key is required when use_vertexai is False.") diff --git a/python/tests/unit/connectors/ai/google/google_ai/services/test_google_ai_chat_completion.py b/python/tests/unit/connectors/ai/google/google_ai/services/test_google_ai_chat_completion.py index e2004e641d07..a0dc2e786195 100644 --- a/python/tests/unit/connectors/ai/google/google_ai/services/test_google_ai_chat_completion.py +++ b/python/tests/unit/connectors/ai/google/google_ai/services/test_google_ai_chat_completion.py @@ -75,6 +75,20 @@ def test_google_ai_chat_completion_init_with_use_vertexai_missing_project_id(goo GoogleAIChatCompletion(use_vertexai=True, env_file_path="fake_env_file_path.env") +@pytest.mark.parametrize("exclude_list", [["GOOGLE_AI_CLOUD_REGION"]], indirect=True) +def test_google_ai_chat_completion_init_with_use_vertexai_missing_region(google_ai_unit_test_env) -> None: + """Test initialization of GoogleAIChatCompletion with use_vertexai true but missing region""" + with pytest.raises(ServiceInitializationError, match="Region must be provided when use_vertexai is True."): + GoogleAIChatCompletion(use_vertexai=True, env_file_path="fake_env_file_path.env") + + +@pytest.mark.parametrize("exclude_list", [["GOOGLE_AI_API_KEY"]], indirect=True) +def test_google_ai_chat_completion_init_with_use_vertexai_no_api_key(google_ai_unit_test_env) -> None: + """Test initialization of GoogleAIChatCompletion succeeds with use_vertexai=True and no api_key""" + chat_completion = GoogleAIChatCompletion(use_vertexai=True) + assert chat_completion.service_settings.use_vertexai is True + + def test_prompt_execution_settings_class(google_ai_unit_test_env) -> None: google_ai_chat_completion = GoogleAIChatCompletion() assert google_ai_chat_completion.get_prompt_execution_settings_class() == GoogleAIChatPromptExecutionSettings diff --git a/python/tests/unit/connectors/ai/google/google_ai/services/test_google_ai_text_completion.py b/python/tests/unit/connectors/ai/google/google_ai/services/test_google_ai_text_completion.py index 00209613bec7..3186b8634ad2 100644 --- a/python/tests/unit/connectors/ai/google/google_ai/services/test_google_ai_text_completion.py +++ b/python/tests/unit/connectors/ai/google/google_ai/services/test_google_ai_text_completion.py @@ -67,6 +67,20 @@ def test_google_ai_text_completion_init_with_use_vertexai_missing_project_id(goo GoogleAITextCompletion(use_vertexai=True, env_file_path="fake_env_file_path.env") +@pytest.mark.parametrize("exclude_list", [["GOOGLE_AI_CLOUD_REGION"]], indirect=True) +def test_google_ai_text_completion_init_with_use_vertexai_missing_region(google_ai_unit_test_env) -> None: + """Test initialization of GoogleAITextCompletion with use_vertexai true but missing region""" + with pytest.raises(ServiceInitializationError, match="Region must be provided when use_vertexai is True."): + GoogleAITextCompletion(use_vertexai=True, env_file_path="fake_env_file_path.env") + + +@pytest.mark.parametrize("exclude_list", [["GOOGLE_AI_API_KEY"]], indirect=True) +def test_google_ai_text_completion_init_with_use_vertexai_no_api_key(google_ai_unit_test_env) -> None: + """Test initialization of GoogleAITextCompletion succeeds with use_vertexai=True and no api_key""" + text_completion = GoogleAITextCompletion(use_vertexai=True) + assert text_completion.service_settings.use_vertexai is True + + def test_prompt_execution_settings_class(google_ai_unit_test_env) -> None: google_ai_text_completion = GoogleAITextCompletion() assert google_ai_text_completion.get_prompt_execution_settings_class() == GoogleAITextPromptExecutionSettings diff --git a/python/tests/unit/connectors/ai/google/google_ai/services/test_google_ai_text_embedding.py b/python/tests/unit/connectors/ai/google/google_ai/services/test_google_ai_text_embedding.py index 485b2f884c57..9b734d145f4a 100644 --- a/python/tests/unit/connectors/ai/google/google_ai/services/test_google_ai_text_embedding.py +++ b/python/tests/unit/connectors/ai/google/google_ai/services/test_google_ai_text_embedding.py @@ -57,7 +57,14 @@ def test_google_ai_text_embedding_init_with_empty_model_id(google_ai_unit_test_e def test_google_ai_text_embedding_init_with_empty_api_key(google_ai_unit_test_env) -> None: """Test initialization of GoogleAITextEmbedding with an empty api_key""" with pytest.raises(ServiceInitializationError, match="The API key is required when use_vertexai is False."): - GoogleAITextEmbedding(use_vertexai=True, env_file_path="fake_env_file_path.env") + GoogleAITextEmbedding(env_file_path="fake_env_file_path.env") + + +@pytest.mark.parametrize("exclude_list", [["GOOGLE_AI_API_KEY"]], indirect=True) +def test_google_ai_text_embedding_init_with_use_vertexai_no_api_key(google_ai_unit_test_env) -> None: + """Test initialization of GoogleAITextEmbedding succeeds with use_vertexai=True and no api_key""" + embedding = GoogleAITextEmbedding(use_vertexai=True) + assert embedding.service_settings.use_vertexai is True @pytest.mark.parametrize("exclude_list", [["GOOGLE_AI_CLOUD_PROJECT_ID"]], indirect=True) @@ -67,6 +74,13 @@ def test_google_ai_text_embedding_init_with_use_vertexai_missing_project_id(goog GoogleAITextEmbedding(use_vertexai=True, env_file_path="fake_env_file_path.env") +@pytest.mark.parametrize("exclude_list", [["GOOGLE_AI_CLOUD_REGION"]], indirect=True) +def test_google_ai_text_embedding_init_with_use_vertexai_missing_region(google_ai_unit_test_env) -> None: + """Test initialization of GoogleAITextEmbedding with use_vertexai true but missing region""" + with pytest.raises(ServiceInitializationError, match="Region must be provided when use_vertexai is True."): + GoogleAITextEmbedding(use_vertexai=True, env_file_path="fake_env_file_path.env") + + def test_prompt_execution_settings_class(google_ai_unit_test_env) -> None: google_ai_text_embedding = GoogleAITextEmbedding() assert google_ai_text_embedding.get_prompt_execution_settings_class() == GoogleAIEmbeddingPromptExecutionSettings From 59a0bea3737ebfe4f1cc34fa49cca41bef63ec26 Mon Sep 17 00:00:00 2001 From: giulio-leone Date: Mon, 23 Mar 2026 02:08:16 +0100 Subject: [PATCH 3/5] test: require region for vertex ai integration setup Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../integration/completions/chat_completion_test_base.py | 4 +++- python/tests/integration/completions/test_text_completion.py | 4 +++- .../integration/embeddings/test_embedding_service_base.py | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/python/tests/integration/completions/chat_completion_test_base.py b/python/tests/integration/completions/chat_completion_test_base.py index c266860ad85b..f1cc6a4c5833 100644 --- a/python/tests/integration/completions/chat_completion_test_base.py +++ b/python/tests/integration/completions/chat_completion_test_base.py @@ -61,7 +61,9 @@ ollama_image_setup: bool = is_service_setup_for_testing(["OLLAMA_CHAT_MODEL_ID_IMAGE"]) ollama_tool_call_setup: bool = is_service_setup_for_testing(["OLLAMA_CHAT_MODEL_ID_TOOL_CALL"]) google_ai_setup: bool = is_service_setup_for_testing(["GOOGLE_AI_API_KEY", "GOOGLE_AI_GEMINI_MODEL_ID"]) -vertex_ai_setup: bool = is_service_setup_for_testing(["GOOGLE_AI_CLOUD_PROJECT_ID", "GOOGLE_AI_GEMINI_MODEL_ID"]) +vertex_ai_setup: bool = is_service_setup_for_testing( + ["GOOGLE_AI_CLOUD_PROJECT_ID", "GOOGLE_AI_GEMINI_MODEL_ID", "GOOGLE_AI_CLOUD_REGION"] +) onnx_setup: bool = is_service_setup_for_testing( ["ONNX_GEN_AI_CHAT_MODEL_FOLDER"], raise_if_not_set=False ) # Tests are optional for ONNX diff --git a/python/tests/integration/completions/test_text_completion.py b/python/tests/integration/completions/test_text_completion.py index 03eda3038ddd..bee7b37aaadc 100644 --- a/python/tests/integration/completions/test_text_completion.py +++ b/python/tests/integration/completions/test_text_completion.py @@ -32,7 +32,9 @@ "Linux" ]) google_ai_setup: bool = is_service_setup_for_testing(["GOOGLE_AI_API_KEY", "GOOGLE_AI_GEMINI_MODEL_ID"]) -vertex_ai_setup: bool = is_service_setup_for_testing(["GOOGLE_AI_CLOUD_PROJECT_ID", "GOOGLE_AI_GEMINI_MODEL_ID"]) +vertex_ai_setup: bool = is_service_setup_for_testing( + ["GOOGLE_AI_CLOUD_PROJECT_ID", "GOOGLE_AI_GEMINI_MODEL_ID", "GOOGLE_AI_CLOUD_REGION"] +) onnx_setup: bool = is_service_setup_for_testing( ["ONNX_GEN_AI_TEXT_MODEL_FOLDER"], raise_if_not_set=False ) # Tests are optional for ONNX diff --git a/python/tests/integration/embeddings/test_embedding_service_base.py b/python/tests/integration/embeddings/test_embedding_service_base.py index 6178754fc415..0c0f6c4b8a45 100644 --- a/python/tests/integration/embeddings/test_embedding_service_base.py +++ b/python/tests/integration/embeddings/test_embedding_service_base.py @@ -43,7 +43,9 @@ ["MISTRALAI_API_KEY", "MISTRALAI_EMBEDDING_MODEL_ID"], raise_if_not_set=False ) # We don't have a MistralAI deployment google_ai_setup: bool = is_service_setup_for_testing(["GOOGLE_AI_API_KEY", "GOOGLE_AI_EMBEDDING_MODEL_ID"]) -vertex_ai_setup: bool = is_service_setup_for_testing(["GOOGLE_AI_CLOUD_PROJECT_ID", "GOOGLE_AI_EMBEDDING_MODEL_ID"]) +vertex_ai_setup: bool = is_service_setup_for_testing( + ["GOOGLE_AI_CLOUD_PROJECT_ID", "GOOGLE_AI_EMBEDDING_MODEL_ID", "GOOGLE_AI_CLOUD_REGION"] +) ollama_setup: bool = is_service_setup_for_testing(["OLLAMA_EMBEDDING_MODEL_ID"]) # When testing Bedrock, after logging into AWS CLI this has been set, so we can use it to check if the service is setup bedrock_setup: bool = is_service_setup_for_testing(["AWS_DEFAULT_REGION"], raise_if_not_set=False) From ead9d42240c175bb4b310ea6cc1ea5824a39b9dc Mon Sep 17 00:00:00 2001 From: giulio-leone Date: Mon, 23 Mar 2026 05:11:13 +0100 Subject: [PATCH 4/5] test: normalize Vertex AI integration selector formatting Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../integration/completions/chat_completion_test_base.py | 8 +++++--- .../tests/integration/completions/test_text_completion.py | 8 +++++--- .../integration/embeddings/test_embedding_service_base.py | 8 +++++--- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/python/tests/integration/completions/chat_completion_test_base.py b/python/tests/integration/completions/chat_completion_test_base.py index f1cc6a4c5833..762773929636 100644 --- a/python/tests/integration/completions/chat_completion_test_base.py +++ b/python/tests/integration/completions/chat_completion_test_base.py @@ -61,9 +61,11 @@ ollama_image_setup: bool = is_service_setup_for_testing(["OLLAMA_CHAT_MODEL_ID_IMAGE"]) ollama_tool_call_setup: bool = is_service_setup_for_testing(["OLLAMA_CHAT_MODEL_ID_TOOL_CALL"]) google_ai_setup: bool = is_service_setup_for_testing(["GOOGLE_AI_API_KEY", "GOOGLE_AI_GEMINI_MODEL_ID"]) -vertex_ai_setup: bool = is_service_setup_for_testing( - ["GOOGLE_AI_CLOUD_PROJECT_ID", "GOOGLE_AI_GEMINI_MODEL_ID", "GOOGLE_AI_CLOUD_REGION"] -) +vertex_ai_setup: bool = is_service_setup_for_testing([ + "GOOGLE_AI_CLOUD_PROJECT_ID", + "GOOGLE_AI_GEMINI_MODEL_ID", + "GOOGLE_AI_CLOUD_REGION", +]) onnx_setup: bool = is_service_setup_for_testing( ["ONNX_GEN_AI_CHAT_MODEL_FOLDER"], raise_if_not_set=False ) # Tests are optional for ONNX diff --git a/python/tests/integration/completions/test_text_completion.py b/python/tests/integration/completions/test_text_completion.py index bee7b37aaadc..65802a505eaa 100644 --- a/python/tests/integration/completions/test_text_completion.py +++ b/python/tests/integration/completions/test_text_completion.py @@ -32,9 +32,11 @@ "Linux" ]) google_ai_setup: bool = is_service_setup_for_testing(["GOOGLE_AI_API_KEY", "GOOGLE_AI_GEMINI_MODEL_ID"]) -vertex_ai_setup: bool = is_service_setup_for_testing( - ["GOOGLE_AI_CLOUD_PROJECT_ID", "GOOGLE_AI_GEMINI_MODEL_ID", "GOOGLE_AI_CLOUD_REGION"] -) +vertex_ai_setup: bool = is_service_setup_for_testing([ + "GOOGLE_AI_CLOUD_PROJECT_ID", + "GOOGLE_AI_GEMINI_MODEL_ID", + "GOOGLE_AI_CLOUD_REGION", +]) onnx_setup: bool = is_service_setup_for_testing( ["ONNX_GEN_AI_TEXT_MODEL_FOLDER"], raise_if_not_set=False ) # Tests are optional for ONNX diff --git a/python/tests/integration/embeddings/test_embedding_service_base.py b/python/tests/integration/embeddings/test_embedding_service_base.py index 0c0f6c4b8a45..f582ab785bce 100644 --- a/python/tests/integration/embeddings/test_embedding_service_base.py +++ b/python/tests/integration/embeddings/test_embedding_service_base.py @@ -43,9 +43,11 @@ ["MISTRALAI_API_KEY", "MISTRALAI_EMBEDDING_MODEL_ID"], raise_if_not_set=False ) # We don't have a MistralAI deployment google_ai_setup: bool = is_service_setup_for_testing(["GOOGLE_AI_API_KEY", "GOOGLE_AI_EMBEDDING_MODEL_ID"]) -vertex_ai_setup: bool = is_service_setup_for_testing( - ["GOOGLE_AI_CLOUD_PROJECT_ID", "GOOGLE_AI_EMBEDDING_MODEL_ID", "GOOGLE_AI_CLOUD_REGION"] -) +vertex_ai_setup: bool = is_service_setup_for_testing([ + "GOOGLE_AI_CLOUD_PROJECT_ID", + "GOOGLE_AI_EMBEDDING_MODEL_ID", + "GOOGLE_AI_CLOUD_REGION", +]) ollama_setup: bool = is_service_setup_for_testing(["OLLAMA_EMBEDDING_MODEL_ID"]) # When testing Bedrock, after logging into AWS CLI this has been set, so we can use it to check if the service is setup bedrock_setup: bool = is_service_setup_for_testing(["AWS_DEFAULT_REGION"], raise_if_not_set=False) From d10de6037aeaecdd45db6f71c57e650eb3cdd338 Mon Sep 17 00:00:00 2001 From: giulio-leone Date: Tue, 24 Mar 2026 04:05:39 +0100 Subject: [PATCH 5/5] fix(ci): export google ai cloud region Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/python-integration-tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/python-integration-tests.yml b/.github/workflows/python-integration-tests.yml index 64550641de73..a97ff57c5d27 100644 --- a/.github/workflows/python-integration-tests.yml +++ b/.github/workflows/python-integration-tests.yml @@ -68,6 +68,7 @@ env: GOOGLE_AI_EMBEDDING_MODEL_ID: ${{ vars.GOOGLE_AI_EMBEDDING_MODEL_ID }} GOOGLE_AI_API_KEY: ${{ secrets.GOOGLE_AI_API_KEY }} GOOGLE_AI_CLOUD_PROJECT_ID: ${{ vars.GOOGLE_AI_CLOUD_PROJECT_ID }} + GOOGLE_AI_CLOUD_REGION: ${{ vars.GOOGLE_AI_CLOUD_REGION }} VERTEX_AI_PROJECT_ID: ${{ vars.VERTEX_AI_PROJECT_ID }} VERTEX_AI_GEMINI_MODEL_ID: ${{ vars.VERTEX_AI_GEMINI_MODEL_ID }} VERTEX_AI_EMBEDDING_MODEL_ID: ${{ vars.VERTEX_AI_EMBEDDING_MODEL_ID }}