Skip to content

search_for_pattern: add a snippet stage to the overflow shortening chain#1667

Open
bymebyu wants to merge 2 commits into
oraios:mainfrom
bymebyu:feat/search-overflow-snippets
Open

search_for_pattern: add a snippet stage to the overflow shortening chain#1667
bymebyu wants to merge 2 commits into
oraios:mainfrom
bymebyu:feat/search-overflow-snippets

Conversation

@bymebyu

@bymebyu bymebyu commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Resolves #1640 (direction approved by @opcode81 in the issue).

Summary

When a search_for_pattern result exceeds max_answer_chars, the shortening chain
previously fell back from full match content directly to bare line numbers, so the
agent learned where the matches were but not what matched — and had to re-read files
to recover that. This adds one intermediate stage to the chain:

full matches → {"line": N, "text": "<matched text, truncated to 60 chars>"} → bare line numbers → per-file counts → summary

The snippet stage fits within the limit precisely when the matched lines are long (which
is exactly the case that makes full results overflow), and it degrades gracefully: if even
the snippets exceed the limit, the chain continues on to bare line numbers, per-file counts
and finally a summary, as before.

What the agent actually receives (deterministic)

Reproducible tool-level demonstration — a search with ~1,300 matches whose full result is
196,274 chars, against the default max_answer_chars of 150,000. The task is to find the one
match belonging to a specific class (Message777). This is the first fallback returned in
each case (the The answer is too long (…) banner is added by the framework in both):

Before — bare line numbers:

Match lines per file:
{"generated/pb_models.py": [23, 46, 69, …, 17848, 17871, 17894, 17917, 17940, … (~1300 numbers)]}

Line 17894 is indistinguishable from the other ~1,300 — to tell which match is Message777,
the agent has to open the file.

After — line number + matched text:

Match locations per file (line + matched text):
{"generated/pb_models.py": [ …,
  {"line": 17894, "text": "return cls(field_id=data.get('field_id', 777), field_name=da"}, … ]}

The distinguishing text (777) is inline, so the agent can pick the right match and issue a
targeted read_file — without re-reading the file just to discover what matched.

Changes

  • src/serena/tools/file_tools.py — snippet stage in SearchForPatternTool (adds a
    {line, text} intermediate and keeps a dedicated bare-line-numbers stage after it).
  • CHANGELOG.md — entry under Tools.

The motivating agent-level A/B measurement is described in #1640.

bymebyu added 2 commits July 3, 2026 02:40
When search results exceed max_answer_chars, the tool previously fell back
directly from full match content to bare line numbers, forcing the agent to
re-read files to understand what matched. This adds an intermediate stage
returning line numbers plus the matched text truncated to 60 characters:

  full matches -> {line, text-snippet} -> line numbers -> per-file counts -> summary

In an agent-level A/B benchmark (8 tasks x 5 trials, headless Claude agents),
the bare line-number overflow response caused the agent to time out in 2/5
trials on an overflow-search task; with the snippet stage it succeeded 5/5
with exact line answers.
The snippet stage's header restated "too long" (duplicating the framework's
overflow banner) and said "line ranges" although it emits single line points.
Replace it with a plain label consistent with the sibling shortening factories.
Also add the CHANGELOG entry under Tools.
Comment on lines 628 to +634
def make_lines_only() -> str:
"""Match locations without surrounding context"""
return f"Match lines per file:\n{self._to_json(match_lines_by_file)}"
"""Match locations with line number and truncated matched text."""
compact = {
path: [{"line": m["line"], "text": str(m["text"])[:_TEXT_TRUNCATE]} for m in lines]
for path, lines in match_lines_by_file.items()
}
return f"Match locations per file (line + matched text):\n{self._to_json(compact)}"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of adding a new stage to the shortening chain which adds truncation, this replaces the previous first stage, where the full first line is retained.

Also, for the new shortening stage, the LLM is not informed

  • that lines are truncated to _TEXT_TRUNCATE characters in general
  • which lines are truncated (could add an indicator like ... at the end of affected lines)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

search_for_pattern overflow fallback: agents time out on bare line numbers — proposal: intermediate snippet stage

2 participants