mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-12 09:41:11 +00:00
refactor: share plugin runtime load context
This commit is contained in:
@@ -142,7 +142,7 @@ describe("ensurePluginRegistryLoaded", () => {
|
||||
expect(mocks.loadOpenClawPlugins).toHaveBeenCalledTimes(2);
|
||||
expect(mocks.loadOpenClawPlugins).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
expect.objectContaining({ onlyPluginIds: [], throwOnLoadError: true }),
|
||||
expect.objectContaining({ throwOnLoadError: true }),
|
||||
);
|
||||
expect(mocks.loadOpenClawPlugins).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent-scope.js";
|
||||
import { collectUniqueCommandDescriptors } from "../cli/program/command-descriptor-utils.js";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { loadConfig } from "../config/config.js";
|
||||
import { applyPluginAutoEnable } from "../config/plugin-auto-enable.js";
|
||||
import { createSubsystemLogger } from "../logging/subsystem.js";
|
||||
import type { PluginLoadOptions } from "./loader.js";
|
||||
import { loadOpenClawPluginCliRegistry, loadOpenClawPlugins } from "./loader.js";
|
||||
import type { PluginRegistry } from "./registry.js";
|
||||
import {
|
||||
buildPluginRuntimeLoadOptions,
|
||||
createPluginRuntimeLoaderLogger,
|
||||
resolvePluginRuntimeLoadContext,
|
||||
type PluginRuntimeLoadContext,
|
||||
} from "./runtime/load-context.js";
|
||||
import type {
|
||||
OpenClawPluginCliCommandDescriptor,
|
||||
OpenClawPluginCliContext,
|
||||
PluginLogger,
|
||||
} from "./types.js";
|
||||
|
||||
const log = createSubsystemLogger("plugins");
|
||||
|
||||
export type PluginCliLoaderOptions = Pick<PluginLoadOptions, "pluginSdkResolution">;
|
||||
|
||||
export type PluginCliPublicLoadParams = {
|
||||
@@ -24,13 +24,7 @@ export type PluginCliPublicLoadParams = {
|
||||
logger?: PluginLogger;
|
||||
};
|
||||
|
||||
export type PluginCliLoadContext = {
|
||||
rawConfig: OpenClawConfig;
|
||||
config: OpenClawConfig;
|
||||
autoEnabledReasons: Readonly<Record<string, string[]>>;
|
||||
workspaceDir: string | undefined;
|
||||
logger: PluginLogger;
|
||||
};
|
||||
export type PluginCliLoadContext = PluginRuntimeLoadContext;
|
||||
|
||||
export type PluginCliRegistryLoadResult = PluginCliLoadContext & {
|
||||
registry: PluginRegistry;
|
||||
@@ -44,12 +38,7 @@ export type PluginCliCommandGroupEntry = {
|
||||
};
|
||||
|
||||
export function createPluginCliLogger(): PluginLogger {
|
||||
return {
|
||||
info: (message: string) => log.info(message),
|
||||
warn: (message: string) => log.warn(message),
|
||||
error: (message: string) => log.error(message),
|
||||
debug: (message: string) => log.debug(message),
|
||||
};
|
||||
return createPluginRuntimeLoaderLogger();
|
||||
}
|
||||
|
||||
function resolvePluginCliLogger(logger?: PluginLogger): PluginLogger {
|
||||
@@ -80,18 +69,9 @@ function mergeCliRegistrars(params: {
|
||||
|
||||
function buildPluginCliLoaderParams(
|
||||
context: PluginCliLoadContext,
|
||||
env?: NodeJS.ProcessEnv,
|
||||
loaderOptions?: PluginCliLoaderOptions,
|
||||
) {
|
||||
return {
|
||||
config: context.config,
|
||||
activationSourceConfig: context.rawConfig,
|
||||
autoEnabledReasons: context.autoEnabledReasons,
|
||||
workspaceDir: context.workspaceDir,
|
||||
env,
|
||||
logger: context.logger,
|
||||
...loaderOptions,
|
||||
};
|
||||
return buildPluginRuntimeLoadOptions(context, loaderOptions);
|
||||
}
|
||||
|
||||
export function resolvePluginCliLoadContext(params: {
|
||||
@@ -99,40 +79,32 @@ export function resolvePluginCliLoadContext(params: {
|
||||
env?: NodeJS.ProcessEnv;
|
||||
logger: PluginLogger;
|
||||
}): PluginCliLoadContext {
|
||||
const rawConfig = params.cfg ?? loadConfig();
|
||||
const autoEnabled = applyPluginAutoEnable({ config: rawConfig, env: params.env ?? process.env });
|
||||
const config = autoEnabled.config;
|
||||
const workspaceDir = resolveAgentWorkspaceDir(config, resolveDefaultAgentId(config));
|
||||
return {
|
||||
rawConfig,
|
||||
config,
|
||||
autoEnabledReasons: autoEnabled.autoEnabledReasons,
|
||||
workspaceDir,
|
||||
return resolvePluginRuntimeLoadContext({
|
||||
config: params.cfg,
|
||||
env: params.env,
|
||||
logger: params.logger,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export async function loadPluginCliMetadataRegistryWithContext(
|
||||
context: PluginCliLoadContext,
|
||||
env?: NodeJS.ProcessEnv,
|
||||
loaderOptions?: PluginCliLoaderOptions,
|
||||
): Promise<PluginCliRegistryLoadResult> {
|
||||
return {
|
||||
...context,
|
||||
registry: await loadOpenClawPluginCliRegistry(
|
||||
buildPluginCliLoaderParams(context, env, loaderOptions),
|
||||
buildPluginCliLoaderParams(context, loaderOptions),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
export async function loadPluginCliCommandRegistryWithContext(params: {
|
||||
context: PluginCliLoadContext;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
loaderOptions?: PluginCliLoaderOptions;
|
||||
onMetadataFallbackError: (error: unknown) => void;
|
||||
}): Promise<PluginCliRegistryLoadResult> {
|
||||
const runtimeRegistry = loadOpenClawPlugins(
|
||||
buildPluginCliLoaderParams(params.context, params.env, params.loaderOptions),
|
||||
buildPluginCliLoaderParams(params.context, params.loaderOptions),
|
||||
);
|
||||
|
||||
if (!hasIgnoredAsyncPluginRegistration(runtimeRegistry)) {
|
||||
@@ -144,7 +116,7 @@ export async function loadPluginCliCommandRegistryWithContext(params: {
|
||||
|
||||
try {
|
||||
const metadataRegistry = await loadOpenClawPluginCliRegistry(
|
||||
buildPluginCliLoaderParams(params.context, params.env, params.loaderOptions),
|
||||
buildPluginCliLoaderParams(params.context, params.loaderOptions),
|
||||
);
|
||||
return {
|
||||
...params.context,
|
||||
@@ -202,7 +174,6 @@ export async function loadPluginCliDescriptors(
|
||||
});
|
||||
const { registry } = await loadPluginCliMetadataRegistryWithContext(
|
||||
context,
|
||||
params.env,
|
||||
params.loaderOptions,
|
||||
);
|
||||
return collectUniqueCommandDescriptors(
|
||||
@@ -228,7 +199,6 @@ export async function loadPluginCliRegistrationEntries(params: {
|
||||
});
|
||||
const { config, workspaceDir, logger, registry } = await loadPluginCliCommandRegistryWithContext({
|
||||
context,
|
||||
env: params.env,
|
||||
loaderOptions: params.loaderOptions,
|
||||
onMetadataFallbackError: params.onMetadataFallbackError,
|
||||
});
|
||||
|
||||
@@ -3,11 +3,18 @@ import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
const resolveRuntimePluginRegistryMock = vi.fn();
|
||||
const applyPluginAutoEnableMock = vi.fn();
|
||||
const getMemoryRuntimeMock = vi.fn();
|
||||
const resolveAgentWorkspaceDirMock = vi.fn();
|
||||
const resolveDefaultAgentIdMock = vi.fn(() => "default");
|
||||
|
||||
vi.mock("../config/plugin-auto-enable.js", () => ({
|
||||
applyPluginAutoEnable: (...args: unknown[]) => applyPluginAutoEnableMock(...args),
|
||||
}));
|
||||
|
||||
vi.mock("../agents/agent-scope.js", () => ({
|
||||
resolveAgentWorkspaceDir: (...args: unknown[]) => resolveAgentWorkspaceDirMock(...args),
|
||||
resolveDefaultAgentId: (...args: unknown[]) => resolveDefaultAgentIdMock(...args),
|
||||
}));
|
||||
|
||||
vi.mock("./loader.js", () => ({
|
||||
resolveRuntimePluginRegistry: (...args: unknown[]) => resolveRuntimePluginRegistryMock(...args),
|
||||
}));
|
||||
@@ -116,11 +123,14 @@ describe("memory runtime auto-enable loading", () => {
|
||||
resolveRuntimePluginRegistryMock.mockReset();
|
||||
applyPluginAutoEnableMock.mockReset();
|
||||
getMemoryRuntimeMock.mockReset();
|
||||
resolveAgentWorkspaceDirMock.mockReset();
|
||||
resolveDefaultAgentIdMock.mockClear();
|
||||
applyPluginAutoEnableMock.mockImplementation((params: { config: unknown }) => ({
|
||||
config: params.config,
|
||||
changes: [],
|
||||
autoEnabledReasons: {},
|
||||
}));
|
||||
resolveAgentWorkspaceDirMock.mockReturnValue(undefined);
|
||||
});
|
||||
|
||||
it.each([
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { applyPluginAutoEnable } from "../config/plugin-auto-enable.js";
|
||||
import { resolveRuntimePluginRegistry } from "./loader.js";
|
||||
import { getMemoryRuntime } from "./memory-state.js";
|
||||
import {
|
||||
buildPluginRuntimeLoadOptions,
|
||||
resolvePluginRuntimeLoadContext,
|
||||
} from "./runtime/load-context.js";
|
||||
|
||||
function ensureMemoryRuntime(cfg?: OpenClawConfig) {
|
||||
const current = getMemoryRuntime();
|
||||
if (current || !cfg) {
|
||||
return current;
|
||||
}
|
||||
const autoEnabled = applyPluginAutoEnable({ config: cfg, env: process.env });
|
||||
resolveRuntimePluginRegistry({
|
||||
config: autoEnabled.config,
|
||||
activationSourceConfig: cfg,
|
||||
autoEnabledReasons: autoEnabled.autoEnabledReasons,
|
||||
});
|
||||
resolveRuntimePluginRegistry(
|
||||
buildPluginRuntimeLoadOptions(resolvePluginRuntimeLoadContext({ config: cfg })),
|
||||
);
|
||||
return getMemoryRuntime();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { createSubsystemLogger } from "../logging/subsystem.js";
|
||||
import { withActivatedPluginIds } from "./activation-context.js";
|
||||
import { resolveBundledPluginCompatibleActivationInputs } from "./activation-context.js";
|
||||
import {
|
||||
@@ -6,7 +5,6 @@ import {
|
||||
resolveRuntimePluginRegistry,
|
||||
type PluginLoadOptions,
|
||||
} from "./loader.js";
|
||||
import { createPluginLoaderLogger } from "./logger.js";
|
||||
import {
|
||||
resolveDiscoveredProviderPluginIds,
|
||||
resolveEnabledProviderPluginIds,
|
||||
@@ -16,9 +14,12 @@ import {
|
||||
withBundledProviderVitestCompat,
|
||||
} from "./providers.js";
|
||||
import { getActivePluginRegistryWorkspaceDir } from "./runtime.js";
|
||||
import {
|
||||
buildPluginRuntimeLoadOptionsFromValues,
|
||||
createPluginRuntimeLoaderLogger,
|
||||
} from "./runtime/load-context.js";
|
||||
import type { ProviderPlugin } from "./types.js";
|
||||
|
||||
const log = createSubsystemLogger("plugins");
|
||||
export function resolvePluginProviders(params: {
|
||||
config?: PluginLoadOptions["config"];
|
||||
workspaceDir?: string;
|
||||
@@ -87,21 +88,27 @@ export function resolvePluginProviders(params: {
|
||||
if (providerPluginIds.length === 0) {
|
||||
return [];
|
||||
}
|
||||
const registry = loadOpenClawPlugins({
|
||||
config: withActivatedPluginIds({
|
||||
config: runtimeConfig,
|
||||
pluginIds: providerPluginIds,
|
||||
}),
|
||||
activationSourceConfig: runtimeConfig,
|
||||
autoEnabledReasons: {},
|
||||
workspaceDir,
|
||||
env,
|
||||
onlyPluginIds: providerPluginIds,
|
||||
pluginSdkResolution: params.pluginSdkResolution,
|
||||
cache: params.cache ?? false,
|
||||
activate: params.activate ?? false,
|
||||
logger: createPluginLoaderLogger(log),
|
||||
});
|
||||
const registry = loadOpenClawPlugins(
|
||||
buildPluginRuntimeLoadOptionsFromValues(
|
||||
{
|
||||
config: withActivatedPluginIds({
|
||||
config: runtimeConfig,
|
||||
pluginIds: providerPluginIds,
|
||||
}),
|
||||
activationSourceConfig: runtimeConfig,
|
||||
autoEnabledReasons: {},
|
||||
workspaceDir,
|
||||
env,
|
||||
logger: createPluginRuntimeLoaderLogger(),
|
||||
},
|
||||
{
|
||||
onlyPluginIds: providerPluginIds,
|
||||
pluginSdkResolution: params.pluginSdkResolution,
|
||||
cache: params.cache ?? false,
|
||||
activate: params.activate ?? false,
|
||||
},
|
||||
),
|
||||
);
|
||||
return registry.providers.map((entry) => ({
|
||||
...entry.provider,
|
||||
pluginId: entry.pluginId,
|
||||
@@ -133,18 +140,24 @@ export function resolvePluginProviders(params: {
|
||||
env,
|
||||
onlyPluginIds: requestedPluginIds,
|
||||
});
|
||||
const registry = resolveRuntimePluginRegistry({
|
||||
config,
|
||||
activationSourceConfig: activation.activationSourceConfig,
|
||||
autoEnabledReasons: activation.autoEnabledReasons,
|
||||
workspaceDir,
|
||||
env,
|
||||
onlyPluginIds: providerPluginIds,
|
||||
pluginSdkResolution: params.pluginSdkResolution,
|
||||
cache: params.cache ?? false,
|
||||
activate: params.activate ?? false,
|
||||
logger: createPluginLoaderLogger(log),
|
||||
});
|
||||
const registry = resolveRuntimePluginRegistry(
|
||||
buildPluginRuntimeLoadOptionsFromValues(
|
||||
{
|
||||
config,
|
||||
activationSourceConfig: activation.activationSourceConfig,
|
||||
autoEnabledReasons: activation.autoEnabledReasons,
|
||||
workspaceDir,
|
||||
env,
|
||||
logger: createPluginRuntimeLoaderLogger(),
|
||||
},
|
||||
{
|
||||
onlyPluginIds: providerPluginIds,
|
||||
pluginSdkResolution: params.pluginSdkResolution,
|
||||
cache: params.cache ?? false,
|
||||
activate: params.activate ?? false,
|
||||
},
|
||||
),
|
||||
);
|
||||
if (!registry) {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ function setOwningProviderManifestPlugins() {
|
||||
createManifestProviderPlugin({
|
||||
id: "openai",
|
||||
providerIds: ["openai", "openai-codex"],
|
||||
cliBackends: ["codex-cli"],
|
||||
modelSupport: {
|
||||
modelPrefixes: ["gpt-", "o1", "o3", "o4"],
|
||||
},
|
||||
@@ -87,6 +88,7 @@ function setOwningProviderManifestPluginsWithWorkspace() {
|
||||
createManifestProviderPlugin({
|
||||
id: "openai",
|
||||
providerIds: ["openai", "openai-codex"],
|
||||
cliBackends: ["codex-cli"],
|
||||
modelSupport: {
|
||||
modelPrefixes: ["gpt-", "o1", "o3", "o4"],
|
||||
},
|
||||
@@ -255,6 +257,10 @@ function expectProviderRuntimeRegistryLoad(params?: { config?: unknown; env?: No
|
||||
describe("resolvePluginProviders", () => {
|
||||
beforeAll(async () => {
|
||||
vi.resetModules();
|
||||
loadPluginManifestRegistryMock.mockReturnValue({
|
||||
plugins: [],
|
||||
diagnostics: [],
|
||||
});
|
||||
vi.doMock("./loader.js", () => ({
|
||||
loadOpenClawPlugins: (...args: Parameters<LoadOpenClawPlugins>) =>
|
||||
loadOpenClawPluginsMock(...args),
|
||||
|
||||
115
src/plugins/runtime/load-context.test.ts
Normal file
115
src/plugins/runtime/load-context.test.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const loadConfigMock = vi.fn();
|
||||
const applyPluginAutoEnableMock = vi.fn();
|
||||
const resolveAgentWorkspaceDirMock = vi.fn(() => "/resolved-workspace");
|
||||
const resolveDefaultAgentIdMock = vi.fn(() => "default");
|
||||
|
||||
let resolvePluginRuntimeLoadContext: typeof import("./load-context.js").resolvePluginRuntimeLoadContext;
|
||||
let buildPluginRuntimeLoadOptions: typeof import("./load-context.js").buildPluginRuntimeLoadOptions;
|
||||
|
||||
vi.mock("../../config/config.js", () => ({
|
||||
loadConfig: () => loadConfigMock(),
|
||||
}));
|
||||
|
||||
vi.mock("../../config/plugin-auto-enable.js", () => ({
|
||||
applyPluginAutoEnable: (...args: unknown[]) => applyPluginAutoEnableMock(...args),
|
||||
}));
|
||||
|
||||
vi.mock("../../agents/agent-scope.js", () => ({
|
||||
resolveAgentWorkspaceDir: (...args: unknown[]) => resolveAgentWorkspaceDirMock(...args),
|
||||
resolveDefaultAgentId: (...args: unknown[]) => resolveDefaultAgentIdMock(...args),
|
||||
}));
|
||||
|
||||
describe("resolvePluginRuntimeLoadContext", () => {
|
||||
beforeAll(async () => {
|
||||
({ resolvePluginRuntimeLoadContext, buildPluginRuntimeLoadOptions } =
|
||||
await import("./load-context.js"));
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
loadConfigMock.mockReset();
|
||||
applyPluginAutoEnableMock.mockReset();
|
||||
resolveAgentWorkspaceDirMock.mockClear();
|
||||
resolveDefaultAgentIdMock.mockClear();
|
||||
|
||||
loadConfigMock.mockReturnValue({ plugins: {} });
|
||||
applyPluginAutoEnableMock.mockImplementation((params: { config: unknown }) => ({
|
||||
config: params.config,
|
||||
changes: [],
|
||||
autoEnabledReasons: {},
|
||||
}));
|
||||
});
|
||||
|
||||
it("builds the runtime plugin load context from the auto-enabled config", () => {
|
||||
const rawConfig = { plugins: {} };
|
||||
const resolvedConfig = {
|
||||
plugins: {
|
||||
entries: {
|
||||
demo: { enabled: true },
|
||||
},
|
||||
},
|
||||
};
|
||||
const env = { HOME: "/tmp/openclaw-home" } as NodeJS.ProcessEnv;
|
||||
|
||||
applyPluginAutoEnableMock.mockReturnValue({
|
||||
config: resolvedConfig,
|
||||
changes: [],
|
||||
autoEnabledReasons: {
|
||||
demo: ["demo configured"],
|
||||
},
|
||||
});
|
||||
|
||||
const context = resolvePluginRuntimeLoadContext({
|
||||
config: rawConfig,
|
||||
env,
|
||||
});
|
||||
|
||||
expect(context).toEqual(
|
||||
expect.objectContaining({
|
||||
rawConfig,
|
||||
config: resolvedConfig,
|
||||
activationSourceConfig: rawConfig,
|
||||
env,
|
||||
workspaceDir: "/resolved-workspace",
|
||||
autoEnabledReasons: {
|
||||
demo: ["demo configured"],
|
||||
},
|
||||
}),
|
||||
);
|
||||
expect(applyPluginAutoEnableMock).toHaveBeenCalledWith({
|
||||
config: rawConfig,
|
||||
env,
|
||||
});
|
||||
expect(resolveDefaultAgentIdMock).toHaveBeenCalledWith(resolvedConfig);
|
||||
expect(resolveAgentWorkspaceDirMock).toHaveBeenCalledWith(resolvedConfig, "default");
|
||||
});
|
||||
|
||||
it("builds plugin load options from the shared runtime context", () => {
|
||||
const context = resolvePluginRuntimeLoadContext({
|
||||
config: { plugins: {} },
|
||||
env: { HOME: "/tmp/openclaw-home" } as NodeJS.ProcessEnv,
|
||||
workspaceDir: "/explicit-workspace",
|
||||
});
|
||||
|
||||
expect(
|
||||
buildPluginRuntimeLoadOptions(context, {
|
||||
cache: false,
|
||||
activate: false,
|
||||
onlyPluginIds: ["demo"],
|
||||
}),
|
||||
).toEqual(
|
||||
expect.objectContaining({
|
||||
config: context.config,
|
||||
activationSourceConfig: context.activationSourceConfig,
|
||||
autoEnabledReasons: context.autoEnabledReasons,
|
||||
workspaceDir: "/explicit-workspace",
|
||||
env: context.env,
|
||||
logger: context.logger,
|
||||
cache: false,
|
||||
activate: false,
|
||||
onlyPluginIds: ["demo"],
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
83
src/plugins/runtime/load-context.ts
Normal file
83
src/plugins/runtime/load-context.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../../agents/agent-scope.js";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { loadConfig } from "../../config/config.js";
|
||||
import { applyPluginAutoEnable } from "../../config/plugin-auto-enable.js";
|
||||
import { createSubsystemLogger } from "../../logging.js";
|
||||
import type { PluginLoadOptions } from "../loader.js";
|
||||
import type { PluginLogger } from "../types.js";
|
||||
|
||||
const log = createSubsystemLogger("plugins");
|
||||
|
||||
export type PluginRuntimeLoadContext = {
|
||||
rawConfig: OpenClawConfig;
|
||||
config: OpenClawConfig;
|
||||
activationSourceConfig: OpenClawConfig;
|
||||
autoEnabledReasons: Readonly<Record<string, string[]>>;
|
||||
workspaceDir: string | undefined;
|
||||
env: NodeJS.ProcessEnv;
|
||||
logger: PluginLogger;
|
||||
};
|
||||
|
||||
export type PluginRuntimeResolvedLoadValues = Pick<
|
||||
PluginLoadOptions,
|
||||
"config" | "activationSourceConfig" | "autoEnabledReasons" | "workspaceDir" | "env" | "logger"
|
||||
>;
|
||||
|
||||
export type PluginRuntimeLoadContextOptions = {
|
||||
config?: OpenClawConfig;
|
||||
activationSourceConfig?: OpenClawConfig;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
workspaceDir?: string;
|
||||
logger?: PluginLogger;
|
||||
};
|
||||
|
||||
export function createPluginRuntimeLoaderLogger(): PluginLogger {
|
||||
return {
|
||||
info: (message) => log.info(message),
|
||||
warn: (message) => log.warn(message),
|
||||
error: (message) => log.error(message),
|
||||
debug: (message) => log.debug(message),
|
||||
};
|
||||
}
|
||||
|
||||
export function resolvePluginRuntimeLoadContext(
|
||||
options?: PluginRuntimeLoadContextOptions,
|
||||
): PluginRuntimeLoadContext {
|
||||
const env = options?.env ?? process.env;
|
||||
const rawConfig = options?.config ?? loadConfig();
|
||||
const autoEnabled = applyPluginAutoEnable({ config: rawConfig, env });
|
||||
const config = autoEnabled.config;
|
||||
const workspaceDir =
|
||||
options?.workspaceDir ?? resolveAgentWorkspaceDir(config, resolveDefaultAgentId(config));
|
||||
return {
|
||||
rawConfig,
|
||||
config,
|
||||
activationSourceConfig: options?.activationSourceConfig ?? rawConfig,
|
||||
autoEnabledReasons: autoEnabled.autoEnabledReasons,
|
||||
workspaceDir,
|
||||
env,
|
||||
logger: options?.logger ?? createPluginRuntimeLoaderLogger(),
|
||||
};
|
||||
}
|
||||
|
||||
export function buildPluginRuntimeLoadOptions(
|
||||
context: PluginRuntimeLoadContext,
|
||||
overrides?: Partial<PluginLoadOptions>,
|
||||
): PluginLoadOptions {
|
||||
return buildPluginRuntimeLoadOptionsFromValues(context, overrides);
|
||||
}
|
||||
|
||||
export function buildPluginRuntimeLoadOptionsFromValues(
|
||||
values: PluginRuntimeResolvedLoadValues,
|
||||
overrides?: Partial<PluginLoadOptions>,
|
||||
): PluginLoadOptions {
|
||||
return {
|
||||
config: values.config,
|
||||
activationSourceConfig: values.activationSourceConfig,
|
||||
autoEnabledReasons: values.autoEnabledReasons,
|
||||
workspaceDir: values.workspaceDir,
|
||||
env: values.env,
|
||||
logger: values.logger,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
@@ -1,13 +1,7 @@
|
||||
import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../../agents/agent-scope.js";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { loadConfig } from "../../config/config.js";
|
||||
import { applyPluginAutoEnable } from "../../config/plugin-auto-enable.js";
|
||||
import { createSubsystemLogger } from "../../logging.js";
|
||||
import { loadOpenClawPlugins } from "../loader.js";
|
||||
import type { PluginRegistry } from "../registry.js";
|
||||
import type { PluginLogger } from "../types.js";
|
||||
|
||||
const log = createSubsystemLogger("plugins");
|
||||
import { buildPluginRuntimeLoadOptions, resolvePluginRuntimeLoadContext } from "./load-context.js";
|
||||
|
||||
export function loadPluginMetadataRegistrySnapshot(options?: {
|
||||
config?: OpenClawConfig;
|
||||
@@ -17,32 +11,16 @@ export function loadPluginMetadataRegistrySnapshot(options?: {
|
||||
onlyPluginIds?: string[];
|
||||
loadModules?: boolean;
|
||||
}): PluginRegistry {
|
||||
const env = options?.env ?? process.env;
|
||||
const baseConfig = options?.config ?? loadConfig();
|
||||
const autoEnabled = applyPluginAutoEnable({ config: baseConfig, env });
|
||||
const resolvedConfig = autoEnabled.config;
|
||||
const workspaceDir =
|
||||
options?.workspaceDir ??
|
||||
resolveAgentWorkspaceDir(resolvedConfig, resolveDefaultAgentId(resolvedConfig));
|
||||
const logger: PluginLogger = {
|
||||
info: (message) => log.info(message),
|
||||
warn: (message) => log.warn(message),
|
||||
error: (message) => log.error(message),
|
||||
debug: (message) => log.debug(message),
|
||||
};
|
||||
const context = resolvePluginRuntimeLoadContext(options);
|
||||
|
||||
return loadOpenClawPlugins({
|
||||
config: resolvedConfig,
|
||||
activationSourceConfig: options?.activationSourceConfig ?? baseConfig,
|
||||
autoEnabledReasons: autoEnabled.autoEnabledReasons,
|
||||
workspaceDir,
|
||||
env,
|
||||
logger,
|
||||
throwOnLoadError: true,
|
||||
cache: false,
|
||||
activate: false,
|
||||
mode: "validate",
|
||||
loadModules: options?.loadModules,
|
||||
...(options?.onlyPluginIds?.length ? { onlyPluginIds: options.onlyPluginIds } : {}),
|
||||
});
|
||||
return loadOpenClawPlugins(
|
||||
buildPluginRuntimeLoadOptions(context, {
|
||||
throwOnLoadError: true,
|
||||
cache: false,
|
||||
activate: false,
|
||||
mode: "validate",
|
||||
loadModules: options?.loadModules,
|
||||
...(options?.onlyPluginIds?.length ? { onlyPluginIds: options.onlyPluginIds } : {}),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
145
src/plugins/runtime/runtime-registry-loader.test.ts
Normal file
145
src/plugins/runtime/runtime-registry-loader.test.ts
Normal file
@@ -0,0 +1,145 @@
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const loadOpenClawPluginsMock = vi.fn();
|
||||
const getActivePluginRegistryMock = vi.fn();
|
||||
const resolveConfiguredChannelPluginIdsMock = vi.fn();
|
||||
const resolveChannelPluginIdsMock = vi.fn();
|
||||
const applyPluginAutoEnableMock = vi.fn();
|
||||
const resolveAgentWorkspaceDirMock = vi.fn(() => "/resolved-workspace");
|
||||
const resolveDefaultAgentIdMock = vi.fn(() => "default");
|
||||
|
||||
let ensurePluginRegistryLoaded: typeof import("./runtime-registry-loader.js").ensurePluginRegistryLoaded;
|
||||
let resetPluginRegistryLoadedForTests: typeof import("./runtime-registry-loader.js").__testing.resetPluginRegistryLoadedForTests;
|
||||
|
||||
vi.mock("../loader.js", () => ({
|
||||
loadOpenClawPlugins: (...args: unknown[]) => loadOpenClawPluginsMock(...args),
|
||||
}));
|
||||
|
||||
vi.mock("../runtime.js", () => ({
|
||||
getActivePluginRegistry: (...args: unknown[]) => getActivePluginRegistryMock(...args),
|
||||
}));
|
||||
|
||||
vi.mock("../channel-plugin-ids.js", () => ({
|
||||
resolveConfiguredChannelPluginIds: (...args: unknown[]) =>
|
||||
resolveConfiguredChannelPluginIdsMock(...args),
|
||||
resolveChannelPluginIds: (...args: unknown[]) => resolveChannelPluginIdsMock(...args),
|
||||
}));
|
||||
|
||||
vi.mock("../../config/plugin-auto-enable.js", () => ({
|
||||
applyPluginAutoEnable: (...args: unknown[]) => applyPluginAutoEnableMock(...args),
|
||||
}));
|
||||
|
||||
vi.mock("../../agents/agent-scope.js", () => ({
|
||||
resolveAgentWorkspaceDir: (...args: unknown[]) => resolveAgentWorkspaceDirMock(...args),
|
||||
resolveDefaultAgentId: (...args: unknown[]) => resolveDefaultAgentIdMock(...args),
|
||||
}));
|
||||
|
||||
describe("ensurePluginRegistryLoaded", () => {
|
||||
beforeAll(async () => {
|
||||
const mod = await import("./runtime-registry-loader.js");
|
||||
ensurePluginRegistryLoaded = mod.ensurePluginRegistryLoaded;
|
||||
resetPluginRegistryLoadedForTests = () => mod.__testing.resetPluginRegistryLoadedForTests();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
loadOpenClawPluginsMock.mockReset();
|
||||
getActivePluginRegistryMock.mockReset();
|
||||
resolveConfiguredChannelPluginIdsMock.mockReset();
|
||||
resolveChannelPluginIdsMock.mockReset();
|
||||
applyPluginAutoEnableMock.mockReset();
|
||||
resolveAgentWorkspaceDirMock.mockClear();
|
||||
resolveDefaultAgentIdMock.mockClear();
|
||||
resetPluginRegistryLoadedForTests();
|
||||
|
||||
getActivePluginRegistryMock.mockReturnValue({
|
||||
plugins: [],
|
||||
channels: [],
|
||||
tools: [],
|
||||
});
|
||||
applyPluginAutoEnableMock.mockImplementation((params: { config: unknown }) => ({
|
||||
config:
|
||||
params.config && typeof params.config === "object"
|
||||
? {
|
||||
...params.config,
|
||||
plugins: {
|
||||
entries: {
|
||||
demo: { enabled: true },
|
||||
},
|
||||
},
|
||||
}
|
||||
: params.config,
|
||||
changes: [],
|
||||
autoEnabledReasons: {
|
||||
demo: ["demo configured"],
|
||||
},
|
||||
}));
|
||||
});
|
||||
|
||||
it("uses the shared runtime load context for configured-channel loads", () => {
|
||||
const rawConfig = { channels: { demo: { enabled: true } } };
|
||||
const resolvedConfig = {
|
||||
...rawConfig,
|
||||
plugins: {
|
||||
entries: {
|
||||
demo: { enabled: true },
|
||||
},
|
||||
},
|
||||
};
|
||||
const env = { HOME: "/tmp/openclaw-home" } as NodeJS.ProcessEnv;
|
||||
|
||||
resolveConfiguredChannelPluginIdsMock.mockReturnValue(["demo-channel"]);
|
||||
ensurePluginRegistryLoaded({
|
||||
scope: "configured-channels",
|
||||
config: rawConfig as never,
|
||||
env,
|
||||
activationSourceConfig: { plugins: { allow: ["demo-channel"] } } as never,
|
||||
});
|
||||
|
||||
expect(resolveConfiguredChannelPluginIdsMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
config: resolvedConfig,
|
||||
env,
|
||||
workspaceDir: "/resolved-workspace",
|
||||
}),
|
||||
);
|
||||
expect(applyPluginAutoEnableMock).toHaveBeenCalledWith({
|
||||
config: rawConfig,
|
||||
env,
|
||||
});
|
||||
expect(loadOpenClawPluginsMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
config: resolvedConfig,
|
||||
activationSourceConfig: { plugins: { allow: ["demo-channel"] } },
|
||||
autoEnabledReasons: {
|
||||
demo: ["demo configured"],
|
||||
},
|
||||
workspaceDir: "/resolved-workspace",
|
||||
onlyPluginIds: ["demo-channel"],
|
||||
throwOnLoadError: true,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("does not cache scoped loads by explicit plugin ids", () => {
|
||||
ensurePluginRegistryLoaded({
|
||||
scope: "configured-channels",
|
||||
config: {} as never,
|
||||
onlyPluginIds: ["demo-a"],
|
||||
});
|
||||
ensurePluginRegistryLoaded({
|
||||
scope: "configured-channels",
|
||||
config: {} as never,
|
||||
onlyPluginIds: ["demo-b"],
|
||||
});
|
||||
|
||||
expect(loadOpenClawPluginsMock).toHaveBeenCalledTimes(2);
|
||||
expect(loadOpenClawPluginsMock).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
expect.objectContaining({ onlyPluginIds: ["demo-a"] }),
|
||||
);
|
||||
expect(loadOpenClawPluginsMock).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
expect.objectContaining({ onlyPluginIds: ["demo-b"] }),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,17 +1,12 @@
|
||||
import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../../agents/agent-scope.js";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { loadConfig } from "../../config/config.js";
|
||||
import { applyPluginAutoEnable } from "../../config/plugin-auto-enable.js";
|
||||
import { createSubsystemLogger } from "../../logging.js";
|
||||
import {
|
||||
resolveChannelPluginIds,
|
||||
resolveConfiguredChannelPluginIds,
|
||||
} from "../channel-plugin-ids.js";
|
||||
import { loadOpenClawPlugins } from "../loader.js";
|
||||
import { getActivePluginRegistry } from "../runtime.js";
|
||||
import type { PluginLogger } from "../types.js";
|
||||
import { buildPluginRuntimeLoadOptions, resolvePluginRuntimeLoadContext } from "./load-context.js";
|
||||
|
||||
const log = createSubsystemLogger("plugins");
|
||||
let pluginRegistryLoaded: "none" | "configured-channels" | "channels" | "all" = "none";
|
||||
|
||||
export type PluginRegistryScope = "configured-channels" | "channels" | "all";
|
||||
@@ -71,27 +66,20 @@ export function ensurePluginRegistryLoaded(options?: {
|
||||
if (!scopedLoad && scopeRank(pluginRegistryLoaded) >= scopeRank(scope)) {
|
||||
return;
|
||||
}
|
||||
const env = options?.env ?? process.env;
|
||||
const baseConfig = options?.config ?? loadConfig();
|
||||
const autoEnabled = applyPluginAutoEnable({ config: baseConfig, env });
|
||||
const resolvedConfig = autoEnabled.config;
|
||||
const workspaceDir = resolveAgentWorkspaceDir(
|
||||
resolvedConfig,
|
||||
resolveDefaultAgentId(resolvedConfig),
|
||||
);
|
||||
const context = resolvePluginRuntimeLoadContext(options);
|
||||
const expectedChannelPluginIds = scopedLoad
|
||||
? requestedPluginIds
|
||||
: scope === "configured-channels"
|
||||
? resolveConfiguredChannelPluginIds({
|
||||
config: resolvedConfig,
|
||||
workspaceDir,
|
||||
env,
|
||||
config: context.config,
|
||||
workspaceDir: context.workspaceDir,
|
||||
env: context.env,
|
||||
})
|
||||
: scope === "channels"
|
||||
? resolveChannelPluginIds({
|
||||
config: resolvedConfig,
|
||||
workspaceDir,
|
||||
env,
|
||||
config: context.config,
|
||||
workspaceDir: context.workspaceDir,
|
||||
env: context.env,
|
||||
})
|
||||
: [];
|
||||
const active = getActivePluginRegistry();
|
||||
@@ -104,21 +92,12 @@ export function ensurePluginRegistryLoaded(options?: {
|
||||
}
|
||||
return;
|
||||
}
|
||||
const logger: PluginLogger = {
|
||||
info: (msg) => log.info(msg),
|
||||
warn: (msg) => log.warn(msg),
|
||||
error: (msg) => log.error(msg),
|
||||
debug: (msg) => log.debug(msg),
|
||||
};
|
||||
loadOpenClawPlugins({
|
||||
config: resolvedConfig,
|
||||
activationSourceConfig: options?.activationSourceConfig ?? baseConfig,
|
||||
autoEnabledReasons: autoEnabled.autoEnabledReasons,
|
||||
workspaceDir,
|
||||
logger,
|
||||
throwOnLoadError: true,
|
||||
...(expectedChannelPluginIds.length > 0 ? { onlyPluginIds: expectedChannelPluginIds } : {}),
|
||||
});
|
||||
loadOpenClawPlugins(
|
||||
buildPluginRuntimeLoadOptions(context, {
|
||||
throwOnLoadError: true,
|
||||
...(expectedChannelPluginIds.length > 0 ? { onlyPluginIds: expectedChannelPluginIds } : {}),
|
||||
}),
|
||||
);
|
||||
if (!scopedLoad) {
|
||||
pluginRegistryLoaded = scope;
|
||||
}
|
||||
|
||||
@@ -674,7 +674,7 @@ describe("plugin status reports", () => {
|
||||
expectCapabilityKinds(inspect[1], ["text-inference", "web-search"]);
|
||||
});
|
||||
|
||||
it("treats a CLI-command-only plugin as a non-capability", () => {
|
||||
it("treats a CLI-command-only plugin as a plain capability", () => {
|
||||
setSinglePluginLoadResult(
|
||||
createPluginRecord({
|
||||
id: "anthropic",
|
||||
@@ -686,9 +686,9 @@ describe("plugin status reports", () => {
|
||||
const inspect = expectInspectReport("anthropic");
|
||||
|
||||
expectInspectShape(inspect, {
|
||||
shape: "non-capability",
|
||||
capabilityMode: "none",
|
||||
capabilityKinds: [],
|
||||
shape: "plain-capability",
|
||||
capabilityMode: "plain",
|
||||
capabilityKinds: ["cli-backend"],
|
||||
});
|
||||
expect(inspect.capabilities).toEqual([{ kind: "cli-backend", ids: ["claude-cli"] }]);
|
||||
});
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent-scope.js";
|
||||
import { resolveDefaultAgentWorkspaceDir } from "../agents/workspace.js";
|
||||
import { loadConfig } from "../config/config.js";
|
||||
import { applyPluginAutoEnable } from "../config/plugin-auto-enable.js";
|
||||
import { normalizeOpenClawVersionBase } from "../config/version.js";
|
||||
import { createSubsystemLogger } from "../logging/subsystem.js";
|
||||
import { listImportedBundledPluginFacadeIds } from "../plugin-sdk/facade-runtime.js";
|
||||
import { resolveCompatibilityHostVersion } from "../version.js";
|
||||
import { inspectBundleLspRuntimeSupport } from "./bundle-lsp.js";
|
||||
@@ -14,10 +11,13 @@ import {
|
||||
} from "./bundled-compat.js";
|
||||
import { normalizePluginsConfig } from "./config-state.js";
|
||||
import { loadOpenClawPlugins } from "./loader.js";
|
||||
import { createPluginLoaderLogger } from "./logger.js";
|
||||
import { resolveBundledProviderCompatPluginIds } from "./providers.js";
|
||||
import type { PluginRegistry } from "./registry.js";
|
||||
import { listImportedRuntimePluginIds } from "./runtime.js";
|
||||
import {
|
||||
buildPluginRuntimeLoadOptions,
|
||||
resolvePluginRuntimeLoadContext,
|
||||
} from "./runtime/load-context.js";
|
||||
import { loadPluginMetadataRegistrySnapshot } from "./runtime/metadata-registry-loader.js";
|
||||
import type { PluginDiagnostic, PluginHookName } from "./types.js";
|
||||
|
||||
@@ -126,18 +126,6 @@ function buildCompatibilityNoticesForInspect(
|
||||
return warnings;
|
||||
}
|
||||
|
||||
const log = createSubsystemLogger("plugins");
|
||||
|
||||
function resolveStatusConfig(
|
||||
config: ReturnType<typeof loadConfig>,
|
||||
env: NodeJS.ProcessEnv | undefined,
|
||||
) {
|
||||
return applyPluginAutoEnable({
|
||||
config,
|
||||
env: env ?? process.env,
|
||||
});
|
||||
}
|
||||
|
||||
function resolveReportedPluginVersion(
|
||||
plugin: PluginRegistry["plugins"][number],
|
||||
env: NodeJS.ProcessEnv | undefined,
|
||||
@@ -163,13 +151,21 @@ function buildPluginReport(
|
||||
params: PluginReportParams | undefined,
|
||||
loadModules: boolean,
|
||||
): PluginStatusReport {
|
||||
const rawConfig = params?.config ?? loadConfig();
|
||||
const autoEnabled = resolveStatusConfig(rawConfig, params?.env);
|
||||
const config = autoEnabled.config;
|
||||
const workspaceDir = params?.workspaceDir
|
||||
? params.workspaceDir
|
||||
: (resolveAgentWorkspaceDir(config, resolveDefaultAgentId(config)) ??
|
||||
resolveDefaultAgentWorkspaceDir());
|
||||
const baseContext = resolvePluginRuntimeLoadContext({
|
||||
config: params?.config ?? loadConfig(),
|
||||
env: params?.env,
|
||||
workspaceDir: params?.workspaceDir,
|
||||
});
|
||||
const workspaceDir = baseContext.workspaceDir ?? resolveDefaultAgentWorkspaceDir();
|
||||
const context =
|
||||
workspaceDir === baseContext.workspaceDir
|
||||
? baseContext
|
||||
: {
|
||||
...baseContext,
|
||||
workspaceDir,
|
||||
};
|
||||
const rawConfig = context.rawConfig;
|
||||
const config = context.config;
|
||||
|
||||
// Apply bundled-provider allowlist compat so that `plugins list` and `doctor`
|
||||
// report the same loaded/disabled status the gateway uses at runtime. Without
|
||||
@@ -192,20 +188,21 @@ function buildPluginReport(
|
||||
});
|
||||
|
||||
const registry = loadModules
|
||||
? loadOpenClawPlugins({
|
||||
config: runtimeCompatConfig,
|
||||
activationSourceConfig: rawConfig,
|
||||
autoEnabledReasons: autoEnabled.autoEnabledReasons,
|
||||
workspaceDir,
|
||||
env: params?.env,
|
||||
logger: createPluginLoaderLogger(log),
|
||||
activate: false,
|
||||
cache: false,
|
||||
loadModules,
|
||||
})
|
||||
? loadOpenClawPlugins(
|
||||
buildPluginRuntimeLoadOptions(context, {
|
||||
config: runtimeCompatConfig,
|
||||
activationSourceConfig: rawConfig,
|
||||
workspaceDir,
|
||||
env: params?.env,
|
||||
loadModules,
|
||||
activate: false,
|
||||
cache: false,
|
||||
}),
|
||||
)
|
||||
: loadPluginMetadataRegistrySnapshot({
|
||||
config: runtimeCompatConfig,
|
||||
activationSourceConfig: rawConfig,
|
||||
activate: false,
|
||||
workspaceDir,
|
||||
env: params?.env,
|
||||
loadModules: false,
|
||||
@@ -292,8 +289,11 @@ export function buildPluginInspectReport(params: {
|
||||
report?: PluginStatusReport;
|
||||
}): PluginInspectReport | null {
|
||||
const rawConfig = params.config ?? loadConfig();
|
||||
const resolvedConfig = resolveStatusConfig(rawConfig, params.env);
|
||||
const config = resolvedConfig.config;
|
||||
const config = resolvePluginRuntimeLoadContext({
|
||||
config: rawConfig,
|
||||
env: params.env,
|
||||
workspaceDir: params.workspaceDir,
|
||||
}).config;
|
||||
const report =
|
||||
params.report ??
|
||||
buildPluginDiagnosticsReport({
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
import { normalizeToolName } from "../agents/tool-policy.js";
|
||||
import type { AnyAgentTool } from "../agents/tools/common.js";
|
||||
import { applyPluginAutoEnable } from "../config/plugin-auto-enable.js";
|
||||
import { createSubsystemLogger } from "../logging/subsystem.js";
|
||||
import { applyTestPluginDefaults, normalizePluginsConfig } from "./config-state.js";
|
||||
import { resolveRuntimePluginRegistry, type PluginLoadOptions } from "./loader.js";
|
||||
import { createPluginLoaderLogger } from "./logger.js";
|
||||
import {
|
||||
getActivePluginRegistry,
|
||||
getActivePluginRegistryKey,
|
||||
getActivePluginRuntimeSubagentMode,
|
||||
} from "./runtime.js";
|
||||
import {
|
||||
buildPluginRuntimeLoadOptions,
|
||||
resolvePluginRuntimeLoadContext,
|
||||
} from "./runtime/load-context.js";
|
||||
import type { OpenClawPluginToolContext } from "./types.js";
|
||||
|
||||
const log = createSubsystemLogger("plugins");
|
||||
|
||||
type PluginToolMeta = {
|
||||
pluginId: string;
|
||||
optional: boolean;
|
||||
@@ -81,9 +80,12 @@ export function resolvePluginTools(params: {
|
||||
// This matters a lot for unit tests and for tool construction hot paths.
|
||||
const env = params.env ?? process.env;
|
||||
const baseConfig = applyTestPluginDefaults(params.context.config ?? {}, env);
|
||||
const autoEnabled = applyPluginAutoEnable({ config: baseConfig, env });
|
||||
const effectiveConfig = autoEnabled.config;
|
||||
const normalized = normalizePluginsConfig(effectiveConfig.plugins);
|
||||
const context = resolvePluginRuntimeLoadContext({
|
||||
config: baseConfig,
|
||||
env,
|
||||
workspaceDir: params.context.workspaceDir,
|
||||
});
|
||||
const normalized = normalizePluginsConfig(context.config.plugins);
|
||||
if (!normalized.enabled) {
|
||||
return [];
|
||||
}
|
||||
@@ -91,15 +93,7 @@ export function resolvePluginTools(params: {
|
||||
const runtimeOptions = params.allowGatewaySubagentBinding
|
||||
? { allowGatewaySubagentBinding: true as const }
|
||||
: undefined;
|
||||
const loadOptions = {
|
||||
config: effectiveConfig,
|
||||
activationSourceConfig: baseConfig,
|
||||
autoEnabledReasons: autoEnabled.autoEnabledReasons,
|
||||
workspaceDir: params.context.workspaceDir,
|
||||
runtimeOptions,
|
||||
env,
|
||||
logger: createPluginLoaderLogger(log),
|
||||
};
|
||||
const loadOptions = buildPluginRuntimeLoadOptions(context, { runtimeOptions });
|
||||
const registry = resolvePluginToolRegistry({
|
||||
loadOptions,
|
||||
allowGatewaySubagentBinding: params.allowGatewaySubagentBinding,
|
||||
@@ -122,7 +116,7 @@ export function resolvePluginTools(params: {
|
||||
if (existingNormalized.has(pluginIdKey)) {
|
||||
const message = `plugin id conflicts with core tool name (${entry.pluginId})`;
|
||||
if (!params.suppressNameConflicts) {
|
||||
log.error(message);
|
||||
context.logger.error(message);
|
||||
registry.diagnostics.push({
|
||||
level: "error",
|
||||
pluginId: entry.pluginId,
|
||||
@@ -137,12 +131,12 @@ export function resolvePluginTools(params: {
|
||||
try {
|
||||
resolved = entry.factory(params.context);
|
||||
} catch (err) {
|
||||
log.error(`plugin tool failed (${entry.pluginId}): ${String(err)}`);
|
||||
context.logger.error(`plugin tool failed (${entry.pluginId}): ${String(err)}`);
|
||||
continue;
|
||||
}
|
||||
if (!resolved) {
|
||||
if (entry.names.length > 0) {
|
||||
log.debug(
|
||||
context.logger.debug(
|
||||
`plugin tool factory returned null (${entry.pluginId}): [${entry.names.join(", ")}]`,
|
||||
);
|
||||
}
|
||||
@@ -166,7 +160,7 @@ export function resolvePluginTools(params: {
|
||||
if (nameSet.has(tool.name) || existing.has(tool.name)) {
|
||||
const message = `plugin tool name conflict (${entry.pluginId}): ${tool.name}`;
|
||||
if (!params.suppressNameConflicts) {
|
||||
log.error(message);
|
||||
context.logger.error(message);
|
||||
registry.diagnostics.push({
|
||||
level: "error",
|
||||
pluginId: entry.pluginId,
|
||||
|
||||
Reference in New Issue
Block a user