From 08ca2483780934c957692003528672203df9f239 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 13 Apr 2026 17:12:27 +0100 Subject: [PATCH] perf(outbound): use loaded-only channel plugin reads --- src/channels/plugins/registry-loaded-read.ts | 36 +++++++++++++++++++ src/cron/isolated-agent/delivery-target.ts | 2 +- .../outbound/target-normalization.test.ts | 4 +-- src/infra/outbound/target-normalization.ts | 11 +++--- src/infra/outbound/targets-loaded.test.ts | 2 +- src/infra/outbound/targets-loaded.ts | 2 +- 6 files changed, 47 insertions(+), 10 deletions(-) create mode 100644 src/channels/plugins/registry-loaded-read.ts diff --git a/src/channels/plugins/registry-loaded-read.ts b/src/channels/plugins/registry-loaded-read.ts new file mode 100644 index 00000000000..47cfe3f1435 --- /dev/null +++ b/src/channels/plugins/registry-loaded-read.ts @@ -0,0 +1,36 @@ +import type { ActiveChannelPluginRuntimeShape } from "../../plugins/channel-registry-state.types.js"; +import { getActivePluginChannelRegistryFromState } from "../../plugins/runtime-channel-state.js"; +import { normalizeOptionalString } from "../../shared/string-coerce.js"; +import type { ChannelPlugin } from "./types.plugin.js"; +import type { ChannelId } from "./types.public.js"; + +function coerceLoadedChannelPlugin( + plugin: ActiveChannelPluginRuntimeShape | null | undefined, +): ChannelPlugin | undefined { + const id = normalizeOptionalString(plugin?.id) ?? ""; + if (!plugin || !id) { + return undefined; + } + if (!plugin.meta || typeof plugin.meta !== "object") { + plugin.meta = {}; + } + return plugin as ChannelPlugin; +} + +export function getLoadedChannelPluginForRead(id: ChannelId): ChannelPlugin | undefined { + const resolvedId = normalizeOptionalString(id) ?? ""; + if (!resolvedId) { + return undefined; + } + const registry = getActivePluginChannelRegistryFromState(); + if (!registry || !Array.isArray(registry.channels)) { + return undefined; + } + for (const entry of registry.channels) { + const plugin = coerceLoadedChannelPlugin(entry?.plugin); + if (plugin && plugin.id === resolvedId) { + return plugin; + } + } + return undefined; +} diff --git a/src/cron/isolated-agent/delivery-target.ts b/src/cron/isolated-agent/delivery-target.ts index d2dd454d76d..f2163bff5e0 100644 --- a/src/cron/isolated-agent/delivery-target.ts +++ b/src/cron/isolated-agent/delivery-target.ts @@ -1,4 +1,4 @@ -import { getLoadedChannelPluginForRead } from "../../channels/plugins/registry-read.js"; +import { getLoadedChannelPluginForRead } from "../../channels/plugins/registry-loaded-read.js"; import type { ChannelId } from "../../channels/plugins/types.public.js"; import { resolveAgentMainSessionKey } from "../../config/sessions/main-session.js"; import { resolveStorePath } from "../../config/sessions/paths.js"; diff --git a/src/infra/outbound/target-normalization.test.ts b/src/infra/outbound/target-normalization.test.ts index a8d7c80dfc2..d3c37463689 100644 --- a/src/infra/outbound/target-normalization.test.ts +++ b/src/infra/outbound/target-normalization.test.ts @@ -14,8 +14,8 @@ let resolveNormalizedTargetInput: TargetNormalizationModule["resolveNormalizedTa let normalizeTargetForProvider: TargetNormalizationModule["normalizeTargetForProvider"]; let resetTargetNormalizerCacheForTests: TargetNormalizationModule["__testing"]["resetTargetNormalizerCacheForTests"]; -vi.mock("../../channels/plugins/registry-read.js", () => ({ - getChannelPluginForRead: (...args: unknown[]) => getChannelPluginMock(...args), +vi.mock("../../channels/plugins/registry-loaded-read.js", () => ({ + getLoadedChannelPluginForRead: (...args: unknown[]) => getChannelPluginMock(...args), })); vi.mock("../../plugins/runtime.js", () => ({ diff --git a/src/infra/outbound/target-normalization.ts b/src/infra/outbound/target-normalization.ts index 39d99e92ce0..fbd89c7067a 100644 --- a/src/infra/outbound/target-normalization.ts +++ b/src/infra/outbound/target-normalization.ts @@ -1,4 +1,4 @@ -import { getChannelPluginForRead } from "../../channels/plugins/registry-read.js"; +import { getLoadedChannelPluginForRead } from "../../channels/plugins/registry-loaded-read.js"; import type { ChannelDirectoryEntryKind, ChannelId } from "../../channels/plugins/types.public.js"; import type { OpenClawConfig } from "../../config/types.openclaw.js"; import { getActivePluginChannelRegistryVersion } from "../../plugins/runtime.js"; @@ -33,7 +33,7 @@ function resolveTargetNormalizer(channelId: ChannelId): TargetNormalizer { if (cached && cached.version === version) { return cached.normalizer; } - const plugin = getChannelPluginForRead(channelId); + const plugin = getLoadedChannelPluginForRead(channelId); const normalizer = plugin?.messaging?.normalizeTarget; targetNormalizerCacheByChannelId.set(channelId, { version, @@ -85,7 +85,8 @@ export function looksLikeTargetId(params: { }): boolean { const normalizedInput = params.normalized ?? normalizeTargetForProvider(params.channel, params.raw); - const lookup = getChannelPluginForRead(params.channel)?.messaging?.targetResolver?.looksLikeId; + const lookup = getLoadedChannelPluginForRead(params.channel)?.messaging?.targetResolver + ?.looksLikeId; if (lookup) { return lookup(params.raw, normalizedInput ?? params.raw); } @@ -116,7 +117,7 @@ export async function maybeResolvePluginMessagingTarget(params: { if (!normalizedInput) { return undefined; } - const resolver = getChannelPluginForRead(params.channel)?.messaging?.targetResolver; + const resolver = getLoadedChannelPluginForRead(params.channel)?.messaging?.targetResolver; if (!resolver?.resolveTarget) { return undefined; } @@ -149,7 +150,7 @@ export async function maybeResolvePluginMessagingTarget(params: { } export function buildTargetResolverSignature(channel: ChannelId): string { - const plugin = getChannelPluginForRead(channel); + const plugin = getLoadedChannelPluginForRead(channel); const resolver = plugin?.messaging?.targetResolver; const hint = resolver?.hint ?? ""; const looksLike = resolver?.looksLikeId; diff --git a/src/infra/outbound/targets-loaded.test.ts b/src/infra/outbound/targets-loaded.test.ts index 5f639a64cc6..87b324c8db7 100644 --- a/src/infra/outbound/targets-loaded.test.ts +++ b/src/infra/outbound/targets-loaded.test.ts @@ -6,7 +6,7 @@ const mocks = vi.hoisted(() => ({ getLoadedChannelPlugin: vi.fn(), })); -vi.mock("../../channels/plugins/registry-read.js", () => ({ +vi.mock("../../channels/plugins/registry-loaded-read.js", () => ({ getLoadedChannelPluginForRead: mocks.getLoadedChannelPlugin, })); diff --git a/src/infra/outbound/targets-loaded.ts b/src/infra/outbound/targets-loaded.ts index 8769215b726..e09b4a6b130 100644 --- a/src/infra/outbound/targets-loaded.ts +++ b/src/infra/outbound/targets-loaded.ts @@ -1,4 +1,4 @@ -import { getLoadedChannelPluginForRead } from "../../channels/plugins/registry-read.js"; +import { getLoadedChannelPluginForRead } from "../../channels/plugins/registry-loaded-read.js"; import type { ChannelPlugin } from "../../channels/plugins/types.plugin.js"; import type { ChannelOutboundTargetMode } from "../../channels/plugins/types.public.js"; import type { OpenClawConfig } from "../../config/types.openclaw.js";