agent-starter-pack 0.18.2__py3-none-any.whl → 0.21.0__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.
Files changed (114) hide show
  1. agent_starter_pack/agents/{langgraph_base_react → adk_a2a_base}/.template/templateconfig.yaml +5 -12
  2. agent_starter_pack/agents/adk_a2a_base/README.md +37 -0
  3. agent_starter_pack/{frontends/streamlit/frontend/style/app_markdown.py → agents/adk_a2a_base/app/__init__.py} +3 -23
  4. agent_starter_pack/agents/adk_a2a_base/app/agent.py +70 -0
  5. agent_starter_pack/agents/adk_a2a_base/notebooks/adk_a2a_app_testing.ipynb +583 -0
  6. agent_starter_pack/agents/{crewai_coding_crew/notebooks/evaluating_crewai_agent.ipynb → adk_a2a_base/notebooks/evaluating_adk_agent.ipynb} +163 -199
  7. agent_starter_pack/agents/adk_a2a_base/tests/integration/test_agent.py +58 -0
  8. agent_starter_pack/agents/adk_base/app/__init__.py +2 -2
  9. agent_starter_pack/agents/adk_base/app/agent.py +3 -0
  10. agent_starter_pack/agents/adk_base/notebooks/adk_app_testing.ipynb +13 -28
  11. agent_starter_pack/agents/adk_live/app/__init__.py +17 -0
  12. agent_starter_pack/agents/adk_live/app/agent.py +3 -0
  13. agent_starter_pack/agents/agentic_rag/app/__init__.py +2 -2
  14. agent_starter_pack/agents/agentic_rag/app/agent.py +3 -0
  15. agent_starter_pack/agents/agentic_rag/notebooks/adk_app_testing.ipynb +13 -28
  16. agent_starter_pack/agents/{crewai_coding_crew → langgraph_base}/.template/templateconfig.yaml +12 -9
  17. agent_starter_pack/agents/langgraph_base/README.md +30 -0
  18. agent_starter_pack/agents/langgraph_base/app/__init__.py +17 -0
  19. agent_starter_pack/agents/{langgraph_base_react → langgraph_base}/app/agent.py +4 -4
  20. agent_starter_pack/agents/{langgraph_base_react → langgraph_base}/tests/integration/test_agent.py +1 -1
  21. agent_starter_pack/base_template/.gitignore +4 -2
  22. agent_starter_pack/base_template/Makefile +110 -16
  23. agent_starter_pack/base_template/README.md +97 -12
  24. agent_starter_pack/base_template/deployment/terraform/dev/apis.tf +4 -6
  25. agent_starter_pack/base_template/deployment/terraform/dev/providers.tf +5 -1
  26. agent_starter_pack/base_template/deployment/terraform/dev/variables.tf +5 -3
  27. agent_starter_pack/base_template/deployment/terraform/dev/{% if cookiecutter.is_adk %}telemetry.tf{% else %}unused_telemetry.tf{% endif %} +193 -0
  28. agent_starter_pack/base_template/deployment/terraform/github.tf +16 -9
  29. agent_starter_pack/base_template/deployment/terraform/locals.tf +7 -7
  30. agent_starter_pack/base_template/deployment/terraform/providers.tf +5 -1
  31. agent_starter_pack/base_template/deployment/terraform/sql/completions.sql +138 -0
  32. agent_starter_pack/base_template/deployment/terraform/storage.tf +0 -9
  33. agent_starter_pack/base_template/deployment/terraform/variables.tf +15 -19
  34. agent_starter_pack/base_template/deployment/terraform/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}build_triggers.tf{% else %}unused_build_triggers.tf{% endif %} +20 -22
  35. agent_starter_pack/base_template/deployment/terraform/{% if cookiecutter.is_adk %}telemetry.tf{% else %}unused_telemetry.tf{% endif %} +206 -0
  36. agent_starter_pack/base_template/pyproject.toml +5 -17
  37. agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/deploy-to-prod.yaml +19 -4
  38. agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/staging.yaml +36 -11
  39. agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}.cloudbuild{% else %}unused_.cloudbuild{% endif %}/deploy-to-prod.yaml +24 -5
  40. agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}.cloudbuild{% else %}unused_.cloudbuild{% endif %}/staging.yaml +44 -9
  41. agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/telemetry.py +96 -0
  42. agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/{utils → app_utils}/typing.py +4 -6
  43. agent_starter_pack/{agents/crewai_coding_crew/app/crew/config/agents.yaml → base_template/{{cookiecutter.agent_directory}}/app_utils/{% if cookiecutter.is_a2a and cookiecutter.agent_name == 'langgraph_base' %}converters{% else %}unused_converters{% endif %}/__init__.py } +9 -23
  44. agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/{% if cookiecutter.is_a2a and cookiecutter.agent_name == 'langgraph_base' %}converters{% else %}unused_converters{% endif %}/part_converter.py +138 -0
  45. agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/{% if cookiecutter.is_a2a and cookiecutter.agent_name == 'langgraph_base' %}executor{% else %}unused_executor{% endif %}/__init__.py +13 -0
  46. agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/{% if cookiecutter.is_a2a and cookiecutter.agent_name == 'langgraph_base' %}executor{% else %}unused_executor{% endif %}/a2a_agent_executor.py +265 -0
  47. agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/{% if cookiecutter.is_a2a and cookiecutter.agent_name == 'langgraph_base' %}executor{% else %}unused_executor{% endif %}/task_result_aggregator.py +152 -0
  48. agent_starter_pack/cli/commands/create.py +40 -4
  49. agent_starter_pack/cli/commands/enhance.py +1 -1
  50. agent_starter_pack/cli/commands/register_gemini_enterprise.py +1070 -0
  51. agent_starter_pack/cli/main.py +2 -0
  52. agent_starter_pack/cli/utils/cicd.py +20 -4
  53. agent_starter_pack/cli/utils/template.py +257 -25
  54. agent_starter_pack/deployment_targets/agent_engine/tests/integration/test_agent_engine_app.py +113 -16
  55. agent_starter_pack/deployment_targets/agent_engine/tests/load_test/README.md +2 -2
  56. agent_starter_pack/deployment_targets/agent_engine/tests/load_test/load_test.py +178 -9
  57. agent_starter_pack/deployment_targets/agent_engine/tests/{% if cookiecutter.is_a2a %}helpers.py{% else %}unused_helpers.py{% endif %} +138 -0
  58. agent_starter_pack/deployment_targets/agent_engine/{{cookiecutter.agent_directory}}/agent_engine_app.py +193 -307
  59. agent_starter_pack/deployment_targets/agent_engine/{{cookiecutter.agent_directory}}/app_utils/deploy.py +414 -0
  60. agent_starter_pack/deployment_targets/agent_engine/{{cookiecutter.agent_directory}}/{utils → app_utils}/{% if cookiecutter.is_adk_live %}expose_app.py{% else %}unused_expose_app.py{% endif %} +13 -14
  61. agent_starter_pack/deployment_targets/cloud_run/Dockerfile +4 -1
  62. agent_starter_pack/deployment_targets/cloud_run/deployment/terraform/dev/service.tf +85 -86
  63. agent_starter_pack/deployment_targets/cloud_run/deployment/terraform/service.tf +139 -107
  64. agent_starter_pack/deployment_targets/cloud_run/tests/integration/test_server_e2e.py +228 -12
  65. agent_starter_pack/deployment_targets/cloud_run/tests/load_test/README.md +4 -4
  66. agent_starter_pack/deployment_targets/cloud_run/tests/load_test/load_test.py +92 -12
  67. agent_starter_pack/deployment_targets/cloud_run/{{cookiecutter.agent_directory}}/{server.py → fast_api_app.py} +194 -121
  68. agent_starter_pack/frontends/adk_live_react/frontend/package-lock.json +18 -18
  69. agent_starter_pack/frontends/adk_live_react/frontend/src/multimodal-live-types.ts +5 -3
  70. agent_starter_pack/resources/docs/adk-cheatsheet.md +198 -41
  71. agent_starter_pack/resources/locks/uv-adk_a2a_base-agent_engine.lock +4966 -0
  72. agent_starter_pack/resources/locks/uv-adk_a2a_base-cloud_run.lock +5011 -0
  73. agent_starter_pack/resources/locks/uv-adk_base-agent_engine.lock +1443 -709
  74. agent_starter_pack/resources/locks/uv-adk_base-cloud_run.lock +1058 -874
  75. agent_starter_pack/resources/locks/uv-adk_live-agent_engine.lock +1443 -709
  76. agent_starter_pack/resources/locks/uv-adk_live-cloud_run.lock +1058 -874
  77. agent_starter_pack/resources/locks/uv-agentic_rag-agent_engine.lock +1568 -749
  78. agent_starter_pack/resources/locks/uv-agentic_rag-cloud_run.lock +1123 -929
  79. agent_starter_pack/resources/locks/{uv-langgraph_base_react-agent_engine.lock → uv-langgraph_base-agent_engine.lock} +1714 -1689
  80. agent_starter_pack/resources/locks/{uv-langgraph_base_react-cloud_run.lock → uv-langgraph_base-cloud_run.lock} +1285 -2374
  81. agent_starter_pack/utils/watch_and_rebuild.py +1 -1
  82. {agent_starter_pack-0.18.2.dist-info → agent_starter_pack-0.21.0.dist-info}/METADATA +3 -6
  83. {agent_starter_pack-0.18.2.dist-info → agent_starter_pack-0.21.0.dist-info}/RECORD +89 -93
  84. agent_starter_pack-0.21.0.dist-info/entry_points.txt +2 -0
  85. llm.txt +4 -5
  86. agent_starter_pack/agents/crewai_coding_crew/README.md +0 -34
  87. agent_starter_pack/agents/crewai_coding_crew/app/agent.py +0 -47
  88. agent_starter_pack/agents/crewai_coding_crew/app/crew/config/tasks.yaml +0 -37
  89. agent_starter_pack/agents/crewai_coding_crew/app/crew/crew.py +0 -71
  90. agent_starter_pack/agents/crewai_coding_crew/tests/integration/test_agent.py +0 -47
  91. agent_starter_pack/agents/langgraph_base_react/README.md +0 -9
  92. agent_starter_pack/agents/langgraph_base_react/notebooks/evaluating_langgraph_agent.ipynb +0 -1574
  93. agent_starter_pack/base_template/deployment/terraform/dev/log_sinks.tf +0 -69
  94. agent_starter_pack/base_template/deployment/terraform/log_sinks.tf +0 -79
  95. agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/utils/tracing.py +0 -155
  96. agent_starter_pack/cli/utils/register_gemini_enterprise.py +0 -406
  97. agent_starter_pack/deployment_targets/agent_engine/deployment/terraform/{% if not cookiecutter.is_adk_live %}service.tf{% else %}unused_service.tf{% endif %} +0 -82
  98. agent_starter_pack/deployment_targets/agent_engine/notebooks/intro_agent_engine.ipynb +0 -1025
  99. agent_starter_pack/deployment_targets/agent_engine/{{cookiecutter.agent_directory}}/utils/deployment.py +0 -99
  100. agent_starter_pack/frontends/streamlit/frontend/side_bar.py +0 -214
  101. agent_starter_pack/frontends/streamlit/frontend/streamlit_app.py +0 -265
  102. agent_starter_pack/frontends/streamlit/frontend/utils/chat_utils.py +0 -67
  103. agent_starter_pack/frontends/streamlit/frontend/utils/local_chat_history.py +0 -127
  104. agent_starter_pack/frontends/streamlit/frontend/utils/message_editing.py +0 -59
  105. agent_starter_pack/frontends/streamlit/frontend/utils/multimodal_utils.py +0 -217
  106. agent_starter_pack/frontends/streamlit/frontend/utils/stream_handler.py +0 -310
  107. agent_starter_pack/frontends/streamlit/frontend/utils/title_summary.py +0 -94
  108. agent_starter_pack/resources/locks/uv-crewai_coding_crew-agent_engine.lock +0 -6650
  109. agent_starter_pack/resources/locks/uv-crewai_coding_crew-cloud_run.lock +0 -7825
  110. agent_starter_pack-0.18.2.dist-info/entry_points.txt +0 -3
  111. /agent_starter_pack/agents/{crewai_coding_crew → langgraph_base}/notebooks/evaluating_langgraph_agent.ipynb +0 -0
  112. /agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/{utils → app_utils}/gcs.py +0 -0
  113. {agent_starter_pack-0.18.2.dist-info → agent_starter_pack-0.21.0.dist-info}/WHEEL +0 -0
  114. {agent_starter_pack-0.18.2.dist-info → agent_starter_pack-0.21.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,58 @@
1
+ # Copyright 2025 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # mypy: disable-error-code="union-attr"
16
+ from google.adk.agents.run_config import RunConfig, StreamingMode
17
+ from google.adk.runners import Runner
18
+ from google.adk.sessions import InMemorySessionService
19
+ from google.genai import types
20
+
21
+ from {{cookiecutter.agent_directory}}.agent import root_agent
22
+
23
+
24
+ def test_agent_stream() -> None:
25
+ """
26
+ Integration test for the agent stream functionality.
27
+ Tests that the agent returns valid streaming responses.
28
+ """
29
+
30
+ session_service = InMemorySessionService()
31
+
32
+ session = session_service.create_session_sync(user_id="test_user", app_name="test")
33
+ runner = Runner(agent=root_agent, session_service=session_service, app_name="test")
34
+
35
+ message = types.Content(
36
+ role="user", parts=[types.Part.from_text(text="Why is the sky blue?")]
37
+ )
38
+
39
+ events = list(
40
+ runner.run(
41
+ new_message=message,
42
+ user_id="test_user",
43
+ session_id=session.id,
44
+ run_config=RunConfig(streaming_mode=StreamingMode.SSE),
45
+ )
46
+ )
47
+ assert len(events) > 0, "Expected at least one message"
48
+
49
+ has_text_content = False
50
+ for event in events:
51
+ if (
52
+ event.content
53
+ and event.content.parts
54
+ and any(part.text for part in event.content.parts)
55
+ ):
56
+ has_text_content = True
57
+ break
58
+ assert has_text_content, "Expected at least one message with text content"
@@ -12,6 +12,6 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- from .agent import root_agent
15
+ from .agent import app
16
16
 
17
- __all__ = ["root_agent"]
17
+ __all__ = ["app"]
@@ -18,6 +18,7 @@ from zoneinfo import ZoneInfo
18
18
 
19
19
  import google.auth
20
20
  from google.adk.agents import Agent
21
+ from google.adk.apps.app import App
21
22
 
22
23
  _, project_id = google.auth.default()
23
24
  os.environ.setdefault("GOOGLE_CLOUD_PROJECT", project_id)
@@ -64,3 +65,5 @@ root_agent = Agent(
64
65
  instruction="You are a helpful AI assistant designed to provide accurate and useful information.",
65
66
  tools=[get_weather, get_current_time],
66
67
  )
68
+
69
+ app = App(root_agent=root_agent, name="app")
@@ -16,7 +16,9 @@
16
16
  "cell_type": "markdown",
17
17
  "metadata": {},
18
18
  "source": [
19
- "## Install dependencies"
19
+ "## Set Up Your Environment\n",
20
+ "\n",
21
+ "> **Note:** For best results, use the same `.venv` created for local development with `uv` to ensure dependency compatibility and avoid environment-related issues."
20
22
  ]
21
23
  },
22
24
  {
@@ -25,7 +27,11 @@
25
27
  "metadata": {},
26
28
  "outputs": [],
27
29
  "source": [
28
- "!pip install google-cloud-aiplatform --upgrade"
30
+ "# Uncomment the following lines if you're not using the virtual environment created by uv\n",
31
+ "# import sys\n",
32
+ "\n",
33
+ "# sys.path.append(\"../\")\n",
34
+ "# !pip install google-cloud-aiplatform a2a-sdk --upgrade"
29
35
  ]
30
36
  },
31
37
  {
@@ -123,16 +129,7 @@
123
129
  "execution_count": null,
124
130
  "metadata": {},
125
131
  "outputs": [],
126
- "source": [
127
- "remote_agent_engine.register_feedback(\n",
128
- " feedback={\n",
129
- " \"score\": 5,\n",
130
- " \"text\": \"Great response!\",\n",
131
- " \"invocation_id\": \"test-invocation-123\",\n",
132
- " \"user_id\": \"test\",\n",
133
- " }\n",
134
- ")"
135
- ]
132
+ "source": "remote_agent_engine.register_feedback(\n feedback={\n \"score\": 5,\n \"text\": \"Great response!\",\n \"user_id\": \"test-user-123\",\n \"session_id\": \"test-session-123\",\n }\n)"
136
133
  },
137
134
  {
138
135
  "cell_type": "markdown",
@@ -154,21 +151,9 @@
154
151
  "metadata": {},
155
152
  "outputs": [],
156
153
  "source": [
157
- "# Uncomment the following lines if you're not using the virtual environment created by uv\n",
158
- "# import sys\n",
159
- "# sys.path.append(\"../\")"
160
- ]
161
- },
162
- {
163
- "cell_type": "code",
164
- "execution_count": null,
165
- "metadata": {},
166
- "outputs": [],
167
- "source": [
168
- "from app.agent import root_agent\n",
169
- "from app.agent_engine_app import AgentEngineApp\n",
154
+ "from app.agent_engine_app import agent_engine\n",
170
155
  "\n",
171
- "agent_engine = AgentEngineApp(agent=root_agent)"
156
+ "agent_engine.set_up()"
172
157
  ]
173
158
  },
174
159
  {
@@ -360,7 +345,7 @@
360
345
  ],
361
346
  "metadata": {
362
347
  "kernelspec": {
363
- "display_name": "myagent-1758791726",
348
+ "display_name": "myagent-1762384391",
364
349
  "language": "python",
365
350
  "name": "python3"
366
351
  },
@@ -379,4 +364,4 @@
379
364
  },
380
365
  "nbformat": 4,
381
366
  "nbformat_minor": 2
382
- }
367
+ }
@@ -0,0 +1,17 @@
1
+ # Copyright 2025 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from .agent import app
16
+
17
+ __all__ = ["app"]
@@ -17,6 +17,7 @@ import os
17
17
  import google.auth
18
18
  import vertexai
19
19
  from google.adk.agents import Agent
20
+ from google.adk.apps.app import App
20
21
 
21
22
  _, project_id = google.auth.default()
22
23
  os.environ.setdefault("GOOGLE_CLOUD_PROJECT", project_id)
@@ -46,3 +47,5 @@ root_agent = Agent(
46
47
  instruction="You are a helpful AI assistant designed to provide accurate and useful information.",
47
48
  tools=[get_weather],
48
49
  )
50
+
51
+ app = App(root_agent=root_agent, name="app")
@@ -12,6 +12,6 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- from .agent import root_agent
15
+ from .agent import app
16
16
 
17
- __all__ = ["root_agent"]
17
+ __all__ = ["app"]
@@ -18,6 +18,7 @@ import os
18
18
  import google
19
19
  import vertexai
20
20
  from google.adk.agents import Agent
21
+ from google.adk.apps.app import App
21
22
  from langchain_google_vertexai import VertexAIEmbeddings
22
23
 
23
24
  from {{cookiecutter.agent_directory}}.retrievers import get_compressor, get_retriever
@@ -115,3 +116,5 @@ root_agent = Agent(
115
116
  instruction=instruction,
116
117
  tools=[retrieve_docs],
117
118
  )
119
+
120
+ app = App(root_agent=root_agent, name="app")
@@ -16,7 +16,9 @@
16
16
  "cell_type": "markdown",
17
17
  "metadata": {},
18
18
  "source": [
19
- "## Install dependencies"
19
+ "## Set Up Your Environment\n",
20
+ "\n",
21
+ "> **Note:** For best results, use the same `.venv` created for local development with `uv` to ensure dependency compatibility and avoid environment-related issues."
20
22
  ]
21
23
  },
22
24
  {
@@ -25,7 +27,11 @@
25
27
  "metadata": {},
26
28
  "outputs": [],
27
29
  "source": [
28
- "!pip install google-cloud-aiplatform --upgrade"
30
+ "# Uncomment the following lines if you're not using the virtual environment created by uv\n",
31
+ "# import sys\n",
32
+ "\n",
33
+ "# sys.path.append(\"../\")\n",
34
+ "# !pip install google-cloud-aiplatform a2a-sdk --upgrade"
29
35
  ]
30
36
  },
31
37
  {
@@ -123,16 +129,7 @@
123
129
  "execution_count": null,
124
130
  "metadata": {},
125
131
  "outputs": [],
126
- "source": [
127
- "remote_agent_engine.register_feedback(\n",
128
- " feedback={\n",
129
- " \"score\": 5,\n",
130
- " \"text\": \"Great response!\",\n",
131
- " \"invocation_id\": \"test-invocation-123\",\n",
132
- " \"user_id\": \"test\",\n",
133
- " }\n",
134
- ")"
135
- ]
132
+ "source": "remote_agent_engine.register_feedback(\n feedback={\n \"score\": 5,\n \"text\": \"Great response!\",\n \"user_id\": \"test-user-123\",\n \"session_id\": \"test-session-123\",\n }\n)"
136
133
  },
137
134
  {
138
135
  "cell_type": "markdown",
@@ -154,21 +151,9 @@
154
151
  "metadata": {},
155
152
  "outputs": [],
156
153
  "source": [
157
- "# Uncomment the following lines if you're not using the virtual environment created by uv\n",
158
- "# import sys\n",
159
- "# sys.path.append(\"../\")"
160
- ]
161
- },
162
- {
163
- "cell_type": "code",
164
- "execution_count": null,
165
- "metadata": {},
166
- "outputs": [],
167
- "source": [
168
- "from app.agent import root_agent\n",
169
- "from app.agent_engine_app import AgentEngineApp\n",
154
+ "from app.agent_engine_app import agent_engine\n",
170
155
  "\n",
171
- "agent_engine = AgentEngineApp(agent=root_agent)"
156
+ "agent_engine.set_up()"
172
157
  ]
173
158
  },
174
159
  {
@@ -360,7 +345,7 @@
360
345
  ],
361
346
  "metadata": {
362
347
  "kernelspec": {
363
- "display_name": "myagent-1758791726",
348
+ "display_name": "myagent-1762384391",
364
349
  "language": "python",
365
350
  "name": "python3"
366
351
  },
@@ -379,4 +364,4 @@
379
364
  },
380
365
  "nbformat": 4,
381
366
  "nbformat_minor": 2
382
- }
367
+ }
@@ -12,17 +12,20 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- description: "A multi-agent system implemented with CrewAI created to support coding activities"
15
+ description: "A base ReAct agent implemented using LangGraph with Agent2Agent (A2A) Protocol support"
16
16
  settings:
17
17
  requires_data_ingestion: false
18
18
  deployment_targets: ["agent_engine", "cloud_run"]
19
19
  extra_dependencies: [
20
- "langchain-google-vertexai~=2.0.22",
21
- "langchain~=0.3.14",
22
- "langchain-community~=0.3.17",
23
- "langchain-openai~=0.3.5",
24
- "langgraph~=0.6.2",
25
- "crewai~=0.152.0"
20
+ "langchain-google-vertexai>=3.0.3",
21
+ "langchain~=1.0.7",
22
+ "langgraph~=1.0.3",
23
+ "langchain-community~=0.4.1",
24
+ "a2a-sdk[http-server]~=0.3.12",
25
+ "nest-asyncio>=1.6.0,<2.0.0",
26
+ "traceloop-sdk>=0.10.0,<1.0.0",
27
+ "opentelemetry-exporter-gcp-trace>=1.9.0,<2.0.0",
26
28
  ]
27
- frontend_type: "streamlit"
28
- example_question: "How can I implement a function to sort a list in Python?"
29
+ tags: ["langgraph", "a2a"]
30
+ frontend_type: "inspector"
31
+ example_question: "What's the weather in San Francisco?"
@@ -0,0 +1,30 @@
1
+ # LangGraph Base ReAct Agent with A2A Protocol
2
+
3
+ <p align="center">
4
+ <img src="https://langchain-ai.github.io/langgraph/static/wordmark_dark.svg" width="50%" alt="LangGraph Logo" style="margin-right: 40px; vertical-align: middle;">
5
+ <img src="https://github.com/a2aproject/A2A/blob/main/docs/assets/a2a-logo-white.svg?raw=true" width="40%" alt="A2A Logo" style="vertical-align: middle;">
6
+ </p>
7
+
8
+ A base ReAct agent built using **[LangGraph](https://docs.langchain.com/oss/python/langgraph/overview)** with **[Agent2Agent (A2A) Protocol](https://a2a-protocol.org/)** support. This example demonstrates how to build a LangGraph-based agent with distributed agent communication capabilities through the A2A protocol for interoperability with agents across different frameworks and languages.
9
+
10
+ ## Key Features
11
+
12
+ - **Simple Architecture**: Shows the basic building blocks of a LangGraph agent
13
+ - **A2A Protocol Support**: Enables distributed agent communication and interoperability
14
+ - **Streaming Support**: Includes streaming response capability using Vertex AI
15
+ - **Sample Tool Integration**: Includes a basic search tool to demonstrate tool usage
16
+
17
+ ## Validating Your A2A Implementation
18
+
19
+ This template includes the **[A2A Protocol Inspector](https://github.com/a2aproject/a2a-inspector)** for validating your agent's A2A implementation.
20
+
21
+ ```bash
22
+ make inspector
23
+ ```
24
+
25
+ The inspector now supports both JSON-RPC 2.0 (Cloud Run) and HTTP-JSON (Agent Engine) transport protocols:
26
+
27
+ - **Cloud Run**: Test locally at `http://localhost:8000` or connect to your deployed Cloud Run URL
28
+ - **Agent Engine**: Must deploy first, then connect to your deployed Agent Engine URL (local testing not available)
29
+
30
+ For detailed setup instructions including local and remote testing workflows, refer to the `README.md` in your generated project.
@@ -0,0 +1,17 @@
1
+ # Copyright 2025 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from .agent import root_agent
16
+
17
+ __all__ = ["root_agent"]
@@ -12,9 +12,9 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- # mypy: disable-error-code="union-attr"
15
+ from langchain.agents import create_agent
16
16
  from langchain_google_vertexai import ChatVertexAI
17
- from langgraph.prebuilt import create_react_agent
17
+ from langgraph.graph.state import CompiledStateGraph
18
18
 
19
19
  LOCATION = "global"
20
20
  LLM = "gemini-2.5-flash"
@@ -29,6 +29,6 @@ def get_weather(query: str) -> str:
29
29
  return "It's 90 degrees and sunny."
30
30
 
31
31
 
32
- agent = create_react_agent(
33
- model=llm, tools=[get_weather], prompt="You are a helpful assistant"
32
+ root_agent: CompiledStateGraph = create_agent(
33
+ model=llm, tools=[get_weather], system_prompt="You are a helpful assistant"
34
34
  )
@@ -13,7 +13,7 @@
13
13
  # limitations under the License.
14
14
 
15
15
  # mypy: ignore-errors
16
- from {{cookiecutter.agent_directory}}.agent import agent
16
+ from {{cookiecutter.agent_directory}}.agent import root_agent as agent
17
17
 
18
18
 
19
19
  def test_agent_stream() -> None:
@@ -189,9 +189,11 @@ Thumbs.db
189
189
  .persist_vector_store
190
190
  tests/load_test/.results/*.html
191
191
  tests/load_test/.results/*.csv
192
- locust_env
192
+ .locust_env
193
193
  my_env.tfvars
194
- .streamlit_chats
195
194
  .saved_chats
196
195
  .env
197
196
  .requirements.txt
197
+
198
+ # A2A Inspector
199
+ tools/a2a-inspector/
@@ -8,7 +8,7 @@ install:
8
8
  {%- if cookiecutter.settings.get("commands", {}).get("override", {}).get("install") %}
9
9
  {{cookiecutter.settings.get("commands", {}).get("override", {}).get("install")}}
10
10
  {%- else %}
11
- uv sync --dev{% if not cookiecutter.is_adk and not cookiecutter.is_adk_live %} --extra streamlit{%- endif %}{% if cookiecutter.is_adk_live %} && (cd frontend && npm install){%- endif %}
11
+ uv sync{% if cookiecutter.is_adk_live %} && (cd frontend && npm install){%- endif %}
12
12
  {%- endif %}
13
13
 
14
14
  # ==============================================================================
@@ -38,17 +38,29 @@ playground:{%- if cookiecutter.is_adk_live %} build-frontend-if-needed{%- endif
38
38
  @echo "==============================================================================="
39
39
  {%- if cookiecutter.is_adk_live %}
40
40
  {%- if cookiecutter.deployment_target == 'agent_engine' %}
41
- uv run python -m {{cookiecutter.agent_directory}}.utils.expose_app --mode local --local-agent {{cookiecutter.agent_directory}}.agent.root_agent
41
+ uv run python -m {{cookiecutter.agent_directory}}.app_utils.expose_app --mode local --local-agent {{cookiecutter.agent_directory}}.agent.root_agent
42
42
  {%- else %}
43
- uv run uvicorn {{cookiecutter.agent_directory}}.server:app --host localhost --port 8000 --reload
43
+ uv run uvicorn {{cookiecutter.agent_directory}}.fast_api_app:app --host localhost --port 8000 --reload
44
44
  {%- endif %}
45
45
  {%- elif cookiecutter.is_adk %}
46
46
  uv run adk web . --port 8501 --reload_agents
47
- {%- else %}
47
+ {%- elif cookiecutter.is_a2a %}
48
48
  {%- if cookiecutter.deployment_target == 'cloud_run' %}
49
- uv run uvicorn {{cookiecutter.agent_directory}}.server:app --host localhost --port 8000 --reload &
49
+ uv run uvicorn {{cookiecutter.agent_directory}}.fast_api_app:app --host localhost --port 8000 --reload &
50
+ $(MAKE) inspector
51
+ {%- else %}
52
+ {%- if cookiecutter.agent_name == 'langgraph_base' %}
53
+ @echo "ℹ️ Note: Local playground not supported for LangGraph on Agent Engine."
54
+ @echo " To test your agent, deploy first with 'make deploy' then use 'make inspector'."
55
+ {%- else %}
56
+ @echo "ℹ️ Note: Local playground uses ADK web interface (not A2A endpoints)."
57
+ @echo " To test A2A protocol, deploy first with 'make deploy' then use 'make inspector'."
58
+ @echo ""
59
+ uv run adk web . --port 8501 --reload_agents
50
60
  {%- endif %}
51
- {% if cookiecutter.deployment_target == 'agent_engine' %}PYTHONPATH=. {% endif %}uv run streamlit run frontend/streamlit_app.py --browser.serverAddress=localhost --server.enableCORS=false --server.enableXsrfProtection=false
61
+ {%- endif %}
62
+ {%- else %}
63
+ uv run uvicorn {{cookiecutter.agent_directory}}.fast_api_app:app --host localhost --port 8000 --reload
52
64
  {%- endif %}
53
65
  {%- endif %}
54
66
  {%- if cookiecutter.settings.get("commands", {}).get("extra", {}) %}
@@ -88,9 +100,9 @@ playground:{%- if cookiecutter.is_adk_live %} build-frontend-if-needed{%- endif
88
100
  # Launch local development server with hot-reload
89
101
  local-backend:
90
102
  {%- if cookiecutter.deployment_target == 'cloud_run' %}
91
- uv run uvicorn {{cookiecutter.agent_directory}}.server:app --host localhost --port 8000 --reload
103
+ uv run uvicorn {{cookiecutter.agent_directory}}.fast_api_app:app --host localhost --port 8000 --reload
92
104
  {%- else %}
93
- uv run python -m {{cookiecutter.agent_directory}}.utils.expose_app --mode local --port 8000 --local-agent {{cookiecutter.agent_directory}}.agent.root_agent
105
+ uv run python -m {{cookiecutter.agent_directory}}.app_utils.expose_app --mode local --port 8000 --local-agent {{cookiecutter.agent_directory}}.agent.root_agent
94
106
  {%- endif %}
95
107
  {%- endif %}
96
108
  {%- if cookiecutter.is_adk_live %}
@@ -125,7 +137,7 @@ playground-remote: build-frontend-if-needed
125
137
  @echo "| 🌐 Access your app at: http://localhost:8000 |"
126
138
  @echo "| ☁️ Connected to deployed agent engine |"
127
139
  @echo "==============================================================================="
128
- uv run python -m {{cookiecutter.agent_directory}}.utils.expose_app --mode remote
140
+ uv run python -m {{cookiecutter.agent_directory}}.app_utils.expose_app --mode remote
129
141
  {%- endif %}
130
142
  {%- endif %}
131
143
  {%- if cookiecutter.is_adk_live and cookiecutter.deployment_target == 'agent_engine' %}
@@ -149,6 +161,68 @@ playground-dev:
149
161
  @echo "Starting frontend dev server..."
150
162
  $(MAKE) ui
151
163
  {%- endif %}
164
+ {%- if cookiecutter.is_a2a %}
165
+
166
+ # ==============================================================================
167
+ # A2A Protocol Inspector
168
+ # ==============================================================================
169
+
170
+ # Launch A2A Protocol Inspector to test your agent implementation
171
+ inspector: setup-inspector-if-needed build-inspector-if-needed
172
+ @echo "==============================================================================="
173
+ @echo "| 🔍 A2A Protocol Inspector |"
174
+ @echo "==============================================================================="
175
+ @echo "| 🌐 Inspector UI: http://localhost:5001 |"
176
+ @echo "| |"
177
+ {%- if cookiecutter.deployment_target == 'cloud_run' %}
178
+ @echo "| 💡 Testing Locally: |"
179
+ @echo "| Paste this URL into the inspector: |"
180
+ @echo "| http://localhost:8000/a2a/{{cookiecutter.agent_directory}}/.well-known/agent-card.json |"
181
+ @echo "| |"
182
+ {%- endif %}
183
+ @echo "| 💡 Testing Remote Deployment: |"
184
+ {%- if cookiecutter.deployment_target == 'cloud_run' %}
185
+ @echo "| Connect to your deployed Cloud Run URL |"
186
+ @echo "| 🔐 See README for authentication setup |"
187
+ {%- else %}
188
+ @echo "| Connect to your deployed Agent Engine URL |"
189
+ @echo "| 🔐 See README for authentication setup |"
190
+ @echo "| |"
191
+ @echo "| ℹ️ Note: Local testing requires deploying to Agent Engine first. |"
192
+ @echo "| Local 'make playground' uses ADK web interface (not A2A endpoints) |"
193
+ {%- endif %}
194
+ @echo "==============================================================================="
195
+ @echo ""
196
+ cd tools/a2a-inspector/backend && uv run app.py
197
+
198
+ # Internal: Setup inspector if not already present (runs once)
199
+ # TODO: Update to --branch v1.0.0 when a2a-inspector publishes releases
200
+ setup-inspector-if-needed:
201
+ @if [ ! -d "tools/a2a-inspector" ]; then \
202
+ echo "" && \
203
+ echo "📦 First-time setup: Installing A2A Inspector..." && \
204
+ echo "" && \
205
+ mkdir -p tools && \
206
+ git clone --quiet https://github.com/a2aproject/a2a-inspector.git tools/a2a-inspector && \
207
+ (cd tools/a2a-inspector && git -c advice.detachedHead=false checkout --quiet 893e4062f6fbd85a8369228ce862ebbf4a025694) && \
208
+ echo "📥 Installing Python dependencies..." && \
209
+ (cd tools/a2a-inspector && uv sync --quiet) && \
210
+ echo "📥 Installing Node.js dependencies..." && \
211
+ (cd tools/a2a-inspector/frontend && npm install --silent) && \
212
+ echo "🔨 Building frontend..." && \
213
+ (cd tools/a2a-inspector/frontend && npm run build --silent) && \
214
+ echo "" && \
215
+ echo "✅ A2A Inspector setup complete!" && \
216
+ echo ""; \
217
+ fi
218
+
219
+ # Internal: Build inspector frontend if needed
220
+ build-inspector-if-needed:
221
+ @if [ -d "tools/a2a-inspector" ] && [ ! -f "tools/a2a-inspector/frontend/public/script.js" ]; then \
222
+ echo "🔨 Building inspector frontend..."; \
223
+ cd tools/a2a-inspector/frontend && npm run build; \
224
+ fi
225
+ {%- endif %}
152
226
 
153
227
  # ==============================================================================
154
228
  # Backend Deployment Targets
@@ -161,6 +235,9 @@ playground-dev:
161
235
  deploy:
162
236
  {%- if cookiecutter.deployment_target == 'cloud_run' %}
163
237
  PROJECT_ID=$$(gcloud config get-value project) && \
238
+ {%- if cookiecutter.is_a2a %}
239
+ PROJECT_NUMBER=$$(gcloud projects describe $$PROJECT_ID --format="value(projectNumber)") && \
240
+ {%- endif %}
164
241
  gcloud beta run deploy {{cookiecutter.project_name}} \
165
242
  --source . \
166
243
  --memory "4Gi" \
@@ -169,14 +246,20 @@ deploy:
169
246
  --no-allow-unauthenticated \
170
247
  --no-cpu-throttling \
171
248
  --labels "{% if cookiecutter.is_adk %}created-by=adk{% if cookiecutter.agent_garden %},{% endif %}{% endif %}{% if cookiecutter.agent_garden %}deployed-with=agent-garden{% if cookiecutter.agent_sample_id %},vertex-agent-sample-id={{cookiecutter.agent_sample_id}},vertex-agent-sample-publisher={{cookiecutter.agent_sample_publisher}}{% endif %}{% endif %}" \
249
+ --update-build-env-vars "AGENT_VERSION=$(shell awk -F'"' '/^version = / {print $$2}' pyproject.toml || echo '0.0.0')" \
172
250
  --set-env-vars \
173
- "COMMIT_SHA=$(shell git rev-parse HEAD){%- if cookiecutter.data_ingestion %}{%- if cookiecutter.datastore_type == "vertex_ai_search" %},DATA_STORE_ID={{cookiecutter.project_name}}-datastore,DATA_STORE_REGION=us{%- elif cookiecutter.datastore_type == "vertex_ai_vector_search" %},VECTOR_SEARCH_INDEX={{cookiecutter.project_name}}-vector-search,VECTOR_SEARCH_INDEX_ENDPOINT={{cookiecutter.project_name}}-vector-search-endpoint,VECTOR_SEARCH_BUCKET=$$PROJECT_ID-{{cookiecutter.project_name}}-vs{%- endif %}{%- endif %}" \
251
+ "COMMIT_SHA=$(shell git rev-parse HEAD){%- if cookiecutter.is_a2a %},APP_URL=https://{{cookiecutter.project_name}}-$$PROJECT_NUMBER.us-central1.run.app{%- endif %}{%- if cookiecutter.data_ingestion %}{%- if cookiecutter.datastore_type == "vertex_ai_search" %},DATA_STORE_ID={{cookiecutter.project_name}}-datastore,DATA_STORE_REGION=us{%- elif cookiecutter.datastore_type == "vertex_ai_vector_search" %},VECTOR_SEARCH_INDEX={{cookiecutter.project_name}}-vector-search,VECTOR_SEARCH_INDEX_ENDPOINT={{cookiecutter.project_name}}-vector-search-endpoint,VECTOR_SEARCH_BUCKET=$$PROJECT_ID-{{cookiecutter.project_name}}-vs{%- endif %}{%- endif %}" \
174
252
  $(if $(IAP),--iap) \
175
253
  $(if $(PORT),--port=$(PORT))
176
254
  {%- elif cookiecutter.deployment_target == 'agent_engine' %}
177
255
  # Export dependencies to requirements file using uv export.
178
- uv export --no-hashes --no-header --no-dev --no-emit-project --no-annotate > .requirements.txt 2>/dev/null || \
179
- uv export --no-hashes --no-header --no-dev --no-emit-project > .requirements.txt && uv run {{cookiecutter.agent_directory}}/agent_engine_app.py
256
+ (uv export --no-hashes --no-header --no-dev --no-emit-project --no-annotate > {{cookiecutter.agent_directory}}/app_utils/.requirements.txt 2>/dev/null || \
257
+ uv export --no-hashes --no-header --no-dev --no-emit-project > {{cookiecutter.agent_directory}}/app_utils/.requirements.txt) && \
258
+ uv run -m {{cookiecutter.agent_directory}}.app_utils.deploy \
259
+ --source-packages=./{{cookiecutter.agent_directory}} \
260
+ --entrypoint-module={{cookiecutter.agent_directory}}.agent_engine_app \
261
+ --entrypoint-object=agent_engine \
262
+ --requirements-file={{cookiecutter.agent_directory}}/app_utils/.requirements.txt
180
263
  {%- endif %}
181
264
 
182
265
  # Alias for 'make deploy' for backward compatibility
@@ -222,6 +305,7 @@ data-ingestion:
222
305
 
223
306
  # Run unit and integration tests
224
307
  test:
308
+ uv sync --dev
225
309
  uv run pytest tests/unit && uv run pytest tests/integration
226
310
 
227
311
  # Run code quality checks (codespell, ruff, mypy)
@@ -231,15 +315,25 @@ lint:
231
315
  uv run ruff check . --diff
232
316
  uv run ruff format . --check --diff
233
317
  uv run mypy .
234
- {%- if cookiecutter.is_adk and cookiecutter.deployment_target == 'agent_engine' %}
318
+ {%- if (cookiecutter.is_a2a and cookiecutter.deployment_target == 'cloud_run') or (cookiecutter.is_adk and not cookiecutter.is_a2a and cookiecutter.deployment_target == 'agent_engine') %}
235
319
 
236
320
  # ==============================================================================
237
321
  # Gemini Enterprise Integration
238
322
  # ==============================================================================
239
323
 
240
324
  # Register the deployed agent to Gemini Enterprise
241
- # Usage: make register-gemini-enterprise ARGS="--gemini-enterprise-app-id=xxx --display-name='My Agent'"
242
- # Or set environment variables: GEMINI_ENTERPRISE_APP_ID, GEMINI_DISPLAY_NAME, GEMINI_DESCRIPTION, etc.
325
+ # Usage: make register-gemini-enterprise (interactive - will prompt for required details)
326
+ # For non-interactive use, set env vars: ID or GEMINI_ENTERPRISE_APP_ID (full GE resource name)
327
+ # Optional env vars: GEMINI_DISPLAY_NAME, GEMINI_DESCRIPTION{%- if cookiecutter.deployment_target == 'agent_engine' %}, GEMINI_TOOL_DESCRIPTION, AGENT_ENGINE_ID{%- endif %}{%- if cookiecutter.deployment_target == 'cloud_run' %}, AGENT_CARD_URL{%- endif %}
243
328
  register-gemini-enterprise:
244
- uvx --from agent-starter-pack agent-starter-pack-register-gemini-enterprise $(ARGS)
329
+ {%- if cookiecutter.deployment_target == 'cloud_run' and cookiecutter.is_a2a %}
330
+ @PROJECT_ID=$$(gcloud config get-value project 2>/dev/null) && \
331
+ PROJECT_NUMBER=$$(gcloud projects describe $$PROJECT_ID --format="value(projectNumber)" 2>/dev/null) && \
332
+ uvx agent-starter-pack@{{ cookiecutter.package_version }} register-gemini-enterprise \
333
+ --agent-card-url="https://{{cookiecutter.project_name}}-$$PROJECT_NUMBER.us-central1.run.app/a2a/{{cookiecutter.agent_directory}}/.well-known/agent-card.json" \
334
+ --deployment-target="{{cookiecutter.deployment_target}}" \
335
+ --project-number="$$PROJECT_NUMBER"
336
+ {%- else %}
337
+ @uvx agent-starter-pack@{{ cookiecutter.package_version }} register-gemini-enterprise
338
+ {%- endif %}
245
339
  {%- endif %}