Add Agent Engine module. (#3429)
This commit is contained in:
248
modules/agent-engine/README.md
Normal file
248
modules/agent-engine/README.md
Normal file
@@ -0,0 +1,248 @@
|
||||
# Agent Engine Module
|
||||
|
||||
The module creates Agent Engine and related dependencies.
|
||||
|
||||
- It can automatically generate and update the Pickle file for you, given a source file.
|
||||
- It optionally creates a GCS storage bucket or can use an existing one and loads on it all your dependencies (`pickle`, `dependencies.tar.gz`, `requirements.txt`)
|
||||
- Manages the service accounts lifecycle
|
||||
|
||||
<!-- BEGIN TOC -->
|
||||
- [Packaging dependencies](#packaging-dependencies)
|
||||
- [Minimal deployment](#minimal-deployment)
|
||||
- [Service accounts](#service-accounts)
|
||||
- [Specify an encryption key](#specify-an-encryption-key)
|
||||
- [Define environment variables and use secrets](#define-environment-variables-and-use-secrets)
|
||||
- [Getting values from context](#getting-values-from-context)
|
||||
- [Variables](#variables)
|
||||
- [Outputs](#outputs)
|
||||
<!-- END TOC -->
|
||||
|
||||
## Packaging dependencies
|
||||
|
||||
To deploy an agent, you first need package your dependencies. This consists of a folder with
|
||||
|
||||
- The source Python file defining your agent to be pickled (or the equivalent pickle file).
|
||||
- The `dependencies.tar.gz`.
|
||||
- The `requirements.txt` file.
|
||||
|
||||
By default, the module expects these files to be in an `src` subfolder.
|
||||
|
||||
You can decide to **let the module create the pickle file for you**, starting from a source agent file.
|
||||
In this case, the module expects you to have in `src` a source file called `agent.py` with a variable referencing your agent function definition called `local_agent`.
|
||||
|
||||
This is an example of `agent.py` file for ADK:
|
||||
|
||||
```python
|
||||
from google.adk.agents import LlmAgent
|
||||
from vertexai.agent_engines import AdkApp
|
||||
|
||||
def get_exchange_rate(
|
||||
currency_from: str = "USD",
|
||||
currency_to: str = "EUR",
|
||||
currency_date: str = "latest",
|
||||
):
|
||||
import requests
|
||||
response = requests.get(
|
||||
f"https://api.frankfurter.app/{currency_date}",
|
||||
params={"from": currency_from, "to": currency_to},
|
||||
)
|
||||
return response.json()
|
||||
|
||||
root_agent = LlmAgent(
|
||||
model="gemini-2.5-flash",
|
||||
instruction="You are a helpful assistant",
|
||||
name='currency_exchange_agent',
|
||||
tools=[get_exchange_rate],
|
||||
)
|
||||
|
||||
local_agent = AdkApp(agent=root_agent)
|
||||
```
|
||||
|
||||
The [tools/serialize_agent.py](tools/serialize_agent.py) is used to generate the `pickle.pkl` file.
|
||||
You module needs [these packages](tools/requirements.txt) to work.
|
||||
|
||||
If you **already have a pickle file**, the module expects you to have in the `src` subfolder a `pickle.pkl` file.
|
||||
|
||||
You can customize these values by using the `source_files` variable.
|
||||
|
||||
## Minimal deployment
|
||||
|
||||
This example assumes you are providing the [source packages](#packaging-dependencies) (`agent.py`, `dependencies.tar.gz` and `requirements.txt`) in the `src` subfolder. Every time you will change the agent definition, the module will generate the new pickle file for you, will update it on the GCS bucket and will update your agent.
|
||||
|
||||
```hcl
|
||||
module "agent_engine" {
|
||||
source = "./fabric/modules/agent-engine"
|
||||
name = "my-agent"
|
||||
project_id = var.project_id
|
||||
region = var.region
|
||||
|
||||
agent_engine_config = {
|
||||
agent_framework = "google-adk"
|
||||
}
|
||||
|
||||
source_files = {
|
||||
path = "assets/src/"
|
||||
}
|
||||
}
|
||||
# tftest inventory=minimal.yaml
|
||||
```
|
||||
|
||||
Alternatively, you can pass a pre-generated `pickle.pkl` file.
|
||||
|
||||
```hcl
|
||||
module "agent_engine" {
|
||||
source = "./fabric/modules/agent-engine"
|
||||
name = "my-agent"
|
||||
project_id = var.project_id
|
||||
region = var.region
|
||||
generate_pickle = false
|
||||
|
||||
agent_engine_config = {
|
||||
agent_framework = "google-adk"
|
||||
}
|
||||
|
||||
source_files = {
|
||||
path = "assets/src/"
|
||||
}
|
||||
}
|
||||
# tftest inventory=minimal-pickle.yaml
|
||||
```
|
||||
|
||||
## Service accounts
|
||||
|
||||
By default, the module creates a dedicated service account for your agent and grants it the roles needed to deploy the agent. The default roles are defined in `var.service_account_config.roles`. You can add more roles, as needed.
|
||||
|
||||
You can also use the default Agent Engine (Reasoning Engine) service agent.
|
||||
In this case, it will be your responsibility to grant any other role needed to the service agent service account.
|
||||
At the moment, you'll need at least to grant to it the `roles/viewer` role.
|
||||
|
||||
```hcl
|
||||
module "agent_engine" {
|
||||
source = "./fabric/modules/agent-engine"
|
||||
name = "my-agent"
|
||||
project_id = var.project_id
|
||||
region = var.region
|
||||
|
||||
agent_engine_config = {
|
||||
agent_framework = "google-adk"
|
||||
}
|
||||
|
||||
service_account_config = {
|
||||
create = false
|
||||
}
|
||||
|
||||
source_files = {
|
||||
path = "assets/src/"
|
||||
}
|
||||
}
|
||||
# tftest inventory=sa-default.yaml
|
||||
```
|
||||
|
||||
Alternatively, you can use an existing service account.
|
||||
|
||||
```hcl
|
||||
module "agent_engine" {
|
||||
source = "./fabric/modules/agent-engine"
|
||||
name = "my-agent"
|
||||
project_id = var.project_id
|
||||
region = var.region
|
||||
|
||||
agent_engine_config = {
|
||||
agent_framework = "google-adk"
|
||||
}
|
||||
|
||||
service_account_config = {
|
||||
create = false
|
||||
email = "my-sa@${var.project_id}.iam.gserviceaccount.com"
|
||||
}
|
||||
|
||||
source_files = {
|
||||
path = "assets/src/"
|
||||
}
|
||||
}
|
||||
# tftest inventory=sa-custom.yaml
|
||||
```
|
||||
|
||||
## Specify an encryption key
|
||||
|
||||
You can optionally specify an existing encryption key, created in KMS.
|
||||
|
||||
To use KMS keys you'll need to grant the AI Platform Service Agent (`service-YOUR_PROJECT_NUMBER@gcp-sa-aiplatform-re.iam.gserviceaccount.com`) the `roles/cloudkms.cryptoKeyEncrypterDecrypter` role on the key.
|
||||
|
||||
```hcl
|
||||
module "agent_engine" {
|
||||
source = "./fabric/modules/agent-engine"
|
||||
name = "my-agent"
|
||||
project_id = var.project_id
|
||||
region = var.region
|
||||
encryption_key = "projects/${var.project_id}/locations/${var.region}/keyRings/my-keyring/cryptoKeys/my-key"
|
||||
|
||||
agent_engine_config = {
|
||||
agent_framework = "google-adk"
|
||||
}
|
||||
|
||||
source_files = {
|
||||
path = "assets/src/"
|
||||
}
|
||||
}
|
||||
# tftest inventory=encryption.yaml
|
||||
```
|
||||
|
||||
## Define environment variables and use secrets
|
||||
|
||||
You can define environment variables and load existing secrets as environment variables into your agent.
|
||||
|
||||
```hcl
|
||||
module "agent_engine" {
|
||||
source = "./fabric/modules/agent-engine"
|
||||
name = "my-agent"
|
||||
project_id = var.project_id
|
||||
region = var.region
|
||||
|
||||
agent_engine_config = {
|
||||
agent_framework = "google-adk"
|
||||
|
||||
environment_variables = {
|
||||
FOO = "my-foo-variable"
|
||||
}
|
||||
secret_environment_variables = {
|
||||
BAR = {
|
||||
secret_id = "projects/YOUR_PROJECT_NUMBER/secrets/my-bar-secret"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
source_files = {
|
||||
path = "assets/src/"
|
||||
}
|
||||
}
|
||||
# tftest inventory=environment.yaml
|
||||
```
|
||||
|
||||
## Getting values from context
|
||||
|
||||
The module allows you to dynamically reference context values for resources created outside this module, through the `context` variable. This includes the definition of custom roles, iam_principals, locations, kms_keys and project ids.
|
||||
<!-- BEGIN TFDOC -->
|
||||
## Variables
|
||||
|
||||
| name | description | type | required | default |
|
||||
|---|---|:---:|:---:|:---:|
|
||||
| [agent_engine_config](variables.tf#L17) | The agent configuration. | <code title="object({ agent_framework = string class_methods = optional(list(any), []) environment_variables = optional(map(string), {}) python_version = optional(string, "3.12") secret_environment_variables = optional(map(object({ secret_id = string version = optional(string, "latest") })), {}) })">object({…})</code> | ✓ | |
|
||||
| [name](variables.tf#L77) | The name of the agent. | <code>string</code> | ✓ | |
|
||||
| [project_id](variables.tf#L83) | The id of the project where to deploy the agent. | <code>string</code> | ✓ | |
|
||||
| [region](variables.tf#L89) | The region where to deploy the agent. | <code>string</code> | ✓ | |
|
||||
| [bucket_config](variables.tf#L32) | The GCS bucket configuration. | <code title="object({ create = optional(bool, true) deletion_protection = optional(bool, true) name = optional(string) uniform_bucket_level_access = optional(bool, true) })">object({…})</code> | | <code>{}</code> |
|
||||
| [context](variables.tf#L44) | Context-specific interpolations. | <code title="object({ custom_roles = optional(map(string), {}) iam_principals = optional(map(string), {}) locations = optional(map(string), {}) kms_keys = optional(map(string), {}) project_ids = optional(map(string), {}) })">object({…})</code> | | <code>{}</code> |
|
||||
| [description](variables.tf#L57) | The Agent Engine description. | <code>string</code> | | <code>"Terraform managed."</code> |
|
||||
| [encryption_key](variables.tf#L64) | The full resource name of the Cloud KMS CryptoKey. | <code>string</code> | | <code>null</code> |
|
||||
| [generate_pickle](variables.tf#L70) | Generate the pickle file from a source file. | <code>bool</code> | | <code>true</code> |
|
||||
| [service_account_config](variables.tf#L95) | Service account configurations. | <code title="object({ create = optional(bool, true) email = optional(string) name = optional(string) roles = optional(list(string), [ "roles/aiplatform.user", "roles/storage.objectViewer", "roles/viewer" ]) })">object({…})</code> | | <code>{}</code> |
|
||||
| [source_files](variables.tf#L112) | The to source files path and names. | <code title="object({ dependencies = optional(string, "dependencies.tar.gz") path = optional(string, "./src") pickle_out = optional(string, "pickle.pkl") pickle_src = optional(string, "agent.py") pickle_src_var_name = optional(string, "local_agent") requirements = optional(string, "requirements.txt") })">object({…})</code> | | <code>{}</code> |
|
||||
|
||||
## Outputs
|
||||
|
||||
| name | description | sensitive |
|
||||
|---|---|:---:|
|
||||
| [id](outputs.tf#L17) | Fully qualified Agent Engine id. | |
|
||||
| [service_account](outputs.tf#L22) | Service account resource. | |
|
||||
<!-- END TFDOC -->
|
||||
212
modules/agent-engine/main.tf
Normal file
212
modules/agent-engine/main.tf
Normal file
@@ -0,0 +1,212 @@
|
||||
/**
|
||||
* Copyright 2025 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
locals {
|
||||
_ctx_p = "$"
|
||||
_service_account_external_email = (
|
||||
var.service_account_config.email == null
|
||||
? null
|
||||
: lookup(
|
||||
local.ctx.iam_principals,
|
||||
var.service_account_config.email,
|
||||
var.service_account_config.email
|
||||
)
|
||||
)
|
||||
bucket_name = (
|
||||
var.bucket_config.create
|
||||
? google_storage_bucket.default[0].name
|
||||
: coalesce(var.bucket_config.name, var.name)
|
||||
)
|
||||
ctx = {
|
||||
for k, v in var.context : k => {
|
||||
for kk, vv in v : "${local._ctx_p}${k}:${kk}" => vv
|
||||
} if k != "condition_vars"
|
||||
}
|
||||
location = lookup(
|
||||
local.ctx.locations, var.region, var.region
|
||||
)
|
||||
project_id = lookup(
|
||||
local.ctx.project_ids, var.project_id, var.project_id
|
||||
)
|
||||
service_account_email = (
|
||||
var.service_account_config.create
|
||||
? google_service_account.default[0].email
|
||||
: local._service_account_external_email
|
||||
)
|
||||
service_account_roles = [
|
||||
for role in var.service_account_config.roles
|
||||
: lookup(local.ctx.custom_roles, role, role)
|
||||
]
|
||||
}
|
||||
|
||||
resource "google_vertex_ai_reasoning_engine" "default" {
|
||||
display_name = var.name
|
||||
project = local.project_id
|
||||
description = var.description
|
||||
region = local.location
|
||||
|
||||
dynamic "encryption_spec" {
|
||||
for_each = var.encryption_key == null ? {} : { 1 = 1 }
|
||||
|
||||
content {
|
||||
kms_key_name = lookup(
|
||||
local.ctx.kms_keys,
|
||||
var.encryption_key,
|
||||
var.encryption_key
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
spec {
|
||||
agent_framework = var.agent_engine_config.agent_framework
|
||||
class_methods = (
|
||||
length(var.agent_engine_config.class_methods) > 0
|
||||
? jsonencode(var.agent_engine_config.class_methods)
|
||||
: null
|
||||
)
|
||||
service_account = local.service_account_email
|
||||
|
||||
dynamic "deployment_spec" {
|
||||
for_each = (
|
||||
# length(var.container_spec) > 0 ||
|
||||
length(var.agent_engine_config.environment_variables) > 0 ||
|
||||
length(var.agent_engine_config.secret_environment_variables) > 0
|
||||
? { 1 = 1 }
|
||||
: {}
|
||||
)
|
||||
|
||||
content {
|
||||
dynamic "env" {
|
||||
for_each = var.agent_engine_config.environment_variables
|
||||
|
||||
content {
|
||||
name = env.key
|
||||
value = env.value
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "secret_env" {
|
||||
for_each = var.agent_engine_config.secret_environment_variables
|
||||
|
||||
content {
|
||||
name = secret_env.key
|
||||
|
||||
secret_ref {
|
||||
secret = secret_env.value.secret_id
|
||||
version = secret_env.value.version
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
package_spec {
|
||||
python_version = var.agent_engine_config.python_version
|
||||
dependency_files_gcs_uri = "gs://${local.bucket_name}/${google_storage_bucket_object.dependencies.name}"
|
||||
requirements_gcs_uri = "gs://${local.bucket_name}/${google_storage_bucket_object.requirements.name}"
|
||||
pickle_object_gcs_uri = (
|
||||
var.generate_pickle
|
||||
? "gs://${local.bucket_name}/${google_storage_bucket_object.pickle_from_src[0].name}"
|
||||
: "gs://${local.bucket_name}/${google_storage_bucket_object.pickle[0].name}"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# TODO: fix once eventual consistency issue is solved.
|
||||
# AE doesn't retry the deployment (yet) if bindings are still not active.
|
||||
resource "time_sleep" "wait_5_minutes" {
|
||||
create_duration = "5m"
|
||||
|
||||
depends_on = [
|
||||
google_project_iam_member.default
|
||||
]
|
||||
}
|
||||
|
||||
resource "google_storage_bucket" "default" {
|
||||
count = var.bucket_config.create ? 1 : 0
|
||||
name = coalesce(var.bucket_config.name, var.name)
|
||||
project = local.project_id
|
||||
location = local.location
|
||||
uniform_bucket_level_access = var.bucket_config.uniform_bucket_level_access
|
||||
force_destroy = !var.bucket_config.deletion_protection
|
||||
}
|
||||
|
||||
resource "null_resource" "default" {
|
||||
count = var.generate_pickle ? 1 : 0
|
||||
|
||||
provisioner "local-exec" {
|
||||
command = join(" ", [
|
||||
"python",
|
||||
"./tools/serialize_agent.py",
|
||||
"${var.source_files.path}/${var.source_files.pickle_src}",
|
||||
"--output-file ${var.source_files.path}/${var.source_files.pickle_out}",
|
||||
"--variable-name ${var.source_files.pickle_src_var_name}"
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_storage_bucket_object" "dependencies" {
|
||||
name = "dependencies.tar.gz"
|
||||
bucket = local.bucket_name
|
||||
source = "${var.source_files.path}/${var.source_files.dependencies}"
|
||||
source_md5hash = filemd5("${var.source_files.path}/${var.source_files.dependencies}")
|
||||
}
|
||||
|
||||
resource "google_storage_bucket_object" "pickle_from_src" {
|
||||
count = var.generate_pickle ? 1 : 0
|
||||
name = "pickle.pkl"
|
||||
bucket = local.bucket_name
|
||||
source = "${var.source_files.path}/${var.source_files.pickle_out}"
|
||||
source_md5hash = filemd5("${var.source_files.path}/${var.source_files.pickle_out}")
|
||||
|
||||
depends_on = [
|
||||
null_resource.default
|
||||
]
|
||||
}
|
||||
|
||||
resource "google_storage_bucket_object" "pickle" {
|
||||
count = var.generate_pickle ? 0 : 1
|
||||
name = "pickle.pkl"
|
||||
bucket = local.bucket_name
|
||||
source = "${var.source_files.path}/${var.source_files.pickle_out}"
|
||||
source_md5hash = filemd5("${var.source_files.path}/${var.source_files.pickle_out}")
|
||||
}
|
||||
|
||||
resource "google_storage_bucket_object" "requirements" {
|
||||
name = "requirements.txt"
|
||||
bucket = local.bucket_name
|
||||
source = "${var.source_files.path}/${var.source_files.requirements}"
|
||||
source_md5hash = filemd5("${var.source_files.path}/${var.source_files.requirements}")
|
||||
}
|
||||
|
||||
resource "google_service_account" "default" {
|
||||
count = var.service_account_config.create ? 1 : 0
|
||||
account_id = coalesce(var.service_account_config.name, var.name)
|
||||
project = local.project_id
|
||||
display_name = "Agent Engine ${coalesce(var.service_account_config.name, var.name)}."
|
||||
}
|
||||
|
||||
resource "google_project_iam_member" "default" {
|
||||
for_each = (
|
||||
var.service_account_config.create
|
||||
? toset(local.service_account_roles)
|
||||
: toset([])
|
||||
)
|
||||
role = each.key
|
||||
project = local.project_id
|
||||
member = google_service_account.default[0].member
|
||||
}
|
||||
25
modules/agent-engine/outputs.tf
Normal file
25
modules/agent-engine/outputs.tf
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright 2025 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
output "id" {
|
||||
description = "Fully qualified Agent Engine id."
|
||||
value = google_vertex_ai_reasoning_engine.default.id
|
||||
}
|
||||
|
||||
output "service_account" {
|
||||
description = "Service account resource."
|
||||
value = try(google_service_account.default[0], null)
|
||||
}
|
||||
1
modules/agent-engine/tools/requirements.txt
Normal file
1
modules/agent-engine/tools/requirements.txt
Normal file
@@ -0,0 +1 @@
|
||||
cloudpickle
|
||||
95
modules/agent-engine/tools/serialize_agent.py
Normal file
95
modules/agent-engine/tools/serialize_agent.py
Normal file
@@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import argparse
|
||||
import cloudpickle
|
||||
import importlib.util
|
||||
import os
|
||||
import sys
|
||||
from google.adk.agents import LlmAgent
|
||||
|
||||
|
||||
def serialize_agent_from_file(input_file, variable_name, output_file):
|
||||
"""
|
||||
Dynamically loads a Python module from a full file path, accesses a
|
||||
top-level variable containing an agent object, and serializes that object
|
||||
to a specified output file.
|
||||
|
||||
Args:
|
||||
input_file (str): The full path to the Python source file.
|
||||
variable_name (str): The name of the variable holding the agent object.
|
||||
output_file (str): The full path for the output pickle file.
|
||||
"""
|
||||
try:
|
||||
output_dir = os.path.dirname(output_file)
|
||||
if output_dir and not os.path.isdir(output_dir):
|
||||
print(f"Error: The output directory '{output_dir}' does not exist.",
|
||||
file=sys.stderr)
|
||||
return
|
||||
|
||||
module_name = os.path.splitext(os.path.basename(input_file))[0]
|
||||
|
||||
spec = importlib.util.spec_from_file_location(module_name, input_file)
|
||||
if spec is None or spec.loader is None:
|
||||
print(f"Error: Could not import module from {input_file}",
|
||||
file=sys.stderr)
|
||||
return
|
||||
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
|
||||
spec.loader.exec_module(module)
|
||||
|
||||
local_agent = getattr(module, variable_name)
|
||||
|
||||
with open(output_file, "wb") as f:
|
||||
cloudpickle.dump(local_agent, f)
|
||||
|
||||
print(
|
||||
f"Successfully serialized '{variable_name}' from '{input_file}' to '{output_file}'"
|
||||
)
|
||||
|
||||
except FileNotFoundError:
|
||||
print(f"Error: The input file '{input_file}' was not found.",
|
||||
file=sys.stderr)
|
||||
except AttributeError:
|
||||
print(
|
||||
f"Error: The variable '{variable_name}' was not found in '{input_file}'.",
|
||||
file=sys.stderr)
|
||||
except Exception as e:
|
||||
print(f"An unexpected error occurred: {e}", file=sys.stderr)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(
|
||||
description=
|
||||
"Serialize a dynamically loaded agent from a variable in a specified file."
|
||||
)
|
||||
parser.add_argument(
|
||||
"input_file",
|
||||
help="The full path to the Python source file (e.g., 'my_agents/main.py')."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--variable-name", default="local_agent", help=
|
||||
"The name of the agent variable to serialize (default: 'local_agent').")
|
||||
parser.add_argument(
|
||||
"--output-file", default="pickle.pkl", help=
|
||||
"The full path for the output pickle file (e.g., 'output/agent.pkl'). Default is 'pickle.pkl' in the current directory."
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
serialize_agent_from_file(args.input_file, args.variable_name,
|
||||
args.output_file)
|
||||
124
modules/agent-engine/variables.tf
Normal file
124
modules/agent-engine/variables.tf
Normal file
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Copyright 2025 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
variable "agent_engine_config" {
|
||||
description = "The agent configuration."
|
||||
type = object({
|
||||
# Add validation once API stabilizes
|
||||
agent_framework = string
|
||||
class_methods = optional(list(any), [])
|
||||
environment_variables = optional(map(string), {})
|
||||
python_version = optional(string, "3.12")
|
||||
secret_environment_variables = optional(map(object({
|
||||
secret_id = string
|
||||
version = optional(string, "latest")
|
||||
})), {})
|
||||
})
|
||||
}
|
||||
|
||||
variable "bucket_config" {
|
||||
description = "The GCS bucket configuration."
|
||||
type = object({
|
||||
create = optional(bool, true)
|
||||
deletion_protection = optional(bool, true)
|
||||
name = optional(string)
|
||||
uniform_bucket_level_access = optional(bool, true)
|
||||
})
|
||||
nullable = false
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "context" {
|
||||
description = "Context-specific interpolations."
|
||||
type = object({
|
||||
custom_roles = optional(map(string), {})
|
||||
iam_principals = optional(map(string), {})
|
||||
locations = optional(map(string), {})
|
||||
kms_keys = optional(map(string), {})
|
||||
project_ids = optional(map(string), {})
|
||||
})
|
||||
nullable = false
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "description" {
|
||||
description = "The Agent Engine description."
|
||||
type = string
|
||||
nullable = false
|
||||
default = "Terraform managed."
|
||||
}
|
||||
|
||||
variable "encryption_key" {
|
||||
description = "The full resource name of the Cloud KMS CryptoKey."
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "generate_pickle" {
|
||||
description = "Generate the pickle file from a source file."
|
||||
type = bool
|
||||
nullable = false
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "name" {
|
||||
description = "The name of the agent."
|
||||
type = string
|
||||
nullable = false
|
||||
}
|
||||
|
||||
variable "project_id" {
|
||||
description = "The id of the project where to deploy the agent."
|
||||
type = string
|
||||
nullable = false
|
||||
}
|
||||
|
||||
variable "region" {
|
||||
description = "The region where to deploy the agent."
|
||||
type = string
|
||||
nullable = false
|
||||
}
|
||||
|
||||
variable "service_account_config" {
|
||||
description = "Service account configurations."
|
||||
type = object({
|
||||
create = optional(bool, true)
|
||||
email = optional(string)
|
||||
name = optional(string)
|
||||
roles = optional(list(string), [
|
||||
"roles/aiplatform.user",
|
||||
"roles/storage.objectViewer",
|
||||
# TODO: remove when b/441480710 is solved
|
||||
"roles/viewer"
|
||||
])
|
||||
})
|
||||
nullable = false
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "source_files" {
|
||||
description = "The to source files path and names."
|
||||
type = object({
|
||||
dependencies = optional(string, "dependencies.tar.gz")
|
||||
path = optional(string, "./src")
|
||||
pickle_out = optional(string, "pickle.pkl")
|
||||
pickle_src = optional(string, "agent.py")
|
||||
pickle_src_var_name = optional(string, "local_agent")
|
||||
requirements = optional(string, "requirements.txt")
|
||||
})
|
||||
nullable = false
|
||||
default = {}
|
||||
}
|
||||
35
modules/agent-engine/versions.tf
generated
Normal file
35
modules/agent-engine/versions.tf
generated
Normal file
@@ -0,0 +1,35 @@
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# Fabric release: v45.0.0
|
||||
|
||||
terraform {
|
||||
required_version = ">= 1.12.2"
|
||||
required_providers {
|
||||
google = {
|
||||
source = "hashicorp/google"
|
||||
version = ">= 7.6.0, < 8.0.0" # tftest
|
||||
}
|
||||
google-beta = {
|
||||
source = "hashicorp/google-beta"
|
||||
version = ">= 7.6.0, < 8.0.0" # tftest
|
||||
}
|
||||
}
|
||||
provider_meta "google" {
|
||||
module_name = "google-pso-tool/cloud-foundation-fabric/modules/ai-applications:v45.0.0-tf"
|
||||
}
|
||||
provider_meta "google-beta" {
|
||||
module_name = "google-pso-tool/cloud-foundation-fabric/modules/ai-applications:v45.0.0-tf"
|
||||
}
|
||||
}
|
||||
35
modules/agent-engine/versions.tofu
generated
Normal file
35
modules/agent-engine/versions.tofu
generated
Normal file
@@ -0,0 +1,35 @@
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# Fabric release: v45.0.0
|
||||
|
||||
terraform {
|
||||
required_version = ">= 1.10.0"
|
||||
required_providers {
|
||||
google = {
|
||||
source = "hashicorp/google"
|
||||
version = ">= 7.6.0, < 8.0.0" # tftest
|
||||
}
|
||||
google-beta = {
|
||||
source = "hashicorp/google-beta"
|
||||
version = ">= 7.6.0, < 8.0.0" # tftest
|
||||
}
|
||||
}
|
||||
provider_meta "google" {
|
||||
module_name = "google-pso-tool/cloud-foundation-fabric/modules/ai-applications:v45.0.0-tofu"
|
||||
}
|
||||
provider_meta "google-beta" {
|
||||
module_name = "google-pso-tool/cloud-foundation-fabric/modules/ai-applications:v45.0.0-tofu"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user