azure-ai-evaluation 1.0.0b2__py3-none-any.whl → 1.13.3__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.

Potentially problematic release.


This version of azure-ai-evaluation might be problematic. Click here for more details.

Files changed (299) hide show
  1. azure/ai/evaluation/__init__.py +100 -5
  2. azure/ai/evaluation/{_evaluators/_chat → _aoai}/__init__.py +3 -2
  3. azure/ai/evaluation/_aoai/aoai_grader.py +140 -0
  4. azure/ai/evaluation/_aoai/label_grader.py +68 -0
  5. azure/ai/evaluation/_aoai/python_grader.py +86 -0
  6. azure/ai/evaluation/_aoai/score_model_grader.py +94 -0
  7. azure/ai/evaluation/_aoai/string_check_grader.py +66 -0
  8. azure/ai/evaluation/_aoai/text_similarity_grader.py +80 -0
  9. azure/ai/evaluation/_azure/__init__.py +3 -0
  10. azure/ai/evaluation/_azure/_clients.py +204 -0
  11. azure/ai/evaluation/_azure/_envs.py +207 -0
  12. azure/ai/evaluation/_azure/_models.py +227 -0
  13. azure/ai/evaluation/_azure/_token_manager.py +129 -0
  14. azure/ai/evaluation/_common/__init__.py +9 -1
  15. azure/ai/evaluation/{simulator/_helpers → _common}/_experimental.py +24 -9
  16. azure/ai/evaluation/_common/constants.py +131 -2
  17. azure/ai/evaluation/_common/evaluation_onedp_client.py +169 -0
  18. azure/ai/evaluation/_common/math.py +89 -0
  19. azure/ai/evaluation/_common/onedp/__init__.py +32 -0
  20. azure/ai/evaluation/_common/onedp/_client.py +166 -0
  21. azure/ai/evaluation/_common/onedp/_configuration.py +72 -0
  22. azure/ai/evaluation/_common/onedp/_model_base.py +1232 -0
  23. azure/ai/evaluation/_common/onedp/_patch.py +21 -0
  24. azure/ai/evaluation/_common/onedp/_serialization.py +2032 -0
  25. azure/ai/evaluation/_common/onedp/_types.py +21 -0
  26. azure/ai/evaluation/_common/onedp/_utils/__init__.py +6 -0
  27. azure/ai/evaluation/_common/onedp/_utils/model_base.py +1232 -0
  28. azure/ai/evaluation/_common/onedp/_utils/serialization.py +2032 -0
  29. azure/ai/evaluation/_common/onedp/_validation.py +66 -0
  30. azure/ai/evaluation/_common/onedp/_vendor.py +50 -0
  31. azure/ai/evaluation/_common/onedp/_version.py +9 -0
  32. azure/ai/evaluation/_common/onedp/aio/__init__.py +29 -0
  33. azure/ai/evaluation/_common/onedp/aio/_client.py +168 -0
  34. azure/ai/evaluation/_common/onedp/aio/_configuration.py +72 -0
  35. azure/ai/evaluation/_common/onedp/aio/_patch.py +21 -0
  36. azure/ai/evaluation/_common/onedp/aio/operations/__init__.py +49 -0
  37. azure/ai/evaluation/_common/onedp/aio/operations/_operations.py +7143 -0
  38. azure/ai/evaluation/_common/onedp/aio/operations/_patch.py +21 -0
  39. azure/ai/evaluation/_common/onedp/models/__init__.py +358 -0
  40. azure/ai/evaluation/_common/onedp/models/_enums.py +447 -0
  41. azure/ai/evaluation/_common/onedp/models/_models.py +5963 -0
  42. azure/ai/evaluation/_common/onedp/models/_patch.py +21 -0
  43. azure/ai/evaluation/_common/onedp/operations/__init__.py +49 -0
  44. azure/ai/evaluation/_common/onedp/operations/_operations.py +8951 -0
  45. azure/ai/evaluation/_common/onedp/operations/_patch.py +21 -0
  46. azure/ai/evaluation/_common/onedp/py.typed +1 -0
  47. azure/ai/evaluation/_common/onedp/servicepatterns/__init__.py +1 -0
  48. azure/ai/evaluation/_common/onedp/servicepatterns/aio/__init__.py +1 -0
  49. azure/ai/evaluation/_common/onedp/servicepatterns/aio/operations/__init__.py +25 -0
  50. azure/ai/evaluation/_common/onedp/servicepatterns/aio/operations/_operations.py +34 -0
  51. azure/ai/evaluation/_common/onedp/servicepatterns/aio/operations/_patch.py +20 -0
  52. azure/ai/evaluation/_common/onedp/servicepatterns/buildingblocks/__init__.py +1 -0
  53. azure/ai/evaluation/_common/onedp/servicepatterns/buildingblocks/aio/__init__.py +1 -0
  54. azure/ai/evaluation/_common/onedp/servicepatterns/buildingblocks/aio/operations/__init__.py +22 -0
  55. azure/ai/evaluation/_common/onedp/servicepatterns/buildingblocks/aio/operations/_operations.py +29 -0
  56. azure/ai/evaluation/_common/onedp/servicepatterns/buildingblocks/aio/operations/_patch.py +20 -0
  57. azure/ai/evaluation/_common/onedp/servicepatterns/buildingblocks/operations/__init__.py +22 -0
  58. azure/ai/evaluation/_common/onedp/servicepatterns/buildingblocks/operations/_operations.py +29 -0
  59. azure/ai/evaluation/_common/onedp/servicepatterns/buildingblocks/operations/_patch.py +20 -0
  60. azure/ai/evaluation/_common/onedp/servicepatterns/operations/__init__.py +25 -0
  61. azure/ai/evaluation/_common/onedp/servicepatterns/operations/_operations.py +34 -0
  62. azure/ai/evaluation/_common/onedp/servicepatterns/operations/_patch.py +20 -0
  63. azure/ai/evaluation/_common/rai_service.py +831 -142
  64. azure/ai/evaluation/_common/raiclient/__init__.py +34 -0
  65. azure/ai/evaluation/_common/raiclient/_client.py +128 -0
  66. azure/ai/evaluation/_common/raiclient/_configuration.py +87 -0
  67. azure/ai/evaluation/_common/raiclient/_model_base.py +1235 -0
  68. azure/ai/evaluation/_common/raiclient/_patch.py +20 -0
  69. azure/ai/evaluation/_common/raiclient/_serialization.py +2050 -0
  70. azure/ai/evaluation/_common/raiclient/_version.py +9 -0
  71. azure/ai/evaluation/_common/raiclient/aio/__init__.py +29 -0
  72. azure/ai/evaluation/_common/raiclient/aio/_client.py +130 -0
  73. azure/ai/evaluation/_common/raiclient/aio/_configuration.py +87 -0
  74. azure/ai/evaluation/_common/raiclient/aio/_patch.py +20 -0
  75. azure/ai/evaluation/_common/raiclient/aio/operations/__init__.py +25 -0
  76. azure/ai/evaluation/_common/raiclient/aio/operations/_operations.py +981 -0
  77. azure/ai/evaluation/_common/raiclient/aio/operations/_patch.py +20 -0
  78. azure/ai/evaluation/_common/raiclient/models/__init__.py +60 -0
  79. azure/ai/evaluation/_common/raiclient/models/_enums.py +18 -0
  80. azure/ai/evaluation/_common/raiclient/models/_models.py +651 -0
  81. azure/ai/evaluation/_common/raiclient/models/_patch.py +20 -0
  82. azure/ai/evaluation/_common/raiclient/operations/__init__.py +25 -0
  83. azure/ai/evaluation/_common/raiclient/operations/_operations.py +1238 -0
  84. azure/ai/evaluation/_common/raiclient/operations/_patch.py +20 -0
  85. azure/ai/evaluation/_common/raiclient/py.typed +1 -0
  86. azure/ai/evaluation/_common/utils.py +870 -34
  87. azure/ai/evaluation/_constants.py +167 -6
  88. azure/ai/evaluation/_converters/__init__.py +3 -0
  89. azure/ai/evaluation/_converters/_ai_services.py +899 -0
  90. azure/ai/evaluation/_converters/_models.py +467 -0
  91. azure/ai/evaluation/_converters/_sk_services.py +495 -0
  92. azure/ai/evaluation/_eval_mapping.py +83 -0
  93. azure/ai/evaluation/_evaluate/_batch_run/__init__.py +17 -0
  94. azure/ai/evaluation/_evaluate/_batch_run/_run_submitter_client.py +176 -0
  95. azure/ai/evaluation/_evaluate/_batch_run/batch_clients.py +82 -0
  96. azure/ai/evaluation/_evaluate/{_batch_run_client → _batch_run}/code_client.py +47 -25
  97. azure/ai/evaluation/_evaluate/{_batch_run_client/batch_run_context.py → _batch_run/eval_run_context.py} +42 -13
  98. azure/ai/evaluation/_evaluate/_batch_run/proxy_client.py +124 -0
  99. azure/ai/evaluation/_evaluate/_batch_run/target_run_context.py +62 -0
  100. azure/ai/evaluation/_evaluate/_eval_run.py +102 -59
  101. azure/ai/evaluation/_evaluate/_evaluate.py +2134 -311
  102. azure/ai/evaluation/_evaluate/_evaluate_aoai.py +992 -0
  103. azure/ai/evaluation/_evaluate/_telemetry/__init__.py +14 -99
  104. azure/ai/evaluation/_evaluate/_utils.py +289 -40
  105. azure/ai/evaluation/_evaluator_definition.py +76 -0
  106. azure/ai/evaluation/_evaluators/_bleu/_bleu.py +93 -42
  107. azure/ai/evaluation/_evaluators/_code_vulnerability/__init__.py +5 -0
  108. azure/ai/evaluation/_evaluators/_code_vulnerability/_code_vulnerability.py +119 -0
  109. azure/ai/evaluation/_evaluators/_coherence/_coherence.py +117 -91
  110. azure/ai/evaluation/_evaluators/_coherence/coherence.prompty +76 -39
  111. azure/ai/evaluation/_evaluators/_common/__init__.py +15 -0
  112. azure/ai/evaluation/_evaluators/_common/_base_eval.py +742 -0
  113. azure/ai/evaluation/_evaluators/_common/_base_multi_eval.py +63 -0
  114. azure/ai/evaluation/_evaluators/_common/_base_prompty_eval.py +345 -0
  115. azure/ai/evaluation/_evaluators/_common/_base_rai_svc_eval.py +198 -0
  116. azure/ai/evaluation/_evaluators/_common/_conversation_aggregators.py +49 -0
  117. azure/ai/evaluation/_evaluators/_content_safety/__init__.py +0 -4
  118. azure/ai/evaluation/_evaluators/_content_safety/_content_safety.py +144 -86
  119. azure/ai/evaluation/_evaluators/_content_safety/_hate_unfairness.py +138 -57
  120. azure/ai/evaluation/_evaluators/_content_safety/_self_harm.py +123 -55
  121. azure/ai/evaluation/_evaluators/_content_safety/_sexual.py +133 -54
  122. azure/ai/evaluation/_evaluators/_content_safety/_violence.py +134 -54
  123. azure/ai/evaluation/_evaluators/_document_retrieval/__init__.py +7 -0
  124. azure/ai/evaluation/_evaluators/_document_retrieval/_document_retrieval.py +442 -0
  125. azure/ai/evaluation/_evaluators/_eci/_eci.py +49 -56
  126. azure/ai/evaluation/_evaluators/_f1_score/_f1_score.py +102 -60
  127. azure/ai/evaluation/_evaluators/_fluency/_fluency.py +115 -92
  128. azure/ai/evaluation/_evaluators/_fluency/fluency.prompty +66 -41
  129. azure/ai/evaluation/_evaluators/_gleu/_gleu.py +90 -37
  130. azure/ai/evaluation/_evaluators/_groundedness/_groundedness.py +318 -82
  131. azure/ai/evaluation/_evaluators/_groundedness/groundedness_with_query.prompty +114 -0
  132. azure/ai/evaluation/_evaluators/_groundedness/groundedness_without_query.prompty +104 -0
  133. azure/ai/evaluation/{_evaluate/_batch_run_client → _evaluators/_intent_resolution}/__init__.py +3 -4
  134. azure/ai/evaluation/_evaluators/_intent_resolution/_intent_resolution.py +196 -0
  135. azure/ai/evaluation/_evaluators/_intent_resolution/intent_resolution.prompty +275 -0
  136. azure/ai/evaluation/_evaluators/_meteor/_meteor.py +107 -61
  137. azure/ai/evaluation/_evaluators/_protected_material/_protected_material.py +104 -77
  138. azure/ai/evaluation/_evaluators/_qa/_qa.py +115 -63
  139. azure/ai/evaluation/_evaluators/_relevance/_relevance.py +182 -98
  140. azure/ai/evaluation/_evaluators/_relevance/relevance.prompty +178 -49
  141. azure/ai/evaluation/_evaluators/_response_completeness/__init__.py +7 -0
  142. azure/ai/evaluation/_evaluators/_response_completeness/_response_completeness.py +202 -0
  143. azure/ai/evaluation/_evaluators/_response_completeness/response_completeness.prompty +84 -0
  144. azure/ai/evaluation/_evaluators/{_chat/retrieval → _retrieval}/__init__.py +2 -2
  145. azure/ai/evaluation/_evaluators/_retrieval/_retrieval.py +148 -0
  146. azure/ai/evaluation/_evaluators/_retrieval/retrieval.prompty +93 -0
  147. azure/ai/evaluation/_evaluators/_rouge/_rouge.py +189 -50
  148. azure/ai/evaluation/_evaluators/_service_groundedness/__init__.py +9 -0
  149. azure/ai/evaluation/_evaluators/_service_groundedness/_service_groundedness.py +179 -0
  150. azure/ai/evaluation/_evaluators/_similarity/_similarity.py +102 -91
  151. azure/ai/evaluation/_evaluators/_similarity/similarity.prompty +0 -5
  152. azure/ai/evaluation/_evaluators/_task_adherence/__init__.py +7 -0
  153. azure/ai/evaluation/_evaluators/_task_adherence/_task_adherence.py +226 -0
  154. azure/ai/evaluation/_evaluators/_task_adherence/task_adherence.prompty +101 -0
  155. azure/ai/evaluation/_evaluators/_task_completion/__init__.py +7 -0
  156. azure/ai/evaluation/_evaluators/_task_completion/_task_completion.py +177 -0
  157. azure/ai/evaluation/_evaluators/_task_completion/task_completion.prompty +220 -0
  158. azure/ai/evaluation/_evaluators/_task_navigation_efficiency/__init__.py +7 -0
  159. azure/ai/evaluation/_evaluators/_task_navigation_efficiency/_task_navigation_efficiency.py +384 -0
  160. azure/ai/evaluation/_evaluators/_tool_call_accuracy/__init__.py +9 -0
  161. azure/ai/evaluation/_evaluators/_tool_call_accuracy/_tool_call_accuracy.py +298 -0
  162. azure/ai/evaluation/_evaluators/_tool_call_accuracy/tool_call_accuracy.prompty +166 -0
  163. azure/ai/evaluation/_evaluators/_tool_input_accuracy/__init__.py +9 -0
  164. azure/ai/evaluation/_evaluators/_tool_input_accuracy/_tool_input_accuracy.py +263 -0
  165. azure/ai/evaluation/_evaluators/_tool_input_accuracy/tool_input_accuracy.prompty +76 -0
  166. azure/ai/evaluation/_evaluators/_tool_output_utilization/__init__.py +7 -0
  167. azure/ai/evaluation/_evaluators/_tool_output_utilization/_tool_output_utilization.py +225 -0
  168. azure/ai/evaluation/_evaluators/_tool_output_utilization/tool_output_utilization.prompty +221 -0
  169. azure/ai/evaluation/_evaluators/_tool_selection/__init__.py +9 -0
  170. azure/ai/evaluation/_evaluators/_tool_selection/_tool_selection.py +266 -0
  171. azure/ai/evaluation/_evaluators/_tool_selection/tool_selection.prompty +104 -0
  172. azure/ai/evaluation/_evaluators/_tool_success/__init__.py +7 -0
  173. azure/ai/evaluation/_evaluators/_tool_success/_tool_success.py +301 -0
  174. azure/ai/evaluation/_evaluators/_tool_success/tool_success.prompty +321 -0
  175. azure/ai/evaluation/_evaluators/_ungrounded_attributes/__init__.py +5 -0
  176. azure/ai/evaluation/_evaluators/_ungrounded_attributes/_ungrounded_attributes.py +102 -0
  177. azure/ai/evaluation/_evaluators/_xpia/xpia.py +109 -107
  178. azure/ai/evaluation/_exceptions.py +51 -7
  179. azure/ai/evaluation/_http_utils.py +210 -137
  180. azure/ai/evaluation/_legacy/__init__.py +3 -0
  181. azure/ai/evaluation/_legacy/_adapters/__init__.py +7 -0
  182. azure/ai/evaluation/_legacy/_adapters/_check.py +17 -0
  183. azure/ai/evaluation/_legacy/_adapters/_configuration.py +45 -0
  184. azure/ai/evaluation/_legacy/_adapters/_constants.py +10 -0
  185. azure/ai/evaluation/_legacy/_adapters/_errors.py +29 -0
  186. azure/ai/evaluation/_legacy/_adapters/_flows.py +28 -0
  187. azure/ai/evaluation/_legacy/_adapters/_service.py +16 -0
  188. azure/ai/evaluation/_legacy/_adapters/client.py +51 -0
  189. azure/ai/evaluation/_legacy/_adapters/entities.py +26 -0
  190. azure/ai/evaluation/_legacy/_adapters/tracing.py +28 -0
  191. azure/ai/evaluation/_legacy/_adapters/types.py +15 -0
  192. azure/ai/evaluation/_legacy/_adapters/utils.py +31 -0
  193. azure/ai/evaluation/_legacy/_batch_engine/__init__.py +9 -0
  194. azure/ai/evaluation/_legacy/_batch_engine/_config.py +48 -0
  195. azure/ai/evaluation/_legacy/_batch_engine/_engine.py +477 -0
  196. azure/ai/evaluation/_legacy/_batch_engine/_exceptions.py +88 -0
  197. azure/ai/evaluation/_legacy/_batch_engine/_openai_injector.py +132 -0
  198. azure/ai/evaluation/_legacy/_batch_engine/_result.py +107 -0
  199. azure/ai/evaluation/_legacy/_batch_engine/_run.py +127 -0
  200. azure/ai/evaluation/_legacy/_batch_engine/_run_storage.py +128 -0
  201. azure/ai/evaluation/_legacy/_batch_engine/_run_submitter.py +262 -0
  202. azure/ai/evaluation/_legacy/_batch_engine/_status.py +25 -0
  203. azure/ai/evaluation/_legacy/_batch_engine/_trace.py +97 -0
  204. azure/ai/evaluation/_legacy/_batch_engine/_utils.py +97 -0
  205. azure/ai/evaluation/_legacy/_batch_engine/_utils_deprecated.py +131 -0
  206. azure/ai/evaluation/_legacy/_common/__init__.py +3 -0
  207. azure/ai/evaluation/_legacy/_common/_async_token_provider.py +117 -0
  208. azure/ai/evaluation/_legacy/_common/_logging.py +292 -0
  209. azure/ai/evaluation/_legacy/_common/_thread_pool_executor_with_context.py +17 -0
  210. azure/ai/evaluation/_legacy/prompty/__init__.py +36 -0
  211. azure/ai/evaluation/_legacy/prompty/_connection.py +119 -0
  212. azure/ai/evaluation/_legacy/prompty/_exceptions.py +139 -0
  213. azure/ai/evaluation/_legacy/prompty/_prompty.py +430 -0
  214. azure/ai/evaluation/_legacy/prompty/_utils.py +663 -0
  215. azure/ai/evaluation/_legacy/prompty/_yaml_utils.py +99 -0
  216. azure/ai/evaluation/_model_configurations.py +130 -8
  217. azure/ai/evaluation/_safety_evaluation/__init__.py +3 -0
  218. azure/ai/evaluation/_safety_evaluation/_generated_rai_client.py +0 -0
  219. azure/ai/evaluation/_safety_evaluation/_safety_evaluation.py +917 -0
  220. azure/ai/evaluation/_user_agent.py +32 -1
  221. azure/ai/evaluation/_vendor/__init__.py +3 -0
  222. azure/ai/evaluation/_vendor/rouge_score/__init__.py +14 -0
  223. azure/ai/evaluation/_vendor/rouge_score/rouge_scorer.py +324 -0
  224. azure/ai/evaluation/_vendor/rouge_score/scoring.py +59 -0
  225. azure/ai/evaluation/_vendor/rouge_score/tokenize.py +59 -0
  226. azure/ai/evaluation/_vendor/rouge_score/tokenizers.py +53 -0
  227. azure/ai/evaluation/_version.py +2 -1
  228. azure/ai/evaluation/red_team/__init__.py +22 -0
  229. azure/ai/evaluation/red_team/_agent/__init__.py +3 -0
  230. azure/ai/evaluation/red_team/_agent/_agent_functions.py +261 -0
  231. azure/ai/evaluation/red_team/_agent/_agent_tools.py +461 -0
  232. azure/ai/evaluation/red_team/_agent/_agent_utils.py +89 -0
  233. azure/ai/evaluation/red_team/_agent/_semantic_kernel_plugin.py +228 -0
  234. azure/ai/evaluation/red_team/_attack_objective_generator.py +268 -0
  235. azure/ai/evaluation/red_team/_attack_strategy.py +49 -0
  236. azure/ai/evaluation/red_team/_callback_chat_target.py +115 -0
  237. azure/ai/evaluation/red_team/_default_converter.py +21 -0
  238. azure/ai/evaluation/red_team/_evaluation_processor.py +505 -0
  239. azure/ai/evaluation/red_team/_mlflow_integration.py +430 -0
  240. azure/ai/evaluation/red_team/_orchestrator_manager.py +803 -0
  241. azure/ai/evaluation/red_team/_red_team.py +1717 -0
  242. azure/ai/evaluation/red_team/_red_team_result.py +661 -0
  243. azure/ai/evaluation/red_team/_result_processor.py +1708 -0
  244. azure/ai/evaluation/red_team/_utils/__init__.py +37 -0
  245. azure/ai/evaluation/red_team/_utils/_rai_service_eval_chat_target.py +128 -0
  246. azure/ai/evaluation/red_team/_utils/_rai_service_target.py +601 -0
  247. azure/ai/evaluation/red_team/_utils/_rai_service_true_false_scorer.py +114 -0
  248. azure/ai/evaluation/red_team/_utils/constants.py +72 -0
  249. azure/ai/evaluation/red_team/_utils/exception_utils.py +345 -0
  250. azure/ai/evaluation/red_team/_utils/file_utils.py +266 -0
  251. azure/ai/evaluation/red_team/_utils/formatting_utils.py +365 -0
  252. azure/ai/evaluation/red_team/_utils/logging_utils.py +139 -0
  253. azure/ai/evaluation/red_team/_utils/metric_mapping.py +73 -0
  254. azure/ai/evaluation/red_team/_utils/objective_utils.py +46 -0
  255. azure/ai/evaluation/red_team/_utils/progress_utils.py +252 -0
  256. azure/ai/evaluation/red_team/_utils/retry_utils.py +218 -0
  257. azure/ai/evaluation/red_team/_utils/strategy_utils.py +218 -0
  258. azure/ai/evaluation/simulator/__init__.py +2 -1
  259. azure/ai/evaluation/simulator/_adversarial_scenario.py +26 -1
  260. azure/ai/evaluation/simulator/_adversarial_simulator.py +270 -144
  261. azure/ai/evaluation/simulator/_constants.py +12 -1
  262. azure/ai/evaluation/simulator/_conversation/__init__.py +151 -23
  263. azure/ai/evaluation/simulator/_conversation/_conversation.py +10 -6
  264. azure/ai/evaluation/simulator/_conversation/constants.py +1 -1
  265. azure/ai/evaluation/simulator/_data_sources/__init__.py +3 -0
  266. azure/ai/evaluation/simulator/_data_sources/grounding.json +1150 -0
  267. azure/ai/evaluation/simulator/_direct_attack_simulator.py +54 -75
  268. azure/ai/evaluation/simulator/_helpers/__init__.py +1 -2
  269. azure/ai/evaluation/simulator/_helpers/_language_suffix_mapping.py +1 -0
  270. azure/ai/evaluation/simulator/_helpers/_simulator_data_classes.py +26 -5
  271. azure/ai/evaluation/simulator/_indirect_attack_simulator.py +145 -104
  272. azure/ai/evaluation/simulator/_model_tools/__init__.py +2 -1
  273. azure/ai/evaluation/simulator/_model_tools/_generated_rai_client.py +225 -0
  274. azure/ai/evaluation/simulator/_model_tools/_identity_manager.py +80 -30
  275. azure/ai/evaluation/simulator/_model_tools/_proxy_completion_model.py +117 -45
  276. azure/ai/evaluation/simulator/_model_tools/_rai_client.py +109 -7
  277. azure/ai/evaluation/simulator/_model_tools/_template_handler.py +97 -33
  278. azure/ai/evaluation/simulator/_model_tools/models.py +30 -27
  279. azure/ai/evaluation/simulator/_prompty/task_query_response.prompty +6 -10
  280. azure/ai/evaluation/simulator/_prompty/task_simulate.prompty +6 -5
  281. azure/ai/evaluation/simulator/_simulator.py +302 -208
  282. azure/ai/evaluation/simulator/_utils.py +31 -13
  283. azure_ai_evaluation-1.13.3.dist-info/METADATA +939 -0
  284. azure_ai_evaluation-1.13.3.dist-info/RECORD +305 -0
  285. {azure_ai_evaluation-1.0.0b2.dist-info → azure_ai_evaluation-1.13.3.dist-info}/WHEEL +1 -1
  286. azure_ai_evaluation-1.13.3.dist-info/licenses/NOTICE.txt +70 -0
  287. azure/ai/evaluation/_evaluate/_batch_run_client/proxy_client.py +0 -71
  288. azure/ai/evaluation/_evaluators/_chat/_chat.py +0 -357
  289. azure/ai/evaluation/_evaluators/_chat/retrieval/_retrieval.py +0 -157
  290. azure/ai/evaluation/_evaluators/_chat/retrieval/retrieval.prompty +0 -48
  291. azure/ai/evaluation/_evaluators/_content_safety/_content_safety_base.py +0 -65
  292. azure/ai/evaluation/_evaluators/_content_safety/_content_safety_chat.py +0 -301
  293. azure/ai/evaluation/_evaluators/_groundedness/groundedness.prompty +0 -54
  294. azure/ai/evaluation/_evaluators/_protected_materials/__init__.py +0 -5
  295. azure/ai/evaluation/_evaluators/_protected_materials/_protected_materials.py +0 -104
  296. azure/ai/evaluation/simulator/_tracing.py +0 -89
  297. azure_ai_evaluation-1.0.0b2.dist-info/METADATA +0 -449
  298. azure_ai_evaluation-1.0.0b2.dist-info/RECORD +0 -99
  299. {azure_ai_evaluation-1.0.0b2.dist-info → azure_ai_evaluation-1.13.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,225 @@
1
+ # ---------------------------------------------------------
2
+ # Copyright (c) Microsoft Corporation. All rights reserved.
3
+ # ---------------------------------------------------------
4
+
5
+ import logging
6
+ import os
7
+ from typing import Dict, List, Optional, Union
8
+
9
+ from azure.core.credentials import TokenCredential
10
+ from azure.core.pipeline.policies import UserAgentPolicy
11
+ from azure.ai.evaluation._model_configurations import AzureAIProject
12
+ from azure.ai.evaluation.simulator._model_tools import ManagedIdentityAPITokenManager
13
+ from azure.ai.evaluation._common.raiclient import MachineLearningServicesClient
14
+ from azure.ai.evaluation._constants import TokenScope
15
+ from azure.ai.evaluation._common.utils import is_onedp_project
16
+ from azure.ai.evaluation._common.onedp import ProjectsClient as AIProjectClient
17
+ from azure.ai.evaluation._common import EvaluationServiceOneDPClient
18
+ from azure.ai.evaluation._user_agent import UserAgentSingleton
19
+ import jwt
20
+ import time
21
+ import ast
22
+
23
+
24
+ class GeneratedRAIClient:
25
+ """Client for the Responsible AI Service using the auto-generated MachineLearningServicesClient.
26
+
27
+ :param azure_ai_project: The Azure AI project, which can either be a string representing the project endpoint
28
+ or an instance of AzureAIProject. It contains subscription id, resource group, and project name.
29
+ :type azure_ai_project: Union[str, ~azure.ai.evaluation.AzureAIProject]
30
+ :param token_manager: The token manager
31
+ :type token_manager: ~azure.ai.evaluation.simulator._model_tools._identity_manager.APITokenManager
32
+ """
33
+
34
+ def __init__(
35
+ self,
36
+ azure_ai_project: Union[AzureAIProject, str],
37
+ token_manager: ManagedIdentityAPITokenManager,
38
+ ):
39
+ self.azure_ai_project = azure_ai_project
40
+ self.token_manager = token_manager
41
+ self.logger = logging.getLogger(__name__)
42
+
43
+ user_agent_policy = UserAgentPolicy(base_user_agent=UserAgentSingleton().value)
44
+
45
+ if not is_onedp_project(azure_ai_project):
46
+ # Service URL construction
47
+ if "RAI_SVC_URL" in os.environ:
48
+ endpoint = os.environ["RAI_SVC_URL"].rstrip("/")
49
+ else:
50
+ endpoint = self._get_service_discovery_url()
51
+
52
+ # Create the autogenerated client
53
+ self._client = MachineLearningServicesClient(
54
+ endpoint=endpoint,
55
+ subscription_id=self.azure_ai_project["subscription_id"],
56
+ resource_group_name=self.azure_ai_project["resource_group_name"],
57
+ workspace_name=self.azure_ai_project["project_name"],
58
+ credential=self.token_manager,
59
+ ).rai_svc
60
+ else:
61
+ self._client = AIProjectClient(
62
+ endpoint=azure_ai_project,
63
+ credential=token_manager,
64
+ user_agent_policy=user_agent_policy,
65
+ ).red_teams
66
+ self._evaluation_onedp_client = EvaluationServiceOneDPClient(
67
+ endpoint=azure_ai_project,
68
+ credential=token_manager,
69
+ user_agent_policy=user_agent_policy,
70
+ )
71
+
72
+ def _get_service_discovery_url(self):
73
+ """Get the service discovery URL.
74
+
75
+ :return: The service discovery URL
76
+ :rtype: str
77
+ """
78
+ import requests
79
+
80
+ bearer_token = self._fetch_or_reuse_token(self.token_manager)
81
+ headers = {
82
+ "Authorization": f"Bearer {bearer_token}",
83
+ "Content-Type": "application/json",
84
+ }
85
+
86
+ response = requests.get(
87
+ f"https://management.azure.com/subscriptions/{self.azure_ai_project['subscription_id']}/"
88
+ f"resourceGroups/{self.azure_ai_project['resource_group_name']}/"
89
+ f"providers/Microsoft.MachineLearningServices/workspaces/{self.azure_ai_project['project_name']}?"
90
+ f"api-version=2023-08-01-preview",
91
+ headers=headers,
92
+ timeout=5,
93
+ )
94
+
95
+ if response.status_code != 200:
96
+ msg = (
97
+ f"Failed to connect to your Azure AI project. Please check if the project scope is configured "
98
+ f"correctly, and make sure you have the necessary access permissions. "
99
+ f"Status code: {response.status_code}."
100
+ )
101
+ raise Exception(msg)
102
+
103
+ # Parse the discovery URL
104
+ from urllib.parse import urlparse
105
+
106
+ base_url = urlparse(response.json()["properties"]["discoveryUrl"])
107
+ return f"{base_url.scheme}://{base_url.netloc}"
108
+
109
+ async def get_attack_objectives(
110
+ self,
111
+ *,
112
+ risk_type: Optional[str] = None,
113
+ risk_category: Optional[str] = None,
114
+ application_scenario: str = None,
115
+ strategy: Optional[str] = None,
116
+ language: str = "en",
117
+ scan_session_id: Optional[str] = None,
118
+ target: Optional[str] = None,
119
+ client_id: Optional[str] = None,
120
+ ) -> Dict:
121
+ """Get attack objectives using the auto-generated operations.
122
+
123
+ :param risk_type: Optional risk type to filter the attack objectives
124
+ :type risk_type: Optional[str]
125
+ :param risk_category: Optional risk category to filter the attack objectives
126
+ :type risk_category: Optional[str]
127
+ :param application_scenario: Optional description of the application scenario for context
128
+ :type application_scenario: str
129
+ :param strategy: Optional strategy to filter the attack objectives
130
+ :type strategy: Optional[str]
131
+ :param language: Language code for the attack objectives (e.g., "en", "es", "fr")
132
+ :type language: str
133
+ :param scan_session_id: Optional unique session ID for the scan
134
+ :type scan_session_id: Optional[str]
135
+ :param target: Optional target type (model/agent)
136
+ :type target: Optional[str]
137
+ :param client_id: Optional client ID for ACA token authorization
138
+ :type client_id: Optional[str]
139
+ :return: The attack objectives
140
+ :rtype: Dict
141
+ """
142
+ try:
143
+ # Build headers dictionary
144
+ headers = {}
145
+ if scan_session_id:
146
+ headers["x-ms-client-request-id"] = scan_session_id
147
+ if client_id:
148
+ from azure.identity import DefaultAzureCredential
149
+
150
+ self.logger.info(f"Using client_id: {client_id} to set token in aml-aca-token header ")
151
+
152
+ # Get token using the client_id for managed identity
153
+ managed_identity_credential = DefaultAzureCredential(
154
+ managed_identity_client_id=client_id, exclude_interactive_browser_credential=True
155
+ )
156
+ token = managed_identity_credential.get_token(TokenScope.DEFAULT_AZURE_MANAGEMENT).token
157
+ headers["aml-aca-token"] = token
158
+
159
+ # Send the request using the autogenerated client
160
+ response = self._client.get_attack_objectives(
161
+ risk_types=[risk_type],
162
+ risk_category=risk_category,
163
+ lang=language,
164
+ strategy=strategy,
165
+ target_type=target,
166
+ headers=headers,
167
+ )
168
+
169
+ return response
170
+
171
+ except Exception as e:
172
+ # Log the exception for debugging purposes
173
+ import logging
174
+
175
+ logging.error(f"Error in get_attack_objectives: {str(e)}")
176
+ raise
177
+
178
+ async def get_jailbreak_prefixes(self, scan_session_id: Optional[str] = None) -> List[str]:
179
+ """Get jailbreak prefixes using the auto-generated operations.
180
+
181
+ :param scan_session_id: Optional unique session ID for the scan
182
+ :type scan_session_id: Optional[str]
183
+ :return: The jailbreak prefixes
184
+ :rtype: List[str]
185
+ """
186
+ try:
187
+ # Send the request using the autogenerated client
188
+ response = self._client.get_jail_break_dataset_with_type(
189
+ type="upia", headers={"x-ms-client-request-id": scan_session_id}
190
+ )
191
+ if isinstance(response, list):
192
+ return response
193
+ else:
194
+ self.logger.error("Unexpected response format from get_jail_break_dataset_with_type")
195
+ raise ValueError("Unexpected response format from get_jail_break_dataset_with_type")
196
+
197
+ except Exception as e:
198
+ return [""]
199
+
200
+ def _fetch_or_reuse_token(self, credential: TokenCredential, token: Optional[str] = None) -> str:
201
+ """Get token. Fetch a new token if the current token is near expiry
202
+
203
+ :param credential: The Azure authentication credential.
204
+ :type credential:
205
+ ~azure.core.credentials.TokenCredential
206
+ :param token: The Azure authentication token. Defaults to None. If none, a new token will be fetched.
207
+ :type token: str
208
+ :return: The Azure authentication token.
209
+ """
210
+ if token:
211
+ # Decode the token to get its expiration time
212
+ try:
213
+ decoded_token = jwt.decode(token, options={"verify_signature": False})
214
+ except jwt.PyJWTError:
215
+ pass
216
+ else:
217
+ exp_time = decoded_token["exp"]
218
+ current_time = time.time()
219
+
220
+ # Return current token if not near expiry
221
+ if (exp_time - current_time) >= 300:
222
+ return token
223
+
224
+ # Get token
225
+ return credential.get_token(TokenScope.DEFAULT_AZURE_MANAGEMENT).token
@@ -3,22 +3,20 @@
3
3
  # ---------------------------------------------------------
4
4
 
5
5
  import asyncio
6
+ import inspect
6
7
  import logging
7
8
  import os
8
9
  import time
9
10
  from abc import ABC, abstractmethod
10
- from enum import Enum
11
- from typing import Dict, Optional, Union
11
+ from typing import Optional, Union, Any
12
12
 
13
+ from azure.ai.evaluation._constants import TokenScope
14
+ from azure.core.credentials import AccessToken, TokenCredential
13
15
  from azure.identity import DefaultAzureCredential, ManagedIdentityCredential
14
16
 
15
- AZURE_TOKEN_REFRESH_INTERVAL = 600 # seconds
16
-
17
-
18
- class TokenScope(Enum):
19
- """Token scopes for Azure endpoints"""
20
-
21
- DEFAULT_AZURE_MANAGEMENT = "https://management.azure.com/.default"
17
+ AZURE_TOKEN_REFRESH_INTERVAL = int(
18
+ os.getenv("AZURE_TOKEN_REFRESH_INTERVAL", "600")
19
+ ) # token refresh interval in seconds
22
20
 
23
21
 
24
22
  class APITokenManager(ABC):
@@ -29,24 +27,24 @@ class APITokenManager(ABC):
29
27
  :param auth_header: Authorization header prefix. Defaults to "Bearer"
30
28
  :type auth_header: str
31
29
  :param credential: Azure credential object
32
- :type credential: Optional[Union[azure.identity.DefaultAzureCredential, azure.identity.ManagedIdentityCredential]
30
+ :type credential: Optional[TokenCredential]
33
31
  """
34
32
 
35
33
  def __init__(
36
34
  self,
37
35
  logger: logging.Logger,
38
36
  auth_header: str = "Bearer",
39
- credential: Optional[Union[DefaultAzureCredential, ManagedIdentityCredential]] = None,
37
+ credential: Optional[TokenCredential] = None,
40
38
  ) -> None:
41
39
  self.logger = logger
42
40
  self.auth_header = auth_header
43
- self._lock = None
41
+ self._lock: Optional[asyncio.Lock] = None
44
42
  if credential is not None:
45
43
  self.credential = credential
46
44
  else:
47
45
  self.credential = self.get_aad_credential()
48
- self.token = None
49
- self.last_refresh_time = None
46
+ self.token: Optional[str] = None
47
+ self.last_refresh_time: Optional[float] = None
50
48
 
51
49
  @property
52
50
  def lock(self) -> asyncio.Lock:
@@ -73,39 +71,58 @@ class APITokenManager(ABC):
73
71
  identity_client_id = os.environ.get("DEFAULT_IDENTITY_CLIENT_ID", None)
74
72
  if identity_client_id is not None:
75
73
  self.logger.info(f"Using DEFAULT_IDENTITY_CLIENT_ID: {identity_client_id}")
76
- credential = ManagedIdentityCredential(client_id=identity_client_id)
77
- else:
78
- self.logger.info("Environment variable DEFAULT_IDENTITY_CLIENT_ID is not set, using DefaultAzureCredential")
79
- credential = DefaultAzureCredential()
80
- return credential
74
+ return ManagedIdentityCredential(client_id=identity_client_id)
75
+
76
+ self.logger.info("Environment variable DEFAULT_IDENTITY_CLIENT_ID is not set, using DefaultAzureCredential")
77
+ return DefaultAzureCredential()
81
78
 
82
79
  @abstractmethod
83
- async def get_token(self) -> str:
80
+ def get_token(
81
+ self,
82
+ scopes: Union[str, None] = None,
83
+ claims: Union[str, None] = None,
84
+ tenant_id: Union[str, None] = None,
85
+ enable_cae: bool = False,
86
+ **kwargs: Any,
87
+ ) -> AccessToken:
88
+ """Async method to get the API token. Subclasses should implement this method.
89
+
90
+ :return: API token
91
+ :rtype: str
92
+ """
93
+
94
+ @abstractmethod
95
+ async def get_token_async(self) -> str:
84
96
  """Async method to get the API token. Subclasses should implement this method.
85
97
 
86
98
  :return: API token
87
99
  :rtype: str
88
100
  """
89
- pass # pylint: disable=unnecessary-pass
90
101
 
91
102
 
92
103
  class ManagedIdentityAPITokenManager(APITokenManager):
93
104
  """API Token Manager for Azure Managed Identity
94
105
 
95
106
  :param token_scope: Token scope for Azure endpoint
96
- :type token_scope: ~azure.ai.evaluation.simulator._model_tools.TokenScope
107
+ :type token_scope: ~azure.ai.evaluation._constants.TokenScope
97
108
  :param logger: Logger object
98
109
  :type logger: logging.Logger
99
110
  :keyword kwargs: Additional keyword arguments
100
111
  :paramtype kwargs: Dict
101
112
  """
102
113
 
103
- def __init__(self, token_scope: TokenScope, logger: logging.Logger, **kwargs: Dict):
104
- super().__init__(logger, **kwargs)
114
+ def __init__(
115
+ self,
116
+ token_scope: TokenScope,
117
+ logger: logging.Logger,
118
+ *,
119
+ auth_header: str = "Bearer",
120
+ credential: Optional[TokenCredential] = None,
121
+ ):
122
+ super().__init__(logger, auth_header=auth_header, credential=credential)
105
123
  self.token_scope = token_scope
106
124
 
107
- # Bug 3353724: This get_token is sync method, but it is defined as async method in the base class
108
- def get_token(self) -> str: # pylint: disable=invalid-overridden-method
125
+ def get_token(self) -> str:
109
126
  """Get the API token. If the token is not available or has expired, refresh the token.
110
127
 
111
128
  :return: API token
@@ -122,6 +139,32 @@ class ManagedIdentityAPITokenManager(APITokenManager):
122
139
 
123
140
  return self.token
124
141
 
142
+ async def get_token_async(self) -> str:
143
+ """Get the API token synchronously. If the token is not available or has expired, refresh it.
144
+
145
+ :return: API token
146
+ :rtype: str
147
+ """
148
+ if (
149
+ self.token is None
150
+ or self.last_refresh_time is None
151
+ or time.time() - self.last_refresh_time > AZURE_TOKEN_REFRESH_INTERVAL
152
+ ):
153
+ self.last_refresh_time = time.time()
154
+ get_token_method = self.credential.get_token(self.token_scope.value)
155
+
156
+ if inspect.isawaitable(get_token_method):
157
+ # If it's awaitable, await it
158
+ token_response: AccessToken = await get_token_method
159
+ else:
160
+ # Otherwise, call it synchronously
161
+ token_response = get_token_method
162
+
163
+ self.token = token_response.token
164
+ self.logger.info("Refreshed Azure endpoint token.")
165
+
166
+ return self.token
167
+
125
168
 
126
169
  class PlainTokenManager(APITokenManager):
127
170
  """Plain API Token Manager
@@ -134,11 +177,18 @@ class PlainTokenManager(APITokenManager):
134
177
  :paramtype kwargs: Dict
135
178
  """
136
179
 
137
- def __init__(self, openapi_key: str, logger: logging.Logger, **kwargs: Dict):
138
- super().__init__(logger, **kwargs)
139
- self.token = openapi_key
180
+ def __init__(
181
+ self,
182
+ openapi_key: str,
183
+ logger: logging.Logger,
184
+ *,
185
+ auth_header: str = "Bearer",
186
+ credential: Optional[TokenCredential] = None,
187
+ ) -> None:
188
+ super().__init__(logger, auth_header=auth_header, credential=credential)
189
+ self.token: str = openapi_key
140
190
 
141
- async def get_token(self) -> str:
191
+ def get_token(self) -> str:
142
192
  """Get the API token
143
193
 
144
194
  :return: API token
@@ -6,13 +6,17 @@ import copy
6
6
  import json
7
7
  import time
8
8
  import uuid
9
- from typing import Dict, List
9
+ from typing import Any, Dict, List, Optional, cast, Union
10
10
 
11
11
  from azure.ai.evaluation._http_utils import AsyncHttpPipeline, get_async_http_client
12
- from azure.ai.evaluation._user_agent import USER_AGENT
13
- from azure.core.exceptions import HttpResponseError
12
+ from azure.ai.evaluation._user_agent import UserAgentSingleton
13
+ from azure.core.exceptions import HttpResponseError, ServiceResponseError
14
14
  from azure.core.pipeline.policies import AsyncRetryPolicy, RetryMode
15
+ from azure.ai.evaluation._common.onedp._client import ProjectsClient as AIProjectClient
16
+ from azure.ai.evaluation._common.onedp.models import SimulationDTO
17
+ from azure.ai.evaluation._common.constants import RAIService
15
18
 
19
+ from .._model_tools._template_handler import TemplateParameters
16
20
  from .models import OpenAIChatCompletionsModel
17
21
 
18
22
 
@@ -33,13 +37,21 @@ class SimulationRequestDTO:
33
37
  :type template_parameters: Dict
34
38
  """
35
39
 
36
- def __init__(self, url, headers, payload, params, templatekey, template_parameters):
40
+ def __init__(
41
+ self,
42
+ url: str,
43
+ headers: Dict[str, str],
44
+ payload: Dict[str, Any],
45
+ params: Dict[str, str],
46
+ templateKey: str,
47
+ templateParameters: Optional[TemplateParameters],
48
+ ):
37
49
  self.url = url
38
50
  self.headers = headers
39
51
  self.json = json.dumps(payload)
40
52
  self.params = params
41
- self.templatekey = templatekey
42
- self.templateParameters = template_parameters
53
+ self.templateKey = templateKey
54
+ self.templateParameters = templateParameters
43
55
 
44
56
  def to_dict(self) -> Dict:
45
57
  """Convert the DTO to a dictionary.
@@ -47,9 +59,12 @@ class SimulationRequestDTO:
47
59
  :return: The DTO as a dictionary.
48
60
  :rtype: Dict
49
61
  """
50
- if self.templateParameters is not None:
51
- self.templateParameters = {str(k): str(v) for k, v in self.templateParameters.items()}
52
- return self.__dict__
62
+ toReturn = self.__dict__.copy()
63
+
64
+ if toReturn["templateParameters"] is not None:
65
+ toReturn["templateParameters"] = {str(k): str(v) for k, v in toReturn["templateParameters"].items()}
66
+
67
+ return toReturn
53
68
 
54
69
  def to_json(self):
55
70
  """Convert the DTO to a JSON string.
@@ -73,12 +88,13 @@ class ProxyChatCompletionsModel(OpenAIChatCompletionsModel):
73
88
  :keyword kwargs: Additional keyword arguments to pass to the parent class.
74
89
  """
75
90
 
76
- def __init__(self, name: str, template_key: str, template_parameters, *args, **kwargs) -> None:
91
+ def __init__(self, name: str, template_key: str, template_parameters: TemplateParameters, **kwargs) -> None:
77
92
  self.tkey = template_key
78
93
  self.tparam = template_parameters
79
- self.result_url = None
94
+ self.result_url: Optional[str] = None
95
+ self.simulation_id: Optional[str] = kwargs.pop("simulation_id", "")
80
96
 
81
- super().__init__(name=name, *args, **kwargs)
97
+ super().__init__(name=name, **kwargs)
82
98
 
83
99
  def format_request_data(self, messages: List[Dict], **request_params) -> Dict: # type: ignore[override]
84
100
  """Format the request data to query the model with.
@@ -98,7 +114,7 @@ class ProxyChatCompletionsModel(OpenAIChatCompletionsModel):
98
114
  async def get_conversation_completion(
99
115
  self,
100
116
  messages: List[Dict],
101
- session: AsyncHttpPipeline,
117
+ session: Union[AsyncHttpPipeline, AIProjectClient],
102
118
  role: str = "assistant", # pylint: disable=unused-argument
103
119
  **request_params,
104
120
  ) -> dict:
@@ -129,7 +145,7 @@ class ProxyChatCompletionsModel(OpenAIChatCompletionsModel):
129
145
 
130
146
  async def request_api(
131
147
  self,
132
- session: AsyncHttpPipeline,
148
+ session: Union[AsyncHttpPipeline, AIProjectClient],
133
149
  request_data: dict,
134
150
  ) -> dict:
135
151
  """
@@ -150,17 +166,17 @@ class ProxyChatCompletionsModel(OpenAIChatCompletionsModel):
150
166
  proxy_headers = {
151
167
  "Authorization": f"Bearer {token}",
152
168
  "Content-Type": "application/json",
153
- "User-Agent": USER_AGENT,
169
+ "User-Agent": UserAgentSingleton().value,
154
170
  }
155
171
 
156
172
  headers = {
157
173
  "Content-Type": "application/json",
158
174
  "X-CV": f"{uuid.uuid4()}",
159
175
  "X-ModelType": self.model or "",
176
+ "x-ms-client-request-id": self.simulation_id,
160
177
  }
161
178
  # add all additional headers
162
179
  headers.update(self.additional_headers) # type: ignore[arg-type]
163
-
164
180
  params = {}
165
181
  if self.api_version:
166
182
  params["api-version"] = self.api_version
@@ -170,45 +186,101 @@ class ProxyChatCompletionsModel(OpenAIChatCompletionsModel):
170
186
  headers=headers,
171
187
  payload=request_data,
172
188
  params=params,
173
- templatekey=self.tkey,
174
- template_parameters=self.tparam,
189
+ templateKey=self.tkey,
190
+ templateParameters=self.tparam,
175
191
  )
176
192
 
177
193
  time_start = time.time()
178
194
  full_response = None
179
195
 
180
- response = await session.post(url=self.endpoint_url, headers=proxy_headers, json=sim_request_dto.to_dict())
181
-
182
- if response.status_code != 202:
183
- raise HttpResponseError(
184
- message=f"Received unexpected HTTP status: {response.status_code} {response.text()}", response=response
196
+ if isinstance(session, AIProjectClient):
197
+ sim_request_dto = SimulationDTO(
198
+ headers=headers,
199
+ params=params,
200
+ json=json.dumps(request_data),
201
+ template_key=self.tkey,
202
+ template_parameters=self.tparam,
203
+ )
204
+ response_data = session.red_teams.submit_simulation(sim_request_dto, headers=headers, params=params)
205
+ operation_id = response_data["location"].split("/")[-1]
206
+
207
+ request_count = 0
208
+ flag = True
209
+ while flag:
210
+ try:
211
+ response = session.red_teams.operation_results(operation_id, headers=headers)
212
+ except Exception as e:
213
+ from types import SimpleNamespace # pylint: disable=forgotten-debug-statement
214
+
215
+ response = SimpleNamespace(status_code=202, text=str(e), json=lambda: {"error": str(e)})
216
+ if isinstance(response, dict):
217
+ response_data = response
218
+ flag = False
219
+ break
220
+ if not isinstance(response, SimpleNamespace) and response.get("object") == "chat.completion":
221
+ response_data = response
222
+ flag = False
223
+ break
224
+ else:
225
+ request_count += 1
226
+ sleep_time = RAIService.SLEEP_TIME**request_count
227
+ await asyncio.sleep(sleep_time)
228
+ else:
229
+ # Retry policy for POST request to RAI service
230
+ service_call_retry_policy = AsyncRetryPolicy(
231
+ retry_on_exceptions=[ServiceResponseError],
232
+ retry_total=7,
233
+ retry_backoff_factor=10.0,
234
+ retry_backoff_max=180,
235
+ retry_mode=RetryMode.Exponential,
185
236
  )
186
237
 
187
- response = response.json()
188
- self.result_url = response["location"]
189
-
190
- retry_policy = AsyncRetryPolicy( # set up retry configuration
191
- retry_on_status_codes=[202], # on which statuses to retry
192
- retry_total=7,
193
- retry_backoff_factor=10.0,
194
- retry_backoff_max=180,
195
- retry_mode=RetryMode.Exponential,
196
- )
197
-
198
- # initial 15 seconds wait before attempting to fetch result
199
- # Need to wait both in this thread and in the async thread for some reason?
200
- # Someone not under a crunch and with better async understandings should dig into this more.
201
- await asyncio.sleep(15)
202
- time.sleep(15)
203
-
204
- async with get_async_http_client().with_policies(retry_policy=retry_policy) as exp_retry_client:
205
- response = await exp_retry_client.get( # pylint: disable=too-many-function-args,unexpected-keyword-arg
206
- self.result_url, headers=proxy_headers
238
+ response = None
239
+ async with get_async_http_client().with_policies(retry_policy=service_call_retry_policy) as retry_client:
240
+ try:
241
+ response = await retry_client.post(
242
+ url=self.endpoint_url, headers=proxy_headers, json=sim_request_dto.to_dict()
243
+ )
244
+ except ServiceResponseError as e:
245
+ self.logger.error("ServiceResponseError during POST request to rai svc after retries: %s", str(e))
246
+ raise
247
+
248
+ # response.raise_for_status()
249
+ if response.status_code != 202:
250
+ raise HttpResponseError(
251
+ message=f"Received unexpected HTTP status: {response.status_code} {response.text()}",
252
+ response=response,
253
+ )
254
+ response_data = response.json()
255
+
256
+ self.result_url = cast(str, response_data["location"])
257
+ retry_policy = AsyncRetryPolicy( # set up retry configuration
258
+ retry_on_status_codes=[202], # on which statuses to retry
259
+ retry_total=7,
260
+ retry_backoff_factor=10.0,
261
+ retry_backoff_max=180,
262
+ retry_mode=RetryMode.Exponential,
207
263
  )
208
264
 
209
- response.raise_for_status()
265
+ # initial 15 seconds wait before attempting to fetch result
266
+ # Need to wait both in this thread and in the async thread for some reason?
267
+ # Someone not under a crunch and with better async understandings should dig into this more.
268
+ await asyncio.sleep(15)
269
+ time.sleep(15)
270
+
271
+ async with get_async_http_client().with_policies(retry_policy=retry_policy) as exp_retry_client:
272
+ token = await self.token_manager.get_token_async()
273
+ proxy_headers = {
274
+ "Authorization": f"Bearer {token}",
275
+ "Content-Type": "application/json",
276
+ "User-Agent": UserAgentSingleton().value,
277
+ }
278
+ response = await exp_retry_client.get( # pylint: disable=too-many-function-args,unexpected-keyword-arg
279
+ self.result_url, headers=proxy_headers
280
+ )
281
+ response.raise_for_status()
282
+ response_data = response.json()
210
283
 
211
- response_data = response.json()
212
284
  self.logger.info("Response: %s", response_data)
213
285
 
214
286
  # Copy the full response and return it to be saved in jsonl.