import { StreamChannel } from "../stream-channel.js";
import { hasPrefix } from "../mux.js";
import { ChatModelStream } from "@langchain/core/language_models/stream";
//#region src/stream/transformers/messages.ts
function getMessageStreamKey(data) {
	const record = data;
	if (typeof record.run_id === "string") return `run:${record.run_id}`;
	if (data.event === "message-start" && typeof record.id === "string") return `message:${record.id}`;
	return "__default__";
}
/**
* Creates a {@link StreamTransformer} that groups `messages` channel events into
* per-message {@link ChatModelStream} instances.
*
* A new `ChatModelStream` is created on `message-start` and closed on
* `message-finish`. Content-block events in between are forwarded to the
* active stream. Only events whose namespace exactly matches {@link path}
* are processed; child namespaces are ignored.
*
* @param path - Namespace prefix to match against incoming events.
* @param nodeFilter - If provided, only events emitted by this graph node
*   are processed; all others are skipped.
* @returns A `StreamTransformer` whose projection contains the `messages`
*   async iterable.
*/
function createMessagesTransformer(path, nodeFilter) {
	const log = StreamChannel.local();
	const active = /* @__PURE__ */ new Map();
	const ignored = /* @__PURE__ */ new Set();
	return {
		init: () => ({ messages: log.toAsyncIterable() }),
		process(event) {
			if (event.method !== "messages") return true;
			if (!hasPrefix(event.params.namespace, path)) return true;
			if (event.params.namespace.length !== path.length + 1) return true;
			if (nodeFilter !== void 0 && event.params.node !== nodeFilter) return true;
			const data = event.params.data;
			switch (data.event) {
				case "message-start": {
					const key = getMessageStreamKey(data);
					if (data.role === "tool") {
						ignored.add(key);
						break;
					}
					const source = StreamChannel.local();
					const stream = Object.assign(new ChatModelStream(source.toAsyncIterable()), {
						namespace: event.params.namespace,
						node: event.params.node
					});
					active.set(key, {
						source,
						stream
					});
					source.push(data);
					log.push(stream);
					break;
				}
				case "content-block-start":
				case "content-block-delta":
				case "content-block-finish":
					if (ignored.has(getMessageStreamKey(data))) break;
					active.get(getMessageStreamKey(data))?.source.push(data);
					break;
				case "message-finish": {
					const key = getMessageStreamKey(data);
					if (ignored.delete(key)) break;
					const stream = active.get(key);
					if (stream) {
						stream.source.push(data);
						stream.source.close();
						active.delete(key);
					}
					break;
				}
				case "error":
					if (ignored.has(getMessageStreamKey(data))) break;
					active.get(getMessageStreamKey(data))?.source.push(data);
					break;
			}
			return true;
		},
		finalize() {
			for (const [key, stream] of active) {
				stream.source.push({ event: "message-finish" });
				stream.source.close();
				active.delete(key);
			}
			ignored.clear();
			log.close();
		},
		fail(err) {
			for (const [key, stream] of active) {
				stream.source.fail(err);
				active.delete(key);
			}
			ignored.clear();
			log.fail(err);
		}
	};
}
//#endregion
export { createMessagesTransformer };

//# sourceMappingURL=messages.js.map