fix(plugins): log runtime deps staging progress

This commit is contained in:
Peter Steinberger
2026-04-25 01:42:11 +01:00
parent f9207e5d39
commit 867b4c2a32
3 changed files with 52 additions and 2 deletions

View File

@@ -11,6 +11,7 @@ Docs: https://docs.openclaw.ai
### Fixes
- Plugins/runtime deps: log bundled plugin runtime-dependency staging before synchronous npm installs start and include elapsed timing afterward, so first boot after upgrades no longer looks hung while dependencies are being repaired.
- Agents/failover: forward embedded run abort signals into provider-owned model streams, cap implicit LLM idle watchdogs below long run timeouts, and mark 429 responses without usable retry timing as non-retryable so GitHub Copilot rate limits fail over or surface promptly instead of hanging until run timeout. Fixes #71120.
- Plugins/Google Meet: make meeting creation join by default, with an explicit URL-only opt-out, so agents that create a Meet also enter it.
- Telegram/polling: persist accepted update offsets before long-running handlers complete so poller restarts do not replay already-ingested updates, while keeping same-process retries for handler failures.

View File

@@ -939,9 +939,16 @@ module.exports = {
"utf-8",
);
const installedSpecs: string[] = [];
const logger = {
info: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
debug: vi.fn(),
};
const registry = loadOpenClawPlugins({
cache: false,
logger,
config: {
plugins: {
enabled: true,
@@ -953,6 +960,9 @@ module.exports = {
},
},
bundledRuntimeDepsInstaller: ({ installRoot, missingSpecs }) => {
expect(logger.info).toHaveBeenCalledWith(
"[plugins] discord staging bundled runtime deps (1 missing, 1 install specs): discord-runtime@1.0.0",
);
installedSpecs.push(...missingSpecs);
expect(fs.realpathSync(installRoot)).toBe(fs.realpathSync(plugin.dir));
fs.mkdirSync(path.join(installRoot, "node_modules", "discord-runtime"), {
@@ -968,6 +978,11 @@ module.exports = {
expect(installedSpecs).toEqual(["discord-runtime@1.0.0"]);
expect(registry.plugins.find((entry) => entry.id === "discord")?.status).toBe("loaded");
expect(logger.info).toHaveBeenCalledWith(
expect.stringMatching(
/^\[plugins\] discord installed bundled runtime deps in \d+ms: discord-runtime@1\.0\.0$/u,
),
);
});
it("keeps bundled runtime dep install logs off non-activating loads", () => {
@@ -1040,6 +1055,9 @@ module.exports = {
expect(logger.info).not.toHaveBeenCalledWith(
"[plugins] discord installed bundled runtime deps: discord-runtime@1.0.0",
);
expect(logger.info).not.toHaveBeenCalledWith(
"[plugins] discord staging bundled runtime deps (1 missing, 1 install specs): discord-runtime@1.0.0",
);
});
it("does not repair disabled bundled plugin runtime deps", () => {

View File

@@ -34,6 +34,7 @@ import { buildPluginApi } from "./api-builder.js";
import { inspectBundleMcpRuntimeSupport } from "./bundle-mcp.js";
import {
ensureBundledPluginRuntimeDeps,
installBundledRuntimeDeps,
resolveBundledRuntimeDependencyInstallRoot,
type BundledRuntimeDepsInstallParams,
} from "./bundled-runtime-deps.js";
@@ -2325,6 +2326,8 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
candidate.origin === "bundled" &&
enableState.enabled
) {
let runtimeDepsInstallStartedAt: number | null = null;
let runtimeDepsInstallSpecs: string[] = [];
try {
const installRoot = resolveBundledRuntimeDependencyInstallRoot(pluginRoot, { env });
const retainSpecs = bundledRuntimeDepsRetainSpecsByInstallRoot.get(installRoot) ?? [];
@@ -2334,7 +2337,26 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
env,
config: cfg,
retainSpecs,
installDeps: options.bundledRuntimeDepsInstaller,
installDeps: (installParams) => {
const installSpecs = installParams.installSpecs ?? installParams.missingSpecs;
runtimeDepsInstallStartedAt = Date.now();
runtimeDepsInstallSpecs = installParams.missingSpecs;
if (shouldActivate) {
logger.info(
`[plugins] ${record.id} staging bundled runtime deps (${installParams.missingSpecs.length} missing, ${installSpecs.length} install specs): ${installParams.missingSpecs.join(", ")}`,
);
}
const installer =
options.bundledRuntimeDepsInstaller ??
((params: BundledRuntimeDepsInstallParams) =>
installBundledRuntimeDeps({
installRoot: params.installRoot,
installExecutionRoot: params.installExecutionRoot,
missingSpecs: params.installSpecs ?? params.missingSpecs,
env,
}));
installer(installParams);
},
});
if (depsInstallResult.installedSpecs.length > 0) {
bundledRuntimeDepsRetainSpecsByInstallRoot.set(
@@ -2344,8 +2366,12 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
),
);
if (shouldActivate) {
const elapsed =
runtimeDepsInstallStartedAt === null
? ""
: ` in ${Date.now() - runtimeDepsInstallStartedAt}ms`;
logger.info(
`[plugins] ${record.id} installed bundled runtime deps: ${depsInstallResult.installedSpecs.join(", ")}`,
`[plugins] ${record.id} installed bundled runtime deps${elapsed}: ${depsInstallResult.installedSpecs.join(", ")}`,
);
}
}
@@ -2371,6 +2397,11 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
ensureOpenClawPluginSdkAlias(path.dirname(path.dirname(pluginRoot)));
}
} catch (error) {
if (shouldActivate && runtimeDepsInstallStartedAt !== null) {
logger.error(
`[plugins] ${record.id} failed to stage bundled runtime deps after ${Date.now() - runtimeDepsInstallStartedAt}ms: ${runtimeDepsInstallSpecs.join(", ")}`,
);
}
pushPluginLoadError(`failed to install bundled runtime deps: ${String(error)}`);
continue;
}