perf: reduce plugin runtime startup overhead

This commit is contained in:
Peter Steinberger
2026-03-22 09:34:08 +00:00
parent aa6b962a3a
commit 3382ef2724
24 changed files with 83 additions and 22 deletions

View File

@@ -20,7 +20,7 @@ import {
import {
createRuntimeOutboundDelegates,
resolveOutboundSendDep,
} from "openclaw/plugin-sdk/infra-runtime";
} from "openclaw/plugin-sdk/outbound-runtime";
import {
buildOutboundBaseSessionKey,
normalizeMessageChannel,

View File

@@ -4,7 +4,10 @@ import {
createAttachedChannelResultAdapter,
} from "openclaw/plugin-sdk/channel-send-result";
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
import { resolveOutboundSendDep, type OutboundIdentity } from "openclaw/plugin-sdk/infra-runtime";
import {
resolveOutboundSendDep,
type OutboundIdentity,
} from "openclaw/plugin-sdk/outbound-runtime";
import {
resolvePayloadMediaUrls,
sendPayloadMediaSequenceOrFallback,

View File

@@ -17,8 +17,8 @@ import {
createChannelDirectoryAdapter,
createRuntimeDirectoryLiveAdapter,
} from "openclaw/plugin-sdk/directory-runtime";
import { createRuntimeOutboundDelegates } from "openclaw/plugin-sdk/infra-runtime";
import { createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime";
import { createRuntimeOutboundDelegates } from "openclaw/plugin-sdk/outbound-runtime";
import type { ChannelMeta, ChannelPlugin, ClawdbotConfig } from "../runtime-api.js";
import {
buildChannelConfigSchema,

View File

@@ -1,4 +1,4 @@
import { resolveOutboundSendDep } from "openclaw/plugin-sdk/infra-runtime";
import { resolveOutboundSendDep } from "openclaw/plugin-sdk/outbound-runtime";
import { PAIRING_APPROVED_MESSAGE, resolveChannelMediaMaxBytes } from "../runtime-api.js";
import type { ResolvedIMessageAccount } from "./accounts.js";
import { monitorIMessageProvider } from "./monitor.js";

View File

@@ -1,8 +1,8 @@
import { buildDmGroupAccountAllowlistAdapter } from "openclaw/plugin-sdk/allowlist-config-edit";
import { createAttachedChannelResultAdapter } from "openclaw/plugin-sdk/channel-send-result";
import { buildPassiveProbedChannelStatusSummary } from "openclaw/plugin-sdk/extension-shared";
import { resolveOutboundSendDep } from "openclaw/plugin-sdk/infra-runtime";
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
import { resolveOutboundSendDep } from "openclaw/plugin-sdk/outbound-runtime";
import { buildOutboundBaseSessionKey, type RoutePeer } from "openclaw/plugin-sdk/routing";
import {
collectStatusIssuesFromLastError,

View File

@@ -1,8 +1,11 @@
import { resolveOutboundSendDep, type OutboundSendDeps } from "openclaw/plugin-sdk/infra-runtime";
import {
createDirectTextMediaOutbound,
createScopedChannelMediaMaxBytesResolver,
} from "openclaw/plugin-sdk/media-runtime";
import {
resolveOutboundSendDep,
type OutboundSendDeps,
} from "openclaw/plugin-sdk/outbound-runtime";
import { sendMessageIMessage } from "./send.js";
function resolveIMessageSender(deps: OutboundSendDeps | undefined) {

View File

@@ -17,8 +17,8 @@ import {
listResolvedDirectoryEntriesFromSources,
} from "openclaw/plugin-sdk/directory-runtime";
import { buildTrafficStatusSummary } from "openclaw/plugin-sdk/extension-shared";
import { createRuntimeOutboundDelegates } from "openclaw/plugin-sdk/infra-runtime";
import { createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime";
import { createRuntimeOutboundDelegates } from "openclaw/plugin-sdk/outbound-runtime";
import { matrixMessageActions } from "./actions.js";
import { MatrixConfigSchema } from "./config-schema.js";
import {

View File

@@ -18,8 +18,8 @@ import {
createRuntimeDirectoryLiveAdapter,
listDirectoryEntriesFromSources,
} from "openclaw/plugin-sdk/directory-runtime";
import { createRuntimeOutboundDelegates } from "openclaw/plugin-sdk/infra-runtime";
import { createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime";
import { createRuntimeOutboundDelegates } from "openclaw/plugin-sdk/outbound-runtime";
import type { ChannelMessageActionName, ChannelPlugin, OpenClawConfig } from "../runtime-api.js";
import {
buildProbeChannelStatusSummary,

View File

@@ -1,5 +1,5 @@
import { createAttachedChannelResultAdapter } from "openclaw/plugin-sdk/channel-send-result";
import { resolveOutboundSendDep } from "openclaw/plugin-sdk/infra-runtime";
import { resolveOutboundSendDep } from "openclaw/plugin-sdk/outbound-runtime";
import type { ChannelOutboundAdapter } from "../runtime-api.js";
import { createMSTeamsPollStoreFs } from "./polls.js";
import { getMSTeamsRuntime } from "./runtime.js";

View File

@@ -9,7 +9,7 @@ import {
createAttachedChannelResultAdapter,
} from "openclaw/plugin-sdk/channel-send-result";
import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/config-runtime";
import { resolveOutboundSendDep } from "openclaw/plugin-sdk/infra-runtime";
import { resolveOutboundSendDep } from "openclaw/plugin-sdk/outbound-runtime";
import { resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-runtime";
import { buildOutboundBaseSessionKey, type RoutePeer } from "openclaw/plugin-sdk/routing";
import { resolveSignalAccount, type ResolvedSignalAccount } from "./accounts.js";

View File

@@ -5,8 +5,11 @@ import {
createAttachedChannelResultAdapter,
} from "openclaw/plugin-sdk/channel-send-result";
import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/config-runtime";
import { resolveOutboundSendDep, type OutboundSendDeps } from "openclaw/plugin-sdk/infra-runtime";
import { createScopedChannelMediaMaxBytesResolver } from "openclaw/plugin-sdk/media-runtime";
import {
resolveOutboundSendDep,
type OutboundSendDeps,
} from "openclaw/plugin-sdk/outbound-runtime";
import { resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-runtime";
import { markdownToSignalTextChunks } from "./format.js";
import { sendMessageSignal } from "./send.js";

View File

@@ -20,7 +20,7 @@ import { buildPassiveProbedChannelStatusSummary } from "openclaw/plugin-sdk/exte
import {
createRuntimeOutboundDelegates,
resolveOutboundSendDep,
} from "openclaw/plugin-sdk/infra-runtime";
} from "openclaw/plugin-sdk/outbound-runtime";
import {
buildOutboundBaseSessionKey,
normalizeOutboundThreadId,

View File

@@ -6,7 +6,7 @@ import {
} from "openclaw/plugin-sdk/channel-feedback";
import { createChannelReplyPipeline } from "openclaw/plugin-sdk/channel-reply-pipeline";
import { resolveStorePath, updateLastRoute } from "openclaw/plugin-sdk/config-runtime";
import { resolveAgentOutboundIdentity } from "openclaw/plugin-sdk/infra-runtime";
import { resolveAgentOutboundIdentity } from "openclaw/plugin-sdk/outbound-runtime";
import { clearHistoryEntriesIfEnabled } from "openclaw/plugin-sdk/reply-history";
import { resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
import { dispatchInboundMessage } from "openclaw/plugin-sdk/reply-runtime";

View File

@@ -3,11 +3,14 @@ import {
type ChannelOutboundAdapter,
createAttachedChannelResultAdapter,
} from "openclaw/plugin-sdk/channel-send-result";
import { resolveOutboundSendDep, type OutboundIdentity } from "openclaw/plugin-sdk/infra-runtime";
import {
resolveInteractiveTextFallback,
type InteractiveReply,
} from "openclaw/plugin-sdk/interactive-runtime";
import {
resolveOutboundSendDep,
type OutboundIdentity,
} from "openclaw/plugin-sdk/outbound-runtime";
import { getGlobalHookRunner } from "openclaw/plugin-sdk/plugin-runtime";
import {
resolvePayloadMediaUrls,

View File

@@ -9,7 +9,10 @@ import { createChatChannelPlugin } from "openclaw/plugin-sdk/core";
import { createChannelDirectoryAdapter } from "openclaw/plugin-sdk/directory-runtime";
import { resolveExecApprovalCommandDisplay } from "openclaw/plugin-sdk/infra-runtime";
import { buildExecApprovalPendingReplyPayload } from "openclaw/plugin-sdk/infra-runtime";
import { resolveOutboundSendDep, type OutboundSendDeps } from "openclaw/plugin-sdk/infra-runtime";
import {
resolveOutboundSendDep,
type OutboundSendDeps,
} from "openclaw/plugin-sdk/outbound-runtime";
import {
buildOutboundBaseSessionKey,
normalizeMessageChannel,

View File

@@ -3,8 +3,11 @@ import {
attachChannelToResult,
createAttachedChannelResultAdapter,
} from "openclaw/plugin-sdk/channel-send-result";
import { resolveOutboundSendDep, type OutboundSendDeps } from "openclaw/plugin-sdk/infra-runtime";
import { resolveInteractiveTextFallback } from "openclaw/plugin-sdk/interactive-runtime";
import {
resolveOutboundSendDep,
type OutboundSendDeps,
} from "openclaw/plugin-sdk/outbound-runtime";
import {
resolvePayloadMediaUrls,
sendPayloadMediaSequenceOrFallback,

View File

@@ -2,8 +2,8 @@ import { createHybridChannelConfigAdapter } from "openclaw/plugin-sdk/channel-co
import type { ChannelAccountSnapshot } from "openclaw/plugin-sdk/channel-contract";
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
import type { ChannelPlugin } from "openclaw/plugin-sdk/core";
import { createRuntimeOutboundDelegates } from "openclaw/plugin-sdk/infra-runtime";
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
import { createRuntimeOutboundDelegates } from "openclaw/plugin-sdk/outbound-runtime";
import { tlonChannelConfigSchema } from "./config-schema.js";
import { resolveTlonOutboundSessionRoute } from "./session-route.js";
import {

View File

@@ -3,7 +3,7 @@ import {
createAttachedChannelResultAdapter,
createEmptyChannelResult,
} from "openclaw/plugin-sdk/channel-send-result";
import { resolveOutboundSendDep } from "openclaw/plugin-sdk/infra-runtime";
import { resolveOutboundSendDep } from "openclaw/plugin-sdk/outbound-runtime";
import {
resolveSendableOutboundReplyParts,
sendTextMediaPayload,

View File

@@ -117,6 +117,10 @@
"types": "./dist/plugin-sdk/interactive-runtime.d.ts",
"default": "./dist/plugin-sdk/interactive-runtime.js"
},
"./plugin-sdk/outbound-runtime": {
"types": "./dist/plugin-sdk/outbound-runtime.d.ts",
"default": "./dist/plugin-sdk/outbound-runtime.js"
},
"./plugin-sdk/infra-runtime": {
"types": "./dist/plugin-sdk/infra-runtime.d.ts",
"default": "./dist/plugin-sdk/infra-runtime.js"

View File

@@ -19,6 +19,7 @@
"channel-reply-pipeline",
"channel-runtime",
"interactive-runtime",
"outbound-runtime",
"infra-runtime",
"ssrf-runtime",
"media-runtime",

View File

@@ -43,8 +43,10 @@ describe("resolveWhatsAppHeartbeatRecipients", () => {
vi.resetModules();
loadSessionStoreMock.mockReset();
readChannelAllowFromStoreSyncMock.mockReset();
vi.doMock("../../config/sessions.js", () => ({
loadSessionStore: loadSessionStoreMock,
vi.doMock("../../config/sessions/store-summary.js", () => ({
loadSessionStoreSummary: loadSessionStoreMock,
}));
vi.doMock("../../config/sessions/paths.js", () => ({
resolveStorePath: vi.fn(() => "/tmp/test-sessions.json"),
}));
vi.doMock("../../pairing/pairing-store.js", () => ({

View File

@@ -1,5 +1,6 @@
import type { OpenClawConfig } from "../../config/config.js";
import { loadSessionStore, resolveStorePath } from "../../config/sessions.js";
import { resolveStorePath } from "../../config/sessions/paths.js";
import { loadSessionStoreSummary } from "../../config/sessions/store-summary.js";
import { readChannelAllowFromStoreSync } from "../../pairing/pairing-store.js";
import { DEFAULT_ACCOUNT_ID } from "../../routing/session-key.js";
import { normalizeE164 } from "../../utils.js";
@@ -15,7 +16,7 @@ function getSessionRecipients(cfg: OpenClawConfig) {
return [];
}
const storePath = resolveStorePath(cfg.session?.store);
const store = loadSessionStore(storePath);
const store = loadSessionStoreSummary(storePath);
const isGroupKey = (key: string) =>
key.includes(":group:") || key.includes(":channel:") || key.includes("@g.us");
const isCronKey = (key: string) => key.startsWith("cron:");

View File

@@ -0,0 +1,32 @@
import fs from "node:fs";
export type SessionStoreSummaryEntry = {
lastChannel?: string;
lastTo?: string;
updatedAt?: number;
};
function isSummaryRecord(value: unknown): value is Record<string, SessionStoreSummaryEntry> {
return !!value && typeof value === "object" && !Array.isArray(value);
}
// Heartbeat recipient resolution only needs a shallow snapshot of the session
// store. A direct read avoids dragging in the full session maintenance/cache
// stack on cold imports.
export function loadSessionStoreSummary(
storePath: string,
): Record<string, SessionStoreSummaryEntry> {
try {
const raw = fs.readFileSync(storePath, "utf8");
if (!raw) {
return {};
}
const parsed = JSON.parse(raw);
if (!isSummaryRecord(parsed)) {
return {};
}
return parsed;
} catch {
return {};
}
}

View File

@@ -0,0 +1,3 @@
export { createRuntimeOutboundDelegates } from "../channels/plugins/runtime-forwarders.js";
export { resolveOutboundSendDep, type OutboundSendDeps } from "../infra/outbound/send-deps.js";
export { resolveAgentOutboundIdentity, type OutboundIdentity } from "../infra/outbound/identity.js";