import { coerceTimeoutPolicy } from "../pregel/utils/timeout.js";
import { CONFIG_KEY_NODE_ERROR, Command, END, OVERWRITE, SELF, START, TAG_HIDDEN, _getOverwriteValue, _isSend, isCommand, isInterrupted } from "../constants.js";
import { InvalidUpdateError, ParentCommand, StateGraphInputError } from "../errors.js";
import { LastValueAfterFinish } from "../channels/last_value.js";
import { AnnotationRoot, getChannel } from "./annotation.js";
import { RunnableCallable } from "../utils.js";
import { ChannelWrite, PASSTHROUGH } from "../pregel/write.js";
import { ChannelRead, PregelNode } from "../pregel/read.js";
import "../pregel/utils/index.js";
import { isPregelLike } from "../pregel/utils/subgraph.js";
import { EphemeralValue } from "../channels/ephemeral_value.js";
import { Branch, CompiledGraph, Graph } from "./graph.js";
import { NamedBarrierValue, NamedBarrierValueAfterFinish } from "../channels/named_barrier_value.js";
import { StateSchema } from "../state/schema.js";
import "../state/index.js";
import { schemaMetaRegistry } from "./zod/meta.js";
import { isStateDefinitionInit, isStateGraphInit } from "./types.js";
import { Runnable, _coerceToRunnable } from "@langchain/core/runnables";
import { getInteropZodObjectShape, interopParse, interopZodObjectPartial, isInteropZodObject } from "@langchain/core/utils/types";
//#region src/graph/state.ts
const ROOT = "__root__";
/**
* Reserved node name for the single shared error handler that is materialized
* when a graph-wide default error handler is set via
* {@link StateGraph.setNodeDefaults}. Every regular node that lacks its own
* `errorHandler` routes failures to this node. Mirrors Python's
* `__default_error_handler__`.
*/
const DEFAULT_ERROR_HANDLER_NODE = "__default_error_handler__";
const PartialStateSchema = Symbol.for("langgraph.state.partial");
/**
* A graph whose nodes communicate by reading and writing to a shared state.
* Each node takes a defined `State` as input and returns a `Partial<State>`.
*
* Each state key can optionally be annotated with a reducer function that
* will be used to aggregate the values of that key received from multiple nodes.
* The signature of a reducer function is (left: Value, right: UpdateValue) => Value.
*
* See {@link Annotation} for more on defining state.
*
* After adding nodes and edges to your graph, you must call `.compile()` on it before
* you can use it.
*
* @typeParam SD - The state definition used to construct the graph. Can be an
*   {@link AnnotationRoot}, {@link StateSchema}, or Zod object schema. This is the
*   primary generic from which `S` and `U` are derived.
*
* @typeParam S - The full state type representing the complete shape of your graph's
*   state after all reducers have been applied. Automatically inferred from `SD`.
*
* @typeParam U - The update type representing what nodes can return to modify state.
*   Typically a partial of the state type. Automatically inferred from `SD`.
*
* @typeParam N - Union of all node names in the graph (e.g., `"agent" | "tool"`).
*   Accumulated as you call `.addNode()`. Used for type-safe routing.
*
* @typeParam I - The input schema definition. Set via the `input` option in the
*   constructor to restrict what data the graph accepts when invoked.
*
* @typeParam O - The output schema definition. Set via the `output` option in the
*   constructor to restrict what data the graph returns after execution.
*
* @typeParam C - The config/context schema definition. Set via the `context` option
*   to define additional configuration passed at runtime.
*
* @typeParam NodeReturnType - Constrains what types nodes in this graph can return.
*
* @typeParam InterruptType - The type for {@link interrupt} resume values. Set via
*   the `interrupt` option for typed human-in-the-loop patterns.
*
* @typeParam WriterType - The type for custom stream writers. Set via the `writer`
*   option to enable typed custom streaming from within nodes.
*
* @example
* ```ts
* import {
*   type BaseMessage,
*   AIMessage,
*   HumanMessage,
* } from "@langchain/core/messages";
* import { StateGraph, Annotation } from "@langchain/langgraph";
*
* // Define a state with a single key named "messages" that will
* // combine a returned BaseMessage or arrays of BaseMessages
* const StateAnnotation = Annotation.Root({
*   sentiment: Annotation<string>,
*   messages: Annotation<BaseMessage[]>({
*     reducer: (left: BaseMessage[], right: BaseMessage | BaseMessage[]) => {
*       if (Array.isArray(right)) {
*         return left.concat(right);
*       }
*       return left.concat([right]);
*     },
*     default: () => [],
*   }),
* });
*
* const graphBuilder = new StateGraph(StateAnnotation);
*
* // A node in the graph that returns an object with a "messages" key
* // will update the state by combining the existing value with the returned one.
* const myNode = (state: typeof StateAnnotation.State) => {
*   return {
*     messages: [new AIMessage("Some new response")],
*     sentiment: "positive",
*   };
* };
*
* const graph = graphBuilder
*   .addNode("myNode", myNode)
*   .addEdge("__start__", "myNode")
*   .addEdge("myNode", "__end__")
*   .compile();
*
* await graph.invoke({ messages: [new HumanMessage("how are you?")] });
*
* // {
* //   messages: [HumanMessage("how are you?"), AIMessage("Some new response")],
* //   sentiment: "positive",
* // }
* ```
*/
var StateGraph = class extends Graph {
	channels = {};
	waitingEdges = /* @__PURE__ */ new Set();
	/** @internal */
	_schemaDefinition;
	/** @internal */
	_schemaRuntimeDefinition;
	/** @internal */
	_inputDefinition;
	/** @internal */
	_inputRuntimeDefinition;
	/** @internal */
	_outputDefinition;
	/** @internal */
	_outputRuntimeDefinition;
	/**
	* Map schemas to managed values
	* @internal
	*/
	_schemaDefinitions = /* @__PURE__ */ new Map();
	/** @internal */
	_metaRegistry = schemaMetaRegistry;
	/** @internal Used only for typing. */
	_configSchema;
	/** @internal */
	_configRuntimeSchema;
	/** @internal */
	_interrupt;
	/** @internal */
	_writer;
	/**
	* Graph-wide default node policies, resolved at `compile()` time.
	* @internal
	*/
	_nodeDefaults = {};
	constructor(stateOrInit, options) {
		super();
		const init = this._normalizeToStateGraphInit(stateOrInit, options);
		const stateSchema = init.state ?? init.stateSchema ?? init.input;
		if (!stateSchema) throw new StateGraphInputError();
		const stateChannelDef = this._getChannelsFromSchema(stateSchema);
		this._schemaDefinition = stateChannelDef;
		if (StateSchema.isInstance(stateSchema)) this._schemaRuntimeDefinition = stateSchema;
		else if (isInteropZodObject(stateSchema)) this._schemaRuntimeDefinition = stateSchema;
		if (init.input) if (StateSchema.isInstance(init.input)) this._inputRuntimeDefinition = init.input;
		else if (isInteropZodObject(init.input)) this._inputRuntimeDefinition = init.input;
		else this._inputRuntimeDefinition = PartialStateSchema;
		else this._inputRuntimeDefinition = PartialStateSchema;
		if (init.output) if (StateSchema.isInstance(init.output)) this._outputRuntimeDefinition = init.output;
		else if (isInteropZodObject(init.output)) this._outputRuntimeDefinition = init.output;
		else this._outputRuntimeDefinition = this._schemaRuntimeDefinition;
		else this._outputRuntimeDefinition = this._schemaRuntimeDefinition;
		const inputChannelDef = init.input ? this._getChannelsFromSchema(init.input) : stateChannelDef;
		const outputChannelDef = init.output ? this._getChannelsFromSchema(init.output) : stateChannelDef;
		this._inputDefinition = inputChannelDef;
		this._outputDefinition = outputChannelDef;
		this._addSchema(this._schemaDefinition);
		this._addSchema(this._inputDefinition);
		this._addSchema(this._outputDefinition);
		if (init.context) {
			if (isInteropZodObject(init.context)) this._configRuntimeSchema = init.context;
		}
		this._interrupt = init.interrupt;
		this._writer = init.writer;
	}
	/**
	* Set graph-wide default node policies that apply to every node in this
	* graph.
	*
	* Per-node values passed to {@link addNode} always take precedence over these
	* defaults. Defaults are resolved at {@link compile} time, so call order does
	* not matter — you may call this before or after `addNode`, including as the
	* last step before `compile()`. Calling it multiple times merges the provided
	* fields, with later calls overriding earlier ones on a per-field basis.
	*
	* Policies set here are **not** inherited by subgraphs.
	*
	* `retryPolicy` and `timeout` defaults apply to **all** nodes, including
	* auto-generated error-handler nodes. `cachePolicy` and `errorHandler`
	* defaults apply to **regular nodes only** — caching an error-handler result
	* is unsafe, and a handler must never catch its own (or another handler's)
	* failure.
	*
	* @param defaults - The default node policies to apply.
	* @returns The builder instance, for chaining.
	*
	* @example Call before `addNode`
	* ```ts
	* const graph = new StateGraph(State)
	*   .setNodeDefaults({
	*     retryPolicy: { maxAttempts: 3 },
	*     cachePolicy: { ttl: 60 },
	*     timeout: 60_000,
	*     errorHandler: (state, { node, error }) => ({ lastError: error.message }),
	*   })
	*   .addNode("a", nodeA)
	*   .addNode("b", nodeB, { retryPolicy: { maxAttempts: 5 } }) // overrides default
	*   .addEdge(START, "a")
	*   .compile();
	* ```
	*
	* @example Call after `addNode`, immediately before `compile()`
	* ```ts
	* const graph = new StateGraph(State)
	*   .addNode("a", nodeA)
	*   .addNode("b", nodeB, { retryPolicy: { maxAttempts: 5 } }) // overrides default
	*   .addEdge(START, "a")
	*   .setNodeDefaults({
	*     retryPolicy: { maxAttempts: 3 },
	*     cachePolicy: { ttl: 60 },
	*   })
	*   .compile();
	* ```
	*/
	setNodeDefaults(defaults) {
		if (defaults.retryPolicy !== void 0) this._nodeDefaults.retryPolicy = defaults.retryPolicy;
		if (defaults.cachePolicy !== void 0) this._nodeDefaults.cachePolicy = typeof defaults.cachePolicy === "boolean" ? defaults.cachePolicy ? {} : void 0 : defaults.cachePolicy;
		if (defaults.timeout !== void 0) this._nodeDefaults.timeout = coerceTimeoutPolicy(defaults.timeout);
		if (defaults.errorHandler !== void 0) this._nodeDefaults.errorHandler = defaults.errorHandler;
		return this;
	}
	/**
	* Build the shared spec for a graph-wide default error handler, or
	* `undefined` when {@link setNodeDefaults} did not configure one. The spec is
	* installed under {@link DEFAULT_ERROR_HANDLER_NODE} for the duration of a
	* single {@link compile} call and routes failures from every regular node
	* that lacks its own handler.
	* @internal
	*/
	_createDefaultErrorHandlerSpec() {
		const userHandler = this._nodeDefaults.errorHandler;
		if (userHandler === void 0) return;
		return {
			runnable: new RunnableCallable({
				func: (state, config) => {
					const nodeError = config?.configurable?.[CONFIG_KEY_NODE_ERROR];
					return userHandler(state, nodeError, config);
				},
				name: DEFAULT_ERROR_HANDLER_NODE,
				trace: false
			}),
			metadata: void 0,
			input: this._schemaDefinition,
			retryPolicy: void 0,
			cachePolicy: void 0,
			isErrorHandler: true
		};
	}
	/**
	* Normalize all constructor input patterns to a unified StateGraphInit object.
	* @internal
	*/
	_normalizeToStateGraphInit(stateOrInit, options) {
		if (isStateGraphInit(stateOrInit)) {
			if (isInteropZodObject(options) || AnnotationRoot.isInstance(options)) return {
				...stateOrInit,
				context: options
			};
			const opts = options;
			return {
				...stateOrInit,
				input: stateOrInit.input ?? opts?.input,
				output: stateOrInit.output ?? opts?.output,
				context: stateOrInit.context ?? opts?.context,
				interrupt: stateOrInit.interrupt ?? opts?.interrupt,
				writer: stateOrInit.writer ?? opts?.writer,
				nodes: stateOrInit.nodes ?? opts?.nodes
			};
		}
		if (isStateDefinitionInit(stateOrInit)) {
			if (isInteropZodObject(options) || AnnotationRoot.isInstance(options)) return {
				state: stateOrInit,
				context: options
			};
			const opts = options;
			return {
				state: stateOrInit,
				input: opts?.input,
				output: opts?.output,
				context: opts?.context,
				interrupt: opts?.interrupt,
				writer: opts?.writer,
				nodes: opts?.nodes
			};
		}
		if (isStateGraphArgs(stateOrInit)) return { state: _getChannels(stateOrInit.channels) };
		throw new StateGraphInputError();
	}
	/**
	* Convert any supported schema type to a StateDefinition (channel map).
	* @internal
	*/
	_getChannelsFromSchema(schema) {
		if (StateSchema.isInstance(schema)) return schema.getChannels();
		if (isInteropZodObject(schema)) return this._metaRegistry.getChannelsForSchema(schema);
		if (typeof schema === "object" && "lc_graph_name" in schema && schema.lc_graph_name === "AnnotationRoot") return schema.spec;
		if (typeof schema === "object" && !Array.isArray(schema) && Object.keys(schema).length > 0) return schema;
		throw new StateGraphInputError("Invalid schema type. Expected StateSchema, Zod object, AnnotationRoot, or StateDefinition.");
	}
	get allEdges() {
		return new Set([...this.edges, ...Array.from(this.waitingEdges).flatMap(([starts, end]) => starts.map((start) => [start, end]))]);
	}
	_addSchema(stateDefinition) {
		if (this._schemaDefinitions.has(stateDefinition)) return;
		this._schemaDefinitions.set(stateDefinition, stateDefinition);
		for (const [key, val] of Object.entries(stateDefinition)) {
			let channel;
			if (typeof val === "function") channel = val();
			else channel = val;
			if (this.channels[key] !== void 0) {
				if (!this.channels[key].equals(channel)) {
					if (channel.lc_graph_name !== "LastValue") throw new Error(`Channel "${key}" already exists with a different type.`);
				}
			} else this.channels[key] = channel;
		}
	}
	addNode(...args) {
		function isMultipleNodes(args) {
			return args.length >= 1 && typeof args[0] !== "string";
		}
		const nodes = isMultipleNodes(args) ? Array.isArray(args[0]) ? args[0] : Object.entries(args[0]).map(([key, action]) => [key, action]) : [[
			args[0],
			args[1],
			args[2]
		]];
		if (nodes.length === 0) throw new Error("No nodes provided in `addNode`");
		for (const [key, action, options] of nodes) {
			if (key in this.channels) throw new Error(`${key} is already being used as a state attribute (a.k.a. a channel), cannot also be used as a node name.`);
			for (const reservedChar of ["|", ":"]) if (key.includes(reservedChar)) throw new Error(`"${reservedChar}" is a reserved character and is not allowed in node names.`);
			this.warnIfCompiled(`Adding a node to a graph that has already been compiled. This will not be reflected in the compiled graph.`);
			if (key in this.nodes) throw new Error(`Node \`${key}\` already present.`);
			if (key === "__end__" || key === "__start__") throw new Error(`Node \`${key}\` is reserved.`);
			let inputSpec = this._schemaDefinition;
			if (options?.input !== void 0) inputSpec = this._getChannelsFromSchema(options.input);
			this._addSchema(inputSpec);
			let runnable;
			if (Runnable.isRunnable(action)) runnable = action;
			else if (typeof action === "function") runnable = new RunnableCallable({
				func: action,
				name: key,
				trace: false
			});
			else runnable = _coerceToRunnable(action);
			const rawCachePolicy = options?.cachePolicy;
			let cachePolicy;
			if (rawCachePolicy !== void 0) cachePolicy = typeof rawCachePolicy === "boolean" ? rawCachePolicy ? {} : false : rawCachePolicy;
			let errorHandlerNode;
			if (options?.errorHandler !== void 0) {
				errorHandlerNode = `__error_handler__${key}`;
				if (errorHandlerNode in this.nodes) throw new Error(`Cannot add error handler to node \`${key}\`: the reserved name \`${errorHandlerNode}\` is already in use. StateGraph registers \`__error_handler__<nodeName>\` when you pass \`errorHandler\` in addNode options. Remove or rename the existing node with that name (for example, you may have added it manually).`);
				const userHandler = options.errorHandler;
				const handlerSpec = {
					runnable: new RunnableCallable({
						func: (state, config) => {
							const nodeError = config?.configurable?.[CONFIG_KEY_NODE_ERROR];
							return userHandler(state, nodeError, config);
						},
						name: errorHandlerNode,
						trace: false
					}),
					metadata: void 0,
					input: inputSpec ?? this._schemaDefinition,
					retryPolicy: void 0,
					cachePolicy: void 0,
					isErrorHandler: true
				};
				this.nodes[errorHandlerNode] = handlerSpec;
			}
			const nodeSpec = {
				runnable,
				retryPolicy: options?.retryPolicy,
				cachePolicy,
				timeout: coerceTimeoutPolicy(options?.timeout),
				metadata: options?.metadata,
				input: inputSpec ?? this._schemaDefinition,
				subgraphs: isPregelLike(runnable) ? [runnable] : options?.subgraphs,
				ends: options?.ends,
				defer: options?.defer,
				errorHandlerNode
			};
			this.nodes[key] = nodeSpec;
		}
		return this;
	}
	addEdge(startKey, endKey) {
		if (typeof startKey === "string") return super.addEdge(startKey, endKey);
		if (this.compiled) console.warn("Adding an edge to a graph that has already been compiled. This will not be reflected in the compiled graph.");
		for (const start of startKey) {
			if (start === "__end__") throw new Error("END cannot be a start node");
			if (!Object.keys(this.nodes).some((node) => node === start)) throw new Error(`Need to add a node named "${start}" first`);
		}
		if (endKey === "__end__") throw new Error("END cannot be an end node");
		if (!Object.keys(this.nodes).some((node) => node === endKey)) throw new Error(`Need to add a node named "${endKey}" first`);
		this.waitingEdges.add([startKey, endKey]);
		return this;
	}
	addSequence(nodes) {
		const parsedNodes = Array.isArray(nodes) ? nodes : Object.entries(nodes);
		if (parsedNodes.length === 0) throw new Error("Sequence requires at least one node.");
		let previousNode;
		for (const [key, action, options] of parsedNodes) {
			if (key in this.nodes) throw new Error(`Node names must be unique: node with the name "${key}" already exists.`);
			const validKey = key;
			this.addNode(key, action, options);
			if (previousNode != null) this.addEdge(previousNode, validKey);
			previousNode = validKey;
		}
		return this;
	}
	compile({ checkpointer, store, cache, interruptBefore, interruptAfter, name, description, transformers } = {}) {
		const defaultErrorHandlerSpec = this._createDefaultErrorHandlerSpec();
		if (defaultErrorHandlerSpec !== void 0) {
			if (DEFAULT_ERROR_HANDLER_NODE in this.nodes) throw new Error(`Cannot apply a default error handler: the reserved node name \`${DEFAULT_ERROR_HANDLER_NODE}\` is already in use. setNodeDefaults({ errorHandler }) registers a node with that name; rename the conflicting node.`);
			this.nodes[DEFAULT_ERROR_HANDLER_NODE] = defaultErrorHandlerSpec;
		}
		try {
			return this._compileResolved({
				checkpointer,
				store,
				cache,
				interruptBefore,
				interruptAfter,
				name,
				description,
				transformers,
				defaultErrorHandlerNode: defaultErrorHandlerSpec !== void 0 ? DEFAULT_ERROR_HANDLER_NODE : void 0
			});
		} finally {
			if (defaultErrorHandlerSpec !== void 0) delete this.nodes[DEFAULT_ERROR_HANDLER_NODE];
		}
	}
	/** @internal */
	_compileResolved({ checkpointer, store, cache, interruptBefore, interruptAfter, name, description, transformers, defaultErrorHandlerNode }) {
		this.validate([...Array.isArray(interruptBefore) ? interruptBefore : [], ...Array.isArray(interruptAfter) ? interruptAfter : []]);
		const outputKeys = Object.keys(this._schemaDefinitions.get(this._outputDefinition));
		const outputChannels = outputKeys.length === 1 && outputKeys[0] === ROOT ? ROOT : outputKeys;
		const streamKeys = Object.keys(this.channels);
		const streamChannels = streamKeys.length === 1 && streamKeys[0] === ROOT ? ROOT : streamKeys;
		const userInterrupt = this._interrupt;
		const compiled = new CompiledStateGraph({
			builder: this,
			checkpointer,
			interruptAfter,
			interruptBefore,
			autoValidate: false,
			nodes: {},
			channels: {
				...this.channels,
				[START]: new EphemeralValue()
			},
			inputChannels: START,
			outputChannels,
			streamChannels,
			streamMode: "updates",
			store,
			cache,
			name,
			description,
			userInterrupt,
			streamTransformers: transformers
		});
		compiled.attachNode(START);
		const nodeDefaults = this._nodeDefaults;
		const hasNodeDefaults = nodeDefaults.retryPolicy !== void 0 || nodeDefaults.cachePolicy !== void 0 || nodeDefaults.timeout !== void 0 || defaultErrorHandlerNode !== void 0;
		for (const [key, node] of Object.entries(this.nodes)) {
			const isErrorHandlerNode = node.isErrorHandler === true;
			const resolvedNode = hasNodeDefaults ? {
				...node,
				retryPolicy: node.retryPolicy ?? nodeDefaults.retryPolicy,
				cachePolicy: isErrorHandlerNode ? void 0 : node.cachePolicy === false ? void 0 : node.cachePolicy ?? nodeDefaults.cachePolicy,
				timeout: node.timeout ?? nodeDefaults.timeout,
				errorHandlerNode: !isErrorHandlerNode && defaultErrorHandlerNode !== void 0 && node.errorHandlerNode === void 0 ? defaultErrorHandlerNode : node.errorHandlerNode
			} : node;
			compiled.attachNode(key, resolvedNode);
		}
		compiled.attachBranch(START, SELF, _getControlBranch(), { withReader: false });
		for (const [key] of Object.entries(this.nodes)) compiled.attachBranch(key, SELF, _getControlBranch(), { withReader: false });
		for (const [start, end] of this.edges) compiled.attachEdge(start, end);
		for (const [starts, end] of this.waitingEdges) compiled.attachEdge(starts, end);
		for (const [start, branches] of Object.entries(this.branches)) for (const [name, branch] of Object.entries(branches)) compiled.attachBranch(start, name, branch);
		return compiled.validate();
	}
};
function _getChannels(schema) {
	const channels = {};
	for (const [name, val] of Object.entries(schema)) if (name === ROOT) channels[name] = getChannel(val);
	else channels[name] = getChannel(val);
	return channels;
}
/**
* Final result from building and compiling a {@link StateGraph}.
* Should not be instantiated directly, only using the StateGraph `.compile()`
* instance method.
*
* @typeParam S - The full state type representing the complete shape of your graph's
*   state after all reducers have been applied. This is the type you receive when
*   reading state in nodes or after invoking the graph.
*
* @typeParam U - The update type representing what nodes can return to modify state.
*   Typically a partial of the state type, allowing nodes to update only specific fields.
*   Can also include {@link Command} objects for advanced control flow.
*
* @typeParam N - Union of all node names in the graph (e.g., `"agent" | "tool"`).
*   Used for type-safe routing with {@link Command.goto} and edge definitions.
*
* @typeParam I - The input schema definition. Determines what shape of data the graph
*   accepts when invoked. Defaults to the main state schema if not explicitly set.
*
* @typeParam O - The output schema definition. Determines what shape of data the graph
*   returns after execution. Defaults to the main state schema if not explicitly set.
*
* @typeParam C - The config/context schema definition. Defines additional configuration
*   that can be passed to the graph at runtime via {@link LangGraphRunnableConfig}.
*
* @typeParam NodeReturnType - Constrains what types nodes in this graph can return.
*   Useful for enforcing consistent return patterns across all nodes.
*
* @typeParam InterruptType - The type of values that can be passed when resuming from
*   an {@link interrupt}. Used with human-in-the-loop patterns.
*
* @typeParam WriterType - The type for custom stream writers. Used with the `writer`
*   option to enable typed custom streaming from within nodes.
*
* @typeParam TStreamTransformers - Stream transformer factories registered at
*   compile time via the `transformers` option. Used to type extensions on
*   `streamEvents(..., { version: "v3" })`.
*/
var CompiledStateGraph = class extends CompiledGraph {
	/**
	* The description of the compiled graph.
	* This is used by the supervisor agent to describe the handoff to the agent.
	*/
	description;
	/** @internal */
	_metaRegistry = schemaMetaRegistry;
	constructor({ description, ...rest }) {
		super(rest);
		this.description = description;
	}
	attachNode(key, node) {
		let outputKeys;
		if (key === "__start__") outputKeys = Object.entries(this.builder._schemaDefinitions.get(this.builder._inputDefinition)).map(([k]) => k);
		else outputKeys = Object.keys(this.builder.channels);
		function _getRoot(input) {
			if (isCommand(input)) {
				if (input.graph === Command.PARENT) return null;
				return input._updateAsTuples();
			} else if (Array.isArray(input) && input.length > 0 && input.some((i) => isCommand(i))) {
				const updates = [];
				for (const i of input) if (isCommand(i)) {
					if (i.graph === Command.PARENT) continue;
					updates.push(...i._updateAsTuples());
				} else updates.push([ROOT, i]);
				return updates;
			} else if (input != null) return [[ROOT, input]];
			return null;
		}
		const nodeKey = key;
		const validateStateUpdates = async (updates) => {
			if (updates == null || updates.length === 0) return updates;
			const schemaDef = this.builder._schemaRuntimeDefinition;
			if (StateSchema.isInstance(schemaDef)) {
				const schemaKeys = new Set(schemaDef.getChannelKeys());
				return Promise.all(updates.map(async ([k, v]) => {
					if (!schemaKeys.has(k)) return [k, v];
					const parsed = await schemaDef.validateInput({ [k]: v });
					return [k, Object.prototype.hasOwnProperty.call(parsed, k) ? parsed[k] : v];
				}));
			}
			if (isInteropZodObject(schemaDef)) {
				const schemaKeys = new Set(Object.keys(getInteropZodObjectShape(schemaDef)));
				if (updates.filter(([k]) => schemaKeys.has(k)).length === 0) return updates;
				const updateSchema = interopZodObjectPartial(this._metaRegistry.getExtendedChannelSchemas(schemaDef, { withReducerSchema: true }));
				const valueSchema = interopZodObjectPartial(schemaDef);
				return updates.map(([k, v]) => {
					if (!schemaKeys.has(k)) return [k, v];
					const [isOverwrite, overwriteValue] = _getOverwriteValue(v);
					if (isOverwrite) {
						const parsed = interopParse(valueSchema, { [k]: overwriteValue });
						return [k, Object.prototype.hasOwnProperty.call(parsed, k) ? { [OVERWRITE]: parsed[k] } : v];
					}
					const parsed = interopParse(updateSchema, { [k]: v });
					return [k, Object.prototype.hasOwnProperty.call(parsed, k) ? parsed[k] : v];
				});
			}
			return updates;
		};
		async function _getUpdates(input) {
			if (!input) return null;
			else if (isCommand(input)) {
				if (input.graph === Command.PARENT) return null;
				return validateStateUpdates(input._updateAsTuples().filter(([k]) => outputKeys.includes(k)));
			} else if (Array.isArray(input) && input.length > 0 && input.some(isCommand)) {
				const updates = [];
				for (const item of input) if (isCommand(item)) {
					if (item.graph === Command.PARENT) continue;
					updates.push(...item._updateAsTuples().filter(([k]) => outputKeys.includes(k)));
				} else {
					const itemUpdates = await _getUpdates(item);
					if (itemUpdates) updates.push(...itemUpdates ?? []);
				}
				return validateStateUpdates(updates);
			} else if (typeof input === "object" && !Array.isArray(input)) return validateStateUpdates(Object.entries(input).filter(([k]) => outputKeys.includes(k)));
			else {
				const typeofInput = Array.isArray(input) ? "array" : typeof input;
				throw new InvalidUpdateError(`Expected node "${nodeKey.toString()}" to return an object or an array containing at least one Command object, received ${typeofInput}`, { lc_error_code: "INVALID_GRAPH_NODE_RETURN_VALUE" });
			}
		}
		const stateWriteEntries = [{
			value: PASSTHROUGH,
			mapper: new RunnableCallable({
				func: outputKeys.length && outputKeys[0] === ROOT ? _getRoot : _getUpdates,
				trace: false,
				recurse: false
			})
		}];
		if (key === "__start__") this.nodes[key] = new PregelNode({
			tags: [TAG_HIDDEN],
			triggers: [START],
			channels: [START],
			writers: [new ChannelWrite(stateWriteEntries, [TAG_HIDDEN])]
		});
		else {
			const inputDefinition = node?.input ?? this.builder._schemaDefinition;
			const inputValues = Object.fromEntries(Object.keys(this.builder._schemaDefinitions.get(inputDefinition)).map((k) => [k, k]));
			const isSingleInput = Object.keys(inputValues).length === 1 && ROOT in inputValues;
			const branchChannel = `branch:to:${key}`;
			this.channels[branchChannel] = node?.defer ? new LastValueAfterFinish() : new EphemeralValue(false);
			const nodeCachePolicy = node?.cachePolicy;
			const cachePolicy = nodeCachePolicy === false ? void 0 : nodeCachePolicy;
			this.nodes[key] = new PregelNode({
				triggers: [branchChannel],
				channels: isSingleInput ? Object.keys(inputValues) : inputValues,
				writers: [new ChannelWrite(stateWriteEntries, [TAG_HIDDEN])],
				mapper: isSingleInput ? void 0 : (input) => {
					return Object.fromEntries(Object.entries(input).filter(([k]) => k in inputValues));
				},
				bound: node?.runnable,
				metadata: node?.metadata,
				retryPolicy: node?.retryPolicy,
				cachePolicy,
				timeout: node?.timeout,
				subgraphs: node?.subgraphs,
				ends: node?.ends,
				isErrorHandler: node?.isErrorHandler,
				errorHandlerNode: node?.errorHandlerNode
			});
		}
	}
	attachEdge(starts, end) {
		if (end === "__end__") return;
		if (typeof starts === "string") this.nodes[starts].writers.push(new ChannelWrite([{
			channel: `branch:to:${end}`,
			value: null
		}], [TAG_HIDDEN]));
		else if (Array.isArray(starts)) {
			const channelName = `join:${starts.join("+")}:${end}`;
			this.channels[channelName] = this.builder.nodes[end].defer ? new NamedBarrierValueAfterFinish(new Set(starts)) : new NamedBarrierValue(new Set(starts));
			this.nodes[end].triggers.push(channelName);
			for (const start of starts) this.nodes[start].writers.push(new ChannelWrite([{
				channel: channelName,
				value: start
			}], [TAG_HIDDEN]));
		}
	}
	attachBranch(start, _, branch, options = { withReader: true }) {
		const branchWriter = async (packets, config) => {
			const filteredPackets = packets.filter((p) => p !== END);
			if (!filteredPackets.length) return;
			const writes = filteredPackets.map((p) => {
				if (_isSend(p)) return p;
				return {
					channel: p === "__end__" ? p : `branch:to:${p}`,
					value: start
				};
			});
			await ChannelWrite.doWrite({
				...config,
				tags: (config.tags ?? []).concat([TAG_HIDDEN])
			}, writes);
		};
		this.nodes[start].writers.push(branch.run(branchWriter, options.withReader ? (config) => ChannelRead.doRead(config, this.streamChannels ?? this.outputChannels, true) : void 0));
	}
	async _validateInput(input) {
		if (input == null) return input;
		const inputDef = this.builder._inputRuntimeDefinition;
		const schemaDef = this.builder._schemaRuntimeDefinition;
		if (StateSchema.isInstance(inputDef)) {
			if (isCommand(input)) {
				const parsedInput = input;
				if (input.update) parsedInput.update = await inputDef.validateInput(Array.isArray(input.update) ? Object.fromEntries(input.update) : input.update);
				return parsedInput;
			}
			return await inputDef.validateInput(input);
		}
		if (inputDef === PartialStateSchema && StateSchema.isInstance(schemaDef)) {
			if (isCommand(input)) {
				const parsedInput = input;
				if (input.update) parsedInput.update = await schemaDef.validateInput(Array.isArray(input.update) ? Object.fromEntries(input.update) : input.update);
				return parsedInput;
			}
			return await schemaDef.validateInput(input);
		}
		const schema = (() => {
			const apply = (schema) => {
				if (schema == null) return void 0;
				return this._metaRegistry.getExtendedChannelSchemas(schema, { withReducerSchema: true });
			};
			if (isInteropZodObject(inputDef)) return apply(inputDef);
			if (inputDef === PartialStateSchema) {
				if (isInteropZodObject(schemaDef)) return interopZodObjectPartial(apply(schemaDef));
				return;
			}
		})();
		if (isCommand(input)) {
			const parsedInput = input;
			if (input.update && schema != null) {
				const updateObj = Array.isArray(input.update) ? Object.fromEntries(input.update) : input.update;
				const parsed = interopParse(schema, updateObj);
				parsedInput.update = Object.fromEntries(Object.keys(updateObj).map((k) => [k, parsed[k]]));
			}
			return parsedInput;
		}
		if (schema != null) return interopParse(schema, input);
		return input;
	}
	isInterrupted(input) {
		return isInterrupted(input);
	}
	async _validateContext(config) {
		const configSchema = this.builder._configRuntimeSchema;
		if (isInteropZodObject(configSchema)) interopParse(configSchema, config);
		return config;
	}
};
/**
* Check if value is a legacy StateGraphArgs with channels.
* @internal
* @deprecated Use StateGraphInit instead
*/
function isStateGraphArgs(obj) {
	return typeof obj === "object" && obj !== null && obj.channels !== void 0;
}
function _controlBranch(value) {
	if (_isSend(value)) return [value];
	const commands = [];
	if (isCommand(value)) commands.push(value);
	else if (Array.isArray(value)) commands.push(...value.filter(isCommand));
	const destinations = [];
	for (const command of commands) {
		if (command.graph === Command.PARENT) throw new ParentCommand(command);
		if (_isSend(command.goto)) destinations.push(command.goto);
		else if (typeof command.goto === "string") destinations.push(command.goto);
		else if (Array.isArray(command.goto)) destinations.push(...command.goto);
	}
	return destinations;
}
function _getControlBranch() {
	return new Branch({ path: new RunnableCallable({
		func: _controlBranch,
		tags: [TAG_HIDDEN],
		trace: false,
		recurse: false,
		name: "<control_branch>"
	}) });
}
//#endregion
export { CompiledStateGraph, StateGraph };

//# sourceMappingURL=state.js.map