perf(logging): skip the base64 data URI scan and thread hop for text without a data URI

This commit is contained in:
mateo-berri 2026-10-28 22:38:17 -07:00
parent 764a7a6536
commit 0cecc9ea94
2 changed files with 67 additions and 5 deletions

View file

@ -44,6 +44,7 @@ Helper utils used for logging callbacks
# Regex matching data-URI base64 content: "data:<mime>;base64,<payload>"
# Captures: group(1)=mime_type, group(2)=base64_payload
_DATA_URI_RE: Final = re.compile(r"data:([^;,\s]{1,255});base64,([A-Za-z0-9+/=]+)")
_DATA_URI_BASE64_MARKER: Final = ";base64,"
# Maximum nesting depth for _truncate_base64_in_value to guard against
# pathological payloads. OpenAI message format is typically 3-4 levels deep.
@ -60,9 +61,13 @@ def _base64_data_uri_replacer(match: re.Match[str]) -> str:
return f"data:{mime_type};base64,[base64_data truncated: {size_str}]"
def _may_contain_base64_data_uri(value: str) -> bool:
return ";" in value and _DATA_URI_BASE64_MARKER in value
def _truncate_base64_in_string(value: str) -> str:
"""Replace long base64 data-URI payloads in a string with a size placeholder."""
if MAX_BASE64_LENGTH_FOR_LOGGING <= 0:
if MAX_BASE64_LENGTH_FOR_LOGGING <= 0 or not _may_contain_base64_data_uri(value):
return value
return _DATA_URI_RE.sub(_base64_data_uri_replacer, value)
@ -155,14 +160,16 @@ async def truncate_base64_in_messages_async(
messages: str | list | dict | None, # mutable-ok: same contract as truncate_base64_in_messages
) -> str | list | dict | None: # mutable-ok: same contract as truncate_base64_in_messages
"""
Same result as truncate_base64_in_messages, but payloads whose string content
reaches BASE64_TRUNCATION_OFFLOAD_THRESHOLD_CHARS are scanned in a worker
Same result as truncate_base64_in_messages, but payloads whose data-URI-bearing
strings reach BASE64_TRUNCATION_OFFLOAD_THRESHOLD_CHARS are scanned in a worker
thread so the regex pass over multi-MB base64 images does not block the event loop.
"""
if messages is None or MAX_BASE64_LENGTH_FOR_LOGGING <= 0:
return messages
total_chars: Final = sum(len(leaf) for leaf in _iter_string_leaves(messages))
if total_chars < BASE64_TRUNCATION_OFFLOAD_THRESHOLD_CHARS:
data_uri_chars: Final = sum(
len(leaf) for leaf in _iter_string_leaves(messages) if _may_contain_base64_data_uri(leaf)
)
if data_uri_chars < BASE64_TRUNCATION_OFFLOAD_THRESHOLD_CHARS:
return truncate_base64_in_messages(messages)
return await asyncio.to_thread(truncate_base64_in_messages, messages)

View file

@ -241,6 +241,38 @@ def scan_threads(monkeypatch):
return threads
@pytest.fixture
def regex_scans(monkeypatch):
"""Record every string the data URI regex runs over."""
scanned: list[str] = []
original = logging_utils._DATA_URI_RE
class RecordingPattern:
def sub(self, repl, string: str) -> str:
scanned.append(string)
return original.sub(repl, string)
monkeypatch.setattr(logging_utils, "_DATA_URI_RE", RecordingPattern())
return scanned
def _tool_result_messages(tool_output: str) -> list:
return [
{"role": "user", "content": "Summarize the rows the tool returned."},
{
"role": "assistant",
"content": None,
"tool_calls": [
{"id": "call_1", "type": "function", "function": {"name": "dump_rows", "arguments": "{}"}}
],
},
{"role": "tool", "tool_call_id": "call_1", "content": tool_output},
]
_PLAIN_TOOL_OUTPUT_CHARS = 400 * 1024
class TestTruncateBase64InMessagesAsync:
@pytest.mark.asyncio
async def test_large_payload_is_scanned_off_the_event_loop(self, monkeypatch, scan_threads):
@ -268,6 +300,29 @@ class TestTruncateBase64InMessagesAsync:
assert scan_threads
assert set(scan_threads) == {threading.get_ident()}
@pytest.mark.asyncio
@pytest.mark.parametrize(
"row",
[
'{"id": 7, "name": "widget", "status": "ok"}\n',
"data: {\"choices\": [{\"delta\": {\"content\": \"hi\"}}]}\n\n",
"const total = rows.map((r) => r.price).reduce((a, b) => a + b, 0);\n",
],
ids=["json_rows", "sse_lines", "code_with_semicolons"],
)
async def test_tool_message_without_data_uri_skips_the_regex_and_the_thread_hop(
self, scan_threads, regex_scans, row
):
tool_output = (row * (_PLAIN_TOOL_OUTPUT_CHARS // len(row) + 1))[:_PLAIN_TOOL_OUTPUT_CHARS]
messages = _tool_result_messages(tool_output)
result = await truncate_base64_in_messages_async(messages)
assert result == messages
assert regex_scans == []
assert scan_threads
assert set(scan_threads) == {threading.get_ident()}
@pytest.mark.asyncio
async def test_none_and_disabled_truncation_short_circuit(self, monkeypatch, scan_threads):
assert await truncate_base64_in_messages_async(None) is None