



























@@ -51,6 +51,7 @@ type EventHandlerContext = {
5151};
52525353const DEFAULT_STREAMING_WATCHDOG_MS = 30_000;
54+const LIFECYCLE_ERROR_RETRY_GRACE_MS = 15_000;
5455const STREAMING_WATCHDOG_USER_MESSAGE =
5556"This response is taking longer than expected. Still waiting for the current run.";
5657@@ -80,6 +81,10 @@ export function createEventHandlers(context: EventHandlerContext) {
8081let lastSessionKey = state.currentSessionKey;
8182let pendingHistoryRefresh = false;
8283let reconnectPendingRunId: string | null = null;
84+const pendingTerminalLifecycleErrors = new Map<
85+string,
86+{ errorMessage: string; timer: ReturnType<typeof setTimeout> }
87+>();
83888489const streamingWatchdogMs =
8590typeof context.streamingWatchdogMs === "number" &&
@@ -106,6 +111,22 @@ export function createEventHandlers(context: EventHandlerContext) {
106111streamingWatchdogRunId = null;
107112};
108113114+const clearPendingTerminalLifecycleError = (runId: string) => {
115+const pending = pendingTerminalLifecycleErrors.get(runId);
116+if (!pending) {
117+return;
118+}
119+clearTimeout(pending.timer);
120+pendingTerminalLifecycleErrors.delete(runId);
121+};
122+123+const clearPendingTerminalLifecycleErrors = () => {
124+for (const pending of pendingTerminalLifecycleErrors.values()) {
125+clearTimeout(pending.timer);
126+}
127+pendingTerminalLifecycleErrors.clear();
128+};
129+109130const pauseStreamingWatchdog = () => {
110131clearStreamingWatchdog();
111132};
@@ -182,6 +203,7 @@ export function createEventHandlers(context: EventHandlerContext) {
182203reconnectPendingRunId = null;
183204clearLocalRunIds?.();
184205clearLocalBtwRunIds?.();
206+clearPendingTerminalLifecycleErrors();
185207btw.clear();
186208clearStreamingWatchdog();
187209};
@@ -336,6 +358,46 @@ export function createEventHandlers(context: EventHandlerContext) {
336358void refreshSessionInfo?.();
337359};
338360361+const renderTerminalRunError = (params: {
362+runId: string;
363+errorMessage: string;
364+requireActiveOrPending?: boolean;
365+}): boolean => {
366+const { runId, errorMessage } = params;
367+const wasActiveRun = state.activeChatRunId === runId;
368+if (
369+params.requireActiveOrPending === true &&
370+!wasActiveRun &&
371+state.pendingChatRunId !== runId
372+) {
373+return false;
374+}
375+const renderedError = formatRawAssistantErrorForUi(errorMessage);
376+chatLog.dismissPendingSystem(runId);
377+chatLog.addSystem(resolveAuthErrorHint(errorMessage) ?? `run error: ${renderedError}`);
378+noteFinalizedRun(runId, { displayedFinal: true });
379+terminateRun({ runId, wasActiveRun, status: "error" });
380+maybeRefreshHistoryForRun(runId);
381+return true;
382+};
383+384+const renderTerminalLifecycleError = (runId: string, errorMessage: string) => {
385+if (!renderTerminalRunError({ runId, errorMessage, requireActiveOrPending: true })) {
386+return;
387+}
388+tui.requestRender(true);
389+};
390+391+const scheduleTerminalLifecycleError = (runId: string, errorMessage: string) => {
392+clearPendingTerminalLifecycleError(runId);
393+const timer = setTimeout(() => {
394+pendingTerminalLifecycleErrors.delete(runId);
395+renderTerminalLifecycleError(runId, errorMessage);
396+}, LIFECYCLE_ERROR_RETRY_GRACE_MS);
397+timer.unref?.();
398+pendingTerminalLifecycleErrors.set(runId, { errorMessage, timer });
399+};
400+339401const hasConcurrentActiveRun = (runId: string) => {
340402const activeRunId = state.activeChatRunId;
341403if (!activeRunId || activeRunId === runId) {
@@ -463,6 +525,10 @@ export function createEventHandlers(context: EventHandlerContext) {
463525if (evt.state === "delta") {
464526return;
465527}
528+if (evt.state === "error" && finalizedRunsWithDisplay.has(evt.runId)) {
529+clearStaleStreamingIfNoTrackedRunRemains();
530+return;
531+}
466532if (evt.state === "final") {
467533const hasLateDisplayableFinal =
468534hasDisplayableFinalEvent(evt) && !finalizedRunsWithDisplay.has(evt.runId);
@@ -475,6 +541,7 @@ export function createEventHandlers(context: EventHandlerContext) {
475541if (reconnectPendingRunId === evt.runId) {
476542reconnectPendingRunId = null;
477543}
544+clearPendingTerminalLifecycleError(evt.runId);
478545chatLog.dismissPendingSystem(evt.runId);
479546noteSessionRun(evt.runId);
480547if (!state.activeChatRunId && !isLocalBtwRunId?.(evt.runId)) {
@@ -567,12 +634,10 @@ export function createEventHandlers(context: EventHandlerContext) {
567634}
568635if (evt.state === "error") {
569636forgetLocalBtwRunId?.(evt.runId);
570-const wasActiveRun = state.activeChatRunId === evt.runId;
571-const errorMessage = evt.errorMessage ?? "unknown";
572-const renderedError = formatRawAssistantErrorForUi(errorMessage);
573-chatLog.addSystem(resolveAuthErrorHint(errorMessage) ?? `run error: ${renderedError}`);
574-terminateRun({ runId: evt.runId, wasActiveRun, status: "error" });
575-maybeRefreshHistoryForRun(evt.runId);
637+renderTerminalRunError({
638+runId: evt.runId,
639+errorMessage: evt.errorMessage ?? "unknown",
640+});
576641}
577642tui.requestRender();
578643};
@@ -651,6 +716,9 @@ export function createEventHandlers(context: EventHandlerContext) {
651716}
652717}
653718const phase = typeof evt.data?.phase === "string" ? evt.data.phase : "";
719+if (phase && phase !== "error") {
720+clearPendingTerminalLifecycleError(evt.runId);
721+}
654722const isPostFinalizingRun = postFinalizingRuns.has(evt.runId);
655723const isPostFinalTerminalPhase =
656724isPostFinalizingRun && (phase === "end" || phase === "error");
@@ -687,7 +755,19 @@ export function createEventHandlers(context: EventHandlerContext) {
687755if (!canUpdateActivityStatus) {
688756return;
689757}
690-setActivityStatus("error");
758+const isTerminalLifecycleError = typeof evt.data?.endedAt === "number";
759+if (isTerminalLifecycleError && (isActiveRun || isPendingRun)) {
760+const errorMessage =
761+typeof evt.data?.error === "string"
762+ ? evt.data.error
763+ : typeof evt.data?.errorMessage === "string"
764+ ? evt.data.errorMessage
765+ : "unknown";
766+scheduleTerminalLifecycleError(evt.runId, errorMessage);
767+setActivityStatus("error");
768+} else {
769+setActivityStatus("error");
770+}
691771}
692772tui.requestRender();
693773}
@@ -723,6 +803,7 @@ export function createEventHandlers(context: EventHandlerContext) {
723803724804const dispose = () => {
725805clearStreamingWatchdog();
806+clearPendingTerminalLifecycleErrors();
726807};
727808728809return {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。