mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 13:40:44 +00:00
feat(plugins): warn on ignored setup runtime (#71253)
* feat(plugins): warn on ignored setup runtime * fix(plugins): avoid fallback setup runtime diagnostics * refactor(plugins): clarify setup runtime lookup
This commit is contained in:
@@ -17,6 +17,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Plugin hooks: expose first-class run, message, sender, session, and trace correlation fields on message hook contexts and run lifecycle events. Thanks @vincentkoc.
|
||||
- Plugins/setup: include `setup.providers[].envVars` in generic provider auth/env lookups and warn non-bundled plugins that still rely on deprecated `providerAuthEnvVars` compatibility metadata. Thanks @vincentkoc.
|
||||
- Plugins/setup: surface manifest provider auth choices directly in provider setup flow before falling back to setup runtime or install-catalog choices. Thanks @vincentkoc.
|
||||
- Plugins/setup: warn when descriptor-only setup plugins still ship ignored setup runtime entries, keeping `setup.requiresRuntime: false` semantics explicit without breaking existing metadata. Thanks @vincentkoc.
|
||||
- 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.
|
||||
- Diagnostics/OTEL: export run, model-call, and tool-execution diagnostic lifecycle events as OTEL spans without retaining live span state. Thanks @vincentkoc.
|
||||
- Providers/Anthropic Vertex: move the Vertex SDK runtime behind the bundled provider plugin so core no longer owns that provider-specific dependency. Thanks @vincentkoc.
|
||||
|
||||
@@ -337,9 +337,11 @@ on `setup.providers[].envVars`.
|
||||
|
||||
Set `requiresRuntime: false` only when those descriptors are sufficient for the
|
||||
setup surface. OpenClaw treats explicit `false` as a descriptor-only contract
|
||||
and will not execute `setup-api` for setup lookup. Omitted `requiresRuntime`
|
||||
keeps legacy fallback behavior so existing plugins that added descriptors
|
||||
without the flag do not break.
|
||||
and will not execute `setup-api` or `openclaw.setupEntry` for setup lookup. If
|
||||
a descriptor-only plugin still ships one of those setup runtime entries,
|
||||
OpenClaw reports an additive diagnostic and continues ignoring it. Omitted
|
||||
`requiresRuntime` keeps legacy fallback behavior so existing plugins that added
|
||||
descriptors without the flag do not break.
|
||||
|
||||
Because setup lookup can execute plugin-owned `setup-api` code, normalized
|
||||
`setup.providers[].id` and `setup.cliBackends[]` values must stay unique across
|
||||
|
||||
@@ -373,6 +373,42 @@ describe("setup-registry getJiti", () => {
|
||||
|
||||
expect(resolvePluginSetupProvider({ provider: "openai", env: {} })).toBeUndefined();
|
||||
expect(resolvePluginSetupCliBackend({ backend: "codex-cli", env: {} })).toBeUndefined();
|
||||
expect(resolvePluginSetupRegistry({ env: {} })).toEqual({
|
||||
providers: [],
|
||||
cliBackends: [],
|
||||
configMigrations: [],
|
||||
autoEnableProbes: [],
|
||||
diagnostics: [
|
||||
expect.objectContaining({
|
||||
pluginId: "openai",
|
||||
code: "setup-descriptor-runtime-disabled",
|
||||
}),
|
||||
],
|
||||
});
|
||||
expect(mocks.createJiti).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not report descriptor-only diagnostics for bundled setup-api fallback paths", () => {
|
||||
const parentDir = makeTempDir();
|
||||
const pluginRoot = path.join(parentDir, "openai");
|
||||
fs.mkdirSync(pluginRoot);
|
||||
expect(fs.existsSync(path.join(process.cwd(), "extensions", "openai", "setup-api.ts"))).toBe(
|
||||
true,
|
||||
);
|
||||
mocks.loadPluginManifestRegistry.mockReturnValue({
|
||||
plugins: [
|
||||
{
|
||||
id: "workspace-openai",
|
||||
rootDir: pluginRoot,
|
||||
setup: {
|
||||
providers: [{ id: "workspace-openai" }],
|
||||
requiresRuntime: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
diagnostics: [],
|
||||
});
|
||||
|
||||
expect(resolvePluginSetupRegistry({ env: {} })).toEqual({
|
||||
providers: [],
|
||||
cliBackends: [],
|
||||
|
||||
@@ -47,6 +47,7 @@ type SetupAutoEnableProbeEntry = {
|
||||
};
|
||||
|
||||
export type PluginSetupRegistryDiagnosticCode =
|
||||
| "setup-descriptor-runtime-disabled"
|
||||
| "setup-descriptor-provider-missing-runtime"
|
||||
| "setup-descriptor-provider-runtime-undeclared"
|
||||
| "setup-descriptor-cli-backend-missing-runtime"
|
||||
@@ -189,7 +190,10 @@ function buildSetupCliBackendCacheKey(params: {
|
||||
});
|
||||
}
|
||||
|
||||
function resolveSetupApiPath(rootDir: string): string | null {
|
||||
function resolveSetupApiPath(
|
||||
rootDir: string,
|
||||
options?: { includeBundledSourceFallback?: boolean },
|
||||
): string | null {
|
||||
const orderedExtensions = RUNNING_FROM_BUILT_ARTIFACT
|
||||
? SETUP_API_EXTENSIONS
|
||||
: ([...SETUP_API_EXTENSIONS.slice(3), ...SETUP_API_EXTENSIONS.slice(0, 3)] as const);
|
||||
@@ -209,6 +213,10 @@ function resolveSetupApiPath(rootDir: string): string | null {
|
||||
return direct;
|
||||
}
|
||||
|
||||
if (options?.includeBundledSourceFallback === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const bundledExtensionDir = path.basename(rootDir);
|
||||
const repoRootCandidates = [path.resolve(path.dirname(CURRENT_MODULE_PATH), "..", "..")];
|
||||
for (const repoRoot of repoRootCandidates) {
|
||||
@@ -283,6 +291,19 @@ function resolveRegister(mod: OpenClawPluginModule): {
|
||||
return {};
|
||||
}
|
||||
|
||||
function resolveLoadableSetupRuntimeSource(record: PluginManifestRecord): string | null {
|
||||
return record.setupSource ?? resolveSetupApiPath(record.rootDir);
|
||||
}
|
||||
|
||||
function resolveDeclaredSetupRuntimeSource(record: PluginManifestRecord): string | null {
|
||||
return (
|
||||
record.setupSource ??
|
||||
resolveSetupApiPath(record.rootDir, {
|
||||
includeBundledSourceFallback: false,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function resolveSetupRegistration(record: PluginManifestRecord): {
|
||||
setupSource: string;
|
||||
register: (api: ReturnType<typeof buildPluginApi>) => void | Promise<void>;
|
||||
@@ -290,7 +311,7 @@ function resolveSetupRegistration(record: PluginManifestRecord): {
|
||||
if (record.setup?.requiresRuntime === false) {
|
||||
return null;
|
||||
}
|
||||
const setupSource = record.setupSource ?? resolveSetupApiPath(record.rootDir);
|
||||
const setupSource = resolveLoadableSetupRuntimeSource(record);
|
||||
if (!setupSource) {
|
||||
return null;
|
||||
}
|
||||
@@ -399,6 +420,21 @@ function mapNormalizedIds(ids: readonly string[]): Map<string, string> {
|
||||
return mapped;
|
||||
}
|
||||
|
||||
function pushDescriptorRuntimeDisabledDiagnostic(params: {
|
||||
record: PluginManifestRecord;
|
||||
diagnostics: PluginSetupRegistryDiagnostic[];
|
||||
}): void {
|
||||
if (!resolveDeclaredSetupRuntimeSource(params.record)) {
|
||||
return;
|
||||
}
|
||||
params.diagnostics.push({
|
||||
pluginId: params.record.id,
|
||||
code: "setup-descriptor-runtime-disabled",
|
||||
message:
|
||||
"setup.requiresRuntime is false, so OpenClaw ignored the plugin setup runtime entry. Remove setup-api/openclaw.setupEntry or set requiresRuntime true if setup lookup still needs plugin code.",
|
||||
});
|
||||
}
|
||||
|
||||
function pushSetupDescriptorDriftDiagnostics(params: {
|
||||
record: PluginManifestRecord;
|
||||
providers: readonly ProviderPlugin[];
|
||||
@@ -504,6 +540,13 @@ export function resolvePluginSetupRegistry(params?: {
|
||||
if (selectedPluginIds && !selectedPluginIds.has(record.id)) {
|
||||
continue;
|
||||
}
|
||||
if (record.setup?.requiresRuntime === false) {
|
||||
pushDescriptorRuntimeDisabledDiagnostic({
|
||||
record,
|
||||
diagnostics,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
const setupRegistration = resolveSetupRegistration(record);
|
||||
if (!setupRegistration) {
|
||||
continue;
|
||||
|
||||
Reference in New Issue
Block a user