payi 0.1.0a80__tar.gz → 0.1.0a82__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 (205) hide show
  1. payi-0.1.0a82/.release-please-manifest.json +3 -0
  2. {payi-0.1.0a80 → payi-0.1.0a82}/CHANGELOG.md +16 -0
  3. {payi-0.1.0a80 → payi-0.1.0a82}/PKG-INFO +1 -1
  4. {payi-0.1.0a80 → payi-0.1.0a82}/pyproject.toml +1 -1
  5. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/_version.py +1 -1
  6. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/lib/AnthropicInstrumentor.py +7 -4
  7. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/lib/BedrockInstrumentor.py +16 -4
  8. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/lib/GoogleGenAiInstrumentor.py +27 -8
  9. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/lib/OpenAIInstrumentor.py +12 -7
  10. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/lib/VertexInstrumentor.py +25 -7
  11. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/lib/instrument.py +130 -22
  12. payi-0.1.0a80/.release-please-manifest.json +0 -3
  13. {payi-0.1.0a80 → payi-0.1.0a82}/.gitignore +0 -0
  14. {payi-0.1.0a80 → payi-0.1.0a82}/CONTRIBUTING.md +0 -0
  15. {payi-0.1.0a80 → payi-0.1.0a82}/LICENSE +0 -0
  16. {payi-0.1.0a80 → payi-0.1.0a82}/README.md +0 -0
  17. {payi-0.1.0a80 → payi-0.1.0a82}/SECURITY.md +0 -0
  18. {payi-0.1.0a80 → payi-0.1.0a82}/api.md +0 -0
  19. {payi-0.1.0a80 → payi-0.1.0a82}/bin/check-release-environment +0 -0
  20. {payi-0.1.0a80 → payi-0.1.0a82}/bin/publish-pypi +0 -0
  21. {payi-0.1.0a80 → payi-0.1.0a82}/examples/.keep +0 -0
  22. {payi-0.1.0a80 → payi-0.1.0a82}/mypy.ini +0 -0
  23. {payi-0.1.0a80 → payi-0.1.0a82}/noxfile.py +0 -0
  24. {payi-0.1.0a80 → payi-0.1.0a82}/release-please-config.json +0 -0
  25. {payi-0.1.0a80 → payi-0.1.0a82}/requirements-dev.lock +0 -0
  26. {payi-0.1.0a80 → payi-0.1.0a82}/requirements.lock +0 -0
  27. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/__init__.py +0 -0
  28. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/_base_client.py +0 -0
  29. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/_client.py +0 -0
  30. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/_compat.py +0 -0
  31. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/_constants.py +0 -0
  32. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/_exceptions.py +0 -0
  33. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/_files.py +0 -0
  34. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/_models.py +0 -0
  35. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/_qs.py +0 -0
  36. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/_resource.py +0 -0
  37. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/_response.py +0 -0
  38. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/_streaming.py +0 -0
  39. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/_types.py +0 -0
  40. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/_utils/__init__.py +0 -0
  41. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/_utils/_logs.py +0 -0
  42. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/_utils/_proxy.py +0 -0
  43. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/_utils/_reflection.py +0 -0
  44. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/_utils/_resources_proxy.py +0 -0
  45. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/_utils/_streams.py +0 -0
  46. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/_utils/_sync.py +0 -0
  47. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/_utils/_transform.py +0 -0
  48. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/_utils/_typing.py +0 -0
  49. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/_utils/_utils.py +0 -0
  50. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/lib/.keep +0 -0
  51. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/lib/Stopwatch.py +0 -0
  52. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/lib/helpers.py +0 -0
  53. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/pagination.py +0 -0
  54. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/py.typed +0 -0
  55. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/resources/__init__.py +0 -0
  56. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/resources/categories/__init__.py +0 -0
  57. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/resources/categories/categories.py +0 -0
  58. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/resources/categories/resources.py +0 -0
  59. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/resources/experiences/__init__.py +0 -0
  60. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/resources/experiences/experiences.py +0 -0
  61. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/resources/experiences/properties.py +0 -0
  62. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/resources/experiences/types/__init__.py +0 -0
  63. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/resources/experiences/types/limit_config.py +0 -0
  64. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/resources/experiences/types/types.py +0 -0
  65. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/resources/ingest.py +0 -0
  66. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/resources/limits/__init__.py +0 -0
  67. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/resources/limits/limits.py +0 -0
  68. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/resources/limits/tags.py +0 -0
  69. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/resources/requests/__init__.py +0 -0
  70. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/resources/requests/properties.py +0 -0
  71. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/resources/requests/requests.py +0 -0
  72. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/resources/requests/result.py +0 -0
  73. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/resources/use_cases/__init__.py +0 -0
  74. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/resources/use_cases/definitions/__init__.py +0 -0
  75. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/resources/use_cases/definitions/definitions.py +0 -0
  76. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/resources/use_cases/definitions/kpis.py +0 -0
  77. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/resources/use_cases/definitions/limit_config.py +0 -0
  78. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/resources/use_cases/definitions/version.py +0 -0
  79. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/resources/use_cases/kpis.py +0 -0
  80. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/resources/use_cases/properties.py +0 -0
  81. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/resources/use_cases/use_cases.py +0 -0
  82. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/__init__.py +0 -0
  83. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/bulk_ingest_response.py +0 -0
  84. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/categories/__init__.py +0 -0
  85. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/categories/resource_create_params.py +0 -0
  86. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/categories/resource_list_params.py +0 -0
  87. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/category_delete_resource_response.py +0 -0
  88. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/category_delete_response.py +0 -0
  89. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/category_list_params.py +0 -0
  90. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/category_list_resources_params.py +0 -0
  91. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/category_resource_response.py +0 -0
  92. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/category_response.py +0 -0
  93. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/cost_data.py +0 -0
  94. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/cost_details.py +0 -0
  95. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/default_response.py +0 -0
  96. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/experience_instance_response.py +0 -0
  97. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/experiences/__init__.py +0 -0
  98. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/experiences/experience_type.py +0 -0
  99. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/experiences/property_create_params.py +0 -0
  100. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/experiences/type_create_params.py +0 -0
  101. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/experiences/type_list_params.py +0 -0
  102. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/experiences/type_update_params.py +0 -0
  103. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/experiences/types/__init__.py +0 -0
  104. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/experiences/types/limit_config_create_params.py +0 -0
  105. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/ingest_bulk_params.py +0 -0
  106. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/ingest_event_param.py +0 -0
  107. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/ingest_response.py +0 -0
  108. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/ingest_units_params.py +0 -0
  109. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/limit_create_params.py +0 -0
  110. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/limit_history_response.py +0 -0
  111. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/limit_list_params.py +0 -0
  112. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/limit_list_response.py +0 -0
  113. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/limit_reset_params.py +0 -0
  114. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/limit_response.py +0 -0
  115. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/limit_update_params.py +0 -0
  116. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/limits/__init__.py +0 -0
  117. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/limits/limit_tags.py +0 -0
  118. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/limits/tag_create_params.py +0 -0
  119. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/limits/tag_create_response.py +0 -0
  120. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/limits/tag_delete_response.py +0 -0
  121. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/limits/tag_list_response.py +0 -0
  122. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/limits/tag_remove_params.py +0 -0
  123. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/limits/tag_remove_response.py +0 -0
  124. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/limits/tag_update_params.py +0 -0
  125. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/limits/tag_update_response.py +0 -0
  126. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/pay_i_common_models_api_router_header_info_param.py +0 -0
  127. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/requests/__init__.py +0 -0
  128. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/requests/property_create_params.py +0 -0
  129. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/requests/request_result.py +0 -0
  130. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/requests_data.py +0 -0
  131. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/shared/__init__.py +0 -0
  132. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/shared/evaluation_response.py +0 -0
  133. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/shared/ingest_units.py +0 -0
  134. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/shared/pay_i_common_models_budget_management_cost_details_base.py +0 -0
  135. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/shared/pay_i_common_models_budget_management_create_limit_base.py +0 -0
  136. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/shared/properties_response.py +0 -0
  137. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/shared/xproxy_error.py +0 -0
  138. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/shared/xproxy_result.py +0 -0
  139. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/shared_params/__init__.py +0 -0
  140. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/shared_params/ingest_units.py +0 -0
  141. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/shared_params/pay_i_common_models_budget_management_create_limit_base.py +0 -0
  142. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/total_cost_data.py +0 -0
  143. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/use_case_instance_response.py +0 -0
  144. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/use_cases/__init__.py +0 -0
  145. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/use_cases/definition_create_params.py +0 -0
  146. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/use_cases/definition_list_params.py +0 -0
  147. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/use_cases/definition_update_params.py +0 -0
  148. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/use_cases/definitions/__init__.py +0 -0
  149. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/use_cases/definitions/kpi_create_params.py +0 -0
  150. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/use_cases/definitions/kpi_create_response.py +0 -0
  151. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/use_cases/definitions/kpi_delete_response.py +0 -0
  152. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/use_cases/definitions/kpi_list_params.py +0 -0
  153. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/use_cases/definitions/kpi_list_response.py +0 -0
  154. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/use_cases/definitions/kpi_retrieve_response.py +0 -0
  155. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/use_cases/definitions/kpi_update_params.py +0 -0
  156. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/use_cases/definitions/kpi_update_response.py +0 -0
  157. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/use_cases/definitions/limit_config_create_params.py +0 -0
  158. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/use_cases/kpi_create_params.py +0 -0
  159. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/use_cases/kpi_list_params.py +0 -0
  160. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/use_cases/kpi_list_response.py +0 -0
  161. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/use_cases/kpi_update_params.py +0 -0
  162. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/use_cases/property_create_params.py +0 -0
  163. {payi-0.1.0a80 → payi-0.1.0a82}/src/payi/types/use_cases/use_case_definition.py +0 -0
  164. {payi-0.1.0a80 → payi-0.1.0a82}/tests/__init__.py +0 -0
  165. {payi-0.1.0a80 → payi-0.1.0a82}/tests/api_resources/__init__.py +0 -0
  166. {payi-0.1.0a80 → payi-0.1.0a82}/tests/api_resources/categories/__init__.py +0 -0
  167. {payi-0.1.0a80 → payi-0.1.0a82}/tests/api_resources/categories/test_resources.py +0 -0
  168. {payi-0.1.0a80 → payi-0.1.0a82}/tests/api_resources/experiences/__init__.py +0 -0
  169. {payi-0.1.0a80 → payi-0.1.0a82}/tests/api_resources/experiences/test_properties.py +0 -0
  170. {payi-0.1.0a80 → payi-0.1.0a82}/tests/api_resources/experiences/test_types.py +0 -0
  171. {payi-0.1.0a80 → payi-0.1.0a82}/tests/api_resources/experiences/types/__init__.py +0 -0
  172. {payi-0.1.0a80 → payi-0.1.0a82}/tests/api_resources/experiences/types/test_limit_config.py +0 -0
  173. {payi-0.1.0a80 → payi-0.1.0a82}/tests/api_resources/limits/__init__.py +0 -0
  174. {payi-0.1.0a80 → payi-0.1.0a82}/tests/api_resources/limits/test_tags.py +0 -0
  175. {payi-0.1.0a80 → payi-0.1.0a82}/tests/api_resources/requests/__init__.py +0 -0
  176. {payi-0.1.0a80 → payi-0.1.0a82}/tests/api_resources/requests/test_properties.py +0 -0
  177. {payi-0.1.0a80 → payi-0.1.0a82}/tests/api_resources/requests/test_result.py +0 -0
  178. {payi-0.1.0a80 → payi-0.1.0a82}/tests/api_resources/test_categories.py +0 -0
  179. {payi-0.1.0a80 → payi-0.1.0a82}/tests/api_resources/test_experiences.py +0 -0
  180. {payi-0.1.0a80 → payi-0.1.0a82}/tests/api_resources/test_ingest.py +0 -0
  181. {payi-0.1.0a80 → payi-0.1.0a82}/tests/api_resources/test_limits.py +0 -0
  182. {payi-0.1.0a80 → payi-0.1.0a82}/tests/api_resources/test_use_cases.py +0 -0
  183. {payi-0.1.0a80 → payi-0.1.0a82}/tests/api_resources/use_cases/__init__.py +0 -0
  184. {payi-0.1.0a80 → payi-0.1.0a82}/tests/api_resources/use_cases/definitions/__init__.py +0 -0
  185. {payi-0.1.0a80 → payi-0.1.0a82}/tests/api_resources/use_cases/definitions/test_kpis.py +0 -0
  186. {payi-0.1.0a80 → payi-0.1.0a82}/tests/api_resources/use_cases/definitions/test_limit_config.py +0 -0
  187. {payi-0.1.0a80 → payi-0.1.0a82}/tests/api_resources/use_cases/definitions/test_version.py +0 -0
  188. {payi-0.1.0a80 → payi-0.1.0a82}/tests/api_resources/use_cases/test_definitions.py +0 -0
  189. {payi-0.1.0a80 → payi-0.1.0a82}/tests/api_resources/use_cases/test_kpis.py +0 -0
  190. {payi-0.1.0a80 → payi-0.1.0a82}/tests/api_resources/use_cases/test_properties.py +0 -0
  191. {payi-0.1.0a80 → payi-0.1.0a82}/tests/conftest.py +0 -0
  192. {payi-0.1.0a80 → payi-0.1.0a82}/tests/sample_file.txt +0 -0
  193. {payi-0.1.0a80 → payi-0.1.0a82}/tests/test_client.py +0 -0
  194. {payi-0.1.0a80 → payi-0.1.0a82}/tests/test_deepcopy.py +0 -0
  195. {payi-0.1.0a80 → payi-0.1.0a82}/tests/test_extract_files.py +0 -0
  196. {payi-0.1.0a80 → payi-0.1.0a82}/tests/test_files.py +0 -0
  197. {payi-0.1.0a80 → payi-0.1.0a82}/tests/test_models.py +0 -0
  198. {payi-0.1.0a80 → payi-0.1.0a82}/tests/test_qs.py +0 -0
  199. {payi-0.1.0a80 → payi-0.1.0a82}/tests/test_required_args.py +0 -0
  200. {payi-0.1.0a80 → payi-0.1.0a82}/tests/test_response.py +0 -0
  201. {payi-0.1.0a80 → payi-0.1.0a82}/tests/test_streaming.py +0 -0
  202. {payi-0.1.0a80 → payi-0.1.0a82}/tests/test_transform.py +0 -0
  203. {payi-0.1.0a80 → payi-0.1.0a82}/tests/test_utils/test_proxy.py +0 -0
  204. {payi-0.1.0a80 → payi-0.1.0a82}/tests/test_utils/test_typing.py +0 -0
  205. {payi-0.1.0a80 → payi-0.1.0a82}/tests/utils.py +0 -0
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.1.0-alpha.82"
3
+ }
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.0-alpha.82 (2025-06-06)
4
+
5
+ Full Changelog: [v0.1.0-alpha.81...v0.1.0-alpha.82](https://github.com/Pay-i/pay-i-python/compare/v0.1.0-alpha.81...v0.1.0-alpha.82)
6
+
7
+ ### Bug Fixes
8
+
9
+ * vertex, google.genai report tokens when details missing ([#314](https://github.com/Pay-i/pay-i-python/issues/314)) ([54dd25b](https://github.com/Pay-i/pay-i-python/commit/54dd25b1abd93e6fdec22dd7bb8dae39236ee532))
10
+
11
+ ## 0.1.0-alpha.81 (2025-06-06)
12
+
13
+ Full Changelog: [v0.1.0-alpha.80...v0.1.0-alpha.81](https://github.com/Pay-i/pay-i-python/compare/v0.1.0-alpha.80...v0.1.0-alpha.81)
14
+
15
+ ### Features
16
+
17
+ * logger support ([#312](https://github.com/Pay-i/pay-i-python/issues/312)) ([f353bb2](https://github.com/Pay-i/pay-i-python/commit/f353bb2cbc24d28114c3bd770a8243f8b115d1fc))
18
+
3
19
  ## 0.1.0-alpha.80 (2025-06-04)
4
20
 
5
21
  Full Changelog: [v0.1.0-alpha.79...v0.1.0-alpha.80](https://github.com/Pay-i/pay-i-python/compare/v0.1.0-alpha.79...v0.1.0-alpha.80)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: payi
3
- Version: 0.1.0a80
3
+ Version: 0.1.0a82
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.80"
3
+ version = "0.1.0-alpha.82"
4
4
  description = "The official Python library for the payi API"
5
5
  dynamic = ["readme"]
6
6
  license = "Apache-2.0"
@@ -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.80" # x-release-please-version
4
+ __version__ = "0.1.0-alpha.82" # x-release-please-version
@@ -1,4 +1,3 @@
1
- import logging
2
1
  from typing import Any, Union, Optional, Sequence
3
2
  from typing_extensions import override
4
3
 
@@ -48,7 +47,7 @@ class AnthropicInstrumentor:
48
47
  )
49
48
 
50
49
  except Exception as e:
51
- logging.debug(f"Error instrumenting anthropic: {e}")
50
+ instrumentor._logger.debug(f"Error instrumenting anthropic: {e}")
52
51
  return
53
52
 
54
53
 
@@ -60,6 +59,7 @@ def messages_wrapper(
60
59
  *args: Any,
61
60
  **kwargs: Any,
62
61
  ) -> Any:
62
+ instrumentor._logger.debug("Anthropic messages wrapper")
63
63
  return instrumentor.invoke_wrapper(
64
64
  _AnthropicProviderRequest(instrumentor=instrumentor, streaming_type=_StreamingType.iterator, instance=instance),
65
65
  _IsStreaming.kwargs,
@@ -77,6 +77,7 @@ def stream_messages_wrapper(
77
77
  *args: Any,
78
78
  **kwargs: Any,
79
79
  ) -> Any:
80
+ instrumentor._logger.debug("Anthropic stream wrapper")
80
81
  return instrumentor.invoke_wrapper(
81
82
  _AnthropicProviderRequest(instrumentor=instrumentor, streaming_type=_StreamingType.stream_manager, instance=instance),
82
83
  _IsStreaming.true,
@@ -94,6 +95,7 @@ async def amessages_wrapper(
94
95
  *args: Any,
95
96
  **kwargs: Any,
96
97
  ) -> Any:
98
+ instrumentor._logger.debug("aync Anthropic messages wrapper")
97
99
  return await instrumentor.async_invoke_wrapper(
98
100
  _AnthropicProviderRequest(instrumentor=instrumentor, streaming_type=_StreamingType.iterator, instance=instance),
99
101
  _IsStreaming.kwargs,
@@ -111,6 +113,7 @@ async def astream_messages_wrapper(
111
113
  *args: Any,
112
114
  **kwargs: Any,
113
115
  ) -> Any:
116
+ instrumentor._logger.debug("aync Anthropic stream wrapper")
114
117
  return await instrumentor.async_invoke_wrapper(
115
118
  _AnthropicProviderRequest(instrumentor=instrumentor, streaming_type=_StreamingType.stream_manager, instance=instance),
116
119
  _IsStreaming.true,
@@ -202,7 +205,7 @@ class _AnthropicProviderRequest(_ProviderRequest):
202
205
  self._estimated_prompt_tokens = estimated_token_count
203
206
 
204
207
  except Exception:
205
- logging.warning("Error getting encoding for cl100k_base")
208
+ self._instrumentor._logger.warning("Error getting encoding for cl100k_base")
206
209
 
207
210
  return True
208
211
 
@@ -233,7 +236,7 @@ class _AnthropicProviderRequest(_ProviderRequest):
233
236
  self._ingest["provider_response_json"] = text
234
237
 
235
238
  except Exception as e:
236
- logging.debug(f"Error processing exception: {e}")
239
+ self._instrumentor._logger.debug(f"Error processing exception: {e}")
237
240
  return False
238
241
 
239
242
  return True
@@ -1,6 +1,5 @@
1
1
  import os
2
2
  import json
3
- import logging
4
3
  from typing import Any, Sequence
5
4
  from functools import wraps
6
5
  from typing_extensions import override
@@ -38,12 +37,13 @@ class BedrockInstrumentor:
38
37
  )
39
38
 
40
39
  except Exception as e:
41
- logging.debug(f"Error instrumenting bedrock: {e}")
40
+ instrumentor._logger.debug(f"Error instrumenting bedrock: {e}")
42
41
  return
43
42
 
44
43
  @_PayiInstrumentor.payi_wrapper
45
44
  def create_client_wrapper(instrumentor: _PayiInstrumentor, wrapped: Any, instance: Any, *args: Any, **kwargs: Any) -> Any: # noqa: ARG001
46
45
  if kwargs.get("service_name") != "bedrock-runtime":
46
+ instrumentor._logger.debug(f"skipping client wrapper creation for {kwargs.get('service_name', '')} service")
47
47
  return wrapped(*args, **kwargs)
48
48
 
49
49
  try:
@@ -53,13 +53,16 @@ def create_client_wrapper(instrumentor: _PayiInstrumentor, wrapped: Any, instanc
53
53
  client.converse = wrap_converse(instrumentor, client.converse)
54
54
  client.converse_stream = wrap_converse_stream(instrumentor, client.converse_stream)
55
55
 
56
+ instrumentor._logger.debug(f"Instrumented bedrock client")
57
+
56
58
  if BedrockInstrumentor._instrumentor._proxy_default:
57
59
  # Register client callbacks to handle the Pay-i extra_headers parameter in the inference calls and redirect the request to the Pay-i endpoint
58
60
  _register_bedrock_client_callbacks(client)
61
+ instrumentor._logger.debug(f"Registered bedrock client callbaks for proxy")
59
62
 
60
63
  return client
61
64
  except Exception as e:
62
- logging.debug(f"Error instrumenting bedrock client: {e}")
65
+ instrumentor._logger.debug(f"Error instrumenting bedrock client: {e}")
63
66
 
64
67
  return wrapped(*args, **kwargs)
65
68
 
@@ -148,6 +151,7 @@ def wrap_invoke(instrumentor: _PayiInstrumentor, wrapped: Any) -> Any:
148
151
  modelId:str = kwargs.get("modelId", "") # type: ignore
149
152
 
150
153
  if _is_supported_model(modelId):
154
+ instrumentor._logger.debug(f"bedrock invoke wrapper, modelId: {modelId}")
151
155
  return instrumentor.invoke_wrapper(
152
156
  _BedrockInvokeSynchronousProviderRequest(instrumentor=instrumentor),
153
157
  _IsStreaming.false,
@@ -156,6 +160,8 @@ def wrap_invoke(instrumentor: _PayiInstrumentor, wrapped: Any) -> Any:
156
160
  args,
157
161
  kwargs,
158
162
  )
163
+
164
+ instrumentor._logger.debug(f"bedrock invoke wrapper, unsupported modelId: {modelId}")
159
165
  return wrapped(*args, **kwargs)
160
166
 
161
167
  return invoke_wrapper
@@ -166,6 +172,7 @@ def wrap_invoke_stream(instrumentor: _PayiInstrumentor, wrapped: Any) -> Any:
166
172
  modelId: str = kwargs.get("modelId", "") # type: ignore
167
173
 
168
174
  if _is_supported_model(modelId):
175
+ instrumentor._logger.debug(f"bedrock invoke stream wrapper, modelId: {modelId}")
169
176
  return instrumentor.invoke_wrapper(
170
177
  _BedrockInvokeStreamingProviderRequest(instrumentor=instrumentor, model_id=modelId),
171
178
  _IsStreaming.true,
@@ -174,6 +181,7 @@ def wrap_invoke_stream(instrumentor: _PayiInstrumentor, wrapped: Any) -> Any:
174
181
  args,
175
182
  kwargs,
176
183
  )
184
+ instrumentor._logger.debug(f"bedrock invoke stream wrapper, unsupported modelId: {modelId}")
177
185
  return wrapped(*args, **kwargs)
178
186
 
179
187
  return invoke_wrapper
@@ -184,6 +192,7 @@ def wrap_converse(instrumentor: _PayiInstrumentor, wrapped: Any) -> Any:
184
192
  modelId:str = kwargs.get("modelId", "") # type: ignore
185
193
 
186
194
  if _is_supported_model(modelId):
195
+ instrumentor._logger.debug(f"bedrock converse wrapper, modelId: {modelId}")
187
196
  return instrumentor.invoke_wrapper(
188
197
  _BedrockConverseSynchronousProviderRequest(instrumentor=instrumentor),
189
198
  _IsStreaming.false,
@@ -192,6 +201,7 @@ def wrap_converse(instrumentor: _PayiInstrumentor, wrapped: Any) -> Any:
192
201
  args,
193
202
  kwargs,
194
203
  )
204
+ instrumentor._logger.debug(f"bedrock converse wrapper, unsupported modelId: {modelId}")
195
205
  return wrapped(*args, **kwargs)
196
206
 
197
207
  return invoke_wrapper
@@ -202,6 +212,7 @@ def wrap_converse_stream(instrumentor: _PayiInstrumentor, wrapped: Any) -> Any:
202
212
  modelId: str = kwargs.get("modelId", "") # type: ignore
203
213
 
204
214
  if _is_supported_model(modelId):
215
+ instrumentor._logger.debug(f"bedrock converse stream wrapper, modelId: {modelId}")
205
216
  return instrumentor.invoke_wrapper(
206
217
  _BedrockConverseStreamingProviderRequest(instrumentor=instrumentor),
207
218
  _IsStreaming.true,
@@ -210,6 +221,7 @@ def wrap_converse_stream(instrumentor: _PayiInstrumentor, wrapped: Any) -> Any:
210
221
  args,
211
222
  kwargs,
212
223
  )
224
+ instrumentor._logger.debug(f"bedrock converse stream wrapper, unsupported modelId: {modelId}")
213
225
  return wrapped(*args, **kwargs)
214
226
 
215
227
  return invoke_wrapper
@@ -251,7 +263,7 @@ class _BedrockProviderRequest(_ProviderRequest):
251
263
  return True
252
264
 
253
265
  except Exception as e:
254
- logging.debug(f"Error processing exception: {e}")
266
+ self._instrumentor._logger.debug(f"Error processing exception: {e}")
255
267
  return False
256
268
 
257
269
  class _BedrockInvokeStreamingProviderRequest(_BedrockProviderRequest):
@@ -1,6 +1,5 @@
1
1
  import json
2
2
  import math
3
- import logging
4
3
  from typing import Any, List, Union, Optional, Sequence
5
4
  from typing_extensions import override
6
5
 
@@ -41,7 +40,7 @@ class GoogleGenAiInstrumentor:
41
40
  )
42
41
 
43
42
  except Exception as e:
44
- logging.debug(f"Error instrumenting vertex: {e}")
43
+ instrumentor._logger.debug(f"Error instrumenting vertex: {e}")
45
44
  return
46
45
 
47
46
  @_PayiInstrumentor.payi_wrapper
@@ -52,6 +51,7 @@ def generate_wrapper(
52
51
  *args: Any,
53
52
  **kwargs: Any,
54
53
  ) -> Any:
54
+ instrumentor._logger.debug("genai generate_content wrapper")
55
55
  return instrumentor.invoke_wrapper(
56
56
  _GoogleGenAiRequest(instrumentor),
57
57
  _IsStreaming.false,
@@ -69,6 +69,7 @@ def generate_stream_wrapper(
69
69
  *args: Any,
70
70
  **kwargs: Any,
71
71
  ) -> Any:
72
+ instrumentor._logger.debug("genai generate_content_stream wrapper")
72
73
  return instrumentor.invoke_wrapper(
73
74
  _GoogleGenAiRequest(instrumentor),
74
75
  _IsStreaming.true,
@@ -86,6 +87,7 @@ async def agenerate_wrapper(
86
87
  *args: Any,
87
88
  **kwargs: Any,
88
89
  ) -> Any:
90
+ instrumentor._logger.debug("async genai generate_content wrapper")
89
91
  return await instrumentor.async_invoke_wrapper(
90
92
  _GoogleGenAiRequest(instrumentor),
91
93
  _IsStreaming.false,
@@ -103,6 +105,7 @@ async def agenerate_stream_wrapper(
103
105
  *args: Any,
104
106
  **kwargs: Any,
105
107
  ) -> Any:
108
+ instrumentor._logger.debug("async genai generate_content_stream wrapper")
106
109
  return await instrumentor.async_invoke_wrapper(
107
110
  _GoogleGenAiRequest(instrumentor),
108
111
  _IsStreaming.true,
@@ -306,15 +309,15 @@ class _GoogleGenAiRequest(_ProviderRequest):
306
309
  usage = response_dict.get("usage_metadata", {})
307
310
  input = usage.get("prompt_token_count", 0)
308
311
 
309
- prompt_tokens_details: list[dict[str, Any]] = usage.get("prompt_tokens_details")
310
- candidates_tokens_details: list[dict[str, Any]] = usage.get("candidates_tokens_details")
312
+ prompt_tokens_details: list[dict[str, Any]] = usage.get("prompt_tokens_details", [])
313
+ candidates_tokens_details: list[dict[str, Any]] = usage.get("candidates_tokens_details", [])
311
314
 
312
315
  model: str = response_dict.get("model_version", "")
316
+
317
+ # for character billing only
318
+ large_context = "" if input < 128000 else "_large_context"
313
319
 
314
320
  if self._is_character_billing_model(model):
315
- # gemini 1.0 and 1.5 units are reported in characters, per second, per image, etc...
316
- large_context = "" if input < 128000 else "_large_context"
317
-
318
321
  for details in prompt_tokens_details:
319
322
  modality = details.get("modality", "")
320
323
  if not modality:
@@ -354,7 +357,7 @@ class _GoogleGenAiRequest(_ProviderRequest):
354
357
  audio_seconds = math.ceil(modality_token_count / 25)
355
358
  self.add_units("audio"+large_context, input=audio_seconds)
356
359
 
357
- elif model.startswith("gemini-2.0"):
360
+ else:
358
361
  for details in prompt_tokens_details:
359
362
  modality = details.get("modality", "")
360
363
  if not modality:
@@ -373,3 +376,19 @@ class _GoogleGenAiRequest(_ProviderRequest):
373
376
  modality_token_count = details.get("token_count", 0)
374
377
  if modality in ("VIDEO", "AUDIO", "TEXT", "IMAGE"):
375
378
  self.add_units(modality.lower(), output=modality_token_count)
379
+
380
+ if not self._ingest["units"]:
381
+ input = usage.get("prompt_token_count", 0)
382
+ output = usage.get("candidates_token_count", 0) * 4
383
+
384
+ if self._is_character_billing_model(model):
385
+ if self._prompt_character_count > 0:
386
+ input = self._prompt_character_count
387
+ else:
388
+ input *= 4
389
+
390
+ # if no units were added, add a default unit and assume 4 characters per token
391
+ self._ingest["units"]["text"+large_context] = Units(input=input, output=output)
392
+ else:
393
+ # if no units were added, add a default unit
394
+ self._ingest["units"]["text"] = Units(input=input, output=output)
@@ -1,5 +1,4 @@
1
1
  import json
2
- import logging
3
2
  from typing import Any, Union, Optional, Sequence
4
3
  from typing_extensions import override
5
4
  from importlib.metadata import version
@@ -62,7 +61,7 @@ class OpenAiInstrumentor:
62
61
  )
63
62
 
64
63
  except Exception as e:
65
- logging.debug(f"Error instrumenting openai: {e}")
64
+ instrumentor._logger.debug(f"Error instrumenting openai: {e}")
66
65
  return
67
66
 
68
67
 
@@ -74,6 +73,7 @@ def embeddings_wrapper(
74
73
  *args: Any,
75
74
  **kwargs: Any,
76
75
  ) -> Any:
76
+ instrumentor._logger.debug("OpenAI Embeddings wrapper")
77
77
  return instrumentor.invoke_wrapper(
78
78
  _OpenAiEmbeddingsProviderRequest(instrumentor),
79
79
  _IsStreaming.false,
@@ -91,6 +91,7 @@ async def aembeddings_wrapper(
91
91
  *args: Any,
92
92
  **kwargs: Any,
93
93
  ) -> Any:
94
+ instrumentor._logger.debug("async OpenAI Embeddings wrapper")
94
95
  return await instrumentor.async_invoke_wrapper(
95
96
  _OpenAiEmbeddingsProviderRequest(instrumentor),
96
97
  _IsStreaming.false,
@@ -108,6 +109,7 @@ def chat_wrapper(
108
109
  *args: Any,
109
110
  **kwargs: Any,
110
111
  ) -> Any:
112
+ instrumentor._logger.debug("OpenAI completions wrapper")
111
113
  return instrumentor.invoke_wrapper(
112
114
  _OpenAiChatProviderRequest(instrumentor),
113
115
  _IsStreaming.kwargs,
@@ -125,6 +127,7 @@ async def achat_wrapper(
125
127
  *args: Any,
126
128
  **kwargs: Any,
127
129
  ) -> Any:
130
+ instrumentor._logger.debug("async OpenAI completions wrapper")
128
131
  return await instrumentor.async_invoke_wrapper(
129
132
  _OpenAiChatProviderRequest(instrumentor),
130
133
  _IsStreaming.kwargs,
@@ -142,6 +145,7 @@ def responses_wrapper(
142
145
  *args: Any,
143
146
  **kwargs: Any,
144
147
  ) -> Any:
148
+ instrumentor._logger.debug("OpenAI responses wrapper")
145
149
  return instrumentor.invoke_wrapper(
146
150
  _OpenAiResponsesProviderRequest(instrumentor),
147
151
  _IsStreaming.kwargs,
@@ -159,6 +163,7 @@ async def aresponses_wrapper(
159
163
  *args: Any,
160
164
  **kwargs: Any,
161
165
  ) -> Any:
166
+ instrumentor._logger.debug("async OpenAI responses wrapper")
162
167
  return await instrumentor.async_invoke_wrapper(
163
168
  _OpenAiResponsesProviderRequest(instrumentor),
164
169
  _IsStreaming.kwargs,
@@ -207,12 +212,12 @@ class _OpenAiProviderRequest(_ProviderRequest):
207
212
  del extra_headers[PayiHeaderNames.resource_scope]
208
213
 
209
214
  if not price_as_resource and not price_as_category:
210
- logging.error("Azure OpenAI requires price as resource and/or category to be specified, not ingesting")
215
+ self._instrumentor._logger.error("Azure OpenAI requires price as resource and/or category to be specified, not ingesting")
211
216
  return False
212
217
 
213
218
  if resource_scope:
214
219
  if not(resource_scope in ["global", "datazone"] or resource_scope.startswith("region")):
215
- logging.error("Azure OpenAI invalid resource scope, not ingesting")
220
+ self._instrumentor._logger.error("Azure OpenAI invalid resource scope, not ingesting")
216
221
  return False
217
222
 
218
223
  self._ingest["resource_scope"] = resource_scope
@@ -256,7 +261,7 @@ class _OpenAiProviderRequest(_ProviderRequest):
256
261
  self._ingest["provider_response_json"] = text
257
262
 
258
263
  except Exception as e:
259
- logging.debug(f"Error processing exception: {e}")
264
+ self._instrumentor._logger.debug(f"Error processing exception: {e}")
260
265
  return False
261
266
 
262
267
  return True
@@ -372,7 +377,7 @@ class _OpenAiChatProviderRequest(_OpenAiProviderRequest):
372
377
  try:
373
378
  enc = tiktoken.get_encoding("o200k_base") # type: ignore
374
379
  except Exception:
375
- logging.warning("Error getting encoding for fallback o200k_base")
380
+ self._instrumentor._logger.warning("Error getting encoding for fallback o200k_base")
376
381
  enc = None
377
382
 
378
383
  if enc:
@@ -450,7 +455,7 @@ class _OpenAiResponsesProviderRequest(_OpenAiProviderRequest):
450
455
  try:
451
456
  enc = tiktoken.get_encoding("o200k_base") # type: ignore
452
457
  except Exception:
453
- logging.warning("Error getting encoding for fallback o200k_base")
458
+ self._instrumentor._logger.warning("Error getting encoding for fallback o200k_base")
454
459
  enc = None
455
460
 
456
461
  # find each content..type="input_text" and count tokens
@@ -1,6 +1,5 @@
1
1
  import json
2
2
  import math
3
- import logging
4
3
  from typing import Any, List, Union, Optional, Sequence
5
4
  from typing_extensions import override
6
5
 
@@ -43,7 +42,7 @@ class VertexInstrumentor:
43
42
  )
44
43
 
45
44
  except Exception as e:
46
- logging.debug(f"Error instrumenting vertex: {e}")
45
+ instrumentor._logger.debug(f"Error instrumenting vertex: {e}")
47
46
  return
48
47
 
49
48
  @_PayiInstrumentor.payi_wrapper
@@ -54,6 +53,7 @@ def generate_wrapper(
54
53
  *args: Any,
55
54
  **kwargs: Any,
56
55
  ) -> Any:
56
+ instrumentor._logger.debug("vertexai generate_content wrapper")
57
57
  return instrumentor.invoke_wrapper(
58
58
  _GoogleVertexRequest(instrumentor),
59
59
  _IsStreaming.kwargs,
@@ -71,6 +71,7 @@ async def agenerate_wrapper(
71
71
  *args: Any,
72
72
  **kwargs: Any,
73
73
  ) -> Any:
74
+ instrumentor._logger.debug("async vertexai generate_content wrapper")
74
75
  return await instrumentor.async_invoke_wrapper(
75
76
  _GoogleVertexRequest(instrumentor),
76
77
  _IsStreaming.kwargs,
@@ -252,15 +253,16 @@ class _GoogleVertexRequest(_ProviderRequest):
252
253
  usage = response_dict.get("usage_metadata", {})
253
254
  input = usage.get("prompt_token_count", 0)
254
255
 
255
- prompt_tokens_details: list[dict[str, Any]] = usage.get("prompt_tokens_details")
256
- candidates_tokens_details: list[dict[str, Any]] = usage.get("candidates_tokens_details")
256
+ prompt_tokens_details: list[dict[str, Any]] = usage.get("prompt_tokens_details", [])
257
+ candidates_tokens_details: list[dict[str, Any]] = usage.get("candidates_tokens_details", [])
257
258
 
258
259
  model: str = response_dict.get("model_version", "")
260
+
261
+ # for character billing only
262
+ large_context = "" if input < 128000 else "_large_context"
259
263
 
260
264
  if self._is_character_billing_model(model):
261
265
  # gemini 1.0 and 1.5 units are reported in characters, per second, per image, etc...
262
- large_context = "" if input < 128000 else "_large_context"
263
-
264
266
  for details in prompt_tokens_details:
265
267
  modality = details.get("modality", "")
266
268
  if not modality:
@@ -300,7 +302,7 @@ class _GoogleVertexRequest(_ProviderRequest):
300
302
  audio_seconds = math.ceil(modality_token_count / 25)
301
303
  self.add_units("audio"+large_context, input=audio_seconds)
302
304
 
303
- elif model.startswith("gemini-2.0"):
305
+ else:
304
306
  for details in prompt_tokens_details:
305
307
  modality = details.get("modality", "")
306
308
  if not modality:
@@ -319,3 +321,19 @@ class _GoogleVertexRequest(_ProviderRequest):
319
321
  modality_token_count = details.get("token_count", 0)
320
322
  if modality in ("VIDEO", "AUDIO", "TEXT", "IMAGE"):
321
323
  self.add_units(modality.lower(), output=modality_token_count)
324
+
325
+ if not self._ingest["units"]:
326
+ input = usage.get("prompt_token_count", 0)
327
+ output = usage.get("candidates_token_count", 0) * 4
328
+
329
+ if self._is_character_billing_model(model):
330
+ if self._prompt_character_count > 0:
331
+ input = self._prompt_character_count
332
+ else:
333
+ input *= 4
334
+
335
+ # if no units were added, add a default unit and assume 4 characters per token
336
+ self._ingest["units"]["text"+large_context] = Units(input=input, output=output)
337
+ else:
338
+ # if no units were added, add a default unit
339
+ self._ingest["units"]["text"] = Units(input=input, output=output)