fix(agents): avoid secrets snapshot clones in plugin tool prep

This commit is contained in:
Peter Steinberger
2026-05-04 02:47:15 +01:00
parent 45cfe1dfa1
commit 5be66ca648
3 changed files with 73 additions and 41 deletions

View File

@@ -45,6 +45,7 @@ Docs: https://docs.openclaw.ai
- Release validation: install the cross-OS TypeScript harness through Windows-safe Node/npm shims so native Windows package checks reach the OpenClaw smoke suites instead of exiting before artifact capture. Thanks @vincentkoc.
- Release validation: let Windows packaged-upgrade checks continue after the shipped 2026.5.2 updater hits its native-module swap cleanup fallback, verifying the fallback-installed candidate through package metadata and downstream smoke instead of crashing on the immediate update-status probe. Thanks @vincentkoc.
- Doctor/plugins: skip channel-derived official plugin installs when another configured plugin is the effective owner for the same channel, so `doctor --repair` does not reinstall `feishu` while `openclaw-lark` handles `channels.feishu`. Fixes #76623. Thanks @fuyizheng3120.
- Agents/tools: use config-only runtime snapshots for plugin tool registration and live runtime config getters, avoiding expensive full secrets snapshot clones on the core-plugin-tools prep path. Fixes #76295.
- Agents/bootstrap: keep pending `BOOTSTRAP.md` and bootstrap truncation notices in system-prompt Project Context instead of copying setup text or raw warning diagnostics into WebChat user/runtime context. Fixes #76946.
- Channels/WhatsApp: allow `@whiskeysockets/libsignal-node` in `onlyBuiltDependencies` so pnpm v9+ `blockExoticSubdeps` no longer rejects the baileys git-tarball subdep and silences all inbound agent replies. Fixes #76539. Thanks @ottodeng and @vincentkoc.
- Gateway/install: keep `.env`-managed values in the macOS LaunchAgent env file while still tracking `OPENCLAW_SERVICE_MANAGED_ENV_KEYS`, so regenerated services do not boot without managed auth/provider keys. Fixes #75374.

View File

@@ -1,7 +1,10 @@
import { selectApplicableRuntimeConfig } from "../config/config.js";
import {
getRuntimeConfigSnapshot,
getRuntimeConfigSourceSnapshot,
} from "../config/runtime-snapshot.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { resolvePluginTools } from "../plugins/tools.js";
import { getActiveSecretsRuntimeSnapshot } from "../secrets/runtime.js";
import { normalizeDeliveryContext } from "../utils/delivery-context.js";
import { listProfilesForProvider } from "./auth-profiles.js";
import type { AuthProfileStore } from "./auth-profiles/types.js";
@@ -28,6 +31,27 @@ type ResolveOpenClawPluginToolsOptions = OpenClawPluginToolOptions & {
authProfileStore?: AuthProfileStore;
};
function resolveApplicablePluginRuntimeConfig(
inputConfig?: OpenClawConfig,
): OpenClawConfig | undefined {
const runtimeConfig = getRuntimeConfigSnapshot() ?? undefined;
if (!runtimeConfig) {
return inputConfig;
}
if (!inputConfig || inputConfig === runtimeConfig) {
return runtimeConfig;
}
const runtimeSourceConfig = getRuntimeConfigSourceSnapshot() ?? undefined;
if (!runtimeSourceConfig) {
return inputConfig;
}
return selectApplicableRuntimeConfig({
inputConfig,
runtimeConfig,
runtimeSourceConfig,
});
}
export function resolveOpenClawPluginToolsForOptions(params: {
options?: ResolveOpenClawPluginToolsOptions;
resolvedConfig?: OpenClawConfig;
@@ -45,12 +69,7 @@ export function resolveOpenClawPluginToolsForOptions(params: {
});
const resolveCurrentRuntimeConfig = () => {
const currentRuntimeSnapshot = getActiveSecretsRuntimeSnapshot();
return selectApplicableRuntimeConfig({
inputConfig: params.resolvedConfig ?? params.options?.config,
runtimeConfig: currentRuntimeSnapshot?.config,
runtimeSourceConfig: currentRuntimeSnapshot?.sourceConfig,
});
return resolveApplicablePluginRuntimeConfig(params.resolvedConfig ?? params.options?.config);
};
const authProfileStore = params.options?.authProfileStore;
const pluginTools = resolvePluginTools({

View File

@@ -1,5 +1,6 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../config/config.js";
import { resetConfigRuntimeState, setRuntimeConfigSnapshot } from "../config/config.js";
import { activateSecretsRuntimeSnapshot, clearSecretsRuntimeSnapshot } from "../secrets/runtime.js";
import { resolveOpenClawPluginToolsForOptions } from "./openclaw-plugin-tools.js";
@@ -15,6 +16,7 @@ describe("createOpenClawTools browser plugin integration", () => {
afterEach(() => {
hoisted.resolvePluginTools.mockReset();
clearSecretsRuntimeSnapshot();
resetConfigRuntimeState();
});
it("keeps the browser tool returned by plugin resolution", () => {
@@ -193,6 +195,48 @@ describe("createOpenClawTools browser plugin integration", () => {
expect(capturedRuntimeConfig).toBe(resolvedRunConfig);
});
it("does not let a source-less pinned config snapshot override explicit plugin tool config", () => {
const pinnedRuntimeConfig = {
plugins: {
allow: ["old-plugin"],
},
} as OpenClawConfig;
const explicitConfig = {
plugins: {
allow: ["browser"],
},
tools: {
experimental: {
planTool: true,
},
},
} as OpenClawConfig;
let capturedRuntimeConfig: OpenClawConfig | undefined;
let getRuntimeConfig: (() => OpenClawConfig | undefined) | undefined;
hoisted.resolvePluginTools.mockImplementation((params: unknown) => {
const context = (
params as {
context?: {
runtimeConfig?: OpenClawConfig;
getRuntimeConfig?: () => OpenClawConfig | undefined;
};
}
).context;
capturedRuntimeConfig = context?.runtimeConfig;
getRuntimeConfig = context?.getRuntimeConfig;
return [];
});
setRuntimeConfigSnapshot(pinnedRuntimeConfig);
resolveOpenClawPluginToolsForOptions({
options: { config: explicitConfig },
resolvedConfig: explicitConfig,
});
expect(capturedRuntimeConfig).toBe(explicitConfig);
expect(getRuntimeConfig?.()).toBe(explicitConfig);
});
it("exposes a live runtime config getter to plugin tool factories", () => {
const sourceConfig = {
plugins: {
@@ -218,23 +262,7 @@ describe("createOpenClawTools browser plugin integration", () => {
).context?.getRuntimeConfig;
return [];
});
activateSecretsRuntimeSnapshot({
sourceConfig,
config: firstRuntimeConfig,
authStores: [],
warnings: [],
webTools: {
search: {
providerSource: "none",
diagnostics: [],
},
fetch: {
providerSource: "none",
diagnostics: [],
},
diagnostics: [],
},
});
setRuntimeConfigSnapshot(firstRuntimeConfig, sourceConfig);
resolveOpenClawPluginToolsForOptions({
options: { config: sourceConfig },
@@ -243,23 +271,7 @@ describe("createOpenClawTools browser plugin integration", () => {
expect(getRuntimeConfig?.()).toStrictEqual(firstRuntimeConfig);
activateSecretsRuntimeSnapshot({
sourceConfig,
config: nextRuntimeConfig,
authStores: [],
warnings: [],
webTools: {
search: {
providerSource: "none",
diagnostics: [],
},
fetch: {
providerSource: "none",
diagnostics: [],
},
diagnostics: [],
},
});
setRuntimeConfigSnapshot(nextRuntimeConfig, sourceConfig);
expect(getRuntimeConfig?.()).toStrictEqual(nextRuntimeConfig);
expect(getRuntimeConfig?.()?.plugins?.entries?.["memory-core"]?.enabled).toBe(false);