From 907074a45403b6fc4cd4287745b39e4f9e10430b Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Sun, 22 Mar 2026 21:08:36 +0700 Subject: [PATCH] fix(agent-manager): add missing touchUpdatedAt before emitState calls Several emitState() calls were missing a preceding touchUpdatedAt(), causing agent state updates to be silently dropped by the bootstrap dedup logic in session.ts (which drops updates where updateUpdatedAt <= snapshotUpdatedAt). This caused two user-visible bugs: - Permission mode switches not reflected in UI until next message - Agent stuck showing "running" when it had transitioned to idle Added touchUpdatedAt() to: setAgentMode, setAgentModel, setAgentThinkingOption, setLabels, streamAgent.finalize, replacement error fallback, and cancelAgentRun permission clear. --- packages/server/src/server/agent/agent-manager.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/server/src/server/agent/agent-manager.ts b/packages/server/src/server/agent/agent-manager.ts index 75af92f33..aa61e1a5f 100644 --- a/packages/server/src/server/agent/agent-manager.ts +++ b/packages/server/src/server/agent/agent-manager.ts @@ -790,6 +790,7 @@ export class AgentManager { if (agent.runtimeInfo) { agent.runtimeInfo = { ...agent.runtimeInfo, modeId }; } + this.touchUpdatedAt(agent); this.emitState(agent); } @@ -806,6 +807,7 @@ export class AgentManager { if (agent.runtimeInfo) { agent.runtimeInfo = { ...agent.runtimeInfo, model: normalizedModelId }; } + this.touchUpdatedAt(agent); this.emitState(agent); } @@ -821,6 +823,7 @@ export class AgentManager { } agent.config.thinkingOptionId = normalizedThinkingOptionId ?? undefined; + this.touchUpdatedAt(agent); this.emitState(agent); } @@ -839,6 +842,7 @@ export class AgentManager { const agent = this.requireAgent(agentId); agent.labels = { ...agent.labels, ...labels }; await this.persistSnapshot(agent); + this.touchUpdatedAt(agent); this.emitState(agent); } @@ -1054,6 +1058,7 @@ export class AgentManager { "streamAgent.finalize: applying terminal state", ); if (!shouldHoldBusyForReplacement) { + this.touchUpdatedAt(mutableAgent); this.emitState(mutableAgent); this.flushLiveEventBacklog(mutableAgent); } @@ -1150,6 +1155,7 @@ export class AgentManager { const lifecycle = (latestActive as { lifecycle: AgentLifecycleStatus }).lifecycle; if (!hasForegroundRun && lifecycle === "running") { latestActive.lifecycle = "idle"; + self.touchUpdatedAt(latestActive); self.emitState(latestActive); self.flushLiveEventBacklog(latestActive); } @@ -1307,6 +1313,7 @@ export class AgentManager { }); } agent.pendingPermissions.clear(); + this.touchUpdatedAt(agent); this.emitState(agent); }