From a254fdaf4212a43b3d48d56913623199a527f8ea Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 2 May 2026 13:00:42 +0100 Subject: [PATCH] refactor: isolate plugin tool factory execution --- src/plugins/tools.ts | 150 +++++++++++++++++++++++++++++-------------- 1 file changed, 102 insertions(+), 48 deletions(-) diff --git a/src/plugins/tools.ts b/src/plugins/tools.ts index cd0d3bef244..316e6f80c70 100644 --- a/src/plugins/tools.ts +++ b/src/plugins/tools.ts @@ -8,6 +8,7 @@ import { loadManifestContractSnapshot, } from "./manifest-contract-eligibility.js"; import { hasManifestToolAvailability } from "./manifest-tool-availability.js"; +import type { PluginToolRegistration } from "./registry-types.js"; import { getActivePluginChannelRegistry, getActivePluginRegistry, @@ -148,6 +149,99 @@ function describePluginToolFactoryResult( return { result: "single", resultCount: 1 }; } +function createPluginToolFactoryTiming(params: { + pluginId: string; + names: string[]; + durationMs: number; + elapsedMs: number; + resolved: PluginToolFactoryResult; + failed: boolean; + optional: boolean; +}): PluginToolFactoryTiming { + const result = describePluginToolFactoryResult(params.resolved, params.failed); + return { + pluginId: params.pluginId, + names: params.names, + durationMs: params.durationMs, + elapsedMs: params.elapsedMs, + result: result.result, + resultCount: result.resultCount, + optional: params.optional, + }; +} + +function resolvePluginToolFactoryEntry(params: { + entry: PluginToolRegistration; + ctx: OpenClawPluginToolContext; + declaredNames: string[]; + currentRuntimeConfig: PluginLoadOptions["config"] | null | undefined; + factoryTimingStartedAt: number; + logError: (message: string) => void; +}): { + resolved: PluginToolFactoryResult; + failed: boolean; + timing: PluginToolFactoryTiming; +} { + let resolved: PluginToolFactoryResult = null; + let failed = false; + const factoryStartedAt = Date.now(); + const factoryCacheKey = buildPluginToolFactoryCacheKey({ + ctx: params.ctx, + currentRuntimeConfig: params.currentRuntimeConfig, + }); + const cached = readCachedPluginToolFactoryResult({ + factory: params.entry.factory, + cacheKey: factoryCacheKey, + }); + + if (cached.hit) { + resolved = cached.result; + return { + resolved, + failed: false, + timing: createPluginToolFactoryTiming({ + pluginId: params.entry.pluginId, + names: params.declaredNames, + durationMs: 0, + elapsedMs: toElapsedMs(Date.now() - params.factoryTimingStartedAt), + resolved, + failed: false, + optional: params.entry.optional, + }), + }; + } + + try { + resolved = params.entry.factory(params.ctx); + } catch (err) { + failed = true; + params.logError(`plugin tool failed (${params.entry.pluginId}): ${String(err)}`); + } finally { + if (!failed) { + writeCachedPluginToolFactoryResult({ + factory: params.entry.factory, + cacheKey: factoryCacheKey, + result: resolved, + }); + } + } + + const factoryEndedAt = Date.now(); + return { + resolved, + failed, + timing: createPluginToolFactoryTiming({ + pluginId: params.entry.pluginId, + names: params.declaredNames, + durationMs: toElapsedMs(factoryEndedAt - factoryStartedAt), + elapsedMs: toElapsedMs(factoryEndedAt - params.factoryTimingStartedAt), + resolved, + failed, + optional: params.entry.optional, + }), + }; +} + function formatPluginToolFactoryTiming(timing: PluginToolFactoryTiming): string { const names = timing.names.length > 0 ? timing.names.join("|") : "-"; return [ @@ -445,59 +539,19 @@ export function resolvePluginTools(params: { ) { continue; } - let resolved: PluginToolFactoryResult = null; - let factoryFailed = false; - const factoryStartedAt = Date.now(); - const factoryCacheKey = buildPluginToolFactoryCacheKey({ + const factoryResult = resolvePluginToolFactoryEntry({ + entry, ctx: params.context, + declaredNames, currentRuntimeConfig: currentRuntimeConfigForFactoryCache, + factoryTimingStartedAt, + logError: (message) => context.logger.error(message), }); - const cached = readCachedPluginToolFactoryResult({ - factory: entry.factory, - cacheKey: factoryCacheKey, - }); - if (cached.hit) { - resolved = cached.result; - const result = describePluginToolFactoryResult(resolved, false); - factoryTimings.push({ - pluginId: entry.pluginId, - names: declaredNames, - durationMs: 0, - elapsedMs: toElapsedMs(Date.now() - factoryTimingStartedAt), - result: result.result, - resultCount: result.resultCount, - optional: entry.optional, - }); - } else { - try { - resolved = entry.factory(params.context); - } catch (err) { - factoryFailed = true; - context.logger.error(`plugin tool failed (${entry.pluginId}): ${String(err)}`); - } finally { - const factoryEndedAt = Date.now(); - const result = describePluginToolFactoryResult(resolved, factoryFailed); - factoryTimings.push({ - pluginId: entry.pluginId, - names: declaredNames, - durationMs: toElapsedMs(factoryEndedAt - factoryStartedAt), - elapsedMs: toElapsedMs(factoryEndedAt - factoryTimingStartedAt), - result: result.result, - resultCount: result.resultCount, - optional: entry.optional, - }); - if (!factoryFailed) { - writeCachedPluginToolFactoryResult({ - factory: entry.factory, - cacheKey: factoryCacheKey, - result: resolved, - }); - } - } - } - if (factoryFailed) { + factoryTimings.push(factoryResult.timing); + if (factoryResult.failed) { continue; } + const { resolved } = factoryResult; if (!resolved) { if (declaredNames.length > 0) { context.logger.debug?.(