5 Commits

Author SHA1 Message Date
kshitijk4poor
ab84dc8d57 fix(context): drop stale _shrink reference in marker comment
_shrink was deleted along with _truncate_tool_call_args_json, so the
comment pointed at code that no longer exists.
2026-09-27 18:38:58 +05:30
kshitijk4poor
be834681dc fix(context): measure pruned regions, bound arg redaction, drop dead counters
Follow-ups to making tool-call args byte-exact:
- _record_compression_regions measured canonical_messages slices while
  compress_start/compress_end are indices into the pruned copy that head/tail
  are assembled from; measure the pruned rows actually sent, as before. This
  also removes the only canonical slicing, so blank-echo classification drift
  between the two copies can no longer misalign anything.
- _render_tool_call_for_summary redacted the full (now unbounded) args before
  cutting to 1200 chars; cut to head+4096 first. Output unchanged for args
  within that window.
- pressure_hits always equalled demoted once arg truncation left; fold it.
- Drop the fixture-only tautological assert in the guardrail test helper.
- Reword stale compress()/compression_marker docstrings that still described
  canonical head/tail and compressor-written arg markers.
2026-09-27 18:38:58 +05:30
kshitijk4poor
8bd34fbd5a refactor(agent): derive the elision marker from the args marker template
The guard only catches a copied elision marker because its first sentence is
byte-identical to _COMPRESSION_MARKER_TEMPLATE's; re-typing it by hand left
that invariant to a comment. Derive it the same way _COMPRESSION_MARKER_RE is
derived (verified byte-identical to the previous literal).

Also fix elide_middle(tail=0), where text[-0:] appended the whole text, and
expose ELISION_MARKER_MAX_LEN so callers with a small leftover budget can
skip an item instead of emitting a marker-only line.

Co-authored-by: ahisblessed <ahisblessed@users.noreply.github.com>
2026-09-26 23:49:25 +05:30
ahisblessed
77b9ea0831 fix(agent): route every model-visible elision through the non-imitable compression marker (#121548)
The #83714 fix hardened only the tool-call args renderer; five other
renderers (plus three same-idiom siblings) still composed the bare
truncation marker, which the model imitated from replayed context into
new durable writes (#83435).

This routes all model-visible elision in agent/ through shared helpers
in agent/compression_marker.py:

- elide(text, limit): head + marker cap with accurate omitted/total counts
- elide_middle(text, head, tail): kept head/tail with the middle elided

The elision marker's first sentence is byte-identical to the args marker's,
so the existing _COMPRESSION_MARKER_RE (and the dispatch-boundary guard in
tool_dispatch_helpers) rejects a copied marker regardless of which renderer
leaked it; only the tool-call-specific second sentence is dropped so the
marker still fits small caps (the clarify summary cap is 199 chars).

Routed sites:
- context_compressor.py: static-fallback turn renderer, _sum_clarify(),
  summarizer prompt builder (middle elision), active-task snapshot,
  lean user-message quotes (2 sites)
- skill_preprocessing.py: inline-shell output embedded into skill bodies
- lsp/reporter.py: truncate() for <diagnostics> tool output
- verification_stop.py: verify-on-stop nudge output summary

Regression test asserts the imitable idiom appears nowhere in agent/
strings (comments excluded), so a new open-coded renderer cannot land
silently.

Fixes #121548

(cherry picked from commit 69c63d50b4ababedf4fb4ff88c08f5d1e144a79f)
2026-09-26 23:49:25 +05:30
kshitijk4poor
159f716313 refactor(agent): derive the pruned-marker matcher from the compressor template
The dispatch-boundary detector re-typed the marker's wording next to the
producer's template and hid the import behind functools.lru_cache, citing a
context_compressor -> prompt_builder -> tool_dispatch_helpers cycle that does
not exist (prompt_builder only mentions this module in a comment; both import
orders succeed). Two copies of one string means a template edit silently
disables the guard.

Move the prefix/template into a dependency-free leaf, agent/compression_marker,
and build the regex from the template's first sentence with the count
placeholders swapped for \d[\d,]*. context_compressor re-exports the names, so
its callers and tests are unchanged. The matcher keeps the intended behaviour:
prefix-only mentions do not match; a minted marker, flat or nested, does. The
old \s+ tolerance for multiple spaces is dropped because the producer never
emits one, so only a template-shaped copy counts.

tool_dispatch_helpers stays light: importing it alone still does not load
context_compressor (auxiliary_client, context_engine, ...).
2026-09-24 16:29:19 +05:30