import { AIMessage, HumanMessage, RemoveMessage, SystemMessage, ToolMessage, coerceMessageLikeToMessage } from "@langchain/core/messages";
//#region src/stream/message-coercion.ts
/**
* Stream-local message coercion for serialized messages returned by
* `getState()`, `getHistory()`, and `values` events.
*
* LangGraph API payloads may carry v1 content blocks as snake_case
* `content_blocks`, while `@langchain/core` message constructors only
* understand camelCase `contentBlocks` (or `content`). Normalize that
* boundary here so stream consumers always see `BaseMessage.text`.
*/
function tryCoerceMessageLikeToMessage(message) {
	const normalized = normalizeAIMessageToolCalls(message);
	if (normalized.type === "human" || normalized.type === "user") return new HumanMessage(normalized);
	if (normalized.type === "ai" || normalized.type === "assistant") return new AIMessage(normalized);
	if (normalized.type === "system") return new SystemMessage(normalized);
	if (normalized.type === "tool" && "tool_call_id" in normalized) return new ToolMessage({
		...normalized,
		tool_call_id: normalized.tool_call_id
	});
	if (normalized.type === "remove" && normalized.id != null) return new RemoveMessage({
		...normalized,
		id: normalized.id
	});
	return coerceMessageLikeToMessage(normalized);
}
/**
* Ensures all messages in an array are BaseMessage class instances.
* Messages that are already class instances pass through unchanged.
*/
function ensureMessageInstances(messages) {
	return messages.map((msg) => {
		if (typeof msg.getType === "function") return msg;
		return tryCoerceMessageLikeToMessage(msg);
	});
}
function normalizeSerializedContentBlocks(message) {
	const record = message;
	const contentBlocks = record.contentBlocks ?? record.content_blocks;
	if (!Array.isArray(contentBlocks) || contentBlocks.length === 0) return message;
	const shouldPreferContentBlocks = isEmptyContent(record.content) || !hasTextContent(record.content) && hasTextContent(contentBlocks);
	if (!shouldPreferContentBlocks && record.contentBlocks === contentBlocks) return message;
	return {
		...message,
		content: shouldPreferContentBlocks ? contentBlocks : record.content,
		contentBlocks
	};
}
function normalizeAIMessageToolCalls(message) {
	const normalized = normalizeSerializedContentBlocks(message);
	const record = normalized;
	if (Array.isArray(record.tool_calls) && record.tool_calls.length > 0) return normalized;
	const toolCalls = extractToolCallsFromContent(record.content);
	if (toolCalls.length === 0) return normalized;
	return {
		...normalized,
		tool_calls: toolCalls
	};
}
function extractToolCallsFromContent(content) {
	if (!Array.isArray(content)) return [];
	return content.flatMap((block) => {
		if (block == null || typeof block !== "object") return [];
		const record = block;
		if (record.type !== "tool_call" && record.type !== "tool_use") return [];
		return [{
			id: record.id ?? "",
			name: record.name ?? "",
			args: normalizeToolCallArgs(record.args ?? record.input),
			type: "tool_call"
		}];
	});
}
function normalizeToolCallArgs(value) {
	if (value != null && typeof value === "object" && !Array.isArray(value)) return value;
	if (typeof value === "string" && value.length > 0) try {
		const parsed = JSON.parse(value);
		if (parsed != null && typeof parsed === "object" && !Array.isArray(parsed)) return parsed;
	} catch {}
	return {};
}
function isEmptyContent(content) {
	return content == null || content === "" || Array.isArray(content) && content.length === 0;
}
function hasTextContent(content) {
	if (typeof content === "string") return content.length > 0;
	if (!Array.isArray(content)) return false;
	return content.some((block) => {
		if (typeof block === "string") return block.length > 0;
		if (block == null || typeof block !== "object") return false;
		const record = block;
		return record.type === "text" && typeof record.text === "string" && record.text.length > 0;
	});
}
//#endregion
export { ensureMessageInstances, normalizeAIMessageToolCalls, tryCoerceMessageLikeToMessage };

//# sourceMappingURL=message-coercion.js.map