Skip to content

Commit ab0b6f4

Browse files
authored
Don't require mcp or logfire to use Temporal or DBOS (#2908)
1 parent 25fb3a6 commit ab0b6f4

File tree

4 files changed

+50
-26
lines changed

4 files changed

+50
-26
lines changed

pydantic_ai_slim/pydantic_ai/durable_exec/dbos/_agent.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
)
1616
from pydantic_ai.agent import AbstractAgent, AgentRun, AgentRunResult, EventStreamHandler, RunOutputDataT, WrapperAgent
1717
from pydantic_ai.exceptions import UserError
18-
from pydantic_ai.mcp import MCPServer
1918
from pydantic_ai.models import Model
2019
from pydantic_ai.output import OutputDataT, OutputSpec
2120
from pydantic_ai.result import StreamedRunResult
@@ -29,7 +28,6 @@
2928
)
3029
from pydantic_ai.toolsets import AbstractToolset
3130

32-
from ._mcp_server import DBOSMCPServer
3331
from ._model import DBOSModel
3432
from ._utils import StepConfig
3533

@@ -86,14 +84,21 @@ def __init__(
8684

8785
def dbosify_toolset(toolset: AbstractToolset[AgentDepsT]) -> AbstractToolset[AgentDepsT]:
8886
# Replace MCPServer with DBOSMCPServer
89-
if isinstance(toolset, MCPServer):
90-
return DBOSMCPServer(
91-
wrapped=toolset,
92-
step_name_prefix=dbosagent_name,
93-
step_config=self._mcp_step_config,
94-
)
87+
try:
88+
from pydantic_ai.mcp import MCPServer
89+
90+
from ._mcp_server import DBOSMCPServer
91+
except ImportError:
92+
pass
9593
else:
96-
return toolset
94+
if isinstance(toolset, MCPServer):
95+
return DBOSMCPServer(
96+
wrapped=toolset,
97+
step_name_prefix=dbosagent_name,
98+
step_config=self._mcp_step_config,
99+
)
100+
101+
return toolset
97102

98103
dbos_toolsets = [toolset.visit_and_replace(dbosify_toolset) for toolset in wrapped.toolsets]
99104
self._toolsets = dbos_toolsets

pydantic_ai_slim/pydantic_ai/durable_exec/dbos/_mcp_server.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,20 @@
22

33
from abc import ABC
44
from collections.abc import Callable
5-
from typing import Any
5+
from typing import TYPE_CHECKING, Any
66

77
from dbos import DBOS
88
from typing_extensions import Self
99

10-
from pydantic_ai.mcp import MCPServer, ToolResult
1110
from pydantic_ai.tools import AgentDepsT, RunContext
1211
from pydantic_ai.toolsets.abstract import AbstractToolset, ToolsetTool
1312
from pydantic_ai.toolsets.wrapper import WrapperToolset
1413

1514
from ._utils import StepConfig
1615

16+
if TYPE_CHECKING:
17+
from pydantic_ai.mcp import MCPServer, ToolResult
18+
1719

1820
class DBOSMCPServer(WrapperToolset[AgentDepsT], ABC):
1921
"""A wrapper for MCPServer that integrates with DBOS, turning call_tool and get_tools to DBOS steps."""

pydantic_ai_slim/pydantic_ai/durable_exec/temporal/_logfire.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
from __future__ import annotations
22

33
from collections.abc import Callable
4+
from typing import TYPE_CHECKING
45

5-
from logfire import Logfire
6-
from opentelemetry.trace import get_tracer
76
from temporalio.client import ClientConfig, Plugin as ClientPlugin
8-
from temporalio.contrib.opentelemetry import TracingInterceptor
97
from temporalio.runtime import OpenTelemetryConfig, Runtime, TelemetryConfig
108
from temporalio.service import ConnectConfig, ServiceClient
119

10+
if TYPE_CHECKING:
11+
from logfire import Logfire
12+
1213

1314
def _default_setup_logfire() -> Logfire:
1415
import logfire
@@ -22,13 +23,24 @@ class LogfirePlugin(ClientPlugin):
2223
"""Temporal client plugin for Logfire."""
2324

2425
def __init__(self, setup_logfire: Callable[[], Logfire] = _default_setup_logfire, *, metrics: bool = True):
26+
try:
27+
import logfire # noqa: F401 # pyright: ignore[reportUnusedImport]
28+
except ImportError as _import_error:
29+
raise ImportError(
30+
'Please install the `logfire` package to use the Logfire plugin, '
31+
'you can use the `logfire` optional group — `pip install "pydantic-ai-slim[logfire]"`'
32+
) from _import_error
33+
2534
self.setup_logfire = setup_logfire
2635
self.metrics = metrics
2736

2837
def init_client_plugin(self, next: ClientPlugin) -> None:
2938
self.next_client_plugin = next
3039

3140
def configure_client(self, config: ClientConfig) -> ClientConfig:
41+
from opentelemetry.trace import get_tracer
42+
from temporalio.contrib.opentelemetry import TracingInterceptor
43+
3244
interceptors = config.get('interceptors', [])
3345
config['interceptors'] = [*interceptors, TracingInterceptor(get_tracer('temporalio'))]
3446
return self.next_client_plugin.configure_client(config)

pydantic_ai_slim/pydantic_ai/durable_exec/temporal/_toolset.py

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
from temporalio.workflow import ActivityConfig
88

9-
from pydantic_ai.mcp import MCPServer
109
from pydantic_ai.tools import AgentDepsT
1110
from pydantic_ai.toolsets.abstract import AbstractToolset
1211
from pydantic_ai.toolsets.function import FunctionToolset
@@ -63,16 +62,22 @@ def temporalize_toolset(
6362
deps_type=deps_type,
6463
run_context_type=run_context_type,
6564
)
66-
elif isinstance(toolset, MCPServer):
67-
from ._mcp_server import TemporalMCPServer
6865

69-
return TemporalMCPServer(
70-
toolset,
71-
activity_name_prefix=activity_name_prefix,
72-
activity_config=activity_config,
73-
tool_activity_config=tool_activity_config,
74-
deps_type=deps_type,
75-
run_context_type=run_context_type,
76-
)
66+
try:
67+
from pydantic_ai.mcp import MCPServer
68+
69+
from ._mcp_server import TemporalMCPServer
70+
except ImportError:
71+
pass
7772
else:
78-
return toolset
73+
if isinstance(toolset, MCPServer):
74+
return TemporalMCPServer(
75+
toolset,
76+
activity_name_prefix=activity_name_prefix,
77+
activity_config=activity_config,
78+
tool_activity_config=tool_activity_config,
79+
deps_type=deps_type,
80+
run_context_type=run_context_type,
81+
)
82+
83+
return toolset

0 commit comments

Comments
 (0)