fix(plugins): honor descriptor-only setup flag · openclaw/openclaw@7418adf
vincentkoc
·
2026-04-25
·
via Recent Commits to openclaw:main
| Original file line number | Diff line number | Diff line change |
|---|
@@ -7,6 +7,7 @@ Docs: https://docs.openclaw.ai
|
7 | 7 | ### Changes |
8 | 8 | |
9 | 9 | - Gradium: add a bundled text-to-speech provider with voice-note and telephony output support. (#64958) Thanks @LaurentMazare. |
| 10 | +- Plugins/setup: honor explicit `setup.requiresRuntime: false` as a descriptor-only setup contract while keeping omitted values on the legacy setup-api fallback path. Thanks @vincentkoc. |
10 | 11 | - TUI/dependencies: remove direct `cli-highlight` usage from the OpenClaw TUI code-block renderer, keeping themed code coloring without the extra root dependency. Thanks @vincentkoc. |
11 | 12 | - Diagnostics/OTEL: export run, model-call, and tool-execution diagnostic lifecycle events as OTEL spans without retaining live span state. Thanks @vincentkoc. |
12 | 13 | - Plugins/activation: expose activation plan reasons and a richer plan API so callers can inspect why a plugin was selected while preserving existing id-list activation behavior. (#70943) Thanks @vincentkoc. |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -71,10 +71,12 @@ or fallback behavior without changing runtime loading semantics.
|
71 | 71 | |
72 | 72 | Setup discovery now prefers descriptor-owned ids such as `setup.providers` and |
73 | 73 | `setup.cliBackends` to narrow candidate plugins before it falls back to |
74 | | -`setup-api` for plugins that still need setup-time runtime hooks. If more than |
75 | | -one discovered plugin claims the same normalized setup provider or CLI backend |
76 | | -id, setup lookup refuses the ambiguous owner instead of relying on discovery |
77 | | -order. |
| 74 | +`setup-api` for plugins that still need setup-time runtime hooks. Explicit |
| 75 | +`setup.requiresRuntime: false` is a descriptor-only cutoff; omitted |
| 76 | +`requiresRuntime` keeps the legacy setup-api fallback for compatibility. If more |
| 77 | +than one discovered plugin claims the same normalized setup provider or CLI |
| 78 | +backend id, setup lookup refuses the ambiguous owner instead of relying on |
| 79 | +discovery order. |
78 | 80 | |
79 | 81 | ### What the loader caches |
80 | 82 | |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -327,6 +327,12 @@ narrows the candidate plugin and setup still needs richer setup-time runtime
|
327 | 327 | hooks, set `requiresRuntime: true` and keep `setup-api` in place as the |
328 | 328 | fallback execution path. |
329 | 329 | |
| 330 | +Set `requiresRuntime: false` only when those descriptors are sufficient for the |
| 331 | +setup surface. OpenClaw treats explicit `false` as a descriptor-only contract |
| 332 | +and will not execute `setup-api` for setup lookup. Omitted `requiresRuntime` |
| 333 | +keeps legacy fallback behavior so existing plugins that added descriptors |
| 334 | +without the flag do not break. |
| 335 | + |
330 | 336 | Because setup lookup can execute plugin-owned `setup-api` code, normalized |
331 | 337 | `setup.providers[].id` and `setup.cliBackends[]` values must stay unique across |
332 | 338 | discovered plugins. Ambiguous ownership fails closed instead of picking a |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -349,6 +349,39 @@ describe("setup-registry getJiti", () => {
|
349 | 349 | expect(mocks.createJiti.mock.calls[0]?.[0]).toBe(path.join(pluginRoot, "setup-api.js")); |
350 | 350 | }); |
351 | 351 | |
| 352 | +it("treats explicit descriptor-only setup as a runtime cutoff", () => { |
| 353 | +const pluginRoot = makeTempDir(); |
| 354 | +fs.writeFileSync( |
| 355 | +path.join(pluginRoot, "setup-api.js"), |
| 356 | +"export default { register(api) { api.registerProvider({ id: 'openai', label: 'OpenAI', auth: [] }); api.registerCliBackend({ id: 'codex-cli', config: { command: 'codex' } }); } };\n", |
| 357 | +"utf-8", |
| 358 | +); |
| 359 | +mocks.loadPluginManifestRegistry.mockReturnValue({ |
| 360 | +plugins: [ |
| 361 | +{ |
| 362 | +id: "openai", |
| 363 | +rootDir: pluginRoot, |
| 364 | +setup: { |
| 365 | +providers: [{ id: "openai" }], |
| 366 | +cliBackends: ["codex-cli"], |
| 367 | +requiresRuntime: false, |
| 368 | +}, |
| 369 | +}, |
| 370 | +], |
| 371 | +diagnostics: [], |
| 372 | +}); |
| 373 | + |
| 374 | +expect(resolvePluginSetupProvider({ provider: "openai", env: {} })).toBeUndefined(); |
| 375 | +expect(resolvePluginSetupCliBackend({ backend: "codex-cli", env: {} })).toBeUndefined(); |
| 376 | +expect(resolvePluginSetupRegistry({ env: {} })).toEqual({ |
| 377 | +providers: [], |
| 378 | +cliBackends: [], |
| 379 | +configMigrations: [], |
| 380 | +autoEnableProbes: [], |
| 381 | +}); |
| 382 | +expect(mocks.createJiti).not.toHaveBeenCalled(); |
| 383 | +}); |
| 384 | + |
352 | 385 | it("does not load setup-api modules from the current working directory", () => { |
353 | 386 | const pluginRoot = makeTempDir(); |
354 | 387 | const workspaceRoot = makeTempDir(); |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -272,6 +272,9 @@ function resolveSetupRegistration(record: PluginManifestRecord): {
|
272 | 272 | setupSource: string; |
273 | 273 | register: (api: ReturnType<typeof buildPluginApi>) => void | Promise<void>; |
274 | 274 | } | null { |
| 275 | +if (record.setup?.requiresRuntime === false) { |
| 276 | +return null; |
| 277 | +} |
275 | 278 | const setupSource = record.setupSource ?? resolveSetupApiPath(record.rootDir); |
276 | 279 | if (!setupSource) { |
277 | 280 | return null; |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。