sentry-sdk 0.18.0__py2.py3-none-any.whl → 2.46.0__py2.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.
- sentry_sdk/__init__.py +48 -6
- sentry_sdk/_compat.py +64 -56
- sentry_sdk/_init_implementation.py +84 -0
- sentry_sdk/_log_batcher.py +172 -0
- sentry_sdk/_lru_cache.py +47 -0
- sentry_sdk/_metrics_batcher.py +167 -0
- sentry_sdk/_queue.py +81 -19
- sentry_sdk/_types.py +311 -11
- sentry_sdk/_werkzeug.py +98 -0
- sentry_sdk/ai/__init__.py +7 -0
- sentry_sdk/ai/monitoring.py +137 -0
- sentry_sdk/ai/utils.py +144 -0
- sentry_sdk/api.py +409 -67
- sentry_sdk/attachments.py +75 -0
- sentry_sdk/client.py +849 -103
- sentry_sdk/consts.py +1389 -34
- sentry_sdk/crons/__init__.py +10 -0
- sentry_sdk/crons/api.py +62 -0
- sentry_sdk/crons/consts.py +4 -0
- sentry_sdk/crons/decorator.py +135 -0
- sentry_sdk/debug.py +12 -15
- sentry_sdk/envelope.py +112 -61
- sentry_sdk/feature_flags.py +71 -0
- sentry_sdk/hub.py +442 -386
- sentry_sdk/integrations/__init__.py +228 -58
- sentry_sdk/integrations/_asgi_common.py +108 -0
- sentry_sdk/integrations/_wsgi_common.py +131 -40
- sentry_sdk/integrations/aiohttp.py +221 -72
- sentry_sdk/integrations/anthropic.py +439 -0
- sentry_sdk/integrations/argv.py +4 -6
- sentry_sdk/integrations/ariadne.py +161 -0
- sentry_sdk/integrations/arq.py +247 -0
- sentry_sdk/integrations/asgi.py +237 -135
- sentry_sdk/integrations/asyncio.py +144 -0
- sentry_sdk/integrations/asyncpg.py +208 -0
- sentry_sdk/integrations/atexit.py +13 -18
- sentry_sdk/integrations/aws_lambda.py +233 -80
- sentry_sdk/integrations/beam.py +27 -35
- sentry_sdk/integrations/boto3.py +137 -0
- sentry_sdk/integrations/bottle.py +91 -69
- sentry_sdk/integrations/celery/__init__.py +529 -0
- sentry_sdk/integrations/celery/beat.py +293 -0
- sentry_sdk/integrations/celery/utils.py +43 -0
- sentry_sdk/integrations/chalice.py +35 -28
- sentry_sdk/integrations/clickhouse_driver.py +177 -0
- sentry_sdk/integrations/cloud_resource_context.py +280 -0
- sentry_sdk/integrations/cohere.py +274 -0
- sentry_sdk/integrations/dedupe.py +32 -8
- sentry_sdk/integrations/django/__init__.py +343 -89
- sentry_sdk/integrations/django/asgi.py +201 -22
- sentry_sdk/integrations/django/caching.py +204 -0
- sentry_sdk/integrations/django/middleware.py +80 -32
- sentry_sdk/integrations/django/signals_handlers.py +91 -0
- sentry_sdk/integrations/django/templates.py +69 -2
- sentry_sdk/integrations/django/transactions.py +39 -14
- sentry_sdk/integrations/django/views.py +69 -16
- sentry_sdk/integrations/dramatiq.py +226 -0
- sentry_sdk/integrations/excepthook.py +19 -13
- sentry_sdk/integrations/executing.py +5 -6
- sentry_sdk/integrations/falcon.py +128 -65
- sentry_sdk/integrations/fastapi.py +141 -0
- sentry_sdk/integrations/flask.py +114 -75
- sentry_sdk/integrations/gcp.py +67 -36
- sentry_sdk/integrations/gnu_backtrace.py +14 -22
- sentry_sdk/integrations/google_genai/__init__.py +301 -0
- sentry_sdk/integrations/google_genai/consts.py +16 -0
- sentry_sdk/integrations/google_genai/streaming.py +155 -0
- sentry_sdk/integrations/google_genai/utils.py +576 -0
- sentry_sdk/integrations/gql.py +162 -0
- sentry_sdk/integrations/graphene.py +151 -0
- sentry_sdk/integrations/grpc/__init__.py +168 -0
- sentry_sdk/integrations/grpc/aio/__init__.py +7 -0
- sentry_sdk/integrations/grpc/aio/client.py +95 -0
- sentry_sdk/integrations/grpc/aio/server.py +100 -0
- sentry_sdk/integrations/grpc/client.py +91 -0
- sentry_sdk/integrations/grpc/consts.py +1 -0
- sentry_sdk/integrations/grpc/server.py +66 -0
- sentry_sdk/integrations/httpx.py +178 -0
- sentry_sdk/integrations/huey.py +174 -0
- sentry_sdk/integrations/huggingface_hub.py +378 -0
- sentry_sdk/integrations/langchain.py +1132 -0
- sentry_sdk/integrations/langgraph.py +337 -0
- sentry_sdk/integrations/launchdarkly.py +61 -0
- sentry_sdk/integrations/litellm.py +287 -0
- sentry_sdk/integrations/litestar.py +315 -0
- sentry_sdk/integrations/logging.py +261 -85
- sentry_sdk/integrations/loguru.py +213 -0
- sentry_sdk/integrations/mcp.py +566 -0
- sentry_sdk/integrations/modules.py +6 -33
- sentry_sdk/integrations/openai.py +725 -0
- sentry_sdk/integrations/openai_agents/__init__.py +61 -0
- sentry_sdk/integrations/openai_agents/consts.py +1 -0
- sentry_sdk/integrations/openai_agents/patches/__init__.py +5 -0
- sentry_sdk/integrations/openai_agents/patches/agent_run.py +140 -0
- sentry_sdk/integrations/openai_agents/patches/error_tracing.py +77 -0
- sentry_sdk/integrations/openai_agents/patches/models.py +50 -0
- sentry_sdk/integrations/openai_agents/patches/runner.py +45 -0
- sentry_sdk/integrations/openai_agents/patches/tools.py +77 -0
- sentry_sdk/integrations/openai_agents/spans/__init__.py +5 -0
- sentry_sdk/integrations/openai_agents/spans/agent_workflow.py +21 -0
- sentry_sdk/integrations/openai_agents/spans/ai_client.py +42 -0
- sentry_sdk/integrations/openai_agents/spans/execute_tool.py +48 -0
- sentry_sdk/integrations/openai_agents/spans/handoff.py +19 -0
- sentry_sdk/integrations/openai_agents/spans/invoke_agent.py +86 -0
- sentry_sdk/integrations/openai_agents/utils.py +199 -0
- sentry_sdk/integrations/openfeature.py +35 -0
- sentry_sdk/integrations/opentelemetry/__init__.py +7 -0
- sentry_sdk/integrations/opentelemetry/consts.py +5 -0
- sentry_sdk/integrations/opentelemetry/integration.py +58 -0
- sentry_sdk/integrations/opentelemetry/propagator.py +117 -0
- sentry_sdk/integrations/opentelemetry/span_processor.py +391 -0
- sentry_sdk/integrations/otlp.py +82 -0
- sentry_sdk/integrations/pure_eval.py +20 -11
- sentry_sdk/integrations/pydantic_ai/__init__.py +47 -0
- sentry_sdk/integrations/pydantic_ai/consts.py +1 -0
- sentry_sdk/integrations/pydantic_ai/patches/__init__.py +4 -0
- sentry_sdk/integrations/pydantic_ai/patches/agent_run.py +215 -0
- sentry_sdk/integrations/pydantic_ai/patches/graph_nodes.py +110 -0
- sentry_sdk/integrations/pydantic_ai/patches/model_request.py +40 -0
- sentry_sdk/integrations/pydantic_ai/patches/tools.py +98 -0
- sentry_sdk/integrations/pydantic_ai/spans/__init__.py +3 -0
- sentry_sdk/integrations/pydantic_ai/spans/ai_client.py +246 -0
- sentry_sdk/integrations/pydantic_ai/spans/execute_tool.py +49 -0
- sentry_sdk/integrations/pydantic_ai/spans/invoke_agent.py +112 -0
- sentry_sdk/integrations/pydantic_ai/utils.py +223 -0
- sentry_sdk/integrations/pymongo.py +214 -0
- sentry_sdk/integrations/pyramid.py +71 -60
- sentry_sdk/integrations/quart.py +237 -0
- sentry_sdk/integrations/ray.py +165 -0
- sentry_sdk/integrations/redis/__init__.py +48 -0
- sentry_sdk/integrations/redis/_async_common.py +116 -0
- sentry_sdk/integrations/redis/_sync_common.py +119 -0
- sentry_sdk/integrations/redis/consts.py +19 -0
- sentry_sdk/integrations/redis/modules/__init__.py +0 -0
- sentry_sdk/integrations/redis/modules/caches.py +118 -0
- sentry_sdk/integrations/redis/modules/queries.py +65 -0
- sentry_sdk/integrations/redis/rb.py +32 -0
- sentry_sdk/integrations/redis/redis.py +69 -0
- sentry_sdk/integrations/redis/redis_cluster.py +107 -0
- sentry_sdk/integrations/redis/redis_py_cluster_legacy.py +50 -0
- sentry_sdk/integrations/redis/utils.py +148 -0
- sentry_sdk/integrations/rq.py +62 -52
- sentry_sdk/integrations/rust_tracing.py +284 -0
- sentry_sdk/integrations/sanic.py +248 -114
- sentry_sdk/integrations/serverless.py +13 -22
- sentry_sdk/integrations/socket.py +96 -0
- sentry_sdk/integrations/spark/spark_driver.py +115 -62
- sentry_sdk/integrations/spark/spark_worker.py +42 -50
- sentry_sdk/integrations/sqlalchemy.py +82 -37
- sentry_sdk/integrations/starlette.py +737 -0
- sentry_sdk/integrations/starlite.py +292 -0
- sentry_sdk/integrations/statsig.py +37 -0
- sentry_sdk/integrations/stdlib.py +100 -58
- sentry_sdk/integrations/strawberry.py +394 -0
- sentry_sdk/integrations/sys_exit.py +70 -0
- sentry_sdk/integrations/threading.py +142 -38
- sentry_sdk/integrations/tornado.py +68 -53
- sentry_sdk/integrations/trytond.py +15 -20
- sentry_sdk/integrations/typer.py +60 -0
- sentry_sdk/integrations/unleash.py +33 -0
- sentry_sdk/integrations/unraisablehook.py +53 -0
- sentry_sdk/integrations/wsgi.py +126 -125
- sentry_sdk/logger.py +96 -0
- sentry_sdk/metrics.py +81 -0
- sentry_sdk/monitor.py +120 -0
- sentry_sdk/profiler/__init__.py +49 -0
- sentry_sdk/profiler/continuous_profiler.py +730 -0
- sentry_sdk/profiler/transaction_profiler.py +839 -0
- sentry_sdk/profiler/utils.py +195 -0
- sentry_sdk/scope.py +1542 -112
- sentry_sdk/scrubber.py +177 -0
- sentry_sdk/serializer.py +152 -210
- sentry_sdk/session.py +177 -0
- sentry_sdk/sessions.py +202 -179
- sentry_sdk/spotlight.py +242 -0
- sentry_sdk/tracing.py +1202 -294
- sentry_sdk/tracing_utils.py +1236 -0
- sentry_sdk/transport.py +693 -189
- sentry_sdk/types.py +52 -0
- sentry_sdk/utils.py +1395 -228
- sentry_sdk/worker.py +30 -17
- sentry_sdk-2.46.0.dist-info/METADATA +268 -0
- sentry_sdk-2.46.0.dist-info/RECORD +189 -0
- {sentry_sdk-0.18.0.dist-info → sentry_sdk-2.46.0.dist-info}/WHEEL +1 -1
- sentry_sdk-2.46.0.dist-info/entry_points.txt +2 -0
- sentry_sdk-2.46.0.dist-info/licenses/LICENSE +21 -0
- sentry_sdk/_functools.py +0 -66
- sentry_sdk/integrations/celery.py +0 -275
- sentry_sdk/integrations/redis.py +0 -103
- sentry_sdk-0.18.0.dist-info/LICENSE +0 -9
- sentry_sdk-0.18.0.dist-info/METADATA +0 -66
- sentry_sdk-0.18.0.dist-info/RECORD +0 -65
- {sentry_sdk-0.18.0.dist-info → sentry_sdk-2.46.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
from functools import wraps
|
|
3
|
+
|
|
4
|
+
import sentry_sdk
|
|
5
|
+
from sentry_sdk.ai.monitoring import record_token_usage
|
|
6
|
+
from sentry_sdk.ai.utils import set_data_normalized
|
|
7
|
+
from sentry_sdk.consts import OP, SPANDATA
|
|
8
|
+
from sentry_sdk.integrations import DidNotEnable, Integration
|
|
9
|
+
from sentry_sdk.scope import should_send_default_pii
|
|
10
|
+
from sentry_sdk.tracing_utils import set_span_errored
|
|
11
|
+
from sentry_sdk.utils import (
|
|
12
|
+
capture_internal_exceptions,
|
|
13
|
+
event_from_exception,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
from typing import TYPE_CHECKING
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from typing import Any, Callable, Iterable
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
import huggingface_hub.inference._client
|
|
23
|
+
except ImportError:
|
|
24
|
+
raise DidNotEnable("Huggingface not installed")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class HuggingfaceHubIntegration(Integration):
|
|
28
|
+
identifier = "huggingface_hub"
|
|
29
|
+
origin = f"auto.ai.{identifier}"
|
|
30
|
+
|
|
31
|
+
def __init__(self, include_prompts=True):
|
|
32
|
+
# type: (HuggingfaceHubIntegration, bool) -> None
|
|
33
|
+
self.include_prompts = include_prompts
|
|
34
|
+
|
|
35
|
+
@staticmethod
|
|
36
|
+
def setup_once():
|
|
37
|
+
# type: () -> None
|
|
38
|
+
|
|
39
|
+
# Other tasks that can be called: https://huggingface.co/docs/huggingface_hub/guides/inference#supported-providers-and-tasks
|
|
40
|
+
huggingface_hub.inference._client.InferenceClient.text_generation = (
|
|
41
|
+
_wrap_huggingface_task(
|
|
42
|
+
huggingface_hub.inference._client.InferenceClient.text_generation,
|
|
43
|
+
OP.GEN_AI_GENERATE_TEXT,
|
|
44
|
+
)
|
|
45
|
+
)
|
|
46
|
+
huggingface_hub.inference._client.InferenceClient.chat_completion = (
|
|
47
|
+
_wrap_huggingface_task(
|
|
48
|
+
huggingface_hub.inference._client.InferenceClient.chat_completion,
|
|
49
|
+
OP.GEN_AI_CHAT,
|
|
50
|
+
)
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _capture_exception(exc):
|
|
55
|
+
# type: (Any) -> None
|
|
56
|
+
set_span_errored()
|
|
57
|
+
|
|
58
|
+
event, hint = event_from_exception(
|
|
59
|
+
exc,
|
|
60
|
+
client_options=sentry_sdk.get_client().options,
|
|
61
|
+
mechanism={"type": "huggingface_hub", "handled": False},
|
|
62
|
+
)
|
|
63
|
+
sentry_sdk.capture_event(event, hint=hint)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _wrap_huggingface_task(f, op):
|
|
67
|
+
# type: (Callable[..., Any], str) -> Callable[..., Any]
|
|
68
|
+
@wraps(f)
|
|
69
|
+
def new_huggingface_task(*args, **kwargs):
|
|
70
|
+
# type: (*Any, **Any) -> Any
|
|
71
|
+
integration = sentry_sdk.get_client().get_integration(HuggingfaceHubIntegration)
|
|
72
|
+
if integration is None:
|
|
73
|
+
return f(*args, **kwargs)
|
|
74
|
+
|
|
75
|
+
prompt = None
|
|
76
|
+
if "prompt" in kwargs:
|
|
77
|
+
prompt = kwargs["prompt"]
|
|
78
|
+
elif "messages" in kwargs:
|
|
79
|
+
prompt = kwargs["messages"]
|
|
80
|
+
elif len(args) >= 2:
|
|
81
|
+
if isinstance(args[1], str) or isinstance(args[1], list):
|
|
82
|
+
prompt = args[1]
|
|
83
|
+
|
|
84
|
+
if prompt is None:
|
|
85
|
+
# invalid call, dont instrument, let it return error
|
|
86
|
+
return f(*args, **kwargs)
|
|
87
|
+
|
|
88
|
+
client = args[0]
|
|
89
|
+
model = client.model or kwargs.get("model") or ""
|
|
90
|
+
operation_name = op.split(".")[-1]
|
|
91
|
+
|
|
92
|
+
span = sentry_sdk.start_span(
|
|
93
|
+
op=op,
|
|
94
|
+
name=f"{operation_name} {model}",
|
|
95
|
+
origin=HuggingfaceHubIntegration.origin,
|
|
96
|
+
)
|
|
97
|
+
span.__enter__()
|
|
98
|
+
|
|
99
|
+
span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, operation_name)
|
|
100
|
+
|
|
101
|
+
if model:
|
|
102
|
+
span.set_data(SPANDATA.GEN_AI_REQUEST_MODEL, model)
|
|
103
|
+
|
|
104
|
+
# Input attributes
|
|
105
|
+
if should_send_default_pii() and integration.include_prompts:
|
|
106
|
+
set_data_normalized(
|
|
107
|
+
span, SPANDATA.GEN_AI_REQUEST_MESSAGES, prompt, unpack=False
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
attribute_mapping = {
|
|
111
|
+
"tools": SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS,
|
|
112
|
+
"frequency_penalty": SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY,
|
|
113
|
+
"max_tokens": SPANDATA.GEN_AI_REQUEST_MAX_TOKENS,
|
|
114
|
+
"presence_penalty": SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY,
|
|
115
|
+
"temperature": SPANDATA.GEN_AI_REQUEST_TEMPERATURE,
|
|
116
|
+
"top_p": SPANDATA.GEN_AI_REQUEST_TOP_P,
|
|
117
|
+
"top_k": SPANDATA.GEN_AI_REQUEST_TOP_K,
|
|
118
|
+
"stream": SPANDATA.GEN_AI_RESPONSE_STREAMING,
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
for attribute, span_attribute in attribute_mapping.items():
|
|
122
|
+
value = kwargs.get(attribute, None)
|
|
123
|
+
if value is not None:
|
|
124
|
+
if isinstance(value, (int, float, bool, str)):
|
|
125
|
+
span.set_data(span_attribute, value)
|
|
126
|
+
else:
|
|
127
|
+
set_data_normalized(span, span_attribute, value, unpack=False)
|
|
128
|
+
|
|
129
|
+
# LLM Execution
|
|
130
|
+
try:
|
|
131
|
+
res = f(*args, **kwargs)
|
|
132
|
+
except Exception as e:
|
|
133
|
+
_capture_exception(e)
|
|
134
|
+
span.__exit__(None, None, None)
|
|
135
|
+
raise e from None
|
|
136
|
+
|
|
137
|
+
# Output attributes
|
|
138
|
+
finish_reason = None
|
|
139
|
+
response_model = None
|
|
140
|
+
response_text_buffer: list[str] = []
|
|
141
|
+
tokens_used = 0
|
|
142
|
+
tool_calls = None
|
|
143
|
+
usage = None
|
|
144
|
+
|
|
145
|
+
with capture_internal_exceptions():
|
|
146
|
+
if isinstance(res, str) and res is not None:
|
|
147
|
+
response_text_buffer.append(res)
|
|
148
|
+
|
|
149
|
+
if hasattr(res, "generated_text") and res.generated_text is not None:
|
|
150
|
+
response_text_buffer.append(res.generated_text)
|
|
151
|
+
|
|
152
|
+
if hasattr(res, "model") and res.model is not None:
|
|
153
|
+
response_model = res.model
|
|
154
|
+
|
|
155
|
+
if hasattr(res, "details") and hasattr(res.details, "finish_reason"):
|
|
156
|
+
finish_reason = res.details.finish_reason
|
|
157
|
+
|
|
158
|
+
if (
|
|
159
|
+
hasattr(res, "details")
|
|
160
|
+
and hasattr(res.details, "generated_tokens")
|
|
161
|
+
and res.details.generated_tokens is not None
|
|
162
|
+
):
|
|
163
|
+
tokens_used = res.details.generated_tokens
|
|
164
|
+
|
|
165
|
+
if hasattr(res, "usage") and res.usage is not None:
|
|
166
|
+
usage = res.usage
|
|
167
|
+
|
|
168
|
+
if hasattr(res, "choices") and res.choices is not None:
|
|
169
|
+
for choice in res.choices:
|
|
170
|
+
if hasattr(choice, "finish_reason"):
|
|
171
|
+
finish_reason = choice.finish_reason
|
|
172
|
+
if hasattr(choice, "message") and hasattr(
|
|
173
|
+
choice.message, "tool_calls"
|
|
174
|
+
):
|
|
175
|
+
tool_calls = choice.message.tool_calls
|
|
176
|
+
if (
|
|
177
|
+
hasattr(choice, "message")
|
|
178
|
+
and hasattr(choice.message, "content")
|
|
179
|
+
and choice.message.content is not None
|
|
180
|
+
):
|
|
181
|
+
response_text_buffer.append(choice.message.content)
|
|
182
|
+
|
|
183
|
+
if response_model is not None:
|
|
184
|
+
span.set_data(SPANDATA.GEN_AI_RESPONSE_MODEL, response_model)
|
|
185
|
+
|
|
186
|
+
if finish_reason is not None:
|
|
187
|
+
set_data_normalized(
|
|
188
|
+
span,
|
|
189
|
+
SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS,
|
|
190
|
+
finish_reason,
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
if should_send_default_pii() and integration.include_prompts:
|
|
194
|
+
if tool_calls is not None and len(tool_calls) > 0:
|
|
195
|
+
set_data_normalized(
|
|
196
|
+
span,
|
|
197
|
+
SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS,
|
|
198
|
+
tool_calls,
|
|
199
|
+
unpack=False,
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
if len(response_text_buffer) > 0:
|
|
203
|
+
text_response = "".join(response_text_buffer)
|
|
204
|
+
if text_response:
|
|
205
|
+
set_data_normalized(
|
|
206
|
+
span,
|
|
207
|
+
SPANDATA.GEN_AI_RESPONSE_TEXT,
|
|
208
|
+
text_response,
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
if usage is not None:
|
|
212
|
+
record_token_usage(
|
|
213
|
+
span,
|
|
214
|
+
input_tokens=usage.prompt_tokens,
|
|
215
|
+
output_tokens=usage.completion_tokens,
|
|
216
|
+
total_tokens=usage.total_tokens,
|
|
217
|
+
)
|
|
218
|
+
elif tokens_used > 0:
|
|
219
|
+
record_token_usage(
|
|
220
|
+
span,
|
|
221
|
+
total_tokens=tokens_used,
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
# If the response is not a generator (meaning a streaming response)
|
|
225
|
+
# we are done and can return the response
|
|
226
|
+
if not inspect.isgenerator(res):
|
|
227
|
+
span.__exit__(None, None, None)
|
|
228
|
+
return res
|
|
229
|
+
|
|
230
|
+
if kwargs.get("details", False):
|
|
231
|
+
# text-generation stream output
|
|
232
|
+
def new_details_iterator():
|
|
233
|
+
# type: () -> Iterable[Any]
|
|
234
|
+
finish_reason = None
|
|
235
|
+
response_text_buffer: list[str] = []
|
|
236
|
+
tokens_used = 0
|
|
237
|
+
|
|
238
|
+
with capture_internal_exceptions():
|
|
239
|
+
for chunk in res:
|
|
240
|
+
if (
|
|
241
|
+
hasattr(chunk, "token")
|
|
242
|
+
and hasattr(chunk.token, "text")
|
|
243
|
+
and chunk.token.text is not None
|
|
244
|
+
):
|
|
245
|
+
response_text_buffer.append(chunk.token.text)
|
|
246
|
+
|
|
247
|
+
if hasattr(chunk, "details") and hasattr(
|
|
248
|
+
chunk.details, "finish_reason"
|
|
249
|
+
):
|
|
250
|
+
finish_reason = chunk.details.finish_reason
|
|
251
|
+
|
|
252
|
+
if (
|
|
253
|
+
hasattr(chunk, "details")
|
|
254
|
+
and hasattr(chunk.details, "generated_tokens")
|
|
255
|
+
and chunk.details.generated_tokens is not None
|
|
256
|
+
):
|
|
257
|
+
tokens_used = chunk.details.generated_tokens
|
|
258
|
+
|
|
259
|
+
yield chunk
|
|
260
|
+
|
|
261
|
+
if finish_reason is not None:
|
|
262
|
+
set_data_normalized(
|
|
263
|
+
span,
|
|
264
|
+
SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS,
|
|
265
|
+
finish_reason,
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
if should_send_default_pii() and integration.include_prompts:
|
|
269
|
+
if len(response_text_buffer) > 0:
|
|
270
|
+
text_response = "".join(response_text_buffer)
|
|
271
|
+
if text_response:
|
|
272
|
+
set_data_normalized(
|
|
273
|
+
span,
|
|
274
|
+
SPANDATA.GEN_AI_RESPONSE_TEXT,
|
|
275
|
+
text_response,
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
if tokens_used > 0:
|
|
279
|
+
record_token_usage(
|
|
280
|
+
span,
|
|
281
|
+
total_tokens=tokens_used,
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
span.__exit__(None, None, None)
|
|
285
|
+
|
|
286
|
+
return new_details_iterator()
|
|
287
|
+
|
|
288
|
+
else:
|
|
289
|
+
# chat-completion stream output
|
|
290
|
+
def new_iterator():
|
|
291
|
+
# type: () -> Iterable[str]
|
|
292
|
+
finish_reason = None
|
|
293
|
+
response_model = None
|
|
294
|
+
response_text_buffer: list[str] = []
|
|
295
|
+
tool_calls = None
|
|
296
|
+
usage = None
|
|
297
|
+
|
|
298
|
+
with capture_internal_exceptions():
|
|
299
|
+
for chunk in res:
|
|
300
|
+
if hasattr(chunk, "model") and chunk.model is not None:
|
|
301
|
+
response_model = chunk.model
|
|
302
|
+
|
|
303
|
+
if hasattr(chunk, "usage") and chunk.usage is not None:
|
|
304
|
+
usage = chunk.usage
|
|
305
|
+
|
|
306
|
+
if isinstance(chunk, str):
|
|
307
|
+
if chunk is not None:
|
|
308
|
+
response_text_buffer.append(chunk)
|
|
309
|
+
|
|
310
|
+
if hasattr(chunk, "choices") and chunk.choices is not None:
|
|
311
|
+
for choice in chunk.choices:
|
|
312
|
+
if (
|
|
313
|
+
hasattr(choice, "delta")
|
|
314
|
+
and hasattr(choice.delta, "content")
|
|
315
|
+
and choice.delta.content is not None
|
|
316
|
+
):
|
|
317
|
+
response_text_buffer.append(
|
|
318
|
+
choice.delta.content
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
if (
|
|
322
|
+
hasattr(choice, "finish_reason")
|
|
323
|
+
and choice.finish_reason is not None
|
|
324
|
+
):
|
|
325
|
+
finish_reason = choice.finish_reason
|
|
326
|
+
|
|
327
|
+
if (
|
|
328
|
+
hasattr(choice, "delta")
|
|
329
|
+
and hasattr(choice.delta, "tool_calls")
|
|
330
|
+
and choice.delta.tool_calls is not None
|
|
331
|
+
):
|
|
332
|
+
tool_calls = choice.delta.tool_calls
|
|
333
|
+
|
|
334
|
+
yield chunk
|
|
335
|
+
|
|
336
|
+
if response_model is not None:
|
|
337
|
+
span.set_data(
|
|
338
|
+
SPANDATA.GEN_AI_RESPONSE_MODEL, response_model
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
if finish_reason is not None:
|
|
342
|
+
set_data_normalized(
|
|
343
|
+
span,
|
|
344
|
+
SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS,
|
|
345
|
+
finish_reason,
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
if should_send_default_pii() and integration.include_prompts:
|
|
349
|
+
if tool_calls is not None and len(tool_calls) > 0:
|
|
350
|
+
set_data_normalized(
|
|
351
|
+
span,
|
|
352
|
+
SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS,
|
|
353
|
+
tool_calls,
|
|
354
|
+
unpack=False,
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
if len(response_text_buffer) > 0:
|
|
358
|
+
text_response = "".join(response_text_buffer)
|
|
359
|
+
if text_response:
|
|
360
|
+
set_data_normalized(
|
|
361
|
+
span,
|
|
362
|
+
SPANDATA.GEN_AI_RESPONSE_TEXT,
|
|
363
|
+
text_response,
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
if usage is not None:
|
|
367
|
+
record_token_usage(
|
|
368
|
+
span,
|
|
369
|
+
input_tokens=usage.prompt_tokens,
|
|
370
|
+
output_tokens=usage.completion_tokens,
|
|
371
|
+
total_tokens=usage.total_tokens,
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
span.__exit__(None, None, None)
|
|
375
|
+
|
|
376
|
+
return new_iterator()
|
|
377
|
+
|
|
378
|
+
return new_huggingface_task
|