fix(compression): pre-pass v2 — avoid blind LLM summarization for stale skill views#44166
Conversation
…ompression Complements PR NousResearch#32562 (P0/P1 Ghost Skill mitigation). Pre-pass v2: - New _prune_stale_skill_views() runs BEFORE _prune_old_tool_results - Heuristic: single-use skills pruned, reused/recent skills protected - Early return if pruning brings tokens below threshold (saves LLM call) Summary P2: - Extract [SKILL_PRUNED] markers before _serialize_for_summary() - Add '## Pruned Skills' section to summary template with verbatim directive - Post-LLM: re-inject markers if summarizer paraphrased them away - Fixes NousResearch#32106: LLM summary was diluting [SKILL_PRUNED] into vague prose
Review: P2 regex never matches v2 pre-pass placeholdersThe P2 P2 regex (context_compressor.py ~line 1584): r"\[SKILL_PRUNED:.*?reload with skill_view\(name='([^']+)'\)"v2 pre-pass placeholder ( f"[SKILL_PRUNED: content lost in compression; reload with skill_view before relying on it]"The placeholder says
The pruned content does get a summary placeholder ( Fix: Either update the regex to match the v2 format, or change the v2 placeholder to include Also: the |
…_view(name) The P1 Skill Safety Rule only triggers on [SKILL_PRUNED]. Checking skill_view(name='...') in the LLM summary is insufficient — the LLM can mention a skill name without the canonical marker, causing the re-injection to be skipped while P1 remains inactive. Use the simpler and more correct check: '[SKILL_PRUNED]' not in summary. Fixes NousResearch#32106.
Even if a skill is loaded only once (count==1), if the user mentions its name in recent messages, we keep it protected instead of pruning. This prevents false positives where a single-use skill is actually the focus of the current task (e.g. user says 'use the doc-builder skill'). Cost: zero — simple string matching on recent user messages. Fixes NousResearch#32106.
…mpactions After successive compressions, the same skill may appear as [SKILL_PRUNED] multiple times in head/tail/summary. Without guidance, the LLM could redundantly reload the same skill multiple times. Add an explicit note in the summary: one reload is sufficient. Fixes NousResearch#32106.
…ompaction After multiple compactions, the same skill may appear as [SKILL_PRUNED] multiple times. Without guidance, the LLM could redundantly reload the same skill on every turn, seeing the old markers as 'unresolved'. Add: - P1-DEDUP: System rule to ignore remaining markers after one reload - P2-Dedup note: Summary reminder that markers are historical artifacts Fixes NousResearch#32106.
…anagement Allows listing currently loaded skills and manually pruning specific ones to free context space. Complements the automatic pre-pass v2 pruning. Usage via Telegram: - 'Liste les skills chargés' - 'Prune le skill hermes-architecture'
The session_search tool returns a JSON string, not a dict. Added json.loads() to parse the result before extracting skill_view calls. Now correctly shows loaded skills in session.
…view(name='X') The P2 extraction regex expects skill_view(name='X') but the v2 pre-pass placeholder used 'reload with skill_view before relying on it'. This mismatch meant _pruned_skill_names was always empty, so the P2 defense (pre-LLM extraction + post-LLM re-injection) never fired. Align both Phase 1 and pre-pass v2 placeholders to use the callable skill_view(name='X') format so the regex matches and the agent can reload the pruned skill directly. Addresses review comment from @liuhao1024 on PR NousResearch#44166.
|
@liuhao1024 Thanks for catching this! You're absolutely right — the P2 regex expected Fixed in commit 8d86b2b:
Regarding the The fix ensures the full P2 defense chain works: extraction → template directive → re-injection. |
Context
Complement to PR #32562 (P0/P1 Ghost Skill mitigation).
Current bug: LLM compression triggers as soon as the context exceeds the threshold, even when the primary cause is the presence of multiple skill dumps (skill_view) of thousands of chars that are no longer useful. The LLM summarizer is invoked unnecessarily (token cost + latency) and tends to dilute the
[SKILL_PRUNED]markers by paraphrasing them, which breaks the P1 rule (Skill Safety Rule) and causes hallucinations (Ghost Skill).What this PR does:
Instead of dumping everything into the LLM summarizer, we introduce a heuristic Pre-pass v2 that distinguishes useful skills from stale ones before calculating the token budget.
Solution
1. Pre-pass v2 — The main fix
[SKILL_PRUNED]2. Summary P2 — Defense in depth
If despite the pre-pass, LLM compression is triggered (very long session), P2 ensures that
[SKILL_PRUNED]markers survive the pass through the summarizer:Impact
[SKILL_PRUNED]markers in the final summary, preserving the activation of the P1 rule.Fixes #32106