Skip to content

Commit 2ff0e02

Browse files
committed
fix: apply tool policy before PTC bridge creation
The sandbox bridge was built from allTools before applyToolPolicy ran, so the mux.* API inside code_execution ignored allow/deny filters. Now the policy is applied first, and policyFilteredTools is passed to ToolBridge, ensuring the sandbox only exposes policy-allowed tools.
1 parent 6edb774 commit 2ff0e02

File tree

2 files changed

+18
-11
lines changed

2 files changed

+18
-11
lines changed

src/browser/utils/messages/StreamingMessageAggregator.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,7 @@ describe("StreamingMessageAggregator", () => {
653653
messageId: "msg-1",
654654
historySequence: 1,
655655
model: "claude-3-5-sonnet-20241022",
656+
startTime: Date.now(),
656657
});
657658

658659
// Start parent code_execution tool
@@ -707,6 +708,7 @@ describe("StreamingMessageAggregator", () => {
707708
messageId: "msg-1",
708709
historySequence: 1,
709710
model: "claude-3-5-sonnet-20241022",
711+
startTime: Date.now(),
710712
});
711713

712714
aggregator.handleToolCallStart({
@@ -766,6 +768,7 @@ describe("StreamingMessageAggregator", () => {
766768
messageId: "msg-1",
767769
historySequence: 1,
768770
model: "claude-3-5-sonnet-20241022",
771+
startTime: Date.now(),
769772
});
770773

771774
aggregator.handleToolCallStart({
@@ -853,6 +856,7 @@ describe("StreamingMessageAggregator", () => {
853856
messageId: "msg-1",
854857
historySequence: 1,
855858
model: "claude-3-5-sonnet-20241022",
859+
startTime: Date.now(),
856860
});
857861

858862
// Try to add nested call with non-existent parent
@@ -884,6 +888,7 @@ describe("StreamingMessageAggregator", () => {
884888
messageId: "msg-1",
885889
historySequence: 1,
886890
model: "claude-3-5-sonnet-20241022",
891+
startTime: Date.now(),
887892
});
888893

889894
aggregator.handleToolCallStart({

src/node/services/aiService.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,8 +1279,13 @@ export class AIService extends EventEmitter {
12791279
mcpTools
12801280
);
12811281

1282+
// Apply tool policy FIRST - this must happen before PTC to ensure sandbox
1283+
// respects allow/deny filters. The policy-filtered tools are passed to
1284+
// ToolBridge so the mux.* API only exposes policy-allowed tools.
1285+
const policyFilteredTools = applyToolPolicy(allTools, toolPolicy);
1286+
12821287
// Handle PTC experiments - add or replace tools with code_execution
1283-
let toolsWithPTC = allTools;
1288+
let tools = policyFilteredTools;
12841289
if (experiments?.programmaticToolCalling || experiments?.programmaticToolCallingExclusive) {
12851290
try {
12861291
// Lazy-load PTC modules only when experiments are enabled
@@ -1295,8 +1300,8 @@ export class AIService extends EventEmitter {
12951300
// Console events are not streamed (appear in final result only)
12961301
};
12971302

1298-
// ToolBridge determines which tools can be bridged into the sandbox
1299-
const toolBridge = new ptc.ToolBridge(allTools);
1303+
// ToolBridge uses policy-filtered tools - sandbox only exposes allowed tools
1304+
const toolBridge = new ptc.ToolBridge(policyFilteredTools);
13001305

13011306
// Singleton runtime factory (WASM module is expensive to load)
13021307
ptc.runtimeFactory ??= new ptc.QuickJSRuntimeFactory();
@@ -1310,22 +1315,19 @@ export class AIService extends EventEmitter {
13101315
if (experiments?.programmaticToolCallingExclusive) {
13111316
// Exclusive mode: code_execution + non-bridgeable tools (web_search, propose_plan, etc.)
13121317
// Non-bridgeable tools can't be used from within code_execution, so they're still
1313-
// available directly to the model
1318+
// available directly to the model (subject to policy)
13141319
const nonBridgeable = toolBridge.getNonBridgeableTools();
1315-
toolsWithPTC = { ...nonBridgeable, code_execution: codeExecutionTool };
1320+
tools = { ...nonBridgeable, code_execution: codeExecutionTool };
13161321
} else {
1317-
// Supplement mode: add code_execution alongside other tools
1318-
toolsWithPTC = { ...allTools, code_execution: codeExecutionTool };
1322+
// Supplement mode: add code_execution alongside policy-filtered tools
1323+
tools = { ...policyFilteredTools, code_execution: codeExecutionTool };
13191324
}
13201325
} catch (error) {
1321-
// Fall back to base tools if PTC creation fails
1326+
// Fall back to policy-filtered tools if PTC creation fails
13221327
log.error("Failed to create code_execution tool, falling back to base tools", { error });
13231328
}
13241329
}
13251330

1326-
// Apply tool policy to filter tools (if policy provided)
1327-
const tools = applyToolPolicy(toolsWithPTC, toolPolicy);
1328-
13291331
const effectiveMcpStats: MCPWorkspaceStats =
13301332
mcpStats ??
13311333
({

0 commit comments

Comments
 (0)