mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:50:43 +00:00
fix: reuse provider discovery plugin metadata
This commit is contained in:
@@ -58,6 +58,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Plugins/capabilities: cache manifest-derived capability provider plugin IDs per config snapshot so repeated TTS, media, realtime, memory, image, video, and music provider resolution avoids redundant manifest scans. Thanks @shakkernerd.
|
||||
- Plugins/contracts: resolve runtime manifest-contract plugin owners from one plugin index plus manifest pass instead of rebuilding manifest metadata separately for all owners and enabled owners. Thanks @shakkernerd.
|
||||
- Plugins/extractors: reuse one manifest registry pass while resolving bundled document and web-content extractor plugins instead of rereading manifests for compatibility and enablement filtering. Thanks @shakkernerd.
|
||||
- Plugins/providers: reuse one plugin registry snapshot and manifest registry while resolving provider discovery entries instead of rebuilding manifest metadata after provider owner discovery. Thanks @shakkernerd.
|
||||
- Plugins/registry: resolve lookup-table owner maps for providers, CLI backends, setup providers, command aliases, model catalogs, channel configs, and manifest contracts while preserving setup-only CLI backend ownership. Thanks @shakkernerd.
|
||||
- Mattermost: keep direct-message replies top-level by suppressing reply roots for DM delivery while preserving channel and group thread roots, and derive inbound chat kind from the trusted channel lookup instead of the websocket event channel type. Carries forward #60115, #55186, #72305, and #72659; refs #59758, #59981, #59791, and #57565. Thanks @vincentkoc, @jwchmodx, and @hnykda.
|
||||
- Process/Windows: decode command stdout and stderr from raw bytes with console-codepage awareness, while preserving valid UTF-8 output and multibyte characters split across chunks. Fixes #50519. Thanks @iready, @kevinten10, @zhangyongjie1997, @knightplat-blip, @heiqishi666, and @slepybear.
|
||||
|
||||
@@ -3,14 +3,19 @@ import type { PluginManifestRecord } from "./manifest-registry.js";
|
||||
import type { ProviderPlugin } from "./types.js";
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
loadPluginManifestRegistry: vi.fn(),
|
||||
loadPluginRegistrySnapshot: vi.fn(),
|
||||
loadPluginManifestRegistryForInstalledIndex: vi.fn(),
|
||||
resolveDiscoveredProviderPluginIds: vi.fn(),
|
||||
resolvePluginProviders: vi.fn(),
|
||||
loadSource: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("./manifest-registry.js", () => ({
|
||||
loadPluginManifestRegistry: mocks.loadPluginManifestRegistry,
|
||||
vi.mock("./plugin-registry.js", () => ({
|
||||
loadPluginRegistrySnapshot: mocks.loadPluginRegistrySnapshot,
|
||||
}));
|
||||
|
||||
vi.mock("./manifest-registry-installed.js", () => ({
|
||||
loadPluginManifestRegistryForInstalledIndex: mocks.loadPluginManifestRegistryForInstalledIndex,
|
||||
}));
|
||||
|
||||
vi.mock("./providers.js", () => ({
|
||||
@@ -77,8 +82,9 @@ function createProvider(params: { id: string; mode: "static" | "catalog" }): Pro
|
||||
describe("resolvePluginDiscoveryProvidersRuntime", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
mocks.loadPluginRegistrySnapshot.mockReturnValue({ plugins: [] });
|
||||
mocks.resolveDiscoveredProviderPluginIds.mockReturnValue(["deepseek"]);
|
||||
mocks.loadPluginManifestRegistry.mockReturnValue({
|
||||
mocks.loadPluginManifestRegistryForInstalledIndex.mockReturnValue({
|
||||
plugins: [createManifestPlugin("deepseek")],
|
||||
diagnostics: [],
|
||||
});
|
||||
@@ -110,7 +116,7 @@ describe("resolvePluginDiscoveryProvidersRuntime", () => {
|
||||
"kilocode",
|
||||
"unused",
|
||||
]);
|
||||
mocks.loadPluginManifestRegistry.mockReturnValue({
|
||||
mocks.loadPluginManifestRegistryForInstalledIndex.mockReturnValue({
|
||||
plugins: [
|
||||
createManifestPlugin("codex"),
|
||||
createManifestPlugin("deepseek"),
|
||||
@@ -144,6 +150,35 @@ describe("resolvePluginDiscoveryProvidersRuntime", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("shares one registry snapshot and manifest registry between provider id discovery and entry loading", () => {
|
||||
const registry = { plugins: [] };
|
||||
const manifestRegistry = {
|
||||
plugins: [createManifestPlugin("deepseek")],
|
||||
diagnostics: [],
|
||||
};
|
||||
mocks.loadPluginRegistrySnapshot.mockReturnValue(registry);
|
||||
mocks.loadPluginManifestRegistryForInstalledIndex.mockReturnValue(manifestRegistry);
|
||||
mocks.loadSource.mockReturnValue(createProvider({ id: "deepseek", mode: "catalog" }));
|
||||
|
||||
resolvePluginDiscoveryProvidersRuntime({ config: {}, env: {} as NodeJS.ProcessEnv });
|
||||
|
||||
expect(mocks.loadPluginRegistrySnapshot).toHaveBeenCalledOnce();
|
||||
expect(mocks.loadPluginManifestRegistryForInstalledIndex).toHaveBeenCalledWith({
|
||||
index: registry,
|
||||
config: {},
|
||||
workspaceDir: undefined,
|
||||
env: {},
|
||||
includeDisabled: true,
|
||||
});
|
||||
expect(mocks.loadPluginManifestRegistryForInstalledIndex).toHaveBeenCalledOnce();
|
||||
expect(mocks.resolveDiscoveredProviderPluginIds).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
registry,
|
||||
manifestRegistry,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("returns static-only discovery entries for callers that explicitly request them", () => {
|
||||
const staticProvider = createProvider({ id: "deepseek", mode: "static" });
|
||||
mocks.loadSource.mockReturnValue(staticProvider);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { loadPluginManifestRegistryForInstalledIndex } from "./manifest-registry-installed.js";
|
||||
import type { PluginManifestRecord } from "./manifest-registry.js";
|
||||
import { loadPluginManifestRegistryForPluginRegistry } from "./plugin-registry.js";
|
||||
import { loadPluginRegistrySnapshot } from "./plugin-registry.js";
|
||||
import { resolveDiscoveredProviderPluginIds } from "./providers.js";
|
||||
import { resolvePluginProviders } from "./providers.runtime.js";
|
||||
import { createPluginSourceLoader } from "./source-loader.js";
|
||||
@@ -76,13 +77,21 @@ function resolveProviderDiscoveryEntryPlugins(params: {
|
||||
requireCompleteDiscoveryEntryCoverage?: boolean;
|
||||
discoveryEntriesOnly?: boolean;
|
||||
}): ProviderDiscoveryEntryResult {
|
||||
const pluginIds = resolveDiscoveredProviderPluginIds(params);
|
||||
const pluginIdSet = new Set(pluginIds);
|
||||
const pluginRecords = loadPluginManifestRegistryForPluginRegistry({
|
||||
...params,
|
||||
pluginIds,
|
||||
const registry = loadPluginRegistrySnapshot(params);
|
||||
const manifestRegistry = loadPluginManifestRegistryForInstalledIndex({
|
||||
index: registry,
|
||||
config: params.config,
|
||||
workspaceDir: params.workspaceDir,
|
||||
env: params.env,
|
||||
includeDisabled: true,
|
||||
}).plugins.filter((plugin) => pluginIdSet.has(plugin.id));
|
||||
});
|
||||
const pluginIds = resolveDiscoveredProviderPluginIds({
|
||||
...params,
|
||||
registry,
|
||||
manifestRegistry,
|
||||
});
|
||||
const pluginIdSet = new Set(pluginIds);
|
||||
const pluginRecords = manifestRegistry.plugins.filter((plugin) => pluginIdSet.has(plugin.id));
|
||||
const entryRecords = pluginRecords.filter((plugin) => plugin.providerDiscoverySource);
|
||||
const entryPluginIds = new Set(entryRecords.map((plugin) => plugin.id));
|
||||
if (entryRecords.length === 0) {
|
||||
|
||||
@@ -233,6 +233,8 @@ export function resolveDiscoveredProviderPluginIds(params: {
|
||||
config?: PluginLoadOptions["config"];
|
||||
workspaceDir?: string;
|
||||
env?: PluginLoadOptions["env"];
|
||||
registry?: PluginRegistrySnapshot;
|
||||
manifestRegistry?: PluginManifestRegistry;
|
||||
onlyPluginIds?: readonly string[];
|
||||
includeUntrustedWorkspacePlugins?: boolean;
|
||||
}): string[] {
|
||||
|
||||
Reference in New Issue
Block a user