Skip to content
10 changes: 8 additions & 2 deletions sentry_sdk/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -479,16 +479,22 @@ class ReasoningPart(TypedDict):

class ToolCallPart(TypedDict):
type: Literal["tool_call"]
id: NotRequired[str]
name: NotRequired[str]
arguments: NotRequired[Any]

class ToolCallResponsePart(TypedDict):
type: Literal["tool_call_response"]
id: NotRequired[str]
result: NotRequired[Any]

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

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

class ToolDefinition(TypedDict):
type: str
Expand Down
6 changes: 6 additions & 0 deletions sentry_sdk/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,12 @@ class SPANDATA:
Example: "1234567890"
"""

GEN_AI_REQUEST_STOP_SEQUENCES = "gen_ai.request.stop_sequences"
"""
List of sequences that the model will use to stop generating further tokens.
Example: ["forest", "lived"]
"""

GEN_AI_REQUEST_TEMPERATURE = "gen_ai.request.temperature"
"""
The temperature parameter used to control randomness in the output.
Expand Down
5 changes: 5 additions & 0 deletions sentry_sdk/integrations/boto3/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ class Boto3Integration(Integration):
identifier = IDENTIFIER
origin = ORIGIN

def __init__(self: "Boto3Integration", include_prompts: bool = True) -> None:
# whether to record gen_ai prompts and responses, e.g. of Bedrock Runtime
# calls, when `send_default_pii` is on and `data_collection` isn't set.
self.include_prompts = include_prompts

@staticmethod
def setup_once() -> None:
version = parse_version(BOTOCORE_VERSION)
Expand Down
21 changes: 18 additions & 3 deletions sentry_sdk/integrations/boto3/_instrumentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,12 +176,18 @@ def _start_client_span(
with capture_internal_exceptions():
attributes.update(_get_client_attributes(ctx))

# `sentry.span_op` and `sentry.span_origin` are set to generic defaults;
# a service extension can override them with `get_span_op()` and `get_span_origin()`.
# the span name, `sentry.span_op`, and `sentry.span_origin` are set to generic defaults;
# a service extension can override them with `get_span_name()`, `get_span_op()`, and
# `get_span_origin()`.
span_op = OP.HTTP_CLIENT
span_origin = ORIGIN

if service_ext is not None:
with capture_internal_exceptions():
service_span_name = service_ext.get_span_name(ctx)
if service_span_name is not None:
span_name = service_span_name

with capture_internal_exceptions():
service_op = service_ext.get_span_op(ctx)
if service_op is not None:
Expand All @@ -207,13 +213,19 @@ def _start_client_span(
SPANDATA.SENTRY_ORIGIN: span_origin,
}
)
return sentry_sdk.traces.start_span(
streamed_span = sentry_sdk.traces.start_span(
name=span_name,
attributes=attributes,
# `StreamingBody` responses outlive `_make_api_call()`. `_activate_client_span()`
# activates this span only while the call itself runs.
active=False,
)
if service_ext is not None:
with capture_internal_exceptions():
streamed_span.set_attributes(
service_ext.get_span_start_attributes(ctx, streamed_span)
)
return streamed_span

span = sentry_sdk.start_span(
name=span_name,
Expand All @@ -222,6 +234,9 @@ def _start_client_span(
)
with capture_internal_exceptions():
_set_span_attributes(span, attributes)
if service_ext is not None:
with capture_internal_exceptions():
_set_span_attributes(span, service_ext.get_span_start_attributes(ctx, span))
Comment thread
sentry-junior[bot] marked this conversation as resolved.
Resolved
with capture_internal_exceptions():
if ctx.service_id_hyphenized is not None:
span.set_tag("aws.service_id", ctx.service_id_hyphenized)
Expand Down
18 changes: 17 additions & 1 deletion sentry_sdk/integrations/boto3/_services/base.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from typing import TYPE_CHECKING

if TYPE_CHECKING:
from typing import Any, Optional
from typing import Any, Optional, Union

from sentry_sdk._types import Attributes
from sentry_sdk.integrations.boto3._context import AwsCallContext
from sentry_sdk.traces import StreamedSpan
from sentry_sdk.tracing import Span


class _ServiceExtension:
Expand All @@ -17,6 +19,10 @@ class _ServiceExtension:

__slots__ = ()

def get_span_name(self, ctx: "AwsCallContext") -> "Optional[str]":
"""Return an optional span name override, or `None` to keep the default."""
return None

def get_span_op(self, ctx: "AwsCallContext") -> "Optional[str]":
"""Return an optional `sentry.op` override, or `None` to keep the default."""
return None
Expand All @@ -29,6 +35,16 @@ def get_request_attributes(self, ctx: "AwsCallContext") -> "Attributes":
"""Return request attributes to add before the AWS request is made."""
return {}

def get_span_start_attributes(
self, ctx: "AwsCallContext", span: "Union[Span, StreamedSpan]"
) -> "Attributes":
"""
Return request attributes that need the started span, e.g. truncated
`gen_ai` messages. Unlike `get_request_attributes()`, they're added after
the span starts, so `ignore_spans` doesn't see them.
"""
return {}

def get_response_attributes(
self, ctx: "AwsCallContext", response: "Any"
) -> "Attributes":
Expand Down
Loading
Loading