
























@@ -154,6 +154,7 @@ import { ADMIN_SCOPE } from "../method-scopes.js";
154154import { chatAbortMarkerTimestampMs, type ChatRunTiming } from "../server-chat-state.js";
155155import { getMaxChatHistoryMessagesBytes, MAX_PAYLOAD_BYTES } from "../server-constants.js";
156156import { resolveSessionHistoryTailReadOptions } from "../session-history-state.js";
157+import { persistGatewaySessionLifecycleEvent } from "../session-lifecycle-state.js";
157158import { readSessionTranscriptIndex } from "../session-transcript-index.fs.js";
158159import {
159160capArrayByJsonBytes,
@@ -3746,6 +3747,14 @@ export const chatHandlers: GatewayRequestHandlers = {
37463747const deliveredReplies: Array<{ payload: ReplyPayload; kind: "block" | "final" }> = [];
37473748let appendedWebchatAgentMedia = false;
37483749let agentRunStarted = false;
3750+let pendingDispatchLifecycleError:
3751+| {
3752+endedAt: number;
3753+error: string;
3754+sessionId: string;
3755+startedAt: number;
3756+}
3757+| undefined;
37493758const userTurnRecorder: UserTurnTranscriptRecorder = createUserTurnTranscriptRecorder({
37503759input: baseUserTurnInput,
37513760resolveInput: () => userTurnInputPromise,
@@ -4957,6 +4966,7 @@ export const chatHandlers: GatewayRequestHandlers = {
49574966);
49584967})
49594968.catch(async (err: unknown) => {
4969+const errorMessage = String(err);
49604970const emitAfterError =
49614971userTurnRecorder.hasPersisted() || userTurnRecorder.isBlocked()
49624972 ? Promise.resolve()
@@ -4966,7 +4976,19 @@ export const chatHandlers: GatewayRequestHandlers = {
49664976`webchat user transcript update failed after error: ${formatForLog(transcriptErr)}`,
49674977);
49684978});
4969-const error = errorShape(ErrorCodes.UNAVAILABLE, String(err));
4979+if (
4980+!agentRunStarted &&
4981+!activeRunAbort.controller.signal.aborted &&
4982+!context.chatAbortedRuns.has(clientRunId)
4983+) {
4984+pendingDispatchLifecycleError = {
4985+endedAt: Date.now(),
4986+error: errorMessage,
4987+sessionId: activeRunAbort.entry?.sessionId ?? backingSessionId ?? clientRunId,
4988+startedAt: activeRunAbort.entry?.startedAtMs ?? now,
4989+};
4990+}
4991+const error = errorShape(ErrorCodes.UNAVAILABLE, errorMessage);
49704992setGatewayDedupeEntry({
49714993dedupe: context.dedupe,
49724994key: `chat:${clientRunId}`,
@@ -4976,7 +4998,7 @@ export const chatHandlers: GatewayRequestHandlers = {
49764998payload: {
49774999runId: clientRunId,
49785000status: "error" as const,
4979-summary: String(err),
5001+summary: errorMessage,
49805002},
49815003 error,
49825004},
@@ -4986,14 +5008,61 @@ export const chatHandlers: GatewayRequestHandlers = {
49865008runId: clientRunId,
49875009 sessionKey,
49885010 agentId,
4989-errorMessage: String(err),
5011+ errorMessage,
49905012});
49915013})
49925014.finally(() => {
49935015activeRunAbort.cleanup();
49945016clearAgentRunContext(clientRunId, lifecycleGeneration);
49955017clearActiveChatSendDedupeRun(context.dedupe, activeChatSendDedupeKey, clientRunId);
49965018context.removeChatRun(clientRunId, clientRunId, sessionKey);
5019+if (!pendingDispatchLifecycleError) {
5020+return;
5021+}
5022+const persistDispatchLifecycleError = async () => {
5023+const dispatchError = pendingDispatchLifecycleError;
5024+if (!dispatchError) {
5025+return;
5026+}
5027+const hasActiveRun = hasTrackedActiveSessionRun({
5028+ context,
5029+requestedKey: rawSessionKey,
5030+canonicalKey: sessionKey,
5031+ ...(sessionKey === "global" && agentId ? { agentId } : {}),
5032+defaultAgentId: resolveDefaultAgentId(cfg),
5033+});
5034+if (hasActiveRun) {
5035+return;
5036+}
5037+try {
5038+await persistGatewaySessionLifecycleEvent({
5039+ sessionKey,
5040+ ...(sessionKey === "global" && agentId ? { agentId } : {}),
5041+event: {
5042+runId: clientRunId,
5043+sessionId: dispatchError.sessionId,
5044+ lifecycleGeneration,
5045+ts: dispatchError.endedAt,
5046+data: {
5047+phase: "error",
5048+startedAt: dispatchError.startedAt,
5049+endedAt: dispatchError.endedAt,
5050+error: dispatchError.error,
5051+},
5052+},
5053+});
5054+emitSessionsChanged(context, {
5055+ sessionKey,
5056+ ...(agentId ? { agentId } : {}),
5057+reason: "chat.dispatch-error",
5058+});
5059+} catch (persistErr: unknown) {
5060+context.logGateway.warn(
5061+`webchat session lifecycle persist failed after error: ${formatForLog(persistErr)}`,
5062+);
5063+}
5064+};
5065+void persistDispatchLifecycleError();
49975066});
49985067} catch (err) {
49995068activeRunAbort.cleanup({ force: true });
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。