Skip to content

Commit cce0542

Browse files
committed
Merge remote-tracking branch 'upstream/main'
2 parents a5132a3 + 86739b1 commit cce0542

File tree

11 files changed

+317
-168
lines changed

11 files changed

+317
-168
lines changed

docs/ja/tracing.md

Lines changed: 48 additions & 56 deletions
Large diffs are not rendered by default.

docs/ko/tracing.md

Lines changed: 47 additions & 46 deletions
Large diffs are not rendered by default.

docs/tracing.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,3 +221,4 @@ The following community and vendor integrations support the OpenAI Agents SDK tr
221221
- [Traccia](https://traccia.ai/docs/integrations/openai-agents)
222222
- [PromptLayer](https://docs.promptlayer.com/languages/integrations#openai-agents-sdk)
223223
- [HoneyHive](https://docs.honeyhive.ai/v2/integrations/openai-agents)
224+
- [Asqav](https://www.asqav.com/docs/integrations#openai-agents)

docs/zh/tracing.md

Lines changed: 62 additions & 60 deletions
Large diffs are not rendered by default.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "openai-agents"
3-
version = "0.13.5"
3+
version = "0.13.6"
44
description = "OpenAI Agents SDK"
55
readme = "README.md"
66
requires-python = ">=3.10"

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
@@ -214,6 +213,19 @@
214213
from .usage import Usage
215214
from .version import __version__
216215

216+
if TYPE_CHECKING:
217+
from .memory.sqlite_session import SQLiteSession
218+
219+
220+
def __getattr__(name: str) -> Any:
221+
if name == "SQLiteSession":
222+
from .memory.sqlite_session import SQLiteSession
223+
224+
globals()[name] = SQLiteSession
225+
return SQLiteSession
226+
227+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
228+
217229

218230
def set_default_openai_key(key: str, use_for_tracing: bool = True) -> None:
219231
"""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}")

src/agents/tracing/processors.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,11 @@ def _truncate_json_value_for_limit(self, value: Any, max_bytes: int) -> Any:
296296
if isinstance(value, list):
297297
return self._truncate_list_for_json_limit(value, max_bytes)
298298

299-
return self._truncated_preview(value)
299+
preview = self._truncated_preview(value)
300+
if self._value_json_size_bytes(preview) <= max_bytes:
301+
return preview
302+
303+
return value
300304

301305
def _truncate_mapping_for_json_limit(
302306
self, value: dict[str, Any], max_bytes: int

tests/test_trace_processor.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -920,6 +920,48 @@ def test_sanitize_for_openai_tracing_api_replaces_unserializable_output():
920920
exporter.close()
921921

922922

923+
def test_truncate_json_value_for_limit_terminates_preview_dict_under_zero_budget():
924+
exporter = BackendSpanExporter(api_key="test_key")
925+
preview = exporter._truncated_preview(None)
926+
927+
truncated = exporter._truncate_json_value_for_limit(preview, 0)
928+
929+
assert truncated == {}
930+
exporter.close()
931+
932+
933+
def test_sanitize_for_openai_tracing_api_handles_none_content_under_tight_budget():
934+
exporter = BackendSpanExporter(api_key="test_key")
935+
payload: dict[str, Any] = {
936+
"object": "trace.span",
937+
"span_data": {
938+
"type": "generation",
939+
"output": [
940+
{
941+
"role": "assistant",
942+
"content": None,
943+
"name": "a" * 25_000,
944+
"tool_calls": [],
945+
}
946+
for _ in range(8)
947+
],
948+
"usage": {"input_tokens": 1, "output_tokens": 1},
949+
},
950+
}
951+
952+
sanitized = exporter._sanitize_for_openai_tracing_api(payload)
953+
sanitized_output = cast(list[Any], sanitized["span_data"]["output"])
954+
955+
assert isinstance(sanitized_output, list)
956+
assert sanitized_output != payload["span_data"]["output"]
957+
assert (
958+
exporter._value_json_size_bytes(sanitized_output)
959+
<= exporter._OPENAI_TRACING_MAX_FIELD_BYTES
960+
)
961+
assert any(item == {} for item in sanitized_output)
962+
exporter.close()
963+
964+
923965
def test_truncate_string_for_json_limit_returns_original_when_within_limit():
924966
exporter = BackendSpanExporter(api_key="test_key")
925967
value = "hello"

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)