Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## [Unreleased]

### Bug Fixes
* Sanitize Agent Engine temp folder names to avoid invalid module imports.
* Fix Agent Engine template imports for agents in an app/ subdirectory.

## [1.23.0](https://github.com/google/adk-python/compare/v1.22.1...v1.23.0) (2026-01-22)

### ⚠ BREAKING CHANGES
Expand Down Expand Up @@ -82,8 +88,6 @@
* Upgrade the sample BigQuery agent model version to `gemini-2.5-flash` ([fd2c0f5](https://github.com/google/adk-python/commit/fd2c0f556b786417a9f6add744827b07e7a06b7d))
* Import `migration_runner` lazily within the migrate command ([905604f](https://github.com/google/adk-python/commit/905604faac82aca8ae0935eebea288f82985e9c5))



## [1.22.1](https://github.com/google/adk-python/compare/v1.22.0...v1.22.1) (2026-01-09)

### Bug Fixes
Expand Down
28 changes: 26 additions & 2 deletions src/google/adk/cli/cli_deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,17 @@
)


def _sanitize_temp_folder_name(folder_name: str) -> str:
if not folder_name:
return folder_name
sanitized = ''.join(
char if char.isalnum() or char == '_' else '_' for char in folder_name
)
if sanitized and sanitized[0].isdigit():
return '_' + sanitized
return sanitized


def _ensure_agent_engine_dependency(requirements_txt_path: str) -> None:
"""Ensures staged requirements include Agent Engine dependencies."""
if not os.path.exists(requirements_txt_path):
Expand Down Expand Up @@ -107,7 +118,7 @@ def _ensure_agent_engine_dependency(requirements_txt_path: str) -> None:
from google.adk.agents import config_agent_utils
root_agent = config_agent_utils.from_config("{agent_folder}/root_agent.yaml")
else:
from .agent import {adk_app_object}
from {adk_app_import_module} import {adk_app_object}

if {express_mode}: # Whether or not to use Express Mode
vertexai.init(api_key=os.environ.get("GOOGLE_API_KEY"))
Expand Down Expand Up @@ -789,7 +800,8 @@ def to_agent_engine(
os.chdir(parent_folder)
did_change_cwd = True
tmp_app_name = app_name + '_tmp' + datetime.now().strftime('%Y%m%d_%H%M%S')
temp_folder = temp_folder or tmp_app_name
raw_temp_folder = temp_folder or tmp_app_name
temp_folder = _sanitize_temp_folder_name(raw_temp_folder)
agent_src_path = os.path.join(parent_folder, temp_folder)
click.echo(f'Staging all files in: {agent_src_path}')
# remove agent_src_path if it exists
Expand Down Expand Up @@ -953,6 +965,17 @@ def to_agent_engine(
is_config_agent = True

adk_app_file = os.path.join(temp_folder, f'{adk_app}.py')
app_subdir_agent = os.path.join(agent_src_path, 'app', 'agent.py')
app_subdir_init = os.path.join(agent_src_path, 'app', '__init__.py')
root_agent_file = os.path.join(agent_src_path, 'agent.py')
if (
os.path.exists(app_subdir_agent)
and os.path.exists(app_subdir_init)
and not os.path.exists(root_agent_file)
):
adk_app_import_module = '.app.agent'
else:
adk_app_import_module = '.agent'
if adk_app_object == 'root_agent':
adk_app_type = 'agent'
elif adk_app_object == 'app':
Expand All @@ -972,6 +995,7 @@ def to_agent_engine(
agent_folder=f'./{temp_folder}',
adk_app_object=adk_app_object,
adk_app_type=adk_app_type,
adk_app_import_module=adk_app_import_module,
express_mode=api_key is not None,
)
)
Expand Down