google-cloud-agentplatform 1.165.1.dev0__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 (62) hide show
  1. agentplatform/__init__.py +72 -0
  2. agentplatform/_genai/__init__.py +43 -0
  3. agentplatform/_genai/_agent_engines_utils.py +2341 -0
  4. agentplatform/_genai/_bigquery_utils.py +49 -0
  5. agentplatform/_genai/_datasets_utils.py +344 -0
  6. agentplatform/_genai/_evals_builtin_tools.py +209 -0
  7. agentplatform/_genai/_evals_common.py +4268 -0
  8. agentplatform/_genai/_evals_constant.py +122 -0
  9. agentplatform/_genai/_evals_data_converters.py +926 -0
  10. agentplatform/_genai/_evals_metric_handlers.py +1783 -0
  11. agentplatform/_genai/_evals_metric_loaders.py +401 -0
  12. agentplatform/_genai/_evals_utils.py +1043 -0
  13. agentplatform/_genai/_evals_visualization.py +2070 -0
  14. agentplatform/_genai/_gcs_utils.py +262 -0
  15. agentplatform/_genai/_logging_utils.py +47 -0
  16. agentplatform/_genai/_memory_bank_utils.py +206 -0
  17. agentplatform/_genai/_observability_data_converter.py +186 -0
  18. agentplatform/_genai/_operations_utils.py +94 -0
  19. agentplatform/_genai/_prompt_management_utils.py +147 -0
  20. agentplatform/_genai/_prompt_optimizer_utils.py +215 -0
  21. agentplatform/_genai/_skills_utils.py +69 -0
  22. agentplatform/_genai/_transformers.py +628 -0
  23. agentplatform/_genai/a2a_task_events.py +509 -0
  24. agentplatform/_genai/a2a_tasks.py +861 -0
  25. agentplatform/_genai/agent_engines.py +3931 -0
  26. agentplatform/_genai/client.py +519 -0
  27. agentplatform/_genai/datasets.py +3045 -0
  28. agentplatform/_genai/endpoints.py +1149 -0
  29. agentplatform/_genai/evals.py +6883 -0
  30. agentplatform/_genai/example_stores.py +1445 -0
  31. agentplatform/_genai/feedback_contexts.py +700 -0
  32. agentplatform/_genai/feedback_entries.py +1644 -0
  33. agentplatform/_genai/live.py +64 -0
  34. agentplatform/_genai/live_agent_engines.py +179 -0
  35. agentplatform/_genai/memories.py +2962 -0
  36. agentplatform/_genai/memory_banks.py +1927 -0
  37. agentplatform/_genai/memory_revisions.py +465 -0
  38. agentplatform/_genai/model_garden.py +2638 -0
  39. agentplatform/_genai/prompt_optimizer.py +995 -0
  40. agentplatform/_genai/prompts.py +4515 -0
  41. agentplatform/_genai/rag.py +4961 -0
  42. agentplatform/_genai/runtime_revisions.py +1257 -0
  43. agentplatform/_genai/runtimes.py +78 -0
  44. agentplatform/_genai/sandbox_snapshots.py +1015 -0
  45. agentplatform/_genai/sandbox_templates.py +1088 -0
  46. agentplatform/_genai/sandboxes.py +1604 -0
  47. agentplatform/_genai/session_events.py +543 -0
  48. agentplatform/_genai/sessions.py +1449 -0
  49. agentplatform/_genai/skill_revisions.py +377 -0
  50. agentplatform/_genai/skills.py +1708 -0
  51. agentplatform/_genai/types/__init__.py +4695 -0
  52. agentplatform/_genai/types/agent_engines.py +16 -0
  53. agentplatform/_genai/types/common.py +32784 -0
  54. agentplatform/_genai/types/evals.py +1031 -0
  55. agentplatform/_genai/types/prompt_optimizer.py +107 -0
  56. agentplatform/_genai/types/prompts.py +107 -0
  57. agentplatform/version.py +17 -0
  58. google_cloud_agentplatform-1.165.1.dev0.dist-info/METADATA +79 -0
  59. google_cloud_agentplatform-1.165.1.dev0.dist-info/RECORD +62 -0
  60. google_cloud_agentplatform-1.165.1.dev0.dist-info/WHEEL +5 -0
  61. google_cloud_agentplatform-1.165.1.dev0.dist-info/licenses/LICENSE +202 -0
  62. google_cloud_agentplatform-1.165.1.dev0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,401 @@
1
+ # Copyright 2025 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #
15
+ """Utility functions for evals."""
16
+
17
+ import json
18
+ import logging
19
+ import os
20
+ import re
21
+ from typing import Any, Optional, Union, TYPE_CHECKING
22
+
23
+ import yaml
24
+
25
+ from . import _evals_constant
26
+ from . import _gcs_utils
27
+
28
+ if TYPE_CHECKING:
29
+ from . import types
30
+
31
+
32
+ logger = logging.getLogger(__name__)
33
+
34
+
35
+ class LazyLoadedPrebuiltMetric:
36
+ """A proxy object representing a prebuilt metric to be loaded on demand.
37
+
38
+ This can resolve to either an API Predefined Metric or an LLM Metric
39
+ loaded from GCS.
40
+ """
41
+
42
+ _cache: dict[str, "types.Metric"] = {}
43
+ _base_gcs_path = (
44
+ "gs://vertex-ai-generative-ai-eval-sdk-resources/metrics/{metric_name}/"
45
+ )
46
+
47
+ def __init__(self, name: str, version: Optional[str] = None, **kwargs: Any):
48
+ self.name = name.upper()
49
+ self.version = version
50
+ self.metric_kwargs = kwargs
51
+ self._resolved_metric: Optional["types.Metric"] = None
52
+
53
+ def _get_api_metric_spec_name(self) -> Optional[str]:
54
+ """Constructs the metric_spec_name for API Predefined Metrics."""
55
+ base_name = self.name.lower()
56
+ if self.version:
57
+ # Explicit version provided.
58
+ version = self.version.lower()
59
+ potential_name = f"{base_name}_{version}"
60
+ return (
61
+ potential_name
62
+ if potential_name in _evals_constant.SUPPORTED_PREDEFINED_METRICS
63
+ else None
64
+ )
65
+ else:
66
+ # No version specified: resolve to the latest available version,
67
+ # falling back to _v1, then the bare base name.
68
+ if base_name in _evals_constant.METRIC_LATEST_SPEC_NAME:
69
+ return _evals_constant.METRIC_LATEST_SPEC_NAME[base_name]
70
+ v1_name = f"{base_name}_v1"
71
+ if v1_name in _evals_constant.SUPPORTED_PREDEFINED_METRICS:
72
+ return v1_name
73
+ if base_name in _evals_constant.SUPPORTED_PREDEFINED_METRICS:
74
+ return base_name
75
+ return None
76
+
77
+ def _resolve_api_predefined(self) -> Optional["types.Metric"]:
78
+ """Attempts to resolve as an API Predefined Metric."""
79
+ from . import types
80
+
81
+ metric_spec_name = self._get_api_metric_spec_name()
82
+ if metric_spec_name:
83
+ logger.info(
84
+ "Resolving '%s' as API Predefined Metric with spec name: %s",
85
+ self.name,
86
+ metric_spec_name,
87
+ )
88
+ return types.Metric(name=metric_spec_name, **self.metric_kwargs)
89
+ return None
90
+
91
+ def _get_latest_version_uri(self, api_client: Any, metric_gcs_dir: str) -> str:
92
+ """Lists files in GCS directory and determines the latest version URI."""
93
+ gcs_utils = _gcs_utils.GcsUtils(api_client)
94
+ bucket_name, prefix = gcs_utils.parse_gcs_path(metric_gcs_dir)
95
+
96
+ blobs = gcs_utils.storage_client.list_blobs(bucket_name, prefix=prefix)
97
+
98
+ version_files: list[dict[str, Union[list[int], str]]] = (
99
+ []
100
+ ) # {'version_parts': [1,0,0], 'filename': 'v1.0.0.yaml'}
101
+
102
+ version_pattern = re.compile(
103
+ r"v(\d+)(?:\.(\d+))?(?:\.(\d+))?\.(yaml|yml|json)$", re.IGNORECASE
104
+ )
105
+
106
+ for blob in blobs:
107
+ match = version_pattern.match(os.path.basename(blob.name))
108
+ if match:
109
+ major = int(match.group(1))
110
+ minor = int(match.group(2)) if match.group(2) else 0
111
+ patch = int(match.group(3)) if match.group(3) else 0
112
+ version_files.append(
113
+ {
114
+ "version_parts": [major, minor, patch],
115
+ "filename": os.path.basename(blob.name),
116
+ }
117
+ )
118
+
119
+ if not version_files:
120
+ raise IOError(f"No versioned metric files found in {metric_gcs_dir}")
121
+
122
+ version_files.sort(key=lambda x: x["version_parts"], reverse=True)
123
+
124
+ latest_filename = version_files[0]["filename"]
125
+ return os.path.join(metric_gcs_dir, latest_filename)
126
+
127
+ def _fetch_and_parse(self, api_client: Any) -> "types.LLMMetric":
128
+ """Fetches and parses the metric definition from GCS."""
129
+
130
+ from . import types
131
+
132
+ metric_gcs_dir = self._base_gcs_path.format(metric_name=self.name.lower())
133
+ uri: str
134
+ if self.version == "latest" or self.version is None:
135
+ uri = self._get_latest_version_uri(api_client, metric_gcs_dir)
136
+ resolved_version_match = re.match(
137
+ r"(v\d+(?:\.\d+)*)\.(?:yaml|yml|json)",
138
+ os.path.basename(uri),
139
+ re.IGNORECASE,
140
+ )
141
+ if resolved_version_match:
142
+ self.version = resolved_version_match.group(1)
143
+ else:
144
+ # Fallback if regex fails
145
+ self.version = os.path.splitext(os.path.basename(uri))[0]
146
+ else:
147
+ yaml_uri = os.path.join(metric_gcs_dir, f"{self.version}.yaml")
148
+ json_uri = os.path.join(metric_gcs_dir, f"{self.version}.json")
149
+
150
+ gcs_utils = _gcs_utils.GcsUtils(api_client)
151
+ try:
152
+ bucket_name, blob_path = gcs_utils.parse_gcs_path(yaml_uri)
153
+ if (
154
+ gcs_utils.storage_client.bucket(bucket_name)
155
+ .blob(blob_path)
156
+ .exists()
157
+ ):
158
+ uri = yaml_uri
159
+ else:
160
+ bucket_name_json, blob_path_json = gcs_utils.parse_gcs_path(
161
+ json_uri
162
+ )
163
+ if (
164
+ gcs_utils.storage_client.bucket(bucket_name_json)
165
+ .blob(blob_path_json)
166
+ .exists()
167
+ ):
168
+ uri = json_uri
169
+ else:
170
+ raise IOError(
171
+ f"Metric file for version '{self.version}' "
172
+ f"not found as .yaml or .json in {metric_gcs_dir}"
173
+ )
174
+ except Exception as e:
175
+ raise IOError(
176
+ f"Error checking for metric file version '{self.version}' in"
177
+ f" {metric_gcs_dir}: {e}"
178
+ ) from e
179
+
180
+ logger.info(
181
+ "Fetching predefined metric '%s@%s' from %s...",
182
+ self.name,
183
+ self.version,
184
+ uri,
185
+ )
186
+
187
+ gcs_utils = _gcs_utils.GcsUtils(api_client)
188
+ content_str = gcs_utils.read_file_contents(uri)
189
+
190
+ file_extension = os.path.splitext(uri)[1].lower()
191
+ data: dict[str, Any]
192
+ if file_extension == ".yaml" or file_extension == ".yml":
193
+ if yaml is None:
194
+ raise ImportError(
195
+ "YAML parsing requires the pyyaml library. Please install it"
196
+ " with `pip install google-cloud-aiplatform[evaluation]`."
197
+ )
198
+ data = yaml.safe_load(content_str)
199
+ elif file_extension == ".json":
200
+ data = json.loads(content_str)
201
+ else:
202
+ raise ValueError(f"Unsupported file extension: {file_extension}")
203
+
204
+ if not isinstance(data, dict):
205
+ raise ValueError("Metric config content did not parse into a dictionary.")
206
+
207
+ metric_obj = types.LLMMetric.model_validate({**data, **self.metric_kwargs})
208
+ metric_obj._is_predefined = True
209
+ metric_obj._config_source = uri
210
+ metric_obj._version = self.version
211
+ return metric_obj
212
+
213
+ def resolve(self, api_client: Any) -> "types.Metric":
214
+ """Resolves the metric by checking API Predefined, then GCS, caching results."""
215
+ if self._resolved_metric:
216
+ return self._resolved_metric
217
+
218
+ cache_key = f"{self.name}@{self.version or 'default'}"
219
+ if cache_key in LazyLoadedPrebuiltMetric._cache:
220
+ self._resolved_metric = LazyLoadedPrebuiltMetric._cache[cache_key]
221
+ logger.debug("Metric '%s' found in cache.", cache_key)
222
+ return self._resolved_metric
223
+
224
+ # Try resolving as API Predefined Metric first
225
+ api_metric = self._resolve_api_predefined()
226
+ if api_metric:
227
+ self._resolved_metric = api_metric
228
+ LazyLoadedPrebuiltMetric._cache[cache_key] = self._resolved_metric
229
+ return self._resolved_metric
230
+
231
+ # Fallback to GCS loading for custom LLM-based Prebuilt Metrics
232
+ logger.debug(
233
+ "Metric '%s' not an API Predefined Metric, trying GCS...", self.name
234
+ )
235
+ try:
236
+ gcs_metric = self._fetch_and_parse(api_client)
237
+ final_cache_key = f"{self.name}@{self.version}"
238
+ LazyLoadedPrebuiltMetric._cache[final_cache_key] = gcs_metric
239
+ self._resolved_metric = gcs_metric
240
+ return self._resolved_metric
241
+ except Exception as e:
242
+ logger.error(
243
+ "Error loading metric %s (requested version: %s) from GCS: %s",
244
+ self.name,
245
+ self.version,
246
+ e,
247
+ )
248
+ raise ValueError(
249
+ f"Metric '{self.name}' could not be resolved as an API "
250
+ "Predefined Metric or loaded from GCS."
251
+ ) from e
252
+
253
+ def __call__(
254
+ self, version: Optional[str] = None, **kwargs: Any
255
+ ) -> "LazyLoadedPrebuiltMetric":
256
+ """Allows setting a specific version and other metric attributes."""
257
+ updated_kwargs = self.metric_kwargs.copy()
258
+ updated_kwargs.update(kwargs)
259
+ return LazyLoadedPrebuiltMetric(
260
+ name=self.name, version=version or self.version, **updated_kwargs
261
+ )
262
+
263
+
264
+ class PrebuiltMetricLoader:
265
+ """Provides access to predefined evaluation metrics via attributes.
266
+
267
+ This class provides a set of predefined LLM-based metrics (Autorater recipes)
268
+ for evaluation. These metrics are lazily loaded from a GCS repository
269
+ when they are first accessed.
270
+
271
+ Example:
272
+ from agentplatform import types
273
+ text_quality_metric = types.RubricMetric.TEXT_QUALITY
274
+ """
275
+
276
+ def __getattr__(
277
+ self, name: str, version: Optional[str] = None, **kwargs: Any
278
+ ) -> LazyLoadedPrebuiltMetric:
279
+ return LazyLoadedPrebuiltMetric(name=name, version=version, **kwargs)
280
+
281
+ @property
282
+ def GENERAL_QUALITY(self) -> LazyLoadedPrebuiltMetric:
283
+ return self.__getattr__("GENERAL_QUALITY", version="v1")
284
+
285
+ @property
286
+ def TEXT_QUALITY(self) -> LazyLoadedPrebuiltMetric:
287
+ return self.__getattr__("TEXT_QUALITY", version="v1")
288
+
289
+ @property
290
+ def INSTRUCTION_FOLLOWING(self) -> LazyLoadedPrebuiltMetric:
291
+ return self.__getattr__("INSTRUCTION_FOLLOWING", version="v1")
292
+
293
+ @property
294
+ def SAFETY(self) -> LazyLoadedPrebuiltMetric:
295
+ return self.__getattr__("SAFETY", version="v1")
296
+
297
+ @property
298
+ def MULTI_TURN_GENERAL_QUALITY(self) -> LazyLoadedPrebuiltMetric:
299
+ return self.__getattr__("MULTI_TURN_GENERAL_QUALITY", version="v1")
300
+
301
+ @property
302
+ def MULTI_TURN_TEXT_QUALITY(self) -> LazyLoadedPrebuiltMetric:
303
+ return self.__getattr__("MULTI_TURN_TEXT_QUALITY", version="v1")
304
+
305
+ @property
306
+ def MULTI_TURN_TOOL_USE_QUALITY(self) -> LazyLoadedPrebuiltMetric:
307
+ return self.__getattr__("MULTI_TURN_TOOL_USE_QUALITY", version="v1")
308
+
309
+ @property
310
+ def MULTI_TURN_TRAJECTORY_QUALITY(self) -> LazyLoadedPrebuiltMetric:
311
+ return self.__getattr__("MULTI_TURN_TRAJECTORY_QUALITY", version="v1")
312
+
313
+ @property
314
+ def MULTI_TURN_TASK_SUCCESS(self) -> LazyLoadedPrebuiltMetric:
315
+ return self.__getattr__("MULTI_TURN_TASK_SUCCESS", version="v1")
316
+
317
+ @property
318
+ def FINAL_RESPONSE_MATCH(self) -> LazyLoadedPrebuiltMetric:
319
+ return self.__getattr__("FINAL_RESPONSE_MATCH", version="v2")
320
+
321
+ @property
322
+ def FINAL_RESPONSE_REFERENCE_FREE(self) -> LazyLoadedPrebuiltMetric:
323
+ return self.__getattr__("FINAL_RESPONSE_REFERENCE_FREE", version="v1")
324
+
325
+ @property
326
+ def COHERENCE(self) -> LazyLoadedPrebuiltMetric:
327
+ return self.__getattr__("COHERENCE", version="v1")
328
+
329
+ @property
330
+ def FLUENCY(self) -> LazyLoadedPrebuiltMetric:
331
+ return self.__getattr__("FLUENCY", version="v1")
332
+
333
+ @property
334
+ def VERBOSITY(self) -> LazyLoadedPrebuiltMetric:
335
+ return self.__getattr__("VERBOSITY", version="v1")
336
+
337
+ @property
338
+ def SUMMARIZATION_QUALITY(self) -> LazyLoadedPrebuiltMetric:
339
+ return self.__getattr__("SUMMARIZATION_QUALITY", version="v1")
340
+
341
+ @property
342
+ def QUESTION_ANSWERING_QUALITY(self) -> LazyLoadedPrebuiltMetric:
343
+ return self.__getattr__("QUESTION_ANSWERING_QUALITY", version="v1")
344
+
345
+ @property
346
+ def MULTI_TURN_CHAT_QUALITY(self) -> LazyLoadedPrebuiltMetric:
347
+ return self.__getattr__("MULTI_TURN_CHAT_QUALITY", version="v1")
348
+
349
+ @property
350
+ def MULTI_TURN_SAFETY(self) -> LazyLoadedPrebuiltMetric:
351
+ return self.__getattr__("MULTI_TURN_SAFETY", version="v1")
352
+
353
+ @property
354
+ def FINAL_RESPONSE_QUALITY(self) -> LazyLoadedPrebuiltMetric:
355
+ return self.__getattr__("FINAL_RESPONSE_QUALITY", version="v1")
356
+
357
+ @property
358
+ def HALLUCINATION(self) -> LazyLoadedPrebuiltMetric:
359
+ return self.__getattr__("HALLUCINATION", version="v1")
360
+
361
+ @property
362
+ def GROUNDING(self) -> LazyLoadedPrebuiltMetric: # pylint: disable=invalid-name
363
+ return self.__getattr__("GROUNDING", version="v1")
364
+
365
+ @property
366
+ def GROUNDEDNESS(self) -> LazyLoadedPrebuiltMetric: # pylint: disable=invalid-name
367
+ logger.warning(
368
+ "RubricMetric.GROUNDEDNESS is a deprecated alias and now maps to"
369
+ " RubricMetric.GROUNDING (grounding_v1). Note that the input"
370
+ " contract changed: legacy GROUNDEDNESS scored 'response' against"
371
+ " 'prompt'; grounding_v1 scores 'response' sentence-by-sentence"
372
+ " against an additional 'context' field. Add a 'context' field to"
373
+ " your dataset, otherwise scores will silently collapse to 0."
374
+ " Update your code to use RubricMetric.GROUNDING directly."
375
+ )
376
+ return self.__getattr__("GROUNDING", version="v1")
377
+
378
+ @property
379
+ def TOOL_USE_QUALITY(self) -> LazyLoadedPrebuiltMetric:
380
+ return self.__getattr__("TOOL_USE_QUALITY", version="v1")
381
+
382
+ @property
383
+ def GECKO_TEXT2IMAGE(self) -> LazyLoadedPrebuiltMetric:
384
+ return self.__getattr__("GECKO_TEXT2IMAGE", version="v1")
385
+
386
+ @property
387
+ def GECKO_TEXT2VIDEO(self) -> LazyLoadedPrebuiltMetric:
388
+ return self.__getattr__("GECKO_TEXT2VIDEO", version="v1")
389
+
390
+
391
+ PrebuiltMetric = PrebuiltMetricLoader()
392
+ RubricMetric = PrebuiltMetric
393
+
394
+
395
+ def CodeExecutionMetric(
396
+ name: str, custom_function: str, **kwargs: Any
397
+ ) -> "types.Metric":
398
+ """Instantiates a code execution metric."""
399
+ from . import types
400
+
401
+ return types.Metric(name=name, remote_custom_function=custom_function, **kwargs)