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,1208 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ import datetime as dt
4
+ import typing
5
+ from json.decoder import JSONDecodeError
6
+
7
+ from ..commons.errors.access_denied_error import AccessDeniedError
8
+ from ..commons.errors.error import Error
9
+ from ..commons.errors.method_not_allowed_error import MethodNotAllowedError
10
+ from ..commons.errors.not_found_error import NotFoundError
11
+ from ..commons.errors.unauthorized_error import UnauthorizedError
12
+ from ..commons.types.trace_with_full_details import TraceWithFullDetails
13
+ from ..core.api_error import ApiError
14
+ from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
15
+ from ..core.datetime_utils import serialize_datetime
16
+ from ..core.http_response import AsyncHttpResponse, HttpResponse
17
+ from ..core.jsonable_encoder import jsonable_encoder
18
+ from ..core.pydantic_utilities import parse_obj_as
19
+ from ..core.request_options import RequestOptions
20
+ from .types.delete_trace_response import DeleteTraceResponse
21
+ from .types.traces import Traces
22
+
23
+ # this is used as the default value for optional parameters
24
+ OMIT = typing.cast(typing.Any, ...)
25
+
26
+
27
+ class RawTraceClient:
28
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
29
+ self._client_wrapper = client_wrapper
30
+
31
+ def get(
32
+ self, trace_id: str, *, request_options: typing.Optional[RequestOptions] = None
33
+ ) -> HttpResponse[TraceWithFullDetails]:
34
+ """
35
+ Get a specific trace
36
+
37
+ Parameters
38
+ ----------
39
+ trace_id : str
40
+ The unique aeri identifier of a trace
41
+
42
+ request_options : typing.Optional[RequestOptions]
43
+ Request-specific configuration.
44
+
45
+ Returns
46
+ -------
47
+ HttpResponse[TraceWithFullDetails]
48
+ """
49
+ _response = self._client_wrapper.httpx_client.request(
50
+ f"api/public/traces/{jsonable_encoder(trace_id)}",
51
+ method="GET",
52
+ request_options=request_options,
53
+ )
54
+ try:
55
+ if 200 <= _response.status_code < 300:
56
+ _data = typing.cast(
57
+ TraceWithFullDetails,
58
+ parse_obj_as(
59
+ type_=TraceWithFullDetails, # type: ignore
60
+ object_=_response.json(),
61
+ ),
62
+ )
63
+ return HttpResponse(response=_response, data=_data)
64
+ if _response.status_code == 400:
65
+ raise Error(
66
+ headers=dict(_response.headers),
67
+ body=typing.cast(
68
+ typing.Any,
69
+ parse_obj_as(
70
+ type_=typing.Any, # type: ignore
71
+ object_=_response.json(),
72
+ ),
73
+ ),
74
+ )
75
+ if _response.status_code == 401:
76
+ raise UnauthorizedError(
77
+ headers=dict(_response.headers),
78
+ body=typing.cast(
79
+ typing.Any,
80
+ parse_obj_as(
81
+ type_=typing.Any, # type: ignore
82
+ object_=_response.json(),
83
+ ),
84
+ ),
85
+ )
86
+ if _response.status_code == 403:
87
+ raise AccessDeniedError(
88
+ headers=dict(_response.headers),
89
+ body=typing.cast(
90
+ typing.Any,
91
+ parse_obj_as(
92
+ type_=typing.Any, # type: ignore
93
+ object_=_response.json(),
94
+ ),
95
+ ),
96
+ )
97
+ if _response.status_code == 405:
98
+ raise MethodNotAllowedError(
99
+ headers=dict(_response.headers),
100
+ body=typing.cast(
101
+ typing.Any,
102
+ parse_obj_as(
103
+ type_=typing.Any, # type: ignore
104
+ object_=_response.json(),
105
+ ),
106
+ ),
107
+ )
108
+ if _response.status_code == 404:
109
+ raise NotFoundError(
110
+ headers=dict(_response.headers),
111
+ body=typing.cast(
112
+ typing.Any,
113
+ parse_obj_as(
114
+ type_=typing.Any, # type: ignore
115
+ object_=_response.json(),
116
+ ),
117
+ ),
118
+ )
119
+ _response_json = _response.json()
120
+ except JSONDecodeError:
121
+ raise ApiError(
122
+ status_code=_response.status_code,
123
+ headers=dict(_response.headers),
124
+ body=_response.text,
125
+ )
126
+ raise ApiError(
127
+ status_code=_response.status_code,
128
+ headers=dict(_response.headers),
129
+ body=_response_json,
130
+ )
131
+
132
+ def delete(
133
+ self, trace_id: str, *, request_options: typing.Optional[RequestOptions] = None
134
+ ) -> HttpResponse[DeleteTraceResponse]:
135
+ """
136
+ Delete a specific trace
137
+
138
+ Parameters
139
+ ----------
140
+ trace_id : str
141
+ The unique aeri identifier of the trace to delete
142
+
143
+ request_options : typing.Optional[RequestOptions]
144
+ Request-specific configuration.
145
+
146
+ Returns
147
+ -------
148
+ HttpResponse[DeleteTraceResponse]
149
+ """
150
+ _response = self._client_wrapper.httpx_client.request(
151
+ f"api/public/traces/{jsonable_encoder(trace_id)}",
152
+ method="DELETE",
153
+ request_options=request_options,
154
+ )
155
+ try:
156
+ if 200 <= _response.status_code < 300:
157
+ _data = typing.cast(
158
+ DeleteTraceResponse,
159
+ parse_obj_as(
160
+ type_=DeleteTraceResponse, # type: ignore
161
+ object_=_response.json(),
162
+ ),
163
+ )
164
+ return HttpResponse(response=_response, data=_data)
165
+ if _response.status_code == 400:
166
+ raise Error(
167
+ headers=dict(_response.headers),
168
+ body=typing.cast(
169
+ typing.Any,
170
+ parse_obj_as(
171
+ type_=typing.Any, # type: ignore
172
+ object_=_response.json(),
173
+ ),
174
+ ),
175
+ )
176
+ if _response.status_code == 401:
177
+ raise UnauthorizedError(
178
+ headers=dict(_response.headers),
179
+ body=typing.cast(
180
+ typing.Any,
181
+ parse_obj_as(
182
+ type_=typing.Any, # type: ignore
183
+ object_=_response.json(),
184
+ ),
185
+ ),
186
+ )
187
+ if _response.status_code == 403:
188
+ raise AccessDeniedError(
189
+ headers=dict(_response.headers),
190
+ body=typing.cast(
191
+ typing.Any,
192
+ parse_obj_as(
193
+ type_=typing.Any, # type: ignore
194
+ object_=_response.json(),
195
+ ),
196
+ ),
197
+ )
198
+ if _response.status_code == 405:
199
+ raise MethodNotAllowedError(
200
+ headers=dict(_response.headers),
201
+ body=typing.cast(
202
+ typing.Any,
203
+ parse_obj_as(
204
+ type_=typing.Any, # type: ignore
205
+ object_=_response.json(),
206
+ ),
207
+ ),
208
+ )
209
+ if _response.status_code == 404:
210
+ raise NotFoundError(
211
+ headers=dict(_response.headers),
212
+ body=typing.cast(
213
+ typing.Any,
214
+ parse_obj_as(
215
+ type_=typing.Any, # type: ignore
216
+ object_=_response.json(),
217
+ ),
218
+ ),
219
+ )
220
+ _response_json = _response.json()
221
+ except JSONDecodeError:
222
+ raise ApiError(
223
+ status_code=_response.status_code,
224
+ headers=dict(_response.headers),
225
+ body=_response.text,
226
+ )
227
+ raise ApiError(
228
+ status_code=_response.status_code,
229
+ headers=dict(_response.headers),
230
+ body=_response_json,
231
+ )
232
+
233
+ def list(
234
+ self,
235
+ *,
236
+ page: typing.Optional[int] = None,
237
+ limit: typing.Optional[int] = None,
238
+ user_id: typing.Optional[str] = None,
239
+ name: typing.Optional[str] = None,
240
+ session_id: typing.Optional[str] = None,
241
+ from_timestamp: typing.Optional[dt.datetime] = None,
242
+ to_timestamp: typing.Optional[dt.datetime] = None,
243
+ order_by: typing.Optional[str] = None,
244
+ tags: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
245
+ version: typing.Optional[str] = None,
246
+ release: typing.Optional[str] = None,
247
+ environment: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
248
+ fields: typing.Optional[str] = None,
249
+ filter: typing.Optional[str] = None,
250
+ request_options: typing.Optional[RequestOptions] = None,
251
+ ) -> HttpResponse[Traces]:
252
+ """
253
+ Get list of traces
254
+
255
+ Parameters
256
+ ----------
257
+ page : typing.Optional[int]
258
+ Page number, starts at 1
259
+
260
+ limit : typing.Optional[int]
261
+ Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit.
262
+
263
+ user_id : typing.Optional[str]
264
+
265
+ name : typing.Optional[str]
266
+
267
+ session_id : typing.Optional[str]
268
+
269
+ from_timestamp : typing.Optional[dt.datetime]
270
+ Optional filter to only include traces with a trace.timestamp on or after a certain datetime (ISO 8601)
271
+
272
+ to_timestamp : typing.Optional[dt.datetime]
273
+ Optional filter to only include traces with a trace.timestamp before a certain datetime (ISO 8601)
274
+
275
+ order_by : typing.Optional[str]
276
+ Format of the string [field].[asc/desc]. Fields: id, timestamp, name, userId, release, version, public, bookmarked, sessionId. Example: timestamp.asc
277
+
278
+ tags : typing.Optional[typing.Union[str, typing.Sequence[str]]]
279
+ Only traces that include all of these tags will be returned.
280
+
281
+ version : typing.Optional[str]
282
+ Optional filter to only include traces with a certain version.
283
+
284
+ release : typing.Optional[str]
285
+ Optional filter to only include traces with a certain release.
286
+
287
+ environment : typing.Optional[typing.Union[str, typing.Sequence[str]]]
288
+ Optional filter for traces where the environment is one of the provided values.
289
+
290
+ fields : typing.Optional[str]
291
+ Comma-separated list of fields to include in the response. Available field groups: 'core' (always included), 'io' (input, output, metadata), 'scores', 'observations', 'metrics'. If not specified, all fields are returned. Example: 'core,scores,metrics'. Note: Excluded 'observations' or 'scores' fields return empty arrays; excluded 'metrics' returns -1 for 'totalCost' and 'latency'.
292
+
293
+ filter : typing.Optional[str]
294
+ JSON string containing an array of filter conditions. When provided, this takes precedence over query parameter filters (userId, name, sessionId, tags, version, release, environment, fromTimestamp, toTimestamp).
295
+
296
+ ## Filter Structure
297
+ Each filter condition has the following structure:
298
+ ```json
299
+ [
300
+ {
301
+ "type": string, // Required. One of: "datetime", "string", "number", "stringOptions", "categoryOptions", "arrayOptions", "stringObject", "numberObject", "boolean", "null"
302
+ "column": string, // Required. Column to filter on (see available columns below)
303
+ "operator": string, // Required. Operator based on type:
304
+ // - datetime: ">", "<", ">=", "<="
305
+ // - string: "=", "contains", "does not contain", "starts with", "ends with"
306
+ // - stringOptions: "any of", "none of"
307
+ // - categoryOptions: "any of", "none of"
308
+ // - arrayOptions: "any of", "none of", "all of"
309
+ // - number: "=", ">", "<", ">=", "<="
310
+ // - stringObject: "=", "contains", "does not contain", "starts with", "ends with"
311
+ // - numberObject: "=", ">", "<", ">=", "<="
312
+ // - boolean: "=", "<>"
313
+ // - null: "is null", "is not null"
314
+ "value": any, // Required (except for null type). Value to compare against. Type depends on filter type
315
+ "key": string // Required only for stringObject, numberObject, and categoryOptions types when filtering on nested fields like metadata
316
+ }
317
+ ]
318
+ ```
319
+
320
+ ## Available Columns
321
+
322
+ ### Core Trace Fields
323
+ - `id` (string) - Trace ID
324
+ - `name` (string) - Trace name
325
+ - `timestamp` (datetime) - Trace timestamp
326
+ - `userId` (string) - User ID
327
+ - `sessionId` (string) - Session ID
328
+ - `environment` (string) - Environment tag
329
+ - `version` (string) - Version tag
330
+ - `release` (string) - Release tag
331
+ - `tags` (arrayOptions) - Array of tags
332
+ - `bookmarked` (boolean) - Bookmark status
333
+
334
+ ### Structured Data
335
+ - `metadata` (stringObject/numberObject/categoryOptions) - Metadata key-value pairs. Use `key` parameter to filter on specific metadata keys.
336
+
337
+ ### Aggregated Metrics (from observations)
338
+ These metrics are aggregated from all observations within the trace:
339
+ - `latency` (number) - Latency in seconds (time from first observation start to last observation end)
340
+ - `inputTokens` (number) - Total input tokens across all observations
341
+ - `outputTokens` (number) - Total output tokens across all observations
342
+ - `totalTokens` (number) - Total tokens (alias: `tokens`)
343
+ - `inputCost` (number) - Total input cost in USD
344
+ - `outputCost` (number) - Total output cost in USD
345
+ - `totalCost` (number) - Total cost in USD
346
+
347
+ ### Observation Level Aggregations
348
+ These fields aggregate observation levels within the trace:
349
+ - `level` (string) - Highest severity level (ERROR > WARNING > DEFAULT > DEBUG)
350
+ - `warningCount` (number) - Count of WARNING level observations
351
+ - `errorCount` (number) - Count of ERROR level observations
352
+ - `defaultCount` (number) - Count of DEFAULT level observations
353
+ - `debugCount` (number) - Count of DEBUG level observations
354
+
355
+ ### Scores (requires join with scores table)
356
+ - `scores_avg` (number) - Average of numeric scores (alias: `scores`)
357
+ - `score_categories` (categoryOptions) - Categorical score values
358
+
359
+ ## Filter Examples
360
+ ```json
361
+ [
362
+ {
363
+ "type": "datetime",
364
+ "column": "timestamp",
365
+ "operator": ">=",
366
+ "value": "2024-01-01T00:00:00Z"
367
+ },
368
+ {
369
+ "type": "string",
370
+ "column": "userId",
371
+ "operator": "=",
372
+ "value": "user-123"
373
+ },
374
+ {
375
+ "type": "number",
376
+ "column": "totalCost",
377
+ "operator": ">=",
378
+ "value": 0.01
379
+ },
380
+ {
381
+ "type": "arrayOptions",
382
+ "column": "tags",
383
+ "operator": "all of",
384
+ "value": ["production", "critical"]
385
+ },
386
+ {
387
+ "type": "stringObject",
388
+ "column": "metadata",
389
+ "key": "customer_tier",
390
+ "operator": "=",
391
+ "value": "enterprise"
392
+ }
393
+ ]
394
+ ```
395
+
396
+ ## Performance Notes
397
+ - Filtering on `userId`, `sessionId`, or `metadata` may enable skip indexes for better query performance
398
+ - Score filters require a join with the scores table and may impact query performance
399
+
400
+ request_options : typing.Optional[RequestOptions]
401
+ Request-specific configuration.
402
+
403
+ Returns
404
+ -------
405
+ HttpResponse[Traces]
406
+ """
407
+ _response = self._client_wrapper.httpx_client.request(
408
+ "api/public/traces",
409
+ method="GET",
410
+ params={
411
+ "page": page,
412
+ "limit": limit,
413
+ "userId": user_id,
414
+ "name": name,
415
+ "sessionId": session_id,
416
+ "fromTimestamp": serialize_datetime(from_timestamp)
417
+ if from_timestamp is not None
418
+ else None,
419
+ "toTimestamp": serialize_datetime(to_timestamp)
420
+ if to_timestamp is not None
421
+ else None,
422
+ "orderBy": order_by,
423
+ "tags": tags,
424
+ "version": version,
425
+ "release": release,
426
+ "environment": environment,
427
+ "fields": fields,
428
+ "filter": filter,
429
+ },
430
+ request_options=request_options,
431
+ )
432
+ try:
433
+ if 200 <= _response.status_code < 300:
434
+ _data = typing.cast(
435
+ Traces,
436
+ parse_obj_as(
437
+ type_=Traces, # type: ignore
438
+ object_=_response.json(),
439
+ ),
440
+ )
441
+ return HttpResponse(response=_response, data=_data)
442
+ if _response.status_code == 400:
443
+ raise Error(
444
+ headers=dict(_response.headers),
445
+ body=typing.cast(
446
+ typing.Any,
447
+ parse_obj_as(
448
+ type_=typing.Any, # type: ignore
449
+ object_=_response.json(),
450
+ ),
451
+ ),
452
+ )
453
+ if _response.status_code == 401:
454
+ raise UnauthorizedError(
455
+ headers=dict(_response.headers),
456
+ body=typing.cast(
457
+ typing.Any,
458
+ parse_obj_as(
459
+ type_=typing.Any, # type: ignore
460
+ object_=_response.json(),
461
+ ),
462
+ ),
463
+ )
464
+ if _response.status_code == 403:
465
+ raise AccessDeniedError(
466
+ headers=dict(_response.headers),
467
+ body=typing.cast(
468
+ typing.Any,
469
+ parse_obj_as(
470
+ type_=typing.Any, # type: ignore
471
+ object_=_response.json(),
472
+ ),
473
+ ),
474
+ )
475
+ if _response.status_code == 405:
476
+ raise MethodNotAllowedError(
477
+ headers=dict(_response.headers),
478
+ body=typing.cast(
479
+ typing.Any,
480
+ parse_obj_as(
481
+ type_=typing.Any, # type: ignore
482
+ object_=_response.json(),
483
+ ),
484
+ ),
485
+ )
486
+ if _response.status_code == 404:
487
+ raise NotFoundError(
488
+ headers=dict(_response.headers),
489
+ body=typing.cast(
490
+ typing.Any,
491
+ parse_obj_as(
492
+ type_=typing.Any, # type: ignore
493
+ object_=_response.json(),
494
+ ),
495
+ ),
496
+ )
497
+ _response_json = _response.json()
498
+ except JSONDecodeError:
499
+ raise ApiError(
500
+ status_code=_response.status_code,
501
+ headers=dict(_response.headers),
502
+ body=_response.text,
503
+ )
504
+ raise ApiError(
505
+ status_code=_response.status_code,
506
+ headers=dict(_response.headers),
507
+ body=_response_json,
508
+ )
509
+
510
+ def delete_multiple(
511
+ self,
512
+ *,
513
+ trace_ids: typing.Sequence[str],
514
+ request_options: typing.Optional[RequestOptions] = None,
515
+ ) -> HttpResponse[DeleteTraceResponse]:
516
+ """
517
+ Delete multiple traces
518
+
519
+ Parameters
520
+ ----------
521
+ trace_ids : typing.Sequence[str]
522
+ List of trace IDs to delete
523
+
524
+ request_options : typing.Optional[RequestOptions]
525
+ Request-specific configuration.
526
+
527
+ Returns
528
+ -------
529
+ HttpResponse[DeleteTraceResponse]
530
+ """
531
+ _response = self._client_wrapper.httpx_client.request(
532
+ "api/public/traces",
533
+ method="DELETE",
534
+ json={
535
+ "traceIds": trace_ids,
536
+ },
537
+ request_options=request_options,
538
+ omit=OMIT,
539
+ )
540
+ try:
541
+ if 200 <= _response.status_code < 300:
542
+ _data = typing.cast(
543
+ DeleteTraceResponse,
544
+ parse_obj_as(
545
+ type_=DeleteTraceResponse, # type: ignore
546
+ object_=_response.json(),
547
+ ),
548
+ )
549
+ return HttpResponse(response=_response, data=_data)
550
+ if _response.status_code == 400:
551
+ raise Error(
552
+ headers=dict(_response.headers),
553
+ body=typing.cast(
554
+ typing.Any,
555
+ parse_obj_as(
556
+ type_=typing.Any, # type: ignore
557
+ object_=_response.json(),
558
+ ),
559
+ ),
560
+ )
561
+ if _response.status_code == 401:
562
+ raise UnauthorizedError(
563
+ headers=dict(_response.headers),
564
+ body=typing.cast(
565
+ typing.Any,
566
+ parse_obj_as(
567
+ type_=typing.Any, # type: ignore
568
+ object_=_response.json(),
569
+ ),
570
+ ),
571
+ )
572
+ if _response.status_code == 403:
573
+ raise AccessDeniedError(
574
+ headers=dict(_response.headers),
575
+ body=typing.cast(
576
+ typing.Any,
577
+ parse_obj_as(
578
+ type_=typing.Any, # type: ignore
579
+ object_=_response.json(),
580
+ ),
581
+ ),
582
+ )
583
+ if _response.status_code == 405:
584
+ raise MethodNotAllowedError(
585
+ headers=dict(_response.headers),
586
+ body=typing.cast(
587
+ typing.Any,
588
+ parse_obj_as(
589
+ type_=typing.Any, # type: ignore
590
+ object_=_response.json(),
591
+ ),
592
+ ),
593
+ )
594
+ if _response.status_code == 404:
595
+ raise NotFoundError(
596
+ headers=dict(_response.headers),
597
+ body=typing.cast(
598
+ typing.Any,
599
+ parse_obj_as(
600
+ type_=typing.Any, # type: ignore
601
+ object_=_response.json(),
602
+ ),
603
+ ),
604
+ )
605
+ _response_json = _response.json()
606
+ except JSONDecodeError:
607
+ raise ApiError(
608
+ status_code=_response.status_code,
609
+ headers=dict(_response.headers),
610
+ body=_response.text,
611
+ )
612
+ raise ApiError(
613
+ status_code=_response.status_code,
614
+ headers=dict(_response.headers),
615
+ body=_response_json,
616
+ )
617
+
618
+
619
+ class AsyncRawTraceClient:
620
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
621
+ self._client_wrapper = client_wrapper
622
+
623
+ async def get(
624
+ self, trace_id: str, *, request_options: typing.Optional[RequestOptions] = None
625
+ ) -> AsyncHttpResponse[TraceWithFullDetails]:
626
+ """
627
+ Get a specific trace
628
+
629
+ Parameters
630
+ ----------
631
+ trace_id : str
632
+ The unique aeri identifier of a trace
633
+
634
+ request_options : typing.Optional[RequestOptions]
635
+ Request-specific configuration.
636
+
637
+ Returns
638
+ -------
639
+ AsyncHttpResponse[TraceWithFullDetails]
640
+ """
641
+ _response = await self._client_wrapper.httpx_client.request(
642
+ f"api/public/traces/{jsonable_encoder(trace_id)}",
643
+ method="GET",
644
+ request_options=request_options,
645
+ )
646
+ try:
647
+ if 200 <= _response.status_code < 300:
648
+ _data = typing.cast(
649
+ TraceWithFullDetails,
650
+ parse_obj_as(
651
+ type_=TraceWithFullDetails, # type: ignore
652
+ object_=_response.json(),
653
+ ),
654
+ )
655
+ return AsyncHttpResponse(response=_response, data=_data)
656
+ if _response.status_code == 400:
657
+ raise Error(
658
+ headers=dict(_response.headers),
659
+ body=typing.cast(
660
+ typing.Any,
661
+ parse_obj_as(
662
+ type_=typing.Any, # type: ignore
663
+ object_=_response.json(),
664
+ ),
665
+ ),
666
+ )
667
+ if _response.status_code == 401:
668
+ raise UnauthorizedError(
669
+ headers=dict(_response.headers),
670
+ body=typing.cast(
671
+ typing.Any,
672
+ parse_obj_as(
673
+ type_=typing.Any, # type: ignore
674
+ object_=_response.json(),
675
+ ),
676
+ ),
677
+ )
678
+ if _response.status_code == 403:
679
+ raise AccessDeniedError(
680
+ headers=dict(_response.headers),
681
+ body=typing.cast(
682
+ typing.Any,
683
+ parse_obj_as(
684
+ type_=typing.Any, # type: ignore
685
+ object_=_response.json(),
686
+ ),
687
+ ),
688
+ )
689
+ if _response.status_code == 405:
690
+ raise MethodNotAllowedError(
691
+ headers=dict(_response.headers),
692
+ body=typing.cast(
693
+ typing.Any,
694
+ parse_obj_as(
695
+ type_=typing.Any, # type: ignore
696
+ object_=_response.json(),
697
+ ),
698
+ ),
699
+ )
700
+ if _response.status_code == 404:
701
+ raise NotFoundError(
702
+ headers=dict(_response.headers),
703
+ body=typing.cast(
704
+ typing.Any,
705
+ parse_obj_as(
706
+ type_=typing.Any, # type: ignore
707
+ object_=_response.json(),
708
+ ),
709
+ ),
710
+ )
711
+ _response_json = _response.json()
712
+ except JSONDecodeError:
713
+ raise ApiError(
714
+ status_code=_response.status_code,
715
+ headers=dict(_response.headers),
716
+ body=_response.text,
717
+ )
718
+ raise ApiError(
719
+ status_code=_response.status_code,
720
+ headers=dict(_response.headers),
721
+ body=_response_json,
722
+ )
723
+
724
+ async def delete(
725
+ self, trace_id: str, *, request_options: typing.Optional[RequestOptions] = None
726
+ ) -> AsyncHttpResponse[DeleteTraceResponse]:
727
+ """
728
+ Delete a specific trace
729
+
730
+ Parameters
731
+ ----------
732
+ trace_id : str
733
+ The unique aeri identifier of the trace to delete
734
+
735
+ request_options : typing.Optional[RequestOptions]
736
+ Request-specific configuration.
737
+
738
+ Returns
739
+ -------
740
+ AsyncHttpResponse[DeleteTraceResponse]
741
+ """
742
+ _response = await self._client_wrapper.httpx_client.request(
743
+ f"api/public/traces/{jsonable_encoder(trace_id)}",
744
+ method="DELETE",
745
+ request_options=request_options,
746
+ )
747
+ try:
748
+ if 200 <= _response.status_code < 300:
749
+ _data = typing.cast(
750
+ DeleteTraceResponse,
751
+ parse_obj_as(
752
+ type_=DeleteTraceResponse, # type: ignore
753
+ object_=_response.json(),
754
+ ),
755
+ )
756
+ return AsyncHttpResponse(response=_response, data=_data)
757
+ if _response.status_code == 400:
758
+ raise Error(
759
+ headers=dict(_response.headers),
760
+ body=typing.cast(
761
+ typing.Any,
762
+ parse_obj_as(
763
+ type_=typing.Any, # type: ignore
764
+ object_=_response.json(),
765
+ ),
766
+ ),
767
+ )
768
+ if _response.status_code == 401:
769
+ raise UnauthorizedError(
770
+ headers=dict(_response.headers),
771
+ body=typing.cast(
772
+ typing.Any,
773
+ parse_obj_as(
774
+ type_=typing.Any, # type: ignore
775
+ object_=_response.json(),
776
+ ),
777
+ ),
778
+ )
779
+ if _response.status_code == 403:
780
+ raise AccessDeniedError(
781
+ headers=dict(_response.headers),
782
+ body=typing.cast(
783
+ typing.Any,
784
+ parse_obj_as(
785
+ type_=typing.Any, # type: ignore
786
+ object_=_response.json(),
787
+ ),
788
+ ),
789
+ )
790
+ if _response.status_code == 405:
791
+ raise MethodNotAllowedError(
792
+ headers=dict(_response.headers),
793
+ body=typing.cast(
794
+ typing.Any,
795
+ parse_obj_as(
796
+ type_=typing.Any, # type: ignore
797
+ object_=_response.json(),
798
+ ),
799
+ ),
800
+ )
801
+ if _response.status_code == 404:
802
+ raise NotFoundError(
803
+ headers=dict(_response.headers),
804
+ body=typing.cast(
805
+ typing.Any,
806
+ parse_obj_as(
807
+ type_=typing.Any, # type: ignore
808
+ object_=_response.json(),
809
+ ),
810
+ ),
811
+ )
812
+ _response_json = _response.json()
813
+ except JSONDecodeError:
814
+ raise ApiError(
815
+ status_code=_response.status_code,
816
+ headers=dict(_response.headers),
817
+ body=_response.text,
818
+ )
819
+ raise ApiError(
820
+ status_code=_response.status_code,
821
+ headers=dict(_response.headers),
822
+ body=_response_json,
823
+ )
824
+
825
+ async def list(
826
+ self,
827
+ *,
828
+ page: typing.Optional[int] = None,
829
+ limit: typing.Optional[int] = None,
830
+ user_id: typing.Optional[str] = None,
831
+ name: typing.Optional[str] = None,
832
+ session_id: typing.Optional[str] = None,
833
+ from_timestamp: typing.Optional[dt.datetime] = None,
834
+ to_timestamp: typing.Optional[dt.datetime] = None,
835
+ order_by: typing.Optional[str] = None,
836
+ tags: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
837
+ version: typing.Optional[str] = None,
838
+ release: typing.Optional[str] = None,
839
+ environment: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
840
+ fields: typing.Optional[str] = None,
841
+ filter: typing.Optional[str] = None,
842
+ request_options: typing.Optional[RequestOptions] = None,
843
+ ) -> AsyncHttpResponse[Traces]:
844
+ """
845
+ Get list of traces
846
+
847
+ Parameters
848
+ ----------
849
+ page : typing.Optional[int]
850
+ Page number, starts at 1
851
+
852
+ limit : typing.Optional[int]
853
+ Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit.
854
+
855
+ user_id : typing.Optional[str]
856
+
857
+ name : typing.Optional[str]
858
+
859
+ session_id : typing.Optional[str]
860
+
861
+ from_timestamp : typing.Optional[dt.datetime]
862
+ Optional filter to only include traces with a trace.timestamp on or after a certain datetime (ISO 8601)
863
+
864
+ to_timestamp : typing.Optional[dt.datetime]
865
+ Optional filter to only include traces with a trace.timestamp before a certain datetime (ISO 8601)
866
+
867
+ order_by : typing.Optional[str]
868
+ Format of the string [field].[asc/desc]. Fields: id, timestamp, name, userId, release, version, public, bookmarked, sessionId. Example: timestamp.asc
869
+
870
+ tags : typing.Optional[typing.Union[str, typing.Sequence[str]]]
871
+ Only traces that include all of these tags will be returned.
872
+
873
+ version : typing.Optional[str]
874
+ Optional filter to only include traces with a certain version.
875
+
876
+ release : typing.Optional[str]
877
+ Optional filter to only include traces with a certain release.
878
+
879
+ environment : typing.Optional[typing.Union[str, typing.Sequence[str]]]
880
+ Optional filter for traces where the environment is one of the provided values.
881
+
882
+ fields : typing.Optional[str]
883
+ Comma-separated list of fields to include in the response. Available field groups: 'core' (always included), 'io' (input, output, metadata), 'scores', 'observations', 'metrics'. If not specified, all fields are returned. Example: 'core,scores,metrics'. Note: Excluded 'observations' or 'scores' fields return empty arrays; excluded 'metrics' returns -1 for 'totalCost' and 'latency'.
884
+
885
+ filter : typing.Optional[str]
886
+ JSON string containing an array of filter conditions. When provided, this takes precedence over query parameter filters (userId, name, sessionId, tags, version, release, environment, fromTimestamp, toTimestamp).
887
+
888
+ ## Filter Structure
889
+ Each filter condition has the following structure:
890
+ ```json
891
+ [
892
+ {
893
+ "type": string, // Required. One of: "datetime", "string", "number", "stringOptions", "categoryOptions", "arrayOptions", "stringObject", "numberObject", "boolean", "null"
894
+ "column": string, // Required. Column to filter on (see available columns below)
895
+ "operator": string, // Required. Operator based on type:
896
+ // - datetime: ">", "<", ">=", "<="
897
+ // - string: "=", "contains", "does not contain", "starts with", "ends with"
898
+ // - stringOptions: "any of", "none of"
899
+ // - categoryOptions: "any of", "none of"
900
+ // - arrayOptions: "any of", "none of", "all of"
901
+ // - number: "=", ">", "<", ">=", "<="
902
+ // - stringObject: "=", "contains", "does not contain", "starts with", "ends with"
903
+ // - numberObject: "=", ">", "<", ">=", "<="
904
+ // - boolean: "=", "<>"
905
+ // - null: "is null", "is not null"
906
+ "value": any, // Required (except for null type). Value to compare against. Type depends on filter type
907
+ "key": string // Required only for stringObject, numberObject, and categoryOptions types when filtering on nested fields like metadata
908
+ }
909
+ ]
910
+ ```
911
+
912
+ ## Available Columns
913
+
914
+ ### Core Trace Fields
915
+ - `id` (string) - Trace ID
916
+ - `name` (string) - Trace name
917
+ - `timestamp` (datetime) - Trace timestamp
918
+ - `userId` (string) - User ID
919
+ - `sessionId` (string) - Session ID
920
+ - `environment` (string) - Environment tag
921
+ - `version` (string) - Version tag
922
+ - `release` (string) - Release tag
923
+ - `tags` (arrayOptions) - Array of tags
924
+ - `bookmarked` (boolean) - Bookmark status
925
+
926
+ ### Structured Data
927
+ - `metadata` (stringObject/numberObject/categoryOptions) - Metadata key-value pairs. Use `key` parameter to filter on specific metadata keys.
928
+
929
+ ### Aggregated Metrics (from observations)
930
+ These metrics are aggregated from all observations within the trace:
931
+ - `latency` (number) - Latency in seconds (time from first observation start to last observation end)
932
+ - `inputTokens` (number) - Total input tokens across all observations
933
+ - `outputTokens` (number) - Total output tokens across all observations
934
+ - `totalTokens` (number) - Total tokens (alias: `tokens`)
935
+ - `inputCost` (number) - Total input cost in USD
936
+ - `outputCost` (number) - Total output cost in USD
937
+ - `totalCost` (number) - Total cost in USD
938
+
939
+ ### Observation Level Aggregations
940
+ These fields aggregate observation levels within the trace:
941
+ - `level` (string) - Highest severity level (ERROR > WARNING > DEFAULT > DEBUG)
942
+ - `warningCount` (number) - Count of WARNING level observations
943
+ - `errorCount` (number) - Count of ERROR level observations
944
+ - `defaultCount` (number) - Count of DEFAULT level observations
945
+ - `debugCount` (number) - Count of DEBUG level observations
946
+
947
+ ### Scores (requires join with scores table)
948
+ - `scores_avg` (number) - Average of numeric scores (alias: `scores`)
949
+ - `score_categories` (categoryOptions) - Categorical score values
950
+
951
+ ## Filter Examples
952
+ ```json
953
+ [
954
+ {
955
+ "type": "datetime",
956
+ "column": "timestamp",
957
+ "operator": ">=",
958
+ "value": "2024-01-01T00:00:00Z"
959
+ },
960
+ {
961
+ "type": "string",
962
+ "column": "userId",
963
+ "operator": "=",
964
+ "value": "user-123"
965
+ },
966
+ {
967
+ "type": "number",
968
+ "column": "totalCost",
969
+ "operator": ">=",
970
+ "value": 0.01
971
+ },
972
+ {
973
+ "type": "arrayOptions",
974
+ "column": "tags",
975
+ "operator": "all of",
976
+ "value": ["production", "critical"]
977
+ },
978
+ {
979
+ "type": "stringObject",
980
+ "column": "metadata",
981
+ "key": "customer_tier",
982
+ "operator": "=",
983
+ "value": "enterprise"
984
+ }
985
+ ]
986
+ ```
987
+
988
+ ## Performance Notes
989
+ - Filtering on `userId`, `sessionId`, or `metadata` may enable skip indexes for better query performance
990
+ - Score filters require a join with the scores table and may impact query performance
991
+
992
+ request_options : typing.Optional[RequestOptions]
993
+ Request-specific configuration.
994
+
995
+ Returns
996
+ -------
997
+ AsyncHttpResponse[Traces]
998
+ """
999
+ _response = await self._client_wrapper.httpx_client.request(
1000
+ "api/public/traces",
1001
+ method="GET",
1002
+ params={
1003
+ "page": page,
1004
+ "limit": limit,
1005
+ "userId": user_id,
1006
+ "name": name,
1007
+ "sessionId": session_id,
1008
+ "fromTimestamp": serialize_datetime(from_timestamp)
1009
+ if from_timestamp is not None
1010
+ else None,
1011
+ "toTimestamp": serialize_datetime(to_timestamp)
1012
+ if to_timestamp is not None
1013
+ else None,
1014
+ "orderBy": order_by,
1015
+ "tags": tags,
1016
+ "version": version,
1017
+ "release": release,
1018
+ "environment": environment,
1019
+ "fields": fields,
1020
+ "filter": filter,
1021
+ },
1022
+ request_options=request_options,
1023
+ )
1024
+ try:
1025
+ if 200 <= _response.status_code < 300:
1026
+ _data = typing.cast(
1027
+ Traces,
1028
+ parse_obj_as(
1029
+ type_=Traces, # type: ignore
1030
+ object_=_response.json(),
1031
+ ),
1032
+ )
1033
+ return AsyncHttpResponse(response=_response, data=_data)
1034
+ if _response.status_code == 400:
1035
+ raise Error(
1036
+ headers=dict(_response.headers),
1037
+ body=typing.cast(
1038
+ typing.Any,
1039
+ parse_obj_as(
1040
+ type_=typing.Any, # type: ignore
1041
+ object_=_response.json(),
1042
+ ),
1043
+ ),
1044
+ )
1045
+ if _response.status_code == 401:
1046
+ raise UnauthorizedError(
1047
+ headers=dict(_response.headers),
1048
+ body=typing.cast(
1049
+ typing.Any,
1050
+ parse_obj_as(
1051
+ type_=typing.Any, # type: ignore
1052
+ object_=_response.json(),
1053
+ ),
1054
+ ),
1055
+ )
1056
+ if _response.status_code == 403:
1057
+ raise AccessDeniedError(
1058
+ headers=dict(_response.headers),
1059
+ body=typing.cast(
1060
+ typing.Any,
1061
+ parse_obj_as(
1062
+ type_=typing.Any, # type: ignore
1063
+ object_=_response.json(),
1064
+ ),
1065
+ ),
1066
+ )
1067
+ if _response.status_code == 405:
1068
+ raise MethodNotAllowedError(
1069
+ headers=dict(_response.headers),
1070
+ body=typing.cast(
1071
+ typing.Any,
1072
+ parse_obj_as(
1073
+ type_=typing.Any, # type: ignore
1074
+ object_=_response.json(),
1075
+ ),
1076
+ ),
1077
+ )
1078
+ if _response.status_code == 404:
1079
+ raise NotFoundError(
1080
+ headers=dict(_response.headers),
1081
+ body=typing.cast(
1082
+ typing.Any,
1083
+ parse_obj_as(
1084
+ type_=typing.Any, # type: ignore
1085
+ object_=_response.json(),
1086
+ ),
1087
+ ),
1088
+ )
1089
+ _response_json = _response.json()
1090
+ except JSONDecodeError:
1091
+ raise ApiError(
1092
+ status_code=_response.status_code,
1093
+ headers=dict(_response.headers),
1094
+ body=_response.text,
1095
+ )
1096
+ raise ApiError(
1097
+ status_code=_response.status_code,
1098
+ headers=dict(_response.headers),
1099
+ body=_response_json,
1100
+ )
1101
+
1102
+ async def delete_multiple(
1103
+ self,
1104
+ *,
1105
+ trace_ids: typing.Sequence[str],
1106
+ request_options: typing.Optional[RequestOptions] = None,
1107
+ ) -> AsyncHttpResponse[DeleteTraceResponse]:
1108
+ """
1109
+ Delete multiple traces
1110
+
1111
+ Parameters
1112
+ ----------
1113
+ trace_ids : typing.Sequence[str]
1114
+ List of trace IDs to delete
1115
+
1116
+ request_options : typing.Optional[RequestOptions]
1117
+ Request-specific configuration.
1118
+
1119
+ Returns
1120
+ -------
1121
+ AsyncHttpResponse[DeleteTraceResponse]
1122
+ """
1123
+ _response = await self._client_wrapper.httpx_client.request(
1124
+ "api/public/traces",
1125
+ method="DELETE",
1126
+ json={
1127
+ "traceIds": trace_ids,
1128
+ },
1129
+ request_options=request_options,
1130
+ omit=OMIT,
1131
+ )
1132
+ try:
1133
+ if 200 <= _response.status_code < 300:
1134
+ _data = typing.cast(
1135
+ DeleteTraceResponse,
1136
+ parse_obj_as(
1137
+ type_=DeleteTraceResponse, # type: ignore
1138
+ object_=_response.json(),
1139
+ ),
1140
+ )
1141
+ return AsyncHttpResponse(response=_response, data=_data)
1142
+ if _response.status_code == 400:
1143
+ raise Error(
1144
+ headers=dict(_response.headers),
1145
+ body=typing.cast(
1146
+ typing.Any,
1147
+ parse_obj_as(
1148
+ type_=typing.Any, # type: ignore
1149
+ object_=_response.json(),
1150
+ ),
1151
+ ),
1152
+ )
1153
+ if _response.status_code == 401:
1154
+ raise UnauthorizedError(
1155
+ headers=dict(_response.headers),
1156
+ body=typing.cast(
1157
+ typing.Any,
1158
+ parse_obj_as(
1159
+ type_=typing.Any, # type: ignore
1160
+ object_=_response.json(),
1161
+ ),
1162
+ ),
1163
+ )
1164
+ if _response.status_code == 403:
1165
+ raise AccessDeniedError(
1166
+ headers=dict(_response.headers),
1167
+ body=typing.cast(
1168
+ typing.Any,
1169
+ parse_obj_as(
1170
+ type_=typing.Any, # type: ignore
1171
+ object_=_response.json(),
1172
+ ),
1173
+ ),
1174
+ )
1175
+ if _response.status_code == 405:
1176
+ raise MethodNotAllowedError(
1177
+ headers=dict(_response.headers),
1178
+ body=typing.cast(
1179
+ typing.Any,
1180
+ parse_obj_as(
1181
+ type_=typing.Any, # type: ignore
1182
+ object_=_response.json(),
1183
+ ),
1184
+ ),
1185
+ )
1186
+ if _response.status_code == 404:
1187
+ raise NotFoundError(
1188
+ headers=dict(_response.headers),
1189
+ body=typing.cast(
1190
+ typing.Any,
1191
+ parse_obj_as(
1192
+ type_=typing.Any, # type: ignore
1193
+ object_=_response.json(),
1194
+ ),
1195
+ ),
1196
+ )
1197
+ _response_json = _response.json()
1198
+ except JSONDecodeError:
1199
+ raise ApiError(
1200
+ status_code=_response.status_code,
1201
+ headers=dict(_response.headers),
1202
+ body=_response.text,
1203
+ )
1204
+ raise ApiError(
1205
+ status_code=_response.status_code,
1206
+ headers=dict(_response.headers),
1207
+ body=_response_json,
1208
+ )