Skip to content

Commit 6b816f7

Browse files
committed
Merge branch 'master' into antonpirker/openai-token-usage
2 parents 1fe97c9 + 657c2b1 commit 6b816f7

File tree

18 files changed

+308
-103
lines changed

18 files changed

+308
-103
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
# Changelog
22

3+
## 2.33.0
4+
5+
### Various fixes & improvements
6+
7+
- feat(langchain): Support `BaseCallbackManager` (#4486) by @szokeasaurusrex
8+
- Use `span.data` instead of `measurements` for token usage (#4567) by @antonpirker
9+
- Fix custom model name (#4569) by @antonpirker
10+
- fix: shut down "session flusher" more promptly (#4561) by @bukzor
11+
- chore: Remove Lambda urllib3 pin on Python 3.10+ (#4549) by @sentrivana
12+
313
## 2.32.0
414

515
### Various fixes & improvements

docs/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
copyright = "2019-{}, Sentry Team and Contributors".format(datetime.now().year)
3232
author = "Sentry Team and Contributors"
3333

34-
release = "2.32.0"
34+
release = "2.33.0"
3535
version = ".".join(release.split(".")[:2]) # The short X.Y version.
3636

3737

scripts/populate_tox/populate_tox.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,8 @@ def _compare_min_version_with_defined(
508508
):
509509
print(
510510
f" Integration defines {defined_min_version} as minimum "
511-
f"version, but the effective minimum version is {releases[0]}."
511+
f"version, but the effective minimum version based on metadata "
512+
f"is {releases[0]}."
512513
)
513514

514515

sentry_sdk/consts.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1181,4 +1181,4 @@ def _get_default_options():
11811181
del _get_default_options
11821182

11831183

1184-
VERSION = "2.32.0"
1184+
VERSION = "2.33.0"

sentry_sdk/integrations/langchain.py

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from langchain_core.callbacks import (
2424
manager,
2525
BaseCallbackHandler,
26+
BaseCallbackManager,
2627
Callbacks,
2728
)
2829
from langchain_core.agents import AgentAction, AgentFinish
@@ -434,12 +435,20 @@ def new_configure(
434435
**kwargs,
435436
)
436437

437-
callbacks_list = local_callbacks or []
438-
439-
if isinstance(callbacks_list, BaseCallbackHandler):
440-
callbacks_list = [callbacks_list]
441-
elif not isinstance(callbacks_list, list):
442-
logger.debug("Unknown callback type: %s", callbacks_list)
438+
local_callbacks = local_callbacks or []
439+
440+
# Handle each possible type of local_callbacks. For each type, we
441+
# extract the list of callbacks to check for SentryLangchainCallback,
442+
# and define a function that would add the SentryLangchainCallback
443+
# to the existing callbacks list.
444+
if isinstance(local_callbacks, BaseCallbackManager):
445+
callbacks_list = local_callbacks.handlers
446+
elif isinstance(local_callbacks, BaseCallbackHandler):
447+
callbacks_list = [local_callbacks]
448+
elif isinstance(local_callbacks, list):
449+
callbacks_list = local_callbacks
450+
else:
451+
logger.debug("Unknown callback type: %s", local_callbacks)
443452
# Just proceed with original function call
444453
return f(
445454
callback_manager_cls,
@@ -449,28 +458,38 @@ def new_configure(
449458
**kwargs,
450459
)
451460

452-
inheritable_callbacks_list = (
453-
inheritable_callbacks if isinstance(inheritable_callbacks, list) else []
454-
)
461+
# Handle each possible type of inheritable_callbacks.
462+
if isinstance(inheritable_callbacks, BaseCallbackManager):
463+
inheritable_callbacks_list = inheritable_callbacks.handlers
464+
elif isinstance(inheritable_callbacks, list):
465+
inheritable_callbacks_list = inheritable_callbacks
466+
else:
467+
inheritable_callbacks_list = []
455468

456469
if not any(
457470
isinstance(cb, SentryLangchainCallback)
458471
for cb in itertools.chain(callbacks_list, inheritable_callbacks_list)
459472
):
460-
# Avoid mutating the existing callbacks list
461-
callbacks_list = [
462-
*callbacks_list,
463-
SentryLangchainCallback(
464-
integration.max_spans,
465-
integration.include_prompts,
466-
integration.tiktoken_encoding_name,
467-
),
468-
]
473+
sentry_handler = SentryLangchainCallback(
474+
integration.max_spans,
475+
integration.include_prompts,
476+
integration.tiktoken_encoding_name,
477+
)
478+
if isinstance(local_callbacks, BaseCallbackManager):
479+
local_callbacks = local_callbacks.copy()
480+
local_callbacks.handlers = [
481+
*local_callbacks.handlers,
482+
sentry_handler,
483+
]
484+
elif isinstance(local_callbacks, BaseCallbackHandler):
485+
local_callbacks = [local_callbacks, sentry_handler]
486+
else: # local_callbacks is a list
487+
local_callbacks = [*local_callbacks, sentry_handler]
469488

470489
return f(
471490
callback_manager_cls,
472491
inheritable_callbacks,
473-
callbacks_list,
492+
local_callbacks,
474493
*args,
475494
**kwargs,
476495
)

sentry_sdk/integrations/openai_agents/spans/ai_client.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@
1919
def ai_client_span(agent, get_response_kwargs):
2020
# type: (Agent, dict[str, Any]) -> sentry_sdk.tracing.Span
2121
# TODO-anton: implement other types of operations. Now "chat" is hardcoded.
22+
model_name = agent.model.model if hasattr(agent.model, "model") else agent.model
2223
span = sentry_sdk.start_span(
2324
op=OP.GEN_AI_CHAT,
24-
description=f"chat {agent.model}",
25+
description=f"chat {model_name}",
2526
origin=SPAN_ORIGIN,
2627
)
2728
# TODO-anton: remove hardcoded stuff and replace something that also works for embedding and so on

sentry_sdk/integrations/openai_agents/utils.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ def _set_agent_data(span, agent):
5353
)
5454

5555
if agent.model:
56-
span.set_data(SPANDATA.GEN_AI_REQUEST_MODEL, agent.model)
56+
model_name = agent.model.model if hasattr(agent.model, "model") else agent.model
57+
span.set_data(SPANDATA.GEN_AI_REQUEST_MODEL, model_name)
5758

5859
if agent.model_settings.presence_penalty:
5960
span.set_data(

sentry_sdk/sessions.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import os
2-
import time
32
import warnings
4-
from threading import Thread, Lock
3+
from threading import Thread, Lock, Event
54
from contextlib import contextmanager
65

76
import sentry_sdk
@@ -162,7 +161,7 @@ def __init__(
162161
self._thread_lock = Lock()
163162
self._aggregate_lock = Lock()
164163
self._thread_for_pid = None # type: Optional[int]
165-
self._running = True
164+
self.__shutdown_requested = Event()
166165

167166
def flush(self):
168167
# type: (...) -> None
@@ -208,10 +207,10 @@ def _ensure_running(self):
208207

209208
def _thread():
210209
# type: (...) -> None
211-
while self._running:
212-
time.sleep(self.flush_interval)
213-
if self._running:
214-
self.flush()
210+
running = True
211+
while running:
212+
running = not self.__shutdown_requested.wait(self.flush_interval)
213+
self.flush()
215214

216215
thread = Thread(target=_thread)
217216
thread.daemon = True
@@ -220,7 +219,7 @@ def _thread():
220219
except RuntimeError:
221220
# Unfortunately at this point the interpreter is in a state that no
222221
# longer allows us to spawn a thread and we have to bail.
223-
self._running = False
222+
self.__shutdown_requested.set()
224223
return None
225224

226225
self._thread = thread
@@ -271,7 +270,7 @@ def add_session(
271270

272271
def kill(self):
273272
# type: (...) -> None
274-
self._running = False
273+
self.__shutdown_requested.set()
275274

276275
def __del__(self):
277276
# type: (...) -> None

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def get_file_text(file_name):
2121

2222
setup(
2323
name="sentry-sdk",
24-
version="2.32.0",
24+
version="2.33.0",
2525
author="Sentry Team and Contributors",
2626
author_email="[email protected]",
2727
url="https://github.com/getsentry/sentry-python",

tests/integrations/anthropic/test_anthropic.py

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,9 @@ def test_nonstreaming_create_message(
125125
assert SPANDATA.AI_INPUT_MESSAGES not in span["data"]
126126
assert SPANDATA.AI_RESPONSES not in span["data"]
127127

128-
assert span["measurements"]["ai_prompt_tokens_used"]["value"] == 10
129-
assert span["measurements"]["ai_completion_tokens_used"]["value"] == 20
130-
assert span["measurements"]["ai_total_tokens_used"]["value"] == 30
128+
assert span["data"]["gen_ai.usage.input_tokens"] == 10
129+
assert span["data"]["gen_ai.usage.output_tokens"] == 20
130+
assert span["data"]["gen_ai.usage.total_tokens"] == 30
131131
assert span["data"][SPANDATA.AI_STREAMING] is False
132132

133133

@@ -193,9 +193,9 @@ async def test_nonstreaming_create_message_async(
193193
assert SPANDATA.AI_INPUT_MESSAGES not in span["data"]
194194
assert SPANDATA.AI_RESPONSES not in span["data"]
195195

196-
assert span["measurements"]["ai_prompt_tokens_used"]["value"] == 10
197-
assert span["measurements"]["ai_completion_tokens_used"]["value"] == 20
198-
assert span["measurements"]["ai_total_tokens_used"]["value"] == 30
196+
assert span["data"]["gen_ai.usage.input_tokens"] == 10
197+
assert span["data"]["gen_ai.usage.output_tokens"] == 20
198+
assert span["data"]["gen_ai.usage.total_tokens"] == 30
199199
assert span["data"][SPANDATA.AI_STREAMING] is False
200200

201201

@@ -293,9 +293,9 @@ def test_streaming_create_message(
293293
assert SPANDATA.AI_INPUT_MESSAGES not in span["data"]
294294
assert SPANDATA.AI_RESPONSES not in span["data"]
295295

296-
assert span["measurements"]["ai_prompt_tokens_used"]["value"] == 10
297-
assert span["measurements"]["ai_completion_tokens_used"]["value"] == 30
298-
assert span["measurements"]["ai_total_tokens_used"]["value"] == 40
296+
assert span["data"]["gen_ai.usage.input_tokens"] == 10
297+
assert span["data"]["gen_ai.usage.output_tokens"] == 30
298+
assert span["data"]["gen_ai.usage.total_tokens"] == 40
299299
assert span["data"][SPANDATA.AI_STREAMING] is True
300300

301301

@@ -396,9 +396,9 @@ async def test_streaming_create_message_async(
396396
assert SPANDATA.AI_INPUT_MESSAGES not in span["data"]
397397
assert SPANDATA.AI_RESPONSES not in span["data"]
398398

399-
assert span["measurements"]["ai_prompt_tokens_used"]["value"] == 10
400-
assert span["measurements"]["ai_completion_tokens_used"]["value"] == 30
401-
assert span["measurements"]["ai_total_tokens_used"]["value"] == 40
399+
assert span["data"]["gen_ai.usage.input_tokens"] == 10
400+
assert span["data"]["gen_ai.usage.output_tokens"] == 30
401+
assert span["data"]["gen_ai.usage.total_tokens"] == 40
402402
assert span["data"][SPANDATA.AI_STREAMING] is True
403403

404404

@@ -525,9 +525,9 @@ def test_streaming_create_message_with_input_json_delta(
525525
assert SPANDATA.AI_INPUT_MESSAGES not in span["data"]
526526
assert SPANDATA.AI_RESPONSES not in span["data"]
527527

528-
assert span["measurements"]["ai_prompt_tokens_used"]["value"] == 366
529-
assert span["measurements"]["ai_completion_tokens_used"]["value"] == 51
530-
assert span["measurements"]["ai_total_tokens_used"]["value"] == 417
528+
assert span["data"]["gen_ai.usage.input_tokens"] == 366
529+
assert span["data"]["gen_ai.usage.output_tokens"] == 51
530+
assert span["data"]["gen_ai.usage.total_tokens"] == 417
531531
assert span["data"][SPANDATA.AI_STREAMING] is True
532532

533533

@@ -662,9 +662,9 @@ async def test_streaming_create_message_with_input_json_delta_async(
662662
assert SPANDATA.AI_INPUT_MESSAGES not in span["data"]
663663
assert SPANDATA.AI_RESPONSES not in span["data"]
664664

665-
assert span["measurements"]["ai_prompt_tokens_used"]["value"] == 366
666-
assert span["measurements"]["ai_completion_tokens_used"]["value"] == 51
667-
assert span["measurements"]["ai_total_tokens_used"]["value"] == 417
665+
assert span["data"]["gen_ai.usage.input_tokens"] == 366
666+
assert span["data"]["gen_ai.usage.output_tokens"] == 51
667+
assert span["data"]["gen_ai.usage.total_tokens"] == 417
668668
assert span["data"][SPANDATA.AI_STREAMING] is True
669669

670670

@@ -807,10 +807,10 @@ def test_add_ai_data_to_span_with_input_json_delta(sentry_init):
807807
content_blocks=["{'test': 'data',", "'more': 'json'}"],
808808
)
809809

810-
assert span._data.get(SPANDATA.AI_RESPONSES) == [
810+
assert span._data.get("ai.responses") == [
811811
{"type": "text", "text": "{'test': 'data','more': 'json'}"}
812812
]
813-
assert span._data.get(SPANDATA.AI_STREAMING) is True
814-
assert span._measurements.get("ai_prompt_tokens_used")["value"] == 10
815-
assert span._measurements.get("ai_completion_tokens_used")["value"] == 20
816-
assert span._measurements.get("ai_total_tokens_used")["value"] == 30
813+
assert span._data.get("ai.streaming") is True
814+
assert span._data.get("gen_ai.usage.input_tokens") == 10
815+
assert span._data.get("gen_ai.usage.output_tokens") == 20
816+
assert span._data.get("gen_ai.usage.total_tokens") == 30

0 commit comments

Comments
 (0)