openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
648 lines (647 loc) • 30.7 kB
JavaScript
import { F as resolveTimerTimeoutMs } from "./number-coercion-CLj0HTDM.js";
import { y as uniqueStrings } from "./string-normalization-DsCfAx8q.js";
import { i as allowsProcessHomeSessionScan } from "./paths-D2sRr1a_.js";
import { r as getPluginModuleLoaderStats } from "./plugin-module-loader-cache-lf3kAaBw.js";
import { f as extractPluginInstallRecordsFromInstalledPluginIndex } from "./installed-plugin-index-wrDsjyMD.js";
import { l as normalizePluginsConfig } from "./config-state-BkU1frVq.js";
import { t as createDeferredCore } from "./deferred-D0La5CRk.js";
import { n as getCurrentPluginMetadataSnapshot } from "./current-plugin-metadata-snapshot-CmSX4G3W.js";
import { s as normalizeModelRef } from "./model-ref-shared-Dz7QU0Lx.js";
import { n as parseModelRef } from "./model-selection-normalize-D1HuPOqZ.js";
import { t as ADMIN_SCOPE, u as normalizeOperatorScopeList } from "./operator-scopes-Dw7Gu2cA.js";
import { i as NODE_DUPLEX_INVOKE_IDLE_TIMEOUT_MS } from "./node-commands-BC8PhxqU.js";
import { u as getActivePluginRegistry } from "./runtime-BL4wZfTq.js";
import { t as createEmptyPluginRegistry } from "./registry-empty-55wlVNzO.js";
import { a as getPluginRuntimeGatewayRequestScope, c as withPluginRuntimeGatewayContextResolver, t as bindGatewayContextResolver } from "./gateway-request-scope-BCMYlsDI.js";
import { r as authorizeOperatorScopesForRequiredScope } from "./method-scopes-K6J_UQGL.js";
import { t as applyPluginAutoEnable } from "./plugin-auto-enable-Tv_C18cS.js";
import { u as resolvePluginSubagentCompletionRequester } from "./hook-runner-global-0kfmMG4T.js";
import { t as loadAndActivateRootPluginRegistry } from "./loader-DPiOPJjR.js";
import { t as activatePluginRegistry } from "./loader-shared-_jCvj6B_.js";
import { a as setPluginRuntimeLoadContext, r as createPluginRuntimeLoaderLogger, t as buildPluginRuntimeLoadOptions } from "./load-context-BdeWeJHL.js";
import { i as prepareInProcessAgentExecution, r as getInProcessGatewayRequestContext, t as dispatchGatewayMethodInProcess } from "./server-plugin-in-process-dispatch-DYlW9gzA.js";
import { t as loadPluginLookUpTable } from "./plugin-lookup-table-DXuDIg4u.js";
import { r as resolvePluginSubagentToolsAlsoAllow } from "./server-plugin-runtime-client-CfhFBErP.js";
import { t as compileModelAllowlist } from "./model-allowlist-Vk4n4FlI.js";
import { t as createBackgroundWorkOwner } from "./background-work-DAaUk-Kp.js";
import { t as createNodeDuplexEndpoint } from "./node-duplex-framing-SEDM1SDZ.js";
import { l as resolveNodeCommandAllowlist, o as isNodeCommandAllowed } from "./node-command-policy-H4FpS0aA.js";
import { randomUUID } from "node:crypto";
import { performance } from "node:perf_hooks";
//#region src/gateway/server-plugin-subagent-runtime.ts
function resolvePluginSubagentRequestedModelRef(params) {
if (params.provider && params.model) {
const normalizedRequest = normalizeModelRef(params.provider, params.model);
return `${normalizedRequest.provider}/${normalizedRequest.model}`;
}
const rawModel = params.model?.trim();
if (!rawModel || !rawModel.includes("/")) return null;
const parsed = parseModelRef(rawModel, "");
if (!parsed?.provider || !parsed.model) return null;
return `${parsed.provider}/${parsed.model}`;
}
function normalizePluginSubagentRunRuntime(value) {
if (!value || typeof value !== "object" || Array.isArray(value)) return;
const record = value;
const harness = typeof record.harness === "string" ? record.harness.trim() : "";
const provider = typeof record.provider === "string" ? record.provider.trim() : "";
const model = typeof record.model === "string" ? record.model.trim() : "";
return harness && provider && model ? {
harness,
provider,
model
} : void 0;
}
function resolvePluginSubagentOverridePolicies(cfg) {
const normalized = normalizePluginsConfig(cfg.plugins);
const policies = {};
for (const [pluginId, entry] of Object.entries(normalized.entries)) {
const allowModelOverride = entry.subagent?.allowModelOverride === true;
const allowlist = compileModelAllowlist({
configured: entry.subagent?.hasAllowedModelsConfig === true,
values: entry.subagent?.allowedModels,
formatKey: (provider, model) => `${provider}/${model}`
});
if (!allowModelOverride && !allowlist.configured && !allowlist.models.size && !allowlist.allowAny) continue;
policies[pluginId] = {
allowModelOverride,
...allowlist
};
}
return policies;
}
function authorizeFallbackModelOverride(params) {
const pluginId = params.pluginId?.trim();
if (!pluginId) return {
allowed: false,
reason: "provider/model override requires plugin identity in fallback subagent runs."
};
const policy = params.policies[pluginId];
if (!policy?.allowModelOverride) return {
allowed: false,
reason: `plugin "${pluginId}" is not trusted for fallback provider/model override requests. See https://docs.openclaw.ai/plugins/sdk-runtime#api-runtime-subagent and search for: plugins.entries.<id>.subagent.allowModelOverride`
};
if (policy.allowAny) return { allowed: true };
if (policy.configured && policy.models.size === 0) return {
allowed: false,
reason: `plugin "${pluginId}" configured subagent.allowedModels, but none of the entries normalized to a valid provider/model target.`
};
if (policy.models.size === 0) return { allowed: true };
const requestedModelRef = resolvePluginSubagentRequestedModelRef(params);
if (!requestedModelRef) return {
allowed: false,
reason: "fallback provider/model overrides that use an allowlist must resolve to a canonical provider/model target."
};
if (policy.models.has(requestedModelRef)) return { allowed: true };
return {
allowed: false,
reason: `model override "${requestedModelRef}" is not allowlisted for plugin "${pluginId}".`
};
}
function hasAdminScope(client) {
return (Array.isArray(client?.connect?.scopes) ? client.connect.scopes : []).includes(ADMIN_SCOPE);
}
function canClientUseModelOverride(client) {
return hasAdminScope(client) || client?.internal?.allowModelOverride === true;
}
function canTrustedOfficialPluginRequestScopes(params) {
if (!params.pluginId) return false;
if (params.pluginOrigin === "bundled" || params.pluginTrustedOfficialInstall === true) return true;
const record = getActivePluginRegistry()?.plugins.find((entry) => entry.id === params.pluginId);
return record?.origin === "bundled" || record?.trustedOfficialInstall === true;
}
const PLUGIN_SUBAGENT_SESSION_MESSAGES_MAX_LIMIT = 1e3;
function createGatewaySubagentRuntime(resolveGatewayContext, overridePolicies = {}, runtimeLifetime) {
const authorizeModelOverride = (params) => {
const scope = getPluginRuntimeGatewayRequestScope();
const overrideRequested = Boolean(params.provider || params.model);
const hasRequestScopeClient = Boolean(scope?.client);
let allowOverride = hasRequestScopeClient && canClientUseModelOverride(scope?.client ?? null);
let allowSyntheticModelOverride = false;
if (overrideRequested && !allowOverride && !hasRequestScopeClient) {
const fallbackAuth = authorizeFallbackModelOverride({
policies: overridePolicies,
pluginId: scope?.pluginId,
provider: params.provider,
model: params.model
});
if (!fallbackAuth.allowed) throw new Error(fallbackAuth.reason);
allowOverride = true;
allowSyntheticModelOverride = true;
}
if (overrideRequested && !allowOverride) throw new Error("provider/model override is not authorized for this plugin subagent run.");
return {
allowOverride,
allowSyntheticModelOverride
};
};
const getSessionMessages = async (params) => {
const scope = getPluginRuntimeGatewayRequestScope();
const limit = params.limit == null || !Number.isFinite(params.limit) ? void 0 : Math.min(PLUGIN_SUBAGENT_SESSION_MESSAGES_MAX_LIMIT, Math.max(1, Math.floor(params.limit)));
const payload = await dispatchGatewayMethodInProcess("sessions.get", {
key: params.sessionKey,
...limit != null && { limit }
}, {
resolveGatewayContext,
...!scope?.client && canTrustedOfficialPluginRequestScopes(scope ?? {}) ? { operatorRoleActor: { kind: "system" } } : {}
});
return { messages: Array.isArray(payload?.messages) ? payload.messages : [] };
};
const subagentRuntime = {
async complete(request) {
const params = { ...request };
const pluginId = getPluginRuntimeGatewayRequestScope()?.pluginId?.trim();
if (!pluginId) throw new Error("Plugin background completion requires a plugin identity and Gateway binding.");
const execution = prepareInProcessAgentExecution({
agentId: params.agentId,
pluginRuntimeOwnerId: pluginId,
resolveGatewayContext
});
const assertCurrent = () => {
runtimeLifetime?.throwIfAborted();
execution.assertCurrent();
};
runtimeLifetime?.throwIfAborted();
await execution.authorize();
assertCurrent();
authorizeModelOverride(params);
const signals = [
params.signal,
runtimeLifetime,
execution.signal
].filter((signal) => signal !== void 0);
return await createBackgroundWorkOwner({
owner: `plugin:${pluginId}`,
maxConcurrent: 3
}).enqueue(async (signal) => {
assertCurrent();
const [{ resolveConfiguredAgentId }, { resolveSimpleCompletionSelectionForAgent }, { runIsolatedCompletion }, { finalizePluginLlmCompletion }] = await Promise.all([
import("./agent-scope-BHLMs19p.js"),
import("./simple-completion-runtime-CYTFMIFR.js"),
import("./isolated-completion-BGUOyVW_.js"),
import("./runtime-llm.runtime.js")
]);
await execution.authorize();
assertCurrent();
signal.throwIfAborted();
authorizeModelOverride(params);
const cfg = execution.context.getRuntimeConfig();
const agentId = resolveConfiguredAgentId(cfg, params.agentId);
const selection = resolveSimpleCompletionSelectionForAgent({
cfg,
agentId,
modelRef: params.model
});
if (!selection) throw new Error(`No model configured for agent ${agentId}.`);
const timeoutMs = resolveTimerTimeoutMs(params.timeoutMs, 3e4);
const runSignal = AbortSignal.any([signal, AbortSignal.timeout(timeoutMs)]);
const result = await execution.run(() => runIsolatedCompletion({
config: cfg,
agentId,
provider: selection.provider,
model: selection.modelId,
authProfileId: selection.profileId,
systemPrompt: params.extraSystemPrompt ?? "",
prompt: params.message,
timeoutMs,
abortSignal: runSignal,
assertCurrent
}));
runSignal.throwIfAborted();
assertCurrent();
signal.throwIfAborted();
finalizePluginLlmCompletion({
cfg,
hostPluginId: pluginId,
rawUsage: result.usage,
result: {
text: result.text,
provider: result.provider,
model: result.model,
agentId,
execution: {
mode: "isolated-agent-runtime",
owner: result.owner
},
audit: { caller: {
kind: "plugin",
id: pluginId
} }
}
});
return { text: result.text };
}, { abortSignal: signals.length ? AbortSignal.any(signals) : void 0 });
},
async run(params) {
if (params.disableTools === true && (params.toolsAlsoAllow?.length ?? 0) > 0) throw new Error("Tool-free plugin subagent runs cannot request additive tools.");
const pluginSubagentRequester = resolvePluginSubagentCompletionRequester(params.completionDelivery);
const scope = getPluginRuntimeGatewayRequestScope();
const pluginId = typeof scope?.pluginId === "string" && scope.pluginId.trim() ? scope.pluginId.trim() : void 0;
const runtimePluginToolGrant = resolvePluginSubagentToolsAlsoAllow({
pluginId,
toolsAlsoAllow: params.toolsAlsoAllow
});
const { allowOverride, allowSyntheticModelOverride } = authorizeModelOverride(params);
const payload = await dispatchGatewayMethodInProcess("agent", {
sessionKey: params.sessionKey,
message: params.message,
deliver: params.deliver ?? false,
...allowOverride && params.provider && { provider: params.provider },
...allowOverride && params.model && { model: params.model },
...params.extraSystemPrompt && { extraSystemPrompt: params.extraSystemPrompt },
...params.promptMode === "minimal" && { promptMode: params.promptMode },
...params.lane && { lane: params.lane },
...params.cwd && { cwd: params.cwd },
...params.lightContext === true && { bootstrapContextMode: "lightweight" },
idempotencyKey: params.idempotencyKey || randomUUID()
}, {
allowSyntheticModelOverride,
agentRunTracking: "plugin_subagent",
...!scope?.client ? { operatorRoleActor: { kind: "system" } } : {},
...pluginId ? { pluginRuntimeOwnerId: pluginId } : {},
...pluginSubagentRequester ? { pluginSubagentRequester } : {},
...runtimePluginToolGrant ? { runtimePluginToolGrant } : {},
...params.disableTools === true ? { pluginSubagentToolsAllow: [] } : {},
resolveGatewayContext
});
const runId = payload?.runId;
if (typeof runId !== "string" || !runId) throw new Error("Gateway agent method returned an invalid runId.");
const sessionKey = payload?.sessionKey?.trim() || params.sessionKey;
const runtime = normalizePluginSubagentRunRuntime(payload?.runtime);
return {
runId,
sessionKey,
...runtime ? { runtime } : {}
};
},
async waitForRun(params) {
const { status: rawStatus, error, ...metadata } = await dispatchGatewayMethodInProcess("agent.wait", {
runId: params.runId,
...params.timeoutMs != null && { timeoutMs: params.timeoutMs }
}, { resolveGatewayContext });
let status = rawStatus;
if (status === "completed" || status === "succeeded") status = "ok";
else if (status === "error" && error?.trim().toLowerCase() === "completed") status = "ok";
if (status !== "ok" && status !== "error" && status !== "timeout" && status !== "pending") throw new Error(`Gateway agent.wait returned unexpected status: ${rawStatus}`);
return {
...metadata,
status,
...status !== "ok" && error ? { error } : {}
};
},
getSessionMessages,
async deleteSession(params) {
const scope = getPluginRuntimeGatewayRequestScope();
const pluginId = typeof scope?.pluginId === "string" && scope.pluginId.trim() ? scope.pluginId.trim() : void 0;
const pluginOwnedCleanupOptions = pluginId ? {
pluginRuntimeOwnerId: pluginId,
...!hasAdminScope(scope?.client) ? {
forceSyntheticClient: true,
syntheticScopes: [ADMIN_SCOPE]
} : {}
} : void 0;
await dispatchGatewayMethodInProcess("sessions.delete", {
key: params.sessionKey,
deleteTranscript: params.deleteTranscript ?? true
}, {
...pluginOwnedCleanupOptions,
resolveGatewayContext,
...!scope?.client && canTrustedOfficialPluginRequestScopes(scope ?? {}) ? { operatorRoleActor: { kind: "system" } } : {}
});
}
};
if (resolveGatewayContext) bindGatewayContextResolver(subagentRuntime, resolveGatewayContext);
return subagentRuntime;
}
//#endregion
//#region src/gateway/server-plugins-node-runtime.ts
function hasInProcessGatewayContext(resolveGatewayContext) {
return Boolean(getInProcessGatewayRequestContext(resolveGatewayContext));
}
/** Opens one lifecycle-fenced binary channel through the canonical node invocation owner. */
async function openGatewayNodeDuplex(options) {
const { params, resolveGatewayContext, runtimeLifetime, invokeNode } = options;
const scope = getPluginRuntimeGatewayRequestScope();
if (!scope?.pluginId?.trim()) throw new Error("Plugin node duplex commands require an active owning plugin identity.");
const registrations = scope.pluginRegistry?.nodeHostCommands.filter((entry) => entry.command.command === params.command);
if (registrations?.length !== 1 || registrations[0]?.pluginId !== scope.pluginId || registrations[0]?.command.duplex !== true) throw new Error(`Node command "${params.command}" must be registered exactly once by plugin "${scope.pluginId}" and declare duplex: true.`);
const callerIdentity = scope.client?.internal?.agentRuntimeIdentity;
const context = getInProcessGatewayRequestContext(resolveGatewayContext);
if (!context?.nodeRegistry) throw new Error("Plugin node duplex commands require an active Gateway node registry.");
const controller = new AbortController();
const signals = [
controller.signal,
runtimeLifetime,
params.signal
].filter((candidate) => candidate !== void 0);
const signal = AbortSignal.any(signals);
const abortError = () => signal.reason instanceof Error ? signal.reason : /* @__PURE__ */ new Error("Node duplex invocation cancelled.");
if (signal.aborted) throw abortError();
let invokeId;
let framedReady = false;
const ready = createDeferredCore();
const isRuntimeCurrent = () => !signal.aborted && (!resolveGatewayContext || resolveGatewayContext() === context) && (!callerIdentity || context.validateAgentRuntimeApprovalAuthority?.(callerIdentity) === true);
const assertRuntimeCurrent = () => {
if (!isRuntimeCurrent()) {
const error = signal.aborted ? abortError() : /* @__PURE__ */ new Error("Plugin Gateway runtime authority is no longer current.");
controller.abort(error);
throw error;
}
};
const endpoint = createNodeDuplexEndpoint({
requireReady: true,
maxMessageBytes: params.maxMessageBytes,
maxOutstandingDeliveryBytes: params.maxOutstandingDeliveryBytes,
sendFrame(frame) {
assertRuntimeCurrent();
if (!invokeId || !framedReady) throw new Error("Node duplex command is not ready for binary messages.");
context.nodeRegistry.sendInvokeInput(invokeId, JSON.parse(frame));
},
onReady() {
if (!invokeId) throw new Error("Node duplex command announced readiness before its dispatch.");
framedReady = true;
ready.resolve();
},
onError: (error) => controller.abort(error)
});
const onAbort = () => endpoint.close();
signal.addEventListener("abort", onAbort, { once: true });
const closed = invokeNode(params, {
onProgress: (chunk) => {
assertRuntimeCurrent();
endpoint.receive(chunk);
},
onDispatchReady: (id) => {
assertRuntimeCurrent();
invokeId = id;
},
isRuntimeCurrent,
idleTimeoutMs: NODE_DUPLEX_INVOKE_IDLE_TIMEOUT_MS
}, signal).then(async (result) => {
if (!invokeId || !framedReady) throw new Error("Node command completed without opening a ready duplex invocation.");
await endpoint.drain();
return result;
}).finally(() => {
signal.removeEventListener("abort", onAbort);
endpoint.close();
controller.abort(/* @__PURE__ */ new Error("Node duplex command has closed."));
});
closed.catch(ready.reject);
await ready.promise;
return {
send: (message) => endpoint.send(message),
onMessage: (listener) => {
assertRuntimeCurrent();
return endpoint.onMessage(listener);
},
closed,
close: () => controller.abort(/* @__PURE__ */ new Error("Node duplex channel closed by its caller."))
};
}
function projectGatewayRuntimeNodes(nodes, context) {
return nodes.map((node) => {
if (!node || typeof node !== "object" || Array.isArray(node) || !context?.nodeRegistry?.get || !context.getRuntimeConfig) return node;
const nodeRecord = node;
const nodeId = typeof nodeRecord.nodeId === "string" ? nodeRecord.nodeId : "";
const liveNode = nodeId ? context.nodeRegistry.get(nodeId) : void 0;
if (!liveNode) return node;
const allowlist = resolveNodeCommandAllowlist(context.getRuntimeConfig(), {
...liveNode,
approvedCommands: liveNode.commands
});
const invocableCommands = liveNode.commands.filter((command) => isNodeCommandAllowed({
command,
declaredCommands: liveNode.commands,
allowlist
}).ok);
return Object.assign({}, nodeRecord, { invocableCommands });
});
}
function createGatewayHooksRuntime(resolveGatewayContext) {
return { dispatchHookAgentTurn: async (params) => {
const pluginId = getPluginRuntimeGatewayRequestScope()?.pluginId;
const gatewayContext = resolveGatewayContext?.();
if (!pluginId || !gatewayContext?.dispatchHookAgentTurn) throw new Error("Plugin hook runtime requires an active Gateway and plugin identity.");
return await gatewayContext.dispatchHookAgentTurn(pluginId, params);
} };
}
//#endregion
//#region src/gateway/server-plugins.ts
function resolveRuntimeNodeInvokeSyntheticScopes(params) {
return canTrustedOfficialPluginRequestScopes(params) ? params.requestedScopes : void 0;
}
async function dispatchTrustedPluginGatewayMethod(method, params = {}, options, resolveGatewayContext) {
const scope = getPluginRuntimeGatewayRequestScope();
const pluginId = scope?.pluginId?.trim();
if (!canTrustedOfficialPluginRequestScopes(scope ?? {})) throw new Error("Gateway requests are only available to bundled or trusted official plugins.");
const syntheticScopes = normalizeOperatorScopeList(options?.scopes);
return await dispatchGatewayMethodInProcess(method, params, {
forceSyntheticClient: true,
pluginRuntimeOwnerId: pluginId,
resolveGatewayContext,
...!scope?.client ? { operatorRoleActor: { kind: "system" } } : {},
...syntheticScopes ? { syntheticScopes } : {},
...options?.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : {}
});
}
function createGatewayNodesRuntime(resolveGatewayContext, runtimeLifetime) {
const invokeNode = async (params, stream, signal = params.signal) => {
const scope = getPluginRuntimeGatewayRequestScope();
const pluginId = scope?.pluginId?.trim() || void 0;
const requestedScopes = resolveRuntimeNodeInvokeSyntheticScopes({
pluginId,
pluginOrigin: scope?.pluginOrigin,
pluginTrustedOfficialInstall: scope?.pluginTrustedOfficialInstall,
requestedScopes: normalizeOperatorScopeList(params.scopes)
});
const callerScopes = stream && scope?.client ? normalizeOperatorScopeList(scope.client.connect.scopes) ?? [] : void 0;
if (callerScopes && requestedScopes?.some((requestedScope) => !authorizeOperatorScopesForRequiredScope(requestedScope, callerScopes).allowed)) throw new Error("Requested node scopes exceed the authenticated Gateway caller's authority.");
const syntheticScopes = requestedScopes ?? callerScopes;
return dispatchGatewayMethodInProcess("node.invoke", {
nodeId: params.nodeId,
command: params.command,
...params.params !== void 0 && { params: params.params },
timeoutMs: params.timeoutMs,
idempotencyKey: params.idempotencyKey || randomUUID(),
...params.sessionKey ? { sessionKey: params.sessionKey } : {}
}, {
...pluginId ? { pluginRuntimeOwnerId: pluginId } : {},
nodeInvokeApprovalSessionKey: params.sessionKey,
...syntheticScopes ? { syntheticScopes } : {},
...stream || syntheticScopes ? { forceSyntheticClient: true } : {},
...stream ? { nodeInvokeStream: stream } : {},
...signal ? { signal } : {},
resolveGatewayContext
});
};
return {
async list(params) {
const context = getInProcessGatewayRequestContext(resolveGatewayContext);
const payload = await dispatchGatewayMethodInProcess("node.list", {}, { resolveGatewayContext: () => context });
const nodes = Array.isArray(payload?.nodes) ? payload.nodes : [];
return { nodes: projectGatewayRuntimeNodes(params?.connected === true ? nodes.filter((node) => typeof node === "object" && node?.connected === true) : nodes, context) };
},
invoke: invokeNode,
openDuplex: (params) => openGatewayNodeDuplex({
params,
invokeNode,
resolveGatewayContext,
runtimeLifetime
})
};
}
function createGatewayPluginRuntimeBindings(resolveGatewayContext, overridePolicies) {
let active = true;
const lifetime = new AbortController();
const resolveBoundGatewayContext = resolveGatewayContext ? () => active ? resolveGatewayContext() : void 0 : void 0;
if (resolveBoundGatewayContext) bindGatewayContextResolver(resolveBoundGatewayContext, resolveGatewayContext);
return {
retire: () => {
lifetime.abort(/* @__PURE__ */ new Error("Plugin Gateway runtime retired; duplex invocation cancelled."));
active = false;
},
runtime: {
dispatchReplyFromConfig: async (params) => {
const { dispatchLowLevelChannelReplyFromConfig } = await import("./dispatch-from-config-uRb_c9Gp.js");
const sessionWorkerPlacementContext = getInProcessGatewayRequestContext(resolveBoundGatewayContext);
const run = async () => await dispatchLowLevelChannelReplyFromConfig({
...params,
...sessionWorkerPlacementContext ? { sessionWorkerPlacementContext } : {}
});
return resolveBoundGatewayContext ? await withPluginRuntimeGatewayContextResolver(resolveBoundGatewayContext, run) : await run();
},
gateway: {
isAvailable: async () => hasInProcessGatewayContext(resolveBoundGatewayContext),
request: (method, params, options) => dispatchTrustedPluginGatewayMethod(method, params, options, resolveBoundGatewayContext)
},
hooks: createGatewayHooksRuntime(resolveBoundGatewayContext),
nodes: createGatewayNodesRuntime(resolveBoundGatewayContext, lifetime.signal),
subagent: createGatewaySubagentRuntime(resolveBoundGatewayContext, overridePolicies, lifetime.signal)
}
};
}
function createGatewayPluginRegistrationLogger(params) {
const logger = createPluginRuntimeLoaderLogger();
if (params?.suppressInfoLogs !== true) return logger;
return {
...logger,
info: (_message) => void 0
};
}
function loadGatewayPlugins(params) {
const started = performance.now();
const allowProcessHomeSessionCatalogs = allowsProcessHomeSessionScan();
const activationAutoEnabled = params.activationSourceConfig !== void 0 && params.autoEnabledReasons === void 0 ? applyPluginAutoEnable({
config: params.activationSourceConfig,
env: process.env,
...params.pluginLookUpTable?.manifestRegistry ? { manifestRegistry: params.pluginLookUpTable.manifestRegistry } : {},
discovery: params.pluginLookUpTable?.discovery,
ambientEnvTriggers: params.ambientEnvTriggers
}) : void 0;
const autoEnableMs = performance.now() - started;
const autoEnabled = params.activationSourceConfig !== void 0 || params.autoEnabledReasons !== void 0 ? {
config: params.cfg,
autoEnabledReasons: params.autoEnabledReasons ?? activationAutoEnabled?.autoEnabledReasons ?? {}
} : applyPluginAutoEnable({
config: params.cfg,
env: process.env,
manifestRegistry: params.pluginLookUpTable?.manifestRegistry,
discovery: params.pluginLookUpTable?.discovery,
ambientEnvTriggers: params.ambientEnvTriggers
});
const resolvedConfigMs = performance.now() - started;
const resolvedConfig = autoEnabled.config;
const pluginIds = params.pluginIds ?? [...(params.pluginLookUpTable ?? loadPluginLookUpTable({
config: resolvedConfig,
activationSourceConfig: params.activationSourceConfig,
workspaceDir: params.workspaceDir,
env: process.env,
ambientEnvTriggers: params.ambientEnvTriggers
})).startup.pluginIds];
const pluginIdsMs = performance.now() - started;
const metadataSnapshot = params.pluginMetadataSnapshot ?? getCurrentPluginMetadataSnapshot({
config: params.cfg,
workspaceDir: params.workspaceDir
});
const loaderMetadata = metadataSnapshot ?? params.pluginLookUpTable;
const loadContext = {
rawConfig: params.cfg,
config: resolvedConfig,
activationSourceConfig: params.activationSourceConfig ?? params.cfg,
autoEnabledReasons: autoEnabled.autoEnabledReasons,
workspaceDir: params.workspaceDir,
env: process.env,
logger: createGatewayPluginRegistrationLogger({ suppressInfoLogs: params.suppressPluginInfoLogs }),
preferBuiltPluginArtifacts: true,
metadataSnapshot,
...loaderMetadata ? {
manifestRegistry: loaderMetadata.manifestRegistry,
installRecords: extractPluginInstallRecordsFromInstalledPluginIndex(loaderMetadata.index)
} : {}
};
if (pluginIds.length === 0) {
const pluginRegistry = createEmptyPluginRegistry();
setPluginRuntimeLoadContext(pluginRegistry, loadContext);
activatePluginRegistry(pluginRegistry, null, "gateway-bindable", params.workspaceDir);
params.startupTrace?.detail("plugins.gateway-load", [
["autoEnableMs", autoEnableMs],
["resolvedConfigMs", resolvedConfigMs],
["pluginIdsMs", pluginIdsMs],
["loadMs", 0],
["pluginIds", "0"],
["pluginCount", 0],
["gatewayHandlerCount", 0]
]);
return {
pluginRegistry,
gatewayMethods: [...params.baseMethods],
retireGatewayRuntimeBindings: () => {}
};
}
const beforeLoad = performance.now();
const loaderStatsBefore = getPluginModuleLoaderStats();
const gatewayRuntimeBindings = createGatewayPluginRuntimeBindings(params.resolveGatewayContext, resolvePluginSubagentOverridePolicies(resolvedConfig));
const pluginRegistry = loadAndActivateRootPluginRegistry({
...buildPluginRuntimeLoadOptions(loadContext),
manifestRegistry: params.pluginLookUpTable?.manifestRegistry ?? loadContext.manifestRegistry,
allowProcessHomeSessionCatalogs,
onlyPluginIds: pluginIds,
coreGatewayHandlers: params.coreGatewayHandlers,
coreGatewayMethodNames: params.coreGatewayMethodNames,
hostServices: params.hostServices,
runtimeOptions: {
allowGatewaySubagentBinding: true,
...gatewayRuntimeBindings.runtime
},
channelPluginLoadIntent: params.channelPluginLoadIntent,
startupTrace: params.startupTrace
});
setPluginRuntimeLoadContext(pluginRegistry, loadContext);
const loadMs = performance.now() - beforeLoad;
const loaderStatsAfter = getPluginModuleLoaderStats();
const pluginMethods = Object.keys(pluginRegistry.gatewayHandlers);
const gatewayMethods = uniqueStrings([...params.baseMethods, ...pluginMethods]);
params.startupTrace?.detail("plugins.gateway-load", [
["autoEnableMs", autoEnableMs],
["resolvedConfigMs", resolvedConfigMs],
["pluginIdsMs", pluginIdsMs],
["loadMs", loadMs],
["pluginIds", String(pluginIds.length)],
["pluginCount", pluginIds.length],
["gatewayHandlers", String(pluginMethods.length)],
["gatewayHandlerCount", pluginMethods.length],
["loaderCallsCount", loaderStatsAfter.calls - loaderStatsBefore.calls],
["loaderNativeHitsCount", loaderStatsAfter.nativeHits - loaderStatsBefore.nativeHits],
["loaderNativeMissesCount", loaderStatsAfter.nativeMisses - loaderStatsBefore.nativeMisses],
["loaderSourceTransformForcedCount", loaderStatsAfter.sourceTransformForced - loaderStatsBefore.sourceTransformForced],
["loaderSourceTransformFallbacksCount", loaderStatsAfter.sourceTransformFallbacks - loaderStatsBefore.sourceTransformFallbacks],
["loaderTopSourceTransformTargets", loaderStatsAfter.topSourceTransformTargets.slice(0, 3).map((entry) => `${entry.count}:${entry.target}`).join(",")]
]);
return {
pluginRegistry,
gatewayMethods,
retireGatewayRuntimeBindings: gatewayRuntimeBindings.retire
};
}
//#endregion
export { createGatewaySubagentRuntime as a, hasInProcessGatewayContext as i, dispatchTrustedPluginGatewayMethod as n, loadGatewayPlugins as r, createGatewayNodesRuntime as t };