Skip to content

Browse catalog

Search catalog

[READY] Type a title, tag, or description.

NOTES // snippet

Observation masking

LAST_MODIFIED
2026.07.29
CATEGORY
snippet

Observation masking keeps a rolling window of recent tool results and replaces older ones with a placeholder. The transcript still shows what the agent tried; the expensive bytes leave the billed context.

JetBrains Research on SWE-bench Verified (Qwen3-Coder 480B): a 10-turn masking window was 52% cheaper than unmanaged history with solve rate +2.6%. LLM summarization also cut cost over 50% but ran 13% longer - summaries can smooth over stop signals. Masking matched or beat summarization in 4 of 5 settings they tested.

MASK = "[tool output masked - older turn]"

def mask_observations(messages, keep_last=10, drop_failed=False):
    """Replace tool results outside the rolling window with a placeholder."""
    tool_turns = [i for i, m in enumerate(messages) if is_tool_result(m)]
    live = set(tool_turns[-keep_last:])
    out = []
    for i, m in enumerate(messages):
        if not is_tool_result(m) or i in live:
            out.append(m)
        elif drop_failed and is_error(m):
            continue
        else:
            out.append({**m, "content": MASK})
    return out

Two details that decide whether it saves money

  1. Mask before the call, not in stored history - keep the full log on disk; rewriting stored history can invalidate a cache-stable prefix.
  2. Mask in batches at a threshold - every mask changes the prefix from that point forward; re-masking one more turn on every call burns the cache.

Evidence and siblings: Prune the log, not the window. Discipline frame: Context engineering.

contextcostagentstokens

Related_Notes