paid-python 0.2.0__tar.gz → 0.3.0__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.
- {paid_python-0.2.0 → paid_python-0.3.0}/PKG-INFO +2 -1
- {paid_python-0.2.0 → paid_python-0.3.0}/pyproject.toml +2 -1
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/tracing/autoinstrumentation.py +26 -2
- paid_python-0.3.0/src/paid/tracing/context_data.py +60 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/tracing/context_manager.py +8 -35
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/tracing/distributed_tracing.py +3 -3
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/tracing/tracing.py +17 -41
- {paid_python-0.2.0 → paid_python-0.3.0}/LICENSE +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/README.md +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/__init__.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/agents/__init__.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/agents/client.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/agents/raw_client.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/client.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/contacts/__init__.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/contacts/client.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/contacts/raw_client.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/core/__init__.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/core/api_error.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/core/client_wrapper.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/core/datetime_utils.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/core/file.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/core/force_multipart.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/core/http_client.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/core/http_response.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/core/jsonable_encoder.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/core/pydantic_utilities.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/core/query_encoder.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/core/remove_none_from_dict.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/core/request_options.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/core/serialization.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/customers/__init__.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/customers/client.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/customers/raw_client.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/environment.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/errors/__init__.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/errors/bad_request_error.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/errors/forbidden_error.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/errors/not_found_error.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/logger.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/orders/__init__.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/orders/client.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/orders/lines/__init__.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/orders/lines/client.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/orders/lines/raw_client.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/orders/raw_client.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/py.typed +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/tracing/__init__.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/tracing/signal.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/tracing/wrappers/__init__.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/tracing/wrappers/anthropic/__init__.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/tracing/wrappers/anthropic/anthropicWrapper.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/tracing/wrappers/bedrock/__init__.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/tracing/wrappers/bedrock/bedrockWrapper.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/tracing/wrappers/gemini/__init__.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/tracing/wrappers/gemini/geminiWrapper.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/tracing/wrappers/langchain/__init__.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/tracing/wrappers/langchain/paidLangChainCallback.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/tracing/wrappers/llamaindex/__init__.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/tracing/wrappers/llamaindex/llamaIndexWrapper.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/tracing/wrappers/mistral/__init__.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/tracing/wrappers/mistral/mistralWrapper.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/tracing/wrappers/openai/__init__.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/tracing/wrappers/openai/openAiWrapper.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/tracing/wrappers/openai_agents/__init__.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/tracing/wrappers/openai_agents/openaiAgentsHook.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/tracing/wrappers/utils.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/__init__.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/address.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/agent.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/agent_attribute.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/agent_price_point.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/agent_price_point_tiers.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/agent_update.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/api_error.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/billing_frequency.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/charge_type.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/contact.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/cost_amount.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/cost_trace.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/cost_traces_response.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/creation_source.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/creation_state.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/customer.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/customer_update.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/entitlement_usage.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/error.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/order.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/order_line.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/order_line_attribute.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/order_line_attribute_create.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/order_line_attribute_pricing.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/order_line_create.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/pagination_meta.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/price_point.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/pricing.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/pricing_model_type.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/salutation.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/signal.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/tax_exempt_status.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/types/tier.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/usage/__init__.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/usage/client.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/usage/raw_client.py +0 -0
- {paid_python-0.2.0 → paid_python-0.3.0}/src/paid/version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: paid-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary:
|
|
5
5
|
Requires-Python: >=3.9,<3.14
|
|
6
6
|
Classifier: Intended Audience :: Developers
|
|
@@ -20,6 +20,7 @@ Classifier: Typing :: Typed
|
|
|
20
20
|
Requires-Dist: httpx (>=0.21.0)
|
|
21
21
|
Requires-Dist: mutagen (>=1.47.0)
|
|
22
22
|
Requires-Dist: openinference-instrumentation-bedrock (>=0.1.0)
|
|
23
|
+
Requires-Dist: openinference-instrumentation-google-genai (>=0.1.8)
|
|
23
24
|
Requires-Dist: openinference-instrumentation-openai-agents (>=1.0.0)
|
|
24
25
|
Requires-Dist: opentelemetry-api (>=1.23.0)
|
|
25
26
|
Requires-Dist: opentelemetry-exporter-otlp-proto-http (>=1.23.0)
|
|
@@ -3,7 +3,7 @@ name = "paid-python"
|
|
|
3
3
|
|
|
4
4
|
[tool.poetry]
|
|
5
5
|
name = "paid-python"
|
|
6
|
-
version = "0.
|
|
6
|
+
version = "0.3.0"
|
|
7
7
|
description = ""
|
|
8
8
|
readme = "README.md"
|
|
9
9
|
authors = []
|
|
@@ -49,6 +49,7 @@ opentelemetry-instrumentation-openai = ">=0.47.0"
|
|
|
49
49
|
opentelemetry-instrumentation-langchain = ">=0.47.0"
|
|
50
50
|
openinference-instrumentation-openai-agents = ">=1.0.0"
|
|
51
51
|
openinference-instrumentation-bedrock = ">=0.1.0"
|
|
52
|
+
openinference-instrumentation-google-genai = ">=0.1.8"
|
|
52
53
|
|
|
53
54
|
[tool.poetry.group.dev.dependencies]
|
|
54
55
|
mypy = "==1.13.0"
|
|
@@ -56,6 +56,13 @@ try:
|
|
|
56
56
|
except ImportError:
|
|
57
57
|
LANGCHAIN_AVAILABLE = False
|
|
58
58
|
|
|
59
|
+
try:
|
|
60
|
+
from openinference.instrumentation.google_genai import GoogleGenAIInstrumentor
|
|
61
|
+
|
|
62
|
+
GOOGLE_GENAI_AVAILABLE = True
|
|
63
|
+
except ImportError:
|
|
64
|
+
GOOGLE_GENAI_AVAILABLE = False
|
|
65
|
+
|
|
59
66
|
|
|
60
67
|
# Track which instrumentors have been initialized
|
|
61
68
|
_initialized_instrumentors: List[str] = []
|
|
@@ -77,6 +84,7 @@ def paid_autoinstrument(libraries: Optional[List[str]] = None) -> None:
|
|
|
77
84
|
- "openai-agents": OpenAI Agents SDK
|
|
78
85
|
- "bedrock": AWS Bedrock
|
|
79
86
|
- "langchain": LangChain library
|
|
87
|
+
- "google-genai": Google GenAI library
|
|
80
88
|
If None, all supported libraries that are installed will be instrumented.
|
|
81
89
|
|
|
82
90
|
Note:
|
|
@@ -106,7 +114,7 @@ def paid_autoinstrument(libraries: Optional[List[str]] = None) -> None:
|
|
|
106
114
|
|
|
107
115
|
# Default to all supported libraries if none specified
|
|
108
116
|
if libraries is None:
|
|
109
|
-
libraries = ["anthropic", "gemini", "openai", "openai-agents", "bedrock", "langchain"]
|
|
117
|
+
libraries = ["anthropic", "gemini", "openai", "openai-agents", "bedrock", "langchain", "google-genai"]
|
|
110
118
|
|
|
111
119
|
for library in libraries:
|
|
112
120
|
if library in _initialized_instrumentors:
|
|
@@ -125,6 +133,8 @@ def paid_autoinstrument(libraries: Optional[List[str]] = None) -> None:
|
|
|
125
133
|
_instrument_bedrock()
|
|
126
134
|
elif library == "langchain":
|
|
127
135
|
_instrument_langchain()
|
|
136
|
+
elif library == "google-genai":
|
|
137
|
+
_instrument_google_genai()
|
|
128
138
|
else:
|
|
129
139
|
logger.warning(
|
|
130
140
|
f"Unknown library '{library}' - supported libraries: anthropic, gemini, openai, openai-agents, bedrock, langchain"
|
|
@@ -217,7 +227,21 @@ def _instrument_langchain() -> None:
|
|
|
217
227
|
return
|
|
218
228
|
|
|
219
229
|
# Instrument LangChain with Paid's tracer provider
|
|
220
|
-
LangchainInstrumentor().instrument(tracer_provider=tracing.paid_tracer_provider)
|
|
230
|
+
LangchainInstrumentor(disable_trace_context_propagation=True).instrument(tracer_provider=tracing.paid_tracer_provider)
|
|
231
|
+
|
|
221
232
|
|
|
222
233
|
_initialized_instrumentors.append("langchain")
|
|
223
234
|
logger.info("LangChain auto-instrumentation enabled")
|
|
235
|
+
|
|
236
|
+
def _instrument_google_genai() -> None:
|
|
237
|
+
"""
|
|
238
|
+
Instrument Google GenAI using openinference-instrumentation-google-genai.
|
|
239
|
+
"""
|
|
240
|
+
if not GOOGLE_GENAI_AVAILABLE:
|
|
241
|
+
logger.warning("Google GenAI instrumentation library not available, skipping instrumentation")
|
|
242
|
+
return
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
GoogleGenAIInstrumentor().instrument(tracer_provider=tracing.paid_tracer_provider)
|
|
246
|
+
_initialized_instrumentors.append("google-genai")
|
|
247
|
+
logger.info("Google GenAI auto-instrumentation enabled")
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import contextvars
|
|
2
|
+
from typing import Any, Optional
|
|
3
|
+
|
|
4
|
+
from paid.logger import logger
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# this class is used like a namespace, it's not for instantiation
|
|
8
|
+
class ContextData:
|
|
9
|
+
_EXTERNAL_CUSTOMER_ID = contextvars.ContextVar[Optional[str]]("external_customer_id", default=None)
|
|
10
|
+
_EXTERNAL_AGENT_ID = contextvars.ContextVar[Optional[str]]("external_agent_id", default=None)
|
|
11
|
+
_TRACE_ID = contextvars.ContextVar[Optional[int]]("trace_id", default=None)
|
|
12
|
+
_STORE_PROMPT = contextvars.ContextVar[Optional[bool]]("store_prompt", default=False)
|
|
13
|
+
_USER_METADATA = contextvars.ContextVar[Optional[dict[str, Any]]]("user_metadata", default=None)
|
|
14
|
+
|
|
15
|
+
_context: dict[str, contextvars.ContextVar] = {
|
|
16
|
+
"external_customer_id": _EXTERNAL_CUSTOMER_ID,
|
|
17
|
+
"external_agent_id": _EXTERNAL_AGENT_ID,
|
|
18
|
+
"trace_id": _TRACE_ID,
|
|
19
|
+
"store_prompt": _STORE_PROMPT,
|
|
20
|
+
"user_metadata": _USER_METADATA,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
# Use ContextVar for reset tokens to avoid race conditions in async/concurrent scenarios
|
|
24
|
+
_reset_tokens: contextvars.ContextVar[Optional[dict[str, Any]]] = contextvars.ContextVar(
|
|
25
|
+
"reset_tokens", default=None
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
@classmethod
|
|
29
|
+
def _get_or_create_reset_tokens(cls) -> dict[str, Any]:
|
|
30
|
+
"""Get the reset tokens dict for this context, creating a new one if needed."""
|
|
31
|
+
reset_tokens = cls._reset_tokens.get()
|
|
32
|
+
if reset_tokens is None:
|
|
33
|
+
reset_tokens = {}
|
|
34
|
+
cls._reset_tokens.set(reset_tokens)
|
|
35
|
+
return reset_tokens
|
|
36
|
+
|
|
37
|
+
@classmethod
|
|
38
|
+
def get_context(cls) -> dict[str, Any]:
|
|
39
|
+
return {key: var.get() for key, var in cls._context.items()}
|
|
40
|
+
|
|
41
|
+
@classmethod
|
|
42
|
+
def get_context_key(cls, key: str) -> Any:
|
|
43
|
+
return cls._context[key].get() if key in cls._context else None
|
|
44
|
+
|
|
45
|
+
@classmethod
|
|
46
|
+
def set_context_key(cls, key: str, value: Any) -> None:
|
|
47
|
+
if key not in cls._context:
|
|
48
|
+
logger.warning(f"Invalid context key: {key}")
|
|
49
|
+
return
|
|
50
|
+
reset_token = cls._context[key].set(value)
|
|
51
|
+
reset_tokens = cls._get_or_create_reset_tokens()
|
|
52
|
+
reset_tokens[key] = reset_token
|
|
53
|
+
|
|
54
|
+
@classmethod
|
|
55
|
+
def reset_context(cls) -> None:
|
|
56
|
+
reset_tokens = cls._reset_tokens.get()
|
|
57
|
+
if reset_tokens:
|
|
58
|
+
for key, reset_token in reset_tokens.items():
|
|
59
|
+
cls._context[key].reset(reset_token)
|
|
60
|
+
reset_tokens.clear()
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
import contextvars
|
|
3
2
|
import functools
|
|
4
|
-
from typing import Any, Callable, Dict, Optional
|
|
3
|
+
from typing import Any, Callable, Dict, Optional
|
|
5
4
|
|
|
6
5
|
from . import distributed_tracing, tracing
|
|
6
|
+
from .context_data import ContextData
|
|
7
7
|
from .tracing import get_paid_tracer, get_token, initialize_tracing, trace_async_, trace_sync_
|
|
8
8
|
from opentelemetry import trace
|
|
9
9
|
from opentelemetry.context import Context
|
|
@@ -78,14 +78,6 @@ class paid_tracing:
|
|
|
78
78
|
self.metadata = metadata
|
|
79
79
|
self.span: Optional[Span] = None
|
|
80
80
|
self.span_ctx: Optional[Any] = None # Context manager for the span
|
|
81
|
-
self.reset_tokens: Optional[
|
|
82
|
-
Tuple[
|
|
83
|
-
contextvars.Token[Optional[str]], # external_customer_id
|
|
84
|
-
contextvars.Token[Optional[str]], # external_agent_id
|
|
85
|
-
contextvars.Token[Optional[bool]], # store_prompt
|
|
86
|
-
contextvars.Token[Optional[Dict[str, Any]]], # metadata
|
|
87
|
-
]
|
|
88
|
-
] = None
|
|
89
81
|
|
|
90
82
|
if not get_token():
|
|
91
83
|
initialize_tracing(None, self.collector_endpoint)
|
|
@@ -94,23 +86,15 @@ class paid_tracing:
|
|
|
94
86
|
"""Set up context variables and return OTEL context if needed."""
|
|
95
87
|
|
|
96
88
|
# Set context variables
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
# Store reset tokens for cleanup
|
|
103
|
-
self.reset_tokens = (
|
|
104
|
-
reset_customer_id_ctx_token,
|
|
105
|
-
reset_agent_id_ctx_token,
|
|
106
|
-
reset_store_prompt_ctx_token,
|
|
107
|
-
reset_user_metadata_ctx_token,
|
|
108
|
-
)
|
|
89
|
+
ContextData.set_context_key("external_customer_id", self.external_customer_id)
|
|
90
|
+
ContextData.set_context_key("external_agent_id", self.external_agent_id)
|
|
91
|
+
ContextData.set_context_key("store_prompt", self.store_prompt)
|
|
92
|
+
ContextData.set_context_key("user_metadata", self.metadata)
|
|
109
93
|
|
|
110
94
|
# Handle distributed tracing token
|
|
111
95
|
override_trace_id = self.tracing_token
|
|
112
96
|
if not override_trace_id:
|
|
113
|
-
override_trace_id =
|
|
97
|
+
override_trace_id = ContextData.get_context_key("trace_id")
|
|
114
98
|
|
|
115
99
|
ctx: Optional[Context] = None
|
|
116
100
|
if override_trace_id is not None:
|
|
@@ -126,18 +110,7 @@ class paid_tracing:
|
|
|
126
110
|
|
|
127
111
|
def _cleanup_context(self):
|
|
128
112
|
"""Reset all context variables."""
|
|
129
|
-
|
|
130
|
-
(
|
|
131
|
-
reset_customer_id_ctx_token,
|
|
132
|
-
reset_agent_id_ctx_token,
|
|
133
|
-
reset_store_prompt_ctx_token,
|
|
134
|
-
reset_user_metadata_ctx_token,
|
|
135
|
-
) = self.reset_tokens
|
|
136
|
-
tracing.paid_external_customer_id_var.reset(reset_customer_id_ctx_token)
|
|
137
|
-
tracing.paid_external_agent_id_var.reset(reset_agent_id_ctx_token)
|
|
138
|
-
tracing.paid_store_prompt_var.reset(reset_store_prompt_ctx_token)
|
|
139
|
-
tracing.paid_user_metadata_var.reset(reset_user_metadata_ctx_token)
|
|
140
|
-
self.reset_tokens = None
|
|
113
|
+
ContextData.reset_context()
|
|
141
114
|
|
|
142
115
|
# Context manager methods for sync
|
|
143
116
|
def __enter__(self):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import warnings
|
|
2
2
|
|
|
3
|
-
from . import
|
|
3
|
+
from .context_data import ContextData
|
|
4
4
|
from opentelemetry.sdk.trace.id_generator import RandomIdGenerator
|
|
5
5
|
|
|
6
6
|
otel_id_generator = RandomIdGenerator()
|
|
@@ -85,7 +85,7 @@ def set_tracing_token(token: int):
|
|
|
85
85
|
DeprecationWarning,
|
|
86
86
|
stacklevel=2,
|
|
87
87
|
)
|
|
88
|
-
|
|
88
|
+
ContextData.set_context_key("trace_id", token)
|
|
89
89
|
|
|
90
90
|
|
|
91
91
|
def unset_tracing_token():
|
|
@@ -110,4 +110,4 @@ def unset_tracing_token():
|
|
|
110
110
|
DeprecationWarning,
|
|
111
111
|
stacklevel=2,
|
|
112
112
|
)
|
|
113
|
-
|
|
113
|
+
ContextData.set_context_key("trace_id", None)
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# Initializing tracing for OTLP
|
|
2
2
|
import asyncio
|
|
3
3
|
import atexit
|
|
4
|
-
import contextvars
|
|
5
4
|
import os
|
|
6
5
|
import signal
|
|
7
6
|
from typing import Any, Awaitable, Callable, Dict, Optional, Tuple, TypeVar, Union
|
|
8
7
|
|
|
9
8
|
import dotenv
|
|
10
9
|
from . import distributed_tracing
|
|
10
|
+
from .context_data import ContextData
|
|
11
11
|
from opentelemetry import trace
|
|
12
12
|
from opentelemetry.context import Context
|
|
13
13
|
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
|
|
@@ -23,24 +23,6 @@ DEFAULT_COLLECTOR_ENDPOINT = (
|
|
|
23
23
|
os.environ.get("PAID_OTEL_COLLECTOR_ENDPOINT") or "https://collector.agentpaid.io:4318/v1/traces"
|
|
24
24
|
)
|
|
25
25
|
|
|
26
|
-
# Context variables for passing data to nested spans (e.g., in openAiWrapper)
|
|
27
|
-
paid_external_customer_id_var: contextvars.ContextVar[Optional[str]] = contextvars.ContextVar(
|
|
28
|
-
"paid_external_customer_id", default=None
|
|
29
|
-
)
|
|
30
|
-
paid_external_agent_id_var: contextvars.ContextVar[Optional[str]] = contextvars.ContextVar(
|
|
31
|
-
"paid_external_agent_id", default=None
|
|
32
|
-
)
|
|
33
|
-
# trace id storage (generated from token)
|
|
34
|
-
paid_trace_id_var: contextvars.ContextVar[Optional[int]] = contextvars.ContextVar("paid_trace_id", default=None)
|
|
35
|
-
# flag to enable storing prompt contents
|
|
36
|
-
paid_store_prompt_var: contextvars.ContextVar[Optional[bool]] = contextvars.ContextVar(
|
|
37
|
-
"paid_store_prompt", default=False
|
|
38
|
-
)
|
|
39
|
-
# user metadata
|
|
40
|
-
paid_user_metadata_var: contextvars.ContextVar[Optional[Dict[str, Any]]] = contextvars.ContextVar(
|
|
41
|
-
"paid_user_metadata", default=None
|
|
42
|
-
)
|
|
43
|
-
|
|
44
26
|
T = TypeVar("T")
|
|
45
27
|
|
|
46
28
|
|
|
@@ -102,15 +84,15 @@ class PaidSpanProcessor(SpanProcessor):
|
|
|
102
84
|
span.update_name(f"{self.SPAN_NAME_PREFIX}{span.name}")
|
|
103
85
|
|
|
104
86
|
# Add customer and agent IDs from context
|
|
105
|
-
customer_id =
|
|
87
|
+
customer_id = ContextData.get_context_key("external_customer_id")
|
|
106
88
|
if customer_id:
|
|
107
89
|
span.set_attribute("external_customer_id", customer_id)
|
|
108
90
|
|
|
109
|
-
agent_id =
|
|
91
|
+
agent_id = ContextData.get_context_key("external_agent_id")
|
|
110
92
|
if agent_id:
|
|
111
93
|
span.set_attribute("external_agent_id", agent_id)
|
|
112
94
|
|
|
113
|
-
metadata =
|
|
95
|
+
metadata = ContextData.get_context_key("user_metadata")
|
|
114
96
|
if metadata:
|
|
115
97
|
metadata_attributes: dict[str, Any] = {}
|
|
116
98
|
|
|
@@ -131,7 +113,7 @@ class PaidSpanProcessor(SpanProcessor):
|
|
|
131
113
|
|
|
132
114
|
def on_end(self, span: ReadableSpan) -> None:
|
|
133
115
|
"""Filter out prompt and response contents unless explicitly asked to store"""
|
|
134
|
-
store_prompt =
|
|
116
|
+
store_prompt = ContextData.get_context_key("store_prompt")
|
|
135
117
|
if store_prompt:
|
|
136
118
|
return
|
|
137
119
|
|
|
@@ -299,15 +281,15 @@ def trace_sync_(
|
|
|
299
281
|
kwargs = kwargs or {}
|
|
300
282
|
|
|
301
283
|
# Set context variables for access by nested spans
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
284
|
+
ContextData.set_context_key("external_customer_id", external_customer_id)
|
|
285
|
+
ContextData.set_context_key("external_agent_id", external_agent_id)
|
|
286
|
+
ContextData.set_context_key("store_prompt", store_prompt)
|
|
287
|
+
ContextData.set_context_key("user_metadata", metadata)
|
|
306
288
|
|
|
307
289
|
# If user set trace context manually
|
|
308
290
|
override_trace_id = tracing_token
|
|
309
291
|
if not override_trace_id:
|
|
310
|
-
override_trace_id =
|
|
292
|
+
override_trace_id = ContextData.get_context_key("trace_id")
|
|
311
293
|
ctx: Optional[Context] = None
|
|
312
294
|
if override_trace_id is not None:
|
|
313
295
|
span_context = SpanContext(
|
|
@@ -331,10 +313,7 @@ def trace_sync_(
|
|
|
331
313
|
span.set_status(Status(StatusCode.ERROR, str(error)))
|
|
332
314
|
raise
|
|
333
315
|
finally:
|
|
334
|
-
|
|
335
|
-
paid_external_agent_id_var.reset(reset_agent_id_ctx_token)
|
|
336
|
-
paid_store_prompt_var.reset(reset_store_prompt_ctx_token)
|
|
337
|
-
paid_user_metadata_var.reset(reset_user_metadata_ctx_token)
|
|
316
|
+
ContextData.reset_context()
|
|
338
317
|
|
|
339
318
|
|
|
340
319
|
async def trace_async_(
|
|
@@ -373,15 +352,15 @@ async def trace_async_(
|
|
|
373
352
|
kwargs = kwargs or {}
|
|
374
353
|
|
|
375
354
|
# Set context variables for access by nested spans
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
355
|
+
ContextData.set_context_key("external_customer_id", external_customer_id)
|
|
356
|
+
ContextData.set_context_key("external_agent_id", external_agent_id)
|
|
357
|
+
ContextData.set_context_key("store_prompt", store_prompt)
|
|
358
|
+
ContextData.set_context_key("user_metadata", metadata)
|
|
380
359
|
|
|
381
360
|
# If user set trace context manually
|
|
382
361
|
override_trace_id = tracing_token
|
|
383
362
|
if not override_trace_id:
|
|
384
|
-
override_trace_id =
|
|
363
|
+
override_trace_id = ContextData.get_context_key("trace_id")
|
|
385
364
|
ctx: Optional[Context] = None
|
|
386
365
|
if override_trace_id is not None:
|
|
387
366
|
span_context = SpanContext(
|
|
@@ -408,7 +387,4 @@ async def trace_async_(
|
|
|
408
387
|
span.set_status(Status(StatusCode.ERROR, str(error)))
|
|
409
388
|
raise
|
|
410
389
|
finally:
|
|
411
|
-
|
|
412
|
-
paid_external_agent_id_var.reset(reset_agent_id_ctx_token)
|
|
413
|
-
paid_store_prompt_var.reset(reset_store_prompt_ctx_token)
|
|
414
|
-
paid_user_metadata_var.reset(reset_user_metadata_ctx_token)
|
|
390
|
+
ContextData.reset_context()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{paid_python-0.2.0 → paid_python-0.3.0}/src/paid/tracing/wrappers/anthropic/anthropicWrapper.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{paid_python-0.2.0 → paid_python-0.3.0}/src/paid/tracing/wrappers/langchain/paidLangChainCallback.py
RENAMED
|
File without changes
|
|
File without changes
|
{paid_python-0.2.0 → paid_python-0.3.0}/src/paid/tracing/wrappers/llamaindex/llamaIndexWrapper.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{paid_python-0.2.0 → paid_python-0.3.0}/src/paid/tracing/wrappers/openai_agents/openaiAgentsHook.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|