UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

513 lines (512 loc) 25.1 kB
import { o as normalizeLowercaseStringOrEmpty } from "./string-coerce-CIXf7egm.js"; import { r as racePromiseWithAbortSignal } from "./abort-signal-D2k14JsD.js"; import { t as formatErrorMessage } from "./errors-Db3Ymjlb.js"; import { t as createSubsystemLogger } from "./subsystem-Dy2tqXOS.js"; import { t as isDiagnosticFlagEnabled } from "./diagnostic-flags-qVPAqdVk.js"; import { c as getAgentEventLifecycleGeneration } from "./agent-events-CoxiItUi.js"; import { a as getPluginRuntimeGatewayRequestScope, c as withPluginRuntimeGatewayContextResolver, r as getGatewayContextResolver, t as bindGatewayContextResolver } from "./gateway-request-scope-BCMYlsDI.js"; import "./session-accessor-YsytfDtG.js"; import { l as loadSessionEntry } from "./session-accessor.sqlite-entry-CWk3jL7s.js"; import { c as getSessionWorkAdmissionOwnerRelease, n as beginSessionWorkAdmission } from "./session-lifecycle-admission-CS8v45tk.js"; import { C as waitForReplyRunSuccessorAdmission, F as isReplyRunRecoveryBlocked, G as REPLY_RUN_TERMINAL_SETTLE_TIMEOUT_MS, H as runAfterReplyOperationClear, I as isReplyRunSuccessorAdmissionBlocked, J as ReplyRunSuccessorAdmissionBlockedError, K as ReplyRunAlreadyActiveError, P as isReplyRunEvidenceStale, S as waitForReplyRunFollowupAdmission, V as retainReplyOperationUntilComplete, W as REPLY_RUN_IDLE_SETTLE_TIMEOUT_MS, h as replyRunRegistry, k as expireStaleReplyOperation, q as ReplyRunFollowupAdmissionBlockedError, w as createReplyOperation, z as registerReplyOperationSuccessorBarrier } from "./reply-run-registry.registry-BMo0d96L.js"; import { o as getDiagnosticSessionActivitySnapshot, v as resolveRunStaleThresholdMs } from "./diagnostic-run-activity-CJrEba4R.js"; import "./reply-run-registry-BlmBKV23.js"; import { f as resolveSessionWorkStartError, i as SessionWorkStartChangedError, l as isRestartRecoveryTombstone, n as SESSION_RESTART_RECOVERY_TOMBSTONE_ERROR_CODE, r as SessionRestartRecoveryTombstoneError } from "./lifecycle-BaroCBMc.js"; import { i as isMainRestartRecoveryCandidate } from "./main-session-recovery-state-DD1DvBOq.js"; import { t as MAIN_SESSION_RECOVERY_WORK_ADMISSION_OWNER } from "./main-session-recovery-admission-BnYEQypz.js"; import { t as scheduleMainSessionRecoveryPendingTarget } from "./main-session-recovery-owner-release-CNuMN7iH.js"; import { a as releaseMainSessionRecoveryOwner, t as claimMainSessionRecoveryOwner } from "./main-session-recovery-store-jMegHmAf.js"; //#region src/shared/silent-reply-policy.ts const DEFAULT_SILENT_REPLY_POLICY = { direct: "disallow", group: "allow", internal: "allow" }; /** Classifies a reply context for silent-reply policy from explicit type, session key, or surface. */ function classifySilentReplyConversationType(params) { if (params.conversationType) return params.conversationType; const normalizedSessionKey = normalizeLowercaseStringOrEmpty(params.sessionKey); if (normalizedSessionKey.includes(":group:") || normalizedSessionKey.includes(":channel:")) return "group"; if (normalizedSessionKey.includes(":direct:") || normalizedSessionKey.includes(":dm:")) return "direct"; if (normalizeLowercaseStringOrEmpty(params.surface) === "webchat") return "direct"; return "internal"; } /** Resolves silent-reply policy with surface overrides while keeping direct replies audible. */ function resolveSilentReplyPolicyFromPolicies(params) { if (params.conversationType === "direct") return "disallow"; return params.surfacePolicy?.[params.conversationType] ?? params.defaultPolicy?.[params.conversationType] ?? DEFAULT_SILENT_REPLY_POLICY[params.conversationType]; } //#endregion //#region src/config/silent-reply.ts function resolveSilentReplyConversationContext(params) { const conversationType = classifySilentReplyConversationType({ sessionKey: params.sessionKey, surface: params.surface, conversationType: params.conversationType }); const normalizedSurface = normalizeLowercaseStringOrEmpty(params.surface); const surface = normalizedSurface ? params.cfg?.surfaces?.[normalizedSurface] : void 0; return { conversationType, defaultPolicy: params.cfg?.agents?.defaults?.silentReply, surfacePolicy: surface?.silentReply }; } /** Resolves the effective silent-reply settings for a routed conversation. */ function resolveSilentReplySettings(params) { return { policy: resolveSilentReplyPolicyFromPolicies(resolveSilentReplyConversationContext(params)) }; } /** Returns just the effective silent-reply policy for callers that do not need metadata. */ function resolveSilentReplyPolicy(params) { return resolveSilentReplySettings(params).policy; } //#endregion //#region src/auto-reply/reply/reply-turn-admission.ts var QueuedFollowupLifecycleInvalidatedError = class extends Error {}; const log = createSubsystemLogger("auto-reply/reply-turn-admission"); const lifecycleAdmissionByOperation = /* @__PURE__ */ new WeakMap(); async function releaseReplyRecoveryOwner(lease) { if (!lease) return; try { return await releaseMainSessionRecoveryOwner(lease); } catch (error) { log.warn(`failed to release main-session recovery reply owner: ${formatErrorMessage(error)}`); return; } } /** Runs owner work with its admission marked as the initiating lifecycle context. */ async function runWithReplyOperationLifecycleAdmission(operation, run) { const admission = lifecycleAdmissionByOperation.get(operation); if (admission) return await admission.run(run); const resolver = getGatewayContextResolver(operation); return await withPluginRuntimeGatewayContextResolver(resolver, run); } function rejectLifecycleInvalidatedWork(params) { if (params.kind === "queued_followup") { const error = new QueuedFollowupLifecycleInvalidatedError(params.message); if (params.restartRecoveryTombstone === true) Object.assign(error, { code: SESSION_RESTART_RECOVERY_TOMBSTONE_ERROR_CODE }); throw error; } if (params.restartRecoveryTombstone === true) throw new SessionRestartRecoveryTombstoneError(params.message); if (params.kind === "visible" && params.transientSessionChange === true) throw new SessionWorkStartChangedError(params.message); throw new Error(params.message); } function isAbortSignalAborted(signal) { return signal?.aborted === true; } function expireVisibleStaleOperation(operation) { if (!operation) return false; const idleMs = Date.now() - operation.lastActivityAtMs; if (operation.result) return idleMs >= 6e4 && expireStaleReplyOperation(operation, "terminal_unreleased"); return isReplyRunEvidenceStale(operation) && expireStaleReplyOperation(operation, "no_activity"); } function resolveVisibleActiveWaitMs(operation) { if (!operation || isReplyRunRecoveryBlocked(operation)) return REPLY_RUN_IDLE_SETTLE_TIMEOUT_MS; const ageMs = Date.now() - operation.lastActivityAtMs; const activity = getDiagnosticSessionActivitySnapshot({ sessionId: operation.sessionId, sessionKey: operation.key }); const remainingMs = operation.result ? REPLY_RUN_TERMINAL_SETTLE_TIMEOUT_MS - ageMs : resolveRunStaleThresholdMs(activity, ageMs) - ageMs; return Math.min(REPLY_RUN_IDLE_SETTLE_TIMEOUT_MS, Math.max(1, remainingMs)); } /** Waits for or claims the per-session reply run slot. */ async function admitReplyTurn(params) { let sessionId = params.sessionId; const resolveGatewayContext = params.adoptOperation ? getGatewayContextResolver(params.adoptOperation) : Object.hasOwn(params, "resolveGatewayContext") ? params.resolveGatewayContext : getPluginRuntimeGatewayRequestScope()?.resolveGatewayContext; let expectedSessionId = params.expectedSessionId; const waitTimeoutMs = params.waitTimeoutMs ?? (params.kind === "queued_followup" ? 15e3 : void 0); while (true) { if (isAbortSignalAborted(params.upstreamAbortSignal)) return { status: "skipped", reason: "aborted" }; if (isReplyRunSuccessorAdmissionBlocked(params.sessionKey)) { if (params.kind === "heartbeat") return { status: "skipped", reason: "active-run" }; const successorAdmission = await waitForReplyRunSuccessorAdmission(params.sessionKey, params.kind === "visible" ? null : waitTimeoutMs, { signal: params.upstreamAbortSignal }); if (!successorAdmission.settled) return { status: "skipped", reason: isAbortSignalAborted(params.upstreamAbortSignal) ? "aborted" : "active-run" }; sessionId = successorAdmission.sessionId ?? sessionId; if (expectedSessionId && successorAdmission.sessionId) expectedSessionId = successorAdmission.sessionId; continue; } try { const storePath = params.storePath; let operation; let admittedSessionEntry; let recoveryOwnerLease; let interruptedBeforeOperation = false; const admission = storePath ? await beginSessionWorkAdmission({ scope: storePath, resolveGatewayContext, identities: [params.sessionKey], signal: params.upstreamAbortSignal, onInterrupt: () => { interruptedBeforeOperation = true; operation?.abortForRestart(); params.onLifecycleInterrupt?.(); }, assertAllowed: () => { const currentEntry = loadSessionEntry({ storePath, sessionKey: params.sessionKey, readConsistency: "latest" }); admittedSessionEntry = currentEntry; if (expectedSessionId && !currentEntry) rejectLifecycleInvalidatedWork({ kind: params.kind, message: `Session "${params.sessionKey}" was deleted while starting work. Retry.`, transientSessionChange: true }); const registeredOperation = replyRunRegistry.get(params.sessionKey); const rotationOperation = [registeredOperation, params.expectedActiveOperation].find((candidate) => { if (!candidate || !expectedSessionId || currentEntry?.sessionId !== candidate.sessionId || !candidate.hasOwnedSessionId(expectedSessionId)) return false; if (candidate.result?.kind === "aborted" && candidate.result.code === "aborted_for_restart") return false; return candidate === registeredOperation || candidate.result !== null; }); const activeOperationRotatedExpectedSession = Boolean(rotationOperation && currentEntry?.sessionId === rotationOperation.sessionId); if (expectedSessionId && currentEntry?.sessionId !== expectedSessionId && !activeOperationRotatedExpectedSession) rejectLifecycleInvalidatedWork({ kind: params.kind, message: `Session "${params.sessionKey}" changed while starting work. Retry.`, transientSessionChange: true }); if (activeOperationRotatedExpectedSession) expectedSessionId = currentEntry?.sessionId; const archivedSessionError = resolveSessionWorkStartError(params.sessionKey || sessionId, currentEntry, { allowRestartTombstoneReplacement: params.resetTriggered && params.allowRestartTombstoneReset === true || params.allowRestartTombstoneParentFork === true }); if (archivedSessionError) rejectLifecycleInvalidatedWork({ kind: params.kind, message: archivedSessionError, restartRecoveryTombstone: isRestartRecoveryTombstone(currentEntry) }); sessionId = currentEntry?.sessionId ?? sessionId; } }) : void 0; try { if (isReplyRunSuccessorAdmissionBlocked(params.sessionKey)) throw new ReplyRunSuccessorAdmissionBlockedError(params.sessionKey); const mayWaitForRecoveryOwner = storePath && !params.resetTriggered && params.allowRestartTombstoneParentFork !== true; const recoveryOwnerRelease = mayWaitForRecoveryOwner ? getSessionWorkAdmissionOwnerRelease({ scope: storePath, identities: [params.sessionKey, sessionId], owner: MAIN_SESSION_RECOVERY_WORK_ADMISSION_OWNER }) : void 0; if (mayWaitForRecoveryOwner && admittedSessionEntry && (admittedSessionEntry.status === "running" && (admittedSessionEntry.abortedLastRun === true || admittedSessionEntry.restartRecoveryRuns !== void 0) || admittedSessionEntry.mainRestartRecovery?.tombstone !== void 0) && isMainRestartRecoveryCandidate(admittedSessionEntry, params.sessionKey) && recoveryOwnerRelease === void 0) { const ownerClaim = await claimMainSessionRecoveryOwner({ lifecycleGeneration: getAgentEventLifecycleGeneration(), sessionId, target: { sessionKey: params.sessionKey, storePath } }); if (ownerClaim.kind === "invalidated") rejectLifecycleInvalidatedWork({ kind: params.kind, message: `Session "${params.sessionKey}" changed while starting work. Retry.`, transientSessionChange: true }); recoveryOwnerLease = ownerClaim.kind === "claimed" ? ownerClaim.lease : void 0; } if (params.kind === "queued_followup" && recoveryOwnerRelease) { admission?.release(); await racePromiseWithAbortSignal(recoveryOwnerRelease, params.upstreamAbortSignal); continue; } if (interruptedBeforeOperation || isAbortSignalAborted(params.upstreamAbortSignal)) rejectLifecycleInvalidatedWork({ kind: params.kind, message: `Session "${params.sessionKey}" changed while starting work. Retry.`, transientSessionChange: true }); if (params.adoptOperation) { params.adoptOperation.updateSessionKey(params.sessionKey); operation = params.adoptOperation; } else { operation = createReplyOperation({ sessionKey: params.sessionKey, sessionId, turnKind: params.kind, resetTriggered: params.resetTriggered, routeThreadId: params.routeThreadId, originatingLeafEntryId: params.originatingLeafEntryId, upstreamAbortSignal: params.upstreamAbortSignal, respectFollowupAdmissionBarrier: params.kind === "queued_followup" || params.kind === "heartbeat" }); bindGatewayContextResolver(operation, resolveGatewayContext); } } catch (error) { const pendingRecovery = recoveryOwnerLease ? await releaseReplyRecoveryOwner(recoveryOwnerLease) : void 0; if (error instanceof ReplyRunAlreadyActiveError && admission && params.retainLifecycleAdmissionOnActive) { admission.released.then(() => { scheduleMainSessionRecoveryPendingTarget(pendingRecovery); }); return { status: "skipped", reason: "active-run", activeOperation: replyRunRegistry.get(params.sessionKey), lifecycleAdmission: admission }; } admission?.release(); scheduleMainSessionRecoveryPendingTarget(pendingRecovery); throw error; } if (admission) { retainReplyOperationUntilComplete(operation); lifecycleAdmissionByOperation.set(operation, admission); let recoveryOwnerRelease; const releaseRecoveryOwner = () => recoveryOwnerRelease ??= releaseReplyRecoveryOwner(recoveryOwnerLease); if (recoveryOwnerLease) registerReplyOperationSuccessorBarrier({ operation, sessionId: recoveryOwnerLease.sessionId, sessionKeys: [params.sessionKey, recoveryOwnerLease.sessionKey], start: releaseRecoveryOwner }); runAfterReplyOperationClear(operation, () => { lifecycleAdmissionByOperation.delete(operation); releaseRecoveryOwner().then((pendingTarget) => { admission.release(); scheduleMainSessionRecoveryPendingTarget(pendingTarget); }); }); } return { status: "owned", operation, ...admittedSessionEntry ? { sessionEntry: admittedSessionEntry } : {} }; } catch (error) { if (isAbortSignalAborted(params.upstreamAbortSignal)) return { status: "skipped", reason: "aborted" }; if (error instanceof QueuedFollowupLifecycleInvalidatedError) return { status: "skipped", reason: "lifecycle-invalidated" }; if (error instanceof ReplyRunSuccessorAdmissionBlockedError) { if (params.kind === "heartbeat") return { status: "skipped", reason: "active-run" }; continue; } if (error instanceof ReplyRunFollowupAdmissionBlockedError) { if (params.kind === "heartbeat") return { status: "skipped", reason: "active-run" }; const followupAdmission = await waitForReplyRunFollowupAdmission(params.sessionKey, waitTimeoutMs ?? 15e3, { signal: params.upstreamAbortSignal }); if (!followupAdmission.settled) return { status: "skipped", reason: isAbortSignalAborted(params.upstreamAbortSignal) ? "aborted" : "active-run" }; sessionId = followupAdmission.sessionId ?? sessionId; if (expectedSessionId && followupAdmission.sessionId) expectedSessionId = followupAdmission.sessionId; continue; } if (!(error instanceof ReplyRunAlreadyActiveError)) throw error; const activeOperation = replyRunRegistry.get(params.sessionKey); if (params.kind === "visible" && activeOperation?.turnKind === "heartbeat") activeOperation.supersede(); if (params.kind === "visible" && expireVisibleStaleOperation(activeOperation)) continue; if (params.kind === "heartbeat") return { status: "skipped", reason: "active-run", activeOperation }; if (params.waitForActive === false) return { status: "skipped", reason: "active-run", activeOperation }; const activeWaitTimeoutMs = params.kind === "visible" ? resolveVisibleActiveWaitMs(activeOperation) : waitTimeoutMs; if (!await replyRunRegistry.waitForIdle(params.sessionKey, activeWaitTimeoutMs, { signal: params.upstreamAbortSignal })) { if (params.kind === "visible" && !isAbortSignalAborted(params.upstreamAbortSignal)) { expireVisibleStaleOperation(replyRunRegistry.get(params.sessionKey) ?? activeOperation); continue; } return { status: "skipped", reason: isAbortSignalAborted(params.upstreamAbortSignal) ? "aborted" : "active-run", activeOperation }; } if (activeOperation) { sessionId = activeOperation.sessionId; if (expectedSessionId && !(activeOperation.result?.kind === "aborted" && activeOperation.result.code === "aborted_for_restart")) expectedSessionId = activeOperation.sessionId; } } } } /** Resolves the default turn kind from reply options. */ function resolveReplyTurnKind(opts) { return opts?.isHeartbeat === true ? "heartbeat" : "visible"; } //#endregion //#region src/auto-reply/reply/reply-timing-tracker.ts /** Checks config/env diagnostic flags for reply profiling. */ function isReplyProfilerEnabled(params) { const cfg = params?.config; const env = params?.env ?? process.env; return isDiagnosticFlagEnabled("profiler", cfg, env) || isDiagnosticFlagEnabled("reply.profiler", cfg, env); } /** Keeps slow replies diagnosable; profiling lowers the warning thresholds. */ function createReplyTimingTracker(params) { const profilerEnabled = params.enabled ?? isReplyProfilerEnabled({ config: params.config, env: params.env }); const startedAt = Date.now(); const spans = []; let didLog = false; const totalWarnMs = params.totalWarnMs ?? (profilerEnabled ? 1e3 : 1e4); const stageWarnMs = params.stageWarnMs ?? (profilerEnabled ? 500 : 5e3); const toMs = (value) => Math.max(0, Math.round(value)); const record = (name, spanStartedAt) => { const currentAt = Date.now(); spans.push({ name, durationMs: toMs(currentAt - spanStartedAt), elapsedMs: toMs(currentAt - startedAt) }); }; return { async measure(name, run) { const spanStartedAt = Date.now(); try { return await run(); } finally { record(name, spanStartedAt); } }, measureSync(name, run) { const spanStartedAt = Date.now(); try { return run(); } finally { record(name, spanStartedAt); } }, logIfSlow(logParams, options) { if (didLog && !options?.repeat) return; const summary = { totalMs: toMs(Date.now() - startedAt), spans: spans.slice() }; if (summary.totalMs < totalWarnMs && !summary.spans.some((span) => span.durationMs >= stageWarnMs)) return; if (!options?.repeat) didLog = true; const formattedSpans = summary.spans.length > 0 ? summary.spans.map((span) => `${span.name}:${span.durationMs}ms@${span.elapsedMs}ms`).join(",") : "none"; if (params.formatMessage) { const detailParams = logParams; const details = Object.fromEntries((params.detailKeys?.(logParams) ?? []).map((key) => [key, detailParams[key]])); params.log.warn(params.formatMessage(logParams, summary, formattedSpans), { ...details, totalMs: summary.totalMs, spans: summary.spans }); return; } const defaults = logParams; const suffix = [ `totalMs=${summary.totalMs}`, `stages=${formattedSpans}`, defaults.outcome ? `outcome=${defaults.outcome}` : void 0, defaults.reason ? `reason=${defaults.reason}` : void 0, defaults.error ? `error="${defaults.error}"` : void 0 ].filter(Boolean).join(" "); params.log.warn(`${defaults.message} ${suffix}`, { ...defaults.details, outcome: defaults.outcome, reason: defaults.reason, error: defaults.error, totalMs: summary.totalMs, spans: summary.spans }); } }; } //#endregion //#region src/auto-reply/reply/session-entry-handle.ts var ReplySessionGenerationInvalidatedError = class extends Error {}; function createReplySessionEntryHandle(params) { const { generationFence, sessionKey, sessionStore } = params; const entries = sessionStore ?? {}; let ownedSessionId = generationFence?.sessionId; let ownedLifecycleRevision = params.sessionEntry && params.sessionEntry.sessionId === ownedSessionId ? params.sessionEntry.lifecycleRevision : void 0; const matchesGeneration = (entry) => entry !== void 0 && (!generationFence || entry.sessionId === ownedSessionId && entry.lifecycleRevision === ownedLifecycleRevision); let currentEntry = matchesGeneration(params.sessionEntry) ? params.sessionEntry : void 0; if (sessionKey && currentEntry) { const storedEntry = entries[sessionKey]; if (!generationFence || !sessionStore || storedEntry && (storedEntry === generationFence.expectedStoreEntry && !matchesGeneration(storedEntry) || matchesGeneration(storedEntry) && currentEntry.updatedAt >= storedEntry.updatedAt)) entries[sessionKey] = currentEntry; } const current = () => { const storedEntry = sessionKey ? entries[sessionKey] : void 0; if (generationFence && matchesGeneration(storedEntry) && (!currentEntry || storedEntry.updatedAt >= currentEntry.updatedAt)) currentEntry = storedEntry; return currentEntry; }; const replaceCurrent = (entry, adopt = false) => { if (!generationFence) { currentEntry = entry; if (sessionKey) entries[sessionKey] = entry; return; } const storedEntry = sessionKey ? entries[sessionKey] : void 0; const storedMatchesOwned = matchesGeneration(storedEntry); let nextEntry = entry; if (adopt) { const storedMatchesAdopted = Boolean(storedEntry && storedEntry.sessionId === entry.sessionId && storedEntry.lifecycleRevision === entry.lifecycleRevision); if (sessionStore && sessionKey && !storedEntry && generationFence.expectedStoreEntry || storedEntry && !storedMatchesOwned && !storedMatchesAdopted) throw new ReplySessionGenerationInvalidatedError("Follow-up session generation was replaced during admission"); if (storedMatchesAdopted && storedEntry && storedEntry.updatedAt >= entry.updatedAt) nextEntry = storedEntry; ownedSessionId = nextEntry.sessionId; ownedLifecycleRevision = nextEntry.lifecycleRevision; } else if (!matchesGeneration(nextEntry)) return; if (adopt || !currentEntry || nextEntry.updatedAt >= currentEntry.updatedAt) currentEntry = nextEntry; if (sessionKey && (adopt ? !storedEntry || storedMatchesOwned || nextEntry !== storedEntry : !storedEntry && !generationFence.expectedStoreEntry || storedMatchesOwned && storedEntry && nextEntry.updatedAt >= storedEntry.updatedAt)) entries[sessionKey] = nextEntry; }; const handle = { adoptCurrent: (entry) => replaceCurrent(entry, true), clearCurrent: () => { currentEntry = void 0; if (sessionKey && (!generationFence || matchesGeneration(entries[sessionKey]))) delete entries[sessionKey]; }, get: (key) => entries[key], getCurrent: current, patchCurrent: (patch) => { if (currentEntry) replaceCurrent({ ...currentEntry, ...patch }); return currentEntry; }, replaceCurrent, set: (key, entry) => { if (key === sessionKey) replaceCurrent(entry); else entries[key] = entry; }, toCompatSessionStore: () => { if (!generationFence || !sessionKey) return entries; const view = { ...entries, ...currentEntry ? { [sessionKey]: currentEntry } : {} }; return new Proxy(view, { get: (target, key) => key === sessionKey ? current() : Reflect.get(target, key), set(target, key, entry) { if (key !== sessionKey) return Reflect.set(target, key, entry); if (!entry) handle.clearCurrent(); else replaceCurrent(entry, !matchesGeneration(entry)); return true; }, deleteProperty(target, key) { if (key !== sessionKey) return Reflect.deleteProperty(target, key); handle.clearCurrent(); return true; } }); } }; return handle; } //#endregion export { admitReplyTurn as a, resolveSilentReplyPolicy as c, isReplyProfilerEnabled as i, resolveSilentReplySettings as l, createReplySessionEntryHandle as n, resolveReplyTurnKind as o, createReplyTimingTracker as r, runWithReplyOperationLifecycleAdmission as s, ReplySessionGenerationInvalidatedError as t, resolveSilentReplyPolicyFromPolicies as u };