Skip to content

Commit 0b824e0

Browse files
LucaPreteLuca Prete
andauthored
Add new Agent Engine (google_vertex_ai_reasoning_engine) resource (#14480)
Co-authored-by: Luca Prete <[email protected]>
1 parent 5550af8 commit 0b824e0

File tree

10 files changed

+837
-0
lines changed

10 files changed

+837
-0
lines changed
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
# Copyright 2025 Google Inc.
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
14+
---
15+
name: 'ReasoningEngine'
16+
description: |-
17+
ReasoningEngine provides a customizable runtime for models to determine which actions to take and in which order.
18+
references:
19+
guides:
20+
'Develop and deploy agents on Vertex AI Agent Engine': 'https://cloud.google.com/vertex-ai/generative-ai/docs/agent-engine/quickstart'
21+
api: 'https://cloud.google.com/vertex-ai/docs/reference/rest/v1/projects.locations.reasoningEngines/'
22+
docs:
23+
base_url: 'projects/{{project}}/locations/{{region}}/reasoningEngines'
24+
self_link: 'projects/{{project}}/locations/{{region}}/reasoningEngines/{{name}}'
25+
create_url: 'projects/{{project}}/locations/{{region}}/reasoningEngines'
26+
update_verb: 'PATCH'
27+
update_mask: true
28+
timeouts:
29+
insert_minutes: 20
30+
update_minutes: 20
31+
delete_minutes: 20
32+
async:
33+
actions: ['create', 'delete', 'update']
34+
type: 'OpAsync'
35+
operation:
36+
base_url: '{{op_id}}'
37+
result:
38+
resource_inside_response: true
39+
examples:
40+
- name: 'vertex_ai_reasoning_engine_basic'
41+
primary_resource_id: 'reasoning_engine'
42+
exclude_docs: true
43+
vars:
44+
name: 'reasoning-engine'
45+
- name: 'vertex_ai_reasoning_engine_full'
46+
primary_resource_id: 'reasoning_engine'
47+
vars:
48+
name: 'reasoning-engine'
49+
bucket_name: 'reasoning-engine'
50+
kms_key_name: 'example-key'
51+
secret_name: 'secret'
52+
service_account_id: 'sa'
53+
bootstrap_iam:
54+
- member: "serviceAccount:service-{project_number}@gcp-sa-aiplatform.iam.gserviceaccount.com"
55+
role: "roles/cloudkms.cryptoKeyEncrypterDecrypter"
56+
test_vars_overrides:
57+
'kms_key_name': 'acctest.BootstrapKMSKeyWithPurposeInLocationAndName(t, "ENCRYPT_DECRYPT", "us-central1", "tf-bootstrap-re-key1").CryptoKey.Name'
58+
external_providers: ["time"]
59+
parameters:
60+
- name: 'region'
61+
type: String
62+
description: The region of the reasoning engine. eg us-central1
63+
url_param_only: true
64+
immutable: true
65+
properties:
66+
- name: 'name'
67+
type: String
68+
description: |-
69+
The generated name of the ReasoningEngine, in the format
70+
'projects/{project}/locations/{location}/reasoningEngines/{reasoningEngine}'
71+
output: true
72+
custom_flatten: 'templates/terraform/custom_flatten/name_from_self_link.tmpl'
73+
- name: 'displayName'
74+
type: String
75+
description: The display name of the ReasoningEngine.
76+
required: true
77+
- name: 'description'
78+
type: String
79+
description: The description of the ReasoningEngine.
80+
- name: 'createTime'
81+
type: String
82+
description: |-
83+
The timestamp of when the Index was created in RFC3339 UTC "Zulu" format,
84+
with nanosecond resolution and up to nine fractional digits.
85+
output: true
86+
- name: 'updateTime'
87+
type: String
88+
description: |-
89+
The timestamp of when the Index was last updated in RFC3339 UTC "Zulu" format,
90+
with nanosecond resolution and up to nine fractional digits.
91+
output: true
92+
- name: 'encryptionSpec'
93+
type: NestedObject
94+
description: |-
95+
Optional. Customer-managed encryption key spec for a ReasoningEngine.
96+
If set, this ReasoningEngine and all sub-resources of this ReasoningEngine will be secured by this key.
97+
immutable: true
98+
properties:
99+
- name: 'kmsKeyName'
100+
type: String
101+
description: |-
102+
Required. The Cloud KMS resource identifier of the customer managed encryption key used to protect a resource.
103+
Has the form: projects/my-project/locations/my-region/keyRings/my-kr/cryptoKeys/my-key.
104+
The key needs to be in the same region as where the compute resource is created.
105+
required: true
106+
- name: 'spec'
107+
type: NestedObject
108+
description: |-
109+
Optional. Configurations of the ReasoningEngine.
110+
properties:
111+
- name: 'agentFramework'
112+
type: String
113+
description: Optional. The OSS agent framework used to develop the agent.
114+
- name: 'classMethods'
115+
type: String
116+
description: Optional. Declarations for object class methods in OpenAPI specification format.
117+
state_func: 'func(v interface{}) string { s, _ := structure.NormalizeJsonString(v); return s }'
118+
custom_flatten: 'templates/terraform/custom_flatten/json_schema.tmpl'
119+
custom_expand: 'templates/terraform/custom_expand/json_value.tmpl'
120+
validation:
121+
function: 'validation.StringIsJSON'
122+
- name: 'deploymentSpec'
123+
type: NestedObject
124+
description: |-
125+
Optional. The specification of a Reasoning Engine deployment.
126+
properties:
127+
- name: 'env'
128+
type: Array
129+
description: |-
130+
Optional. Environment variables to be set with the Reasoning Engine deployment.
131+
is_set: true
132+
item_type:
133+
type: NestedObject
134+
properties:
135+
- name: 'name'
136+
type: String
137+
description: |-
138+
The name of the environment variable. Must be a valid C identifier.
139+
required: true
140+
- name: 'value'
141+
type: String
142+
description: |-
143+
Variables that reference a $(VAR_NAME) are expanded using the previous defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, regardless of whether the variable exists or not.
144+
required: true
145+
- name: 'secretEnv'
146+
type: Array
147+
description: |-
148+
Optional. Environment variables where the value is a secret in Cloud Secret Manager. To use this feature, add 'Secret Manager Secret Accessor' role (roles/secretmanager.secretAccessor) to AI Platform Reasoning Engine service Agent.
149+
is_set: true
150+
item_type:
151+
type: NestedObject
152+
properties:
153+
- name: 'name'
154+
type: String
155+
description: |-
156+
The name of the environment variable. Must be a valid C identifier.
157+
required: true
158+
- name: 'secretRef'
159+
type: NestedObject
160+
description: |-
161+
Reference to a secret stored in the Cloud Secret Manager that will provide the value for this environment variable.
162+
required: true
163+
properties:
164+
- name: 'secret'
165+
type: String
166+
description: |-
167+
The name of the secret in Cloud Secret Manager. Format: {secret_name}.
168+
required: true
169+
- name: 'version'
170+
type: String
171+
description: |-
172+
The Cloud Secret Manager secret version. Can be 'latest' for the latest version, an integer for a specific version, or a version alias.
173+
- name: 'packageSpec'
174+
type: NestedObject
175+
description: |-
176+
Optional. User provided package spec of the ReasoningEngine.
177+
Ignored when users directly specify a deployment image through
178+
deploymentSpec.first_party_image_override, but keeping the
179+
field_behavior to avoid introducing breaking changes.
180+
properties:
181+
- name: 'dependencyFilesGcsUri'
182+
type: String
183+
description: Optional. The Cloud Storage URI of the dependency files in tar.gz format.
184+
- name: 'pickleObjectGcsUri'
185+
type: String
186+
description: Optional. The Cloud Storage URI of the pickled python object.
187+
- name: 'pythonVersion'
188+
type: String
189+
description: Optional. The Python version.
190+
- name: 'requirementsGcsUri'
191+
type: String
192+
description: Optional. The Cloud Storage URI of the requirements.txt file
193+
- name: 'serviceAccount'
194+
type: String
195+
description: |-
196+
Optional. The service account that the Reasoning Engine artifact runs as.
197+
It should have "roles/storage.objectViewer" for reading the user project's
198+
Cloud Storage and "roles/aiplatform.user" for using Vertex extensions.
199+
If not specified, the Vertex AI Reasoning Engine service Agent in the project will be used.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
resource "google_vertex_ai_reasoning_engine" "{{$.PrimaryResourceId}}" {
2+
display_name = "{{index $.Vars "name"}}"
3+
description = "A basic reasoning engine"
4+
region = "us-central1"
5+
}
6+
7+
data "google_project" "project" {
8+
}
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
# Generate pickle files with the cloudpickle library:
2+
#
3+
# local_agent = LangchainAgent(
4+
# model=MODEL,
5+
# agent_executor_kwargs={"return_intermediate_steps": True},
6+
# )
7+
#
8+
# output_filename = "pickle.pkl"
9+
#
10+
# with open(output_filename, "wb") as f:
11+
# cloudpickle.dump(local_agent, f)
12+
13+
locals {
14+
class_methods = [
15+
{
16+
api_mode = "async"
17+
description = null
18+
name = "async_query"
19+
parameters = {
20+
type = "object"
21+
required = []
22+
properties = {}
23+
}
24+
}
25+
]
26+
}
27+
28+
resource "google_vertex_ai_reasoning_engine" "{{$.PrimaryResourceId}}" {
29+
display_name = "{{index $.Vars "name"}}"
30+
description = "A basic reasoning engine"
31+
region = "us-central1"
32+
33+
encryption_spec {
34+
kms_key_name = "{{index $.Vars "kms_key_name"}}"
35+
}
36+
37+
spec {
38+
agent_framework = "google-adk"
39+
class_methods = jsonencode(local.class_methods)
40+
service_account = google_service_account.service_account.email
41+
42+
deployment_spec {
43+
44+
env {
45+
name = "var_1"
46+
value = "value_2"
47+
}
48+
49+
env {
50+
name = "var_2"
51+
value = "value_2"
52+
}
53+
54+
secret_env {
55+
name = "secret_var_1"
56+
57+
secret_ref {
58+
secret = google_secret_manager_secret.secret.secret_id
59+
version = "latest"
60+
}
61+
}
62+
63+
secret_env {
64+
name = "secret_var_2"
65+
66+
secret_ref {
67+
secret = google_secret_manager_secret.secret.secret_id
68+
version = "latest"
69+
}
70+
}
71+
}
72+
73+
package_spec {
74+
dependency_files_gcs_uri = "${google_storage_bucket.bucket.url}/${google_storage_bucket_object.bucket_obj_dependencies_tar_gz.name}"
75+
pickle_object_gcs_uri = "${google_storage_bucket.bucket.url}/${google_storage_bucket_object.bucket_obj_pickle.name}"
76+
python_version = "3.11"
77+
requirements_gcs_uri = "${google_storage_bucket.bucket.url}/${google_storage_bucket_object.bucket_obj_requirements_txt.name}"
78+
}
79+
}
80+
81+
depends_on = [
82+
time_sleep.wait_5_minutes
83+
]
84+
}
85+
86+
# Ensure we wait enough time for IAM permissions to be propagated
87+
resource "time_sleep" "wait_5_minutes" {
88+
create_duration = "5m"
89+
90+
depends_on = [
91+
google_project_iam_member.sa_iam_ai_platform_user,
92+
google_project_iam_member.sa_iam_object_viewer,
93+
google_project_iam_member.sa_iam_viewer,
94+
google_secret_manager_secret_iam_member.secret_access,
95+
google_secret_manager_secret_version.secret_version
96+
]
97+
}
98+
99+
resource "google_secret_manager_secret_version" "secret_version" {
100+
secret = google_secret_manager_secret.secret.id
101+
secret_data = "test"
102+
}
103+
104+
resource "google_secret_manager_secret" "secret" {
105+
secret_id = "{{index $.Vars "secret_name"}}"
106+
107+
replication {
108+
auto {}
109+
}
110+
}
111+
112+
resource "google_secret_manager_secret_iam_member" "secret_access" {
113+
secret_id = google_secret_manager_secret.secret.id
114+
role = "roles/secretmanager.secretAccessor"
115+
member = google_service_account.service_account.member
116+
}
117+
118+
resource "google_storage_bucket" "bucket" {
119+
name = "{{index $.Vars "bucket_name"}}"
120+
location = "us-central1"
121+
uniform_bucket_level_access = true
122+
force_destroy = true
123+
}
124+
125+
resource "google_storage_bucket_object" "bucket_obj_requirements_txt" {
126+
name = "requirements.txt"
127+
bucket = google_storage_bucket.bucket.id
128+
source = "./test-fixtures/requirements_adk.txt"
129+
}
130+
131+
resource "google_storage_bucket_object" "bucket_obj_pickle" {
132+
name = "code.pkl"
133+
bucket = google_storage_bucket.bucket.id
134+
source = "./test-fixtures/pickle_adk.pkl"
135+
}
136+
137+
resource "google_storage_bucket_object" "bucket_obj_dependencies_tar_gz" {
138+
name = "dependencies.tar.gz"
139+
bucket = google_storage_bucket.bucket.id
140+
source = "./test-fixtures/dependencies_adk.tar.gz"
141+
}
142+
143+
resource "google_service_account" "service_account" {
144+
account_id = "{{index $.Vars "service_account_id"}}"
145+
}
146+
147+
resource "google_project_iam_member" "sa_iam_object_viewer" {
148+
role = "roles/storage.objectViewer"
149+
project = data.google_project.project.id
150+
member = google_service_account.service_account.member
151+
}
152+
153+
resource "google_project_iam_member" "sa_iam_ai_platform_user" {
154+
role = "roles/aiplatform.user"
155+
project = data.google_project.project.id
156+
member = google_service_account.service_account.member
157+
}
158+
159+
resource "google_project_iam_member" "sa_iam_viewer" {
160+
role = "roles/viewer"
161+
project = data.google_project.project.id
162+
member = google_service_account.service_account.member
163+
}
164+
165+
data "google_project" "project" {
166+
}

0 commit comments

Comments
 (0)