Skip to content

feat(runtime): add LLVM Wasm plugin runtime and Rust Arrow example - #6069

Open
likun666661 wants to merge 1 commit into
mainfrom
feat/llvm-wasm-plugin-runtime
Open

likun666661 wants to merge 1 commit into
mainfrom
feat/llvm-wasm-plugin-runtime

Conversation

@likun666661

Copy link
Copy Markdown
Member

Summary

This PR adds an experimental language-neutral core-Wasm plugin path to Maka and uses a Rust Apache Arrow Compute plugin as the first real example.

The current JavaScript/TypeScript plugin loader remains unchanged. A package opts into the new path with runtime.format = "wasm" and runtime.abi = "maka:plugin/runtime@1".

Why LLVM makes Rust plugins possible

Maka does not need to understand Rust source code or embed a Rust runtime. Rust code is compiled by rustc, whose backend lowers the program through LLVM to wasm32-unknown-unknown. The resulting Wasm core module exports the small Maka ABI:

  • linear memory
  • manifest pointer and length
  • guest allocator and free functions
  • JSON Tool invocation returning a packed pointer/length i64

The Runtime Host validates the manifest, starts the module in a worker with no imports, enforces memory/input/output/time limits, and adapts each manifest contribution into the existing PluginToolService. The resulting Tool is indistinguishable from a JavaScript plugin Tool to the rest of Maka.

Rust + Arrow Compute
        | rustc / LLVM backend
        v
wasm32-unknown-unknown core module
        | maka:plugin/runtime@1
        v
WasmPluginRuntime worker
        | existing Tool adapter
        v
PluginToolService -> Maka Tool

This is why the approach extends beyond Rust: C, C++, Zig, Swift, or another LLVM frontend can target the same Wasm ABI. LLVM is the compilation and audit layer; it is not a Runtime Host dependency.

Arrow example

experiments/llvm-plugin/arrow-data-analysis is a complete Rust plugin package:

  • summary builds an Arrow Float64Array and computes sum, min, max, mean, and null statistics.
  • group_sum builds Arrow numeric/string arrays and computes per-group aggregates.
  • maka.extension.json declares the Wasm runtime.
  • maka.composition.yml installs the arrow_analyze Tool at profile scope.
  • e2e.mjs installs the package through the real HostPluginPlatform, invokes it, and uninstalls it.
  • deepseek-e2e.mjs optionally exercises DeepSeek function calling through the same Tool. It only reads DEEPSEEK_API_KEY from the environment and never prints it.

The local DeepSeek run completed successfully: DeepSeek selected group_sum, the Arrow plugin returned east = 120 and west = 280, and DeepSeek generated a follow-up explanation from the Tool result.

Package boundary change

The hard 256-file plugin package limit is removed. The package store still enforces:

  • 8 MiB per file
  • 16 MiB total package bytes
  • canonical safe paths
  • no symlinks or unsupported filesystem entries

A regression test installs a package with 300 files successfully.

Design and scope

  • Experimental core-Wasm transport only; this is not yet the Wasm Component Model.
  • Tool contributions only; Executor, LSP, UI, and other high-authority capabilities are intentionally not exposed by this ABI.
  • No host imports are available to guest modules. Filesystem, network, Context, and Node access require a future explicit capability ABI.
  • Existing JavaScript package loading and Tool composition behavior remain supported.
  • Rust SDK, C ABI header, and Rust/C/Zig templates are included for follow-up language support.

Verification

  • npm --workspace @maka/runtime-host run typecheck — passed
  • npm --workspace @maka/runtime-host run build — passed
  • node --test --test-name-pattern="loads the versioned Wasm tool ABI" packages/runtime-host/dist/__tests__/wasm-plugin-runtime.test.js — passed
  • node --test --test-name-pattern="Plugin packages do not impose a file-count cap" packages/runtime-host/dist/__tests__/plugin-platform.test.js — passed
  • cargo check --manifest-path experiments/llvm-plugin/arrow-data-analysis/Cargo.toml — passed
  • cd experiments/llvm-plugin && node sdk/build.mjs rust ../arrow-data-analysis — produced dist/plugin.wasm
  • node experiments/llvm-plugin/arrow-data-analysis/e2e.mjs — passed summary and group_sum installation/invocation/uninstall flow
  • node experiments/llvm-plugin/arrow-data-analysis/deepseek-e2e.mjs — passed with the local DeepSeek API key
  • node scripts/asf-license-headers.mjs check — passed
  • git diff --check and targeted Biome checks — passed

The full Runtime Host suite was not used as the acceptance gate because the existing checkout has unrelated baseline failures in ACP/deep-research fixtures and hosted execution metadata.

AI use

  • No generative tool made a substantive contribution
  • Generative tooling made a substantive contribution

Tool(s) and scope: OpenAI Codex authored the implementation, tests, architecture documentation, and verification commands under human direction. The commit retains Generated-by: Codex.

Checklist

  • Tests cover the change and fail without it
  • Lint, format, typecheck and the affected suites pass locally

Does this PR entail a change in behavior?

  • Yes — Maka can now load experimental core-Wasm Tool plugins; the behavior and limitations are described above.
  • No

@github-actions github-actions Bot added the effort/XL Under 2500 readable lines label Oct 11, 2026
Add the experimental maka:plugin/runtime@1 core-Wasm ABI, Rust/C/Zig SDK templates, and a Rust Apache Arrow Compute Tool example. Keep the existing JavaScript loader path intact while allowing Rust-generated Wasm modules to register ordinary Maka Tools.

Remove the plugin package file-count cap while retaining per-file and total package byte limits. Add Runtime Host, package lifecycle, Arrow, and DeepSeek Tool Calling verification.

Generated-by: Codex
@likun666661
likun666661 force-pushed the feat/llvm-wasm-plugin-runtime branch from 7912df6 to b9188dc Compare October 11, 2026 14:31

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review notice: This comment was posted by an automated review agent. It is not an independent human review and does not replace one.

I found two P2 issues at b9188dc761bb25ab0b1c7c8e161fbf8d60a38a5f.

  • P2 — preserve the memory limit through guest cleanup (packages/runtime-host/src/server/wasm-plugin-worker.ts:124–125). The memory check occurs before the guest's two maka_plugin_free calls. A controlled module grows its memory to 128 MiB in free, yet the real runtime returns a successful first invocation; only the next invocation reports the exceeded 64 MiB limit. Thus the check neither bounds guest execution nor guarantees the retained worker satisfies the advertised limit. Enforce a maximum before guest execution, including module instantiation/start, initialization, allocation, invocation, and cleanup. Adding a post-cleanup check catches this reproduction but is not sufficient to prevent allocation above the limit. A Worker shares the host process's resource exposure; Node's documentation also explains that JavaScript heap limits do not limit ArrayBuffers.
  • P2 — do not forward unsupported parent-process flags to the Worker (packages/runtime-host/src/server/wasm-plugin-runtime.ts:88). Filtering only --input-type leaves ordinary Node/V8 flags such as --stack-trace-limit=10. Running the new test with that flag reproduces ERR_WORKER_INVALID_EXEC_ARGV before the plugin initializes. Exact-head CI run 38147503774 fails in this newly added test with the same error and additional inherited flags. An isolated generated-code control using an empty argument list passes the same test. Use an explicit supported argument policy rather than copying the parent list.

I cannot support production integration of this new runtime on the current evidence. The Arrow example can demonstrate feasibility, but does not establish why a new permanent plugin ABI and three-language SDK are needed instead of the existing Tool integration or a separate computation service. Please provide that requirement and the intended compatibility/maintenance commitment, or keep the prototype outside production loading. Also justify removing the file-count limit from all plugin packages: the remaining byte budget counts file contents, not empty files or path metadata.

Validation and limits:

  • Fresh dependency installation and the normal full root build passed. The two complete Wasm/platform test files passed all 46 tests; Host type checking and ASF header checks passed.
  • Independent controlled modules verified rejection of an unavailable host import, cancellation of an infinite invocation, and rejection of an oversized initial memory after instantiation. They also reproduced the cleanup bypass above. I did not perform an out-of-memory stress test or verify a pre-instantiation resource bound.
  • The complete local Host run was not green: 2,130 passed, one sandbox-execution assertion failed, six resumable-stream tests were cancelled, and 19 were skipped. I have not independently established those failures on the parent checkout and do not present them as additional PR findings.
  • No Wasm/object binaries or vendored crates are committed in the added experiment tree. I retrieved declared license metadata for all 105 registry packages in the Cargo lock; that is not a target-resolved binary dependency or NOTICE audit. Permissive license alternatives must be selected and any required notices retained under the ASF third-party policy. I found no basis here for asserting a prohibited dependency, but cannot claim full binary-license closure.
  • Rust, LLVM, and Zig compilers are unavailable locally. I did not independently build the Arrow/template binaries or run the live DeepSeek example; the author's results are not my verification.
  • The branch's parent advertises epoch 191. Its merge with current main 6b9457f5bb3c1af96e65ec9a12cc6bae63f49aaa is clean and passes the epoch-217 guard; no protocol-file change requires another epoch on that merged tree. Exact head remains unchanged and CI is failing as described above.

checkMemory(wasm.memory);
return response;
} finally {
wasm.maka_plugin_free(inputPtr, encoded.byteLength);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The memory check above precedes both calls into guest maka_plugin_free. I reproduced a module whose free grows linear memory to 128 MiB: the first real runtime invocation still succeeds and retains the oversized worker, while only a later invocation detects the exceeded 64 MiB limit. Bound memory before executing guest code and cover cleanup/start/init/exception paths as well. A post-free check catches the successful-response hole, but alone cannot prevent excessive allocation inside guest code.

throw new Error('Wasm plugin entry exceeds its size limit');
}
const worker = new Worker(new URL('./wasm-plugin-worker.js', import.meta.url), {
execArgv: process.execArgv.filter((argument) => !argument.startsWith('--input-type')),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: --input-type is not the only parent flag rejected by Worker. node --stack-trace-limit=10 --test packages/runtime-host/dist/__tests__/wasm-plugin-runtime.test.js fails with ERR_WORKER_INVALID_EXEC_ARGV at this constructor. Exact-head CI 38147503774 fails in the added test for the same reason. A generated-code control with execArgv: [] passes the same test. Do not copy arbitrary process.execArgv; select only explicitly supported worker arguments.

This branch has not been deployed

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

Labels

effort/XL Under 2500 readable lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants