@@ -3,7 +3,12 @@ import fs from "node:fs";
33import os from "node:os" ;
44import path from "node:path" ;
55import { describe , expect , it } from "vitest" ;
6+ import type { OpenClawConfig } from "../../config/types.openclaw.js" ;
67import { setPluginToolMeta } from "../../plugins/tools.js" ;
8+ import {
9+ type ConversationCapabilityProfileParams ,
10+ resolveConversationCapabilityProfile ,
11+ } from "../conversation-capability-profile.js" ;
712import type { AnyAgentTool } from "../tools/common.js" ;
813import { applyFinalEffectiveToolPolicy } from "./effective-tool-policy.js" ;
914
@@ -19,9 +24,33 @@ function makeTool(name: string): AnyAgentTool {
1924 } ;
2025}
2126
27+ // Mirrors the production composition: resolve the conversation capability
28+ // profile from server-verified inputs, then apply the final bundled pass.
29+ function applyFinalPolicy (
30+ params : {
31+ bundledTools : AnyAgentTool [ ] ;
32+ config ?: OpenClawConfig ;
33+ warn ?: ( message : string ) => void ;
34+ } & Pick <
35+ ConversationCapabilityProfileParams ,
36+ "sessionKey" | "messageProvider" | "senderId" | "groupId" | "groupChannel"
37+ > ,
38+ ) : AnyAgentTool [ ] {
39+ const { bundledTools, config, warn, ...profileParams } = params ;
40+ return applyFinalEffectiveToolPolicy ( {
41+ bundledTools,
42+ config,
43+ conversationCapabilityProfile : resolveConversationCapabilityProfile ( {
44+ config,
45+ ...profileParams ,
46+ } ) ,
47+ warn : warn ?? ( ( ) => { } ) ,
48+ } ) ;
49+ }
50+
2251describe ( "applyFinalEffectiveToolPolicy" , ( ) => {
2352 it ( "filters bundled tools through the configured allowlist" , ( ) => {
24- const filtered = applyFinalEffectiveToolPolicy ( {
53+ const filtered = applyFinalPolicy ( {
2554 bundledTools : [ makeTool ( "mcp__bundle__fs_delete" ) , makeTool ( "mcp__bundle__fs_read" ) ] ,
2655 config : { tools : { allow : [ "mcp__bundle__fs_read" ] } } ,
2756 warn : ( ) => { } ,
@@ -55,7 +84,7 @@ describe("applyFinalEffectiveToolPolicy", () => {
5584 "utf-8" ,
5685 ) ;
5786
58- const filtered = applyFinalEffectiveToolPolicy ( {
87+ const filtered = applyFinalPolicy ( {
5988 bundledTools : [ makeTool ( "mcp__bundle__fs_delete" ) , makeTool ( "mcp__bundle__fs_read" ) ] ,
6089 config : {
6190 session : {
@@ -96,7 +125,7 @@ describe("applyFinalEffectiveToolPolicy", () => {
96125 setPluginToolMeta ( deniedTool , { pluginId : "bundle-mcp" , optional : false } ) ;
97126 setPluginToolMeta ( allowedTool , { pluginId : "bundle-mcp" , optional : false } ) ;
98127
99- const filtered = applyFinalEffectiveToolPolicy ( {
128+ const filtered = applyFinalPolicy ( {
100129 bundledTools : [ deniedTool , allowedTool ] ,
101130 config : {
102131 session : {
@@ -120,7 +149,7 @@ describe("applyFinalEffectiveToolPolicy", () => {
120149 it ( "applies channel-normalized per-sender policy to bundled tools" , ( ) => {
121150 // Teams normalizes to msteams in policy keys, which must happen before
122151 // sender-specific deny rules are applied.
123- const filtered = applyFinalEffectiveToolPolicy ( {
152+ const filtered = applyFinalPolicy ( {
124153 bundledTools : [ makeTool ( "mcp__bundle__exec" ) , makeTool ( "mcp__bundle__read" ) ] ,
125154 config : {
126155 tools : {
@@ -138,7 +167,7 @@ describe("applyFinalEffectiveToolPolicy", () => {
138167 } ) ;
139168
140169 it ( "returns the empty array unchanged when there are no bundled tools" , ( ) => {
141- const filtered = applyFinalEffectiveToolPolicy ( {
170+ const filtered = applyFinalPolicy ( {
142171 bundledTools : [ ] ,
143172 config : { tools : { allow : [ "message" ] } } ,
144173 warn : ( ) => { } ,
@@ -149,7 +178,7 @@ describe("applyFinalEffectiveToolPolicy", () => {
149178
150179 it ( "drops caller-provided groupId when it disagrees with session-derived group context" , ( ) => {
151180 const warnings : string [ ] = [ ] ;
152- applyFinalEffectiveToolPolicy ( {
181+ applyFinalPolicy ( {
153182 bundledTools : [ makeTool ( "mcp__bundle__read" ) ] ,
154183 // Session key encodes a concrete group (discord room 111); caller tries
155184 // to override with a different group id so a more permissive group
@@ -167,7 +196,7 @@ describe("applyFinalEffectiveToolPolicy", () => {
167196
168197 it ( "drops caller-provided groupId when session encodes no group context (fail-closed)" , ( ) => {
169198 const warnings : string [ ] = [ ] ;
170- applyFinalEffectiveToolPolicy ( {
199+ applyFinalPolicy ( {
171200 bundledTools : [ makeTool ( "mcp__bundle__read" ) ] ,
172201 // Direct/non-group session key: no session-derived group ids. A caller
173202 // supplying a groupId here has no server-verified ground truth; it
@@ -185,7 +214,7 @@ describe("applyFinalEffectiveToolPolicy", () => {
185214
186215 it ( "leaves groupId untouched when caller did not supply one" , ( ) => {
187216 const warnings : string [ ] = [ ] ;
188- applyFinalEffectiveToolPolicy ( {
217+ applyFinalPolicy ( {
189218 bundledTools : [ makeTool ( "mcp__bundle__read" ) ] ,
190219 sessionKey : "agent:alice:main" ,
191220 warn : ( message ) => warnings . push ( message ) ,
@@ -198,7 +227,7 @@ describe("applyFinalEffectiveToolPolicy", () => {
198227
199228 it ( "does not emit unknown-entry warnings for core tool allowlists in the bundled pass" , ( ) => {
200229 const warnings : string [ ] = [ ] ;
201- applyFinalEffectiveToolPolicy ( {
230+ applyFinalPolicy ( {
202231 bundledTools : [ makeTool ( "mcp__bundle__read" ) ] ,
203232 // Core tool names like `read` and `exec` are not in the bundled-only
204233 // input here, but they are valid core tools resolved by the first
@@ -212,7 +241,7 @@ describe("applyFinalEffectiveToolPolicy", () => {
212241
213242 it ( "still warns on genuinely unknown entries in the bundled pass" , ( ) => {
214243 const warnings : string [ ] = [ ] ;
215- applyFinalEffectiveToolPolicy ( {
244+ applyFinalPolicy ( {
216245 bundledTools : [ makeTool ( "mcp__bundle__read" ) ] ,
217246 config : { tools : { allow : [ "mcp__bundle__read" , "totally-made-up-tool" ] } } ,
218247 warn : ( message ) => warnings . push ( message ) ,
@@ -225,7 +254,7 @@ describe("applyFinalEffectiveToolPolicy", () => {
225254 const mcpTool = makeTool ( "bundleProbe__bundle_probe" ) ;
226255 setPluginToolMeta ( mcpTool , { pluginId : "bundle-mcp" , optional : false } ) ;
227256
228- const filtered = applyFinalEffectiveToolPolicy ( {
257+ const filtered = applyFinalPolicy ( {
229258 bundledTools : [ mcpTool ] ,
230259 config : { tools : { profile : "coding" } } ,
231260 warn : ( ) => { } ,
@@ -238,7 +267,7 @@ describe("applyFinalEffectiveToolPolicy", () => {
238267 const mcpTool = makeTool ( "bundleProbe__bundle_probe" ) ;
239268 setPluginToolMeta ( mcpTool , { pluginId : "bundle-mcp" , optional : false } ) ;
240269
241- const filtered = applyFinalEffectiveToolPolicy ( {
270+ const filtered = applyFinalPolicy ( {
242271 bundledTools : [ mcpTool ] ,
243272 config : { tools : { profile : "coding" , deny : [ "bundle-mcp" ] } } ,
244273 warn : ( ) => { } ,
0 commit comments