Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/workflows/test-integrations-ai.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.14t"]
python-version: ["3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.14t","3.15","3.15t"]
os: [ubuntu-22.04]
env:
# 3.7 runs in the python:X.Y container; tell uv to use that system Python.
Expand Down Expand Up @@ -57,6 +57,10 @@ jobs:
run: |
set -x # print commands that are executed
./scripts/runtox.sh "py${{ matrix.python-version }}-litellm"
- name: Test mistral
run: |
set -x # print commands that are executed
./scripts/runtox.sh "py${{ matrix.python-version }}-mistral"
- name: Test openai-base
run: |
set -x # print commands that are executed
Expand Down
75 changes: 75 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,80 @@
# Changelog

## 2.70.0

### New Features ✨

- **New integration:** Mistral AI (#4733) by @alexander-alderman-webb

Add the Mistral integration to your `sentry_sdk.init` call:

```python
import sentry_sdk
from sentry_sdk.integrations.mistral import MistralIntegration

sentry_sdk.init(
dsn="...",
traces_sample_rate=1.0,
integrations=[
MistralIntegration(),
]
)
```

- **New option:** A fine-grained way to configure what data should be sent from the SDK.

Offers much more flexibility than `send_default_pii`, allowing you to specify what
data should be collected. If `data_collection` is defined, it takes precedence over
`send_default_pii`.

See https://docs.sentry.io/platforms/python/configuration/options/#data_collection
for the available configuration options.

```python
import sentry_sdk

sentry_sdk.init(
data_collection={
"user_info": False,
"gen_ai": {"inputs": False, "outputs": False},
"graphql": {"document": False, "variables": False},
"database_query_data": False,
"queues": False,
"http_bodies": [],
"cookies": {
"mode": "denylist",
"terms": ["forwarded", "-ip", "remote-", "via", "-user"],
},
"http_headers": {
"request": {
"mode": "denylist",
"terms": ["forwarded", "-ip", "remote-", "via", "-user"],
},
},
"url_query_params": {
"mode": "denylist",
"terms": ["forwarded", "-ip", "remote-", "via", "-user"],
},
}
)
```

#### Mistral

- Record `gen_ai.output.messages` by @alexander-alderman-webb in [#7549](https://github.com/getsentry/sentry-python/pull/7549)
- Record `gen_ai.input.messages` by @alexander-alderman-webb in [#7548](https://github.com/getsentry/sentry-python/pull/7548)
- Record `gen_ai.system_instructions` by @alexander-alderman-webb in [#7547](https://github.com/getsentry/sentry-python/pull/7547)
- Record request parameters by @alexander-alderman-webb in [#7531](https://github.com/getsentry/sentry-python/pull/7531)
- Record token usage by @alexander-alderman-webb in [#7529](https://github.com/getsentry/sentry-python/pull/7529)
- Add integration with `Chat.complete` and `Chat.complete_async` patches by @alexander-alderman-webb in [#7528](https://github.com/getsentry/sentry-python/pull/7528)

### Internal Changes 🔧

- (data-collection) Promote `data_collection` from `_experiments` o top-level by @ericapisani in [#7560](https://github.com/getsentry/sentry-python/pull/7560)
- Close client on teardown by @alexander-alderman-webb in [#7562](https://github.com/getsentry/sentry-python/pull/7562)
- 🤖 Update test matrix with new releases (09/21) by @github-actions in [#7546](https://github.com/getsentry/sentry-python/pull/7546)
- Remove `getsentry/testing-ai-sdk-integrations` by @alexander-alderman-webb in [#7526](https://github.com/getsentry/sentry-python/pull/7526)

## 2.69.2

### Bug Fixes 🐛
Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
copyright = "2019-{}, Sentry Team and Contributors".format(datetime.now().year)
author = "Sentry Team and Contributors"

release = "2.69.2"
release = "2.70.0"
version = ".".join(release.split(".")[:2]) # The short X.Y version.


Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ typing = [
"tiktoken>=0.14.0",
"aiohttp>=3.14.3",
"openai-agents>=0.22.0",
"mistralai>=2.10.1",
]
test = [
"dataclasses ; python_full_version < '3.7'",
Expand Down
6 changes: 6 additions & 0 deletions scripts/populate_tox/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,12 @@
"*": ["pytest-asyncio", "httpx"],
},
},
"mistral": {
"package": "mistralai",
"deps": {
"*": ["pytest-asyncio", "httpx"],
},
},
"fastmcp": {
"package": "fastmcp",
"deps": {
Expand Down
120 changes: 88 additions & 32 deletions scripts/populate_tox/package_dependencies.jsonl

Large diffs are not rendered by default.

26 changes: 17 additions & 9 deletions scripts/populate_tox/releases.jsonl

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions scripts/split_tox_gh_actions/split_tox_gh_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
"google_genai",
"huggingface_hub",
"litellm",
"mistral",
"openai-base",
"openai-notiktoken",
],
Expand Down
8 changes: 8 additions & 0 deletions sentry_sdk/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,14 @@ class ToolCallPart(TypedDict):
name: NotRequired[str]
arguments: NotRequired[Any]

class InputMessage(TypedDict):
role: Literal["user", "assistant", "tool"]
parts: list[Union[TextPart, ReasoningPart, ToolCallPart]]

class OutputMessage(TypedDict):
role: Literal["assistant"]
parts: list[Union[TextPart, ReasoningPart]]

class ToolDefinition(TypedDict):
type: str
name: NotRequired[str]
Expand Down
38 changes: 19 additions & 19 deletions sentry_sdk/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -1167,12 +1167,12 @@
"""
A list of names identifying enabled integrations.
Example: ["AtexitIntegration", "StdlibIntegration"]
"""


class OP:
ANTHROPIC_MESSAGES_CREATE = "ai.messages.create.anthropic"
CACHE_GET = "cache.get"

Check warning on line 1175 in sentry_sdk/consts.py

View check run for this annotation

@sentry/warden / warden: code-review

SPANSTATUS removal lacks migration path documentation

`SPANSTATUS` was removed from `consts` without a MIGRATION_GUIDE entry; document that callers should use `sentry_sdk.traces.SpanStatus` (`ok`/`error` only) instead of the old multi-value constants.
CACHE_PUT = "cache.put"
COHERE_CHAT_COMPLETIONS_CREATE = "ai.chat_completions.create.cohere"
COHERE_EMBEDDINGS_CREATE = "ai.embeddings.create.cohere"
Expand Down Expand Up @@ -1265,6 +1265,7 @@
transport_queue_size: int = DEFAULT_QUEUE_SIZE,
sample_rate: float = 1.0,
send_default_pii: "Optional[bool]" = None,
data_collection: "Optional[DataCollectionUserOptions]" = None,
http_proxy: "Optional[str]" = None,
https_proxy: "Optional[str]" = None,
ignore_errors: "Sequence[Union[type, str]]" = [], # noqa: B006
Expand All @@ -1275,19 +1276,19 @@
before_breadcrumb: "Optional[BreadcrumbProcessor]" = None,
debug: "Optional[bool]" = None,
attach_stacktrace: bool = True,
ca_certs: "Optional[str]" = None,
traces_sample_rate: "Optional[float]" = None,
traces_sampler: "Optional[TracesSampler]" = None,

Check warning on line 1281 in sentry_sdk/consts.py

View check run for this annotation

@sentry/warden / warden: code-review

trace_lifecycle removed without migration note

Removing `trace_lifecycle` will hard-fail existing `init(trace_lifecycle=...)` callers, and MIGRATION_GUIDE.md does not document the removal or that stream mode is now the only behavior.
profiler_mode: "Optional[ContinuousProfilerMode]" = None,
profile_lifecycle: 'Literal["manual", "trace"]' = "manual",
profile_session_sample_rate: "Optional[float]" = None,
auto_enabling_integrations: bool = True,
disabled_integrations: "Optional[Sequence[Union[sentry_sdk.integrations.Integration, type[sentry_sdk.integrations.Integration]]]]" = None,
auto_session_tracking: bool = True,
send_client_reports: bool = True,
_experiments: "Experiments" = {}, # noqa: B006
proxy_headers: "Optional[Dict[str, str]]" = None,
project_root: "Optional[str]" = None,

Check failure on line 1291 in sentry_sdk/consts.py

View check run for this annotation

@sentry/warden / warden: code-review

[DCD-EZ8] Legacy before_send_transaction configurations now fail SDK initialization (additional location)

The 3.0 branch no longer accepts the previously supported `before_send_transaction` option, so applications upgrading with that option receive `TypeError: Unknown option 'before_send_transaction'` during `init()`. The migration guide does not document this removal or provide a migration path. `before_send_span` only modifies streamed spans and explicitly cannot drop them, so it is not an equivalent replacement for transaction filtering.
include_local_variables: "Optional[bool]" = True,
include_source_context: "Optional[bool]" = True,
trace_propagation_targets: "Optional[Sequence[str]]" = [ # noqa: B006
Expand Down Expand Up @@ -1410,6 +1411,23 @@
If you enable this option, be sure to manually remove what you don't want to send using our features for
managing `Sensitive Data <https://docs.sentry.io/data-management/sensitive-data/>`_.

:param data_collection: Structured configuration controlling what data integrations collect
automatically, superseding `send_default_pii`. Passing a dict opts into the feature; omitted
fields use their defaults (most categories are collected, with the sensitive denylist
scrubbing values). When it is not set, the SDK derives behaviour from `send_default_pii` so
that upgrading changes nothing. Restrict collection per category (user identity, cookies,
HTTP headers/bodies, query params, generative AI inputs/outputs, stack frame variables,
source context). If `send_default_pii` is also set, `data_collection` takes precedence.

Example::

sentry_sdk.init(
dsn="...",
data_collection={"user_info": False, "http_bodies": []},
)

See https://docs.sentry.io/platforms/python/configuration/options/#data_collection for more details.

:param event_scrubber: Scrubs the event payload for sensitive information such as cookies, sessions, and
passwords from a `denylist`.

Expand Down Expand Up @@ -1703,24 +1721,6 @@
:param ignore_spans: A sequence of span-matching rules. Matching spans are ignored.

:param _experiments: Dictionary of experimental, opt-in features that are not yet stable.

``data_collection`` (EXPERIMENTAL): structured configuration controlling what data integrations
collect automatically, superseding `send_default_pii`. Passing a dict under
`_experiments={"data_collection": {...}}` opts into the feature; omitted fields use their
defaults (most categories are collected, with the sensitive denylist scrubbing values).
When it is not set, the SDK derives behaviour from `send_default_pii` so that upgrading
changes nothing. Restrict collection per category (user identity, cookies, HTTP
headers/bodies, query params, generative AI inputs/outputs, stack frame variables, source
context). If `send_default_pii` is also set, `data_collection` takes precedence.

Example::

sentry_sdk.init(
dsn="...",
_experiments={"data_collection": {"user_info": False, "http_bodies": []}},
)

See https://docs.sentry.io/platforms/python/configuration/options/#data_collection for more details.
"""
pass

Expand All @@ -1744,4 +1744,4 @@
del _get_default_options


VERSION = "2.69.2"
VERSION = "2.70.0"
9 changes: 8 additions & 1 deletion sentry_sdk/data_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,10 +292,17 @@ def _resolve_data_collection(options: "Dict[str, Any]") -> "DataCollection":
concrete values for every field.

``data_collection`` must be a plain ``dict``.

Must be called exactly once per options dict, before ``client._get_options``
overwrites ``options["data_collection"]`` with the resolved result. Feeding an
already-resolved dict back in would flip ``provided_by_user`` to ``True``.
"""
from sentry_sdk.utils import deprecation_warning

user_dc = options.get("_experiments", {}).get("data_collection")
user_dc = options.get("data_collection")
if user_dc is None:
user_dc = options.get("_experiments", {}).get("data_collection")

send_default_pii = options.get("send_default_pii")

include_local_variables = (
Expand Down
1 change: 1 addition & 0 deletions sentry_sdk/integrations/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@
"litellm": (1, 77, 5),
"loguru": (0, 7, 0),
"mcp": (2, 0),
"mistral": (2, 0, 5),
"openai": (1, 0, 0),
"openai_agents": (0, 10, 3),
"openfeature": (0, 7, 1),
Expand Down Expand Up @@ -217,9 +218,9 @@
):
if integration_cls.identifier not in integrations:
instance = integration_cls()
integrations[instance.identifier] = instance
used_as_default_integration.add(instance.identifier)

Check failure on line 223 in sentry_sdk/integrations/__init__.py

View check run for this annotation

@sentry/warden / warden: code-review

[2DG-45W] Chat generation context never clears agent-framework flag on success (additional location)

`_exit_span` ends the inner `Span` only, so successful `on_chat_model_end` paths never call `_AgentFrameworkChatGenerationContext.__exit__` and leave `_agent_framework_chat_generation_entered` stuck True, permanently suppressing OpenAI/Anthropic/Google GenAI spans afterward. Exit the stored context (as `_handle_error` already does) instead of only the inner span.
for identifier, integration in integrations.items():
with _installer_lock:
if identifier not in _processed_integrations:
Expand Down
Loading
Loading