google-adk 0.5.0__py3-none-any.whl → 1.0.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 (113) hide show
  1. google/adk/agents/base_agent.py +76 -30
  2. google/adk/agents/base_agent.py.orig +330 -0
  3. google/adk/agents/callback_context.py +0 -5
  4. google/adk/agents/llm_agent.py +122 -30
  5. google/adk/agents/loop_agent.py +1 -1
  6. google/adk/agents/parallel_agent.py +7 -0
  7. google/adk/agents/readonly_context.py +7 -1
  8. google/adk/agents/run_config.py +1 -1
  9. google/adk/agents/sequential_agent.py +31 -0
  10. google/adk/agents/transcription_entry.py +4 -2
  11. google/adk/artifacts/gcs_artifact_service.py +1 -1
  12. google/adk/artifacts/in_memory_artifact_service.py +1 -1
  13. google/adk/auth/auth_credential.py +6 -1
  14. google/adk/auth/auth_preprocessor.py +7 -1
  15. google/adk/auth/auth_tool.py +3 -4
  16. google/adk/cli/agent_graph.py +5 -5
  17. google/adk/cli/browser/index.html +2 -2
  18. google/adk/cli/browser/{main-ULN5R5I5.js → main-QOEMUXM4.js} +44 -45
  19. google/adk/cli/cli.py +7 -7
  20. google/adk/cli/cli_deploy.py +7 -2
  21. google/adk/cli/cli_eval.py +172 -99
  22. google/adk/cli/cli_tools_click.py +147 -64
  23. google/adk/cli/fast_api.py +330 -148
  24. google/adk/cli/fast_api.py.orig +174 -80
  25. google/adk/cli/utils/common.py +23 -0
  26. google/adk/cli/utils/evals.py +83 -1
  27. google/adk/cli/utils/logs.py +13 -5
  28. google/adk/code_executors/__init__.py +3 -1
  29. google/adk/code_executors/built_in_code_executor.py +52 -0
  30. google/adk/evaluation/__init__.py +1 -1
  31. google/adk/evaluation/agent_evaluator.py +168 -128
  32. google/adk/evaluation/eval_case.py +102 -0
  33. google/adk/evaluation/eval_set.py +37 -0
  34. google/adk/evaluation/eval_sets_manager.py +42 -0
  35. google/adk/evaluation/evaluation_generator.py +88 -113
  36. google/adk/evaluation/evaluator.py +56 -0
  37. google/adk/evaluation/local_eval_sets_manager.py +264 -0
  38. google/adk/evaluation/response_evaluator.py +106 -2
  39. google/adk/evaluation/trajectory_evaluator.py +83 -2
  40. google/adk/events/event.py +6 -1
  41. google/adk/events/event_actions.py +6 -1
  42. google/adk/examples/example_util.py +3 -2
  43. google/adk/flows/llm_flows/_code_execution.py +9 -1
  44. google/adk/flows/llm_flows/audio_transcriber.py +4 -3
  45. google/adk/flows/llm_flows/base_llm_flow.py +54 -15
  46. google/adk/flows/llm_flows/functions.py +9 -8
  47. google/adk/flows/llm_flows/instructions.py +13 -5
  48. google/adk/flows/llm_flows/single_flow.py +1 -1
  49. google/adk/memory/__init__.py +1 -1
  50. google/adk/memory/_utils.py +23 -0
  51. google/adk/memory/base_memory_service.py +23 -21
  52. google/adk/memory/base_memory_service.py.orig +76 -0
  53. google/adk/memory/in_memory_memory_service.py +57 -25
  54. google/adk/memory/memory_entry.py +37 -0
  55. google/adk/memory/vertex_ai_rag_memory_service.py +38 -15
  56. google/adk/models/anthropic_llm.py +16 -9
  57. google/adk/models/gemini_llm_connection.py +11 -11
  58. google/adk/models/google_llm.py +9 -2
  59. google/adk/models/google_llm.py.orig +305 -0
  60. google/adk/models/lite_llm.py +77 -21
  61. google/adk/models/llm_response.py +14 -2
  62. google/adk/models/registry.py +1 -1
  63. google/adk/runners.py +65 -41
  64. google/adk/sessions/__init__.py +1 -1
  65. google/adk/sessions/base_session_service.py +6 -33
  66. google/adk/sessions/database_session_service.py +58 -65
  67. google/adk/sessions/in_memory_session_service.py +106 -24
  68. google/adk/sessions/session.py +3 -0
  69. google/adk/sessions/vertex_ai_session_service.py +23 -45
  70. google/adk/telemetry.py +3 -0
  71. google/adk/tools/__init__.py +4 -7
  72. google/adk/tools/{built_in_code_execution_tool.py → _built_in_code_execution_tool.py} +11 -0
  73. google/adk/tools/_memory_entry_utils.py +30 -0
  74. google/adk/tools/agent_tool.py +9 -9
  75. google/adk/tools/apihub_tool/apihub_toolset.py +55 -74
  76. google/adk/tools/application_integration_tool/application_integration_toolset.py +107 -85
  77. google/adk/tools/application_integration_tool/clients/connections_client.py +20 -0
  78. google/adk/tools/application_integration_tool/clients/integration_client.py +6 -6
  79. google/adk/tools/application_integration_tool/integration_connector_tool.py +69 -26
  80. google/adk/tools/base_toolset.py +58 -0
  81. google/adk/tools/enterprise_search_tool.py +65 -0
  82. google/adk/tools/function_parameter_parse_util.py +2 -2
  83. google/adk/tools/google_api_tool/__init__.py +18 -70
  84. google/adk/tools/google_api_tool/google_api_tool.py +11 -5
  85. google/adk/tools/google_api_tool/google_api_toolset.py +126 -0
  86. google/adk/tools/google_api_tool/google_api_toolsets.py +102 -0
  87. google/adk/tools/google_api_tool/googleapi_to_openapi_converter.py +40 -42
  88. google/adk/tools/langchain_tool.py +96 -49
  89. google/adk/tools/load_memory_tool.py +14 -5
  90. google/adk/tools/mcp_tool/__init__.py +3 -2
  91. google/adk/tools/mcp_tool/mcp_session_manager.py +153 -16
  92. google/adk/tools/mcp_tool/mcp_session_manager.py.orig +322 -0
  93. google/adk/tools/mcp_tool/mcp_tool.py +12 -12
  94. google/adk/tools/mcp_tool/mcp_toolset.py +155 -195
  95. google/adk/tools/openapi_tool/openapi_spec_parser/openapi_toolset.py +32 -7
  96. google/adk/tools/openapi_tool/openapi_spec_parser/operation_parser.py +31 -31
  97. google/adk/tools/openapi_tool/openapi_spec_parser/tool_auth_handler.py +1 -1
  98. google/adk/tools/preload_memory_tool.py +27 -18
  99. google/adk/tools/retrieval/__init__.py +1 -1
  100. google/adk/tools/retrieval/vertex_ai_rag_retrieval.py +1 -1
  101. google/adk/tools/toolbox_toolset.py +79 -0
  102. google/adk/tools/transfer_to_agent_tool.py +0 -1
  103. google/adk/version.py +1 -1
  104. {google_adk-0.5.0.dist-info → google_adk-1.0.0.dist-info}/METADATA +7 -5
  105. google_adk-1.0.0.dist-info/RECORD +195 -0
  106. google/adk/agents/remote_agent.py +0 -50
  107. google/adk/tools/google_api_tool/google_api_tool_set.py +0 -110
  108. google/adk/tools/google_api_tool/google_api_tool_sets.py +0 -112
  109. google/adk/tools/toolbox_tool.py +0 -46
  110. google_adk-0.5.0.dist-info/RECORD +0 -180
  111. {google_adk-0.5.0.dist-info → google_adk-1.0.0.dist-info}/WHEEL +0 -0
  112. {google_adk-0.5.0.dist-info → google_adk-1.0.0.dist-info}/entry_points.txt +0 -0
  113. {google_adk-0.5.0.dist-info → google_adk-1.0.0.dist-info}/licenses/LICENSE +0 -0
@@ -26,13 +26,58 @@ import uvicorn
26
26
 
27
27
  from . import cli_create
28
28
  from . import cli_deploy
29
+ from .. import version
29
30
  from .cli import run_cli
30
31
  from .cli_eval import MISSING_EVAL_DEPENDENCIES_MESSAGE
31
32
  from .fast_api import get_fast_api_app
32
33
  from .utils import envs
33
34
  from .utils import logs
34
35
 
35
- logger = logging.getLogger(__name__)
36
+
37
+ class HelpfulCommand(click.Command):
38
+ """Command that shows full help on error instead of just the error message.
39
+
40
+ A custom Click Command class that overrides the default error handling
41
+ behavior to display the full help text when a required argument is missing,
42
+ followed by the error message. This provides users with better context
43
+ about command usage without needing to run a separate --help command.
44
+
45
+ Args:
46
+ *args: Variable length argument list to pass to the parent class.
47
+ **kwargs: Arbitrary keyword arguments to pass to the parent class.
48
+
49
+ Returns:
50
+ None. Inherits behavior from the parent Click Command class.
51
+
52
+ Returns:
53
+ """
54
+
55
+ def __init__(self, *args, **kwargs):
56
+ super().__init__(*args, **kwargs)
57
+
58
+ def parse_args(self, ctx, args):
59
+ """Override the parse_args method to show help text on error.
60
+
61
+ Args:
62
+ ctx: Click context object for the current command.
63
+ args: List of command-line arguments to parse.
64
+
65
+ Returns:
66
+ The parsed arguments as returned by the parent class's parse_args method.
67
+
68
+ Raises:
69
+ click.MissingParameter: When a required parameter is missing, but this
70
+ is caught and handled by displaying the help text before exiting.
71
+ """
72
+ try:
73
+ return super().parse_args(ctx, args)
74
+ except click.MissingParameter as exc:
75
+ click.echo(ctx.get_help())
76
+ click.secho(f"\nError: {str(exc)}", fg="red", err=True)
77
+ ctx.exit(2)
78
+
79
+
80
+ logger = logging.getLogger("google_adk." + __name__)
36
81
 
37
82
 
38
83
  @click.group(context_settings={"max_content_width": 240})
@@ -47,7 +92,7 @@ def deploy():
47
92
  pass
48
93
 
49
94
 
50
- @main.command("create")
95
+ @main.command("create", cls=HelpfulCommand)
51
96
  @click.option(
52
97
  "--model",
53
98
  type=str,
@@ -113,7 +158,7 @@ def validate_exclusive(ctx, param, value):
113
158
  return value
114
159
 
115
160
 
116
- @main.command("run")
161
+ @main.command("run", cls=HelpfulCommand)
117
162
  @click.option(
118
163
  "--save_session",
119
164
  type=bool,
@@ -122,6 +167,15 @@ def validate_exclusive(ctx, param, value):
122
167
  default=False,
123
168
  help="Optional. Whether to save the session to a json file on exit.",
124
169
  )
170
+ @click.option(
171
+ "--session_id",
172
+ type=str,
173
+ help=(
174
+ "Optional. The session ID to save the session to on exit when"
175
+ " --save_session is set to true. User will be prompted to enter a"
176
+ " session ID if not set."
177
+ ),
178
+ )
125
179
  @click.option(
126
180
  "--replay",
127
181
  type=click.Path(
@@ -156,6 +210,7 @@ def validate_exclusive(ctx, param, value):
156
210
  def cli_run(
157
211
  agent: str,
158
212
  save_session: bool,
213
+ session_id: Optional[str],
159
214
  replay: Optional[str],
160
215
  resume: Optional[str],
161
216
  ):
@@ -179,11 +234,12 @@ def cli_run(
179
234
  input_file=replay,
180
235
  saved_session_file=resume,
181
236
  save_session=save_session,
237
+ session_id=session_id,
182
238
  )
183
239
  )
184
240
 
185
241
 
186
- @main.command("eval")
242
+ @main.command("eval", cls=HelpfulCommand)
187
243
  @click.argument(
188
244
  "agent_module_file_path",
189
245
  type=click.Path(
@@ -231,8 +287,9 @@ def cli_eval(
231
287
  envs.load_dotenv_for_agent(agent_module_file_path, ".")
232
288
 
233
289
  try:
290
+ from ..evaluation.local_eval_sets_manager import load_eval_set_from_file
291
+ from .cli_eval import EvalCaseResult
234
292
  from .cli_eval import EvalMetric
235
- from .cli_eval import EvalResult
236
293
  from .cli_eval import EvalStatus
237
294
  from .cli_eval import get_evaluation_criteria_or_default
238
295
  from .cli_eval import get_root_agent
@@ -254,20 +311,32 @@ def cli_eval(
254
311
  root_agent = get_root_agent(agent_module_file_path)
255
312
  reset_func = try_get_reset_func(agent_module_file_path)
256
313
 
257
- eval_set_to_evals = parse_and_get_evals_to_run(eval_set_file_path)
314
+ eval_set_file_path_to_evals = parse_and_get_evals_to_run(eval_set_file_path)
315
+ eval_set_id_to_eval_cases = {}
258
316
 
259
- try:
260
- eval_results = list(
261
- asyncio.run(
262
- run_evals(
263
- eval_set_to_evals,
264
- root_agent,
265
- reset_func,
266
- eval_metrics,
267
- print_detailed_results=print_detailed_results,
268
- )
317
+ # Read the eval_set files and get the cases.
318
+ for eval_set_file_path, eval_case_ids in eval_set_file_path_to_evals.items():
319
+ eval_set = load_eval_set_from_file(eval_set_file_path, eval_set_file_path)
320
+ eval_cases = eval_set.eval_cases
321
+
322
+ if eval_case_ids:
323
+ # There are eval_ids that we should select.
324
+ eval_cases = [
325
+ e for e in eval_set.eval_cases if e.eval_id in eval_case_ids
326
+ ]
327
+
328
+ eval_set_id_to_eval_cases[eval_set_file_path] = eval_cases
329
+
330
+ async def _collect_eval_results() -> list[EvalCaseResult]:
331
+ return [
332
+ result
333
+ async for result in run_evals(
334
+ eval_set_id_to_eval_cases, root_agent, reset_func, eval_metrics
269
335
  )
270
- )
336
+ ]
337
+
338
+ try:
339
+ eval_results = asyncio.run(_collect_eval_results())
271
340
  except ModuleNotFoundError:
272
341
  raise click.ClickException(MISSING_EVAL_DEPENDENCIES_MESSAGE)
273
342
 
@@ -275,22 +344,30 @@ def cli_eval(
275
344
  eval_run_summary = {}
276
345
 
277
346
  for eval_result in eval_results:
278
- eval_result: EvalResult
347
+ eval_result: EvalCaseResult
279
348
 
280
- if eval_result.eval_set_file not in eval_run_summary:
281
- eval_run_summary[eval_result.eval_set_file] = [0, 0]
349
+ if eval_result.eval_set_id not in eval_run_summary:
350
+ eval_run_summary[eval_result.eval_set_id] = [0, 0]
282
351
 
283
352
  if eval_result.final_eval_status == EvalStatus.PASSED:
284
- eval_run_summary[eval_result.eval_set_file][0] += 1
353
+ eval_run_summary[eval_result.eval_set_id][0] += 1
285
354
  else:
286
- eval_run_summary[eval_result.eval_set_file][1] += 1
355
+ eval_run_summary[eval_result.eval_set_id][1] += 1
287
356
  print("Eval Run Summary")
288
- for eval_set_file, pass_fail_count in eval_run_summary.items():
357
+ for eval_set_id, pass_fail_count in eval_run_summary.items():
289
358
  print(
290
- f"{eval_set_file}:\n Tests passed: {pass_fail_count[0]}\n Tests"
359
+ f"{eval_set_id}:\n Tests passed: {pass_fail_count[0]}\n Tests"
291
360
  f" failed: {pass_fail_count[1]}"
292
361
  )
293
362
 
363
+ if print_detailed_results:
364
+ for eval_result in eval_results:
365
+ eval_result: EvalCaseResult
366
+ print(
367
+ "*********************************************************************"
368
+ )
369
+ print(eval_result.model_dump_json(indent=2))
370
+
294
371
 
295
372
  @main.command("web")
296
373
  @click.option(
@@ -305,6 +382,13 @@ def cli_eval(
305
382
  - See https://docs.sqlalchemy.org/en/20/core/engines.html#backend-specific-urls for more details on supported DB URLs."""
306
383
  ),
307
384
  )
385
+ @click.option(
386
+ "--host",
387
+ type=str,
388
+ help="Optional. The binding host of the server",
389
+ default="127.0.0.1",
390
+ show_default=True,
391
+ )
308
392
  @click.option(
309
393
  "--port",
310
394
  type=int,
@@ -324,16 +408,6 @@ def cli_eval(
324
408
  default="INFO",
325
409
  help="Optional. Set the logging level",
326
410
  )
327
- @click.option(
328
- "--log_to_tmp",
329
- is_flag=True,
330
- show_default=True,
331
- default=False,
332
- help=(
333
- "Optional. Whether to log to system temp folder instead of console."
334
- " This is useful for local debugging."
335
- ),
336
- )
337
411
  @click.option(
338
412
  "--trace_to_cloud",
339
413
  is_flag=True,
@@ -341,6 +415,11 @@ def cli_eval(
341
415
  default=False,
342
416
  help="Optional. Whether to enable cloud trace for telemetry.",
343
417
  )
418
+ @click.option(
419
+ "--reload/--no-reload",
420
+ default=True,
421
+ help="Optional. Whether to enable auto reload for server.",
422
+ )
344
423
  @click.argument(
345
424
  "agents_dir",
346
425
  type=click.Path(
@@ -350,12 +429,13 @@ def cli_eval(
350
429
  )
351
430
  def cli_web(
352
431
  agents_dir: str,
353
- log_to_tmp: bool,
354
432
  session_db_url: str = "",
355
433
  log_level: str = "INFO",
356
434
  allow_origins: Optional[list[str]] = None,
435
+ host: str = "127.0.0.1",
357
436
  port: int = 8000,
358
437
  trace_to_cloud: bool = False,
438
+ reload: bool = True,
359
439
  ):
360
440
  """Starts a FastAPI server with Web UI for agents.
361
441
 
@@ -366,12 +446,7 @@ def cli_web(
366
446
 
367
447
  adk web --session_db_url=[db_url] --port=[port] path/to/agents_dir
368
448
  """
369
- if log_to_tmp:
370
- logs.log_to_tmp_folder()
371
- else:
372
- logs.log_to_stderr()
373
-
374
- logging.getLogger().setLevel(log_level)
449
+ logs.setup_adk_logger(getattr(logging, log_level.upper()))
375
450
 
376
451
  @asynccontextmanager
377
452
  async def _lifespan(app: FastAPI):
@@ -405,9 +480,9 @@ def cli_web(
405
480
  )
406
481
  config = uvicorn.Config(
407
482
  app,
408
- host="0.0.0.0",
483
+ host=host,
409
484
  port=port,
410
- reload=True,
485
+ reload=reload,
411
486
  )
412
487
 
413
488
  server = uvicorn.Server(config)
@@ -427,6 +502,13 @@ def cli_web(
427
502
  - See https://docs.sqlalchemy.org/en/20/core/engines.html#backend-specific-urls for more details on supported DB URLs."""
428
503
  ),
429
504
  )
505
+ @click.option(
506
+ "--host",
507
+ type=str,
508
+ help="Optional. The binding host of the server",
509
+ default="127.0.0.1",
510
+ show_default=True,
511
+ )
430
512
  @click.option(
431
513
  "--port",
432
514
  type=int,
@@ -446,16 +528,6 @@ def cli_web(
446
528
  default="INFO",
447
529
  help="Optional. Set the logging level",
448
530
  )
449
- @click.option(
450
- "--log_to_tmp",
451
- is_flag=True,
452
- show_default=True,
453
- default=False,
454
- help=(
455
- "Optional. Whether to log to system temp folder instead of console."
456
- " This is useful for local debugging."
457
- ),
458
- )
459
531
  @click.option(
460
532
  "--trace_to_cloud",
461
533
  is_flag=True,
@@ -463,6 +535,11 @@ def cli_web(
463
535
  default=False,
464
536
  help="Optional. Whether to enable cloud trace for telemetry.",
465
537
  )
538
+ @click.option(
539
+ "--reload/--no-reload",
540
+ default=True,
541
+ help="Optional. Whether to enable auto reload for server.",
542
+ )
466
543
  # The directory of agents, where each sub-directory is a single agent.
467
544
  # By default, it is the current working directory
468
545
  @click.argument(
@@ -474,12 +551,13 @@ def cli_web(
474
551
  )
475
552
  def cli_api_server(
476
553
  agents_dir: str,
477
- log_to_tmp: bool,
478
554
  session_db_url: str = "",
479
555
  log_level: str = "INFO",
480
556
  allow_origins: Optional[list[str]] = None,
557
+ host: str = "127.0.0.1",
481
558
  port: int = 8000,
482
559
  trace_to_cloud: bool = False,
560
+ reload: bool = True,
483
561
  ):
484
562
  """Starts a FastAPI server for agents.
485
563
 
@@ -490,12 +568,7 @@ def cli_api_server(
490
568
 
491
569
  adk api_server --session_db_url=[db_url] --port=[port] path/to/agents_dir
492
570
  """
493
- if log_to_tmp:
494
- logs.log_to_tmp_folder()
495
- else:
496
- logs.log_to_stderr()
497
-
498
- logging.getLogger().setLevel(log_level)
571
+ logs.setup_adk_logger(getattr(logging, log_level.upper()))
499
572
 
500
573
  config = uvicorn.Config(
501
574
  get_fast_api_app(
@@ -505,9 +578,9 @@ def cli_api_server(
505
578
  web=False,
506
579
  trace_to_cloud=trace_to_cloud,
507
580
  ),
508
- host="0.0.0.0",
581
+ host=host,
509
582
  port=port,
510
- reload=True,
583
+ reload=reload,
511
584
  )
512
585
  server = uvicorn.Server(config)
513
586
  server.run()
@@ -556,7 +629,6 @@ def cli_api_server(
556
629
  )
557
630
  @click.option(
558
631
  "--trace_to_cloud",
559
- type=bool,
560
632
  is_flag=True,
561
633
  show_default=True,
562
634
  default=False,
@@ -564,7 +636,6 @@ def cli_api_server(
564
636
  )
565
637
  @click.option(
566
638
  "--with_ui",
567
- type=bool,
568
639
  is_flag=True,
569
640
  show_default=True,
570
641
  default=False,
@@ -612,6 +683,16 @@ def cli_api_server(
612
683
  exists=True, dir_okay=True, file_okay=False, resolve_path=True
613
684
  ),
614
685
  )
686
+ @click.option(
687
+ "--adk_version",
688
+ type=str,
689
+ default=version.__version__,
690
+ show_default=True,
691
+ help=(
692
+ "Optional. The ADK version used in Cloud Run deployment. (default: the"
693
+ " version in the dev environment)"
694
+ ),
695
+ )
615
696
  def cli_deploy_cloud_run(
616
697
  agent: str,
617
698
  project: Optional[str],
@@ -624,6 +705,7 @@ def cli_deploy_cloud_run(
624
705
  with_ui: bool,
625
706
  verbosity: str,
626
707
  session_db_url: str,
708
+ adk_version: str,
627
709
  ):
628
710
  """Deploys an agent to Cloud Run.
629
711
 
@@ -646,6 +728,7 @@ def cli_deploy_cloud_run(
646
728
  with_ui=with_ui,
647
729
  verbosity=verbosity,
648
730
  session_db_url=session_db_url,
731
+ adk_version=adk_version,
649
732
  )
650
733
  except Exception as e:
651
734
  click.secho(f"Deploy failed: {e}", fg="red", err=True)