aeri-python 4.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (391) hide show
  1. aeri/__init__.py +72 -0
  2. aeri/_client/_validation.py +204 -0
  3. aeri/_client/attributes.py +188 -0
  4. aeri/_client/client.py +3761 -0
  5. aeri/_client/constants.py +65 -0
  6. aeri/_client/datasets.py +302 -0
  7. aeri/_client/environment_variables.py +158 -0
  8. aeri/_client/get_client.py +149 -0
  9. aeri/_client/observe.py +661 -0
  10. aeri/_client/propagation.py +475 -0
  11. aeri/_client/resource_manager.py +510 -0
  12. aeri/_client/span.py +1519 -0
  13. aeri/_client/span_filter.py +76 -0
  14. aeri/_client/span_processor.py +206 -0
  15. aeri/_client/utils.py +132 -0
  16. aeri/_task_manager/media_manager.py +331 -0
  17. aeri/_task_manager/media_upload_consumer.py +44 -0
  18. aeri/_task_manager/media_upload_queue.py +12 -0
  19. aeri/_task_manager/score_ingestion_consumer.py +208 -0
  20. aeri/_task_manager/task_manager.py +475 -0
  21. aeri/_utils/__init__.py +19 -0
  22. aeri/_utils/environment.py +34 -0
  23. aeri/_utils/error_logging.py +47 -0
  24. aeri/_utils/parse_error.py +99 -0
  25. aeri/_utils/prompt_cache.py +188 -0
  26. aeri/_utils/request.py +137 -0
  27. aeri/_utils/serializer.py +205 -0
  28. aeri/api/.fern/metadata.json +14 -0
  29. aeri/api/__init__.py +836 -0
  30. aeri/api/annotation_queues/__init__.py +82 -0
  31. aeri/api/annotation_queues/client.py +1111 -0
  32. aeri/api/annotation_queues/raw_client.py +2288 -0
  33. aeri/api/annotation_queues/types/__init__.py +84 -0
  34. aeri/api/annotation_queues/types/annotation_queue.py +28 -0
  35. aeri/api/annotation_queues/types/annotation_queue_assignment_request.py +16 -0
  36. aeri/api/annotation_queues/types/annotation_queue_item.py +34 -0
  37. aeri/api/annotation_queues/types/annotation_queue_object_type.py +26 -0
  38. aeri/api/annotation_queues/types/annotation_queue_status.py +22 -0
  39. aeri/api/annotation_queues/types/create_annotation_queue_assignment_response.py +18 -0
  40. aeri/api/annotation_queues/types/create_annotation_queue_item_request.py +25 -0
  41. aeri/api/annotation_queues/types/create_annotation_queue_request.py +20 -0
  42. aeri/api/annotation_queues/types/delete_annotation_queue_assignment_response.py +14 -0
  43. aeri/api/annotation_queues/types/delete_annotation_queue_item_response.py +15 -0
  44. aeri/api/annotation_queues/types/paginated_annotation_queue_items.py +17 -0
  45. aeri/api/annotation_queues/types/paginated_annotation_queues.py +17 -0
  46. aeri/api/annotation_queues/types/update_annotation_queue_item_request.py +15 -0
  47. aeri/api/blob_storage_integrations/__init__.py +73 -0
  48. aeri/api/blob_storage_integrations/client.py +550 -0
  49. aeri/api/blob_storage_integrations/raw_client.py +976 -0
  50. aeri/api/blob_storage_integrations/types/__init__.py +77 -0
  51. aeri/api/blob_storage_integrations/types/blob_storage_export_frequency.py +26 -0
  52. aeri/api/blob_storage_integrations/types/blob_storage_export_mode.py +26 -0
  53. aeri/api/blob_storage_integrations/types/blob_storage_integration_deletion_response.py +14 -0
  54. aeri/api/blob_storage_integrations/types/blob_storage_integration_file_type.py +26 -0
  55. aeri/api/blob_storage_integrations/types/blob_storage_integration_response.py +64 -0
  56. aeri/api/blob_storage_integrations/types/blob_storage_integration_status_response.py +50 -0
  57. aeri/api/blob_storage_integrations/types/blob_storage_integration_type.py +26 -0
  58. aeri/api/blob_storage_integrations/types/blob_storage_integrations_response.py +15 -0
  59. aeri/api/blob_storage_integrations/types/blob_storage_sync_status.py +47 -0
  60. aeri/api/blob_storage_integrations/types/create_blob_storage_integration_request.py +91 -0
  61. aeri/api/client.py +679 -0
  62. aeri/api/comments/__init__.py +44 -0
  63. aeri/api/comments/client.py +407 -0
  64. aeri/api/comments/raw_client.py +750 -0
  65. aeri/api/comments/types/__init__.py +46 -0
  66. aeri/api/comments/types/create_comment_request.py +47 -0
  67. aeri/api/comments/types/create_comment_response.py +17 -0
  68. aeri/api/comments/types/get_comments_response.py +17 -0
  69. aeri/api/commons/__init__.py +210 -0
  70. aeri/api/commons/errors/__init__.py +56 -0
  71. aeri/api/commons/errors/access_denied_error.py +12 -0
  72. aeri/api/commons/errors/error.py +12 -0
  73. aeri/api/commons/errors/method_not_allowed_error.py +12 -0
  74. aeri/api/commons/errors/not_found_error.py +12 -0
  75. aeri/api/commons/errors/unauthorized_error.py +12 -0
  76. aeri/api/commons/types/__init__.py +190 -0
  77. aeri/api/commons/types/base_score.py +90 -0
  78. aeri/api/commons/types/base_score_v1.py +70 -0
  79. aeri/api/commons/types/boolean_score.py +26 -0
  80. aeri/api/commons/types/boolean_score_v1.py +26 -0
  81. aeri/api/commons/types/categorical_score.py +26 -0
  82. aeri/api/commons/types/categorical_score_v1.py +26 -0
  83. aeri/api/commons/types/comment.py +36 -0
  84. aeri/api/commons/types/comment_object_type.py +30 -0
  85. aeri/api/commons/types/config_category.py +15 -0
  86. aeri/api/commons/types/correction_score.py +26 -0
  87. aeri/api/commons/types/create_score_value.py +5 -0
  88. aeri/api/commons/types/dataset.py +49 -0
  89. aeri/api/commons/types/dataset_item.py +58 -0
  90. aeri/api/commons/types/dataset_run.py +63 -0
  91. aeri/api/commons/types/dataset_run_item.py +40 -0
  92. aeri/api/commons/types/dataset_run_with_items.py +19 -0
  93. aeri/api/commons/types/dataset_status.py +22 -0
  94. aeri/api/commons/types/map_value.py +11 -0
  95. aeri/api/commons/types/model.py +125 -0
  96. aeri/api/commons/types/model_price.py +14 -0
  97. aeri/api/commons/types/model_usage_unit.py +42 -0
  98. aeri/api/commons/types/numeric_score.py +17 -0
  99. aeri/api/commons/types/numeric_score_v1.py +17 -0
  100. aeri/api/commons/types/observation.py +142 -0
  101. aeri/api/commons/types/observation_level.py +30 -0
  102. aeri/api/commons/types/observation_v2.py +235 -0
  103. aeri/api/commons/types/observations_view.py +89 -0
  104. aeri/api/commons/types/pricing_tier.py +91 -0
  105. aeri/api/commons/types/pricing_tier_condition.py +68 -0
  106. aeri/api/commons/types/pricing_tier_input.py +76 -0
  107. aeri/api/commons/types/pricing_tier_operator.py +42 -0
  108. aeri/api/commons/types/score.py +201 -0
  109. aeri/api/commons/types/score_config.py +66 -0
  110. aeri/api/commons/types/score_config_data_type.py +26 -0
  111. aeri/api/commons/types/score_data_type.py +30 -0
  112. aeri/api/commons/types/score_source.py +26 -0
  113. aeri/api/commons/types/score_v1.py +131 -0
  114. aeri/api/commons/types/session.py +25 -0
  115. aeri/api/commons/types/session_with_traces.py +15 -0
  116. aeri/api/commons/types/trace.py +84 -0
  117. aeri/api/commons/types/trace_with_details.py +43 -0
  118. aeri/api/commons/types/trace_with_full_details.py +45 -0
  119. aeri/api/commons/types/usage.py +59 -0
  120. aeri/api/core/__init__.py +111 -0
  121. aeri/api/core/api_error.py +23 -0
  122. aeri/api/core/client_wrapper.py +141 -0
  123. aeri/api/core/datetime_utils.py +30 -0
  124. aeri/api/core/enum.py +20 -0
  125. aeri/api/core/file.py +70 -0
  126. aeri/api/core/force_multipart.py +18 -0
  127. aeri/api/core/http_client.py +711 -0
  128. aeri/api/core/http_response.py +55 -0
  129. aeri/api/core/http_sse/__init__.py +48 -0
  130. aeri/api/core/http_sse/_api.py +114 -0
  131. aeri/api/core/http_sse/_decoders.py +66 -0
  132. aeri/api/core/http_sse/_exceptions.py +7 -0
  133. aeri/api/core/http_sse/_models.py +17 -0
  134. aeri/api/core/jsonable_encoder.py +102 -0
  135. aeri/api/core/pydantic_utilities.py +310 -0
  136. aeri/api/core/query_encoder.py +60 -0
  137. aeri/api/core/remove_none_from_dict.py +11 -0
  138. aeri/api/core/request_options.py +35 -0
  139. aeri/api/core/serialization.py +282 -0
  140. aeri/api/dataset_items/__init__.py +52 -0
  141. aeri/api/dataset_items/client.py +499 -0
  142. aeri/api/dataset_items/raw_client.py +973 -0
  143. aeri/api/dataset_items/types/__init__.py +50 -0
  144. aeri/api/dataset_items/types/create_dataset_item_request.py +37 -0
  145. aeri/api/dataset_items/types/delete_dataset_item_response.py +17 -0
  146. aeri/api/dataset_items/types/paginated_dataset_items.py +17 -0
  147. aeri/api/dataset_run_items/__init__.py +43 -0
  148. aeri/api/dataset_run_items/client.py +323 -0
  149. aeri/api/dataset_run_items/raw_client.py +547 -0
  150. aeri/api/dataset_run_items/types/__init__.py +44 -0
  151. aeri/api/dataset_run_items/types/create_dataset_run_item_request.py +51 -0
  152. aeri/api/dataset_run_items/types/paginated_dataset_run_items.py +17 -0
  153. aeri/api/datasets/__init__.py +55 -0
  154. aeri/api/datasets/client.py +661 -0
  155. aeri/api/datasets/raw_client.py +1368 -0
  156. aeri/api/datasets/types/__init__.py +53 -0
  157. aeri/api/datasets/types/create_dataset_request.py +31 -0
  158. aeri/api/datasets/types/delete_dataset_run_response.py +14 -0
  159. aeri/api/datasets/types/paginated_dataset_runs.py +17 -0
  160. aeri/api/datasets/types/paginated_datasets.py +17 -0
  161. aeri/api/health/__init__.py +44 -0
  162. aeri/api/health/client.py +112 -0
  163. aeri/api/health/errors/__init__.py +42 -0
  164. aeri/api/health/errors/service_unavailable_error.py +13 -0
  165. aeri/api/health/raw_client.py +227 -0
  166. aeri/api/health/types/__init__.py +40 -0
  167. aeri/api/health/types/health_response.py +30 -0
  168. aeri/api/ingestion/__init__.py +169 -0
  169. aeri/api/ingestion/client.py +221 -0
  170. aeri/api/ingestion/raw_client.py +293 -0
  171. aeri/api/ingestion/types/__init__.py +169 -0
  172. aeri/api/ingestion/types/base_event.py +27 -0
  173. aeri/api/ingestion/types/create_event_body.py +14 -0
  174. aeri/api/ingestion/types/create_event_event.py +15 -0
  175. aeri/api/ingestion/types/create_generation_body.py +40 -0
  176. aeri/api/ingestion/types/create_generation_event.py +15 -0
  177. aeri/api/ingestion/types/create_observation_event.py +15 -0
  178. aeri/api/ingestion/types/create_span_body.py +19 -0
  179. aeri/api/ingestion/types/create_span_event.py +15 -0
  180. aeri/api/ingestion/types/ingestion_error.py +17 -0
  181. aeri/api/ingestion/types/ingestion_event.py +155 -0
  182. aeri/api/ingestion/types/ingestion_response.py +17 -0
  183. aeri/api/ingestion/types/ingestion_success.py +15 -0
  184. aeri/api/ingestion/types/ingestion_usage.py +8 -0
  185. aeri/api/ingestion/types/observation_body.py +53 -0
  186. aeri/api/ingestion/types/observation_type.py +54 -0
  187. aeri/api/ingestion/types/open_ai_completion_usage_schema.py +26 -0
  188. aeri/api/ingestion/types/open_ai_response_usage_schema.py +24 -0
  189. aeri/api/ingestion/types/open_ai_usage.py +28 -0
  190. aeri/api/ingestion/types/optional_observation_body.py +36 -0
  191. aeri/api/ingestion/types/score_body.py +75 -0
  192. aeri/api/ingestion/types/score_event.py +15 -0
  193. aeri/api/ingestion/types/sdk_log_body.py +14 -0
  194. aeri/api/ingestion/types/sdk_log_event.py +15 -0
  195. aeri/api/ingestion/types/trace_body.py +36 -0
  196. aeri/api/ingestion/types/trace_event.py +15 -0
  197. aeri/api/ingestion/types/update_event_body.py +14 -0
  198. aeri/api/ingestion/types/update_generation_body.py +40 -0
  199. aeri/api/ingestion/types/update_generation_event.py +15 -0
  200. aeri/api/ingestion/types/update_observation_event.py +15 -0
  201. aeri/api/ingestion/types/update_span_body.py +19 -0
  202. aeri/api/ingestion/types/update_span_event.py +15 -0
  203. aeri/api/ingestion/types/usage_details.py +10 -0
  204. aeri/api/legacy/__init__.py +61 -0
  205. aeri/api/legacy/client.py +105 -0
  206. aeri/api/legacy/metrics_v1/__init__.py +40 -0
  207. aeri/api/legacy/metrics_v1/client.py +214 -0
  208. aeri/api/legacy/metrics_v1/raw_client.py +322 -0
  209. aeri/api/legacy/metrics_v1/types/__init__.py +40 -0
  210. aeri/api/legacy/metrics_v1/types/metrics_response.py +19 -0
  211. aeri/api/legacy/observations_v1/__init__.py +43 -0
  212. aeri/api/legacy/observations_v1/client.py +523 -0
  213. aeri/api/legacy/observations_v1/raw_client.py +759 -0
  214. aeri/api/legacy/observations_v1/types/__init__.py +44 -0
  215. aeri/api/legacy/observations_v1/types/observations.py +17 -0
  216. aeri/api/legacy/observations_v1/types/observations_views.py +17 -0
  217. aeri/api/legacy/raw_client.py +13 -0
  218. aeri/api/legacy/score_v1/__init__.py +43 -0
  219. aeri/api/legacy/score_v1/client.py +329 -0
  220. aeri/api/legacy/score_v1/raw_client.py +545 -0
  221. aeri/api/legacy/score_v1/types/__init__.py +44 -0
  222. aeri/api/legacy/score_v1/types/create_score_request.py +75 -0
  223. aeri/api/legacy/score_v1/types/create_score_response.py +17 -0
  224. aeri/api/llm_connections/__init__.py +55 -0
  225. aeri/api/llm_connections/client.py +311 -0
  226. aeri/api/llm_connections/raw_client.py +541 -0
  227. aeri/api/llm_connections/types/__init__.py +53 -0
  228. aeri/api/llm_connections/types/llm_adapter.py +38 -0
  229. aeri/api/llm_connections/types/llm_connection.py +77 -0
  230. aeri/api/llm_connections/types/paginated_llm_connections.py +17 -0
  231. aeri/api/llm_connections/types/upsert_llm_connection_request.py +69 -0
  232. aeri/api/media/__init__.py +58 -0
  233. aeri/api/media/client.py +427 -0
  234. aeri/api/media/raw_client.py +739 -0
  235. aeri/api/media/types/__init__.py +56 -0
  236. aeri/api/media/types/get_media_response.py +55 -0
  237. aeri/api/media/types/get_media_upload_url_request.py +51 -0
  238. aeri/api/media/types/get_media_upload_url_response.py +28 -0
  239. aeri/api/media/types/media_content_type.py +232 -0
  240. aeri/api/media/types/patch_media_body.py +43 -0
  241. aeri/api/metrics/__init__.py +40 -0
  242. aeri/api/metrics/client.py +422 -0
  243. aeri/api/metrics/raw_client.py +530 -0
  244. aeri/api/metrics/types/__init__.py +40 -0
  245. aeri/api/metrics/types/metrics_v2response.py +19 -0
  246. aeri/api/models/__init__.py +43 -0
  247. aeri/api/models/client.py +523 -0
  248. aeri/api/models/raw_client.py +993 -0
  249. aeri/api/models/types/__init__.py +44 -0
  250. aeri/api/models/types/create_model_request.py +103 -0
  251. aeri/api/models/types/paginated_models.py +17 -0
  252. aeri/api/observations/__init__.py +43 -0
  253. aeri/api/observations/client.py +522 -0
  254. aeri/api/observations/raw_client.py +641 -0
  255. aeri/api/observations/types/__init__.py +44 -0
  256. aeri/api/observations/types/observations_v2meta.py +21 -0
  257. aeri/api/observations/types/observations_v2response.py +28 -0
  258. aeri/api/opentelemetry/__init__.py +67 -0
  259. aeri/api/opentelemetry/client.py +276 -0
  260. aeri/api/opentelemetry/raw_client.py +291 -0
  261. aeri/api/opentelemetry/types/__init__.py +65 -0
  262. aeri/api/opentelemetry/types/otel_attribute.py +27 -0
  263. aeri/api/opentelemetry/types/otel_attribute_value.py +46 -0
  264. aeri/api/opentelemetry/types/otel_resource.py +24 -0
  265. aeri/api/opentelemetry/types/otel_resource_span.py +32 -0
  266. aeri/api/opentelemetry/types/otel_scope.py +34 -0
  267. aeri/api/opentelemetry/types/otel_scope_span.py +28 -0
  268. aeri/api/opentelemetry/types/otel_span.py +76 -0
  269. aeri/api/opentelemetry/types/otel_trace_response.py +16 -0
  270. aeri/api/organizations/__init__.py +73 -0
  271. aeri/api/organizations/client.py +756 -0
  272. aeri/api/organizations/raw_client.py +1707 -0
  273. aeri/api/organizations/types/__init__.py +71 -0
  274. aeri/api/organizations/types/delete_membership_request.py +16 -0
  275. aeri/api/organizations/types/membership_deletion_response.py +17 -0
  276. aeri/api/organizations/types/membership_request.py +18 -0
  277. aeri/api/organizations/types/membership_response.py +20 -0
  278. aeri/api/organizations/types/membership_role.py +30 -0
  279. aeri/api/organizations/types/memberships_response.py +15 -0
  280. aeri/api/organizations/types/organization_api_key.py +31 -0
  281. aeri/api/organizations/types/organization_api_keys_response.py +19 -0
  282. aeri/api/organizations/types/organization_project.py +25 -0
  283. aeri/api/organizations/types/organization_projects_response.py +15 -0
  284. aeri/api/projects/__init__.py +67 -0
  285. aeri/api/projects/client.py +760 -0
  286. aeri/api/projects/raw_client.py +1577 -0
  287. aeri/api/projects/types/__init__.py +65 -0
  288. aeri/api/projects/types/api_key_deletion_response.py +18 -0
  289. aeri/api/projects/types/api_key_list.py +23 -0
  290. aeri/api/projects/types/api_key_response.py +30 -0
  291. aeri/api/projects/types/api_key_summary.py +35 -0
  292. aeri/api/projects/types/organization.py +22 -0
  293. aeri/api/projects/types/project.py +34 -0
  294. aeri/api/projects/types/project_deletion_response.py +15 -0
  295. aeri/api/projects/types/projects.py +15 -0
  296. aeri/api/prompt_version/__init__.py +4 -0
  297. aeri/api/prompt_version/client.py +157 -0
  298. aeri/api/prompt_version/raw_client.py +264 -0
  299. aeri/api/prompts/__init__.py +100 -0
  300. aeri/api/prompts/client.py +550 -0
  301. aeri/api/prompts/raw_client.py +987 -0
  302. aeri/api/prompts/types/__init__.py +96 -0
  303. aeri/api/prompts/types/base_prompt.py +42 -0
  304. aeri/api/prompts/types/chat_message.py +17 -0
  305. aeri/api/prompts/types/chat_message_type.py +15 -0
  306. aeri/api/prompts/types/chat_message_with_placeholders.py +8 -0
  307. aeri/api/prompts/types/chat_prompt.py +15 -0
  308. aeri/api/prompts/types/create_chat_prompt_request.py +37 -0
  309. aeri/api/prompts/types/create_chat_prompt_type.py +15 -0
  310. aeri/api/prompts/types/create_prompt_request.py +8 -0
  311. aeri/api/prompts/types/create_text_prompt_request.py +36 -0
  312. aeri/api/prompts/types/create_text_prompt_type.py +15 -0
  313. aeri/api/prompts/types/placeholder_message.py +16 -0
  314. aeri/api/prompts/types/placeholder_message_type.py +15 -0
  315. aeri/api/prompts/types/prompt.py +58 -0
  316. aeri/api/prompts/types/prompt_meta.py +35 -0
  317. aeri/api/prompts/types/prompt_meta_list_response.py +17 -0
  318. aeri/api/prompts/types/prompt_type.py +20 -0
  319. aeri/api/prompts/types/text_prompt.py +14 -0
  320. aeri/api/scim/__init__.py +94 -0
  321. aeri/api/scim/client.py +686 -0
  322. aeri/api/scim/raw_client.py +1528 -0
  323. aeri/api/scim/types/__init__.py +92 -0
  324. aeri/api/scim/types/authentication_scheme.py +20 -0
  325. aeri/api/scim/types/bulk_config.py +22 -0
  326. aeri/api/scim/types/empty_response.py +16 -0
  327. aeri/api/scim/types/filter_config.py +17 -0
  328. aeri/api/scim/types/resource_meta.py +17 -0
  329. aeri/api/scim/types/resource_type.py +27 -0
  330. aeri/api/scim/types/resource_types_response.py +21 -0
  331. aeri/api/scim/types/schema_extension.py +17 -0
  332. aeri/api/scim/types/schema_resource.py +19 -0
  333. aeri/api/scim/types/schemas_response.py +21 -0
  334. aeri/api/scim/types/scim_email.py +16 -0
  335. aeri/api/scim/types/scim_feature_support.py +14 -0
  336. aeri/api/scim/types/scim_name.py +14 -0
  337. aeri/api/scim/types/scim_user.py +24 -0
  338. aeri/api/scim/types/scim_users_list_response.py +25 -0
  339. aeri/api/scim/types/service_provider_config.py +36 -0
  340. aeri/api/scim/types/user_meta.py +20 -0
  341. aeri/api/score_configs/__init__.py +44 -0
  342. aeri/api/score_configs/client.py +526 -0
  343. aeri/api/score_configs/raw_client.py +1012 -0
  344. aeri/api/score_configs/types/__init__.py +46 -0
  345. aeri/api/score_configs/types/create_score_config_request.py +46 -0
  346. aeri/api/score_configs/types/score_configs.py +17 -0
  347. aeri/api/score_configs/types/update_score_config_request.py +53 -0
  348. aeri/api/scores/__init__.py +76 -0
  349. aeri/api/scores/client.py +420 -0
  350. aeri/api/scores/raw_client.py +656 -0
  351. aeri/api/scores/types/__init__.py +76 -0
  352. aeri/api/scores/types/get_scores_response.py +17 -0
  353. aeri/api/scores/types/get_scores_response_data.py +211 -0
  354. aeri/api/scores/types/get_scores_response_data_boolean.py +15 -0
  355. aeri/api/scores/types/get_scores_response_data_categorical.py +15 -0
  356. aeri/api/scores/types/get_scores_response_data_correction.py +15 -0
  357. aeri/api/scores/types/get_scores_response_data_numeric.py +15 -0
  358. aeri/api/scores/types/get_scores_response_trace_data.py +38 -0
  359. aeri/api/sessions/__init__.py +40 -0
  360. aeri/api/sessions/client.py +262 -0
  361. aeri/api/sessions/raw_client.py +500 -0
  362. aeri/api/sessions/types/__init__.py +40 -0
  363. aeri/api/sessions/types/paginated_sessions.py +17 -0
  364. aeri/api/trace/__init__.py +44 -0
  365. aeri/api/trace/client.py +728 -0
  366. aeri/api/trace/raw_client.py +1208 -0
  367. aeri/api/trace/types/__init__.py +46 -0
  368. aeri/api/trace/types/delete_trace_response.py +14 -0
  369. aeri/api/trace/types/sort.py +14 -0
  370. aeri/api/trace/types/traces.py +17 -0
  371. aeri/api/utils/__init__.py +44 -0
  372. aeri/api/utils/pagination/__init__.py +40 -0
  373. aeri/api/utils/pagination/types/__init__.py +40 -0
  374. aeri/api/utils/pagination/types/meta_response.py +38 -0
  375. aeri/batch_evaluation.py +1643 -0
  376. aeri/experiment.py +1044 -0
  377. aeri/langchain/CallbackHandler.py +1377 -0
  378. aeri/langchain/__init__.py +5 -0
  379. aeri/langchain/utils.py +212 -0
  380. aeri/logger.py +28 -0
  381. aeri/media.py +352 -0
  382. aeri/model.py +477 -0
  383. aeri/openai.py +1124 -0
  384. aeri/py.typed +0 -0
  385. aeri/span_filter.py +17 -0
  386. aeri/types.py +79 -0
  387. aeri/version.py +3 -0
  388. aeri_python-4.0.0.dist-info/METADATA +51 -0
  389. aeri_python-4.0.0.dist-info/RECORD +391 -0
  390. aeri_python-4.0.0.dist-info/WHEEL +4 -0
  391. aeri_python-4.0.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,475 @@
1
+ """Attribute propagation utilities for Aeri OpenTelemetry integration.
2
+
3
+ This module provides the `propagate_attributes` context manager for setting trace-level
4
+ attributes (user_id, session_id, metadata) that automatically propagate to all child spans
5
+ within the context.
6
+ """
7
+
8
+ from typing import Any, Dict, Generator, List, Literal, Optional, TypedDict, Union, cast
9
+
10
+ from opentelemetry import baggage
11
+ from opentelemetry import (
12
+ baggage as otel_baggage_api,
13
+ )
14
+ from opentelemetry import (
15
+ context as otel_context_api,
16
+ )
17
+ from opentelemetry import (
18
+ trace as otel_trace_api,
19
+ )
20
+ from opentelemetry.util._decorator import (
21
+ _AgnosticContextManager,
22
+ _agnosticcontextmanager,
23
+ )
24
+
25
+ from aeri._client.attributes import AeriOtelSpanAttributes
26
+ from aeri._client.constants import AERI_SDK_EXPERIMENT_ENVIRONMENT
27
+ from aeri.logger import aeri_logger
28
+
29
+ PropagatedKeys = Literal[
30
+ "user_id",
31
+ "session_id",
32
+ "metadata",
33
+ "version",
34
+ "tags",
35
+ "trace_name",
36
+ ]
37
+
38
+ InternalPropagatedKeys = Literal[
39
+ "experiment_id",
40
+ "experiment_name",
41
+ "experiment_metadata",
42
+ "experiment_dataset_id",
43
+ "experiment_item_id",
44
+ "experiment_item_metadata",
45
+ "experiment_item_root_observation_id",
46
+ ]
47
+
48
+ propagated_keys: List[Union[PropagatedKeys, InternalPropagatedKeys]] = [
49
+ "user_id",
50
+ "session_id",
51
+ "metadata",
52
+ "version",
53
+ "tags",
54
+ "trace_name",
55
+ "experiment_id",
56
+ "experiment_name",
57
+ "experiment_metadata",
58
+ "experiment_dataset_id",
59
+ "experiment_item_id",
60
+ "experiment_item_metadata",
61
+ "experiment_item_root_observation_id",
62
+ ]
63
+
64
+
65
+ class PropagatedExperimentAttributes(TypedDict):
66
+ experiment_id: str
67
+ experiment_name: str
68
+ experiment_metadata: Optional[str]
69
+ experiment_dataset_id: Optional[str]
70
+ experiment_item_id: str
71
+ experiment_item_metadata: Optional[str]
72
+ experiment_item_root_observation_id: str
73
+
74
+
75
+ def propagate_attributes(
76
+ *,
77
+ user_id: Optional[str] = None,
78
+ session_id: Optional[str] = None,
79
+ metadata: Optional[Dict[str, str]] = None,
80
+ version: Optional[str] = None,
81
+ tags: Optional[List[str]] = None,
82
+ trace_name: Optional[str] = None,
83
+ as_baggage: bool = False,
84
+ ) -> _AgnosticContextManager[Any]:
85
+ """Propagate trace-level attributes to all spans created within this context.
86
+
87
+ This context manager sets attributes on the currently active span AND automatically
88
+ propagates them to all new child spans created within the context. This is the
89
+ recommended way to set trace-level attributes like user_id, session_id, and metadata
90
+ dimensions that should be consistently applied across all observations in a trace.
91
+
92
+ **IMPORTANT**: Call this as early as possible within your trace/workflow. Only the
93
+ currently active span and spans created after entering this context will have these
94
+ attributes. Pre-existing spans will NOT be retroactively updated.
95
+
96
+ **Why this matters**: Aeri aggregation queries (e.g., total cost by user_id,
97
+ filtering by session_id) only include observations that have the attribute set.
98
+ If you call `propagate_attributes` late in your workflow, earlier spans won't be
99
+ included in aggregations for that attribute.
100
+
101
+ Args:
102
+ user_id: User identifier to associate with all spans in this context.
103
+ Must be US-ASCII string, ≤200 characters. Use this to track which user
104
+ generated each trace and enable e.g. per-user cost/performance analysis.
105
+ session_id: Session identifier to associate with all spans in this context.
106
+ Must be US-ASCII string, ≤200 characters. Use this to group related traces
107
+ within a user session (e.g., a conversation thread, multi-turn interaction).
108
+ metadata: Additional key-value metadata to propagate to all spans.
109
+ - Keys and values must be US-ASCII strings
110
+ - All values must be ≤200 characters
111
+ - Use for dimensions like internal correlating identifiers
112
+ - AVOID: large payloads, sensitive data, non-string values (will be dropped with warning)
113
+ version: Version identfier for parts of your application that are independently versioned, e.g. agents
114
+ tags: List of tags to categorize the group of observations
115
+ trace_name: Name to assign to the trace. Must be US-ASCII string, ≤200 characters.
116
+ Use this to set a consistent trace name for all spans created within this context.
117
+ as_baggage: If True, propagates attributes using OpenTelemetry baggage for
118
+ cross-process/service propagation. **Security warning**: When enabled,
119
+ attribute values are added to HTTP headers on ALL outbound requests.
120
+ Only enable if values are safe to transmit via HTTP headers and you need
121
+ cross-service tracing. Default: False.
122
+
123
+ Returns:
124
+ Context manager that propagates attributes to all child spans.
125
+
126
+ Example:
127
+ Basic usage with user and session tracking:
128
+
129
+ ```python
130
+ from aeri import Aeri
131
+
132
+ aeri = Aeri()
133
+
134
+ # Set attributes early in the trace
135
+ with aeri.start_as_current_observation(name="user_workflow") as span:
136
+ with aeri.propagate_attributes(
137
+ user_id="user_123",
138
+ session_id="session_abc",
139
+ metadata={"experiment": "variant_a", "environment": "production"}
140
+ ):
141
+ # All spans created here will have user_id, session_id, and metadata
142
+ with aeri.start_observation(name="llm_call") as llm_span:
143
+ # This span inherits: user_id, session_id, experiment, environment
144
+ ...
145
+
146
+ with aeri.start_generation(name="completion") as gen:
147
+ # This span also inherits all attributes
148
+ ...
149
+ ```
150
+
151
+ Late propagation (anti-pattern):
152
+
153
+ ```python
154
+ with aeri.start_as_current_observation(name="workflow") as span:
155
+ # These spans WON'T have user_id
156
+ early_span = aeri.start_observation(name="early_work")
157
+ early_span.end()
158
+
159
+ # Set attributes in the middle
160
+ with aeri.propagate_attributes(user_id="user_123"):
161
+ # Only spans created AFTER this point will have user_id
162
+ late_span = aeri.start_observation(name="late_work")
163
+ late_span.end()
164
+
165
+ # Result: Aggregations by user_id will miss "early_work" span
166
+ ```
167
+
168
+ Cross-service propagation with baggage (advanced):
169
+
170
+ ```python
171
+ # Service A - originating service
172
+ with aeri.start_as_current_observation(name="api_request"):
173
+ with aeri.propagate_attributes(
174
+ user_id="user_123",
175
+ session_id="session_abc",
176
+ as_baggage=True # Propagate via HTTP headers
177
+ ):
178
+ # Make HTTP request to Service B
179
+ response = requests.get("https://service-b.example.com/api")
180
+ # user_id and session_id are now in HTTP headers
181
+
182
+ # Service B - downstream service
183
+ # OpenTelemetry will automatically extract baggage from HTTP headers
184
+ # and propagate to spans in Service B
185
+ ```
186
+
187
+ Note:
188
+ - **Validation**: All attribute values (user_id, session_id, metadata values)
189
+ must be strings ≤200 characters. Invalid values will be dropped with a
190
+ warning logged. Ensure values meet constraints before calling.
191
+ - **OpenTelemetry**: This uses OpenTelemetry context propagation under the hood,
192
+ making it compatible with other OTel-instrumented libraries.
193
+
194
+ Raises:
195
+ No exceptions are raised. Invalid values are logged as warnings and dropped.
196
+ """
197
+ return _propagate_attributes(
198
+ user_id=user_id,
199
+ session_id=session_id,
200
+ metadata=metadata,
201
+ version=version,
202
+ tags=tags,
203
+ trace_name=trace_name,
204
+ as_baggage=as_baggage,
205
+ )
206
+
207
+
208
+ @_agnosticcontextmanager
209
+ def _propagate_attributes(
210
+ *,
211
+ user_id: Optional[str] = None,
212
+ session_id: Optional[str] = None,
213
+ metadata: Optional[Dict[str, str]] = None,
214
+ version: Optional[str] = None,
215
+ tags: Optional[List[str]] = None,
216
+ trace_name: Optional[str] = None,
217
+ as_baggage: bool = False,
218
+ experiment: Optional[PropagatedExperimentAttributes] = None,
219
+ ) -> Generator[Any, Any, Any]:
220
+ context = otel_context_api.get_current()
221
+ current_span = otel_trace_api.get_current_span()
222
+
223
+ propagated_string_attributes: Dict[str, Optional[Union[str, List[str]]]] = {
224
+ "user_id": user_id,
225
+ "session_id": session_id,
226
+ "version": version,
227
+ "tags": tags,
228
+ "trace_name": trace_name,
229
+ }
230
+
231
+ propagated_string_attributes = propagated_string_attributes | (
232
+ cast(Dict[str, Union[str, List[str], None]], experiment) or {}
233
+ )
234
+
235
+ # Filter out None values
236
+ propagated_string_attributes = {
237
+ k: v for k, v in propagated_string_attributes.items() if v is not None
238
+ }
239
+
240
+ for key, value in propagated_string_attributes.items():
241
+ validated_value = _validate_propagated_value(value=value, key=key)
242
+
243
+ if validated_value is not None:
244
+ context = _set_propagated_attribute(
245
+ key=key,
246
+ value=validated_value,
247
+ context=context,
248
+ span=current_span,
249
+ as_baggage=as_baggage,
250
+ )
251
+
252
+ if metadata is not None:
253
+ validated_metadata: Dict[str, str] = {}
254
+
255
+ for key, value in metadata.items():
256
+ if _validate_string_value(value=value, key=f"metadata.{key}"):
257
+ validated_metadata[key] = value
258
+
259
+ if validated_metadata:
260
+ context = _set_propagated_attribute(
261
+ key="metadata",
262
+ value=validated_metadata,
263
+ context=context,
264
+ span=current_span,
265
+ as_baggage=as_baggage,
266
+ )
267
+
268
+ # Activate context, execute, and detach context
269
+ token = otel_context_api.attach(context=context)
270
+
271
+ try:
272
+ yield
273
+
274
+ finally:
275
+ otel_context_api.detach(token)
276
+
277
+
278
+ def _get_propagated_attributes_from_context(
279
+ context: otel_context_api.Context,
280
+ ) -> Dict[str, Union[str, List[str]]]:
281
+ propagated_attributes: Dict[str, Union[str, List[str]]] = {}
282
+
283
+ # Handle baggage
284
+ baggage_entries = baggage.get_all(context=context)
285
+ for baggage_key, baggage_value in baggage_entries.items():
286
+ if baggage_key.startswith(AERI_BAGGAGE_PREFIX):
287
+ span_key = _get_span_key_from_baggage_key(baggage_key)
288
+
289
+ if span_key:
290
+ propagated_attributes[span_key] = (
291
+ baggage_value
292
+ if isinstance(baggage_value, (str, list))
293
+ else str(baggage_value)
294
+ )
295
+
296
+ # Handle OTEL context
297
+ for key in propagated_keys:
298
+ context_key = _get_propagated_context_key(key)
299
+ value = otel_context_api.get_value(key=context_key, context=context)
300
+
301
+ if value is None:
302
+ continue
303
+
304
+ if isinstance(value, dict):
305
+ # Handle metadata
306
+ for k, v in value.items():
307
+ span_key = f"{AeriOtelSpanAttributes.TRACE_METADATA}.{k}"
308
+ propagated_attributes[span_key] = v
309
+
310
+ else:
311
+ span_key = _get_propagated_span_key(key)
312
+
313
+ propagated_attributes[span_key] = (
314
+ value if isinstance(value, (str, list)) else str(value)
315
+ )
316
+
317
+ if (
318
+ AeriOtelSpanAttributes.EXPERIMENT_ITEM_ROOT_OBSERVATION_ID
319
+ in propagated_attributes
320
+ ):
321
+ propagated_attributes[AeriOtelSpanAttributes.ENVIRONMENT] = (
322
+ AERI_SDK_EXPERIMENT_ENVIRONMENT
323
+ )
324
+
325
+ return propagated_attributes
326
+
327
+
328
+ def _set_propagated_attribute(
329
+ *,
330
+ key: str,
331
+ value: Union[str, List[str], Dict[str, str]],
332
+ context: otel_context_api.Context,
333
+ span: otel_trace_api.Span,
334
+ as_baggage: bool,
335
+ ) -> otel_context_api.Context:
336
+ # Get key names
337
+ context_key = _get_propagated_context_key(key)
338
+ span_key = _get_propagated_span_key(key)
339
+ baggage_key = _get_propagated_baggage_key(key)
340
+
341
+ # Merge metadata with previously set metadata keys
342
+ if isinstance(value, dict):
343
+ existing_metadata_in_context = cast(
344
+ dict, otel_context_api.get_value(context_key) or {}
345
+ )
346
+ value = existing_metadata_in_context | value
347
+
348
+ # Merge tags with previously set tags
349
+ if isinstance(value, list):
350
+ existing_tags_in_context = cast(
351
+ list, otel_context_api.get_value(context_key) or []
352
+ )
353
+ merged_tags = list(existing_tags_in_context)
354
+ merged_tags.extend(tag for tag in value if tag not in existing_tags_in_context)
355
+
356
+ value = merged_tags
357
+
358
+ # Set in context
359
+ context = otel_context_api.set_value(
360
+ key=context_key,
361
+ value=value,
362
+ context=context,
363
+ )
364
+
365
+ # Set on current span
366
+ if span is not None and span.is_recording():
367
+ if isinstance(value, dict):
368
+ # Handle metadata
369
+ for k, v in value.items():
370
+ span.set_attribute(
371
+ key=f"{AeriOtelSpanAttributes.TRACE_METADATA}.{k}",
372
+ value=v,
373
+ )
374
+
375
+ else:
376
+ span.set_attribute(key=span_key, value=value)
377
+
378
+ # Set on baggage
379
+ if as_baggage:
380
+ if isinstance(value, dict):
381
+ # Handle metadata
382
+ for k, v in value.items():
383
+ context = otel_baggage_api.set_baggage(
384
+ name=f"{baggage_key}_{k}", value=v, context=context
385
+ )
386
+ else:
387
+ context = otel_baggage_api.set_baggage(
388
+ name=baggage_key, value=value, context=context
389
+ )
390
+
391
+ return context
392
+
393
+
394
+ def _validate_propagated_value(
395
+ *, value: Any, key: str
396
+ ) -> Optional[Union[str, List[str]]]:
397
+ if isinstance(value, list):
398
+ validated_values = [
399
+ v for v in value if _validate_string_value(key=key, value=v)
400
+ ]
401
+
402
+ return validated_values if len(validated_values) > 0 else None
403
+
404
+ if not isinstance(value, str):
405
+ aeri_logger.warning( # type: ignore
406
+ f"Propagated attribute '{key}' value is not a string. Dropping value."
407
+ )
408
+ return None
409
+
410
+ if len(value) > 200:
411
+ aeri_logger.warning(
412
+ f"Propagated attribute '{key}' value is over 200 characters ({len(value)} chars). Dropping value."
413
+ )
414
+ return None
415
+
416
+ return value
417
+
418
+
419
+ def _validate_string_value(*, value: str, key: str) -> bool:
420
+ if not isinstance(value, str):
421
+ aeri_logger.warning( # type: ignore
422
+ f"Propagated attribute '{key}' value is not a string. Dropping value."
423
+ )
424
+ return False
425
+
426
+ if len(value) > 200:
427
+ aeri_logger.warning(
428
+ f"Propagated attribute '{key}' value is over 200 characters ({len(value)} chars). Dropping value."
429
+ )
430
+ return False
431
+
432
+ return True
433
+
434
+
435
+ def _get_propagated_context_key(key: str) -> str:
436
+ return f"aeri.propagated.{key}"
437
+
438
+
439
+ AERI_BAGGAGE_PREFIX = "aeri_"
440
+
441
+
442
+ def _get_propagated_baggage_key(key: str) -> str:
443
+ return f"{AERI_BAGGAGE_PREFIX}{key}"
444
+
445
+
446
+ def _get_span_key_from_baggage_key(key: str) -> Optional[str]:
447
+ if not key.startswith(AERI_BAGGAGE_PREFIX):
448
+ return None
449
+
450
+ # Remove prefix to get the actual key name
451
+ suffix = key[len(AERI_BAGGAGE_PREFIX) :]
452
+
453
+ if suffix.startswith("metadata_"):
454
+ metadata_key = suffix[len("metadata_") :]
455
+
456
+ return _get_propagated_span_key(metadata_key)
457
+
458
+ return _get_propagated_span_key(suffix)
459
+
460
+
461
+ def _get_propagated_span_key(key: str) -> str:
462
+ return {
463
+ "session_id": AeriOtelSpanAttributes.TRACE_SESSION_ID,
464
+ "user_id": AeriOtelSpanAttributes.TRACE_USER_ID,
465
+ "version": AeriOtelSpanAttributes.VERSION,
466
+ "tags": AeriOtelSpanAttributes.TRACE_TAGS,
467
+ "trace_name": AeriOtelSpanAttributes.TRACE_NAME,
468
+ "experiment_id": AeriOtelSpanAttributes.EXPERIMENT_ID,
469
+ "experiment_name": AeriOtelSpanAttributes.EXPERIMENT_NAME,
470
+ "experiment_metadata": AeriOtelSpanAttributes.EXPERIMENT_METADATA,
471
+ "experiment_dataset_id": AeriOtelSpanAttributes.EXPERIMENT_DATASET_ID,
472
+ "experiment_item_id": AeriOtelSpanAttributes.EXPERIMENT_ITEM_ID,
473
+ "experiment_item_metadata": AeriOtelSpanAttributes.EXPERIMENT_ITEM_METADATA,
474
+ "experiment_item_root_observation_id": AeriOtelSpanAttributes.EXPERIMENT_ITEM_ROOT_OBSERVATION_ID,
475
+ }.get(key) or f"{AeriOtelSpanAttributes.TRACE_METADATA}.{key}"