Skip to content

Commit 7fc847a

Browse files
committed
commit from other branch. needs cleanup
1 parent a7b2d67 commit 7fc847a

File tree

2 files changed

+101
-18
lines changed

2 files changed

+101
-18
lines changed

sentry_sdk/consts.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,7 @@ class OP:
652652
GEN_AI_EXECUTE_TOOL = "gen_ai.execute_tool"
653653
GEN_AI_HANDOFF = "gen_ai.handoff"
654654
GEN_AI_INVOKE_AGENT = "gen_ai.invoke_agent"
655+
GEN_AI_RESPONSES = "gen_ai.responses"
655656
GRAPHQL_EXECUTE = "graphql.execute"
656657
GRAPHQL_MUTATION = "graphql.mutation"
657658
GRAPHQL_PARSE = "graphql.parse"

sentry_sdk/integrations/openai.py

Lines changed: 100 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from functools import wraps
2+
import json
23

34
import sentry_sdk
45
from sentry_sdk import consts
@@ -21,6 +22,7 @@
2122
try:
2223
from openai.resources.chat.completions import Completions, AsyncCompletions
2324
from openai.resources import Embeddings, AsyncEmbeddings
25+
from openai.resources.responses import Responses
2426

2527
if TYPE_CHECKING:
2628
from openai.types.chat import ChatCompletionMessageParam, ChatCompletionChunk
@@ -47,6 +49,7 @@ def setup_once():
4749
# type: () -> None
4850
Completions.create = _wrap_chat_completion_create(Completions.create)
4951
Embeddings.create = _wrap_embeddings_create(Embeddings.create)
52+
Responses.create = _wrap_responses_create(Responses.create)
5053

5154
AsyncCompletions.create = _wrap_async_chat_completion_create(
5255
AsyncCompletions.create
@@ -74,44 +77,46 @@ def _calculate_chat_completion_usage(
7477
messages, response, span, streaming_message_responses, count_tokens
7578
):
7679
# type: (Iterable[ChatCompletionMessageParam], Any, Span, Optional[List[str]], Callable[..., Any]) -> None
77-
completion_tokens = 0 # type: Optional[int]
78-
prompt_tokens = 0 # type: Optional[int]
80+
input_tokens = 0 # type: Optional[int]
81+
output_tokens = 0 # type: Optional[int]
7982
total_tokens = 0 # type: Optional[int]
8083
if hasattr(response, "usage"):
81-
if hasattr(response.usage, "completion_tokens") and isinstance(
82-
response.usage.completion_tokens, int
84+
if hasattr(response.usage, "input_tokens") and isinstance(
85+
response.usage.input_tokens, int
8386
):
84-
completion_tokens = response.usage.completion_tokens
85-
if hasattr(response.usage, "prompt_tokens") and isinstance(
86-
response.usage.prompt_tokens, int
87+
input_tokens = response.usage.input_tokens
88+
89+
if hasattr(response.usage, "output_tokens") and isinstance(
90+
response.usage.output_tokens, int
8791
):
88-
prompt_tokens = response.usage.prompt_tokens
92+
output_tokens = response.usage.output_tokens
93+
8994
if hasattr(response.usage, "total_tokens") and isinstance(
9095
response.usage.total_tokens, int
9196
):
9297
total_tokens = response.usage.total_tokens
9398

94-
if prompt_tokens == 0:
99+
if input_tokens == 0:
95100
for message in messages:
96101
if "content" in message:
97-
prompt_tokens += count_tokens(message["content"])
102+
input_tokens += count_tokens(message["content"])
98103

99-
if completion_tokens == 0:
104+
if output_tokens == 0:
100105
if streaming_message_responses is not None:
101106
for message in streaming_message_responses:
102-
completion_tokens += count_tokens(message)
107+
output_tokens += count_tokens(message)
103108
elif hasattr(response, "choices"):
104109
for choice in response.choices:
105110
if hasattr(choice, "message"):
106-
completion_tokens += count_tokens(choice.message)
111+
output_tokens += count_tokens(choice.message)
107112

108-
if prompt_tokens == 0:
109-
prompt_tokens = None
110-
if completion_tokens == 0:
111-
completion_tokens = None
113+
if input_tokens == 0:
114+
input_tokens = None
115+
if output_tokens == 0:
116+
output_tokens = None
112117
if total_tokens == 0:
113118
total_tokens = None
114-
record_token_usage(span, prompt_tokens, completion_tokens, total_tokens)
119+
record_token_usage(span, input_tokens, output_tokens, total_tokens)
115120

116121

117122
def _new_chat_completion_common(f, *args, **kwargs):
@@ -427,3 +432,80 @@ async def _sentry_patched_create_async(*args, **kwargs):
427432
return await _execute_async(f, *args, **kwargs)
428433

429434
return _sentry_patched_create_async
435+
436+
437+
def _new_responses_create_common(f, *args, **kwargs):
438+
# type: (Any, *Any, **Any) -> Any
439+
integration = sentry_sdk.get_client().get_integration(OpenAIIntegration)
440+
if integration is None:
441+
return f(*args, **kwargs)
442+
443+
model = kwargs.get("model")
444+
input = kwargs.get("input")
445+
446+
span = sentry_sdk.start_span(
447+
op=consts.OP.GEN_AI_RESPONSES,
448+
name=f"{consts.OP.GEN_AI_RESPONSES} {model}",
449+
origin=OpenAIIntegration.origin,
450+
)
451+
span.__enter__()
452+
453+
set_data_normalized(span, SPANDATA.GEN_AI_REQUEST_MODEL, model)
454+
455+
if should_send_default_pii() and integration.include_prompts:
456+
set_data_normalized(span, SPANDATA.GEN_AI_REQUEST_MESSAGES, input)
457+
458+
res = yield f, args, kwargs
459+
460+
if hasattr(res, "output"):
461+
if should_send_default_pii() and integration.include_prompts:
462+
set_data_normalized(
463+
span,
464+
SPANDATA.GEN_AI_RESPONSE_TEXT,
465+
json.dumps([item.to_dict() for item in res.output]),
466+
)
467+
import ipdb
468+
469+
ipdb.set_trace()
470+
_calculate_chat_completion_usage([], res, span, None, integration.count_tokens)
471+
span.__exit__(None, None, None)
472+
473+
else:
474+
set_data_normalized(span, "unknown_response", True)
475+
span.__exit__(None, None, None)
476+
477+
return res
478+
479+
480+
def _wrap_responses_create(f):
481+
# type: (Any) -> Any
482+
def _execute_sync(f, *args, **kwargs):
483+
# type: (Any, *Any, **Any) -> Any
484+
gen = _new_responses_create_common(f, *args, **kwargs)
485+
486+
try:
487+
f, args, kwargs = next(gen)
488+
except StopIteration as e:
489+
return e.value
490+
491+
try:
492+
try:
493+
result = f(*args, **kwargs)
494+
except Exception as e:
495+
_capture_exception(e)
496+
raise e from None
497+
498+
return gen.send(result)
499+
except StopIteration as e:
500+
return e.value
501+
502+
@wraps(f)
503+
def _sentry_patched_create_sync(*args, **kwargs):
504+
# type: (*Any, **Any) -> Any
505+
integration = sentry_sdk.get_client().get_integration(OpenAIIntegration)
506+
if integration is None:
507+
return f(*args, **kwargs)
508+
509+
return _execute_sync(f, *args, **kwargs)
510+
511+
return _sentry_patched_create_sync

0 commit comments

Comments
 (0)