Skip to content

Commit a8a9785

Browse files
polish: pr feedback.
1 parent f7549cd commit a8a9785

4 files changed

Lines changed: 31 additions & 48 deletions

File tree

instrumentation-genai/opentelemetry-instrumentation-anthropic/src/opentelemetry/instrumentation/anthropic/patch.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,6 @@
2727
)
2828
from opentelemetry.util.genai.handler import TelemetryHandler
2929
from opentelemetry.util.genai.invocation import InferenceInvocation
30-
from opentelemetry.util.genai.utils import (
31-
should_capture_content_on_spans_in_experimental_mode,
32-
)
3330

3431
from .messages_extractors import (
3532
extract_params,
@@ -113,7 +110,10 @@ def _create_invocation(
113110
args: tuple[Any, ...],
114111
kwargs: dict[str, Any],
115112
) -> tuple[InferenceInvocation, bool]:
116-
capture_content = should_capture_content_on_spans_in_experimental_mode()
113+
should_capture_content = cast(
114+
"Callable[[], bool]", getattr(handler, "should_capture_content")
115+
)
116+
capture_content = should_capture_content()
117117
params = extract_params(*args, **kwargs)
118118
attributes = get_llm_request_attributes(params, instance)
119119
request_model_attribute = attributes.get(
@@ -145,7 +145,7 @@ def messages_stream(
145145
"""Wrap the sync `stream` method of the `Messages` class."""
146146

147147
def traced_method(
148-
wrapped: Callable[..., "MessageStreamManager[Any]"],
148+
wrapped: Callable[..., "MessageStreamManager"],
149149
instance: "Messages",
150150
args: tuple[Any, ...],
151151
kwargs: dict[str, Any],

instrumentation-genai/opentelemetry-instrumentation-anthropic/src/opentelemetry/instrumentation/anthropic/utils.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import base64
2020
import json
2121
from dataclasses import dataclass
22-
from typing import TYPE_CHECKING, Any
22+
from typing import TYPE_CHECKING, Any, cast
2323

2424
from anthropic.types import (
2525
InputJSONDelta,
@@ -160,12 +160,9 @@ def _convert_content_block_to_part(
160160
id=block.tool_use_id,
161161
)
162162

163-
# ContentBlockParam variants are TypedDicts (dicts at runtime);
164-
# newer SDK versions may add Pydantic block types not handled above.
165-
if isinstance(block, dict):
166-
return _convert_dict_block_to_part(block)
167-
168-
return None
163+
if not hasattr(block, "get"):
164+
return None
165+
return _convert_dict_block_to_part(cast("Mapping[str, Any]", block))
169166

170167

171168
def convert_content_to_parts(

instrumentation-genai/opentelemetry-instrumentation-anthropic/src/opentelemetry/instrumentation/anthropic/wrappers.py

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,6 @@
2828
cast,
2929
)
3030

31-
from opentelemetry.util.genai.types import (
32-
Error,
33-
)
34-
3531
from .messages_extractors import set_invocation_response_attributes
3632

3733
try:
@@ -58,6 +54,8 @@
5854
)
5955
from anthropic.types.parsed_message import ParsedMessage
6056

57+
from opentelemetry.util.genai.invocation import InferenceInvocation
58+
6159

6260
_logger = logging.getLogger(__name__)
6361
ResponseT = TypeVar("ResponseT")
@@ -66,7 +64,7 @@
6664

6765

6866
def _set_response_attributes(
69-
invocation: Any,
67+
invocation: "InferenceInvocation",
7068
result: "Message | None",
7169
capture_content: bool,
7270
) -> None:
@@ -110,7 +108,7 @@ def __init__(self, message: Message, capture_content: bool):
110108
self._message = message
111109
self._capture_content = capture_content
112110

113-
def extract_into(self, invocation: Any) -> None:
111+
def extract_into(self, invocation: "InferenceInvocation") -> None:
114112
"""Extract response data into the invocation."""
115113
set_invocation_response_attributes(
116114
invocation, self._message, self._capture_content
@@ -133,7 +131,7 @@ class MessagesStreamWrapper(
133131
def __init__(
134132
self,
135133
stream: "Stream[RawMessageStreamEvent] | MessageStream[ResponseFormatT]",
136-
invocation: Any,
134+
invocation: "InferenceInvocation",
137135
capture_content: bool,
138136
):
139137
self.stream = stream
@@ -153,9 +151,7 @@ def __exit__(
153151
) -> bool:
154152
try:
155153
if exc_type is not None:
156-
self._fail(
157-
str(exc_val), type(exc_val) if exc_val else Exception
158-
)
154+
self._fail(exc_val or Exception())
159155
finally:
160156
self.close()
161157
return False
@@ -178,7 +174,7 @@ def __next__(
178174
self._stop()
179175
raise
180176
except Exception as exc:
181-
self._fail(str(exc), type(exc))
177+
self._fail(exc)
182178
raise
183179
with self._safe_instrumentation("stream chunk processing"):
184180
self._process_chunk(chunk)
@@ -202,11 +198,11 @@ def _stop(self) -> None:
202198
self.invocation.stop()
203199
self._finalized = True
204200

205-
def _fail(self, message: str, error_type: type[BaseException]) -> None:
201+
def _fail(self, exc: BaseException) -> None:
206202
if self._finalized:
207203
return
208204
with self._safe_instrumentation("invocation fail"):
209-
self.invocation.fail(Error(message=message, type=error_type))
205+
self.invocation.fail(exc)
210206
self._finalized = True
211207

212208
@staticmethod
@@ -251,7 +247,7 @@ class AsyncMessagesStreamWrapper(MessagesStreamWrapper[ResponseFormatT]):
251247
def __init__(
252248
self,
253249
stream: "AsyncStream[RawMessageStreamEvent] | AsyncMessageStream[ResponseFormatT]",
254-
invocation: Any,
250+
invocation: "InferenceInvocation",
255251
capture_content: bool,
256252
):
257253
self.stream = stream
@@ -273,9 +269,7 @@ async def __aexit__(
273269
) -> bool:
274270
try:
275271
if exc_type is not None:
276-
self._fail(
277-
str(exc_val), type(exc_val) if exc_val else Exception
278-
)
272+
self._fail(exc_val or Exception())
279273
finally:
280274
await self.close()
281275
return False
@@ -302,7 +296,7 @@ async def __anext__(
302296
self._stop()
303297
raise
304298
except Exception as exc:
305-
self._fail(str(exc), type(exc))
299+
self._fail(exc)
306300
raise
307301
with self._safe_instrumentation("stream chunk processing"):
308302
self._process_chunk(chunk)
@@ -315,7 +309,7 @@ class MessagesStreamManagerWrapper(Generic[ResponseFormatT]):
315309
def __init__(
316310
self,
317311
manager: "MessageStreamManager[ResponseFormatT]",
318-
invocation: Any,
312+
invocation: "InferenceInvocation",
319313
capture_content: bool,
320314
):
321315
self._manager = manager
@@ -374,7 +368,7 @@ class AsyncMessagesStreamManagerWrapper(Generic[ResponseFormatT]):
374368
def __init__(
375369
self,
376370
manager: "AsyncMessageStreamManager[ResponseFormatT]",
377-
invocation: Any,
371+
invocation: "InferenceInvocation",
378372
capture_content: bool,
379373
):
380374
self._manager = manager

instrumentation-genai/opentelemetry-instrumentation-anthropic/tests/test_async_wrappers.py

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -192,17 +192,15 @@ def test_sync_stream_wrapper_exit_fails_and_closes_on_exception():
192192
failures = []
193193

194194
wrapper._stop = lambda: stopped.append(True)
195-
wrapper._fail = lambda message, error_type: failures.append(
196-
(message, error_type)
197-
)
195+
wrapper._fail = failures.append
198196

199197
error = ValueError("boom")
200198
result = wrapper.__exit__(ValueError, error, None)
201199

202200
assert result is False
203201
assert stream.close_calls == 1
204202
assert stopped == [True]
205-
assert failures == [("boom", ValueError)]
203+
assert failures == [error]
206204

207205

208206
def test_sync_stream_wrapper_processes_events_and_stops_on_completion():
@@ -232,14 +230,12 @@ def test_sync_stream_wrapper_fails_and_reraises_stream_errors():
232230
wrapper = _make_stream_wrapper(stream)
233231
failures = []
234232

235-
wrapper._fail = lambda message, error_type: failures.append(
236-
(message, error_type)
237-
)
233+
wrapper._fail = failures.append
238234

239235
with pytest.raises(ValueError, match="boom"):
240236
next(wrapper)
241237

242-
assert failures == [("boom", ValueError)]
238+
assert failures == [error]
243239

244240

245241
def test_sync_stream_wrapper_getattr_passthrough():
@@ -376,17 +372,15 @@ async def test_async_stream_wrapper_exit_fails_and_closes_on_exception():
376372
failures = []
377373

378374
wrapper._stop = lambda: stopped.append(True)
379-
wrapper._fail = lambda message, error_type: failures.append(
380-
(message, error_type)
381-
)
375+
wrapper._fail = failures.append
382376

383377
error = ValueError("boom")
384378
result = await wrapper.__aexit__(ValueError, error, None)
385379

386380
assert result is False
387381
assert stream.close_calls == 1
388382
assert stopped == [True]
389-
assert failures == [("boom", ValueError)]
383+
assert failures == [error]
390384

391385

392386
@pytest.mark.asyncio
@@ -432,14 +426,12 @@ async def test_async_stream_wrapper_fails_and_reraises_stream_errors():
432426
wrapper = _make_async_stream_wrapper(stream)
433427
failures = []
434428

435-
wrapper._fail = lambda message, error_type: failures.append(
436-
(message, error_type)
437-
)
429+
wrapper._fail = failures.append
438430

439431
with pytest.raises(ValueError, match="boom"):
440432
await anext(wrapper)
441433

442-
assert failures == [("boom", ValueError)]
434+
assert failures == [error]
443435

444436

445437
@pytest.mark.asyncio

0 commit comments

Comments
 (0)