create-google-adk-agent 1.0.0__tar.gz

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.
Files changed (27) hide show
  1. create_google_adk_agent-1.0.0/PKG-INFO +35 -0
  2. create_google_adk_agent-1.0.0/README.md +15 -0
  3. create_google_adk_agent-1.0.0/create_adk_agent/__init__.py +0 -0
  4. create_google_adk_agent-1.0.0/create_adk_agent/cli.py +179 -0
  5. create_google_adk_agent-1.0.0/create_adk_agent/template/agentic_rag/tests/test_agent.py +27 -0
  6. create_google_adk_agent-1.0.0/create_adk_agent/template/agentic_rag/{{PROJECT_NAME}}/__init__.py +1 -0
  7. create_google_adk_agent-1.0.0/create_adk_agent/template/agentic_rag/{{PROJECT_NAME}}/agent.py +76 -0
  8. create_google_adk_agent-1.0.0/create_adk_agent/template/base/Makefile +15 -0
  9. create_google_adk_agent-1.0.0/create_adk_agent/template/base/README.md +63 -0
  10. create_google_adk_agent-1.0.0/create_adk_agent/template/base/_dot_env.example +5 -0
  11. create_google_adk_agent-1.0.0/create_adk_agent/template/base/_dot_github/copilot-instructions.md +59 -0
  12. create_google_adk_agent-1.0.0/create_adk_agent/template/base/_dot_gitignore +7 -0
  13. create_google_adk_agent-1.0.0/create_adk_agent/template/base/pyproject.toml +19 -0
  14. create_google_adk_agent-1.0.0/create_adk_agent/template/multi/tests/test_agent.py +14 -0
  15. create_google_adk_agent-1.0.0/create_adk_agent/template/multi/{{PROJECT_NAME}}/__init__.py +1 -0
  16. create_google_adk_agent-1.0.0/create_adk_agent/template/multi/{{PROJECT_NAME}}/agent.py +49 -0
  17. create_google_adk_agent-1.0.0/create_adk_agent/template/single/tests/test_agent.py +28 -0
  18. create_google_adk_agent-1.0.0/create_adk_agent/template/single/{{PROJECT_NAME}}/__init__.py +1 -0
  19. create_google_adk_agent-1.0.0/create_adk_agent/template/single/{{PROJECT_NAME}}/agent.py +43 -0
  20. create_google_adk_agent-1.0.0/create_google_adk_agent.egg-info/PKG-INFO +35 -0
  21. create_google_adk_agent-1.0.0/create_google_adk_agent.egg-info/SOURCES.txt +25 -0
  22. create_google_adk_agent-1.0.0/create_google_adk_agent.egg-info/dependency_links.txt +1 -0
  23. create_google_adk_agent-1.0.0/create_google_adk_agent.egg-info/entry_points.txt +2 -0
  24. create_google_adk_agent-1.0.0/create_google_adk_agent.egg-info/requires.txt +1 -0
  25. create_google_adk_agent-1.0.0/create_google_adk_agent.egg-info/top_level.txt +1 -0
  26. create_google_adk_agent-1.0.0/setup.cfg +4 -0
  27. create_google_adk_agent-1.0.0/setup.py +32 -0
@@ -0,0 +1,35 @@
1
+ Metadata-Version: 2.4
2
+ Name: create-google-adk-agent
3
+ Version: 1.0.0
4
+ Summary: Interactive one-command scaffold for Google ADK (Agent Development Kit) projects
5
+ Home-page: https://github.com/unrealandychan/create-adk-agent
6
+ Author: unrealandychan
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Requires-Python: >=3.11
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: inquirerpy>=0.3.4
12
+ Dynamic: author
13
+ Dynamic: classifier
14
+ Dynamic: description
15
+ Dynamic: description-content-type
16
+ Dynamic: home-page
17
+ Dynamic: requires-dist
18
+ Dynamic: requires-python
19
+ Dynamic: summary
20
+
21
+ # create-google-adk-agent
22
+
23
+ Interactive one-command scaffold for [Google ADK](https://google.github.io/adk-docs/) projects.
24
+
25
+ ```bash
26
+ uvx create-google-adk-agent
27
+ # or
28
+ npx create-google-adk-agent
29
+ ```
30
+
31
+ Supports:
32
+ - **3 agent types**: single, multi-agent, agentic RAG
33
+ - **5 LLM providers**: Google AI Studio, Vertex AI, OpenAI, Anthropic, Ollama
34
+ - Copilot instructions pre-wired
35
+ - `uv` + `adk web` ready out of the box
@@ -0,0 +1,15 @@
1
+ # create-google-adk-agent
2
+
3
+ Interactive one-command scaffold for [Google ADK](https://google.github.io/adk-docs/) projects.
4
+
5
+ ```bash
6
+ uvx create-google-adk-agent
7
+ # or
8
+ npx create-google-adk-agent
9
+ ```
10
+
11
+ Supports:
12
+ - **3 agent types**: single, multi-agent, agentic RAG
13
+ - **5 LLM providers**: Google AI Studio, Vertex AI, OpenAI, Anthropic, Ollama
14
+ - Copilot instructions pre-wired
15
+ - `uv` + `adk web` ready out of the box
@@ -0,0 +1,179 @@
1
+ """create-google-adk-agent CLI — interactive ADK project scaffold."""
2
+
3
+ import os
4
+ import sys
5
+ import shutil
6
+ from pathlib import Path
7
+
8
+ try:
9
+ from InquirerPy import inquirer
10
+ from InquirerPy.base.control import Choice
11
+ except ImportError:
12
+ print("Installing InquirerPy...")
13
+ os.system(f"{sys.executable} -m pip install inquirerpy -q")
14
+ from InquirerPy import inquirer
15
+ from InquirerPy.base.control import Choice
16
+
17
+ TEMPLATE_DIR = Path(__file__).parent / "template"
18
+
19
+ PROVIDERS = {
20
+ "google_ai_studio": {
21
+ "label": "Google AI Studio (free tier, just GOOGLE_API_KEY)",
22
+ "envVars": ["GOOGLE_API_KEY"],
23
+ "envComment": "# Get yours: https://aistudio.google.com/app/apikey",
24
+ "defaultModel": "gemini-2.0-flash",
25
+ "modelExpr": lambda m: f'"{m}"',
26
+ "litellmImport": "",
27
+ "extraDeps": "",
28
+ },
29
+ "vertex_ai": {
30
+ "label": "Vertex AI (GCP project required)",
31
+ "envVars": ["GOOGLE_CLOUD_PROJECT", "GOOGLE_CLOUD_LOCATION"],
32
+ "envComment": "# Set up: gcloud auth application-default login",
33
+ "defaultModel": "gemini-2.0-flash",
34
+ "modelExpr": lambda m: f'"{m}"',
35
+ "litellmImport": "",
36
+ "extraDeps": ' "google-cloud-aiplatform>=1.38",',
37
+ },
38
+ "openai": {
39
+ "label": "OpenAI (gpt-4o via ADK LiteLLM)",
40
+ "envVars": ["OPENAI_API_KEY"],
41
+ "envComment": "# Get yours: https://platform.openai.com/api-keys",
42
+ "defaultModel": "gpt-4o",
43
+ "modelExpr": lambda m: f'LiteLlm(model="openai/{m}")',
44
+ "litellmImport": "from google.adk.models.lite_llm import LiteLlm\n",
45
+ "extraDeps": ' "litellm>=1.40",',
46
+ },
47
+ "anthropic": {
48
+ "label": "Anthropic (claude via ADK LiteLLM)",
49
+ "envVars": ["ANTHROPIC_API_KEY"],
50
+ "envComment": "# Get yours: https://console.anthropic.com/",
51
+ "defaultModel": "claude-3-5-sonnet-20241022",
52
+ "modelExpr": lambda m: f'LiteLlm(model="anthropic/{m}")',
53
+ "litellmImport": "from google.adk.models.lite_llm import LiteLlm\n",
54
+ "extraDeps": ' "litellm>=1.40",',
55
+ },
56
+ "ollama": {
57
+ "label": "Ollama (local, no API key needed)",
58
+ "envVars": [],
59
+ "envComment": "# Make sure ollama is running: ollama serve",
60
+ "defaultModel": "llama3.2",
61
+ "modelExpr": lambda m: f'LiteLlm(model="ollama/{m}")',
62
+ "litellmImport": "from google.adk.models.lite_llm import LiteLlm\n",
63
+ "extraDeps": ' "litellm>=1.40",',
64
+ },
65
+ }
66
+
67
+ AGENT_TYPES = {
68
+ "single": "One agent with tools — best starting point",
69
+ "multi": "Orchestrator + specialist sub-agents",
70
+ "agentic_rag": "RAG pipeline — load & query documents",
71
+ }
72
+
73
+
74
+ def render(text: str, vars: dict) -> str:
75
+ for k, v in vars.items():
76
+ text = text.replace("{{" + k + "}}", v)
77
+ return text
78
+
79
+
80
+ def copy_tree(src: Path, dest: Path, vars: dict):
81
+ dest.mkdir(parents=True, exist_ok=True)
82
+ for entry in src.iterdir():
83
+ real_name = entry.name.replace("_dot_", ".", 1)
84
+ dest_name = render(real_name, vars)
85
+ dest_path = dest / dest_name
86
+ if entry.is_dir():
87
+ copy_tree(entry, dest_path, vars)
88
+ else:
89
+ content = render(entry.read_text(errors="replace"), vars)
90
+ dest_path.parent.mkdir(parents=True, exist_ok=True)
91
+ dest_path.write_text(content)
92
+
93
+
94
+ def main():
95
+ print("\n \033[1;36m╔═══════════════════════════════════╗")
96
+ print(" ║ create-google-adk-agent 🤖 ║")
97
+ print(" ╚═══════════════════════════════════╝\033[0m")
98
+ print(" \033[2mBootstrap a Google ADK project in seconds\033[0m\n")
99
+
100
+ # Project name
101
+ project_name = inquirer.text(
102
+ message="Project name:",
103
+ default="my-adk-agent",
104
+ ).execute()
105
+ safe_name = "".join(c if c.isalnum() or c == "_" else "_" for c in project_name)
106
+ if safe_name[0].isdigit():
107
+ safe_name = "_" + safe_name
108
+
109
+ # Agent type
110
+ agent_type = inquirer.select(
111
+ message="Agent type:",
112
+ choices=[Choice(k, name=f"{k:<14} — {v}") for k, v in AGENT_TYPES.items()],
113
+ ).execute()
114
+
115
+ # Provider
116
+ provider_key = inquirer.select(
117
+ message="LLM Provider:",
118
+ choices=[Choice(k, name=v["label"]) for k, v in PROVIDERS.items()],
119
+ ).execute()
120
+ provider = PROVIDERS[provider_key]
121
+
122
+ # Model
123
+ model = inquirer.text(
124
+ message="Model:",
125
+ default=provider["defaultModel"],
126
+ ).execute()
127
+
128
+ # Build vars
129
+ env_content = (
130
+ "\n".join(f"{v}=your_key_here" for v in provider["envVars"])
131
+ if provider["envVars"]
132
+ else "# No API key required for this provider"
133
+ )
134
+ VARS = {
135
+ "PROJECT_NAME": safe_name,
136
+ "AGENT_TYPE": agent_type,
137
+ "PROVIDER_KEY": provider_key,
138
+ "MODEL_NAME": model,
139
+ "MODEL_EXPR": provider["modelExpr"](model),
140
+ "LITELM_IMPORT": provider["litellmImport"],
141
+ "EXTRA_DEPS": provider["extraDeps"],
142
+ "ENV_VARS_COMMENT": provider["envComment"],
143
+ "ENV_CONTENT": env_content,
144
+ "LITELM_IMPORT_COPILOT": provider["litellmImport"],
145
+ }
146
+
147
+ out_dir = Path.cwd() / project_name
148
+ if out_dir.exists():
149
+ print(f"\n\033[31m✗ Directory '{project_name}' already exists.\033[0m\n")
150
+ sys.exit(1)
151
+
152
+ copy_tree(TEMPLATE_DIR / "base", out_dir, VARS)
153
+ copy_tree(TEMPLATE_DIR / agent_type, out_dir, VARS)
154
+
155
+ env_ex = out_dir / "_dot_env.example"
156
+ if env_ex.exists():
157
+ env_ex.rename(out_dir / ".env.example")
158
+
159
+ env_note = "\n".join(f" {v}=<your_key>" for v in provider["envVars"]) or " # No key needed!"
160
+
161
+ print(f"""
162
+ \033[32m✅ Done!\033[0m \033[1m{project_name}\033[0m created.
163
+
164
+ \033[1mNext steps:\033[0m
165
+
166
+ 1. \033[36mcd {project_name}\033[0m
167
+ 2. Edit \033[36m.env.example\033[0m → \033[36m.env\033[0m:
168
+ \033[2m{env_note}\033[0m
169
+ 3. \033[36muv sync\033[0m
170
+ 4. \033[36muv run adk web\033[0m \033[2m→ open http://localhost:8000\033[0m
171
+
172
+ \033[2mAgent type: \033[0m\033[1m{agent_type}\033[0m
173
+ \033[2mProvider: \033[0m\033[1m{provider_key}\033[0m
174
+ \033[2mModel: \033[0m\033[1m{model}\033[0m
175
+ """)
176
+
177
+
178
+ if __name__ == "__main__":
179
+ main()
@@ -0,0 +1,27 @@
1
+ """Tests for {{PROJECT_NAME}} RAG agent."""
2
+
3
+ import pytest
4
+ import tempfile, os
5
+
6
+ def test_root_agent_exists():
7
+ from {{PROJECT_NAME}}.agent import root_agent
8
+ assert root_agent.name == "{{PROJECT_NAME}}"
9
+
10
+ def test_load_documents_missing_folder():
11
+ from {{PROJECT_NAME}}.agent import load_documents
12
+ result = load_documents("/nonexistent/folder")
13
+ assert result["status"] == "error"
14
+
15
+ def test_load_documents_success():
16
+ from {{PROJECT_NAME}}.agent import load_documents, search_documents
17
+ with tempfile.TemporaryDirectory() as tmpdir:
18
+ (open(f"{tmpdir}/test.txt", "w")).write("ADK is a framework for building AI agents by Google.")
19
+ result = load_documents(tmpdir)
20
+ assert result["status"] == "success"
21
+ assert result["loaded"] == 1
22
+
23
+ def test_search_no_docs():
24
+ from {{PROJECT_NAME}}.agent import _DOCS, search_documents
25
+ _DOCS.clear()
26
+ result = search_documents("anything")
27
+ assert result["status"] == "error"
@@ -0,0 +1,76 @@
1
+ """{{PROJECT_NAME}} — ADK agentic RAG pipeline."""
2
+
3
+ import os
4
+ from pathlib import Path
5
+ from dotenv import load_dotenv
6
+ {{LITELM_IMPORT}}from google.adk.agents import Agent
7
+
8
+ load_dotenv()
9
+
10
+ _MODEL = {{MODEL_EXPR}}
11
+
12
+ # ── Simple in-memory document store (replace with your vector DB) ─────────────
13
+
14
+ _DOCS: list[dict] = [] # {"id": str, "content": str, "source": str}
15
+
16
+ def load_documents(folder: str = "./docs") -> dict:
17
+ """
18
+ Load all .txt and .md files from a folder into the document store.
19
+ Call this before asking questions.
20
+ """
21
+ global _DOCS
22
+ _DOCS = []
23
+ p = Path(folder)
24
+ if not p.exists():
25
+ return {"status": "error", "message": f"Folder '{folder}' not found."}
26
+ for f in p.glob("**/*.txt"):
27
+ _DOCS.append({"id": str(f), "content": f.read_text(errors="replace"), "source": str(f)})
28
+ for f in p.glob("**/*.md"):
29
+ _DOCS.append({"id": str(f), "content": f.read_text(errors="replace"), "source": str(f)})
30
+ return {"status": "success", "loaded": len(_DOCS), "sources": [d["source"] for d in _DOCS]}
31
+
32
+
33
+ def search_documents(query: str, top_k: int = 3) -> dict:
34
+ """
35
+ Search loaded documents for content relevant to the query.
36
+ Returns top matching passages. Load documents first with load_documents().
37
+ """
38
+ if not _DOCS:
39
+ return {
40
+ "status": "error",
41
+ "message": "No documents loaded. Call load_documents() first.",
42
+ }
43
+ # Simple keyword search — swap for vector similarity in production
44
+ query_words = set(query.lower().split())
45
+ scored = []
46
+ for doc in _DOCS:
47
+ content_lower = doc["content"].lower()
48
+ score = sum(1 for w in query_words if w in content_lower)
49
+ if score > 0:
50
+ # Return a relevant chunk (first 500 chars for now)
51
+ scored.append((score, doc))
52
+ scored.sort(key=lambda x: x[0], reverse=True)
53
+ results = [
54
+ {"source": d["source"], "excerpt": d["content"][:500]}
55
+ for _, d in scored[:top_k]
56
+ ]
57
+ if not results:
58
+ return {"status": "not_found", "message": "No relevant documents found.", "results": []}
59
+ return {"status": "success", "results": results}
60
+
61
+
62
+ root_agent = Agent(
63
+ name="{{PROJECT_NAME}}",
64
+ model=_MODEL,
65
+ description="RAG agent that answers questions from loaded documents.",
66
+ instruction="""
67
+ You are a helpful RAG assistant. To answer questions:
68
+ 1. First call search_documents() to retrieve relevant passages
69
+ 2. Base your answer strictly on the retrieved content
70
+ 3. Always cite which document your answer comes from
71
+ 4. If no relevant documents are found, say so clearly
72
+
73
+ If the user wants to load documents, call load_documents() with the folder path.
74
+ """,
75
+ tools=[load_documents, search_documents],
76
+ )
@@ -0,0 +1,15 @@
1
+ .PHONY: dev test
2
+
3
+ dev:
4
+ uv run adk web
5
+
6
+ run:
7
+ uv run adk run {{PROJECT_NAME}}
8
+
9
+ api:
10
+ uv run adk api_server
11
+
12
+ test:
13
+ uv run pytest -v
14
+
15
+ .DEFAULT_GOAL := dev
@@ -0,0 +1,63 @@
1
+ # {{PROJECT_NAME}}
2
+
3
+ > 🤖 ADK agent — powered by [Google Agent Development Kit](https://google.github.io/adk-docs/)
4
+ > **Type:** {{AGENT_TYPE}} | **Provider:** {{PROVIDER_KEY}} | **Model:** {{MODEL_NAME}}
5
+
6
+ ## Quick Start
7
+
8
+ ```bash
9
+ cp .env.example .env # add your API key
10
+ uv sync # install deps
11
+ uv run adk web # open Dev UI at http://localhost:8000
12
+ ```
13
+
14
+ ## Project Structure
15
+
16
+ ```
17
+ {{PROJECT_NAME}}/ ← ADK requires this folder = module name
18
+ __init__.py
19
+ agent.py ← root_agent defined here
20
+ tools/
21
+ example.py
22
+ tests/
23
+ test_agent.py
24
+ pyproject.toml
25
+ .env.example
26
+ ```
27
+
28
+ > ⚠️ ADK convention: `adk web` is run from the **parent** folder, and it loads `{{PROJECT_NAME}}/agent.py`
29
+
30
+ ## Running
31
+
32
+ | Command | What it does |
33
+ |---------|-------------|
34
+ | `uv run adk web` | Dev UI at localhost:8000 (chat + trace + events) |
35
+ | `uv run adk run {{PROJECT_NAME}}` | CLI chat mode |
36
+ | `uv run adk api_server` | FastAPI server |
37
+ | `make dev` | Same as `adk web` |
38
+ | `make test` | Run pytest |
39
+
40
+ ## Adding Tools
41
+
42
+ ```python
43
+ # {{PROJECT_NAME}}/tools/my_tool.py
44
+ def my_tool(input: str) -> dict:
45
+ """Describe what this tool does — ADK uses this as the tool description."""
46
+ return {"result": input}
47
+ ```
48
+
49
+ Register in `agent.py`:
50
+ ```python
51
+ from .tools.my_tool import my_tool
52
+ root_agent = Agent(..., tools=[my_tool])
53
+ ```
54
+
55
+ ## Provider: {{PROVIDER_KEY}}
56
+
57
+ {{ENV_CONTENT}}
58
+
59
+ ## Docs
60
+
61
+ - [ADK Docs](https://google.github.io/adk-docs/)
62
+ - [ADK Samples](https://github.com/google/adk-samples)
63
+ - [ADK Python](https://github.com/google/adk-python)
@@ -0,0 +1,5 @@
1
+ # {{PROJECT_NAME}} environment config
2
+ # Provider: {{PROVIDER_KEY}}
3
+ {{ENV_VARS_COMMENT}}
4
+
5
+ {{ENV_CONTENT}}
@@ -0,0 +1,59 @@
1
+ # Copilot Instructions — {{PROJECT_NAME}}
2
+
3
+ ## What this project is
4
+
5
+ A **Google ADK** (Agent Development Kit) agent.
6
+ - **Type:** {{AGENT_TYPE}}
7
+ - **Provider:** {{PROVIDER_KEY}}
8
+ - **Model:** {{MODEL_NAME}}
9
+
10
+ ## ADK Key Concepts
11
+
12
+ - `Agent` — core agent class with `name`, `model`, `instruction`, `tools`, `sub_agents`
13
+ - `root_agent` — **must** be named exactly `root_agent` in `agent.py` (ADK convention)
14
+ - Tools are plain Python functions with a docstring — ADK auto-generates the schema
15
+ - `SequentialAgent` — runs sub-agents one after another
16
+ - `ParallelAgent` — runs sub-agents concurrently
17
+ - `LoopAgent` — repeats a sub-agent until condition met
18
+
19
+ ## Project Layout
20
+
21
+ ```
22
+ {{PROJECT_NAME}}/ ← Python module (ADK loads this)
23
+ __init__.py
24
+ agent.py ← root_agent lives here
25
+ tools/ ← plain Python functions used as tools
26
+ tests/
27
+ pyproject.toml
28
+ .env / .env.example
29
+ ```
30
+
31
+ ## Running
32
+
33
+ ```bash
34
+ uv run adk web # Dev UI at http://localhost:8000
35
+ uv run adk run {{PROJECT_NAME}} # CLI mode
36
+ ```
37
+
38
+ > ⚠️ Run from the **parent** folder, not inside `{{PROJECT_NAME}}/`
39
+
40
+ ## Model config ({{PROVIDER_KEY}})
41
+
42
+ ```python
43
+ {{LITELM_IMPORT}}model = {{MODEL_EXPR}}
44
+ ```
45
+
46
+ ## Common Copilot tasks
47
+
48
+ - "Add a tool that fetches live stock prices"
49
+ - "Add a sub-agent for data analysis and wire it with SequentialAgent"
50
+ - "Add input/output guardrails"
51
+ - "Write a pytest test for the root agent"
52
+ - "Add session memory so the agent remembers previous turns"
53
+ - "Switch the model to gemini-1.5-pro"
54
+
55
+ ## Code style
56
+
57
+ - Python 3.11+, type hints everywhere
58
+ - Tool functions: return `dict` with `{"status": "success", ...}` or `{"status": "error", "message": ...}`
59
+ - `root_agent` must always be exported from `agent.py`
@@ -0,0 +1,7 @@
1
+ .env
2
+ __pycache__/
3
+ *.pyc
4
+ .venv/
5
+ dist/
6
+ .ruff_cache/
7
+ *.db
@@ -0,0 +1,19 @@
1
+ [project]
2
+ name = "{{PROJECT_NAME}}"
3
+ version = "0.1.0"
4
+ requires-python = ">=3.11"
5
+ dependencies = [
6
+ "google-adk>=1.0",
7
+ "python-dotenv>=1.0",
8
+ {{EXTRA_DEPS}}
9
+ ]
10
+
11
+ [project.optional-dependencies]
12
+ dev = ["pytest>=8.0", "pytest-asyncio>=0.23"]
13
+
14
+ [build-system]
15
+ requires = ["hatchling"]
16
+ build-backend = "hatchling.build"
17
+
18
+ [tool.pytest.ini_options]
19
+ asyncio_mode = "auto"
@@ -0,0 +1,14 @@
1
+ """Tests for {{PROJECT_NAME}} multi-agent."""
2
+
3
+ def test_root_agent_exists():
4
+ from {{PROJECT_NAME}}.agent import root_agent
5
+ assert root_agent.name == "{{PROJECT_NAME}}"
6
+
7
+ def test_root_agent_has_sub_agents():
8
+ from {{PROJECT_NAME}}.agent import root_agent
9
+ assert len(root_agent.sub_agents) == 2
10
+
11
+ def test_specialist_agents():
12
+ from {{PROJECT_NAME}}.agent import research_agent, writer_agent
13
+ assert research_agent.name == "research_agent"
14
+ assert writer_agent.name == "writer_agent"
@@ -0,0 +1,49 @@
1
+ """{{PROJECT_NAME}} — ADK multi-agent (orchestrator + specialists)."""
2
+
3
+ from dotenv import load_dotenv
4
+ {{LITELM_IMPORT}}from google.adk.agents import Agent
5
+
6
+ load_dotenv()
7
+
8
+ _MODEL = {{MODEL_EXPR}}
9
+
10
+ # ── Specialist agents ─────────────────────────────────────────────────────────
11
+
12
+ research_agent = Agent(
13
+ name="research_agent",
14
+ model=_MODEL,
15
+ description="Specialist for research, facts, and information retrieval.",
16
+ instruction="""
17
+ You are a research specialist. Answer factual questions thoroughly.
18
+ Be precise and cite reasoning. Return structured, detailed answers.
19
+ """,
20
+ tools=[],
21
+ )
22
+
23
+ writer_agent = Agent(
24
+ name="writer_agent",
25
+ model=_MODEL,
26
+ description="Specialist for writing, editing, summarising, and drafting content.",
27
+ instruction="""
28
+ You are a writing specialist. Help draft, edit, summarise, and improve text.
29
+ Be clear, concise, and match the requested tone.
30
+ """,
31
+ tools=[],
32
+ )
33
+
34
+ # ── Orchestrator ──────────────────────────────────────────────────────────────
35
+
36
+ root_agent = Agent(
37
+ name="{{PROJECT_NAME}}",
38
+ model=_MODEL,
39
+ description="Orchestrator that routes requests to the right specialist.",
40
+ instruction="""
41
+ You are an orchestrator. Delegate tasks to the most suitable specialist:
42
+ - research_agent: factual questions, research, data, analysis
43
+ - writer_agent: writing, editing, drafting, summarising
44
+
45
+ If neither specialist is needed, handle it yourself briefly.
46
+ Always pass the full user request to the chosen specialist.
47
+ """,
48
+ sub_agents=[research_agent, writer_agent],
49
+ )
@@ -0,0 +1,28 @@
1
+ """Tests for {{PROJECT_NAME}}."""
2
+
3
+ import pytest
4
+ from unittest.mock import patch, MagicMock
5
+
6
+
7
+ def test_root_agent_exists():
8
+ from {{PROJECT_NAME}}.agent import root_agent
9
+ assert root_agent is not None
10
+ assert root_agent.name == "{{PROJECT_NAME}}"
11
+
12
+
13
+ def test_root_agent_has_tools():
14
+ from {{PROJECT_NAME}}.agent import root_agent
15
+ assert len(root_agent.tools) > 0
16
+
17
+
18
+ def test_get_current_time_known_city():
19
+ from {{PROJECT_NAME}}.agent import get_current_time
20
+ result = get_current_time("hong kong")
21
+ assert result["status"] == "success"
22
+ assert "time" in result
23
+
24
+
25
+ def test_get_current_time_unknown_city():
26
+ from {{PROJECT_NAME}}.agent import get_current_time
27
+ result = get_current_time("atlantis")
28
+ assert result["status"] == "error"
@@ -0,0 +1,43 @@
1
+ """{{PROJECT_NAME}} — ADK single agent."""
2
+
3
+ import datetime
4
+ from zoneinfo import ZoneInfo
5
+ from dotenv import load_dotenv
6
+
7
+ {{LITELM_IMPORT}}from google.adk.agents import Agent
8
+
9
+ load_dotenv()
10
+
11
+
12
+ def get_current_time(city: str) -> dict:
13
+ """Get the current time in a given city. Returns time as a formatted string."""
14
+ TIMEZONES = {
15
+ "hong kong": "Asia/Hong_Kong",
16
+ "london": "Europe/London",
17
+ "new york": "America/New_York",
18
+ "tokyo": "Asia/Tokyo",
19
+ "sydney": "Australia/Sydney",
20
+ "paris": "Europe/Paris",
21
+ }
22
+ tz_name = TIMEZONES.get(city.lower())
23
+ if not tz_name:
24
+ return {"status": "error", "message": f"Timezone for '{city}' not found."}
25
+ now = datetime.datetime.now(ZoneInfo(tz_name))
26
+ return {
27
+ "status": "success",
28
+ "city": city,
29
+ "time": now.strftime("%Y-%m-%d %H:%M:%S %Z"),
30
+ }
31
+
32
+
33
+ root_agent = Agent(
34
+ name="{{PROJECT_NAME}}",
35
+ model={{MODEL_EXPR}},
36
+ description="A helpful AI assistant.",
37
+ instruction="""
38
+ You are a helpful and concise AI assistant.
39
+ Use available tools when relevant to answer the user's question.
40
+ Always be accurate, friendly, and brief.
41
+ """,
42
+ tools=[get_current_time],
43
+ )
@@ -0,0 +1,35 @@
1
+ Metadata-Version: 2.4
2
+ Name: create-google-adk-agent
3
+ Version: 1.0.0
4
+ Summary: Interactive one-command scaffold for Google ADK (Agent Development Kit) projects
5
+ Home-page: https://github.com/unrealandychan/create-adk-agent
6
+ Author: unrealandychan
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Requires-Python: >=3.11
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: inquirerpy>=0.3.4
12
+ Dynamic: author
13
+ Dynamic: classifier
14
+ Dynamic: description
15
+ Dynamic: description-content-type
16
+ Dynamic: home-page
17
+ Dynamic: requires-dist
18
+ Dynamic: requires-python
19
+ Dynamic: summary
20
+
21
+ # create-google-adk-agent
22
+
23
+ Interactive one-command scaffold for [Google ADK](https://google.github.io/adk-docs/) projects.
24
+
25
+ ```bash
26
+ uvx create-google-adk-agent
27
+ # or
28
+ npx create-google-adk-agent
29
+ ```
30
+
31
+ Supports:
32
+ - **3 agent types**: single, multi-agent, agentic RAG
33
+ - **5 LLM providers**: Google AI Studio, Vertex AI, OpenAI, Anthropic, Ollama
34
+ - Copilot instructions pre-wired
35
+ - `uv` + `adk web` ready out of the box
@@ -0,0 +1,25 @@
1
+ README.md
2
+ setup.py
3
+ create_adk_agent/__init__.py
4
+ create_adk_agent/cli.py
5
+ create_adk_agent/template/agentic_rag/tests/test_agent.py
6
+ create_adk_agent/template/agentic_rag/{{PROJECT_NAME}}/__init__.py
7
+ create_adk_agent/template/agentic_rag/{{PROJECT_NAME}}/agent.py
8
+ create_adk_agent/template/base/Makefile
9
+ create_adk_agent/template/base/README.md
10
+ create_adk_agent/template/base/_dot_env.example
11
+ create_adk_agent/template/base/_dot_gitignore
12
+ create_adk_agent/template/base/pyproject.toml
13
+ create_adk_agent/template/base/_dot_github/copilot-instructions.md
14
+ create_adk_agent/template/multi/tests/test_agent.py
15
+ create_adk_agent/template/multi/{{PROJECT_NAME}}/__init__.py
16
+ create_adk_agent/template/multi/{{PROJECT_NAME}}/agent.py
17
+ create_adk_agent/template/single/tests/test_agent.py
18
+ create_adk_agent/template/single/{{PROJECT_NAME}}/__init__.py
19
+ create_adk_agent/template/single/{{PROJECT_NAME}}/agent.py
20
+ create_google_adk_agent.egg-info/PKG-INFO
21
+ create_google_adk_agent.egg-info/SOURCES.txt
22
+ create_google_adk_agent.egg-info/dependency_links.txt
23
+ create_google_adk_agent.egg-info/entry_points.txt
24
+ create_google_adk_agent.egg-info/requires.txt
25
+ create_google_adk_agent.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ create-google-adk-agent = create_adk_agent.cli:main
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,32 @@
1
+
2
+ from setuptools import setup, find_packages
3
+ import os
4
+
5
+ # Collect all template files
6
+ def get_package_data():
7
+ data = []
8
+ for root, dirs, files in os.walk("create_adk_agent/template"):
9
+ for f in files:
10
+ rel = os.path.relpath(os.path.join(root, f), "create_adk_agent")
11
+ data.append(rel)
12
+ return data
13
+
14
+ setup(
15
+ name="create-google-adk-agent",
16
+ version="1.0.0",
17
+ description="Interactive one-command scaffold for Google ADK (Agent Development Kit) projects",
18
+ long_description=open("README.md").read(),
19
+ long_description_content_type="text/markdown",
20
+ author="unrealandychan",
21
+ url="https://github.com/unrealandychan/create-adk-agent",
22
+ packages=find_packages(),
23
+ package_data={"create_adk_agent": get_package_data()},
24
+ include_package_data=True,
25
+ entry_points={"console_scripts": ["create-google-adk-agent=create_adk_agent.cli:main"]},
26
+ python_requires=">=3.11",
27
+ install_requires=["inquirerpy>=0.3.4"],
28
+ classifiers=[
29
+ "Programming Language :: Python :: 3",
30
+ "License :: OSI Approved :: MIT License",
31
+ ],
32
+ )