fix(graceful-handoff): model-aware context window detection (v2.1.0)
Stop hook fallback antok 200K-vindu. På Opus 4.7 (faktisk 1M) kunne auto-handoff fyre 5–7x for tidlig — estimert 70% når reell bruk var ~14%. Erstatter enkel fallback med 4-stegs resolution-kjede: 1. payload.context_window.used_percentage (autoritativ) 2. payload.context_window.context_window_size + transcript-estimat 3. MODEL_WINDOWS[payload.model.id] + estimat 4. FALLBACK_WINDOW=1_000_000 + estimat (2026-default) additionalContext-meldinger inkluderer nå [kilde: <source>] for innsyn. Brief som kilde-artefakt i docs/brief-context-window-detection.md. 6 nye tester (57 totalt). Ingen regresjoner.
This commit is contained in:
parent
346b4c4fb7
commit
40a82ccdb4
10 changed files with 347 additions and 34 deletions
144
plugins/graceful-handoff/docs/brief-context-window-detection.md
Normal file
144
plugins/graceful-handoff/docs/brief-context-window-detection.md
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
# Brief: Modell-bevisst kontekstvindu i graceful-handoff
|
||||
|
||||
**Dato:** 2026-05-01
|
||||
**Status:** Forslag — ikke implementert
|
||||
**Trigger:** Bruker oppdaget at Opus 4.7 har 1M kontekstvindu, ikke 200K. Plugin antar 200K i fallback.
|
||||
|
||||
## Problem
|
||||
|
||||
`hooks/scripts/stop-context-monitor.mjs:23` definerer:
|
||||
|
||||
```js
|
||||
const FALLBACK_WINDOW = 200_000;
|
||||
```
|
||||
|
||||
Logikken (linje 76-77):
|
||||
|
||||
```js
|
||||
const windowSize = payload?.context_window?.context_window_size || FALLBACK_WINDOW;
|
||||
const pctRaw = estimateUsedPct(transcriptPath, windowSize);
|
||||
```
|
||||
|
||||
Hvis Stop-hook payload ikke leverer `context_window.context_window_size` — eller leverer `0`/`undefined` — beregner hooken brukt prosent mot 200K. På en Opus 4.7-sesjon med faktisk 1M-vindu betyr det:
|
||||
|
||||
- Estimat treffer 70% når faktisk bruk er **~14%** (140K av 1M)
|
||||
- Auto-handoff fyrer 5-7x for tidlig
|
||||
- Bruker mister kontinuitet i lange sesjoner
|
||||
|
||||
`statusline-monitor.mjs` har ikke samme problem — den leser `used_percentage` direkte fra payload og er modell-agnostisk.
|
||||
|
||||
## Hvorfor 200K-fallback ble valgt
|
||||
|
||||
Kommentar (linje 14-16):
|
||||
> Token estimation: char_count / 3.5 → approximate tokens. Compares against
|
||||
> context_window_size from payload (200000 fallback). Approximation is
|
||||
> known to drift ±10% — 70% threshold is conservative buffer.
|
||||
|
||||
Antakelsen ved skriving av v2.0: Claude-modeller har 200K-vindu som standard. Det stemmer ikke lenger.
|
||||
|
||||
## Modell-landskap (verifisert 2026-05-01)
|
||||
|
||||
| Modell | Kontekstvindu |
|
||||
|--------|---------------|
|
||||
| Opus 4.7 | **1M tokens** (standard, ingen long-context premium) |
|
||||
| Sonnet 4.6 | 1M tokens (1M tier, beta) eller 200K |
|
||||
| Haiku 4.5 | 200K tokens |
|
||||
| Eldre Claude 3.x | 200K tokens |
|
||||
|
||||
Kilder:
|
||||
- https://platform.claude.com/docs/en/about-claude/models/whats-new-claude-4-7
|
||||
- https://platform.claude.com/docs/en/build-with-claude/context-windows
|
||||
|
||||
## Løsningsalternativer
|
||||
|
||||
### Alt 1 — Bedre fallback-detektering (minimal endring)
|
||||
|
||||
Detekter modell fra payload (`payload?.model` eller lignende felt) og map til kontekstvindu:
|
||||
|
||||
```js
|
||||
const MODEL_WINDOWS = {
|
||||
'claude-opus-4-7': 1_000_000,
|
||||
'claude-sonnet-4-6': 200_000, // default, kan ha 1M tier
|
||||
'claude-haiku-4-5-20251001': 200_000,
|
||||
};
|
||||
|
||||
function resolveWindowSize(payload) {
|
||||
const fromPayload = payload?.context_window?.context_window_size;
|
||||
if (fromPayload && fromPayload > 0) return fromPayload;
|
||||
const model = payload?.model || payload?.session?.model;
|
||||
if (model && MODEL_WINDOWS[model]) return MODEL_WINDOWS[model];
|
||||
return 1_000_000; // safer default i 2026
|
||||
}
|
||||
```
|
||||
|
||||
**Pros:** Minimal kode, dekker 95% av tilfellene.
|
||||
**Cons:** Hard-kodet modell-tabell må vedlikeholdes. Sonnet 4.6 1M-tier er ikke alltid aktiv — kan over-estimere.
|
||||
|
||||
### Alt 2 — Foretrekk `used_percentage` fra payload (foretrukket)
|
||||
|
||||
Hvis Stop-hook payload har `context_window.used_percentage` (slik statusline-payload har), bruk den direkte og hopp over transcript-estimat helt:
|
||||
|
||||
```js
|
||||
function estimateUsedPct(payload, transcriptPath, windowSize) {
|
||||
const direct = payload?.context_window?.used_percentage;
|
||||
if (typeof direct === 'number' && !isNaN(direct)) {
|
||||
return direct / 100; // already a percent
|
||||
}
|
||||
// Fall back to transcript-size estimate
|
||||
const stat = statSync(transcriptPath);
|
||||
const tokens = stat.size / CHARS_PER_TOKEN;
|
||||
return tokens / windowSize;
|
||||
}
|
||||
```
|
||||
|
||||
**Pros:** Bruker autoritativ kilde når tilgjengelig. Modell-agnostisk.
|
||||
**Cons:** Krever verifisering av Stop-hook payload-schema — usikkert om feltet alltid er der.
|
||||
|
||||
### Alt 3 — Kombinert (anbefalt)
|
||||
|
||||
1. Foretrekk `used_percentage` fra payload (Alt 2)
|
||||
2. Hvis ikke tilgjengelig, bruk `context_window_size` fra payload + transcript-estimat
|
||||
3. Hvis heller ikke det, prøv modell-mapping (Alt 1)
|
||||
4. Siste fallback: 1M (oppdatert default for 2026)
|
||||
|
||||
Behold 70% terskel — den er prosent-basert og fungerer uavhengig av vindusstørrelse.
|
||||
|
||||
## Sekundært designspørsmål
|
||||
|
||||
Er fast 70% terskel optimal for både 200K og 1M?
|
||||
|
||||
- 200K × 70% = 140K brukt → 60K headroom
|
||||
- 1M × 70% = 700K brukt → 300K headroom
|
||||
|
||||
Det er rimelig argumenterbart at terskelen bør være høyere ved store vinduer (f.eks. 75-80% for 1M-modeller), siden absolutt headroom betyr mer enn relativ. Men auto-compaction og prompt cache TTL er også prosent-baserte fenomener — så en universell 70% er sannsynligvis fortsatt riktig som default. Lavere prioritet enn fallback-fixen.
|
||||
|
||||
## Verifisering
|
||||
|
||||
Etter implementering, test:
|
||||
|
||||
1. **Smoke test:** Opus 4.7-sesjon, kjør til ~50% (statusline viser pct), bekreft at auto-handoff IKKE trigger.
|
||||
2. **Unit test:** Mock payload uten `context_window`, med `model: 'claude-opus-4-7'`, verifiser at `windowSize` resolver til 1M.
|
||||
3. **Unit test:** Payload med `used_percentage: 75`, verifiser at funksjonen returnerer 0.75 uansett windowSize.
|
||||
4. **Regresjon:** Eksisterende tester i `tests/` skal fortsatt passere.
|
||||
|
||||
## Scope-vurdering
|
||||
|
||||
- **Innenfor:** Fix av `stop-context-monitor.mjs` fallback. Oppdater inline-kommentar (linje 14-16) og README/CLAUDE.md hvis 200K nevnes der.
|
||||
- **Utenfor:** Endring av terskel-strategi (70% → variabel). Kan vurderes som separat oppgave.
|
||||
- **Utenfor:** Endring av `statusline-monitor.mjs` (fungerer allerede modell-agnostisk).
|
||||
|
||||
## Estimat
|
||||
|
||||
- Implementering: ~30 min (én fil + tester)
|
||||
- Verifisering: ~15 min smoke + 15 min regresjon
|
||||
- Doc-oppdatering: ~10 min (README, CLAUDE.md, CHANGELOG)
|
||||
- Total: ~70 min, én sesjon
|
||||
|
||||
## Neste skritt (når godkjent)
|
||||
|
||||
1. Bekreft Stop-hook payload-schema (har den `used_percentage` eller bare `context_window_size`?)
|
||||
2. Implementer Alt 3 i `stop-context-monitor.mjs`
|
||||
3. Oppdater fallback-kommentaren
|
||||
4. Skriv tester for nye fallback-veier
|
||||
5. Bump til v2.1.0 (minor — bug-fix + behavioral change)
|
||||
6. Oppdater CHANGELOG, README, CLAUDE.md, rot-README
|
||||
Loading…
Add table
Add a link
Reference in a new issue