Skip to content

Commit 5df38a7

Browse files
authored
feat: add Agent engine session in Cloud Run (#275)
1 parent b36516f commit 5df38a7

21 files changed

+2851
-2846
lines changed

.cloudbuild/terraform/build_triggers.tf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ locals {
9898
name = "adk_base-cloud_run-alloydb"
9999
value = "adk_base,cloud_run,--session-type,alloydb"
100100
},
101+
{
102+
name = "adk_base-cloud_run-agent_engine"
103+
value = "adk_base,cloud_run,--session-type,agent_engine"
104+
},
101105
]
102106

103107
agent_testing_included_files = { for combo in local.agent_testing_combinations :

agents/adk_base/.template/templateconfig.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ settings:
1818
requires_data_ingestion: false
1919
requires_session: true
2020
deployment_targets: ["agent_engine", "cloud_run"]
21-
extra_dependencies: ["google-adk~=1.6.0"]
21+
extra_dependencies: ["google-adk~=1.8.0"]
2222
tags: ["adk"]
2323
frontend_type: "None"
2424

agents/adk_gemini_fullstack/.template/templateconfig.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ settings:
1818
requires_data_ingestion: false
1919
requires_session: true
2020
deployment_targets: ["agent_engine", "cloud_run"]
21-
extra_dependencies: ["google-adk~=1.6.0"]
21+
extra_dependencies: ["google-adk~=1.8.0"]
2222
tags: ["adk"]
2323
frontend_type: "adk_gemini_fullstack"
2424
commands:

agents/agentic_rag/.template/templateconfig.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ settings:
1919
requires_session: true
2020
deployment_targets: ["agent_engine", "cloud_run"]
2121
extra_dependencies: [
22-
"google-adk~=1.6.0",
22+
"google-adk~=1.8.0",
2323
"langchain-google-vertexai~=2.0.7",
2424
"langchain~=0.3.24",
2525
"langchain-core~=0.3.55",

docs/cli/create.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ The following options will be prompted interactively if not provided via the com
2222
- `--deployment-target`, `-d`: Deployment target (`agent_engine` or `cloud_run`). Prompts if omitted.
2323
- `--datastore`, `-ds`: Datastore for RAG agents (`vertex_ai_search` or `vertex_ai_vector_search`). Prompted if `--include-data-ingestion` is specified, or if the selected agent (e.g., `agentic_rag`) requires data ingestion, and this option is omitted.
2424
- `--region`: GCP region for deployment (default: `us-central1`). Prompts for confirmation if not specified and `--auto-approve` is not used.
25-
- `--session-type`: Type of session storage to use (`in_memory` or `alloydb`). This is only applicable for agents that require session management and when the deployment target is `cloud_run`.
25+
- `--session-type`: Type of session storage to use (`in_memory`, `alloydb`, or `agent_engine`). This is only applicable for agents that require session management and when the deployment target is `cloud_run`.
2626

2727
GCP account and project ID are detected automatically (using your active `gcloud config` settings). You will be prompted to confirm or change them unless `--auto-approve` is used.
2828

llm.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ agent-starter-pack create PROJECT_NAME [OPTIONS]
6969
* `-d, --deployment-target`: Target deployment environment (`cloud_run` or `agent_engine`).
7070
* `-ds, --datastore`: For RAG agents, the datastore (`vertex_ai_search` or `vertex_ai_vector_search`).
7171
* `-i, --include-data-ingestion`: Include data ingestion pipeline scaffolding.
72-
* `--session-type`: For agents requiring session management on Cloud Run, specifies the storage type (`in_memory` or `alloydb`).
72+
* `--session-type`: For agents requiring session management on Cloud Run, specifies the storage type (`in_memory`, `alloydb`, `agent_engine`).
7373
* `--region`: GCP region (e.g., `us-central1`).
7474
* `--auto-approve`: **Skips all interactive prompts (crucial for automation).**
7575
* `--debug`: Enables debug logging during creation.

src/cli/commands/create.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ def normalize_project_name(project_name: str) -> str:
116116
)
117117
@click.option(
118118
"--session-type",
119-
type=click.Choice(["in_memory", "alloydb"]),
119+
type=click.Choice(["in_memory", "alloydb", "agent_engine"]),
120120
help="Type of session storage to use",
121121
)
122122
@click.option("--debug", is_flag=True, help="Enable debug logging")

src/cli/utils/template.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,10 @@ def prompt_session_type_selection() -> str:
230230
"display_name": "AlloyDB",
231231
"description": "Use AlloyDB for session management. Comes with terraform resources for deployment.",
232232
},
233+
"agent_engine": {
234+
"display_name": "Vertex AI Agent Engine",
235+
"description": "Managed session service that automatically handles conversation history",
236+
},
233237
}
234238

235239
console.print("\n> Please select a session type:")

src/deployment_targets/cloud_run/app/server.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
from google.cloud import logging as google_cloud_logging
2121
from opentelemetry import trace
2222
from opentelemetry.sdk.trace import TracerProvider, export
23+
{%- if cookiecutter.session_type == "agent_engine" %}
24+
from vertexai import agent_engines
25+
{%- endif %}
2326

2427
from app.utils.gcs import create_bucket_if_not_exists
2528
from app.utils.tracing import CloudTraceLoggingSpanExporter
@@ -55,6 +58,22 @@
5558
session_service_uri = None
5659
if db_host and db_pass:
5760
session_service_uri = f"postgresql://{db_user}:{db_pass}@{db_host}:5432/{db_name}"
61+
{%- elif cookiecutter.session_type == "agent_engine" %}
62+
# Agent Engine session configuration
63+
# Use environment variable for agent name, default to project name
64+
agent_name = os.environ.get("AGENT_ENGINE_SESSION_NAME", "{{cookiecutter.project_name}}")
65+
66+
# Check if an agent with this name already exists
67+
existing_agents = list(agent_engines.list(filter=f"display_name={agent_name}"))
68+
69+
if existing_agents:
70+
# Use the existing agent
71+
agent_engine = existing_agents[0]
72+
else:
73+
# Create a new agent if none exists
74+
agent_engine = agent_engines.create(display_name=agent_name)
75+
76+
session_service_uri = f"agentengine://{agent_engine.resource_name}"
5877
{%- else %}
5978
# In-memory session configuration - no persistent storage
6079
session_service_uri = None

src/deployment_targets/cloud_run/tests/integration/test_server_e2e.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ def start_server() -> subprocess.Popen[str]:
6262
]
6363
env = os.environ.copy()
6464
env["INTEGRATION_TEST"] = "TRUE"
65+
{%- if cookiecutter.session_type == "agent_engine" %}
66+
# Set test-specific agent engine session name
67+
env["AGENT_ENGINE_SESSION_NAME"] = "test-{{cookiecutter.project_name}}"
68+
{%- endif %}
6569
process = subprocess.Popen(
6670
command,
6771
stdout=subprocess.PIPE,
@@ -250,3 +254,34 @@ def test_collect_feedback(server_fixture: subprocess.Popen[str]) -> None:
250254
FEEDBACK_URL, json=feedback_data, headers=HEADERS, timeout=10
251255
)
252256
assert response.status_code == 200
257+
{%- if cookiecutter.session_type == "agent_engine" %}
258+
259+
260+
@pytest.fixture(scope="session", autouse=True)
261+
def cleanup_agent_engine_sessions() -> None:
262+
"""Cleanup agent engine sessions created during tests."""
263+
yield # Run tests first
264+
265+
# Cleanup after tests complete
266+
from vertexai import agent_engines
267+
268+
try:
269+
# Use same environment variable as server, default to project name
270+
agent_name = os.environ.get(
271+
"AGENT_ENGINE_SESSION_NAME", "{{cookiecutter.project_name}}"
272+
)
273+
274+
# Find and delete agent engines with this name
275+
existing_agents = list(agent_engines.list(filter=f"display_name={agent_name}"))
276+
277+
for agent_engine in existing_agents:
278+
try:
279+
agent_engines.delete(resource_name=agent_engine.name)
280+
logger.info(f"Cleaned up agent engine: {agent_engine.name}")
281+
except Exception as e:
282+
logger.warning(
283+
f"Failed to cleanup agent engine {agent_engine.name}: {e}"
284+
)
285+
except Exception as e:
286+
logger.warning(f"Failed to cleanup agent engine sessions: {e}")
287+
{%- endif %}

0 commit comments

Comments
 (0)