Gestione delle sessioni e compattazione (approfondimento)
Questo documento spiega come OpenClaw gestisce le sessioni end-to-end:- Instradamento delle sessioni (come i messaggi in ingresso vengono mappati a una
sessionKey) - Store delle sessioni (
sessions.json) e cosa tiene traccia - Persistenza delle trascrizioni (
*.jsonl) e la loro struttura - Igiene delle trascrizioni (correzioni specifiche del provider prima delle esecuzioni)
- Limiti del contesto (finestra di contesto rispetto ai token tracciati)
- Compattazione (compattazione manuale + automatica) e dove collegare il lavoro preliminare prima della compattazione
- Pulizia silenziosa (ad esempio scritture in memoria che non dovrebbero produrre output visibile all’utente)
- /concepts/session
- /concepts/compaction
- /concepts/memory
- /concepts/memory-search
- /concepts/session-pruning
- /reference/transcript-hygiene
Fonte di verità: il Gateway
OpenClaw è progettato attorno a un singolo processo Gateway che possiede lo stato della sessione.- Le UI (app macOS, web Control UI, TUI) dovrebbero interrogare il Gateway per gli elenchi delle sessioni e il conteggio dei token.
- In modalità remota, i file di sessione si trovano sull’host remoto; “controllare i file sul tuo Mac locale” non rifletterà ciò che il Gateway sta usando.
Due livelli di persistenza
OpenClaw rende persistenti le sessioni su due livelli:-
Store delle sessioni (
sessions.json)- Mappa chiave/valore:
sessionKey -> SessionEntry - Piccolo, mutabile, sicuro da modificare (o da cui eliminare voci)
- Tiene traccia dei metadati della sessione (ID sessione corrente, ultima attività, interruttori, contatori di token, ecc.)
- Mappa chiave/valore:
-
Trascrizione (
<sessionId>.jsonl)- Trascrizione append-only con struttura ad albero (le voci hanno
id+parentId) - Memorizza la conversazione effettiva + chiamate agli strumenti + riepiloghi di compattazione
- Usata per ricostruire il contesto del modello per i turni futuri
- Trascrizione append-only con struttura ad albero (le voci hanno
Posizioni su disco
Per agent, sull’host Gateway:- Store:
~/.openclaw/agents/<agentId>/sessions/sessions.json - Trascrizioni:
~/.openclaw/agents/<agentId>/sessions/<sessionId>.jsonl- Sessioni dei topic Telegram:
.../<sessionId>-topic-<threadId>.jsonl
- Sessioni dei topic Telegram:
src/config/sessions.ts.
Manutenzione dello store e controlli su disco
La persistenza delle sessioni ha controlli automatici di manutenzione (session.maintenance) per sessions.json e gli artefatti delle trascrizioni:
mode:warn(predefinito) oppureenforcepruneAfter: soglia di età delle voci obsolete (predefinita30d)maxEntries: limite massimo di voci insessions.json(predefinito500)rotateBytes: ruotasessions.jsonquando è troppo grande (predefinito10mb)resetArchiveRetention: retention per gli archivi delle trascrizioni*.reset.<timestamp>(predefinita: uguale apruneAfter;falsedisabilita la pulizia)maxDiskBytes: budget facoltativo per la directory delle sessionihighWaterBytes: obiettivo facoltativo dopo la pulizia (predefinito80%dimaxDiskBytes)
mode: "enforce"):
- Rimuove prima gli artefatti delle trascrizioni archiviati o orfani più vecchi.
- Se ancora sopra l’obiettivo, sfratta le voci di sessione più vecchie e i relativi file di trascrizione.
- Continua finché l’utilizzo non è pari o inferiore a
highWaterBytes.
mode: "warn", OpenClaw segnala le possibili espulsioni ma non modifica store/file.
Esegui la manutenzione su richiesta:
Sessioni cron e log delle esecuzioni
Anche le esecuzioni cron isolate creano voci/trascrizioni di sessione e hanno controlli di retention dedicati:cron.sessionRetention(predefinito24h) elimina dallo store delle sessioni le vecchie sessioni isolate delle esecuzioni cron (falsedisabilita).cron.runLog.maxBytes+cron.runLog.keepLineseliminano i file~/.openclaw/cron/runs/<jobId>.jsonl(predefiniti:2_000_000byte e2000righe).
Chiavi di sessione (sessionKey)
Una sessionKey identifica in quale contenitore di conversazione ti trovi (instradamento + isolamento).
Pattern comuni:
- Chat principale/diretta (per agent):
agent:<agentId>:<mainKey>(predefinitomain) - Gruppo:
agent:<agentId>:<channel>:group:<id> - Stanza/canale (Discord/Slack):
agent:<agentId>:<channel>:channel:<id>oppure...:room:<id> - Cron:
cron:<job.id> - Webhook:
hook:<uuid>(salvo override)
ID sessione (sessionId)
Ogni sessionKey punta a un sessionId corrente (il file di trascrizione che continua la conversazione).
Regole pratiche:
- Reset (
/new,/reset) crea un nuovosessionIdper quellasessionKey. - Reset giornaliero (predefinito alle 4:00 ora locale sull’host Gateway) crea un nuovo
sessionIdal messaggio successivo dopo il confine di reset. - Scadenza per inattività (
session.reset.idleMinuteso legacysession.idleMinutes) crea un nuovosessionIdquando arriva un messaggio dopo la finestra di inattività. Quando sono configurati sia giornaliero sia inattività, prevale quello che scade per primo. - Protezione fork del genitore del thread (
session.parentForkMaxTokens, predefinito100000) salta il fork della trascrizione genitore quando la sessione genitore è già troppo grande; il nuovo thread inizia da zero. Imposta0per disabilitare.
initSessionState() in src/auto-reply/reply/session.ts.
Schema dello store delle sessioni (sessions.json)
Il tipo di valore dello store è SessionEntry in src/config/sessions.ts.
Campi principali (non esaustivi):
sessionId: ID della trascrizione corrente (il nome file deriva da questo salvo che sia impostatosessionFile)updatedAt: timestamp dell’ultima attivitàsessionFile: override facoltativo del percorso esplicito della trascrizionechatType:direct | group | room(aiuta le UI e la policy di invio)provider,subject,room,space,displayName: metadati per etichettatura di gruppi/canali- Interruttori:
thinkingLevel,verboseLevel,reasoningLevel,elevatedLevelsendPolicy(override per sessione)
- Selezione del modello:
providerOverride,modelOverride,authProfileOverride
- Contatori di token (best-effort / dipendenti dal provider):
inputTokens,outputTokens,totalTokens,contextTokens
compactionCount: quante volte la compattazione automatica è stata completata per questa chiave di sessionememoryFlushAt: timestamp dell’ultimo flush della memoria prima della compattazionememoryFlushCompactionCount: conteggio di compattazione al momento dell’ultimo flush
Struttura della trascrizione (*.jsonl)
Le trascrizioni sono gestite dal SessionManager di @mariozechner/pi-coding-agent.
Il file è JSONL:
- Prima riga: intestazione della sessione (
type: "session", includeid,cwd,timestamp,parentSessionfacoltativo) - Poi: voci di sessione con
id+parentId(albero)
message: messaggi utente/assistente/toolResultcustom_message: messaggi iniettati dall’estensione che entrano nel contesto del modello (possono essere nascosti nella UI)custom: stato dell’estensione che non entra nel contesto del modellocompaction: riepilogo di compattazione persistito confirstKeptEntryIdetokensBeforebranch_summary: riepilogo persistito durante la navigazione in un ramo dell’albero
SessionManager per leggerle/scriverle.
Finestre di contesto rispetto ai token tracciati
Contano due concetti diversi:- Finestra di contesto del modello: limite rigido per modello (token visibili al modello)
- Contatori dello store delle sessioni: statistiche progressive scritte in
sessions.json(usate per /status e dashboard)
- La finestra di contesto proviene dal catalogo dei modelli (e può essere sovrascritta tramite configurazione).
contextTokensnello store è un valore di stima/reporting a runtime; non trattarlo come una garanzia rigorosa.
Compattazione: cos’è
La compattazione riassume la conversazione più vecchia in una vocecompaction persistita nella trascrizione e mantiene intatti i messaggi recenti.
Dopo la compattazione, i turni futuri vedono:
- Il riepilogo di compattazione
- I messaggi dopo
firstKeptEntryId
Confini dei chunk di compattazione e accoppiamento con gli strumenti
Quando OpenClaw divide una lunga trascrizione in chunk di compattazione, mantiene accoppiate le chiamate agli strumenti dell’assistente con le vocitoolResult corrispondenti.
- Se la suddivisione in base alla quota di token cade tra una chiamata a uno strumento e il suo risultato, OpenClaw sposta il confine al messaggio di chiamata allo strumento dell’assistente invece di separare la coppia.
- Se un blocco finale di risultati degli strumenti altrimenti farebbe superare al chunk l’obiettivo, OpenClaw preserva quel blocco di strumenti in sospeso e mantiene intatta la coda non riassunta.
- I blocchi di chiamata agli strumenti interrotti/con errore non mantengono aperta una divisione in sospeso.
Quando avviene la compattazione automatica (runtime Pi)
Nell’agent Pi integrato, la compattazione automatica si attiva in due casi:- Recupero da overflow: il modello restituisce un errore di overflow del contesto
(
request_too_large,context length exceeded,input exceeds the maximum number of tokens,input token count exceeds the maximum number of input tokens,input is too long for the model,ollama error: context length exceedede varianti simili modellate dal provider) → compatta → ritenta. - Manutenzione della soglia: dopo un turno riuscito, quando:
contextTokens > contextWindow - reserveTokens
Dove:
contextWindowè la finestra di contesto del modelloreserveTokensè il margine riservato per prompt + output del modello successivo
Impostazioni della compattazione (reserveTokens, keepRecentTokens)
Le impostazioni di compattazione di Pi si trovano nelle impostazioni Pi:
- Se
compaction.reserveTokens < reserveTokensFloor, OpenClaw la aumenta. - La soglia minima predefinita è
20000token. - Imposta
agents.defaults.compaction.reserveTokensFloor: 0per disabilitare la soglia minima. - Se è già più alta, OpenClaw la lascia invariata.
ensurePiCompactionReserveTokens() in src/agents/pi-settings.ts
(chiamata da src/agents/pi-embedded-runner.ts).
Provider di compattazione pluggable
I plugin possono registrare un provider di compattazione tramiteregisterCompactionProvider() sull’API del plugin. Quando agents.defaults.compaction.provider è impostato su un ID provider registrato, l’estensione safeguard delega il riepilogo a quel provider invece che alla pipeline integrata summarizeInStages.
provider: ID di un plugin provider di compattazione registrato. Lascialo non impostato per il riepilogo LLM predefinito.- Impostare un
providerforzamode: "safeguard". - I provider ricevono le stesse istruzioni di compattazione e la stessa policy di preservazione degli identificatori del percorso integrato.
- Il safeguard preserva comunque il contesto dei turni recenti e del suffisso della suddivisione dei turni dopo l’output del provider.
- Se il provider fallisce o restituisce un risultato vuoto, OpenClaw torna automaticamente al riepilogo LLM integrato.
- I segnali di interruzione/timeout vengono rilanciati (non ignorati) per rispettare l’annullamento del chiamante.
src/plugins/compaction-provider.ts, src/agents/pi-hooks/compaction-safeguard.ts.
Superfici visibili all’utente
Puoi osservare compattazione e stato della sessione tramite:/status(in qualsiasi sessione chat)openclaw status(CLI)openclaw sessions/sessions --json- Modalità dettagliata:
🧹 Auto-compaction complete+ conteggio di compattazione
Pulizia silenziosa (NO_REPLY)
OpenClaw supporta turni “silenziosi” per attività in background in cui l’utente non dovrebbe vedere output intermedio.
Convenzione:
- L’assistente inizia il proprio output con l’esatto token silenzioso
NO_REPLY/no_replyper indicare “non consegnare una risposta all’utente”. - OpenClaw lo rimuove/lo sopprime nel livello di consegna.
- La soppressione dell’esatto token silenzioso non distingue tra maiuscole e minuscole, quindi
NO_REPLYeno_replycontano entrambi quando l’intero payload è solo il token silenzioso. - Questo serve solo per veri turni in background/senza consegna; non è una scorciatoia per normali richieste utente con azioni da eseguire.
2026.1.10, OpenClaw sopprime anche lo streaming draft/digitazione quando un
chunk parziale inizia con NO_REPLY, così le operazioni silenziose non fanno trapelare output parziale a metà turno.
”Memory flush” prima della compattazione (implementato)
Obiettivo: prima che avvenga la compattazione automatica, eseguire un turno agentico silenzioso che scriva stato durevole su disco (ad esempiomemory/YYYY-MM-DD.md nel workspace dell’agent) così la compattazione non possa
cancellare contesto critico.
OpenClaw usa l’approccio di flush prima della soglia:
- Monitora l’utilizzo del contesto della sessione.
- Quando supera una “soglia morbida” (al di sotto della soglia di compattazione di Pi), esegue una direttiva silenziosa “scrivi ora in memoria” verso l’agent.
- Usa l’esatto token silenzioso
NO_REPLY/no_replycosì l’utente non vede nulla.
agents.defaults.compaction.memoryFlush):
enabled(predefinito:true)softThresholdTokens(predefinito:4000)prompt(messaggio utente per il turno di flush)systemPrompt(prompt di sistema aggiuntivo aggiunto per il turno di flush)
- Il prompt/system prompt predefinito include un suggerimento
NO_REPLYper sopprimere la consegna. - Il flush viene eseguito una volta per ciclo di compattazione (tracciato in
sessions.json). - Il flush viene eseguito solo per sessioni Pi integrate (i backend CLI lo saltano).
- Il flush viene saltato quando il workspace della sessione è in sola lettura (
workspaceAccess: "ro"o"none"). - Vedi Memory per il layout dei file del workspace e i pattern di scrittura.
session_before_compact nell’API dell’estensione, ma oggi la logica di
flush di OpenClaw vive lato Gateway.
Checklist di risoluzione dei problemi
- Chiave di sessione errata? Inizia da /concepts/session e conferma la
sessionKeyin/status. - Mancata corrispondenza tra store e trascrizione? Conferma l’host Gateway e il percorso dello store da
openclaw status. - Spam di compattazione? Controlla:
- finestra di contesto del modello (troppo piccola)
- impostazioni di compattazione (
reserveTokenstroppo alto rispetto alla finestra del modello può causare una compattazione anticipata) - crescita eccessiva dei risultati degli strumenti: abilita/regola il pruning della sessione
- I turni silenziosi trapelano? Conferma che la risposta inizi con
NO_REPLY(token esatto case-insensitive) e che tu stia usando una build che include la correzione della soppressione dello streaming.