payi 0.1.0a70__py3-none-any.whl → 0.1.0a71__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 +8 -6
- payi/lib/BedrockInstrumentor.py +8 -8
- payi/lib/OpenAIInstrumentor.py +11 -10
- payi/lib/VertexInstrumentor.py +313 -0
- payi/lib/helpers.py +1 -1
- payi/lib/instrument.py +190 -47
- payi/resources/ingest.py +55 -24
- payi/resources/limits/limits.py +0 -8
- payi/types/__init__.py +3 -0
- payi/types/bulk_ingest_response.py +3 -8
- payi/types/category_resource_response.py +2 -0
- payi/types/ingest_event_param.py +7 -10
- payi/types/ingest_response.py +2 -41
- payi/types/ingest_units_params.py +5 -2
- payi/types/limit_create_params.py +2 -2
- payi/types/requests/request_result.py +2 -42
- payi/types/shared/__init__.py +3 -0
- payi/types/shared/ingest_units.py +13 -0
- payi/types/shared/xproxy_error.py +13 -0
- payi/types/shared/xproxy_result.py +49 -0
- payi/types/shared_params/__init__.py +1 -0
- payi/types/shared_params/ingest_units.py +13 -0
- {payi-0.1.0a70.dist-info → payi-0.1.0a71.dist-info}/METADATA +1 -1
- {payi-0.1.0a70.dist-info → payi-0.1.0a71.dist-info}/RECORD +27 -22
- {payi-0.1.0a70.dist-info → payi-0.1.0a71.dist-info}/WHEEL +0 -0
- {payi-0.1.0a70.dist-info → payi-0.1.0a71.dist-info}/licenses/LICENSE +0 -0
payi/lib/instrument.py
CHANGED
|
@@ -4,11 +4,13 @@ import uuid
|
|
|
4
4
|
import asyncio
|
|
5
5
|
import inspect
|
|
6
6
|
import logging
|
|
7
|
+
import warnings
|
|
7
8
|
import traceback
|
|
8
9
|
from abc import abstractmethod
|
|
9
10
|
from enum import Enum
|
|
10
|
-
from typing import Any, Set, Union, Callable, Optional, TypedDict
|
|
11
|
+
from typing import Any, Set, Union, Callable, Optional, Sequence, TypedDict
|
|
11
12
|
from datetime import datetime, timezone
|
|
13
|
+
from typing_extensions import deprecated
|
|
12
14
|
|
|
13
15
|
import nest_asyncio # type: ignore
|
|
14
16
|
from wrapt import ObjectProxy # type: ignore
|
|
@@ -38,20 +40,26 @@ class _ProviderRequest:
|
|
|
38
40
|
return None
|
|
39
41
|
|
|
40
42
|
@abstractmethod
|
|
41
|
-
def process_request(self, instance: Any, extra_headers: 'dict[str, str]', kwargs: Any) -> bool:
|
|
43
|
+
def process_request(self, instance: Any, extra_headers: 'dict[str, str]', args: Sequence[Any], kwargs: Any) -> bool:
|
|
44
|
+
...
|
|
45
|
+
|
|
46
|
+
def process_request_prompt(self, prompt: 'dict[str, Any]', args: Sequence[Any], kwargs: 'dict[str, Any]') -> None:
|
|
42
47
|
...
|
|
43
48
|
|
|
44
49
|
def is_bedrock(self) -> bool:
|
|
45
50
|
return self._category == PayiCategories.aws_bedrock
|
|
46
|
-
|
|
51
|
+
|
|
52
|
+
def is_vertex(self) -> bool:
|
|
53
|
+
return self._category == PayiCategories.google_vertex
|
|
54
|
+
|
|
47
55
|
def process_exception(self, exception: Exception, kwargs: Any, ) -> bool: # noqa: ARG002
|
|
48
|
-
|
|
56
|
+
self.exception_to_semantic_failure(exception)
|
|
57
|
+
return True
|
|
49
58
|
|
|
50
59
|
def exception_to_semantic_failure(self, e: Exception) -> None:
|
|
51
60
|
exception_str = f"{type(e).__name__}"
|
|
52
61
|
|
|
53
62
|
fields: list[str] = []
|
|
54
|
-
# fields += f"args: {e.args}"
|
|
55
63
|
|
|
56
64
|
for attr in dir(e):
|
|
57
65
|
if not attr.startswith("__"):
|
|
@@ -76,8 +84,8 @@ class PayiInstrumentConfig(TypedDict, total=False):
|
|
|
76
84
|
proxy: bool
|
|
77
85
|
global_instrumentation: bool
|
|
78
86
|
limit_ids: Optional["list[str]"]
|
|
79
|
-
experience_name: Optional[str]
|
|
80
|
-
experience_id: Optional[str]
|
|
87
|
+
experience_name: Optional[str] = deprecated("experience_name is deprecated, use use_case_name instead") # type: ignore
|
|
88
|
+
experience_id: Optional[str] = deprecated("experience_id is deprecated, use use_case_id instead") # type: ignore
|
|
81
89
|
use_case_name: Optional[str]
|
|
82
90
|
use_case_id: Optional[str]
|
|
83
91
|
use_case_version: Optional[int]
|
|
@@ -163,11 +171,12 @@ class _PayiInstrumentor:
|
|
|
163
171
|
self._apayi = AsyncPayi()
|
|
164
172
|
|
|
165
173
|
if "use_case_name" not in global_config and caller_filename:
|
|
174
|
+
description = f"Default use case for {caller_filename}.py"
|
|
166
175
|
try:
|
|
167
176
|
if self._payi:
|
|
168
|
-
self._payi.use_cases.definitions.create(name=caller_filename, description=
|
|
177
|
+
self._payi.use_cases.definitions.create(name=caller_filename, description=description)
|
|
169
178
|
elif self._apayi:
|
|
170
|
-
self._call_async_use_case_definition_create(use_case_name=caller_filename)
|
|
179
|
+
self._call_async_use_case_definition_create(use_case_name=caller_filename, use_case_description=description)
|
|
171
180
|
global_config["use_case_name"] = caller_filename
|
|
172
181
|
except Exception as e:
|
|
173
182
|
logging.error(f"Error creating default use case definition based on file name {caller_filename}: {e}")
|
|
@@ -180,6 +189,7 @@ class _PayiInstrumentor:
|
|
|
180
189
|
self._instrument_openai()
|
|
181
190
|
self._instrument_anthropic()
|
|
182
191
|
self._instrument_aws_bedrock()
|
|
192
|
+
self._instrument_google_vertex()
|
|
183
193
|
|
|
184
194
|
def _instrument_specific(self, instruments: Set[str]) -> None:
|
|
185
195
|
if PayiCategories.openai in instruments or PayiCategories.azure_openai in instruments:
|
|
@@ -188,6 +198,8 @@ class _PayiInstrumentor:
|
|
|
188
198
|
self._instrument_anthropic()
|
|
189
199
|
if PayiCategories.aws_bedrock in instruments:
|
|
190
200
|
self._instrument_aws_bedrock()
|
|
201
|
+
if PayiCategories.google_vertex in instruments:
|
|
202
|
+
self._instrument_google_vertex()
|
|
191
203
|
|
|
192
204
|
def _instrument_openai(self) -> None:
|
|
193
205
|
from .OpenAIInstrumentor import OpenAiInstrumentor
|
|
@@ -216,6 +228,16 @@ class _PayiInstrumentor:
|
|
|
216
228
|
except Exception as e:
|
|
217
229
|
logging.error(f"Error instrumenting AWS bedrock: {e}")
|
|
218
230
|
|
|
231
|
+
def _instrument_google_vertex(self) -> None:
|
|
232
|
+
from .VertexInstrumentor import VertexInstrumentor
|
|
233
|
+
|
|
234
|
+
try:
|
|
235
|
+
VertexInstrumentor.instrument(self)
|
|
236
|
+
|
|
237
|
+
except Exception as e:
|
|
238
|
+
logging.error(f"Error instrumenting Google Vertex: {e}")
|
|
239
|
+
|
|
240
|
+
|
|
219
241
|
def _process_ingest_units(self, ingest_units: IngestUnitsParams, log_data: 'dict[str, str]') -> bool:
|
|
220
242
|
if int(ingest_units.get("http_status_code") or 0) < 400:
|
|
221
243
|
units = ingest_units.get("units", {})
|
|
@@ -285,7 +307,7 @@ class _PayiInstrumentor:
|
|
|
285
307
|
|
|
286
308
|
return None
|
|
287
309
|
|
|
288
|
-
def _call_async_use_case_definition_create(self, use_case_name: str) -> None:
|
|
310
|
+
def _call_async_use_case_definition_create(self, use_case_name: str, use_case_description: str) -> None:
|
|
289
311
|
if not self._apayi:
|
|
290
312
|
return
|
|
291
313
|
|
|
@@ -297,10 +319,10 @@ class _PayiInstrumentor:
|
|
|
297
319
|
try:
|
|
298
320
|
if loop and loop.is_running():
|
|
299
321
|
nest_asyncio.apply(loop) # type: ignore
|
|
300
|
-
asyncio.run(self._apayi.use_cases.definitions.create(name=use_case_name, description=
|
|
322
|
+
asyncio.run(self._apayi.use_cases.definitions.create(name=use_case_name, description=use_case_description))
|
|
301
323
|
else:
|
|
302
324
|
# When there's no running loop, create a new one
|
|
303
|
-
asyncio.run(self._apayi.use_cases.definitions.create(name=use_case_name, description=
|
|
325
|
+
asyncio.run(self._apayi.use_cases.definitions.create(name=use_case_name, description=use_case_description))
|
|
304
326
|
except Exception as e:
|
|
305
327
|
logging.error(f"Error calling async use_cases.definitions.create synchronously: {e}")
|
|
306
328
|
|
|
@@ -531,9 +553,10 @@ class _PayiInstrumentor:
|
|
|
531
553
|
|
|
532
554
|
def _prepare_ingest(
|
|
533
555
|
self,
|
|
534
|
-
|
|
556
|
+
request: _ProviderRequest,
|
|
535
557
|
ingest_extra_headers: "dict[str, str]", # do not coflict potential kwargs["extra_headers"]
|
|
536
|
-
|
|
558
|
+
args: Sequence[Any],
|
|
559
|
+
kwargs: 'dict[str, Any]',
|
|
537
560
|
) -> None:
|
|
538
561
|
limit_ids = ingest_extra_headers.pop(PayiHeaderNames.limit_ids, None)
|
|
539
562
|
request_tags = ingest_extra_headers.pop(PayiHeaderNames.request_tags, None)
|
|
@@ -545,24 +568,24 @@ class _PayiInstrumentor:
|
|
|
545
568
|
user_id = ingest_extra_headers.pop(PayiHeaderNames.user_id, None)
|
|
546
569
|
|
|
547
570
|
if limit_ids:
|
|
548
|
-
|
|
571
|
+
request._ingest["limit_ids"] = limit_ids.split(",")
|
|
549
572
|
if request_tags:
|
|
550
|
-
|
|
573
|
+
request._ingest["request_tags"] = request_tags.split(",")
|
|
551
574
|
if experience_name:
|
|
552
|
-
|
|
575
|
+
request._ingest["experience_name"] = experience_name
|
|
553
576
|
if experience_id:
|
|
554
|
-
|
|
577
|
+
request._ingest["experience_id"] = experience_id
|
|
555
578
|
if use_case_name:
|
|
556
|
-
|
|
579
|
+
request._ingest["use_case_name"] = use_case_name
|
|
557
580
|
if use_case_id:
|
|
558
|
-
|
|
581
|
+
request._ingest["use_case_id"] = use_case_id
|
|
559
582
|
if use_case_version:
|
|
560
|
-
|
|
583
|
+
request._ingest["use_case_version"] = int(use_case_version)
|
|
561
584
|
if user_id:
|
|
562
|
-
|
|
585
|
+
request._ingest["user_id"] = user_id
|
|
563
586
|
|
|
564
587
|
if len(ingest_extra_headers) > 0:
|
|
565
|
-
|
|
588
|
+
request._ingest["provider_request_headers"] = [PayICommonModelsAPIRouterHeaderInfoParam(name=k, value=v) for k, v in ingest_extra_headers.items()]
|
|
566
589
|
|
|
567
590
|
provider_prompt: "dict[str, Any]" = {}
|
|
568
591
|
for k, v in kwargs.items():
|
|
@@ -572,24 +595,29 @@ class _PayiInstrumentor:
|
|
|
572
595
|
pass
|
|
573
596
|
else:
|
|
574
597
|
try:
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
598
|
+
if hasattr(v, "to_dict"):
|
|
599
|
+
provider_prompt[k] = v.to_dict()
|
|
600
|
+
else:
|
|
601
|
+
json.dumps(v)
|
|
602
|
+
provider_prompt[k] = v
|
|
603
|
+
except Exception as _e:
|
|
578
604
|
pass
|
|
579
605
|
|
|
606
|
+
request.process_request_prompt(provider_prompt, args, kwargs)
|
|
607
|
+
|
|
580
608
|
if self._log_prompt_and_response:
|
|
581
|
-
|
|
609
|
+
request._ingest["provider_request_json"] = json.dumps(provider_prompt)
|
|
582
610
|
|
|
583
|
-
|
|
611
|
+
request._ingest["event_timestamp"] = datetime.now(timezone.utc)
|
|
584
612
|
|
|
585
|
-
async def
|
|
613
|
+
async def async_invoke_wrapper(
|
|
586
614
|
self,
|
|
587
615
|
request: _ProviderRequest,
|
|
588
616
|
is_streaming: _IsStreaming,
|
|
589
617
|
wrapped: Any,
|
|
590
618
|
instance: Any,
|
|
591
|
-
args: Any,
|
|
592
|
-
kwargs: Any,
|
|
619
|
+
args: Sequence[Any],
|
|
620
|
+
kwargs: 'dict[str, Any]',
|
|
593
621
|
) -> Any:
|
|
594
622
|
context = self.get_context()
|
|
595
623
|
|
|
@@ -615,7 +643,7 @@ class _PayiInstrumentor:
|
|
|
615
643
|
|
|
616
644
|
request._ingest['properties'] = { 'system.stack_trace': json.dumps(stack) }
|
|
617
645
|
|
|
618
|
-
if request.process_request(instance, extra_headers, kwargs) is False:
|
|
646
|
+
if request.process_request(instance, extra_headers, args, kwargs) is False:
|
|
619
647
|
return await wrapped(*args, **kwargs)
|
|
620
648
|
|
|
621
649
|
sw = Stopwatch()
|
|
@@ -629,7 +657,7 @@ class _PayiInstrumentor:
|
|
|
629
657
|
stream = False
|
|
630
658
|
|
|
631
659
|
try:
|
|
632
|
-
self._prepare_ingest(request
|
|
660
|
+
self._prepare_ingest(request, extra_headers, args, kwargs)
|
|
633
661
|
sw.start()
|
|
634
662
|
response = await wrapped(*args, **kwargs)
|
|
635
663
|
|
|
@@ -644,6 +672,15 @@ class _PayiInstrumentor:
|
|
|
644
672
|
raise e
|
|
645
673
|
|
|
646
674
|
if stream:
|
|
675
|
+
if request.is_vertex():
|
|
676
|
+
return _GeneratorWrapper(
|
|
677
|
+
generator=response,
|
|
678
|
+
instance=instance,
|
|
679
|
+
instrumentor=self,
|
|
680
|
+
stopwatch=sw,
|
|
681
|
+
request=request,
|
|
682
|
+
log_prompt_and_response=self._log_prompt_and_response)
|
|
683
|
+
|
|
647
684
|
stream_result = ChatStreamWrapper(
|
|
648
685
|
response=response,
|
|
649
686
|
instance=instance,
|
|
@@ -672,14 +709,14 @@ class _PayiInstrumentor:
|
|
|
672
709
|
|
|
673
710
|
return response
|
|
674
711
|
|
|
675
|
-
def
|
|
712
|
+
def invoke_wrapper(
|
|
676
713
|
self,
|
|
677
714
|
request: _ProviderRequest,
|
|
678
715
|
is_streaming: _IsStreaming,
|
|
679
716
|
wrapped: Any,
|
|
680
717
|
instance: Any,
|
|
681
|
-
args: Any,
|
|
682
|
-
kwargs: Any,
|
|
718
|
+
args: Sequence[Any],
|
|
719
|
+
kwargs: 'dict[str, Any]',
|
|
683
720
|
) -> Any:
|
|
684
721
|
context = self.get_context()
|
|
685
722
|
|
|
@@ -711,7 +748,7 @@ class _PayiInstrumentor:
|
|
|
711
748
|
|
|
712
749
|
request._ingest['properties'] = { 'system.stack_trace': json.dumps(stack) }
|
|
713
750
|
|
|
714
|
-
if request.process_request(instance, extra_headers, kwargs) is False:
|
|
751
|
+
if request.process_request(instance, extra_headers, args, kwargs) is False:
|
|
715
752
|
return wrapped(*args, **kwargs)
|
|
716
753
|
|
|
717
754
|
sw = Stopwatch()
|
|
@@ -725,10 +762,10 @@ class _PayiInstrumentor:
|
|
|
725
762
|
stream = False
|
|
726
763
|
|
|
727
764
|
try:
|
|
728
|
-
self._prepare_ingest(request
|
|
765
|
+
self._prepare_ingest(request, extra_headers, args, kwargs)
|
|
729
766
|
sw.start()
|
|
730
767
|
response = wrapped(*args, **kwargs)
|
|
731
|
-
|
|
768
|
+
|
|
732
769
|
except Exception as e: # pylint: disable=broad-except
|
|
733
770
|
sw.stop()
|
|
734
771
|
duration = sw.elapsed_ms_int()
|
|
@@ -740,6 +777,15 @@ class _PayiInstrumentor:
|
|
|
740
777
|
raise e
|
|
741
778
|
|
|
742
779
|
if stream:
|
|
780
|
+
if request.is_vertex():
|
|
781
|
+
return _GeneratorWrapper(
|
|
782
|
+
generator=response,
|
|
783
|
+
instance=instance,
|
|
784
|
+
instrumentor=self,
|
|
785
|
+
stopwatch=sw,
|
|
786
|
+
request=request,
|
|
787
|
+
log_prompt_and_response=self._log_prompt_and_response)
|
|
788
|
+
|
|
743
789
|
stream_result = ChatStreamWrapper(
|
|
744
790
|
response=response,
|
|
745
791
|
instance=instance,
|
|
@@ -1046,6 +1092,92 @@ class ChatStreamWrapper(ObjectProxy): # type: ignore
|
|
|
1046
1092
|
# assume dict
|
|
1047
1093
|
return json.dumps(chunk)
|
|
1048
1094
|
|
|
1095
|
+
class _GeneratorWrapper: # type: ignore
|
|
1096
|
+
def __init__(
|
|
1097
|
+
self,
|
|
1098
|
+
generator: Any,
|
|
1099
|
+
instance: Any,
|
|
1100
|
+
instrumentor: _PayiInstrumentor,
|
|
1101
|
+
stopwatch: Stopwatch,
|
|
1102
|
+
request: _ProviderRequest,
|
|
1103
|
+
log_prompt_and_response: bool = True,
|
|
1104
|
+
) -> None:
|
|
1105
|
+
super().__init__() # type: ignore
|
|
1106
|
+
|
|
1107
|
+
self._generator = generator
|
|
1108
|
+
self._instance = instance
|
|
1109
|
+
self._instrumentor = instrumentor
|
|
1110
|
+
self._stopwatch: Stopwatch = stopwatch
|
|
1111
|
+
self._log_prompt_and_response: bool = log_prompt_and_response
|
|
1112
|
+
self._responses: list[str] = []
|
|
1113
|
+
self._request: _ProviderRequest = request
|
|
1114
|
+
self._first_token: bool = True
|
|
1115
|
+
self._done: bool = False
|
|
1116
|
+
|
|
1117
|
+
def __iter__(self) -> Any:
|
|
1118
|
+
return self
|
|
1119
|
+
|
|
1120
|
+
def __aiter__(self) -> Any:
|
|
1121
|
+
return self
|
|
1122
|
+
|
|
1123
|
+
def __next__(self) -> Any:
|
|
1124
|
+
if self._done:
|
|
1125
|
+
raise StopIteration
|
|
1126
|
+
|
|
1127
|
+
try:
|
|
1128
|
+
chunk = next(self._generator)
|
|
1129
|
+
return self._process_chunk(chunk)
|
|
1130
|
+
|
|
1131
|
+
except StopIteration as stop_exception:
|
|
1132
|
+
self._process_stop_iteration()
|
|
1133
|
+
raise stop_exception
|
|
1134
|
+
|
|
1135
|
+
async def __anext__(self) -> Any:
|
|
1136
|
+
if self._done:
|
|
1137
|
+
raise StopAsyncIteration
|
|
1138
|
+
|
|
1139
|
+
try:
|
|
1140
|
+
chunk = await anext(self._generator) # type: ignore
|
|
1141
|
+
return self._process_chunk(chunk)
|
|
1142
|
+
|
|
1143
|
+
except StopAsyncIteration as stop_exception:
|
|
1144
|
+
await self._process_async_stop_iteration()
|
|
1145
|
+
raise stop_exception
|
|
1146
|
+
|
|
1147
|
+
def _process_chunk(self, chunk: Any) -> Any:
|
|
1148
|
+
if self._first_token:
|
|
1149
|
+
self._request._ingest["time_to_first_token_ms"] = self._stopwatch.elapsed_ms_int()
|
|
1150
|
+
self._first_token = False
|
|
1151
|
+
|
|
1152
|
+
if self._log_prompt_and_response:
|
|
1153
|
+
dict = chunk.to_dict() # type: ignore
|
|
1154
|
+
self._responses.append(json.dumps(dict))
|
|
1155
|
+
|
|
1156
|
+
self._request.process_chunk(chunk)
|
|
1157
|
+
return chunk
|
|
1158
|
+
|
|
1159
|
+
def _process_stop_iteration(self) -> None:
|
|
1160
|
+
self._stopwatch.stop()
|
|
1161
|
+
self._request._ingest["end_to_end_latency_ms"] = self._stopwatch.elapsed_ms_int()
|
|
1162
|
+
self._request._ingest["http_status_code"] = 200
|
|
1163
|
+
|
|
1164
|
+
if self._log_prompt_and_response:
|
|
1165
|
+
self._request._ingest["provider_response_json"] = self._responses
|
|
1166
|
+
|
|
1167
|
+
self._instrumentor._ingest_units(self._request._ingest)
|
|
1168
|
+
self._done = True
|
|
1169
|
+
|
|
1170
|
+
async def _process_async_stop_iteration(self) -> None:
|
|
1171
|
+
self._stopwatch.stop()
|
|
1172
|
+
self._request._ingest["end_to_end_latency_ms"] = self._stopwatch.elapsed_ms_int()
|
|
1173
|
+
self._request._ingest["http_status_code"] = 200
|
|
1174
|
+
|
|
1175
|
+
if self._log_prompt_and_response:
|
|
1176
|
+
self._request._ingest["provider_response_json"] = self._responses
|
|
1177
|
+
|
|
1178
|
+
await self._instrumentor._aingest_units(self._request._ingest)
|
|
1179
|
+
self._done = True
|
|
1180
|
+
|
|
1049
1181
|
global _instrumentor
|
|
1050
1182
|
_instrumentor: Optional[_PayiInstrumentor] = None
|
|
1051
1183
|
|
|
@@ -1057,7 +1189,7 @@ def payi_instrument(
|
|
|
1057
1189
|
config: Optional[PayiInstrumentConfig] = None,
|
|
1058
1190
|
) -> None:
|
|
1059
1191
|
global _instrumentor
|
|
1060
|
-
if _instrumentor:
|
|
1192
|
+
if (_instrumentor):
|
|
1061
1193
|
return
|
|
1062
1194
|
|
|
1063
1195
|
payi_param: Optional[Payi] = None
|
|
@@ -1141,8 +1273,6 @@ def track(
|
|
|
1141
1273
|
|
|
1142
1274
|
def track_context(
|
|
1143
1275
|
limit_ids: Optional["list[str]"] = None,
|
|
1144
|
-
experience_name: Optional[str] = None,
|
|
1145
|
-
experience_id: Optional[str] = None,
|
|
1146
1276
|
use_case_name: Optional[str] = None,
|
|
1147
1277
|
use_case_id: Optional[str] = None,
|
|
1148
1278
|
use_case_version: Optional[int] = None,
|
|
@@ -1152,14 +1282,9 @@ def track_context(
|
|
|
1152
1282
|
resource_scope: Optional[str] = None,
|
|
1153
1283
|
proxy: Optional[bool] = None,
|
|
1154
1284
|
) -> _TrackContext:
|
|
1155
|
-
if not _instrumentor:
|
|
1156
|
-
raise RuntimeError("Pay-i instrumentor not initialized. Use payi_instrument() to initialize.")
|
|
1157
|
-
|
|
1158
1285
|
# Create a new context for tracking
|
|
1159
1286
|
context: _Context = {}
|
|
1160
1287
|
context["limit_ids"] = limit_ids
|
|
1161
|
-
context["experience_name"] = experience_name
|
|
1162
|
-
context["experience_id"] = experience_id
|
|
1163
1288
|
context["use_case_name"] = use_case_name
|
|
1164
1289
|
context["use_case_id"] = use_case_id
|
|
1165
1290
|
context["use_case_version"] = use_case_version
|
|
@@ -1171,6 +1296,8 @@ def track_context(
|
|
|
1171
1296
|
|
|
1172
1297
|
return _TrackContext(context)
|
|
1173
1298
|
|
|
1299
|
+
|
|
1300
|
+
@deprecated("@ingest() is deprecated. Use @track() instead")
|
|
1174
1301
|
def ingest(
|
|
1175
1302
|
limit_ids: Optional["list[str]"] = None,
|
|
1176
1303
|
experience_name: Optional[str] = None,
|
|
@@ -1180,6 +1307,13 @@ def ingest(
|
|
|
1180
1307
|
use_case_version: Optional[int] = None,
|
|
1181
1308
|
user_id: Optional[str] = None,
|
|
1182
1309
|
) -> Any:
|
|
1310
|
+
warnings.warn(
|
|
1311
|
+
"@ingest is deprecated and will be removed in a future version. Use @track instead.",
|
|
1312
|
+
DeprecationWarning,
|
|
1313
|
+
stacklevel=2
|
|
1314
|
+
|
|
1315
|
+
)
|
|
1316
|
+
|
|
1183
1317
|
def _ingest(func: Any) -> Any:
|
|
1184
1318
|
import asyncio
|
|
1185
1319
|
if asyncio.iscoroutinefunction(func):
|
|
@@ -1219,8 +1353,10 @@ def ingest(
|
|
|
1219
1353
|
**kwargs,
|
|
1220
1354
|
)
|
|
1221
1355
|
return wrapper
|
|
1356
|
+
|
|
1222
1357
|
return _ingest
|
|
1223
1358
|
|
|
1359
|
+
@deprecated("@proxy() is deprecated. Use @track() instead")
|
|
1224
1360
|
def proxy(
|
|
1225
1361
|
limit_ids: Optional["list[str]"] = None,
|
|
1226
1362
|
experience_name: Optional[str] = None,
|
|
@@ -1230,6 +1366,13 @@ def proxy(
|
|
|
1230
1366
|
use_case_version: Optional[int] = None,
|
|
1231
1367
|
user_id: Optional[str] = None,
|
|
1232
1368
|
) -> Any:
|
|
1369
|
+
warnings.warn(
|
|
1370
|
+
"@proxy is deprecated and will be removed in a future version. Use @track instead.",
|
|
1371
|
+
DeprecationWarning,
|
|
1372
|
+
stacklevel=2
|
|
1373
|
+
|
|
1374
|
+
)
|
|
1375
|
+
|
|
1233
1376
|
def _proxy(func: Any) -> Any:
|
|
1234
1377
|
import asyncio
|
|
1235
1378
|
if asyncio.iscoroutinefunction(func):
|
payi/resources/ingest.py
CHANGED
|
@@ -7,6 +7,8 @@ from datetime import datetime
|
|
|
7
7
|
|
|
8
8
|
import httpx
|
|
9
9
|
|
|
10
|
+
from payi._utils._utils import is_given
|
|
11
|
+
|
|
10
12
|
from ..types import ingest_units_params
|
|
11
13
|
from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven
|
|
12
14
|
from .._utils import maybe_transform, strip_not_given, async_maybe_transform
|
|
@@ -22,6 +24,7 @@ from .._base_client import make_request_options
|
|
|
22
24
|
from ..types.ingest_response import IngestResponse
|
|
23
25
|
from ..types.ingest_event_param import IngestEventParam
|
|
24
26
|
from ..types.bulk_ingest_response import BulkIngestResponse
|
|
27
|
+
from ..types.shared_params.ingest_units import IngestUnits
|
|
25
28
|
from ..types.pay_i_common_models_api_router_header_info_param import PayICommonModelsAPIRouterHeaderInfoParam
|
|
26
29
|
|
|
27
30
|
__all__ = ["IngestResource", "AsyncIngestResource"]
|
|
@@ -84,7 +87,7 @@ class IngestResource(SyncAPIResource):
|
|
|
84
87
|
*,
|
|
85
88
|
category: str,
|
|
86
89
|
resource: str,
|
|
87
|
-
units: Dict[str,
|
|
90
|
+
units: Dict[str, IngestUnits],
|
|
88
91
|
end_to_end_latency_ms: Optional[int] | NotGiven = NOT_GIVEN,
|
|
89
92
|
event_timestamp: Union[str, datetime, None] | NotGiven = NOT_GIVEN,
|
|
90
93
|
experience_properties: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN,
|
|
@@ -104,6 +107,7 @@ class IngestResource(SyncAPIResource):
|
|
|
104
107
|
experience_name: Optional[str] | NotGiven = NOT_GIVEN,
|
|
105
108
|
use_case_id: Optional[str] | NotGiven = NOT_GIVEN,
|
|
106
109
|
use_case_name: Optional[str] | NotGiven = NOT_GIVEN,
|
|
110
|
+
use_case_step: Optional[str] | NotGiven = NOT_GIVEN,
|
|
107
111
|
use_case_version: Optional[int] | NotGiven = NOT_GIVEN,
|
|
108
112
|
user_id: Optional[str] | NotGiven = NOT_GIVEN,
|
|
109
113
|
resource_scope: Optional[str] | NotGiven = NOT_GIVEN,
|
|
@@ -140,6 +144,8 @@ class IngestResource(SyncAPIResource):
|
|
|
140
144
|
|
|
141
145
|
use_case_id (str, optional): The use case instance id
|
|
142
146
|
|
|
147
|
+
use_case_step (str, optional): The use case step
|
|
148
|
+
|
|
143
149
|
use_case_version (int, optional): The use case instance version
|
|
144
150
|
|
|
145
151
|
user_id (str, optional): The user id
|
|
@@ -184,6 +190,9 @@ class IngestResource(SyncAPIResource):
|
|
|
184
190
|
|
|
185
191
|
if use_case_name is None or isinstance(use_case_name, NotGiven):
|
|
186
192
|
use_case_name = NOT_GIVEN
|
|
193
|
+
|
|
194
|
+
if use_case_step is None or isinstance(use_case_step, NotGiven):
|
|
195
|
+
use_case_step = NOT_GIVEN
|
|
187
196
|
|
|
188
197
|
if use_case_id is None or isinstance(use_case_id, NotGiven):
|
|
189
198
|
use_case_id = NOT_GIVEN
|
|
@@ -196,18 +205,26 @@ class IngestResource(SyncAPIResource):
|
|
|
196
205
|
if user_id is None or isinstance(user_id, NotGiven):
|
|
197
206
|
user_id = NOT_GIVEN
|
|
198
207
|
|
|
208
|
+
if resource_scope is None or isinstance(resource_scope, NotGiven):
|
|
209
|
+
resource_scope = NOT_GIVEN
|
|
210
|
+
|
|
199
211
|
extra_headers = {
|
|
200
|
-
**
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
212
|
+
**strip_not_given(
|
|
213
|
+
{
|
|
214
|
+
"xProxy-Experience-ID": experience_id,
|
|
215
|
+
"xProxy-Experience-Name": experience_name,
|
|
216
|
+
"xProxy-Limit-IDs": valid_ids_str,
|
|
217
|
+
"xProxy-Request-Tags": valid_tags_str,
|
|
218
|
+
"xProxy-UseCase-ID": use_case_id,
|
|
219
|
+
"xProxy-UseCase-Name": use_case_name,
|
|
220
|
+
"xProxy-UseCase-Step": use_case_step,
|
|
221
|
+
"xProxy-UseCase-Version": use_case_version_str
|
|
222
|
+
if is_given(use_case_version)
|
|
223
|
+
else NOT_GIVEN,
|
|
224
|
+
"xProxy-User-ID": user_id,
|
|
225
|
+
"xProxy-Resource-Scope": resource_scope,
|
|
226
|
+
}
|
|
227
|
+
),
|
|
211
228
|
**(extra_headers or {}),
|
|
212
229
|
}
|
|
213
230
|
|
|
@@ -298,7 +315,7 @@ class AsyncIngestResource(AsyncAPIResource):
|
|
|
298
315
|
*,
|
|
299
316
|
category: str,
|
|
300
317
|
resource: str,
|
|
301
|
-
units: Dict[str,
|
|
318
|
+
units: Dict[str, IngestUnits],
|
|
302
319
|
end_to_end_latency_ms: Optional[int] | NotGiven = NOT_GIVEN,
|
|
303
320
|
event_timestamp: Union[str, datetime, None] | NotGiven = NOT_GIVEN,
|
|
304
321
|
experience_properties: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN,
|
|
@@ -318,6 +335,7 @@ class AsyncIngestResource(AsyncAPIResource):
|
|
|
318
335
|
experience_id: Optional[str] | NotGiven = NOT_GIVEN,
|
|
319
336
|
use_case_id: Optional[str] | NotGiven = NOT_GIVEN,
|
|
320
337
|
use_case_name: Optional[str] | NotGiven = NOT_GIVEN,
|
|
338
|
+
use_case_step: Optional[str] | NotGiven = NOT_GIVEN,
|
|
321
339
|
use_case_version: Optional[int] | NotGiven = NOT_GIVEN,
|
|
322
340
|
user_id: Optional[str] | NotGiven = NOT_GIVEN,
|
|
323
341
|
resource_scope: Union[str, None] | NotGiven = NOT_GIVEN,
|
|
@@ -351,6 +369,8 @@ class AsyncIngestResource(AsyncAPIResource):
|
|
|
351
369
|
|
|
352
370
|
use_case_name (str, optional): The use case name
|
|
353
371
|
|
|
372
|
+
use_case_step (str, optional): The use case step
|
|
373
|
+
|
|
354
374
|
use_case_id (str, optional): The use case instance id
|
|
355
375
|
|
|
356
376
|
use_case_version (int, optional): The use case instance version
|
|
@@ -398,6 +418,9 @@ class AsyncIngestResource(AsyncAPIResource):
|
|
|
398
418
|
if use_case_name is None or isinstance(use_case_name, NotGiven):
|
|
399
419
|
use_case_name = NOT_GIVEN
|
|
400
420
|
|
|
421
|
+
if use_case_step is None or isinstance(use_case_step, NotGiven):
|
|
422
|
+
use_case_step = NOT_GIVEN
|
|
423
|
+
|
|
401
424
|
if use_case_id is None or isinstance(use_case_id, NotGiven):
|
|
402
425
|
use_case_id = NOT_GIVEN
|
|
403
426
|
|
|
@@ -409,18 +432,26 @@ class AsyncIngestResource(AsyncAPIResource):
|
|
|
409
432
|
if user_id is None or isinstance(user_id, NotGiven):
|
|
410
433
|
user_id = NOT_GIVEN
|
|
411
434
|
|
|
435
|
+
if resource_scope is None or isinstance(resource_scope, NotGiven):
|
|
436
|
+
resource_scope = NOT_GIVEN
|
|
437
|
+
|
|
412
438
|
extra_headers = {
|
|
413
|
-
**
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
439
|
+
**strip_not_given(
|
|
440
|
+
{
|
|
441
|
+
"xProxy-Experience-ID": experience_id,
|
|
442
|
+
"xProxy-Experience-Name": experience_name,
|
|
443
|
+
"xProxy-Limit-IDs": valid_ids_str,
|
|
444
|
+
"xProxy-Request-Tags": valid_tags_str,
|
|
445
|
+
"xProxy-UseCase-ID": use_case_id,
|
|
446
|
+
"xProxy-UseCase-Name": use_case_name,
|
|
447
|
+
"xProxy-UseCase-Step": use_case_step,
|
|
448
|
+
"xProxy-UseCase-Version": use_case_version_str
|
|
449
|
+
if is_given(use_case_version)
|
|
450
|
+
else NOT_GIVEN,
|
|
451
|
+
"xProxy-User-ID": user_id,
|
|
452
|
+
"xProxy-Resource-Scope": resource_scope,
|
|
453
|
+
}
|
|
454
|
+
),
|
|
424
455
|
**(extra_headers or {}),
|
|
425
456
|
}
|
|
426
457
|
return await self._post(
|
payi/resources/limits/limits.py
CHANGED
|
@@ -66,8 +66,6 @@ class LimitsResource(SyncAPIResource):
|
|
|
66
66
|
*,
|
|
67
67
|
limit_name: str,
|
|
68
68
|
max: float,
|
|
69
|
-
billing_model_id: Optional[str] | NotGiven = NOT_GIVEN,
|
|
70
|
-
limit_basis: Literal["base", "billed"] | NotGiven = NOT_GIVEN,
|
|
71
69
|
limit_tags: Optional[List[str]] | NotGiven = NOT_GIVEN,
|
|
72
70
|
limit_type: Literal["block", "allow"] | NotGiven = NOT_GIVEN,
|
|
73
71
|
threshold: Optional[float] | NotGiven = NOT_GIVEN,
|
|
@@ -96,8 +94,6 @@ class LimitsResource(SyncAPIResource):
|
|
|
96
94
|
{
|
|
97
95
|
"limit_name": limit_name,
|
|
98
96
|
"max": max,
|
|
99
|
-
"billing_model_id": billing_model_id,
|
|
100
|
-
"limit_basis": limit_basis,
|
|
101
97
|
"limit_tags": limit_tags,
|
|
102
98
|
"limit_type": limit_type,
|
|
103
99
|
"threshold": threshold,
|
|
@@ -335,8 +331,6 @@ class AsyncLimitsResource(AsyncAPIResource):
|
|
|
335
331
|
*,
|
|
336
332
|
limit_name: str,
|
|
337
333
|
max: float,
|
|
338
|
-
billing_model_id: Optional[str] | NotGiven = NOT_GIVEN,
|
|
339
|
-
limit_basis: Literal["base", "billed"] | NotGiven = NOT_GIVEN,
|
|
340
334
|
limit_tags: Optional[List[str]] | NotGiven = NOT_GIVEN,
|
|
341
335
|
limit_type: Literal["block", "allow"] | NotGiven = NOT_GIVEN,
|
|
342
336
|
threshold: Optional[float] | NotGiven = NOT_GIVEN,
|
|
@@ -365,8 +359,6 @@ class AsyncLimitsResource(AsyncAPIResource):
|
|
|
365
359
|
{
|
|
366
360
|
"limit_name": limit_name,
|
|
367
361
|
"max": max,
|
|
368
|
-
"billing_model_id": billing_model_id,
|
|
369
|
-
"limit_basis": limit_basis,
|
|
370
362
|
"limit_tags": limit_tags,
|
|
371
363
|
"limit_type": limit_type,
|
|
372
364
|
"threshold": threshold,
|
payi/types/__init__.py
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from .shared import (
|
|
6
|
+
IngestUnits as IngestUnits,
|
|
7
|
+
XproxyError as XproxyError,
|
|
8
|
+
XproxyResult as XproxyResult,
|
|
6
9
|
PropertiesResponse as PropertiesResponse,
|
|
7
10
|
PayICommonModelsBudgetManagementCostDetailsBase as PayICommonModelsBudgetManagementCostDetailsBase,
|
|
8
11
|
PayICommonModelsBudgetManagementCreateLimitBase as PayICommonModelsBudgetManagementCreateLimitBase,
|