Repository navigation
Conversation
…arizer instructions as system + turns as user The context-compression summarizer built one giant user message: preamble, turns, structure template and focus guidance all in a single slot. Every other auxiliary caller in the repo (title generator, smart approval, MCP sampling, TTS) already sends [system, user]. Why: providers train the instruction hierarchy on the role split, so a directive smuggled inside a compacted turn now competes with a *user* message rather than sitting beside the summarizer's own instructions; it is the canonical shape for Chat Completions and for the Responses instructions/input pair; and the static instruction block becomes a stable, cacheable prefix across compactions instead of being interleaved with per-call content. Prompt prose is byte-identical (the section instructions are pinned for Azure content filters); only the data blocks (PREVIOUS SUMMARY / TURNS TO SUMMARIZE / memory-provider context) move to the user message. Tests that read the summarizer request now join every message rather than slot 0, which is also the correct redaction assertion (secrets must be absent from the WHOLE request).
૮ >ﻌ< ა ci reviewran on 556bc2a — test: pin the summarizer request roles (system instructions, debug infoCI timingsCI timings · View report · View jobWall time 23m37s vs 21m11s (+11.5%). 10 job(s) slower, 7 faster, 1 unchanged.
|
|
One instruction-hierarchy regression in the new split: |
|
Numbers for the stacked successor: on its own, this split moves laundering 72.2% → 60.6% (z=1.48, null) on 12 real sessions × 3 weak summarizers. With typed turns on top, it reaches 19.4% (z=6.36). That work is #154891, which includes both commits from this PR unchanged. Landing #154891 lands this one. |
The context-compression summarizer now sends its instructions as a
systemmessage and the turns to summarize as ausermessage, instead of one giantusermessage. Port of OpenHands/software-agent-sdk#5143.Changes
agent/context_compressor.py::_build_summary_promptreturns[system, user]: preamble + task framing + structure template + focus guidance insystem;PREVIOUS SUMMARY/TURNS TO SUMMARIZE/ memory-provider context inuser. Prompt prose is byte-identical (the section instructions are pinned for Azure content filters); only the data blocks move._call_summary_llm(messages, …)takes the pair;prompt_charslog line sums both slots.TestSummaryRequestRoles(2 invariants, red on base): instructions never share a message with turn content; iterative update keeps the previous summary in the user slot.Why
system/userand the Responsesinstructions/inputpair; every other auxiliary caller in the repo (title_generator,approval_smart,mcp_tool_sampling,tts_tool_providers) already sends this shape. The compaction summarizer was the outlier.Validation
call_llm→ loopback OpenAI-compatible server, before (origin/main)roles=['user'], one 6,131-char messageroles=['system','user']: 5,962-char instructions, 167-char turnsTestSummaryRequestRoleson base / headtests/agent/*compress* *compaction* *summar* *auxiliary* test_lean_single_aux_call test_context_engine* test_pre_compress_memory_context(160 files)TestResolveVisionCustomProvider) are cron-shell env leakage, green underenv -i, untouched by this PRruff,check_no_tmp_literals,check-windows-footguns,git diff --checkRoot cause: the summarizer assembled a standalone single-slot prompt while the rest of the auxiliary surface had moved to the system/user split.
Non-overlap: open #85481 (cache-aware summarization replaying the real conversation prefix) is a different, larger design from Aug 13; this PR is the minimal role-split on the current summarizer and does not touch its plumbing.
Infographic