fix: 收口上下文压缩生命周期边界

This commit is contained in:
2026-08-15 09:17:07 +08:00
parent 1d0878bb5b
commit 7a811590c4
4 changed files with 166 additions and 6 deletions

View File

@@ -674,8 +674,18 @@ export function hydrateOpenCodeSession(
const snapshotOrder = [...next.compactionOrder];
snapshotOrder.forEach((id, index) => {
const snapshotEvent = next.compactionsById[id];
const existingID = snapshotEvent.nativePartID
? findCompactionId(current ?? state, { nativePartID: snapshotEvent.nativePartID })
const existingID = current
? findCompactionId(current, { id: snapshotEvent.id })
?? (snapshotEvent.nativePartID
? findCompactionId(current, { nativePartID: snapshotEvent.nativePartID })
: undefined)
?? (snapshotEvent.anchorPartID
? [...current.compactionOrder].reverse().find((candidateID) => {
const candidate = current.compactionsById[candidateID];
return candidate?.anchorPartID === snapshotEvent.anchorPartID
&& candidate.anchorMessageID === snapshotEvent.anchorMessageID;
})
: undefined)
: undefined;
const pendingID = !existingID && snapshotEvent.source === 'manual'
? [...(current?.compactionOrder ?? [])].reverse().find((candidateID) => {
@@ -694,10 +704,10 @@ export function hydrateOpenCodeSession(
const preservedID = existingID ?? pendingID;
const existing = preservedID ? current?.compactionsById[preservedID] : undefined;
const idToUse = preservedID ?? id;
const isLatestActive = status !== 'idle' && index === snapshotOrder.length - 1;
const completed = existing?.status === 'completed'
|| snapshotEvent.completedAt !== undefined
|| !isLatestActive;
|| status === 'idle'
|| existing?.status !== 'running';
if (idToUse !== id) {
const compactionsById = { ...next.compactionsById };
delete compactionsById[id];

View File

@@ -2390,6 +2390,7 @@ function finishSessionRunSuccessfully(
runToken: number,
messages: RawMessage[],
statuses: Record<string, OpencodeSessionStatus> = {},
compactionGeneration?: number,
): boolean {
if (!isSessionRunCurrent(sessionId, runToken)) return false;
flushSessionRunStreamBatch(set, sessionId, runToken);
@@ -2397,6 +2398,19 @@ function finishSessionRunSuccessfully(
set((state) => {
const sendingSessionIds = withoutKey(state.sendingSessionIds, sessionId);
const nextState = { ...state, sendingSessionIds };
const currentTranscript = state.sessionTranscriptBySessionId[sessionId];
const completedTranscript = compactionGeneration !== undefined
&& state.runtimeGeneration === compactionGeneration
? completeCompaction(
getOrCreateSessionTranscript(state, sessionId),
{ runID: String(runToken), generation: compactionGeneration },
{
runID: String(runToken),
generation: compactionGeneration,
completedAt: Date.now(),
},
)
: currentTranscript;
return {
...getSessionMessagePatch(state, sessionId, messages),
...dispatchSessionRunEvent(state, sessionId, {
@@ -2413,6 +2427,14 @@ function finishSessionRunSuccessfully(
sendingSessionId: getSendingSessionIdForSelection(nextState),
loading: false,
...errorState(null),
...(completedTranscript && completedTranscript !== currentTranscript
? {
sessionTranscriptBySessionId: {
...state.sessionTranscriptBySessionId,
[sessionId]: completedTranscript,
},
}
: {}),
};
});
invalidateSessionRun(sessionId);
@@ -3051,6 +3073,7 @@ async function runSessionSubmission(
runToken,
messages,
statuses,
submission.kind === 'compact' ? runGeneration : undefined,
);
if (
completed