Skip to content

Commit 90e8c5e

Browse files
ref(openai): Separate sync and async Chat Completions patches (#6187)
Remove generator pattern so that AI Client Spans are created and finished in the same function.
1 parent 675c7d2 commit 90e8c5e

1 file changed

Lines changed: 62 additions & 47 deletions

File tree

sentry_sdk/integrations/openai.py

Lines changed: 62 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,7 @@ def _set_common_output_data(
670670
span.__exit__(None, None, None)
671671

672672

673-
def _new_chat_completion_common(f: "Any", *args: "Any", **kwargs: "Any") -> "Any":
673+
def _new_sync_chat_completion(f: "Any", *args: "Any", **kwargs: "Any") -> "Any":
674674
integration = sentry_sdk.get_client().get_integration(OpenAIIntegration)
675675
if integration is None:
676676
return f(*args, **kwargs)
@@ -703,7 +703,14 @@ def _new_chat_completion_common(f: "Any", *args: "Any", **kwargs: "Any") -> "Any
703703
_set_completions_api_input_data(span, kwargs, integration)
704704

705705
start_time = time.perf_counter()
706-
response = yield f, args, kwargs
706+
707+
try:
708+
response = f(*args, **kwargs)
709+
except Exception as exc:
710+
exc_info = sys.exc_info()
711+
with capture_internal_exceptions():
712+
_capture_exception(exc)
713+
reraise(*exc_info)
707714

708715
# Attribute check to fail gracefully if the attribute is not present in future `openai` versions.
709716
if isinstance(response, Stream) and hasattr(response, "_iterator"):
@@ -722,8 +729,58 @@ def _new_chat_completion_common(f: "Any", *args: "Any", **kwargs: "Any") -> "Any
722729
finish_span=True,
723730
)
724731

732+
else:
733+
_set_completions_api_output_data(
734+
span, response, kwargs, integration, finish_span=True
735+
)
736+
737+
return response
738+
739+
740+
async def _new_async_chat_completion(f: "Any", *args: "Any", **kwargs: "Any") -> "Any":
741+
integration = sentry_sdk.get_client().get_integration(OpenAIIntegration)
742+
if integration is None:
743+
return await f(*args, **kwargs)
744+
745+
if "messages" not in kwargs:
746+
# invalid call (in all versions of openai), let it return error
747+
return await f(*args, **kwargs)
748+
749+
try:
750+
iter(kwargs["messages"])
751+
except TypeError:
752+
# invalid call (in all versions), messages must be iterable
753+
return await f(*args, **kwargs)
754+
755+
model = kwargs.get("model")
756+
757+
span = sentry_sdk.start_span(
758+
op=consts.OP.GEN_AI_CHAT,
759+
name=f"chat {model}",
760+
origin=OpenAIIntegration.origin,
761+
)
762+
span.__enter__()
763+
764+
span.set_data(SPANDATA.GEN_AI_SYSTEM, "openai")
765+
766+
# Same bool handling as in https://github.com/openai/openai-python/blob/acd0c54d8a68efeedde0e5b4e6c310eef1ce7867/src/openai/resources/completions.py#L585
767+
is_streaming_response = kwargs.get("stream", False) or False
768+
span.set_data(SPANDATA.GEN_AI_RESPONSE_STREAMING, is_streaming_response)
769+
770+
_set_completions_api_input_data(span, kwargs, integration)
771+
772+
start_time = time.perf_counter()
773+
774+
try:
775+
response = await f(*args, **kwargs)
776+
except Exception as exc:
777+
exc_info = sys.exc_info()
778+
with capture_internal_exceptions():
779+
_capture_exception(exc)
780+
reraise(*exc_info)
781+
725782
# Attribute check to fail gracefully if the attribute is not present in future `openai` versions.
726-
elif isinstance(response, AsyncStream) and hasattr(response, "_iterator"):
783+
if isinstance(response, AsyncStream) and hasattr(response, "_iterator"):
727784
messages = kwargs.get("messages")
728785

729786
if messages is not None and isinstance(messages, str):
@@ -1060,69 +1117,27 @@ def _set_embeddings_output_data(
10601117

10611118

10621119
def _wrap_chat_completion_create(f: "Callable[..., Any]") -> "Callable[..., Any]":
1063-
def _execute_sync(f: "Any", *args: "Any", **kwargs: "Any") -> "Any":
1064-
gen = _new_chat_completion_common(f, *args, **kwargs)
1065-
1066-
try:
1067-
f, args, kwargs = next(gen)
1068-
except StopIteration as e:
1069-
return e.value
1070-
1071-
try:
1072-
try:
1073-
result = f(*args, **kwargs)
1074-
except Exception as e:
1075-
exc_info = sys.exc_info()
1076-
with capture_internal_exceptions():
1077-
_capture_exception(e)
1078-
reraise(*exc_info)
1079-
1080-
return gen.send(result)
1081-
except StopIteration as e:
1082-
return e.value
1083-
10841120
@wraps(f)
10851121
def _sentry_patched_create_sync(*args: "Any", **kwargs: "Any") -> "Any":
10861122
integration = sentry_sdk.get_client().get_integration(OpenAIIntegration)
10871123
if integration is None or "messages" not in kwargs:
10881124
# no "messages" means invalid call (in all versions of openai), let it return error
10891125
return f(*args, **kwargs)
10901126

1091-
return _execute_sync(f, *args, **kwargs)
1127+
return _new_sync_chat_completion(f, *args, **kwargs)
10921128

10931129
return _sentry_patched_create_sync
10941130

10951131

10961132
def _wrap_async_chat_completion_create(f: "Callable[..., Any]") -> "Callable[..., Any]":
1097-
async def _execute_async(f: "Any", *args: "Any", **kwargs: "Any") -> "Any":
1098-
gen = _new_chat_completion_common(f, *args, **kwargs)
1099-
1100-
try:
1101-
f, args, kwargs = next(gen)
1102-
except StopIteration as e:
1103-
return await e.value
1104-
1105-
try:
1106-
try:
1107-
result = await f(*args, **kwargs)
1108-
except Exception as e:
1109-
exc_info = sys.exc_info()
1110-
with capture_internal_exceptions():
1111-
_capture_exception(e)
1112-
reraise(*exc_info)
1113-
1114-
return gen.send(result)
1115-
except StopIteration as e:
1116-
return e.value
1117-
11181133
@wraps(f)
11191134
async def _sentry_patched_create_async(*args: "Any", **kwargs: "Any") -> "Any":
11201135
integration = sentry_sdk.get_client().get_integration(OpenAIIntegration)
11211136
if integration is None or "messages" not in kwargs:
11221137
# no "messages" means invalid call (in all versions of openai), let it return error
11231138
return await f(*args, **kwargs)
11241139

1125-
return await _execute_async(f, *args, **kwargs)
1140+
return await _new_async_chat_completion(f, *args, **kwargs)
11261141

11271142
return _sentry_patched_create_async
11281143

0 commit comments

Comments
 (0)