Skip to content

Commit 690079e

Browse files
authored
fix: #2863 lazy-load SQLiteSession exports (#2864)
1 parent fb67680 commit 690079e

File tree

3 files changed

+110
-3
lines changed

3 files changed

+110
-3
lines changed

src/agents/__init__.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import logging
22
import sys
3-
from typing import Literal
3+
from typing import TYPE_CHECKING, Any, Literal
44

55
from openai import AsyncOpenAI
66

@@ -74,7 +74,6 @@
7474
Session,
7575
SessionABC,
7676
SessionSettings,
77-
SQLiteSession,
7877
is_openai_responses_compaction_aware_session,
7978
)
8079
from .model_settings import ModelSettings
@@ -225,6 +224,19 @@
225224
from .usage import Usage
226225
from .version import __version__
227226

227+
if TYPE_CHECKING:
228+
from .memory.sqlite_session import SQLiteSession
229+
230+
231+
def __getattr__(name: str) -> Any:
232+
if name == "SQLiteSession":
233+
from .memory.sqlite_session import SQLiteSession
234+
235+
globals()[name] = SQLiteSession
236+
return SQLiteSession
237+
238+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
239+
228240

229241
def set_default_openai_key(key: str, use_for_tracing: bool = True) -> None:
230242
"""Set the default OpenAI API key to use for LLM requests (and optionally tracing()). This is

src/agents/memory/__init__.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
from __future__ import annotations
2+
3+
from typing import TYPE_CHECKING, Any
4+
15
from .openai_conversations_session import OpenAIConversationsSession
26
from .openai_responses_compaction_session import OpenAIResponsesCompactionSession
37
from .session import (
@@ -8,9 +12,11 @@
812
is_openai_responses_compaction_aware_session,
913
)
1014
from .session_settings import SessionSettings
11-
from .sqlite_session import SQLiteSession
1215
from .util import SessionInputCallback
1316

17+
if TYPE_CHECKING:
18+
from .sqlite_session import SQLiteSession
19+
1420
__all__ = [
1521
"Session",
1622
"SessionABC",
@@ -23,3 +29,13 @@
2329
"OpenAIResponsesCompactionAwareSession",
2430
"is_openai_responses_compaction_aware_session",
2531
]
32+
33+
34+
def __getattr__(name: str) -> Any:
35+
if name == "SQLiteSession":
36+
from .sqlite_session import SQLiteSession
37+
38+
globals()[name] = SQLiteSession
39+
return SQLiteSession
40+
41+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")

tests/tracing/test_import_side_effects.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,85 @@ def test_import_agents_has_no_tracing_side_effects() -> None:
6767
assert payload["shutdown_handler_registered"] is False
6868

6969

70+
def test_import_agents_does_not_require_sqlite3() -> None:
71+
payload = _run_python(
72+
"""
73+
import importlib.abc
74+
import json
75+
import sys
76+
77+
class BlockSqlite3(importlib.abc.MetaPathFinder):
78+
def find_spec(self, fullname, path, target=None):
79+
if fullname in {"sqlite3", "_sqlite3"}:
80+
raise ModuleNotFoundError(f"blocked optional backend module: {fullname}")
81+
return None
82+
83+
sys.meta_path.insert(0, BlockSqlite3())
84+
85+
import agents
86+
from agents import Agent, Runner
87+
from agents.memory import Session, SessionSettings
88+
89+
print(
90+
json.dumps(
91+
{
92+
"agent_name": Agent.__name__,
93+
"runner_name": Runner.__name__,
94+
"session_name": Session.__name__,
95+
"settings_name": SessionSettings.__name__,
96+
"sqlite3_loaded": "sqlite3" in sys.modules,
97+
"private_sqlite3_loaded": "_sqlite3" in sys.modules,
98+
"sqlite_session_loaded": "agents.memory.sqlite_session" in sys.modules,
99+
"sqlite_session_exported": "SQLiteSession" in agents.__all__,
100+
}
101+
)
102+
)
103+
"""
104+
)
105+
106+
assert payload["agent_name"] == "Agent"
107+
assert payload["runner_name"] == "Runner"
108+
assert payload["session_name"] == "Session"
109+
assert payload["settings_name"] == "SessionSettings"
110+
assert payload["sqlite3_loaded"] is False
111+
assert payload["private_sqlite3_loaded"] is False
112+
assert payload["sqlite_session_loaded"] is False
113+
assert payload["sqlite_session_exported"] is True
114+
115+
116+
def test_sqlite_session_top_level_export_is_lazy() -> None:
117+
payload = _run_python(
118+
"""
119+
import json
120+
import sys
121+
122+
import agents
123+
124+
loaded_after_import = "agents.memory.sqlite_session" in sys.modules
125+
126+
from agents import SQLiteSession
127+
128+
loaded_after_export = "agents.memory.sqlite_session" in sys.modules
129+
130+
print(
131+
json.dumps(
132+
{
133+
"sqlite_session_name": SQLiteSession.__name__,
134+
"loaded_after_import": loaded_after_import,
135+
"loaded_after_export": loaded_after_export,
136+
"sqlite3_loaded": "sqlite3" in sys.modules,
137+
}
138+
)
139+
)
140+
"""
141+
)
142+
143+
assert payload["sqlite_session_name"] == "SQLiteSession"
144+
assert payload["loaded_after_import"] is False
145+
assert payload["loaded_after_export"] is True
146+
assert payload["sqlite3_loaded"] is True
147+
148+
70149
def test_get_trace_provider_lazily_initializes_defaults() -> None:
71150
payload = _run_python(
72151
"""

0 commit comments

Comments
 (0)