#13540: feat: persist channel histories to disk
channel: imessage
channel: signal
channel: slack
channel: telegram
channel: whatsapp-web
stale
Cluster:
Telegram History and Features
## Summary
Channel histories (pending messages from non-mentioned users in group chats) are currently stored in an in-memory `Map` that is lost on every process restart. This means the agent loses all "between-reply" conversational context whenever the process is restarted (e.g. during deployments).
This PR adds transparent disk persistence to channel histories so that context survives process restarts.
## Changes
- **New file `src/auto-reply/reply/history-persistence.ts`**
- `createPersistentHistoryMap<T>(filePath, debounceMs?)` — drop-in replacement for `new Map()`
- Loads existing data from disk on creation
- Hooks `Map.set` / `Map.delete` to schedule debounced writes (default 5s)
- Atomic write (tmp file → rename) for crash safety
- Synchronous flush on process exit to prevent data loss during graceful shutdown
- Timer is `unref()`'d so it doesn't keep the process alive
- **`src/config/sessions/paths.ts`**
- Added `resolveChannelHistoriesPath(channel, accountId?, agentId?)` for consistent file path resolution
- File path: `~/.openclaw/agents/<agentId>/sessions/channel-histories-<channel>-<accountId>.json`
- **All 5 channel monitors updated** (one-line change each):
- `src/slack/monitor/context.ts`
- `src/telegram/bot.ts`
- `src/signal/monitor.ts`
- `src/web/auto-reply/monitor.ts`
- `src/imessage/monitor/monitor-provider.ts`
## What is NOT changed
- All existing history functions (`appendHistoryEntry`, `clearHistoryEntries`, `buildHistoryContextFromMap`, etc.) are completely unchanged
- No new dependencies added
- No configuration required (works out of the box)
## Design decisions
- **Debounce over immediate write**: Group chats can receive bursts of messages; debouncing avoids excessive I/O while still persisting within seconds
- **Atomic write**: Uses tmp file + rename pattern (same as session store) to prevent corruption from partial writes
- **Per-channel files**: Each channel + account combination gets its own JSON file, avoiding contention between channels
- **Generic type parameter**: `createPersistentHistoryMap<T>` works with any entry type (WhatsApp uses extended fields beyond `HistoryEntry`)
## Related
- Closes #13449
✍️ **Author**: Claude Code with @carrotRakko (AI-written, human-approved)
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR replaces in-memory channel/group history `Map`s with a persistent map that loads/saves JSON on disk, and adds a `resolveChannelHistoriesPath()` helper under the sessions paths module. The monitors for Slack/Telegram/Signal/iMessage/WhatsApp web are updated to construct their history map via `createPersistentHistoryMap(...)` so pending “between reply” context can survive process restarts.
Persistence is implemented via synchronous JSON read on startup and debounced synchronous writes (tmp+rename on non-Windows) on `Map.set`/`Map.delete`, with a synchronous flush on process exit.
<h3>Confidence Score: 3/5</h3>
- This PR introduces persistence but has correctness risks in how histories are scoped and how process exit listeners are managed.
- Main concerns are that persistence is currently keyed only by provider/account/agent, which will conflate histories from multiple concurrent group chats for the same account, and that each persistent map instance registers a global `process.on("exit")` handler without cleanup (risking listener leaks / duplicated flushes).
- src/config/sessions/paths.ts, src/auto-reply/reply/history-persistence.ts
<!-- greptile_other_comments_section -->
<sub>(4/5) You can add custom instructions or style guidelines for the agent [here](https://app.greptile.com/review/github)!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#7751: Telegram: persist inbound history (SQLite) + add read action
by welttowelt · 2026-02-03
77.3%
#6611: fix(webchat): persist assistant messages for CLI backends
by JorgeAlan · 2026-02-01
76.8%
#16622: fix(mattermost): record pending history for messages dropped by gro...
by oskarmodig · 2026-02-14
76.7%
#3045: [AI-Assisted] fix: preserve pending tasks when subagent completes
by sid1943 · 2026-01-28
76.0%
#8344: fix: persist webchat message queue to localStorage across browser r...
by vishaltandale00 · 2026-02-03
75.8%
#22945: feat(discord): seed channel history from API and persist to disk
by iamhitarth · 2026-02-21
75.0%
#20078: feat(session): Add channelGroups config(optional config) for shared...
by demarlik01 · 2026-02-18
74.8%
#14966: fix(webchat): preserve user message visibility after chat.send
by BenediktSchackenberg · 2026-02-12
74.3%
#11123: Fix webchat→external channel cross-delivery
by jingkang0822 · 2026-02-07
74.2%
#4664: fix: per-session metadata files to eliminate lock contention
by tsukhani · 2026-01-30
73.8%