google-adk 0.4.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 (129) hide show
  1. google/adk/agents/active_streaming_tool.py +1 -0
  2. google/adk/agents/base_agent.py +91 -47
  3. google/adk/agents/base_agent.py.orig +330 -0
  4. google/adk/agents/callback_context.py +4 -9
  5. google/adk/agents/invocation_context.py +1 -0
  6. google/adk/agents/langgraph_agent.py +1 -0
  7. google/adk/agents/live_request_queue.py +1 -0
  8. google/adk/agents/llm_agent.py +172 -35
  9. google/adk/agents/loop_agent.py +1 -1
  10. google/adk/agents/parallel_agent.py +7 -0
  11. google/adk/agents/readonly_context.py +7 -1
  12. google/adk/agents/run_config.py +5 -1
  13. google/adk/agents/sequential_agent.py +31 -0
  14. google/adk/agents/transcription_entry.py +5 -2
  15. google/adk/artifacts/base_artifact_service.py +5 -10
  16. google/adk/artifacts/gcs_artifact_service.py +9 -9
  17. google/adk/artifacts/in_memory_artifact_service.py +6 -6
  18. google/adk/auth/auth_credential.py +9 -5
  19. google/adk/auth/auth_preprocessor.py +7 -1
  20. google/adk/auth/auth_tool.py +3 -4
  21. google/adk/cli/agent_graph.py +5 -5
  22. google/adk/cli/browser/index.html +2 -2
  23. google/adk/cli/browser/{main-HWIBUY2R.js → main-QOEMUXM4.js} +58 -58
  24. google/adk/cli/cli.py +7 -7
  25. google/adk/cli/cli_deploy.py +7 -2
  26. google/adk/cli/cli_eval.py +181 -106
  27. google/adk/cli/cli_tools_click.py +147 -62
  28. google/adk/cli/fast_api.py +340 -158
  29. google/adk/cli/fast_api.py.orig +822 -0
  30. google/adk/cli/utils/common.py +23 -0
  31. google/adk/cli/utils/evals.py +83 -1
  32. google/adk/cli/utils/logs.py +13 -5
  33. google/adk/code_executors/__init__.py +3 -1
  34. google/adk/code_executors/built_in_code_executor.py +52 -0
  35. google/adk/evaluation/__init__.py +1 -1
  36. google/adk/evaluation/agent_evaluator.py +168 -128
  37. google/adk/evaluation/eval_case.py +102 -0
  38. google/adk/evaluation/eval_set.py +37 -0
  39. google/adk/evaluation/eval_sets_manager.py +42 -0
  40. google/adk/evaluation/evaluation_constants.py +1 -0
  41. google/adk/evaluation/evaluation_generator.py +89 -114
  42. google/adk/evaluation/evaluator.py +56 -0
  43. google/adk/evaluation/local_eval_sets_manager.py +264 -0
  44. google/adk/evaluation/response_evaluator.py +107 -3
  45. google/adk/evaluation/trajectory_evaluator.py +83 -2
  46. google/adk/events/event.py +7 -1
  47. google/adk/events/event_actions.py +7 -1
  48. google/adk/examples/example.py +1 -0
  49. google/adk/examples/example_util.py +3 -2
  50. google/adk/flows/__init__.py +0 -1
  51. google/adk/flows/llm_flows/_code_execution.py +19 -11
  52. google/adk/flows/llm_flows/audio_transcriber.py +4 -3
  53. google/adk/flows/llm_flows/base_llm_flow.py +86 -22
  54. google/adk/flows/llm_flows/basic.py +3 -0
  55. google/adk/flows/llm_flows/functions.py +10 -9
  56. google/adk/flows/llm_flows/instructions.py +28 -9
  57. google/adk/flows/llm_flows/single_flow.py +1 -1
  58. google/adk/memory/__init__.py +1 -1
  59. google/adk/memory/_utils.py +23 -0
  60. google/adk/memory/base_memory_service.py +25 -21
  61. google/adk/memory/base_memory_service.py.orig +76 -0
  62. google/adk/memory/in_memory_memory_service.py +59 -27
  63. google/adk/memory/memory_entry.py +37 -0
  64. google/adk/memory/vertex_ai_rag_memory_service.py +40 -17
  65. google/adk/models/anthropic_llm.py +36 -11
  66. google/adk/models/base_llm.py +45 -4
  67. google/adk/models/gemini_llm_connection.py +15 -2
  68. google/adk/models/google_llm.py +9 -44
  69. google/adk/models/google_llm.py.orig +305 -0
  70. google/adk/models/lite_llm.py +94 -38
  71. google/adk/models/llm_request.py +1 -1
  72. google/adk/models/llm_response.py +15 -3
  73. google/adk/models/registry.py +1 -1
  74. google/adk/runners.py +68 -44
  75. google/adk/sessions/__init__.py +1 -1
  76. google/adk/sessions/_session_util.py +14 -0
  77. google/adk/sessions/base_session_service.py +8 -32
  78. google/adk/sessions/database_session_service.py +58 -61
  79. google/adk/sessions/in_memory_session_service.py +108 -26
  80. google/adk/sessions/session.py +4 -0
  81. google/adk/sessions/vertex_ai_session_service.py +23 -45
  82. google/adk/telemetry.py +3 -0
  83. google/adk/tools/__init__.py +4 -7
  84. google/adk/tools/{built_in_code_execution_tool.py → _built_in_code_execution_tool.py} +11 -0
  85. google/adk/tools/_memory_entry_utils.py +30 -0
  86. google/adk/tools/agent_tool.py +16 -13
  87. google/adk/tools/apihub_tool/apihub_toolset.py +55 -74
  88. google/adk/tools/application_integration_tool/application_integration_toolset.py +107 -85
  89. google/adk/tools/application_integration_tool/clients/connections_client.py +29 -25
  90. google/adk/tools/application_integration_tool/clients/integration_client.py +6 -6
  91. google/adk/tools/application_integration_tool/integration_connector_tool.py +69 -26
  92. google/adk/tools/base_toolset.py +58 -0
  93. google/adk/tools/enterprise_search_tool.py +65 -0
  94. google/adk/tools/function_parameter_parse_util.py +2 -2
  95. google/adk/tools/google_api_tool/__init__.py +18 -70
  96. google/adk/tools/google_api_tool/google_api_tool.py +11 -5
  97. google/adk/tools/google_api_tool/google_api_toolset.py +126 -0
  98. google/adk/tools/google_api_tool/google_api_toolsets.py +102 -0
  99. google/adk/tools/google_api_tool/googleapi_to_openapi_converter.py +40 -42
  100. google/adk/tools/langchain_tool.py +96 -49
  101. google/adk/tools/load_artifacts_tool.py +4 -4
  102. google/adk/tools/load_memory_tool.py +16 -5
  103. google/adk/tools/mcp_tool/__init__.py +3 -2
  104. google/adk/tools/mcp_tool/conversion_utils.py +1 -1
  105. google/adk/tools/mcp_tool/mcp_session_manager.py +167 -16
  106. google/adk/tools/mcp_tool/mcp_session_manager.py.orig +322 -0
  107. google/adk/tools/mcp_tool/mcp_tool.py +12 -12
  108. google/adk/tools/mcp_tool/mcp_toolset.py +155 -195
  109. google/adk/tools/openapi_tool/common/common.py +2 -5
  110. google/adk/tools/openapi_tool/openapi_spec_parser/openapi_toolset.py +32 -7
  111. google/adk/tools/openapi_tool/openapi_spec_parser/operation_parser.py +43 -33
  112. google/adk/tools/openapi_tool/openapi_spec_parser/tool_auth_handler.py +1 -1
  113. google/adk/tools/preload_memory_tool.py +27 -18
  114. google/adk/tools/retrieval/__init__.py +1 -1
  115. google/adk/tools/retrieval/vertex_ai_rag_retrieval.py +1 -1
  116. google/adk/tools/tool_context.py +4 -4
  117. google/adk/tools/toolbox_toolset.py +79 -0
  118. google/adk/tools/transfer_to_agent_tool.py +0 -1
  119. google/adk/version.py +1 -1
  120. {google_adk-0.4.0.dist-info → google_adk-1.0.0.dist-info}/METADATA +7 -5
  121. google_adk-1.0.0.dist-info/RECORD +195 -0
  122. google/adk/agents/remote_agent.py +0 -50
  123. google/adk/tools/google_api_tool/google_api_tool_set.py +0 -110
  124. google/adk/tools/google_api_tool/google_api_tool_sets.py +0 -112
  125. google/adk/tools/toolbox_tool.py +0 -46
  126. google_adk-0.4.0.dist-info/RECORD +0 -179
  127. {google_adk-0.4.0.dist-info → google_adk-1.0.0.dist-info}/WHEEL +0 -0
  128. {google_adk-0.4.0.dist-info → google_adk-1.0.0.dist-info}/entry_points.txt +0 -0
  129. {google_adk-0.4.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,18 +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
- run_evals(
262
- eval_set_to_evals,
263
- root_agent,
264
- reset_func,
265
- eval_metrics,
266
- print_detailed_results=print_detailed_results,
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
267
335
  )
268
- )
336
+ ]
337
+
338
+ try:
339
+ eval_results = asyncio.run(_collect_eval_results())
269
340
  except ModuleNotFoundError:
270
341
  raise click.ClickException(MISSING_EVAL_DEPENDENCIES_MESSAGE)
271
342
 
@@ -273,22 +344,30 @@ def cli_eval(
273
344
  eval_run_summary = {}
274
345
 
275
346
  for eval_result in eval_results:
276
- eval_result: EvalResult
347
+ eval_result: EvalCaseResult
277
348
 
278
- if eval_result.eval_set_file not in eval_run_summary:
279
- 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]
280
351
 
281
352
  if eval_result.final_eval_status == EvalStatus.PASSED:
282
- eval_run_summary[eval_result.eval_set_file][0] += 1
353
+ eval_run_summary[eval_result.eval_set_id][0] += 1
283
354
  else:
284
- eval_run_summary[eval_result.eval_set_file][1] += 1
355
+ eval_run_summary[eval_result.eval_set_id][1] += 1
285
356
  print("Eval Run Summary")
286
- 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():
287
358
  print(
288
- 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"
289
360
  f" failed: {pass_fail_count[1]}"
290
361
  )
291
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
+
292
371
 
293
372
  @main.command("web")
294
373
  @click.option(
@@ -303,6 +382,13 @@ def cli_eval(
303
382
  - See https://docs.sqlalchemy.org/en/20/core/engines.html#backend-specific-urls for more details on supported DB URLs."""
304
383
  ),
305
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
+ )
306
392
  @click.option(
307
393
  "--port",
308
394
  type=int,
@@ -322,16 +408,6 @@ def cli_eval(
322
408
  default="INFO",
323
409
  help="Optional. Set the logging level",
324
410
  )
325
- @click.option(
326
- "--log_to_tmp",
327
- is_flag=True,
328
- show_default=True,
329
- default=False,
330
- help=(
331
- "Optional. Whether to log to system temp folder instead of console."
332
- " This is useful for local debugging."
333
- ),
334
- )
335
411
  @click.option(
336
412
  "--trace_to_cloud",
337
413
  is_flag=True,
@@ -339,6 +415,11 @@ def cli_eval(
339
415
  default=False,
340
416
  help="Optional. Whether to enable cloud trace for telemetry.",
341
417
  )
418
+ @click.option(
419
+ "--reload/--no-reload",
420
+ default=True,
421
+ help="Optional. Whether to enable auto reload for server.",
422
+ )
342
423
  @click.argument(
343
424
  "agents_dir",
344
425
  type=click.Path(
@@ -348,12 +429,13 @@ def cli_eval(
348
429
  )
349
430
  def cli_web(
350
431
  agents_dir: str,
351
- log_to_tmp: bool,
352
432
  session_db_url: str = "",
353
433
  log_level: str = "INFO",
354
434
  allow_origins: Optional[list[str]] = None,
435
+ host: str = "127.0.0.1",
355
436
  port: int = 8000,
356
437
  trace_to_cloud: bool = False,
438
+ reload: bool = True,
357
439
  ):
358
440
  """Starts a FastAPI server with Web UI for agents.
359
441
 
@@ -364,12 +446,7 @@ def cli_web(
364
446
 
365
447
  adk web --session_db_url=[db_url] --port=[port] path/to/agents_dir
366
448
  """
367
- if log_to_tmp:
368
- logs.log_to_tmp_folder()
369
- else:
370
- logs.log_to_stderr()
371
-
372
- logging.getLogger().setLevel(log_level)
449
+ logs.setup_adk_logger(getattr(logging, log_level.upper()))
373
450
 
374
451
  @asynccontextmanager
375
452
  async def _lifespan(app: FastAPI):
@@ -403,9 +480,9 @@ def cli_web(
403
480
  )
404
481
  config = uvicorn.Config(
405
482
  app,
406
- host="0.0.0.0",
483
+ host=host,
407
484
  port=port,
408
- reload=True,
485
+ reload=reload,
409
486
  )
410
487
 
411
488
  server = uvicorn.Server(config)
@@ -425,6 +502,13 @@ def cli_web(
425
502
  - See https://docs.sqlalchemy.org/en/20/core/engines.html#backend-specific-urls for more details on supported DB URLs."""
426
503
  ),
427
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
+ )
428
512
  @click.option(
429
513
  "--port",
430
514
  type=int,
@@ -444,16 +528,6 @@ def cli_web(
444
528
  default="INFO",
445
529
  help="Optional. Set the logging level",
446
530
  )
447
- @click.option(
448
- "--log_to_tmp",
449
- is_flag=True,
450
- show_default=True,
451
- default=False,
452
- help=(
453
- "Optional. Whether to log to system temp folder instead of console."
454
- " This is useful for local debugging."
455
- ),
456
- )
457
531
  @click.option(
458
532
  "--trace_to_cloud",
459
533
  is_flag=True,
@@ -461,6 +535,11 @@ def cli_web(
461
535
  default=False,
462
536
  help="Optional. Whether to enable cloud trace for telemetry.",
463
537
  )
538
+ @click.option(
539
+ "--reload/--no-reload",
540
+ default=True,
541
+ help="Optional. Whether to enable auto reload for server.",
542
+ )
464
543
  # The directory of agents, where each sub-directory is a single agent.
465
544
  # By default, it is the current working directory
466
545
  @click.argument(
@@ -472,12 +551,13 @@ def cli_web(
472
551
  )
473
552
  def cli_api_server(
474
553
  agents_dir: str,
475
- log_to_tmp: bool,
476
554
  session_db_url: str = "",
477
555
  log_level: str = "INFO",
478
556
  allow_origins: Optional[list[str]] = None,
557
+ host: str = "127.0.0.1",
479
558
  port: int = 8000,
480
559
  trace_to_cloud: bool = False,
560
+ reload: bool = True,
481
561
  ):
482
562
  """Starts a FastAPI server for agents.
483
563
 
@@ -488,12 +568,7 @@ def cli_api_server(
488
568
 
489
569
  adk api_server --session_db_url=[db_url] --port=[port] path/to/agents_dir
490
570
  """
491
- if log_to_tmp:
492
- logs.log_to_tmp_folder()
493
- else:
494
- logs.log_to_stderr()
495
-
496
- logging.getLogger().setLevel(log_level)
571
+ logs.setup_adk_logger(getattr(logging, log_level.upper()))
497
572
 
498
573
  config = uvicorn.Config(
499
574
  get_fast_api_app(
@@ -503,9 +578,9 @@ def cli_api_server(
503
578
  web=False,
504
579
  trace_to_cloud=trace_to_cloud,
505
580
  ),
506
- host="0.0.0.0",
581
+ host=host,
507
582
  port=port,
508
- reload=True,
583
+ reload=reload,
509
584
  )
510
585
  server = uvicorn.Server(config)
511
586
  server.run()
@@ -554,7 +629,6 @@ def cli_api_server(
554
629
  )
555
630
  @click.option(
556
631
  "--trace_to_cloud",
557
- type=bool,
558
632
  is_flag=True,
559
633
  show_default=True,
560
634
  default=False,
@@ -562,7 +636,6 @@ def cli_api_server(
562
636
  )
563
637
  @click.option(
564
638
  "--with_ui",
565
- type=bool,
566
639
  is_flag=True,
567
640
  show_default=True,
568
641
  default=False,
@@ -610,6 +683,16 @@ def cli_api_server(
610
683
  exists=True, dir_okay=True, file_okay=False, resolve_path=True
611
684
  ),
612
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
+ )
613
696
  def cli_deploy_cloud_run(
614
697
  agent: str,
615
698
  project: Optional[str],
@@ -622,6 +705,7 @@ def cli_deploy_cloud_run(
622
705
  with_ui: bool,
623
706
  verbosity: str,
624
707
  session_db_url: str,
708
+ adk_version: str,
625
709
  ):
626
710
  """Deploys an agent to Cloud Run.
627
711
 
@@ -644,6 +728,7 @@ def cli_deploy_cloud_run(
644
728
  with_ui=with_ui,
645
729
  verbosity=verbosity,
646
730
  session_db_url=session_db_url,
731
+ adk_version=adk_version,
647
732
  )
648
733
  except Exception as e:
649
734
  click.secho(f"Deploy failed: {e}", fg="red", err=True)