//#region src/utils/testing/stream.ts
function isChatModelStream(received) {
	if (received == null || typeof received !== "object") return false;
	const stream = received;
	return typeof stream.text !== "undefined" && typeof stream.toolCalls !== "undefined" && typeof stream.reasoning !== "undefined" && typeof stream.usage !== "undefined" && typeof stream.output !== "undefined" && typeof stream[Symbol.asyncIterator] === "function";
}
function matchesPartialObject(actual, expected, equals) {
	if (actual == null) return false;
	return Object.entries(expected).every(([key, value]) => equals(actual[key], value));
}
function matchesStreamUsage(actual, expected, equals) {
	if (actual == null) return false;
	return matchesPartialObject(actual, expected, equals);
}
function getOutputText(message) {
	return message.content.find((block) => block.type === "text")?.text;
}
function matchesStreamOutput(message, expected, equals) {
	if (expected.id !== void 0 && message.id !== expected.id) return false;
	if (expected.text !== void 0 && getOutputText(message) !== expected.text) return false;
	if (expected.toolCalls !== void 0) {
		const calls = message.tool_calls ?? [];
		if (calls.length !== expected.toolCalls.length) return false;
		for (let i = 0; i < expected.toolCalls.length; i++) {
			const call = calls[i];
			const exp = expected.toolCalls[i];
			if (call?.name !== exp.name || !equals(call.args, exp.args)) return false;
		}
	}
	if (expected.usage !== void 0 && !matchesStreamUsage(message.usage_metadata, expected.usage, equals)) return false;
	if (expected.responseMetadata !== void 0 && !matchesPartialObject(message.response_metadata, expected.responseMetadata, equals)) return false;
	return true;
}
function invalidStreamResult(received, matcherName, utils) {
	return {
		pass: false,
		message: () => `${utils.matcherHint(matcherName)}\n\nExpected: ChatModelStream (return value of model.streamEvents("Hello"))\nReceived: ${utils.printReceived(received)}`,
		actual: received,
		expected: "ChatModelStream"
	};
}
function applyNot(pass, isNot) {
	return isNot ? !pass : pass;
}
async function toHaveStreamText(received, expected) {
	const { isNot, utils } = this;
	const matcherName = "toHaveStreamText";
	if (!isChatModelStream(received)) return invalidStreamResult(received, matcherName, utils);
	const actual = await received.text;
	return {
		pass: applyNot(actual === expected, isNot),
		message: () => `${utils.matcherHint(matcherName, void 0, void 0, { isNot })}\n\nExpected stream text: ${isNot ? "not " : ""}${utils.printExpected(expected)}\nReceived stream text: ${utils.printReceived(actual)}`,
		actual,
		expected
	};
}
async function toHaveStreamReasoning(received, expected) {
	const { isNot, utils } = this;
	const matcherName = "toHaveStreamReasoning";
	if (!isChatModelStream(received)) return invalidStreamResult(received, matcherName, utils);
	const actual = await received.reasoning;
	return {
		pass: applyNot(actual === expected, isNot),
		message: () => `${utils.matcherHint(matcherName, void 0, void 0, { isNot })}\n\nExpected stream reasoning: ${isNot ? "not " : ""}${utils.printExpected(expected)}\nReceived stream reasoning: ${utils.printReceived(actual)}`,
		actual,
		expected
	};
}
async function toHaveStreamToolCalls(received, expected) {
	const { isNot, utils } = this;
	const matcherName = "toHaveStreamToolCalls";
	if (!isChatModelStream(received)) return invalidStreamResult(received, matcherName, utils);
	const actual = await received.toolCalls;
	let pass = actual.length === expected.length && expected.every((exp, i) => {
		const call = actual[i];
		return call?.name === exp.name && this.equals(call.args, exp.args);
	});
	pass = applyNot(pass, isNot);
	return {
		pass,
		message: () => `${utils.matcherHint(matcherName, void 0, void 0, { isNot })}\n\nExpected stream tool calls: ${utils.printExpected(expected)}\nReceived stream tool calls: ${utils.printReceived(actual.map((tc) => ({
			name: tc.name,
			args: tc.args
		})))}`,
		actual: actual.map((tc) => ({
			name: tc.name,
			args: tc.args
		})),
		expected
	};
}
async function toHaveStreamUsage(received, expected) {
	const { isNot, utils } = this;
	const matcherName = "toHaveStreamUsage";
	if (!isChatModelStream(received)) return invalidStreamResult(received, matcherName, utils);
	const actual = await received.usage;
	return {
		pass: applyNot(matchesStreamUsage(actual, expected, this.equals), isNot),
		message: () => `${utils.matcherHint(matcherName, void 0, void 0, { isNot })}\n\nExpected stream usage: ${utils.printExpected(expected)}\nReceived stream usage: ${utils.printReceived(actual)}`,
		actual,
		expected
	};
}
async function toHaveStreamOutput(received, expected) {
	const { isNot, utils } = this;
	const matcherName = "toHaveStreamOutput";
	if (!isChatModelStream(received)) return invalidStreamResult(received, matcherName, utils);
	const message = await received.output;
	return {
		pass: applyNot(matchesStreamOutput(message, expected, this.equals), isNot),
		message: () => `${utils.matcherHint(matcherName, void 0, void 0, { isNot })}\n\nExpected stream output: ${utils.printExpected(expected)}\nReceived stream output: ${utils.printReceived({
			id: message.id,
			text: getOutputText(message),
			tool_calls: message.tool_calls?.map((tc) => ({
				name: tc.name,
				args: tc.args
			})),
			usage_metadata: message.usage_metadata,
			response_metadata: message.response_metadata
		})}`,
		actual: message,
		expected
	};
}
/** Stream matchers for `expect.extend()`. */
const streamMatchers = {
	toHaveStreamText,
	toHaveStreamReasoning,
	toHaveStreamToolCalls,
	toHaveStreamUsage,
	toHaveStreamOutput
};
//#endregion
export { streamMatchers };

//# sourceMappingURL=stream.js.map