import { a as normalizeLowercaseStringOrEmpty, s as normalizeOptionalLowercaseString } from "./string-coerce-Bje8XVt9.js";
import { r as openBoundaryFile } from "./boundary-file-read-6rU9DotD.js";
import { a as logWarn } from "./logger-PkdEIloJ.js";
import { v as resolveAgentConfig } from "./agent-scope-DYPLTPla.js";
import { g as writeFileWithinRoot, o as mkdirPathWithinRoot, p as removePathWithinRoot } from "./fs-safe-DuyWGaBt.js";
import { t as PATH_ALIAS_POLICIES } from "./path-alias-guards-kw7vvQoW.js";
import { d as resolveGatewayMessageChannel } from "./message-channel-DtX9jhh_.js";
import { i as resolveSubagentCapabilityStore, t as isSubagentEnvelopeSession } from "./subagent-capabilities-CGoEl7zn.js";
import { b as EXEC_TOOL_DISPLAY_SUMMARY, c as mergeAlsoAllowPolicy, i as collectExplicitAllowlist, m as resolveToolProfilePolicy, n as applyOwnerOnlyToolPolicy, x as PROCESS_TOOL_DISPLAY_SUMMARY } from "./tool-policy-CD6MU3lK.js";
import { n as copyPluginToolMeta, r as getPluginToolMeta } from "./tools-Dl8wjoGa.js";
import { t as bindAbortRelay } from "./fetch-timeout-CkiSffW0.js";
import { t as isToolAllowedByPolicies } from "./tool-policy-match-9haeOQmH.js";
import { i as resolveToolFsConfig, t as createToolFsPolicy } from "./tool-fs-policy-BtSPYMsg.js";
import { a as createSandboxedEditTool, c as wrapToolMemoryFlushAppendOnlyWrite, i as createOpenClawReadTool, l as wrapToolWorkspaceRootGuard, n as createHostWorkspaceEditTool, o as createSandboxedReadTool, r as createHostWorkspaceWriteTool, s as createSandboxedWriteTool, t as createOpenClawTools, u as wrapToolWorkspaceRootGuardWithOptions } from "./openclaw-tools-BvkkRg0s.js";
import { i as resolveImageSanitizationLimits } from "./tool-images-9v4VjY-Y.js";
import { i as listChannelAgentTools, t as copyChannelAgentToolMeta } from "./channel-tools-BrdnEE7b.js";
import { t as normalizeToolParameterSchema } from "./pi-tools-parameter-schema-y5JI9MhH.js";
import { c as wrapToolWithBeforeToolCallHook } from "./pi-tools.before-tool-call-CNqY7wT7.js";
import { i as resolveMergedSafeBinProfileFixtures } from "./exec-safe-bin-runtime-policy-5DS2qWOn.js";
import { n as assertSandboxPath } from "./sandbox-paths-Cj6n8_FZ.js";
import { a as toRelativeSandboxPath, i as resolvePathFromInput, r as resolveWorkspaceRoot } from "./read-capability-Dg6WTLBk.js";
import { n as describeProcessTool, t as describeExecTool } from "./bash-tools.descriptions-DHlp2UHm.js";
import { n as processSchema, t as execSchema } from "./bash-tools.schemas-Bq-UB8tM.js";
import { s as shouldSuppressManagedWebSearchTool } from "./codex-native-web-search-core-D7cV0hmV.js";
import "./codex-native-web-search-Ci91FSjd.js";
import { a as resolveSubagentToolPolicyForSession, i as resolveGroupToolPolicy, n as resolveEffectiveToolPolicy } from "./pi-tools.policy-CMjABa-e.js";
import { n as buildDefaultToolPolicyPipelineSteps, t as applyToolPolicyPipeline } from "./tool-policy-pipeline-DopNBfVs.js";
import fs from "node:fs";
import path from "node:path";
import fs$1 from "node:fs/promises";
import { Type } from "typebox";
import { createCodingTools, createReadTool } from "@mariozechner/pi-coding-agent";
//#region src/agents/apply-patch-update.ts
async function defaultReadFile(filePath) {
	return fs$1.readFile(filePath, "utf8");
}
async function applyUpdateHunk(filePath, chunks, options) {
	const originalLines = (await (options?.readFile ?? defaultReadFile)(filePath).catch((err) => {
		throw new Error(`Failed to read file to update ${filePath}: ${err}`);
	})).split("\n");
	if (originalLines.length > 0 && originalLines[originalLines.length - 1] === "") originalLines.pop();
	let newLines = applyReplacements(originalLines, computeReplacements(originalLines, filePath, chunks));
	if (newLines.length === 0 || newLines[newLines.length - 1] !== "") newLines = [...newLines, ""];
	return newLines.join("\n");
}
function computeReplacements(originalLines, filePath, chunks) {
	const replacements = [];
	let lineIndex = 0;
	for (const chunk of chunks) {
		if (chunk.changeContext) {
			const ctxIndex = seekSequence(originalLines, [chunk.changeContext], lineIndex, false);
			if (ctxIndex === null) throw new Error(`Failed to find context '${chunk.changeContext}' in ${filePath}`);
			lineIndex = ctxIndex + 1;
		}
		if (chunk.oldLines.length === 0) {
			const insertionIndex = originalLines.length > 0 && originalLines[originalLines.length - 1] === "" ? originalLines.length - 1 : originalLines.length;
			replacements.push([
				insertionIndex,
				0,
				chunk.newLines
			]);
			continue;
		}
		let pattern = chunk.oldLines;
		let newSlice = chunk.newLines;
		let found = seekSequence(originalLines, pattern, lineIndex, chunk.isEndOfFile);
		if (found === null && pattern[pattern.length - 1] === "") {
			pattern = pattern.slice(0, -1);
			if (newSlice.length > 0 && newSlice[newSlice.length - 1] === "") newSlice = newSlice.slice(0, -1);
			found = seekSequence(originalLines, pattern, lineIndex, chunk.isEndOfFile);
		}
		if (found === null) throw new Error(`Failed to find expected lines in ${filePath}:\n${chunk.oldLines.join("\n")}`);
		replacements.push([
			found,
			pattern.length,
			newSlice
		]);
		lineIndex = found + pattern.length;
	}
	replacements.sort((a, b) => a[0] - b[0]);
	return replacements;
}
function applyReplacements(lines, replacements) {
	const result = [...lines];
	for (const [startIndex, oldLen, newLines] of [...replacements].toReversed()) {
		for (let i = 0; i < oldLen; i += 1) if (startIndex < result.length) result.splice(startIndex, 1);
		for (let i = 0; i < newLines.length; i += 1) result.splice(startIndex + i, 0, newLines[i]);
	}
	return result;
}
function seekSequence(lines, pattern, start, eof) {
	if (pattern.length === 0) return start;
	if (pattern.length > lines.length) return null;
	const maxStart = lines.length - pattern.length;
	const searchStart = eof && lines.length >= pattern.length ? maxStart : start;
	if (searchStart > maxStart) return null;
	for (let i = searchStart; i <= maxStart; i += 1) if (linesMatch(lines, pattern, i, (value) => value)) return i;
	for (let i = searchStart; i <= maxStart; i += 1) if (linesMatch(lines, pattern, i, (value) => value.trimEnd())) return i;
	for (let i = searchStart; i <= maxStart; i += 1) if (linesMatch(lines, pattern, i, (value) => value.trim())) return i;
	for (let i = searchStart; i <= maxStart; i += 1) if (linesMatch(lines, pattern, i, (value) => normalizePunctuation(value.trim()))) return i;
	return null;
}
function linesMatch(lines, pattern, start, normalize) {
	for (let idx = 0; idx < pattern.length; idx += 1) if (normalize(lines[start + idx]) !== normalize(pattern[idx])) return false;
	return true;
}
function normalizePunctuation(value) {
	return Array.from(value).map((char) => {
		switch (char) {
			case "‐":
			case "‑":
			case "‒":
			case "–":
			case "—":
			case "―":
			case "−": return "-";
			case "‘":
			case "’":
			case "‚":
			case "‛": return "'";
			case "“":
			case "”":
			case "„":
			case "‟": return "\"";
			case "\xA0":
			case " ":
			case " ":
			case " ":
			case " ":
			case " ":
			case " ":
			case " ":
			case " ":
			case " ":
			case " ":
			case " ":
			case "　": return " ";
			default: return char;
		}
	}).join("");
}
//#endregion
//#region src/agents/apply-patch.ts
const BEGIN_PATCH_MARKER = "*** Begin Patch";
const END_PATCH_MARKER = "*** End Patch";
const ADD_FILE_MARKER = "*** Add File: ";
const DELETE_FILE_MARKER = "*** Delete File: ";
const UPDATE_FILE_MARKER = "*** Update File: ";
const MOVE_TO_MARKER = "*** Move to: ";
const EOF_MARKER = "*** End of File";
const CHANGE_CONTEXT_MARKER = "@@ ";
const EMPTY_CHANGE_CONTEXT_MARKER = "@@";
const applyPatchSchema = Type.Object({ input: Type.String({ description: "Patch content using the *** Begin Patch/End Patch format." }) });
function createApplyPatchTool(options = {}) {
	const cwd = options.cwd ?? process.cwd();
	const sandbox = options.sandbox;
	const workspaceOnly = options.workspaceOnly !== false;
	return {
		name: "apply_patch",
		label: "apply_patch",
		description: "Apply a patch to one or more files using the apply_patch format. The input should include *** Begin Patch and *** End Patch markers.",
		parameters: applyPatchSchema,
		execute: async (_toolCallId, args, signal) => {
			const params = args;
			const input = typeof params.input === "string" ? params.input : "";
			if (!input.trim()) throw new Error("Provide a patch input.");
			if (signal?.aborted) {
				const err = /* @__PURE__ */ new Error("Aborted");
				err.name = "AbortError";
				throw err;
			}
			const result = await applyPatch(input, {
				cwd,
				sandbox,
				workspaceOnly,
				signal
			});
			return {
				content: [{
					type: "text",
					text: result.text
				}],
				details: { summary: result.summary }
			};
		}
	};
}
async function applyPatch(input, options) {
	const parsed = parsePatchText(input);
	if (parsed.hunks.length === 0) throw new Error("No files were modified.");
	const summary = {
		added: [],
		modified: [],
		deleted: []
	};
	const seen = {
		added: /* @__PURE__ */ new Set(),
		modified: /* @__PURE__ */ new Set(),
		deleted: /* @__PURE__ */ new Set()
	};
	const fileOps = resolvePatchFileOps(options);
	for (const hunk of parsed.hunks) {
		if (options.signal?.aborted) {
			const err = /* @__PURE__ */ new Error("Aborted");
			err.name = "AbortError";
			throw err;
		}
		if (hunk.kind === "add") {
			const target = await resolvePatchPath(hunk.path, options);
			await ensureDir(target.resolved, fileOps);
			await fileOps.writeFile(target.resolved, hunk.contents);
			recordSummary(summary, seen, "added", target.display);
			continue;
		}
		if (hunk.kind === "delete") {
			const target = await resolvePatchPath(hunk.path, options, PATH_ALIAS_POLICIES.unlinkTarget);
			await fileOps.remove(target.resolved);
			recordSummary(summary, seen, "deleted", target.display);
			continue;
		}
		const target = await resolvePatchPath(hunk.path, options);
		const applied = await applyUpdateHunk(target.resolved, hunk.chunks, { readFile: (path) => fileOps.readFile(path) });
		if (hunk.movePath) {
			const moveTarget = await resolvePatchPath(hunk.movePath, options);
			await ensureDir(moveTarget.resolved, fileOps);
			await fileOps.writeFile(moveTarget.resolved, applied);
			await fileOps.remove(target.resolved);
			recordSummary(summary, seen, "modified", moveTarget.display);
		} else {
			await fileOps.writeFile(target.resolved, applied);
			recordSummary(summary, seen, "modified", target.display);
		}
	}
	return {
		summary,
		text: formatSummary(summary)
	};
}
function recordSummary(summary, seen, bucket, value) {
	if (seen[bucket].has(value)) return;
	seen[bucket].add(value);
	summary[bucket].push(value);
}
function formatSummary(summary) {
	const lines = ["Success. Updated the following files:"];
	for (const file of summary.added) lines.push(`A ${file}`);
	for (const file of summary.modified) lines.push(`M ${file}`);
	for (const file of summary.deleted) lines.push(`D ${file}`);
	return lines.join("\n");
}
function resolvePatchFileOps(options) {
	if (options.sandbox) {
		const { root, bridge } = options.sandbox;
		return {
			readFile: async (filePath) => {
				return (await bridge.readFile({
					filePath,
					cwd: root
				})).toString("utf8");
			},
			writeFile: (filePath, content) => bridge.writeFile({
				filePath,
				cwd: root,
				data: content
			}),
			remove: (filePath) => bridge.remove({
				filePath,
				cwd: root,
				force: false
			}),
			mkdirp: (dir) => bridge.mkdirp({
				filePath: dir,
				cwd: root
			})
		};
	}
	const workspaceOnly = options.workspaceOnly !== false;
	return {
		readFile: async (filePath) => {
			if (!workspaceOnly) return await fs$1.readFile(filePath, "utf8");
			const opened = await openBoundaryFile({
				absolutePath: filePath,
				rootPath: options.cwd,
				boundaryLabel: "workspace root"
			});
			assertBoundaryRead(opened, filePath);
			try {
				return fs.readFileSync(opened.fd, "utf8");
			} finally {
				fs.closeSync(opened.fd);
			}
		},
		writeFile: async (filePath, content) => {
			if (!workspaceOnly) {
				await fs$1.writeFile(filePath, content, "utf8");
				return;
			}
			const relative = toRelativeSandboxPath(options.cwd, filePath);
			await writeFileWithinRoot({
				rootDir: options.cwd,
				relativePath: relative,
				data: content,
				encoding: "utf8"
			});
		},
		remove: async (filePath) => {
			if (!workspaceOnly) {
				await fs$1.rm(filePath);
				return;
			}
			const relative = toRelativeSandboxPath(options.cwd, filePath);
			await removePathWithinRoot({
				rootDir: options.cwd,
				relativePath: relative
			});
		},
		mkdirp: async (dir) => {
			if (!workspaceOnly) {
				await fs$1.mkdir(dir, { recursive: true });
				return;
			}
			const relative = toRelativeSandboxPath(options.cwd, dir, { allowRoot: true });
			await mkdirPathWithinRoot({
				rootDir: options.cwd,
				relativePath: relative,
				allowRoot: true
			});
		}
	};
}
async function ensureDir(filePath, ops) {
	const parent = path.dirname(filePath);
	if (!parent || parent === ".") return;
	await ops.mkdirp(parent);
}
async function resolvePatchPath(filePath, options, aliasPolicy = PATH_ALIAS_POLICIES.strict) {
	if (options.sandbox) {
		const resolved = options.sandbox.bridge.resolvePath({
			filePath,
			cwd: options.cwd
		});
		if (options.workspaceOnly !== false && resolved.hostPath) await assertSandboxPath({
			filePath: resolved.hostPath,
			cwd: options.cwd,
			root: options.cwd,
			allowFinalSymlinkForUnlink: aliasPolicy.allowFinalSymlinkForUnlink,
			allowFinalHardlinkForUnlink: aliasPolicy.allowFinalHardlinkForUnlink
		});
		return {
			resolved: resolved.hostPath ?? resolved.containerPath,
			display: resolved.relativePath || resolved.containerPath
		};
	}
	const resolved = options.workspaceOnly !== false ? (await assertSandboxPath({
		filePath,
		cwd: options.cwd,
		root: options.cwd,
		allowFinalSymlinkForUnlink: aliasPolicy.allowFinalSymlinkForUnlink,
		allowFinalHardlinkForUnlink: aliasPolicy.allowFinalHardlinkForUnlink
	})).resolved : resolvePathFromInput(filePath, options.cwd);
	return {
		resolved,
		display: toDisplayPath(resolved, options.cwd)
	};
}
function assertBoundaryRead(opened, targetPath) {
	if (opened.ok) return;
	const reason = opened.reason === "validation" ? "unsafe path" : "path not found";
	throw new Error(`Failed boundary read for ${targetPath} (${reason})`);
}
function toDisplayPath(resolved, cwd) {
	const relative = path.relative(cwd, resolved);
	if (!relative || relative === "") return path.basename(resolved);
	if (relative.startsWith("..") || path.isAbsolute(relative)) return resolved;
	return relative;
}
function parsePatchText(input) {
	const trimmed = input.trim();
	if (!trimmed) throw new Error("Invalid patch: input is empty.");
	const validated = checkPatchBoundariesLenient(trimmed.split(/\r?\n/));
	const hunks = [];
	const lastLineIndex = validated.length - 1;
	let remaining = validated.slice(1, lastLineIndex);
	let lineNumber = 2;
	while (remaining.length > 0) {
		const { hunk, consumed } = parseOneHunk(remaining, lineNumber);
		hunks.push(hunk);
		lineNumber += consumed;
		remaining = remaining.slice(consumed);
	}
	return {
		hunks,
		patch: validated.join("\n")
	};
}
function checkPatchBoundariesLenient(lines) {
	const strictError = checkPatchBoundariesStrict(lines);
	if (!strictError) return lines;
	if (lines.length < 4) throw new Error(strictError);
	const first = lines[0];
	const last = lines.at(-1);
	if (last && (first === "<<EOF" || first === "<<'EOF'" || first === "<<\"EOF\"") && last.endsWith("EOF")) {
		const inner = lines.slice(1, -1);
		const innerError = checkPatchBoundariesStrict(inner);
		if (!innerError) return inner;
		throw new Error(innerError);
	}
	throw new Error(strictError);
}
function checkPatchBoundariesStrict(lines) {
	const firstLine = lines[0]?.trim();
	const lastLine = lines[lines.length - 1]?.trim();
	if (firstLine === BEGIN_PATCH_MARKER && lastLine === END_PATCH_MARKER) return null;
	if (firstLine !== BEGIN_PATCH_MARKER) return "The first line of the patch must be '*** Begin Patch'";
	return "The last line of the patch must be '*** End Patch'";
}
function parseOneHunk(lines, lineNumber) {
	if (lines.length === 0) throw new Error(`Invalid patch hunk at line ${lineNumber}: empty hunk`);
	const firstLine = lines[0].trim();
	if (firstLine.startsWith(ADD_FILE_MARKER)) {
		const targetPath = firstLine.slice(14);
		let contents = "";
		let consumed = 1;
		for (const addLine of lines.slice(1)) if (addLine.startsWith("+")) {
			contents += `${addLine.slice(1)}\n`;
			consumed += 1;
		} else break;
		return {
			hunk: {
				kind: "add",
				path: targetPath,
				contents
			},
			consumed
		};
	}
	if (firstLine.startsWith(DELETE_FILE_MARKER)) return {
		hunk: {
			kind: "delete",
			path: firstLine.slice(17)
		},
		consumed: 1
	};
	if (firstLine.startsWith(UPDATE_FILE_MARKER)) {
		const targetPath = firstLine.slice(17);
		let remaining = lines.slice(1);
		let consumed = 1;
		let movePath;
		const moveCandidate = remaining[0]?.trim();
		if (moveCandidate?.startsWith(MOVE_TO_MARKER)) {
			movePath = moveCandidate.slice(13);
			remaining = remaining.slice(1);
			consumed += 1;
		}
		const chunks = [];
		while (remaining.length > 0) {
			if (remaining[0].trim() === "") {
				remaining = remaining.slice(1);
				consumed += 1;
				continue;
			}
			if (remaining[0].startsWith("***")) break;
			const { chunk, consumed: chunkLines } = parseUpdateFileChunk(remaining, lineNumber + consumed, chunks.length === 0);
			chunks.push(chunk);
			remaining = remaining.slice(chunkLines);
			consumed += chunkLines;
		}
		if (chunks.length === 0) throw new Error(`Invalid patch hunk at line ${lineNumber}: Update file hunk for path '${targetPath}' is empty`);
		return {
			hunk: {
				kind: "update",
				path: targetPath,
				movePath,
				chunks
			},
			consumed
		};
	}
	throw new Error(`Invalid patch hunk at line ${lineNumber}: '${lines[0]}' is not a valid hunk header. Valid hunk headers: '*** Add File: {path}', '*** Delete File: {path}', '*** Update File: {path}'`);
}
function parseUpdateFileChunk(lines, lineNumber, allowMissingContext) {
	if (lines.length === 0) throw new Error(`Invalid patch hunk at line ${lineNumber}: Update hunk does not contain any lines`);
	let changeContext;
	let startIndex = 0;
	if (lines[0] === EMPTY_CHANGE_CONTEXT_MARKER) startIndex = 1;
	else if (lines[0].startsWith(CHANGE_CONTEXT_MARKER)) {
		changeContext = lines[0].slice(3);
		startIndex = 1;
	} else if (!allowMissingContext) throw new Error(`Invalid patch hunk at line ${lineNumber}: Expected update hunk to start with a @@ context marker, got: '${lines[0]}'`);
	if (startIndex >= lines.length) throw new Error(`Invalid patch hunk at line ${lineNumber + 1}: Update hunk does not contain any lines`);
	const chunk = {
		changeContext,
		oldLines: [],
		newLines: [],
		isEndOfFile: false
	};
	let parsedLines = 0;
	for (const line of lines.slice(startIndex)) {
		if (line === EOF_MARKER) {
			if (parsedLines === 0) throw new Error(`Invalid patch hunk at line ${lineNumber + 1}: Update hunk does not contain any lines`);
			chunk.isEndOfFile = true;
			parsedLines += 1;
			break;
		}
		const marker = line[0];
		if (!marker) {
			chunk.oldLines.push("");
			chunk.newLines.push("");
			parsedLines += 1;
			continue;
		}
		if (marker === " ") {
			const content = line.slice(1);
			chunk.oldLines.push(content);
			chunk.newLines.push(content);
			parsedLines += 1;
			continue;
		}
		if (marker === "+") {
			chunk.newLines.push(line.slice(1));
			parsedLines += 1;
			continue;
		}
		if (marker === "-") {
			chunk.oldLines.push(line.slice(1));
			parsedLines += 1;
			continue;
		}
		if (parsedLines === 0) throw new Error(`Invalid patch hunk at line ${lineNumber + 1}: Unexpected line found in update hunk: '${line}'. Every line should start with ' ' (context line), '+' (added line), or '-' (removed line)`);
		break;
	}
	return {
		chunk,
		consumed: parsedLines + startIndex
	};
}
//#endregion
//#region src/agents/pi-tools.abort.ts
function throwAbortError() {
	const err = /* @__PURE__ */ new Error("Aborted");
	err.name = "AbortError";
	throw err;
}
/**
* Checks if an object is a valid AbortSignal using structural typing.
* This is more reliable than `instanceof` across different realms (VM, iframe, etc.)
* where the AbortSignal constructor may differ.
*/
function isAbortSignal(obj) {
	return obj instanceof AbortSignal;
}
function combineAbortSignals(a, b) {
	if (!a && !b) return;
	if (a && !b) return a;
	if (b && !a) return b;
	if (a?.aborted) return a;
	if (b?.aborted) return b;
	if (typeof AbortSignal.any === "function" && isAbortSignal(a) && isAbortSignal(b)) return AbortSignal.any([a, b]);
	const controller = new AbortController();
	const onAbort = bindAbortRelay(controller);
	a?.addEventListener("abort", onAbort, { once: true });
	b?.addEventListener("abort", onAbort, { once: true });
	return controller.signal;
}
function wrapToolWithAbortSignal(tool, abortSignal) {
	if (!abortSignal) return tool;
	const execute = tool.execute;
	if (!execute) return tool;
	const wrappedTool = {
		...tool,
		execute: async (toolCallId, params, signal, onUpdate) => {
			const combined = combineAbortSignals(signal, abortSignal);
			if (combined?.aborted) throwAbortError();
			return await execute(toolCallId, params, combined, onUpdate);
		}
	};
	copyPluginToolMeta(tool, wrappedTool);
	copyChannelAgentToolMeta(tool, wrappedTool);
	return wrappedTool;
}
//#endregion
//#region src/agents/pi-tools.deferred-followup.ts
function applyDeferredFollowupToolDescriptions(tools, params) {
	const hasCronTool = tools.some((tool) => tool.name === "cron");
	return tools.map((tool) => {
		if (tool.name === "exec") return {
			...tool,
			description: describeExecTool({
				agentId: params?.agentId,
				hasCronTool
			})
		};
		if (tool.name === "process") return {
			...tool,
			description: describeProcessTool({ hasCronTool })
		};
		return tool;
	});
}
//#endregion
//#region src/agents/pi-tools.message-provider-policy.ts
const TOOL_DENY_BY_MESSAGE_PROVIDER = { voice: ["tts"] };
const TOOL_ALLOW_BY_MESSAGE_PROVIDER = { node: [
	"canvas",
	"image",
	"pdf",
	"tts",
	"web_fetch",
	"web_search"
] };
function filterToolNamesByMessageProvider(toolNames, messageProvider) {
	const normalizedProvider = normalizeOptionalLowercaseString(messageProvider);
	if (!normalizedProvider) return [...toolNames];
	const allowedTools = TOOL_ALLOW_BY_MESSAGE_PROVIDER[normalizedProvider];
	if (allowedTools && allowedTools.length > 0) {
		const allowedSet = new Set(allowedTools);
		return toolNames.filter((toolName) => allowedSet.has(toolName));
	}
	const deniedTools = TOOL_DENY_BY_MESSAGE_PROVIDER[normalizedProvider];
	if (!deniedTools || deniedTools.length === 0) return [...toolNames];
	const deniedSet = new Set(deniedTools);
	return toolNames.filter((toolName) => !deniedSet.has(toolName));
}
function filterToolsByMessageProvider(tools, messageProvider) {
	const filteredToolNames = filterToolNamesByMessageProvider(tools.map((tool) => tool.name), messageProvider);
	const remainingCounts = /* @__PURE__ */ new Map();
	for (const toolName of filteredToolNames) remainingCounts.set(toolName, (remainingCounts.get(toolName) ?? 0) + 1);
	return tools.filter((tool) => {
		const remaining = remainingCounts.get(tool.name) ?? 0;
		if (remaining <= 0) return false;
		remainingCounts.set(tool.name, remaining - 1);
		return true;
	});
}
//#endregion
//#region src/agents/pi-tools.schema.ts
function isObjectSchemaWithNoRequiredParams(schema) {
	if (!schema || typeof schema !== "object" || Array.isArray(schema)) return false;
	const record = schema;
	const type = record.type;
	if (!(type === "object" || Array.isArray(type) && type.some((entry) => entry === "object"))) return false;
	return !schemaHasRequiredParams(record);
}
function schemaHasRequiredParams(schema) {
	if (Array.isArray(schema.required) && schema.required.length > 0) return true;
	for (const key of [
		"allOf",
		"anyOf",
		"oneOf"
	]) {
		const variants = schema[key];
		if (!Array.isArray(variants)) continue;
		if (variants.some((variant) => variant !== null && typeof variant === "object" && !Array.isArray(variant) && schemaHasRequiredParams(variant))) return true;
	}
	return false;
}
function addEmptyObjectArgumentPreparation(tool, parameters) {
	if (!isObjectSchemaWithNoRequiredParams(parameters)) return tool;
	return {
		...tool,
		prepareArguments: (args) => {
			const prepared = tool.prepareArguments ? tool.prepareArguments(args) : args;
			return prepared === null || prepared === void 0 ? {} : prepared;
		}
	};
}
function normalizeToolParameters(tool, options) {
	function preserveToolMeta(target) {
		copyPluginToolMeta(tool, target);
		copyChannelAgentToolMeta(tool, target);
		return target;
	}
	const schema = tool.parameters && typeof tool.parameters === "object" ? tool.parameters : void 0;
	if (!schema) return tool;
	const parameters = normalizeToolParameterSchema(schema, options);
	return preserveToolMeta({
		...tool,
		...addEmptyObjectArgumentPreparation(tool, parameters),
		parameters
	});
}
//#endregion
//#region src/agents/pi-tools.ts
function isOpenAIProvider(provider) {
	const normalized = normalizeOptionalLowercaseString(provider);
	return normalized === "openai" || normalized === "openai-codex";
}
const MEMORY_FLUSH_ALLOWED_TOOL_NAMES = new Set(["read", "write"]);
let bashToolsModulePromise;
function loadBashToolsModule() {
	bashToolsModulePromise ??= import("./bash-tools-CH6fDY-7.js");
	return bashToolsModulePromise;
}
function createLazyExecTool(defaults) {
	let loadedTool;
	const loadTool = async () => {
		if (!loadedTool) {
			const { createExecTool } = await loadBashToolsModule();
			loadedTool = createExecTool(defaults);
		}
		return loadedTool;
	};
	return {
		name: "exec",
		label: "exec",
		displaySummary: EXEC_TOOL_DISPLAY_SUMMARY,
		get description() {
			return describeExecTool({
				agentId: defaults?.agentId,
				hasCronTool: defaults?.hasCronTool === true
			});
		},
		parameters: execSchema,
		execute: async (...args) => (await loadTool()).execute(...args)
	};
}
function createLazyProcessTool(defaults) {
	let loadedTool;
	const loadTool = async () => {
		if (!loadedTool) {
			const { createProcessTool } = await loadBashToolsModule();
			loadedTool = createProcessTool(defaults);
		}
		return loadedTool;
	};
	return {
		name: "process",
		label: "process",
		displaySummary: PROCESS_TOOL_DISPLAY_SUMMARY,
		description: describeProcessTool({ hasCronTool: defaults?.hasCronTool === true }),
		parameters: processSchema,
		execute: async (...args) => (await loadTool()).execute(...args)
	};
}
function applyModelProviderToolPolicy(tools, params) {
	if (params?.config?.agents?.defaults?.experimental?.localModelLean === true) {
		const leanDeny = new Set([
			"browser",
			"cron",
			"message"
		]);
		tools = tools.filter((tool) => !leanDeny.has(tool.name));
	}
	if (shouldSuppressManagedWebSearchTool({
		config: params?.config,
		modelProvider: params?.modelProvider,
		modelApi: params?.modelApi,
		agentDir: params?.agentDir
	})) return tools.filter((tool) => tool.name !== "web_search");
	return tools;
}
function isApplyPatchAllowedForModel(params) {
	const allowModels = Array.isArray(params.allowModels) ? params.allowModels : [];
	if (allowModels.length === 0) return true;
	const modelId = params.modelId?.trim();
	if (!modelId) return false;
	const normalizedModelId = normalizeLowercaseStringOrEmpty(modelId);
	const provider = normalizeOptionalLowercaseString(params.modelProvider);
	const normalizedFull = provider && !normalizedModelId.includes("/") ? `${provider}/${normalizedModelId}` : normalizedModelId;
	return allowModels.some((entry) => {
		const normalized = normalizeOptionalLowercaseString(entry);
		if (!normalized) return false;
		return normalized === normalizedModelId || normalized === normalizedFull;
	});
}
function resolveExecConfig(params) {
	const cfg = params.cfg;
	const globalExec = cfg?.tools?.exec;
	const agentExec = cfg && params.agentId ? resolveAgentConfig(cfg, params.agentId)?.tools?.exec : void 0;
	return {
		host: agentExec?.host ?? globalExec?.host,
		security: agentExec?.security ?? globalExec?.security,
		ask: agentExec?.ask ?? globalExec?.ask,
		node: agentExec?.node ?? globalExec?.node,
		pathPrepend: agentExec?.pathPrepend ?? globalExec?.pathPrepend,
		safeBins: agentExec?.safeBins ?? globalExec?.safeBins,
		strictInlineEval: agentExec?.strictInlineEval ?? globalExec?.strictInlineEval,
		safeBinTrustedDirs: agentExec?.safeBinTrustedDirs ?? globalExec?.safeBinTrustedDirs,
		safeBinProfiles: resolveMergedSafeBinProfileFixtures({
			global: globalExec,
			local: agentExec
		}),
		backgroundMs: agentExec?.backgroundMs ?? globalExec?.backgroundMs,
		timeoutSec: agentExec?.timeoutSec ?? globalExec?.timeoutSec,
		approvalRunningNoticeMs: agentExec?.approvalRunningNoticeMs ?? globalExec?.approvalRunningNoticeMs,
		cleanupMs: agentExec?.cleanupMs ?? globalExec?.cleanupMs,
		notifyOnExit: agentExec?.notifyOnExit ?? globalExec?.notifyOnExit,
		notifyOnExitEmptySuccess: agentExec?.notifyOnExitEmptySuccess ?? globalExec?.notifyOnExitEmptySuccess,
		applyPatch: agentExec?.applyPatch ?? globalExec?.applyPatch
	};
}
function resolveToolLoopDetectionConfig(params) {
	const global = params.cfg?.tools?.loopDetection;
	const agent = params.agentId && params.cfg ? resolveAgentConfig(params.cfg, params.agentId)?.tools?.loopDetection : void 0;
	if (!agent) return global;
	if (!global) return agent;
	return {
		...global,
		...agent,
		detectors: {
			...global.detectors,
			...agent.detectors
		}
	};
}
function createOpenClawCodingTools(options) {
	const execToolName = "exec";
	const sandbox = options?.sandbox?.enabled ? options.sandbox : void 0;
	const isMemoryFlushRun = options?.trigger === "memory";
	if (isMemoryFlushRun && !options?.memoryFlushWritePath) throw new Error("memoryFlushWritePath required for memory-triggered tool runs");
	const memoryFlushWritePath = isMemoryFlushRun ? options.memoryFlushWritePath : void 0;
	const { agentId, globalPolicy, globalProviderPolicy, agentPolicy, agentProviderPolicy, profile, providerProfile, profileAlsoAllow, providerProfileAlsoAllow } = resolveEffectiveToolPolicy({
		config: options?.config,
		sessionKey: options?.sessionKey,
		agentId: options?.agentId,
		modelProvider: options?.modelProvider,
		modelId: options?.modelId
	});
	const sandboxToolPolicy = sandbox?.tools;
	const groupPolicy = resolveGroupToolPolicy({
		config: options?.config,
		sessionKey: options?.sessionKey,
		spawnedBy: options?.spawnedBy,
		messageProvider: options?.messageProvider,
		groupId: options?.groupId,
		groupChannel: options?.groupChannel,
		groupSpace: options?.groupSpace,
		accountId: options?.agentAccountId,
		senderId: options?.senderId,
		senderName: options?.senderName,
		senderUsername: options?.senderUsername,
		senderE164: options?.senderE164
	});
	const profilePolicy = resolveToolProfilePolicy(profile);
	const providerProfilePolicy = resolveToolProfilePolicy(providerProfile);
	const runtimeProfileAlsoAllow = options?.forceMessageTool ? ["message"] : [];
	const profilePolicyWithAlsoAllow = mergeAlsoAllowPolicy(profilePolicy, [...profileAlsoAllow ?? [], ...runtimeProfileAlsoAllow]);
	const providerProfilePolicyWithAlsoAllow = mergeAlsoAllowPolicy(providerProfilePolicy, [...providerProfileAlsoAllow ?? [], ...runtimeProfileAlsoAllow]);
	const scopeKey = options?.exec?.scopeKey ?? options?.sessionKey ?? (agentId ? `agent:${agentId}` : void 0);
	const subagentStore = resolveSubagentCapabilityStore(options?.sessionKey, { cfg: options?.config });
	const subagentPolicy = options?.sessionKey && isSubagentEnvelopeSession(options.sessionKey, {
		cfg: options.config,
		store: subagentStore
	}) ? resolveSubagentToolPolicyForSession(options.config, options.sessionKey, { store: subagentStore }) : void 0;
	const allowBackground = isToolAllowedByPolicies("process", [
		profilePolicyWithAlsoAllow,
		providerProfilePolicyWithAlsoAllow,
		globalPolicy,
		globalProviderPolicy,
		agentPolicy,
		agentProviderPolicy,
		groupPolicy,
		sandboxToolPolicy,
		subagentPolicy
	]);
	const execConfig = resolveExecConfig({
		cfg: options?.config,
		agentId
	});
	const fsConfig = resolveToolFsConfig({
		cfg: options?.config,
		agentId
	});
	const fsPolicy = createToolFsPolicy({ workspaceOnly: isMemoryFlushRun || fsConfig.workspaceOnly });
	const sandboxRoot = sandbox?.workspaceDir;
	const sandboxFsBridge = sandbox?.fsBridge;
	const allowWorkspaceWrites = sandbox?.workspaceAccess !== "ro";
	const workspaceRoot = resolveWorkspaceRoot(options?.workspaceDir);
	const workspaceOnly = fsPolicy.workspaceOnly;
	const applyPatchConfig = execConfig.applyPatch;
	const applyPatchWorkspaceOnly = workspaceOnly || applyPatchConfig?.workspaceOnly !== false;
	const applyPatchEnabled = applyPatchConfig?.enabled !== false && isOpenAIProvider(options?.modelProvider) && isApplyPatchAllowedForModel({
		modelProvider: options?.modelProvider,
		modelId: options?.modelId,
		allowModels: applyPatchConfig?.allowModels
	});
	if (sandboxRoot && !sandboxFsBridge) throw new Error("Sandbox filesystem bridge is unavailable.");
	const imageSanitization = resolveImageSanitizationLimits(options?.config);
	const base = createCodingTools(workspaceRoot).flatMap((tool) => {
		if (tool.name === "read") {
			if (sandboxRoot) {
				const sandboxed = createSandboxedReadTool({
					root: sandboxRoot,
					bridge: sandboxFsBridge,
					modelContextWindowTokens: options?.modelContextWindowTokens,
					imageSanitization
				});
				return [workspaceOnly ? wrapToolWorkspaceRootGuardWithOptions(sandboxed, sandboxRoot, { containerWorkdir: sandbox.containerWorkdir }) : sandboxed];
			}
			const wrapped = createOpenClawReadTool(createReadTool(workspaceRoot), {
				modelContextWindowTokens: options?.modelContextWindowTokens,
				imageSanitization
			});
			return [workspaceOnly ? wrapToolWorkspaceRootGuard(wrapped, workspaceRoot) : wrapped];
		}
		if (tool.name === "bash" || tool.name === execToolName) return [];
		if (tool.name === "write") {
			if (sandboxRoot) return [];
			const wrapped = createHostWorkspaceWriteTool(workspaceRoot, { workspaceOnly });
			return [workspaceOnly ? wrapToolWorkspaceRootGuard(wrapped, workspaceRoot) : wrapped];
		}
		if (tool.name === "edit") {
			if (sandboxRoot) return [];
			const wrapped = createHostWorkspaceEditTool(workspaceRoot, { workspaceOnly });
			return [workspaceOnly ? wrapToolWorkspaceRootGuard(wrapped, workspaceRoot) : wrapped];
		}
		return [tool];
	});
	const { cleanupMs: cleanupMsOverride, ...execDefaults } = options?.exec ?? {};
	const execTool = createLazyExecTool({
		...execDefaults,
		host: options?.exec?.host ?? execConfig.host,
		security: options?.exec?.security ?? execConfig.security,
		ask: options?.exec?.ask ?? execConfig.ask,
		trigger: options?.trigger,
		node: options?.exec?.node ?? execConfig.node,
		pathPrepend: options?.exec?.pathPrepend ?? execConfig.pathPrepend,
		safeBins: options?.exec?.safeBins ?? execConfig.safeBins,
		strictInlineEval: options?.exec?.strictInlineEval ?? execConfig.strictInlineEval,
		safeBinTrustedDirs: options?.exec?.safeBinTrustedDirs ?? execConfig.safeBinTrustedDirs,
		safeBinProfiles: options?.exec?.safeBinProfiles ?? execConfig.safeBinProfiles,
		agentId,
		cwd: workspaceRoot,
		allowBackground,
		scopeKey,
		sessionKey: options?.sessionKey,
		messageProvider: options?.messageProvider,
		currentChannelId: options?.currentChannelId,
		currentThreadTs: options?.currentThreadTs,
		accountId: options?.agentAccountId,
		backgroundMs: options?.exec?.backgroundMs ?? execConfig.backgroundMs,
		timeoutSec: options?.exec?.timeoutSec ?? execConfig.timeoutSec,
		approvalRunningNoticeMs: options?.exec?.approvalRunningNoticeMs ?? execConfig.approvalRunningNoticeMs,
		notifyOnExit: options?.exec?.notifyOnExit ?? execConfig.notifyOnExit,
		notifyOnExitEmptySuccess: options?.exec?.notifyOnExitEmptySuccess ?? execConfig.notifyOnExitEmptySuccess,
		sandbox: sandbox ? {
			containerName: sandbox.containerName,
			workspaceDir: sandbox.workspaceDir,
			containerWorkdir: sandbox.containerWorkdir,
			env: sandbox.backend?.env ?? sandbox.docker.env,
			buildExecSpec: sandbox.backend?.buildExecSpec.bind(sandbox.backend),
			finalizeExec: sandbox.backend?.finalizeExec?.bind(sandbox.backend)
		} : void 0
	});
	const processTool = createLazyProcessTool({
		cleanupMs: cleanupMsOverride ?? execConfig.cleanupMs,
		scopeKey
	});
	const applyPatchTool = !applyPatchEnabled || sandboxRoot && !allowWorkspaceWrites ? null : createApplyPatchTool({
		cwd: sandboxRoot ?? workspaceRoot,
		sandbox: sandboxRoot && allowWorkspaceWrites ? {
			root: sandboxRoot,
			bridge: sandboxFsBridge
		} : void 0,
		workspaceOnly: applyPatchWorkspaceOnly
	});
	const tools = [
		...base,
		...sandboxRoot ? allowWorkspaceWrites ? [workspaceOnly ? wrapToolWorkspaceRootGuardWithOptions(createSandboxedEditTool({
			root: sandboxRoot,
			bridge: sandboxFsBridge
		}), sandboxRoot, { containerWorkdir: sandbox.containerWorkdir }) : createSandboxedEditTool({
			root: sandboxRoot,
			bridge: sandboxFsBridge
		}), workspaceOnly ? wrapToolWorkspaceRootGuardWithOptions(createSandboxedWriteTool({
			root: sandboxRoot,
			bridge: sandboxFsBridge
		}), sandboxRoot, { containerWorkdir: sandbox.containerWorkdir }) : createSandboxedWriteTool({
			root: sandboxRoot,
			bridge: sandboxFsBridge
		})] : [] : [],
		...applyPatchTool ? [applyPatchTool] : [],
		execTool,
		processTool,
		...listChannelAgentTools({ cfg: options?.config }),
		...createOpenClawTools({
			sandboxBrowserBridgeUrl: sandbox?.browser?.bridgeUrl,
			allowHostBrowserControl: sandbox ? sandbox.browserAllowHostControl : true,
			agentSessionKey: options?.sessionKey,
			agentChannel: resolveGatewayMessageChannel(options?.messageProvider),
			agentAccountId: options?.agentAccountId,
			agentTo: options?.messageTo,
			agentThreadId: options?.messageThreadId,
			agentGroupId: options?.groupId ?? null,
			agentGroupChannel: options?.groupChannel ?? null,
			agentGroupSpace: options?.groupSpace ?? null,
			agentMemberRoleIds: options?.memberRoleIds,
			agentDir: options?.agentDir,
			sandboxRoot,
			sandboxContainerWorkdir: sandbox?.containerWorkdir,
			sandboxFsBridge,
			fsPolicy,
			workspaceDir: workspaceRoot,
			spawnWorkspaceDir: options?.spawnWorkspaceDir ? resolveWorkspaceRoot(options.spawnWorkspaceDir) : void 0,
			sandboxed: !!sandbox,
			config: options?.config,
			pluginToolAllowlist: collectExplicitAllowlist([
				profilePolicy,
				providerProfilePolicy,
				globalPolicy,
				globalProviderPolicy,
				agentPolicy,
				agentProviderPolicy,
				groupPolicy,
				sandboxToolPolicy,
				subagentPolicy
			]),
			currentChannelId: options?.currentChannelId,
			currentThreadTs: options?.currentThreadTs,
			currentMessageId: options?.currentMessageId,
			modelProvider: options?.modelProvider,
			modelId: options?.modelId,
			replyToMode: options?.replyToMode,
			hasRepliedRef: options?.hasRepliedRef,
			modelHasVision: options?.modelHasVision,
			requireExplicitMessageTarget: options?.requireExplicitMessageTarget,
			disableMessageTool: options?.disableMessageTool,
			requesterAgentIdOverride: agentId,
			requesterSenderId: options?.senderId,
			senderIsOwner: options?.senderIsOwner,
			sessionId: options?.sessionId,
			onYield: options?.onYield,
			allowGatewaySubagentBinding: options?.allowGatewaySubagentBinding
		})
	];
	const withHooks = applyToolPolicyPipeline({
		tools: applyOwnerOnlyToolPolicy(applyModelProviderToolPolicy(filterToolsByMessageProvider(isMemoryFlushRun && memoryFlushWritePath ? tools.flatMap((tool) => {
			if (!MEMORY_FLUSH_ALLOWED_TOOL_NAMES.has(tool.name)) return [];
			if (tool.name === "write") return [wrapToolMemoryFlushAppendOnlyWrite(tool, {
				root: sandboxRoot ?? workspaceRoot,
				relativePath: memoryFlushWritePath,
				containerWorkdir: sandbox?.containerWorkdir,
				sandbox: sandboxRoot && sandboxFsBridge ? {
					root: sandboxRoot,
					bridge: sandboxFsBridge
				} : void 0
			})];
			return [tool];
		}) : tools, options?.messageProvider), {
			config: options?.config,
			modelProvider: options?.modelProvider,
			modelApi: options?.modelApi,
			modelId: options?.modelId,
			agentDir: options?.agentDir,
			modelCompat: options?.modelCompat
		}), options?.senderIsOwner === true),
		toolMeta: (tool) => getPluginToolMeta(tool),
		warn: logWarn,
		steps: [
			...buildDefaultToolPolicyPipelineSteps({
				profilePolicy: profilePolicyWithAlsoAllow,
				profile,
				profileUnavailableCoreWarningAllowlist: profilePolicy?.allow,
				providerProfilePolicy: providerProfilePolicyWithAlsoAllow,
				providerProfile,
				providerProfileUnavailableCoreWarningAllowlist: providerProfilePolicy?.allow,
				globalPolicy,
				globalProviderPolicy,
				agentPolicy,
				agentProviderPolicy,
				groupPolicy,
				agentId
			}),
			{
				policy: sandboxToolPolicy,
				label: "sandbox tools.allow"
			},
			{
				policy: subagentPolicy,
				label: "subagent tools.allow"
			}
		]
	}).map((tool) => normalizeToolParameters(tool, {
		modelProvider: options?.modelProvider,
		modelId: options?.modelId,
		modelCompat: options?.modelCompat
	})).map((tool) => wrapToolWithBeforeToolCallHook(tool, {
		agentId,
		sessionKey: options?.sessionKey,
		sessionId: options?.sessionId,
		runId: options?.runId,
		...options?.trace ? { trace: options.trace } : {},
		loopDetection: resolveToolLoopDetectionConfig({
			cfg: options?.config,
			agentId
		})
	}));
	return applyDeferredFollowupToolDescriptions(options?.abortSignal ? withHooks.map((tool) => wrapToolWithAbortSignal(tool, options.abortSignal)) : withHooks, { agentId });
}
//#endregion
export { resolveToolLoopDetectionConfig as n, normalizeToolParameters as r, createOpenClawCodingTools as t };
