diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b61988375f..b92975f1054 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ Docs: https://docs.openclaw.ai - Channels/Yuanbao: register the Tencent Yuanbao external channel plugin (`openclaw-plugin-yuanbao`) in the official channel catalog, contract suites, and community plugin docs, with a new `docs/channels/yuanbao.md` quick-start guide for WebSocket bot DMs and group chats. (#72756) Thanks @loongfay. - Channels/QQBot: add full group chat support (history tracking, @-mention gating, activation modes, per-group config, FIFO message queue with deliver debounce), C2C `stream_messages` streaming with a `StreamingController` lifecycle manager, unified `sendMedia` with chunked upload for large files, and refactor the engine into pipeline stages, focused outbound submodules, builtin slash-command modules, and explicit DI ports via `createEngineAdapters()`. (#70624) Thanks @cxyhhhhh. - Plugins/startup: migrate bundled plugin manifests to explicit `activation.onStartup` declarations so Gateway startup imports only the bundled plugins that intentionally register startup-time runtime surfaces. Thanks @shakkernerd. +- Plugins/startup: add an opt-in future-mode gate for disabling deprecated implicit startup sidecar loading while preserving explicit startup and narrower activation triggers. Thanks @shakkernerd. - Plugins/startup: add plugin compatibility warnings for deprecated implicit startup loading so authors can migrate to explicit `activation.onStartup` metadata. Thanks @shakkernerd. - Plugins/runtime: load bundled agent tool-result middleware from manifest contracts on demand so tokenjuice stays startup-lazy without losing Pi/Codex tool-output compaction. Thanks @shakkernerd. - Plugins/startup: add explicit `activation.onStartup` metadata so plugins can declare Gateway startup import behavior while the deprecated implicit sidecar fallback remains for legacy plugins. Thanks @shakkernerd. diff --git a/docs/plugins/compatibility.md b/docs/plugins/compatibility.md index 2f08bd886b9..b0359f47978 100644 --- a/docs/plugins/compatibility.md +++ b/docs/plugins/compatibility.md @@ -136,7 +136,8 @@ Current compatibility records include: move to `openclaw/plugin-sdk/channel-route` - activation hints that are being replaced by manifest contribution ownership - deprecated implicit startup sidecar loading for plugins that have not declared - `activation.onStartup` + `activation.onStartup`; maintainers can test the future stricter behavior with + `OPENCLAW_DISABLE_LEGACY_IMPLICIT_STARTUP_SIDECARS=1` - `setup-api` runtime fallback while setup descriptors move to cold `setup.requiresRuntime: false` metadata - provider `discovery` hooks while provider catalog hooks move to diff --git a/docs/plugins/manifest.md b/docs/plugins/manifest.md index 794d6bfcbfa..963163be27c 100644 --- a/docs/plugins/manifest.md +++ b/docs/plugins/manifest.md @@ -268,6 +268,12 @@ plugins unless they declare `activation.onStartup: true`. Plugin status and compatibility reports warn with `legacy-implicit-startup-sidecar` when a plugin still relies on that fallback. +For migration testing, set +`OPENCLAW_DISABLE_LEGACY_IMPLICIT_STARTUP_SIDECARS=1` to disable only that +deprecated fallback. This opt-in mode does not block explicit +`activation.onStartup: true` plugins or plugins loaded by channel, config, +agent-harness, memory, or other narrower activation triggers. + ```json { "activation": { diff --git a/src/plugins/channel-plugin-ids.test.ts b/src/plugins/channel-plugin-ids.test.ts index afc705ff0d8..d0432ba9d7b 100644 --- a/src/plugins/channel-plugin-ids.test.ts +++ b/src/plugins/channel-plugin-ids.test.ts @@ -662,6 +662,22 @@ describe("resolveGatewayStartupPluginIds", () => { }); }); + it("can disable deprecated implicit startup sidecar fallback for future-mode testing", () => { + expectStartupPluginIdsCase({ + config: createStartupConfig({ + enabledPluginIds: ["demo-global-sidecar"], + allowPluginIds: ["demo-global-sidecar"], + noConfiguredChannels: true, + memorySlot: "none", + }), + env: { + ...process.env, + OPENCLAW_DISABLE_LEGACY_IMPLICIT_STARTUP_SIDECARS: "1", + }, + expected: [], + }); + }); + it("skips deprecated implicit startup sidecar fallback when activation.onStartup is false", () => { expectStartupPluginIdsCase({ config: createStartupConfig({ @@ -682,6 +698,10 @@ describe("resolveGatewayStartupPluginIds", () => { noConfiguredChannels: true, memorySlot: "none", }), + env: { + ...process.env, + OPENCLAW_DISABLE_LEGACY_IMPLICIT_STARTUP_SIDECARS: "1", + }, expected: ["demo-global-explicit-startup"], }); }); diff --git a/src/plugins/gateway-startup-plugin-ids.ts b/src/plugins/gateway-startup-plugin-ids.ts index 13890c3d6c8..e930af24d53 100644 --- a/src/plugins/gateway-startup-plugin-ids.ts +++ b/src/plugins/gateway-startup-plugin-ids.ts @@ -20,6 +20,18 @@ import { } from "./plugin-registry-contributions.js"; import { loadPluginRegistrySnapshot } from "./plugin-registry-snapshot.js"; +const DISABLE_LEGACY_IMPLICIT_STARTUP_SIDECARS_ENV = + "OPENCLAW_DISABLE_LEGACY_IMPLICIT_STARTUP_SIDECARS"; + +function isTruthyEnvValue(value: string | undefined): boolean { + const normalized = value?.trim().toLowerCase(); + return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on"; +} + +function shouldDisableLegacyImplicitStartupSidecars(env: NodeJS.ProcessEnv): boolean { + return isTruthyEnvValue(env[DISABLE_LEGACY_IMPLICIT_STARTUP_SIDECARS_ENV]); +} + function listDisabledChannelIds(config: OpenClawConfig): Set { const channels = config.channels; if (!channels || typeof channels !== "object" || Array.isArray(channels)) { @@ -117,6 +129,7 @@ function resolveMemorySlotStartupPluginId(params: { function shouldConsiderForGatewayStartup(params: { plugin: InstalledPluginIndexRecord; manifest: PluginManifestRecord | undefined; + disableLegacyImplicitStartupSidecars: boolean; startupDreamingPluginIds: ReadonlySet; memorySlotStartupPluginId?: string; }): boolean { @@ -127,6 +140,9 @@ function shouldConsiderForGatewayStartup(params: { if (params.manifest?.activation?.onStartup === false) { return false; } + if (params.disableLegacyImplicitStartupSidecars) { + return false; + } // Deprecated compatibility fallback: plugins without explicit startup // activation metadata may still need startup import to register hooks or // services. All plugins should declare activation.onStartup explicitly as @@ -383,6 +399,9 @@ export function resolveGatewayStartupPluginIdsFromRegistry(params: { collectConfiguredAgentHarnessRuntimes(activationSourceConfig, params.env), ); const startupDreamingPluginIds = resolveGatewayStartupDreamingPluginIds(params.config); + const disableLegacyImplicitStartupSidecars = shouldDisableLegacyImplicitStartupSidecars( + params.env, + ); const memorySlotStartupPluginId = resolveMemorySlotStartupPluginId({ activationSourceConfig, activationSourcePlugins, @@ -436,6 +455,7 @@ export function resolveGatewayStartupPluginIdsFromRegistry(params: { !shouldConsiderForGatewayStartup({ plugin, manifest, + disableLegacyImplicitStartupSidecars, startupDreamingPluginIds, memorySlotStartupPluginId, })