payi 0.1.0a39__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.0a39 → payi-0.1.0a41}/CHANGELOG.md +17 -0
  3. {payi-0.1.0a39 → payi-0.1.0a41}/PKG-INFO +2 -1
  4. {payi-0.1.0a39 → payi-0.1.0a41}/pyproject.toml +3 -2
  5. {payi-0.1.0a39 → payi-0.1.0a41}/requirements-dev.lock +13 -2
  6. {payi-0.1.0a39 → payi-0.1.0a41}/requirements.lock +12 -1
  7. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/_constants.py +1 -1
  8. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/_models.py +1 -1
  9. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/_version.py +1 -1
  10. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/lib/AnthropicInstrumentor.py +54 -13
  11. payi-0.1.0a41/src/payi/lib/BedrockInstrumentor.py +288 -0
  12. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/lib/Instruments.py +1 -0
  13. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/lib/OpenAIInstrumentor.py +50 -11
  14. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/lib/instrument.py +126 -18
  15. payi-0.1.0a39/.release-please-manifest.json +0 -3
  16. {payi-0.1.0a39 → payi-0.1.0a41}/.gitignore +0 -0
  17. {payi-0.1.0a39 → payi-0.1.0a41}/CONTRIBUTING.md +0 -0
  18. {payi-0.1.0a39 → payi-0.1.0a41}/LICENSE +0 -0
  19. {payi-0.1.0a39 → payi-0.1.0a41}/README.md +0 -0
  20. {payi-0.1.0a39 → payi-0.1.0a41}/SECURITY.md +0 -0
  21. {payi-0.1.0a39 → payi-0.1.0a41}/api.md +0 -0
  22. {payi-0.1.0a39 → payi-0.1.0a41}/bin/check-release-environment +0 -0
  23. {payi-0.1.0a39 → payi-0.1.0a41}/bin/publish-pypi +0 -0
  24. {payi-0.1.0a39 → payi-0.1.0a41}/examples/.keep +0 -0
  25. {payi-0.1.0a39 → payi-0.1.0a41}/mypy.ini +0 -0
  26. {payi-0.1.0a39 → payi-0.1.0a41}/noxfile.py +0 -0
  27. {payi-0.1.0a39 → payi-0.1.0a41}/release-please-config.json +0 -0
  28. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/__init__.py +0 -0
  29. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/_base_client.py +0 -0
  30. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/_client.py +0 -0
  31. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/_compat.py +0 -0
  32. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/_exceptions.py +0 -0
  33. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/_files.py +0 -0
  34. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/_qs.py +0 -0
  35. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/_resource.py +0 -0
  36. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/_response.py +0 -0
  37. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/_streaming.py +0 -0
  38. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/_types.py +0 -0
  39. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/_utils/__init__.py +0 -0
  40. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/_utils/_logs.py +0 -0
  41. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/_utils/_proxy.py +0 -0
  42. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/_utils/_reflection.py +0 -0
  43. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/_utils/_streams.py +0 -0
  44. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/_utils/_sync.py +0 -0
  45. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/_utils/_transform.py +0 -0
  46. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/_utils/_typing.py +0 -0
  47. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/_utils/_utils.py +0 -0
  48. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/lib/.keep +0 -0
  49. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/lib/Stopwatch.py +0 -0
  50. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/lib/helpers.py +0 -0
  51. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/py.typed +0 -0
  52. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/resources/__init__.py +0 -0
  53. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/resources/billing_models.py +0 -0
  54. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/resources/categories/__init__.py +0 -0
  55. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/resources/categories/categories.py +0 -0
  56. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/resources/categories/resources.py +0 -0
  57. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/resources/experiences/__init__.py +0 -0
  58. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/resources/experiences/experiences.py +0 -0
  59. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/resources/experiences/properties.py +0 -0
  60. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/resources/experiences/types/__init__.py +0 -0
  61. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/resources/experiences/types/limit_config.py +0 -0
  62. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/resources/experiences/types/types.py +0 -0
  63. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/resources/ingest.py +0 -0
  64. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/resources/limits/__init__.py +0 -0
  65. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/resources/limits/limits.py +0 -0
  66. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/resources/limits/tags.py +0 -0
  67. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/resources/price_modifiers.py +0 -0
  68. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/resources/requests/__init__.py +0 -0
  69. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/resources/requests/properties.py +0 -0
  70. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/resources/requests/requests.py +0 -0
  71. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/resources/requests/result.py +0 -0
  72. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/__init__.py +0 -0
  73. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/billing_model.py +0 -0
  74. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/billing_model_create_params.py +0 -0
  75. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/billing_model_list_response.py +0 -0
  76. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/billing_model_update_params.py +0 -0
  77. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/categories/__init__.py +0 -0
  78. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/categories/resource_create_params.py +0 -0
  79. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/categories/resource_list_response.py +0 -0
  80. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/category_delete_resource_response.py +0 -0
  81. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/category_delete_response.py +0 -0
  82. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/category_list_resources_response.py +0 -0
  83. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/category_list_response.py +0 -0
  84. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/category_resource_response.py +0 -0
  85. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/category_response.py +0 -0
  86. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/cost_data.py +0 -0
  87. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/cost_details.py +0 -0
  88. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/default_response.py +0 -0
  89. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/experience_instance_response.py +0 -0
  90. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/experiences/__init__.py +0 -0
  91. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/experiences/experience_type.py +0 -0
  92. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/experiences/properties_response.py +0 -0
  93. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/experiences/property_create_params.py +0 -0
  94. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/experiences/type_create_params.py +0 -0
  95. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/experiences/type_list_params.py +0 -0
  96. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/experiences/type_list_response.py +0 -0
  97. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/experiences/type_update_params.py +0 -0
  98. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/experiences/types/__init__.py +0 -0
  99. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/experiences/types/limit_config_create_params.py +0 -0
  100. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/ingest_response.py +0 -0
  101. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/ingest_units_params.py +0 -0
  102. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/limit_create_params.py +0 -0
  103. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/limit_history_response.py +0 -0
  104. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/limit_list_params.py +0 -0
  105. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/limit_reset_params.py +0 -0
  106. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/limit_response.py +0 -0
  107. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/limit_update_params.py +0 -0
  108. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/limits/__init__.py +0 -0
  109. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/limits/limit_tags.py +0 -0
  110. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/limits/tag_create_params.py +0 -0
  111. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/limits/tag_create_response.py +0 -0
  112. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/limits/tag_delete_response.py +0 -0
  113. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/limits/tag_list_response.py +0 -0
  114. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/limits/tag_remove_params.py +0 -0
  115. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/limits/tag_remove_response.py +0 -0
  116. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/limits/tag_update_params.py +0 -0
  117. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/limits/tag_update_response.py +0 -0
  118. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/paged_limit_list.py +0 -0
  119. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/pay_i_common_models_api_router_header_info_param.py +0 -0
  120. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/price_modifier.py +0 -0
  121. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/price_modifier_create_params.py +0 -0
  122. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/price_modifier_retrieve_response.py +0 -0
  123. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/price_modifier_update_params.py +0 -0
  124. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/requests/__init__.py +0 -0
  125. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/requests/property_create_params.py +0 -0
  126. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/requests/request_result.py +0 -0
  127. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/requests_data.py +0 -0
  128. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/shared/__init__.py +0 -0
  129. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/shared/evaluation_response.py +0 -0
  130. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/shared/pay_i_common_models_budget_management_cost_details_base.py +0 -0
  131. {payi-0.1.0a39 → payi-0.1.0a41}/src/payi/types/total_cost_data.py +0 -0
  132. {payi-0.1.0a39 → payi-0.1.0a41}/tests/__init__.py +0 -0
  133. {payi-0.1.0a39 → payi-0.1.0a41}/tests/api_resources/__init__.py +0 -0
  134. {payi-0.1.0a39 → payi-0.1.0a41}/tests/api_resources/categories/__init__.py +0 -0
  135. {payi-0.1.0a39 → payi-0.1.0a41}/tests/api_resources/categories/test_resources.py +0 -0
  136. {payi-0.1.0a39 → payi-0.1.0a41}/tests/api_resources/experiences/__init__.py +0 -0
  137. {payi-0.1.0a39 → payi-0.1.0a41}/tests/api_resources/experiences/test_properties.py +0 -0
  138. {payi-0.1.0a39 → payi-0.1.0a41}/tests/api_resources/experiences/test_types.py +0 -0
  139. {payi-0.1.0a39 → payi-0.1.0a41}/tests/api_resources/experiences/types/__init__.py +0 -0
  140. {payi-0.1.0a39 → payi-0.1.0a41}/tests/api_resources/experiences/types/test_limit_config.py +0 -0
  141. {payi-0.1.0a39 → payi-0.1.0a41}/tests/api_resources/limits/__init__.py +0 -0
  142. {payi-0.1.0a39 → payi-0.1.0a41}/tests/api_resources/limits/test_tags.py +0 -0
  143. {payi-0.1.0a39 → payi-0.1.0a41}/tests/api_resources/requests/__init__.py +0 -0
  144. {payi-0.1.0a39 → payi-0.1.0a41}/tests/api_resources/requests/test_properties.py +0 -0
  145. {payi-0.1.0a39 → payi-0.1.0a41}/tests/api_resources/requests/test_result.py +0 -0
  146. {payi-0.1.0a39 → payi-0.1.0a41}/tests/api_resources/test_billing_models.py +0 -0
  147. {payi-0.1.0a39 → payi-0.1.0a41}/tests/api_resources/test_categories.py +0 -0
  148. {payi-0.1.0a39 → payi-0.1.0a41}/tests/api_resources/test_experiences.py +0 -0
  149. {payi-0.1.0a39 → payi-0.1.0a41}/tests/api_resources/test_ingest.py +0 -0
  150. {payi-0.1.0a39 → payi-0.1.0a41}/tests/api_resources/test_limits.py +0 -0
  151. {payi-0.1.0a39 → payi-0.1.0a41}/tests/api_resources/test_price_modifiers.py +0 -0
  152. {payi-0.1.0a39 → payi-0.1.0a41}/tests/conftest.py +0 -0
  153. {payi-0.1.0a39 → payi-0.1.0a41}/tests/sample_file.txt +0 -0
  154. {payi-0.1.0a39 → payi-0.1.0a41}/tests/test_client.py +0 -0
  155. {payi-0.1.0a39 → payi-0.1.0a41}/tests/test_deepcopy.py +0 -0
  156. {payi-0.1.0a39 → payi-0.1.0a41}/tests/test_extract_files.py +0 -0
  157. {payi-0.1.0a39 → payi-0.1.0a41}/tests/test_files.py +0 -0
  158. {payi-0.1.0a39 → payi-0.1.0a41}/tests/test_models.py +0 -0
  159. {payi-0.1.0a39 → payi-0.1.0a41}/tests/test_qs.py +0 -0
  160. {payi-0.1.0a39 → payi-0.1.0a41}/tests/test_required_args.py +0 -0
  161. {payi-0.1.0a39 → payi-0.1.0a41}/tests/test_response.py +0 -0
  162. {payi-0.1.0a39 → payi-0.1.0a41}/tests/test_streaming.py +0 -0
  163. {payi-0.1.0a39 → payi-0.1.0a41}/tests/test_transform.py +0 -0
  164. {payi-0.1.0a39 → payi-0.1.0a41}/tests/test_utils/test_proxy.py +0 -0
  165. {payi-0.1.0a39 → payi-0.1.0a41}/tests/test_utils/test_typing.py +0 -0
  166. {payi-0.1.0a39 → payi-0.1.0a41}/tests/utils.py +0 -0
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.1.0-alpha.41"
3
+ }
@@ -1,5 +1,22 @@
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
+
12
+ ## 0.1.0-alpha.40 (2025-01-31)
13
+
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)
15
+
16
+ ### Features
17
+
18
+ * update units calculation ([a8dda4a](https://github.com/Pay-i/pay-i-python/commit/a8dda4a72b4fa6720e7e3b621f503e435630481f))
19
+
3
20
  ## 0.1.0-alpha.39 (2025-01-31)
4
21
 
5
22
  Full Changelog: [v0.1.0-alpha.38...v0.1.0-alpha.39](https://github.com/Pay-i/pay-i-python/compare/v0.1.0-alpha.38...v0.1.0-alpha.39)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: payi
3
- Version: 0.1.0a39
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
@@ -27,6 +27,7 @@ Requires-Dist: distro<2,>=1.7.0
27
27
  Requires-Dist: httpx<1,>=0.23.0
28
28
  Requires-Dist: pydantic<3,>=1.9.0
29
29
  Requires-Dist: sniffio
30
+ Requires-Dist: tiktoken>=0.8.0
30
31
  Requires-Dist: typing-extensions<5,>=4.10
31
32
  Requires-Dist: wrapt>=1.17.2
32
33
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "payi"
3
- version = "0.1.0-alpha.39"
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"
@@ -15,6 +15,7 @@ dependencies = [
15
15
  "distro>=1.7.0, <2",
16
16
  "sniffio",
17
17
  "wrapt>=1.17.2",
18
+ "tiktoken>=0.8.0",
18
19
  ]
19
20
  requires-python = ">= 3.8"
20
21
  classifiers = [
@@ -179,7 +180,7 @@ select = [
179
180
  "T201",
180
181
  "T203",
181
182
  # misuse of typing.TYPE_CHECKING
182
- "TCH004",
183
+ "TC004",
183
184
  # import rules
184
185
  "TID251",
185
186
  ]
@@ -7,7 +7,6 @@
7
7
  # all-features: true
8
8
  # with-sources: false
9
9
  # generate-hashes: false
10
- # universal: false
11
10
 
12
11
  -e file:.
13
12
  annotated-types==0.6.0
@@ -20,6 +19,9 @@ argcomplete==3.1.2
20
19
  certifi==2023.7.22
21
20
  # via httpcore
22
21
  # via httpx
22
+ # via requests
23
+ charset-normalizer==3.4.1
24
+ # via requests
23
25
  colorlog==6.7.0
24
26
  # via nox
25
27
  dirty-equals==0.6.0
@@ -42,6 +44,7 @@ httpx==0.28.1
42
44
  idna==3.4
43
45
  # via anyio
44
46
  # via httpx
47
+ # via requests
45
48
  importlib-metadata==7.0.0
46
49
  iniconfig==2.0.0
47
50
  # via pytest
@@ -77,9 +80,13 @@ python-dateutil==2.8.2
77
80
  # via time-machine
78
81
  pytz==2023.3.post1
79
82
  # via dirty-equals
83
+ regex==2024.11.6
84
+ # via tiktoken
85
+ requests==2.32.3
86
+ # via tiktoken
80
87
  respx==0.22.0
81
88
  rich==13.7.1
82
- ruff==0.6.9
89
+ ruff==0.9.4
83
90
  setuptools==68.2.2
84
91
  # via nodeenv
85
92
  six==1.16.0
@@ -87,6 +94,8 @@ six==1.16.0
87
94
  sniffio==1.3.0
88
95
  # via anyio
89
96
  # via payi
97
+ tiktoken==0.8.0
98
+ # via payi
90
99
  time-machine==2.9.0
91
100
  tomli==2.0.2
92
101
  # via mypy
@@ -98,6 +107,8 @@ typing-extensions==4.12.2
98
107
  # via pydantic
99
108
  # via pydantic-core
100
109
  # via pyright
110
+ urllib3==2.3.0
111
+ # via requests
101
112
  virtualenv==20.24.5
102
113
  # via nox
103
114
  wrapt==1.17.2
@@ -7,7 +7,6 @@
7
7
  # all-features: true
8
8
  # with-sources: false
9
9
  # generate-hashes: false
10
- # universal: false
11
10
 
12
11
  -e file:.
13
12
  annotated-types==0.6.0
@@ -18,6 +17,9 @@ anyio==4.4.0
18
17
  certifi==2023.7.22
19
18
  # via httpcore
20
19
  # via httpx
20
+ # via requests
21
+ charset-normalizer==3.4.1
22
+ # via requests
21
23
  distro==1.8.0
22
24
  # via payi
23
25
  exceptiongroup==1.2.2
@@ -31,17 +33,26 @@ httpx==0.28.1
31
33
  idna==3.4
32
34
  # via anyio
33
35
  # via httpx
36
+ # via requests
34
37
  pydantic==2.10.3
35
38
  # via payi
36
39
  pydantic-core==2.27.1
37
40
  # via pydantic
41
+ regex==2024.11.6
42
+ # via tiktoken
43
+ requests==2.32.3
44
+ # via tiktoken
38
45
  sniffio==1.3.0
39
46
  # via anyio
40
47
  # via payi
48
+ tiktoken==0.8.0
49
+ # via payi
41
50
  typing-extensions==4.12.2
42
51
  # via anyio
43
52
  # via payi
44
53
  # via pydantic
45
54
  # via pydantic-core
55
+ urllib3==2.3.0
56
+ # via requests
46
57
  wrapt==1.17.2
47
58
  # via payi
@@ -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.39" # x-release-please-version
4
+ __version__ = "0.1.0-alpha.41" # x-release-please-version
@@ -1,12 +1,13 @@
1
1
  import logging
2
- from typing import Any
2
+ from typing import Any, Union
3
3
 
4
+ import tiktoken
4
5
  from wrapt import wrap_function_wrapper # type: ignore
5
6
 
6
7
  from payi.types import IngestUnitsParams
7
8
  from payi.types.ingest_units_params import Units
8
9
 
9
- from .instrument import PayiInstrumentor
10
+ from .instrument import IsStreaming, PayiInstrumentor
10
11
 
11
12
 
12
13
  class AnthropicIntrumentor:
@@ -47,13 +48,15 @@ def chat_wrapper(
47
48
  kwargs: Any,
48
49
  ) -> Any:
49
50
  return instrumentor.chat_wrapper(
50
- "system.anthropic",
51
- process_chunk,
52
- process_synchronous_response,
53
- wrapped,
54
- instance,
55
- args,
56
- 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,
57
60
  )
58
61
 
59
62
 
@@ -62,7 +65,9 @@ def process_chunk(chunk: Any, ingest: IngestUnitsParams) -> None:
62
65
  usage = chunk.message.usage
63
66
  units = ingest["units"]
64
67
 
65
- units["text"] = Units(input=usage.input_tokens, output=0)
68
+ input = PayiInstrumentor.update_for_vision(usage.input_tokens, units)
69
+
70
+ units["text"] = Units(input=input, output=0)
66
71
 
67
72
  if hasattr(usage, "cache_creation_input_tokens") and usage.cache_creation_input_tokens > 0:
68
73
  text_cache_write = usage.cache_creation_input_tokens
@@ -77,10 +82,10 @@ def process_chunk(chunk: Any, ingest: IngestUnitsParams) -> None:
77
82
  ingest["units"]["text"]["output"] = usage.output_tokens
78
83
 
79
84
 
80
- 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
81
86
  usage = response.usage
82
87
  input = usage.input_tokens
83
- ouptut = usage.output_tokens
88
+ output = usage.output_tokens
84
89
  units: dict[str, Units] = ingest["units"]
85
90
 
86
91
  if hasattr(usage, "cache_creation_input_tokens") and usage.cache_creation_input_tokens > 0:
@@ -91,7 +96,43 @@ def process_synchronous_response(response: Any, ingest: IngestUnitsParams, log_p
91
96
  text_cache_read = usage.cache_read_input_tokens
92
97
  units["text_cache_read"] = Units(input=text_cache_read, output=0)
93
98
 
94
- units["text"] = Units(input=input, output=ouptut)
99
+ input = PayiInstrumentor.update_for_vision(input, units)
100
+
101
+ units["text"] = Units(input=input, output=output)
95
102
 
96
103
  if log_prompt_and_response:
97
104
  ingest["provider_response_json"] = response.to_json()
105
+
106
+ return None
107
+
108
+ def has_image_and_get_texts(encoding: tiktoken.Encoding, content: Union[str, 'list[Any]']) -> 'tuple[bool, int]':
109
+ if isinstance(content, str):
110
+ return False, 0
111
+ elif isinstance(content, list): # type: ignore
112
+ has_image = any(item.get("type") == "image" for item in content)
113
+ if has_image is False:
114
+ return has_image, 0
115
+
116
+ token_count = sum(len(encoding.encode(item.get("text", ""))) for item in content if item.get("type") == "text")
117
+ return has_image, token_count
118
+
119
+ def process_request(ingest: IngestUnitsParams, kwargs: Any) -> None:
120
+ messages = kwargs.get("messages")
121
+ if not messages or len(messages) == 0:
122
+ return
123
+
124
+ estimated_token_count = 0
125
+ has_image = False
126
+
127
+ enc = tiktoken.get_encoding("cl100k_base")
128
+
129
+ for message in messages:
130
+ msg_has_image, msg_prompt_tokens = has_image_and_get_texts(enc, message.get('content', ''))
131
+ if msg_has_image:
132
+ has_image = True
133
+ estimated_token_count += msg_prompt_tokens
134
+
135
+ if not has_image or estimated_token_count == 0:
136
+ return
137
+
138
+ ingest["units"][PayiInstrumentor.estimated_prompt_tokens] = Units(input=estimated_token_count, output=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"