google-cloud-agentplatform 2.7.0__tar.gz → 2.9.0__tar.gz

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 (74) hide show
  1. {google_cloud_agentplatform-2.7.0/google_cloud_agentplatform.egg-info → google_cloud_agentplatform-2.9.0}/PKG-INFO +2 -3
  2. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/_evals_common.py +31 -3
  3. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/_evals_metric_handlers.py +62 -0
  4. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/_runtimes_utils.py +5 -66
  5. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/_transformers.py +52 -0
  6. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/evals.py +14 -0
  7. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/feedback_entries.py +2 -2
  8. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/runtimes.py +40 -10
  9. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/types/__init__.py +70 -0
  10. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/types/common.py +473 -10
  11. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/frameworks/adk.py +17 -6
  12. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/version.py +1 -1
  13. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0/google_cloud_agentplatform.egg-info}/PKG-INFO +2 -3
  14. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/google_cloud_agentplatform.egg-info/requires.txt +2 -5
  15. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/pyproject.toml +3 -4
  16. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/LICENSE +0 -0
  17. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/README.md +0 -0
  18. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/__init__.py +0 -0
  19. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/__init__.py +0 -0
  20. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/_bigquery_utils.py +0 -0
  21. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/_datasets_utils.py +0 -0
  22. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/_evals_builtin_tools.py +0 -0
  23. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/_evals_constant.py +0 -0
  24. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/_evals_data_converters.py +0 -0
  25. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/_evals_metric_loaders.py +0 -0
  26. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/_evals_utils.py +0 -0
  27. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/_evals_visualization.py +0 -0
  28. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/_gcs_utils.py +0 -0
  29. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/_logging_utils.py +0 -0
  30. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/_memory_bank_utils.py +0 -0
  31. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/_observability_data_converter.py +0 -0
  32. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/_operations_utils.py +0 -0
  33. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/_prompt_management_utils.py +0 -0
  34. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/_prompt_optimizer_utils.py +0 -0
  35. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/_skills_utils.py +0 -0
  36. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/a2a_task_events.py +0 -0
  37. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/a2a_tasks.py +0 -0
  38. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/client.py +0 -0
  39. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/datasets.py +0 -0
  40. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/endpoints.py +0 -0
  41. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/example_stores.py +0 -0
  42. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/feedback_contexts.py +0 -0
  43. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/live.py +0 -0
  44. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/live_runtimes.py +0 -0
  45. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/memories.py +0 -0
  46. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/memory_banks.py +0 -0
  47. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/memory_revisions.py +0 -0
  48. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/model_garden.py +0 -0
  49. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/prompt_optimizer.py +0 -0
  50. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/prompts.py +0 -0
  51. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/rag.py +0 -0
  52. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/runtime_revisions.py +0 -0
  53. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/sandbox_snapshots.py +0 -0
  54. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/sandbox_templates.py +0 -0
  55. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/sandboxes.py +0 -0
  56. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/serving_profiles.py +0 -0
  57. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/session_events.py +0 -0
  58. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/sessions.py +0 -0
  59. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/skill_revisions.py +0 -0
  60. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/skills.py +0 -0
  61. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/types/agent_engines.py +0 -0
  62. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/types/evals.py +0 -0
  63. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/types/prompt_optimizer.py +0 -0
  64. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/_genai/types/prompts.py +0 -0
  65. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/frameworks/__init__.py +0 -0
  66. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/frameworks/a2a.py +0 -0
  67. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/frameworks/ag2.py +0 -0
  68. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/frameworks/langchain.py +0 -0
  69. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/frameworks/langgraph.py +0 -0
  70. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/agentplatform/frameworks/llama_index.py +0 -0
  71. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/google_cloud_agentplatform.egg-info/SOURCES.txt +0 -0
  72. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/google_cloud_agentplatform.egg-info/dependency_links.txt +0 -0
  73. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/google_cloud_agentplatform.egg-info/top_level.txt +0 -0
  74. {google_cloud_agentplatform-2.7.0 → google_cloud_agentplatform-2.9.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: google-cloud-agentplatform
3
- Version: 2.7.0
3
+ Version: 2.9.0
4
4
  Summary: Google Cloud Agent Platform Client Library
5
5
  Author-email: Google LLC <googleapis-packages@google.com>
6
6
  License: Apache-2.0
@@ -61,8 +61,7 @@ Provides-Extra: evaluation
61
61
  Requires-Dist: pandas>=1.0.0; extra == "evaluation"
62
62
  Requires-Dist: tqdm>=4.23.0; extra == "evaluation"
63
63
  Requires-Dist: pyyaml; extra == "evaluation"
64
- Requires-Dist: litellm<1.86.0,>=1.83.7; python_version < "3.14" and extra == "evaluation"
65
- Requires-Dist: litellm<1.97.0,>=1.93.0; python_version >= "3.14" and extra == "evaluation"
64
+ Requires-Dist: litellm!=1.107.0,<1.110.0,>=1.106.5; python_version < "3.15" and extra == "evaluation"
66
65
  Requires-Dist: google-cloud-storage<4.0.0,>=1.32.0; extra == "evaluation"
67
66
  Provides-Extra: bigquery
68
67
  Requires-Dist: google-cloud-bigquery<4.0.0,>=1.15.0; extra == "bigquery"
@@ -3238,6 +3238,31 @@ def _process_multi_turn_agent_response(
3238
3238
  ).model_dump(exclude_unset=True)
3239
3239
 
3240
3240
 
3241
+ def _extract_final_response_text(
3242
+ events: list[dict[str, Any]],
3243
+ ) -> tuple[Optional[int], str]:
3244
+ """Returns the index and text of the last final response in the events.
3245
+
3246
+ As in ADK's `Event.is_final_response()`, events with function calls or
3247
+ responses are not final responses, so they stay in the intermediate events.
3248
+ Thought parts are not part of the response text.
3249
+ """
3250
+ for index in range(len(events) - 1, -1, -1):
3251
+ parts = (events[index].get("content") or {}).get("parts") or []
3252
+ if any(
3253
+ part.get("function_call") or part.get("function_response") for part in parts
3254
+ ):
3255
+ continue
3256
+ texts = [
3257
+ part["text"]
3258
+ for part in parts
3259
+ if part.get("text") and not part.get("thought")
3260
+ ]
3261
+ if texts:
3262
+ return index, "".join(texts)
3263
+ return None, ""
3264
+
3265
+
3241
3266
  def _process_single_turn_agent_response(
3242
3267
  resp_item: Any,
3243
3268
  agent_data_agents: Optional[dict[str, Any]],
@@ -3253,8 +3278,10 @@ def _process_single_turn_agent_response(
3253
3278
 
3254
3279
  if isinstance(resp_item, list):
3255
3280
  try:
3256
- response_row = resp_item[-1]["content"]["parts"][0]["text"]
3257
- for intermediate_event in resp_item[:-1]:
3281
+ response_index, response_row = _extract_final_response_text(resp_item)
3282
+ for index, intermediate_event in enumerate(resp_item):
3283
+ if index == response_index:
3284
+ continue
3258
3285
  intermediate_events_row.append(
3259
3286
  {
3260
3287
  "event_id": intermediate_event.get("id"),
@@ -3263,7 +3290,7 @@ def _process_single_turn_agent_response(
3263
3290
  "author": intermediate_event.get("author"),
3264
3291
  }
3265
3292
  )
3266
- # Construct AgentData natively for single-turn runs
3293
+ # Construct AgentData natively for single-turn runs
3267
3294
  agent_events = []
3268
3295
  for event_dict in resp_item:
3269
3296
  content_dict = event_dict.get("content")
@@ -3288,6 +3315,7 @@ def _process_single_turn_agent_response(
3288
3315
  agents=agent_data_agents,
3289
3316
  ).model_dump(exclude_unset=True)
3290
3317
  except Exception as e: # pylint: disable=broad-exception-caught
3318
+ intermediate_events_row = []
3291
3319
  error_payload = {
3292
3320
  "error": (
3293
3321
  f"Failed to parse agent run response {str(resp_item)} to "
@@ -846,6 +846,66 @@ class LLMMetricHandler(MetricHandler[types.LLMMetric]):
846
846
  return _default_aggregate_scores(self.metric.name, eval_case_metric_results)
847
847
 
848
848
 
849
+ class StepBasedLLMMetricHandler(LLMMetricHandler):
850
+ """Metric handler for step-based LLM metrics."""
851
+
852
+ @override
853
+ def get_metric_result(
854
+ self, eval_case: types.EvalCase, response_index: int
855
+ ) -> types.EvalCaseMetricResult:
856
+ """Evaluates one case with the step-based LLM metric."""
857
+ try:
858
+ response_content = _get_response_from_eval_case(
859
+ eval_case, response_index, self.metric_name
860
+ )
861
+ if not response_content and not getattr(eval_case, "agent_data", None):
862
+ raise ValueError(
863
+ f"Response content missing for candidate {response_index}."
864
+ )
865
+
866
+ # Joined so dataset columns referenced by any step reach other_data.
867
+ prompt_templates = "\n".join(
868
+ step.prompt_template or "" for step in self.metric.steps or []
869
+ )
870
+ instance = _build_evaluation_instance(
871
+ eval_case, response_content, prompt_template=prompt_templates
872
+ )
873
+ api_response = _call_with_retry(
874
+ lambda: self.module._evaluate_instances(
875
+ metrics=[self.metric],
876
+ instance=instance,
877
+ allow_cross_region_model=self.allow_cross_region_model,
878
+ ),
879
+ self.metric_name,
880
+ )
881
+
882
+ if api_response and api_response.metric_results:
883
+ result = api_response.metric_results[0]
884
+ error_msg = None
885
+ if result.error and getattr(result.error, "code"):
886
+ error_msg = f"Error in metric result: {result.error}"
887
+ return types.EvalCaseMetricResult(
888
+ metric_name=self.metric_name,
889
+ score=result.score,
890
+ explanation=result.explanation,
891
+ error_message=error_msg,
892
+ )
893
+ return types.EvalCaseMetricResult(
894
+ metric_name=self.metric_name,
895
+ error_message="Metric results missing in API response.",
896
+ )
897
+ except Exception as e: # pylint: disable=broad-exception-caught
898
+ logger.error(
899
+ "Error processing metric %s for case %s.",
900
+ self.metric_name,
901
+ eval_case.eval_case_id,
902
+ exc_info=True,
903
+ )
904
+ return types.EvalCaseMetricResult(
905
+ metric_name=self.metric_name, error_message=str(e)
906
+ )
907
+
908
+
849
909
  class CustomMetricHandler(MetricHandler[types.Metric]):
850
910
  """Metric handler for custom metrics."""
851
911
 
@@ -1375,6 +1435,7 @@ _METRIC_HANDLER_MAPPING = [
1375
1435
  lambda m: getattr(m, "metric_resource_name", None) is not None,
1376
1436
  RegisteredMetricHandler,
1377
1437
  ),
1438
+ (lambda m: getattr(m, "steps", None), StepBasedLLMMetricHandler),
1378
1439
  (
1379
1440
  lambda m: m.name in ComputationMetricHandler.SUPPORTED_COMPUTATION_METRICS,
1380
1441
  ComputationMetricHandler,
@@ -1395,6 +1456,7 @@ MetricHandlerType = TypeVar(
1395
1456
  ComputationMetricHandler,
1396
1457
  TranslationMetricHandler,
1397
1458
  LLMMetricHandler,
1459
+ StepBasedLLMMetricHandler,
1398
1460
  CustomMetricHandler,
1399
1461
  CustomCodeExecutionMetricHandler,
1400
1462
  PredefinedMetricHandler,
@@ -1322,6 +1322,8 @@ def _upload_extra_packages(
1322
1322
  tar_fileobj = io.BytesIO()
1323
1323
  with tarfile.open(fileobj=tar_fileobj, mode="w|gz") as tar:
1324
1324
  for file in extra_packages:
1325
+ # Note: tar.add(file) preserves each path relative to the current
1326
+ # working directory in the archive (extracted into /code).
1325
1327
  tar.add(file)
1326
1328
  tar_fileobj.seek(0)
1327
1329
  blob = gcs_bucket.blob(f"{gcs_dir_name}/{_EXTRA_PACKAGES_FILE}")
@@ -1360,78 +1362,14 @@ def _validate_packages_or_raise(
1360
1362
  build_options: Optional[Dict[str, Sequence[str]]] = None,
1361
1363
  ) -> Sequence[str]:
1362
1364
  """Tries to validates the packages."""
1365
+ del build_options
1363
1366
  packages = packages or []
1364
- if build_options and _INSTALLATION_SUBDIR in build_options:
1365
- _validate_installation_scripts_or_raise(
1366
- script_paths=build_options[_INSTALLATION_SUBDIR],
1367
- packages=packages,
1368
- )
1369
1367
  for package in packages:
1370
1368
  if not os.path.exists(package):
1371
1369
  raise FileNotFoundError(f"Package specified but not found: {package=}")
1372
1370
  return packages
1373
1371
 
1374
1372
 
1375
- def _validate_installation_scripts_or_raise(
1376
- *,
1377
- script_paths: Sequence[str],
1378
- packages: Sequence[str],
1379
- ) -> None:
1380
- """Validates the installation scripts' path explicitly provided by the user.
1381
-
1382
- Args:
1383
- script_paths (Sequence[str]):
1384
- Required. The paths to the installation scripts.
1385
- packages (Sequence[str]):
1386
- Required. The user-provided packages.
1387
-
1388
- Raises:
1389
- ValueError: If a user-defined script is not under the expected
1390
- subdirectory, or not in `packages`, or if a package is
1391
- in the installation scripts subdirectory, but is not specified as an
1392
- installation script.
1393
- """
1394
- for script_path in script_paths:
1395
- if not script_path.startswith(_INSTALLATION_SUBDIR):
1396
- logger.warning(
1397
- f"User-defined installation script '{script_path}' is not in "
1398
- f"the expected '{_INSTALLATION_SUBDIR}' subdirectory. "
1399
- f"Ensure it is placed in '{_INSTALLATION_SUBDIR}' within your "
1400
- f"'extra_packages' or 'source_packages'."
1401
- )
1402
- raise ValueError(
1403
- f"Required installation script '{script_path}' "
1404
- f"is not under '{_INSTALLATION_SUBDIR}'"
1405
- )
1406
-
1407
- if script_path not in packages:
1408
- logger.warning(
1409
- f"User-defined installation script '{script_path}' is not in "
1410
- f"'extra_packages' or 'source_packages'. Ensure it is added to "
1411
- f"'extra_packages' or 'source_packages'."
1412
- )
1413
- raise ValueError(
1414
- f"User-defined installation script '{script_path}' "
1415
- f"does not exist in 'extra_packages' or 'source_packages'."
1416
- )
1417
-
1418
- for package in packages:
1419
- if package.startswith(_INSTALLATION_SUBDIR) and package not in script_paths:
1420
- logger.warning(
1421
- f"Package '{package}' is in the installation "
1422
- "scripts subdirectory, but is not specified as an installation "
1423
- "script in `build_options`. "
1424
- "Ensure it is added to installation_scripts for "
1425
- "automatic execution."
1426
- )
1427
- raise ValueError(
1428
- f"Package '{package}' is in the installation "
1429
- "scripts subdirectory, but is not specified as an installation "
1430
- "script in `build_options`."
1431
- )
1432
- return
1433
-
1434
-
1435
1373
  def _validate_staging_bucket_or_raise(*, staging_bucket: str) -> str:
1436
1374
  """Tries to validate the staging bucket."""
1437
1375
  if not staging_bucket:
@@ -1875,7 +1813,8 @@ def _wrap_a2a_operation(method_name: str, agent_card: str) -> Callable[..., list
1875
1813
  f"Bearer {self.api_client._api_client._credentials.token}"
1876
1814
  )
1877
1815
  },
1878
- timeout=(
1816
+ timeout=kwargs.pop("timeout", None)
1817
+ or (
1879
1818
  self.api_client._api_client._http_options.timeout / 1000.0
1880
1819
  if self.api_client._api_client._http_options.timeout
1881
1820
  else None
@@ -89,6 +89,11 @@ def t_metrics(
89
89
  metric_payload_item["custom_code_execution_spec"] = {
90
90
  "evaluation_function": metric.custom_function
91
91
  }
92
+ # Step-based LLM metrics
93
+ elif getv(metric, ["steps"]):
94
+ metric_payload_item["step_based_llm_metric_spec"] = (
95
+ _step_based_llm_metric_spec(metric)
96
+ )
92
97
  # LLM-based metrics
93
98
  elif hasattr(metric, "prompt_template") and metric.prompt_template:
94
99
  llm_based_spec: dict[str, Any] = {
@@ -145,6 +150,47 @@ def t_metrics(
145
150
  return metrics_payload
146
151
 
147
152
 
153
+ def _dump(value: Any) -> Any:
154
+ if hasattr(value, "model_dump"):
155
+ return value.model_dump(exclude_none=True)
156
+ return value
157
+
158
+
159
+ def _step_based_llm_metric_spec(metric: Any) -> dict[str, Any]:
160
+ """Builds a StepBasedLlmMetricSpec payload.
161
+
162
+ autorater_config fields a step leaves unset fall back to the metric's judge
163
+ model settings.
164
+ """
165
+ default_autorater_config: dict[str, Any] = {}
166
+ if getv(metric, ["judge_model"]):
167
+ default_autorater_config["autorater_model"] = getv(metric, ["judge_model"])
168
+ if getv(metric, ["judge_model_generation_config"]):
169
+ default_autorater_config["generation_config"] = _dump(
170
+ getv(metric, ["judge_model_generation_config"])
171
+ )
172
+ if getv(metric, ["judge_model_sampling_count"]):
173
+ default_autorater_config["sampling_count"] = getv(
174
+ metric, ["judge_model_sampling_count"]
175
+ )
176
+
177
+ steps = []
178
+ for step in getv(metric, ["steps"]):
179
+ step_payload = _dump(step)
180
+ if default_autorater_config:
181
+ step_payload["autorater_config"] = {
182
+ **default_autorater_config,
183
+ **step_payload.get("autorater_config", {}),
184
+ }
185
+ steps.append(step_payload)
186
+
187
+ spec: dict[str, Any] = {"steps": steps}
188
+ preprocessor = getv(metric, ["preprocessor"])
189
+ if preprocessor:
190
+ spec["preprocessor"] = _dump(preprocessor)
191
+ return spec
192
+
193
+
148
194
  def t_metric_sources(metrics: list[Any]) -> list[dict[str, Any]]:
149
195
  """Prepares the MetricSource payload."""
150
196
  sources_payload = []
@@ -217,6 +263,12 @@ def t_metric_for_registry(
217
263
  "evaluation_function": metric.custom_function
218
264
  }
219
265
 
266
+ # Step-based LLM metric
267
+ elif getv(metric, ["steps"]):
268
+ metric_payload_item["step_based_llm_metric_spec"] = _step_based_llm_metric_spec(
269
+ metric
270
+ )
271
+
220
272
  # LLM-based metric
221
273
  elif (hasattr(metric, "prompt_template") and metric.prompt_template) or (
222
274
  hasattr(metric, "rubric_group_name") and metric.rubric_group_name
@@ -1172,6 +1172,13 @@ def _UnifiedMetric_from_vertex(
1172
1172
  getv(from_object, ["computationBasedMetricSpec"]),
1173
1173
  )
1174
1174
 
1175
+ if getv(from_object, ["stepBasedLlmMetricSpec"]) is not None:
1176
+ setv(
1177
+ to_object,
1178
+ ["step_based_llm_metric_spec"],
1179
+ getv(from_object, ["stepBasedLlmMetricSpec"]),
1180
+ )
1181
+
1175
1182
  return to_object
1176
1183
 
1177
1184
 
@@ -1223,6 +1230,13 @@ def _UnifiedMetric_to_vertex(
1223
1230
  getv(from_object, ["computation_based_metric_spec"]),
1224
1231
  )
1225
1232
 
1233
+ if getv(from_object, ["step_based_llm_metric_spec"]) is not None:
1234
+ setv(
1235
+ to_object,
1236
+ ["stepBasedLlmMetricSpec"],
1237
+ getv(from_object, ["step_based_llm_metric_spec"]),
1238
+ )
1239
+
1226
1240
  return to_object
1227
1241
 
1228
1242
 
@@ -532,7 +532,7 @@ class FeedbackEntries(_api_module.BaseModule):
532
532
  Args:
533
533
  name (str): Required. Name of the Feedback Entry to update. Format:
534
534
  `projects/{project}/locations/{location}/reasoningEngines/{resource_id}/feedbackEntries/{feedback_entry_id}`.
535
- feedback_type (shared.FeedbackType): Optional. The type of feedback provided.
535
+ feedback_type (FeedbackType): Optional. The type of feedback provided.
536
536
  config (UpdateRuntimeFeedbackEntryConfig): Optional. The configuration for updating the Feedback Entry.
537
537
 
538
538
  Returns:
@@ -1245,7 +1245,7 @@ class AsyncFeedbackEntries(_api_module.BaseModule):
1245
1245
  Args:
1246
1246
  name (str): Required. Name of the Feedback Entry to update. Format:
1247
1247
  `projects/{project}/locations/{location}/reasoningEngines/{resource_id}/feedbackEntries/{feedback_entry_id}`.
1248
- feedback_type (shared.FeedbackType): Optional. The type of feedback provided.
1248
+ feedback_type (FeedbackType): Optional. The type of feedback provided.
1249
1249
  config (UpdateRuntimeFeedbackEntryConfig): Optional. The configuration for updating the Feedback Entry.
1250
1250
 
1251
1251
  Returns:
@@ -1607,6 +1607,7 @@ class Runtimes(_api_module.BaseModule):
1607
1607
  agent
1608
1608
  or config.source_packages
1609
1609
  or config.developer_connect_source
1610
+ or config.git_source
1610
1611
  or config.agent_config_source
1611
1612
  or config.container_spec
1612
1613
  ):
@@ -1860,6 +1861,9 @@ class Runtimes(_api_module.BaseModule):
1860
1861
  developer_connect_source = json.loads(
1861
1862
  developer_connect_source.model_dump_json()
1862
1863
  )
1864
+ git_source = config.git_source
1865
+ if git_source is not None:
1866
+ git_source = json.loads(git_source.model_dump_json(exclude_none=True))
1863
1867
  agent_config_source = config.agent_config_source
1864
1868
  if agent_config_source is not None:
1865
1869
  agent_config_source = json.loads(agent_config_source.model_dump_json())
@@ -1900,6 +1904,7 @@ class Runtimes(_api_module.BaseModule):
1900
1904
  class_methods=config.class_methods,
1901
1905
  source_packages=config.source_packages,
1902
1906
  developer_connect_source=developer_connect_source,
1907
+ git_source=git_source,
1903
1908
  entrypoint_module=config.entrypoint_module,
1904
1909
  entrypoint_object=config.entrypoint_object,
1905
1910
  requirements_file=config.requirements_file,
@@ -1969,6 +1974,9 @@ class Runtimes(_api_module.BaseModule):
1969
1974
  developer_connect_source: Optional[
1970
1975
  types.ReasoningEngineSpecSourceCodeSpecDeveloperConnectConfigDict
1971
1976
  ] = None,
1977
+ git_source: Optional[
1978
+ types.ReasoningEngineSpecSourceCodeSpecGitSourceDict
1979
+ ] = None,
1972
1980
  class_methods: Optional[Sequence[dict[str, Any]]] = None,
1973
1981
  entrypoint_module: Optional[str] = None,
1974
1982
  entrypoint_object: Optional[str] = None,
@@ -2000,10 +2008,13 @@ class Runtimes(_api_module.BaseModule):
2000
2008
  source_code_spec["developer_connect_source"] = {
2001
2009
  "config": developer_connect_source
2002
2010
  }
2011
+ elif git_source:
2012
+ update_masks.append("spec.source_code_spec.git_source")
2013
+ source_code_spec["git_source"] = git_source
2003
2014
  elif not agent_config_source:
2004
2015
  raise ValueError(
2005
2016
  "Please specify one of `source_packages`, `developer_connect_source`, "
2006
- "or `agent_config_source`."
2017
+ "`git_source`, or `agent_config_source`."
2007
2018
  )
2008
2019
  if class_methods is not None:
2009
2020
  update_masks.append("spec.class_methods")
@@ -2019,8 +2030,8 @@ class Runtimes(_api_module.BaseModule):
2019
2030
  elif image_spec is None:
2020
2031
  raise ValueError(
2021
2032
  "`class_methods` must be specified if `source_packages`, "
2022
- "`developer_connect_source`, or `agent_config_source` is "
2023
- "specified without a Dockerfile or `image_spec`."
2033
+ "`developer_connect_source`, `git_source`, or `agent_config_source` "
2034
+ "is specified without a Dockerfile or `image_spec`."
2024
2035
  )
2025
2036
  if image_spec is not None:
2026
2037
  if entrypoint_module or entrypoint_object or requirements_file:
@@ -2077,13 +2088,13 @@ class Runtimes(_api_module.BaseModule):
2077
2088
 
2078
2089
  if not entrypoint_module:
2079
2090
  raise ValueError(
2080
- "`entrypoint_module` must be specified if `source_packages` or `developer_connect_source` is specified."
2091
+ "`entrypoint_module` must be specified if `source_packages`, `developer_connect_source`, or `git_source` is specified."
2081
2092
  )
2082
2093
  update_masks.append("spec.source_code_spec.python_spec.entrypoint_module")
2083
2094
  python_spec["entrypoint_module"] = entrypoint_module
2084
2095
  if not entrypoint_object:
2085
2096
  raise ValueError(
2086
- "`entrypoint_object` must be specified if `source_packages` or `developer_connect_source` is specified."
2097
+ "`entrypoint_object` must be specified if `source_packages`, `developer_connect_source`, or `git_source` is specified."
2087
2098
  )
2088
2099
  update_masks.append("spec.source_code_spec.python_spec.entrypoint_object")
2089
2100
  python_spec["entrypoint_object"] = entrypoint_object
@@ -2215,6 +2226,9 @@ class Runtimes(_api_module.BaseModule):
2215
2226
  developer_connect_source: Optional[
2216
2227
  types.ReasoningEngineSpecSourceCodeSpecDeveloperConnectConfigDict
2217
2228
  ] = None,
2229
+ git_source: Optional[
2230
+ types.ReasoningEngineSpecSourceCodeSpecGitSourceDict
2231
+ ] = None,
2218
2232
  entrypoint_module: Optional[str] = None,
2219
2233
  entrypoint_object: Optional[str] = None,
2220
2234
  requirements_file: Optional[str] = None,
@@ -2284,9 +2298,18 @@ class Runtimes(_api_module.BaseModule):
2284
2298
  "do not specify `agent` in `runtimes.create()` or "
2285
2299
  "`runtimes.update()`."
2286
2300
  )
2287
- elif source_packages and developer_connect_source:
2301
+ if git_source:
2302
+ raise ValueError(
2303
+ "If you have provided `git_source` in `config`, please "
2304
+ "do not specify `agent` in `runtimes.create()` or "
2305
+ "`runtimes.update()`."
2306
+ )
2307
+ elif (
2308
+ sum(map(bool, (source_packages, developer_connect_source, git_source))) > 1
2309
+ ):
2288
2310
  raise ValueError(
2289
- "Please specify only one of `source_packages` or `developer_connect_source` in `config`."
2311
+ "Please specify only one of `source_packages`, "
2312
+ "`developer_connect_source`, or `git_source` in `config`."
2290
2313
  )
2291
2314
 
2292
2315
  if container_spec:
@@ -2296,10 +2319,11 @@ class Runtimes(_api_module.BaseModule):
2296
2319
  "do not specify `agent` in `runtimes.create()` or "
2297
2320
  "`runtimes.update()`."
2298
2321
  )
2299
- if source_packages or developer_connect_source:
2322
+ if source_packages or developer_connect_source or git_source:
2300
2323
  raise ValueError(
2301
2324
  "If you have provided `container_spec` in `config`, please "
2302
- "do not specify `source_packages` or `developer_connect_source` in `config`."
2325
+ "do not specify `source_packages`, `developer_connect_source`, or "
2326
+ "`git_source` in `config`."
2303
2327
  )
2304
2328
 
2305
2329
  runtime_spec: Any = None
@@ -2323,6 +2347,7 @@ class Runtimes(_api_module.BaseModule):
2323
2347
  elif (
2324
2348
  source_packages
2325
2349
  or developer_connect_source
2350
+ or git_source
2326
2351
  or image_spec
2327
2352
  or agent_config_source
2328
2353
  ):
@@ -2332,6 +2357,7 @@ class Runtimes(_api_module.BaseModule):
2332
2357
  update_masks=update_masks,
2333
2358
  source_packages=source_packages,
2334
2359
  developer_connect_source=developer_connect_source,
2360
+ git_source=git_source,
2335
2361
  class_methods=class_methods,
2336
2362
  entrypoint_module=entrypoint_module,
2337
2363
  entrypoint_object=entrypoint_object,
@@ -2373,7 +2399,7 @@ class Runtimes(_api_module.BaseModule):
2373
2399
  "`max_instances`, `resource_limits`, `container_concurrency`, or "
2374
2400
  "`keep_alive_probe`, you must also provide the `agent` variable or "
2375
2401
  "the source code options (`source_packages`, "
2376
- "`developer_connect_source` or `agent_config_source`)."
2402
+ "`developer_connect_source`, `git_source` or `agent_config_source`)."
2377
2403
  )
2378
2404
 
2379
2405
  if runtime_spec is not None:
@@ -2672,6 +2698,9 @@ class Runtimes(_api_module.BaseModule):
2672
2698
  developer_connect_source = json.loads(
2673
2699
  developer_connect_source.model_dump_json()
2674
2700
  )
2701
+ git_source = config.git_source
2702
+ if git_source is not None:
2703
+ git_source = json.loads(git_source.model_dump_json(exclude_none=True))
2675
2704
  agent_config_source = config.agent_config_source
2676
2705
  if agent_config_source is not None:
2677
2706
  agent_config_source = json.loads(agent_config_source.model_dump_json())
@@ -2721,6 +2750,7 @@ class Runtimes(_api_module.BaseModule):
2721
2750
  class_methods=config.class_methods,
2722
2751
  source_packages=config.source_packages,
2723
2752
  developer_connect_source=developer_connect_source,
2753
+ git_source=git_source,
2724
2754
  entrypoint_module=config.entrypoint_module,
2725
2755
  entrypoint_object=config.entrypoint_object,
2726
2756
  requirements_file=config.requirements_file,