fix: close PI-140 cutover gaps

Back up unknown legacy Agents, reconnect settled Conversation observation, remove remaining active repository residue, and restore the bundled Python verifier import.
This commit is contained in:
2026-08-24 12:47:16 +08:00
parent 5a275b93a7
commit 7a15b1b49c
12 changed files with 286 additions and 247 deletions

View File

@@ -7,6 +7,7 @@ import {
type ConversationReducerState,
} from '../../shared/coding-conversation-reducer';
import { AppError } from '@/lib/error-model';
import { queueCodingConversationSessionSync } from '@/lib/agent-session-sync';
import {
getCodingConversationSnapshot,
openCodingConversationEvents,
@@ -55,6 +56,7 @@ interface CodingConversationStoreDependencies {
openEvents(conversationId?: string): Promise<EventSource>;
submitPrompt(input: SubmitCodingConversationPromptInput): Promise<PromptAcceptance>;
recover(conversationId: string): Promise<void>;
queueSettledSessionSync(snapshot: ConversationSnapshot): void;
createId(kind: 'request' | 'node'): string;
preparationTimeoutMs: number;
}
@@ -277,6 +279,7 @@ function defaultDependencies(): CodingConversationStoreDependencies {
openEvents: openCodingConversationEvents,
submitPrompt: submitCodingConversationPrompt,
recover: recoverCodingConversation,
queueSettledSessionSync: queueCodingConversationSessionSync,
createId: () => crypto.randomUUID(),
preparationTimeoutMs: 10_000,
};
@@ -332,6 +335,26 @@ function validPatchBatchRange(event: CodingConversationPatchBatchEvent): boolean
));
}
function completesOrdinaryPrompt(
event: CodingConversationPatchBatchEvent,
current: ConversationSnapshot,
): boolean {
let mode = current.run.mode;
let observedActiveRun = current.run.status !== 'idle';
for (const item of event.items) {
if (item.patch.op !== 'run.state') continue;
if (item.patch.run.mode) mode = item.patch.run.mode;
if (item.patch.run.status !== 'idle') observedActiveRun = true;
if (observedActiveRun
&& mode === 'prompt'
&& item.patch.run.status === 'idle'
&& item.patch.run.terminalReason === 'completed') {
return true;
}
}
return false;
}
export function createCodingConversationStore(
dependencies: Partial<CodingConversationStoreDependencies> = {},
): StoreApi<CodingConversationStoreState> {
@@ -892,7 +915,9 @@ export function createCodingConversationStore(
}
return;
}
const shouldSyncSettledSession = completesOrdinaryPrompt(event, currentSnapshot);
let recover = false;
let applied = false;
set((state) => {
const current = state.entriesByConversationId[event.conversationId] ?? emptyEntry();
let reducer = current.reducer;
@@ -911,6 +936,7 @@ export function createCodingConversationStore(
}
}
if (reducer === current.reducer) return state;
applied = true;
const incomingMessages = event.items.flatMap((item) => (
item.patch.op === 'message.upsert' ? [item.patch.node] : []
));
@@ -950,6 +976,9 @@ export function createCodingConversationStore(
});
if (recover) {
void get().loadSnapshot(event.conversationId, true).catch(() => undefined);
} else if (applied && shouldSyncSettledSession) {
const settledSnapshot = selectCodingConversationSnapshot(event.conversationId)(get());
if (settledSnapshot) deps.queueSettledSessionSync(settledSnapshot);
}
},
}));