Skip to content

Commit 4ae8604

Browse files
ref(pydantic-ai): Replace individual hooks with hooks.on.model_request (#7327)
1 parent ff68468 commit 4ae8604

2 files changed

Lines changed: 13 additions & 79 deletions

File tree

sentry_sdk/integrations/pydantic_ai/__init__.py

Lines changed: 13 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import functools
22

33
from sentry_sdk.integrations import DidNotEnable, Integration
4-
from sentry_sdk.utils import capture_internal_exceptions, parse_version
4+
from sentry_sdk.utils import parse_version
55

66
try:
77
import pydantic_ai # noqa: F401
@@ -24,7 +24,7 @@
2424
from typing import Any
2525

2626
from pydantic_ai import ModelRequestContext, RunContext
27-
from pydantic_ai.capabilities import Hooks
27+
from pydantic_ai.capabilities import Hooks, WrapModelRequestHandler
2828
from pydantic_ai.messages import ModelResponse
2929

3030

@@ -33,67 +33,24 @@ def register_hooks(hooks: "Hooks") -> None:
3333
Creates hooks for chat model calls and register the hooks by adding the hooks to the `capabilities` argument passed to `Agent.__init__()`.
3434
"""
3535

36-
@hooks.on.before_model_request
37-
async def on_request(
38-
ctx: "RunContext[None]", request_context: "ModelRequestContext"
39-
) -> "ModelRequestContext":
40-
run_context_metadata = ctx.metadata
41-
if not isinstance(run_context_metadata, dict):
42-
return request_context
43-
44-
span = ai_client_span(
45-
messages=request_context.messages,
46-
agent=None,
47-
model=request_context.model,
48-
model_settings=request_context.model_settings,
49-
)
50-
51-
run_context_metadata["_sentry_span"] = span
52-
span.__enter__()
53-
54-
return request_context
55-
56-
@hooks.on.after_model_request
57-
async def on_response(
36+
@hooks.on.model_request
37+
async def on_model_request(
5838
ctx: "RunContext[None]",
5939
*,
6040
request_context: "ModelRequestContext",
61-
response: "ModelResponse",
41+
handler: "WrapModelRequestHandler",
6242
) -> "ModelResponse":
63-
run_context_metadata = ctx.metadata
64-
if not isinstance(run_context_metadata, dict):
65-
return response
43+
with ai_client_span(
44+
messages=request_context.messages,
45+
agent=None,
46+
model=request_context.model,
47+
model_settings=request_context.model_settings,
48+
) as span:
49+
response = await handler(request_context)
6650

67-
span = run_context_metadata.pop("_sentry_span", None)
68-
if span is None:
51+
update_ai_client_span(span, response)
6952
return response
7053

71-
update_ai_client_span(span, response)
72-
span.__exit__(None, None, None)
73-
74-
return response
75-
76-
@hooks.on.model_request_error
77-
async def on_error(
78-
ctx: "RunContext[None]",
79-
*,
80-
request_context: "ModelRequestContext",
81-
error: "Exception",
82-
) -> "ModelResponse":
83-
run_context_metadata = ctx.metadata
84-
85-
if not isinstance(run_context_metadata, dict):
86-
raise error
87-
88-
span = run_context_metadata.pop("_sentry_span", None)
89-
if span is None:
90-
raise error
91-
92-
with capture_internal_exceptions():
93-
span.__exit__(type(error), error, error.__traceback__)
94-
95-
raise error
96-
9754
original_init = Agent.__init__
9855

9956
@functools.wraps(original_init)
@@ -102,10 +59,6 @@ def patched_init(self: "Agent[Any, Any]", *args: "Any", **kwargs: "Any") -> None
10259
caps.append(hooks)
10360
kwargs["capabilities"] = caps
10461

105-
metadata = kwargs.get("metadata")
106-
if metadata is None:
107-
kwargs["metadata"] = {} # Used as shared reference between hooks
108-
10962
return original_init(self, *args, **kwargs)
11063

11164
Agent.__init__ = patched_init # type: ignore[method-assign]
@@ -129,7 +82,6 @@ class PydanticAIIntegration(Integration):
12982

13083
identifier = "pydantic_ai"
13184
origin = f"auto.ai.{identifier}"
132-
using_request_hooks = False
13385

13486
def __init__(
13587
self, include_prompts: bool = True, handled_tool_call_exceptions: bool = True
@@ -159,7 +111,6 @@ def setup_once() -> None:
159111
_patch_agent_run()
160112
_patch_tool_execution()
161113

162-
PydanticAIIntegration.using_request_hooks = False
163114
try:
164115
PYDANTIC_AI_VERSION = version("pydantic-ai-slim")
165116
except PackageNotFoundError:
@@ -182,6 +133,5 @@ def setup_once() -> None:
182133
except ImportError:
183134
return
184135

185-
PydanticAIIntegration.using_request_hooks = True
186136
hooks = Hooks()
187137
register_hooks(hooks)

sentry_sdk/integrations/pydantic_ai/patches/agent_run.py

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,6 @@ def _create_run_wrapper(
9595
original_func: The original run method
9696
is_streaming: Whether this is a streaming method (for future use)
9797
"""
98-
from sentry_sdk.integrations.pydantic_ai import (
99-
PydanticAIIntegration,
100-
) # Required to avoid circular import
10198

10299
@wraps(original_func)
103100
async def wrapper(self: "Any", *args: "Any", **kwargs: "Any") -> "Any":
@@ -109,11 +106,6 @@ async def wrapper(self: "Any", *args: "Any", **kwargs: "Any") -> "Any":
109106
model = kwargs.get("model")
110107
model_settings = kwargs.get("model_settings")
111108

112-
if PydanticAIIntegration.using_request_hooks:
113-
metadata = kwargs.get("metadata")
114-
if metadata is None:
115-
kwargs["metadata"] = {"_sentry_span": None}
116-
117109
# Create invoke_agent span
118110
with invoke_agent_span(
119111
user_prompt, self, model, model_settings, is_streaming
@@ -147,9 +139,6 @@ def _create_streaming_wrapper(
147139
"""
148140
Wraps run_stream method that returns an async context manager.
149141
"""
150-
from sentry_sdk.integrations.pydantic_ai import (
151-
PydanticAIIntegration,
152-
) # Required to avoid circular import
153142

154143
@wraps(original_func)
155144
def wrapper(self: "Any", *args: "Any", **kwargs: "Any") -> "Any":
@@ -158,11 +147,6 @@ def wrapper(self: "Any", *args: "Any", **kwargs: "Any") -> "Any":
158147
model = kwargs.get("model")
159148
model_settings = kwargs.get("model_settings")
160149

161-
if PydanticAIIntegration.using_request_hooks:
162-
metadata = kwargs.get("metadata")
163-
if metadata is None:
164-
kwargs["metadata"] = {"_sentry_span": None}
165-
166150
# Call original function to get the context manager
167151
original_ctx_manager = original_func(self, *args, **kwargs)
168152

0 commit comments

Comments
 (0)