Install
openclaw skills install compaction-ui-enhancementsBackground memory compaction with auto-trigger, chat summary paragraph, configurable threshold, model selector, settings tab, and result storage for OpenClaw Control UI.
openclaw skills install compaction-ui-enhancementsMemory compaction system for the OpenClaw Control UI — background execution with toast notifications, auto-trigger at configurable token thresholds, conversation summary paragraphs in compacted output, dedicated settings tab with model selector, and result history.
| Component | Status |
|---|---|
| Context Gauge Button | ✅ Working |
| Background Compaction (toast) | ✅ Working |
| Auto-Compaction Trigger | ✅ Working |
| Conversation Summary Paragraph | ✅ Working |
| Settings Tab (plugin-registered) | ✅ Working |
| Model Selector | ✅ Working |
| Last Result Storage + Viewer | ✅ Working |
| Settings Persistence & Reload | ✅ Working |
| Auth Hierarchy (OAuth > API > Fallback) | ✅ Working |
| Chat History Filters | ✅ Working |
| Full Background Isolation (no chat interference) | ✅ Working |
app-render.helpers.ts)A circular SVG progress ring in the chat toolbar that doubles as the manual compact trigger.
renderChatControls()sessionsResult.sessions[].totalTokens and contextTokens from session rowsOn click (or auto-trigger), compaction runs in the background using the standard bottom-right toast system — no blocking modal. The UI remains fully interactive.
backgroundJobToasts system consistent with all other background processes (cron, knowledge extraction, etc.)After every chat response (final event), the UI checks token usage against the configured threshold. If exceeded:
Every compaction output now begins with a ## Conversation Summary section before the structured ## Goal section. This is a 3-6 sentence natural language paragraph that:
Implementation: Custom instructions are injected into the upstream compaction LLM call via compact.ts. The instruction is prepended to any user-provided custom instructions (from /compact [instructions]), so both coexist.
Example output:
## Conversation Summary
The conversation began with the user requesting improvements to the compaction
system, specifically moving from a blocking modal to background toasts. Discussion
then shifted to adding a settings tab with auto-compaction controls. After
implementing and testing those features, the user noticed settings weren't
persisting across tab navigations, which led to a fix for the module-level
state cache. Finally, the user requested adding a narrative summary paragraph
to the compaction output for better context.
## Goal
...
A dedicated Compaction tab under the Agent navigation group, registered via the Plugin UI architecture.
Registration: plugins-ui.ts → BUILTIN_UI_VIEWS with id: "compaction", group: "agent", position: 7, icon: "archive"
Cards:
State Management:
resetCompactionSettingsState() exported for tests and tab switchesCompaction uses resolveApiKeyForProvider via getApiKeyForModel — the same auth chain as chat:
OAuth → API Key → Fallback
No separate configuration needed. If OAuth (Claude Max) is configured as the primary auth profile, compaction uses it automatically. Custom model selection uses this same auth chain independently.
When enabled, the most recent compaction result is persisted to {agentDir}/compaction-config.json:
{
"settings": {
"autoEnabled": true,
"autoThresholdPercent": 60,
"storeLastResult": true,
"compactionModel": "anthropic/claude-sonnet-4-6"
},
"lastResult": {
"timestamp": 1709283600000,
"trigger": "manual",
"tokensBefore": 50614,
"tokensAfter": 4766,
"tokensSaved": 45848,
"percentReduction": 91,
"sessionKey": "agent:main:main",
"summary": "## Conversation Summary\nThe conversation focused on...\n\n## Goal\n..."
}
}
When storage is disabled, metadata (timestamps, token counts) is still saved but the summary text is omitted.
__openclaw.kind === "compaction" messages| Method | Description |
|---|---|
sessions.compact | Execute compaction (records result after completion) |
compaction.getSettings | Read settings from config file |
compaction.saveSettings | Update settings (threshold auto-clamped 10-95%) |
compaction.getLastResult | Get stored last compaction result |
compaction.clearLastResult | Clear stored result |
| File | Purpose |
|---|---|
src/gateway/server-methods/compaction.ts | Settings RPCs, config I/O, result recording |
src/gateway/server-methods/sessions.ts | sessions.compact RPC (records result after compaction) |
src/gateway/server-methods/plugins-ui.ts | Plugin view registration |
src/gateway/server-methods.ts | Handler wiring |
src/gateway/server-methods-list.ts | Method registration |
src/gateway/method-scopes.ts | Scope registration |
src/agents/pi-embedded-runner/compact.ts | Chat summary instruction injection |
ui/src/ui/app-render.helpers.ts | Context gauge + background toast trigger |
ui/src/ui/app-gateway.ts | Auto-compaction check after final event |
ui/src/ui/views/compaction-settings.ts | Settings tab view |
ui/src/ui/app-render.ts | View wiring + import |
ui/src/ui/views/chat.ts | Chat history filters |
{agentDir}/compaction-config.json — per-agent, created on first settings save.
The compaction tab is registered as a builtin plugin view in plugins-ui.ts:
{
id: "compaction",
label: "Compaction",
subtitle: "Memory Management",
icon: "archive",
group: "agent",
position: 7,
pluginId: "compaction-ui",
}
_state.loaded flag was preventing reloads. Now reloads every 2 seconds when re-entering the tab."provider/model" format (e.g. "anthropic/claude-sonnet-4-6"). Invalid formats are silently ignored and fall back to session default.readSessionMessages, the skip set must ONLY propagate through entries with a message field. Non-message protocol entries (type:"custom") bridge between logical turns — if their IDs enter the skip set, the entire remaining conversation gets hidden. The fix: only check parsed?.message entries against the skip set, and only add their IDs to it.app-render.helpers.ts must NEVER render a full-screen overlay modal. Compaction is a background process; all status is communicated via the bottom-right toast system. Remove any position:fixed; inset:0 overlay conditioned on compactState.phase. The button may show a spinner icon while running, but must not block the UI.## Conversation Summary narrative paragraph before structured sectionsreferences/ with current sourcesessions.compact records before/after token counts and optional summarycompaction.getSettings, compaction.saveSettings, compaction.getLastResult, compaction.clearLastResultsessions.compact RPC with LLM summarization, chat history NO_REPLY/HEARTBEAT_OK filtering, compaction divider lines