openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
198 lines (197 loc) • 8.63 kB
JavaScript
import { i as pluginInstanceInvocation } from "./plugin-instance-invocation-CH4zOUb4.mjs";
import "./session-key-C09ow4h0.mjs";
import { n as normalizeAccountId } from "./account-id-DbRsdayc.mjs";
import { o as getPluginValueInstance, r as getPluginInstanceOwner } from "./plugin-instance-scope-DEzoxqBj.mjs";
import { l as getPluginRecordRegistry } from "./registry-lifecycle-CZIcWb1R.mjs";
import { r as resolveChannelAccountEntry } from "./account-lookup-D_rRUHd5.mjs";
import { i as resolveStableChannelIngressPolicy, r as resolveChannelIngressPolicy, t as createChannelIngressPolicyResolver } from "./runtime-BxuQOpST.mjs";
import "./store-allow-from-OzDt_ndJ.mjs";
import { n as createChannelIngressMonitor } from "./ingress-monitor-BwjRnGhS.mjs";
//#region src/config/implicit-mentions.ts
const SHIPPED_IMPLICIT_MENTION_DEFAULTS = {
replyToBot: true,
quotedBot: true,
threadParticipation: true
};
/** Resolves each implicit-mention kind using account, channel, defaults, then shipped behavior. */
function resolveChannelImplicitMentions(params) {
const channelConfig = params.cfg.channels?.[params.channel];
const accountConfig = resolveChannelAccountEntry(channelConfig?.accounts, normalizeAccountId(params.accountId), params.channel);
const defaults = params.cfg.channels?.defaults?.implicitMentions;
return {
replyToBot: accountConfig?.implicitMentions?.replyToBot ?? channelConfig?.implicitMentions?.replyToBot ?? defaults?.replyToBot ?? SHIPPED_IMPLICIT_MENTION_DEFAULTS.replyToBot,
quotedBot: accountConfig?.implicitMentions?.quotedBot ?? channelConfig?.implicitMentions?.quotedBot ?? defaults?.quotedBot ?? SHIPPED_IMPLICIT_MENTION_DEFAULTS.quotedBot,
threadParticipation: accountConfig?.implicitMentions?.threadParticipation ?? channelConfig?.implicitMentions?.threadParticipation ?? defaults?.threadParticipation ?? SHIPPED_IMPLICIT_MENTION_DEFAULTS.threadParticipation
};
}
//#endregion
//#region src/plugin-sdk/channel-ingress-runtime.ts
/**
* High-level runtime resolver for inbound channel access decisions.
*
* New receive paths use runtime.channel.inbound.ingress. This subpath retains
* released resolver adapters alongside identity, policy, and monitor helpers.
*/
function currentIngressInstance() {
const instance = pluginInstanceInvocation.getStore()?.instance;
const owner = instance && getPluginInstanceOwner(instance);
return owner?.instance?.hasActiveCall && owner.instance === instance && !owner.revoked ? owner.instance : void 0;
}
function registeredIngress(instance, channelId) {
const owner = instance?.owner;
if (!instance?.hasActiveCall || instance.lifecycle.signal.aborted || !owner || owner.revoked) return;
const registration = getPluginRecordRegistry(owner.registry, owner.record).channels.find((entry) => entry.pluginId === owner.record.id && entry.plugin.id === channelId.trim() && getPluginValueInstance(entry.plugin) === instance);
return registration?.captureReadAuthority?.()?.() ? registration.resolveChannelRuntime?.().inbound.ingress : void 0;
}
/** Retain the creating instance when adapting a released reusable resolver. */
function createChannelIngressResolver(base) {
const instance = currentIngressInstance();
const policy = createChannelIngressPolicyResolver(base);
const resolve = () => registeredIngress(instance, base.channelId)?.createResolver(base) ?? policy;
return {
message: (params) => resolve().message(params),
command: (params) => resolve().command(params),
event: (params) => resolve().event(params)
};
}
/** Preserve the released helper's trusted attribution within its managed callback. */
async function resolveChannelMessageIngress(params) {
const ingress = registeredIngress(currentIngressInstance(), params.channelId);
return await (ingress ? ingress.resolve(params) : resolveChannelIngressPolicy(params));
}
/** Preserve the released stable-identity helper through the same ingress owner. */
async function resolveStableChannelMessageIngress(params) {
const ingress = registeredIngress(currentIngressInstance(), params.channelId);
return await (ingress ? ingress.resolveStable(params) : resolveStableChannelIngressPolicy(params));
}
/** Version-1 raw events, 500 ms polling, eight deliveries, and standard retention. */
function createStandardRawEventIngressMonitor(options) {
const { classifyAdmissionError, createStoppedError, drain, payload, pollIntervalMs, ...base } = options;
const stoppedError = createStoppedError ?? (() => /* @__PURE__ */ new Error("Channel ingress monitor is stopped."));
const monitor = createChannelIngressMonitor({
...base,
inspect: options.inspect,
payload: {
...payload,
storage: "raw-event",
version: 1
},
pollIntervalMs: pollIntervalMs ?? 500,
retention: "standard",
drain: {
...drain,
startLimit: 8
},
admissionMode: "while-running",
createStoppedError: stoppedError
});
return {
receive: async (raw) => {
if (!monitor.isRunning()) throw stoppedError();
let facts;
try {
facts = options.inspect(raw);
} catch (error) {
const message = classifyAdmissionError(error);
if (message === void 0) throw error;
return {
kind: "invalid",
message
};
}
if (!facts) return { kind: "ignored" };
await monitor.admit(raw, { facts });
return { kind: "durable" };
},
start: monitor.start,
stop: monitor.stop,
waitForIdle: monitor.waitForIdle
};
}
/** Fan one logical inbound turn's ownership lifecycle across its durable claims. */
function fanInChannelIngressLifecycles(inputs) {
const lifecycles = inputs.filter((lifecycle) => lifecycle !== void 0);
const first = lifecycles[0];
if (!first) return {
lifecycle: void 0,
settle: async () => {},
abandon: async () => {},
cancel: async () => {}
};
let handedOff = false;
let settledAll = false;
const settleOnce = async (run) => {
if (settledAll) return;
settledAll = true;
await run();
};
const fanOut = async (invoke, targets = lifecycles) => {
await Promise.all(targets.map(async (lifecycle) => await invoke(lifecycle)));
};
const abandonAll = () => settleOnce(() => fanOut((lifecycle) => lifecycle.onAbandoned()));
const failEach = (targets, error) => fanOut((lifecycle) => lifecycle.onFailed ? lifecycle.onFailed(error) : lifecycle.onAbandoned(), targets);
const failAll = (error) => settleOnce(() => failEach(lifecycles, error));
const adoptAll = async () => {
for (const [index, lifecycle] of lifecycles.entries()) try {
await lifecycle.onAdopted();
} catch (error) {
await Promise.allSettled([settleOnce(() => failEach(lifecycles.slice(index), error))]);
throw error;
}
};
const supportsCancellation = lifecycles.every((lifecycle) => lifecycle.onCancelled !== void 0);
const deferredHeartbeatIntervals = lifecycles.map((lifecycle) => lifecycle.deferredHeartbeatIntervalMs).filter((interval) => interval !== void 0 && Number.isFinite(interval) && interval > 0);
const cancelAll = () => settleOnce(() => fanOut((lifecycle) => lifecycle.onCancelled ? lifecycle.onCancelled() : lifecycle.onAbandoned()));
return {
lifecycle: {
abortSignal: lifecycles.length === 1 ? first.abortSignal : AbortSignal.any(lifecycles.map((lifecycle) => lifecycle.abortSignal)),
onAdopted: async () => {
handedOff = true;
await adoptAll();
},
onDeferred: () => {
handedOff = true;
for (const lifecycle of lifecycles) lifecycle.onDeferred();
},
onDeferredHeartbeat: () => {
for (const lifecycle of lifecycles) lifecycle.onDeferredHeartbeat?.();
},
...deferredHeartbeatIntervals.length > 0 ? { deferredHeartbeatIntervalMs: Math.min(...deferredHeartbeatIntervals) } : {},
onAdoptionFinalizing: () => {
for (const lifecycle of lifecycles) lifecycle.onAdoptionFinalizing();
},
onFailed: async (error) => {
handedOff = true;
await failAll(error);
},
...supportsCancellation ? { onCancelled: async () => {
handedOff = true;
await cancelAll();
} } : {},
onAbandoned: async () => {
handedOff = true;
await abandonAll();
}
},
settle: async () => {
if (!handedOff) {
handedOff = true;
await adoptAll();
}
},
abandon: async (error) => {
if (!handedOff) {
handedOff = true;
await (error === void 0 ? abandonAll() : failAll(error));
}
},
cancel: async () => {
if (!handedOff) {
handedOff = true;
await cancelAll();
}
}
};
}
//#endregion
export { resolveStableChannelMessageIngress as a, resolveChannelMessageIngress as i, createStandardRawEventIngressMonitor as n, resolveChannelImplicitMentions as o, fanInChannelIngressLifecycles as r, createChannelIngressResolver as t };