UNPKG

@langchain/langgraph

Version:

LangGraph

1 lines 20 kB
{"version":3,"file":"constants.cjs","names":["result: unknown"],"sources":["../src/constants.ts"],"sourcesContent":["import { PendingWrite } from \"@langchain/langgraph-checkpoint\";\n\n/** Special reserved node name denoting the start of a graph. */\nexport const START = \"__start__\";\n/** Special reserved node name denoting the end of a graph. */\nexport const END = \"__end__\";\nexport const INPUT = \"__input__\";\nexport const COPY = \"__copy__\";\nexport const ERROR = \"__error__\";\n\n/** Special reserved cache namespaces */\nexport const CACHE_NS_WRITES = \"__pregel_ns_writes\";\n\nexport const CONFIG_KEY_SEND = \"__pregel_send\";\n/** config key containing function used to call a node (push task) */\nexport const CONFIG_KEY_CALL = \"__pregel_call\";\nexport const CONFIG_KEY_READ = \"__pregel_read\";\nexport const CONFIG_KEY_CHECKPOINTER = \"__pregel_checkpointer\";\nexport const CONFIG_KEY_RESUMING = \"__pregel_resuming\";\nexport const CONFIG_KEY_TASK_ID = \"__pregel_task_id\";\nexport const CONFIG_KEY_STREAM = \"__pregel_stream\";\nexport const CONFIG_KEY_RESUME_VALUE = \"__pregel_resume_value\";\nexport const CONFIG_KEY_RESUME_MAP = \"__pregel_resume_map\";\nexport const CONFIG_KEY_SCRATCHPAD = \"__pregel_scratchpad\";\n/** config key containing state from previous invocation of graph for the given thread */\nexport const CONFIG_KEY_PREVIOUS_STATE = \"__pregel_previous\";\nexport const CONFIG_KEY_DURABILITY = \"__pregel_durability\";\nexport const CONFIG_KEY_CHECKPOINT_ID = \"checkpoint_id\";\nexport const CONFIG_KEY_CHECKPOINT_NS = \"checkpoint_ns\";\n\nexport const CONFIG_KEY_NODE_FINISHED = \"__pregel_node_finished\";\n\n// this one is part of public API\nexport const CONFIG_KEY_CHECKPOINT_MAP = \"checkpoint_map\";\n\nexport const CONFIG_KEY_ABORT_SIGNALS = \"__pregel_abort_signals\";\n\n/** Special channel reserved for graph interrupts */\nexport const INTERRUPT = \"__interrupt__\";\n/** Special channel reserved for graph resume */\nexport const RESUME = \"__resume__\";\n/** Special channel reserved for cases when a task exits without any writes */\nexport const NO_WRITES = \"__no_writes__\";\n/** Special channel reserved for graph return */\nexport const RETURN = \"__return__\";\n/** Special channel reserved for graph previous state */\nexport const PREVIOUS = \"__previous__\";\nexport const RUNTIME_PLACEHOLDER = \"__pregel_runtime_placeholder__\";\nexport const RECURSION_LIMIT_DEFAULT = 25;\n\nexport const TAG_HIDDEN = \"langsmith:hidden\";\nexport const TAG_NOSTREAM = \"langsmith:nostream\";\nexport const SELF = \"__self__\";\n\nexport const TASKS = \"__pregel_tasks\";\nexport const PUSH = \"__pregel_push\";\nexport const PULL = \"__pregel_pull\";\n\nexport const TASK_NAMESPACE = \"6ba7b831-9dad-11d1-80b4-00c04fd430c8\";\nexport const NULL_TASK_ID = \"00000000-0000-0000-0000-000000000000\";\n\nexport const RESERVED = [\n TAG_HIDDEN,\n INPUT,\n INTERRUPT,\n RESUME,\n ERROR,\n NO_WRITES,\n\n // reserved config.configurable keys\n CONFIG_KEY_SEND,\n CONFIG_KEY_READ,\n CONFIG_KEY_CHECKPOINTER,\n CONFIG_KEY_DURABILITY,\n CONFIG_KEY_STREAM,\n CONFIG_KEY_RESUMING,\n CONFIG_KEY_TASK_ID,\n CONFIG_KEY_CALL,\n CONFIG_KEY_RESUME_VALUE,\n CONFIG_KEY_SCRATCHPAD,\n CONFIG_KEY_PREVIOUS_STATE,\n CONFIG_KEY_CHECKPOINT_MAP,\n CONFIG_KEY_CHECKPOINT_NS,\n CONFIG_KEY_CHECKPOINT_ID,\n];\n\nexport const CHECKPOINT_NAMESPACE_SEPARATOR = \"|\";\nexport const CHECKPOINT_NAMESPACE_END = \":\";\n\n/** @internal */\nconst COMMAND_SYMBOL = Symbol.for(\"langgraph.command\");\n\n/**\n * Instance of a {@link Command} class.\n *\n * This is used to avoid IntelliSense suggesting public fields\n * of {@link Command} class when a plain object is expected.\n *\n * @see {@link Command}\n * @internal\n */\nexport class CommandInstance<\n Resume = unknown,\n Update extends Record<string, unknown> = Record<string, unknown>,\n Nodes extends string = string\n> {\n [COMMAND_SYMBOL]: CommandParams<Resume, Update, Nodes>;\n\n constructor(args: CommandParams<Resume, Update, Nodes>) {\n this[COMMAND_SYMBOL] = args;\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport interface SendInterface<Node extends string = string, Args = any> {\n node: Node;\n args: Args;\n}\n\nexport function _isSendInterface(x: unknown): x is SendInterface {\n const operation = x as SendInterface;\n return (\n operation !== null &&\n operation !== undefined &&\n typeof operation.node === \"string\" &&\n operation.args !== undefined\n );\n}\n\n/**\n *\n * A message or packet to send to a specific node in the graph.\n *\n * The `Send` class is used within a `StateGraph`'s conditional edges to\n * dynamically invoke a node with a custom state at the next step.\n *\n * Importantly, the sent state can differ from the core graph's state,\n * allowing for flexible and dynamic workflow management.\n *\n * One such example is a \"map-reduce\" workflow where your graph invokes\n * the same node multiple times in parallel with different states,\n * before aggregating the results back into the main graph's state.\n *\n * @example\n * ```typescript\n * import { Annotation, Send, StateGraph } from \"@langchain/langgraph\";\n *\n * const ChainState = Annotation.Root({\n * subjects: Annotation<string[]>,\n * jokes: Annotation<string[]>({\n * reducer: (a, b) => a.concat(b),\n * }),\n * });\n *\n * const continueToJokes = async (state: typeof ChainState.State) => {\n * return state.subjects.map((subject) => {\n * return new Send(\"generate_joke\", { subjects: [subject] });\n * });\n * };\n *\n * const graph = new StateGraph(ChainState)\n * .addNode(\"generate_joke\", (state) => ({\n * jokes: [`Joke about ${state.subjects}`],\n * }))\n * .addConditionalEdges(\"__start__\", continueToJokes)\n * .addEdge(\"generate_joke\", \"__end__\")\n * .compile();\n *\n * const res = await graph.invoke({ subjects: [\"cats\", \"dogs\"] });\n * console.log(res);\n *\n * // Invoking with two subjects results in a generated joke for each\n * // { subjects: [\"cats\", \"dogs\"], jokes: [`Joke about cats`, `Joke about dogs`] }\n * ```\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport class Send<Node extends string = string, Args = any>\n implements SendInterface<Node, Args>\n{\n lg_name = \"Send\";\n\n public node: Node;\n\n public args: Args;\n\n constructor(node: Node, args: Args) {\n this.node = node;\n this.args = _deserializeCommandSendObjectGraph(args) as Args;\n }\n\n toJSON() {\n return { lg_name: this.lg_name, node: this.node, args: this.args };\n }\n}\n\nexport function _isSend(x: unknown): x is Send {\n // eslint-disable-next-line no-instanceof/no-instanceof\n return x instanceof Send;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type Interrupt<Value = any> = {\n id?: string;\n value?: Value;\n};\n\n/**\n * Checks if the given graph invoke / stream chunk contains interrupt.\n *\n * @example\n * ```ts\n * import { INTERRUPT, isInterrupted } from \"@langchain/langgraph\";\n *\n * const values = await graph.invoke({ foo: \"bar\" });\n * if (isInterrupted<string>(values)) {\n * const interrupt = values[INTERRUPT][0].value;\n * }\n * ```\n *\n * @param values - The values to check.\n * @returns `true` if the values contain an interrupt, `false` otherwise.\n */\nexport function isInterrupted<Value = unknown>(\n values: unknown\n): values is { [INTERRUPT]: Interrupt<Value>[] } {\n if (!values || typeof values !== \"object\") return false;\n if (!(INTERRUPT in values)) return false;\n return Array.isArray(values[INTERRUPT]);\n}\n\nexport type CommandParams<\n Resume = unknown,\n Update extends Record<string, unknown> = Record<string, unknown>,\n Nodes extends string = string\n> = {\n /**\n * A discriminator field used to identify the type of object. Must be populated when serializing.\n *\n * Optional because it's not required to specify this when directly constructing a {@link Command}\n * object.\n */\n lg_name?: \"Command\";\n\n /**\n * Value to resume execution with. To be used together with {@link interrupt}.\n */\n resume?: Resume;\n /**\n * Graph to send the command to. Supported values are:\n * - None: the current graph (default)\n * - The specific name of the graph to send the command to\n * - {@link Command.PARENT}: closest parent graph (only supported when returned from a node in a subgraph)\n */\n graph?: string;\n\n /**\n * Update to apply to the graph's state.\n */\n update?: Update | [string, unknown][];\n\n /**\n * Can be one of the following:\n * - name of the node to navigate to next (any node that belongs to the specified `graph`)\n * - sequence of node names to navigate to next\n * - `Send` object (to execute a node with the input provided)\n * - sequence of `Send` objects\n */\n goto?:\n | Nodes\n | SendInterface<Nodes> // eslint-disable-line @typescript-eslint/no-explicit-any\n | (Nodes | SendInterface<Nodes>)[]; // eslint-disable-line @typescript-eslint/no-explicit-any\n};\n\n/**\n * One or more commands to update the graph's state and send messages to nodes.\n * Can be used to combine routing logic with state updates in lieu of conditional edges\n *\n * @example\n * ```ts\n * import { Annotation, Command } from \"@langchain/langgraph\";\n *\n * // Define graph state\n * const StateAnnotation = Annotation.Root({\n * foo: Annotation<string>,\n * });\n *\n * // Define the nodes\n * const nodeA = async (_state: typeof StateAnnotation.State) => {\n * console.log(\"Called A\");\n * // this is a replacement for a real conditional edge function\n * const goto = Math.random() > .5 ? \"nodeB\" : \"nodeC\";\n * // note how Command allows you to BOTH update the graph state AND route to the next node\n * return new Command({\n * // this is the state update\n * update: {\n * foo: \"a\",\n * },\n * // this is a replacement for an edge\n * goto,\n * });\n * };\n *\n * // Nodes B and C are unchanged\n * const nodeB = async (state: typeof StateAnnotation.State) => {\n * console.log(\"Called B\");\n * return {\n * foo: state.foo + \"|b\",\n * };\n * }\n *\n * const nodeC = async (state: typeof StateAnnotation.State) => {\n * console.log(\"Called C\");\n * return {\n * foo: state.foo + \"|c\",\n * };\n * }\n * \n * import { StateGraph } from \"@langchain/langgraph\";\n\n * // NOTE: there are no edges between nodes A, B and C!\n * const graph = new StateGraph(StateAnnotation)\n * .addNode(\"nodeA\", nodeA, {\n * ends: [\"nodeB\", \"nodeC\"],\n * })\n * .addNode(\"nodeB\", nodeB)\n * .addNode(\"nodeC\", nodeC)\n * .addEdge(\"__start__\", \"nodeA\")\n * .compile();\n * \n * await graph.invoke({ foo: \"\" });\n *\n * // Randomly oscillates between\n * // { foo: 'a|c' } and { foo: 'a|b' }\n * ```\n */\nexport class Command<\n Resume = unknown,\n Update extends Record<string, unknown> = Record<string, unknown>,\n Nodes extends string = string\n> extends CommandInstance<Resume, Update, Nodes> {\n readonly lg_name = \"Command\";\n\n lc_direct_tool_output = true;\n\n /**\n * Graph to send the command to. Supported values are:\n * - None: the current graph (default)\n * - The specific name of the graph to send the command to\n * - {@link Command.PARENT}: closest parent graph (only supported when returned from a node in a subgraph)\n */\n graph?: string;\n\n /**\n * Update to apply to the graph's state as a result of executing the node that is returning the command.\n * Written to the state as if the node had simply returned this value instead of the Command object.\n */\n update?: Update | [string, unknown][];\n\n /**\n * Value to resume execution with. To be used together with {@link interrupt}.\n */\n resume?: Resume;\n\n /**\n * Can be one of the following:\n * - name of the node to navigate to next (any node that belongs to the specified `graph`)\n * - sequence of node names to navigate to next\n * - {@link Send} object (to execute a node with the exact input provided in the {@link Send} object)\n * - sequence of {@link Send} objects\n */\n goto?: Nodes | Send<Nodes> | (Nodes | Send<Nodes>)[] = [];\n\n static PARENT = \"__parent__\";\n\n constructor(args: Omit<CommandParams<Resume, Update, Nodes>, \"lg_name\">) {\n super(args);\n this.resume = args.resume;\n this.graph = args.graph;\n this.update = args.update;\n if (args.goto) {\n type ValidArg = Nodes | Send<Nodes, Update>;\n\n this.goto = Array.isArray(args.goto)\n ? (_deserializeCommandSendObjectGraph(args.goto) as ValidArg[])\n : [_deserializeCommandSendObjectGraph(args.goto) as ValidArg];\n }\n }\n\n /**\n * Convert the update field to a list of {@link PendingWrite} tuples\n * @returns List of {@link PendingWrite} tuples of the form `[channelKey, value]`.\n * @internal\n */\n _updateAsTuples(): PendingWrite[] {\n if (\n this.update &&\n typeof this.update === \"object\" &&\n !Array.isArray(this.update)\n ) {\n return Object.entries(this.update);\n } else if (\n Array.isArray(this.update) &&\n this.update.every(\n (t): t is [string, unknown] =>\n Array.isArray(t) && t.length === 2 && typeof t[0] === \"string\"\n )\n ) {\n return this.update;\n } else {\n return [[\"__root__\", this.update]];\n }\n }\n\n toJSON() {\n let serializedGoto;\n if (typeof this.goto === \"string\") {\n serializedGoto = this.goto;\n } else if (_isSend(this.goto)) {\n serializedGoto = this.goto.toJSON();\n } else {\n serializedGoto = this.goto?.map((innerGoto) => {\n if (typeof innerGoto === \"string\") {\n return innerGoto;\n } else {\n return innerGoto.toJSON();\n }\n });\n }\n return {\n lg_name: this.lg_name,\n update: this.update,\n resume: this.resume,\n goto: serializedGoto,\n };\n }\n}\n\n/**\n * A type guard to check if the given value is a {@link Command}.\n *\n * Useful for type narrowing when working with the {@link Command} object.\n *\n * @param x - The value to check.\n * @returns `true` if the value is a {@link Command}, `false` otherwise.\n */\nexport function isCommand(x: unknown): x is Command {\n if (typeof x !== \"object\") {\n return false;\n }\n\n if (x === null || x === undefined) {\n return false;\n }\n\n if (\"lg_name\" in x && x.lg_name === \"Command\") {\n return true;\n }\n\n return false;\n}\n\n/**\n * Reconstructs Command and Send objects from a deeply nested tree of anonymous objects\n * matching their interfaces.\n *\n * This is only exported for testing purposes. It is NOT intended to be used outside of\n * the Command and Send classes.\n *\n * @internal\n *\n * @param x - The command send tree to convert.\n * @param seen - A map of seen objects to avoid infinite loops.\n * @returns The converted command send tree.\n */\nexport function _deserializeCommandSendObjectGraph(\n x: unknown,\n seen: Map<object, unknown> = new Map()\n): unknown {\n if (x !== undefined && x !== null && typeof x === \"object\") {\n // If we've already processed this object, return the transformed version\n if (seen.has(x)) {\n return seen.get(x);\n }\n\n let result: unknown;\n\n if (Array.isArray(x)) {\n // Create the array first, then populate it\n result = [];\n // Add to seen map before processing elements to handle self-references\n seen.set(x, result);\n\n // Now populate the array\n x.forEach((item, index) => {\n (result as unknown[])[index] = _deserializeCommandSendObjectGraph(\n item,\n seen\n );\n });\n // eslint-disable-next-line no-instanceof/no-instanceof\n } else if (isCommand(x) && !(x instanceof Command)) {\n result = new Command(x);\n seen.set(x, result);\n // eslint-disable-next-line no-instanceof/no-instanceof\n } else if (_isSendInterface(x) && !(x instanceof Send)) {\n result = new Send(x.node, x.args);\n seen.set(x, result);\n } else if (isCommand(x) || _isSend(x)) {\n result = x;\n seen.set(x, result);\n } else if (\"lc_serializable\" in x && x.lc_serializable) {\n result = x;\n seen.set(x, result);\n } else {\n // Create empty object first\n result = {};\n // Add to seen map before processing properties to handle self-references\n seen.set(x, result);\n\n // Now populate the object\n for (const [key, value] of Object.entries(x)) {\n (result as Record<string, unknown>)[key] =\n _deserializeCommandSendObjectGraph(value, seen);\n }\n }\n\n return result;\n }\n return x;\n}\n"],"mappings":"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"}