import { s as normalizeOptionalLowercaseString } from "./string-coerce-mnp54Vah.js";
import { t as callGatewayTool } from "./gateway-BEg4yNzU.js";
import { n as parsePairingList, t as parseNodeList } from "./node-list-parse-BSOtZszw.js";
import { n as resolveNodeIdFromNodeList, t as resolveNodeFromNodeList } from "./node-resolve-BawtWMwa.js";
//#region src/agents/agent-tools.params.ts
const RETRY_GUIDANCE_SUFFIX = " Supply correct parameters before retrying.";
const XML_ARG_VALUE_SUFFIX_RE = /<\/arg_value>>+$/;
const XML_ARG_VALUE_PATH_PARAM_KEYS = new Set(["path"]);
function parameterValidationError(message) {
	return /* @__PURE__ */ new Error(`${message}.${RETRY_GUIDANCE_SUFFIX}`);
}
function describeReceivedParamValue(value, allowEmpty = false) {
	if (value === void 0 || value === null) return;
	if (typeof value === "string") {
		if (allowEmpty || value.trim().length > 0) return;
		return "<empty-string>";
	}
	if (Array.isArray(value)) return "<array>";
	return `<${typeof value}>`;
}
function formatReceivedParamHint(record, groups) {
	const allowEmptyKeys = /* @__PURE__ */ new Set();
	for (const group of groups) if (group.allowEmpty) for (const key of group.keys) allowEmptyKeys.add(key);
	const received = [];
	for (const key of Object.keys(record)) {
		const detail = describeReceivedParamValue(record[key], allowEmptyKeys.has(key));
		if (record[key] === void 0 || record[key] === null) continue;
		received.push(detail ? `${key}=${detail}` : key);
	}
	return received.length > 0 ? ` (received: ${received.join(", ")})` : "";
}
function isValidEditReplacement(value) {
	if (!value || typeof value !== "object") return false;
	const record = value;
	return typeof record.oldText === "string" && record.oldText.trim().length > 0 && typeof record.newText === "string";
}
function hasValidEditReplacements(record) {
	const edits = record.edits;
	return Array.isArray(edits) && edits.length > 0 && edits.every((entry) => isValidEditReplacement(entry));
}
/** Required parameter groups for file-style tools that need retry guidance. */
const REQUIRED_PARAM_GROUPS = {
	read: [{
		keys: ["path"],
		label: "path"
	}],
	write: [{
		keys: ["path"],
		label: "path"
	}, {
		keys: ["content"],
		label: "content"
	}],
	edit: [{
		keys: ["path"],
		label: "path"
	}, {
		keys: ["edits"],
		label: "edits",
		validator: hasValidEditReplacements
	}]
};
/** Return a record view of model-supplied tool params when possible. */
function getToolParamsRecord(params) {
	return params && typeof params === "object" ? params : void 0;
}
/** Strip extra closing markers sometimes produced in XML arg_value path params. */
function stripMalformedXmlArgValueSuffix(value) {
	return value.includes("</arg_value>") ? value.replace(XML_ARG_VALUE_SUFFIX_RE, "") : value;
}
/** Strip malformed XML suffixes from selected string fields without mutating input. */
function stripMalformedXmlArgValueSuffixFromKeys(record, keys) {
	let normalized;
	for (const key of keys) {
		const value = record[key];
		if (typeof value !== "string") continue;
		const stripped = stripMalformedXmlArgValueSuffix(value);
		if (stripped !== value) {
			normalized ??= { ...record };
			normalized[key] = stripped;
		}
	}
	return normalized ?? record;
}
function resolveMalformedXmlArgValuePathKeys(groups) {
	const keys = /* @__PURE__ */ new Set();
	for (const group of groups ?? []) for (const key of group.keys) if (XML_ARG_VALUE_PATH_PARAM_KEYS.has(key)) keys.add(key);
	return [...keys];
}
/** Throw actionable retry guidance when required tool params are missing. */
function assertRequiredParams(record, groups, toolName) {
	if (!record || typeof record !== "object") throw parameterValidationError(`Missing parameters for ${toolName}`);
	const missingLabels = [];
	for (const group of groups) if (!(group.validator?.(record) ?? group.keys.some((key) => {
		if (!(key in record)) return false;
		const value = record[key];
		if (typeof value !== "string") return false;
		if (group.allowEmpty) return true;
		return value.trim().length > 0;
	}))) {
		const label = group.label ?? group.keys.join(" or ");
		missingLabels.push(label);
	}
	if (missingLabels.length > 0) {
		const joined = missingLabels.join(", ");
		throw parameterValidationError(`Missing required ${missingLabels.length === 1 ? "parameter" : "parameters"}: ${joined}${formatReceivedParamHint(record, groups)}`);
	}
}
/** Wrap a tool execute function with required-parameter validation. */
function wrapToolParamValidation(tool, requiredParamGroups) {
	return {
		...tool,
		execute: async (toolCallId, params, signal, onUpdate) => {
			const record = getToolParamsRecord(params);
			const pathKeys = resolveMalformedXmlArgValuePathKeys(requiredParamGroups);
			const normalizedParams = record && pathKeys.length > 0 ? stripMalformedXmlArgValueSuffixFromKeys(record, pathKeys) : params;
			if (requiredParamGroups?.length) assertRequiredParams(getToolParamsRecord(normalizedParams), requiredParamGroups, tool.name);
			return tool.execute(toolCallId, normalizedParams, signal, onUpdate);
		}
	};
}
//#endregion
//#region src/agents/tools/nodes-utils.ts
/**
* Nodes lookup helpers.
*
* Loads paired nodes from Gateway and resolves requested/default nodes with legacy pair-list fallback.
*/
function messageFromError(error) {
	if (error instanceof Error) return error.message;
	if (typeof error === "string") return error;
	if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") return error.message;
	if (typeof error === "object" && error !== null) try {
		return JSON.stringify(error);
	} catch {
		return "";
	}
	return "";
}
function shouldFallbackToPairList(error) {
	const message = normalizeOptionalLowercaseString(messageFromError(error)) ?? "";
	if (!message.includes("node.list")) return false;
	return message.includes("unknown method") || message.includes("method not found") || message.includes("not implemented") || message.includes("unsupported");
}
async function loadNodes(opts) {
	try {
		return parseNodeList(await callGatewayTool("node.list", opts, {}));
	} catch (error) {
		if (!shouldFallbackToPairList(error)) throw error;
		const { paired } = parsePairingList(await callGatewayTool("node.pair.list", opts, {}));
		return paired.map((n) => ({
			nodeId: n.nodeId,
			displayName: n.displayName,
			platform: n.platform,
			remoteIp: n.remoteIp
		}));
	}
}
function isLocalMacNode(node) {
	return normalizeOptionalLowercaseString(node.platform)?.startsWith("mac") === true && typeof node.nodeId === "string" && node.nodeId.startsWith("mac-");
}
function compareDefaultNodeOrder(a, b) {
	const aConnectedAt = Number.isFinite(a.connectedAtMs) ? a.connectedAtMs ?? 0 : -1;
	const bConnectedAt = Number.isFinite(b.connectedAtMs) ? b.connectedAtMs ?? 0 : -1;
	if (aConnectedAt !== bConnectedAt) return bConnectedAt - aConnectedAt;
	return a.nodeId.localeCompare(b.nodeId);
}
/** Selects the implicit node target when a tool call omits an explicit node query. */
function selectDefaultNodeFromList(nodes, options = {}) {
	const capability = options.capability?.trim();
	const withCapability = capability ? nodes.filter((n) => Array.isArray(n.caps) ? n.caps.includes(capability) : true) : nodes;
	if (withCapability.length === 0) return null;
	const connected = withCapability.filter((n) => n.connected);
	const candidates = connected.length > 0 ? connected : withCapability;
	if (candidates.length === 1) return candidates[0];
	if (options.preferLocalMac ?? true) {
		const local = candidates.filter(isLocalMacNode);
		if (local.length === 1) return local[0];
	}
	if ((options.fallback ?? "none") === "none") return null;
	return [...candidates].toSorted(compareDefaultNodeOrder)[0] ?? null;
}
function pickDefaultNode(nodes) {
	return selectDefaultNodeFromList(nodes, {
		capability: "canvas",
		fallback: "first",
		preferLocalMac: true
	});
}
/** Lists Gateway nodes, falling back to paired-node records for older Gateway versions. */
async function listNodes(opts) {
	return loadNodes(opts);
}
/** Resolves a node id from an already-loaded node list using shared node matching rules. */
function resolveNodeIdFromList(nodes, query, allowDefault = false) {
	return resolveNodeIdFromNodeList(nodes, query, {
		allowDefault,
		pickDefaultNode
	});
}
/** Loads nodes from the Gateway and resolves the requested or default node id. */
async function resolveNodeId(opts, query, allowDefault = false) {
	return (await resolveNode(opts, query, allowDefault)).nodeId;
}
/** Loads nodes from the Gateway and returns the requested or default node record. */
async function resolveNode(opts, query, allowDefault = false) {
	return resolveNodeFromNodeList(await loadNodes(opts), query, {
		allowDefault,
		pickDefaultNode
	});
}
//#endregion
export { selectDefaultNodeFromList as a, getToolParamsRecord as c, wrapToolParamValidation as d, resolveNodeIdFromList as i, stripMalformedXmlArgValueSuffix as l, resolveNode as n, REQUIRED_PARAM_GROUPS as o, resolveNodeId as r, assertRequiredParams as s, listNodes as t, stripMalformedXmlArgValueSuffixFromKeys as u };
