mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-10 23:36:09 +00:00
Allow explicitly enabled installed plugins to register declared trusted tool policies and agent tool result middleware, with trusted policy ids scoped by plugin owner.\n\nVerification covered targeted plugin/agent tests, typecheck, build, lint, local autoreview, and a Blacksmith Testbox runtime proof (tbx_01ktr1nq0rhq47fjkwrepm7fd3).
213 lines
7.0 KiB
TypeScript
213 lines
7.0 KiB
TypeScript
// Loads agent tool result middleware from plugin runtime surfaces.
|
|
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
|
import { createSubsystemLogger } from "../logging/subsystem.js";
|
|
import { getLoadedRuntimePluginRegistry } from "./active-runtime-registry.js";
|
|
import type {
|
|
AgentToolResultMiddleware,
|
|
AgentToolResultMiddlewareRuntime,
|
|
} from "./agent-tool-result-middleware-types.js";
|
|
import {
|
|
listAgentToolResultMiddlewares,
|
|
normalizeAgentToolResultMiddlewareRuntimeIds,
|
|
} from "./agent-tool-result-middleware.js";
|
|
import {
|
|
createPluginActivationSource,
|
|
normalizePluginsConfig,
|
|
resolveEffectivePluginActivationState,
|
|
type NormalizedPluginsConfig,
|
|
type PluginActivationConfigSource,
|
|
} from "./config-state.js";
|
|
import { isPluginEnabledByDefaultForPlatform } from "./default-enablement.js";
|
|
import { loadOpenClawPlugins } from "./loader.js";
|
|
import {
|
|
loadPluginManifestRegistry,
|
|
type PluginManifestRecord,
|
|
type PluginManifestRegistry,
|
|
} from "./manifest-registry.js";
|
|
import type { PluginRegistry } from "./registry-types.js";
|
|
import { getActivePluginRegistry } from "./runtime.js";
|
|
|
|
const log = createSubsystemLogger("plugins/agent-tool-result-middleware");
|
|
|
|
async function resolveRuntimeConfigContext(): Promise<{
|
|
config: OpenClawConfig;
|
|
activationSourceConfig: OpenClawConfig;
|
|
}> {
|
|
const { getRuntimeConfig, getRuntimeConfigSourceSnapshot } = await import("../config/config.js");
|
|
const config = getRuntimeConfig();
|
|
return {
|
|
config,
|
|
activationSourceConfig: getRuntimeConfigSourceSnapshot() ?? config,
|
|
};
|
|
}
|
|
|
|
function listMiddlewareOwnerPluginIds(params: {
|
|
manifestRegistry: PluginManifestRegistry;
|
|
runtime: AgentToolResultMiddlewareRuntime;
|
|
config: OpenClawConfig;
|
|
pluginsConfig: NormalizedPluginsConfig;
|
|
activationSource: PluginActivationConfigSource;
|
|
}): string[] {
|
|
const pluginIds: string[] = [];
|
|
for (const record of params.manifestRegistry.plugins) {
|
|
if (
|
|
!canLazyLoadMiddlewareOwner({
|
|
record,
|
|
config: params.config,
|
|
pluginsConfig: params.pluginsConfig,
|
|
activationSource: params.activationSource,
|
|
})
|
|
) {
|
|
continue;
|
|
}
|
|
const runtimes = normalizeAgentToolResultMiddlewareRuntimeIds(
|
|
record.contracts?.agentToolResultMiddleware,
|
|
);
|
|
if (runtimes.includes(params.runtime) && !pluginIds.includes(record.id)) {
|
|
pluginIds.push(record.id);
|
|
}
|
|
}
|
|
return pluginIds;
|
|
}
|
|
|
|
function canLazyLoadMiddlewareOwner(params: {
|
|
record: PluginManifestRecord;
|
|
config: OpenClawConfig;
|
|
pluginsConfig: NormalizedPluginsConfig;
|
|
activationSource: PluginActivationConfigSource;
|
|
}): boolean {
|
|
if (params.record.origin === "bundled") {
|
|
return true;
|
|
}
|
|
const activationState = resolveEffectivePluginActivationState({
|
|
id: params.record.id,
|
|
origin: params.record.origin,
|
|
config: params.pluginsConfig,
|
|
rootConfig: params.config,
|
|
enabledByDefault: isPluginEnabledByDefaultForPlatform(params.record),
|
|
activationSource: params.activationSource,
|
|
});
|
|
return activationState.enabled && activationState.explicitlyEnabled;
|
|
}
|
|
|
|
function listRuntimeMiddlewareOwnerPluginIds(
|
|
registry: PluginRegistry | null | undefined,
|
|
runtime: AgentToolResultMiddlewareRuntime,
|
|
): Set<string> {
|
|
const pluginIds = new Set<string>();
|
|
for (const entry of registry?.agentToolResultMiddlewares ?? []) {
|
|
if (entry.runtimes.includes(runtime)) {
|
|
pluginIds.add(entry.pluginId);
|
|
}
|
|
}
|
|
return pluginIds;
|
|
}
|
|
|
|
function listActiveMiddlewareOwnerPluginIds(
|
|
runtime: AgentToolResultMiddlewareRuntime,
|
|
): Set<string> {
|
|
return listRuntimeMiddlewareOwnerPluginIds(getActivePluginRegistry(), runtime);
|
|
}
|
|
|
|
function registryHasMiddlewareOwners(params: {
|
|
registry: PluginRegistry | undefined;
|
|
pluginIds: readonly string[];
|
|
runtime: AgentToolResultMiddlewareRuntime;
|
|
}): boolean {
|
|
if (!params.registry) {
|
|
return false;
|
|
}
|
|
const ownerPluginIds = listRuntimeMiddlewareOwnerPluginIds(params.registry, params.runtime);
|
|
return params.pluginIds.every((pluginId) => ownerPluginIds.has(pluginId));
|
|
}
|
|
|
|
export async function loadAgentToolResultMiddlewaresForRuntime(params: {
|
|
runtime: AgentToolResultMiddlewareRuntime;
|
|
config?: OpenClawConfig;
|
|
activationSourceConfig?: OpenClawConfig;
|
|
workspaceDir?: string;
|
|
env?: NodeJS.ProcessEnv;
|
|
manifestRegistry?: PluginManifestRegistry;
|
|
}): Promise<AgentToolResultMiddleware[]> {
|
|
const activeHandlers = listAgentToolResultMiddlewares(params.runtime);
|
|
|
|
try {
|
|
const runtimeContext = params.config
|
|
? { config: params.config, activationSourceConfig: params.config }
|
|
: await resolveRuntimeConfigContext();
|
|
const config = runtimeContext.config;
|
|
const activationSourceConfig =
|
|
params.activationSourceConfig ?? runtimeContext.activationSourceConfig;
|
|
const env = params.env ?? process.env;
|
|
const manifestRegistry =
|
|
params.manifestRegistry ??
|
|
loadPluginManifestRegistry({
|
|
config,
|
|
workspaceDir: params.workspaceDir,
|
|
env,
|
|
});
|
|
const pluginsConfig = normalizePluginsConfig(config.plugins);
|
|
const activationSourcePlugins = normalizePluginsConfig(activationSourceConfig.plugins);
|
|
const activationSource = createPluginActivationSource({
|
|
config: activationSourceConfig,
|
|
plugins: activationSourcePlugins,
|
|
});
|
|
const pluginIds = listMiddlewareOwnerPluginIds({
|
|
manifestRegistry,
|
|
runtime: params.runtime,
|
|
config,
|
|
pluginsConfig,
|
|
activationSource,
|
|
});
|
|
if (pluginIds.length === 0) {
|
|
return activeHandlers;
|
|
}
|
|
const activePluginIds = listActiveMiddlewareOwnerPluginIds(params.runtime);
|
|
const missingPluginIds = pluginIds.filter((pluginId) => !activePluginIds.has(pluginId));
|
|
if (missingPluginIds.length === 0) {
|
|
return activeHandlers;
|
|
}
|
|
const missingPluginIdSet = new Set(missingPluginIds);
|
|
|
|
const loadedRegistry = getLoadedRuntimePluginRegistry({
|
|
workspaceDir: params.workspaceDir,
|
|
env,
|
|
requiredPluginIds: missingPluginIds,
|
|
});
|
|
const runtimeRegistry =
|
|
loadedRegistry &&
|
|
registryHasMiddlewareOwners({
|
|
registry: loadedRegistry,
|
|
pluginIds: missingPluginIds,
|
|
runtime: params.runtime,
|
|
})
|
|
? loadedRegistry
|
|
: loadOpenClawPlugins({
|
|
config,
|
|
workspaceDir: params.workspaceDir,
|
|
env,
|
|
onlyPluginIds: missingPluginIds,
|
|
manifestRegistry,
|
|
activate: false,
|
|
forceFullRuntimeForChannelPlugins: true,
|
|
});
|
|
|
|
const missingHandlers = runtimeRegistry.agentToolResultMiddlewares
|
|
.filter(
|
|
(entry) =>
|
|
missingPluginIdSet.has(entry.pluginId) && entry.runtimes.includes(params.runtime),
|
|
)
|
|
.map((entry) => entry.handler);
|
|
return [...activeHandlers, ...missingHandlers];
|
|
} catch (error) {
|
|
const detail = error instanceof Error ? error.message : String(error);
|
|
log.warn(`[${params.runtime}] failed to load tool result middleware plugins: ${detail}`);
|
|
return listAgentToolResultMiddlewares(params.runtime);
|
|
}
|
|
}
|
|
|
|
export const testing = {
|
|
listMiddlewareOwnerPluginIds,
|
|
};
|
|
export { testing as __testing };
|