diff --git a/src/agents/agent-tools.create-openclaw-coding-tools.test.ts b/src/agents/agent-tools.create-openclaw-coding-tools.test.ts index d7a5b4648e5e..f0235ad37f86 100644 --- a/src/agents/agent-tools.create-openclaw-coding-tools.test.ts +++ b/src/agents/agent-tools.create-openclaw-coding-tools.test.ts @@ -808,7 +808,7 @@ describe("createOpenClawCodingTools", () => { sourceTool: "subagent_announce", sourceReplyDeliveryMode: "message_tool_only" as const, runtimeToolAllowlist: ["message", "read"], - expected: false, + expected: true, }, { name: "automatic completion delivery", @@ -818,7 +818,7 @@ describe("createOpenClawCodingTools", () => { runtimeToolAllowlist: ["message"], expected: false, }, - ])("limits $name to the source only when its trusted grant is exact", async (testCase) => { + ])("limits $name to the source only for verified completion delivery", async (testCase) => { const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-source-reply-only-")); try { const storeTemplate = path.join(tmpDir, "sessions-{agentId}.json"); diff --git a/src/agents/agent-tools.ts b/src/agents/agent-tools.ts index f9692e8a3596..28debd0a2b7c 100644 --- a/src/agents/agent-tools.ts +++ b/src/agents/agent-tools.ts @@ -559,15 +559,13 @@ function createOpenClawCodingToolsInternal(options?: OpenClawCodingToolsOptions) const normalized = normalizeToolName(toolName); return normalized === "*" || normalized === "message"; }); - // Frozen child output may use only the parent's existing source-delivery grant. - // Trusted ingress plus its exact one-tool cap prevent ordinary private turns from narrowing. + // A verified completion may retain parent tools, but its mandatory delivery + // grant stays bound to the current source regardless of allowlist width. const sourceReplyOnly = capabilityProfile.policy.requesterPolicySource === "completion-handoff" && options?.inputProvenance?.kind === "inter_session" && options.inputProvenance.sourceTool === "subagent_announce" && - options.sourceReplyDeliveryMode === "message_tool_only" && - options.runtimeToolAllowlist?.length === 1 && - normalizeToolName(options.runtimeToolAllowlist[0] ?? "") === "message"; + options.sourceReplyDeliveryMode === "message_tool_only"; const localModelLeanPreserveToolNames = resolveLocalModelLeanPreserveToolNames({ toolNames: capabilityProfile.policy.explicitToolOverrideAllowlist, forceMessageTool: options?.forceMessageTool,