payi 0.1.0a40__tar.gz → 0.1.0a41__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of payi might be problematic. Click here for more details.

Files changed (166) hide show
  1. payi-0.1.0a41/.release-please-manifest.json +3 -0
  2. {payi-0.1.0a40 → payi-0.1.0a41}/CHANGELOG.md +9 -0
  3. {payi-0.1.0a40 → payi-0.1.0a41}/PKG-INFO +1 -1
  4. {payi-0.1.0a40 → payi-0.1.0a41}/pyproject.toml +2 -2
  5. {payi-0.1.0a40 → payi-0.1.0a41}/requirements-dev.lock +1 -1
  6. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/_constants.py +1 -1
  7. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/_models.py +1 -1
  8. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/_version.py +1 -1
  9. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/lib/AnthropicInstrumentor.py +15 -12
  10. payi-0.1.0a41/src/payi/lib/BedrockInstrumentor.py +288 -0
  11. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/lib/Instruments.py +1 -0
  12. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/lib/OpenAIInstrumentor.py +12 -10
  13. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/lib/instrument.py +108 -17
  14. payi-0.1.0a40/.release-please-manifest.json +0 -3
  15. {payi-0.1.0a40 → payi-0.1.0a41}/.gitignore +0 -0
  16. {payi-0.1.0a40 → payi-0.1.0a41}/CONTRIBUTING.md +0 -0
  17. {payi-0.1.0a40 → payi-0.1.0a41}/LICENSE +0 -0
  18. {payi-0.1.0a40 → payi-0.1.0a41}/README.md +0 -0
  19. {payi-0.1.0a40 → payi-0.1.0a41}/SECURITY.md +0 -0
  20. {payi-0.1.0a40 → payi-0.1.0a41}/api.md +0 -0
  21. {payi-0.1.0a40 → payi-0.1.0a41}/bin/check-release-environment +0 -0
  22. {payi-0.1.0a40 → payi-0.1.0a41}/bin/publish-pypi +0 -0
  23. {payi-0.1.0a40 → payi-0.1.0a41}/examples/.keep +0 -0
  24. {payi-0.1.0a40 → payi-0.1.0a41}/mypy.ini +0 -0
  25. {payi-0.1.0a40 → payi-0.1.0a41}/noxfile.py +0 -0
  26. {payi-0.1.0a40 → payi-0.1.0a41}/release-please-config.json +0 -0
  27. {payi-0.1.0a40 → payi-0.1.0a41}/requirements.lock +0 -0
  28. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/__init__.py +0 -0
  29. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/_base_client.py +0 -0
  30. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/_client.py +0 -0
  31. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/_compat.py +0 -0
  32. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/_exceptions.py +0 -0
  33. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/_files.py +0 -0
  34. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/_qs.py +0 -0
  35. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/_resource.py +0 -0
  36. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/_response.py +0 -0
  37. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/_streaming.py +0 -0
  38. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/_types.py +0 -0
  39. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/_utils/__init__.py +0 -0
  40. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/_utils/_logs.py +0 -0
  41. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/_utils/_proxy.py +0 -0
  42. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/_utils/_reflection.py +0 -0
  43. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/_utils/_streams.py +0 -0
  44. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/_utils/_sync.py +0 -0
  45. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/_utils/_transform.py +0 -0
  46. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/_utils/_typing.py +0 -0
  47. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/_utils/_utils.py +0 -0
  48. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/lib/.keep +0 -0
  49. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/lib/Stopwatch.py +0 -0
  50. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/lib/helpers.py +0 -0
  51. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/py.typed +0 -0
  52. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/resources/__init__.py +0 -0
  53. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/resources/billing_models.py +0 -0
  54. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/resources/categories/__init__.py +0 -0
  55. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/resources/categories/categories.py +0 -0
  56. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/resources/categories/resources.py +0 -0
  57. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/resources/experiences/__init__.py +0 -0
  58. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/resources/experiences/experiences.py +0 -0
  59. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/resources/experiences/properties.py +0 -0
  60. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/resources/experiences/types/__init__.py +0 -0
  61. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/resources/experiences/types/limit_config.py +0 -0
  62. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/resources/experiences/types/types.py +0 -0
  63. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/resources/ingest.py +0 -0
  64. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/resources/limits/__init__.py +0 -0
  65. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/resources/limits/limits.py +0 -0
  66. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/resources/limits/tags.py +0 -0
  67. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/resources/price_modifiers.py +0 -0
  68. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/resources/requests/__init__.py +0 -0
  69. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/resources/requests/properties.py +0 -0
  70. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/resources/requests/requests.py +0 -0
  71. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/resources/requests/result.py +0 -0
  72. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/__init__.py +0 -0
  73. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/billing_model.py +0 -0
  74. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/billing_model_create_params.py +0 -0
  75. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/billing_model_list_response.py +0 -0
  76. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/billing_model_update_params.py +0 -0
  77. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/categories/__init__.py +0 -0
  78. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/categories/resource_create_params.py +0 -0
  79. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/categories/resource_list_response.py +0 -0
  80. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/category_delete_resource_response.py +0 -0
  81. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/category_delete_response.py +0 -0
  82. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/category_list_resources_response.py +0 -0
  83. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/category_list_response.py +0 -0
  84. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/category_resource_response.py +0 -0
  85. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/category_response.py +0 -0
  86. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/cost_data.py +0 -0
  87. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/cost_details.py +0 -0
  88. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/default_response.py +0 -0
  89. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/experience_instance_response.py +0 -0
  90. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/experiences/__init__.py +0 -0
  91. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/experiences/experience_type.py +0 -0
  92. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/experiences/properties_response.py +0 -0
  93. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/experiences/property_create_params.py +0 -0
  94. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/experiences/type_create_params.py +0 -0
  95. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/experiences/type_list_params.py +0 -0
  96. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/experiences/type_list_response.py +0 -0
  97. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/experiences/type_update_params.py +0 -0
  98. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/experiences/types/__init__.py +0 -0
  99. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/experiences/types/limit_config_create_params.py +0 -0
  100. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/ingest_response.py +0 -0
  101. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/ingest_units_params.py +0 -0
  102. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/limit_create_params.py +0 -0
  103. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/limit_history_response.py +0 -0
  104. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/limit_list_params.py +0 -0
  105. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/limit_reset_params.py +0 -0
  106. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/limit_response.py +0 -0
  107. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/limit_update_params.py +0 -0
  108. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/limits/__init__.py +0 -0
  109. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/limits/limit_tags.py +0 -0
  110. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/limits/tag_create_params.py +0 -0
  111. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/limits/tag_create_response.py +0 -0
  112. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/limits/tag_delete_response.py +0 -0
  113. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/limits/tag_list_response.py +0 -0
  114. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/limits/tag_remove_params.py +0 -0
  115. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/limits/tag_remove_response.py +0 -0
  116. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/limits/tag_update_params.py +0 -0
  117. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/limits/tag_update_response.py +0 -0
  118. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/paged_limit_list.py +0 -0
  119. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/pay_i_common_models_api_router_header_info_param.py +0 -0
  120. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/price_modifier.py +0 -0
  121. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/price_modifier_create_params.py +0 -0
  122. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/price_modifier_retrieve_response.py +0 -0
  123. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/price_modifier_update_params.py +0 -0
  124. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/requests/__init__.py +0 -0
  125. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/requests/property_create_params.py +0 -0
  126. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/requests/request_result.py +0 -0
  127. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/requests_data.py +0 -0
  128. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/shared/__init__.py +0 -0
  129. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/shared/evaluation_response.py +0 -0
  130. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/shared/pay_i_common_models_budget_management_cost_details_base.py +0 -0
  131. {payi-0.1.0a40 → payi-0.1.0a41}/src/payi/types/total_cost_data.py +0 -0
  132. {payi-0.1.0a40 → payi-0.1.0a41}/tests/__init__.py +0 -0
  133. {payi-0.1.0a40 → payi-0.1.0a41}/tests/api_resources/__init__.py +0 -0
  134. {payi-0.1.0a40 → payi-0.1.0a41}/tests/api_resources/categories/__init__.py +0 -0
  135. {payi-0.1.0a40 → payi-0.1.0a41}/tests/api_resources/categories/test_resources.py +0 -0
  136. {payi-0.1.0a40 → payi-0.1.0a41}/tests/api_resources/experiences/__init__.py +0 -0
  137. {payi-0.1.0a40 → payi-0.1.0a41}/tests/api_resources/experiences/test_properties.py +0 -0
  138. {payi-0.1.0a40 → payi-0.1.0a41}/tests/api_resources/experiences/test_types.py +0 -0
  139. {payi-0.1.0a40 → payi-0.1.0a41}/tests/api_resources/experiences/types/__init__.py +0 -0
  140. {payi-0.1.0a40 → payi-0.1.0a41}/tests/api_resources/experiences/types/test_limit_config.py +0 -0
  141. {payi-0.1.0a40 → payi-0.1.0a41}/tests/api_resources/limits/__init__.py +0 -0
  142. {payi-0.1.0a40 → payi-0.1.0a41}/tests/api_resources/limits/test_tags.py +0 -0
  143. {payi-0.1.0a40 → payi-0.1.0a41}/tests/api_resources/requests/__init__.py +0 -0
  144. {payi-0.1.0a40 → payi-0.1.0a41}/tests/api_resources/requests/test_properties.py +0 -0
  145. {payi-0.1.0a40 → payi-0.1.0a41}/tests/api_resources/requests/test_result.py +0 -0
  146. {payi-0.1.0a40 → payi-0.1.0a41}/tests/api_resources/test_billing_models.py +0 -0
  147. {payi-0.1.0a40 → payi-0.1.0a41}/tests/api_resources/test_categories.py +0 -0
  148. {payi-0.1.0a40 → payi-0.1.0a41}/tests/api_resources/test_experiences.py +0 -0
  149. {payi-0.1.0a40 → payi-0.1.0a41}/tests/api_resources/test_ingest.py +0 -0
  150. {payi-0.1.0a40 → payi-0.1.0a41}/tests/api_resources/test_limits.py +0 -0
  151. {payi-0.1.0a40 → payi-0.1.0a41}/tests/api_resources/test_price_modifiers.py +0 -0
  152. {payi-0.1.0a40 → payi-0.1.0a41}/tests/conftest.py +0 -0
  153. {payi-0.1.0a40 → payi-0.1.0a41}/tests/sample_file.txt +0 -0
  154. {payi-0.1.0a40 → payi-0.1.0a41}/tests/test_client.py +0 -0
  155. {payi-0.1.0a40 → payi-0.1.0a41}/tests/test_deepcopy.py +0 -0
  156. {payi-0.1.0a40 → payi-0.1.0a41}/tests/test_extract_files.py +0 -0
  157. {payi-0.1.0a40 → payi-0.1.0a41}/tests/test_files.py +0 -0
  158. {payi-0.1.0a40 → payi-0.1.0a41}/tests/test_models.py +0 -0
  159. {payi-0.1.0a40 → payi-0.1.0a41}/tests/test_qs.py +0 -0
  160. {payi-0.1.0a40 → payi-0.1.0a41}/tests/test_required_args.py +0 -0
  161. {payi-0.1.0a40 → payi-0.1.0a41}/tests/test_response.py +0 -0
  162. {payi-0.1.0a40 → payi-0.1.0a41}/tests/test_streaming.py +0 -0
  163. {payi-0.1.0a40 → payi-0.1.0a41}/tests/test_transform.py +0 -0
  164. {payi-0.1.0a40 → payi-0.1.0a41}/tests/test_utils/test_proxy.py +0 -0
  165. {payi-0.1.0a40 → payi-0.1.0a41}/tests/test_utils/test_typing.py +0 -0
  166. {payi-0.1.0a40 → payi-0.1.0a41}/tests/utils.py +0 -0
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.1.0-alpha.41"
3
+ }
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.0-alpha.41 (2025-02-04)
4
+
5
+ Full Changelog: [v0.1.0-alpha.40...v0.1.0-alpha.41](https://github.com/Pay-i/pay-i-python/compare/v0.1.0-alpha.40...v0.1.0-alpha.41)
6
+
7
+ ### Chores
8
+
9
+ * **internal:** bummp ruff dependency ([#204](https://github.com/Pay-i/pay-i-python/issues/204)) ([d6e457f](https://github.com/Pay-i/pay-i-python/commit/d6e457f7e62b5d08199e170abfda75fab75099f6))
10
+ * **internal:** change default timeout to an int ([#202](https://github.com/Pay-i/pay-i-python/issues/202)) ([c65e2c5](https://github.com/Pay-i/pay-i-python/commit/c65e2c5c8f420505025be81f7d566f048aa7bc19))
11
+
3
12
  ## 0.1.0-alpha.40 (2025-01-31)
4
13
 
5
14
  Full Changelog: [v0.1.0-alpha.39...v0.1.0-alpha.40](https://github.com/Pay-i/pay-i-python/compare/v0.1.0-alpha.39...v0.1.0-alpha.40)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: payi
3
- Version: 0.1.0a40
3
+ Version: 0.1.0a41
4
4
  Summary: The official Python library for the payi API
5
5
  Project-URL: Homepage, https://github.com/Pay-i/pay-i-python
6
6
  Project-URL: Repository, https://github.com/Pay-i/pay-i-python
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "payi"
3
- version = "0.1.0-alpha.40"
3
+ version = "0.1.0-alpha.41"
4
4
  description = "The official Python library for the payi API"
5
5
  dynamic = ["readme"]
6
6
  license = "Apache-2.0"
@@ -180,7 +180,7 @@ select = [
180
180
  "T201",
181
181
  "T203",
182
182
  # misuse of typing.TYPE_CHECKING
183
- "TCH004",
183
+ "TC004",
184
184
  # import rules
185
185
  "TID251",
186
186
  ]
@@ -86,7 +86,7 @@ requests==2.32.3
86
86
  # via tiktoken
87
87
  respx==0.22.0
88
88
  rich==13.7.1
89
- ruff==0.6.9
89
+ ruff==0.9.4
90
90
  setuptools==68.2.2
91
91
  # via nodeenv
92
92
  six==1.16.0
@@ -6,7 +6,7 @@ RAW_RESPONSE_HEADER = "X-Stainless-Raw-Response"
6
6
  OVERRIDE_CAST_TO_HEADER = "____stainless_override_cast_to"
7
7
 
8
8
  # default timeout is 1 minute
9
- DEFAULT_TIMEOUT = httpx.Timeout(timeout=60.0, connect=5.0)
9
+ DEFAULT_TIMEOUT = httpx.Timeout(timeout=60, connect=5.0)
10
10
  DEFAULT_MAX_RETRIES = 2
11
11
  DEFAULT_CONNECTION_LIMITS = httpx.Limits(max_connections=100, max_keepalive_connections=20)
12
12
 
@@ -172,7 +172,7 @@ class BaseModel(pydantic.BaseModel):
172
172
  @override
173
173
  def __str__(self) -> str:
174
174
  # mypy complains about an invalid self arg
175
- return f'{self.__repr_name__()}({self.__repr_str__(", ")})' # type: ignore[misc]
175
+ return f"{self.__repr_name__()}({self.__repr_str__(', ')})" # type: ignore[misc]
176
176
 
177
177
  # Override the 'construct' method in a way that supports recursive parsing without validation.
178
178
  # Based on https://github.com/samuelcolvin/pydantic/issues/1168#issuecomment-817742836.
@@ -1,4 +1,4 @@
1
1
  # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
2
 
3
3
  __title__ = "payi"
4
- __version__ = "0.1.0-alpha.40" # x-release-please-version
4
+ __version__ = "0.1.0-alpha.41" # x-release-please-version
@@ -7,7 +7,7 @@ from wrapt import wrap_function_wrapper # type: ignore
7
7
  from payi.types import IngestUnitsParams
8
8
  from payi.types.ingest_units_params import Units
9
9
 
10
- from .instrument import PayiInstrumentor
10
+ from .instrument import IsStreaming, PayiInstrumentor
11
11
 
12
12
 
13
13
  class AnthropicIntrumentor:
@@ -48,14 +48,15 @@ def chat_wrapper(
48
48
  kwargs: Any,
49
49
  ) -> Any:
50
50
  return instrumentor.chat_wrapper(
51
- "system.anthropic",
52
- process_chunk,
53
- process_request,
54
- process_synchronous_response,
55
- wrapped,
56
- instance,
57
- args,
58
- kwargs,
51
+ category="system.anthropic",
52
+ process_chunk=process_chunk,
53
+ process_request=process_request,
54
+ process_synchronous_response=process_synchronous_response,
55
+ is_streaming=IsStreaming.kwargs,
56
+ wrapped=wrapped,
57
+ instance=instance,
58
+ args=args,
59
+ kwargs=kwargs,
59
60
  )
60
61
 
61
62
 
@@ -81,10 +82,10 @@ def process_chunk(chunk: Any, ingest: IngestUnitsParams) -> None:
81
82
  ingest["units"]["text"]["output"] = usage.output_tokens
82
83
 
83
84
 
84
- def process_synchronous_response(response: Any, ingest: IngestUnitsParams, log_prompt_and_response: bool) -> None:
85
+ def process_synchronous_response(response: Any, ingest: IngestUnitsParams, log_prompt_and_response: bool, *args: Any, **kwargs: 'dict[str, Any]') -> Any: # noqa: ARG001
85
86
  usage = response.usage
86
87
  input = usage.input_tokens
87
- ouptut = usage.output_tokens
88
+ output = usage.output_tokens
88
89
  units: dict[str, Units] = ingest["units"]
89
90
 
90
91
  if hasattr(usage, "cache_creation_input_tokens") and usage.cache_creation_input_tokens > 0:
@@ -97,11 +98,13 @@ def process_synchronous_response(response: Any, ingest: IngestUnitsParams, log_p
97
98
 
98
99
  input = PayiInstrumentor.update_for_vision(input, units)
99
100
 
100
- units["text"] = Units(input=input, output=ouptut)
101
+ units["text"] = Units(input=input, output=output)
101
102
 
102
103
  if log_prompt_and_response:
103
104
  ingest["provider_response_json"] = response.to_json()
104
105
 
106
+ return None
107
+
105
108
  def has_image_and_get_texts(encoding: tiktoken.Encoding, content: Union[str, 'list[Any]']) -> 'tuple[bool, int]':
106
109
  if isinstance(content, str):
107
110
  return False, 0
@@ -0,0 +1,288 @@
1
+ import json
2
+ import logging
3
+ from typing import Any
4
+ from functools import wraps
5
+
6
+ from wrapt import ObjectProxy, wrap_function_wrapper # type: ignore
7
+
8
+ from payi.types.ingest_units_params import Units, IngestUnitsParams
9
+ from payi.types.pay_i_common_models_api_router_header_info_param import PayICommonModelsAPIRouterHeaderInfoParam
10
+
11
+ from .instrument import IsStreaming, PayiInstrumentor
12
+
13
+
14
+ class BedrockInstrumentor:
15
+ @staticmethod
16
+ def instrument(instrumentor: PayiInstrumentor) -> None:
17
+ try:
18
+ import boto3 # type: ignore # noqa: F401 I001
19
+
20
+ # wrap_function_wrapper(
21
+ # "anthropic.resources.completions",
22
+ # "Completions.create",
23
+ # chat_wrapper(instrumentor),
24
+ # )
25
+
26
+ wrap_function_wrapper(
27
+ "botocore.client",
28
+ "ClientCreator.create_client",
29
+ create_client_wrapper(instrumentor),
30
+ )
31
+
32
+ wrap_function_wrapper(
33
+ "botocore.session",
34
+ "Session.create_client",
35
+ create_client_wrapper(instrumentor),
36
+ )
37
+
38
+ except Exception as e:
39
+ logging.debug(f"Error instrumenting bedrock: {e}")
40
+ return
41
+
42
+ @PayiInstrumentor.payi_wrapper
43
+ def create_client_wrapper(instrumentor: PayiInstrumentor, wrapped: Any, instance: Any, args: Any, kwargs: Any) -> Any: # noqa: ARG001
44
+ if kwargs.get("service_name") != "bedrock-runtime":
45
+ return wrapped(*args, **kwargs)
46
+
47
+ try:
48
+ client: Any = wrapped(*args, **kwargs)
49
+ client.invoke_model = wrap_invoke(instrumentor, client.invoke_model)
50
+ client.invoke_model_with_response_stream = wrap_invoke_stream(instrumentor, client.invoke_model_with_response_stream)
51
+ client.converse = wrap_converse(instrumentor, client.converse)
52
+ client.converse_stream = wrap_converse_stream(instrumentor, client.converse_stream)
53
+
54
+ return client
55
+ except Exception as e:
56
+ logging.debug(f"Error instrumenting bedrock client: {e}")
57
+
58
+ return wrapped(*args, **kwargs)
59
+
60
+ class InvokeResponseWrapper(ObjectProxy): # type: ignore
61
+ def __init__(
62
+ self,
63
+ response: Any,
64
+ instrumentor: PayiInstrumentor,
65
+ ingest: IngestUnitsParams,
66
+ log_prompt_and_response: bool
67
+ ) -> None:
68
+
69
+ super().__init__(response) # type: ignore
70
+ self._response = response
71
+ self._instrumentor = instrumentor
72
+ self._ingest = ingest
73
+ self._log_prompt_and_response = log_prompt_and_response
74
+
75
+ def read(self, amt: Any =None): # type: ignore
76
+ # data is array of bytes
77
+ data: Any = self.__wrapped__.read(amt) # type: ignore
78
+ response = json.loads(data)
79
+
80
+ resource = self._ingest["resource"]
81
+ if not resource:
82
+ return
83
+
84
+ input: int = 0
85
+ output: int = 0
86
+ units: dict[str, Units] = self._ingest["units"]
87
+
88
+ if resource.startswith("meta.llama3"):
89
+ input = response['prompt_token_count']
90
+ output = response['generation_token_count']
91
+ elif resource.startswith("anthropic."):
92
+ usage = response['usage']
93
+ input = usage['input_tokens']
94
+ output = usage['output_tokens']
95
+ units["text"] = Units(input=input, output=output)
96
+
97
+ if self._log_prompt_and_response:
98
+ self._ingest["provider_response_json"] = data.decode('utf-8')
99
+
100
+ self._instrumentor._ingest_units(self._ingest)
101
+
102
+ return data
103
+
104
+ def wrap_invoke(instrumentor: PayiInstrumentor, wrapped: Any) -> Any:
105
+ @wraps(wrapped)
106
+ def invoke_wrapper(*args: Any, **kwargs: 'dict[str, Any]') -> Any:
107
+ modelId:str = kwargs.get("modelId", "") # type: ignore
108
+
109
+ if modelId.startswith("meta.llama3") or modelId.startswith("anthropic."):
110
+ return instrumentor.chat_wrapper(
111
+ category="system.aws.bedrock",
112
+ process_chunk=None,
113
+ process_request=process_invoke_request,
114
+ process_synchronous_response=process_synchronous_invoke_response,
115
+ is_streaming=IsStreaming.false,
116
+ wrapped=wrapped,
117
+ instance=None,
118
+ args=args,
119
+ kwargs=kwargs,
120
+ )
121
+ return wrapped(*args, **kwargs)
122
+
123
+ return invoke_wrapper
124
+
125
+ def wrap_invoke_stream(instrumentor: PayiInstrumentor, wrapped: Any) -> Any:
126
+ @wraps(wrapped)
127
+ def invoke_wrapper(*args: Any, **kwargs: Any) -> Any:
128
+ modelId:str = kwargs.get("modelId", "") # type: ignore
129
+
130
+ if modelId.startswith("meta.llama3") or modelId.startswith("anthropic."):
131
+ return instrumentor.chat_wrapper(
132
+ category="system.aws.bedrock",
133
+ process_chunk=process_invoke_streaming_anthropic_chunk if modelId.startswith("anthropic.") else process_invoke_streaming_llama_chunk,
134
+ process_request=process_invoke_request,
135
+ process_synchronous_response=None,
136
+ is_streaming=IsStreaming.true,
137
+ wrapped=wrapped,
138
+ instance=None,
139
+ args=args,
140
+ kwargs=kwargs,
141
+ )
142
+ return wrapped(*args, **kwargs)
143
+
144
+ return invoke_wrapper
145
+
146
+ def wrap_converse(instrumentor: PayiInstrumentor, wrapped: Any) -> Any:
147
+ @wraps(wrapped)
148
+ def invoke_wrapper(*args: Any, **kwargs: 'dict[str, Any]') -> Any:
149
+ modelId:str = kwargs.get("modelId", "") # type: ignore
150
+
151
+ if modelId.startswith("meta.llama3") or modelId.startswith("anthropic."):
152
+ return instrumentor.chat_wrapper(
153
+ category="system.aws.bedrock",
154
+ process_chunk=None,
155
+ process_request=process_converse_request,
156
+ process_synchronous_response=process_synchronous_converse_response,
157
+ is_streaming=IsStreaming.false,
158
+ wrapped=wrapped,
159
+ instance=None,
160
+ args=args,
161
+ kwargs=kwargs,
162
+ )
163
+ return wrapped(*args, **kwargs)
164
+
165
+ return invoke_wrapper
166
+
167
+ def wrap_converse_stream(instrumentor: PayiInstrumentor, wrapped: Any) -> Any:
168
+ @wraps(wrapped)
169
+ def invoke_wrapper(*args: Any, **kwargs: Any) -> Any:
170
+ modelId:str = kwargs.get("modelId", "") # type: ignore
171
+
172
+ if modelId.startswith("meta.llama3") or modelId.startswith("anthropic."):
173
+ return instrumentor.chat_wrapper(
174
+ category="system.aws.bedrock",
175
+ process_chunk=process_converse_streaming_chunk,
176
+ process_request=process_converse_request,
177
+ process_synchronous_response=None,
178
+ is_streaming=IsStreaming.true,
179
+ wrapped=wrapped,
180
+ instance=None,
181
+ args=args,
182
+ kwargs=kwargs,
183
+ )
184
+ return wrapped(*args, **kwargs)
185
+
186
+ return invoke_wrapper
187
+
188
+ def process_invoke_streaming_anthropic_chunk(chunk: str, ingest: IngestUnitsParams) -> None:
189
+ chunk_dict = json.loads(chunk)
190
+ type = chunk_dict.get("type", "")
191
+
192
+ if type == "message_start":
193
+ usage = chunk_dict['message']['usage']
194
+ units = ingest["units"]
195
+
196
+ input = PayiInstrumentor.update_for_vision(usage['input_tokens'], units)
197
+
198
+ units["text"] = Units(input=input, output=0)
199
+
200
+ text_cache_write: int = usage.get("cache_creation_input_tokens", 0)
201
+ if text_cache_write > 0:
202
+ units["text_cache_write"] = Units(input=text_cache_write, output=0)
203
+
204
+ text_cache_read: int = usage.get("cache_read_input_tokens", 0)
205
+ if text_cache_read > 0:
206
+ units["text_cache_read"] = Units(input=text_cache_read, output=0)
207
+
208
+ elif type == "message_delta":
209
+ usage = chunk_dict['usage']
210
+ ingest["units"]["text"]["output"] = usage['output_tokens']
211
+
212
+ def process_invoke_streaming_llama_chunk(chunk: str, ingest: IngestUnitsParams) -> None:
213
+ chunk_dict = json.loads(chunk)
214
+ metrics = chunk_dict.get("amazon-bedrock-invocationMetrics", {})
215
+ if metrics:
216
+ input = metrics.get("inputTokenCount", 0)
217
+ output = metrics.get("outputTokenCount", 0)
218
+ ingest["units"]["text"] = Units(input=input, output=output)
219
+
220
+ def process_synchronous_invoke_response(
221
+ response: Any,
222
+ ingest: IngestUnitsParams,
223
+ log_prompt_and_response: bool,
224
+ instrumentor: PayiInstrumentor,
225
+ **kargs: Any) -> Any: # noqa: ARG001
226
+
227
+ metadata = response.get("ResponseMetadata", {})
228
+
229
+ # request_id = metadata.get("RequestId", "")
230
+ # if request_id:
231
+ # ingest["provider_request_id"] = request_id
232
+
233
+ response_headers = metadata.get("HTTPHeaders", {}).copy()
234
+ if response_headers:
235
+ ingest["provider_response_headers"] = [PayICommonModelsAPIRouterHeaderInfoParam(name=k, value=v) for k, v in response_headers.items()]
236
+
237
+ response["body"] = InvokeResponseWrapper(
238
+ response=response["body"],
239
+ instrumentor=instrumentor,
240
+ ingest=ingest,
241
+ log_prompt_and_response=log_prompt_and_response)
242
+
243
+ return response
244
+
245
+ def process_invoke_request(ingest: IngestUnitsParams, kwargs: Any) -> None: # noqa: ARG001
246
+ return
247
+
248
+ def process_converse_streaming_chunk(chunk: 'dict[str, Any]', ingest: IngestUnitsParams) -> None:
249
+ metadata = chunk.get("metadata", {})
250
+
251
+ if metadata:
252
+ usage = metadata['usage']
253
+ input = usage["inputTokens"]
254
+ output = usage["outputTokens"]
255
+ ingest["units"]["text"] = Units(input=input, output=output)
256
+
257
+ def process_synchronous_converse_response(
258
+ response: 'dict[str, Any]',
259
+ ingest: IngestUnitsParams,
260
+ log_prompt_and_response: bool,
261
+ **kargs: Any) -> Any: # noqa: ARG001
262
+
263
+ usage = response["usage"]
264
+ input = usage["inputTokens"]
265
+ output = usage["outputTokens"]
266
+
267
+ units: dict[str, Units] = ingest["units"]
268
+ units["text"] = Units(input=input, output=output)
269
+
270
+ metadata = response.get("ResponseMetadata", {})
271
+
272
+ # request_id = metadata.get("RequestId", "")
273
+ # if request_id:
274
+ # ingest["provider_request_id"] = request_id
275
+
276
+ response_headers = metadata.get("HTTPHeaders", {})
277
+ if response_headers:
278
+ ingest["provider_response_headers"] = [PayICommonModelsAPIRouterHeaderInfoParam(name=k, value=v) for k, v in response_headers.items()]
279
+
280
+ if log_prompt_and_response:
281
+ response_without_metadata = response.copy()
282
+ response_without_metadata.pop("ResponseMetadata", None)
283
+ ingest["provider_response_json"] = json.dumps(response_without_metadata)
284
+
285
+ return None
286
+
287
+ def process_converse_request(ingest: IngestUnitsParams, kwargs: Any) -> None: # noqa: ARG001
288
+ return
@@ -5,3 +5,4 @@ class Instruments(Enum):
5
5
  ALL = "all"
6
6
  OPENAI = "openai"
7
7
  ANTHROPIC = "anthropic"
8
+ AWS_BEDROCK = "aws.bedrock"
@@ -9,7 +9,7 @@ from wrapt import wrap_function_wrapper # type: ignore
9
9
  from payi.types import IngestUnitsParams
10
10
  from payi.types.ingest_units_params import Units
11
11
 
12
- from .instrument import PayiInstrumentor
12
+ from .instrument import IsStreaming, PayiInstrumentor
13
13
 
14
14
 
15
15
  class OpenAiInstrumentor:
@@ -37,18 +37,19 @@ def chat_wrapper(
37
37
  kwargs: Any,
38
38
  ) -> Any:
39
39
  return instrumentor.chat_wrapper(
40
- "system.openai",
41
- process_chat_chunk,
42
- process_request,
43
- process_chat_synchronous_response,
44
- wrapped,
45
- instance,
46
- args,
47
- kwargs,
40
+ category="system.openai",
41
+ process_chunk=process_chat_chunk,
42
+ process_request=process_request,
43
+ process_synchronous_response=process_chat_synchronous_response,
44
+ is_streaming=IsStreaming.kwargs,
45
+ wrapped=wrapped,
46
+ instance=instance,
47
+ args=args,
48
+ kwargs=kwargs,
48
49
  )
49
50
 
50
51
 
51
- def process_chat_synchronous_response(response: str, ingest: IngestUnitsParams, log_prompt_and_response: bool) -> None:
52
+ def process_chat_synchronous_response(response: str, ingest: IngestUnitsParams, log_prompt_and_response: bool, **kwargs: Any) -> Any: # noqa: ARG001
52
53
  response_dict = model_to_dict(response)
53
54
 
54
55
  add_usage_units(response_dict["usage"], ingest["units"])
@@ -56,6 +57,7 @@ def process_chat_synchronous_response(response: str, ingest: IngestUnitsParams,
56
57
  if log_prompt_and_response:
57
58
  ingest["provider_response_json"] = [json.dumps(response_dict)]
58
59
 
60
+ return None
59
61
 
60
62
  def process_chat_chunk(chunk: Any, ingest: IngestUnitsParams) -> None:
61
63
  model = model_to_dict(chunk)