Plugins: preserve lazy runtime provider resolution
This commit is contained in:
parent
5e4851ae2b
commit
4c8853122a
@ -2800,6 +2800,7 @@ module.exports = {
|
||||
|
||||
it("preserves runtime reflection semantics when runtime is lazily initialized", () => {
|
||||
useNoBundledPlugins();
|
||||
const stateDir = makeTempDir();
|
||||
const plugin = writePlugin({
|
||||
id: "runtime-introspection",
|
||||
filename: "runtime-introspection.cjs",
|
||||
@ -2818,12 +2819,17 @@ module.exports = {
|
||||
} };`,
|
||||
});
|
||||
|
||||
const registry = loadRegistryFromSinglePlugin({
|
||||
plugin,
|
||||
pluginConfig: {
|
||||
allow: ["runtime-introspection"],
|
||||
},
|
||||
});
|
||||
const registry = withEnv({ OPENCLAW_STATE_DIR: stateDir }, () =>
|
||||
loadRegistryFromSinglePlugin({
|
||||
plugin,
|
||||
pluginConfig: {
|
||||
allow: ["runtime-introspection"],
|
||||
},
|
||||
options: {
|
||||
onlyPluginIds: ["runtime-introspection"],
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const record = registry.plugins.find((entry) => entry.id === "runtime-introspection");
|
||||
expect(record?.status).toBe("loaded");
|
||||
|
||||
@ -60,6 +60,21 @@ export type PluginLoadOptions = {
|
||||
const MAX_PLUGIN_REGISTRY_CACHE_ENTRIES = 128;
|
||||
const registryCache = new Map<string, PluginRegistry>();
|
||||
const openAllowlistWarningCache = new Set<string>();
|
||||
const LAZY_RUNTIME_REFLECTION_KEYS = [
|
||||
"version",
|
||||
"config",
|
||||
"subagent",
|
||||
"system",
|
||||
"media",
|
||||
"tts",
|
||||
"stt",
|
||||
"tools",
|
||||
"channel",
|
||||
"events",
|
||||
"logging",
|
||||
"state",
|
||||
"modelAuth",
|
||||
] as const satisfies readonly (keyof PluginRuntime)[];
|
||||
|
||||
export function clearPluginLoaderCache(): void {
|
||||
registryCache.clear();
|
||||
@ -870,6 +885,22 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
|
||||
resolvedRuntime ??= resolveCreatePluginRuntime()(options.runtimeOptions);
|
||||
return resolvedRuntime;
|
||||
};
|
||||
const lazyRuntimeReflectionKeySet = new Set<PropertyKey>(LAZY_RUNTIME_REFLECTION_KEYS);
|
||||
const resolveLazyRuntimeDescriptor = (prop: PropertyKey): PropertyDescriptor | undefined => {
|
||||
if (!lazyRuntimeReflectionKeySet.has(prop)) {
|
||||
return Reflect.getOwnPropertyDescriptor(resolveRuntime() as object, prop);
|
||||
}
|
||||
return {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
get() {
|
||||
return Reflect.get(resolveRuntime() as object, prop);
|
||||
},
|
||||
set(value: unknown) {
|
||||
Reflect.set(resolveRuntime() as object, prop, value);
|
||||
},
|
||||
};
|
||||
};
|
||||
const runtime = new Proxy({} as PluginRuntime, {
|
||||
get(_target, prop, receiver) {
|
||||
return Reflect.get(resolveRuntime(), prop, receiver);
|
||||
@ -878,13 +909,13 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
|
||||
return Reflect.set(resolveRuntime(), prop, value, receiver);
|
||||
},
|
||||
has(_target, prop) {
|
||||
return Reflect.has(resolveRuntime(), prop);
|
||||
return lazyRuntimeReflectionKeySet.has(prop) || Reflect.has(resolveRuntime(), prop);
|
||||
},
|
||||
ownKeys() {
|
||||
return Reflect.ownKeys(resolveRuntime() as object);
|
||||
return [...LAZY_RUNTIME_REFLECTION_KEYS];
|
||||
},
|
||||
getOwnPropertyDescriptor(_target, prop) {
|
||||
return Reflect.getOwnPropertyDescriptor(resolveRuntime() as object, prop);
|
||||
return resolveLazyRuntimeDescriptor(prop);
|
||||
},
|
||||
defineProperty(_target, prop, attributes) {
|
||||
return Reflect.defineProperty(resolveRuntime() as object, prop, attributes);
|
||||
|
||||
@ -58,6 +58,7 @@ describe("provider-runtime", () => {
|
||||
});
|
||||
|
||||
it("matches providers by alias for runtime hook lookup", () => {
|
||||
resolveOwningPluginIdsForProviderMock.mockReturnValue(["openrouter"]);
|
||||
resolvePluginProvidersMock.mockReturnValue([
|
||||
{
|
||||
id: "openrouter",
|
||||
@ -77,13 +78,35 @@ describe("provider-runtime", () => {
|
||||
);
|
||||
expect(resolvePluginProvidersMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
onlyPluginIds: ["openrouter"],
|
||||
bundledProviderAllowlistCompat: true,
|
||||
bundledProviderVitestCompat: true,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("skips plugin loading when the provider has no owning plugin", () => {
|
||||
const plugin = resolveProviderRuntimePlugin({ provider: "anthropic" });
|
||||
|
||||
expect(plugin).toBeUndefined();
|
||||
expect(resolveOwningPluginIdsForProviderMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
provider: "anthropic",
|
||||
}),
|
||||
);
|
||||
expect(resolvePluginProvidersMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("dispatches runtime hooks for the matched provider", async () => {
|
||||
resolveOwningPluginIdsForProviderMock.mockImplementation((params: { provider?: string }) => {
|
||||
if (params.provider === "demo") {
|
||||
return ["demo"];
|
||||
}
|
||||
if (params.provider === "openai") {
|
||||
return ["openai"];
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
const prepareDynamicModel = vi.fn(async () => undefined);
|
||||
const prepareRuntimeAuth = vi.fn(async () => ({
|
||||
apiKey: "runtime-token",
|
||||
|
||||
@ -54,14 +54,18 @@ export function resolveProviderRuntimePlugin(params: {
|
||||
workspaceDir?: string;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
}): ProviderPlugin | undefined {
|
||||
const owningPluginIds = resolveOwningPluginIdsForProvider({
|
||||
provider: params.provider,
|
||||
config: params.config,
|
||||
workspaceDir: params.workspaceDir,
|
||||
env: params.env,
|
||||
});
|
||||
if (!owningPluginIds || owningPluginIds.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
return resolveProviderPluginsForHooks({
|
||||
...params,
|
||||
onlyPluginIds: resolveOwningPluginIdsForProvider({
|
||||
provider: params.provider,
|
||||
config: params.config,
|
||||
workspaceDir: params.workspaceDir,
|
||||
env: params.env,
|
||||
}),
|
||||
onlyPluginIds: owningPluginIds,
|
||||
}).find((plugin) => matchesProviderId(plugin, params.provider));
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user