google-adk 1.2.1__py3-none-any.whl → 1.4.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 (91) hide show
  1. google/adk/a2a/__init__.py +13 -0
  2. google/adk/a2a/converters/__init__.py +13 -0
  3. google/adk/a2a/converters/part_converter.py +166 -0
  4. google/adk/agents/invocation_context.py +2 -0
  5. google/adk/agents/llm_agent.py +1 -6
  6. google/adk/agents/run_config.py +11 -0
  7. google/adk/auth/auth_credential.py +5 -0
  8. google/adk/auth/auth_handler.py +22 -96
  9. google/adk/auth/auth_preprocessor.py +3 -3
  10. google/adk/auth/auth_tool.py +46 -0
  11. google/adk/auth/credential_manager.py +265 -0
  12. google/adk/auth/credential_service/__init__.py +13 -0
  13. google/adk/auth/credential_service/base_credential_service.py +75 -0
  14. google/adk/auth/credential_service/in_memory_credential_service.py +64 -0
  15. google/adk/auth/exchanger/__init__.py +23 -0
  16. google/adk/auth/exchanger/base_credential_exchanger.py +57 -0
  17. google/adk/auth/exchanger/credential_exchanger_registry.py +58 -0
  18. google/adk/auth/exchanger/oauth2_credential_exchanger.py +104 -0
  19. google/adk/auth/exchanger/service_account_credential_exchanger.py +104 -0
  20. google/adk/auth/oauth2_credential_util.py +107 -0
  21. google/adk/auth/refresher/__init__.py +21 -0
  22. google/adk/auth/refresher/base_credential_refresher.py +74 -0
  23. google/adk/auth/refresher/credential_refresher_registry.py +59 -0
  24. google/adk/auth/refresher/oauth2_credential_refresher.py +154 -0
  25. google/adk/cli/agent_graph.py +34 -32
  26. google/adk/cli/browser/index.html +2 -2
  27. google/adk/cli/browser/main-JAAWEV7F.js +92 -0
  28. google/adk/cli/browser/polyfills-B6TNHZQ6.js +17 -0
  29. google/adk/cli/cli.py +10 -0
  30. google/adk/cli/cli_deploy.py +80 -21
  31. google/adk/cli/cli_tools_click.py +132 -61
  32. google/adk/cli/fast_api.py +46 -41
  33. google/adk/cli/utils/agent_loader.py +15 -2
  34. google/adk/code_executors/container_code_executor.py +10 -6
  35. google/adk/code_executors/vertex_ai_code_executor.py +8 -2
  36. google/adk/evaluation/_eval_set_results_manager_utils.py +44 -0
  37. google/adk/evaluation/_eval_sets_manager_utils.py +108 -0
  38. google/adk/evaluation/eval_metrics.py +0 -5
  39. google/adk/evaluation/eval_result.py +12 -7
  40. google/adk/evaluation/eval_set_results_manager.py +6 -1
  41. google/adk/evaluation/gcs_eval_set_results_manager.py +121 -0
  42. google/adk/evaluation/gcs_eval_sets_manager.py +196 -0
  43. google/adk/evaluation/local_eval_set_results_manager.py +6 -18
  44. google/adk/evaluation/local_eval_sets_manager.py +27 -78
  45. google/adk/flows/llm_flows/basic.py +9 -0
  46. google/adk/models/anthropic_llm.py +1 -1
  47. google/adk/models/gemini_llm_connection.py +2 -0
  48. google/adk/models/google_llm.py +57 -16
  49. google/adk/models/lite_llm.py +2 -1
  50. google/adk/platform/__init__.py +13 -0
  51. google/adk/platform/internal/__init__.py +15 -0
  52. google/adk/platform/internal/thread.py +30 -0
  53. google/adk/platform/thread.py +31 -0
  54. google/adk/runners.py +8 -2
  55. google/adk/sessions/in_memory_session_service.py +12 -1
  56. google/adk/sessions/vertex_ai_session_service.py +71 -50
  57. google/adk/tools/__init__.py +2 -0
  58. google/adk/tools/_automatic_function_calling_util.py +1 -0
  59. google/adk/tools/_forwarding_artifact_service.py +96 -0
  60. google/adk/tools/_function_parameter_parse_util.py +1 -0
  61. google/adk/tools/agent_tool.py +5 -39
  62. google/adk/tools/application_integration_tool/integration_connector_tool.py +2 -2
  63. google/adk/tools/authenticated_function_tool.py +107 -0
  64. google/adk/tools/base_authenticated_tool.py +107 -0
  65. google/adk/tools/bigquery/bigquery_credentials.py +6 -4
  66. google/adk/tools/bigquery/bigquery_tool.py +22 -9
  67. google/adk/tools/bigquery/bigquery_toolset.py +9 -3
  68. google/adk/tools/bigquery/client.py +7 -3
  69. google/adk/tools/bigquery/config.py +46 -0
  70. google/adk/tools/bigquery/metadata_tool.py +114 -91
  71. google/adk/tools/bigquery/query_tool.py +141 -23
  72. google/adk/tools/google_api_tool/googleapi_to_openapi_converter.py +7 -4
  73. google/adk/tools/google_search_tool.py +0 -1
  74. google/adk/tools/mcp_tool/__init__.py +6 -0
  75. google/adk/tools/mcp_tool/mcp_session_manager.py +271 -149
  76. google/adk/tools/mcp_tool/mcp_tool.py +79 -22
  77. google/adk/tools/mcp_tool/mcp_toolset.py +32 -29
  78. google/adk/tools/openapi_tool/openapi_spec_parser/rest_api_tool.py +3 -3
  79. google/adk/tools/openapi_tool/openapi_spec_parser/tool_auth_handler.py +56 -33
  80. google/adk/tools/retrieval/files_retrieval.py +7 -1
  81. google/adk/tools/url_context_tool.py +61 -0
  82. google/adk/tools/vertex_ai_search_tool.py +13 -2
  83. google/adk/utils/feature_decorator.py +175 -0
  84. google/adk/version.py +1 -1
  85. {google_adk-1.2.1.dist-info → google_adk-1.4.0.dist-info}/METADATA +10 -2
  86. {google_adk-1.2.1.dist-info → google_adk-1.4.0.dist-info}/RECORD +89 -58
  87. google/adk/cli/browser/main-CS5OLUMF.js +0 -91
  88. google/adk/cli/browser/polyfills-FFHMD2TL.js +0 -17
  89. {google_adk-1.2.1.dist-info → google_adk-1.4.0.dist-info}/WHEEL +0 -0
  90. {google_adk-1.2.1.dist-info → google_adk-1.4.0.dist-info}/entry_points.txt +0 -0
  91. {google_adk-1.2.1.dist-info → google_adk-1.4.0.dist-info}/licenses/LICENSE +0 -0
@@ -417,28 +417,87 @@ def cli_eval(
417
417
  print(eval_result.model_dump_json(indent=2))
418
418
 
419
419
 
420
- def fast_api_common_options():
421
- """Decorator to add common fast api options to click commands."""
420
+ def adk_services_options():
421
+ """Decorator to add ADK services options to click commands."""
422
422
 
423
423
  def decorator(func):
424
424
  @click.option(
425
- "--session_db_url",
425
+ "--session_service_uri",
426
426
  help=(
427
- """Optional. The database URL to store the session.
427
+ """Optional. The URI of the session service.
428
428
  - Use 'agentengine://<agent_engine_resource_id>' to connect to Agent Engine sessions.
429
429
  - Use 'sqlite://<path_to_sqlite_file>' to connect to a SQLite DB.
430
- - See https://docs.sqlalchemy.org/en/20/core/engines.html#backend-specific-urls for more details on supported DB URLs."""
430
+ - See https://docs.sqlalchemy.org/en/20/core/engines.html#backend-specific-urls for more details on supported database URIs."""
431
431
  ),
432
432
  )
433
433
  @click.option(
434
- "--artifact_storage_uri",
434
+ "--artifact_service_uri",
435
435
  type=str,
436
436
  help=(
437
- "Optional. The artifact storage URI to store the artifacts,"
437
+ "Optional. The URI of the artifact service,"
438
438
  " supported URIs: gs://<bucket name> for GCS artifact service."
439
439
  ),
440
440
  default=None,
441
441
  )
442
+ @click.option(
443
+ "--memory_service_uri",
444
+ type=str,
445
+ help=(
446
+ """Optional. The URI of the memory service.
447
+ - Use 'rag://<rag_corpus_id>' to connect to Vertex AI Rag Memory Service."""
448
+ ),
449
+ default=None,
450
+ )
451
+ @functools.wraps(func)
452
+ def wrapper(*args, **kwargs):
453
+ return func(*args, **kwargs)
454
+
455
+ return wrapper
456
+
457
+ return decorator
458
+
459
+
460
+ def deprecated_adk_services_options():
461
+ """Depracated ADK services options."""
462
+
463
+ def warn(alternative_param, ctx, param, value):
464
+ if value:
465
+ click.echo(
466
+ click.style(
467
+ f"WARNING: Deprecated option {param.name} is used. Please use"
468
+ f" {alternative_param} instead.",
469
+ fg="yellow",
470
+ ),
471
+ err=True,
472
+ )
473
+ return value
474
+
475
+ def decorator(func):
476
+ @click.option(
477
+ "--session_db_url",
478
+ help="Deprecated. Use --session_service_uri instead.",
479
+ callback=functools.partial(warn, "--session_service_uri"),
480
+ )
481
+ @click.option(
482
+ "--artifact_storage_uri",
483
+ type=str,
484
+ help="Deprecated. Use --artifact_service_uri instead.",
485
+ callback=functools.partial(warn, "--artifact_service_uri"),
486
+ default=None,
487
+ )
488
+ @functools.wraps(func)
489
+ def wrapper(*args, **kwargs):
490
+ return func(*args, **kwargs)
491
+
492
+ return wrapper
493
+
494
+ return decorator
495
+
496
+
497
+ def fast_api_common_options():
498
+ """Decorator to add common fast api options to click commands."""
499
+
500
+ def decorator(func):
442
501
  @click.option(
443
502
  "--host",
444
503
  type=str,
@@ -489,6 +548,8 @@ def fast_api_common_options():
489
548
 
490
549
  @main.command("web")
491
550
  @fast_api_common_options()
551
+ @adk_services_options()
552
+ @deprecated_adk_services_options()
492
553
  @click.argument(
493
554
  "agents_dir",
494
555
  type=click.Path(
@@ -498,14 +559,17 @@ def fast_api_common_options():
498
559
  )
499
560
  def cli_web(
500
561
  agents_dir: str,
501
- session_db_url: str = "",
502
- artifact_storage_uri: Optional[str] = None,
503
562
  log_level: str = "INFO",
504
563
  allow_origins: Optional[list[str]] = None,
505
564
  host: str = "127.0.0.1",
506
565
  port: int = 8000,
507
566
  trace_to_cloud: bool = False,
508
567
  reload: bool = True,
568
+ session_service_uri: Optional[str] = None,
569
+ artifact_service_uri: Optional[str] = None,
570
+ memory_service_uri: Optional[str] = None,
571
+ session_db_url: Optional[str] = None, # Deprecated
572
+ artifact_storage_uri: Optional[str] = None, # Deprecated
509
573
  ):
510
574
  """Starts a FastAPI server with Web UI for agents.
511
575
 
@@ -514,7 +578,7 @@ def cli_web(
514
578
 
515
579
  Example:
516
580
 
517
- adk web --session_db_url=[db_url] --port=[port] path/to/agents_dir
581
+ adk web --session_service_uri=[uri] --port=[port] path/to/agents_dir
518
582
  """
519
583
  logs.setup_adk_logger(getattr(logging, log_level.upper()))
520
584
 
@@ -540,10 +604,13 @@ def cli_web(
540
604
  fg="green",
541
605
  )
542
606
 
607
+ session_service_uri = session_service_uri or session_db_url
608
+ artifact_service_uri = artifact_service_uri or artifact_storage_uri
543
609
  app = get_fast_api_app(
544
610
  agents_dir=agents_dir,
545
- session_db_url=session_db_url,
546
- artifact_storage_uri=artifact_storage_uri,
611
+ session_service_uri=session_service_uri,
612
+ artifact_service_uri=artifact_service_uri,
613
+ memory_service_uri=memory_service_uri,
547
614
  allow_origins=allow_origins,
548
615
  web=True,
549
616
  trace_to_cloud=trace_to_cloud,
@@ -571,16 +638,21 @@ def cli_web(
571
638
  default=os.getcwd(),
572
639
  )
573
640
  @fast_api_common_options()
641
+ @adk_services_options()
642
+ @deprecated_adk_services_options()
574
643
  def cli_api_server(
575
644
  agents_dir: str,
576
- session_db_url: str = "",
577
- artifact_storage_uri: Optional[str] = None,
578
645
  log_level: str = "INFO",
579
646
  allow_origins: Optional[list[str]] = None,
580
647
  host: str = "127.0.0.1",
581
648
  port: int = 8000,
582
649
  trace_to_cloud: bool = False,
583
650
  reload: bool = True,
651
+ session_service_uri: Optional[str] = None,
652
+ artifact_service_uri: Optional[str] = None,
653
+ memory_service_uri: Optional[str] = None,
654
+ session_db_url: Optional[str] = None, # Deprecated
655
+ artifact_storage_uri: Optional[str] = None, # Deprecated
584
656
  ):
585
657
  """Starts a FastAPI server for agents.
586
658
 
@@ -589,15 +661,18 @@ def cli_api_server(
589
661
 
590
662
  Example:
591
663
 
592
- adk api_server --session_db_url=[db_url] --port=[port] path/to/agents_dir
664
+ adk api_server --session_service_uri=[uri] --port=[port] path/to/agents_dir
593
665
  """
594
666
  logs.setup_adk_logger(getattr(logging, log_level.upper()))
595
667
 
668
+ session_service_uri = session_service_uri or session_db_url
669
+ artifact_service_uri = artifact_service_uri or artifact_storage_uri
596
670
  config = uvicorn.Config(
597
671
  get_fast_api_app(
598
672
  agents_dir=agents_dir,
599
- session_db_url=session_db_url,
600
- artifact_storage_uri=artifact_storage_uri,
673
+ session_service_uri=session_service_uri,
674
+ artifact_service_uri=artifact_service_uri,
675
+ memory_service_uri=memory_service_uri,
601
676
  allow_origins=allow_origins,
602
677
  web=False,
603
678
  trace_to_cloud=trace_to_cloud,
@@ -689,27 +764,6 @@ def cli_api_server(
689
764
  default="WARNING",
690
765
  help="Optional. Override the default verbosity level.",
691
766
  )
692
- @click.option(
693
- "--session_db_url",
694
- help=(
695
- """Optional. The database URL to store the session.
696
-
697
- - Use 'agentengine://<agent_engine_resource_id>' to connect to Agent Engine sessions.
698
-
699
- - Use 'sqlite://<path_to_sqlite_file>' to connect to a SQLite DB.
700
-
701
- - See https://docs.sqlalchemy.org/en/20/core/engines.html#backend-specific-urls for more details on supported DB URLs."""
702
- ),
703
- )
704
- @click.option(
705
- "--artifact_storage_uri",
706
- type=str,
707
- help=(
708
- "Optional. The artifact storage URI to store the artifacts, supported"
709
- " URIs: gs://<bucket name> for GCS artifact service."
710
- ),
711
- default=None,
712
- )
713
767
  @click.argument(
714
768
  "agent",
715
769
  type=click.Path(
@@ -726,6 +780,8 @@ def cli_api_server(
726
780
  " version in the dev environment)"
727
781
  ),
728
782
  )
783
+ @adk_services_options()
784
+ @deprecated_adk_services_options()
729
785
  def cli_deploy_cloud_run(
730
786
  agent: str,
731
787
  project: Optional[str],
@@ -737,9 +793,12 @@ def cli_deploy_cloud_run(
737
793
  trace_to_cloud: bool,
738
794
  with_ui: bool,
739
795
  verbosity: str,
740
- session_db_url: str,
741
- artifact_storage_uri: Optional[str],
742
796
  adk_version: str,
797
+ session_service_uri: Optional[str] = None,
798
+ artifact_service_uri: Optional[str] = None,
799
+ memory_service_uri: Optional[str] = None,
800
+ session_db_url: Optional[str] = None, # Deprecated
801
+ artifact_storage_uri: Optional[str] = None, # Deprecated
743
802
  ):
744
803
  """Deploys an agent to Cloud Run.
745
804
 
@@ -749,6 +808,8 @@ def cli_deploy_cloud_run(
749
808
 
750
809
  adk deploy cloud_run --project=[project] --region=[region] path/to/my_agent
751
810
  """
811
+ session_service_uri = session_service_uri or session_db_url
812
+ artifact_service_uri = artifact_service_uri or artifact_storage_uri
752
813
  try:
753
814
  cli_deploy.to_cloud_run(
754
815
  agent_folder=agent,
@@ -761,9 +822,10 @@ def cli_deploy_cloud_run(
761
822
  trace_to_cloud=trace_to_cloud,
762
823
  with_ui=with_ui,
763
824
  verbosity=verbosity,
764
- session_db_url=session_db_url,
765
- artifact_storage_uri=artifact_storage_uri,
766
825
  adk_version=adk_version,
826
+ session_service_uri=session_service_uri,
827
+ artifact_service_uri=artifact_service_uri,
828
+ memory_service_uri=memory_service_uri,
767
829
  )
768
830
  except Exception as e:
769
831
  click.secho(f"Deploy failed: {e}", fg="red", err=True)
@@ -773,12 +835,18 @@ def cli_deploy_cloud_run(
773
835
  @click.option(
774
836
  "--project",
775
837
  type=str,
776
- help="Required. Google Cloud project to deploy the agent.",
838
+ help=(
839
+ "Required. Google Cloud project to deploy the agent. It will override"
840
+ " GOOGLE_CLOUD_PROJECT in the .env file (if it exists)."
841
+ ),
777
842
  )
778
843
  @click.option(
779
844
  "--region",
780
845
  type=str,
781
- help="Required. Google Cloud region to deploy the agent.",
846
+ help=(
847
+ "Required. Google Cloud region to deploy the agent. It will override"
848
+ " GOOGLE_CLOUD_LOCATION in the .env file (if it exists)."
849
+ ),
782
850
  )
783
851
  @click.option(
784
852
  "--staging_bucket",
@@ -793,6 +861,20 @@ def cli_deploy_cloud_run(
793
861
  default=False,
794
862
  help="Optional. Whether to enable Cloud Trace for Agent Engine.",
795
863
  )
864
+ @click.option(
865
+ "--display_name",
866
+ type=str,
867
+ show_default=True,
868
+ default="",
869
+ help="Optional. Display name of the agent in Agent Engine.",
870
+ )
871
+ @click.option(
872
+ "--description",
873
+ type=str,
874
+ show_default=True,
875
+ default="",
876
+ help="Optional. Description of the agent in Agent Engine.",
877
+ )
796
878
  @click.option(
797
879
  "--adk_app",
798
880
  type=str,
@@ -847,6 +929,8 @@ def cli_deploy_agent_engine(
847
929
  region: str,
848
930
  staging_bucket: str,
849
931
  trace_to_cloud: bool,
932
+ display_name: str,
933
+ description: str,
850
934
  adk_app: str,
851
935
  temp_folder: str,
852
936
  env_file: str,
@@ -854,27 +938,12 @@ def cli_deploy_agent_engine(
854
938
  ):
855
939
  """Deploys an agent to Agent Engine.
856
940
 
857
- Args:
858
- agent (str): Required. The path to the agent to be deloyed.
859
- project (str): Required. Google Cloud project to deploy the agent.
860
- region (str): Required. Google Cloud region to deploy the agent.
861
- staging_bucket (str): Required. GCS bucket for staging the deployment
862
- artifacts.
863
- trace_to_cloud (bool): Required. Whether to enable Cloud Trace.
864
- adk_app (str): Required. Python file for defining the ADK application.
865
- temp_folder (str): Required. The folder for the generated Agent Engine
866
- files. If the folder already exists, its contents will be replaced.
867
- env_file (str): Required. The filepath to the `.env` file for environment
868
- variables. If it is an empty string, the `.env` file in the `agent`
869
- directory will be used if it exists.
870
- requirements_file (str): Required. The filepath to the `requirements.txt`
871
- file to use. If it is an empty string, the `requirements.txt` file in the
872
- `agent` directory will be used if exists.
941
+ AGENT: The path to the agent source code folder.
873
942
 
874
943
  Example:
875
944
 
876
945
  adk deploy agent_engine --project=[project] --region=[region]
877
- --staging_bucket=[staging_bucket] path/to/my_agent
946
+ --staging_bucket=[staging_bucket] --display_name=[app_name] path/to/my_agent
878
947
  """
879
948
  try:
880
949
  cli_deploy.to_agent_engine(
@@ -883,6 +952,8 @@ def cli_deploy_agent_engine(
883
952
  region=region,
884
953
  staging_bucket=staging_bucket,
885
954
  trace_to_cloud=trace_to_cloud,
955
+ display_name=display_name,
956
+ description=description,
886
957
  adk_app=adk_app,
887
958
  temp_folder=temp_folder,
888
959
  env_file=env_file,
@@ -57,6 +57,7 @@ from ..agents.llm_agent import Agent
57
57
  from ..agents.run_config import StreamingMode
58
58
  from ..artifacts.gcs_artifact_service import GcsArtifactService
59
59
  from ..artifacts.in_memory_artifact_service import InMemoryArtifactService
60
+ from ..auth.credential_service.in_memory_credential_service import InMemoryCredentialService
60
61
  from ..errors.not_found_error import NotFoundError
61
62
  from ..evaluation.eval_case import EvalCase
62
63
  from ..evaluation.eval_case import SessionInput
@@ -68,6 +69,7 @@ from ..evaluation.local_eval_set_results_manager import LocalEvalSetResultsManag
68
69
  from ..evaluation.local_eval_sets_manager import LocalEvalSetsManager
69
70
  from ..events.event import Event
70
71
  from ..memory.in_memory_memory_service import InMemoryMemoryService
72
+ from ..memory.vertex_ai_rag_memory_service import VertexAiRagMemoryService
71
73
  from ..runners import Runner
72
74
  from ..sessions.database_session_service import DatabaseSessionService
73
75
  from ..sessions.in_memory_session_service import InMemorySessionService
@@ -193,8 +195,9 @@ class GetEventGraphResult(common.BaseModel):
193
195
  def get_fast_api_app(
194
196
  *,
195
197
  agents_dir: str,
196
- session_db_url: str = "",
197
- artifact_storage_uri: Optional[str] = None,
198
+ session_service_uri: Optional[str] = None,
199
+ artifact_service_uri: Optional[str] = None,
200
+ memory_service_uri: Optional[str] = None,
198
201
  allow_origins: Optional[list[str]] = None,
199
202
  web: bool,
200
203
  trace_to_cloud: bool = False,
@@ -257,38 +260,55 @@ def get_fast_api_app(
257
260
  eval_set_results_manager = LocalEvalSetResultsManager(agents_dir=agents_dir)
258
261
 
259
262
  # Build the Memory service
260
- memory_service = InMemoryMemoryService()
263
+ if memory_service_uri:
264
+ if memory_service_uri.startswith("rag://"):
265
+ rag_corpus = memory_service_uri.split("://")[1]
266
+ if not rag_corpus:
267
+ raise click.ClickException("Rag corpus can not be empty.")
268
+ envs.load_dotenv_for_agent("", agents_dir)
269
+ memory_service = VertexAiRagMemoryService(
270
+ rag_corpus=f'projects/{os.environ["GOOGLE_CLOUD_PROJECT"]}/locations/{os.environ["GOOGLE_CLOUD_LOCATION"]}/ragCorpora/{rag_corpus}'
271
+ )
272
+ else:
273
+ raise click.ClickException(
274
+ "Unsupported memory service URI: %s" % memory_service_uri
275
+ )
276
+ else:
277
+ memory_service = InMemoryMemoryService()
261
278
 
262
279
  # Build the Session service
263
- agent_engine_id = ""
264
- if session_db_url:
265
- if session_db_url.startswith("agentengine://"):
280
+ if session_service_uri:
281
+ if session_service_uri.startswith("agentengine://"):
266
282
  # Create vertex session service
267
- agent_engine_id = session_db_url.split("://")[1]
283
+ agent_engine_id = session_service_uri.split("://")[1]
268
284
  if not agent_engine_id:
269
285
  raise click.ClickException("Agent engine id can not be empty.")
270
286
  envs.load_dotenv_for_agent("", agents_dir)
271
287
  session_service = VertexAiSessionService(
272
- os.environ["GOOGLE_CLOUD_PROJECT"],
273
- os.environ["GOOGLE_CLOUD_LOCATION"],
288
+ project=os.environ["GOOGLE_CLOUD_PROJECT"],
289
+ location=os.environ["GOOGLE_CLOUD_LOCATION"],
290
+ agent_engine_id=agent_engine_id,
274
291
  )
275
292
  else:
276
- session_service = DatabaseSessionService(db_url=session_db_url)
293
+ session_service = DatabaseSessionService(db_url=session_service_uri)
277
294
  else:
278
295
  session_service = InMemorySessionService()
279
296
 
280
297
  # Build the Artifact service
281
- if artifact_storage_uri:
282
- if artifact_storage_uri.startswith("gs://"):
283
- gcs_bucket = artifact_storage_uri.split("://")[1]
298
+ if artifact_service_uri:
299
+ if artifact_service_uri.startswith("gs://"):
300
+ gcs_bucket = artifact_service_uri.split("://")[1]
284
301
  artifact_service = GcsArtifactService(bucket_name=gcs_bucket)
285
302
  else:
286
303
  raise click.ClickException(
287
- "Unsupported artifact storage URI: %s" % artifact_storage_uri
304
+ "Unsupported artifact service URI: %s" % artifact_service_uri
288
305
  )
289
306
  else:
290
307
  artifact_service = InMemoryArtifactService()
291
308
 
309
+ # Build the Credential service
310
+ credential_service = InMemoryCredentialService()
311
+
292
312
  # initialize Agent Loader
293
313
  agent_loader = AgentLoader(agents_dir)
294
314
 
@@ -341,8 +361,6 @@ def get_fast_api_app(
341
361
  async def get_session(
342
362
  app_name: str, user_id: str, session_id: str
343
363
  ) -> Session:
344
- # Connect to managed session if agent_engine_id is set.
345
- app_name = agent_engine_id if agent_engine_id else app_name
346
364
  session = await session_service.get_session(
347
365
  app_name=app_name, user_id=user_id, session_id=session_id
348
366
  )
@@ -355,8 +373,6 @@ def get_fast_api_app(
355
373
  response_model_exclude_none=True,
356
374
  )
357
375
  async def list_sessions(app_name: str, user_id: str) -> list[Session]:
358
- # Connect to managed session if agent_engine_id is set.
359
- app_name = agent_engine_id if agent_engine_id else app_name
360
376
  list_sessions_response = await session_service.list_sessions(
361
377
  app_name=app_name, user_id=user_id
362
378
  )
@@ -377,8 +393,6 @@ def get_fast_api_app(
377
393
  session_id: str,
378
394
  state: Optional[dict[str, Any]] = None,
379
395
  ) -> Session:
380
- # Connect to managed session if agent_engine_id is set.
381
- app_name = agent_engine_id if agent_engine_id else app_name
382
396
  if (
383
397
  await session_service.get_session(
384
398
  app_name=app_name, user_id=user_id, session_id=session_id
@@ -402,14 +416,19 @@ def get_fast_api_app(
402
416
  app_name: str,
403
417
  user_id: str,
404
418
  state: Optional[dict[str, Any]] = None,
419
+ events: Optional[list[Event]] = None,
405
420
  ) -> Session:
406
- # Connect to managed session if agent_engine_id is set.
407
- app_name = agent_engine_id if agent_engine_id else app_name
408
421
  logger.info("New session created")
409
- return await session_service.create_session(
422
+ session = await session_service.create_session(
410
423
  app_name=app_name, user_id=user_id, state=state
411
424
  )
412
425
 
426
+ if events:
427
+ for event in events:
428
+ await session_service.append_event(session=session, event=event)
429
+
430
+ return session
431
+
413
432
  def _get_eval_set_file_path(app_name, agents_dir, eval_set_id) -> str:
414
433
  return os.path.join(
415
434
  agents_dir,
@@ -644,8 +663,6 @@ def get_fast_api_app(
644
663
 
645
664
  @app.delete("/apps/{app_name}/users/{user_id}/sessions/{session_id}")
646
665
  async def delete_session(app_name: str, user_id: str, session_id: str):
647
- # Connect to managed session if agent_engine_id is set.
648
- app_name = agent_engine_id if agent_engine_id else app_name
649
666
  await session_service.delete_session(
650
667
  app_name=app_name, user_id=user_id, session_id=session_id
651
668
  )
@@ -661,7 +678,6 @@ def get_fast_api_app(
661
678
  artifact_name: str,
662
679
  version: Optional[int] = Query(None),
663
680
  ) -> Optional[types.Part]:
664
- app_name = agent_engine_id if agent_engine_id else app_name
665
681
  artifact = await artifact_service.load_artifact(
666
682
  app_name=app_name,
667
683
  user_id=user_id,
@@ -684,7 +700,6 @@ def get_fast_api_app(
684
700
  artifact_name: str,
685
701
  version_id: int,
686
702
  ) -> Optional[types.Part]:
687
- app_name = agent_engine_id if agent_engine_id else app_name
688
703
  artifact = await artifact_service.load_artifact(
689
704
  app_name=app_name,
690
705
  user_id=user_id,
@@ -703,7 +718,6 @@ def get_fast_api_app(
703
718
  async def list_artifact_names(
704
719
  app_name: str, user_id: str, session_id: str
705
720
  ) -> list[str]:
706
- app_name = agent_engine_id if agent_engine_id else app_name
707
721
  return await artifact_service.list_artifact_keys(
708
722
  app_name=app_name, user_id=user_id, session_id=session_id
709
723
  )
@@ -715,7 +729,6 @@ def get_fast_api_app(
715
729
  async def list_artifact_versions(
716
730
  app_name: str, user_id: str, session_id: str, artifact_name: str
717
731
  ) -> list[int]:
718
- app_name = agent_engine_id if agent_engine_id else app_name
719
732
  return await artifact_service.list_versions(
720
733
  app_name=app_name,
721
734
  user_id=user_id,
@@ -729,7 +742,6 @@ def get_fast_api_app(
729
742
  async def delete_artifact(
730
743
  app_name: str, user_id: str, session_id: str, artifact_name: str
731
744
  ):
732
- app_name = agent_engine_id if agent_engine_id else app_name
733
745
  await artifact_service.delete_artifact(
734
746
  app_name=app_name,
735
747
  user_id=user_id,
@@ -739,10 +751,8 @@ def get_fast_api_app(
739
751
 
740
752
  @app.post("/run", response_model_exclude_none=True)
741
753
  async def agent_run(req: AgentRunRequest) -> list[Event]:
742
- # Connect to managed session if agent_engine_id is set.
743
- app_name = agent_engine_id if agent_engine_id else req.app_name
744
754
  session = await session_service.get_session(
745
- app_name=app_name, user_id=req.user_id, session_id=req.session_id
755
+ app_name=req.app_name, user_id=req.user_id, session_id=req.session_id
746
756
  )
747
757
  if not session:
748
758
  raise HTTPException(status_code=404, detail="Session not found")
@@ -760,11 +770,9 @@ def get_fast_api_app(
760
770
 
761
771
  @app.post("/run_sse")
762
772
  async def agent_run_sse(req: AgentRunRequest) -> StreamingResponse:
763
- # Connect to managed session if agent_engine_id is set.
764
- app_name = agent_engine_id if agent_engine_id else req.app_name
765
773
  # SSE endpoint
766
774
  session = await session_service.get_session(
767
- app_name=app_name, user_id=req.user_id, session_id=req.session_id
775
+ app_name=req.app_name, user_id=req.user_id, session_id=req.session_id
768
776
  )
769
777
  if not session:
770
778
  raise HTTPException(status_code=404, detail="Session not found")
@@ -802,8 +810,6 @@ def get_fast_api_app(
802
810
  async def get_event_graph(
803
811
  app_name: str, user_id: str, session_id: str, event_id: str
804
812
  ):
805
- # Connect to managed session if agent_engine_id is set.
806
- app_name = agent_engine_id if agent_engine_id else app_name
807
813
  session = await session_service.get_session(
808
814
  app_name=app_name, user_id=user_id, session_id=session_id
809
815
  )
@@ -859,8 +865,6 @@ def get_fast_api_app(
859
865
  ) -> None:
860
866
  await websocket.accept()
861
867
 
862
- # Connect to managed session if agent_engine_id is set.
863
- app_name = agent_engine_id if agent_engine_id else app_name
864
868
  session = await session_service.get_session(
865
869
  app_name=app_name, user_id=user_id, session_id=session_id
866
870
  )
@@ -924,11 +928,12 @@ def get_fast_api_app(
924
928
  return runner_dict[app_name]
925
929
  root_agent = agent_loader.load_agent(app_name)
926
930
  runner = Runner(
927
- app_name=agent_engine_id if agent_engine_id else app_name,
931
+ app_name=app_name,
928
932
  agent=root_agent,
929
933
  artifact_service=artifact_service,
930
934
  session_service=session_service,
931
935
  memory_service=memory_service,
936
+ credential_service=credential_service,
932
937
  )
933
938
  runner_dict[app_name] = runner
934
939
  return runner
@@ -76,7 +76,12 @@ class AgentLoader:
76
76
  e.msg = f"Fail to load '{agent_name}' module. " + e.msg
77
77
  raise e
78
78
  except Exception as e:
79
- e.msg = f"Fail to load '{agent_name}' module. " + e.msg
79
+ if hasattr(e, "msg"):
80
+ e.msg = f"Fail to load '{agent_name}' module. " + e.msg
81
+ raise e
82
+ e.args = (
83
+ f"Fail to load '{agent_name}' module. {e.args[0] if e.args else ''}",
84
+ ) + e.args[1:]
80
85
  raise e
81
86
 
82
87
  return None
@@ -110,7 +115,15 @@ class AgentLoader:
110
115
  e.msg = f"Fail to load '{agent_name}.agent' module. " + e.msg
111
116
  raise e
112
117
  except Exception as e:
113
- e.msg = f"Fail to load '{agent_name}.agent' module. " + e.msg
118
+ if hasattr(e, "msg"):
119
+ e.msg = f"Fail to load '{agent_name}.agent' module. " + e.msg
120
+ raise e
121
+ e.args = (
122
+ (
123
+ f"Fail to load '{agent_name}.agent' module."
124
+ f" {e.args[0] if e.args else ''}"
125
+ ),
126
+ ) + e.args[1:]
114
127
  raise e
115
128
 
116
129
  return None
@@ -12,7 +12,10 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ from __future__ import annotations
16
+
15
17
  import atexit
18
+ import logging
16
19
  import os
17
20
  from typing import Optional
18
21
 
@@ -27,6 +30,7 @@ from .base_code_executor import BaseCodeExecutor
27
30
  from .code_execution_utils import CodeExecutionInput
28
31
  from .code_execution_utils import CodeExecutionResult
29
32
 
33
+ logger = logging.getLogger('google_adk.' + __name__)
30
34
  DEFAULT_IMAGE_TAG = 'adk-code-executor:latest'
31
35
 
32
36
 
@@ -151,13 +155,13 @@ class ContainerCodeExecutor(BaseCodeExecutor):
151
155
  if not os.path.exists(self.docker_path):
152
156
  raise FileNotFoundError(f'Invalid Docker path: {self.docker_path}')
153
157
 
154
- print('Building Docker image...')
158
+ logger.info('Building Docker image...')
155
159
  self._client.images.build(
156
160
  path=self.docker_path,
157
161
  tag=self.image,
158
162
  rm=True,
159
163
  )
160
- print(f'Docker image: {self.image} built.')
164
+ logger.info('Docker image: %s built.', self.image)
161
165
 
162
166
  def _verify_python_installation(self):
163
167
  """Verifies the container has python3 installed."""
@@ -173,13 +177,13 @@ class ContainerCodeExecutor(BaseCodeExecutor):
173
177
  if self.docker_path:
174
178
  self._build_docker_image()
175
179
 
176
- print('Starting container for ContainerCodeExecutor...')
180
+ logger.info('Starting container for ContainerCodeExecutor...')
177
181
  self._container = self._client.containers.run(
178
182
  image=self.image,
179
183
  detach=True,
180
184
  tty=True,
181
185
  )
182
- print(f'Container {self._container.id} started.')
186
+ logger.info('Container %s started.', self._container.id)
183
187
 
184
188
  # Verify the container is able to run python3.
185
189
  self._verify_python_installation()
@@ -189,7 +193,7 @@ class ContainerCodeExecutor(BaseCodeExecutor):
189
193
  if not self._container:
190
194
  return
191
195
 
192
- print('[Cleanup] Stopping the container...')
196
+ logger.info('[Cleanup] Stopping the container...')
193
197
  self._container.stop()
194
198
  self._container.remove()
195
- print(f'Container {self._container.id} stopped and removed.')
199
+ logger.info('Container %s stopped and removed.', self._container.id)