From f78fc61768c9b56c01f499a42aa932c36e3ff636 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 23 Apr 2026 01:55:14 +0100 Subject: [PATCH] fix(agents): pass embedded tool allowlist to pi sessions --- src/agents/pi-embedded-runner.splitsdktools.test.ts | 6 ++---- .../pi-embedded-runner/compact.hooks.harness.ts | 2 +- src/agents/pi-embedded-runner/compact.ts | 9 ++++----- .../run/attempt.spawn-workspace.test-support.ts | 1 - src/agents/pi-embedded-runner/run/attempt.ts | 11 +++++------ src/agents/pi-embedded-runner/tool-split.ts | 3 --- 6 files changed, 12 insertions(+), 20 deletions(-) diff --git a/src/agents/pi-embedded-runner.splitsdktools.test.ts b/src/agents/pi-embedded-runner.splitsdktools.test.ts index fb212ca1dc2..b950405b03b 100644 --- a/src/agents/pi-embedded-runner.splitsdktools.test.ts +++ b/src/agents/pi-embedded-runner.splitsdktools.test.ts @@ -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", diff --git a/src/agents/pi-embedded-runner/compact.hooks.harness.ts b/src/agents/pi-embedded-runner/compact.hooks.harness.ts index cb777f33fb8..56dca4071cb 100644 --- a/src/agents/pi-embedded-runner/compact.hooks.harness.ts +++ b/src/agents/pi-embedded-runner/compact.hooks.harness.ts @@ -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", () => ({ diff --git a/src/agents/pi-embedded-runner/compact.ts b/src/agents/pi-embedded-runner/compact.ts index c5eed580ec1..701139f89a6 100644 --- a/src/agents/pi-embedded-runner/compact.ts +++ b/src/agents/pi-embedded-runner/compact.ts @@ -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, diff --git a/src/agents/pi-embedded-runner/run/attempt.spawn-workspace.test-support.ts b/src/agents/pi-embedded-runner/run/attempt.spawn-workspace.test-support.ts index 450053b99b3..3a02f6dc93f 100644 --- a/src/agents/pi-embedded-runner/run/attempt.spawn-workspace.test-support.ts +++ b/src/agents/pi-embedded-runner/run/attempt.spawn-workspace.test-support.ts @@ -603,7 +603,6 @@ vi.mock("../tool-name-allowlist.js", () => ({ vi.mock("../tool-split.js", () => ({ splitSdkTools: ({ tools }: { tools: unknown[] }) => ({ - builtInTools: [], customTools: tools, }), })); diff --git a/src/agents/pi-embedded-runner/run/attempt.ts b/src/agents/pi-embedded-runner/run/attempt.ts index f26dbcd96b2..242068c3765 100644 --- a/src/agents/pi-embedded-runner/run/attempt.ts +++ b/src/agents/pi-embedded-runner/run/attempt.ts @@ -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, diff --git a/src/agents/pi-embedded-runner/tool-split.ts b/src/agents/pi-embedded-runner/tool-split.ts index 50a390ab399..e4dd08b28b3 100644 --- a/src/agents/pi-embedded-runner/tool-split.ts +++ b/src/agents/pi-embedded-runner/tool-split.ts @@ -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; customTools: ReturnType; } { const { tools } = options; return { - builtInTools: [], customTools: toToolDefinitions(tools), }; }