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
aeri/_client/span.py ADDED
@@ -0,0 +1,1519 @@
1
+ """OTEL span wrapper for Aeri.
2
+
3
+ This module defines custom span classes that extend OpenTelemetry spans with
4
+ Aeri-specific functionality. These wrapper classes provide methods for
5
+ creating, updating, and scoring various types of spans used in AI application tracing.
6
+
7
+ Classes:
8
+ - AeriObservationWrapper: Abstract base class for all Aeri spans
9
+ - AeriSpan: Implementation for general-purpose spans
10
+ - AeriGeneration: Specialized span implementation for LLM generations
11
+
12
+ All span classes provide methods for media processing, attribute management,
13
+ and scoring integration specific to Aeri's observability platform.
14
+ """
15
+
16
+ from datetime import datetime
17
+ from time import time_ns
18
+ from typing import (
19
+ TYPE_CHECKING,
20
+ Any,
21
+ Dict,
22
+ Literal,
23
+ Optional,
24
+ Type,
25
+ Union,
26
+ cast,
27
+ overload,
28
+ )
29
+
30
+ from opentelemetry import trace as otel_trace_api
31
+ from opentelemetry.trace.status import Status, StatusCode
32
+ from opentelemetry.util._decorator import _AgnosticContextManager
33
+
34
+ from aeri.model import PromptClient
35
+
36
+ if TYPE_CHECKING:
37
+ from aeri._client.client import Aeri
38
+
39
+ from typing_extensions import deprecated
40
+
41
+ from aeri._client.attributes import (
42
+ AeriOtelSpanAttributes,
43
+ create_generation_attributes,
44
+ create_span_attributes,
45
+ create_trace_attributes,
46
+ )
47
+ from aeri._client.constants import (
48
+ ObservationTypeGenerationLike,
49
+ ObservationTypeLiteral,
50
+ ObservationTypeLiteralNoEvent,
51
+ ObservationTypeSpanLike,
52
+ get_observation_types_list,
53
+ )
54
+ from aeri.api import MapValue, ScoreDataType
55
+ from aeri.logger import aeri_logger
56
+ from aeri.types import SpanLevel
57
+
58
+ # Factory mapping for observation classes
59
+ # Note: "event" is handled separately due to special instantiation logic
60
+ # Populated after class definitions
61
+ _OBSERVATION_CLASS_MAP: Dict[str, Type["AeriObservationWrapper"]] = {}
62
+
63
+
64
+ class AeriObservationWrapper:
65
+ """Abstract base class for all Aeri span types.
66
+
67
+ This class provides common functionality for all Aeri span types, including
68
+ media processing, attribute management, and scoring. It wraps an OpenTelemetry
69
+ span and extends it with Aeri-specific features.
70
+
71
+ Attributes:
72
+ _otel_span: The underlying OpenTelemetry span
73
+ _aeri_client: Reference to the parent Aeri client
74
+ trace_id: The trace ID for this span
75
+ observation_id: The observation ID (span ID) for this span
76
+ """
77
+
78
+ def __init__(
79
+ self,
80
+ *,
81
+ otel_span: otel_trace_api.Span,
82
+ aeri_client: "Aeri",
83
+ as_type: ObservationTypeLiteral,
84
+ input: Optional[Any] = None,
85
+ output: Optional[Any] = None,
86
+ metadata: Optional[Any] = None,
87
+ environment: Optional[str] = None,
88
+ release: Optional[str] = None,
89
+ version: Optional[str] = None,
90
+ level: Optional[SpanLevel] = None,
91
+ status_message: Optional[str] = None,
92
+ completion_start_time: Optional[datetime] = None,
93
+ model: Optional[str] = None,
94
+ model_parameters: Optional[Dict[str, MapValue]] = None,
95
+ usage_details: Optional[Dict[str, int]] = None,
96
+ cost_details: Optional[Dict[str, float]] = None,
97
+ prompt: Optional[PromptClient] = None,
98
+ ):
99
+ """Initialize a new Aeri span wrapper.
100
+
101
+ Args:
102
+ otel_span: The OpenTelemetry span to wrap
103
+ aeri_client: Reference to the parent Aeri client
104
+ as_type: The type of span ("span" or "generation")
105
+ input: Input data for the span (any JSON-serializable object)
106
+ output: Output data from the span (any JSON-serializable object)
107
+ metadata: Additional metadata to associate with the span
108
+ environment: The tracing environment
109
+ release: Release identifier for the application
110
+ version: Version identifier for the code or component
111
+ level: Importance level of the span (info, warning, error)
112
+ status_message: Optional status message for the span
113
+ completion_start_time: When the model started generating the response
114
+ model: Name/identifier of the AI model used (e.g., "gpt-4")
115
+ model_parameters: Parameters used for the model (e.g., temperature, max_tokens)
116
+ usage_details: Token usage information (e.g., prompt_tokens, completion_tokens)
117
+ cost_details: Cost information for the model call
118
+ prompt: Associated prompt template from Aeri prompt management
119
+ """
120
+ self._otel_span = otel_span
121
+ self._otel_span.set_attribute(
122
+ AeriOtelSpanAttributes.OBSERVATION_TYPE, as_type
123
+ )
124
+ self._aeri_client = aeri_client
125
+ self._observation_type = as_type
126
+
127
+ self.trace_id = self._aeri_client._get_otel_trace_id(otel_span)
128
+ self.id = self._aeri_client._get_otel_span_id(otel_span)
129
+
130
+ self._environment = environment or self._aeri_client._environment
131
+ if self._environment is not None:
132
+ self._otel_span.set_attribute(
133
+ AeriOtelSpanAttributes.ENVIRONMENT, self._environment
134
+ )
135
+
136
+ self._release = release or self._aeri_client._release
137
+ if self._release is not None:
138
+ self._otel_span.set_attribute(
139
+ AeriOtelSpanAttributes.RELEASE, self._release
140
+ )
141
+
142
+ # Handle media only if span is sampled
143
+ if self._otel_span.is_recording():
144
+ media_processed_input = self._process_media_and_apply_mask(
145
+ data=input, field="input", span=self._otel_span
146
+ )
147
+ media_processed_output = self._process_media_and_apply_mask(
148
+ data=output, field="output", span=self._otel_span
149
+ )
150
+ media_processed_metadata = self._process_media_and_apply_mask(
151
+ data=metadata, field="metadata", span=self._otel_span
152
+ )
153
+
154
+ attributes = {}
155
+
156
+ if as_type in get_observation_types_list(ObservationTypeGenerationLike):
157
+ attributes = create_generation_attributes(
158
+ input=media_processed_input,
159
+ output=media_processed_output,
160
+ metadata=media_processed_metadata,
161
+ version=version,
162
+ level=level,
163
+ status_message=status_message,
164
+ completion_start_time=completion_start_time,
165
+ model=model,
166
+ model_parameters=model_parameters,
167
+ usage_details=usage_details,
168
+ cost_details=cost_details,
169
+ prompt=prompt,
170
+ observation_type=cast(
171
+ ObservationTypeGenerationLike,
172
+ as_type,
173
+ ),
174
+ )
175
+
176
+ else:
177
+ # For span-like types and events
178
+ attributes = create_span_attributes(
179
+ input=media_processed_input,
180
+ output=media_processed_output,
181
+ metadata=media_processed_metadata,
182
+ version=version,
183
+ level=level,
184
+ status_message=status_message,
185
+ observation_type=cast(
186
+ Optional[Union[ObservationTypeSpanLike, Literal["event"]]],
187
+ as_type
188
+ if as_type
189
+ in get_observation_types_list(ObservationTypeSpanLike)
190
+ or as_type == "event"
191
+ else None,
192
+ ),
193
+ )
194
+
195
+ # We don't want to overwrite the observation type, and already set it
196
+ attributes.pop(AeriOtelSpanAttributes.OBSERVATION_TYPE, None)
197
+
198
+ self._otel_span.set_attributes(
199
+ {k: v for k, v in attributes.items() if v is not None}
200
+ )
201
+ # Set OTEL span status if level is ERROR
202
+ self._set_otel_span_status_if_error(
203
+ level=level, status_message=status_message
204
+ )
205
+
206
+ def end(self, *, end_time: Optional[int] = None) -> "AeriObservationWrapper":
207
+ """End the span, marking it as completed.
208
+
209
+ This method ends the wrapped OpenTelemetry span, marking the end of the
210
+ operation being traced. After this method is called, the span is considered
211
+ complete and can no longer be modified.
212
+
213
+ Args:
214
+ end_time: Optional explicit end time in nanoseconds since epoch
215
+ """
216
+ self._otel_span.end(end_time=end_time)
217
+
218
+ return self
219
+
220
+ @deprecated(
221
+ "Trace-level input/output is deprecated. "
222
+ "For trace attributes (user_id, session_id, tags, etc.), use propagate_attributes() instead. "
223
+ "This method will be removed in a future major version."
224
+ )
225
+ def set_trace_io(
226
+ self,
227
+ *,
228
+ input: Optional[Any] = None,
229
+ output: Optional[Any] = None,
230
+ ) -> "AeriObservationWrapper":
231
+ """Set trace-level input and output for the trace this span belongs to.
232
+
233
+ .. deprecated::
234
+ This is a legacy method for backward compatibility with Aeri platform
235
+ features that still rely on trace-level input/output (e.g., legacy LLM-as-a-judge
236
+ evaluators). It will be removed in a future major version.
237
+
238
+ For setting other trace attributes (user_id, session_id, metadata, tags, version),
239
+ use :meth:`Aeri.propagate_attributes` instead.
240
+
241
+ Args:
242
+ input: Input data to associate with the trace.
243
+ output: Output data to associate with the trace.
244
+
245
+ Returns:
246
+ The span instance for method chaining.
247
+ """
248
+ if not self._otel_span.is_recording():
249
+ return self
250
+
251
+ media_processed_input = self._process_media_and_apply_mask(
252
+ data=input, field="input", span=self._otel_span
253
+ )
254
+ media_processed_output = self._process_media_and_apply_mask(
255
+ data=output, field="output", span=self._otel_span
256
+ )
257
+
258
+ attributes = create_trace_attributes(
259
+ input=media_processed_input,
260
+ output=media_processed_output,
261
+ )
262
+
263
+ self._otel_span.set_attributes(attributes)
264
+
265
+ return self
266
+
267
+ def set_trace_as_public(self) -> "AeriObservationWrapper":
268
+ """Make this trace publicly accessible via its URL.
269
+
270
+ When a trace is published, anyone with the trace link can view the full trace
271
+ without needing to be logged in to Aeri. This action cannot be undone
272
+ programmatically - once any span in a trace is published, the entire trace
273
+ becomes public.
274
+
275
+ Returns:
276
+ The span instance for method chaining.
277
+ """
278
+ if not self._otel_span.is_recording():
279
+ return self
280
+
281
+ attributes = create_trace_attributes(public=True)
282
+
283
+ self._otel_span.set_attributes(attributes)
284
+
285
+ return self
286
+
287
+ @overload
288
+ def score(
289
+ self,
290
+ *,
291
+ name: str,
292
+ value: float,
293
+ score_id: Optional[str] = None,
294
+ data_type: Optional[
295
+ Literal[ScoreDataType.NUMERIC, ScoreDataType.BOOLEAN]
296
+ ] = None,
297
+ comment: Optional[str] = None,
298
+ config_id: Optional[str] = None,
299
+ timestamp: Optional[datetime] = None,
300
+ metadata: Optional[Any] = None,
301
+ ) -> None: ...
302
+
303
+ @overload
304
+ def score(
305
+ self,
306
+ *,
307
+ name: str,
308
+ value: str,
309
+ score_id: Optional[str] = None,
310
+ data_type: Optional[
311
+ Literal[ScoreDataType.CATEGORICAL]
312
+ ] = ScoreDataType.CATEGORICAL,
313
+ comment: Optional[str] = None,
314
+ config_id: Optional[str] = None,
315
+ timestamp: Optional[datetime] = None,
316
+ metadata: Optional[Any] = None,
317
+ ) -> None: ...
318
+
319
+ def score(
320
+ self,
321
+ *,
322
+ name: str,
323
+ value: Union[float, str],
324
+ score_id: Optional[str] = None,
325
+ data_type: Optional[ScoreDataType] = None,
326
+ comment: Optional[str] = None,
327
+ config_id: Optional[str] = None,
328
+ timestamp: Optional[datetime] = None,
329
+ metadata: Optional[Any] = None,
330
+ ) -> None:
331
+ """Create a score for this specific span.
332
+
333
+ This method creates a score associated with this specific span (observation).
334
+ Scores can represent any kind of evaluation, feedback, or quality metric.
335
+
336
+ Args:
337
+ name: Name of the score (e.g., "relevance", "accuracy")
338
+ value: Score value (numeric for NUMERIC/BOOLEAN, string for CATEGORICAL)
339
+ score_id: Optional custom ID for the score (auto-generated if not provided)
340
+ data_type: Type of score (NUMERIC, BOOLEAN, or CATEGORICAL)
341
+ comment: Optional comment or explanation for the score
342
+ config_id: Optional ID of a score config defined in Aeri
343
+ timestamp: Optional timestamp for the score (defaults to current UTC time)
344
+ metadata: Optional metadata to be attached to the score
345
+
346
+ Example:
347
+ ```python
348
+ with aeri.start_as_current_observation(name="process-query") as span:
349
+ # Do work
350
+ result = process_data()
351
+
352
+ # Score the span
353
+ span.score(
354
+ name="accuracy",
355
+ value=0.95,
356
+ data_type="NUMERIC",
357
+ comment="High accuracy result"
358
+ )
359
+ ```
360
+ """
361
+ self._aeri_client.create_score(
362
+ name=name,
363
+ value=cast(str, value),
364
+ trace_id=self.trace_id,
365
+ observation_id=self.id,
366
+ score_id=score_id,
367
+ data_type=cast(Literal["CATEGORICAL"], data_type),
368
+ comment=comment,
369
+ config_id=config_id,
370
+ timestamp=timestamp,
371
+ metadata=metadata,
372
+ )
373
+
374
+ @overload
375
+ def score_trace(
376
+ self,
377
+ *,
378
+ name: str,
379
+ value: float,
380
+ score_id: Optional[str] = None,
381
+ data_type: Optional[
382
+ Literal[ScoreDataType.NUMERIC, ScoreDataType.BOOLEAN]
383
+ ] = None,
384
+ comment: Optional[str] = None,
385
+ config_id: Optional[str] = None,
386
+ timestamp: Optional[datetime] = None,
387
+ metadata: Optional[Any] = None,
388
+ ) -> None: ...
389
+
390
+ @overload
391
+ def score_trace(
392
+ self,
393
+ *,
394
+ name: str,
395
+ value: str,
396
+ score_id: Optional[str] = None,
397
+ data_type: Optional[
398
+ Literal[ScoreDataType.CATEGORICAL]
399
+ ] = ScoreDataType.CATEGORICAL,
400
+ comment: Optional[str] = None,
401
+ config_id: Optional[str] = None,
402
+ timestamp: Optional[datetime] = None,
403
+ metadata: Optional[Any] = None,
404
+ ) -> None: ...
405
+
406
+ def score_trace(
407
+ self,
408
+ *,
409
+ name: str,
410
+ value: Union[float, str],
411
+ score_id: Optional[str] = None,
412
+ data_type: Optional[ScoreDataType] = None,
413
+ comment: Optional[str] = None,
414
+ config_id: Optional[str] = None,
415
+ timestamp: Optional[datetime] = None,
416
+ metadata: Optional[Any] = None,
417
+ ) -> None:
418
+ """Create a score for the entire trace that this span belongs to.
419
+
420
+ This method creates a score associated with the entire trace that this span
421
+ belongs to, rather than the specific span. This is useful for overall
422
+ evaluations that apply to the complete trace.
423
+
424
+ Args:
425
+ name: Name of the score (e.g., "user_satisfaction", "overall_quality")
426
+ value: Score value (numeric for NUMERIC/BOOLEAN, string for CATEGORICAL)
427
+ score_id: Optional custom ID for the score (auto-generated if not provided)
428
+ data_type: Type of score (NUMERIC, BOOLEAN, or CATEGORICAL)
429
+ comment: Optional comment or explanation for the score
430
+ config_id: Optional ID of a score config defined in Aeri
431
+ timestamp: Optional timestamp for the score (defaults to current UTC time)
432
+ metadata: Optional metadata to be attached to the score
433
+
434
+ Example:
435
+ ```python
436
+ with aeri.start_as_current_observation(name="handle-request") as span:
437
+ # Process the complete request
438
+ result = process_request()
439
+
440
+ # Score the entire trace (not just this span)
441
+ span.score_trace(
442
+ name="overall_quality",
443
+ value=0.9,
444
+ data_type="NUMERIC",
445
+ comment="Good overall experience"
446
+ )
447
+ ```
448
+ """
449
+ self._aeri_client.create_score(
450
+ name=name,
451
+ value=cast(str, value),
452
+ trace_id=self.trace_id,
453
+ score_id=score_id,
454
+ data_type=cast(Literal["CATEGORICAL"], data_type),
455
+ comment=comment,
456
+ config_id=config_id,
457
+ timestamp=timestamp,
458
+ metadata=metadata,
459
+ )
460
+
461
+ def _set_processed_span_attributes(
462
+ self,
463
+ *,
464
+ span: otel_trace_api.Span,
465
+ as_type: Optional[ObservationTypeLiteral] = None,
466
+ input: Optional[Any] = None,
467
+ output: Optional[Any] = None,
468
+ metadata: Optional[Any] = None,
469
+ ) -> None:
470
+ """Set span attributes after processing media and applying masks.
471
+
472
+ Internal method that processes media in the input, output, and metadata
473
+ and applies any configured masking before setting them as span attributes.
474
+
475
+ Args:
476
+ span: The OpenTelemetry span to set attributes on
477
+ as_type: The type of span ("span" or "generation")
478
+ input: Input data to process and set
479
+ output: Output data to process and set
480
+ metadata: Metadata to process and set
481
+ """
482
+ processed_input = self._process_media_and_apply_mask(
483
+ span=span,
484
+ data=input,
485
+ field="input",
486
+ )
487
+ processed_output = self._process_media_and_apply_mask(
488
+ span=span,
489
+ data=output,
490
+ field="output",
491
+ )
492
+ processed_metadata = self._process_media_and_apply_mask(
493
+ span=span,
494
+ data=metadata,
495
+ field="metadata",
496
+ )
497
+
498
+ media_processed_attributes = (
499
+ create_generation_attributes(
500
+ input=processed_input,
501
+ output=processed_output,
502
+ metadata=processed_metadata,
503
+ )
504
+ if as_type == "generation"
505
+ else create_span_attributes(
506
+ input=processed_input,
507
+ output=processed_output,
508
+ metadata=processed_metadata,
509
+ )
510
+ )
511
+
512
+ span.set_attributes(media_processed_attributes)
513
+
514
+ def _process_media_and_apply_mask(
515
+ self,
516
+ *,
517
+ data: Optional[Any] = None,
518
+ span: otel_trace_api.Span,
519
+ field: Union[Literal["input"], Literal["output"], Literal["metadata"]],
520
+ ) -> Optional[Any]:
521
+ """Process media in an attribute and apply masking.
522
+
523
+ Internal method that processes any media content in the data and applies
524
+ the configured masking function to the result.
525
+
526
+ Args:
527
+ data: The data to process
528
+ span: The OpenTelemetry span context
529
+ field: Which field this data represents (input, output, or metadata)
530
+
531
+ Returns:
532
+ The processed and masked data
533
+ """
534
+ return self._mask_attribute(
535
+ data=self._process_media_in_attribute(data=data, field=field)
536
+ )
537
+
538
+ def _mask_attribute(self, *, data: Any) -> Any:
539
+ """Apply the configured mask function to data.
540
+
541
+ Internal method that applies the client's configured masking function to
542
+ the provided data, with error handling and fallback.
543
+
544
+ Args:
545
+ data: The data to mask
546
+
547
+ Returns:
548
+ The masked data, or the original data if no mask is configured
549
+ """
550
+ if not self._aeri_client._mask:
551
+ return data
552
+
553
+ try:
554
+ return self._aeri_client._mask(data=data)
555
+ except Exception as e:
556
+ aeri_logger.error(
557
+ f"Masking error: Custom mask function threw exception when processing data. Using fallback masking. Error: {e}"
558
+ )
559
+
560
+ return "<fully masked due to failed mask function>"
561
+
562
+ def _process_media_in_attribute(
563
+ self,
564
+ *,
565
+ data: Optional[Any] = None,
566
+ field: Union[Literal["input"], Literal["output"], Literal["metadata"]],
567
+ ) -> Optional[Any]:
568
+ """Process any media content in the attribute data.
569
+
570
+ Internal method that identifies and processes any media content in the
571
+ provided data, using the client's media manager.
572
+
573
+ Args:
574
+ data: The data to process for media content
575
+ span: The OpenTelemetry span context
576
+ field: Which field this data represents (input, output, or metadata)
577
+
578
+ Returns:
579
+ The data with any media content processed
580
+ """
581
+ if self._aeri_client._resources is not None:
582
+ return (
583
+ self._aeri_client._resources._media_manager._find_and_process_media(
584
+ data=data,
585
+ field=field,
586
+ trace_id=self.trace_id,
587
+ observation_id=self.id,
588
+ )
589
+ )
590
+
591
+ return data
592
+
593
+ def _set_otel_span_status_if_error(
594
+ self, *, level: Optional[SpanLevel] = None, status_message: Optional[str] = None
595
+ ) -> None:
596
+ """Set OpenTelemetry span status to ERROR if level is ERROR.
597
+
598
+ This method sets the underlying OpenTelemetry span status to ERROR when the
599
+ Aeri observation level is set to ERROR, ensuring consistency between
600
+ Aeri and OpenTelemetry error states.
601
+
602
+ Args:
603
+ level: The span level to check
604
+ status_message: Optional status message to include as description
605
+ """
606
+ if level == "ERROR" and self._otel_span.is_recording():
607
+ try:
608
+ self._otel_span.set_status(
609
+ Status(StatusCode.ERROR, description=status_message)
610
+ )
611
+ except Exception:
612
+ # Silently ignore any errors when setting OTEL status to avoid existing flow disruptions
613
+ pass
614
+
615
+ def update(
616
+ self,
617
+ *,
618
+ name: Optional[str] = None,
619
+ input: Optional[Any] = None,
620
+ output: Optional[Any] = None,
621
+ metadata: Optional[Any] = None,
622
+ version: Optional[str] = None,
623
+ level: Optional[SpanLevel] = None,
624
+ status_message: Optional[str] = None,
625
+ completion_start_time: Optional[datetime] = None,
626
+ model: Optional[str] = None,
627
+ model_parameters: Optional[Dict[str, MapValue]] = None,
628
+ usage_details: Optional[Dict[str, int]] = None,
629
+ cost_details: Optional[Dict[str, float]] = None,
630
+ prompt: Optional[PromptClient] = None,
631
+ **kwargs: Any,
632
+ ) -> "AeriObservationWrapper":
633
+ """Update this observation with new information.
634
+
635
+ This method updates the observation with new information that becomes available
636
+ during execution, such as outputs, metadata, or status changes.
637
+
638
+ Args:
639
+ name: Observation name
640
+ input: Updated input data for the operation
641
+ output: Output data from the operation
642
+ metadata: Additional metadata to associate with the observation
643
+ version: Version identifier for the code or component
644
+ level: Importance level of the observation (info, warning, error)
645
+ status_message: Optional status message for the observation
646
+ completion_start_time: When the generation started (for generation types)
647
+ model: Model identifier used (for generation types)
648
+ model_parameters: Parameters passed to the model (for generation types)
649
+ usage_details: Token or other usage statistics (for generation types)
650
+ cost_details: Cost breakdown for the operation (for generation types)
651
+ prompt: Reference to the prompt used (for generation types)
652
+ **kwargs: Additional keyword arguments (ignored)
653
+ """
654
+ if not self._otel_span.is_recording():
655
+ return self
656
+
657
+ processed_input = self._process_media_and_apply_mask(
658
+ data=input, field="input", span=self._otel_span
659
+ )
660
+ processed_output = self._process_media_and_apply_mask(
661
+ data=output, field="output", span=self._otel_span
662
+ )
663
+ processed_metadata = self._process_media_and_apply_mask(
664
+ data=metadata, field="metadata", span=self._otel_span
665
+ )
666
+
667
+ if name:
668
+ self._otel_span.update_name(name)
669
+
670
+ if self._observation_type in get_observation_types_list(
671
+ ObservationTypeGenerationLike
672
+ ):
673
+ attributes = create_generation_attributes(
674
+ input=processed_input,
675
+ output=processed_output,
676
+ metadata=processed_metadata,
677
+ version=version,
678
+ level=level,
679
+ status_message=status_message,
680
+ observation_type=cast(
681
+ ObservationTypeGenerationLike,
682
+ self._observation_type,
683
+ ),
684
+ completion_start_time=completion_start_time,
685
+ model=model,
686
+ model_parameters=model_parameters,
687
+ usage_details=usage_details,
688
+ cost_details=cost_details,
689
+ prompt=prompt,
690
+ )
691
+ else:
692
+ # For span-like types and events
693
+ attributes = create_span_attributes(
694
+ input=processed_input,
695
+ output=processed_output,
696
+ metadata=processed_metadata,
697
+ version=version,
698
+ level=level,
699
+ status_message=status_message,
700
+ observation_type=cast(
701
+ Optional[Union[ObservationTypeSpanLike, Literal["event"]]],
702
+ self._observation_type
703
+ if self._observation_type
704
+ in get_observation_types_list(ObservationTypeSpanLike)
705
+ or self._observation_type == "event"
706
+ else None,
707
+ ),
708
+ )
709
+
710
+ self._otel_span.set_attributes(attributes=attributes)
711
+ # Set OTEL span status if level is ERROR
712
+ self._set_otel_span_status_if_error(level=level, status_message=status_message)
713
+
714
+ return self
715
+
716
+ @overload
717
+ def start_observation(
718
+ self,
719
+ *,
720
+ name: str,
721
+ as_type: Literal["span"],
722
+ input: Optional[Any] = None,
723
+ output: Optional[Any] = None,
724
+ metadata: Optional[Any] = None,
725
+ version: Optional[str] = None,
726
+ level: Optional[SpanLevel] = None,
727
+ status_message: Optional[str] = None,
728
+ ) -> "AeriSpan": ...
729
+
730
+ @overload
731
+ def start_observation(
732
+ self,
733
+ *,
734
+ name: str,
735
+ as_type: Literal["generation"],
736
+ input: Optional[Any] = None,
737
+ output: Optional[Any] = None,
738
+ metadata: Optional[Any] = None,
739
+ version: Optional[str] = None,
740
+ level: Optional[SpanLevel] = None,
741
+ status_message: Optional[str] = None,
742
+ completion_start_time: Optional[datetime] = None,
743
+ model: Optional[str] = None,
744
+ model_parameters: Optional[Dict[str, MapValue]] = None,
745
+ usage_details: Optional[Dict[str, int]] = None,
746
+ cost_details: Optional[Dict[str, float]] = None,
747
+ prompt: Optional[PromptClient] = None,
748
+ ) -> "AeriGeneration": ...
749
+
750
+ @overload
751
+ def start_observation(
752
+ self,
753
+ *,
754
+ name: str,
755
+ as_type: Literal["agent"],
756
+ input: Optional[Any] = None,
757
+ output: Optional[Any] = None,
758
+ metadata: Optional[Any] = None,
759
+ version: Optional[str] = None,
760
+ level: Optional[SpanLevel] = None,
761
+ status_message: Optional[str] = None,
762
+ ) -> "AeriAgent": ...
763
+
764
+ @overload
765
+ def start_observation(
766
+ self,
767
+ *,
768
+ name: str,
769
+ as_type: Literal["tool"],
770
+ input: Optional[Any] = None,
771
+ output: Optional[Any] = None,
772
+ metadata: Optional[Any] = None,
773
+ version: Optional[str] = None,
774
+ level: Optional[SpanLevel] = None,
775
+ status_message: Optional[str] = None,
776
+ ) -> "AeriTool": ...
777
+
778
+ @overload
779
+ def start_observation(
780
+ self,
781
+ *,
782
+ name: str,
783
+ as_type: Literal["chain"],
784
+ input: Optional[Any] = None,
785
+ output: Optional[Any] = None,
786
+ metadata: Optional[Any] = None,
787
+ version: Optional[str] = None,
788
+ level: Optional[SpanLevel] = None,
789
+ status_message: Optional[str] = None,
790
+ ) -> "AeriChain": ...
791
+
792
+ @overload
793
+ def start_observation(
794
+ self,
795
+ *,
796
+ name: str,
797
+ as_type: Literal["retriever"],
798
+ input: Optional[Any] = None,
799
+ output: Optional[Any] = None,
800
+ metadata: Optional[Any] = None,
801
+ version: Optional[str] = None,
802
+ level: Optional[SpanLevel] = None,
803
+ status_message: Optional[str] = None,
804
+ ) -> "AeriRetriever": ...
805
+
806
+ @overload
807
+ def start_observation(
808
+ self,
809
+ *,
810
+ name: str,
811
+ as_type: Literal["evaluator"],
812
+ input: Optional[Any] = None,
813
+ output: Optional[Any] = None,
814
+ metadata: Optional[Any] = None,
815
+ version: Optional[str] = None,
816
+ level: Optional[SpanLevel] = None,
817
+ status_message: Optional[str] = None,
818
+ ) -> "AeriEvaluator": ...
819
+
820
+ @overload
821
+ def start_observation(
822
+ self,
823
+ *,
824
+ name: str,
825
+ as_type: Literal["embedding"],
826
+ input: Optional[Any] = None,
827
+ output: Optional[Any] = None,
828
+ metadata: Optional[Any] = None,
829
+ version: Optional[str] = None,
830
+ level: Optional[SpanLevel] = None,
831
+ status_message: Optional[str] = None,
832
+ completion_start_time: Optional[datetime] = None,
833
+ model: Optional[str] = None,
834
+ model_parameters: Optional[Dict[str, MapValue]] = None,
835
+ usage_details: Optional[Dict[str, int]] = None,
836
+ cost_details: Optional[Dict[str, float]] = None,
837
+ prompt: Optional[PromptClient] = None,
838
+ ) -> "AeriEmbedding": ...
839
+
840
+ @overload
841
+ def start_observation(
842
+ self,
843
+ *,
844
+ name: str,
845
+ as_type: Literal["guardrail"],
846
+ input: Optional[Any] = None,
847
+ output: Optional[Any] = None,
848
+ metadata: Optional[Any] = None,
849
+ version: Optional[str] = None,
850
+ level: Optional[SpanLevel] = None,
851
+ status_message: Optional[str] = None,
852
+ ) -> "AeriGuardrail": ...
853
+
854
+ @overload
855
+ def start_observation(
856
+ self,
857
+ *,
858
+ name: str,
859
+ as_type: Literal["event"],
860
+ input: Optional[Any] = None,
861
+ output: Optional[Any] = None,
862
+ metadata: Optional[Any] = None,
863
+ version: Optional[str] = None,
864
+ level: Optional[SpanLevel] = None,
865
+ status_message: Optional[str] = None,
866
+ ) -> "AeriEvent": ...
867
+
868
+ def start_observation(
869
+ self,
870
+ *,
871
+ name: str,
872
+ as_type: ObservationTypeLiteral = "span",
873
+ input: Optional[Any] = None,
874
+ output: Optional[Any] = None,
875
+ metadata: Optional[Any] = None,
876
+ version: Optional[str] = None,
877
+ level: Optional[SpanLevel] = None,
878
+ status_message: Optional[str] = None,
879
+ completion_start_time: Optional[datetime] = None,
880
+ model: Optional[str] = None,
881
+ model_parameters: Optional[Dict[str, MapValue]] = None,
882
+ usage_details: Optional[Dict[str, int]] = None,
883
+ cost_details: Optional[Dict[str, float]] = None,
884
+ prompt: Optional[PromptClient] = None,
885
+ ) -> Union[
886
+ "AeriSpan",
887
+ "AeriGeneration",
888
+ "AeriAgent",
889
+ "AeriTool",
890
+ "AeriChain",
891
+ "AeriRetriever",
892
+ "AeriEvaluator",
893
+ "AeriEmbedding",
894
+ "AeriGuardrail",
895
+ "AeriEvent",
896
+ ]:
897
+ """Create a new child observation of the specified type.
898
+
899
+ This is the generic method for creating any type of child observation.
900
+ Unlike start_as_current_observation(), this method does not set the new
901
+ observation as the current observation in the context.
902
+
903
+ Args:
904
+ name: Name of the observation
905
+ as_type: Type of observation to create
906
+ input: Input data for the operation
907
+ output: Output data from the operation
908
+ metadata: Additional metadata to associate with the observation
909
+ version: Version identifier for the code or component
910
+ level: Importance level of the observation (info, warning, error)
911
+ status_message: Optional status message for the observation
912
+ completion_start_time: When the model started generating (for generation types)
913
+ model: Name/identifier of the AI model used (for generation types)
914
+ model_parameters: Parameters used for the model (for generation types)
915
+ usage_details: Token usage information (for generation types)
916
+ cost_details: Cost information (for generation types)
917
+ prompt: Associated prompt template (for generation types)
918
+
919
+ Returns:
920
+ A new observation of the specified type that must be ended with .end()
921
+ """
922
+ if as_type == "event":
923
+ timestamp = time_ns()
924
+ event_span = self._aeri_client._otel_tracer.start_span(
925
+ name=name, start_time=timestamp
926
+ )
927
+ return cast(
928
+ AeriEvent,
929
+ AeriEvent(
930
+ otel_span=event_span,
931
+ aeri_client=self._aeri_client,
932
+ input=input,
933
+ output=output,
934
+ metadata=metadata,
935
+ environment=self._environment,
936
+ release=self._release,
937
+ version=version,
938
+ level=level,
939
+ status_message=status_message,
940
+ ).end(end_time=timestamp),
941
+ )
942
+
943
+ observation_class = _OBSERVATION_CLASS_MAP.get(as_type)
944
+ if not observation_class:
945
+ aeri_logger.warning(
946
+ f"Unknown observation type: {as_type}, falling back to AeriSpan"
947
+ )
948
+ observation_class = AeriSpan
949
+
950
+ with otel_trace_api.use_span(self._otel_span):
951
+ new_otel_span = self._aeri_client._otel_tracer.start_span(name=name)
952
+
953
+ common_args = {
954
+ "otel_span": new_otel_span,
955
+ "aeri_client": self._aeri_client,
956
+ "environment": self._environment,
957
+ "release": self._release,
958
+ "input": input,
959
+ "output": output,
960
+ "metadata": metadata,
961
+ "version": version,
962
+ "level": level,
963
+ "status_message": status_message,
964
+ }
965
+
966
+ if as_type in get_observation_types_list(ObservationTypeGenerationLike):
967
+ common_args.update(
968
+ {
969
+ "completion_start_time": completion_start_time,
970
+ "model": model,
971
+ "model_parameters": model_parameters,
972
+ "usage_details": usage_details,
973
+ "cost_details": cost_details,
974
+ "prompt": prompt,
975
+ }
976
+ )
977
+
978
+ return observation_class(**common_args) # type: ignore[no-any-return,return-value,arg-type]
979
+
980
+ @overload
981
+ def start_as_current_observation(
982
+ self,
983
+ *,
984
+ name: str,
985
+ as_type: Literal["span"],
986
+ input: Optional[Any] = None,
987
+ output: Optional[Any] = None,
988
+ metadata: Optional[Any] = None,
989
+ version: Optional[str] = None,
990
+ level: Optional[SpanLevel] = None,
991
+ status_message: Optional[str] = None,
992
+ ) -> _AgnosticContextManager["AeriSpan"]: ...
993
+
994
+ @overload
995
+ def start_as_current_observation(
996
+ self,
997
+ *,
998
+ name: str,
999
+ as_type: Literal["generation"],
1000
+ input: Optional[Any] = None,
1001
+ output: Optional[Any] = None,
1002
+ metadata: Optional[Any] = None,
1003
+ version: Optional[str] = None,
1004
+ level: Optional[SpanLevel] = None,
1005
+ status_message: Optional[str] = None,
1006
+ completion_start_time: Optional[datetime] = None,
1007
+ model: Optional[str] = None,
1008
+ model_parameters: Optional[Dict[str, MapValue]] = None,
1009
+ usage_details: Optional[Dict[str, int]] = None,
1010
+ cost_details: Optional[Dict[str, float]] = None,
1011
+ prompt: Optional[PromptClient] = None,
1012
+ ) -> _AgnosticContextManager["AeriGeneration"]: ...
1013
+
1014
+ @overload
1015
+ def start_as_current_observation(
1016
+ self,
1017
+ *,
1018
+ name: str,
1019
+ as_type: Literal["embedding"],
1020
+ input: Optional[Any] = None,
1021
+ output: Optional[Any] = None,
1022
+ metadata: Optional[Any] = None,
1023
+ version: Optional[str] = None,
1024
+ level: Optional[SpanLevel] = None,
1025
+ status_message: Optional[str] = None,
1026
+ completion_start_time: Optional[datetime] = None,
1027
+ model: Optional[str] = None,
1028
+ model_parameters: Optional[Dict[str, MapValue]] = None,
1029
+ usage_details: Optional[Dict[str, int]] = None,
1030
+ cost_details: Optional[Dict[str, float]] = None,
1031
+ prompt: Optional[PromptClient] = None,
1032
+ ) -> _AgnosticContextManager["AeriEmbedding"]: ...
1033
+
1034
+ @overload
1035
+ def start_as_current_observation(
1036
+ self,
1037
+ *,
1038
+ name: str,
1039
+ as_type: Literal["agent"],
1040
+ input: Optional[Any] = None,
1041
+ output: Optional[Any] = None,
1042
+ metadata: Optional[Any] = None,
1043
+ version: Optional[str] = None,
1044
+ level: Optional[SpanLevel] = None,
1045
+ status_message: Optional[str] = None,
1046
+ ) -> _AgnosticContextManager["AeriAgent"]: ...
1047
+
1048
+ @overload
1049
+ def start_as_current_observation(
1050
+ self,
1051
+ *,
1052
+ name: str,
1053
+ as_type: Literal["tool"],
1054
+ input: Optional[Any] = None,
1055
+ output: Optional[Any] = None,
1056
+ metadata: Optional[Any] = None,
1057
+ version: Optional[str] = None,
1058
+ level: Optional[SpanLevel] = None,
1059
+ status_message: Optional[str] = None,
1060
+ ) -> _AgnosticContextManager["AeriTool"]: ...
1061
+
1062
+ @overload
1063
+ def start_as_current_observation(
1064
+ self,
1065
+ *,
1066
+ name: str,
1067
+ as_type: Literal["chain"],
1068
+ input: Optional[Any] = None,
1069
+ output: Optional[Any] = None,
1070
+ metadata: Optional[Any] = None,
1071
+ version: Optional[str] = None,
1072
+ level: Optional[SpanLevel] = None,
1073
+ status_message: Optional[str] = None,
1074
+ ) -> _AgnosticContextManager["AeriChain"]: ...
1075
+
1076
+ @overload
1077
+ def start_as_current_observation(
1078
+ self,
1079
+ *,
1080
+ name: str,
1081
+ as_type: Literal["retriever"],
1082
+ input: Optional[Any] = None,
1083
+ output: Optional[Any] = None,
1084
+ metadata: Optional[Any] = None,
1085
+ version: Optional[str] = None,
1086
+ level: Optional[SpanLevel] = None,
1087
+ status_message: Optional[str] = None,
1088
+ ) -> _AgnosticContextManager["AeriRetriever"]: ...
1089
+
1090
+ @overload
1091
+ def start_as_current_observation(
1092
+ self,
1093
+ *,
1094
+ name: str,
1095
+ as_type: Literal["evaluator"],
1096
+ input: Optional[Any] = None,
1097
+ output: Optional[Any] = None,
1098
+ metadata: Optional[Any] = None,
1099
+ version: Optional[str] = None,
1100
+ level: Optional[SpanLevel] = None,
1101
+ status_message: Optional[str] = None,
1102
+ ) -> _AgnosticContextManager["AeriEvaluator"]: ...
1103
+
1104
+ @overload
1105
+ def start_as_current_observation(
1106
+ self,
1107
+ *,
1108
+ name: str,
1109
+ as_type: Literal["guardrail"],
1110
+ input: Optional[Any] = None,
1111
+ output: Optional[Any] = None,
1112
+ metadata: Optional[Any] = None,
1113
+ version: Optional[str] = None,
1114
+ level: Optional[SpanLevel] = None,
1115
+ status_message: Optional[str] = None,
1116
+ ) -> _AgnosticContextManager["AeriGuardrail"]: ...
1117
+
1118
+ def start_as_current_observation( # type: ignore[misc]
1119
+ self,
1120
+ *,
1121
+ name: str,
1122
+ as_type: ObservationTypeLiteralNoEvent = "span",
1123
+ input: Optional[Any] = None,
1124
+ output: Optional[Any] = None,
1125
+ metadata: Optional[Any] = None,
1126
+ version: Optional[str] = None,
1127
+ level: Optional[SpanLevel] = None,
1128
+ status_message: Optional[str] = None,
1129
+ completion_start_time: Optional[datetime] = None,
1130
+ model: Optional[str] = None,
1131
+ model_parameters: Optional[Dict[str, MapValue]] = None,
1132
+ usage_details: Optional[Dict[str, int]] = None,
1133
+ cost_details: Optional[Dict[str, float]] = None,
1134
+ prompt: Optional[PromptClient] = None,
1135
+ # TODO: or union of context managers?
1136
+ ) -> _AgnosticContextManager[
1137
+ Union[
1138
+ "AeriSpan",
1139
+ "AeriGeneration",
1140
+ "AeriAgent",
1141
+ "AeriTool",
1142
+ "AeriChain",
1143
+ "AeriRetriever",
1144
+ "AeriEvaluator",
1145
+ "AeriEmbedding",
1146
+ "AeriGuardrail",
1147
+ ]
1148
+ ]:
1149
+ """Create a new child observation and set it as the current observation in a context manager.
1150
+
1151
+ This is the generic method for creating any type of child observation with
1152
+ context management. It delegates to the client's _create_span_with_parent_context method.
1153
+
1154
+ Args:
1155
+ name: Name of the observation
1156
+ as_type: Type of observation to create
1157
+ input: Input data for the operation
1158
+ output: Output data from the operation
1159
+ metadata: Additional metadata to associate with the observation
1160
+ version: Version identifier for the code or component
1161
+ level: Importance level of the observation (info, warning, error)
1162
+ status_message: Optional status message for the observation
1163
+ completion_start_time: When the model started generating (for generation types)
1164
+ model: Name/identifier of the AI model used (for generation types)
1165
+ model_parameters: Parameters used for the model (for generation types)
1166
+ usage_details: Token usage information (for generation types)
1167
+ cost_details: Cost information (for generation types)
1168
+ prompt: Associated prompt template (for generation types)
1169
+
1170
+ Returns:
1171
+ A context manager that yields a new observation of the specified type
1172
+ """
1173
+ return self._aeri_client._create_span_with_parent_context(
1174
+ name=name,
1175
+ as_type=as_type,
1176
+ remote_parent_span=None,
1177
+ parent=self._otel_span,
1178
+ input=input,
1179
+ output=output,
1180
+ metadata=metadata,
1181
+ version=version,
1182
+ level=level,
1183
+ status_message=status_message,
1184
+ completion_start_time=completion_start_time,
1185
+ model=model,
1186
+ model_parameters=model_parameters,
1187
+ usage_details=usage_details,
1188
+ cost_details=cost_details,
1189
+ prompt=prompt,
1190
+ )
1191
+
1192
+ def create_event(
1193
+ self,
1194
+ *,
1195
+ name: str,
1196
+ input: Optional[Any] = None,
1197
+ output: Optional[Any] = None,
1198
+ metadata: Optional[Any] = None,
1199
+ version: Optional[str] = None,
1200
+ level: Optional[SpanLevel] = None,
1201
+ status_message: Optional[str] = None,
1202
+ ) -> "AeriEvent":
1203
+ """Create a new Aeri observation of type 'EVENT'.
1204
+
1205
+ Args:
1206
+ name: Name of the span (e.g., function or operation name)
1207
+ input: Input data for the operation (can be any JSON-serializable object)
1208
+ output: Output data from the operation (can be any JSON-serializable object)
1209
+ metadata: Additional metadata to associate with the span
1210
+ version: Version identifier for the code or component
1211
+ level: Importance level of the span (info, warning, error)
1212
+ status_message: Optional status message for the span
1213
+
1214
+ Returns:
1215
+ The AeriEvent object
1216
+
1217
+ Example:
1218
+ ```python
1219
+ event = aeri.create_event(name="process-event")
1220
+ ```
1221
+ """
1222
+ timestamp = time_ns()
1223
+
1224
+ with otel_trace_api.use_span(self._otel_span):
1225
+ new_otel_span = self._aeri_client._otel_tracer.start_span(
1226
+ name=name, start_time=timestamp
1227
+ )
1228
+
1229
+ return cast(
1230
+ "AeriEvent",
1231
+ AeriEvent(
1232
+ otel_span=new_otel_span,
1233
+ aeri_client=self._aeri_client,
1234
+ input=input,
1235
+ output=output,
1236
+ metadata=metadata,
1237
+ environment=self._environment,
1238
+ release=self._release,
1239
+ version=version,
1240
+ level=level,
1241
+ status_message=status_message,
1242
+ ).end(end_time=timestamp),
1243
+ )
1244
+
1245
+
1246
+ class AeriSpan(AeriObservationWrapper):
1247
+ """Standard span implementation for general operations in Aeri.
1248
+
1249
+ This class represents a general-purpose span that can be used to trace
1250
+ any operation in your application. It extends the base AeriObservationWrapper
1251
+ with specific methods for creating child spans, generations, and updating
1252
+ span-specific attributes. If possible, use a more specific type for
1253
+ better observability and insights.
1254
+ """
1255
+
1256
+ def __init__(
1257
+ self,
1258
+ *,
1259
+ otel_span: otel_trace_api.Span,
1260
+ aeri_client: "Aeri",
1261
+ input: Optional[Any] = None,
1262
+ output: Optional[Any] = None,
1263
+ metadata: Optional[Any] = None,
1264
+ environment: Optional[str] = None,
1265
+ release: Optional[str] = None,
1266
+ version: Optional[str] = None,
1267
+ level: Optional[SpanLevel] = None,
1268
+ status_message: Optional[str] = None,
1269
+ ):
1270
+ """Initialize a new AeriSpan.
1271
+
1272
+ Args:
1273
+ otel_span: The OpenTelemetry span to wrap
1274
+ aeri_client: Reference to the parent Aeri client
1275
+ input: Input data for the span (any JSON-serializable object)
1276
+ output: Output data from the span (any JSON-serializable object)
1277
+ metadata: Additional metadata to associate with the span
1278
+ environment: The tracing environment
1279
+ release: Release identifier for the application
1280
+ version: Version identifier for the code or component
1281
+ level: Importance level of the span (info, warning, error)
1282
+ status_message: Optional status message for the span
1283
+ """
1284
+ super().__init__(
1285
+ otel_span=otel_span,
1286
+ as_type="span",
1287
+ aeri_client=aeri_client,
1288
+ input=input,
1289
+ output=output,
1290
+ metadata=metadata,
1291
+ environment=environment,
1292
+ release=release,
1293
+ version=version,
1294
+ level=level,
1295
+ status_message=status_message,
1296
+ )
1297
+
1298
+
1299
+ class AeriGeneration(AeriObservationWrapper):
1300
+ """Specialized span implementation for AI model generations in Aeri.
1301
+
1302
+ This class represents a generation span specifically designed for tracking
1303
+ AI/LLM operations. It extends the base AeriObservationWrapper with specialized
1304
+ attributes for model details, token usage, and costs.
1305
+ """
1306
+
1307
+ def __init__(
1308
+ self,
1309
+ *,
1310
+ otel_span: otel_trace_api.Span,
1311
+ aeri_client: "Aeri",
1312
+ input: Optional[Any] = None,
1313
+ output: Optional[Any] = None,
1314
+ metadata: Optional[Any] = None,
1315
+ environment: Optional[str] = None,
1316
+ release: Optional[str] = None,
1317
+ version: Optional[str] = None,
1318
+ level: Optional[SpanLevel] = None,
1319
+ status_message: Optional[str] = None,
1320
+ completion_start_time: Optional[datetime] = None,
1321
+ model: Optional[str] = None,
1322
+ model_parameters: Optional[Dict[str, MapValue]] = None,
1323
+ usage_details: Optional[Dict[str, int]] = None,
1324
+ cost_details: Optional[Dict[str, float]] = None,
1325
+ prompt: Optional[PromptClient] = None,
1326
+ ):
1327
+ """Initialize a new AeriGeneration span.
1328
+
1329
+ Args:
1330
+ otel_span: The OpenTelemetry span to wrap
1331
+ aeri_client: Reference to the parent Aeri client
1332
+ input: Input data for the generation (e.g., prompts)
1333
+ output: Output from the generation (e.g., completions)
1334
+ metadata: Additional metadata to associate with the generation
1335
+ environment: The tracing environment
1336
+ release: Release identifier for the application
1337
+ version: Version identifier for the model or component
1338
+ level: Importance level of the generation (info, warning, error)
1339
+ status_message: Optional status message for the generation
1340
+ completion_start_time: When the model started generating the response
1341
+ model: Name/identifier of the AI model used (e.g., "gpt-4")
1342
+ model_parameters: Parameters used for the model (e.g., temperature, max_tokens)
1343
+ usage_details: Token usage information (e.g., prompt_tokens, completion_tokens)
1344
+ cost_details: Cost information for the model call
1345
+ prompt: Associated prompt template from Aeri prompt management
1346
+ """
1347
+ super().__init__(
1348
+ as_type="generation",
1349
+ otel_span=otel_span,
1350
+ aeri_client=aeri_client,
1351
+ input=input,
1352
+ output=output,
1353
+ metadata=metadata,
1354
+ environment=environment,
1355
+ release=release,
1356
+ version=version,
1357
+ level=level,
1358
+ status_message=status_message,
1359
+ completion_start_time=completion_start_time,
1360
+ model=model,
1361
+ model_parameters=model_parameters,
1362
+ usage_details=usage_details,
1363
+ cost_details=cost_details,
1364
+ prompt=prompt,
1365
+ )
1366
+
1367
+
1368
+ class AeriEvent(AeriObservationWrapper):
1369
+ """Specialized span implementation for Aeri Events."""
1370
+
1371
+ def __init__(
1372
+ self,
1373
+ *,
1374
+ otel_span: otel_trace_api.Span,
1375
+ aeri_client: "Aeri",
1376
+ input: Optional[Any] = None,
1377
+ output: Optional[Any] = None,
1378
+ metadata: Optional[Any] = None,
1379
+ environment: Optional[str] = None,
1380
+ release: Optional[str] = None,
1381
+ version: Optional[str] = None,
1382
+ level: Optional[SpanLevel] = None,
1383
+ status_message: Optional[str] = None,
1384
+ ):
1385
+ """Initialize a new AeriEvent span.
1386
+
1387
+ Args:
1388
+ otel_span: The OpenTelemetry span to wrap
1389
+ aeri_client: Reference to the parent Aeri client
1390
+ input: Input data for the event
1391
+ output: Output from the event
1392
+ metadata: Additional metadata to associate with the generation
1393
+ environment: The tracing environment
1394
+ release: Release identifier for the application
1395
+ version: Version identifier for the model or component
1396
+ level: Importance level of the generation (info, warning, error)
1397
+ status_message: Optional status message for the generation
1398
+ """
1399
+ super().__init__(
1400
+ otel_span=otel_span,
1401
+ as_type="event",
1402
+ aeri_client=aeri_client,
1403
+ input=input,
1404
+ output=output,
1405
+ metadata=metadata,
1406
+ environment=environment,
1407
+ release=release,
1408
+ version=version,
1409
+ level=level,
1410
+ status_message=status_message,
1411
+ )
1412
+
1413
+ def update(
1414
+ self,
1415
+ *,
1416
+ name: Optional[str] = None,
1417
+ input: Optional[Any] = None,
1418
+ output: Optional[Any] = None,
1419
+ metadata: Optional[Any] = None,
1420
+ version: Optional[str] = None,
1421
+ level: Optional[SpanLevel] = None,
1422
+ status_message: Optional[str] = None,
1423
+ completion_start_time: Optional[datetime] = None,
1424
+ model: Optional[str] = None,
1425
+ model_parameters: Optional[Dict[str, MapValue]] = None,
1426
+ usage_details: Optional[Dict[str, int]] = None,
1427
+ cost_details: Optional[Dict[str, float]] = None,
1428
+ prompt: Optional[PromptClient] = None,
1429
+ **kwargs: Any,
1430
+ ) -> "AeriEvent":
1431
+ """Update is not allowed for AeriEvent because events cannot be updated.
1432
+
1433
+ This method logs a warning and returns self without making changes.
1434
+
1435
+ Returns:
1436
+ self: Returns the unchanged AeriEvent instance
1437
+ """
1438
+ aeri_logger.warning(
1439
+ "Attempted to update AeriEvent observation. Events cannot be updated after creation."
1440
+ )
1441
+ return self
1442
+
1443
+
1444
+ class AeriAgent(AeriObservationWrapper):
1445
+ """Agent observation for reasoning blocks that act on tools using LLM guidance."""
1446
+
1447
+ def __init__(self, **kwargs: Any) -> None:
1448
+ """Initialize a new AeriAgent span."""
1449
+ kwargs["as_type"] = "agent"
1450
+ super().__init__(**kwargs)
1451
+
1452
+
1453
+ class AeriTool(AeriObservationWrapper):
1454
+ """Tool observation representing external tool calls, e.g., calling a weather API."""
1455
+
1456
+ def __init__(self, **kwargs: Any) -> None:
1457
+ """Initialize a new AeriTool span."""
1458
+ kwargs["as_type"] = "tool"
1459
+ super().__init__(**kwargs)
1460
+
1461
+
1462
+ class AeriChain(AeriObservationWrapper):
1463
+ """Chain observation for connecting LLM application steps, e.g. passing context from retriever to LLM."""
1464
+
1465
+ def __init__(self, **kwargs: Any) -> None:
1466
+ """Initialize a new AeriChain span."""
1467
+ kwargs["as_type"] = "chain"
1468
+ super().__init__(**kwargs)
1469
+
1470
+
1471
+ class AeriRetriever(AeriObservationWrapper):
1472
+ """Retriever observation for data retrieval steps, e.g. vector store or database queries."""
1473
+
1474
+ def __init__(self, **kwargs: Any) -> None:
1475
+ """Initialize a new AeriRetriever span."""
1476
+ kwargs["as_type"] = "retriever"
1477
+ super().__init__(**kwargs)
1478
+
1479
+
1480
+ class AeriEmbedding(AeriObservationWrapper):
1481
+ """Embedding observation for LLM embedding calls, typically used before retrieval."""
1482
+
1483
+ def __init__(self, **kwargs: Any) -> None:
1484
+ """Initialize a new AeriEmbedding span."""
1485
+ kwargs["as_type"] = "embedding"
1486
+ super().__init__(**kwargs)
1487
+
1488
+
1489
+ class AeriEvaluator(AeriObservationWrapper):
1490
+ """Evaluator observation for assessing relevance, correctness, or helpfulness of LLM outputs."""
1491
+
1492
+ def __init__(self, **kwargs: Any) -> None:
1493
+ """Initialize a new AeriEvaluator span."""
1494
+ kwargs["as_type"] = "evaluator"
1495
+ super().__init__(**kwargs)
1496
+
1497
+
1498
+ class AeriGuardrail(AeriObservationWrapper):
1499
+ """Guardrail observation for protection e.g. against jailbreaks or offensive content."""
1500
+
1501
+ def __init__(self, **kwargs: Any) -> None:
1502
+ """Initialize a new AeriGuardrail span."""
1503
+ kwargs["as_type"] = "guardrail"
1504
+ super().__init__(**kwargs)
1505
+
1506
+
1507
+ _OBSERVATION_CLASS_MAP.update(
1508
+ {
1509
+ "span": AeriSpan,
1510
+ "generation": AeriGeneration,
1511
+ "agent": AeriAgent,
1512
+ "tool": AeriTool,
1513
+ "chain": AeriChain,
1514
+ "retriever": AeriRetriever,
1515
+ "evaluator": AeriEvaluator,
1516
+ "embedding": AeriEmbedding,
1517
+ "guardrail": AeriGuardrail,
1518
+ }
1519
+ )