UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

117 lines (116 loc) • 4.57 kB
import { a as resolveGlobalSingleton } from "./global-singleton-0m-JziJW.mjs"; import { AsyncLocalStorage } from "node:async_hooks"; //#region src/shared/channel-read-authority.ts const completionKey = Symbol.for("openclaw.channelReadAuthority.completion"); const authorityScope = resolveGlobalSingleton(Symbol.for("openclaw.channelReadAuthority"), () => new AsyncLocalStorage()); /** Capture at request submission; retain this exact check through queues and retries. */ function captureChannelReadAuthority() { return authorityScope.getStore(); } /** Internal media ownership; the SDK continues to expose only the callable assertion. */ function captureChannelReadScope() { return authorityScope.getStore()?.[completionKey]; } /** Preserve the read failure while reporting failures to release its owned output. */ async function settleChannelReadResource(resource, accepted) { try { await resource.settle(accepted); } catch (error) { try { const [{ createSubsystemLogger }, { redactToolPayloadText }] = await Promise.all([import("./subsystem-CJxVDa1V.mjs"), import("./redact-BkOlsSgX.mjs")]); const log = createSubsystemLogger("channels"); const failures = error instanceof AggregateError ? error.errors : [error]; for (const failure of failures) log.error(`Channel read output cleanup failed: ${redactToolPayloadText(String(failure))}`); } catch { console.error("Channel read output cleanup failed; diagnostic logger unavailable."); } } } async function settleReadResources(resources, accepted) { await Promise.all(Array.from(resources, (resource) => settleChannelReadResource(resource, accepted))); resources.clear(); } /** Host-only entry: neither model params nor plugin declarations mint read authority. */ async function withChannelReadAuthority(assertCurrent, run, signal, onAccepted) { if (!assertCurrent) { const result = await run(); onAccepted?.(result); return result; } const parent = authorityScope.getStore(); const parentCompletion = parent?.[completionKey]; const sourceSignals = [parentCompletion?.signal, signal].filter((source) => Boolean(source)); const sourceSignal = sourceSignals.length > 1 ? AbortSignal.any(sourceSignals) : sourceSignals[0]; const resources = /* @__PURE__ */ new Set(); let open = true; const assertAuthority = () => { parent?.(); if (!open) throw new Error("Channel read authority is no longer active."); sourceSignal?.throwIfAborted(); assertCurrent(); for (const resource of resources) resource.assertCurrent?.(); }; const scopedAuthority = Object.assign(assertAuthority, { [completionKey]: { assertCurrent: assertAuthority, signal: sourceSignal, registerResource: (resource) => { assertAuthority(); resources.add({ key: resource.key, settle: resource.settle, onDelegated: resource.onDelegated, assertCurrent: () => { sourceSignal?.throwIfAborted(); assertCurrent(); resource.assertCurrent?.(); } }); }, delegateResource: (key, settle, assertResourceCurrent) => { assertAuthority(); const resource = Array.from(resources).find((entry) => entry.key === key); if (!resource) return parentCompletion?.delegateResource(key, settle, assertResourceCurrent) ?? false; const original = resource.settle; const assertOriginal = resource.assertCurrent; resource.onDelegated?.(assertResourceCurrent); resource.settle = (accepted) => settle(accepted, original); resource.assertCurrent = () => { assertOriginal?.(); assertResourceCurrent?.(); }; return true; }, discardResource: async (key) => { const resource = Array.from(resources).find((entry) => entry.key === key); if (!resource) return await parentCompletion?.discardResource(key) ?? false; await settleChannelReadResource(resource, false); resources.delete(resource); return true; } } }); assertAuthority(); try { let result; try { result = await authorityScope.run(scopedAuthority, run); } finally { assertAuthority(); } if (parentCompletion) { for (const resource of resources) parentCompletion.registerResource(resource); resources.clear(); } onAccepted?.(result); open = false; if (resources.size > 0) await settleReadResources(resources, true); return result; } catch (error) { open = false; if (resources.size > 0) await settleReadResources(resources, false); throw error; } finally { open = false; } } //#endregion export { withChannelReadAuthority as i, captureChannelReadScope as n, settleChannelReadResource as r, captureChannelReadAuthority as t };