From f27c164e7ff3e3f0e674402b4e06c4ac493934e4 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 20 Apr 2026 14:57:50 +0100 Subject: [PATCH] refactor: share lazy facade value binder --- src/plugin-sdk/facade-runtime.ts | 33 ++++++--- src/plugin-sdk/lmstudio-runtime.ts | 41 +++++------ src/plugin-sdk/tts-runtime.ts | 112 +++++++++++++++++------------ 3 files changed, 109 insertions(+), 77 deletions(-) diff --git a/src/plugin-sdk/facade-runtime.ts b/src/plugin-sdk/facade-runtime.ts index 724a35fa6a7..88f034fee4b 100644 --- a/src/plugin-sdk/facade-runtime.ts +++ b/src/plugin-sdk/facade-runtime.ts @@ -27,6 +27,19 @@ export { listImportedBundledPluginFacadeIds, } from "./facade-loader.js"; +export function createLazyFacadeValue( + loadFacadeModule: () => TFacade, + key: K, +): TFacade[K] { + return ((...args: unknown[]) => { + const value = loadFacadeModule()[key]; + if (typeof value !== "function") { + return value; + } + return (value as (...innerArgs: unknown[]) => unknown)(...args); + }) as TFacade[K]; +} + const OPENCLAW_PACKAGE_ROOT = resolveLoaderPackageRoot({ modulePath: fileURLToPath(import.meta.url), @@ -93,6 +106,16 @@ function resolveRegistryPluginModuleLocation(params: { }); } +function resolveFacadeBoundaryRoot(modulePath: string, bundledPluginsDir: string | undefined) { + if (!bundledPluginsDir) { + return OPENCLAW_PACKAGE_ROOT; + } + const resolvedBundledPluginsDir = path.resolve(bundledPluginsDir); + return modulePath.startsWith(`${resolvedBundledPluginsDir}${path.sep}`) + ? resolvedBundledPluginsDir + : OPENCLAW_PACKAGE_ROOT; +} + function resolveFacadeModuleLocationUncached(params: { dirName: string; artifactBasename: string; @@ -116,10 +139,7 @@ function resolveFacadeModuleLocationUncached(params: { if (modulePath) { return { modulePath, - boundaryRoot: - bundledPluginsDir && modulePath.startsWith(path.resolve(bundledPluginsDir) + path.sep) - ? path.resolve(bundledPluginsDir) - : OPENCLAW_PACKAGE_ROOT, + boundaryRoot: resolveFacadeBoundaryRoot(modulePath, bundledPluginsDir), }; } return resolveRegistryPluginModuleLocation(params); @@ -134,10 +154,7 @@ function resolveFacadeModuleLocationUncached(params: { if (modulePath) { return { modulePath, - boundaryRoot: - bundledPluginsDir && modulePath.startsWith(path.resolve(bundledPluginsDir) + path.sep) - ? path.resolve(bundledPluginsDir) - : OPENCLAW_PACKAGE_ROOT, + boundaryRoot: resolveFacadeBoundaryRoot(modulePath, bundledPluginsDir), }; } return resolveRegistryPluginModuleLocation(params); diff --git a/src/plugin-sdk/lmstudio-runtime.ts b/src/plugin-sdk/lmstudio-runtime.ts index 99d0ed73192..d5c022a0c70 100644 --- a/src/plugin-sdk/lmstudio-runtime.ts +++ b/src/plugin-sdk/lmstudio-runtime.ts @@ -4,7 +4,10 @@ import type { ModelProviderConfig, OpenClawConfig, } from "../config/types.js"; -import { loadBundledPluginPublicSurfaceModuleSync } from "./facade-runtime.js"; +import { + createLazyFacadeValue as createLazyFacadeRuntimeValue, + loadBundledPluginPublicSurfaceModuleSync, +} from "./facade-runtime.js"; type LmstudioReasoningCapabilityWire = { allowed_options?: unknown; @@ -125,38 +128,28 @@ export const LMSTUDIO_DEFAULT_MODEL_ID: FacadeModule["LMSTUDIO_DEFAULT_MODEL_ID" export const LMSTUDIO_PROVIDER_ID: FacadeModule["LMSTUDIO_PROVIDER_ID"] = "lmstudio"; export const resolveLmstudioReasoningCapability: FacadeModule["resolveLmstudioReasoningCapability"] = - createLazyFacadeValue("resolveLmstudioReasoningCapability"); + createLazyFacadeRuntimeValue(loadFacadeModule, "resolveLmstudioReasoningCapability"); export const resolveLoadedContextWindow: FacadeModule["resolveLoadedContextWindow"] = - createLazyFacadeValue("resolveLoadedContextWindow"); + createLazyFacadeRuntimeValue(loadFacadeModule, "resolveLoadedContextWindow"); export const resolveLmstudioServerBase: FacadeModule["resolveLmstudioServerBase"] = - createLazyFacadeValue("resolveLmstudioServerBase"); + createLazyFacadeRuntimeValue(loadFacadeModule, "resolveLmstudioServerBase"); export const resolveLmstudioInferenceBase: FacadeModule["resolveLmstudioInferenceBase"] = - createLazyFacadeValue("resolveLmstudioInferenceBase"); + createLazyFacadeRuntimeValue(loadFacadeModule, "resolveLmstudioInferenceBase"); export const normalizeLmstudioProviderConfig: FacadeModule["normalizeLmstudioProviderConfig"] = - createLazyFacadeValue("normalizeLmstudioProviderConfig"); + createLazyFacadeRuntimeValue(loadFacadeModule, "normalizeLmstudioProviderConfig"); export const fetchLmstudioModels: FacadeModule["fetchLmstudioModels"] = - createLazyFacadeValue("fetchLmstudioModels"); + createLazyFacadeRuntimeValue(loadFacadeModule, "fetchLmstudioModels"); export const mapLmstudioWireEntry: FacadeModule["mapLmstudioWireEntry"] = - createLazyFacadeValue("mapLmstudioWireEntry"); + createLazyFacadeRuntimeValue(loadFacadeModule, "mapLmstudioWireEntry"); export const discoverLmstudioModels: FacadeModule["discoverLmstudioModels"] = - createLazyFacadeValue("discoverLmstudioModels"); + createLazyFacadeRuntimeValue(loadFacadeModule, "discoverLmstudioModels"); export const ensureLmstudioModelLoaded: FacadeModule["ensureLmstudioModelLoaded"] = - createLazyFacadeValue("ensureLmstudioModelLoaded"); + createLazyFacadeRuntimeValue(loadFacadeModule, "ensureLmstudioModelLoaded"); export const buildLmstudioAuthHeaders: FacadeModule["buildLmstudioAuthHeaders"] = - createLazyFacadeValue("buildLmstudioAuthHeaders"); + createLazyFacadeRuntimeValue(loadFacadeModule, "buildLmstudioAuthHeaders"); export const resolveLmstudioConfiguredApiKey: FacadeModule["resolveLmstudioConfiguredApiKey"] = - createLazyFacadeValue("resolveLmstudioConfiguredApiKey"); + createLazyFacadeRuntimeValue(loadFacadeModule, "resolveLmstudioConfiguredApiKey"); export const resolveLmstudioProviderHeaders: FacadeModule["resolveLmstudioProviderHeaders"] = - createLazyFacadeValue("resolveLmstudioProviderHeaders"); + createLazyFacadeRuntimeValue(loadFacadeModule, "resolveLmstudioProviderHeaders"); export const resolveLmstudioRuntimeApiKey: FacadeModule["resolveLmstudioRuntimeApiKey"] = - createLazyFacadeValue("resolveLmstudioRuntimeApiKey"); - -function createLazyFacadeValue(key: K): FacadeModule[K] { - return ((...args: unknown[]) => { - const value = loadFacadeModule()[key]; - if (typeof value !== "function") { - return value; - } - return (value as (...innerArgs: unknown[]) => unknown)(...args); - }) as FacadeModule[K]; -} + createLazyFacadeRuntimeValue(loadFacadeModule, "resolveLmstudioRuntimeApiKey"); diff --git a/src/plugin-sdk/tts-runtime.ts b/src/plugin-sdk/tts-runtime.ts index c5e75bf9a36..b821ddd237a 100644 --- a/src/plugin-sdk/tts-runtime.ts +++ b/src/plugin-sdk/tts-runtime.ts @@ -1,4 +1,5 @@ import { + createLazyFacadeValue as createLazyFacadeRuntimeValue, createLazyFacadeObjectValue, loadActivatedBundledPluginPublicSurfaceModuleSync, } from "./facade-runtime.js"; @@ -28,50 +29,81 @@ export const _test: FacadeModule["_test"] = createLazyFacadeObjectValue( () => loadFacadeModule()._test, ); export const buildTtsSystemPromptHint: FacadeModule["buildTtsSystemPromptHint"] = - createLazyFacadeValue("buildTtsSystemPromptHint"); -export const getLastTtsAttempt: FacadeModule["getLastTtsAttempt"] = - createLazyFacadeValue("getLastTtsAttempt"); + createLazyFacadeRuntimeValue(loadFacadeModule, "buildTtsSystemPromptHint"); +export const getLastTtsAttempt: FacadeModule["getLastTtsAttempt"] = createLazyFacadeRuntimeValue( + loadFacadeModule, + "getLastTtsAttempt", +); export const getResolvedSpeechProviderConfig: FacadeModule["getResolvedSpeechProviderConfig"] = - createLazyFacadeValue("getResolvedSpeechProviderConfig"); -export const getTtsMaxLength: FacadeModule["getTtsMaxLength"] = - createLazyFacadeValue("getTtsMaxLength"); -export const getTtsProvider: FacadeModule["getTtsProvider"] = - createLazyFacadeValue("getTtsProvider"); + createLazyFacadeRuntimeValue(loadFacadeModule, "getResolvedSpeechProviderConfig"); +export const getTtsMaxLength: FacadeModule["getTtsMaxLength"] = createLazyFacadeRuntimeValue( + loadFacadeModule, + "getTtsMaxLength", +); +export const getTtsProvider: FacadeModule["getTtsProvider"] = createLazyFacadeRuntimeValue( + loadFacadeModule, + "getTtsProvider", +); export const isSummarizationEnabled: FacadeModule["isSummarizationEnabled"] = - createLazyFacadeValue("isSummarizationEnabled"); -export const isTtsEnabled: FacadeModule["isTtsEnabled"] = createLazyFacadeValue("isTtsEnabled"); + createLazyFacadeRuntimeValue(loadFacadeModule, "isSummarizationEnabled"); +export const isTtsEnabled: FacadeModule["isTtsEnabled"] = createLazyFacadeRuntimeValue( + loadFacadeModule, + "isTtsEnabled", +); export const isTtsProviderConfigured: FacadeModule["isTtsProviderConfigured"] = - createLazyFacadeValue("isTtsProviderConfigured"); -export const listSpeechVoices: FacadeModule["listSpeechVoices"] = - createLazyFacadeValue("listSpeechVoices"); + createLazyFacadeRuntimeValue(loadFacadeModule, "isTtsProviderConfigured"); +export const listSpeechVoices: FacadeModule["listSpeechVoices"] = createLazyFacadeRuntimeValue( + loadFacadeModule, + "listSpeechVoices", +); export const maybeApplyTtsToPayload: FacadeModule["maybeApplyTtsToPayload"] = - createLazyFacadeValue("maybeApplyTtsToPayload"); + createLazyFacadeRuntimeValue(loadFacadeModule, "maybeApplyTtsToPayload"); export const resolveExplicitTtsOverrides: FacadeModule["resolveExplicitTtsOverrides"] = - createLazyFacadeValue("resolveExplicitTtsOverrides"); -export const resolveTtsAutoMode: FacadeModule["resolveTtsAutoMode"] = - createLazyFacadeValue("resolveTtsAutoMode"); -export const resolveTtsConfig: FacadeModule["resolveTtsConfig"] = - createLazyFacadeValue("resolveTtsConfig"); + createLazyFacadeRuntimeValue(loadFacadeModule, "resolveExplicitTtsOverrides"); +export const resolveTtsAutoMode: FacadeModule["resolveTtsAutoMode"] = createLazyFacadeRuntimeValue( + loadFacadeModule, + "resolveTtsAutoMode", +); +export const resolveTtsConfig: FacadeModule["resolveTtsConfig"] = createLazyFacadeRuntimeValue( + loadFacadeModule, + "resolveTtsConfig", +); export const resolveTtsPrefsPath: FacadeModule["resolveTtsPrefsPath"] = - createLazyFacadeValue("resolveTtsPrefsPath"); + createLazyFacadeRuntimeValue(loadFacadeModule, "resolveTtsPrefsPath"); export const resolveTtsProviderOrder: FacadeModule["resolveTtsProviderOrder"] = - createLazyFacadeValue("resolveTtsProviderOrder"); -export const setLastTtsAttempt: FacadeModule["setLastTtsAttempt"] = - createLazyFacadeValue("setLastTtsAttempt"); + createLazyFacadeRuntimeValue(loadFacadeModule, "resolveTtsProviderOrder"); +export const setLastTtsAttempt: FacadeModule["setLastTtsAttempt"] = createLazyFacadeRuntimeValue( + loadFacadeModule, + "setLastTtsAttempt", +); export const setSummarizationEnabled: FacadeModule["setSummarizationEnabled"] = - createLazyFacadeValue("setSummarizationEnabled"); -export const setTtsAutoMode: FacadeModule["setTtsAutoMode"] = - createLazyFacadeValue("setTtsAutoMode"); -export const setTtsEnabled: FacadeModule["setTtsEnabled"] = createLazyFacadeValue("setTtsEnabled"); -export const setTtsMaxLength: FacadeModule["setTtsMaxLength"] = - createLazyFacadeValue("setTtsMaxLength"); -export const setTtsProvider: FacadeModule["setTtsProvider"] = - createLazyFacadeValue("setTtsProvider"); -export const synthesizeSpeech: FacadeModule["synthesizeSpeech"] = - createLazyFacadeValue("synthesizeSpeech"); -export const textToSpeech: FacadeModule["textToSpeech"] = createLazyFacadeValue("textToSpeech"); + createLazyFacadeRuntimeValue(loadFacadeModule, "setSummarizationEnabled"); +export const setTtsAutoMode: FacadeModule["setTtsAutoMode"] = createLazyFacadeRuntimeValue( + loadFacadeModule, + "setTtsAutoMode", +); +export const setTtsEnabled: FacadeModule["setTtsEnabled"] = createLazyFacadeRuntimeValue( + loadFacadeModule, + "setTtsEnabled", +); +export const setTtsMaxLength: FacadeModule["setTtsMaxLength"] = createLazyFacadeRuntimeValue( + loadFacadeModule, + "setTtsMaxLength", +); +export const setTtsProvider: FacadeModule["setTtsProvider"] = createLazyFacadeRuntimeValue( + loadFacadeModule, + "setTtsProvider", +); +export const synthesizeSpeech: FacadeModule["synthesizeSpeech"] = createLazyFacadeRuntimeValue( + loadFacadeModule, + "synthesizeSpeech", +); +export const textToSpeech: FacadeModule["textToSpeech"] = createLazyFacadeRuntimeValue( + loadFacadeModule, + "textToSpeech", +); export const textToSpeechTelephony: FacadeModule["textToSpeechTelephony"] = - createLazyFacadeValue("textToSpeechTelephony"); + createLazyFacadeRuntimeValue(loadFacadeModule, "textToSpeechTelephony"); export type { ResolvedTtsConfig, @@ -82,13 +114,3 @@ export type { TtsSynthesisResult, TtsTelephonyResult, } from "./tts-runtime.types.js"; - -function createLazyFacadeValue(key: K): FacadeModule[K] { - return ((...args: unknown[]) => { - const value = loadFacadeModule()[key]; - if (typeof value !== "function") { - return value; - } - return (value as (...innerArgs: unknown[]) => unknown)(...args); - }) as FacadeModule[K]; -}