Skip to content

Commit 450b16c

Browse files
committed
fix: prune stale restored agent state
1 parent 9cd3d82 commit 450b16c

2 files changed

Lines changed: 92 additions & 0 deletions

File tree

Sources/Workspace.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,8 @@ extension Workspace {
339339
func restoreSessionSnapshot(_ snapshot: SessionWorkspaceSnapshot) {
340340
restoredTerminalScrollbackByPanelId.removeAll(keepingCapacity: false)
341341
restoredAgentSnapshotsByPanelId.removeAll(keepingCapacity: false)
342+
restoredAgentAutoResumePendingPanelIds.removeAll(keepingCapacity: false)
343+
invalidatedRestoredAgentFingerprintsByPanelId.removeAll(keepingCapacity: false)
342344

343345
let normalizedCurrentDirectory = snapshot.currentDirectory.trimmingCharacters(in: .whitespacesAndNewlines)
344346
if !normalizedCurrentDirectory.isEmpty {
@@ -7991,6 +7993,12 @@ final class Workspace: Identifiable, ObservableObject {
79917993
restoredAgentSnapshotsByPanelId = restoredAgentSnapshotsByPanelId.filter {
79927994
validSurfaceIds.contains($0.key)
79937995
}
7996+
restoredAgentAutoResumePendingPanelIds = restoredAgentAutoResumePendingPanelIds.filter {
7997+
validSurfaceIds.contains($0)
7998+
}
7999+
invalidatedRestoredAgentFingerprintsByPanelId = invalidatedRestoredAgentFingerprintsByPanelId.filter {
8000+
validSurfaceIds.contains($0.key)
8001+
}
79948002
syncRemotePortScanTTYs()
79958003
recomputeListeningPorts()
79968004
}

cmuxTests/SessionPersistenceTests.swift

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,6 +1046,90 @@ final class SessionPersistenceTests: XCTestCase {
10461046
XCTAssertNil(userCommandSnapshot.panels.first?.terminal?.agent)
10471047
}
10481048

1049+
@MainActor
1050+
func testPruneSurfaceMetadataRemovesRestoredAgentBookkeeping() throws {
1051+
let source = Workspace()
1052+
let sourcePanelId = try XCTUnwrap(source.focusedPanelId)
1053+
let sourceIndex = try makeRestorableAgentIndex(
1054+
workspaceId: source.id,
1055+
panelId: sourcePanelId,
1056+
sessionId: "codex-prune-pending-session",
1057+
arguments: [
1058+
"/usr/local/bin/codex",
1059+
"--model",
1060+
"gpt-5.4",
1061+
]
1062+
)
1063+
let snapshot = source.sessionSnapshot(
1064+
includeScrollback: false,
1065+
restorableAgentIndex: sourceIndex
1066+
)
1067+
1068+
let restored = Workspace()
1069+
restored.restoreSessionSnapshot(snapshot)
1070+
let restoredPanelId = try XCTUnwrap(restored.focusedPanelId)
1071+
restored.pruneSurfaceMetadata(validSurfaceIds: [])
1072+
1073+
let postPruneIndex = try makeRestorableAgentIndex(
1074+
workspaceId: restored.id,
1075+
panelId: restoredPanelId,
1076+
sessionId: "codex-post-prune-session",
1077+
arguments: [
1078+
"/usr/local/bin/codex",
1079+
"--model",
1080+
"gpt-5.4-mini",
1081+
]
1082+
)
1083+
let postPruneSnapshot = restored.sessionSnapshot(
1084+
includeScrollback: false,
1085+
restorableAgentIndex: postPruneIndex
1086+
)
1087+
XCTAssertEqual(
1088+
postPruneSnapshot.panels.first?.terminal?.agent?.sessionId,
1089+
"codex-post-prune-session"
1090+
)
1091+
1092+
restored.updatePanelShellActivityState(panelId: restoredPanelId, state: .promptIdle)
1093+
restored.updatePanelShellActivityState(panelId: restoredPanelId, state: .commandRunning)
1094+
let userCommandSnapshot = restored.sessionSnapshot(includeScrollback: false)
1095+
XCTAssertNil(userCommandSnapshot.panels.first?.terminal?.agent)
1096+
1097+
let staleWorkspace = Workspace()
1098+
let stalePanelId = try XCTUnwrap(staleWorkspace.focusedPanelId)
1099+
let staleIndex = try makeRestorableAgentIndex(
1100+
workspaceId: staleWorkspace.id,
1101+
panelId: stalePanelId,
1102+
sessionId: "codex-prune-invalidated-session",
1103+
arguments: [
1104+
"/usr/local/bin/codex",
1105+
"--model",
1106+
"gpt-5.4",
1107+
]
1108+
)
1109+
_ = staleWorkspace.sessionSnapshot(
1110+
includeScrollback: false,
1111+
restorableAgentIndex: staleIndex
1112+
)
1113+
1114+
staleWorkspace.updatePanelShellActivityState(panelId: stalePanelId, state: .promptIdle)
1115+
staleWorkspace.updatePanelShellActivityState(panelId: stalePanelId, state: .commandRunning)
1116+
let staleSnapshot = staleWorkspace.sessionSnapshot(
1117+
includeScrollback: false,
1118+
restorableAgentIndex: staleIndex
1119+
)
1120+
XCTAssertNil(staleSnapshot.panels.first?.terminal?.agent)
1121+
1122+
staleWorkspace.pruneSurfaceMetadata(validSurfaceIds: [])
1123+
let acceptedSnapshot = staleWorkspace.sessionSnapshot(
1124+
includeScrollback: false,
1125+
restorableAgentIndex: staleIndex
1126+
)
1127+
XCTAssertEqual(
1128+
acceptedSnapshot.panels.first?.terminal?.agent?.sessionId,
1129+
"codex-prune-invalidated-session"
1130+
)
1131+
}
1132+
10491133
@MainActor
10501134
func testUserCommandInvalidatesStaleRestoredAgentForAllProviders() throws {
10511135
let scenarios: [(kind: RestorableAgentKind, arguments: [String])] = [

0 commit comments

Comments
 (0)