Skip to content

Commit e20c003

Browse files
vertex-sdk-botcopybara-github
authored andcommitted
feat: add build configuration support to Vertex AI Reasoning Engine
PiperOrigin-RevId: 963119503
1 parent 19144a4 commit e20c003

7 files changed

Lines changed: 200 additions & 0 deletions

File tree

‎agentplatform/_genai/agent_engines.py‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2006,6 +2006,7 @@ def create(
20062006
agent_config_source=agent_config_source,
20072007
container_spec=config.container_spec,
20082008
keep_alive_probe=keep_alive_probe,
2009+
build_config=config.build_config,
20092010
)
20102011
operation = self._create(config=api_config)
20112012
reasoning_engine_id = _agent_engines_utils._get_reasoning_engine_id(
@@ -2319,6 +2320,7 @@ def _create_config(
23192320
container_spec: Optional[types.ReasoningEngineSpecContainerSpecDict] = None,
23202321
keep_alive_probe: Optional[dict[str, Any]] = None,
23212322
traffic_config: Optional[types.ReasoningEngineTrafficConfigDict] = None,
2323+
build_config: Optional[types.ReasoningEngineSpecBuildSpecDict] = None,
23222324
) -> types.UpdateAgentEngineConfigDict:
23232325
import sys
23242326

@@ -2525,6 +2527,25 @@ def _create_config(
25252527
agent_engine_spec["service_account"] = service_account
25262528
update_masks.append("spec.service_account")
25272529

2530+
if build_config is not None:
2531+
if agent_engine_spec is None:
2532+
agent_engine_spec = {}
2533+
build_spec: dict[str, Any] = {}
2534+
if isinstance(build_config, dict):
2535+
worker_pool = build_config.get("worker_pool")
2536+
build_service_account = build_config.get("service_account")
2537+
else:
2538+
worker_pool = getattr(build_config, "worker_pool", None)
2539+
build_service_account = getattr(build_config, "service_account", None)
2540+
if worker_pool is not None:
2541+
build_spec["worker_pool"] = worker_pool
2542+
update_masks.append("spec.build_spec.worker_pool")
2543+
if build_service_account is not None:
2544+
build_spec["service_account"] = build_service_account
2545+
update_masks.append("spec.build_spec.service_account")
2546+
if build_spec:
2547+
agent_engine_spec["build_spec"] = build_spec
2548+
25282549
if agent_engine_spec is not None:
25292550
config["spec"] = agent_engine_spec
25302551

@@ -2796,6 +2817,7 @@ def update(
27962817
container_spec=container_spec,
27972818
keep_alive_probe=keep_alive_probe,
27982819
traffic_config=traffic_config,
2820+
build_config=config.build_config,
27992821
)
28002822
operation = self._update(name=name, config=api_config)
28012823
reasoning_engine_id = _agent_engines_utils._get_reasoning_engine_id(

‎agentplatform/_genai/types/__init__.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1444,6 +1444,9 @@
14441444
from .common import ReasoningEngineRuntimeRevisionDict
14451445
from .common import ReasoningEngineRuntimeRevisionOrDict
14461446
from .common import ReasoningEngineSpec
1447+
from .common import ReasoningEngineSpecBuildSpec
1448+
from .common import ReasoningEngineSpecBuildSpecDict
1449+
from .common import ReasoningEngineSpecBuildSpecOrDict
14471450
from .common import ReasoningEngineSpecContainerSpec
14481451
from .common import ReasoningEngineSpecContainerSpecDict
14491452
from .common import ReasoningEngineSpecContainerSpecOrDict
@@ -2588,6 +2591,9 @@
25882591
"ReasoningEngineSpecContainerSpec",
25892592
"ReasoningEngineSpecContainerSpecDict",
25902593
"ReasoningEngineSpecContainerSpecOrDict",
2594+
"ReasoningEngineSpecBuildSpec",
2595+
"ReasoningEngineSpecBuildSpecDict",
2596+
"ReasoningEngineSpecBuildSpecOrDict",
25912597
"ReasoningEngineSpec",
25922598
"ReasoningEngineSpecDict",
25932599
"ReasoningEngineSpecOrDict",

‎agentplatform/_genai/types/common.py‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8852,6 +8852,34 @@ class ReasoningEngineSpecContainerSpecDict(TypedDict, total=False):
88528852
]
88538853

88548854

8855+
class ReasoningEngineSpecBuildSpec(_common.BaseModel):
8856+
"""Specification for building container image."""
8857+
8858+
service_account: Optional[str] = Field(
8859+
default=None,
8860+
description="""Optional. The service account that Cloud Build uses to run the build. This field is only applicable when `worker_pool` is specified (i.e., for custom worker pools). If `worker_pool` is not specified, this field is ignored and the build runs using the Google-managed service agent.""",
8861+
)
8862+
worker_pool: Optional[str] = Field(
8863+
default=None,
8864+
description="""Optional. The resource name of the Cloud Build WorkerPool to use for the build. Format: `projects/{project}/locations/{location}/workerPools/{worker_pool}`""",
8865+
)
8866+
8867+
8868+
class ReasoningEngineSpecBuildSpecDict(TypedDict, total=False):
8869+
"""Specification for building container image."""
8870+
8871+
service_account: Optional[str]
8872+
"""Optional. The service account that Cloud Build uses to run the build. This field is only applicable when `worker_pool` is specified (i.e., for custom worker pools). If `worker_pool` is not specified, this field is ignored and the build runs using the Google-managed service agent."""
8873+
8874+
worker_pool: Optional[str]
8875+
"""Optional. The resource name of the Cloud Build WorkerPool to use for the build. Format: `projects/{project}/locations/{location}/workerPools/{worker_pool}`"""
8876+
8877+
8878+
ReasoningEngineSpecBuildSpecOrDict = Union[
8879+
ReasoningEngineSpecBuildSpec, ReasoningEngineSpecBuildSpecDict
8880+
]
8881+
8882+
88558883
class ReasoningEngineSpec(_common.BaseModel):
88568884
"""The specification of an agent engine."""
88578885

@@ -8895,6 +8923,10 @@ class ReasoningEngineSpec(_common.BaseModel):
88958923
default=None,
88968924
description="""Deploy from a container image with a defined entrypoint and commands.""",
88978925
)
8926+
build_spec: Optional[ReasoningEngineSpecBuildSpec] = Field(
8927+
default=None,
8928+
description="""Optional. Configuration for building container image.""",
8929+
)
88988930

88998931

89008932
class ReasoningEngineSpecDict(TypedDict, total=False):
@@ -8930,6 +8962,9 @@ class ReasoningEngineSpecDict(TypedDict, total=False):
89308962
container_spec: Optional[ReasoningEngineSpecContainerSpecDict]
89318963
"""Deploy from a container image with a defined entrypoint and commands."""
89328964

8965+
build_spec: Optional[ReasoningEngineSpecBuildSpecDict]
8966+
"""Optional. Configuration for building container image."""
8967+
89338968

89348969
ReasoningEngineSpecOrDict = Union[ReasoningEngineSpec, ReasoningEngineSpecDict]
89358970

@@ -26372,6 +26407,10 @@ class AgentEngineConfig(_common.BaseModel):
2637226407
traffic_config: Optional[ReasoningEngineTrafficConfig] = Field(
2637326408
default=None, description="""The traffic config for the Agent Engine."""
2637426409
)
26410+
build_config: Optional[ReasoningEngineSpecBuildSpec] = Field(
26411+
default=None,
26412+
description="""The build config for the Agent Engine. Allows bringing your own Cloud Build private worker pool (BYOBP) and, optionally, a build-time service account for the container build. Supported keys: `worker_pool` (the resource name of the Cloud Build WorkerPool to use for the build) and `service_account` (the service account that Cloud Build uses to run the build; only applicable when `worker_pool` is specified).""",
26413+
)
2637526414

2637626415

2637726416
class AgentEngineConfigDict(TypedDict, total=False):
@@ -26559,6 +26598,9 @@ class AgentEngineConfigDict(TypedDict, total=False):
2655926598
traffic_config: Optional[ReasoningEngineTrafficConfigDict]
2656026599
"""The traffic config for the Agent Engine."""
2656126600

26601+
build_config: Optional[ReasoningEngineSpecBuildSpecDict]
26602+
"""The build config for the Agent Engine. Allows bringing your own Cloud Build private worker pool (BYOBP) and, optionally, a build-time service account for the container build. Supported keys: `worker_pool` (the resource name of the Cloud Build WorkerPool to use for the build) and `service_account` (the service account that Cloud Build uses to run the build; only applicable when `worker_pool` is specified)."""
26603+
2656226604

2656326605
AgentEngineConfigOrDict = Union[AgentEngineConfig, AgentEngineConfigDict]
2656426606

‎tests/unit/agentplatform/genai/test_agent_engines.py‎

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,16 @@ def register_operations(self) -> Dict[str, List[str]]:
554554
_genai_types.IdentityType.SERVICE_ACCOUNT
555555
)
556556
_TEST_AGENT_ENGINE_ENCRYPTION_SPEC = {"kms_key_name": "test-kms-key"}
557+
_TEST_AGENT_ENGINE_BUILD_WORKER_POOL = (
558+
"projects/test-project/locations/us-central1/workerPools/test-pool"
559+
)
560+
_TEST_AGENT_ENGINE_BUILD_SERVICE_ACCOUNT = (
561+
"test-build-sa@test-project.iam.gserviceaccount.com"
562+
)
563+
_TEST_AGENT_ENGINE_BUILD_CONFIG = _genai_types.ReasoningEngineSpecBuildSpecDict(
564+
worker_pool=_TEST_AGENT_ENGINE_BUILD_WORKER_POOL,
565+
service_account=_TEST_AGENT_ENGINE_BUILD_SERVICE_ACCOUNT,
566+
)
557567
_TEST_AGENT_ENGINE_KEEP_ALIVE_PROBE = {
558568
"http_get": {
559569
"path": "/health",
@@ -1046,6 +1056,51 @@ def test_create_agent_engine_config_full(self, mock_prepare):
10461056
== _TEST_AGENT_ENGINE_IDENTITY_TYPE_SERVICE_ACCOUNT
10471057
)
10481058

1059+
@mock.patch.object(_agent_engines_utils, "_prepare")
1060+
def test_create_agent_engine_config_with_build_config(self, mock_prepare):
1061+
config = self.client.agent_engines._create_config(
1062+
mode="create",
1063+
agent=self.test_agent,
1064+
staging_bucket=_TEST_STAGING_BUCKET,
1065+
requirements=_TEST_AGENT_ENGINE_REQUIREMENTS,
1066+
display_name=_TEST_AGENT_ENGINE_DISPLAY_NAME,
1067+
build_config=_TEST_AGENT_ENGINE_BUILD_CONFIG,
1068+
)
1069+
assert config["spec"]["build_spec"] == {
1070+
"worker_pool": _TEST_AGENT_ENGINE_BUILD_WORKER_POOL,
1071+
"service_account": _TEST_AGENT_ENGINE_BUILD_SERVICE_ACCOUNT,
1072+
}
1073+
1074+
@mock.patch.object(_agent_engines_utils, "_prepare")
1075+
def test_create_agent_engine_config_with_build_config_worker_pool_only(
1076+
self, mock_prepare
1077+
):
1078+
config = self.client.agent_engines._create_config(
1079+
mode="create",
1080+
agent=self.test_agent,
1081+
staging_bucket=_TEST_STAGING_BUCKET,
1082+
requirements=_TEST_AGENT_ENGINE_REQUIREMENTS,
1083+
display_name=_TEST_AGENT_ENGINE_DISPLAY_NAME,
1084+
build_config={"worker_pool": _TEST_AGENT_ENGINE_BUILD_WORKER_POOL},
1085+
)
1086+
assert config["spec"]["build_spec"] == {
1087+
"worker_pool": _TEST_AGENT_ENGINE_BUILD_WORKER_POOL,
1088+
}
1089+
1090+
@mock.patch.object(_agent_engines_utils, "_prepare")
1091+
def test_update_agent_engine_config_with_build_config(self, mock_prepare):
1092+
config = self.client.agent_engines._create_config(
1093+
mode="update",
1094+
build_config=_TEST_AGENT_ENGINE_BUILD_CONFIG,
1095+
)
1096+
assert config["spec"]["build_spec"] == {
1097+
"worker_pool": _TEST_AGENT_ENGINE_BUILD_WORKER_POOL,
1098+
"service_account": _TEST_AGENT_ENGINE_BUILD_SERVICE_ACCOUNT,
1099+
}
1100+
update_mask = config["update_mask"].split(",")
1101+
assert "spec.build_spec.worker_pool" in update_mask
1102+
assert "spec.build_spec.service_account" in update_mask
1103+
10491104
@mock.patch.object(
10501105
_agent_engines_utils,
10511106
"_create_base64_encoded_tarball",
@@ -2236,6 +2291,7 @@ def test_create_agent_engine_with_env_vars_dict(
22362291
agent_config_source=None,
22372292
container_spec=None,
22382293
keep_alive_probe=None,
2294+
build_config=None,
22392295
)
22402296
request_mock.assert_called_with(
22412297
"post",
@@ -2342,6 +2398,7 @@ def test_create_agent_engine_with_custom_service_account(
23422398
agent_config_source=None,
23432399
container_spec=None,
23442400
keep_alive_probe=None,
2401+
build_config=None,
23452402
)
23462403
request_mock.assert_called_with(
23472404
"post",
@@ -2447,6 +2504,7 @@ def test_create_agent_engine_with_experimental_mode(
24472504
agent_config_source=None,
24482505
container_spec=None,
24492506
keep_alive_probe=None,
2507+
build_config=None,
24502508
)
24512509
request_mock.assert_called_with(
24522510
"post",
@@ -2621,6 +2679,7 @@ def test_create_agent_engine_with_class_methods(
26212679
agent_config_source=None,
26222680
container_spec=None,
26232681
keep_alive_probe=None,
2682+
build_config=None,
26242683
)
26252684
request_mock.assert_called_with(
26262685
"post",
@@ -2721,6 +2780,7 @@ def test_create_agent_engine_with_agent_framework(
27212780
agent_config_source=None,
27222781
container_spec=None,
27232782
keep_alive_probe=None,
2783+
build_config=None,
27242784
)
27252785
request_mock.assert_called_with(
27262786
"post",

‎vertexai/_genai/agent_engines.py‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2005,6 +2005,7 @@ def create(
20052005
agent_config_source=agent_config_source,
20062006
container_spec=config.container_spec,
20072007
keep_alive_probe=keep_alive_probe,
2008+
build_config=config.build_config,
20082009
)
20092010
operation = self._create(config=api_config)
20102011
reasoning_engine_id = _agent_engines_utils._get_reasoning_engine_id(
@@ -2318,6 +2319,7 @@ def _create_config(
23182319
container_spec: Optional[types.ReasoningEngineSpecContainerSpecDict] = None,
23192320
keep_alive_probe: Optional[dict[str, Any]] = None,
23202321
traffic_config: Optional[types.ReasoningEngineTrafficConfigDict] = None,
2322+
build_config: Optional[types.ReasoningEngineSpecBuildSpecDict] = None,
23212323
) -> types.UpdateAgentEngineConfigDict:
23222324
import sys
23232325

@@ -2524,6 +2526,25 @@ def _create_config(
25242526
agent_engine_spec["service_account"] = service_account
25252527
update_masks.append("spec.service_account")
25262528

2529+
if build_config is not None:
2530+
if agent_engine_spec is None:
2531+
agent_engine_spec = {}
2532+
build_spec: dict[str, Any] = {}
2533+
if isinstance(build_config, dict):
2534+
worker_pool = build_config.get("worker_pool")
2535+
build_service_account = build_config.get("service_account")
2536+
else:
2537+
worker_pool = getattr(build_config, "worker_pool", None)
2538+
build_service_account = getattr(build_config, "service_account", None)
2539+
if worker_pool is not None:
2540+
build_spec["worker_pool"] = worker_pool
2541+
update_masks.append("spec.build_spec.worker_pool")
2542+
if build_service_account is not None:
2543+
build_spec["service_account"] = build_service_account
2544+
update_masks.append("spec.build_spec.service_account")
2545+
if build_spec:
2546+
agent_engine_spec["build_spec"] = build_spec
2547+
25272548
if agent_engine_spec is not None:
25282549
config["spec"] = agent_engine_spec
25292550

@@ -2795,6 +2816,7 @@ def update(
27952816
container_spec=container_spec,
27962817
keep_alive_probe=keep_alive_probe,
27972818
traffic_config=traffic_config,
2819+
build_config=config.build_config,
27982820
)
27992821
operation = self._update(name=name, config=api_config)
28002822
reasoning_engine_id = _agent_engines_utils._get_reasoning_engine_id(

‎vertexai/_genai/types/__init__.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,9 @@
10311031
from .common import ReasoningEngineRuntimeRevisionDict
10321032
from .common import ReasoningEngineRuntimeRevisionOrDict
10331033
from .common import ReasoningEngineSpec
1034+
from .common import ReasoningEngineSpecBuildSpec
1035+
from .common import ReasoningEngineSpecBuildSpecDict
1036+
from .common import ReasoningEngineSpecBuildSpecOrDict
10341037
from .common import ReasoningEngineSpecContainerSpec
10351038
from .common import ReasoningEngineSpecContainerSpecDict
10361039
from .common import ReasoningEngineSpecContainerSpecOrDict
@@ -2082,6 +2085,9 @@
20822085
"ReasoningEngineSpecContainerSpec",
20832086
"ReasoningEngineSpecContainerSpecDict",
20842087
"ReasoningEngineSpecContainerSpecOrDict",
2088+
"ReasoningEngineSpecBuildSpec",
2089+
"ReasoningEngineSpecBuildSpecDict",
2090+
"ReasoningEngineSpecBuildSpecOrDict",
20852091
"ReasoningEngineSpec",
20862092
"ReasoningEngineSpecDict",
20872093
"ReasoningEngineSpecOrDict",

0 commit comments

Comments
 (0)