agent-starter-pack 0.11.2__py3-none-any.whl → 0.12.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {agent_starter_pack-0.11.2.dist-info → agent_starter_pack-0.12.1.dist-info}/METADATA +2 -1
- {agent_starter_pack-0.11.2.dist-info → agent_starter_pack-0.12.1.dist-info}/RECORD +51 -78
- agents/adk_base/app/__init__.py +17 -0
- agents/adk_base/notebooks/adk_app_testing.ipynb +4 -1
- agents/adk_base/tests/integration/test_agent.py +1 -1
- agents/agentic_rag/app/__init__.py +17 -0
- agents/agentic_rag/app/agent.py +2 -2
- agents/agentic_rag/notebooks/adk_app_testing.ipynb +4 -1
- agents/agentic_rag/tests/integration/test_agent.py +2 -2
- agents/crewai_coding_crew/tests/integration/test_agent.py +1 -1
- agents/langgraph_base_react/tests/integration/test_agent.py +1 -1
- agents/live_api/tests/unit/test_server.py +6 -6
- llm.txt +15 -4
- src/base_template/Makefile +5 -5
- src/base_template/README.md +4 -4
- src/base_template/deployment/terraform/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}build_triggers.tf{% else %}unused_build_triggers.tf{% endif %} +2 -2
- src/base_template/pyproject.toml +2 -2
- src/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/deploy-to-prod.yaml +1 -1
- src/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/pr_checks.yaml +1 -1
- src/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/staging.yaml +2 -2
- src/base_template/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}.cloudbuild{% else %}unused_.cloudbuild{% endif %}/deploy-to-prod.yaml +1 -1
- src/base_template/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}.cloudbuild{% else %}unused_.cloudbuild{% endif %}/staging.yaml +1 -1
- src/cli/commands/create.py +30 -2
- src/cli/commands/enhance.py +98 -15
- src/cli/commands/list.py +6 -1
- src/cli/utils/remote_template.py +5 -1
- src/cli/utils/template.py +120 -41
- src/deployment_targets/agent_engine/tests/integration/test_agent_engine_app.py +3 -3
- src/deployment_targets/agent_engine/{app → {{cookiecutter.agent_directory}}}/agent_engine_app.py +10 -10
- src/deployment_targets/cloud_run/Dockerfile +2 -2
- src/deployment_targets/cloud_run/tests/integration/test_server_e2e.py +3 -3
- src/deployment_targets/cloud_run/tests/load_test/README.md +1 -1
- src/deployment_targets/cloud_run/tests/load_test/load_test.py +2 -2
- {agents/live_api/app → src/deployment_targets/cloud_run/{{cookiecutter.agent_directory}}}/server.py +186 -7
- src/frontends/live_api_react/frontend/package-lock.json +9 -9
- src/resources/docs/adk-cheatsheet.md +3 -3
- src/resources/locks/uv-adk_base-agent_engine.lock +452 -452
- src/resources/locks/uv-adk_base-cloud_run.lock +571 -568
- src/resources/locks/uv-agentic_rag-agent_engine.lock +565 -566
- src/resources/locks/uv-agentic_rag-cloud_run.lock +716 -713
- src/resources/locks/uv-crewai_coding_crew-agent_engine.lock +729 -735
- src/resources/locks/uv-crewai_coding_crew-cloud_run.lock +923 -940
- src/resources/locks/uv-langgraph_base_react-agent_engine.lock +658 -664
- src/resources/locks/uv-langgraph_base_react-cloud_run.lock +852 -869
- src/resources/locks/uv-live_api-cloud_run.lock +758 -775
- src/base_template/app/__init__.py +0 -3
- src/deployment_targets/cloud_run/app/server.py +0 -206
- src/frontends/adk_gemini_fullstack/frontend/components.json +0 -21
- src/frontends/adk_gemini_fullstack/frontend/eslint.config.js +0 -28
- src/frontends/adk_gemini_fullstack/frontend/index.html +0 -12
- src/frontends/adk_gemini_fullstack/frontend/package-lock.json +0 -6105
- src/frontends/adk_gemini_fullstack/frontend/package.json +0 -47
- src/frontends/adk_gemini_fullstack/frontend/src/App.tsx +0 -564
- src/frontends/adk_gemini_fullstack/frontend/src/components/ActivityTimeline.tsx +0 -244
- src/frontends/adk_gemini_fullstack/frontend/src/components/ChatMessagesView.tsx +0 -420
- src/frontends/adk_gemini_fullstack/frontend/src/components/InputForm.tsx +0 -60
- src/frontends/adk_gemini_fullstack/frontend/src/components/WelcomeScreen.tsx +0 -56
- src/frontends/adk_gemini_fullstack/frontend/src/components/ui/badge.tsx +0 -46
- src/frontends/adk_gemini_fullstack/frontend/src/components/ui/button.tsx +0 -59
- src/frontends/adk_gemini_fullstack/frontend/src/components/ui/card.tsx +0 -92
- src/frontends/adk_gemini_fullstack/frontend/src/components/ui/input.tsx +0 -21
- src/frontends/adk_gemini_fullstack/frontend/src/components/ui/scroll-area.tsx +0 -56
- src/frontends/adk_gemini_fullstack/frontend/src/components/ui/select.tsx +0 -183
- src/frontends/adk_gemini_fullstack/frontend/src/components/ui/tabs.tsx +0 -64
- src/frontends/adk_gemini_fullstack/frontend/src/components/ui/textarea.tsx +0 -18
- src/frontends/adk_gemini_fullstack/frontend/src/global.css +0 -154
- src/frontends/adk_gemini_fullstack/frontend/src/main.tsx +0 -13
- src/frontends/adk_gemini_fullstack/frontend/src/utils.ts +0 -7
- src/frontends/adk_gemini_fullstack/frontend/src/vite-env.d.ts +0 -1
- src/frontends/adk_gemini_fullstack/frontend/tsconfig.json +0 -28
- src/frontends/adk_gemini_fullstack/frontend/tsconfig.node.json +0 -24
- src/frontends/adk_gemini_fullstack/frontend/vite.config.ts +0 -41
- src/resources/locks/uv-adk_gemini_fullstack-agent_engine.lock +0 -3938
- src/resources/locks/uv-adk_gemini_fullstack-cloud_run.lock +0 -4501
- {agent_starter_pack-0.11.2.dist-info → agent_starter_pack-0.12.1.dist-info}/WHEEL +0 -0
- {agent_starter_pack-0.11.2.dist-info → agent_starter_pack-0.12.1.dist-info}/entry_points.txt +0 -0
- {agent_starter_pack-0.11.2.dist-info → agent_starter_pack-0.12.1.dist-info}/licenses/LICENSE +0 -0
- /src/base_template/{app → {{cookiecutter.agent_directory}}}/utils/gcs.py +0 -0
- /src/base_template/{app → {{cookiecutter.agent_directory}}}/utils/tracing.py +0 -0
- /src/base_template/{app → {{cookiecutter.agent_directory}}}/utils/typing.py +0 -0
@@ -108,7 +108,7 @@ steps:
|
|
108
108
|
- "-c"
|
109
109
|
- |
|
110
110
|
uv export --no-hashes --no-sources --no-header --no-dev --no-emit-project --no-annotate --locked > .requirements.txt
|
111
|
-
uv run
|
111
|
+
uv run {{cookiecutter.agent_directory}}/agent_engine_app.py \
|
112
112
|
--project ${_STAGING_PROJECT_ID} \
|
113
113
|
--location ${_REGION} \
|
114
114
|
--service-account ${_APP_SA_EMAIL_STAGING} \
|
src/cli/commands/create.py
CHANGED
@@ -18,12 +18,17 @@ import os
|
|
18
18
|
import pathlib
|
19
19
|
import shutil
|
20
20
|
import subprocess
|
21
|
+
import sys
|
21
22
|
import tempfile
|
22
23
|
from collections.abc import Callable
|
23
24
|
|
24
25
|
import click
|
25
|
-
import tomllib
|
26
26
|
from click.core import ParameterSource
|
27
|
+
|
28
|
+
if sys.version_info >= (3, 11):
|
29
|
+
import tomllib
|
30
|
+
else:
|
31
|
+
import tomli as tomllib
|
27
32
|
from rich.console import Console
|
28
33
|
from rich.prompt import IntPrompt, Prompt
|
29
34
|
|
@@ -101,6 +106,11 @@ def shared_template_options(f: Callable) -> Callable:
|
|
101
106
|
type=click.Choice(["agent_engine", "cloud_run"]),
|
102
107
|
help="Deployment target name",
|
103
108
|
)(f)
|
109
|
+
f = click.option(
|
110
|
+
"--agent-directory",
|
111
|
+
"-dir",
|
112
|
+
help="Name of the agent directory (overrides template default)",
|
113
|
+
)(f)
|
104
114
|
return f
|
105
115
|
|
106
116
|
|
@@ -232,8 +242,10 @@ def create(
|
|
232
242
|
region: str,
|
233
243
|
skip_checks: bool,
|
234
244
|
in_folder: bool,
|
245
|
+
agent_directory: str | None,
|
235
246
|
base_template: str | None = None,
|
236
247
|
skip_welcome: bool = False,
|
248
|
+
cli_overrides: dict | None = None,
|
237
249
|
) -> None:
|
238
250
|
"""Create GCP-based AI agent projects from templates."""
|
239
251
|
try:
|
@@ -434,6 +446,14 @@ def create(
|
|
434
446
|
/ ".template"
|
435
447
|
)
|
436
448
|
config = load_template_config(template_path)
|
449
|
+
|
450
|
+
# Apply CLI overrides for local templates if provided (e.g., from enhance command)
|
451
|
+
if cli_overrides:
|
452
|
+
config = merge_template_configs(config, cli_overrides)
|
453
|
+
if debug:
|
454
|
+
logging.debug(
|
455
|
+
f"Applied CLI overrides to local template config: {cli_overrides}"
|
456
|
+
)
|
437
457
|
# Data ingestion and datastore selection
|
438
458
|
if include_data_ingestion or datastore:
|
439
459
|
include_data_ingestion = True
|
@@ -610,6 +630,13 @@ def create(
|
|
610
630
|
if debug:
|
611
631
|
logging.debug(f"Output directory: {destination_dir}")
|
612
632
|
|
633
|
+
# Construct CLI overrides for template processing
|
634
|
+
final_cli_overrides = cli_overrides or {}
|
635
|
+
if agent_directory:
|
636
|
+
if "settings" not in final_cli_overrides:
|
637
|
+
final_cli_overrides["settings"] = {}
|
638
|
+
final_cli_overrides["settings"]["agent_directory"] = agent_directory
|
639
|
+
|
613
640
|
try:
|
614
641
|
# Process template (handles both local and remote templates)
|
615
642
|
process_template(
|
@@ -623,8 +650,9 @@ def create(
|
|
623
650
|
session_type=final_session_type,
|
624
651
|
output_dir=destination_dir,
|
625
652
|
remote_template_path=template_source_path,
|
626
|
-
remote_config=config
|
653
|
+
remote_config=config,
|
627
654
|
in_folder=in_folder,
|
655
|
+
cli_overrides=final_cli_overrides,
|
628
656
|
)
|
629
657
|
|
630
658
|
# Replace region in all files if a different region was specified
|
src/cli/commands/enhance.py
CHANGED
@@ -13,11 +13,18 @@
|
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
15
|
import pathlib
|
16
|
+
import sys
|
17
|
+
from typing import Any
|
16
18
|
|
17
19
|
import click
|
18
20
|
from rich.console import Console
|
19
21
|
from rich.prompt import IntPrompt
|
20
22
|
|
23
|
+
if sys.version_info >= (3, 11):
|
24
|
+
import tomllib
|
25
|
+
else:
|
26
|
+
import tomli as tomllib
|
27
|
+
|
21
28
|
from ..utils.logging import display_welcome_banner, handle_cli_error
|
22
29
|
from ..utils.template import get_available_agents
|
23
30
|
from .create import (
|
@@ -48,7 +55,7 @@ def display_base_template_selection(current_base: str) -> str:
|
|
48
55
|
choice_num = 1
|
49
56
|
current_choice = None
|
50
57
|
|
51
|
-
for
|
58
|
+
for agent in agents.values():
|
52
59
|
template_choices[choice_num] = agent["name"]
|
53
60
|
current_indicator = " (current)" if agent["name"] == current_base else ""
|
54
61
|
console.print(
|
@@ -89,6 +96,10 @@ def display_base_template_selection(current_base: str) -> str:
|
|
89
96
|
"--base-template",
|
90
97
|
help="Base template to inherit from (e.g., adk_base, langgraph_base_react, agentic_rag)",
|
91
98
|
)
|
99
|
+
@click.option(
|
100
|
+
"--agent-directory",
|
101
|
+
help="Custom directory name for agent files (default: 'app' or auto-detected from pyproject.toml)",
|
102
|
+
)
|
92
103
|
@shared_template_options
|
93
104
|
@handle_cli_error
|
94
105
|
def enhance(
|
@@ -105,6 +116,7 @@ def enhance(
|
|
105
116
|
region: str,
|
106
117
|
skip_checks: bool,
|
107
118
|
base_template: str | None,
|
119
|
+
agent_directory: str | None,
|
108
120
|
) -> None:
|
109
121
|
"""Enhance your existing project with AI agent capabilities.
|
110
122
|
|
@@ -113,7 +125,8 @@ def enhance(
|
|
113
125
|
creating a new project directory.
|
114
126
|
|
115
127
|
For best compatibility, your project should follow the agent-starter-pack structure
|
116
|
-
with agent code organized in an
|
128
|
+
with agent code organized in an agent directory (default: /app, configurable via
|
129
|
+
--agent-directory).
|
117
130
|
|
118
131
|
TEMPLATE_PATH can be:
|
119
132
|
- A local directory path (e.g., . for current directory)
|
@@ -191,10 +204,13 @@ def enhance(
|
|
191
204
|
load_remote_template_config,
|
192
205
|
)
|
193
206
|
|
194
|
-
# Prepare CLI overrides for base template
|
195
|
-
cli_overrides = {}
|
207
|
+
# Prepare CLI overrides for base template and agent directory
|
208
|
+
cli_overrides: dict[str, Any] = {}
|
196
209
|
if base_template:
|
197
210
|
cli_overrides["base_template"] = base_template
|
211
|
+
if agent_directory:
|
212
|
+
cli_overrides["settings"] = cli_overrides.get("settings", {})
|
213
|
+
cli_overrides["settings"]["agent_directory"] = agent_directory
|
198
214
|
|
199
215
|
# Load config from current directory for inheritance info
|
200
216
|
current_dir = pathlib.Path.cwd()
|
@@ -209,6 +225,10 @@ def enhance(
|
|
209
225
|
if selected_base_template != original_base_template_name:
|
210
226
|
# Update CLI overrides with the selected base template
|
211
227
|
cli_overrides["base_template"] = selected_base_template
|
228
|
+
# Preserve agent_directory override if it was set
|
229
|
+
if agent_directory:
|
230
|
+
cli_overrides["settings"] = cli_overrides.get("settings", {})
|
231
|
+
cli_overrides["settings"]["agent_directory"] = agent_directory
|
212
232
|
base_template = selected_base_template
|
213
233
|
console.print(
|
214
234
|
f"✅ Selected base template: [cyan]{selected_base_template}[/cyan]"
|
@@ -232,9 +252,51 @@ def enhance(
|
|
232
252
|
# Validate project structure when using current directory template
|
233
253
|
if template_path == pathlib.Path("."):
|
234
254
|
current_dir = pathlib.Path.cwd()
|
235
|
-
app_folder = current_dir / "app"
|
236
255
|
|
237
|
-
|
256
|
+
# Determine agent directory: CLI param > pyproject.toml detection > default
|
257
|
+
detected_agent_directory = "app" # default
|
258
|
+
if not agent_directory: # Only try to detect if not provided via CLI
|
259
|
+
pyproject_path = current_dir / "pyproject.toml"
|
260
|
+
if pyproject_path.exists():
|
261
|
+
try:
|
262
|
+
with open(pyproject_path, "rb") as f:
|
263
|
+
pyproject_data = tomllib.load(f)
|
264
|
+
packages = (
|
265
|
+
pyproject_data.get("tool", {})
|
266
|
+
.get("hatch", {})
|
267
|
+
.get("build", {})
|
268
|
+
.get("targets", {})
|
269
|
+
.get("wheel", {})
|
270
|
+
.get("packages", [])
|
271
|
+
)
|
272
|
+
if packages:
|
273
|
+
# Find the first package that isn't 'frontend'
|
274
|
+
for pkg in packages:
|
275
|
+
if pkg != "frontend":
|
276
|
+
detected_agent_directory = pkg
|
277
|
+
break
|
278
|
+
except Exception as e:
|
279
|
+
if debug:
|
280
|
+
console.print(
|
281
|
+
f"[dim]Could not auto-detect agent directory: {e}[/dim]"
|
282
|
+
)
|
283
|
+
pass # Fall back to default
|
284
|
+
|
285
|
+
final_agent_directory = agent_directory or detected_agent_directory
|
286
|
+
|
287
|
+
# Show info about agent directory selection
|
288
|
+
if agent_directory:
|
289
|
+
console.print(
|
290
|
+
f"ℹ️ Using CLI-specified agent directory: [cyan]{agent_directory}[/cyan]"
|
291
|
+
)
|
292
|
+
elif detected_agent_directory != "app":
|
293
|
+
console.print(
|
294
|
+
f"ℹ️ Auto-detected agent directory: [cyan]{detected_agent_directory}[/cyan]"
|
295
|
+
)
|
296
|
+
|
297
|
+
agent_folder = current_dir / final_agent_directory
|
298
|
+
|
299
|
+
if not agent_folder.exists() or not agent_folder.is_dir():
|
238
300
|
console.print()
|
239
301
|
console.print(
|
240
302
|
"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
@@ -245,42 +307,61 @@ def enhance(
|
|
245
307
|
)
|
246
308
|
console.print()
|
247
309
|
console.print(
|
248
|
-
"📁 [bold]Expected Structure:[/bold] [cyan]/
|
310
|
+
f"📁 [bold]Expected Structure:[/bold] [cyan]/{final_agent_directory}[/cyan] folder containing your agent code"
|
249
311
|
)
|
250
312
|
console.print(f"📍 [bold]Current Directory:[/bold] {current_dir}")
|
251
|
-
console.print(
|
313
|
+
console.print(
|
314
|
+
f"❌ [bold red]Missing:[/bold red] /{final_agent_directory} folder"
|
315
|
+
)
|
252
316
|
console.print()
|
253
317
|
console.print(
|
254
|
-
"
|
255
|
-
" your agent code should be organized in
|
318
|
+
f"The enhance command can still proceed, but for best compatibility"
|
319
|
+
f" your agent code should be organized in a /{final_agent_directory} folder structure."
|
256
320
|
)
|
257
321
|
console.print()
|
258
322
|
|
259
323
|
# Ask for confirmation after showing the structure warning
|
324
|
+
console.print("💡 Options:")
|
260
325
|
console.print(
|
261
|
-
"
|
326
|
+
f" • Create a /{final_agent_directory} folder and move your agent code there"
|
262
327
|
)
|
328
|
+
if final_agent_directory == "app":
|
329
|
+
console.print(
|
330
|
+
" • Use [cyan]--agent-directory <custom_name>[/cyan] if your agent code is in a different directory"
|
331
|
+
)
|
332
|
+
else:
|
333
|
+
console.print(
|
334
|
+
" • Use [cyan]--agent-directory <custom_name>[/cyan] to specify your existing agent directory"
|
335
|
+
)
|
263
336
|
console.print()
|
264
337
|
|
265
338
|
if not auto_approve:
|
266
339
|
if not click.confirm(
|
267
|
-
"Continue with enhancement despite missing /
|
340
|
+
f"Continue with enhancement despite missing /{final_agent_directory} folder?",
|
268
341
|
default=True,
|
269
342
|
):
|
270
343
|
console.print("✋ [yellow]Enhancement cancelled.[/yellow]")
|
271
344
|
return
|
272
345
|
else:
|
273
346
|
# Check for common agent files
|
274
|
-
agent_py =
|
347
|
+
agent_py = agent_folder / "agent.py"
|
275
348
|
if agent_py.exists():
|
276
349
|
console.print(
|
277
|
-
"Detected existing agent structure with [cyan]/
|
350
|
+
f"Detected existing agent structure with [cyan]/{final_agent_directory}/agent.py[/cyan]"
|
278
351
|
)
|
279
352
|
else:
|
280
353
|
console.print(
|
281
|
-
"ℹ️ [blue]Found /
|
354
|
+
f"ℹ️ [blue]Found /{final_agent_directory} folder[/blue] - ensure your agent code is properly organized within it, including an agent.py file"
|
282
355
|
)
|
283
356
|
|
357
|
+
# Prepare CLI overrides to pass to create command
|
358
|
+
final_cli_overrides: dict[str, Any] = {}
|
359
|
+
if base_template:
|
360
|
+
final_cli_overrides["base_template"] = base_template
|
361
|
+
if agent_directory:
|
362
|
+
final_cli_overrides["settings"] = final_cli_overrides.get("settings", {})
|
363
|
+
final_cli_overrides["settings"]["agent_directory"] = agent_directory
|
364
|
+
|
284
365
|
# Call the create command with in-folder mode enabled
|
285
366
|
ctx.invoke(
|
286
367
|
create,
|
@@ -297,6 +378,8 @@ def enhance(
|
|
297
378
|
region=region,
|
298
379
|
skip_checks=skip_checks,
|
299
380
|
in_folder=True, # Always use in-folder mode for enhance
|
381
|
+
agent_directory=agent_directory,
|
300
382
|
base_template=base_template,
|
301
383
|
skip_welcome=True, # Skip welcome message since enhance shows its own
|
384
|
+
cli_overrides=final_cli_overrides if final_cli_overrides else None,
|
302
385
|
)
|
src/cli/commands/list.py
CHANGED
@@ -14,9 +14,14 @@
|
|
14
14
|
|
15
15
|
import logging
|
16
16
|
import pathlib
|
17
|
+
import sys
|
17
18
|
|
18
19
|
import click
|
19
|
-
|
20
|
+
|
21
|
+
if sys.version_info >= (3, 11):
|
22
|
+
import tomllib
|
23
|
+
else:
|
24
|
+
import tomli as tomllib
|
20
25
|
from rich.console import Console
|
21
26
|
from rich.table import Table
|
22
27
|
|
src/cli/utils/remote_template.py
CHANGED
@@ -18,11 +18,15 @@ import pathlib
|
|
18
18
|
import re
|
19
19
|
import shutil
|
20
20
|
import subprocess
|
21
|
+
import sys
|
21
22
|
import tempfile
|
22
23
|
from dataclasses import dataclass
|
23
24
|
from typing import Any
|
24
25
|
|
25
|
-
|
26
|
+
if sys.version_info >= (3, 11):
|
27
|
+
import tomllib
|
28
|
+
else:
|
29
|
+
import tomli as tomllib
|
26
30
|
from jinja2 import Environment
|
27
31
|
|
28
32
|
|
src/cli/utils/template.py
CHANGED
@@ -34,9 +34,6 @@ from .remote_template import (
|
|
34
34
|
render_and_merge_makefiles,
|
35
35
|
)
|
36
36
|
|
37
|
-
ADK_FILES = ["app/__init__.py"]
|
38
|
-
NON_ADK_FILES: list[str] = []
|
39
|
-
|
40
37
|
|
41
38
|
@dataclass
|
42
39
|
class TemplateConfig:
|
@@ -72,7 +69,11 @@ class TemplateConfig:
|
|
72
69
|
raise ValueError(f"Error loading template config: {err}") from err
|
73
70
|
|
74
71
|
|
75
|
-
|
72
|
+
def get_overwrite_folders(agent_directory: str) -> list[str]:
|
73
|
+
"""Get folders to overwrite with configurable agent directory."""
|
74
|
+
return [agent_directory, "frontend", "tests", "notebooks"]
|
75
|
+
|
76
|
+
|
76
77
|
TEMPLATE_CONFIG_FILE = "templateconfig.yaml"
|
77
78
|
DEPLOYMENT_FOLDERS = ["cloud_run", "agent_engine"]
|
78
79
|
DEFAULT_FRONTEND = "streamlit"
|
@@ -446,6 +447,7 @@ def process_template(
|
|
446
447
|
remote_template_path: pathlib.Path | None = None,
|
447
448
|
remote_config: dict[str, Any] | None = None,
|
448
449
|
in_folder: bool = False,
|
450
|
+
cli_overrides: dict[str, Any] | None = None,
|
449
451
|
) -> None:
|
450
452
|
"""Process the template directory and create a new project.
|
451
453
|
|
@@ -462,12 +464,25 @@ def process_template(
|
|
462
464
|
remote_template_path: Optional path to remote template for overlay
|
463
465
|
remote_config: Optional remote template configuration
|
464
466
|
in_folder: Whether to template directly into the output directory instead of creating a subdirectory
|
467
|
+
cli_overrides: Optional CLI override values that should take precedence over template config
|
465
468
|
"""
|
466
469
|
logging.debug(f"Processing template from {template_dir}")
|
467
470
|
logging.debug(f"Project name: {project_name}")
|
468
471
|
logging.debug(f"Include pipeline: {datastore}")
|
469
472
|
logging.debug(f"Output directory: {output_dir}")
|
470
473
|
|
474
|
+
def get_agent_directory(
|
475
|
+
template_config: dict[str, Any], cli_overrides: dict[str, Any] | None = None
|
476
|
+
) -> str:
|
477
|
+
"""Get agent directory with CLI override support."""
|
478
|
+
if (
|
479
|
+
cli_overrides
|
480
|
+
and "settings" in cli_overrides
|
481
|
+
and "agent_directory" in cli_overrides["settings"]
|
482
|
+
):
|
483
|
+
return cli_overrides["settings"]["agent_directory"]
|
484
|
+
return template_config.get("settings", {}).get("agent_directory", "app")
|
485
|
+
|
471
486
|
# Handle remote vs local templates
|
472
487
|
is_remote = remote_template_path is not None
|
473
488
|
|
@@ -519,7 +534,21 @@ def process_template(
|
|
519
534
|
base_template_path = (
|
520
535
|
pathlib.Path(__file__).parent.parent.parent / "base_template"
|
521
536
|
)
|
522
|
-
|
537
|
+
# Get agent directory from config early for use in file copying
|
538
|
+
# Load config early to get agent_directory
|
539
|
+
if is_remote:
|
540
|
+
early_config = remote_config or {}
|
541
|
+
else:
|
542
|
+
template_path = pathlib.Path(template_dir)
|
543
|
+
early_config = load_template_config(template_path)
|
544
|
+
agent_directory = get_agent_directory(early_config, cli_overrides)
|
545
|
+
copy_files(
|
546
|
+
base_template_path,
|
547
|
+
project_template,
|
548
|
+
agent_name,
|
549
|
+
overwrite=True,
|
550
|
+
agent_directory=agent_directory,
|
551
|
+
)
|
523
552
|
logging.debug(f"1. Copied base template from {base_template_path}")
|
524
553
|
|
525
554
|
# 2. Process deployment target if specified
|
@@ -535,6 +564,7 @@ def process_template(
|
|
535
564
|
project_template,
|
536
565
|
agent_name=agent_name,
|
537
566
|
overwrite=True,
|
567
|
+
agent_directory=agent_directory,
|
538
568
|
)
|
539
569
|
logging.debug(
|
540
570
|
f"2. Processed deployment files for target: {deployment_target}"
|
@@ -556,27 +586,11 @@ def process_template(
|
|
556
586
|
copy_frontend_files(frontend_type, project_template)
|
557
587
|
logging.debug(f"4. Processed frontend files for type: {frontend_type}")
|
558
588
|
|
559
|
-
#
|
560
|
-
|
561
|
-
for folder in OVERWRITE_FOLDERS:
|
562
|
-
agent_folder = agent_path / folder
|
563
|
-
project_folder = project_template / folder
|
564
|
-
if agent_folder.exists():
|
565
|
-
logging.debug(f"5. Copying agent folder {folder} with override")
|
566
|
-
copy_files(
|
567
|
-
agent_folder, project_folder, agent_name, overwrite=True
|
568
|
-
)
|
569
|
-
|
570
|
-
# 6. Finally, overlay remote template files if present
|
589
|
+
# 6. Skip remote template files during cookiecutter processing
|
590
|
+
# Remote files will be copied after cookiecutter to avoid Jinja conflicts
|
571
591
|
if is_remote and remote_template_path:
|
572
592
|
logging.debug(
|
573
|
-
|
574
|
-
)
|
575
|
-
copy_files(
|
576
|
-
remote_template_path,
|
577
|
-
project_template,
|
578
|
-
agent_name=agent_name,
|
579
|
-
overwrite=True,
|
593
|
+
"6. Skipping remote template files during cookiecutter processing - will copy after templating"
|
580
594
|
)
|
581
595
|
|
582
596
|
# Load and validate template config first
|
@@ -602,6 +616,45 @@ def process_template(
|
|
602
616
|
# Use the already loaded config
|
603
617
|
template_config = config
|
604
618
|
|
619
|
+
# 5. Copy agent-specific files to override base template (using final config)
|
620
|
+
if agent_path.exists():
|
621
|
+
agent_directory = get_agent_directory(template_config, cli_overrides)
|
622
|
+
|
623
|
+
# Get the template's default agent directory (usually "app")
|
624
|
+
template_agent_directory = template_config.get("settings", {}).get(
|
625
|
+
"agent_directory", "app"
|
626
|
+
)
|
627
|
+
|
628
|
+
# Copy agent directory (always from "app" to target directory)
|
629
|
+
source_agent_folder = agent_path / template_agent_directory
|
630
|
+
target_agent_folder = project_template / agent_directory
|
631
|
+
if source_agent_folder.exists():
|
632
|
+
logging.debug(
|
633
|
+
f"5. Copying agent folder {template_agent_directory} -> {agent_directory} with override"
|
634
|
+
)
|
635
|
+
copy_files(
|
636
|
+
source_agent_folder,
|
637
|
+
target_agent_folder,
|
638
|
+
agent_name,
|
639
|
+
overwrite=True,
|
640
|
+
agent_directory=agent_directory,
|
641
|
+
)
|
642
|
+
|
643
|
+
# Copy other folders (frontend, tests, notebooks)
|
644
|
+
other_folders = ["frontend", "tests", "notebooks"]
|
645
|
+
for folder in other_folders:
|
646
|
+
agent_folder = agent_path / folder
|
647
|
+
project_folder = project_template / folder
|
648
|
+
if agent_folder.exists():
|
649
|
+
logging.debug(f"5. Copying {folder} folder with override")
|
650
|
+
copy_files(
|
651
|
+
agent_folder,
|
652
|
+
project_folder,
|
653
|
+
agent_name,
|
654
|
+
overwrite=True,
|
655
|
+
agent_directory=agent_directory,
|
656
|
+
)
|
657
|
+
|
605
658
|
# Check if data processing should be included
|
606
659
|
if include_data_ingestion and datastore:
|
607
660
|
logging.debug(
|
@@ -649,6 +702,7 @@ def process_template(
|
|
649
702
|
"extra_dependencies": [extra_deps],
|
650
703
|
"data_ingestion": include_data_ingestion,
|
651
704
|
"datastore_type": datastore if datastore else "",
|
705
|
+
"agent_directory": get_agent_directory(template_config, cli_overrides),
|
652
706
|
"adk_cheatsheet": adk_cheatsheet_content,
|
653
707
|
"llm_txt": llm_txt_content,
|
654
708
|
"_copy_without_render": [
|
@@ -664,7 +718,9 @@ def process_template(
|
|
664
718
|
"*templates.py", # Don't render templates files
|
665
719
|
"Makefile", # Don't render Makefile - handled by render_and_merge_makefiles
|
666
720
|
# Don't render agent.py unless it's agentic_rag
|
667
|
-
"
|
721
|
+
f"{get_agent_directory(template_config, cli_overrides)}/agent.py"
|
722
|
+
if agent_name != "agentic_rag"
|
723
|
+
else "",
|
668
724
|
],
|
669
725
|
}
|
670
726
|
|
@@ -690,6 +746,21 @@ def process_template(
|
|
690
746
|
)
|
691
747
|
logging.debug("Template processing completed successfully")
|
692
748
|
|
749
|
+
# Now overlay remote template files if present (after cookiecutter processing)
|
750
|
+
if is_remote and remote_template_path:
|
751
|
+
generated_project_dir = temp_path / project_name
|
752
|
+
logging.debug(
|
753
|
+
f"Copying remote template files from {remote_template_path} to {generated_project_dir}"
|
754
|
+
)
|
755
|
+
copy_files(
|
756
|
+
remote_template_path,
|
757
|
+
generated_project_dir,
|
758
|
+
agent_name=agent_name,
|
759
|
+
overwrite=True,
|
760
|
+
agent_directory=agent_directory,
|
761
|
+
)
|
762
|
+
logging.debug("Remote template files copied successfully")
|
763
|
+
|
693
764
|
# Move the generated project to the final destination
|
694
765
|
generated_project_dir = temp_path / project_name
|
695
766
|
|
@@ -842,15 +913,7 @@ def process_template(
|
|
842
913
|
)
|
843
914
|
|
844
915
|
# Delete appropriate files based on ADK tag
|
845
|
-
|
846
|
-
files_to_delete = [final_destination / f for f in NON_ADK_FILES]
|
847
|
-
else:
|
848
|
-
files_to_delete = [final_destination / f for f in ADK_FILES]
|
849
|
-
|
850
|
-
for file_path in files_to_delete:
|
851
|
-
if file_path.exists():
|
852
|
-
file_path.unlink()
|
853
|
-
logging.debug(f"Deleted {file_path}")
|
916
|
+
agent_directory = get_agent_directory(template_config, cli_overrides)
|
854
917
|
|
855
918
|
# Clean up unused_* files and directories created by conditional templates
|
856
919
|
import glob
|
@@ -923,11 +986,15 @@ def process_template(
|
|
923
986
|
os.chdir(original_dir)
|
924
987
|
|
925
988
|
|
926
|
-
def should_exclude_path(
|
989
|
+
def should_exclude_path(
|
990
|
+
path: pathlib.Path, agent_name: str, agent_directory: str = "app"
|
991
|
+
) -> bool:
|
927
992
|
"""Determine if a path should be excluded based on the agent type."""
|
928
993
|
if agent_name == "live_api":
|
929
|
-
# Exclude the unit test utils folder and
|
930
|
-
if "tests/unit/test_utils" in str(path) or "
|
994
|
+
# Exclude the unit test utils folder and agent utils folder for live_api
|
995
|
+
if "tests/unit/test_utils" in str(path) or f"{agent_directory}/utils" in str(
|
996
|
+
path
|
997
|
+
):
|
931
998
|
logging.debug(f"Excluding path for live_api: {path}")
|
932
999
|
return True
|
933
1000
|
return False
|
@@ -938,6 +1005,7 @@ def copy_files(
|
|
938
1005
|
dst: pathlib.Path,
|
939
1006
|
agent_name: str | None = None,
|
940
1007
|
overwrite: bool = False,
|
1008
|
+
agent_directory: str = "app",
|
941
1009
|
) -> None:
|
942
1010
|
"""
|
943
1011
|
Copy files with configurable behavior for exclusions and overwrites.
|
@@ -947,6 +1015,7 @@ def copy_files(
|
|
947
1015
|
dst: Destination path
|
948
1016
|
agent_name: Name of the agent (for agent-specific exclusions)
|
949
1017
|
overwrite: Whether to overwrite existing files (True) or skip them (False)
|
1018
|
+
agent_directory: Name of the agent directory (for agent-specific exclusions)
|
950
1019
|
"""
|
951
1020
|
|
952
1021
|
def should_skip(path: pathlib.Path) -> bool:
|
@@ -957,7 +1026,9 @@ def copy_files(
|
|
957
1026
|
return True
|
958
1027
|
if ".git" in path.parts:
|
959
1028
|
return True
|
960
|
-
if agent_name is not None and should_exclude_path(
|
1029
|
+
if agent_name is not None and should_exclude_path(
|
1030
|
+
path, agent_name, agent_directory
|
1031
|
+
):
|
961
1032
|
return True
|
962
1033
|
if path.is_dir() and path.name == ".template":
|
963
1034
|
return True
|
@@ -970,9 +1041,10 @@ def copy_files(
|
|
970
1041
|
if should_skip(item):
|
971
1042
|
logging.debug(f"Skipping file/directory: {item}")
|
972
1043
|
continue
|
1044
|
+
|
973
1045
|
d = dst / item.name
|
974
1046
|
if item.is_dir():
|
975
|
-
copy_files(item, d, agent_name, overwrite)
|
1047
|
+
copy_files(item, d, agent_name, overwrite, agent_directory)
|
976
1048
|
else:
|
977
1049
|
if overwrite or not d.exists():
|
978
1050
|
logging.debug(f"Copying file: {item} -> {d}")
|
@@ -1012,7 +1084,10 @@ def copy_frontend_files(frontend_type: str, project_template: pathlib.Path) -> N
|
|
1012
1084
|
|
1013
1085
|
|
1014
1086
|
def copy_deployment_files(
|
1015
|
-
deployment_target: str,
|
1087
|
+
deployment_target: str,
|
1088
|
+
agent_name: str,
|
1089
|
+
project_template: pathlib.Path,
|
1090
|
+
agent_directory: str = "app",
|
1016
1091
|
) -> None:
|
1017
1092
|
"""Copy files from the specified deployment target folder."""
|
1018
1093
|
if not deployment_target:
|
@@ -1028,7 +1103,11 @@ def copy_deployment_files(
|
|
1028
1103
|
logging.debug(f"Copying deployment files from {deployment_path}")
|
1029
1104
|
# Pass agent_name to respect agent-specific exclusions
|
1030
1105
|
copy_files(
|
1031
|
-
deployment_path,
|
1106
|
+
deployment_path,
|
1107
|
+
project_template,
|
1108
|
+
agent_name=agent_name,
|
1109
|
+
overwrite=True,
|
1110
|
+
agent_directory=agent_directory,
|
1032
1111
|
)
|
1033
1112
|
else:
|
1034
1113
|
logging.warning(f"Deployment target directory not found: {deployment_path}")
|
@@ -18,11 +18,11 @@ import pytest
|
|
18
18
|
{%- if "adk" in cookiecutter.tags %}
|
19
19
|
from google.adk.events.event import Event
|
20
20
|
|
21
|
-
from
|
22
|
-
from
|
21
|
+
from {{cookiecutter.agent_directory}}.agent import root_agent
|
22
|
+
from {{cookiecutter.agent_directory}}.agent_engine_app import AgentEngineApp
|
23
23
|
{%- else %}
|
24
24
|
|
25
|
-
from
|
25
|
+
from {{cookiecutter.agent_directory}}.agent_engine_app import AgentEngineApp
|
26
26
|
{%- endif %}
|
27
27
|
|
28
28
|
|