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,4515 @@
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
+
16
+ # Code generated by the Google Gen AI SDK generator DO NOT EDIT.
17
+
18
+ import asyncio
19
+ import datetime
20
+ import json
21
+ import logging
22
+ import time
23
+ from typing import Any, AsyncIterator, Iterator, Optional, Union
24
+ from urllib.parse import urlencode
25
+
26
+ from google.genai import _api_module
27
+ from google.genai import _common
28
+ from google.genai import operations
29
+ from google.genai import types as genai_types
30
+ from google.genai._common import get_value_by_path as getv
31
+ from google.genai._common import set_value_by_path as setv
32
+ from google.genai.pagers import AsyncPager, Pager
33
+ from pydantic import ValidationError
34
+
35
+ from . import _prompt_management_utils
36
+ from . import _prompt_optimizer_utils
37
+ from . import types
38
+
39
+ logger = logging.getLogger("agentplatform_genai.prompts")
40
+
41
+
42
+ def _CreateDatasetParameters_to_vertex(
43
+ from_object: Union[dict[str, Any], object],
44
+ parent_object: Optional[dict[str, Any]] = None,
45
+ ) -> dict[str, Any]:
46
+ to_object: dict[str, Any] = {}
47
+ if getv(from_object, ["name"]) is not None:
48
+ setv(to_object, ["name"], getv(from_object, ["name"]))
49
+
50
+ if getv(from_object, ["display_name"]) is not None:
51
+ setv(to_object, ["displayName"], getv(from_object, ["display_name"]))
52
+
53
+ if getv(from_object, ["metadata_schema_uri"]) is not None:
54
+ setv(
55
+ to_object, ["metadataSchemaUri"], getv(from_object, ["metadata_schema_uri"])
56
+ )
57
+
58
+ if getv(from_object, ["metadata"]) is not None:
59
+ setv(to_object, ["metadata"], getv(from_object, ["metadata"]))
60
+
61
+ if getv(from_object, ["description"]) is not None:
62
+ setv(to_object, ["description"], getv(from_object, ["description"]))
63
+
64
+ if getv(from_object, ["encryption_spec"]) is not None:
65
+ setv(to_object, ["encryptionSpec"], getv(from_object, ["encryption_spec"]))
66
+
67
+ if getv(from_object, ["model_reference"]) is not None:
68
+ setv(to_object, ["modelReference"], getv(from_object, ["model_reference"]))
69
+
70
+ if getv(from_object, ["config"]) is not None:
71
+ setv(to_object, ["config"], getv(from_object, ["config"]))
72
+
73
+ return to_object
74
+
75
+
76
+ def _CreateDatasetVersionParameters_to_vertex(
77
+ from_object: Union[dict[str, Any], object],
78
+ parent_object: Optional[dict[str, Any]] = None,
79
+ ) -> dict[str, Any]:
80
+ to_object: dict[str, Any] = {}
81
+ if getv(from_object, ["dataset_name"]) is not None:
82
+ setv(to_object, ["_url", "name"], getv(from_object, ["dataset_name"]))
83
+
84
+ if getv(from_object, ["metadata"]) is not None:
85
+ setv(to_object, ["metadata"], getv(from_object, ["metadata"]))
86
+
87
+ if getv(from_object, ["model_reference"]) is not None:
88
+ setv(to_object, ["modelReference"], getv(from_object, ["model_reference"]))
89
+
90
+ if getv(from_object, ["parent"]) is not None:
91
+ setv(to_object, ["parent"], getv(from_object, ["parent"]))
92
+
93
+ if getv(from_object, ["display_name"]) is not None:
94
+ setv(to_object, ["displayName"], getv(from_object, ["display_name"]))
95
+
96
+ if getv(from_object, ["config"]) is not None:
97
+ setv(to_object, ["config"], getv(from_object, ["config"]))
98
+
99
+ return to_object
100
+
101
+
102
+ def _CustomJobParameters_to_vertex(
103
+ from_object: Union[dict[str, Any], object],
104
+ parent_object: Optional[dict[str, Any]] = None,
105
+ ) -> dict[str, Any]:
106
+ to_object: dict[str, Any] = {}
107
+ if getv(from_object, ["custom_job"]) is not None:
108
+ setv(
109
+ parent_object,
110
+ ["customJob"],
111
+ _CustomJob_to_vertex(getv(from_object, ["custom_job"]), to_object),
112
+ )
113
+
114
+ if getv(from_object, ["config"]) is not None:
115
+ setv(to_object, ["config"], getv(from_object, ["config"]))
116
+
117
+ return to_object
118
+
119
+
120
+ def _CustomJob_from_vertex(
121
+ from_object: Union[dict[str, Any], object],
122
+ parent_object: Optional[dict[str, Any]] = None,
123
+ ) -> dict[str, Any]:
124
+ to_object: dict[str, Any] = {}
125
+ if getv(parent_object, ["displayName"]) is not None:
126
+ setv(to_object, ["display_name"], getv(parent_object, ["displayName"]))
127
+
128
+ if getv(parent_object, ["jobSpec"]) is not None:
129
+ setv(to_object, ["job_spec"], getv(parent_object, ["jobSpec"]))
130
+
131
+ if getv(parent_object, ["encryptionSpec"]) is not None:
132
+ setv(to_object, ["encryption_spec"], getv(parent_object, ["encryptionSpec"]))
133
+
134
+ if getv(from_object, ["state"]) is not None:
135
+ setv(to_object, ["state"], getv(from_object, ["state"]))
136
+
137
+ if getv(parent_object, ["error"]) is not None:
138
+ setv(to_object, ["error"], getv(parent_object, ["error"]))
139
+
140
+ if getv(from_object, ["createTime"]) is not None:
141
+ setv(to_object, ["create_time"], getv(from_object, ["createTime"]))
142
+
143
+ if getv(from_object, ["endTime"]) is not None:
144
+ setv(to_object, ["end_time"], getv(from_object, ["endTime"]))
145
+
146
+ if getv(from_object, ["labels"]) is not None:
147
+ setv(to_object, ["labels"], getv(from_object, ["labels"]))
148
+
149
+ if getv(from_object, ["name"]) is not None:
150
+ setv(to_object, ["name"], getv(from_object, ["name"]))
151
+
152
+ if getv(from_object, ["satisfiesPzi"]) is not None:
153
+ setv(to_object, ["satisfies_pzi"], getv(from_object, ["satisfiesPzi"]))
154
+
155
+ if getv(from_object, ["satisfiesPzs"]) is not None:
156
+ setv(to_object, ["satisfies_pzs"], getv(from_object, ["satisfiesPzs"]))
157
+
158
+ if getv(from_object, ["startTime"]) is not None:
159
+ setv(to_object, ["start_time"], getv(from_object, ["startTime"]))
160
+
161
+ if getv(from_object, ["updateTime"]) is not None:
162
+ setv(to_object, ["update_time"], getv(from_object, ["updateTime"]))
163
+
164
+ if getv(from_object, ["webAccessUris"]) is not None:
165
+ setv(to_object, ["web_access_uris"], getv(from_object, ["webAccessUris"]))
166
+
167
+ return to_object
168
+
169
+
170
+ def _CustomJob_to_vertex(
171
+ from_object: Union[dict[str, Any], object],
172
+ parent_object: Optional[dict[str, Any]] = None,
173
+ ) -> dict[str, Any]:
174
+ to_object: dict[str, Any] = {}
175
+ if getv(from_object, ["display_name"]) is not None:
176
+ setv(parent_object, ["displayName"], getv(from_object, ["display_name"]))
177
+
178
+ if getv(from_object, ["job_spec"]) is not None:
179
+ setv(parent_object, ["jobSpec"], getv(from_object, ["job_spec"]))
180
+
181
+ if getv(from_object, ["encryption_spec"]) is not None:
182
+ setv(parent_object, ["encryptionSpec"], getv(from_object, ["encryption_spec"]))
183
+
184
+ if getv(from_object, ["state"]) is not None:
185
+ setv(to_object, ["state"], getv(from_object, ["state"]))
186
+
187
+ if getv(from_object, ["error"]) is not None:
188
+ setv(parent_object, ["error"], getv(from_object, ["error"]))
189
+
190
+ if getv(from_object, ["create_time"]) is not None:
191
+ setv(to_object, ["createTime"], getv(from_object, ["create_time"]))
192
+
193
+ if getv(from_object, ["end_time"]) is not None:
194
+ setv(to_object, ["endTime"], getv(from_object, ["end_time"]))
195
+
196
+ if getv(from_object, ["labels"]) is not None:
197
+ setv(to_object, ["labels"], getv(from_object, ["labels"]))
198
+
199
+ if getv(from_object, ["name"]) is not None:
200
+ setv(to_object, ["name"], getv(from_object, ["name"]))
201
+
202
+ if getv(from_object, ["satisfies_pzi"]) is not None:
203
+ setv(to_object, ["satisfiesPzi"], getv(from_object, ["satisfies_pzi"]))
204
+
205
+ if getv(from_object, ["satisfies_pzs"]) is not None:
206
+ setv(to_object, ["satisfiesPzs"], getv(from_object, ["satisfies_pzs"]))
207
+
208
+ if getv(from_object, ["start_time"]) is not None:
209
+ setv(to_object, ["startTime"], getv(from_object, ["start_time"]))
210
+
211
+ if getv(from_object, ["update_time"]) is not None:
212
+ setv(to_object, ["updateTime"], getv(from_object, ["update_time"]))
213
+
214
+ if getv(from_object, ["web_access_uris"]) is not None:
215
+ setv(to_object, ["webAccessUris"], getv(from_object, ["web_access_uris"]))
216
+
217
+ return to_object
218
+
219
+
220
+ def _DeleteDatasetRequestParameters_to_vertex(
221
+ from_object: Union[dict[str, Any], object],
222
+ parent_object: Optional[dict[str, Any]] = None,
223
+ ) -> dict[str, Any]:
224
+ to_object: dict[str, Any] = {}
225
+ if getv(from_object, ["prompt_id"]) is not None:
226
+ setv(to_object, ["_url", "dataset_id"], getv(from_object, ["prompt_id"]))
227
+
228
+ if getv(from_object, ["config"]) is not None:
229
+ setv(to_object, ["config"], getv(from_object, ["config"]))
230
+
231
+ return to_object
232
+
233
+
234
+ def _DeletePromptVersionRequestParameters_to_vertex(
235
+ from_object: Union[dict[str, Any], object],
236
+ parent_object: Optional[dict[str, Any]] = None,
237
+ ) -> dict[str, Any]:
238
+ to_object: dict[str, Any] = {}
239
+ if getv(from_object, ["prompt_id"]) is not None:
240
+ setv(to_object, ["_url", "dataset_id"], getv(from_object, ["prompt_id"]))
241
+
242
+ if getv(from_object, ["version_id"]) is not None:
243
+ setv(to_object, ["_url", "version_id"], getv(from_object, ["version_id"]))
244
+
245
+ if getv(from_object, ["config"]) is not None:
246
+ setv(to_object, ["config"], getv(from_object, ["config"]))
247
+
248
+ return to_object
249
+
250
+
251
+ def _GetCustomJobParameters_to_vertex(
252
+ from_object: Union[dict[str, Any], object],
253
+ parent_object: Optional[dict[str, Any]] = None,
254
+ ) -> dict[str, Any]:
255
+ to_object: dict[str, Any] = {}
256
+ if getv(from_object, ["name"]) is not None:
257
+ setv(to_object, ["_url", "name"], getv(from_object, ["name"]))
258
+
259
+ if getv(from_object, ["config"]) is not None:
260
+ setv(to_object, ["config"], getv(from_object, ["config"]))
261
+
262
+ return to_object
263
+
264
+
265
+ def _GetDatasetOperationParameters_to_vertex(
266
+ from_object: Union[dict[str, Any], object],
267
+ parent_object: Optional[dict[str, Any]] = None,
268
+ ) -> dict[str, Any]:
269
+ to_object: dict[str, Any] = {}
270
+ if getv(from_object, ["dataset_id"]) is not None:
271
+ setv(to_object, ["_url", "dataset_id"], getv(from_object, ["dataset_id"]))
272
+
273
+ if getv(from_object, ["operation_id"]) is not None:
274
+ setv(to_object, ["_url", "operation_id"], getv(from_object, ["operation_id"]))
275
+
276
+ if getv(from_object, ["config"]) is not None:
277
+ setv(to_object, ["config"], getv(from_object, ["config"]))
278
+
279
+ return to_object
280
+
281
+
282
+ def _GetDatasetParameters_to_vertex(
283
+ from_object: Union[dict[str, Any], object],
284
+ parent_object: Optional[dict[str, Any]] = None,
285
+ ) -> dict[str, Any]:
286
+ to_object: dict[str, Any] = {}
287
+ if getv(from_object, ["name"]) is not None:
288
+ setv(to_object, ["_url", "name"], getv(from_object, ["name"]))
289
+
290
+ if getv(from_object, ["config"]) is not None:
291
+ setv(to_object, ["config"], getv(from_object, ["config"]))
292
+
293
+ return to_object
294
+
295
+
296
+ def _GetDatasetVersionParameters_to_vertex(
297
+ from_object: Union[dict[str, Any], object],
298
+ parent_object: Optional[dict[str, Any]] = None,
299
+ ) -> dict[str, Any]:
300
+ to_object: dict[str, Any] = {}
301
+ if getv(from_object, ["dataset_id"]) is not None:
302
+ setv(to_object, ["_url", "dataset_id"], getv(from_object, ["dataset_id"]))
303
+
304
+ if getv(from_object, ["dataset_version_id"]) is not None:
305
+ setv(
306
+ to_object,
307
+ ["_url", "dataset_version_id"],
308
+ getv(from_object, ["dataset_version_id"]),
309
+ )
310
+
311
+ if getv(from_object, ["config"]) is not None:
312
+ setv(to_object, ["config"], getv(from_object, ["config"]))
313
+
314
+ return to_object
315
+
316
+
317
+ def _ListDatasetVersionsRequestParameters_to_vertex(
318
+ from_object: Union[dict[str, Any], object],
319
+ parent_object: Optional[dict[str, Any]] = None,
320
+ ) -> dict[str, Any]:
321
+ to_object: dict[str, Any] = {}
322
+ if getv(from_object, ["read_mask"]) is not None:
323
+ setv(to_object, ["_url", "read_mask"], getv(from_object, ["read_mask"]))
324
+
325
+ if getv(from_object, ["dataset_id"]) is not None:
326
+ setv(to_object, ["_url", "dataset_id"], getv(from_object, ["dataset_id"]))
327
+
328
+ if getv(from_object, ["config"]) is not None:
329
+ setv(
330
+ to_object,
331
+ ["config"],
332
+ _ListPromptsConfig_to_vertex(getv(from_object, ["config"]), to_object),
333
+ )
334
+
335
+ return to_object
336
+
337
+
338
+ def _ListDatasetsRequestParameters_to_vertex(
339
+ from_object: Union[dict[str, Any], object],
340
+ parent_object: Optional[dict[str, Any]] = None,
341
+ ) -> dict[str, Any]:
342
+ to_object: dict[str, Any] = {}
343
+ if getv(from_object, ["config"]) is not None:
344
+ setv(
345
+ to_object,
346
+ ["config"],
347
+ _ListPromptsConfig_to_vertex(getv(from_object, ["config"]), to_object),
348
+ )
349
+
350
+ return to_object
351
+
352
+
353
+ def _ListPromptsConfig_to_vertex(
354
+ from_object: Union[dict[str, Any], object],
355
+ parent_object: Optional[dict[str, Any]] = None,
356
+ ) -> dict[str, Any]:
357
+ to_object: dict[str, Any] = {}
358
+
359
+ if getv(from_object, ["page_size"]) is not None:
360
+ setv(parent_object, ["_query", "pageSize"], getv(from_object, ["page_size"]))
361
+
362
+ if getv(from_object, ["page_token"]) is not None:
363
+ setv(parent_object, ["_query", "pageToken"], getv(from_object, ["page_token"]))
364
+
365
+ if getv(from_object, ["filter"]) is not None:
366
+ setv(parent_object, ["_query", "filter"], getv(from_object, ["filter"]))
367
+
368
+ return to_object
369
+
370
+
371
+ def _OptimizeConfig_to_vertex(
372
+ from_object: Union[dict[str, Any], object],
373
+ parent_object: Optional[dict[str, Any]] = None,
374
+ ) -> dict[str, Any]:
375
+ to_object: dict[str, Any] = {}
376
+
377
+ if getv(from_object, ["optimization_target"]) is not None:
378
+ setv(
379
+ parent_object,
380
+ ["optimizationTarget"],
381
+ getv(from_object, ["optimization_target"]),
382
+ )
383
+
384
+ return to_object
385
+
386
+
387
+ def _OptimizeRequestParameters_to_vertex(
388
+ from_object: Union[dict[str, Any], object],
389
+ parent_object: Optional[dict[str, Any]] = None,
390
+ ) -> dict[str, Any]:
391
+ to_object: dict[str, Any] = {}
392
+ if getv(from_object, ["content"]) is not None:
393
+ setv(to_object, ["content"], getv(from_object, ["content"]))
394
+
395
+ if getv(from_object, ["config"]) is not None:
396
+ setv(
397
+ to_object,
398
+ ["config"],
399
+ _OptimizeConfig_to_vertex(getv(from_object, ["config"]), to_object),
400
+ )
401
+
402
+ return to_object
403
+
404
+
405
+ def _RestoreVersionRequestParameters_to_vertex(
406
+ from_object: Union[dict[str, Any], object],
407
+ parent_object: Optional[dict[str, Any]] = None,
408
+ ) -> dict[str, Any]:
409
+ to_object: dict[str, Any] = {}
410
+ if getv(from_object, ["dataset_id"]) is not None:
411
+ setv(to_object, ["_url", "dataset_id"], getv(from_object, ["dataset_id"]))
412
+
413
+ if getv(from_object, ["version_id"]) is not None:
414
+ setv(to_object, ["_url", "version_id"], getv(from_object, ["version_id"]))
415
+
416
+ if getv(from_object, ["config"]) is not None:
417
+ setv(to_object, ["config"], getv(from_object, ["config"]))
418
+
419
+ return to_object
420
+
421
+
422
+ def _UpdateDatasetParameters_to_vertex(
423
+ from_object: Union[dict[str, Any], object],
424
+ parent_object: Optional[dict[str, Any]] = None,
425
+ ) -> dict[str, Any]:
426
+ to_object: dict[str, Any] = {}
427
+ if getv(from_object, ["name"]) is not None:
428
+ setv(to_object, ["name"], getv(from_object, ["name"]))
429
+
430
+ if getv(from_object, ["dataset_id"]) is not None:
431
+ setv(to_object, ["_url", "dataset_id"], getv(from_object, ["dataset_id"]))
432
+
433
+ if getv(from_object, ["display_name"]) is not None:
434
+ setv(to_object, ["displayName"], getv(from_object, ["display_name"]))
435
+
436
+ if getv(from_object, ["metadata"]) is not None:
437
+ setv(to_object, ["metadata"], getv(from_object, ["metadata"]))
438
+
439
+ if getv(from_object, ["description"]) is not None:
440
+ setv(to_object, ["description"], getv(from_object, ["description"]))
441
+
442
+ if getv(from_object, ["encryption_spec"]) is not None:
443
+ setv(to_object, ["encryptionSpec"], getv(from_object, ["encryption_spec"]))
444
+
445
+ if getv(from_object, ["model_reference"]) is not None:
446
+ setv(to_object, ["modelReference"], getv(from_object, ["model_reference"]))
447
+
448
+ if getv(from_object, ["config"]) is not None:
449
+ setv(to_object, ["config"], getv(from_object, ["config"]))
450
+
451
+ return to_object
452
+
453
+
454
+ class Prompts(_api_module.BaseModule):
455
+
456
+ def _create_dataset_resource(
457
+ self,
458
+ *,
459
+ name: Optional[str] = None,
460
+ display_name: Optional[str] = None,
461
+ metadata_schema_uri: Optional[str] = None,
462
+ metadata: Optional[types.SchemaTextPromptDatasetMetadataOrDict] = None,
463
+ description: Optional[str] = None,
464
+ encryption_spec: Optional[genai_types.EncryptionSpecOrDict] = None,
465
+ model_reference: Optional[str] = None,
466
+ config: Optional[types.CreateDatasetConfigOrDict] = None,
467
+ ) -> types.DatasetOperation:
468
+ """
469
+ Creates a dataset resource to store prompts.
470
+ """
471
+
472
+ parameter_model = types._CreateDatasetParameters(
473
+ name=name,
474
+ display_name=display_name,
475
+ metadata_schema_uri=metadata_schema_uri,
476
+ metadata=metadata,
477
+ description=description,
478
+ encryption_spec=encryption_spec,
479
+ model_reference=model_reference,
480
+ config=config,
481
+ )
482
+
483
+ request_url_dict: Optional[dict[str, str]]
484
+ if not self._api_client.vertexai:
485
+ raise ValueError(
486
+ "This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
487
+ )
488
+ else:
489
+ request_dict = _CreateDatasetParameters_to_vertex(parameter_model)
490
+ request_url_dict = request_dict.get("_url")
491
+ if request_url_dict:
492
+ path = "datasets".format_map(request_url_dict)
493
+ else:
494
+ path = "datasets"
495
+
496
+ query_params = request_dict.get("_query")
497
+ if query_params:
498
+ path = f"{path}?{urlencode(query_params)}"
499
+ # TODO: remove the hack that pops config.
500
+ request_dict.pop("config", None)
501
+
502
+ http_options: Optional[types.HttpOptions] = None
503
+ if (
504
+ parameter_model.config is not None
505
+ and parameter_model.config.http_options is not None
506
+ ):
507
+ http_options = parameter_model.config.http_options
508
+
509
+ request_dict = _common.convert_to_dict(request_dict)
510
+ request_dict = _common.encode_unserializable_types(request_dict)
511
+
512
+ response = self._api_client.request("post", path, request_dict, http_options)
513
+
514
+ response_dict = {} if not response.body else json.loads(response.body)
515
+
516
+ return_value = types.DatasetOperation._from_response(
517
+ response=response_dict,
518
+ kwargs=(
519
+ {
520
+ "config": {
521
+ "response_schema": getattr(
522
+ parameter_model.config, "response_schema", None
523
+ ),
524
+ "response_json_schema": getattr(
525
+ parameter_model.config, "response_json_schema", None
526
+ ),
527
+ "include_all_fields": getattr(
528
+ parameter_model.config, "include_all_fields", None
529
+ ),
530
+ }
531
+ }
532
+ if getattr(parameter_model, "config", None)
533
+ else {}
534
+ ),
535
+ )
536
+
537
+ self._api_client._verify_response(return_value)
538
+ return return_value
539
+
540
+ def _create_dataset_version_resource(
541
+ self,
542
+ *,
543
+ dataset_name: Optional[str] = None,
544
+ metadata: Optional[types.SchemaTextPromptDatasetMetadataOrDict] = None,
545
+ model_reference: Optional[str] = None,
546
+ parent: Optional[str] = None,
547
+ display_name: Optional[str] = None,
548
+ config: Optional[types.CreateDatasetVersionConfigOrDict] = None,
549
+ ) -> types.DatasetOperation:
550
+ """
551
+ Creates a dataset version resource to store prompts.
552
+ """
553
+
554
+ parameter_model = types._CreateDatasetVersionParameters(
555
+ dataset_name=dataset_name,
556
+ metadata=metadata,
557
+ model_reference=model_reference,
558
+ parent=parent,
559
+ display_name=display_name,
560
+ config=config,
561
+ )
562
+
563
+ request_url_dict: Optional[dict[str, str]]
564
+ if not self._api_client.vertexai:
565
+ raise ValueError(
566
+ "This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
567
+ )
568
+ else:
569
+ request_dict = _CreateDatasetVersionParameters_to_vertex(parameter_model)
570
+ request_url_dict = request_dict.get("_url")
571
+ if request_url_dict:
572
+ path = "datasets/{name}/datasetVersions".format_map(request_url_dict)
573
+ else:
574
+ path = "datasets/{name}/datasetVersions"
575
+
576
+ query_params = request_dict.get("_query")
577
+ if query_params:
578
+ path = f"{path}?{urlencode(query_params)}"
579
+ # TODO: remove the hack that pops config.
580
+ request_dict.pop("config", None)
581
+
582
+ http_options: Optional[types.HttpOptions] = None
583
+ if (
584
+ parameter_model.config is not None
585
+ and parameter_model.config.http_options is not None
586
+ ):
587
+ http_options = parameter_model.config.http_options
588
+
589
+ request_dict = _common.convert_to_dict(request_dict)
590
+ request_dict = _common.encode_unserializable_types(request_dict)
591
+
592
+ response = self._api_client.request("post", path, request_dict, http_options)
593
+
594
+ response_dict = {} if not response.body else json.loads(response.body)
595
+
596
+ return_value = types.DatasetOperation._from_response(
597
+ response=response_dict,
598
+ kwargs=(
599
+ {
600
+ "config": {
601
+ "response_schema": getattr(
602
+ parameter_model.config, "response_schema", None
603
+ ),
604
+ "response_json_schema": getattr(
605
+ parameter_model.config, "response_json_schema", None
606
+ ),
607
+ "include_all_fields": getattr(
608
+ parameter_model.config, "include_all_fields", None
609
+ ),
610
+ }
611
+ }
612
+ if getattr(parameter_model, "config", None)
613
+ else {}
614
+ ),
615
+ )
616
+
617
+ self._api_client._verify_response(return_value)
618
+ return return_value
619
+
620
+ def _get_dataset_resource(
621
+ self,
622
+ *,
623
+ name: Optional[str] = None,
624
+ config: Optional[types.VertexBaseConfigOrDict] = None,
625
+ ) -> types.Dataset:
626
+ """
627
+ Gets a dataset resource to store prompts.
628
+ """
629
+
630
+ parameter_model = types._GetDatasetParameters(
631
+ name=name,
632
+ config=config,
633
+ )
634
+
635
+ request_url_dict: Optional[dict[str, str]]
636
+ if not self._api_client.vertexai:
637
+ raise ValueError(
638
+ "This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
639
+ )
640
+ else:
641
+ request_dict = _GetDatasetParameters_to_vertex(parameter_model)
642
+ request_url_dict = request_dict.get("_url")
643
+ if request_url_dict:
644
+ path = "datasets/{name}".format_map(request_url_dict)
645
+ else:
646
+ path = "datasets/{name}"
647
+
648
+ query_params = request_dict.get("_query")
649
+ if query_params:
650
+ path = f"{path}?{urlencode(query_params)}"
651
+ # TODO: remove the hack that pops config.
652
+ request_dict.pop("config", None)
653
+
654
+ http_options: Optional[types.HttpOptions] = None
655
+ if (
656
+ parameter_model.config is not None
657
+ and parameter_model.config.http_options is not None
658
+ ):
659
+ http_options = parameter_model.config.http_options
660
+
661
+ request_dict = _common.convert_to_dict(request_dict)
662
+ request_dict = _common.encode_unserializable_types(request_dict)
663
+
664
+ response = self._api_client.request("get", path, request_dict, http_options)
665
+
666
+ response_dict = {} if not response.body else json.loads(response.body)
667
+
668
+ return_value = types.Dataset._from_response(
669
+ response=response_dict,
670
+ kwargs=(
671
+ {
672
+ "config": {
673
+ "response_schema": getattr(
674
+ parameter_model.config, "response_schema", None
675
+ ),
676
+ "response_json_schema": getattr(
677
+ parameter_model.config, "response_json_schema", None
678
+ ),
679
+ "include_all_fields": getattr(
680
+ parameter_model.config, "include_all_fields", None
681
+ ),
682
+ }
683
+ }
684
+ if getattr(parameter_model, "config", None)
685
+ else {}
686
+ ),
687
+ )
688
+
689
+ self._api_client._verify_response(return_value)
690
+ return return_value
691
+
692
+ def _get_dataset_version_resource(
693
+ self,
694
+ *,
695
+ dataset_id: Optional[str] = None,
696
+ dataset_version_id: Optional[str] = None,
697
+ config: Optional[types.VertexBaseConfigOrDict] = None,
698
+ ) -> types.DatasetVersion:
699
+ """
700
+ Gets a dataset version resource to store prompts.
701
+ """
702
+
703
+ parameter_model = types._GetDatasetVersionParameters(
704
+ dataset_id=dataset_id,
705
+ dataset_version_id=dataset_version_id,
706
+ config=config,
707
+ )
708
+
709
+ request_url_dict: Optional[dict[str, str]]
710
+ if not self._api_client.vertexai:
711
+ raise ValueError(
712
+ "This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
713
+ )
714
+ else:
715
+ request_dict = _GetDatasetVersionParameters_to_vertex(parameter_model)
716
+ request_url_dict = request_dict.get("_url")
717
+ if request_url_dict:
718
+ path = "datasets/{dataset_id}/datasetVersions/{dataset_version_id}".format_map(
719
+ request_url_dict
720
+ )
721
+ else:
722
+ path = "datasets/{dataset_id}/datasetVersions/{dataset_version_id}"
723
+
724
+ query_params = request_dict.get("_query")
725
+ if query_params:
726
+ path = f"{path}?{urlencode(query_params)}"
727
+ # TODO: remove the hack that pops config.
728
+ request_dict.pop("config", None)
729
+
730
+ http_options: Optional[types.HttpOptions] = None
731
+ if (
732
+ parameter_model.config is not None
733
+ and parameter_model.config.http_options is not None
734
+ ):
735
+ http_options = parameter_model.config.http_options
736
+
737
+ request_dict = _common.convert_to_dict(request_dict)
738
+ request_dict = _common.encode_unserializable_types(request_dict)
739
+
740
+ response = self._api_client.request("get", path, request_dict, http_options)
741
+
742
+ response_dict = {} if not response.body else json.loads(response.body)
743
+
744
+ return_value = types.DatasetVersion._from_response(
745
+ response=response_dict,
746
+ kwargs=(
747
+ {
748
+ "config": {
749
+ "response_schema": getattr(
750
+ parameter_model.config, "response_schema", None
751
+ ),
752
+ "response_json_schema": getattr(
753
+ parameter_model.config, "response_json_schema", None
754
+ ),
755
+ "include_all_fields": getattr(
756
+ parameter_model.config, "include_all_fields", None
757
+ ),
758
+ }
759
+ }
760
+ if getattr(parameter_model, "config", None)
761
+ else {}
762
+ ),
763
+ )
764
+
765
+ self._api_client._verify_response(return_value)
766
+ return return_value
767
+
768
+ def _get_dataset_operation(
769
+ self,
770
+ *,
771
+ dataset_id: Optional[str] = None,
772
+ operation_id: Optional[str] = None,
773
+ config: Optional[types.GetDatasetOperationConfigOrDict] = None,
774
+ ) -> types.DatasetOperation:
775
+ """
776
+ Gets the operation from creating a dataset.
777
+ """
778
+
779
+ parameter_model = types._GetDatasetOperationParameters(
780
+ dataset_id=dataset_id,
781
+ operation_id=operation_id,
782
+ config=config,
783
+ )
784
+
785
+ request_url_dict: Optional[dict[str, str]]
786
+ if not self._api_client.vertexai:
787
+ raise ValueError(
788
+ "This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
789
+ )
790
+ else:
791
+ request_dict = _GetDatasetOperationParameters_to_vertex(parameter_model)
792
+ request_url_dict = request_dict.get("_url")
793
+ if request_url_dict:
794
+ path = "datasets/{dataset_id}/operations/{operation_id}".format_map(
795
+ request_url_dict
796
+ )
797
+ else:
798
+ path = "datasets/{dataset_id}/operations/{operation_id}"
799
+
800
+ query_params = request_dict.get("_query")
801
+ if query_params:
802
+ path = f"{path}?{urlencode(query_params)}"
803
+ # TODO: remove the hack that pops config.
804
+ request_dict.pop("config", None)
805
+
806
+ http_options: Optional[types.HttpOptions] = None
807
+ if (
808
+ parameter_model.config is not None
809
+ and parameter_model.config.http_options is not None
810
+ ):
811
+ http_options = parameter_model.config.http_options
812
+
813
+ request_dict = _common.convert_to_dict(request_dict)
814
+ request_dict = _common.encode_unserializable_types(request_dict)
815
+
816
+ response = self._api_client.request("get", path, request_dict, http_options)
817
+
818
+ response_dict = {} if not response.body else json.loads(response.body)
819
+
820
+ return_value = types.DatasetOperation._from_response(
821
+ response=response_dict,
822
+ kwargs=(
823
+ {
824
+ "config": {
825
+ "response_schema": getattr(
826
+ parameter_model.config, "response_schema", None
827
+ ),
828
+ "response_json_schema": getattr(
829
+ parameter_model.config, "response_json_schema", None
830
+ ),
831
+ "include_all_fields": getattr(
832
+ parameter_model.config, "include_all_fields", None
833
+ ),
834
+ }
835
+ }
836
+ if getattr(parameter_model, "config", None)
837
+ else {}
838
+ ),
839
+ )
840
+
841
+ self._api_client._verify_response(return_value)
842
+ return return_value
843
+
844
+ def _list_prompts(
845
+ self, *, config: Optional[types.ListPromptsConfigOrDict] = None
846
+ ) -> types.ListDatasetsResponse:
847
+ """
848
+ Lists Agent Engines.
849
+ """
850
+
851
+ parameter_model = types._ListDatasetsRequestParameters(
852
+ config=config,
853
+ )
854
+
855
+ request_url_dict: Optional[dict[str, str]]
856
+ if not self._api_client.vertexai:
857
+ raise ValueError(
858
+ "This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
859
+ )
860
+ else:
861
+ request_dict = _ListDatasetsRequestParameters_to_vertex(parameter_model)
862
+ request_url_dict = request_dict.get("_url")
863
+ if request_url_dict:
864
+ path = "datasets".format_map(request_url_dict)
865
+ else:
866
+ path = "datasets"
867
+
868
+ query_params = request_dict.get("_query")
869
+ if query_params:
870
+ path = f"{path}?{urlencode(query_params)}"
871
+ # TODO: remove the hack that pops config.
872
+ request_dict.pop("config", None)
873
+
874
+ http_options: Optional[types.HttpOptions] = None
875
+ if (
876
+ parameter_model.config is not None
877
+ and parameter_model.config.http_options is not None
878
+ ):
879
+ http_options = parameter_model.config.http_options
880
+
881
+ request_dict = _common.convert_to_dict(request_dict)
882
+ request_dict = _common.encode_unserializable_types(request_dict)
883
+
884
+ response = self._api_client.request("get", path, request_dict, http_options)
885
+
886
+ response_dict = {} if not response.body else json.loads(response.body)
887
+
888
+ return_value = types.ListDatasetsResponse._from_response(
889
+ response=response_dict,
890
+ kwargs=(
891
+ {
892
+ "config": {
893
+ "response_schema": getattr(
894
+ parameter_model.config, "response_schema", None
895
+ ),
896
+ "response_json_schema": getattr(
897
+ parameter_model.config, "response_json_schema", None
898
+ ),
899
+ "include_all_fields": getattr(
900
+ parameter_model.config, "include_all_fields", None
901
+ ),
902
+ }
903
+ }
904
+ if getattr(parameter_model, "config", None)
905
+ else {}
906
+ ),
907
+ )
908
+
909
+ self._api_client._verify_response(return_value)
910
+ return return_value
911
+
912
+ def _list_versions(
913
+ self,
914
+ *,
915
+ read_mask: Optional[str] = None,
916
+ dataset_id: Optional[str] = None,
917
+ config: Optional[types.ListPromptsConfigOrDict] = None,
918
+ ) -> types.ListDatasetVersionsResponse:
919
+ """
920
+ Lists Agent Engines.
921
+ """
922
+
923
+ parameter_model = types._ListDatasetVersionsRequestParameters(
924
+ read_mask=read_mask,
925
+ dataset_id=dataset_id,
926
+ config=config,
927
+ )
928
+
929
+ request_url_dict: Optional[dict[str, str]]
930
+ if not self._api_client.vertexai:
931
+ raise ValueError(
932
+ "This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
933
+ )
934
+ else:
935
+ request_dict = _ListDatasetVersionsRequestParameters_to_vertex(
936
+ parameter_model
937
+ )
938
+ request_url_dict = request_dict.get("_url")
939
+ if request_url_dict:
940
+ path = "datasets/{dataset_id}/datasetVersions".format_map(
941
+ request_url_dict
942
+ )
943
+ else:
944
+ path = "datasets/{dataset_id}/datasetVersions"
945
+
946
+ query_params = request_dict.get("_query")
947
+ if query_params:
948
+ path = f"{path}?{urlencode(query_params)}"
949
+ # TODO: remove the hack that pops config.
950
+ request_dict.pop("config", None)
951
+
952
+ http_options: Optional[types.HttpOptions] = None
953
+ if (
954
+ parameter_model.config is not None
955
+ and parameter_model.config.http_options is not None
956
+ ):
957
+ http_options = parameter_model.config.http_options
958
+
959
+ request_dict = _common.convert_to_dict(request_dict)
960
+ request_dict = _common.encode_unserializable_types(request_dict)
961
+
962
+ response = self._api_client.request("get", path, request_dict, http_options)
963
+
964
+ response_dict = {} if not response.body else json.loads(response.body)
965
+
966
+ return_value = types.ListDatasetVersionsResponse._from_response(
967
+ response=response_dict,
968
+ kwargs=(
969
+ {
970
+ "config": {
971
+ "response_schema": getattr(
972
+ parameter_model.config, "response_schema", None
973
+ ),
974
+ "response_json_schema": getattr(
975
+ parameter_model.config, "response_json_schema", None
976
+ ),
977
+ "include_all_fields": getattr(
978
+ parameter_model.config, "include_all_fields", None
979
+ ),
980
+ }
981
+ }
982
+ if getattr(parameter_model, "config", None)
983
+ else {}
984
+ ),
985
+ )
986
+
987
+ self._api_client._verify_response(return_value)
988
+ return return_value
989
+
990
+ def _delete_dataset(
991
+ self, *, prompt_id: str, config: Optional[types.DeletePromptConfigOrDict] = None
992
+ ) -> types.DeletePromptOperation:
993
+ parameter_model = types._DeleteDatasetRequestParameters(
994
+ prompt_id=prompt_id,
995
+ config=config,
996
+ )
997
+
998
+ request_url_dict: Optional[dict[str, str]]
999
+ if not self._api_client.vertexai:
1000
+ raise ValueError(
1001
+ "This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
1002
+ )
1003
+ else:
1004
+ request_dict = _DeleteDatasetRequestParameters_to_vertex(parameter_model)
1005
+ request_url_dict = request_dict.get("_url")
1006
+ if request_url_dict:
1007
+ path = "datasets/{dataset_id}".format_map(request_url_dict)
1008
+ else:
1009
+ path = "datasets/{dataset_id}"
1010
+
1011
+ query_params = request_dict.get("_query")
1012
+ if query_params:
1013
+ path = f"{path}?{urlencode(query_params)}"
1014
+ # TODO: remove the hack that pops config.
1015
+ request_dict.pop("config", None)
1016
+
1017
+ http_options: Optional[types.HttpOptions] = None
1018
+ if (
1019
+ parameter_model.config is not None
1020
+ and parameter_model.config.http_options is not None
1021
+ ):
1022
+ http_options = parameter_model.config.http_options
1023
+
1024
+ request_dict = _common.convert_to_dict(request_dict)
1025
+ request_dict = _common.encode_unserializable_types(request_dict)
1026
+
1027
+ response = self._api_client.request("delete", path, request_dict, http_options)
1028
+
1029
+ response_dict = {} if not response.body else json.loads(response.body)
1030
+
1031
+ return_value = types.DeletePromptOperation._from_response(
1032
+ response=response_dict,
1033
+ kwargs=(
1034
+ {
1035
+ "config": {
1036
+ "response_schema": getattr(
1037
+ parameter_model.config, "response_schema", None
1038
+ ),
1039
+ "response_json_schema": getattr(
1040
+ parameter_model.config, "response_json_schema", None
1041
+ ),
1042
+ "include_all_fields": getattr(
1043
+ parameter_model.config, "include_all_fields", None
1044
+ ),
1045
+ }
1046
+ }
1047
+ if getattr(parameter_model, "config", None)
1048
+ else {}
1049
+ ),
1050
+ )
1051
+
1052
+ self._api_client._verify_response(return_value)
1053
+ return return_value
1054
+
1055
+ def _delete_dataset_version(
1056
+ self,
1057
+ *,
1058
+ prompt_id: str,
1059
+ version_id: str,
1060
+ config: Optional[types.DeletePromptConfigOrDict] = None,
1061
+ ) -> types.DeletePromptVersionOperation:
1062
+ parameter_model = types._DeletePromptVersionRequestParameters(
1063
+ prompt_id=prompt_id,
1064
+ version_id=version_id,
1065
+ config=config,
1066
+ )
1067
+
1068
+ request_url_dict: Optional[dict[str, str]]
1069
+ if not self._api_client.vertexai:
1070
+ raise ValueError(
1071
+ "This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
1072
+ )
1073
+ else:
1074
+ request_dict = _DeletePromptVersionRequestParameters_to_vertex(
1075
+ parameter_model
1076
+ )
1077
+ request_url_dict = request_dict.get("_url")
1078
+ if request_url_dict:
1079
+ path = "datasets/{dataset_id}/datasetVersions/{version_id}".format_map(
1080
+ request_url_dict
1081
+ )
1082
+ else:
1083
+ path = "datasets/{dataset_id}/datasetVersions/{version_id}"
1084
+
1085
+ query_params = request_dict.get("_query")
1086
+ if query_params:
1087
+ path = f"{path}?{urlencode(query_params)}"
1088
+ # TODO: remove the hack that pops config.
1089
+ request_dict.pop("config", None)
1090
+
1091
+ http_options: Optional[types.HttpOptions] = None
1092
+ if (
1093
+ parameter_model.config is not None
1094
+ and parameter_model.config.http_options is not None
1095
+ ):
1096
+ http_options = parameter_model.config.http_options
1097
+
1098
+ request_dict = _common.convert_to_dict(request_dict)
1099
+ request_dict = _common.encode_unserializable_types(request_dict)
1100
+
1101
+ response = self._api_client.request("delete", path, request_dict, http_options)
1102
+
1103
+ response_dict = {} if not response.body else json.loads(response.body)
1104
+
1105
+ return_value = types.DeletePromptVersionOperation._from_response(
1106
+ response=response_dict,
1107
+ kwargs=(
1108
+ {
1109
+ "config": {
1110
+ "response_schema": getattr(
1111
+ parameter_model.config, "response_schema", None
1112
+ ),
1113
+ "response_json_schema": getattr(
1114
+ parameter_model.config, "response_json_schema", None
1115
+ ),
1116
+ "include_all_fields": getattr(
1117
+ parameter_model.config, "include_all_fields", None
1118
+ ),
1119
+ }
1120
+ }
1121
+ if getattr(parameter_model, "config", None)
1122
+ else {}
1123
+ ),
1124
+ )
1125
+
1126
+ self._api_client._verify_response(return_value)
1127
+ return return_value
1128
+
1129
+ def _restore_version(
1130
+ self,
1131
+ *,
1132
+ dataset_id: str,
1133
+ version_id: str,
1134
+ config: Optional[types.RestoreVersionConfigOrDict] = None,
1135
+ ) -> types.RestoreVersionOperation:
1136
+ """
1137
+ Restores the provided prompt version to the latest version.
1138
+ """
1139
+
1140
+ parameter_model = types._RestoreVersionRequestParameters(
1141
+ dataset_id=dataset_id,
1142
+ version_id=version_id,
1143
+ config=config,
1144
+ )
1145
+
1146
+ request_url_dict: Optional[dict[str, str]]
1147
+ if not self._api_client.vertexai:
1148
+ raise ValueError(
1149
+ "This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
1150
+ )
1151
+ else:
1152
+ request_dict = _RestoreVersionRequestParameters_to_vertex(parameter_model)
1153
+ request_url_dict = request_dict.get("_url")
1154
+ if request_url_dict:
1155
+ path = "datasets/{dataset_id}/datasetVersions/{version_id}:restore".format_map(
1156
+ request_url_dict
1157
+ )
1158
+ else:
1159
+ path = "datasets/{dataset_id}/datasetVersions/{version_id}:restore"
1160
+
1161
+ query_params = request_dict.get("_query")
1162
+ if query_params:
1163
+ path = f"{path}?{urlencode(query_params)}"
1164
+ # TODO: remove the hack that pops config.
1165
+ request_dict.pop("config", None)
1166
+
1167
+ http_options: Optional[types.HttpOptions] = None
1168
+ if (
1169
+ parameter_model.config is not None
1170
+ and parameter_model.config.http_options is not None
1171
+ ):
1172
+ http_options = parameter_model.config.http_options
1173
+
1174
+ request_dict = _common.convert_to_dict(request_dict)
1175
+ request_dict = _common.encode_unserializable_types(request_dict)
1176
+
1177
+ response = self._api_client.request("get", path, request_dict, http_options)
1178
+
1179
+ response_dict = {} if not response.body else json.loads(response.body)
1180
+
1181
+ return_value = types.RestoreVersionOperation._from_response(
1182
+ response=response_dict,
1183
+ kwargs=(
1184
+ {
1185
+ "config": {
1186
+ "response_schema": getattr(
1187
+ parameter_model.config, "response_schema", None
1188
+ ),
1189
+ "response_json_schema": getattr(
1190
+ parameter_model.config, "response_json_schema", None
1191
+ ),
1192
+ "include_all_fields": getattr(
1193
+ parameter_model.config, "include_all_fields", None
1194
+ ),
1195
+ }
1196
+ }
1197
+ if getattr(parameter_model, "config", None)
1198
+ else {}
1199
+ ),
1200
+ )
1201
+
1202
+ self._api_client._verify_response(return_value)
1203
+ return return_value
1204
+
1205
+ def _update_dataset_resource(
1206
+ self,
1207
+ *,
1208
+ name: Optional[str] = None,
1209
+ dataset_id: Optional[str] = None,
1210
+ display_name: Optional[str] = None,
1211
+ metadata: Optional[types.SchemaTextPromptDatasetMetadataOrDict] = None,
1212
+ description: Optional[str] = None,
1213
+ encryption_spec: Optional[genai_types.EncryptionSpecOrDict] = None,
1214
+ model_reference: Optional[str] = None,
1215
+ config: Optional[types.UpdatePromptConfigOrDict] = None,
1216
+ ) -> types.Dataset:
1217
+ """
1218
+ Creates a dataset resource to store prompts.
1219
+ """
1220
+
1221
+ parameter_model = types._UpdateDatasetParameters(
1222
+ name=name,
1223
+ dataset_id=dataset_id,
1224
+ display_name=display_name,
1225
+ metadata=metadata,
1226
+ description=description,
1227
+ encryption_spec=encryption_spec,
1228
+ model_reference=model_reference,
1229
+ config=config,
1230
+ )
1231
+
1232
+ request_url_dict: Optional[dict[str, str]]
1233
+ if not self._api_client.vertexai:
1234
+ raise ValueError(
1235
+ "This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
1236
+ )
1237
+ else:
1238
+ request_dict = _UpdateDatasetParameters_to_vertex(parameter_model)
1239
+ request_url_dict = request_dict.get("_url")
1240
+ if request_url_dict:
1241
+ path = "datasets/{dataset_id}".format_map(request_url_dict)
1242
+ else:
1243
+ path = "datasets/{dataset_id}"
1244
+
1245
+ query_params = request_dict.get("_query")
1246
+ if query_params:
1247
+ path = f"{path}?{urlencode(query_params)}"
1248
+ # TODO: remove the hack that pops config.
1249
+ request_dict.pop("config", None)
1250
+
1251
+ http_options: Optional[types.HttpOptions] = None
1252
+ if (
1253
+ parameter_model.config is not None
1254
+ and parameter_model.config.http_options is not None
1255
+ ):
1256
+ http_options = parameter_model.config.http_options
1257
+
1258
+ request_dict = _common.convert_to_dict(request_dict)
1259
+ request_dict = _common.encode_unserializable_types(request_dict)
1260
+
1261
+ response = self._api_client.request("patch", path, request_dict, http_options)
1262
+
1263
+ response_dict = {} if not response.body else json.loads(response.body)
1264
+
1265
+ return_value = types.Dataset._from_response(
1266
+ response=response_dict,
1267
+ kwargs=(
1268
+ {
1269
+ "config": {
1270
+ "response_schema": getattr(
1271
+ parameter_model.config, "response_schema", None
1272
+ ),
1273
+ "response_json_schema": getattr(
1274
+ parameter_model.config, "response_json_schema", None
1275
+ ),
1276
+ "include_all_fields": getattr(
1277
+ parameter_model.config, "include_all_fields", None
1278
+ ),
1279
+ }
1280
+ }
1281
+ if getattr(parameter_model, "config", None)
1282
+ else {}
1283
+ ),
1284
+ )
1285
+
1286
+ self._api_client._verify_response(return_value)
1287
+ return return_value
1288
+
1289
+ def _create_custom_job_resource(
1290
+ self,
1291
+ *,
1292
+ custom_job: types.CustomJobOrDict,
1293
+ config: Optional[types.VertexBaseConfigOrDict] = None,
1294
+ ) -> types.CustomJob:
1295
+ """
1296
+ Creates a custom job.
1297
+ """
1298
+
1299
+ parameter_model = types._CustomJobParameters(
1300
+ custom_job=custom_job,
1301
+ config=config,
1302
+ )
1303
+
1304
+ request_url_dict: Optional[dict[str, str]]
1305
+ if not self._api_client.vertexai:
1306
+ raise ValueError(
1307
+ "This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
1308
+ )
1309
+ else:
1310
+ request_dict = _CustomJobParameters_to_vertex(parameter_model)
1311
+ request_url_dict = request_dict.get("_url")
1312
+ if request_url_dict:
1313
+ path = "customJobs".format_map(request_url_dict)
1314
+ else:
1315
+ path = "customJobs"
1316
+
1317
+ query_params = request_dict.get("_query")
1318
+ if query_params:
1319
+ path = f"{path}?{urlencode(query_params)}"
1320
+ # TODO: remove the hack that pops config.
1321
+ request_dict.pop("config", None)
1322
+
1323
+ http_options: Optional[types.HttpOptions] = None
1324
+ if (
1325
+ parameter_model.config is not None
1326
+ and parameter_model.config.http_options is not None
1327
+ ):
1328
+ http_options = parameter_model.config.http_options
1329
+
1330
+ request_dict = _common.convert_to_dict(request_dict)
1331
+ request_dict = _common.encode_unserializable_types(request_dict)
1332
+
1333
+ response = self._api_client.request("post", path, request_dict, http_options)
1334
+
1335
+ response_dict = {} if not response.body else json.loads(response.body)
1336
+
1337
+ if self._api_client.vertexai:
1338
+ response_dict = _CustomJob_from_vertex(response_dict)
1339
+
1340
+ return_value = types.CustomJob._from_response(
1341
+ response=response_dict,
1342
+ kwargs=(
1343
+ {
1344
+ "config": {
1345
+ "response_schema": getattr(
1346
+ parameter_model.config, "response_schema", None
1347
+ ),
1348
+ "response_json_schema": getattr(
1349
+ parameter_model.config, "response_json_schema", None
1350
+ ),
1351
+ "include_all_fields": getattr(
1352
+ parameter_model.config, "include_all_fields", None
1353
+ ),
1354
+ }
1355
+ }
1356
+ if getattr(parameter_model, "config", None)
1357
+ else {}
1358
+ ),
1359
+ )
1360
+
1361
+ self._api_client._verify_response(return_value)
1362
+ return return_value
1363
+
1364
+ def _get_custom_job(
1365
+ self, *, name: str, config: Optional[types.VertexBaseConfigOrDict] = None
1366
+ ) -> types.CustomJob:
1367
+ """
1368
+ Gets a custom job.
1369
+ """
1370
+
1371
+ parameter_model = types._GetCustomJobParameters(
1372
+ name=name,
1373
+ config=config,
1374
+ )
1375
+
1376
+ request_url_dict: Optional[dict[str, str]]
1377
+ if not self._api_client.vertexai:
1378
+ raise ValueError(
1379
+ "This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
1380
+ )
1381
+ else:
1382
+ request_dict = _GetCustomJobParameters_to_vertex(parameter_model)
1383
+ request_url_dict = request_dict.get("_url")
1384
+ if request_url_dict:
1385
+ path = "customJobs/{name}".format_map(request_url_dict)
1386
+ else:
1387
+ path = "customJobs/{name}"
1388
+
1389
+ query_params = request_dict.get("_query")
1390
+ if query_params:
1391
+ path = f"{path}?{urlencode(query_params)}"
1392
+ # TODO: remove the hack that pops config.
1393
+ request_dict.pop("config", None)
1394
+
1395
+ http_options: Optional[types.HttpOptions] = None
1396
+ if (
1397
+ parameter_model.config is not None
1398
+ and parameter_model.config.http_options is not None
1399
+ ):
1400
+ http_options = parameter_model.config.http_options
1401
+
1402
+ request_dict = _common.convert_to_dict(request_dict)
1403
+ request_dict = _common.encode_unserializable_types(request_dict)
1404
+
1405
+ response = self._api_client.request("get", path, request_dict, http_options)
1406
+
1407
+ response_dict = {} if not response.body else json.loads(response.body)
1408
+
1409
+ if self._api_client.vertexai:
1410
+ response_dict = _CustomJob_from_vertex(response_dict)
1411
+
1412
+ return_value = types.CustomJob._from_response(
1413
+ response=response_dict,
1414
+ kwargs=(
1415
+ {
1416
+ "config": {
1417
+ "response_schema": getattr(
1418
+ parameter_model.config, "response_schema", None
1419
+ ),
1420
+ "response_json_schema": getattr(
1421
+ parameter_model.config, "response_json_schema", None
1422
+ ),
1423
+ "include_all_fields": getattr(
1424
+ parameter_model.config, "include_all_fields", None
1425
+ ),
1426
+ }
1427
+ }
1428
+ if getattr(parameter_model, "config", None)
1429
+ else {}
1430
+ ),
1431
+ )
1432
+
1433
+ self._api_client._verify_response(return_value)
1434
+ return return_value
1435
+
1436
+ def _optimize(
1437
+ self,
1438
+ *,
1439
+ content: Optional[genai_types.ContentOrDict] = None,
1440
+ config: Optional[types.OptimizeConfigOrDict] = None,
1441
+ ) -> types.OptimizeResponseEndpoint:
1442
+ """
1443
+ Optimize a single prompt.
1444
+ """
1445
+
1446
+ parameter_model = types._OptimizeRequestParameters(
1447
+ content=content,
1448
+ config=config,
1449
+ )
1450
+
1451
+ request_url_dict: Optional[dict[str, str]]
1452
+ if not self._api_client.vertexai:
1453
+ raise ValueError(
1454
+ "This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
1455
+ )
1456
+ else:
1457
+ request_dict = _OptimizeRequestParameters_to_vertex(parameter_model)
1458
+ request_url_dict = request_dict.get("_url")
1459
+ if request_url_dict:
1460
+ path = "tuningJobs:optimizePrompt".format_map(request_url_dict)
1461
+ else:
1462
+ path = "tuningJobs:optimizePrompt"
1463
+
1464
+ query_params = request_dict.get("_query")
1465
+ if query_params:
1466
+ path = f"{path}?{urlencode(query_params)}"
1467
+ # TODO: remove the hack that pops config.
1468
+ request_dict.pop("config", None)
1469
+
1470
+ http_options: Optional[types.HttpOptions] = None
1471
+ if (
1472
+ parameter_model.config is not None
1473
+ and parameter_model.config.http_options is not None
1474
+ ):
1475
+ http_options = parameter_model.config.http_options
1476
+
1477
+ request_dict = _common.convert_to_dict(request_dict)
1478
+ request_dict = _common.encode_unserializable_types(request_dict)
1479
+
1480
+ response = self._api_client.request("post", path, request_dict, http_options)
1481
+
1482
+ response_dict = {} if not response.body else json.loads(response.body)
1483
+
1484
+ return_value = types.OptimizeResponseEndpoint._from_response(
1485
+ response=response_dict,
1486
+ kwargs=(
1487
+ {
1488
+ "config": {
1489
+ "response_schema": getattr(
1490
+ parameter_model.config, "response_schema", None
1491
+ ),
1492
+ "response_json_schema": getattr(
1493
+ parameter_model.config, "response_json_schema", None
1494
+ ),
1495
+ "include_all_fields": getattr(
1496
+ parameter_model.config, "include_all_fields", None
1497
+ ),
1498
+ }
1499
+ }
1500
+ if getattr(parameter_model, "config", None)
1501
+ else {}
1502
+ ),
1503
+ )
1504
+
1505
+ self._api_client._verify_response(return_value)
1506
+ return return_value
1507
+
1508
+ _DEFAULT_TIMEOUT = 90
1509
+ _DEFAULT_MAX_WAIT_TIME = 60
1510
+
1511
+ def create(
1512
+ self,
1513
+ *,
1514
+ prompt: types.PromptOrDict,
1515
+ config: Optional[types.CreatePromptConfigOrDict] = None,
1516
+ ) -> types.Prompt:
1517
+ """Creates a new prompt in a Vertex Dataset resource.
1518
+
1519
+ This method waits for prompt creation to be complete before returning.
1520
+
1521
+ Note: This method does not create a versioned resource for your prompt.
1522
+ Call create_version() to create a new prompt resource with a version.
1523
+
1524
+ Args:
1525
+ prompt: The prompt to create.
1526
+ config: Optional configuration for creating the prompt.
1527
+
1528
+ Returns:
1529
+ A types.Prompt object representing the prompt with its associated
1530
+ Dataset resources.
1531
+ """
1532
+ if isinstance(prompt, dict):
1533
+ prompt = types.Prompt(**prompt)
1534
+ if isinstance(config, dict):
1535
+ config = types.CreatePromptConfig(**config)
1536
+ elif not config:
1537
+ config = types.CreatePromptConfig()
1538
+
1539
+ _prompt_management_utils._raise_for_invalid_prompt(prompt)
1540
+
1541
+ if prompt.prompt_data is None:
1542
+ raise ValueError("Prompt data is required to create a prompt.")
1543
+
1544
+ prompt_metadata = _prompt_management_utils._create_dataset_metadata_from_prompt(
1545
+ prompt,
1546
+ variables=(
1547
+ prompt.prompt_data.variables
1548
+ if prompt.prompt_data and prompt.prompt_data.variables
1549
+ else None
1550
+ ),
1551
+ )
1552
+
1553
+ # Step 1: Create the dataset resource for the prompt and wait for the operation to complete.
1554
+ create_prompt_dataset_operation = self._create_dataset_resource(
1555
+ display_name=(
1556
+ config.prompt_display_name
1557
+ if config and config.prompt_display_name
1558
+ else f"prompt_{time.strftime('%Y%m%d-%H%M%S')}"
1559
+ ),
1560
+ name=f"projects/{self._api_client.project}/locations/{self._api_client.location}",
1561
+ metadata_schema_uri=_prompt_management_utils.PROMPT_SCHEMA_URI,
1562
+ metadata=prompt_metadata,
1563
+ model_reference=prompt.prompt_data.model,
1564
+ encryption_spec=(
1565
+ config.encryption_spec if config and config.encryption_spec else None
1566
+ ),
1567
+ )
1568
+ dataset_resource_name = self._wait_for_operation(
1569
+ operation=create_prompt_dataset_operation,
1570
+ timeout=(
1571
+ config.timeout
1572
+ if config and config.timeout is not None
1573
+ else self._DEFAULT_TIMEOUT
1574
+ ),
1575
+ max_wait_time=(
1576
+ config.max_wait_time
1577
+ if config and config.max_wait_time is not None
1578
+ else self._DEFAULT_MAX_WAIT_TIME
1579
+ ),
1580
+ )
1581
+ dataset_id = dataset_resource_name.split("/")[-1]
1582
+
1583
+ # Step 2: Get the dataset resource
1584
+ dataset_resource = self._get_dataset_resource(
1585
+ name=dataset_id,
1586
+ )
1587
+ prompt._dataset = dataset_resource
1588
+ return prompt
1589
+
1590
+ def create_version(
1591
+ self,
1592
+ *,
1593
+ prompt: types.PromptOrDict,
1594
+ config: Optional[types.CreatePromptVersionConfigOrDict] = None,
1595
+ ) -> types.Prompt:
1596
+ """Creates a prompt resource and an initial prompt version.
1597
+
1598
+ When creating new prompt and prompt version resources, this waits for
1599
+ the create operation to complete before returning.
1600
+
1601
+ Note: This method is recommended instead of create() since it creates a
1602
+ versioned resource for your prompt.
1603
+
1604
+ Args:
1605
+ prompt: The prompt to create.
1606
+ config: Optional configuration for creating the prompt and prompt version.
1607
+
1608
+ Returns:
1609
+ A types.Prompt object representing the prompt with its associated
1610
+ Dataset and Dataset Version resources.
1611
+ """
1612
+
1613
+ if isinstance(prompt, dict):
1614
+ prompt = types.Prompt(**prompt)
1615
+ if isinstance(config, dict):
1616
+ config = types.CreatePromptVersionConfig(**config)
1617
+ elif not config:
1618
+ config = types.CreatePromptVersionConfig()
1619
+
1620
+ _prompt_management_utils._raise_for_invalid_prompt(prompt)
1621
+
1622
+ if prompt.prompt_data is None:
1623
+ raise ValueError("Prompt data is required to create a prompt.")
1624
+
1625
+ prompt_metadata = _prompt_management_utils._create_dataset_metadata_from_prompt(
1626
+ prompt,
1627
+ variables=(
1628
+ prompt.prompt_data.variables
1629
+ if prompt.prompt_data and prompt.prompt_data.variables
1630
+ else None
1631
+ ),
1632
+ )
1633
+
1634
+ # Step 1: Create the dataset resource for the prompt and wait for the operation to complete.
1635
+ create_prompt_dataset_operation = self._create_dataset_resource(
1636
+ display_name=(
1637
+ config.prompt_display_name
1638
+ if config and config.prompt_display_name
1639
+ else f"prompt_{time.strftime('%Y%m%d-%H%M%S')}"
1640
+ ),
1641
+ name=f"projects/{self._api_client.project}/locations/{self._api_client.location}",
1642
+ metadata_schema_uri=_prompt_management_utils.PROMPT_SCHEMA_URI,
1643
+ metadata=prompt_metadata,
1644
+ model_reference=prompt.prompt_data.model,
1645
+ encryption_spec=(
1646
+ config.encryption_spec if config and config.encryption_spec else None
1647
+ ),
1648
+ )
1649
+ dataset_resource_name = self._wait_for_operation(
1650
+ operation=create_prompt_dataset_operation,
1651
+ timeout=(
1652
+ config.timeout
1653
+ if config and config.timeout is not None
1654
+ else self._DEFAULT_TIMEOUT
1655
+ ),
1656
+ max_wait_time=(
1657
+ config.max_wait_time
1658
+ if config and config.max_wait_time is not None
1659
+ else self._DEFAULT_MAX_WAIT_TIME
1660
+ ),
1661
+ )
1662
+ dataset_id = dataset_resource_name.split("/")[-1]
1663
+
1664
+ # Step 2: Get the dataset resource
1665
+ dataset_resource = self._get_dataset_resource(
1666
+ name=dataset_id,
1667
+ )
1668
+ prompt._dataset = dataset_resource
1669
+
1670
+ if prompt._dataset.name is None:
1671
+ raise ValueError("Invalid dataset resource.")
1672
+
1673
+ # Step 3: Create the dataset version
1674
+ create_dataset_version_operation = self._create_dataset_version_resource(
1675
+ dataset_name=prompt._dataset.name.split("/")[-1],
1676
+ display_name=(
1677
+ config.version_display_name
1678
+ if config and config.version_display_name is not None
1679
+ else f"prompt_version_{time.strftime('%Y%m%d-%H%M%S')}"
1680
+ ),
1681
+ )
1682
+ dataset_version_resource_name = self._wait_for_operation(
1683
+ operation=create_dataset_version_operation,
1684
+ timeout=(
1685
+ config.timeout
1686
+ if config and config.timeout is not None
1687
+ else self._DEFAULT_TIMEOUT
1688
+ ),
1689
+ max_wait_time=(
1690
+ config.max_wait_time
1691
+ if config and config.max_wait_time is not None
1692
+ else self._DEFAULT_MAX_WAIT_TIME
1693
+ ),
1694
+ )
1695
+
1696
+ # Step 4: Get the dataset version resource and return it with the prompt
1697
+ dataset_version_resource = self._get_dataset_version_resource(
1698
+ dataset_id=dataset_id,
1699
+ dataset_version_id=dataset_version_resource_name.split("/")[-1],
1700
+ )
1701
+ prompt = _prompt_management_utils._create_prompt_from_dataset_metadata(
1702
+ dataset_version_resource
1703
+ )
1704
+ prompt._dataset = dataset_resource
1705
+ prompt._dataset_version = dataset_version_resource
1706
+ return prompt
1707
+
1708
+ def _wait_for_operation(
1709
+ self,
1710
+ operation: types.DatasetOperation,
1711
+ timeout: int,
1712
+ max_wait_time: int = _DEFAULT_MAX_WAIT_TIME,
1713
+ ) -> str:
1714
+ """Waits for a dataset operation to complete.
1715
+
1716
+ Args:
1717
+ operation: The dataset operation to wait for.
1718
+ timeout: The maximum time to wait for the operation to complete.
1719
+ max_wait_time: The maximum interval between polling requests in seconds.
1720
+
1721
+ Returns:
1722
+ The name of the Dataset resource from the operation result.
1723
+
1724
+ Raises:
1725
+ TimeoutError: If the operation does not complete within the timeout.
1726
+ ValueError: If the operation fails.
1727
+ """
1728
+ done = False
1729
+ prompt_dataset_operation: Optional[types.DatasetOperation] = None
1730
+
1731
+ response_operation_name = operation.name
1732
+ if response_operation_name is None:
1733
+ raise ValueError("Invalid operation name.")
1734
+
1735
+ dataset_id = response_operation_name.split("/datasets/")[1].split("/")[0]
1736
+ operation_id = response_operation_name.split("/")[-1]
1737
+
1738
+ start_time = time.time()
1739
+ sleep_duration = 5
1740
+ wait_multiplier = 2
1741
+ previous_time = time.time()
1742
+
1743
+ while not done:
1744
+ if (time.time() - start_time) > timeout:
1745
+ raise TimeoutError(
1746
+ "Create prompt operation did not complete within the"
1747
+ f" specified timeout of {timeout} seconds."
1748
+ )
1749
+ current_time = time.time()
1750
+ if current_time - previous_time >= sleep_duration:
1751
+ sleep_duration = min(sleep_duration * wait_multiplier, max_wait_time)
1752
+ previous_time = current_time
1753
+ time.sleep(sleep_duration)
1754
+ prompt_dataset_operation = self._get_dataset_operation(
1755
+ dataset_id=dataset_id,
1756
+ operation_id=operation_id,
1757
+ )
1758
+ done = (
1759
+ (prompt_dataset_operation.done or False)
1760
+ if hasattr(prompt_dataset_operation, "done")
1761
+ else False
1762
+ )
1763
+ if (
1764
+ not prompt_dataset_operation
1765
+ or prompt_dataset_operation.response is None
1766
+ or prompt_dataset_operation.response.get("name") is None
1767
+ ):
1768
+ raise ValueError("Error creating prompt version resource.")
1769
+ if (
1770
+ hasattr(prompt_dataset_operation, "error")
1771
+ and prompt_dataset_operation.error is not None
1772
+ ):
1773
+ raise ValueError(
1774
+ f"Error creating prompt version resource: {prompt_dataset_operation.error}"
1775
+ )
1776
+ return prompt_dataset_operation.response.get("name") # type: ignore[return-value]
1777
+
1778
+ def get(
1779
+ self,
1780
+ *,
1781
+ prompt_id: str,
1782
+ config: Optional[types.GetPromptConfig] = None,
1783
+ ) -> types.Prompt:
1784
+ """Gets a prompt resource from a Vertex Dataset.
1785
+
1786
+ Args:
1787
+ prompt_id: The id of the Vertex Dataset resource containing the prompt. For example, if the prompt resource name is "projects/123/locations/us-central1/datasets/456", then the prompt_id is "456".
1788
+ config: Optional configuration for getting the prompt.
1789
+
1790
+ Returns:
1791
+ A types.Prompt object representing the prompt with its associated Dataset resources.
1792
+ """
1793
+
1794
+ prompt_dataset_resource = self._get_dataset_resource(name=prompt_id)
1795
+ prompt = _prompt_management_utils._create_prompt_from_dataset_metadata(
1796
+ prompt_dataset_resource,
1797
+ )
1798
+ prompt._dataset = prompt_dataset_resource
1799
+
1800
+ return prompt
1801
+
1802
+ def get_version(
1803
+ self,
1804
+ *,
1805
+ prompt_id: str,
1806
+ version_id: str,
1807
+ config: Optional[types.GetPromptConfig] = None,
1808
+ ) -> types.Prompt:
1809
+ """Gets a prompt resource from a Vertex Dataset.
1810
+
1811
+ Args:
1812
+ prompt_id: The id of the Vertex Dataset resource containing the prompt. For example, if the prompt resource name is "projects/123/locations/us-central1/datasets/456", then the prompt_id is "456".
1813
+ version_id: The id of the Vertex Dataset Version resource containing the prompt version. For example, if the prompt version resource name is "projects/123/locations/us-central1/datasets/456/datasetVersions/1", then the version_id is "1".
1814
+ config: Optional configuration for getting the prompt.
1815
+
1816
+ Returns:
1817
+ A types.Prompt object representing the prompt with its associated Dataset and Dataset Version resources.
1818
+ """
1819
+
1820
+ prompt_dataset_resource = self._get_dataset_resource(name=prompt_id)
1821
+ prompt = _prompt_management_utils._create_prompt_from_dataset_metadata(
1822
+ prompt_dataset_resource,
1823
+ )
1824
+ prompt._dataset = prompt_dataset_resource
1825
+
1826
+ prompt_version_resource = self._get_dataset_version_resource(
1827
+ dataset_id=prompt_id,
1828
+ dataset_version_id=version_id,
1829
+ )
1830
+ prompt._dataset_version = prompt_version_resource
1831
+
1832
+ return prompt
1833
+
1834
+ def _list_prompts_pager(
1835
+ self,
1836
+ *,
1837
+ config: Optional[types.ListPromptsConfigOrDict] = None,
1838
+ ) -> Pager[types.Dataset]:
1839
+ return Pager(
1840
+ "datasets",
1841
+ self._list_prompts,
1842
+ self._list_prompts(config=config),
1843
+ config,
1844
+ )
1845
+
1846
+ def _list_versions_pager(
1847
+ self,
1848
+ *,
1849
+ prompt_id: str,
1850
+ config: Optional[types.ListPromptsConfigOrDict] = None,
1851
+ ) -> Pager[types.DatasetVersion]:
1852
+ return Pager(
1853
+ "dataset_versions",
1854
+ self._list_versions,
1855
+ self._list_versions(config=config, dataset_id=prompt_id),
1856
+ config,
1857
+ )
1858
+
1859
+ def list(
1860
+ self,
1861
+ *,
1862
+ config: Optional[types.ListPromptsConfigOrDict] = None,
1863
+ ) -> Iterator[types.PromptRef]:
1864
+ """Lists prompt resources in a project.
1865
+
1866
+ This method retrieves all the prompts from the project provided in the
1867
+ agentplatform.Client constructor and returns a list of prompt references containing the prompt_id and model for the prompt.
1868
+
1869
+ To get the full types.Prompt resource for a PromptRef after calling this method, use the get() method with the prompt_id as the prompt_id argument.
1870
+ Example usage:
1871
+
1872
+ ```
1873
+ # Using an iterator
1874
+ prompt_refs = client.prompt_management.list_prompts()
1875
+ for prompt_ref in prompt_refs:
1876
+ client.prompt_management.get(prompt_id=prompt_ref.prompt_id)
1877
+
1878
+ # Using a list
1879
+ prompts_list = list(client.prompt_management.list_prompts())
1880
+ client.prompt_management.get(prompt_id=prompts_list[0].prompt_id)
1881
+ ```
1882
+
1883
+ Args:
1884
+ config: Optional configuration for listing prompts.
1885
+
1886
+ Returns:
1887
+ An iterable of types.PromptRef objects.
1888
+ """
1889
+ if isinstance(config, dict):
1890
+ config = types.ListPromptsConfig(**config)
1891
+ elif not config:
1892
+ config = types.ListPromptsConfig()
1893
+ for dataset in self._list_prompts_pager(config=config):
1894
+ if not dataset.name:
1895
+ continue
1896
+ prompt_ref = types.PromptRef(
1897
+ model=dataset.model_reference, prompt_id=dataset.name.split("/")[-1]
1898
+ )
1899
+ yield prompt_ref
1900
+
1901
+ def list_versions(
1902
+ self,
1903
+ *,
1904
+ prompt_id: str,
1905
+ config: Optional[types.ListPromptsConfigOrDict] = None,
1906
+ ) -> Iterator[types.PromptVersionRef]:
1907
+ """Lists prompt version resources for a provided prompt_id.
1908
+
1909
+ This method retrieves all the prompt versions for a provided prompt_id.
1910
+
1911
+ To get the full types.Prompt resource for a PromptVersionRef after calling this method, use the get() method with the returned prompt_id and version_id.
1912
+ Example usage:
1913
+
1914
+ ```
1915
+ # Using an iterator
1916
+ prompt_version_refs = client.prompt_management.list_versions(prompt_id="123")
1917
+ for version_ref in prompt_version_refs:
1918
+ client.prompt_management.get(prompt_id=version_ref.prompt_id, version_id=version_ref.version_id)
1919
+
1920
+ # Using a list
1921
+ prompt_versions_list = list(client.prompt_management.list_versions(prompt_id="123"))
1922
+ client.prompt_management.get(prompt_id=prompt_versions_list[0].prompt_id, version_id=prompt_versions_list[0].version_id)
1923
+ ```
1924
+
1925
+ Args:
1926
+ prompt_id: The id of the Vertex Dataset resource containing the prompt. For example, if the prompt resource name is "projects/123/locations/us-central1/datasets/456", then the prompt_id is "456".
1927
+ config: Optional configuration for listing prompts.
1928
+
1929
+ Returns:
1930
+ An iterable of types.PromptVersionRef objects representing the prompt version resources for the provided prompt_id.
1931
+
1932
+ """
1933
+ if isinstance(config, dict):
1934
+ config = types.ListPromptsConfig(**config)
1935
+ elif not config:
1936
+ config = types.ListPromptsConfig()
1937
+ for dataset_version in self._list_versions_pager(
1938
+ config=config, prompt_id=prompt_id
1939
+ ):
1940
+ if (
1941
+ not dataset_version
1942
+ or not dataset_version.model_reference
1943
+ or not dataset_version.name
1944
+ ):
1945
+ continue
1946
+ prompt_version_ref = types.PromptVersionRef(
1947
+ model=dataset_version.model_reference,
1948
+ version_id=dataset_version.name.split("/")[-1],
1949
+ prompt_id=prompt_id,
1950
+ )
1951
+ yield prompt_version_ref
1952
+
1953
+ def _wait_for_project_operation(
1954
+ self,
1955
+ operation: genai_types.ProjectOperation,
1956
+ timeout: int,
1957
+ max_wait_time: int = _DEFAULT_MAX_WAIT_TIME,
1958
+ ) -> None:
1959
+ """Waits for a dataset deletion operation to complete.
1960
+
1961
+ Delete operations are project level operations and are separate from dataset resource operations, for example: projects/123/locations/us-central1/operations/789.
1962
+
1963
+ Args:
1964
+ operation: The project operation to wait for.
1965
+ timeout: The maximum time to wait for the operation to complete.
1966
+ max_wait_time: The maximum interval between polling requests in seconds.
1967
+ Raises:
1968
+ TimeoutError: If the operation does not complete within the timeout.
1969
+ ValueError: If the operation fails.
1970
+ """
1971
+ done = False
1972
+
1973
+ start_time = time.time()
1974
+ sleep_duration = 5
1975
+ wait_multiplier = 2
1976
+ previous_time = time.time()
1977
+ while not done:
1978
+ if (time.time() - start_time) > timeout:
1979
+ raise TimeoutError(
1980
+ f"Delete operation did not complete within the"
1981
+ f" specified timeout of {timeout} seconds."
1982
+ )
1983
+ current_time = time.time()
1984
+ if current_time - previous_time >= sleep_duration:
1985
+ sleep_duration = min(sleep_duration * wait_multiplier, max_wait_time)
1986
+ previous_time = current_time
1987
+ time.sleep(sleep_duration)
1988
+ operations_module = operations.Operations(api_client_=self._api_client)
1989
+
1990
+ if operation.name is None:
1991
+ raise ValueError("Invalid operation name.")
1992
+ operation = operations_module._get(
1993
+ operation_id=operation.name.split("/")[-1],
1994
+ )
1995
+ done = (operation.done or False) if hasattr(operation, "done") else False
1996
+ if hasattr(operation, "error") and operation.error is not None:
1997
+ raise ValueError(f"Error in delete operation: {operation.error}")
1998
+
1999
+ def delete(
2000
+ self,
2001
+ *,
2002
+ prompt_id: str,
2003
+ config: Optional[types.DeletePromptConfig] = None,
2004
+ ) -> None:
2005
+ """Deletes a prompt resource.
2006
+
2007
+ Args:
2008
+ prompt_id: The id of the prompt resource to delete.
2009
+
2010
+ Raises:
2011
+ TimeoutError: If the delete operation does not complete within the timeout.
2012
+ ValueError: If the delete operation fails.
2013
+ """
2014
+
2015
+ delete_prompt_operation = self._delete_dataset(
2016
+ prompt_id=prompt_id,
2017
+ config=config,
2018
+ )
2019
+ self._wait_for_project_operation(
2020
+ operation=delete_prompt_operation,
2021
+ timeout=(
2022
+ config.timeout
2023
+ if config and config.timeout is not None
2024
+ else self._DEFAULT_TIMEOUT
2025
+ ),
2026
+ max_wait_time=(
2027
+ config.max_wait_time
2028
+ if config and config.max_wait_time is not None
2029
+ else self._DEFAULT_MAX_WAIT_TIME
2030
+ ),
2031
+ )
2032
+ logger.info(f"Deleted prompt with id: {prompt_id}")
2033
+
2034
+ def delete_version(
2035
+ self,
2036
+ *,
2037
+ prompt_id: str,
2038
+ version_id: str,
2039
+ config: Optional[types.DeletePromptConfig] = None,
2040
+ ) -> None:
2041
+ """Deletes a prompt version resource.
2042
+
2043
+ Args:
2044
+ prompt_id: The id of the prompt resource to delete.
2045
+ version_id: The id of the prompt version resource to delete.
2046
+
2047
+ Raises:
2048
+ TimeoutError: If the delete operation does not complete within the timeout.
2049
+ ValueError: If the delete operation fails.
2050
+ """
2051
+ delete_version_operation = self._delete_dataset_version(
2052
+ prompt_id=prompt_id,
2053
+ version_id=version_id,
2054
+ config=config,
2055
+ )
2056
+
2057
+ self._wait_for_project_operation(
2058
+ operation=delete_version_operation,
2059
+ timeout=(
2060
+ config.timeout
2061
+ if config and config.timeout is not None
2062
+ else self._DEFAULT_TIMEOUT
2063
+ ),
2064
+ max_wait_time=(
2065
+ config.max_wait_time
2066
+ if config and config.max_wait_time is not None
2067
+ else self._DEFAULT_MAX_WAIT_TIME
2068
+ ),
2069
+ )
2070
+ logger.info(
2071
+ f"Deleted prompt version {version_id} from prompt with id: {prompt_id}"
2072
+ )
2073
+
2074
+ def restore_version(
2075
+ self,
2076
+ *,
2077
+ prompt_id: str,
2078
+ version_id: str,
2079
+ config: Optional[types.RestoreVersionConfig] = None,
2080
+ ) -> types.Prompt:
2081
+ """Restores the provided prompt version to the latest version.
2082
+
2083
+ Args:
2084
+ prompt_id: The id of the Vertex Dataset resource containing the prompt. For example, if the prompt resource name is "projects/123/locations/us-central1/datasets/456", then the prompt_id is "456".
2085
+ version_id: The id of the Vertex Dataset Version resource to restore. For example, if the version resource name is "projects/123/locations/us-central1/datasets/456/datasetVersions/789", then the version_id is "789".
2086
+ config: Optional configuration for restoring the prompt version.
2087
+
2088
+ Returns:
2089
+ A types.Prompt object representing the prompt with the updated Dataset Version resource.
2090
+ """
2091
+
2092
+ restore_prompt_operation = self._restore_version(
2093
+ dataset_id=prompt_id,
2094
+ version_id=version_id,
2095
+ config=config,
2096
+ )
2097
+ self._wait_for_project_operation(
2098
+ operation=restore_prompt_operation,
2099
+ timeout=(
2100
+ config.timeout
2101
+ if config and config.timeout is not None
2102
+ else self._DEFAULT_TIMEOUT
2103
+ ),
2104
+ max_wait_time=(
2105
+ config.max_wait_time
2106
+ if config and config.max_wait_time is not None
2107
+ else self._DEFAULT_MAX_WAIT_TIME
2108
+ ),
2109
+ )
2110
+ dataset_version_resource = self._get_dataset_version_resource(
2111
+ dataset_id=prompt_id,
2112
+ dataset_version_id=version_id,
2113
+ )
2114
+ updated_prompt = _prompt_management_utils._create_prompt_from_dataset_metadata(
2115
+ dataset_version_resource,
2116
+ )
2117
+ updated_prompt._dataset_version = dataset_version_resource
2118
+ return updated_prompt
2119
+
2120
+ def _wait_for_completion(self, job_name: str) -> types.CustomJob:
2121
+
2122
+ JOB_COMPLETE_STATES = [
2123
+ genai_types.JobState.JOB_STATE_SUCCEEDED,
2124
+ genai_types.JobState.JOB_STATE_FAILED,
2125
+ genai_types.JobState.JOB_STATE_CANCELLED,
2126
+ genai_types.JobState.JOB_STATE_PAUSED,
2127
+ ]
2128
+ JOB_ERROR_STATES = [
2129
+ genai_types.JobState.JOB_STATE_FAILED,
2130
+ genai_types.JobState.JOB_STATE_CANCELLED,
2131
+ ]
2132
+
2133
+ log_wait = 5
2134
+ wait_multiplier = 2
2135
+ max_wait_time = self._DEFAULT_MAX_WAIT_TIME
2136
+ previous_time = time.time()
2137
+
2138
+ job = self._get_custom_job(name=job_name)
2139
+
2140
+ while job.state not in JOB_COMPLETE_STATES:
2141
+ current_time = time.time()
2142
+ if current_time - previous_time >= log_wait:
2143
+ logger.info(f"Waiting for job to complete. Current state: {job.state}")
2144
+ log_wait = min(log_wait * wait_multiplier, max_wait_time)
2145
+ previous_time = current_time
2146
+ time.sleep(log_wait)
2147
+ job = self._get_custom_job(name=job_name)
2148
+
2149
+ logger.info(f"Job state: {job.state}")
2150
+
2151
+ if job.state in JOB_ERROR_STATES:
2152
+ raise RuntimeError(f"Job failed with state: {job.state}")
2153
+ else:
2154
+ logger.info(f"Job completed with state: {job.state}")
2155
+ return job
2156
+
2157
+ @_common.experimental_warning(
2158
+ "The Vertex SDK GenAI prompts.launch_optimization_job method is "
2159
+ "experimental, and may change in future versions."
2160
+ )
2161
+ def launch_optimization_job(
2162
+ self,
2163
+ method: types.PromptOptimizerMethod,
2164
+ config: types.PromptOptimizerConfigOrDict,
2165
+ ) -> types.CustomJob:
2166
+ """Call PO-Data optimizer.
2167
+
2168
+ Args:
2169
+ method: The method for optimizing multiple prompts. Supported methods:
2170
+ VAPO, OPTIMIZATION_TARGET_GEMINI_NANO.
2171
+ config: PromptOptimizerConfig instance containing the
2172
+ configuration for prompt optimization.
2173
+ Returns:
2174
+ The custom job that was created.
2175
+ """
2176
+
2177
+ if isinstance(config, dict):
2178
+ config = types.PromptOptimizerConfig(**config)
2179
+
2180
+ if not config.config_path:
2181
+ raise ValueError("Config path is required.")
2182
+
2183
+ _OPTIMIZER_METHOD_TO_CONTAINER_URI = {
2184
+ types.PromptOptimizerMethod.VAPO: "us-docker.pkg.dev/vertex-ai/cair/vaipo:preview_v1_0",
2185
+ types.PromptOptimizerMethod.OPTIMIZATION_TARGET_GEMINI_NANO: "us-docker.pkg.dev/vertex-ai/cair/vaipo:preview_android_v1_0",
2186
+ }
2187
+ container_uri = _OPTIMIZER_METHOD_TO_CONTAINER_URI.get(method)
2188
+ if not container_uri:
2189
+ raise ValueError(
2190
+ 'Only "VAPO" and "OPTIMIZATION_TARGET_GEMINI_NANO" '
2191
+ "methods are currently supported."
2192
+ )
2193
+
2194
+ if config.optimizer_job_display_name:
2195
+ display_name = config.optimizer_job_display_name
2196
+ else:
2197
+ timestamp = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
2198
+ display_name = f"{method.value.lower()}-optimizer-{timestamp}"
2199
+
2200
+ wait_for_completion = config.wait_for_completion
2201
+ bucket = "/".join(config.config_path.split("/")[:-1])
2202
+
2203
+ region = self._api_client.location
2204
+ project = self._api_client.project
2205
+ container_args = {
2206
+ "config": config.config_path,
2207
+ }
2208
+ args = ["--%s=%s" % (k, v) for k, v in container_args.items()]
2209
+ worker_pool_specs = [
2210
+ types.WorkerPoolSpec(
2211
+ replica_count=1,
2212
+ machine_spec=types.MachineSpec(machine_type="n1-standard-4"),
2213
+ container_spec=types.ContainerSpec(
2214
+ image_uri=container_uri,
2215
+ args=args,
2216
+ ),
2217
+ )
2218
+ ]
2219
+
2220
+ service_account = _prompt_optimizer_utils._get_service_account(config)
2221
+
2222
+ job_spec = types.CustomJobSpec(
2223
+ worker_pool_specs=worker_pool_specs,
2224
+ base_output_directory=genai_types.GcsDestination(output_uri_prefix=bucket),
2225
+ service_account=service_account,
2226
+ )
2227
+
2228
+ custom_job = types.CustomJob(
2229
+ display_name=display_name,
2230
+ job_spec=job_spec,
2231
+ )
2232
+
2233
+ job = self._create_custom_job_resource(
2234
+ custom_job=custom_job,
2235
+ )
2236
+
2237
+ # Get the job resource name
2238
+ job_resource_name = job.name
2239
+ if not job_resource_name:
2240
+ raise ValueError(f"Error creating job: {job}")
2241
+ job_id = job_resource_name.split("/")[-1]
2242
+ logger.info("Job created: %s", job.name)
2243
+
2244
+ # Construct the dashboard URL
2245
+ dashboard_url = f"https://console.cloud.google.com/vertex-ai/locations/{region}/training/{job_id}/cpu?project={project}"
2246
+ logger.info("View the job status at: %s", dashboard_url)
2247
+
2248
+ if wait_for_completion:
2249
+ job = self._wait_for_completion(job_id)
2250
+ return job
2251
+
2252
+ @_common.experimental_warning(
2253
+ "The Vertex SDK GenAI prompts.optimize method is "
2254
+ "experimental, and may change in future versions."
2255
+ )
2256
+ def optimize(
2257
+ self,
2258
+ *,
2259
+ prompt: str,
2260
+ config: Optional[types.OptimizeConfigOrDict] = None,
2261
+ ) -> types.OptimizeResponse:
2262
+ """Makes an API request to optimize a prompt and returns the parsed response.
2263
+
2264
+ Example usage:
2265
+ client = agentplatform.Client(project=PROJECT_NAME, location='us-central1')
2266
+ prompt = "Generate system instructions for analyzing medical articles"
2267
+ response = client.prompts.optimize(prompt=prompt)
2268
+
2269
+ Args:
2270
+ prompt: Required. The prompt to optimize.
2271
+ config: Optional. The configuration for prompt optimization. To optimize
2272
+ prompts from Android API provide
2273
+ types.OptimizeConfig(
2274
+ optimization_target=types.OptimizeTarget.OPTIMIZATION_TARGET_GEMINI_NANO
2275
+ )
2276
+ For few-shot optimization, provide:
2277
+
2278
+ optim_target = types.OptimizeTarget.OPTIMIZATION_TARGET_FEW_SHOT_RUBRICS
2279
+ or
2280
+ optim_target = types.OptimizeTarget.OPTIMIZATION_TARGET_FEW_SHOT_TARGET_RESPONSE
2281
+ types.OptimizeConfig(
2282
+ optimization_target=optim_target,
2283
+ examples_dataframe=dataframe
2284
+ )
2285
+ OPTIMIZATION_TARGET_FEW_SHOT_RUBRICS indicates that the few-shot
2286
+ examples include specific scoring rubrics and their corresponding
2287
+ evaluations.
2288
+ OPTIMIZATION_TARGET_FEW_SHOT_TARGET_RESPONSE indicates that the few-shot
2289
+ examples include a ground-truth target response.
2290
+ Returns:
2291
+ The parsed response from the API request.
2292
+ """
2293
+
2294
+ if isinstance(config, dict):
2295
+ config = types.OptimizeConfig(**config)
2296
+
2297
+ optimization_target: Optional[types.OptimizeTarget] = None
2298
+ if config is not None:
2299
+ optimization_target = config.optimization_target
2300
+
2301
+ final_prompt = prompt
2302
+ if (
2303
+ optimization_target
2304
+ == types.OptimizeTarget.OPTIMIZATION_TARGET_FEW_SHOT_RUBRICS
2305
+ or optimization_target
2306
+ == types.OptimizeTarget.OPTIMIZATION_TARGET_FEW_SHOT_TARGET_RESPONSE
2307
+ ):
2308
+ final_prompt = _prompt_optimizer_utils._get_few_shot_prompt(prompt, config)
2309
+
2310
+ # TODO: b/435653980 - replace the custom method with a generated method.
2311
+ config_for_api = config.model_copy() if config else None
2312
+ return self._custom_optimize(
2313
+ content=genai_types.Content(
2314
+ parts=[genai_types.Part(text=final_prompt)], role="user"
2315
+ ),
2316
+ config=config_for_api,
2317
+ )
2318
+
2319
+ def _custom_optimize(
2320
+ self,
2321
+ *,
2322
+ content: Optional[genai_types.ContentOrDict] = None,
2323
+ config: Optional[types.OptimizeConfigOrDict] = None,
2324
+ ) -> types.OptimizeResponse:
2325
+ """Internal method to call the optimizePrompt endpoint.
2326
+
2327
+ Sends a request to the tuningJobs:optimizePrompt streaming endpoint.
2328
+ Then gathers the response, concatenates into one string and returns
2329
+ the parsed response.
2330
+ """
2331
+ if isinstance(config, dict):
2332
+ config.pop("examples_dataframe", None)
2333
+ elif config and hasattr(config, "examples_dataframe"):
2334
+ del config.examples_dataframe
2335
+
2336
+ parameter_model = types._OptimizeRequestParameters(
2337
+ content=content,
2338
+ config=config,
2339
+ )
2340
+ request_url_dict: Optional[dict[str, str]]
2341
+ if not self._api_client.vertexai:
2342
+ raise ValueError("This method is only supported in the Vertex AI client.")
2343
+ else:
2344
+ request_dict = _OptimizeRequestParameters_to_vertex(parameter_model)
2345
+ request_url_dict = request_dict.get("_url")
2346
+ if request_url_dict:
2347
+ path = "tuningJobs:optimizePrompt".format_map(request_url_dict)
2348
+ else:
2349
+ path = "tuningJobs:optimizePrompt"
2350
+
2351
+ query_params = request_dict.get("_query")
2352
+ if query_params:
2353
+ path = f"{path}?{urlencode(query_params)}"
2354
+ # TODO: remove the hack that pops config.
2355
+ request_dict.pop("config", None)
2356
+
2357
+ http_options: Optional[genai_types.HttpOptions] = None
2358
+ if (
2359
+ parameter_model.config is not None
2360
+ and parameter_model.config.http_options is not None
2361
+ ):
2362
+ http_options = parameter_model.config.http_options
2363
+
2364
+ request_dict = _common.convert_to_dict(request_dict)
2365
+ request_dict = _common.encode_unserializable_types(request_dict)
2366
+
2367
+ response = self._api_client.request("post", path, request_dict, http_options)
2368
+
2369
+ response_list = "" if not response.body else json.loads(response.body)
2370
+
2371
+ return_value = []
2372
+
2373
+ for response_dict in response_list:
2374
+ response_value = types.OptimizeResponseEndpoint._from_response(
2375
+ response=response_dict, kwargs=parameter_model.model_dump()
2376
+ )
2377
+ self._api_client._verify_response(response_value)
2378
+ content = response_value.content
2379
+ if content is not None:
2380
+ parts = content.parts
2381
+ if parts and parts[0].text is not None:
2382
+ return_value.append(parts[0].text)
2383
+
2384
+ output = "".join(return_value)
2385
+ final_response = types.OptimizeResponse(raw_text_response=output)
2386
+ try:
2387
+ final_response.parsed_response = _prompt_optimizer_utils._parse(output)
2388
+ except (ValueError, TypeError, ValidationError) as e:
2389
+ logger.warning(
2390
+ f"Failed to parse response: {e}. Returning only raw_text_response."
2391
+ )
2392
+ return final_response
2393
+
2394
+ def update(
2395
+ self,
2396
+ *,
2397
+ prompt_id: str,
2398
+ prompt: types.PromptOrDict,
2399
+ config: Optional[types.UpdatePromptConfigOrDict] = None,
2400
+ ) -> types.Prompt:
2401
+ """Updates an existing prompt and creates a new version for the prompt associated with the provided prompt_id.
2402
+
2403
+ Args:
2404
+ prompt_id: The ID of the prompt to create a new version for.
2405
+ prompt: The updated prompt.
2406
+ config: Optional configuration for updating the prompt.
2407
+
2408
+ Returns:
2409
+ A types.Prompt object representing the updated prompt with its associated
2410
+ Dataset and Dataset Version resources.
2411
+ """
2412
+
2413
+ if isinstance(prompt, dict):
2414
+ prompt = types.Prompt(**prompt)
2415
+ if isinstance(config, dict):
2416
+ config = types.UpdatePromptConfig(**config)
2417
+ elif not config:
2418
+ config = types.UpdatePromptConfig()
2419
+
2420
+ prompt_metadata = _prompt_management_utils._create_dataset_metadata_from_prompt(
2421
+ prompt,
2422
+ variables=(
2423
+ prompt.prompt_data.variables
2424
+ if prompt.prompt_data and prompt.prompt_data.variables
2425
+ else None
2426
+ ),
2427
+ )
2428
+
2429
+ if not prompt.prompt_data:
2430
+ raise ValueError("Prompt data is required to update a prompt.")
2431
+
2432
+ # Step 1: Update the dataset resource for the prompt and wait for the operation to complete.
2433
+ updated_dataset_resource = self._update_dataset_resource(
2434
+ name=f"projects/{self._api_client.project}/locations/{self._api_client.location}/datasets/{prompt_id}",
2435
+ dataset_id=prompt_id,
2436
+ display_name=(
2437
+ config.prompt_display_name
2438
+ if config and config.prompt_display_name
2439
+ else None
2440
+ ),
2441
+ metadata=prompt_metadata,
2442
+ model_reference=prompt.prompt_data.model,
2443
+ encryption_spec=(
2444
+ config.encryption_spec if config and config.encryption_spec else None
2445
+ ),
2446
+ config=config,
2447
+ )
2448
+
2449
+ if not updated_dataset_resource.name:
2450
+ raise ValueError("Failed to update dataset resource.")
2451
+
2452
+ dataset_id = updated_dataset_resource.name.split("/")[-1]
2453
+
2454
+ # Step 2: Create a dataset version for the prompt.
2455
+ create_dataset_version_operation = self._create_dataset_version_resource(
2456
+ dataset_name=dataset_id,
2457
+ display_name=(
2458
+ config.version_display_name
2459
+ if config and config.version_display_name is not None
2460
+ else f"prompt_version_{time.strftime('%Y%m%d-%H%M%S')}"
2461
+ ),
2462
+ )
2463
+ dataset_version_resource_name = self._wait_for_operation(
2464
+ operation=create_dataset_version_operation,
2465
+ timeout=(
2466
+ config.timeout
2467
+ if config and config.timeout is not None
2468
+ else self._DEFAULT_TIMEOUT
2469
+ ),
2470
+ max_wait_time=(
2471
+ config.max_wait_time
2472
+ if config and config.max_wait_time is not None
2473
+ else self._DEFAULT_MAX_WAIT_TIME
2474
+ ),
2475
+ )
2476
+ dataset_version_id = dataset_version_resource_name.split("/")[-1]
2477
+
2478
+ # Step 3: Get the dataset version resource and return it with the prompt.
2479
+ dataset_version_resource = self._get_dataset_version_resource(
2480
+ dataset_id=dataset_id,
2481
+ dataset_version_id=dataset_version_id,
2482
+ )
2483
+ prompt = _prompt_management_utils._create_prompt_from_dataset_metadata(
2484
+ dataset_version_resource
2485
+ )
2486
+ prompt._dataset = updated_dataset_resource
2487
+ prompt._dataset_version = dataset_version_resource
2488
+ return prompt
2489
+
2490
+
2491
+ class AsyncPrompts(_api_module.BaseModule):
2492
+
2493
+ async def _create_dataset_resource(
2494
+ self,
2495
+ *,
2496
+ name: Optional[str] = None,
2497
+ display_name: Optional[str] = None,
2498
+ metadata_schema_uri: Optional[str] = None,
2499
+ metadata: Optional[types.SchemaTextPromptDatasetMetadataOrDict] = None,
2500
+ description: Optional[str] = None,
2501
+ encryption_spec: Optional[genai_types.EncryptionSpecOrDict] = None,
2502
+ model_reference: Optional[str] = None,
2503
+ config: Optional[types.CreateDatasetConfigOrDict] = None,
2504
+ ) -> types.DatasetOperation:
2505
+ """
2506
+ Creates a dataset resource to store prompts.
2507
+ """
2508
+
2509
+ parameter_model = types._CreateDatasetParameters(
2510
+ name=name,
2511
+ display_name=display_name,
2512
+ metadata_schema_uri=metadata_schema_uri,
2513
+ metadata=metadata,
2514
+ description=description,
2515
+ encryption_spec=encryption_spec,
2516
+ model_reference=model_reference,
2517
+ config=config,
2518
+ )
2519
+
2520
+ request_url_dict: Optional[dict[str, str]]
2521
+ if not self._api_client.vertexai:
2522
+ raise ValueError(
2523
+ "This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
2524
+ )
2525
+ else:
2526
+ request_dict = _CreateDatasetParameters_to_vertex(parameter_model)
2527
+ request_url_dict = request_dict.get("_url")
2528
+ if request_url_dict:
2529
+ path = "datasets".format_map(request_url_dict)
2530
+ else:
2531
+ path = "datasets"
2532
+
2533
+ query_params = request_dict.get("_query")
2534
+ if query_params:
2535
+ path = f"{path}?{urlencode(query_params)}"
2536
+ # TODO: remove the hack that pops config.
2537
+ request_dict.pop("config", None)
2538
+
2539
+ http_options: Optional[types.HttpOptions] = None
2540
+ if (
2541
+ parameter_model.config is not None
2542
+ and parameter_model.config.http_options is not None
2543
+ ):
2544
+ http_options = parameter_model.config.http_options
2545
+
2546
+ request_dict = _common.convert_to_dict(request_dict)
2547
+ request_dict = _common.encode_unserializable_types(request_dict)
2548
+
2549
+ response = await self._api_client.async_request(
2550
+ "post", path, request_dict, http_options
2551
+ )
2552
+
2553
+ response_dict = {} if not response.body else json.loads(response.body)
2554
+
2555
+ return_value = types.DatasetOperation._from_response(
2556
+ response=response_dict,
2557
+ kwargs=(
2558
+ {
2559
+ "config": {
2560
+ "response_schema": getattr(
2561
+ parameter_model.config, "response_schema", None
2562
+ ),
2563
+ "response_json_schema": getattr(
2564
+ parameter_model.config, "response_json_schema", None
2565
+ ),
2566
+ "include_all_fields": getattr(
2567
+ parameter_model.config, "include_all_fields", None
2568
+ ),
2569
+ }
2570
+ }
2571
+ if getattr(parameter_model, "config", None)
2572
+ else {}
2573
+ ),
2574
+ )
2575
+
2576
+ self._api_client._verify_response(return_value)
2577
+ return return_value
2578
+
2579
+ async def _create_dataset_version_resource(
2580
+ self,
2581
+ *,
2582
+ dataset_name: Optional[str] = None,
2583
+ metadata: Optional[types.SchemaTextPromptDatasetMetadataOrDict] = None,
2584
+ model_reference: Optional[str] = None,
2585
+ parent: Optional[str] = None,
2586
+ display_name: Optional[str] = None,
2587
+ config: Optional[types.CreateDatasetVersionConfigOrDict] = None,
2588
+ ) -> types.DatasetOperation:
2589
+ """
2590
+ Creates a dataset version resource to store prompts.
2591
+ """
2592
+
2593
+ parameter_model = types._CreateDatasetVersionParameters(
2594
+ dataset_name=dataset_name,
2595
+ metadata=metadata,
2596
+ model_reference=model_reference,
2597
+ parent=parent,
2598
+ display_name=display_name,
2599
+ config=config,
2600
+ )
2601
+
2602
+ request_url_dict: Optional[dict[str, str]]
2603
+ if not self._api_client.vertexai:
2604
+ raise ValueError(
2605
+ "This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
2606
+ )
2607
+ else:
2608
+ request_dict = _CreateDatasetVersionParameters_to_vertex(parameter_model)
2609
+ request_url_dict = request_dict.get("_url")
2610
+ if request_url_dict:
2611
+ path = "datasets/{name}/datasetVersions".format_map(request_url_dict)
2612
+ else:
2613
+ path = "datasets/{name}/datasetVersions"
2614
+
2615
+ query_params = request_dict.get("_query")
2616
+ if query_params:
2617
+ path = f"{path}?{urlencode(query_params)}"
2618
+ # TODO: remove the hack that pops config.
2619
+ request_dict.pop("config", None)
2620
+
2621
+ http_options: Optional[types.HttpOptions] = None
2622
+ if (
2623
+ parameter_model.config is not None
2624
+ and parameter_model.config.http_options is not None
2625
+ ):
2626
+ http_options = parameter_model.config.http_options
2627
+
2628
+ request_dict = _common.convert_to_dict(request_dict)
2629
+ request_dict = _common.encode_unserializable_types(request_dict)
2630
+
2631
+ response = await self._api_client.async_request(
2632
+ "post", path, request_dict, http_options
2633
+ )
2634
+
2635
+ response_dict = {} if not response.body else json.loads(response.body)
2636
+
2637
+ return_value = types.DatasetOperation._from_response(
2638
+ response=response_dict,
2639
+ kwargs=(
2640
+ {
2641
+ "config": {
2642
+ "response_schema": getattr(
2643
+ parameter_model.config, "response_schema", None
2644
+ ),
2645
+ "response_json_schema": getattr(
2646
+ parameter_model.config, "response_json_schema", None
2647
+ ),
2648
+ "include_all_fields": getattr(
2649
+ parameter_model.config, "include_all_fields", None
2650
+ ),
2651
+ }
2652
+ }
2653
+ if getattr(parameter_model, "config", None)
2654
+ else {}
2655
+ ),
2656
+ )
2657
+
2658
+ self._api_client._verify_response(return_value)
2659
+ return return_value
2660
+
2661
+ async def _get_dataset_resource(
2662
+ self,
2663
+ *,
2664
+ name: Optional[str] = None,
2665
+ config: Optional[types.VertexBaseConfigOrDict] = None,
2666
+ ) -> types.Dataset:
2667
+ """
2668
+ Gets a dataset resource to store prompts.
2669
+ """
2670
+
2671
+ parameter_model = types._GetDatasetParameters(
2672
+ name=name,
2673
+ config=config,
2674
+ )
2675
+
2676
+ request_url_dict: Optional[dict[str, str]]
2677
+ if not self._api_client.vertexai:
2678
+ raise ValueError(
2679
+ "This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
2680
+ )
2681
+ else:
2682
+ request_dict = _GetDatasetParameters_to_vertex(parameter_model)
2683
+ request_url_dict = request_dict.get("_url")
2684
+ if request_url_dict:
2685
+ path = "datasets/{name}".format_map(request_url_dict)
2686
+ else:
2687
+ path = "datasets/{name}"
2688
+
2689
+ query_params = request_dict.get("_query")
2690
+ if query_params:
2691
+ path = f"{path}?{urlencode(query_params)}"
2692
+ # TODO: remove the hack that pops config.
2693
+ request_dict.pop("config", None)
2694
+
2695
+ http_options: Optional[types.HttpOptions] = None
2696
+ if (
2697
+ parameter_model.config is not None
2698
+ and parameter_model.config.http_options is not None
2699
+ ):
2700
+ http_options = parameter_model.config.http_options
2701
+
2702
+ request_dict = _common.convert_to_dict(request_dict)
2703
+ request_dict = _common.encode_unserializable_types(request_dict)
2704
+
2705
+ response = await self._api_client.async_request(
2706
+ "get", path, request_dict, http_options
2707
+ )
2708
+
2709
+ response_dict = {} if not response.body else json.loads(response.body)
2710
+
2711
+ return_value = types.Dataset._from_response(
2712
+ response=response_dict,
2713
+ kwargs=(
2714
+ {
2715
+ "config": {
2716
+ "response_schema": getattr(
2717
+ parameter_model.config, "response_schema", None
2718
+ ),
2719
+ "response_json_schema": getattr(
2720
+ parameter_model.config, "response_json_schema", None
2721
+ ),
2722
+ "include_all_fields": getattr(
2723
+ parameter_model.config, "include_all_fields", None
2724
+ ),
2725
+ }
2726
+ }
2727
+ if getattr(parameter_model, "config", None)
2728
+ else {}
2729
+ ),
2730
+ )
2731
+
2732
+ self._api_client._verify_response(return_value)
2733
+ return return_value
2734
+
2735
+ async def _get_dataset_version_resource(
2736
+ self,
2737
+ *,
2738
+ dataset_id: Optional[str] = None,
2739
+ dataset_version_id: Optional[str] = None,
2740
+ config: Optional[types.VertexBaseConfigOrDict] = None,
2741
+ ) -> types.DatasetVersion:
2742
+ """
2743
+ Gets a dataset version resource to store prompts.
2744
+ """
2745
+
2746
+ parameter_model = types._GetDatasetVersionParameters(
2747
+ dataset_id=dataset_id,
2748
+ dataset_version_id=dataset_version_id,
2749
+ config=config,
2750
+ )
2751
+
2752
+ request_url_dict: Optional[dict[str, str]]
2753
+ if not self._api_client.vertexai:
2754
+ raise ValueError(
2755
+ "This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
2756
+ )
2757
+ else:
2758
+ request_dict = _GetDatasetVersionParameters_to_vertex(parameter_model)
2759
+ request_url_dict = request_dict.get("_url")
2760
+ if request_url_dict:
2761
+ path = "datasets/{dataset_id}/datasetVersions/{dataset_version_id}".format_map(
2762
+ request_url_dict
2763
+ )
2764
+ else:
2765
+ path = "datasets/{dataset_id}/datasetVersions/{dataset_version_id}"
2766
+
2767
+ query_params = request_dict.get("_query")
2768
+ if query_params:
2769
+ path = f"{path}?{urlencode(query_params)}"
2770
+ # TODO: remove the hack that pops config.
2771
+ request_dict.pop("config", None)
2772
+
2773
+ http_options: Optional[types.HttpOptions] = None
2774
+ if (
2775
+ parameter_model.config is not None
2776
+ and parameter_model.config.http_options is not None
2777
+ ):
2778
+ http_options = parameter_model.config.http_options
2779
+
2780
+ request_dict = _common.convert_to_dict(request_dict)
2781
+ request_dict = _common.encode_unserializable_types(request_dict)
2782
+
2783
+ response = await self._api_client.async_request(
2784
+ "get", path, request_dict, http_options
2785
+ )
2786
+
2787
+ response_dict = {} if not response.body else json.loads(response.body)
2788
+
2789
+ return_value = types.DatasetVersion._from_response(
2790
+ response=response_dict,
2791
+ kwargs=(
2792
+ {
2793
+ "config": {
2794
+ "response_schema": getattr(
2795
+ parameter_model.config, "response_schema", None
2796
+ ),
2797
+ "response_json_schema": getattr(
2798
+ parameter_model.config, "response_json_schema", None
2799
+ ),
2800
+ "include_all_fields": getattr(
2801
+ parameter_model.config, "include_all_fields", None
2802
+ ),
2803
+ }
2804
+ }
2805
+ if getattr(parameter_model, "config", None)
2806
+ else {}
2807
+ ),
2808
+ )
2809
+
2810
+ self._api_client._verify_response(return_value)
2811
+ return return_value
2812
+
2813
+ async def _get_dataset_operation(
2814
+ self,
2815
+ *,
2816
+ dataset_id: Optional[str] = None,
2817
+ operation_id: Optional[str] = None,
2818
+ config: Optional[types.GetDatasetOperationConfigOrDict] = None,
2819
+ ) -> types.DatasetOperation:
2820
+ """
2821
+ Gets the operation from creating a dataset.
2822
+ """
2823
+
2824
+ parameter_model = types._GetDatasetOperationParameters(
2825
+ dataset_id=dataset_id,
2826
+ operation_id=operation_id,
2827
+ config=config,
2828
+ )
2829
+
2830
+ request_url_dict: Optional[dict[str, str]]
2831
+ if not self._api_client.vertexai:
2832
+ raise ValueError(
2833
+ "This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
2834
+ )
2835
+ else:
2836
+ request_dict = _GetDatasetOperationParameters_to_vertex(parameter_model)
2837
+ request_url_dict = request_dict.get("_url")
2838
+ if request_url_dict:
2839
+ path = "datasets/{dataset_id}/operations/{operation_id}".format_map(
2840
+ request_url_dict
2841
+ )
2842
+ else:
2843
+ path = "datasets/{dataset_id}/operations/{operation_id}"
2844
+
2845
+ query_params = request_dict.get("_query")
2846
+ if query_params:
2847
+ path = f"{path}?{urlencode(query_params)}"
2848
+ # TODO: remove the hack that pops config.
2849
+ request_dict.pop("config", None)
2850
+
2851
+ http_options: Optional[types.HttpOptions] = None
2852
+ if (
2853
+ parameter_model.config is not None
2854
+ and parameter_model.config.http_options is not None
2855
+ ):
2856
+ http_options = parameter_model.config.http_options
2857
+
2858
+ request_dict = _common.convert_to_dict(request_dict)
2859
+ request_dict = _common.encode_unserializable_types(request_dict)
2860
+
2861
+ response = await self._api_client.async_request(
2862
+ "get", path, request_dict, http_options
2863
+ )
2864
+
2865
+ response_dict = {} if not response.body else json.loads(response.body)
2866
+
2867
+ return_value = types.DatasetOperation._from_response(
2868
+ response=response_dict,
2869
+ kwargs=(
2870
+ {
2871
+ "config": {
2872
+ "response_schema": getattr(
2873
+ parameter_model.config, "response_schema", None
2874
+ ),
2875
+ "response_json_schema": getattr(
2876
+ parameter_model.config, "response_json_schema", None
2877
+ ),
2878
+ "include_all_fields": getattr(
2879
+ parameter_model.config, "include_all_fields", None
2880
+ ),
2881
+ }
2882
+ }
2883
+ if getattr(parameter_model, "config", None)
2884
+ else {}
2885
+ ),
2886
+ )
2887
+
2888
+ self._api_client._verify_response(return_value)
2889
+ return return_value
2890
+
2891
+ async def _list_prompts(
2892
+ self, *, config: Optional[types.ListPromptsConfigOrDict] = None
2893
+ ) -> types.ListDatasetsResponse:
2894
+ """
2895
+ Lists Agent Engines.
2896
+ """
2897
+
2898
+ parameter_model = types._ListDatasetsRequestParameters(
2899
+ config=config,
2900
+ )
2901
+
2902
+ request_url_dict: Optional[dict[str, str]]
2903
+ if not self._api_client.vertexai:
2904
+ raise ValueError(
2905
+ "This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
2906
+ )
2907
+ else:
2908
+ request_dict = _ListDatasetsRequestParameters_to_vertex(parameter_model)
2909
+ request_url_dict = request_dict.get("_url")
2910
+ if request_url_dict:
2911
+ path = "datasets".format_map(request_url_dict)
2912
+ else:
2913
+ path = "datasets"
2914
+
2915
+ query_params = request_dict.get("_query")
2916
+ if query_params:
2917
+ path = f"{path}?{urlencode(query_params)}"
2918
+ # TODO: remove the hack that pops config.
2919
+ request_dict.pop("config", None)
2920
+
2921
+ http_options: Optional[types.HttpOptions] = None
2922
+ if (
2923
+ parameter_model.config is not None
2924
+ and parameter_model.config.http_options is not None
2925
+ ):
2926
+ http_options = parameter_model.config.http_options
2927
+
2928
+ request_dict = _common.convert_to_dict(request_dict)
2929
+ request_dict = _common.encode_unserializable_types(request_dict)
2930
+
2931
+ response = await self._api_client.async_request(
2932
+ "get", path, request_dict, http_options
2933
+ )
2934
+
2935
+ response_dict = {} if not response.body else json.loads(response.body)
2936
+
2937
+ return_value = types.ListDatasetsResponse._from_response(
2938
+ response=response_dict,
2939
+ kwargs=(
2940
+ {
2941
+ "config": {
2942
+ "response_schema": getattr(
2943
+ parameter_model.config, "response_schema", None
2944
+ ),
2945
+ "response_json_schema": getattr(
2946
+ parameter_model.config, "response_json_schema", None
2947
+ ),
2948
+ "include_all_fields": getattr(
2949
+ parameter_model.config, "include_all_fields", None
2950
+ ),
2951
+ }
2952
+ }
2953
+ if getattr(parameter_model, "config", None)
2954
+ else {}
2955
+ ),
2956
+ )
2957
+
2958
+ self._api_client._verify_response(return_value)
2959
+ return return_value
2960
+
2961
+ async def _list_versions(
2962
+ self,
2963
+ *,
2964
+ read_mask: Optional[str] = None,
2965
+ dataset_id: Optional[str] = None,
2966
+ config: Optional[types.ListPromptsConfigOrDict] = None,
2967
+ ) -> types.ListDatasetVersionsResponse:
2968
+ """
2969
+ Lists Agent Engines.
2970
+ """
2971
+
2972
+ parameter_model = types._ListDatasetVersionsRequestParameters(
2973
+ read_mask=read_mask,
2974
+ dataset_id=dataset_id,
2975
+ config=config,
2976
+ )
2977
+
2978
+ request_url_dict: Optional[dict[str, str]]
2979
+ if not self._api_client.vertexai:
2980
+ raise ValueError(
2981
+ "This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
2982
+ )
2983
+ else:
2984
+ request_dict = _ListDatasetVersionsRequestParameters_to_vertex(
2985
+ parameter_model
2986
+ )
2987
+ request_url_dict = request_dict.get("_url")
2988
+ if request_url_dict:
2989
+ path = "datasets/{dataset_id}/datasetVersions".format_map(
2990
+ request_url_dict
2991
+ )
2992
+ else:
2993
+ path = "datasets/{dataset_id}/datasetVersions"
2994
+
2995
+ query_params = request_dict.get("_query")
2996
+ if query_params:
2997
+ path = f"{path}?{urlencode(query_params)}"
2998
+ # TODO: remove the hack that pops config.
2999
+ request_dict.pop("config", None)
3000
+
3001
+ http_options: Optional[types.HttpOptions] = None
3002
+ if (
3003
+ parameter_model.config is not None
3004
+ and parameter_model.config.http_options is not None
3005
+ ):
3006
+ http_options = parameter_model.config.http_options
3007
+
3008
+ request_dict = _common.convert_to_dict(request_dict)
3009
+ request_dict = _common.encode_unserializable_types(request_dict)
3010
+
3011
+ response = await self._api_client.async_request(
3012
+ "get", path, request_dict, http_options
3013
+ )
3014
+
3015
+ response_dict = {} if not response.body else json.loads(response.body)
3016
+
3017
+ return_value = types.ListDatasetVersionsResponse._from_response(
3018
+ response=response_dict,
3019
+ kwargs=(
3020
+ {
3021
+ "config": {
3022
+ "response_schema": getattr(
3023
+ parameter_model.config, "response_schema", None
3024
+ ),
3025
+ "response_json_schema": getattr(
3026
+ parameter_model.config, "response_json_schema", None
3027
+ ),
3028
+ "include_all_fields": getattr(
3029
+ parameter_model.config, "include_all_fields", None
3030
+ ),
3031
+ }
3032
+ }
3033
+ if getattr(parameter_model, "config", None)
3034
+ else {}
3035
+ ),
3036
+ )
3037
+
3038
+ self._api_client._verify_response(return_value)
3039
+ return return_value
3040
+
3041
+ async def _delete_dataset(
3042
+ self, *, prompt_id: str, config: Optional[types.DeletePromptConfigOrDict] = None
3043
+ ) -> types.DeletePromptOperation:
3044
+ parameter_model = types._DeleteDatasetRequestParameters(
3045
+ prompt_id=prompt_id,
3046
+ config=config,
3047
+ )
3048
+
3049
+ request_url_dict: Optional[dict[str, str]]
3050
+ if not self._api_client.vertexai:
3051
+ raise ValueError(
3052
+ "This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
3053
+ )
3054
+ else:
3055
+ request_dict = _DeleteDatasetRequestParameters_to_vertex(parameter_model)
3056
+ request_url_dict = request_dict.get("_url")
3057
+ if request_url_dict:
3058
+ path = "datasets/{dataset_id}".format_map(request_url_dict)
3059
+ else:
3060
+ path = "datasets/{dataset_id}"
3061
+
3062
+ query_params = request_dict.get("_query")
3063
+ if query_params:
3064
+ path = f"{path}?{urlencode(query_params)}"
3065
+ # TODO: remove the hack that pops config.
3066
+ request_dict.pop("config", None)
3067
+
3068
+ http_options: Optional[types.HttpOptions] = None
3069
+ if (
3070
+ parameter_model.config is not None
3071
+ and parameter_model.config.http_options is not None
3072
+ ):
3073
+ http_options = parameter_model.config.http_options
3074
+
3075
+ request_dict = _common.convert_to_dict(request_dict)
3076
+ request_dict = _common.encode_unserializable_types(request_dict)
3077
+
3078
+ response = await self._api_client.async_request(
3079
+ "delete", path, request_dict, http_options
3080
+ )
3081
+
3082
+ response_dict = {} if not response.body else json.loads(response.body)
3083
+
3084
+ return_value = types.DeletePromptOperation._from_response(
3085
+ response=response_dict,
3086
+ kwargs=(
3087
+ {
3088
+ "config": {
3089
+ "response_schema": getattr(
3090
+ parameter_model.config, "response_schema", None
3091
+ ),
3092
+ "response_json_schema": getattr(
3093
+ parameter_model.config, "response_json_schema", None
3094
+ ),
3095
+ "include_all_fields": getattr(
3096
+ parameter_model.config, "include_all_fields", None
3097
+ ),
3098
+ }
3099
+ }
3100
+ if getattr(parameter_model, "config", None)
3101
+ else {}
3102
+ ),
3103
+ )
3104
+
3105
+ self._api_client._verify_response(return_value)
3106
+ return return_value
3107
+
3108
+ async def _delete_dataset_version(
3109
+ self,
3110
+ *,
3111
+ prompt_id: str,
3112
+ version_id: str,
3113
+ config: Optional[types.DeletePromptConfigOrDict] = None,
3114
+ ) -> types.DeletePromptVersionOperation:
3115
+ parameter_model = types._DeletePromptVersionRequestParameters(
3116
+ prompt_id=prompt_id,
3117
+ version_id=version_id,
3118
+ config=config,
3119
+ )
3120
+
3121
+ request_url_dict: Optional[dict[str, str]]
3122
+ if not self._api_client.vertexai:
3123
+ raise ValueError(
3124
+ "This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
3125
+ )
3126
+ else:
3127
+ request_dict = _DeletePromptVersionRequestParameters_to_vertex(
3128
+ parameter_model
3129
+ )
3130
+ request_url_dict = request_dict.get("_url")
3131
+ if request_url_dict:
3132
+ path = "datasets/{dataset_id}/datasetVersions/{version_id}".format_map(
3133
+ request_url_dict
3134
+ )
3135
+ else:
3136
+ path = "datasets/{dataset_id}/datasetVersions/{version_id}"
3137
+
3138
+ query_params = request_dict.get("_query")
3139
+ if query_params:
3140
+ path = f"{path}?{urlencode(query_params)}"
3141
+ # TODO: remove the hack that pops config.
3142
+ request_dict.pop("config", None)
3143
+
3144
+ http_options: Optional[types.HttpOptions] = None
3145
+ if (
3146
+ parameter_model.config is not None
3147
+ and parameter_model.config.http_options is not None
3148
+ ):
3149
+ http_options = parameter_model.config.http_options
3150
+
3151
+ request_dict = _common.convert_to_dict(request_dict)
3152
+ request_dict = _common.encode_unserializable_types(request_dict)
3153
+
3154
+ response = await self._api_client.async_request(
3155
+ "delete", path, request_dict, http_options
3156
+ )
3157
+
3158
+ response_dict = {} if not response.body else json.loads(response.body)
3159
+
3160
+ return_value = types.DeletePromptVersionOperation._from_response(
3161
+ response=response_dict,
3162
+ kwargs=(
3163
+ {
3164
+ "config": {
3165
+ "response_schema": getattr(
3166
+ parameter_model.config, "response_schema", None
3167
+ ),
3168
+ "response_json_schema": getattr(
3169
+ parameter_model.config, "response_json_schema", None
3170
+ ),
3171
+ "include_all_fields": getattr(
3172
+ parameter_model.config, "include_all_fields", None
3173
+ ),
3174
+ }
3175
+ }
3176
+ if getattr(parameter_model, "config", None)
3177
+ else {}
3178
+ ),
3179
+ )
3180
+
3181
+ self._api_client._verify_response(return_value)
3182
+ return return_value
3183
+
3184
+ async def _restore_version(
3185
+ self,
3186
+ *,
3187
+ dataset_id: str,
3188
+ version_id: str,
3189
+ config: Optional[types.RestoreVersionConfigOrDict] = None,
3190
+ ) -> types.RestoreVersionOperation:
3191
+ """
3192
+ Restores the provided prompt version to the latest version.
3193
+ """
3194
+
3195
+ parameter_model = types._RestoreVersionRequestParameters(
3196
+ dataset_id=dataset_id,
3197
+ version_id=version_id,
3198
+ config=config,
3199
+ )
3200
+
3201
+ request_url_dict: Optional[dict[str, str]]
3202
+ if not self._api_client.vertexai:
3203
+ raise ValueError(
3204
+ "This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
3205
+ )
3206
+ else:
3207
+ request_dict = _RestoreVersionRequestParameters_to_vertex(parameter_model)
3208
+ request_url_dict = request_dict.get("_url")
3209
+ if request_url_dict:
3210
+ path = "datasets/{dataset_id}/datasetVersions/{version_id}:restore".format_map(
3211
+ request_url_dict
3212
+ )
3213
+ else:
3214
+ path = "datasets/{dataset_id}/datasetVersions/{version_id}:restore"
3215
+
3216
+ query_params = request_dict.get("_query")
3217
+ if query_params:
3218
+ path = f"{path}?{urlencode(query_params)}"
3219
+ # TODO: remove the hack that pops config.
3220
+ request_dict.pop("config", None)
3221
+
3222
+ http_options: Optional[types.HttpOptions] = None
3223
+ if (
3224
+ parameter_model.config is not None
3225
+ and parameter_model.config.http_options is not None
3226
+ ):
3227
+ http_options = parameter_model.config.http_options
3228
+
3229
+ request_dict = _common.convert_to_dict(request_dict)
3230
+ request_dict = _common.encode_unserializable_types(request_dict)
3231
+
3232
+ response = await self._api_client.async_request(
3233
+ "get", path, request_dict, http_options
3234
+ )
3235
+
3236
+ response_dict = {} if not response.body else json.loads(response.body)
3237
+
3238
+ return_value = types.RestoreVersionOperation._from_response(
3239
+ response=response_dict,
3240
+ kwargs=(
3241
+ {
3242
+ "config": {
3243
+ "response_schema": getattr(
3244
+ parameter_model.config, "response_schema", None
3245
+ ),
3246
+ "response_json_schema": getattr(
3247
+ parameter_model.config, "response_json_schema", None
3248
+ ),
3249
+ "include_all_fields": getattr(
3250
+ parameter_model.config, "include_all_fields", None
3251
+ ),
3252
+ }
3253
+ }
3254
+ if getattr(parameter_model, "config", None)
3255
+ else {}
3256
+ ),
3257
+ )
3258
+
3259
+ self._api_client._verify_response(return_value)
3260
+ return return_value
3261
+
3262
+ async def _update_dataset_resource(
3263
+ self,
3264
+ *,
3265
+ name: Optional[str] = None,
3266
+ dataset_id: Optional[str] = None,
3267
+ display_name: Optional[str] = None,
3268
+ metadata: Optional[types.SchemaTextPromptDatasetMetadataOrDict] = None,
3269
+ description: Optional[str] = None,
3270
+ encryption_spec: Optional[genai_types.EncryptionSpecOrDict] = None,
3271
+ model_reference: Optional[str] = None,
3272
+ config: Optional[types.UpdatePromptConfigOrDict] = None,
3273
+ ) -> types.Dataset:
3274
+ """
3275
+ Creates a dataset resource to store prompts.
3276
+ """
3277
+
3278
+ parameter_model = types._UpdateDatasetParameters(
3279
+ name=name,
3280
+ dataset_id=dataset_id,
3281
+ display_name=display_name,
3282
+ metadata=metadata,
3283
+ description=description,
3284
+ encryption_spec=encryption_spec,
3285
+ model_reference=model_reference,
3286
+ config=config,
3287
+ )
3288
+
3289
+ request_url_dict: Optional[dict[str, str]]
3290
+ if not self._api_client.vertexai:
3291
+ raise ValueError(
3292
+ "This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
3293
+ )
3294
+ else:
3295
+ request_dict = _UpdateDatasetParameters_to_vertex(parameter_model)
3296
+ request_url_dict = request_dict.get("_url")
3297
+ if request_url_dict:
3298
+ path = "datasets/{dataset_id}".format_map(request_url_dict)
3299
+ else:
3300
+ path = "datasets/{dataset_id}"
3301
+
3302
+ query_params = request_dict.get("_query")
3303
+ if query_params:
3304
+ path = f"{path}?{urlencode(query_params)}"
3305
+ # TODO: remove the hack that pops config.
3306
+ request_dict.pop("config", None)
3307
+
3308
+ http_options: Optional[types.HttpOptions] = None
3309
+ if (
3310
+ parameter_model.config is not None
3311
+ and parameter_model.config.http_options is not None
3312
+ ):
3313
+ http_options = parameter_model.config.http_options
3314
+
3315
+ request_dict = _common.convert_to_dict(request_dict)
3316
+ request_dict = _common.encode_unserializable_types(request_dict)
3317
+
3318
+ response = await self._api_client.async_request(
3319
+ "patch", path, request_dict, http_options
3320
+ )
3321
+
3322
+ response_dict = {} if not response.body else json.loads(response.body)
3323
+
3324
+ return_value = types.Dataset._from_response(
3325
+ response=response_dict,
3326
+ kwargs=(
3327
+ {
3328
+ "config": {
3329
+ "response_schema": getattr(
3330
+ parameter_model.config, "response_schema", None
3331
+ ),
3332
+ "response_json_schema": getattr(
3333
+ parameter_model.config, "response_json_schema", None
3334
+ ),
3335
+ "include_all_fields": getattr(
3336
+ parameter_model.config, "include_all_fields", None
3337
+ ),
3338
+ }
3339
+ }
3340
+ if getattr(parameter_model, "config", None)
3341
+ else {}
3342
+ ),
3343
+ )
3344
+
3345
+ self._api_client._verify_response(return_value)
3346
+ return return_value
3347
+
3348
+ async def _create_custom_job_resource(
3349
+ self,
3350
+ *,
3351
+ custom_job: types.CustomJobOrDict,
3352
+ config: Optional[types.VertexBaseConfigOrDict] = None,
3353
+ ) -> types.CustomJob:
3354
+ """
3355
+ Creates a custom job.
3356
+ """
3357
+
3358
+ parameter_model = types._CustomJobParameters(
3359
+ custom_job=custom_job,
3360
+ config=config,
3361
+ )
3362
+
3363
+ request_url_dict: Optional[dict[str, str]]
3364
+ if not self._api_client.vertexai:
3365
+ raise ValueError(
3366
+ "This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
3367
+ )
3368
+ else:
3369
+ request_dict = _CustomJobParameters_to_vertex(parameter_model)
3370
+ request_url_dict = request_dict.get("_url")
3371
+ if request_url_dict:
3372
+ path = "customJobs".format_map(request_url_dict)
3373
+ else:
3374
+ path = "customJobs"
3375
+
3376
+ query_params = request_dict.get("_query")
3377
+ if query_params:
3378
+ path = f"{path}?{urlencode(query_params)}"
3379
+ # TODO: remove the hack that pops config.
3380
+ request_dict.pop("config", None)
3381
+
3382
+ http_options: Optional[types.HttpOptions] = None
3383
+ if (
3384
+ parameter_model.config is not None
3385
+ and parameter_model.config.http_options is not None
3386
+ ):
3387
+ http_options = parameter_model.config.http_options
3388
+
3389
+ request_dict = _common.convert_to_dict(request_dict)
3390
+ request_dict = _common.encode_unserializable_types(request_dict)
3391
+
3392
+ response = await self._api_client.async_request(
3393
+ "post", path, request_dict, http_options
3394
+ )
3395
+
3396
+ response_dict = {} if not response.body else json.loads(response.body)
3397
+
3398
+ if self._api_client.vertexai:
3399
+ response_dict = _CustomJob_from_vertex(response_dict)
3400
+
3401
+ return_value = types.CustomJob._from_response(
3402
+ response=response_dict,
3403
+ kwargs=(
3404
+ {
3405
+ "config": {
3406
+ "response_schema": getattr(
3407
+ parameter_model.config, "response_schema", None
3408
+ ),
3409
+ "response_json_schema": getattr(
3410
+ parameter_model.config, "response_json_schema", None
3411
+ ),
3412
+ "include_all_fields": getattr(
3413
+ parameter_model.config, "include_all_fields", None
3414
+ ),
3415
+ }
3416
+ }
3417
+ if getattr(parameter_model, "config", None)
3418
+ else {}
3419
+ ),
3420
+ )
3421
+
3422
+ self._api_client._verify_response(return_value)
3423
+ return return_value
3424
+
3425
+ async def _get_custom_job(
3426
+ self, *, name: str, config: Optional[types.VertexBaseConfigOrDict] = None
3427
+ ) -> types.CustomJob:
3428
+ """
3429
+ Gets a custom job.
3430
+ """
3431
+
3432
+ parameter_model = types._GetCustomJobParameters(
3433
+ name=name,
3434
+ config=config,
3435
+ )
3436
+
3437
+ request_url_dict: Optional[dict[str, str]]
3438
+ if not self._api_client.vertexai:
3439
+ raise ValueError(
3440
+ "This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
3441
+ )
3442
+ else:
3443
+ request_dict = _GetCustomJobParameters_to_vertex(parameter_model)
3444
+ request_url_dict = request_dict.get("_url")
3445
+ if request_url_dict:
3446
+ path = "customJobs/{name}".format_map(request_url_dict)
3447
+ else:
3448
+ path = "customJobs/{name}"
3449
+
3450
+ query_params = request_dict.get("_query")
3451
+ if query_params:
3452
+ path = f"{path}?{urlencode(query_params)}"
3453
+ # TODO: remove the hack that pops config.
3454
+ request_dict.pop("config", None)
3455
+
3456
+ http_options: Optional[types.HttpOptions] = None
3457
+ if (
3458
+ parameter_model.config is not None
3459
+ and parameter_model.config.http_options is not None
3460
+ ):
3461
+ http_options = parameter_model.config.http_options
3462
+
3463
+ request_dict = _common.convert_to_dict(request_dict)
3464
+ request_dict = _common.encode_unserializable_types(request_dict)
3465
+
3466
+ response = await self._api_client.async_request(
3467
+ "get", path, request_dict, http_options
3468
+ )
3469
+
3470
+ response_dict = {} if not response.body else json.loads(response.body)
3471
+
3472
+ if self._api_client.vertexai:
3473
+ response_dict = _CustomJob_from_vertex(response_dict)
3474
+
3475
+ return_value = types.CustomJob._from_response(
3476
+ response=response_dict,
3477
+ kwargs=(
3478
+ {
3479
+ "config": {
3480
+ "response_schema": getattr(
3481
+ parameter_model.config, "response_schema", None
3482
+ ),
3483
+ "response_json_schema": getattr(
3484
+ parameter_model.config, "response_json_schema", None
3485
+ ),
3486
+ "include_all_fields": getattr(
3487
+ parameter_model.config, "include_all_fields", None
3488
+ ),
3489
+ }
3490
+ }
3491
+ if getattr(parameter_model, "config", None)
3492
+ else {}
3493
+ ),
3494
+ )
3495
+
3496
+ self._api_client._verify_response(return_value)
3497
+ return return_value
3498
+
3499
+ async def _optimize(
3500
+ self,
3501
+ *,
3502
+ content: Optional[genai_types.ContentOrDict] = None,
3503
+ config: Optional[types.OptimizeConfigOrDict] = None,
3504
+ ) -> types.OptimizeResponseEndpoint:
3505
+ """
3506
+ Optimize a single prompt.
3507
+ """
3508
+
3509
+ parameter_model = types._OptimizeRequestParameters(
3510
+ content=content,
3511
+ config=config,
3512
+ )
3513
+
3514
+ request_url_dict: Optional[dict[str, str]]
3515
+ if not self._api_client.vertexai:
3516
+ raise ValueError(
3517
+ "This method is only supported in Gemini Enterprise Agent Platform mode, not in Gemini Developer API mode."
3518
+ )
3519
+ else:
3520
+ request_dict = _OptimizeRequestParameters_to_vertex(parameter_model)
3521
+ request_url_dict = request_dict.get("_url")
3522
+ if request_url_dict:
3523
+ path = "tuningJobs:optimizePrompt".format_map(request_url_dict)
3524
+ else:
3525
+ path = "tuningJobs:optimizePrompt"
3526
+
3527
+ query_params = request_dict.get("_query")
3528
+ if query_params:
3529
+ path = f"{path}?{urlencode(query_params)}"
3530
+ # TODO: remove the hack that pops config.
3531
+ request_dict.pop("config", None)
3532
+
3533
+ http_options: Optional[types.HttpOptions] = None
3534
+ if (
3535
+ parameter_model.config is not None
3536
+ and parameter_model.config.http_options is not None
3537
+ ):
3538
+ http_options = parameter_model.config.http_options
3539
+
3540
+ request_dict = _common.convert_to_dict(request_dict)
3541
+ request_dict = _common.encode_unserializable_types(request_dict)
3542
+
3543
+ response = await self._api_client.async_request(
3544
+ "post", path, request_dict, http_options
3545
+ )
3546
+
3547
+ response_dict = {} if not response.body else json.loads(response.body)
3548
+
3549
+ return_value = types.OptimizeResponseEndpoint._from_response(
3550
+ response=response_dict,
3551
+ kwargs=(
3552
+ {
3553
+ "config": {
3554
+ "response_schema": getattr(
3555
+ parameter_model.config, "response_schema", None
3556
+ ),
3557
+ "response_json_schema": getattr(
3558
+ parameter_model.config, "response_json_schema", None
3559
+ ),
3560
+ "include_all_fields": getattr(
3561
+ parameter_model.config, "include_all_fields", None
3562
+ ),
3563
+ }
3564
+ }
3565
+ if getattr(parameter_model, "config", None)
3566
+ else {}
3567
+ ),
3568
+ )
3569
+
3570
+ self._api_client._verify_response(return_value)
3571
+ return return_value
3572
+
3573
+ _DEFAULT_TIMEOUT = 90
3574
+ _DEFAULT_MAX_WAIT_TIME = 60
3575
+
3576
+ async def create(
3577
+ self,
3578
+ *,
3579
+ prompt: types.PromptOrDict,
3580
+ config: Optional[types.CreatePromptConfigOrDict] = None,
3581
+ ) -> types.Prompt:
3582
+ """Creates a new prompt in a Vertex Dataset resource.
3583
+
3584
+ This method waits for prompt creation to be complete before returning.
3585
+
3586
+ Note: This method does not create a versioned resource for your prompt.
3587
+ Call create_version() to create a new prompt resource with a version.
3588
+
3589
+ Args:
3590
+ prompt: The prompt to create.
3591
+ config: Optional configuration for creating the prompt.
3592
+
3593
+ Returns:
3594
+ A types.Prompt object representing the prompt with its associated
3595
+ Dataset resources.
3596
+ """
3597
+ if isinstance(prompt, dict):
3598
+ prompt = types.Prompt(**prompt)
3599
+ if isinstance(config, dict):
3600
+ config = types.CreatePromptConfig(**config)
3601
+ elif not config:
3602
+ config = types.CreatePromptConfig()
3603
+
3604
+ _prompt_management_utils._raise_for_invalid_prompt(prompt)
3605
+
3606
+ if prompt.prompt_data is None:
3607
+ raise ValueError("Prompt data is required to create a prompt.")
3608
+
3609
+ prompt_metadata = _prompt_management_utils._create_dataset_metadata_from_prompt(
3610
+ prompt,
3611
+ variables=(
3612
+ prompt.prompt_data.variables
3613
+ if prompt.prompt_data and prompt.prompt_data.variables
3614
+ else None
3615
+ ),
3616
+ )
3617
+
3618
+ # Step 1: Create the dataset resource for the prompt and wait for the operation to complete.
3619
+ create_prompt_dataset_operation = await self._create_dataset_resource(
3620
+ display_name=(
3621
+ config.prompt_display_name
3622
+ if config and config.prompt_display_name
3623
+ else f"prompt_{time.strftime('%Y%m%d-%H%M%S')}"
3624
+ ),
3625
+ name=f"projects/{self._api_client.project}/locations/{self._api_client.location}",
3626
+ metadata_schema_uri=_prompt_management_utils.PROMPT_SCHEMA_URI,
3627
+ metadata=prompt_metadata,
3628
+ model_reference=prompt.prompt_data.model,
3629
+ encryption_spec=(
3630
+ config.encryption_spec if config and config.encryption_spec else None
3631
+ ),
3632
+ )
3633
+ dataset_resource_name = await self._wait_for_operation(
3634
+ operation=create_prompt_dataset_operation,
3635
+ timeout=(
3636
+ config.timeout
3637
+ if config and config.timeout is not None
3638
+ else self._DEFAULT_TIMEOUT
3639
+ ),
3640
+ max_wait_time=(
3641
+ config.max_wait_time
3642
+ if config and config.max_wait_time is not None
3643
+ else self._DEFAULT_MAX_WAIT_TIME
3644
+ ),
3645
+ )
3646
+ dataset_id = dataset_resource_name.split("/")[-1]
3647
+
3648
+ # Step 2: Get the dataset resource
3649
+ dataset_resource = await self._get_dataset_resource(
3650
+ name=dataset_id,
3651
+ )
3652
+ prompt._dataset = dataset_resource
3653
+ return prompt
3654
+
3655
+ async def create_version(
3656
+ self,
3657
+ *,
3658
+ prompt: types.PromptOrDict,
3659
+ config: Optional[types.CreatePromptVersionConfigOrDict] = None,
3660
+ ) -> types.Prompt:
3661
+ """Creates a prompt resource and an initial prompt version.
3662
+
3663
+ When creating new prompt and prompt version resources, this waits for
3664
+ the create operation to complete before returning.
3665
+
3666
+ Note: This method is recommended instead of create() since it creates a
3667
+ versioned resource for your prompt.
3668
+
3669
+ Args:
3670
+ prompt: The prompt to create.
3671
+ config: Optional configuration for creating the prompt and prompt version.
3672
+
3673
+ Returns:
3674
+ A types.Prompt object representing the prompt with its associated
3675
+ Dataset and Dataset Version resources.
3676
+ """
3677
+ if isinstance(prompt, dict):
3678
+ prompt = types.Prompt(**prompt)
3679
+ if isinstance(config, dict):
3680
+ config = types.CreatePromptVersionConfig(**config)
3681
+ elif not config:
3682
+ config = types.CreatePromptVersionConfig()
3683
+
3684
+ _prompt_management_utils._raise_for_invalid_prompt(prompt)
3685
+
3686
+ if prompt.prompt_data is None:
3687
+ raise ValueError("Prompt data is required to create a prompt.")
3688
+
3689
+ prompt_metadata = _prompt_management_utils._create_dataset_metadata_from_prompt(
3690
+ prompt,
3691
+ variables=(
3692
+ prompt.prompt_data.variables
3693
+ if prompt.prompt_data and prompt.prompt_data.variables
3694
+ else None
3695
+ ),
3696
+ )
3697
+
3698
+ # Step 1: Create the dataset resource for the prompt and wait for the operation to complete.
3699
+ create_prompt_dataset_operation = await self._create_dataset_resource(
3700
+ display_name=(
3701
+ config.prompt_display_name
3702
+ if config and config.prompt_display_name
3703
+ else f"prompt_{time.strftime('%Y%m%d-%H%M%S')}"
3704
+ ),
3705
+ name=f"projects/{self._api_client.project}/locations/{self._api_client.location}",
3706
+ metadata_schema_uri=_prompt_management_utils.PROMPT_SCHEMA_URI,
3707
+ metadata=prompt_metadata,
3708
+ model_reference=prompt.prompt_data.model,
3709
+ encryption_spec=(
3710
+ config.encryption_spec if config and config.encryption_spec else None
3711
+ ),
3712
+ )
3713
+ dataset_resource_name = await self._wait_for_operation(
3714
+ operation=create_prompt_dataset_operation,
3715
+ timeout=(
3716
+ config.timeout
3717
+ if config and config.timeout is not None
3718
+ else self._DEFAULT_TIMEOUT
3719
+ ),
3720
+ max_wait_time=(
3721
+ config.max_wait_time
3722
+ if config and config.max_wait_time is not None
3723
+ else self._DEFAULT_MAX_WAIT_TIME
3724
+ ),
3725
+ )
3726
+ dataset_id = dataset_resource_name.split("/")[-1]
3727
+
3728
+ # Step 2: Get the dataset resource
3729
+ dataset_resource = await self._get_dataset_resource(
3730
+ name=dataset_id,
3731
+ )
3732
+ prompt._dataset = dataset_resource
3733
+
3734
+ if prompt._dataset.name is None:
3735
+ raise ValueError("Invalid dataset resource.")
3736
+
3737
+ # Step 3: Create the dataset version
3738
+ create_dataset_version_operation = await self._create_dataset_version_resource(
3739
+ dataset_name=prompt._dataset.name.split("/")[-1],
3740
+ display_name=(
3741
+ config.version_display_name
3742
+ if config and config.version_display_name is not None
3743
+ else f"prompt_version_{time.strftime('%Y%m%d-%H%M%S')}"
3744
+ ),
3745
+ )
3746
+ dataset_version_resource_name = await self._wait_for_operation(
3747
+ operation=create_dataset_version_operation,
3748
+ timeout=(
3749
+ config.timeout
3750
+ if config and config.timeout is not None
3751
+ else self._DEFAULT_TIMEOUT
3752
+ ),
3753
+ max_wait_time=(
3754
+ config.max_wait_time
3755
+ if config and config.max_wait_time is not None
3756
+ else self._DEFAULT_MAX_WAIT_TIME
3757
+ ),
3758
+ )
3759
+
3760
+ # Step 4: Get the dataset version resource and return it with the prompt
3761
+ dataset_version_resource = await self._get_dataset_version_resource(
3762
+ dataset_id=dataset_id,
3763
+ dataset_version_id=dataset_version_resource_name.split("/")[-1],
3764
+ )
3765
+ prompt = _prompt_management_utils._create_prompt_from_dataset_metadata(
3766
+ dataset_version_resource
3767
+ )
3768
+ prompt._dataset = dataset_resource
3769
+ prompt._dataset_version = dataset_version_resource
3770
+ return prompt
3771
+
3772
+ async def update(
3773
+ self,
3774
+ *,
3775
+ prompt_id: str,
3776
+ prompt: types.PromptOrDict,
3777
+ config: Optional[types.UpdatePromptConfigOrDict] = None,
3778
+ ) -> types.Prompt:
3779
+ """Updates an existing prompt and creates a new version for the prompt
3780
+ associated with the provided prompt_id.
3781
+
3782
+ Args:
3783
+ prompt_id: The ID of the prompt to create a new version for.
3784
+ prompt: The updated prompt.
3785
+ config: Optional configuration for updating the prompt.
3786
+
3787
+ Returns:
3788
+ A types.Prompt object representing the updated prompt with its associated
3789
+ Dataset and Dataset Version resources.
3790
+ """
3791
+
3792
+ if isinstance(prompt, dict):
3793
+ prompt = types.Prompt(**prompt)
3794
+ if isinstance(config, dict):
3795
+ config = types.UpdatePromptConfig(**config)
3796
+ elif not config:
3797
+ config = types.UpdatePromptConfig()
3798
+
3799
+ prompt_metadata = _prompt_management_utils._create_dataset_metadata_from_prompt(
3800
+ prompt,
3801
+ variables=(
3802
+ prompt.prompt_data.variables
3803
+ if prompt.prompt_data and prompt.prompt_data.variables
3804
+ else None
3805
+ ),
3806
+ )
3807
+
3808
+ if not prompt.prompt_data:
3809
+ raise ValueError("Prompt data is required to update a prompt.")
3810
+
3811
+ # Step 1: Update the dataset resource for the prompt and wait for the operation to complete.
3812
+ updated_dataset_resource = await self._update_dataset_resource(
3813
+ name=f"projects/{self._api_client.project}/locations/{self._api_client.location}/datasets/{prompt_id}",
3814
+ dataset_id=prompt_id,
3815
+ display_name=(
3816
+ config.prompt_display_name
3817
+ if config and config.prompt_display_name
3818
+ else None
3819
+ ),
3820
+ metadata=prompt_metadata,
3821
+ model_reference=prompt.prompt_data.model,
3822
+ encryption_spec=(
3823
+ config.encryption_spec if config and config.encryption_spec else None
3824
+ ),
3825
+ config=config,
3826
+ )
3827
+
3828
+ if not updated_dataset_resource.name:
3829
+ raise ValueError("Failed to update dataset resource.")
3830
+
3831
+ dataset_id = updated_dataset_resource.name.split("/")[-1]
3832
+
3833
+ # Step 2: Create a dataset version for the prompt.
3834
+ create_dataset_version_operation = await self._create_dataset_version_resource(
3835
+ dataset_name=dataset_id,
3836
+ display_name=(
3837
+ config.version_display_name
3838
+ if config and config.version_display_name is not None
3839
+ else f"prompt_version_{time.strftime('%Y%m%d-%H%M%S')}"
3840
+ ),
3841
+ )
3842
+ dataset_version_resource_name = await self._wait_for_operation(
3843
+ operation=create_dataset_version_operation,
3844
+ timeout=(
3845
+ config.timeout
3846
+ if config and config.timeout is not None
3847
+ else self._DEFAULT_TIMEOUT
3848
+ ),
3849
+ max_wait_time=(
3850
+ config.max_wait_time
3851
+ if config and config.max_wait_time is not None
3852
+ else self._DEFAULT_MAX_WAIT_TIME
3853
+ ),
3854
+ )
3855
+ dataset_version_id = dataset_version_resource_name.split("/")[-1]
3856
+
3857
+ # Step 3: Get the dataset version resource and return it with the prompt.
3858
+ dataset_version_resource = await self._get_dataset_version_resource(
3859
+ dataset_id=dataset_id,
3860
+ dataset_version_id=dataset_version_id,
3861
+ )
3862
+ prompt = _prompt_management_utils._create_prompt_from_dataset_metadata(
3863
+ dataset_version_resource
3864
+ )
3865
+ prompt._dataset = updated_dataset_resource
3866
+ prompt._dataset_version = dataset_version_resource
3867
+ return prompt
3868
+
3869
+ async def _wait_for_operation(
3870
+ self,
3871
+ operation: types.DatasetOperation,
3872
+ timeout: int,
3873
+ max_wait_time: int = _DEFAULT_MAX_WAIT_TIME,
3874
+ ) -> str:
3875
+ """Waits for a dataset operation to complete.
3876
+
3877
+ Args:
3878
+ operation: The dataset operation to wait for.
3879
+ timeout: The maximum time to wait for the operation to complete.
3880
+ max_wait_time: The maximum interval between polling requests in seconds.
3881
+
3882
+ Returns:
3883
+ The name of the Dataset resource from the operation result.
3884
+
3885
+ Raises:
3886
+ TimeoutError: If the operation does not complete within the timeout.
3887
+ ValueError: If the operation fails.
3888
+ """
3889
+ done = False
3890
+ prompt_dataset_operation: Optional[types.DatasetOperation] = None
3891
+
3892
+ response_operation_name = operation.name
3893
+ if response_operation_name is None:
3894
+ raise ValueError("Invalid operation name.")
3895
+
3896
+ dataset_id = response_operation_name.split("/datasets/")[1].split("/")[0]
3897
+ operation_id = response_operation_name.split("/")[-1]
3898
+
3899
+ start_time = time.time()
3900
+ sleep_duration = 5
3901
+ wait_multiplier = 2
3902
+ previous_time = time.time()
3903
+
3904
+ while not done:
3905
+ if (time.time() - start_time) > timeout:
3906
+ raise TimeoutError(
3907
+ "Create prompt operation did not complete within the"
3908
+ f" specified timeout of {timeout} seconds."
3909
+ )
3910
+ current_time = time.time()
3911
+ if current_time - previous_time >= sleep_duration:
3912
+ sleep_duration = min(sleep_duration * wait_multiplier, max_wait_time)
3913
+ previous_time = current_time
3914
+ await asyncio.sleep(sleep_duration)
3915
+ prompt_dataset_operation = await self._get_dataset_operation(
3916
+ dataset_id=dataset_id,
3917
+ operation_id=operation_id,
3918
+ )
3919
+ done = (
3920
+ (prompt_dataset_operation.done or False)
3921
+ if hasattr(prompt_dataset_operation, "done")
3922
+ else False
3923
+ )
3924
+ if (
3925
+ not prompt_dataset_operation
3926
+ or prompt_dataset_operation.response is None
3927
+ or prompt_dataset_operation.response.get("name") is None
3928
+ ):
3929
+ raise ValueError("Error creating prompt version resource.")
3930
+ if (
3931
+ hasattr(prompt_dataset_operation, "error")
3932
+ and prompt_dataset_operation.error is not None
3933
+ ):
3934
+ raise ValueError(
3935
+ f"Error creating prompt version resource: {prompt_dataset_operation.error}"
3936
+ )
3937
+ return prompt_dataset_operation.response.get("name") # type: ignore[return-value]
3938
+
3939
+ async def get(
3940
+ self,
3941
+ *,
3942
+ prompt_id: str,
3943
+ config: Optional[types.GetPromptConfig] = None,
3944
+ ) -> types.Prompt:
3945
+ """Gets a prompt resource from a Vertex Dataset.
3946
+
3947
+ Args:
3948
+ prompt_id: The id of the Vertex Dataset resource containing the prompt. For example, if the prompt resource name is "projects/123/locations/us-central1/datasets/456", then the prompt_id is "456".
3949
+ config: Optional configuration for getting the prompt.
3950
+
3951
+ Returns:
3952
+ A types.Prompt object representing the prompt with its associated Dataset and Dataset Version resources.
3953
+ """
3954
+
3955
+ prompt_dataset_resource = await self._get_dataset_resource(name=prompt_id)
3956
+ prompt = _prompt_management_utils._create_prompt_from_dataset_metadata(
3957
+ prompt_dataset_resource,
3958
+ )
3959
+ prompt._dataset = prompt_dataset_resource
3960
+
3961
+ return prompt
3962
+
3963
+ async def get_version(
3964
+ self,
3965
+ *,
3966
+ prompt_id: str,
3967
+ version_id: str,
3968
+ config: Optional[types.GetPromptConfig] = None,
3969
+ ) -> types.Prompt:
3970
+ """Gets a prompt resource from a Vertex Dataset.
3971
+
3972
+ Args:
3973
+ prompt_id: The id of the Vertex Dataset resource containing the prompt. For example, if the prompt resource name is "projects/123/locations/us-central1/datasets/456", then the prompt_id is "456".
3974
+ version_id: The id of the Vertex Dataset Version resource containing the prompt version. For example, if the prompt version resource name is "projects/123/locations/us-central1/datasets/456/datasetVersions/1", then the version_id is "1".
3975
+ config: Optional configuration for getting the prompt.
3976
+
3977
+ Returns:
3978
+ A types.Prompt object representing the prompt with its associated Dataset and Dataset Version resources.
3979
+ """
3980
+
3981
+ prompt_dataset_resource = await self._get_dataset_resource(name=prompt_id)
3982
+ prompt = _prompt_management_utils._create_prompt_from_dataset_metadata(
3983
+ prompt_dataset_resource,
3984
+ )
3985
+ prompt._dataset = prompt_dataset_resource
3986
+
3987
+ prompt_version_resource = await self._get_dataset_version_resource(
3988
+ dataset_id=prompt_id,
3989
+ dataset_version_id=version_id,
3990
+ )
3991
+ prompt._dataset_version = prompt_version_resource
3992
+
3993
+ return prompt
3994
+
3995
+ async def _wait_for_project_operation(
3996
+ self,
3997
+ operation: genai_types.ProjectOperation,
3998
+ timeout: int,
3999
+ max_wait_time: int = _DEFAULT_MAX_WAIT_TIME,
4000
+ ) -> None:
4001
+ """Waits for a dataset deletion operation to complete.
4002
+
4003
+ Delete operations are project level operations and are separate from dataset resource operations, for example: projects/123/locations/us-central1/operations/789.
4004
+
4005
+ Args:
4006
+ operation: The project operation to wait for.
4007
+ timeout: The maximum time to wait for the operation to complete.
4008
+ max_wait_time: The maximum interval between polling requests in seconds.
4009
+ Raises:
4010
+ TimeoutError: If the operation does not complete within the timeout.
4011
+ ValueError: If the operation fails.
4012
+ """
4013
+ done = False
4014
+
4015
+ start_time = time.time()
4016
+ sleep_duration = 5
4017
+ wait_multiplier = 2
4018
+ previous_time = time.time()
4019
+ while not done:
4020
+ if (time.time() - start_time) > timeout:
4021
+ raise TimeoutError(
4022
+ f"Delete operation did not complete within the"
4023
+ f" specified timeout of {timeout} seconds."
4024
+ )
4025
+ current_time = time.time()
4026
+ if current_time - previous_time >= sleep_duration:
4027
+ sleep_duration = min(sleep_duration * wait_multiplier, max_wait_time)
4028
+ previous_time = current_time
4029
+ await asyncio.sleep(sleep_duration)
4030
+ operations_module = operations.AsyncOperations(api_client_=self._api_client)
4031
+
4032
+ if operation.name is None:
4033
+ raise ValueError("Invalid operation name.")
4034
+ operation = await operations_module._get(
4035
+ operation_id=operation.name.split("/")[-1],
4036
+ )
4037
+ done = (operation.done or False) if hasattr(operation, "done") else False
4038
+ if hasattr(operation, "error") and operation.error is not None:
4039
+ raise ValueError(f"Error in delete operation: {operation.error}")
4040
+
4041
+ async def delete(
4042
+ self,
4043
+ *,
4044
+ prompt_id: str,
4045
+ config: Optional[types.DeletePromptConfig] = None,
4046
+ ) -> None:
4047
+ """Deletes a prompt resource.
4048
+
4049
+ Args:
4050
+ prompt_id: The id of the prompt resource to delete.
4051
+
4052
+ Raises:
4053
+ TimeoutError: If the delete operation does not complete within the timeout.
4054
+ ValueError: If the delete operation fails.
4055
+ """
4056
+
4057
+ delete_prompt_operation = await self._delete_dataset(
4058
+ prompt_id=prompt_id,
4059
+ config=config,
4060
+ )
4061
+ await self._wait_for_project_operation(
4062
+ operation=delete_prompt_operation,
4063
+ timeout=(
4064
+ config.timeout
4065
+ if config and config.timeout is not None
4066
+ else self._DEFAULT_TIMEOUT
4067
+ ),
4068
+ max_wait_time=(
4069
+ config.max_wait_time
4070
+ if config and config.max_wait_time is not None
4071
+ else self._DEFAULT_MAX_WAIT_TIME
4072
+ ),
4073
+ )
4074
+ logger.info(f"Deleted prompt with id: {prompt_id}")
4075
+
4076
+ async def delete_version(
4077
+ self,
4078
+ *,
4079
+ prompt_id: str,
4080
+ version_id: str,
4081
+ config: Optional[types.DeletePromptConfig] = None,
4082
+ ) -> None:
4083
+ """Deletes a prompt version resource.
4084
+
4085
+ Args:
4086
+ prompt_id: The id of the prompt resource to delete.
4087
+ version_id: The id of the prompt version resource to delete.
4088
+
4089
+ Raises:
4090
+ TimeoutError: If the delete operation does not complete within the timeout.
4091
+ ValueError: If the delete operation fails.
4092
+ """
4093
+ delete_version_operation = await self._delete_dataset_version(
4094
+ prompt_id=prompt_id,
4095
+ version_id=version_id,
4096
+ config=config,
4097
+ )
4098
+
4099
+ await self._wait_for_project_operation(
4100
+ operation=delete_version_operation,
4101
+ timeout=(
4102
+ config.timeout
4103
+ if config and config.timeout is not None
4104
+ else self._DEFAULT_TIMEOUT
4105
+ ),
4106
+ max_wait_time=(
4107
+ config.max_wait_time
4108
+ if config and config.max_wait_time is not None
4109
+ else self._DEFAULT_MAX_WAIT_TIME
4110
+ ),
4111
+ )
4112
+ logger.info(
4113
+ f"Deleted prompt version {version_id} from prompt with id: {prompt_id}"
4114
+ )
4115
+
4116
+ async def _list_prompts_pager(
4117
+ self,
4118
+ *,
4119
+ config: Optional[types.ListPromptsConfigOrDict] = None,
4120
+ ) -> AsyncPager[types.Dataset]:
4121
+ return AsyncPager(
4122
+ "datasets",
4123
+ self._list_prompts,
4124
+ await self._list_prompts(config=config),
4125
+ config,
4126
+ )
4127
+
4128
+ async def _list_versions_pager(
4129
+ self,
4130
+ *,
4131
+ prompt_id: str,
4132
+ config: Optional[types.ListPromptsConfigOrDict] = None,
4133
+ ) -> AsyncPager[types.DatasetVersion]:
4134
+ return AsyncPager(
4135
+ "dataset_versions",
4136
+ self._list_versions,
4137
+ await self._list_versions(config=config, dataset_id=prompt_id),
4138
+ config,
4139
+ )
4140
+
4141
+ async def list(
4142
+ self,
4143
+ *,
4144
+ config: Optional[types.ListPromptsConfigOrDict] = None,
4145
+ ) -> AsyncIterator[types.PromptRef]:
4146
+ """Lists prompt resources in a project.
4147
+
4148
+ This method retrieves all the prompts from the project provided in the
4149
+ agentplatform.Client constructor and returns a list of prompt references containing the prompt_id and model for the prompt.
4150
+
4151
+ To get the full types.Prompt resource for a PromptRef after calling this method, use the get() method with the prompt_id as the prompt_id argument.
4152
+ Example usage:
4153
+
4154
+ ```
4155
+ prompt_refs = client.aio.prompt_management.list_prompts()
4156
+ async for prompt_ref in prompt_refs:
4157
+ await client.prompt_management.get(prompt_id=prompt_ref.prompt_id)
4158
+ ```
4159
+
4160
+ Args:
4161
+ config: Optional configuration for listing prompts.
4162
+
4163
+ Returns:
4164
+ An async iterator of types.PromptRef objects.
4165
+ """
4166
+ if isinstance(config, dict):
4167
+ config = types.ListPromptsConfig(**config)
4168
+ elif not config:
4169
+ config = types.ListPromptsConfig()
4170
+ async for dataset in await self._list_prompts_pager(config=config):
4171
+ if not dataset or not dataset.model_reference or not dataset.name:
4172
+ continue
4173
+ prompt_ref = types.PromptRef(
4174
+ model=dataset.model_reference, prompt_id=dataset.name.split("/")[-1]
4175
+ )
4176
+ yield prompt_ref
4177
+
4178
+ async def list_versions(
4179
+ self,
4180
+ *,
4181
+ prompt_id: str,
4182
+ config: Optional[types.ListPromptsConfigOrDict] = None,
4183
+ ) -> AsyncIterator[types.PromptVersionRef]:
4184
+ """Lists prompt version resources for a provided prompt_id.
4185
+
4186
+ This method retrieves all the prompt versions for a provided prompt_id.
4187
+
4188
+ To get the full types.Prompt resource for a PromptVersionRef after calling this method, use the get() method with the returned prompt_id and version_id.
4189
+ Example usage:
4190
+
4191
+ ```
4192
+ prompt_version_refs = await client.prompt_management.list_versions(prompt_id="123")
4193
+ async for version_ref in prompt_version_refs:
4194
+ await client.aio.prompt_management.get(prompt_id=version_ref.prompt_id, version_id=version_ref.version_id)
4195
+ ```
4196
+
4197
+ Args:
4198
+ prompt_id: The id of the Vertex Dataset resource containing the prompt. For example, if the prompt resource name is "projects/123/locations/us-central1/datasets/456", then the prompt_id is "456".
4199
+ config: Optional configuration for listing prompts.
4200
+
4201
+ Returns:
4202
+ An async iterator of types.PromptVersionRef objects representing the prompt version resources for the provided prompt_id.
4203
+
4204
+ """
4205
+ if isinstance(config, dict):
4206
+ config = types.ListPromptsConfig(**config)
4207
+ elif not config:
4208
+ config = types.ListPromptsConfig()
4209
+ async for dataset_version in await self._list_versions_pager(
4210
+ config=config, prompt_id=prompt_id
4211
+ ):
4212
+ if (
4213
+ not dataset_version
4214
+ or not dataset_version.model_reference
4215
+ or not dataset_version.name
4216
+ ):
4217
+ continue
4218
+ prompt_version_ref = types.PromptVersionRef(
4219
+ model=dataset_version.model_reference,
4220
+ version_id=dataset_version.name.split("/")[-1],
4221
+ prompt_id=prompt_id,
4222
+ )
4223
+ yield prompt_version_ref
4224
+
4225
+ async def restore_version(
4226
+ self,
4227
+ *,
4228
+ prompt_id: str,
4229
+ version_id: str,
4230
+ config: Optional[types.RestoreVersionConfig] = None,
4231
+ ) -> types.Prompt:
4232
+ """Restores the provided prompt version to the latest version.
4233
+
4234
+ Args:
4235
+ prompt_id: The id of the Vertex Dataset resource containing the prompt. For example, if the prompt resource name is "projects/123/locations/us-central1/datasets/456", then the prompt_id is "456".
4236
+ version_id: The id of the Vertex Dataset Version resource to restore. For example, if the version resource name is "projects/123/locations/us-central1/datasets/456/datasetVersions/789", then the version_id is "789".
4237
+ config: Optional configuration for restoring the prompt version.
4238
+
4239
+ Returns:
4240
+ A types.Prompt object representing the prompt with the updated Dataset Version resource.
4241
+ """
4242
+
4243
+ restore_prompt_operation = await self._restore_version(
4244
+ dataset_id=prompt_id,
4245
+ version_id=version_id,
4246
+ config=config,
4247
+ )
4248
+ await self._wait_for_project_operation(
4249
+ operation=restore_prompt_operation,
4250
+ timeout=(
4251
+ config.timeout
4252
+ if config and config.timeout is not None
4253
+ else self._DEFAULT_TIMEOUT
4254
+ ),
4255
+ max_wait_time=(
4256
+ config.max_wait_time
4257
+ if config and config.max_wait_time is not None
4258
+ else self._DEFAULT_MAX_WAIT_TIME
4259
+ ),
4260
+ )
4261
+ dataset_version_resource = await self._get_dataset_version_resource(
4262
+ dataset_id=prompt_id,
4263
+ dataset_version_id=version_id,
4264
+ )
4265
+ updated_prompt = _prompt_management_utils._create_prompt_from_dataset_metadata(
4266
+ dataset_version_resource,
4267
+ )
4268
+ updated_prompt._dataset_version = dataset_version_resource
4269
+ return updated_prompt
4270
+
4271
+ @_common.experimental_warning(
4272
+ "The Vertex SDK GenAI prompts.launch_optimization_job method is "
4273
+ "experimental, and may change in future versions."
4274
+ )
4275
+ async def launch_optimization_job(
4276
+ self,
4277
+ method: types.PromptOptimizerMethod,
4278
+ config: types.PromptOptimizerConfigOrDict,
4279
+ ) -> types.CustomJob:
4280
+ """Call async Vertex AI Prompt Optimizer (VAPO).
4281
+
4282
+
4283
+ Note: The `wait_for_completion` parameter in the config will be
4284
+ ignored when using the AsyncClient, as it is not supported.
4285
+
4286
+ Example usage:
4287
+ client = agentplatform.Client(project=PROJECT_NAME, location='us-central1')
4288
+ vapo_config = agentplatform.types.PromptOptimizerConfig(
4289
+ config_path='gs://you-bucket-name/your-config.json',
4290
+ service_account=service_account,
4291
+ )
4292
+ job = await client.aio.prompts.launch_optimization_job(
4293
+ method=types.PromptOptimizerMethod.VAPO, config=vapo_config)
4294
+
4295
+ Args:
4296
+ method: The method for optimizing multiple prompts. Supported methods:
4297
+ VAPO, OPTIMIZATION_TARGET_GEMINI_NANO.
4298
+ config: PromptOptimizerConfig instance containing the
4299
+ configuration for prompt optimization.
4300
+ Returns:
4301
+ The custom job that was created.
4302
+ """
4303
+ if isinstance(config, dict):
4304
+ config = types.PromptOptimizerConfig(**config)
4305
+
4306
+ if not config.config_path:
4307
+ raise ValueError("Config path is required.")
4308
+
4309
+ _OPTIMIZER_METHOD_TO_CONTAINER_URI = {
4310
+ types.PromptOptimizerMethod.VAPO: "us-docker.pkg.dev/vertex-ai/cair/vaipo:preview_v1_0",
4311
+ types.PromptOptimizerMethod.OPTIMIZATION_TARGET_GEMINI_NANO: "us-docker.pkg.dev/vertex-ai/cair/vaipo:preview_android_v1_0",
4312
+ }
4313
+ container_uri = _OPTIMIZER_METHOD_TO_CONTAINER_URI.get(method)
4314
+ if not container_uri:
4315
+ raise ValueError(
4316
+ 'Only "VAPO" and "OPTIMIZATION_TARGET_GEMINI_NANO" '
4317
+ "methods are currently supported."
4318
+ )
4319
+
4320
+ if config.wait_for_completion:
4321
+ logger.info(
4322
+ "Ignoring wait_for_completion=True since the AsyncClient does not support it."
4323
+ )
4324
+
4325
+ if config.optimizer_job_display_name:
4326
+ display_name = config.optimizer_job_display_name
4327
+ else:
4328
+ timestamp = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
4329
+ display_name = f"{method.value.lower()}-optimizer-{timestamp}"
4330
+
4331
+ if not config.config_path:
4332
+ raise ValueError("Config path is required.")
4333
+ bucket = "/".join(config.config_path.split("/")[:-1])
4334
+
4335
+ region = self._api_client.location
4336
+ project = self._api_client.project
4337
+ container_args = {
4338
+ "config": config.config_path,
4339
+ }
4340
+ args = ["--%s=%s" % (k, v) for k, v in container_args.items()]
4341
+ worker_pool_specs = [
4342
+ types.WorkerPoolSpec(
4343
+ replica_count=1,
4344
+ machine_spec=types.MachineSpec(machine_type="n1-standard-4"),
4345
+ container_spec=types.ContainerSpec(
4346
+ image_uri=container_uri,
4347
+ args=args,
4348
+ ),
4349
+ )
4350
+ ]
4351
+
4352
+ service_account = _prompt_optimizer_utils._get_service_account(config)
4353
+
4354
+ job_spec = types.CustomJobSpec(
4355
+ worker_pool_specs=worker_pool_specs,
4356
+ base_output_directory=genai_types.GcsDestination(output_uri_prefix=bucket),
4357
+ service_account=service_account,
4358
+ )
4359
+
4360
+ custom_job = types.CustomJob(
4361
+ display_name=display_name,
4362
+ job_spec=job_spec,
4363
+ )
4364
+
4365
+ job = await self._create_custom_job_resource(
4366
+ custom_job=custom_job,
4367
+ )
4368
+
4369
+ # Get the job id for the dashboard url and display to the user.
4370
+ job_resource_name = job.name
4371
+ if not job_resource_name:
4372
+ raise ValueError(f"Error creating job: {job}")
4373
+ job_id = job_resource_name.split("/")[-1]
4374
+ logger.info("Job created: %s", job.name)
4375
+
4376
+ # Construct the dashboard URL to show to the user.
4377
+ dashboard_url = f"https://console.cloud.google.com/vertex-ai/locations/{region}/training/{job_id}/cpu?project={project}"
4378
+ logger.info("View the job status at: %s", dashboard_url)
4379
+
4380
+ return job
4381
+
4382
+ async def _custom_optimize(
4383
+ self,
4384
+ *,
4385
+ content: Optional[genai_types.ContentOrDict] = None,
4386
+ config: Optional[types.OptimizeConfigOrDict] = None,
4387
+ ) -> types.OptimizeResponse:
4388
+ """Optimize a single prompt."""
4389
+ if isinstance(config, dict):
4390
+ config.pop("examples_dataframe", None)
4391
+ elif config and hasattr(config, "examples_dataframe"):
4392
+ del config.examples_dataframe
4393
+
4394
+ parameter_model = types._OptimizeRequestParameters(
4395
+ content=content,
4396
+ config=config,
4397
+ )
4398
+ request_url_dict: Optional[dict[str, str]]
4399
+ if not self._api_client.vertexai:
4400
+ raise ValueError("This method is only supported in the Vertex AI client.")
4401
+ else:
4402
+ request_dict = _OptimizeRequestParameters_to_vertex(parameter_model)
4403
+ request_url_dict = request_dict.get("_url")
4404
+ if request_url_dict:
4405
+ path = "tuningJobs:optimizePrompt".format_map(request_url_dict)
4406
+ else:
4407
+ path = "tuningJobs:optimizePrompt"
4408
+
4409
+ query_params = request_dict.get("_query")
4410
+ if query_params:
4411
+ path = f"{path}?{urlencode(query_params)}"
4412
+ # TODO: remove the hack that pops config.
4413
+ request_dict.pop("config", None)
4414
+
4415
+ http_options: Optional[types.HttpOptions] = None
4416
+ if (
4417
+ parameter_model.config is not None
4418
+ and parameter_model.config.http_options is not None
4419
+ ):
4420
+ http_options = parameter_model.config.http_options
4421
+
4422
+ request_dict = _common.convert_to_dict(request_dict)
4423
+ request_dict = _common.encode_unserializable_types(request_dict)
4424
+
4425
+ response = await self._api_client.async_request(
4426
+ "post", path, request_dict, http_options
4427
+ )
4428
+
4429
+ response_list = "" if not response.body else json.loads(response.body)
4430
+
4431
+ return_value = []
4432
+
4433
+ for response_dict in response_list:
4434
+ response_value = types.OptimizeResponseEndpoint._from_response(
4435
+ response=response_dict, kwargs=parameter_model.model_dump()
4436
+ )
4437
+ self._api_client._verify_response(response_value)
4438
+ content = response_value.content
4439
+ if content is not None:
4440
+ parts = content.parts
4441
+ if parts and parts[0].text is not None:
4442
+ return_value.append(parts[0].text)
4443
+
4444
+ output = "".join(return_value)
4445
+ final_response = types.OptimizeResponse(raw_text_response=output)
4446
+ try:
4447
+ final_response.parsed_response = _prompt_optimizer_utils._parse(output)
4448
+ except Exception as e:
4449
+ logger.warning(
4450
+ f"Failed to parse response: {e}. Returning only raw_text_response."
4451
+ )
4452
+ return final_response
4453
+
4454
+ @_common.experimental_warning(
4455
+ "The Vertex SDK GenAI prompts.optimize method is "
4456
+ "experimental, and may change in future versions."
4457
+ )
4458
+ async def optimize(
4459
+ self,
4460
+ *,
4461
+ prompt: str,
4462
+ config: Optional[types.OptimizeConfigOrDict] = None,
4463
+ ) -> types.OptimizeResponse:
4464
+ """Makes an async request to the optimizePrompt endpoint and returns an optimized prompt.
4465
+
4466
+ Example usage:
4467
+ client = agentplatform.Client(project=PROJECT_NAME, location='us-central1')
4468
+ prompt = "Generate system instructions for analyzing medical articles"
4469
+ response = await client.aio.prompts.optimize(prompt=prompt)
4470
+
4471
+ Args:
4472
+ prompt: Required. The prompt to optimize.
4473
+ config: Optional.The configuration for prompt optimization. To optimize
4474
+ prompts from Android API provide
4475
+ types.OptimizeConfig(
4476
+ optimization_target=types.OptimizeTarget.OPTIMIZATION_TARGET_GEMINI_NANO
4477
+ )
4478
+ For few-shot optimization, provide:
4479
+ optim_target = types.OptimizeTarget.OPTIMIZATION_TARGET_FEW_SHOT_RUBRICS # or types.OptimizeTarget.OPTIMIZATION_TARGET_FEW_SHOT_TARGET_RESPONSE
4480
+ types.OptimizeConfig(
4481
+ optimization_target=optim_target,
4482
+ examples_dataframe=dataframe
4483
+ )
4484
+ OPTIMIZATION_TARGET_FEW_SHOT_RUBRICS indicates that the few-shot
4485
+ examples include specific scoring rubrics and their corresponding
4486
+ evaluations.
4487
+ OPTIMIZATION_TARGET_FEW_SHOT_TARGET_RESPONSE indicates that the few-shot
4488
+ examples include a ground-truth target response.
4489
+ Returns:
4490
+ The parsed response from the API request.
4491
+ """
4492
+ if isinstance(config, dict):
4493
+ config = types.OptimizeConfig(**config)
4494
+
4495
+ optimization_target: Optional[types.OptimizeTarget] = None
4496
+ if config is not None:
4497
+ optimization_target = config.optimization_target
4498
+
4499
+ final_prompt = prompt
4500
+ if (
4501
+ optimization_target
4502
+ == types.OptimizeTarget.OPTIMIZATION_TARGET_FEW_SHOT_RUBRICS
4503
+ or optimization_target
4504
+ == types.OptimizeTarget.OPTIMIZATION_TARGET_FEW_SHOT_TARGET_RESPONSE
4505
+ ):
4506
+ final_prompt = _prompt_optimizer_utils._get_few_shot_prompt(prompt, config)
4507
+
4508
+ # TODO: b/435653980 - replace the custom method with a generated method.
4509
+ config_for_api = config.model_copy() if config else None
4510
+ return await self._custom_optimize(
4511
+ content=genai_types.Content(
4512
+ parts=[genai_types.Part(text=final_prompt)], role="user"
4513
+ ),
4514
+ config=config_for_api,
4515
+ )