Extension fails to load: Cannot find package '@earendil-works/pi-ai' (native dynamic import() bypasses the host alias)
Package: pi-agent-browser-native@0.7.1
Pi version: 0.87.1 (built Node.js install, not the compiled binary)
OS: Windows 11
Summary
The extension fails to load with the following error:
Extension "…/pi-agent-browser-native/dist/extensions/agent-browser/index.js" error:
Cannot find package '@earendil-works/pi-ai' imported from
…/pi-agent-browser-native/dist/extensions/agent-browser/lib/tool-surface.js
at Object.getPackageJSONURL (node:internal/modules/package_json_reader:301:9)
at packageResolve (node:internal/modules/esm/resolve:768:81)
at moduleResolve (node:internal/modules/esm/resolve:859:18)
at defaultResolve (node:internal/modules/esm/resolve:992:11)
at #cachedDefaultResolve (node:internal/modules/esm/loader:691:20)
at #resolveAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:708:38)
at ModuleLoader.resolveSync (node:internal/modules/esm/loader:740:52)
at #resolve (node:internal/modules/esm/loader:673:17)
at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:593:35)
at node:internal/modules/esm/loader:622:32
Root cause
dist/extensions/agent-browser/lib/tool-surface.js imports @earendil-works/pi-ai using a
native dynamic import():
// dist/extensions/agent-browser/lib/tool-surface.js:132
const { getCurrentSystemMessage } = await import("@earendil-works/pi-ai");
Pi does not install @earendil-works/pi-ai next to extensions — it is a host-provided peer
dependency (docs/packages.md: "Pi supplies these packages to extensions and skills"). Pi
injects them at load time through its jiti loader:
- In the compiled binary / bundled distribution, via
virtualModules
(dist/core/extensions/virtual-modules.js, VIRTUAL_MODULES).
- In the unbundled Node.js build, via
alias (dist/core/extensions/loader.js, getAliases()).
Both mechanisms only intercept static imports and require(...). A native dynamic
await import(...) inside an ESM file bypasses jiti entirely and hits Node's real ESM
resolver — which is exactly what the stack trace shows (node:internal/modules/esm/loader).
Since the package is not present in the extension's node_modules, resolution fails.
This is not a user configuration problem; other extensions in the same install (e.g.
pi-hermes-memory) import @earendil-works/pi-ai successfully because they use static
imports that jiti rewrites.
Suggested fix
Use a static import instead of the dynamic one, so the host alias is applied:
import { getCurrentSystemMessage } from "@earendil-works/pi-ai";
// …
const current = getCurrentSystemMessage(ctx.sessionManager.buildSessionProjection().messages);
If the import genuinely must stay lazy (the comment says it should remain "behind the awaited
restoration boundary"), options are:
- Use jiti's own dynamic import mechanism rather than the native one, or
- Import a stable host-provided wrapper that can be loaded statically and defer only the call, or
- Document that pi must be run in a mode where the module is resolvable (not applicable for the
standard Node.js install).
Reproduction
- Install pi
0.87.1 (built Node.js distribution).
- Add the package:
pi settings packages: ["npm:pi-agent-browser-native"].
- Start pi. The extension errors during load and none of the browser tools register.
Extension fails to load:
Cannot find package '@earendil-works/pi-ai'(native dynamicimport()bypasses the host alias)Package:
pi-agent-browser-native@0.7.1Pi version:
0.87.1(built Node.js install, not the compiled binary)OS: Windows 11
Summary
The extension fails to load with the following error:
Root cause
dist/extensions/agent-browser/lib/tool-surface.jsimports@earendil-works/pi-aiusing anative dynamic
import():Pi does not install
@earendil-works/pi-ainext to extensions — it is a host-provided peerdependency (
docs/packages.md: "Pi supplies these packages to extensions and skills"). Piinjects them at load time through its jiti loader:
virtualModules(
dist/core/extensions/virtual-modules.js,VIRTUAL_MODULES).alias(dist/core/extensions/loader.js,getAliases()).Both mechanisms only intercept static imports and
require(...). A native dynamicawait import(...)inside an ESM file bypasses jiti entirely and hits Node's real ESMresolver — which is exactly what the stack trace shows (
node:internal/modules/esm/loader).Since the package is not present in the extension's
node_modules, resolution fails.This is not a user configuration problem; other extensions in the same install (e.g.
pi-hermes-memory) import@earendil-works/pi-aisuccessfully because they use staticimports that jiti rewrites.
Suggested fix
Use a static import instead of the dynamic one, so the host alias is applied:
If the import genuinely must stay lazy (the comment says it should remain "behind the awaited
restoration boundary"), options are:
standard Node.js install).
Reproduction
0.87.1(built Node.js distribution).pisettingspackages: ["npm:pi-agent-browser-native"].