diff --git a/src/agents/tracing/processors.py b/src/agents/tracing/processors.py index 1f8cfa9d4e..89042fe133 100644 --- a/src/agents/tracing/processors.py +++ b/src/agents/tracing/processors.py @@ -283,6 +283,8 @@ def _truncate_span_field_value(self, value: Any) -> Any: return self._truncate_json_value_for_limit(sanitized_value, max_bytes) + _TRUNCATED_PREVIEW_KEY = "__truncated_preview__" + def _truncate_json_value_for_limit(self, value: Any, max_bytes: int) -> Any: if self._value_json_size_bytes(value) <= max_bytes: return value @@ -291,6 +293,14 @@ def _truncate_json_value_for_limit(self, value: Any, max_bytes: int) -> Any: return self._truncate_string_for_json_limit(value, max_bytes) if isinstance(value, dict): + # Avoid re-truncating our own truncated preview dicts, which + # would cause infinite recursion (the preview dict contains bool + # values that get wrapped into new preview dicts, and so on). + # Use a sentinel key to reliably identify SDK-generated previews + # without matching arbitrary user data that happens to use the + # same key names. + if value.get(self._TRUNCATED_PREVIEW_KEY) is True and "original_type" in value and "preview" in value: + return value return self._truncate_mapping_for_json_limit(value, max_bytes) if isinstance(value, list): @@ -356,6 +366,7 @@ def _truncated_preview(self, value: Any) -> dict[str, Any]: preview = f"<{type_name} bytes={len(value)} truncated>" return { + self._TRUNCATED_PREVIEW_KEY: True, "truncated": True, "original_type": type_name, "preview": preview,