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.
- agent_starter_pack/agents/{langgraph_base_react → adk_a2a_base}/.template/templateconfig.yaml +5 -12
- agent_starter_pack/agents/adk_a2a_base/README.md +37 -0
- agent_starter_pack/{frontends/streamlit/frontend/style/app_markdown.py → agents/adk_a2a_base/app/__init__.py} +3 -23
- agent_starter_pack/agents/adk_a2a_base/app/agent.py +70 -0
- agent_starter_pack/agents/adk_a2a_base/notebooks/adk_a2a_app_testing.ipynb +583 -0
- agent_starter_pack/agents/{crewai_coding_crew/notebooks/evaluating_crewai_agent.ipynb → adk_a2a_base/notebooks/evaluating_adk_agent.ipynb} +163 -199
- agent_starter_pack/agents/adk_a2a_base/tests/integration/test_agent.py +58 -0
- agent_starter_pack/agents/adk_base/app/__init__.py +2 -2
- agent_starter_pack/agents/adk_base/app/agent.py +3 -0
- agent_starter_pack/agents/adk_base/notebooks/adk_app_testing.ipynb +13 -28
- agent_starter_pack/agents/adk_live/app/__init__.py +17 -0
- agent_starter_pack/agents/adk_live/app/agent.py +3 -0
- agent_starter_pack/agents/agentic_rag/app/__init__.py +2 -2
- agent_starter_pack/agents/agentic_rag/app/agent.py +3 -0
- agent_starter_pack/agents/agentic_rag/notebooks/adk_app_testing.ipynb +13 -28
- agent_starter_pack/agents/{crewai_coding_crew → langgraph_base}/.template/templateconfig.yaml +12 -9
- agent_starter_pack/agents/langgraph_base/README.md +30 -0
- agent_starter_pack/agents/langgraph_base/app/__init__.py +17 -0
- agent_starter_pack/agents/{langgraph_base_react → langgraph_base}/app/agent.py +4 -4
- agent_starter_pack/agents/{langgraph_base_react → langgraph_base}/tests/integration/test_agent.py +1 -1
- agent_starter_pack/base_template/.gitignore +4 -2
- agent_starter_pack/base_template/Makefile +110 -16
- agent_starter_pack/base_template/README.md +97 -12
- agent_starter_pack/base_template/deployment/terraform/dev/apis.tf +4 -6
- agent_starter_pack/base_template/deployment/terraform/dev/providers.tf +5 -1
- agent_starter_pack/base_template/deployment/terraform/dev/variables.tf +5 -3
- agent_starter_pack/base_template/deployment/terraform/dev/{% if cookiecutter.is_adk %}telemetry.tf{% else %}unused_telemetry.tf{% endif %} +193 -0
- agent_starter_pack/base_template/deployment/terraform/github.tf +16 -9
- agent_starter_pack/base_template/deployment/terraform/locals.tf +7 -7
- agent_starter_pack/base_template/deployment/terraform/providers.tf +5 -1
- agent_starter_pack/base_template/deployment/terraform/sql/completions.sql +138 -0
- agent_starter_pack/base_template/deployment/terraform/storage.tf +0 -9
- agent_starter_pack/base_template/deployment/terraform/variables.tf +15 -19
- 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
- agent_starter_pack/base_template/deployment/terraform/{% if cookiecutter.is_adk %}telemetry.tf{% else %}unused_telemetry.tf{% endif %} +206 -0
- agent_starter_pack/base_template/pyproject.toml +5 -17
- agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/deploy-to-prod.yaml +19 -4
- agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/staging.yaml +36 -11
- agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}.cloudbuild{% else %}unused_.cloudbuild{% endif %}/deploy-to-prod.yaml +24 -5
- agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}.cloudbuild{% else %}unused_.cloudbuild{% endif %}/staging.yaml +44 -9
- agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/telemetry.py +96 -0
- agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/{utils → app_utils}/typing.py +4 -6
- 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
- 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
- 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
- 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
- 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
- agent_starter_pack/cli/commands/create.py +40 -4
- agent_starter_pack/cli/commands/enhance.py +1 -1
- agent_starter_pack/cli/commands/register_gemini_enterprise.py +1070 -0
- agent_starter_pack/cli/main.py +2 -0
- agent_starter_pack/cli/utils/cicd.py +20 -4
- agent_starter_pack/cli/utils/template.py +257 -25
- agent_starter_pack/deployment_targets/agent_engine/tests/integration/test_agent_engine_app.py +113 -16
- agent_starter_pack/deployment_targets/agent_engine/tests/load_test/README.md +2 -2
- agent_starter_pack/deployment_targets/agent_engine/tests/load_test/load_test.py +178 -9
- agent_starter_pack/deployment_targets/agent_engine/tests/{% if cookiecutter.is_a2a %}helpers.py{% else %}unused_helpers.py{% endif %} +138 -0
- agent_starter_pack/deployment_targets/agent_engine/{{cookiecutter.agent_directory}}/agent_engine_app.py +193 -307
- agent_starter_pack/deployment_targets/agent_engine/{{cookiecutter.agent_directory}}/app_utils/deploy.py +414 -0
- 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
- agent_starter_pack/deployment_targets/cloud_run/Dockerfile +4 -1
- agent_starter_pack/deployment_targets/cloud_run/deployment/terraform/dev/service.tf +85 -86
- agent_starter_pack/deployment_targets/cloud_run/deployment/terraform/service.tf +139 -107
- agent_starter_pack/deployment_targets/cloud_run/tests/integration/test_server_e2e.py +228 -12
- agent_starter_pack/deployment_targets/cloud_run/tests/load_test/README.md +4 -4
- agent_starter_pack/deployment_targets/cloud_run/tests/load_test/load_test.py +92 -12
- agent_starter_pack/deployment_targets/cloud_run/{{cookiecutter.agent_directory}}/{server.py → fast_api_app.py} +194 -121
- agent_starter_pack/frontends/adk_live_react/frontend/package-lock.json +18 -18
- agent_starter_pack/frontends/adk_live_react/frontend/src/multimodal-live-types.ts +5 -3
- agent_starter_pack/resources/docs/adk-cheatsheet.md +198 -41
- agent_starter_pack/resources/locks/uv-adk_a2a_base-agent_engine.lock +4966 -0
- agent_starter_pack/resources/locks/uv-adk_a2a_base-cloud_run.lock +5011 -0
- agent_starter_pack/resources/locks/uv-adk_base-agent_engine.lock +1443 -709
- agent_starter_pack/resources/locks/uv-adk_base-cloud_run.lock +1058 -874
- agent_starter_pack/resources/locks/uv-adk_live-agent_engine.lock +1443 -709
- agent_starter_pack/resources/locks/uv-adk_live-cloud_run.lock +1058 -874
- agent_starter_pack/resources/locks/uv-agentic_rag-agent_engine.lock +1568 -749
- agent_starter_pack/resources/locks/uv-agentic_rag-cloud_run.lock +1123 -929
- agent_starter_pack/resources/locks/{uv-langgraph_base_react-agent_engine.lock → uv-langgraph_base-agent_engine.lock} +1714 -1689
- agent_starter_pack/resources/locks/{uv-langgraph_base_react-cloud_run.lock → uv-langgraph_base-cloud_run.lock} +1285 -2374
- agent_starter_pack/utils/watch_and_rebuild.py +1 -1
- {agent_starter_pack-0.18.2.dist-info → agent_starter_pack-0.21.0.dist-info}/METADATA +3 -6
- {agent_starter_pack-0.18.2.dist-info → agent_starter_pack-0.21.0.dist-info}/RECORD +89 -93
- agent_starter_pack-0.21.0.dist-info/entry_points.txt +2 -0
- llm.txt +4 -5
- agent_starter_pack/agents/crewai_coding_crew/README.md +0 -34
- agent_starter_pack/agents/crewai_coding_crew/app/agent.py +0 -47
- agent_starter_pack/agents/crewai_coding_crew/app/crew/config/tasks.yaml +0 -37
- agent_starter_pack/agents/crewai_coding_crew/app/crew/crew.py +0 -71
- agent_starter_pack/agents/crewai_coding_crew/tests/integration/test_agent.py +0 -47
- agent_starter_pack/agents/langgraph_base_react/README.md +0 -9
- agent_starter_pack/agents/langgraph_base_react/notebooks/evaluating_langgraph_agent.ipynb +0 -1574
- agent_starter_pack/base_template/deployment/terraform/dev/log_sinks.tf +0 -69
- agent_starter_pack/base_template/deployment/terraform/log_sinks.tf +0 -79
- agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/utils/tracing.py +0 -155
- agent_starter_pack/cli/utils/register_gemini_enterprise.py +0 -406
- agent_starter_pack/deployment_targets/agent_engine/deployment/terraform/{% if not cookiecutter.is_adk_live %}service.tf{% else %}unused_service.tf{% endif %} +0 -82
- agent_starter_pack/deployment_targets/agent_engine/notebooks/intro_agent_engine.ipynb +0 -1025
- agent_starter_pack/deployment_targets/agent_engine/{{cookiecutter.agent_directory}}/utils/deployment.py +0 -99
- agent_starter_pack/frontends/streamlit/frontend/side_bar.py +0 -214
- agent_starter_pack/frontends/streamlit/frontend/streamlit_app.py +0 -265
- agent_starter_pack/frontends/streamlit/frontend/utils/chat_utils.py +0 -67
- agent_starter_pack/frontends/streamlit/frontend/utils/local_chat_history.py +0 -127
- agent_starter_pack/frontends/streamlit/frontend/utils/message_editing.py +0 -59
- agent_starter_pack/frontends/streamlit/frontend/utils/multimodal_utils.py +0 -217
- agent_starter_pack/frontends/streamlit/frontend/utils/stream_handler.py +0 -310
- agent_starter_pack/frontends/streamlit/frontend/utils/title_summary.py +0 -94
- agent_starter_pack/resources/locks/uv-crewai_coding_crew-agent_engine.lock +0 -6650
- agent_starter_pack/resources/locks/uv-crewai_coding_crew-cloud_run.lock +0 -7825
- agent_starter_pack-0.18.2.dist-info/entry_points.txt +0 -3
- /agent_starter_pack/agents/{crewai_coding_crew → langgraph_base}/notebooks/evaluating_langgraph_agent.ipynb +0 -0
- /agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/{utils → app_utils}/gcs.py +0 -0
- {agent_starter_pack-0.18.2.dist-info → agent_starter_pack-0.21.0.dist-info}/WHEEL +0 -0
- {agent_starter_pack-0.18.2.dist-info → agent_starter_pack-0.21.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -30,14 +30,12 @@ from google.adk.memory.in_memory_memory_service import InMemoryMemoryService
|
|
|
30
30
|
from google.adk.runners import Runner
|
|
31
31
|
from google.adk.sessions.in_memory_session_service import InMemorySessionService
|
|
32
32
|
from google.cloud import logging as google_cloud_logging
|
|
33
|
-
from opentelemetry import trace
|
|
34
|
-
from opentelemetry.sdk.trace import TracerProvider, export
|
|
35
33
|
from vertexai.agent_engines import _utils
|
|
36
34
|
from websockets.exceptions import ConnectionClosedError
|
|
37
35
|
|
|
38
|
-
from .agent import
|
|
39
|
-
from .
|
|
40
|
-
from .
|
|
36
|
+
from .agent import app as adk_app
|
|
37
|
+
from .app_utils.telemetry import setup_telemetry
|
|
38
|
+
from .app_utils.typing import Feedback
|
|
41
39
|
|
|
42
40
|
app = FastAPI()
|
|
43
41
|
app.add_middleware(
|
|
@@ -62,13 +60,8 @@ logging_client = google_cloud_logging.Client()
|
|
|
62
60
|
logger = logging_client.logger(__name__)
|
|
63
61
|
logging.basicConfig(level=logging.INFO)
|
|
64
62
|
|
|
63
|
+
setup_telemetry()
|
|
65
64
|
_, project_id = google.auth.default()
|
|
66
|
-
provider = TracerProvider()
|
|
67
|
-
processor = export.BatchSpanProcessor(
|
|
68
|
-
CloudTraceLoggingSpanExporter(project_id=project_id)
|
|
69
|
-
)
|
|
70
|
-
provider.add_span_processor(processor)
|
|
71
|
-
trace.set_tracer_provider(provider)
|
|
72
65
|
|
|
73
66
|
|
|
74
67
|
# Initialize ADK services
|
|
@@ -78,11 +71,10 @@ memory_service = InMemoryMemoryService()
|
|
|
78
71
|
|
|
79
72
|
# Initialize ADK runner
|
|
80
73
|
runner = Runner(
|
|
81
|
-
|
|
74
|
+
app=adk_app,
|
|
82
75
|
session_service=session_service,
|
|
83
76
|
artifact_service=artifact_service,
|
|
84
77
|
memory_service=memory_service,
|
|
85
|
-
app_name="live-app",
|
|
86
78
|
)
|
|
87
79
|
|
|
88
80
|
|
|
@@ -291,67 +283,163 @@ async def serve_frontend_spa(full_path: str) -> FileResponse:
|
|
|
291
283
|
)
|
|
292
284
|
{% elif cookiecutter.is_adk %}
|
|
293
285
|
import os
|
|
286
|
+
{%- if cookiecutter.is_a2a %}
|
|
287
|
+
from collections.abc import AsyncIterator
|
|
288
|
+
from contextlib import asynccontextmanager
|
|
289
|
+
{%- endif %}
|
|
290
|
+
{%- if cookiecutter.session_type == "cloud_sql" %}
|
|
291
|
+
from urllib.parse import quote
|
|
292
|
+
{%- endif %}
|
|
294
293
|
|
|
295
294
|
import google.auth
|
|
295
|
+
{%- if cookiecutter.is_a2a %}
|
|
296
|
+
from a2a.server.apps import A2AFastAPIApplication
|
|
297
|
+
from a2a.server.request_handlers import DefaultRequestHandler
|
|
298
|
+
from a2a.server.tasks import InMemoryTaskStore
|
|
299
|
+
from a2a.types import AgentCapabilities, AgentCard
|
|
300
|
+
from a2a.utils.constants import (
|
|
301
|
+
AGENT_CARD_WELL_KNOWN_PATH,
|
|
302
|
+
EXTENDED_AGENT_CARD_PATH,
|
|
303
|
+
)
|
|
304
|
+
{%- endif %}
|
|
296
305
|
from fastapi import FastAPI
|
|
306
|
+
{%- if cookiecutter.is_a2a %}
|
|
307
|
+
from google.adk.a2a.executor.a2a_agent_executor import A2aAgentExecutor
|
|
308
|
+
from google.adk.a2a.utils.agent_card_builder import AgentCardBuilder
|
|
309
|
+
from google.adk.artifacts.gcs_artifact_service import GcsArtifactService
|
|
310
|
+
from google.adk.runners import Runner
|
|
311
|
+
from google.adk.sessions import InMemorySessionService
|
|
312
|
+
{%- else %}
|
|
297
313
|
from google.adk.cli.fast_api import get_fast_api_app
|
|
314
|
+
{%- endif %}
|
|
298
315
|
from google.cloud import logging as google_cloud_logging
|
|
299
|
-
|
|
300
|
-
from opentelemetry.sdk.trace import TracerProvider, export
|
|
301
|
-
{%- if cookiecutter.session_type == "agent_engine" %}
|
|
316
|
+
{% if cookiecutter.session_type == "agent_engine" -%}
|
|
302
317
|
from vertexai import agent_engines
|
|
303
|
-
{
|
|
318
|
+
{% endif %}
|
|
304
319
|
|
|
305
|
-
|
|
306
|
-
from {{cookiecutter.agent_directory}}.
|
|
307
|
-
|
|
320
|
+
{%- if cookiecutter.is_a2a %}
|
|
321
|
+
from {{cookiecutter.agent_directory}}.agent import app as adk_app
|
|
322
|
+
{%- endif %}
|
|
323
|
+
from {{cookiecutter.agent_directory}}.app_utils.gcs import create_bucket_if_not_exists
|
|
324
|
+
from {{cookiecutter.agent_directory}}.app_utils.telemetry import setup_telemetry
|
|
325
|
+
from {{cookiecutter.agent_directory}}.app_utils.typing import Feedback
|
|
308
326
|
|
|
327
|
+
setup_telemetry()
|
|
309
328
|
_, project_id = google.auth.default()
|
|
310
329
|
logging_client = google_cloud_logging.Client()
|
|
311
330
|
logger = logging_client.logger(__name__)
|
|
331
|
+
{%- if not cookiecutter.is_a2a %}
|
|
312
332
|
allow_origins = (
|
|
313
333
|
os.getenv("ALLOW_ORIGINS", "").split(",") if os.getenv("ALLOW_ORIGINS") else None
|
|
314
334
|
)
|
|
335
|
+
{%- endif %}
|
|
315
336
|
|
|
337
|
+
# Artifact bucket for ADK
|
|
316
338
|
bucket_name = f"gs://{project_id}-{{cookiecutter.project_name}}-logs"
|
|
317
339
|
create_bucket_if_not_exists(
|
|
318
340
|
bucket_name=bucket_name, project=project_id, location="us-central1"
|
|
319
341
|
)
|
|
320
342
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
343
|
+
{%- if cookiecutter.is_a2a %}
|
|
344
|
+
|
|
345
|
+
runner = Runner(
|
|
346
|
+
app=adk_app,
|
|
347
|
+
artifact_service=GcsArtifactService(bucket_name=bucket_name),
|
|
348
|
+
session_service=InMemorySessionService(),
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
request_handler = DefaultRequestHandler(
|
|
352
|
+
agent_executor=A2aAgentExecutor(runner=runner), task_store=InMemoryTaskStore()
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
A2A_RPC_PATH = f"/a2a/{adk_app.name}"
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
async def build_dynamic_agent_card() -> AgentCard:
|
|
359
|
+
"""Builds the Agent Card dynamically from the root_agent."""
|
|
360
|
+
agent_card_builder = AgentCardBuilder(
|
|
361
|
+
agent=adk_app.root_agent,
|
|
362
|
+
capabilities=AgentCapabilities(streaming=True),
|
|
363
|
+
rpc_url=f"{os.getenv('APP_URL', 'http://0.0.0.0:8000')}{A2A_RPC_PATH}",
|
|
364
|
+
agent_version=os.getenv("AGENT_VERSION", "0.1.0"),
|
|
365
|
+
)
|
|
366
|
+
agent_card = await agent_card_builder.build()
|
|
367
|
+
return agent_card
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
@asynccontextmanager
|
|
371
|
+
async def lifespan(app_instance: FastAPI) -> AsyncIterator[None]:
|
|
372
|
+
agent_card = await build_dynamic_agent_card()
|
|
373
|
+
a2a_app = A2AFastAPIApplication(agent_card=agent_card, http_handler=request_handler)
|
|
374
|
+
a2a_app.add_routes_to_app(
|
|
375
|
+
app_instance,
|
|
376
|
+
agent_card_url=f"{A2A_RPC_PATH}{AGENT_CARD_WELL_KNOWN_PATH}",
|
|
377
|
+
rpc_url=A2A_RPC_PATH,
|
|
378
|
+
extended_agent_card_url=f"{A2A_RPC_PATH}{EXTENDED_AGENT_CARD_PATH}",
|
|
379
|
+
)
|
|
380
|
+
yield
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
app = FastAPI(
|
|
384
|
+
title="{{cookiecutter.project_name}}",
|
|
385
|
+
description="API for interacting with the Agent {{cookiecutter.project_name}}",
|
|
386
|
+
lifespan=lifespan,
|
|
387
|
+
)
|
|
388
|
+
{%- else %}
|
|
325
389
|
|
|
326
390
|
AGENT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
327
391
|
|
|
328
|
-
{%- if cookiecutter.session_type == "
|
|
329
|
-
#
|
|
392
|
+
{%- if cookiecutter.session_type == "cloud_sql" %}
|
|
393
|
+
# Cloud SQL session configuration
|
|
330
394
|
db_user = os.environ.get("DB_USER", "postgres")
|
|
331
395
|
db_name = os.environ.get("DB_NAME", "postgres")
|
|
332
396
|
db_pass = os.environ.get("DB_PASS")
|
|
333
|
-
|
|
397
|
+
instance_connection_name = os.environ.get("INSTANCE_CONNECTION_NAME")
|
|
334
398
|
|
|
335
|
-
# Set session_service_uri if database credentials are available
|
|
336
399
|
session_service_uri = None
|
|
337
|
-
if
|
|
338
|
-
|
|
400
|
+
if instance_connection_name and db_pass:
|
|
401
|
+
# Use Unix socket for Cloud SQL
|
|
402
|
+
# URL-encode username and password to handle special characters (e.g., '[', '?', '#', '$')
|
|
403
|
+
# These characters can cause URL parsing errors, especially '[' which triggers IPv6 validation
|
|
404
|
+
encoded_user = quote(db_user, safe="")
|
|
405
|
+
encoded_pass = quote(db_pass, safe="")
|
|
406
|
+
# URL-encode the connection name to prevent colons from being misinterpreted
|
|
407
|
+
encoded_instance = instance_connection_name.replace(":", "%3A")
|
|
408
|
+
|
|
409
|
+
session_service_uri = (
|
|
410
|
+
f"postgresql+psycopg2://{encoded_user}:{encoded_pass}@"
|
|
411
|
+
f"/{db_name}"
|
|
412
|
+
f"?host=/cloudsql/{encoded_instance}"
|
|
413
|
+
)
|
|
339
414
|
{%- elif cookiecutter.session_type == "agent_engine" %}
|
|
340
415
|
# Agent Engine session configuration
|
|
341
|
-
#
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
416
|
+
# Check if we should use in-memory session for testing (set USE_IN_MEMORY_SESSION=true for E2E tests)
|
|
417
|
+
use_in_memory_session = os.environ.get("USE_IN_MEMORY_SESSION", "").lower() in (
|
|
418
|
+
"true",
|
|
419
|
+
"1",
|
|
420
|
+
"yes",
|
|
421
|
+
)
|
|
346
422
|
|
|
347
|
-
if
|
|
348
|
-
# Use
|
|
349
|
-
|
|
423
|
+
if use_in_memory_session:
|
|
424
|
+
# Use in-memory session for local testing
|
|
425
|
+
session_service_uri = None
|
|
350
426
|
else:
|
|
351
|
-
#
|
|
352
|
-
|
|
427
|
+
# Use environment variable for agent name, default to project name
|
|
428
|
+
agent_name = os.environ.get(
|
|
429
|
+
"AGENT_ENGINE_SESSION_NAME", "{{cookiecutter.project_name}}"
|
|
430
|
+
)
|
|
353
431
|
|
|
354
|
-
|
|
432
|
+
# Check if an agent with this name already exists
|
|
433
|
+
existing_agents = list(agent_engines.list(filter=f"display_name={agent_name}"))
|
|
434
|
+
|
|
435
|
+
if existing_agents:
|
|
436
|
+
# Use the existing agent
|
|
437
|
+
agent_engine = existing_agents[0]
|
|
438
|
+
else:
|
|
439
|
+
# Create a new agent if none exists
|
|
440
|
+
agent_engine = agent_engines.create(display_name=agent_name)
|
|
441
|
+
|
|
442
|
+
session_service_uri = f"agentengine://{agent_engine.resource_name}"
|
|
355
443
|
{%- else %}
|
|
356
444
|
# In-memory session configuration - no persistent storage
|
|
357
445
|
session_service_uri = None
|
|
@@ -363,103 +451,88 @@ app: FastAPI = get_fast_api_app(
|
|
|
363
451
|
artifact_service_uri=bucket_name,
|
|
364
452
|
allow_origins=allow_origins,
|
|
365
453
|
session_service_uri=session_service_uri,
|
|
454
|
+
otel_to_cloud=True,
|
|
366
455
|
)
|
|
367
456
|
app.title = "{{cookiecutter.project_name}}"
|
|
368
457
|
app.description = "API for interacting with the Agent {{cookiecutter.project_name}}"
|
|
458
|
+
{%- endif %}
|
|
369
459
|
{% else %}
|
|
370
|
-
import logging
|
|
371
460
|
import os
|
|
372
|
-
from collections.abc import
|
|
373
|
-
|
|
461
|
+
from collections.abc import AsyncIterator
|
|
462
|
+
from contextlib import asynccontextmanager
|
|
463
|
+
|
|
464
|
+
from a2a.server.apps import A2AFastAPIApplication
|
|
465
|
+
from a2a.server.request_handlers import DefaultRequestHandler
|
|
466
|
+
from a2a.server.tasks import InMemoryTaskStore
|
|
467
|
+
from a2a.types import AgentCapabilities, AgentCard, AgentSkill
|
|
468
|
+
from a2a.utils.constants import (
|
|
469
|
+
AGENT_CARD_WELL_KNOWN_PATH,
|
|
470
|
+
EXTENDED_AGENT_CARD_PATH,
|
|
471
|
+
)
|
|
374
472
|
from fastapi import FastAPI
|
|
375
|
-
from fastapi.responses import RedirectResponse, StreamingResponse
|
|
376
473
|
from google.cloud import logging as google_cloud_logging
|
|
377
|
-
from langchain_core.runnables import RunnableConfig
|
|
378
|
-
from traceloop.sdk import Instruments, Traceloop
|
|
379
|
-
|
|
380
|
-
from {{cookiecutter.agent_directory}}.agent import agent
|
|
381
|
-
from {{cookiecutter.agent_directory}}.utils.tracing import CloudTraceLoggingSpanExporter
|
|
382
|
-
from {{cookiecutter.agent_directory}}.utils.typing import Feedback, InputChat, Request, dumps, ensure_valid_config
|
|
383
474
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
description="API for interacting with the Agent {{cookiecutter.project_name}}",
|
|
475
|
+
from {{cookiecutter.agent_directory}}.agent import root_agent
|
|
476
|
+
from {{cookiecutter.agent_directory}}.app_utils.executor.a2a_agent_executor import (
|
|
477
|
+
LangGraphAgentExecutor,
|
|
388
478
|
)
|
|
389
|
-
|
|
390
|
-
|
|
479
|
+
from {{cookiecutter.agent_directory}}.app_utils.telemetry import setup_telemetry
|
|
480
|
+
from {{cookiecutter.agent_directory}}.app_utils.typing import Feedback
|
|
391
481
|
|
|
392
|
-
|
|
393
|
-
try:
|
|
394
|
-
Traceloop.init(
|
|
395
|
-
app_name=app.title,
|
|
396
|
-
disable_batch=False,
|
|
397
|
-
exporter=CloudTraceLoggingSpanExporter(),
|
|
398
|
-
instruments={Instruments.LANGCHAIN, Instruments.CREW},
|
|
399
|
-
)
|
|
400
|
-
except Exception as e:
|
|
401
|
-
logging.error("Failed to initialize Telemetry: %s", str(e))
|
|
482
|
+
setup_telemetry()
|
|
402
483
|
|
|
484
|
+
request_handler = DefaultRequestHandler(
|
|
485
|
+
agent_executor=LangGraphAgentExecutor(graph=root_agent),
|
|
486
|
+
task_store=InMemoryTaskStore(),
|
|
487
|
+
)
|
|
403
488
|
|
|
404
|
-
|
|
405
|
-
"""Sets tracing association properties for the current request.
|
|
406
|
-
|
|
407
|
-
Args:
|
|
408
|
-
config: Optional RunnableConfig containing request metadata
|
|
409
|
-
"""
|
|
410
|
-
Traceloop.set_association_properties(
|
|
411
|
-
{
|
|
412
|
-
"log_type": "tracing",
|
|
413
|
-
"run_id": str(config.get("run_id", "None")),
|
|
414
|
-
"user_id": config["metadata"].pop("user_id", "None"),
|
|
415
|
-
"session_id": config["metadata"].pop("session_id", "None"),
|
|
416
|
-
"commit_sha": os.environ.get("COMMIT_SHA", "None"),
|
|
417
|
-
}
|
|
418
|
-
)
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
def stream_messages(
|
|
422
|
-
input: InputChat,
|
|
423
|
-
config: RunnableConfig | None = None,
|
|
424
|
-
) -> Generator[str, None, None]:
|
|
425
|
-
"""Stream events in response to an input chat.
|
|
426
|
-
|
|
427
|
-
Args:
|
|
428
|
-
input: The input chat messages
|
|
429
|
-
config: Optional configuration for the runnable
|
|
430
|
-
|
|
431
|
-
Yields:
|
|
432
|
-
JSON serialized event data
|
|
433
|
-
"""
|
|
434
|
-
config = ensure_valid_config(config=config)
|
|
435
|
-
set_tracing_properties(config)
|
|
436
|
-
input_dict = input.model_dump()
|
|
437
|
-
|
|
438
|
-
for data in agent.stream(input_dict, config=config, stream_mode="messages"):
|
|
439
|
-
yield dumps(data) + "\n"
|
|
440
|
-
|
|
489
|
+
A2A_RPC_PATH = "/a2a/{{cookiecutter.agent_directory}}"
|
|
441
490
|
|
|
442
|
-
# Routes
|
|
443
|
-
@app.get("/", response_class=RedirectResponse)
|
|
444
|
-
def redirect_root_to_docs() -> RedirectResponse:
|
|
445
|
-
"""Redirect the root URL to the API documentation."""
|
|
446
|
-
return RedirectResponse(url="/docs")
|
|
447
491
|
|
|
492
|
+
def build_agent_card() -> AgentCard:
|
|
493
|
+
"""Builds the Agent Card for the LangGraph agent."""
|
|
494
|
+
skill = AgentSkill(
|
|
495
|
+
id="root_agent-get_weather",
|
|
496
|
+
name="get_weather",
|
|
497
|
+
description="Simulates a web search. Use it get information on weather.",
|
|
498
|
+
tags=["llm", "tools"],
|
|
499
|
+
examples=["What's the weather in San Francisco?"],
|
|
500
|
+
)
|
|
501
|
+
agent_card = AgentCard(
|
|
502
|
+
name="root_agent",
|
|
503
|
+
description="API for interacting with the Agent {{cookiecutter.project_name}}",
|
|
504
|
+
url=f"{os.getenv('APP_URL', 'http://0.0.0.0:8000')}{A2A_RPC_PATH}",
|
|
505
|
+
version=os.getenv("AGENT_VERSION", "0.1.0"),
|
|
506
|
+
default_input_modes=["text/plain"],
|
|
507
|
+
default_output_modes=["text/plain"],
|
|
508
|
+
capabilities=AgentCapabilities(streaming=True),
|
|
509
|
+
skills=[skill],
|
|
510
|
+
)
|
|
511
|
+
return agent_card
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
@asynccontextmanager
|
|
515
|
+
async def lifespan(app_instance: FastAPI) -> AsyncIterator[None]:
|
|
516
|
+
agent_card = build_agent_card()
|
|
517
|
+
a2a_app = A2AFastAPIApplication(agent_card=agent_card, http_handler=request_handler)
|
|
518
|
+
a2a_app.add_routes_to_app(
|
|
519
|
+
app_instance,
|
|
520
|
+
agent_card_url=f"{A2A_RPC_PATH}{AGENT_CARD_WELL_KNOWN_PATH}",
|
|
521
|
+
rpc_url=A2A_RPC_PATH,
|
|
522
|
+
extended_agent_card_url=f"{A2A_RPC_PATH}{EXTENDED_AGENT_CARD_PATH}",
|
|
523
|
+
)
|
|
524
|
+
yield
|
|
448
525
|
|
|
449
|
-
@app.post("/stream_messages")
|
|
450
|
-
def stream_chat_events(request: Request) -> StreamingResponse:
|
|
451
|
-
"""Stream chat events in response to an input request.
|
|
452
526
|
|
|
453
|
-
|
|
454
|
-
|
|
527
|
+
# Initialize FastAPI app and logging
|
|
528
|
+
app = FastAPI(
|
|
529
|
+
title="{{cookiecutter.project_name}}",
|
|
530
|
+
description="API for interacting with the Agent {{cookiecutter.project_name}}",
|
|
531
|
+
lifespan=lifespan,
|
|
532
|
+
)
|
|
455
533
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
"""
|
|
459
|
-
return StreamingResponse(
|
|
460
|
-
stream_messages(input=request.input, config=request.config),
|
|
461
|
-
media_type="text/event-stream",
|
|
462
|
-
)
|
|
534
|
+
logging_client = google_cloud_logging.Client()
|
|
535
|
+
logger = logging_client.logger(__name__)
|
|
463
536
|
{% endif %}
|
|
464
537
|
|
|
465
538
|
@app.post("/feedback")
|
|
@@ -2594,9 +2594,9 @@
|
|
|
2594
2594
|
}
|
|
2595
2595
|
},
|
|
2596
2596
|
"node_modules/@eslint/eslintrc/node_modules/js-yaml": {
|
|
2597
|
-
"version": "4.1.
|
|
2598
|
-
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.
|
|
2599
|
-
"integrity": "sha512-
|
|
2597
|
+
"version": "4.1.1",
|
|
2598
|
+
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
|
|
2599
|
+
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
|
|
2600
2600
|
"license": "MIT",
|
|
2601
2601
|
"dependencies": {
|
|
2602
2602
|
"argparse": "^2.0.1"
|
|
@@ -5856,9 +5856,9 @@
|
|
|
5856
5856
|
"license": "ISC"
|
|
5857
5857
|
},
|
|
5858
5858
|
"node_modules/brace-expansion": {
|
|
5859
|
-
"version": "1.1.
|
|
5860
|
-
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.
|
|
5861
|
-
"integrity": "sha512-
|
|
5859
|
+
"version": "1.1.12",
|
|
5860
|
+
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
|
5861
|
+
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
|
5862
5862
|
"license": "MIT",
|
|
5863
5863
|
"dependencies": {
|
|
5864
5864
|
"balanced-match": "^1.0.0",
|
|
@@ -8283,9 +8283,9 @@
|
|
|
8283
8283
|
}
|
|
8284
8284
|
},
|
|
8285
8285
|
"node_modules/eslint/node_modules/js-yaml": {
|
|
8286
|
-
"version": "4.1.
|
|
8287
|
-
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.
|
|
8288
|
-
"integrity": "sha512-
|
|
8286
|
+
"version": "4.1.1",
|
|
8287
|
+
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
|
|
8288
|
+
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
|
|
8289
8289
|
"license": "MIT",
|
|
8290
8290
|
"dependencies": {
|
|
8291
8291
|
"argparse": "^2.0.1"
|
|
@@ -8702,9 +8702,9 @@
|
|
|
8702
8702
|
}
|
|
8703
8703
|
},
|
|
8704
8704
|
"node_modules/filelist/node_modules/brace-expansion": {
|
|
8705
|
-
"version": "2.0.
|
|
8706
|
-
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.
|
|
8707
|
-
"integrity": "sha512-
|
|
8705
|
+
"version": "2.0.2",
|
|
8706
|
+
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
|
8707
|
+
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
|
8708
8708
|
"license": "MIT",
|
|
8709
8709
|
"dependencies": {
|
|
8710
8710
|
"balanced-match": "^1.0.0"
|
|
@@ -11520,9 +11520,9 @@
|
|
|
11520
11520
|
"license": "MIT"
|
|
11521
11521
|
},
|
|
11522
11522
|
"node_modules/js-yaml": {
|
|
11523
|
-
"version": "3.14.
|
|
11524
|
-
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.
|
|
11525
|
-
"integrity": "sha512-
|
|
11523
|
+
"version": "3.14.2",
|
|
11524
|
+
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
|
|
11525
|
+
"integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
|
|
11526
11526
|
"license": "MIT",
|
|
11527
11527
|
"dependencies": {
|
|
11528
11528
|
"argparse": "^1.0.7",
|
|
@@ -16402,9 +16402,9 @@
|
|
|
16402
16402
|
}
|
|
16403
16403
|
},
|
|
16404
16404
|
"node_modules/sucrase/node_modules/brace-expansion": {
|
|
16405
|
-
"version": "2.0.
|
|
16406
|
-
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.
|
|
16407
|
-
"integrity": "sha512-
|
|
16405
|
+
"version": "2.0.2",
|
|
16406
|
+
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
|
16407
|
+
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
|
16408
16408
|
"license": "MIT",
|
|
16409
16409
|
"dependencies": {
|
|
16410
16410
|
"balanced-match": "^1.0.0"
|
|
@@ -244,7 +244,8 @@ export const isToolCallCancellation = (
|
|
|
244
244
|
|
|
245
245
|
// ADK Event types
|
|
246
246
|
export interface AdkEvent {
|
|
247
|
-
|
|
247
|
+
user_id: string;
|
|
248
|
+
session_id: string;
|
|
248
249
|
author: string;
|
|
249
250
|
actions: {
|
|
250
251
|
state_delta: any;
|
|
@@ -265,9 +266,10 @@ export interface AdkEvent {
|
|
|
265
266
|
|
|
266
267
|
// ADK Event type guards
|
|
267
268
|
export const isAdkEvent = (a: unknown): a is AdkEvent =>
|
|
268
|
-
typeof a === "object" &&
|
|
269
|
+
typeof a === "object" &&
|
|
269
270
|
a !== null &&
|
|
270
|
-
typeof (a as any).
|
|
271
|
+
typeof (a as any).user_id === "string" &&
|
|
272
|
+
typeof (a as any).session_id === "string" &&
|
|
271
273
|
typeof (a as any).author === "string" &&
|
|
272
274
|
typeof (a as any).actions === "object";
|
|
273
275
|
|