@@ -30,6 +30,7 @@ const effectiveInventoryState = vi.hoisted(() => ({
3030 mockTool ( { name : "docs_lookup" , label : "Docs Lookup" , description : "Search docs" } ) ,
3131 ] as AnyAgentTool [ ] ,
3232 pluginMeta : { } as Record < string , { pluginId : string } | undefined > ,
33+ pluginMetaByTool : new WeakMap < object , { pluginId : string } > ( ) ,
3334 channelMeta : { } as Record < string , { channelId : string } | undefined > ,
3435 effectivePolicy : { } as { profile ?: string ; providerProfile ?: string } ,
3536 normalizeToolsMock : vi . fn ( ( options : { tools : AnyAgentTool [ ] } ) => options . tools ) ,
@@ -61,7 +62,9 @@ vi.mock("./agent-tools.js", () => ({
6162} ) ) ;
6263
6364vi . mock ( "../plugins/tools.js" , ( ) => ( {
64- getPluginToolMeta : ( tool : { name : string } ) => effectiveInventoryState . pluginMeta [ tool . name ] ,
65+ getPluginToolMeta : ( tool : { name : string } ) =>
66+ effectiveInventoryState . pluginMetaByTool . get ( tool ) ??
67+ effectiveInventoryState . pluginMeta [ tool . name ] ,
6568 buildPluginToolMetadataKey : ( pluginId : string , toolName : string ) =>
6669 JSON . stringify ( [ pluginId , toolName ] ) ,
6770} ) ) ;
@@ -115,6 +118,7 @@ async function loadHarness(options?: {
115118 tools ?: AnyAgentTool [ ] ;
116119 createToolsMock ?: typeof effectiveInventoryState . createToolsMock ;
117120 pluginMeta ?: Record < string , { pluginId : string } | undefined > ;
121+ pluginMetaByTool ?: WeakMap < object , { pluginId : string } > ;
118122 channelMeta ?: Record < string , { channelId : string } | undefined > ;
119123 effectivePolicy ?: { profile ?: string ; providerProfile ?: string } ;
120124 normalizeToolsMock ?: typeof effectiveInventoryState . normalizeToolsMock ;
@@ -124,6 +128,7 @@ async function loadHarness(options?: {
124128 mockTool ( { name : "docs_lookup" , label : "Docs Lookup" , description : "Search docs" } ) ,
125129 ] ;
126130 effectiveInventoryState . pluginMeta = options ?. pluginMeta ?? { } ;
131+ effectiveInventoryState . pluginMetaByTool = options ?. pluginMetaByTool ?? new WeakMap ( ) ;
127132 effectiveInventoryState . channelMeta = options ?. channelMeta ?? { } ;
128133 effectiveInventoryState . effectivePolicy = options ?. effectivePolicy ?? { } ;
129134 effectiveInventoryState . normalizeToolsMock =
@@ -151,6 +156,7 @@ describe("resolveEffectiveToolInventory", () => {
151156 mockTool ( { name : "docs_lookup" , label : "Docs Lookup" , description : "Search docs" } ) ,
152157 ] ;
153158 effectiveInventoryState . pluginMeta = { } ;
159+ effectiveInventoryState . pluginMetaByTool = new WeakMap ( ) ;
154160 effectiveInventoryState . channelMeta = { } ;
155161 effectiveInventoryState . effectivePolicy = { } ;
156162 effectiveInventoryState . normalizeToolsMock = vi . fn ( ( options ) => options . tools ) ;
@@ -380,6 +386,43 @@ describe("resolveEffectiveToolInventory", () => {
380386 ] ) ;
381387 } ) ;
382388
389+ it ( "preserves plugin ownership for unreadable pre-normalization tool names" , async ( ) => {
390+ const unreadable = mockTool ( {
391+ name : "fuzzplugin_move_angles" ,
392+ label : "Fuzzplugin Move Angles" ,
393+ description : "Move fixture joints" ,
394+ } ) ;
395+ Object . defineProperty ( unreadable , "name" , {
396+ enumerable : true ,
397+ get ( ) {
398+ throw new Error ( "fuzzplugin name getter exploded" ) ;
399+ } ,
400+ } ) ;
401+ const pluginMetaByTool = new WeakMap < object , { pluginId : string } > ( [
402+ [ unreadable , { pluginId : "fuzzplugin" } ] ,
403+ ] ) ;
404+ const { resolveEffectiveToolInventory : resolveEffectiveToolInventoryLocal14 } =
405+ await loadHarness ( {
406+ tools : [
407+ unreadable ,
408+ mockTool ( { name : "exec" , label : "Exec" , description : "Run shell commands" } ) ,
409+ ] ,
410+ pluginMetaByTool,
411+ } ) ;
412+
413+ const result = resolveEffectiveToolInventoryLocal14 ( { cfg : { } } ) ;
414+
415+ expect ( result . groups . flatMap ( ( group ) => group . tools . map ( ( tool ) => tool . id ) ) ) . toEqual ( [ "exec" ] ) ;
416+ expect ( result . notices ) . toEqual ( [
417+ {
418+ id : "unsupported-tool-schema:tool[0]" ,
419+ severity : "warning" ,
420+ message :
421+ 'Tool "tool[0]" from plugin "fuzzplugin" has an unsupported runtime input schema (tool[0].name is unreadable) and was quarantined before model projection. Fix or disable the owner, or remove the tool from active allowlists.' ,
422+ } ,
423+ ] ) ;
424+ } ) ;
425+
383426 it ( "reports unreadable inventory tool entries without crashing" , async ( ) => {
384427 const healthy = mockTool ( { name : "exec" , label : "Exec" , description : "Run shell commands" } ) ;
385428 const tools = new Proxy ( [ healthy ] as AnyAgentTool [ ] , {
0 commit comments