Skip to content

Extension fails to load: Cannot find package '@earendil-works/pi-ai' (native dynamic import bypasses host alias) #210

Description

@diegorlfernandes

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

  1. Install pi 0.87.1 (built Node.js distribution).
  2. Add the package: pi settings packages: ["npm:pi-agent-browser-native"].
  3. Start pi. The extension errors during load and none of the browser tools register.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions