From 0054b7e2802e1b83064eeafe36ddc29d7c078cbb Mon Sep 17 00:00:00 2001 From: Kazuhiro Sera Date: Wed, 8 Apr 2026 20:04:32 +0900 Subject: [PATCH] fix: #2856 stop recursive trace preview truncation --- src/agents/tracing/processors.py | 6 ++++- tests/test_trace_processor.py | 42 ++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/agents/tracing/processors.py b/src/agents/tracing/processors.py index 1f8cfa9d4e..10b4999615 100644 --- a/src/agents/tracing/processors.py +++ b/src/agents/tracing/processors.py @@ -296,7 +296,11 @@ def _truncate_json_value_for_limit(self, value: Any, max_bytes: int) -> Any: if isinstance(value, list): return self._truncate_list_for_json_limit(value, max_bytes) - return self._truncated_preview(value) + preview = self._truncated_preview(value) + if self._value_json_size_bytes(preview) <= max_bytes: + return preview + + return value def _truncate_mapping_for_json_limit( self, value: dict[str, Any], max_bytes: int diff --git a/tests/test_trace_processor.py b/tests/test_trace_processor.py index 1c917990d5..052ed904e6 100644 --- a/tests/test_trace_processor.py +++ b/tests/test_trace_processor.py @@ -920,6 +920,48 @@ def test_sanitize_for_openai_tracing_api_replaces_unserializable_output(): exporter.close() +def test_truncate_json_value_for_limit_terminates_preview_dict_under_zero_budget(): + exporter = BackendSpanExporter(api_key="test_key") + preview = exporter._truncated_preview(None) + + truncated = exporter._truncate_json_value_for_limit(preview, 0) + + assert truncated == {} + exporter.close() + + +def test_sanitize_for_openai_tracing_api_handles_none_content_under_tight_budget(): + exporter = BackendSpanExporter(api_key="test_key") + payload: dict[str, Any] = { + "object": "trace.span", + "span_data": { + "type": "generation", + "output": [ + { + "role": "assistant", + "content": None, + "name": "a" * 25_000, + "tool_calls": [], + } + for _ in range(8) + ], + "usage": {"input_tokens": 1, "output_tokens": 1}, + }, + } + + sanitized = exporter._sanitize_for_openai_tracing_api(payload) + sanitized_output = cast(list[Any], sanitized["span_data"]["output"]) + + assert isinstance(sanitized_output, list) + assert sanitized_output != payload["span_data"]["output"] + assert ( + exporter._value_json_size_bytes(sanitized_output) + <= exporter._OPENAI_TRACING_MAX_FIELD_BYTES + ) + assert any(item == {} for item in sanitized_output) + exporter.close() + + def test_truncate_string_for_json_limit_returns_original_when_within_limit(): exporter = BackendSpanExporter(api_key="test_key") value = "hello"