perf(matrix): narrow register-time runtime surface (#69782)

Merged via squash.

Prepared head SHA: ec32828b52
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
This commit is contained in:
Gustavo Madeira Santana
2026-04-21 12:50:53 -04:00
committed by GitHub
parent acb27bac3a
commit 13636c4521
13 changed files with 325 additions and 23 deletions

View File

@@ -8,6 +8,7 @@ Docs: https://docs.openclaw.ai
- Onboard/wizard: simplify the security disclaimer copy (drop the yellow banner and warning icon in favor of plain-prose paragraphs), and flip remaining onboarding pickers with long dynamic option lists to searchable autocompletes (search provider, plugin configure, model provider filter).
- Ollama/onboard: populate the cloud-only model list from `ollama.com/api/tags` so `openclaw onboard` reflects the live cloud catalog instead of a static three-model seed; cap the discovered list at 500 and fall back to the previous hardcoded suggestions when ollama.com is unreachable or returns no models. (#68463) Thanks @BruceMacD.
- Matrix/startup: narrow Matrix runtime registration and defer setup/doctor surfaces so cold plugin registration spends about 1.8s less in `setChannelRuntime`. (#69782) Thanks @gumadeiras.
### Fixes

View File

@@ -22,7 +22,7 @@ vi.mock("./src/cli.js", () => {
});
vi.mock("./plugin-entry.handlers.runtime.js", () => runtimeMocks);
vi.mock("./runtime-api.js", () => ({ setMatrixRuntime: runtimeMocks.setMatrixRuntime }));
vi.mock("./runtime-setter-api.js", () => ({ setMatrixRuntime: runtimeMocks.setMatrixRuntime }));
describe("matrix plugin", () => {
it("registers matrix CLI through a descriptor-backed lazy registrar", async () => {
@@ -66,6 +66,7 @@ describe("matrix plugin", () => {
expect(entry.kind).toBe("bundled-channel-entry");
expect(entry.id).toBe("matrix");
expect(entry.name).toBe("Matrix");
expect(entry.setChannelRuntime).toEqual(expect.any(Function));
});
it("registers subagent lifecycle hooks during full runtime registration", () => {

View File

@@ -77,7 +77,7 @@ export default defineBundledChannelEntry({
exportName: "channelSecrets",
},
runtime: {
specifier: "./runtime-api.js",
specifier: "./runtime-setter-api.js",
exportName: "setMatrixRuntime",
},
registerCliMetadata: registerMatrixCliMetadata,

View File

@@ -0,0 +1,3 @@
// Narrow entry point for setMatrixRuntime. The full runtime-api barrel is kept
// for external/runtime callers, but bundled plugin register only needs this.
export { setMatrixRuntime } from "./src/runtime.js";

View File

@@ -11,7 +11,7 @@ export default defineBundledChannelSetupEntry({
exportName: "channelSecrets",
},
runtime: {
specifier: "./runtime-api.js",
specifier: "./runtime-setter-api.js",
exportName: "setMatrixRuntime",
},
});

View File

@@ -1,18 +1,20 @@
import { Type } from "@sinclair/typebox";
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
import { extractToolSend } from "openclaw/plugin-sdk/tool-send";
import { requiresExplicitMatrixDefaultAccount } from "./account-selection.js";
import { resolveDefaultMatrixAccountId, resolveMatrixAccount } from "./matrix/accounts.js";
import {
createActionGate,
readNumberParam,
readStringParam,
ToolAuthorizationError,
type ChannelMessageActionAdapter,
type ChannelMessageActionContext,
type ChannelMessageActionName,
type ChannelMessageToolDiscovery,
} from "./runtime-api.js";
} from "openclaw/plugin-sdk/channel-actions";
import type {
ChannelMessageActionAdapter,
ChannelMessageActionContext,
ChannelMessageActionName,
ChannelMessageToolDiscovery,
} from "openclaw/plugin-sdk/channel-contract";
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
import { extractToolSend } from "openclaw/plugin-sdk/tool-send";
import { requiresExplicitMatrixDefaultAccount } from "./account-selection.js";
import { resolveDefaultMatrixAccountId, resolveMatrixAccount } from "./matrix/accounts.js";
import type { CoreConfig } from "./types.js";
const MATRIX_PLUGIN_HANDLED_ACTIONS = new Set<ChannelMessageActionName>([

View File

@@ -4,6 +4,7 @@ import {
createScopedDmSecurityResolver,
} from "openclaw/plugin-sdk/channel-config-helpers";
import { buildChannelConfigSchema } from "openclaw/plugin-sdk/channel-config-primitives";
import type { ChannelDoctorAdapter } from "openclaw/plugin-sdk/channel-contract";
import { createChatChannelPlugin, type ChannelPlugin } from "openclaw/plugin-sdk/channel-core";
import {
createAllowlistProviderOpenWarningCollector,
@@ -15,7 +16,6 @@ import {
createResolvedDirectoryEntriesLister,
createRuntimeDirectoryLiveAdapter,
} from "openclaw/plugin-sdk/directory-runtime";
import { buildTrafficStatusSummary } from "openclaw/plugin-sdk/extension-shared";
import { createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime";
import { createRuntimeOutboundDelegates } from "openclaw/plugin-sdk/outbound-runtime";
import {
@@ -34,7 +34,10 @@ import { matrixApprovalCapability } from "./approval-native.js";
import { createMatrixPairingText, createMatrixProbeAccount } from "./channel-account-paths.js";
import { DEFAULT_ACCOUNT_ID, matrixConfigAdapter } from "./config-adapter.js";
import { MatrixConfigSchema } from "./config-schema.js";
import { matrixDoctor } from "./doctor.js";
import {
legacyConfigRules as MATRIX_LEGACY_CONFIG_RULES,
normalizeCompatibilityConfig as normalizeMatrixCompatibilityConfig,
} from "./doctor-contract.js";
import { shouldSuppressLocalMatrixExecApprovalPrompt } from "./exec-approvals.js";
import {
resolveMatrixGroupRequireMention,
@@ -64,14 +67,17 @@ import {
resolveSingleAccountPromotionTarget,
singleAccountKeysToMove,
} from "./setup-contract.js";
import { matrixSetupAdapter } from "./setup-core.js";
import { matrixSetupWizard } from "./setup-surface.js";
import { createMatrixSetupWizardProxy, matrixSetupAdapter } from "./setup-core.js";
import { runMatrixStartupMaintenance } from "./startup-maintenance.js";
import { resolveMatrixInboundConversation } from "./thread-binding-api.js";
import type { CoreConfig } from "./types.js";
// Mutex for serializing account startup (workaround for concurrent dynamic import race condition)
let matrixStartupLock: Promise<void> = Promise.resolve();
const loadMatrixSetupWizard = createLazyRuntimeNamedExport(
() => import("./setup-surface.js"),
"matrixSetupWizard",
);
const loadMatrixChannelRuntime = createLazyRuntimeNamedExport(
() => import("./channel.runtime.js"),
"matrixChannelRuntime",
@@ -88,6 +94,31 @@ const meta = {
quickstartAllowFrom: true,
};
function buildMatrixTrafficStatusSummary(
snapshot?: {
lastInboundAt?: number | null;
lastOutboundAt?: number | null;
} | null,
) {
return {
lastInboundAt: snapshot?.lastInboundAt ?? null,
lastOutboundAt: snapshot?.lastOutboundAt ?? null,
};
}
const matrixDoctor: ChannelDoctorAdapter = {
dmAllowFromMode: "nestedOnly",
groupModel: "sender",
groupAllowFromFallbackToAllowFrom: false,
warnOnEmptyGroupSenderAllowlist: true,
legacyConfigRules: MATRIX_LEGACY_CONFIG_RULES,
normalizeCompatibilityConfig: normalizeMatrixCompatibilityConfig,
runConfigSequence: async ({ cfg, env, shouldRepair }) =>
await (await import("./doctor.js")).runMatrixDoctorSequence({ cfg, env, shouldRepair }),
cleanStaleConfig: async ({ cfg }) =>
await (await import("./doctor.js")).cleanStaleMatrixPluginConfig(cfg),
};
const listMatrixDirectoryPeersFromConfig =
createResolvedDirectoryEntriesLister<ResolvedMatrixAccount>({
kind: "user",
@@ -294,7 +325,9 @@ export const matrixPlugin: ChannelPlugin<ResolvedMatrixAccount, MatrixProbe> =
base: {
id: "matrix",
meta,
setupWizard: matrixSetupWizard,
setupWizard: createMatrixSetupWizardProxy(async () => ({
matrixSetupWizard: await loadMatrixSetupWizard(),
})),
capabilities: {
chatTypes: ["direct", "group", "thread"],
polls: true,
@@ -432,7 +465,7 @@ export const matrixPlugin: ChannelPlugin<ResolvedMatrixAccount, MatrixProbe> =
extra: {
baseUrl: account.homeserver,
lastProbeAt: runtime?.lastProbeAt ?? null,
...buildTrafficStatusSummary(runtime),
...buildMatrixTrafficStatusSummary(runtime),
},
}),
}),

View File

@@ -5,7 +5,6 @@ import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime";
import {
type ChannelSetupDmPolicy,
type ChannelSetupWizardAdapter,
addWildcardAllowFrom,
formatDocsLink,
hasConfiguredSecretInput,
mergeAllowFromEntries,
@@ -36,6 +35,7 @@ import {
import { resolveMatrixConfigFieldPath, updateMatrixAccountConfig } from "./matrix/config-update.js";
import { ensureMatrixSdkInstalled, isMatrixSdkAvailable } from "./matrix/deps.js";
import { moveSingleMatrixAccountConfigToNamedAccount } from "./setup-config.js";
import { resolveMatrixSetupDmAllowFrom } from "./setup-dm-policy.js";
import type { CoreConfig, MatrixConfig } from "./types.js";
const channel = "matrix" as const;
@@ -84,12 +84,12 @@ function setMatrixDmPolicy(cfg: CoreConfig, policy: DmPolicy, accountId?: string
cfg,
accountId: resolvedAccountId,
});
const allowFrom = policy === "open" ? addWildcardAllowFrom(existing.dm?.allowFrom) : undefined;
const allowFrom = resolveMatrixSetupDmAllowFrom(policy, existing.dm?.allowFrom);
return updateMatrixAccountConfig(cfg, resolvedAccountId, {
dm: {
...existing.dm,
policy,
...(allowFrom ? { allowFrom } : {}),
allowFrom,
},
});
}

View File

@@ -1,5 +1,6 @@
import { describe, expect, it } from "vitest";
import { matrixSetupAdapter } from "./setup-core.js";
import type { ChannelSetupWizardAdapter } from "openclaw/plugin-sdk/setup";
import { describe, expect, it, vi } from "vitest";
import { createMatrixSetupWizardProxy, matrixSetupAdapter } from "./setup-core.js";
import type { CoreConfig } from "./types.js";
function applyOpsAccountConfig(cfg: CoreConfig): CoreConfig {
@@ -35,6 +36,138 @@ function expectOpsAccount(next: CoreConfig): void {
});
}
function makeFakeSetupWizard(
overrides: Partial<ChannelSetupWizardAdapter> = {},
): ChannelSetupWizardAdapter {
return {
channel: "matrix",
getStatus: vi.fn(async () => ({
channel: "matrix",
configured: false,
statusLines: [],
})),
configure: vi.fn(async ({ cfg }) => ({ cfg })),
...overrides,
} as ChannelSetupWizardAdapter;
}
describe("createMatrixSetupWizardProxy", () => {
it("does not load the setup surface when constructing the proxy", () => {
const loader = vi.fn(async () => ({ matrixSetupWizard: makeFakeSetupWizard() }));
const proxy = createMatrixSetupWizardProxy(loader);
expect(proxy.channel).toBe("matrix");
expect(loader).not.toHaveBeenCalled();
});
it("loads the setup surface when setup status is requested", async () => {
const status = {
channel: "matrix" as const,
configured: true,
statusLines: ["Matrix: configured"],
};
const getStatus = vi.fn(async () => status);
const configure = vi.fn(async ({ cfg }) => ({ cfg }));
const loader = vi.fn(async () => ({
matrixSetupWizard: makeFakeSetupWizard({ configure, getStatus }),
}));
const proxy = createMatrixSetupWizardProxy(loader);
const cfg = { channels: { matrix: {} } } as CoreConfig;
const result = await proxy.getStatus({ cfg, accountOverrides: {} });
const configured = await proxy.configure({
cfg,
runtime: {} as never,
prompter: {} as never,
forceAllowFrom: false,
accountOverrides: {},
shouldPromptAccountIds: false,
});
expect(loader).toHaveBeenCalledTimes(1);
expect(getStatus).toHaveBeenCalledWith({ cfg, accountOverrides: {} });
expect(configure).toHaveBeenCalledTimes(1);
expect(result).toBe(status);
expect(configured).toEqual({ cfg });
});
it("keeps sync dmPolicy helpers local and lazy-loads only promptAllowFrom", async () => {
const promptAllowFrom = vi.fn(async ({ cfg }) => cfg);
const loader = vi.fn(async () => ({
matrixSetupWizard: makeFakeSetupWizard({
dmPolicy: {
label: "Matrix",
channel: "matrix",
policyKey: "unused",
allowFromKey: "unused",
getCurrent: () => "pairing",
setPolicy: (cfg) => cfg,
promptAllowFrom,
},
}),
}));
const proxy = createMatrixSetupWizardProxy(loader);
const cfg = {
channels: {
matrix: {
accounts: {
ops: {
dm: {
allowFrom: [" @ops:example.org ", "", "*"],
},
},
},
},
},
} as CoreConfig;
expect(proxy.dmPolicy?.getCurrent(cfg, "ops")).toBe("pairing");
const next = proxy.dmPolicy?.setPolicy(cfg, "open", "ops") as CoreConfig;
expect(next.channels?.matrix?.accounts?.ops?.dm).toMatchObject({
policy: "open",
allowFrom: ["@ops:example.org", "*"],
});
expect(loader).not.toHaveBeenCalled();
await proxy.dmPolicy?.promptAllowFrom?.({
cfg,
prompter: {} as never,
});
expect(loader).toHaveBeenCalledTimes(1);
expect(promptAllowFrom).toHaveBeenCalledTimes(1);
});
it("removes wildcard allowFrom when switching from open to a restrictive policy", () => {
const loader = vi.fn(async () => ({ matrixSetupWizard: makeFakeSetupWizard() }));
const proxy = createMatrixSetupWizardProxy(loader);
const cfg = {
channels: {
matrix: {
accounts: {
ops: {
dm: {
policy: "open",
allowFrom: ["*", " @ops:example.org "],
},
},
},
},
},
} as CoreConfig;
const next = proxy.dmPolicy?.setPolicy(cfg, "allowlist", "ops") as CoreConfig;
expect(next.channels?.matrix?.accounts?.ops?.dm).toMatchObject({
policy: "allowlist",
allowFrom: ["@ops:example.org"],
});
expect(loader).not.toHaveBeenCalled();
});
});
describe("matrixSetupAdapter", () => {
it("moves legacy default config before writing a named account", () => {
const cfg = {

View File

@@ -1,18 +1,114 @@
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
import {
DEFAULT_ACCOUNT_ID,
type DmPolicy,
normalizeAccountId,
prepareScopedSetupConfig,
type ChannelSetupAdapter,
type ChannelSetupWizardAdapter,
} from "openclaw/plugin-sdk/setup";
import { resolveDefaultMatrixAccountId, resolveMatrixAccountConfig } from "./matrix/accounts.js";
import { resolveMatrixConfigFieldPath, updateMatrixAccountConfig } from "./matrix/config-update.js";
import { applyMatrixSetupAccountConfig, validateMatrixSetupInput } from "./setup-config.js";
import { resolveMatrixSetupDmAllowFrom } from "./setup-dm-policy.js";
import type { CoreConfig } from "./types.js";
const channel = "matrix" as const;
type MatrixSetupWizardModule = { matrixSetupWizard: ChannelSetupWizardAdapter };
function resolveMatrixSetupAccountId(params: { accountId?: string; name?: string }): string {
return normalizeAccountId(params.accountId?.trim() || params.name?.trim() || DEFAULT_ACCOUNT_ID);
}
function resolveMatrixSetupWizardAccountId(cfg: CoreConfig, accountId?: string): string {
return normalizeAccountId(
accountId?.trim() || resolveDefaultMatrixAccountId(cfg) || DEFAULT_ACCOUNT_ID,
);
}
function setMatrixDmPolicy(cfg: CoreConfig, policy: DmPolicy, accountId?: string): CoreConfig {
const resolvedAccountId = resolveMatrixSetupWizardAccountId(cfg, accountId);
const existing = resolveMatrixAccountConfig({
cfg,
accountId: resolvedAccountId,
});
const allowFrom = resolveMatrixSetupDmAllowFrom(policy, existing.dm?.allowFrom);
return updateMatrixAccountConfig(cfg, resolvedAccountId, {
dm: {
...existing.dm,
policy,
allowFrom,
},
});
}
export function createMatrixSetupWizardProxy(
loadWizardModule: () => Promise<MatrixSetupWizardModule>,
): ChannelSetupWizardAdapter {
let wizardPromise: Promise<ChannelSetupWizardAdapter> | null = null;
const loadWizard = () => {
wizardPromise ??= loadWizardModule().then((module) => module.matrixSetupWizard);
return wizardPromise;
};
return {
channel,
getStatus: async (ctx) => await (await loadWizard()).getStatus(ctx),
configure: async (ctx) => await (await loadWizard()).configure(ctx),
configureInteractive: async (ctx) => {
const wizard = await loadWizard();
return await (wizard.configureInteractive ?? wizard.configure)(ctx);
},
configureWhenConfigured: async (ctx) => {
const wizard = await loadWizard();
return await (
wizard.configureWhenConfigured ??
wizard.configureInteractive ??
wizard.configure
)(ctx);
},
afterConfigWritten: async (ctx) => await (await loadWizard()).afterConfigWritten?.(ctx),
dmPolicy: {
label: "Matrix",
channel,
policyKey: "channels.matrix.dm.policy",
allowFromKey: "channels.matrix.dm.allowFrom",
resolveConfigKeys: (cfg, accountId) => {
const resolvedAccountId = resolveMatrixSetupWizardAccountId(cfg as CoreConfig, accountId);
return {
policyKey: resolveMatrixConfigFieldPath(
cfg as CoreConfig,
resolvedAccountId,
"dm.policy",
),
allowFromKey: resolveMatrixConfigFieldPath(
cfg as CoreConfig,
resolvedAccountId,
"dm.allowFrom",
),
};
},
getCurrent: (cfg, accountId) =>
resolveMatrixAccountConfig({
cfg: cfg as CoreConfig,
accountId: resolveMatrixSetupWizardAccountId(cfg as CoreConfig, accountId),
}).dm?.policy ?? "pairing",
setPolicy: (cfg, policy, accountId) =>
setMatrixDmPolicy(cfg as CoreConfig, policy, accountId) as OpenClawConfig,
promptAllowFrom: async (params) => {
const promptAllowFrom = (await loadWizard()).dmPolicy?.promptAllowFrom;
return promptAllowFrom ? await promptAllowFrom(params) : params.cfg;
},
},
disable: (cfg) => ({
...(cfg as CoreConfig),
channels: {
...(cfg as CoreConfig).channels,
matrix: { ...(cfg as CoreConfig).channels?.matrix, enabled: false },
},
}),
};
}
export const matrixSetupAdapter: ChannelSetupAdapter = {
resolveAccountId: ({ accountId, input }) =>
resolveMatrixSetupAccountId({

View File

@@ -0,0 +1,15 @@
import type { DmPolicy } from "openclaw/plugin-sdk/config-runtime";
import { addWildcardAllowFrom, normalizeAllowFromEntries } from "openclaw/plugin-sdk/setup";
import type { MatrixConfig } from "./types.js";
type MatrixDmAllowFrom = NonNullable<MatrixConfig["dm"]>["allowFrom"];
export function resolveMatrixSetupDmAllowFrom(
policy: DmPolicy,
allowFrom: MatrixDmAllowFrom,
): string[] {
if (policy === "open") {
return addWildcardAllowFrom(allowFrom);
}
return normalizeAllowFromEntries(allowFrom ?? []).filter((entry) => entry !== "*");
}

View File

@@ -187,6 +187,13 @@ describe("bundled plugin metadata", () => {
});
});
it("keeps Matrix's narrow runtime-setter sidecar on the bundled public surface", () => {
const matrix = listRepoBundledPluginMetadata().find((entry) => entry.dirName === "matrix");
expectArtifactPresence(matrix?.publicSurfaceArtifacts, {
contains: ["runtime-setter-api.js"],
});
});
it("keeps bundled configured-state metadata on channel package manifests", () => {
const configuredChannels = listRepoBundledPluginMetadata()
.filter((entry) => ["discord", "irc", "slack", "telegram"].includes(entry.dirName))

View File

@@ -238,4 +238,15 @@ describe("runtime api guardrails", () => {
);
}
});
it("keeps Matrix's narrow runtime-setter entrypoint pinned to a single export", () => {
const setterFile = bundledPluginFile({
rootDir: ROOT_DIR,
pluginId: "matrix",
relativePath: "runtime-setter-api.ts",
});
expect(readExportStatements(setterFile)).toEqual([
'export { setMatrixRuntime } from "./src/runtime.js";',
]);
});
});