Changeset 0.15.0 (#71)
This commit is contained in:
186
docs/CHANGES-0.15.0-phase2.md
Normal file
186
docs/CHANGES-0.15.0-phase2.md
Normal file
@@ -0,0 +1,186 @@
|
||||
# v0.15.0 Phase 2 — Changeset Notes
|
||||
|
||||
## Files included in this zip (new)
|
||||
|
||||
```
|
||||
server/compaction/estimator.go NEW — EstimateTokens, EstimatePath, EstimatePathFromSummary
|
||||
server/compaction/estimator_test.go NEW — unit tests (no DB required)
|
||||
server/compaction/scanner.go NEW — Scanner, scan loop, candidate query, shouldCompact
|
||||
```
|
||||
|
||||
## Surgical edits needed in existing files
|
||||
|
||||
### 1. `server/main.go`
|
||||
|
||||
Phase 1 already introduced `compactionSvc`. Now add the scanner below it
|
||||
(after the `compactionSvc` line, before route registration):
|
||||
|
||||
```go
|
||||
import "git.gobha.me/xcaliber/chat-switchboard/compaction" // already present from Phase 1
|
||||
|
||||
// ── Auto-Compaction Scanner ───────────
|
||||
compactionScanner := compaction.NewScanner(compactionSvc, stores, compaction.ScannerConfig{
|
||||
Interval: 5 * time.Minute,
|
||||
Concurrency: 2,
|
||||
})
|
||||
compactionScanner.Start()
|
||||
defer compactionScanner.Stop() // drain in-flight compactions on shutdown
|
||||
```
|
||||
|
||||
Place `defer compactionScanner.Stop()` near the existing
|
||||
`defer kbIngester.Wait()` line.
|
||||
|
||||
**Note:** The scanner re-reads all config from `global_settings` each
|
||||
tick. The `ScannerConfig` struct only sets the ticker interval and
|
||||
semaphore size at startup. Everything else (enabled, threshold, cooldown)
|
||||
is dynamic.
|
||||
|
||||
---
|
||||
|
||||
### 2. `src/index.html`
|
||||
|
||||
Add an auto-compaction section to the admin Settings tab. Insert **before**
|
||||
the Encryption section (before `<section class="admin-section">` with
|
||||
`🔐 Encryption`):
|
||||
|
||||
```html
|
||||
<section class="settings-section">
|
||||
<h3>Auto-Compaction</h3>
|
||||
<label class="checkbox-label"><input type="checkbox" id="adminCompactionEnabled"> Enable automatic conversation compaction</label>
|
||||
<p class="section-hint">When enabled, long conversations are automatically summarized in the background using the utility model. Ships off by default — requires a utility model role to be configured.</p>
|
||||
<div id="compactionConfigFields" style="display:none;margin-top:8px">
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label>Threshold</label>
|
||||
<div class="form-row" style="gap:4px;align-items:center">
|
||||
<input type="number" id="adminCompactionThreshold" value="70" min="10" max="95" step="5" style="width:70px">
|
||||
<span class="form-hint">% of context window</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Cooldown</label>
|
||||
<div class="form-row" style="gap:4px;align-items:center">
|
||||
<input type="number" id="adminCompactionCooldown" value="30" min="5" max="360" step="5" style="width:70px">
|
||||
<span class="form-hint">minutes per channel</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. `src/js/ui-admin.js` — `loadAdminSettings()`
|
||||
|
||||
Add these lines **after** the Web Search config loading block
|
||||
(after `document.getElementById('searxngConfigFields').style.display = ...`):
|
||||
|
||||
```javascript
|
||||
// Auto-Compaction (global_settings)
|
||||
const compactionCfg = getSetting('auto_compaction', {}) || {};
|
||||
const compactionEnabled = document.getElementById('adminCompactionEnabled');
|
||||
if (compactionEnabled) {
|
||||
compactionEnabled.checked = !!compactionCfg.enabled;
|
||||
document.getElementById('compactionConfigFields').style.display =
|
||||
compactionCfg.enabled ? '' : 'none';
|
||||
}
|
||||
const compThreshold = document.getElementById('adminCompactionThreshold');
|
||||
if (compThreshold) compThreshold.value = String(compactionCfg.threshold || 70);
|
||||
const compCooldown = document.getElementById('adminCompactionCooldown');
|
||||
if (compCooldown) compCooldown.value = String(compactionCfg.cooldown || 30);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. `src/js/settings-handlers.js` — `handleSaveAdminSettings()`
|
||||
|
||||
Add these lines **after** the `search_config` save block (before
|
||||
`UI.toast('Settings saved', 'success')`):
|
||||
|
||||
```javascript
|
||||
// Auto-Compaction config → global_settings
|
||||
const compactionEnabled = document.getElementById('adminCompactionEnabled')?.checked || false;
|
||||
const compactionThreshold = parseInt(document.getElementById('adminCompactionThreshold')?.value) || 70;
|
||||
const compactionCooldown = parseInt(document.getElementById('adminCompactionCooldown')?.value) || 30;
|
||||
await API.adminUpdateSetting('auto_compaction', { value: {
|
||||
enabled: compactionEnabled,
|
||||
threshold: compactionThreshold,
|
||||
cooldown: compactionCooldown,
|
||||
}});
|
||||
|
||||
// Persist individual keys for scanner (reads these independently)
|
||||
await API.adminUpdateSetting('auto_compaction_enabled', { value: compactionEnabled });
|
||||
await API.adminUpdateSetting('auto_compaction_threshold', { value: compactionThreshold / 100 });
|
||||
await API.adminUpdateSetting('auto_compaction_cooldown_minutes', { value: compactionCooldown });
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. `src/js/settings-handlers.js` — `_initSettingsListeners()`
|
||||
|
||||
Add a toggle listener for the compaction checkbox, alongside the existing
|
||||
banner toggle. Add **after** the `adminBannerEnabled` change listener:
|
||||
|
||||
```javascript
|
||||
document.getElementById('adminCompactionEnabled')?.addEventListener('change', (e) => {
|
||||
document.getElementById('compactionConfigFields').style.display = e.target.checked ? '' : 'none';
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6. `src/js/ui-core.js` — `_summaryHTML()`
|
||||
|
||||
Show "(auto)" label on auto-triggered summaries. The `trigger` field is
|
||||
already in message metadata from Phase 1.
|
||||
|
||||
**Replace** the `_summaryHTML` method:
|
||||
|
||||
```javascript
|
||||
_summaryHTML(msg) {
|
||||
const meta = msg.metadata || {};
|
||||
const count = meta.summarized_count || '?';
|
||||
const model = meta.utility_model || 'utility model';
|
||||
const trigger = meta.trigger === 'auto' ? ' · auto' : '';
|
||||
return `
|
||||
<div class="message-summary" data-msg-id="${esc(msg.id || '')}">
|
||||
<div class="summary-header">
|
||||
<span>📝 Conversation summary (${count} messages, by ${esc(model)}${trigger})</span>
|
||||
</div>
|
||||
<div class="msg-text">${formatMessage(msg.content)}</div>
|
||||
</div>`;
|
||||
},
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## How the scanner reads settings
|
||||
|
||||
The scanner calls `GlobalConfig.Get()` **every tick** for these keys:
|
||||
|
||||
| Key | Read by | How stored |
|
||||
|-----|---------|------------|
|
||||
| `auto_compaction_enabled` | `isEnabled()` | `{value: true/false}` |
|
||||
| `auto_compaction_threshold` | `getThreshold()` | `{value: 0.70}` (float 0-1) |
|
||||
| `auto_compaction_cooldown_minutes` | `getCooldownDuration()` | `{value: 30}` |
|
||||
|
||||
The admin UI stores a combined `auto_compaction` key (for display) AND
|
||||
the individual keys (for scanner consumption). This avoids the scanner
|
||||
needing to parse a composite object.
|
||||
|
||||
Interval and concurrency are set at startup via `ScannerConfig` and
|
||||
require a restart to change. This is intentional — they affect the
|
||||
goroutine pool size and ticker, which shouldn't be hot-swapped.
|
||||
|
||||
## Verification
|
||||
|
||||
1. `cd server && go test ./compaction/` — estimator tests pass (no DB)
|
||||
2. `cd server && go build .` — compiles cleanly
|
||||
3. Manual test: Admin → Settings → enable auto-compaction → Save →
|
||||
check server logs for `🔍 compaction scanner started`
|
||||
4. Manual test: with utility role configured and a long conversation,
|
||||
verify auto-compaction fires after the threshold is exceeded
|
||||
5. Verify cooldown: same channel should not re-compact within 30 minutes
|
||||
6. Verify kill switch: disable auto-compaction → scanner stops processing
|
||||
on next tick
|
||||
Reference in New Issue
Block a user