diff --git a/src/agents/pi-embedded-runner/compact.ts b/src/agents/pi-embedded-runner/compact.ts index 3f6788a14cb..f0abbb46bf4 100644 --- a/src/agents/pi-embedded-runner/compact.ts +++ b/src/agents/pi-embedded-runner/compact.ts @@ -843,14 +843,13 @@ export async function compactEmbeddedPiSessionDirect( contextTokenBudget: ctxInfo.tokens, }); - const { customTools } = splitSdkTools({ + const { builtInTools, customTools } = splitSdkTools({ tools: effectiveTools, sandboxEnabled: !!sandbox?.enabled, }); - // Pi 0.68.1 uses `tools` as a global allowlist across built-in and - // custom tools. Keep the built-in tool list empty, but still pass the - // exact registered custom-tool names so our OpenClaw-managed - // registrations remain active without broadening the session boundary. + // 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. const sessionToolAllowlist = toSessionToolAllowlist(collectRegisteredToolNames(customTools)); const providerStreamFn = resolveCompactionProviderStream({ @@ -889,7 +888,7 @@ export async function compactEmbeddedPiSessionDirect( modelRegistry, model: effectiveModel, thinkingLevel: mapThinkingLevel(thinkLevel), - tools: sessionToolAllowlist, + tools: builtInTools, customTools, sessionManager, settingsManager, @@ -897,6 +896,7 @@ export async function compactEmbeddedPiSessionDirect( }); session = createdSession.session; applySystemPromptOverrideToSession(session, buildSystemPromptOverride(thinkLevel)()); + session.setActiveToolsByName(sessionToolAllowlist); // Compaction builds the same embedded system prompt, so it must flow // through the same transport/payload shaping stack as normal turns. prepareCompactionSessionAgent({ diff --git a/src/agents/pi-embedded-runner/run/attempt.ts b/src/agents/pi-embedded-runner/run/attempt.ts index bd338375353..90255855a1e 100644 --- a/src/agents/pi-embedded-runner/run/attempt.ts +++ b/src/agents/pi-embedded-runner/run/attempt.ts @@ -1067,7 +1067,7 @@ export async function runEmbeddedAttempt( // Get hook runner early so it's available when creating tools const hookRunner = getGlobalHookRunner(); - const { customTools } = splitSdkTools({ + const { builtInTools, customTools } = splitSdkTools({ tools: effectiveTools, sandboxEnabled: !!sandbox?.enabled, }); @@ -1126,16 +1126,17 @@ export async function runEmbeddedAttempt( : []; const allCustomTools = [...customTools, ...clientToolDefs]; - // Pi 0.68.1 uses `tools` as a global allowlist across built-in and - // custom tools. Keep the built-in tool list empty, but still pass the - // exact registered custom-tool names so our OpenClaw-managed - // registrations remain active without widening the session boundary to - // raw client-provided names. + // 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. const sessionToolAllowlist = toSessionToolAllowlist( collectRegisteredToolNames(allCustomTools), ); - ({ session } = await createEmbeddedAgentSessionWithResourceLoader({ + const createdSession = await createEmbeddedAgentSessionWithResourceLoader< + Awaited> + >({ createAgentSession: async (options) => await createAgentSession(options as unknown as Parameters[0]), options: { @@ -1145,17 +1146,19 @@ export async function runEmbeddedAttempt( modelRegistry: params.modelRegistry, model: params.model, thinkingLevel: mapThinkingLevel(params.thinkLevel), - tools: sessionToolAllowlist, + tools: builtInTools, customTools: allCustomTools, sessionManager, settingsManager, resourceLoader, }, - })); + }); + session = createdSession.session; applySystemPromptOverrideToSession(session, systemPromptText); if (!session) { throw new Error("Embedded agent session missing"); } + session.setActiveToolsByName(sessionToolAllowlist); const activeSession = session; if (typeof activeSession.agent.convertToLlm === "function") { const baseConvertToLlm = activeSession.agent.convertToLlm.bind(activeSession.agent);