payi 0.1.0a82__py3-none-any.whl → 0.1.0a83__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of payi might be problematic. Click here for more details.
- payi/_version.py +1 -1
- payi/lib/AnthropicInstrumentor.py +10 -3
- payi/lib/BedrockInstrumentor.py +16 -11
- payi/lib/GoogleGenAiInstrumentor.py +5 -3
- payi/lib/OpenAIInstrumentor.py +13 -9
- payi/lib/VertexInstrumentor.py +40 -16
- payi/lib/instrument.py +119 -64
- {payi-0.1.0a82.dist-info → payi-0.1.0a83.dist-info}/METADATA +1 -1
- {payi-0.1.0a82.dist-info → payi-0.1.0a83.dist-info}/RECORD +11 -11
- {payi-0.1.0a82.dist-info → payi-0.1.0a83.dist-info}/WHEEL +0 -0
- {payi-0.1.0a82.dist-info → payi-0.1.0a83.dist-info}/licenses/LICENSE +0 -0
payi/_version.py
CHANGED
|
@@ -7,7 +7,7 @@ from wrapt import wrap_function_wrapper # type: ignore
|
|
|
7
7
|
from payi.lib.helpers import PayiCategories
|
|
8
8
|
from payi.types.ingest_units_params import Units
|
|
9
9
|
|
|
10
|
-
from .instrument import _IsStreaming, _StreamingType, _ProviderRequest, _PayiInstrumentor
|
|
10
|
+
from .instrument import _ChunkResult, _IsStreaming, _StreamingType, _ProviderRequest, _PayiInstrumentor
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class AnthropicInstrumentor:
|
|
@@ -133,7 +133,8 @@ class _AnthropicProviderRequest(_ProviderRequest):
|
|
|
133
133
|
)
|
|
134
134
|
|
|
135
135
|
@override
|
|
136
|
-
def process_chunk(self, chunk: Any) ->
|
|
136
|
+
def process_chunk(self, chunk: Any) -> _ChunkResult:
|
|
137
|
+
ingest = False
|
|
137
138
|
if chunk.type == "message_start":
|
|
138
139
|
self._ingest["provider_response_id"] = chunk.message.id
|
|
139
140
|
|
|
@@ -154,9 +155,15 @@ class _AnthropicProviderRequest(_ProviderRequest):
|
|
|
154
155
|
|
|
155
156
|
elif chunk.type == "message_delta":
|
|
156
157
|
usage = chunk.usage
|
|
158
|
+
ingest = True
|
|
159
|
+
|
|
160
|
+
# Web search will return an updated input tokens value at the end of streaming
|
|
161
|
+
if usage.input_tokens > 0:
|
|
162
|
+
self._ingest["units"]["text"]["input"] = usage.input_tokens
|
|
163
|
+
|
|
157
164
|
self._ingest["units"]["text"]["output"] = usage.output_tokens
|
|
158
165
|
|
|
159
|
-
return True
|
|
166
|
+
return _ChunkResult(send_chunk_to_caller=True, ingest=ingest)
|
|
160
167
|
|
|
161
168
|
@override
|
|
162
169
|
def process_synchronous_response(self, response: Any, log_prompt_and_response: bool, kwargs: Any) -> Any:
|
payi/lib/BedrockInstrumentor.py
CHANGED
|
@@ -10,7 +10,7 @@ from payi.lib.helpers import PayiCategories, PayiHeaderNames, payi_aws_bedrock_u
|
|
|
10
10
|
from payi.types.ingest_units_params import Units, IngestUnitsParams
|
|
11
11
|
from payi.types.pay_i_common_models_api_router_header_info_param import PayICommonModelsAPIRouterHeaderInfoParam
|
|
12
12
|
|
|
13
|
-
from .instrument import _IsStreaming, _StreamingType, _ProviderRequest, _PayiInstrumentor
|
|
13
|
+
from .instrument import _ChunkResult, _IsStreaming, _StreamingType, _ProviderRequest, _PayiInstrumentor
|
|
14
14
|
|
|
15
15
|
_supported_model_prefixes = ["meta.llama3", "anthropic.", "amazon.nova-pro", "amazon.nova-lite", "amazon.nova-micro"]
|
|
16
16
|
|
|
@@ -22,8 +22,6 @@ class BedrockInstrumentor:
|
|
|
22
22
|
BedrockInstrumentor._instrumentor = instrumentor
|
|
23
23
|
|
|
24
24
|
try:
|
|
25
|
-
import boto3 # type: ignore # noqa: F401 I001
|
|
26
|
-
|
|
27
25
|
wrap_function_wrapper(
|
|
28
26
|
"botocore.client",
|
|
29
27
|
"ClientCreator.create_client",
|
|
@@ -43,7 +41,7 @@ class BedrockInstrumentor:
|
|
|
43
41
|
@_PayiInstrumentor.payi_wrapper
|
|
44
42
|
def create_client_wrapper(instrumentor: _PayiInstrumentor, wrapped: Any, instance: Any, *args: Any, **kwargs: Any) -> Any: # noqa: ARG001
|
|
45
43
|
if kwargs.get("service_name") != "bedrock-runtime":
|
|
46
|
-
instrumentor._logger.debug(f"skipping client wrapper creation for {kwargs.get('service_name', '')} service")
|
|
44
|
+
# instrumentor._logger.debug(f"skipping client wrapper creation for {kwargs.get('service_name', '')} service")
|
|
47
45
|
return wrapped(*args, **kwargs)
|
|
48
46
|
|
|
49
47
|
try:
|
|
@@ -272,13 +270,14 @@ class _BedrockInvokeStreamingProviderRequest(_BedrockProviderRequest):
|
|
|
272
270
|
self._is_anthropic: bool = model_id.startswith("anthropic.")
|
|
273
271
|
|
|
274
272
|
@override
|
|
275
|
-
def process_chunk(self, chunk: Any) ->
|
|
273
|
+
def process_chunk(self, chunk: Any) -> _ChunkResult:
|
|
276
274
|
if self._is_anthropic:
|
|
277
275
|
return self.process_invoke_streaming_anthropic_chunk(chunk)
|
|
278
276
|
else:
|
|
279
277
|
return self.process_invoke_streaming_llama_chunk(chunk)
|
|
280
278
|
|
|
281
|
-
def process_invoke_streaming_anthropic_chunk(self, chunk: str) ->
|
|
279
|
+
def process_invoke_streaming_anthropic_chunk(self, chunk: str) -> _ChunkResult:
|
|
280
|
+
ingest = False
|
|
282
281
|
chunk_dict = json.loads(chunk)
|
|
283
282
|
type = chunk_dict.get("type", "")
|
|
284
283
|
|
|
@@ -301,18 +300,21 @@ class _BedrockInvokeStreamingProviderRequest(_BedrockProviderRequest):
|
|
|
301
300
|
elif type == "message_delta":
|
|
302
301
|
usage = chunk_dict['usage']
|
|
303
302
|
self._ingest["units"]["text"]["output"] = usage['output_tokens']
|
|
303
|
+
ingest = True
|
|
304
304
|
|
|
305
|
-
return True
|
|
305
|
+
return _ChunkResult(send_chunk_to_caller=True, ingest=ingest)
|
|
306
306
|
|
|
307
|
-
def process_invoke_streaming_llama_chunk(self, chunk: str) ->
|
|
307
|
+
def process_invoke_streaming_llama_chunk(self, chunk: str) -> _ChunkResult:
|
|
308
|
+
ingest = False
|
|
308
309
|
chunk_dict = json.loads(chunk)
|
|
309
310
|
metrics = chunk_dict.get("amazon-bedrock-invocationMetrics", {})
|
|
310
311
|
if metrics:
|
|
311
312
|
input = metrics.get("inputTokenCount", 0)
|
|
312
313
|
output = metrics.get("outputTokenCount", 0)
|
|
313
314
|
self._ingest["units"]["text"] = Units(input=input, output=output)
|
|
315
|
+
ingest = True
|
|
314
316
|
|
|
315
|
-
return True
|
|
317
|
+
return _ChunkResult(send_chunk_to_caller=True, ingest=ingest)
|
|
316
318
|
|
|
317
319
|
class _BedrockInvokeSynchronousProviderRequest(_BedrockProviderRequest):
|
|
318
320
|
@override
|
|
@@ -374,7 +376,8 @@ class _BedrockConverseSynchronousProviderRequest(_BedrockProviderRequest):
|
|
|
374
376
|
|
|
375
377
|
class _BedrockConverseStreamingProviderRequest(_BedrockProviderRequest):
|
|
376
378
|
@override
|
|
377
|
-
def process_chunk(self, chunk: 'dict[str, Any]') ->
|
|
379
|
+
def process_chunk(self, chunk: 'dict[str, Any]') -> _ChunkResult:
|
|
380
|
+
ingest = False
|
|
378
381
|
metadata = chunk.get("metadata", {})
|
|
379
382
|
|
|
380
383
|
if metadata:
|
|
@@ -383,4 +386,6 @@ class _BedrockConverseStreamingProviderRequest(_BedrockProviderRequest):
|
|
|
383
386
|
output = usage["outputTokens"]
|
|
384
387
|
self._ingest["units"]["text"] = Units(input=input, output=output)
|
|
385
388
|
|
|
386
|
-
|
|
389
|
+
ingest = True
|
|
390
|
+
|
|
391
|
+
return _ChunkResult(send_chunk_to_caller=True, ingest=ingest)
|
|
@@ -8,7 +8,7 @@ from wrapt import wrap_function_wrapper # type: ignore
|
|
|
8
8
|
from payi.lib.helpers import PayiCategories
|
|
9
9
|
from payi.types.ingest_units_params import Units
|
|
10
10
|
|
|
11
|
-
from .instrument import _IsStreaming, _StreamingType, _ProviderRequest, _PayiInstrumentor
|
|
11
|
+
from .instrument import _ChunkResult, _IsStreaming, _StreamingType, _ProviderRequest, _PayiInstrumentor
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class GoogleGenAiInstrumentor:
|
|
@@ -248,7 +248,8 @@ class _GoogleGenAiRequest(_ProviderRequest):
|
|
|
248
248
|
prompt["tool_config"] = tool_config
|
|
249
249
|
|
|
250
250
|
@override
|
|
251
|
-
def process_chunk(self, chunk: Any) ->
|
|
251
|
+
def process_chunk(self, chunk: Any) -> _ChunkResult:
|
|
252
|
+
ingest = False
|
|
252
253
|
response_dict: dict[str, Any] = chunk.to_json_dict()
|
|
253
254
|
if "provider_response_id" not in self._ingest:
|
|
254
255
|
id = response_dict.get("response_id", None)
|
|
@@ -267,8 +268,9 @@ class _GoogleGenAiRequest(_ProviderRequest):
|
|
|
267
268
|
usage = response_dict.get("usage_metadata", {})
|
|
268
269
|
if usage and "prompt_token_count" in usage and "candidates_token_count" in usage:
|
|
269
270
|
self._compute_usage(response_dict, streaming_candidates_characters=self._candiates_character_count)
|
|
271
|
+
ingest = True
|
|
270
272
|
|
|
271
|
-
return True
|
|
273
|
+
return _ChunkResult(send_chunk_to_caller=True, ingest=ingest)
|
|
272
274
|
|
|
273
275
|
@staticmethod
|
|
274
276
|
def _is_character_billing_model(model: str) -> bool:
|
payi/lib/OpenAIInstrumentor.py
CHANGED
|
@@ -9,7 +9,7 @@ from wrapt import wrap_function_wrapper # type: ignore
|
|
|
9
9
|
from payi.lib.helpers import PayiCategories, PayiHeaderNames
|
|
10
10
|
from payi.types.ingest_units_params import Units
|
|
11
11
|
|
|
12
|
-
from .instrument import _IsStreaming, _StreamingType, _ProviderRequest, _PayiInstrumentor
|
|
12
|
+
from .instrument import _ChunkResult, _IsStreaming, _StreamingType, _ProviderRequest, _PayiInstrumentor
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
class OpenAiInstrumentor:
|
|
@@ -22,8 +22,6 @@ class OpenAiInstrumentor:
|
|
|
22
22
|
@staticmethod
|
|
23
23
|
def instrument(instrumentor: _PayiInstrumentor) -> None:
|
|
24
24
|
try:
|
|
25
|
-
from openai import OpenAI # type: ignore # noqa: F401 I001
|
|
26
|
-
|
|
27
25
|
wrap_function_wrapper(
|
|
28
26
|
"openai.resources.chat.completions",
|
|
29
27
|
"Completions.create",
|
|
@@ -47,7 +45,11 @@ class OpenAiInstrumentor:
|
|
|
47
45
|
"AsyncEmbeddings.create",
|
|
48
46
|
aembeddings_wrapper(instrumentor),
|
|
49
47
|
)
|
|
48
|
+
except Exception as e:
|
|
49
|
+
instrumentor._logger.debug(f"Error instrumenting openai: {e}")
|
|
50
50
|
|
|
51
|
+
# responses separately as they are relatively new and the client may not be using the latest openai module
|
|
52
|
+
try:
|
|
51
53
|
wrap_function_wrapper(
|
|
52
54
|
"openai.resources.responses",
|
|
53
55
|
"Responses.create",
|
|
@@ -62,8 +64,6 @@ class OpenAiInstrumentor:
|
|
|
62
64
|
|
|
63
65
|
except Exception as e:
|
|
64
66
|
instrumentor._logger.debug(f"Error instrumenting openai: {e}")
|
|
65
|
-
return
|
|
66
|
-
|
|
67
67
|
|
|
68
68
|
@_PayiInstrumentor.payi_wrapper
|
|
69
69
|
def embeddings_wrapper(
|
|
@@ -338,7 +338,8 @@ class _OpenAiChatProviderRequest(_OpenAiProviderRequest):
|
|
|
338
338
|
self._include_usage_added = False
|
|
339
339
|
|
|
340
340
|
@override
|
|
341
|
-
def process_chunk(self, chunk: Any) ->
|
|
341
|
+
def process_chunk(self, chunk: Any) -> _ChunkResult:
|
|
342
|
+
ingest = False
|
|
342
343
|
model = model_to_dict(chunk)
|
|
343
344
|
|
|
344
345
|
if "provider_response_id" not in self._ingest:
|
|
@@ -356,8 +357,9 @@ class _OpenAiChatProviderRequest(_OpenAiProviderRequest):
|
|
|
356
357
|
# packet which contains the usage to the client as they are not expecting the data
|
|
357
358
|
if self._include_usage_added:
|
|
358
359
|
send_chunk_to_client = False
|
|
360
|
+
ingest = True
|
|
359
361
|
|
|
360
|
-
return send_chunk_to_client
|
|
362
|
+
return _ChunkResult(send_chunk_to_caller=send_chunk_to_client, ingest=ingest)
|
|
361
363
|
|
|
362
364
|
@override
|
|
363
365
|
def process_request(self, instance: Any, extra_headers: 'dict[str, str]', args: Sequence[Any], kwargs: Any) -> bool:
|
|
@@ -420,7 +422,8 @@ class _OpenAiResponsesProviderRequest(_OpenAiProviderRequest):
|
|
|
420
422
|
input_tokens_details_key=_OpenAiProviderRequest.responses_input_tokens_details_key)
|
|
421
423
|
|
|
422
424
|
@override
|
|
423
|
-
def process_chunk(self, chunk: Any) ->
|
|
425
|
+
def process_chunk(self, chunk: Any) -> _ChunkResult:
|
|
426
|
+
ingest = False
|
|
424
427
|
model = model_to_dict(chunk)
|
|
425
428
|
response: dict[str, Any] = model.get("response", {})
|
|
426
429
|
|
|
@@ -432,8 +435,9 @@ class _OpenAiResponsesProviderRequest(_OpenAiProviderRequest):
|
|
|
432
435
|
usage = response.get("usage")
|
|
433
436
|
if usage:
|
|
434
437
|
self.add_usage_units(usage)
|
|
438
|
+
ingest = True
|
|
435
439
|
|
|
436
|
-
return True
|
|
440
|
+
return _ChunkResult(send_chunk_to_caller=True, ingest=ingest)
|
|
437
441
|
|
|
438
442
|
@override
|
|
439
443
|
def process_request(self, instance: Any, extra_headers: 'dict[str, str]', args: Sequence[Any], kwargs: Any) -> bool:
|
payi/lib/VertexInstrumentor.py
CHANGED
|
@@ -8,33 +8,37 @@ from wrapt import wrap_function_wrapper # type: ignore
|
|
|
8
8
|
from payi.lib.helpers import PayiCategories
|
|
9
9
|
from payi.types.ingest_units_params import Units
|
|
10
10
|
|
|
11
|
-
from .instrument import _IsStreaming, _StreamingType, _ProviderRequest, _PayiInstrumentor
|
|
11
|
+
from .instrument import _ChunkResult, _IsStreaming, _StreamingType, _ProviderRequest, _PayiInstrumentor
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class VertexInstrumentor:
|
|
15
15
|
@staticmethod
|
|
16
16
|
def instrument(instrumentor: _PayiInstrumentor) -> None:
|
|
17
17
|
try:
|
|
18
|
-
import vertexai # type: ignore # noqa: F401 I001
|
|
19
|
-
|
|
20
18
|
wrap_function_wrapper(
|
|
21
19
|
"vertexai.generative_models",
|
|
22
20
|
"GenerativeModel.generate_content",
|
|
23
21
|
generate_wrapper(instrumentor),
|
|
24
22
|
)
|
|
25
23
|
|
|
26
|
-
wrap_function_wrapper(
|
|
27
|
-
"vertexai.preview.generative_models",
|
|
28
|
-
"GenerativeModel.generate_content",
|
|
29
|
-
generate_wrapper(instrumentor),
|
|
30
|
-
)
|
|
31
|
-
|
|
32
24
|
wrap_function_wrapper(
|
|
33
25
|
"vertexai.generative_models",
|
|
34
26
|
"GenerativeModel.generate_content_async",
|
|
35
27
|
agenerate_wrapper(instrumentor),
|
|
36
28
|
)
|
|
37
29
|
|
|
30
|
+
except Exception as e:
|
|
31
|
+
instrumentor._logger.debug(f"Error instrumenting vertex: {e}")
|
|
32
|
+
return
|
|
33
|
+
|
|
34
|
+
# separate instrumetning preview functionality from released in case it fails
|
|
35
|
+
try:
|
|
36
|
+
wrap_function_wrapper(
|
|
37
|
+
"vertexai.preview.generative_models",
|
|
38
|
+
"GenerativeModel.generate_content",
|
|
39
|
+
generate_wrapper(instrumentor),
|
|
40
|
+
)
|
|
41
|
+
|
|
38
42
|
wrap_function_wrapper(
|
|
39
43
|
"vertexai.preview.generative_models",
|
|
40
44
|
"GenerativeModel.generate_content_async",
|
|
@@ -93,11 +97,19 @@ class _GoogleVertexRequest(_ProviderRequest):
|
|
|
93
97
|
)
|
|
94
98
|
self._prompt_character_count = 0
|
|
95
99
|
self._candiates_character_count = 0
|
|
100
|
+
self._model_name: Optional[str] = None
|
|
96
101
|
|
|
97
102
|
@override
|
|
98
103
|
def process_request(self, instance: Any, extra_headers: 'dict[str, str]', args: Sequence[Any], kwargs: Any) -> bool:
|
|
99
104
|
from vertexai.generative_models import Content, Image, Part # type: ignore # noqa: F401 I001
|
|
100
105
|
|
|
106
|
+
# Try to extra the model name as a backup if the response does not provide it (older vertexai versions do not)
|
|
107
|
+
if instance and hasattr(instance, "_model_name"):
|
|
108
|
+
model = instance._model_name
|
|
109
|
+
if model and isinstance(model, str):
|
|
110
|
+
# Extract the model name after the last slash
|
|
111
|
+
self._model_name = model.split('/')[-1]
|
|
112
|
+
|
|
101
113
|
if not args:
|
|
102
114
|
return True
|
|
103
115
|
|
|
@@ -191,17 +203,26 @@ class _GoogleVertexRequest(_ProviderRequest):
|
|
|
191
203
|
# tool_config does not have to_dict or any other serializable object
|
|
192
204
|
prompt["tool_config"] = str(tool_config) # type: ignore
|
|
193
205
|
|
|
206
|
+
def _get_model_name(self, response: 'dict[str, Any]') -> Optional[str]:
|
|
207
|
+
model: Optional[str] = response.get("model_version", None)
|
|
208
|
+
if model:
|
|
209
|
+
return model
|
|
210
|
+
|
|
211
|
+
return self._model_name
|
|
212
|
+
|
|
194
213
|
@override
|
|
195
|
-
def process_chunk(self, chunk: Any) ->
|
|
214
|
+
def process_chunk(self, chunk: Any) -> _ChunkResult:
|
|
215
|
+
ingest = False
|
|
196
216
|
response_dict: dict[str, Any] = chunk.to_dict()
|
|
197
217
|
if "provider_response_id" not in self._ingest:
|
|
198
218
|
id = response_dict.get("response_id", None)
|
|
199
219
|
if id:
|
|
200
220
|
self._ingest["provider_response_id"] = id
|
|
201
221
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
222
|
+
if "resource" not in self._ingest:
|
|
223
|
+
model: Optional[str] = self._get_model_name(response_dict) # type: ignore[unreachable]
|
|
224
|
+
if model:
|
|
225
|
+
self._ingest["resource"] = "google." + model
|
|
205
226
|
|
|
206
227
|
for candidate in response_dict.get("candidates", []):
|
|
207
228
|
parts = candidate.get("content", {}).get("parts", [])
|
|
@@ -211,8 +232,9 @@ class _GoogleVertexRequest(_ProviderRequest):
|
|
|
211
232
|
usage = response_dict.get("usage_metadata", {})
|
|
212
233
|
if usage and "prompt_token_count" in usage and "candidates_token_count" in usage:
|
|
213
234
|
self._compute_usage(response_dict, streaming_candidates_characters=self._candiates_character_count)
|
|
235
|
+
ingest = True
|
|
214
236
|
|
|
215
|
-
return True
|
|
237
|
+
return _ChunkResult(send_chunk_to_caller=True, ingest=ingest)
|
|
216
238
|
|
|
217
239
|
@staticmethod
|
|
218
240
|
def _is_character_billing_model(model: str) -> bool:
|
|
@@ -230,7 +252,7 @@ class _GoogleVertexRequest(_ProviderRequest):
|
|
|
230
252
|
if id:
|
|
231
253
|
self._ingest["provider_response_id"] = id
|
|
232
254
|
|
|
233
|
-
model: Optional[str] =
|
|
255
|
+
model: Optional[str] = self._get_model_name(response_dict)
|
|
234
256
|
if model:
|
|
235
257
|
self._ingest["resource"] = "google." + model
|
|
236
258
|
|
|
@@ -256,7 +278,9 @@ class _GoogleVertexRequest(_ProviderRequest):
|
|
|
256
278
|
prompt_tokens_details: list[dict[str, Any]] = usage.get("prompt_tokens_details", [])
|
|
257
279
|
candidates_tokens_details: list[dict[str, Any]] = usage.get("candidates_tokens_details", [])
|
|
258
280
|
|
|
259
|
-
model: str =
|
|
281
|
+
model: Optional[str] = self._get_model_name(response_dict)
|
|
282
|
+
if not model:
|
|
283
|
+
model = ""
|
|
260
284
|
|
|
261
285
|
# for character billing only
|
|
262
286
|
large_context = "" if input < 128000 else "_large_context"
|
payi/lib/instrument.py
CHANGED
|
@@ -10,6 +10,7 @@ from abc import abstractmethod
|
|
|
10
10
|
from enum import Enum
|
|
11
11
|
from typing import Any, Set, Union, Callable, Optional, Sequence, TypedDict
|
|
12
12
|
from datetime import datetime, timezone
|
|
13
|
+
from dataclasses import dataclass
|
|
13
14
|
from typing_extensions import deprecated
|
|
14
15
|
|
|
15
16
|
import nest_asyncio # type: ignore
|
|
@@ -28,6 +29,11 @@ from .Stopwatch import Stopwatch
|
|
|
28
29
|
global _g_logger
|
|
29
30
|
_g_logger: logging.Logger = logging.getLogger("payi.instrument")
|
|
30
31
|
|
|
32
|
+
@dataclass
|
|
33
|
+
class _ChunkResult:
|
|
34
|
+
send_chunk_to_caller: bool
|
|
35
|
+
ingest: bool = False
|
|
36
|
+
|
|
31
37
|
class _ProviderRequest:
|
|
32
38
|
def __init__(self, instrumentor: '_PayiInstrumentor', category: str, streaming_type: '_StreamingType'):
|
|
33
39
|
self._instrumentor: '_PayiInstrumentor' = instrumentor
|
|
@@ -36,8 +42,8 @@ class _ProviderRequest:
|
|
|
36
42
|
self._ingest: IngestUnitsParams = { "category": category, "units": {} } # type: ignore
|
|
37
43
|
self._streaming_type: '_StreamingType' = streaming_type
|
|
38
44
|
|
|
39
|
-
def process_chunk(self, _chunk: Any) ->
|
|
40
|
-
return True
|
|
45
|
+
def process_chunk(self, _chunk: Any) -> _ChunkResult:
|
|
46
|
+
return _ChunkResult(send_chunk_to_caller=True)
|
|
41
47
|
|
|
42
48
|
def process_synchronous_response(self, response: Any, log_prompt_and_response: bool, kwargs: Any) -> Optional[object]: # noqa: ARG002
|
|
43
49
|
return None
|
|
@@ -275,8 +281,7 @@ class _PayiInstrumentor:
|
|
|
275
281
|
if int(ingest_units.get("http_status_code") or 0) < 400:
|
|
276
282
|
units = ingest_units.get("units", {})
|
|
277
283
|
if not units or all(unit.get("input", 0) == 0 and unit.get("output", 0) == 0 for unit in units.values()):
|
|
278
|
-
self._logger.
|
|
279
|
-
return False
|
|
284
|
+
self._logger.info('ingesting with no token counts')
|
|
280
285
|
|
|
281
286
|
if self._log_prompt_and_response and self._prompt_and_response_logger:
|
|
282
287
|
response_json = ingest_units.pop("provider_response_json", None)
|
|
@@ -341,7 +346,7 @@ class _PayiInstrumentor:
|
|
|
341
346
|
|
|
342
347
|
return ingest_response
|
|
343
348
|
except Exception as e:
|
|
344
|
-
self._logger.error(f"Error Pay-i ingesting
|
|
349
|
+
self._logger.error(f"Error Pay-i async ingesting: exception {e}, request {ingest_units}")
|
|
345
350
|
|
|
346
351
|
return None
|
|
347
352
|
|
|
@@ -413,7 +418,7 @@ class _PayiInstrumentor:
|
|
|
413
418
|
self._logger.error("No payi instance to ingest units")
|
|
414
419
|
|
|
415
420
|
except Exception as e:
|
|
416
|
-
self._logger.error(f"Error Pay-i ingesting
|
|
421
|
+
self._logger.error(f"Error Pay-i ingesting: exception {e}, request {ingest_units}")
|
|
417
422
|
|
|
418
423
|
return None
|
|
419
424
|
|
|
@@ -1105,6 +1110,8 @@ class _StreamIteratorWrapper(ObjectProxy): # type: ignore
|
|
|
1105
1110
|
self._first_token: bool = True
|
|
1106
1111
|
self._is_bedrock: bool = request.is_bedrock()
|
|
1107
1112
|
self._bedrock_from_stream: bool = bedrock_from_stream
|
|
1113
|
+
self._ingested: bool = False
|
|
1114
|
+
self._iter_started: bool = False
|
|
1108
1115
|
|
|
1109
1116
|
def __enter__(self) -> Any:
|
|
1110
1117
|
self._instrumentor._logger.debug(f"StreamIteratorWrapper: __enter__")
|
|
@@ -1123,6 +1130,7 @@ class _StreamIteratorWrapper(ObjectProxy): # type: ignore
|
|
|
1123
1130
|
await self.__wrapped__.__aexit__(exc_type, exc_val, exc_tb) # type: ignore
|
|
1124
1131
|
|
|
1125
1132
|
def __iter__(self) -> Any:
|
|
1133
|
+
self._iter_started = True
|
|
1126
1134
|
if self._is_bedrock:
|
|
1127
1135
|
# MUST reside in a separate function so that the yield statement (e.g. the generator) doesn't implicitly return its own iterator and overriding self
|
|
1128
1136
|
self._instrumentor._logger.debug(f"StreamIteratorWrapper: bedrock __iter__")
|
|
@@ -1134,13 +1142,19 @@ class _StreamIteratorWrapper(ObjectProxy): # type: ignore
|
|
|
1134
1142
|
def _iter_bedrock(self) -> Any:
|
|
1135
1143
|
# botocore EventStream doesn't have a __next__ method so iterate over the wrapped object in place
|
|
1136
1144
|
for event in self.__wrapped__: # type: ignore
|
|
1145
|
+
result: Optional[_ChunkResult] = None
|
|
1146
|
+
|
|
1137
1147
|
if (self._bedrock_from_stream):
|
|
1138
|
-
self._evaluate_chunk(event)
|
|
1148
|
+
result = self._evaluate_chunk(event)
|
|
1139
1149
|
else:
|
|
1140
1150
|
chunk = event.get('chunk') # type: ignore
|
|
1141
1151
|
if chunk:
|
|
1142
1152
|
decode = chunk.get('bytes').decode() # type: ignore
|
|
1143
|
-
self._evaluate_chunk(decode)
|
|
1153
|
+
result = self._evaluate_chunk(decode)
|
|
1154
|
+
|
|
1155
|
+
if result and result.ingest:
|
|
1156
|
+
self._stop_iteration()
|
|
1157
|
+
|
|
1144
1158
|
yield event
|
|
1145
1159
|
|
|
1146
1160
|
self._instrumentor._logger.debug(f"StreamIteratorWrapper: bedrock iter finished")
|
|
@@ -1148,40 +1162,60 @@ class _StreamIteratorWrapper(ObjectProxy): # type: ignore
|
|
|
1148
1162
|
self._stop_iteration()
|
|
1149
1163
|
|
|
1150
1164
|
def __aiter__(self) -> Any:
|
|
1165
|
+
self._iter_started = True
|
|
1151
1166
|
self._instrumentor._logger.debug(f"StreamIteratorWrapper: __aiter__")
|
|
1152
1167
|
return self
|
|
1153
1168
|
|
|
1154
1169
|
def __next__(self) -> object:
|
|
1155
1170
|
try:
|
|
1156
1171
|
chunk: object = self.__wrapped__.__next__() # type: ignore
|
|
1172
|
+
|
|
1173
|
+
if self._ingested:
|
|
1174
|
+
self._instrumentor._logger.debug(f"StreamIteratorWrapper: __next__ already ingested, not processing chunk {chunk}")
|
|
1175
|
+
return chunk # type: ignore
|
|
1176
|
+
|
|
1177
|
+
result = self._evaluate_chunk(chunk)
|
|
1178
|
+
|
|
1179
|
+
if result.ingest:
|
|
1180
|
+
self._stop_iteration()
|
|
1181
|
+
|
|
1182
|
+
if result.send_chunk_to_caller:
|
|
1183
|
+
return chunk # type: ignore
|
|
1184
|
+
else:
|
|
1185
|
+
return self.__next__()
|
|
1157
1186
|
except Exception as e:
|
|
1158
1187
|
if isinstance(e, StopIteration):
|
|
1159
1188
|
self._stop_iteration()
|
|
1160
1189
|
else:
|
|
1161
1190
|
self._instrumentor._logger.debug(f"StreamIteratorWrapper: __next__ exception {e}")
|
|
1162
1191
|
raise e
|
|
1163
|
-
else:
|
|
1164
|
-
if self._evaluate_chunk(chunk) == False:
|
|
1165
|
-
return self.__next__()
|
|
1166
|
-
|
|
1167
|
-
return chunk # type: ignore
|
|
1168
1192
|
|
|
1169
1193
|
async def __anext__(self) -> object:
|
|
1170
1194
|
try:
|
|
1171
1195
|
chunk: object = await self.__wrapped__.__anext__() # type: ignore
|
|
1196
|
+
|
|
1197
|
+
if self._ingested:
|
|
1198
|
+
self._instrumentor._logger.debug(f"StreamIteratorWrapper: __next__ already ingested, not processing chunk {chunk}")
|
|
1199
|
+
return chunk # type: ignore
|
|
1200
|
+
|
|
1201
|
+
result = self._evaluate_chunk(chunk)
|
|
1202
|
+
|
|
1203
|
+
if result.ingest:
|
|
1204
|
+
await self._astop_iteration()
|
|
1205
|
+
|
|
1206
|
+
if result.send_chunk_to_caller:
|
|
1207
|
+
return chunk # type: ignore
|
|
1208
|
+
else:
|
|
1209
|
+
return await self.__anext__()
|
|
1210
|
+
|
|
1172
1211
|
except Exception as e:
|
|
1173
1212
|
if isinstance(e, StopAsyncIteration):
|
|
1174
1213
|
await self._astop_iteration()
|
|
1175
1214
|
else:
|
|
1176
1215
|
self._instrumentor._logger.debug(f"StreamIteratorWrapper: __anext__ exception {e}")
|
|
1177
1216
|
raise e
|
|
1178
|
-
else:
|
|
1179
|
-
if self._evaluate_chunk(chunk) == False:
|
|
1180
|
-
return await self.__anext__()
|
|
1181
1217
|
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
def _evaluate_chunk(self, chunk: Any) -> bool:
|
|
1218
|
+
def _evaluate_chunk(self, chunk: Any) -> _ChunkResult:
|
|
1185
1219
|
if self._first_token:
|
|
1186
1220
|
self._request._ingest["time_to_first_token_ms"] = self._stopwatch.elapsed_ms_int()
|
|
1187
1221
|
self._first_token = False
|
|
@@ -1192,7 +1226,7 @@ class _StreamIteratorWrapper(ObjectProxy): # type: ignore
|
|
|
1192
1226
|
return self._request.process_chunk(chunk)
|
|
1193
1227
|
|
|
1194
1228
|
def _process_stop_iteration(self) -> None:
|
|
1195
|
-
self._instrumentor._logger.debug(f"StreamIteratorWrapper: stop iteration")
|
|
1229
|
+
self._instrumentor._logger.debug(f"StreamIteratorWrapper: process stop iteration")
|
|
1196
1230
|
|
|
1197
1231
|
self._stopwatch.stop()
|
|
1198
1232
|
self._request._ingest["end_to_end_latency_ms"] = self._stopwatch.elapsed_ms_int()
|
|
@@ -1202,12 +1236,23 @@ class _StreamIteratorWrapper(ObjectProxy): # type: ignore
|
|
|
1202
1236
|
self._request._ingest["provider_response_json"] = self._responses
|
|
1203
1237
|
|
|
1204
1238
|
async def _astop_iteration(self) -> None:
|
|
1239
|
+
if self._ingested:
|
|
1240
|
+
self._instrumentor._logger.debug(f"StreamIteratorWrapper: astop iteration already ingested, skipping")
|
|
1241
|
+
return
|
|
1242
|
+
|
|
1205
1243
|
self._process_stop_iteration()
|
|
1244
|
+
|
|
1206
1245
|
await self._instrumentor._aingest_units(self._request._ingest)
|
|
1246
|
+
self._ingested = True
|
|
1207
1247
|
|
|
1208
1248
|
def _stop_iteration(self) -> None:
|
|
1249
|
+
if self._ingested:
|
|
1250
|
+
self._instrumentor._logger.debug(f"StreamIteratorWrapper: stop iteration already ingested, skipping")
|
|
1251
|
+
return
|
|
1252
|
+
|
|
1209
1253
|
self._process_stop_iteration()
|
|
1210
1254
|
self._instrumentor._ingest_units(self._request._ingest)
|
|
1255
|
+
self._ingested = True
|
|
1211
1256
|
|
|
1212
1257
|
@staticmethod
|
|
1213
1258
|
def chunk_to_json(chunk: Any) -> str:
|
|
@@ -1241,7 +1286,6 @@ class _StreamManagerWrapper(ObjectProxy): # type: ignore
|
|
|
1241
1286
|
self._responses: list[str] = []
|
|
1242
1287
|
self._request: _ProviderRequest = request
|
|
1243
1288
|
self._first_token: bool = True
|
|
1244
|
-
self._done: bool = False
|
|
1245
1289
|
|
|
1246
1290
|
def __enter__(self) -> _StreamIteratorWrapper:
|
|
1247
1291
|
self._instrumentor._logger.debug(f"_StreamManagerWrapper: __enter__")
|
|
@@ -1275,92 +1319,103 @@ class _GeneratorWrapper: # type: ignore
|
|
|
1275
1319
|
self._responses: list[str] = []
|
|
1276
1320
|
self._request: _ProviderRequest = request
|
|
1277
1321
|
self._first_token: bool = True
|
|
1278
|
-
self.
|
|
1279
|
-
|
|
1322
|
+
self._ingested: bool = False
|
|
1323
|
+
self._iter_started: bool = False
|
|
1324
|
+
|
|
1280
1325
|
def __iter__(self) -> Any:
|
|
1326
|
+
self._iter_started = True
|
|
1281
1327
|
self._instrumentor._logger.debug(f"GeneratorWrapper: __iter__")
|
|
1282
1328
|
return self
|
|
1283
1329
|
|
|
1284
1330
|
def __aiter__(self) -> Any:
|
|
1285
1331
|
self._instrumentor._logger.debug(f"GeneratorWrapper: __aiter__")
|
|
1286
1332
|
return self
|
|
1287
|
-
|
|
1288
|
-
def
|
|
1289
|
-
if self.
|
|
1290
|
-
|
|
1333
|
+
|
|
1334
|
+
def _process_chunk(self, chunk: Any) -> _ChunkResult:
|
|
1335
|
+
if self._first_token:
|
|
1336
|
+
self._request._ingest["time_to_first_token_ms"] = self._stopwatch.elapsed_ms_int()
|
|
1337
|
+
self._first_token = False
|
|
1291
1338
|
|
|
1339
|
+
if self._log_prompt_and_response:
|
|
1340
|
+
dict = self._chunk_to_dict(chunk)
|
|
1341
|
+
self._responses.append(json.dumps(dict))
|
|
1342
|
+
|
|
1343
|
+
return self._request.process_chunk(chunk)
|
|
1344
|
+
|
|
1345
|
+
def __next__(self) -> Any:
|
|
1292
1346
|
try:
|
|
1293
1347
|
chunk = next(self._generator)
|
|
1294
|
-
|
|
1348
|
+
result = self._process_chunk(chunk)
|
|
1349
|
+
|
|
1350
|
+
if result.ingest:
|
|
1351
|
+
self._stop_iteration()
|
|
1352
|
+
|
|
1353
|
+
# ignore result.send_chunk_to_caller:
|
|
1354
|
+
return chunk
|
|
1295
1355
|
|
|
1296
1356
|
except Exception as e:
|
|
1297
1357
|
if isinstance(e, StopIteration):
|
|
1298
|
-
self.
|
|
1358
|
+
self._stop_iteration()
|
|
1299
1359
|
else:
|
|
1300
1360
|
self._instrumentor._logger.debug(f"GeneratorWrapper: __next__ exception {e}")
|
|
1301
1361
|
raise e
|
|
1302
1362
|
|
|
1303
1363
|
async def __anext__(self) -> Any:
|
|
1304
|
-
if self._done:
|
|
1305
|
-
raise StopAsyncIteration
|
|
1306
|
-
|
|
1307
1364
|
try:
|
|
1308
1365
|
chunk = await anext(self._generator) # type: ignore
|
|
1309
|
-
|
|
1366
|
+
result = self._process_chunk(chunk)
|
|
1367
|
+
|
|
1368
|
+
if result.ingest:
|
|
1369
|
+
await self._astop_iteration()
|
|
1370
|
+
|
|
1371
|
+
# ignore result.send_chunk_to_caller:
|
|
1372
|
+
return chunk # type: ignore
|
|
1310
1373
|
|
|
1311
1374
|
except Exception as e:
|
|
1312
1375
|
if isinstance(e, StopAsyncIteration):
|
|
1313
|
-
await self.
|
|
1376
|
+
await self._astop_iteration()
|
|
1314
1377
|
else:
|
|
1315
1378
|
self._instrumentor._logger.debug(f"GeneratorWrapper: __anext__ exception {e}")
|
|
1316
1379
|
raise e
|
|
1317
1380
|
|
|
1318
1381
|
@staticmethod
|
|
1319
1382
|
def _chunk_to_dict(chunk: Any) -> 'dict[str, object]':
|
|
1320
|
-
if hasattr(chunk, "
|
|
1321
|
-
return chunk.
|
|
1383
|
+
if hasattr(chunk, "to_dict"):
|
|
1384
|
+
return chunk.to_dict() # type: ignore
|
|
1322
1385
|
elif hasattr(chunk, "to_json_dict"):
|
|
1323
1386
|
return chunk.to_json_dict() # type: ignore
|
|
1324
1387
|
else:
|
|
1325
1388
|
return {}
|
|
1326
1389
|
|
|
1327
|
-
def
|
|
1328
|
-
if self.
|
|
1329
|
-
self.
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
if self._log_prompt_and_response:
|
|
1333
|
-
dict = self._chunk_to_dict(chunk)
|
|
1334
|
-
self._responses.append(json.dumps(dict))
|
|
1335
|
-
|
|
1336
|
-
self._request.process_chunk(chunk)
|
|
1337
|
-
return chunk
|
|
1390
|
+
def _stop_iteration(self) -> None:
|
|
1391
|
+
if self._ingested:
|
|
1392
|
+
self._instrumentor._logger.debug(f"GeneratorWrapper: stop iteration already ingested, skipping")
|
|
1393
|
+
return
|
|
1338
1394
|
|
|
1339
|
-
|
|
1340
|
-
self._instrumentor._logger.debug(f"GeneratorWrapper: stop iteration")
|
|
1395
|
+
self._process_stop_iteration()
|
|
1341
1396
|
|
|
1342
|
-
self._stopwatch.stop()
|
|
1343
|
-
self._request._ingest["end_to_end_latency_ms"] = self._stopwatch.elapsed_ms_int()
|
|
1344
|
-
self._request._ingest["http_status_code"] = 200
|
|
1345
|
-
|
|
1346
|
-
if self._log_prompt_and_response:
|
|
1347
|
-
self._request._ingest["provider_response_json"] = self._responses
|
|
1348
|
-
|
|
1349
1397
|
self._instrumentor._ingest_units(self._request._ingest)
|
|
1350
|
-
self.
|
|
1398
|
+
self._ingested = True
|
|
1351
1399
|
|
|
1352
|
-
async def
|
|
1353
|
-
self.
|
|
1400
|
+
async def _astop_iteration(self) -> None:
|
|
1401
|
+
if self._ingested:
|
|
1402
|
+
self._instrumentor._logger.debug(f"GeneratorWrapper: astop iteration already ingested, skipping")
|
|
1403
|
+
return
|
|
1404
|
+
|
|
1405
|
+
self._process_stop_iteration()
|
|
1354
1406
|
|
|
1355
|
-
self.
|
|
1407
|
+
await self._instrumentor._aingest_units(self._request._ingest)
|
|
1408
|
+
self._ingested = True
|
|
1409
|
+
|
|
1410
|
+
def _process_stop_iteration(self) -> None:
|
|
1411
|
+
self._instrumentor._logger.debug(f"GeneratorWrapper: stop iteration")
|
|
1412
|
+
|
|
1413
|
+
self._stopwatch.stop()
|
|
1356
1414
|
self._request._ingest["end_to_end_latency_ms"] = self._stopwatch.elapsed_ms_int()
|
|
1357
1415
|
self._request._ingest["http_status_code"] = 200
|
|
1358
1416
|
|
|
1359
1417
|
if self._log_prompt_and_response:
|
|
1360
1418
|
self._request._ingest["provider_response_json"] = self._responses
|
|
1361
|
-
|
|
1362
|
-
await self._instrumentor._aingest_units(self._request._ingest)
|
|
1363
|
-
self._done = True
|
|
1364
1419
|
|
|
1365
1420
|
global _instrumentor
|
|
1366
1421
|
_instrumentor: Optional[_PayiInstrumentor] = None
|
|
@@ -1630,4 +1685,4 @@ def proxy(
|
|
|
1630
1685
|
|
|
1631
1686
|
return _proxy_wrapper
|
|
1632
1687
|
|
|
1633
|
-
return _proxy
|
|
1688
|
+
return _proxy
|
|
@@ -11,7 +11,7 @@ payi/_resource.py,sha256=j2jIkTr8OIC8sU6-05nxSaCyj4MaFlbZrwlyg4_xJos,1088
|
|
|
11
11
|
payi/_response.py,sha256=rh9oJAvCKcPwQFm4iqH_iVrmK8bNx--YP_A2a4kN1OU,28776
|
|
12
12
|
payi/_streaming.py,sha256=Z_wIyo206T6Jqh2rolFg2VXZgX24PahLmpURp0-NssU,10092
|
|
13
13
|
payi/_types.py,sha256=7jE5MoQQFVoVxw5vVzvZ2Ao0kcjfNOGsBgyJfLBEnMo,6195
|
|
14
|
-
payi/_version.py,sha256=
|
|
14
|
+
payi/_version.py,sha256=xOYzE4HfPmVs-tN-N7yfhmNSvAgnTtRTnr0gUxo0tVg,165
|
|
15
15
|
payi/pagination.py,sha256=k2356QGPOUSjRF2vHpwLBdF6P-2vnQzFfRIJQAHGQ7A,1258
|
|
16
16
|
payi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
17
|
payi/_utils/__init__.py,sha256=PNZ_QJuzZEgyYXqkO1HVhGkj5IU9bglVUcw7H-Knjzw,2062
|
|
@@ -25,14 +25,14 @@ payi/_utils/_transform.py,sha256=n7kskEWz6o__aoNvhFoGVyDoalNe6mJwp-g7BWkdj88,156
|
|
|
25
25
|
payi/_utils/_typing.py,sha256=D0DbbNu8GnYQTSICnTSHDGsYXj8TcAKyhejb0XcnjtY,4602
|
|
26
26
|
payi/_utils/_utils.py,sha256=ts4CiiuNpFiGB6YMdkQRh2SZvYvsl7mAF-JWHCcLDf4,12312
|
|
27
27
|
payi/lib/.keep,sha256=wuNrz-5SXo3jJaJOJgz4vFHM41YH_g20F5cRQo0vLes,224
|
|
28
|
-
payi/lib/AnthropicInstrumentor.py,sha256=
|
|
29
|
-
payi/lib/BedrockInstrumentor.py,sha256=
|
|
30
|
-
payi/lib/GoogleGenAiInstrumentor.py,sha256=
|
|
31
|
-
payi/lib/OpenAIInstrumentor.py,sha256=
|
|
28
|
+
payi/lib/AnthropicInstrumentor.py,sha256=O48WQIK1WvjAz1lvIEYoqgnS-UmzKhb5becNpSjinbE,9515
|
|
29
|
+
payi/lib/BedrockInstrumentor.py,sha256=vtJoPsYJ8Re3ODe3onTPcq9nSblL7IBjnE811qhMkdU,15424
|
|
30
|
+
payi/lib/GoogleGenAiInstrumentor.py,sha256=ru2odN7aA66z_UGAHRpHsJ1dm5HbffQ0eFhcAHOqHR4,14610
|
|
31
|
+
payi/lib/OpenAIInstrumentor.py,sha256=FjIRlQk5t95ySspH0VXsBv7my_f-c6HluvReY2hRvmM,18852
|
|
32
32
|
payi/lib/Stopwatch.py,sha256=7OJlxvr2Jyb6Zr1LYCYKczRB7rDVKkIR7gc4YoleNdE,764
|
|
33
|
-
payi/lib/VertexInstrumentor.py,sha256=
|
|
33
|
+
payi/lib/VertexInstrumentor.py,sha256=lF1BcKKCQdHOMn563e1OdzeDfhjLhPyhZSyM3PycZjA,13881
|
|
34
34
|
payi/lib/helpers.py,sha256=K1KAfWrpPT1UUGNxspLe1lHzQjP3XV5Pkh9IU4pKMok,4624
|
|
35
|
-
payi/lib/instrument.py,sha256=
|
|
35
|
+
payi/lib/instrument.py,sha256=qgV6f-Z2Egl1WsjTDyxg-2Unx6iIizhV4DPi44qPEAY,66360
|
|
36
36
|
payi/resources/__init__.py,sha256=1rtrPLWbNt8oJGOp6nwPumKLJ-ftez0B6qwLFyfcoP4,2972
|
|
37
37
|
payi/resources/ingest.py,sha256=8HNHEyfgIyJNqCh0rOhO9msoc61-8IyifJ6AbxjCrDg,22612
|
|
38
38
|
payi/resources/categories/__init__.py,sha256=w5gMiPdBSzJA_qfoVtFBElaoe8wGf_O63R7R1Spr6Gk,1093
|
|
@@ -142,7 +142,7 @@ payi/types/use_cases/definitions/kpi_retrieve_response.py,sha256=uQXliSvS3k-yDYw
|
|
|
142
142
|
payi/types/use_cases/definitions/kpi_update_params.py,sha256=jbawdWAdMnsTWVH0qfQGb8W7_TXe3lq4zjSRu44d8p8,373
|
|
143
143
|
payi/types/use_cases/definitions/kpi_update_response.py,sha256=zLyEoT0S8d7XHsnXZYT8tM7yDw0Aze0Mk-_Z6QeMtc8,459
|
|
144
144
|
payi/types/use_cases/definitions/limit_config_create_params.py,sha256=pzQza_16N3z8cFNEKr6gPbFvuGFrwNuGxAYb--Kbo2M,449
|
|
145
|
-
payi-0.1.
|
|
146
|
-
payi-0.1.
|
|
147
|
-
payi-0.1.
|
|
148
|
-
payi-0.1.
|
|
145
|
+
payi-0.1.0a83.dist-info/METADATA,sha256=uY2n8H_NGmAxXXCm6a6yFC6HXxiuAl3I6RvYn5W2FcU,15180
|
|
146
|
+
payi-0.1.0a83.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
|
|
147
|
+
payi-0.1.0a83.dist-info/licenses/LICENSE,sha256=CQt03aM-P4a3Yg5qBg3JSLVoQS3smMyvx7tYg_6V7Gk,11334
|
|
148
|
+
payi-0.1.0a83.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|