fix(agents): pass embedded tool allowlist to pi sessions

This commit is contained in:
Peter Steinberger
2026-04-23 01:55:14 +01:00
parent 2ba43f5d27
commit f78fc61768
6 changed files with 12 additions and 20 deletions

View File

@@ -12,11 +12,10 @@ describe("splitSdkTools", () => {
];
it("routes all tools to customTools when sandboxed", () => {
const { builtInTools, customTools } = splitSdkTools({
const { customTools } = splitSdkTools({
tools,
sandboxEnabled: true,
});
expect(builtInTools).toEqual([]);
expect(customTools.map((tool) => tool.name)).toEqual([
"read",
"exec",
@@ -27,11 +26,10 @@ describe("splitSdkTools", () => {
});
it("routes all tools to customTools even when not sandboxed", () => {
const { builtInTools, customTools } = splitSdkTools({
const { customTools } = splitSdkTools({
tools,
sandboxEnabled: false,
});
expect(builtInTools).toEqual([]);
expect(customTools.map((tool) => tool.name)).toEqual([
"read",
"exec",

View File

@@ -389,7 +389,7 @@ export async function loadCompactHooksHarness(): Promise<{
}));
vi.doMock("./tool-split.js", () => ({
splitSdkTools: vi.fn(() => ({ builtInTools: [], customTools: [] })),
splitSdkTools: vi.fn(() => ({ customTools: [] })),
}));
vi.doMock("./compaction-safety-timeout.js", () => ({

View File

@@ -844,13 +844,12 @@ export async function compactEmbeddedPiSessionDirect(
contextTokenBudget: ctxInfo.tokens,
});
const { builtInTools, customTools } = splitSdkTools({
const { customTools } = splitSdkTools({
tools: effectiveTools,
sandboxEnabled: !!sandbox?.enabled,
});
// Pi only accepts built-in Tool[] at session creation time. After the
// session registers custom tools, narrow the active tool names against
// the exact OpenClaw-managed registrations.
// Pi treats `tools` as a name allowlist during session creation. Pass the
// exact OpenClaw-managed registrations so custom tools survive startup.
const sessionToolAllowlist = toSessionToolAllowlist(collectRegisteredToolNames(customTools));
const providerStreamFn = resolveCompactionProviderStream({
@@ -889,7 +888,7 @@ export async function compactEmbeddedPiSessionDirect(
modelRegistry,
model: effectiveModel,
thinkingLevel: mapThinkingLevel(thinkLevel),
tools: builtInTools,
tools: sessionToolAllowlist,
customTools,
sessionManager,
settingsManager,

View File

@@ -603,7 +603,6 @@ vi.mock("../tool-name-allowlist.js", () => ({
vi.mock("../tool-split.js", () => ({
splitSdkTools: ({ tools }: { tools: unknown[] }) => ({
builtInTools: [],
customTools: tools,
}),
}));

View File

@@ -1068,7 +1068,7 @@ export async function runEmbeddedAttempt(
// Get hook runner early so it's available when creating tools
const hookRunner = getGlobalHookRunner();
const { builtInTools, customTools } = splitSdkTools({
const { customTools } = splitSdkTools({
tools: effectiveTools,
sandboxEnabled: !!sandbox?.enabled,
});
@@ -1127,10 +1127,9 @@ export async function runEmbeddedAttempt(
: [];
const allCustomTools = [...customTools, ...clientToolDefs];
// Pi only accepts built-in Tool[] at session creation time. After the
// session registers custom tools, narrow the active tool names against
// the exact OpenClaw-managed registrations so client-provided names do
// not broaden the prompt/runtime boundary.
// Pi treats `tools` as a name allowlist during session creation. Pass the
// exact OpenClaw-managed registrations so custom tools survive startup and
// client-provided names do not broaden the prompt/runtime boundary.
const sessionToolAllowlist = toSessionToolAllowlist(
collectRegisteredToolNames(allCustomTools),
);
@@ -1147,7 +1146,7 @@ export async function runEmbeddedAttempt(
modelRegistry: params.modelRegistry,
model: params.model,
thinkingLevel: mapThinkingLevel(params.thinkLevel),
tools: builtInTools,
tools: sessionToolAllowlist,
customTools: allCustomTools,
sessionManager,
settingsManager,

View File

@@ -1,5 +1,4 @@
import type { AgentTool } from "@mariozechner/pi-agent-core";
import type { CreateAgentSessionOptions } from "@mariozechner/pi-coding-agent";
import { toToolDefinitions } from "../pi-tool-definition-adapter.js";
// We always pass tools via `customTools` so our policy filtering, sandbox integration,
@@ -7,12 +6,10 @@ import { toToolDefinitions } from "../pi-tool-definition-adapter.js";
type AnyAgentTool = AgentTool;
export function splitSdkTools(options: { tools: AnyAgentTool[]; sandboxEnabled: boolean }): {
builtInTools: NonNullable<CreateAgentSessionOptions["tools"]>;
customTools: ReturnType<typeof toToolDefinitions>;
} {
const { tools } = options;
return {
builtInTools: [],
customTools: toToolDefinitions(tools),
};
}