From aea8a661125e6fb4531cbd4f9868d6ba779a84e5 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Thu, 25 Dec 2025 19:26:28 +0700 Subject: [PATCH] Remove module-level SESSION_HISTORY Map from codex-mcp-agent.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactored history storage from module-level Map to instance-level persistedHistory field. This fixes: - Memory leak: sessions were never cleaned up from global Map - Shared state: unrelated sessions could collide - Restart handling: history now always loads from disk on resume Changes: - Removed SESSION_HISTORY Map (was at line 118) - Constructor now sets historyPending=true for resume instead of looking up from global Map - connect() always loads from disk when resuming - recordHistory() appends to this.persistedHistory instead of Map - flushPendingHistory() appends to this.persistedHistory instead of Map - loadPersistedHistoryFromDisk() no longer populates global Map 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../server/agent/providers/codex-mcp-agent.ts | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/packages/server/src/server/agent/providers/codex-mcp-agent.ts b/packages/server/src/server/agent/providers/codex-mcp-agent.ts index f1f01eb3f..e7acffa1d 100644 --- a/packages/server/src/server/agent/providers/codex-mcp-agent.ts +++ b/packages/server/src/server/agent/providers/codex-mcp-agent.ts @@ -115,8 +115,6 @@ const MODE_PRESETS: Record< }, }; -const SESSION_HISTORY = new Map(); - function createToolCallTimelineItem( data: Omit ): AgentTimelineItem { @@ -2563,11 +2561,8 @@ class CodexMcpAgentSession implements AgentSession { this.conversationId = this.sessionId; } } - // Try in-memory history first (for same-process resume) - const history = this.sessionId ? SESSION_HISTORY.get(this.sessionId) : undefined; - this.persistedHistory = history ? [...history] : []; - this.historyPending = this.persistedHistory.length > 0; - // Note: If SESSION_HISTORY is empty (daemon restarted), we load from disk in connect() + // Mark history as pending; actual loading happens in connect() from disk + this.historyPending = true; } this.client = new Client( @@ -2608,9 +2603,8 @@ class CodexMcpAgentSession implements AgentSession { async connect(): Promise { if (this.connected) return; - // If resuming with no in-memory history, load from rollout file on disk - // This handles the case where the daemon restarted and SESSION_HISTORY was lost - if (this.resumeHandle && this.sessionId && this.persistedHistory.length === 0) { + // Load history from disk when resuming a session + if (this.resumeHandle && this.sessionId) { await this.loadPersistedHistoryFromDisk(); } @@ -2641,8 +2635,6 @@ class CodexMcpAgentSession implements AgentSession { if (timeline.length > 0) { this.persistedHistory = timeline; this.historyPending = true; - // Also populate SESSION_HISTORY so future in-process resumes work - SESSION_HISTORY.set(this.sessionId, [...timeline]); } } @@ -3154,9 +3146,7 @@ class CodexMcpAgentSession implements AgentSession { private recordHistory(item: AgentTimelineItem): void { if (this.sessionId) { - const history = SESSION_HISTORY.get(this.sessionId) || []; - history.push(item); - SESSION_HISTORY.set(this.sessionId, history); + this.persistedHistory.push(item); return; } this.pendingHistory.push(item); @@ -3166,9 +3156,7 @@ class CodexMcpAgentSession implements AgentSession { if (!this.sessionId || this.pendingHistory.length === 0) { return; } - const history = SESSION_HISTORY.get(this.sessionId) || []; - history.push(...this.pendingHistory); - SESSION_HISTORY.set(this.sessionId, history); + this.persistedHistory.push(...this.pendingHistory); this.pendingHistory = []; }