Skip to content
20 changes: 16 additions & 4 deletions src/google/adk/cli/cli_deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ def _ensure_agent_engine_dependency(requirements_txt_path: str) -> None:
config_path = os.path.join(os.path.dirname(__file__), "root_agent.yaml")
root_agent = config_agent_utils.from_config(config_path)
else:
from .agent import {adk_app_object}
from .{agent_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 @@ -473,6 +473,7 @@ def _validate_agent_import(
agent_src_path: str,
adk_app_object: str,
is_config_agent: bool,
agent_module: str = 'agent',
) -> None:
"""Validates that the agent module can be imported successfully.

Expand All @@ -485,6 +486,8 @@ def _validate_agent_import(
agent_src_path: Path to the staged agent source code.
adk_app_object: The Python object name to import ('root_agent' or 'app').
is_config_agent: Whether this is a config-based agent.
agent_module: The Python module name containing the agent object.
Defaults to 'agent'.

Raises:
click.ClickException: If the agent module cannot be imported.
Expand All @@ -493,11 +496,12 @@ def _validate_agent_import(
# Config agents are loaded from YAML, skip Python import validation
return

agent_module_path = os.path.join(agent_src_path, 'agent.py')
agent_module_path = os.path.join(agent_src_path, f'{agent_module}.py')
if not os.path.exists(agent_module_path):
raise click.ClickException(
f'Agent module not found at {agent_module_path}. '
'Please ensure your agent folder contains an agent.py file.'
f'Please ensure your agent folder contains a {agent_module}.py file,'
' or use --agent_module to specify a different module name.'
)

# Add the parent directory to sys.path temporarily for import resolution
Expand Down Expand Up @@ -836,6 +840,7 @@ def to_agent_engine(
otel_to_cloud: Optional[bool] = None,
api_key: Optional[str] = None,
adk_app_object: Optional[str] = None,
agent_module: Optional[str] = None,
agent_engine_id: Optional[str] = None,
absolutize_imports: bool = True,
project: Optional[str] = None,
Expand Down Expand Up @@ -886,6 +891,9 @@ def to_agent_engine(
will be used. It will only be used if GOOGLE_GENAI_USE_VERTEXAI is true.
adk_app_object (str): Optional. The Python object corresponding to the root
ADK agent or app. Defaults to `root_agent` if not specified.
agent_module (str): Optional. The Python module name (without .py) that
contains the agent object. Defaults to `agent`. Use this when your entry
point is not named `agent.py` (e.g., `core.py` or `adk_agent.py`).
agent_engine_id (str): Optional. The ID of the Agent Engine instance to
update. If not specified, a new Agent Engine instance will be created.
absolutize_imports (bool): Optional. Default is True. Whether to absolutize
Expand Down Expand Up @@ -918,6 +926,7 @@ def to_agent_engine(
display_name = display_name or app_name
parent_folder = os.path.dirname(agent_folder)
adk_app_object = adk_app_object or 'root_agent'
agent_module = agent_module or 'agent'
if adk_app_object not in ['root_agent', 'app']:
click.echo(
f'Invalid adk_app_object: {adk_app_object}. Please use "root_agent"'
Expand Down Expand Up @@ -1123,7 +1132,9 @@ def to_agent_engine(
# Validate that the agent module can be imported before deployment.
if not skip_agent_import_validation:
click.echo('Validating agent module...')
_validate_agent_import(agent_src_path, adk_app_object, is_config_agent)
_validate_agent_import(
agent_src_path, adk_app_object, is_config_agent, agent_module
)

adk_app_file = os.path.join(temp_folder, f'{adk_app}.py')
if adk_app_object == 'root_agent':
Expand All @@ -1144,6 +1155,7 @@ def to_agent_engine(
is_config_agent=is_config_agent,
agent_folder=f'./{temp_folder}',
adk_app_object=adk_app_object,
agent_module=agent_module,
adk_app_type=adk_app_type,
express_mode=api_key is not None,
)
Expand Down
14 changes: 13 additions & 1 deletion src/google/adk/cli/cli_tools_click.py
Original file line number Diff line number Diff line change
Expand Up @@ -2197,6 +2197,16 @@ def cli_migrate_session(
" It can only be `root_agent` or `app`. (default: `root_agent`)"
),
)
@click.option(
"--agent_module",
type=str,
default=None,
help=(
"Optional. Python module name (without .py) containing the agent"
" object. Use this when your entry point is not named `agent.py`"
" (e.g. `core` or `adk_agent`). (default: `agent`)"
),
)
@click.option(
"--env_file",
type=str,
Expand Down Expand Up @@ -2271,14 +2281,15 @@ def cli_deploy_agent_engine(
description: str,
adk_app: str,
adk_app_object: Optional[str],
agent_module: Optional[str],
temp_folder: Optional[str],
env_file: str,
requirements_file: str,
absolutize_imports: bool,
agent_engine_config_file: str,
validate_agent_import: bool = False,
skip_agent_import_validation_alias: bool = False,
):
) -> None:
"""Deploys an agent to Agent Engine.

Example:
Expand Down Expand Up @@ -2308,6 +2319,7 @@ def cli_deploy_agent_engine(
otel_to_cloud=otel_to_cloud,
api_key=api_key,
adk_app_object=adk_app_object,
agent_module=agent_module,
display_name=display_name,
description=description,
adk_app=adk_app,
Expand Down
1 change: 1 addition & 0 deletions tests/unittests/cli/utils/test_cli_deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ def test_agent_engine_app_template_compiles_with_windows_paths() -> None:
adk_app_type="agent",
trace_to_cloud_option=False,
express_mode=False,
agent_module="agent",
)
compile(rendered, "<agent_engine_app.py>", "exec")

Expand Down