
























@@ -28,6 +28,7 @@ import {
2828} from "../utils/delivery-context.shared.js";
2929import { injectTimestamp, timestampOptsFromConfig } from "./server-methods/agent-timestamp.js";
3030import { loadSessionEntry } from "./session-utils.js";
31+import { runStartupTasks, type StartupTask } from "./startup-tasks.js";
31323233const log = createSubsystemLogger("gateway/restart-sentinel");
3334const OUTBOUND_RETRY_DELAY_MS = 1_000;
@@ -299,10 +300,12 @@ async function dispatchRestartSentinelContinuation(params: {
299300}
300301}
301302302-export async function scheduleRestartSentinelWake(params: { deps: CliDeps }) {
303+async function loadRestartSentinelStartupTask(params: {
304+deps: CliDeps;
305+}): Promise<StartupTask | null> {
303306const sentinel = await consumeRestartSentinel();
304307if (!sentinel) {
305-return;
308+return null;
306309}
307310const payload = sentinel.payload;
308311const sessionKey = payload.sessionKey?.trim();
@@ -315,123 +318,138 @@ export async function scheduleRestartSentinelWake(params: { deps: CliDeps }) {
315318undefined,
316319);
317320318-if (!sessionKey) {
319-const mainSessionKey = resolveMainSessionKeyFromConfig();
320-enqueueSystemEvent(message, { sessionKey: mainSessionKey });
321-if (payload.continuation) {
322-log.warn(`${summary}: continuation skipped: restart sentinel sessionKey unavailable`, {
323-sessionKey: mainSessionKey,
324-continuationKind: payload.continuation.kind,
325-});
321+const run = async () => {
322+if (!sessionKey) {
323+const mainSessionKey = resolveMainSessionKeyFromConfig();
324+enqueueSystemEvent(message, { sessionKey: mainSessionKey });
325+if (payload.continuation) {
326+log.warn(`${summary}: continuation skipped: restart sentinel sessionKey unavailable`, {
327+sessionKey: mainSessionKey,
328+continuationKind: payload.continuation.kind,
329+});
330+}
331+return { status: "ran" as const };
326332}
327-return;
328-}
329333330-const { baseSessionKey, threadId: sessionThreadId } = parseSessionThreadInfo(sessionKey);
334+ const { baseSessionKey, threadId: sessionThreadId } = parseSessionThreadInfo(sessionKey);
331335332-const { cfg, entry, canonicalKey, storePath } = loadSessionEntry(sessionKey);
336+ const { cfg, entry, canonicalKey, storePath } = loadSessionEntry(sessionKey);
333337334-// Prefer delivery context from sentinel (captured at restart) over session store
335-// Handles race condition where store wasn't flushed before restart
336-const sentinelContext = payload.deliveryContext;
337-let sessionDeliveryContext = deliveryContextFromSession(entry);
338-if (
339-!hasRoutableDeliveryContext(sessionDeliveryContext) &&
340-baseSessionKey &&
341-baseSessionKey !== sessionKey
342-) {
343-const { entry: baseEntry } = loadSessionEntry(baseSessionKey);
344-sessionDeliveryContext = mergeDeliveryContext(
345-sessionDeliveryContext,
346-deliveryContextFromSession(baseEntry),
347-);
348-}
338+const sentinelContext = payload.deliveryContext;
339+let sessionDeliveryContext = deliveryContextFromSession(entry);
340+if (
341+!hasRoutableDeliveryContext(sessionDeliveryContext) &&
342+baseSessionKey &&
343+baseSessionKey !== sessionKey
344+) {
345+const { entry: baseEntry } = loadSessionEntry(baseSessionKey);
346+sessionDeliveryContext = mergeDeliveryContext(
347+sessionDeliveryContext,
348+deliveryContextFromSession(baseEntry),
349+);
350+}
349351350-const origin = mergeDeliveryContext(sentinelContext, sessionDeliveryContext);
352+ const origin = mergeDeliveryContext(sentinelContext, sessionDeliveryContext);
351353352-enqueueRestartSentinelWake(message, sessionKey, wakeDeliveryContext);
354+ enqueueRestartSentinelWake(message, sessionKey, wakeDeliveryContext);
353355354-const channelRaw = origin?.channel;
355-const channel = channelRaw ? normalizeChannelId(channelRaw) : null;
356-const to = origin?.to;
357-const threadId =
358-payload.threadId ??
359-sessionThreadId ??
360-(origin?.threadId != null ? String(origin.threadId) : undefined);
361-let resolvedTo: string | undefined;
362-let replyToId: string | undefined;
363-let resolvedThreadId = threadId;
356+ const channelRaw = origin?.channel;
357+ const channel = channelRaw ? normalizeChannelId(channelRaw) : null;
358+ const to = origin?.to;
359+ const threadId =
360+ payload.threadId ??
361+ sessionThreadId ??
362+ (origin?.threadId != null ? String(origin.threadId) : undefined);
363+ let resolvedTo: string | undefined;
364+ let replyToId: string | undefined;
365+ let resolvedThreadId = threadId;
364366365-if (channel && to) {
366-const resolved = resolveOutboundTarget({
367- channel,
368- to,
369- cfg,
370-accountId: origin?.accountId,
371-mode: "implicit",
372-});
373-if (resolved.ok) {
374-resolvedTo = resolved.to;
375-const replyTransport =
376-getChannelPlugin(channel)?.threading?.resolveReplyTransport?.({
377- cfg,
378-accountId: origin?.accountId,
379- threadId,
380-}) ?? null;
381-replyToId = replyTransport?.replyToId ?? undefined;
382-resolvedThreadId =
383-replyTransport && Object.hasOwn(replyTransport, "threadId")
384- ? replyTransport.threadId != null
385- ? String(replyTransport.threadId)
386- : undefined
387- : threadId;
388-const outboundSession = buildOutboundSessionContext({
367+if (channel && to) {
368+const resolved = resolveOutboundTarget({
369+ channel,
370+ to,
389371 cfg,
390-sessionKey: canonicalKey,
372+accountId: origin?.accountId,
373+mode: "implicit",
391374});
375+if (resolved.ok) {
376+resolvedTo = resolved.to;
377+const replyTransport =
378+getChannelPlugin(channel)?.threading?.resolveReplyTransport?.({
379+ cfg,
380+accountId: origin?.accountId,
381+ threadId,
382+}) ?? null;
383+replyToId = replyTransport?.replyToId ?? undefined;
384+resolvedThreadId =
385+replyTransport && Object.hasOwn(replyTransport, "threadId")
386+ ? replyTransport.threadId != null
387+ ? String(replyTransport.threadId)
388+ : undefined
389+ : threadId;
390+const outboundSession = buildOutboundSessionContext({
391+ cfg,
392+sessionKey: canonicalKey,
393+});
392394393-await deliverRestartSentinelNotice({
395+await deliverRestartSentinelNotice({
396+deps: params.deps,
397+ cfg,
398+sessionKey: canonicalKey,
399+ summary,
400+ message,
401+ channel,
402+to: resolvedTo,
403+accountId: origin?.accountId,
404+ replyToId,
405+threadId: resolvedThreadId,
406+session: outboundSession,
407+});
408+}
409+}
410+411+if (!payload.continuation) {
412+return { status: "ran" as const };
413+}
414+415+try {
416+await dispatchRestartSentinelContinuation({
394417deps: params.deps,
395418 cfg,
419+ storePath,
396420sessionKey: canonicalKey,
397- summary,
398- message,
399- channel,
400-to: resolvedTo,
401-accountId: origin?.accountId,
402- replyToId,
403-threadId: resolvedThreadId,
404-session: outboundSession,
421+continuation: payload.continuation,
422+ts: payload.ts,
423+route: resolveRestartContinuationRoute({
424+channel: channel ?? undefined,
425+to: resolvedTo,
426+accountId: origin?.accountId,
427+ replyToId,
428+threadId: resolvedThreadId,
429+}),
430+});
431+} catch (err) {
432+log.warn(`${summary}: continuation delivery failed: ${String(err)}`, {
433+sessionKey: canonicalKey,
434+continuationKind: payload.continuation.kind,
405435});
406436}
407-}
437+return { status: "ran" as const };
438+};
408439409-if (!payload.continuation) {
410-return;
411-}
440+return {
441+source: "restart-sentinel",
442+ ...(sessionKey ? { sessionKey } : {}),
443+ run,
444+};
445+}
412446413-try {
414-await dispatchRestartSentinelContinuation({
415-deps: params.deps,
416- cfg,
417- storePath,
418-sessionKey: canonicalKey,
419-continuation: payload.continuation,
420-ts: payload.ts,
421-route: resolveRestartContinuationRoute({
422-channel: channel ?? undefined,
423-to: resolvedTo,
424-accountId: origin?.accountId,
425- replyToId,
426-threadId: resolvedThreadId,
427-}),
428-});
429-} catch (err) {
430-log.warn(`${summary}: continuation delivery failed: ${String(err)}`, {
431-sessionKey: canonicalKey,
432-continuationKind: payload.continuation.kind,
433-});
447+export async function scheduleRestartSentinelWake(params: { deps: CliDeps }) {
448+const task = await loadRestartSentinelStartupTask(params);
449+if (!task) {
450+return;
434451}
452+await runStartupTasks({ tasks: [task], log });
435453}
436454437455export function shouldWakeFromRestartSentinel() {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。