




















@@ -1602,6 +1602,7 @@ export async function runEmbeddedAttempt(
16021602let removeToolResultContextGuard: (() => void) | undefined;
16031603let trajectoryRecorder: ReturnType<typeof createTrajectoryRuntimeRecorder> | null = null;
16041604let trajectoryEndRecorded = false;
1605+let buildAbortSettlePromise: () => Promise<void> | null = () => null;
16051606try {
16061607await repairSessionFileIfNeeded({
16071608sessionFile: params.sessionFile,
@@ -1905,8 +1906,38 @@ export async function runEmbeddedAttempt(
19051906let unwindowedContextEngineMessagesForPrecheck: AgentMessage[] | undefined;
19061907let contextEnginePromptAuthority: NonNullable<AssembleResult["promptAuthority"]> =
19071908"assembled";
1909+const inFlightPromptSettlePromises = new Set<Promise<void>>();
1910+const inFlightAbortSettlePromises = new Set<Promise<void>>();
1911+const trackSettlePromise = (
1912+promises: Set<Promise<void>>,
1913+promise: Promise<void>,
1914+): Promise<void> => {
1915+promises.add(promise);
1916+void promise.then(
1917+() => {
1918+promises.delete(promise);
1919+},
1920+() => {
1921+promises.delete(promise);
1922+},
1923+);
1924+return promise;
1925+};
1926+const trackPromptSettlePromise = (promise: Promise<void>): Promise<void> =>
1927+trackSettlePromise(inFlightPromptSettlePromises, promise);
1928+const trackAbortSettlePromise = (promise: Promise<void>): Promise<void> =>
1929+trackSettlePromise(inFlightAbortSettlePromises, promise);
1930+const abortActiveSession = (): Promise<void> =>
1931+trackAbortSettlePromise(Promise.resolve(activeSession.abort()));
1932+buildAbortSettlePromise = (): Promise<void> | null => {
1933+const promises = [...inFlightPromptSettlePromises, ...inFlightAbortSettlePromises];
1934+if (promises.length === 0) {
1935+return null;
1936+}
1937+return Promise.allSettled(promises).then(() => undefined);
1938+};
19081939abortSessionForYield = () => {
1909-yieldAbortSettled = Promise.resolve(activeSession.abort());
1940+yieldAbortSettled = abortActiveSession();
19101941};
19111942queueYieldInterruptForSession = () => {
19121943queueSessionsYieldInterruptMessage(activeSession);
@@ -2596,14 +2627,19 @@ export async function runEmbeddedAttempt(
25962627runAbortController.abort(reason);
25972628}
25982629abortCompaction();
2599-void activeSession.abort();
2630+void abortActiveSession();
26002631};
26012632idleTimeoutTrigger = (error) => {
26022633idleTimedOut = true;
26032634abortRun(true, error);
26042635};
26052636const abortable = <T>(promise: Promise<T>): Promise<T> =>
26062637abortableWithSignal(runAbortController.signal, promise);
2638+const promptActiveSession = (
2639+prompt: string,
2640+options?: Parameters<typeof activeSession.prompt>[1],
2641+): Promise<void> =>
2642+abortable(trackPromptSettlePromise(activeSession.prompt(prompt, options)));
2607264326082644const subscription = subscribeEmbeddedPiSession(
26092645buildEmbeddedSubscriptionParams({
@@ -3488,7 +3524,7 @@ export async function runEmbeddedAttempt(
34883524inFlightPrompt: promptForModel,
34893525});
34903526if (promptSubmission.runtimeOnly) {
3491-await abortable(activeSession.prompt(promptForModel));
3527+await promptActiveSession(promptForModel);
34923528} else {
34933529await queueRuntimeContextForNextTurn({
34943530session: activeSession,
@@ -3498,11 +3534,9 @@ export async function runEmbeddedAttempt(
34983534// Only pass images option if there are actually images to pass
34993535// This avoids potential issues with models that don't expect the images parameter
35003536if (imageResult.images.length > 0) {
3501-await abortable(
3502-activeSession.prompt(promptForModel, { images: imageResult.images }),
3503-);
3537+await promptActiveSession(promptForModel, { images: imageResult.images });
35043538} else {
3505-await abortable(activeSession.prompt(promptForModel));
3539+await promptActiveSession(promptForModel);
35063540}
35073541}
35083542}
@@ -4116,6 +4150,12 @@ export async function runEmbeddedAttempt(
41164150runId: params.runId,
41174151catalogRef: toolSearchCatalogRef,
41184152});
4153+const cleanupAborted =
4154+Boolean(params.abortSignal?.aborted) ||
4155+aborted ||
4156+timedOut ||
4157+idleTimedOut ||
4158+timedOutDuringCompaction;
41194159await cleanupEmbeddedAttemptResources({
41204160 removeToolResultContextGuard,
41214161 flushPendingToolResultsAfterIdle,
@@ -4124,14 +4164,10 @@ export async function runEmbeddedAttempt(
41244164 bundleMcpRuntime,
41254165 bundleLspRuntime,
41264166 sessionLock,
4127-// PERF: If the run was aborted (user stop, timeout, etc.), skip the idle wait
4128-// and clear pending results synchronously so we can release the session lock ASAP.
4129-aborted:
4130-Boolean(params.abortSignal?.aborted) ||
4131-aborted ||
4132-timedOut ||
4133-idleTimedOut ||
4134-timedOutDuringCompaction,
4167+aborted: cleanupAborted,
4168+abortSettlePromise: cleanupAborted ? buildAbortSettlePromise() : null,
4169+runId: params.runId,
4170+sessionId: params.sessionId,
41354171});
41364172} catch (err) {
41374173cleanupError = err;
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。