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
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 @@ -818,6 +822,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 @@ -868,6 +873,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 @@ -900,6 +908,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 @@ -1105,7 +1114,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 @@ -1126,6 +1137,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