"use client";
import { BytesLineDecoder, SSEDecoder } from "../utils/sse.js";
import { IterableReadableStream } from "../utils/stream.js";
import "../stream/constants.js";
import { MessageTupleManager } from "../ui/messages.js";
import { flushPendingHeadlessToolInterrupts } from "../headless-tools.js";
import { userFacingInterruptsFromValuesArray } from "../ui/interrupts.js";
import { getToolCallsWithResults } from "../utils/tools.js";
import { StreamManager } from "../ui/manager.js";
import { useControllableThreadId } from "./thread.js";
import { useEffect, useRef, useState, useSyncExternalStore } from "react";
//#region src/react/stream.custom.tsx
var FetchStreamTransport = class {
	constructor(options) {
		this.options = options;
	}
	async stream(payload) {
		const { signal, ...body } = payload;
		let requestInit = {
			method: "POST",
			headers: {
				"Content-Type": "application/json",
				...this.options.defaultHeaders
			},
			body: JSON.stringify(body),
			signal
		};
		if (this.options.onRequest) requestInit = await this.options.onRequest(this.options.apiUrl, requestInit);
		const response = await (this.options.fetch ?? fetch)(this.options.apiUrl, requestInit);
		if (!response.ok) throw new Error(`Failed to stream: ${response.statusText}`);
		const stream = (response.body || new ReadableStream({ start: (ctrl) => ctrl.close() })).pipeThrough(BytesLineDecoder()).pipeThrough(SSEDecoder());
		return IterableReadableStream.fromReadableStream(stream);
	}
};
function createCustomTransportThreadState(values, threadId) {
	return {
		values,
		next: [],
		tasks: [],
		metadata: void 0,
		created_at: null,
		checkpoint: {
			thread_id: threadId,
			checkpoint_id: null,
			checkpoint_ns: "",
			checkpoint_map: null
		},
		parent_checkpoint: null
	};
}
function useStreamCustom(options) {
	const [messageManager] = useState(() => new MessageTupleManager());
	const [stream] = useState(() => new StreamManager(messageManager, {
		throttle: options.throttle ?? false,
		subagentToolNames: options.subagentToolNames,
		filterSubagentMessages: options.filterSubagentMessages
	}));
	useSyncExternalStore(stream.subscribe, stream.getSnapshot, stream.getSnapshot);
	const [threadId, onThreadId] = useControllableThreadId(options);
	const threadIdRef = useRef(threadId);
	useEffect(() => {
		if (threadIdRef.current !== threadId) {
			threadIdRef.current = threadId;
			stream.clear();
		}
	}, [threadId, stream]);
	const getMessages = (value) => {
		const messagesKey = options.messagesKey ?? "messages";
		return Array.isArray(value[messagesKey]) ? value[messagesKey] : [];
	};
	const setMessages = (current, messages) => {
		const messagesKey = options.messagesKey ?? "messages";
		return {
			...current,
			[messagesKey]: messages
		};
	};
	const historyValues = options.initialValues ?? {};
	const historyMessages = getMessages(historyValues);
	const shouldReconstructSubagents = options.filterSubagentMessages && !stream.isLoading && historyMessages.length > 0;
	useEffect(() => {
		if (shouldReconstructSubagents) stream.reconstructSubagents(historyMessages, { skipIfPopulated: true });
	}, [shouldReconstructSubagents, historyMessages.length]);
	const stop = () => stream.stop(historyValues, { onStop: options.onStop });
	const submit = async (values, submitOptions) => {
		let usableThreadId = threadId;
		stream.setStreamValues(() => {
			if (submitOptions?.optimisticValues != null) return {
				...historyValues,
				...typeof submitOptions.optimisticValues === "function" ? submitOptions.optimisticValues(historyValues) : submitOptions.optimisticValues
			};
			return { ...historyValues };
		});
		await stream.start(async (signal) => {
			if (!usableThreadId) {
				usableThreadId = crypto.randomUUID();
				threadIdRef.current = usableThreadId;
				onThreadId(usableThreadId);
			}
			if (!usableThreadId) throw new Error("Failed to obtain valid thread ID.");
			return options.transport.stream({
				input: values,
				context: submitOptions?.context,
				command: submitOptions?.command,
				signal,
				config: {
					...submitOptions?.config,
					configurable: {
						thread_id: usableThreadId,
						...submitOptions?.config?.configurable
					}
				}
			});
		}, {
			getMessages,
			setMessages,
			initialValues: {},
			callbacks: options,
			onSuccess: () => {
				if (!usableThreadId) return void 0;
				const finalValues = stream.values ?? historyValues;
				options.onFinish?.(createCustomTransportThreadState(finalValues, usableThreadId), void 0);
			},
			onError(error) {
				options.onError?.(error, void 0);
			}
		});
	};
	const handledToolsRef = useRef(/* @__PURE__ */ new Set());
	useEffect(() => {
		handledToolsRef.current.clear();
	}, [threadId]);
	useEffect(() => {
		flushPendingHeadlessToolInterrupts(stream.values, options.tools, handledToolsRef.current, {
			onTool: options.onTool,
			defer: (run) => {
				Promise.resolve().then(run);
			},
			resumeSubmit: (command) => submit(null, { command })
		});
	}, [
		options.onTool,
		options.tools,
		stream.values,
		submit
	]);
	return {
		get values() {
			return stream.values ?? {};
		},
		error: stream.error,
		isLoading: stream.isLoading,
		stop,
		submit,
		get interrupts() {
			if (stream.values != null && "__interrupt__" in stream.values && Array.isArray(stream.values.__interrupt__)) return userFacingInterruptsFromValuesArray(stream.values.__interrupt__);
			return [];
		},
		get interrupt() {
			const all = this.interrupts;
			if (all.length === 0) return void 0;
			if (all.length === 1) return all[0];
			return all;
		},
		get messages() {
			if (!stream.values) return [];
			return getMessages(stream.values);
		},
		get toolCalls() {
			if (!stream.values) return [];
			return getToolCallsWithResults(getMessages(stream.values));
		},
		getToolCalls(message) {
			if (!stream.values) return [];
			return getToolCallsWithResults(getMessages(stream.values)).filter((tc) => tc.aiMessage.id === message.id);
		},
		get subagents() {
			return stream.getSubagents();
		},
		get activeSubagents() {
			return stream.getActiveSubagents();
		},
		getSubagent(toolCallId) {
			return stream.getSubagent(toolCallId);
		},
		getSubagentsByType(type) {
			return stream.getSubagentsByType(type);
		},
		getSubagentsByMessage(messageId) {
			return stream.getSubagentsByMessage(messageId);
		}
	};
}
//#endregion
export { FetchStreamTransport, useStreamCustom };

//# sourceMappingURL=stream.custom.js.map