From bda2dbc29edc3f807bbc003227a428ec2a5245b2 Mon Sep 17 00:00:00 2001 From: briandevans <252620095+briandevans@users.noreply.github.com> Date: Sun, 26 Apr 2026 11:21:25 -0700 Subject: [PATCH] fix(compressor): apply bare-string guard to protect-tail boundary scan The bare-string isinstance guard added in 80ae2621 covered _find_tail_cut_by_tokens (line 1084) but missed the identical pattern in _calculate_protect_tail_boundary (line 487, the protect-tail scan loop). Both loops call .get("text", "") on every list item in message["content"]; both crash with AttributeError when that list contains a bare string. Apply the same dict/str/fallback isinstance guard to the protect-tail path. Co-Authored-By: Claude Opus 4.7 (1M context) --- agent/context_compressor.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/agent/context_compressor.py b/agent/context_compressor.py index 9f90a96163..887be7f7bf 100644 --- a/agent/context_compressor.py +++ b/agent/context_compressor.py @@ -484,7 +484,18 @@ class ContextCompressor(ContextEngine): for i in range(len(result) - 1, -1, -1): msg = result[i] raw_content = msg.get("content") or "" - content_len = sum(len(p.get("text", "")) for p in raw_content) if isinstance(raw_content, list) else len(raw_content) + content_len = ( + sum( + len(p.get("text", "")) + if isinstance(p, dict) + else len(p) + if isinstance(p, str) + else len(str(p)) + for p in raw_content + ) + if isinstance(raw_content, list) + else len(raw_content) + ) msg_tokens = content_len // _CHARS_PER_TOKEN + 10 for tc in msg.get("tool_calls") or []: if isinstance(tc, dict):