[AAASM-3532] 🐛 (adapters): Patch frameworks via shim instead of mutating frozen ESM#175
Conversation
The Vercel adapter assigned `module.tool = governed` onto the loaded `ai`
module. When a consumer has the real `ai` 5.x/6.x installed, its namespace is
a frozen ES-module exotic object whose named exports are non-writable, so the
assignment throws `Cannot assign to read only property 'tool'` and crashes
`initAssembly()`.
Install the governed factory through `applyGovernedToolFactory`: assign in
place only for writable plain objects (the unit suite's loadModule fakes), and
otherwise fall back to a mutable shim copy `{ ...module, tool: governed }` —
the approach the AAASM-3525 driver proved works — never touching the frozen
namespace. `unpatch` restores the original only when it was mutated in place.
Refs AAASM-3532
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The `.pnpmfile.cjs` from PR #174 stripped `ai` from this repo's install to avoid the frozen-ESM crash in the unit suite. With AAASM-3532 fixed, that workaround is no longer needed for `ai`: add `ai` as a devDependency and drop it from the strip list so the real-module regression test exercises the genuine frozen namespace. `@langchain/langgraph` / `@mastra/core` stay stripped — their adapters mutate a class prototype (not the namespace) and never crashed. Refs AAASM-3532 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drive `patchVercelAiSdk` against the real, frozen `ai` namespace via the default loader (no loadModule fake) and assert: patching no longer crashes, the original `ai.tool` export is left untouched, and governance (deny/allow) flows through the governed factory on the shim copy. This test crashes with `Cannot assign to read only property 'tool'` under the pre-fix code. Reset the new `mutatedOriginal` patch-state field in the existing suite's teardown. Refs AAASM-3532 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
|
|
Claude Code — review result ✅ All CI checks green, mergeable (state BLOCKED = awaiting the required approval only). Root cause: the Vercel AI adapter assigned Fix reviewed: Coverage: new Ready to merge. Closes AAASM-3532. |



Target
Task summary:
Fix the Vercel AI SDK (and audit the other framework) adapters crashing with
Cannot assign to read only property 'tool'when a consumer has the realai5.x/6.x installed.
initAssembly()patched governance by assigning onto thefrozen ES-module namespace, which throws.
Task tickets:
{ tool: aiModule.tool }shim copy works)..pnpmfile.cjsthat strippedaito work around this crash).Key point change:
src/hooks/ai-sdk.tsdidmodule.tool = createPatchedToolFactory(...).A real
aipackage loaded viaimport()is an ES module whose namespace is a frozenexotic object — named exports are non-writable — so the assignment throws.
applyGovernedToolFactory()installs the governed factory withoutmutating the frozen namespace. It assigns in place only for writable plain objects
(the unit suite's
loadModulefakes); for the frozen-ESM case it falls back to amutable shim copy
{ ...module, tool: governed }(the AAASM-3525 approach). A newmutatedOriginalflag makesunpatchrestore the original only when it was mutated.langgraph.ts,mastra.ts, andopenai-agents.tsmutate a class prototype (e.g.module.StateGraph.prototype.compile), not the namespace binding, which is a normalmutable object — verified safe through a frozen namespace, so they need no change.
aiis now an installable devDependency (removed from the.pnpmfile.cjsstrip list) so the new regression test exercises the real frozen
aimodule.Effecting Scope
No public API change; the SDK now patches the real
aipackage without crashing.Description
src/hooks/ai-sdk.ts:185,210— replace the frozen-namespace mutation with a shim-awareapplyGovernedToolFactory();unpatchonly restores when the original was mutated in place.tests/vercel-ai-real-module.test.ts— new regression suite drivingpatchVercelAiSdkagainst the real frozen
ainamespace via the default loader (not a shim/fake): itproves patching no longer crashes, the real
ai.toolexport is untouched, and deny/allowgovernance flows through the governed factory. This test crashes under the pre-fix code.
.pnpmfile.cjs/package.json— install realai(^6.0.0) as a devDependency; keep@langchain/langgraph/@mastra/corestripped (their adapters never crashed).Validation
pnpm install,pnpm test(330 passed, 2 skipped),pnpm lint,pnpm typecheck,pnpm build— all green.Closes AAASM-3532
🤖 Generated with Claude Code