Skip to content

Commit fa4a3b2

Browse files
vertex-sdk-botcopybara-github
authored andcommitted
feat: Add the identity type option for the agent engine and add effective identity to the resource
PiperOrigin-RevId: 819733517
1 parent 1513d8f commit fa4a3b2

File tree

4 files changed

+99
-4
lines changed

4 files changed

+99
-4
lines changed

tests/unit/vertexai/genai/test_agent_engines.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,9 @@ def register_operations(self) -> Dict[str, List[str]]:
533533
}
534534
_TEST_AGENT_ENGINE_CONTAINER_CONCURRENCY = 4
535535
_TEST_AGENT_ENGINE_CUSTOM_SERVICE_ACCOUNT = "test-custom-service-account"
536+
_TEST_AGENT_ENGINE_IDENTITY_TYPE_SERVICE_ACCOUNT = (
537+
_genai_types.IdentityType.SERVICE_ACCOUNT
538+
)
536539
_TEST_AGENT_ENGINE_ENCRYPTION_SPEC = {"kms_key_name": "test-kms-key"}
537540
_TEST_AGENT_ENGINE_SPEC = _genai_types.ReasoningEngineSpecDict(
538541
agent_framework=_TEST_AGENT_ENGINE_FRAMEWORK,
@@ -559,6 +562,7 @@ def register_operations(self) -> Dict[str, List[str]]:
559562
requirements_gcs_uri=_TEST_AGENT_ENGINE_REQUIREMENTS_GCS_URI,
560563
),
561564
service_account=_TEST_AGENT_ENGINE_CUSTOM_SERVICE_ACCOUNT,
565+
identity_type=_TEST_AGENT_ENGINE_IDENTITY_TYPE_SERVICE_ACCOUNT,
562566
)
563567
_TEST_AGENT_ENGINE_STREAM_QUERY_RESPONSE = [{"output": "hello"}, {"output": "world"}]
564568
_TEST_AGENT_ENGINE_OPERATION_SCHEMAS = []
@@ -908,6 +912,7 @@ def test_create_agent_engine_config_full(self, mock_prepare):
908912
extra_packages=[_TEST_AGENT_ENGINE_EXTRA_PACKAGE_PATH],
909913
env_vars=_TEST_AGENT_ENGINE_ENV_VARS_INPUT,
910914
service_account=_TEST_AGENT_ENGINE_CUSTOM_SERVICE_ACCOUNT,
915+
identity_type=_TEST_AGENT_ENGINE_IDENTITY_TYPE_SERVICE_ACCOUNT,
911916
psc_interface_config=_TEST_AGENT_ENGINE_PSC_INTERFACE_CONFIG,
912917
min_instances=_TEST_AGENT_ENGINE_MIN_INSTANCES,
913918
max_instances=_TEST_AGENT_ENGINE_MAX_INSTANCES,
@@ -950,6 +955,10 @@ def test_create_agent_engine_config_full(self, mock_prepare):
950955
config["spec"]["service_account"]
951956
== _TEST_AGENT_ENGINE_CUSTOM_SERVICE_ACCOUNT
952957
)
958+
assert (
959+
config["spec"]["identity_type"]
960+
== _TEST_AGENT_ENGINE_IDENTITY_TYPE_SERVICE_ACCOUNT
961+
)
953962

954963
@mock.patch.object(
955964
_agent_engines_utils,
@@ -977,6 +986,7 @@ def test_create_agent_engine_config_with_source_packages(
977986
requirements_file=requirements_file_path,
978987
class_methods=_TEST_AGENT_ENGINE_CLASS_METHODS,
979988
agent_framework=_TEST_AGENT_FRAMEWORK,
989+
identity_type=_TEST_AGENT_ENGINE_IDENTITY_TYPE_SERVICE_ACCOUNT,
980990
)
981991
assert config["display_name"] == _TEST_AGENT_ENGINE_DISPLAY_NAME
982992
assert config["description"] == _TEST_AGENT_ENGINE_DESCRIPTION
@@ -994,6 +1004,10 @@ def test_create_agent_engine_config_with_source_packages(
9941004
mock_create_base64_encoded_tarball.assert_called_once_with(
9951005
source_packages=[test_file_path]
9961006
)
1007+
assert (
1008+
config["spec"]["identity_type"]
1009+
== _TEST_AGENT_ENGINE_IDENTITY_TYPE_SERVICE_ACCOUNT
1010+
)
9971011

9981012
@mock.patch.object(_agent_engines_utils, "_prepare")
9991013
def test_update_agent_engine_config_full(self, mock_prepare):
@@ -1008,6 +1022,7 @@ def test_update_agent_engine_config_full(self, mock_prepare):
10081022
extra_packages=[_TEST_AGENT_ENGINE_EXTRA_PACKAGE_PATH],
10091023
env_vars=_TEST_AGENT_ENGINE_ENV_VARS_INPUT,
10101024
service_account=_TEST_AGENT_ENGINE_CUSTOM_SERVICE_ACCOUNT,
1025+
identity_type=_TEST_AGENT_ENGINE_IDENTITY_TYPE_SERVICE_ACCOUNT,
10111026
)
10121027
assert config["display_name"] == _TEST_AGENT_ENGINE_DISPLAY_NAME
10131028
assert config["description"] == _TEST_AGENT_ENGINE_DESCRIPTION
@@ -1038,6 +1053,10 @@ def test_update_agent_engine_config_full(self, mock_prepare):
10381053
config["spec"]["service_account"]
10391054
== _TEST_AGENT_ENGINE_CUSTOM_SERVICE_ACCOUNT
10401055
)
1056+
assert (
1057+
config["spec"]["identity_type"]
1058+
== _TEST_AGENT_ENGINE_IDENTITY_TYPE_SERVICE_ACCOUNT
1059+
)
10411060
assert config["update_mask"] == ",".join(
10421061
[
10431062
"display_name",
@@ -1048,8 +1067,28 @@ def test_update_agent_engine_config_full(self, mock_prepare):
10481067
"spec.class_methods",
10491068
"spec.deployment_spec.env",
10501069
"spec.deployment_spec.secret_env",
1051-
"spec.service_account",
10521070
"spec.agent_framework",
1071+
"spec.identity_type",
1072+
"spec.service_account",
1073+
]
1074+
)
1075+
1076+
@mock.patch.object(_agent_engines_utils, "_prepare")
1077+
def test_update_agent_engine_clear_service_account(self, mock_prepare):
1078+
config = self.client.agent_engines._create_config(
1079+
mode="update",
1080+
service_account="",
1081+
identity_type=_TEST_AGENT_ENGINE_IDENTITY_TYPE_SERVICE_ACCOUNT,
1082+
)
1083+
assert "service_account" not in config["spec"].keys()
1084+
assert (
1085+
config["spec"]["identity_type"]
1086+
== _TEST_AGENT_ENGINE_IDENTITY_TYPE_SERVICE_ACCOUNT
1087+
)
1088+
assert config["update_mask"] == ",".join(
1089+
[
1090+
"spec.identity_type",
1091+
"spec.service_account",
10531092
]
10541093
)
10551094

@@ -1488,6 +1527,7 @@ def test_create_agent_engine_with_env_vars_dict(
14881527
extra_packages=[_TEST_AGENT_ENGINE_EXTRA_PACKAGE_PATH],
14891528
env_vars=_TEST_AGENT_ENGINE_ENV_VARS_INPUT,
14901529
service_account=None,
1530+
identity_type=None,
14911531
context_spec=None,
14921532
psc_interface_config=None,
14931533
min_instances=None,
@@ -1543,6 +1583,7 @@ def test_create_agent_engine_with_custom_service_account(
15431583
},
15441584
"class_methods": [_TEST_AGENT_ENGINE_CLASS_METHOD_1],
15451585
"service_account": _TEST_AGENT_ENGINE_CUSTOM_SERVICE_ACCOUNT,
1586+
"identity_type": _TEST_AGENT_ENGINE_IDENTITY_TYPE_SERVICE_ACCOUNT,
15461587
"agent_framework": _TEST_AGENT_ENGINE_FRAMEWORK,
15471588
},
15481589
}
@@ -1564,6 +1605,7 @@ def test_create_agent_engine_with_custom_service_account(
15641605
extra_packages=[_TEST_AGENT_ENGINE_EXTRA_PACKAGE_PATH],
15651606
staging_bucket=_TEST_STAGING_BUCKET,
15661607
service_account=_TEST_AGENT_ENGINE_CUSTOM_SERVICE_ACCOUNT,
1608+
identity_type=_TEST_AGENT_ENGINE_IDENTITY_TYPE_SERVICE_ACCOUNT,
15671609
),
15681610
)
15691611
mock_create_config.assert_called_with(
@@ -1577,6 +1619,7 @@ def test_create_agent_engine_with_custom_service_account(
15771619
extra_packages=[_TEST_AGENT_ENGINE_EXTRA_PACKAGE_PATH],
15781620
env_vars=None,
15791621
service_account=_TEST_AGENT_ENGINE_CUSTOM_SERVICE_ACCOUNT,
1622+
identity_type=_TEST_AGENT_ENGINE_IDENTITY_TYPE_SERVICE_ACCOUNT,
15801623
context_spec=None,
15811624
psc_interface_config=None,
15821625
min_instances=None,
@@ -1608,6 +1651,7 @@ def test_create_agent_engine_with_custom_service_account(
16081651
"requirements_gcs_uri": _TEST_AGENT_ENGINE_REQUIREMENTS_GCS_URI,
16091652
},
16101653
"service_account": _TEST_AGENT_ENGINE_CUSTOM_SERVICE_ACCOUNT,
1654+
"identity_type": _TEST_AGENT_ENGINE_IDENTITY_TYPE_SERVICE_ACCOUNT,
16111655
},
16121656
},
16131657
None,
@@ -1666,6 +1710,7 @@ def test_create_agent_engine_with_experimental_mode(
16661710
extra_packages=[_TEST_AGENT_ENGINE_EXTRA_PACKAGE_PATH],
16671711
env_vars=None,
16681712
service_account=None,
1713+
identity_type=None,
16691714
context_spec=None,
16701715
psc_interface_config=None,
16711716
min_instances=None,
@@ -1819,6 +1864,7 @@ def test_create_agent_engine_with_class_methods(
18191864
extra_packages=[_TEST_AGENT_ENGINE_EXTRA_PACKAGE_PATH],
18201865
env_vars=None,
18211866
service_account=None,
1867+
identity_type=None,
18221868
context_spec=None,
18231869
psc_interface_config=None,
18241870
min_instances=None,
@@ -1919,6 +1965,7 @@ def test_create_agent_engine_with_agent_framework(
19191965
entrypoint_object=None,
19201966
requirements_file=None,
19211967
agent_framework=_TEST_AGENT_FRAMEWORK,
1968+
identity_type=None,
19221969
)
19231970
request_mock.assert_called_with(
19241971
"post",

vertexai/_genai/agent_engines.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,7 @@ def create(
907907
api_config = self._create_config(
908908
mode="create",
909909
agent=agent,
910+
identity_type=config.identity_type,
910911
staging_bucket=config.staging_bucket,
911912
requirements=config.requirements,
912913
display_name=config.display_name,
@@ -971,6 +972,7 @@ def _create_config(
971972
*,
972973
mode: str,
973974
agent: Any = None,
975+
identity_type: Optional[types.IdentityType] = None,
974976
staging_bucket: Optional[str] = None,
975977
requirements: Optional[Union[str, Sequence[str]]] = None,
976978
display_name: Optional[str] = None,
@@ -1189,9 +1191,6 @@ def _create_config(
11891191
)
11901192
update_masks.extend(deployment_update_masks)
11911193
agent_engine_spec["deployment_spec"] = deployment_spec
1192-
if service_account is not None:
1193-
agent_engine_spec["service_account"] = service_account
1194-
update_masks.append("spec.service_account")
11951194

11961195
if agent_server_mode:
11971196
if not agent_engine_spec.get("deployment_spec"):
@@ -1209,6 +1208,21 @@ def _create_config(
12091208
)
12101209
)
12111210
update_masks.append("spec.agent_framework")
1211+
1212+
if identity_type is not None or service_account is not None:
1213+
if agent_engine_spec is None:
1214+
agent_engine_spec = {}
1215+
1216+
if identity_type is not None:
1217+
agent_engine_spec["identity_type"] = identity_type
1218+
update_masks.append("spec.identity_type")
1219+
if service_account is not None:
1220+
# Clear the field in case of empty service_account.
1221+
if service_account:
1222+
agent_engine_spec["service_account"] = service_account
1223+
update_masks.append("spec.service_account")
1224+
1225+
if agent_engine_spec is not None:
12121226
config["spec"] = agent_engine_spec
12131227

12141228
if update_masks and mode == "update":
@@ -1414,6 +1428,7 @@ def update(
14141428
api_config = self._create_config(
14151429
mode="update",
14161430
agent=agent,
1431+
identity_type=config.identity_type,
14171432
staging_bucket=config.staging_bucket,
14181433
requirements=config.requirements,
14191434
display_name=config.display_name,

vertexai/_genai/types/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@
430430
from .common import GetPromptConfig
431431
from .common import GetPromptConfigDict
432432
from .common import GetPromptConfigOrDict
433+
from .common import IdentityType
433434
from .common import Importance
434435
from .common import IntermediateExtractedMemory
435436
from .common import IntermediateExtractedMemoryDict
@@ -1798,6 +1799,7 @@
17981799
"AcceleratorType",
17991800
"Type",
18001801
"JobState",
1802+
"IdentityType",
18011803
"AgentServerMode",
18021804
"ManagedTopicEnum",
18031805
"Language",

vertexai/_genai/types/common.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,17 @@ class JobState(_common.CaseInSensitiveEnum):
205205
"""The job is partially succeeded, some results may be missing due to errors."""
206206

207207

208+
class IdentityType(_common.CaseInSensitiveEnum):
209+
"""The identity type to use for the Reasoning Engine. If not specified, the `service_account` field will be used if set, otherwise the default Vertex AI Reasoning Engine Service Agent in the project will be used."""
210+
211+
IDENTITY_TYPE_UNSPECIFIED = "IDENTITY_TYPE_UNSPECIFIED"
212+
"""Default value. Use a custom service account if the `service_account` field is set, otherwise use the default Vertex AI Reasoning Engine Service Agent in the project. Same behavior as SERVICE_ACCOUNT."""
213+
SERVICE_ACCOUNT = "SERVICE_ACCOUNT"
214+
"""Use a custom service account if the `service_account` field is set, otherwise use the default Vertex AI Reasoning Engine Service Agent in the project."""
215+
AGENT_IDENTITY = "AGENT_IDENTITY"
216+
"""Use Agent Identity. The `service_account` field must not be set."""
217+
218+
208219
class AgentServerMode(_common.CaseInSensitiveEnum):
209220
"""The agent server mode."""
210221

@@ -4784,6 +4795,14 @@ class ReasoningEngineSpec(_common.BaseModel):
47844795
default=None,
47854796
description="""Optional. The specification of a Reasoning Engine deployment.""",
47864797
)
4798+
effective_identity: Optional[str] = Field(
4799+
default=None,
4800+
description="""Output only. The identity to use for the Reasoning Engine. It can contain one of the following values: * service-{project}@gcp-sa-aiplatform-re.googleapis.com (for SERVICE_AGENT identity type) * {name}@{project}.gserviceaccount.com (for SERVICE_ACCOUNT identity type) * agents.global.{org}.system.id.goog/resources/aiplatform/projects/{project}/locations/{location}/reasoningEngines/{reasoning_engine} (for AGENT_IDENTITY identity type)""",
4801+
)
4802+
identity_type: Optional[IdentityType] = Field(
4803+
default=None,
4804+
description="""Optional. The identity type to use for the Reasoning Engine. If not specified, the `service_account` field will be used if set, otherwise the default Vertex AI Reasoning Engine Service Agent in the project will be used.""",
4805+
)
47874806
package_spec: Optional[ReasoningEngineSpecPackageSpec] = Field(
47884807
default=None,
47894808
description="""Optional. User provided package spec of the ReasoningEngine. Ignored when users directly specify a deployment image through `deployment_spec.first_party_image_override`, but keeping the field_behavior to avoid introducing breaking changes. The `deployment_source` field should not be set if `package_spec` is specified.""",
@@ -4810,6 +4829,12 @@ class ReasoningEngineSpecDict(TypedDict, total=False):
48104829
deployment_spec: Optional[ReasoningEngineSpecDeploymentSpecDict]
48114830
"""Optional. The specification of a Reasoning Engine deployment."""
48124831

4832+
effective_identity: Optional[str]
4833+
"""Output only. The identity to use for the Reasoning Engine. It can contain one of the following values: * service-{project}@gcp-sa-aiplatform-re.googleapis.com (for SERVICE_AGENT identity type) * {name}@{project}.gserviceaccount.com (for SERVICE_ACCOUNT identity type) * agents.global.{org}.system.id.goog/resources/aiplatform/projects/{project}/locations/{location}/reasoningEngines/{reasoning_engine} (for AGENT_IDENTITY identity type)"""
4834+
4835+
identity_type: Optional[IdentityType]
4836+
"""Optional. The identity type to use for the Reasoning Engine. If not specified, the `service_account` field will be used if set, otherwise the default Vertex AI Reasoning Engine Service Agent in the project will be used."""
4837+
48134838
package_spec: Optional[ReasoningEngineSpecPackageSpecDict]
48144839
"""Optional. User provided package spec of the ReasoningEngine. Ignored when users directly specify a deployment image through `deployment_spec.first_party_image_override`, but keeping the field_behavior to avoid introducing breaking changes. The `deployment_source` field should not be set if `package_spec` is specified."""
48154840

@@ -12905,6 +12930,9 @@ class AgentEngineConfig(_common.BaseModel):
1290512930

1290612931
If not specified, the default Reasoning Engine P6SA service agent will be used.""",
1290712932
)
12933+
identity_type: Optional[IdentityType] = Field(
12934+
default=None, description="""The identity type to use for the Agent Engine."""
12935+
)
1290812936
context_spec: Optional[ReasoningEngineContextSpec] = Field(
1290912937
default=None,
1291012938
description="""The context spec to be used for the Agent Engine.""",
@@ -13057,6 +13085,9 @@ class AgentEngineConfigDict(TypedDict, total=False):
1305713085

1305813086
If not specified, the default Reasoning Engine P6SA service agent will be used."""
1305913087

13088+
identity_type: Optional[IdentityType]
13089+
"""The identity type to use for the Agent Engine."""
13090+
1306013091
context_spec: Optional[ReasoningEngineContextSpecDict]
1306113092
"""The context spec to be used for the Agent Engine."""
1306213093

0 commit comments

Comments
 (0)