mirror of
https://github.com/headroomlabs-ai/headroom.git
synced 2026-08-27 14:17:10 -04:00
fix(proxy/interceptors): validate truncation window length, not absolute end index
_is_plausible_truncation_range compared end_line directly against the payload's line count, which only holds when a read starts at line 1. For an offset read (e.g. "showing lines 100-148 of 300"), the payload only contains that window's ~49 lines, so the check silently rejected a genuinely truncated, correctly-formatted banner. Validate the inclusive window length (end_line - start_line + 1) instead, which is invariant to where the window starts. Also collapses test_astgrep_flags_truncated_read onto the _read_result_messages() helper introduced later in the same file, removing a leftover duplicate. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
2432a43d85
commit
ed67f5bd9f
2 changed files with 34 additions and 18 deletions
|
|
@ -111,7 +111,8 @@ def _is_plausible_truncation_range(
|
|||
# end_line == total_lines means the whole file was shown, not truncated.
|
||||
if start_line < 1 or end_line < start_line or end_line >= total_lines:
|
||||
return False
|
||||
return end_line <= source_line_count
|
||||
window_length = end_line - start_line + 1
|
||||
return window_length <= source_line_count
|
||||
|
||||
|
||||
def _detect_truncation(source: str) -> tuple[int, int] | None:
|
||||
|
|
|
|||
|
|
@ -221,23 +221,7 @@ def test_astgrep_flags_truncated_read(tokenizer):
|
|||
"showing lines 1-42 of 90 total (26031 tokens, cap 25000). "
|
||||
"Call Read with offset=43 to see more.]\n"
|
||||
)
|
||||
messages = [
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": [
|
||||
{
|
||||
"type": "tool_use",
|
||||
"id": "abc",
|
||||
"name": "Read",
|
||||
"input": {"file_path": "/repo/payments.py"},
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": [{"type": "tool_result", "tool_use_id": "abc", "content": truncated_source}],
|
||||
},
|
||||
]
|
||||
messages = _read_result_messages(truncated_source)
|
||||
result = apply_to_messages(messages, tokenizer)
|
||||
assert len(result.spans) == 1
|
||||
new_content = result.messages[1]["content"][0]["content"]
|
||||
|
|
@ -343,6 +327,37 @@ def test_astgrep_accepts_truncation_at_start_equals_end(tokenizer):
|
|||
assert "showing through line 42 of 90 total" in new_content
|
||||
|
||||
|
||||
def test_astgrep_flags_truncated_read_offset_window(tokenizer):
|
||||
"""A legitimate offset read (not starting at line 1) must still be
|
||||
recognized -- window length, not the absolute end index, is what's
|
||||
checked against the visible payload."""
|
||||
truncated_source = (
|
||||
_PY_FIXTURE + "\n\n[Truncated: PARTIAL view — /repo/payments.py: "
|
||||
"showing lines 100-148 of 300 total (26031 tokens, cap 25000). "
|
||||
"Call Read with offset=149 to see more.]\n"
|
||||
)
|
||||
messages = _read_result_messages(truncated_source)
|
||||
result = apply_to_messages(messages, tokenizer)
|
||||
new_content = result.messages[1]["content"][0]["content"]
|
||||
assert "truncated upstream" in new_content
|
||||
assert "showing through line 148 of 300 total" in new_content
|
||||
|
||||
|
||||
def test_astgrep_ignores_offset_window_exceeding_visible_payload(tokenizer):
|
||||
"""An offset window is still checked for plausibility -- a claimed
|
||||
window far longer than what's actually visible must not trigger."""
|
||||
truncated_source = (
|
||||
_PY_FIXTURE + "\n\n[Truncated: PARTIAL view — /repo/payments.py: "
|
||||
"showing lines 100-5148 of 9999 total (26031 tokens, cap 25000). "
|
||||
"Call Read with offset=5149 to see more.]\n"
|
||||
)
|
||||
messages = _read_result_messages(truncated_source)
|
||||
result = apply_to_messages(messages, tokenizer)
|
||||
new_content = result.messages[1]["content"][0]["content"]
|
||||
assert "outlined by ast-grep" in new_content
|
||||
assert "truncated upstream" not in new_content
|
||||
|
||||
|
||||
def test_astgrep_skips_small_files(tokenizer):
|
||||
small = "def foo(): return 1\n"
|
||||
messages = [
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue