require("../stream/constants.cjs");
const require_messages = require("./messages.cjs");
const require_headless_tools = require("../headless-tools.cjs");
const require_interrupts = require("./interrupts.cjs");
const require_tools = require("../utils/tools.cjs");
const require_manager = require("./manager.cjs");
//#region src/ui/orchestrator-custom.ts
/**
* Create a custom transport thread state.
* @param values - The values to use.
* @param threadId - The ID of the thread to use.
* @returns The custom transport thread state.
*/
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
	};
}
/**
* Framework-agnostic orchestrator for custom transport streams.
*
* Encapsulates all business logic shared across React, Vue, Svelte, and Angular
* for custom transport (non-LGP) streaming.
*/
var CustomStreamOrchestrator = class {
	stream;
	messageManager;
	#options;
	#historyValues;
	#threadId;
	#branch = "";
	#listeners = /* @__PURE__ */ new Set();
	#version = 0;
	#streamUnsub = null;
	#disposed = false;
	#handledHeadlessToolInterruptIds = /* @__PURE__ */ new Set();
	/**
	* Create a new {@link CustomStreamOrchestrator} instance.
	*
	* @param options - Configuration options for the custom transport stream,
	*   including thread ID, transport, callbacks, and subagent settings.
	*/
	constructor(options) {
		this.#options = options;
		this.#threadId = options.threadId ?? null;
		this.messageManager = new require_messages.MessageTupleManager();
		this.stream = new require_manager.StreamManager(this.messageManager, {
			throttle: options.throttle ?? false,
			subagentToolNames: options.subagentToolNames,
			filterSubagentMessages: options.filterSubagentMessages,
			toMessage: options.toMessage ?? require_messages.toMessageClass
		});
		this.#historyValues = options.initialValues ?? {};
		this.#streamUnsub = this.stream.subscribe(() => {
			this.#flushPendingHeadlessToolInterrupts();
			this.#notify();
		});
		const historyMessages = this.#getMessages(this.#historyValues);
		if (options.filterSubagentMessages && !this.stream.isLoading && historyMessages.length > 0) this.stream.reconstructSubagents(historyMessages, { skipIfPopulated: true });
	}
	/**
	* Register a listener that is called whenever the orchestrator state changes.
	*
	* @param listener - Callback invoked on each state change.
	* @returns An unsubscribe function that removes the listener.
	*/
	subscribe = (listener) => {
		this.#listeners.add(listener);
		return () => {
			this.#listeners.delete(listener);
		};
	};
	/**
	* Return the current version number, incremented on each state change.
	* Useful as a cache key for external sync (e.g. `useSyncExternalStore`).
	*
	* @returns The current version counter.
	*/
	getSnapshot = () => this.#version;
	/**
	* Custom transports do not negotiate stream modes with the server the way
	* LangGraph Platform streams do, but framework adapters call this method on
	* both orchestrator variants. Keep the API surface aligned as a no-op.
	*/
	trackStreamMode(..._modes) {}
	#notify() {
		if (this.#disposed) return;
		this.#version += 1;
		for (const listener of this.#listeners) listener();
	}
	/**
	* Synchronize the external thread ID with the orchestrator.
	* If the ID has changed, the current stream is cleared and listeners
	* are notified.
	*
	* @param newId - The new thread ID, or `null` to clear.
	*/
	syncThreadId(newId) {
		if (newId !== this.#threadId) {
			this.#threadId = newId;
			this.#handledHeadlessToolInterruptIds.clear();
			this.stream.clear();
			this.#notify();
		}
	}
	#getMessages = (value) => {
		const messagesKey = this.#options.messagesKey ?? "messages";
		return Array.isArray(value[messagesKey]) ? value[messagesKey] : [];
	};
	#setMessages = (current, messages) => {
		const messagesKey = this.#options.messagesKey ?? "messages";
		return {
			...current,
			[messagesKey]: messages
		};
	};
	/**
	* The current stream state values, falling back to an empty object
	* when no stream values are available.
	*/
	get values() {
		return this.stream.values ?? {};
	}
	/**
	* The raw stream state values, or `null` if no stream has been started
	* or values have not yet been received.
	*/
	get streamValues() {
		return this.stream.values;
	}
	/** The most recent stream error, or `undefined` if no error occurred. */
	get error() {
		return this.stream.error;
	}
	/** Whether a stream is currently in progress. */
	get isLoading() {
		return this.stream.isLoading;
	}
	/** The current branch identifier. */
	get branch() {
		return this.#branch;
	}
	/**
	* Update the current branch and notify listeners.
	*
	* @param value - The new branch identifier.
	*/
	setBranch(value) {
		this.#branch = value;
		this.#notify();
	}
	/**
	* All messages from the current stream values, converted to
	* {@link BaseMessage} instances. Returns an empty array when no
	* stream values are available.
	*/
	get messages() {
		if (!this.stream.values) return [];
		return require_messages.ensureMessageInstances(this.#getMessages(this.stream.values));
	}
	/**
	* All tool calls paired with their results extracted from the
	* current stream messages.
	*/
	get toolCalls() {
		if (!this.stream.values) return [];
		return require_tools.getToolCallsWithResults(this.#getMessages(this.stream.values));
	}
	/**
	* Get tool calls (with results) that belong to a specific AI message.
	*
	* @param message - The AI message whose tool calls to retrieve.
	* @returns Tool calls associated with the given message.
	*/
	getToolCalls(message) {
		if (!this.stream.values) return [];
		return require_tools.getToolCallsWithResults(this.#getMessages(this.stream.values)).filter((tc) => tc.aiMessage.id === message.id);
	}
	/**
	* All active interrupts from the current stream values.
	* Returns a single breakpoint interrupt when the interrupt array is
	* present but empty, or an empty array when no interrupts exist.
	*/
	get interrupts() {
		if (this.stream.values != null && "__interrupt__" in this.stream.values && Array.isArray(this.stream.values.__interrupt__)) return require_interrupts.userFacingInterruptsFromValuesArray(this.stream.values.__interrupt__);
		return [];
	}
	/**
	* The first active interrupt extracted from the current stream values,
	* or `undefined` if there are no interrupts.
	*/
	get interrupt() {
		return require_interrupts.extractInterrupts(this.stream.values);
	}
	/**
	* Retrieve stream-level metadata for a given message.
	*
	* @param message - The message to look up metadata for.
	* @param index - Optional positional index used as fallback message ID.
	* @returns The metadata associated with the message, or `undefined`
	*   if no stream metadata is available.
	*/
	getMessagesMetadata(message, index) {
		const streamMetadata = this.messageManager.get(message.id)?.metadata;
		if (streamMetadata != null) return {
			messageId: message.id ?? String(index),
			firstSeenState: void 0,
			branch: void 0,
			branchOptions: void 0,
			streamMetadata
		};
	}
	/** A map of all tracked subagent streams, keyed by tool call ID. */
	get subagents() {
		return this.stream.getSubagents();
	}
	/** The subset of subagent streams that are currently active (loading). */
	get activeSubagents() {
		return this.stream.getActiveSubagents();
	}
	/**
	* Look up a single subagent stream by its tool call ID.
	*
	* @param toolCallId - The tool call ID that initiated the subagent.
	* @returns The subagent stream, or `undefined` if not found.
	*/
	getSubagent(toolCallId) {
		return this.stream.getSubagent(toolCallId);
	}
	/**
	* Retrieve all subagent streams matching a given tool name / type.
	*
	* @param type - The subagent type (tool name) to filter by.
	* @returns An array of matching subagent streams.
	*/
	getSubagentsByType(type) {
		return this.stream.getSubagentsByType(type);
	}
	/**
	* Retrieve all subagent streams associated with a specific AI message.
	*
	* @param messageId - The ID of the parent AI message.
	* @returns An array of subagent streams linked to the message.
	*/
	getSubagentsByMessage(messageId) {
		return this.stream.getSubagentsByMessage(messageId);
	}
	/**
	* Reconstruct subagent streams from history values when subagent
	* filtering is enabled and the stream is not currently loading.
	* This is a no-op if subagents are already populated.
	*/
	reconstructSubagentsIfNeeded() {
		const hvMessages = this.#getMessages(this.#historyValues);
		if (this.#options.filterSubagentMessages && !this.stream.isLoading && hvMessages.length > 0) this.stream.reconstructSubagents(hvMessages, { skipIfPopulated: true });
	}
	/**
	* Abort the current stream and invoke the `onStop` callback
	* if one was provided in the options.
	*/
	stop() {
		this.stream.stop(this.#historyValues, { onStop: this.#options.onStop });
	}
	/**
	* Switch to a different thread. If the thread ID actually changed,
	* the current stream is cleared and listeners are notified.
	*
	* @param newThreadId - The thread ID to switch to, or `null` to clear.
	*/
	switchThread(newThreadId) {
		if (newThreadId !== this.#threadId) {
			this.#threadId = newThreadId;
			this.#handledHeadlessToolInterruptIds.clear();
			this.stream.clear();
			this.#notify();
		}
	}
	/**
	* Start a new stream run against the custom transport.
	*
	* This is the low-level submit entry point that handles thread ID
	* resolution, optimistic value merging, and transport invocation.
	* Prefer {@link submit} unless you need to bypass higher-level wrappers.
	*
	* @param values - The input values to send, or `null`/`undefined` for
	*   a resume-style invocation.
	* @param submitOptions - Optional per-call overrides such as
	*   `optimisticValues`, `config`, `command`, and error callbacks.
	*/
	async submitDirect(values, submitOptions) {
		const currentThreadId = this.#options.threadId ?? null;
		if (currentThreadId !== this.#threadId) {
			this.#threadId = currentThreadId;
			this.stream.clear();
		}
		let usableThreadId = this.#threadId ?? submitOptions?.threadId;
		this.stream.setStreamValues(() => {
			if (submitOptions?.optimisticValues != null) return {
				...this.#historyValues,
				...typeof submitOptions.optimisticValues === "function" ? submitOptions.optimisticValues(this.#historyValues) : submitOptions.optimisticValues
			};
			return { ...this.#historyValues };
		});
		await this.stream.start(async (signal) => {
			if (!usableThreadId) {
				usableThreadId = crypto.randomUUID();
				this.#threadId = usableThreadId;
				this.#options.onThreadId?.(usableThreadId);
			}
			if (!usableThreadId) throw new Error("Failed to obtain valid thread ID.");
			return this.#options.transport.stream({
				input: values,
				context: submitOptions?.context,
				command: submitOptions?.command,
				streamSubgraphs: submitOptions?.streamSubgraphs,
				signal,
				config: {
					...submitOptions?.config,
					configurable: {
						thread_id: usableThreadId,
						...submitOptions?.config?.configurable
					}
				}
			});
		}, {
			getMessages: this.#getMessages,
			setMessages: this.#setMessages,
			initialValues: {},
			callbacks: this.#options,
			onSuccess: () => {
				if (!usableThreadId) return void 0;
				const finalValues = this.stream.values ?? this.#historyValues;
				this.#options.onFinish?.(createCustomTransportThreadState(finalValues, usableThreadId), void 0);
			},
			onError: (error) => {
				this.#options.onError?.(error, void 0);
				submitOptions?.onError?.(error, void 0);
			}
		});
	}
	/**
	* Submit input values and start a new stream run.
	*
	* Delegates to {@link submitDirect}. Override or wrap this method
	* in framework adapters to add queuing or other middleware.
	*
	* @param values - The input values to send, or `null`/`undefined` for
	*   a resume-style invocation.
	* @param submitOptions - Optional per-call overrides.
	*/
	async submit(values, submitOptions) {
		await this.submitDirect(values, submitOptions);
	}
	/**
	* Tear down the orchestrator. Marks the instance as disposed,
	* unsubscribes from the stream, and aborts any in-progress stream.
	* After calling this method, no further notifications will be emitted.
	*/
	dispose() {
		this.#disposed = true;
		this.#streamUnsub?.();
		this.#streamUnsub = null;
		this.stream.stop(this.#historyValues, { onStop: this.#options.onStop });
	}
	#flushPendingHeadlessToolInterrupts() {
		require_headless_tools.flushPendingHeadlessToolInterrupts(this.stream.values, this.#options.tools, this.#handledHeadlessToolInterruptIds, {
			onTool: this.#options.onTool,
			defer: (run) => {
				Promise.resolve().then(run);
			},
			resumeSubmit: (command) => this.submit(null, { command })
		});
	}
};
//#endregion
exports.CustomStreamOrchestrator = CustomStreamOrchestrator;

//# sourceMappingURL=orchestrator-custom.cjs.map